mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:30:42 +00:00
fix(replies): keep queued followup typing alive
This commit is contained in:
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Web search/MiniMax: allow `MINIMAX_OAUTH_TOKEN` to satisfy MiniMax Search credentials, so OAuth-authorized MiniMax Token Plan setups do not need a separate web-search key. Fixes #65768. Thanks @kikibrian and @zhouhe-xydt.
|
||||
- Subagents: honor `sessions_spawn` with `expectsCompletionMessage: false` by skipping parent completion handoff delivery while still running child cleanup. Fixes #75848. Thanks @alfredjbclaw.
|
||||
- Gateway/logging: keep deferred channel startup logs on the subsystem logger, so Slack, Discord, Telegram, and voice-call startup messages keep timestamped prefixes. Thanks @vincentkoc.
|
||||
- Replies/typing: keep typing alive for queued follow-up messages that are genuinely waiting behind an active run, instead of making chat surfaces look idle while work is queued. Fixes #65685. Thanks @papag00se.
|
||||
- ACP/Discord: suppress completion announce delivery for inline thread-bound ACP session runs, so Discord thread-bound ACP replies are not delivered twice. Fixes #60780. Thanks @solavrc.
|
||||
- Discord/threads: ignore webhook-authored copies in already-bound Discord session threads even when the webhook id differs, preventing PluralKit proxy copies from creating duplicate turn pressure. Fixes #52005. Thanks @acgh213.
|
||||
- Discord/threads: return the created thread as partial success when the follow-up initial message fails, so agents do not retry thread creation and create empty duplicate threads. Fixes #48450. Thanks @dahifi.
|
||||
|
||||
@@ -219,8 +219,28 @@ describe("runReplyAgent heartbeat followup guard", () => {
|
||||
expect(state.runEmbeddedPiAgentMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps typing alive when a followup is queued behind a live active run", async () => {
|
||||
const { run, typing } = createMinimalRun({
|
||||
opts: { isHeartbeat: false },
|
||||
isActive: true,
|
||||
isRunActive: () => true,
|
||||
shouldFollowup: true,
|
||||
resolvedQueueMode: "collect",
|
||||
});
|
||||
|
||||
const result = await run();
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
expect(vi.mocked(enqueueFollowupRun)).toHaveBeenCalledTimes(1);
|
||||
expect(vi.mocked(scheduleFollowupDrain)).not.toHaveBeenCalled();
|
||||
expect(state.runEmbeddedPiAgentMock).not.toHaveBeenCalled();
|
||||
expect(typing.startTypingLoop).toHaveBeenCalledTimes(1);
|
||||
expect(typing.refreshTypingTtl).toHaveBeenCalledTimes(1);
|
||||
expect(typing.cleanup).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("starts draining immediately when the active snapshot is already stale", async () => {
|
||||
const { run } = createMinimalRun({
|
||||
const { run, typing } = createMinimalRun({
|
||||
opts: { isHeartbeat: false },
|
||||
isActive: true,
|
||||
isRunActive: () => false,
|
||||
@@ -234,6 +254,7 @@ describe("runReplyAgent heartbeat followup guard", () => {
|
||||
expect(vi.mocked(enqueueFollowupRun)).toHaveBeenCalledTimes(1);
|
||||
expect(vi.mocked(scheduleFollowupDrain)).toHaveBeenCalledTimes(1);
|
||||
expect(state.runEmbeddedPiAgentMock).not.toHaveBeenCalled();
|
||||
expect(typing.cleanup).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("drains followup queue when an unexpected exception escapes the run path", async () => {
|
||||
|
||||
@@ -1045,11 +1045,16 @@ export async function runReplyAgent(params: {
|
||||
);
|
||||
// Re-check liveness after enqueue so a stale active snapshot cannot leave
|
||||
// the followup queue idle if the original run already finished.
|
||||
if (!isRunActive?.()) {
|
||||
const queuedBehindActiveRun = isRunActive?.() === true;
|
||||
if (!queuedBehindActiveRun) {
|
||||
finalizeWithFollowup(undefined, queueKey, queuedRunFollowupTurn);
|
||||
}
|
||||
await touchActiveSessionEntry();
|
||||
typing.cleanup();
|
||||
if (queuedBehindActiveRun) {
|
||||
await typingSignals.signalToolStart();
|
||||
} else {
|
||||
typing.cleanup();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user