diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index bd559c035..e74c67963 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixed -- Fixed Assistant-mode TTS playback aborting when an agent continued after a tool call in the same run; internal turn boundaries now preserve queued speech, while a new agent run still interrupts prior playback. ([#6375](https://github.com/can1357/oh-my-pi/issues/6375)) +- Fixed Assistant-mode TTS playback aborting when an agent continued after a tool call or automatic follow-up in the same run; internal continuation boundaries now preserve queued speech, while a new user message still interrupts prior playback. ([#6375](https://github.com/can1357/oh-my-pi/issues/6375)) - Fixed credential-shaped tokens (GitHub/GitLab/OpenAI/Anthropic key patterns) being redacted from outbound provider requests even with `secrets.enabled` off; the pattern redaction now follows the `secrets.enabled` ("Hide Secrets") setting like the secret obfuscator. - Fixed Ctrl-clicking a wrapped OAuth authorization URL opening only the clicked row's truncated fragment by preserving the complete hyperlink target on every rendered row. - Fixed used-only absolute usage amounts across output surfaces: CLI now renders `$123.45 used`; the TUI shows a neutral, width-bounded amount instead of a pending/dotted/account-count placeholder; and ACP preserves `123.45 usd used` while suppressing duplicate window suffixes such as `— extra`. ([#5575](https://github.com/can1357/oh-my-pi/issues/5575)) diff --git a/packages/coding-agent/src/modes/controllers/event-controller.ts b/packages/coding-agent/src/modes/controllers/event-controller.ts index 10e92d797..1e2be54bd 100644 --- a/packages/coding-agent/src/modes/controllers/event-controller.ts +++ b/packages/coding-agent/src/modes/controllers/event-controller.ts @@ -405,7 +405,6 @@ export class EventController { } async #handleAgentStart(_event: Extract): Promise { - vocalizer.clear(); this.#toolTimelineComponents.clear(); this.#postToolAssistantComponents.clear(); this.#lastIntent = undefined; @@ -450,6 +449,7 @@ export class EventController { } this.ctx.ui.requestRender(); } else if (event.message.role === "user") { + vocalizer.clear(); const textContent = this.ctx.getUserMessageText(event.message); const imageBlocks = typeof event.message.content === "string" diff --git a/packages/coding-agent/test/modes/controllers/event-controller-interrupt.test.ts b/packages/coding-agent/test/modes/controllers/event-controller-interrupt.test.ts index 7072b8c31..77b1218c1 100644 --- a/packages/coding-agent/test/modes/controllers/event-controller-interrupt.test.ts +++ b/packages/coding-agent/test/modes/controllers/event-controller-interrupt.test.ts @@ -22,6 +22,11 @@ function createContext() { transcriptMessageComponents: new WeakMap(), pendingTools, hideThinkingBlock: false, + getUserMessageText: () => "new prompt", + locallySubmittedUserSignatures: new Set(), + addMessageToChat: vi.fn(), + editor: { setText: vi.fn() }, + updatePendingMessagesDisplay: vi.fn(), setWorkingMessage, clearPinnedError: vi.fn(), ensureLoadingAnimation, @@ -62,15 +67,24 @@ describe("EventController aborted-turn working messages", () => { resetSettingsForTest(); }); - it("preserves playback across internal turns and clears it for a new agent run", async () => { + it("preserves playback across internal continuations and clears it for a user message", async () => { const clear = vi.spyOn(vocalizer, "clear").mockImplementation(() => {}); const { ctx } = createContext(); const controller = new EventController(ctx); + await controller.handleEvent(AGENT_START); await controller.handleEvent({ type: "turn_start" }); expect(clear).not.toHaveBeenCalled(); - await controller.handleEvent(AGENT_START); + await controller.handleEvent({ + type: "message_start", + message: { + role: "user", + content: [{ type: "text", text: "new prompt" }], + attribution: "user", + timestamp: Date.now(), + }, + }); expect(clear).toHaveBeenCalledTimes(1); });