From 3c391358c4323fb77698d5f5575f146ef167a42f Mon Sep 17 00:00:00 2001 From: Vojta Bartos Date: Wed, 17 Jun 2026 14:34:52 +0200 Subject: [PATCH 1/6] feat(agent): broadcast tool-use status notifications Emit a POSTHOG_NOTIFICATIONS.STATUS notification when a tool first starts. The payload carries the existing toolInfo.title as a human-readable text so downstream consumers can render a live "agent is doing X" status line without inferring intent from raw tool names. The orchestrator consumes this in a follow-up PR; existing ACP clients already ignore unknown status values, so this is backwards-compatible. --- .../src/adapters/claude/conversion/sdk-to-acp.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts index 3d5dc0e28b..87c6871555 100644 --- a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts +++ b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts @@ -249,6 +249,21 @@ function handleToolUseChunk( cwd: ctx.cwd, }); + // Broadcast a live "agent is doing X" status when a tool first starts so + // downstream consumers (the Slack orchestrator) can render it as a status + // line in the thread without inferring intent from raw tool names. + if (!alreadyCached && toolInfo.title) { + void ctx.client + .extNotification(POSTHOG_NOTIFICATIONS.STATUS, { + sessionId: ctx.sessionId, + status: "tool_use", + text: toolInfo.title, + }) + .catch(() => { + // Best-effort — a failed status broadcast must not break tool execution. + }); + } + const meta: Record = { ...toolMeta( chunk.name, From 8ec27129f73ab0bb700f48b06893d76acb7c20fe Mon Sep 17 00:00:00 2001 From: Vojta Bartos Date: Wed, 17 Jun 2026 16:17:01 +0200 Subject: [PATCH 2/6] feat(agent): enrich status notification with tool_name + tool_args_preview The downstream Slack orchestrator now renders each agent action as a plan-block step (task_update chunk) with the bare tool name as the title and a short preview of the args as the details line. Match Slack's task_update field shape so the orchestrator can pass these through with no further transformation. tool_args_preview is derived from the first matching arg field (bash command / file_path / path / query / pattern / url / description), collapsed to a single line and trimmed to 240 chars (well under the 256-char Slack limit). --- .../adapters/claude/conversion/sdk-to-acp.ts | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts index 87c6871555..24636c41c1 100644 --- a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts +++ b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts @@ -136,6 +136,35 @@ function bashCommandFromToolUse( return typeof command === "string" ? command : undefined; } +const TOOL_ARGS_PREVIEW_LIMIT = 240; + +function toolArgsPreview( + chunk: ToolUseCache[string], + bashCommand: string | undefined, +): string { + const input = chunk.input as Record | undefined; + const tryField = (key: string): string | undefined => { + const v = input?.[key]; + return typeof v === "string" && v ? v : undefined; + }; + + const raw = + bashCommand ?? + tryField("file_path") ?? + tryField("notebook_path") ?? + tryField("path") ?? + tryField("query") ?? + tryField("pattern") ?? + tryField("url") ?? + tryField("description") ?? + ""; + if (!raw) return ""; + const oneLine = raw.replace(/\s+/g, " ").trim(); + return oneLine.length > TOOL_ARGS_PREVIEW_LIMIT + ? `${oneLine.slice(0, TOOL_ARGS_PREVIEW_LIMIT - 1)}…` + : oneLine; +} + function handleTextChunk( chunk: { text: string }, role: Role, @@ -251,13 +280,22 @@ function handleToolUseChunk( // Broadcast a live "agent is doing X" status when a tool first starts so // downstream consumers (the Slack orchestrator) can render it as a status - // line in the thread without inferring intent from raw tool names. + // line in the thread without inferring intent from raw tool names. The + // `tool_name` + `tool_args_preview` fields let renderers show the bare tool + // name on the plan-block step and a short preview of the args (file path, + // command, query) on the `details` line — same shape as Slack's + // task_update chunk. if (!alreadyCached && toolInfo.title) { void ctx.client .extNotification(POSTHOG_NOTIFICATIONS.STATUS, { sessionId: ctx.sessionId, status: "tool_use", text: toolInfo.title, + tool_name: chunk.name, + tool_args_preview: toolArgsPreview( + chunk, + bashCommandFromToolUse(chunk), + ), }) .catch(() => { // Best-effort — a failed status broadcast must not break tool execution. From f5caa2931a379d36971625052c8483862543fb2e Mon Sep 17 00:00:00 2001 From: Vojta Bartos Date: Wed, 17 Jun 2026 16:46:47 +0200 Subject: [PATCH 3/6] feat(agent): tag relayMessage calls with reply vs question kind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Slack orchestrator suppresses the post-turn 'reply' relay when the streaming plan-block path is active (the streamed message already carries the agent's text). Questions still need to render as a standalone thread message so the user can see and respond, so they're passed through with kind="question". Default stays "reply" — pre-existing callers continue to behave the same; only the question relay opts into the new kind. --- packages/agent/src/posthog-api.ts | 3 ++- packages/agent/src/server/agent-server.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/agent/src/posthog-api.ts b/packages/agent/src/posthog-api.ts index fb0c161d1a..3cd3889c9d 100644 --- a/packages/agent/src/posthog-api.ts +++ b/packages/agent/src/posthog-api.ts @@ -209,13 +209,14 @@ export class PostHogAPIClient { taskId: string, runId: string, text: string, + kind: "reply" | "question" = "reply", ): Promise { const teamId = this.getTeamId(); await this.apiRequest<{ status: string }>( `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`, { method: "POST", - body: JSON.stringify({ text }), + body: JSON.stringify({ text, kind }), }, ); } diff --git a/packages/agent/src/server/agent-server.ts b/packages/agent/src/server/agent-server.ts index 0492b9fd06..17988ad6aa 100644 --- a/packages/agent/src/server/agent-server.ts +++ b/packages/agent/src/server/agent-server.ts @@ -2315,7 +2315,7 @@ ${signedCommitInstructions} this.questionRelayedToSlack = true; this.posthogAPI - .relayMessage(payload.task_id, payload.run_id, message) + .relayMessage(payload.task_id, payload.run_id, message, "question") .catch((err) => this.logger.debug("Failed to relay question to Slack", { err }), ); From 6b7c0e82b70b44abeb021b290a80b1314f64c28e Mon Sep 17 00:00:00 2001 From: Vojta Bartos Date: Wed, 17 Jun 2026 17:41:28 +0200 Subject: [PATCH 4/6] feat(agent): broaden tool_args_preview to cover MCP and sub-agent args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCP tools (mcp__posthog__exec, MCP gateways) typically pass their payload in a 'code' arg — not the file_path/path/query/bash keys the preview originally scanned. Add 'code', 'prompt', 'name', 'title' to the explicit allow-list and fall back to the first short string-valued input arg when nothing in the list matches, so any MCP tool with a single descriptive arg gets a useful details line on the Slack plan block rather than an empty one. --- .../adapters/claude/conversion/sdk-to-acp.ts | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts index 24636c41c1..589a7793b9 100644 --- a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts +++ b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts @@ -138,6 +138,20 @@ function bashCommandFromToolUse( const TOOL_ARGS_PREVIEW_LIMIT = 240; +const TOOL_ARGS_PREVIEW_KEYS = [ + "file_path", + "notebook_path", + "path", + "code", // MCP exec / hogql / sql payloads + "query", // search queries + "pattern", // grep / glob patterns + "url", + "description", + "prompt", // Task / Agent sub-agent prompt + "name", // schema lookups + "title", +]; + function toolArgsPreview( chunk: ToolUseCache[string], bashCommand: string | undefined, @@ -148,16 +162,27 @@ function toolArgsPreview( return typeof v === "string" && v ? v : undefined; }; - const raw = - bashCommand ?? - tryField("file_path") ?? - tryField("notebook_path") ?? - tryField("path") ?? - tryField("query") ?? - tryField("pattern") ?? - tryField("url") ?? - tryField("description") ?? - ""; + let raw = bashCommand; + if (!raw) { + for (const key of TOOL_ARGS_PREVIEW_KEYS) { + const v = tryField(key); + if (v) { + raw = v; + break; + } + } + } + // Fallback: take the first short-string arg of the input. Avoids returning + // the empty string when an MCP tool uses an arg name we don't enumerate + // above. Bound by ``TOOL_ARGS_PREVIEW_LIMIT`` after the truncation below. + if (!raw && input) { + for (const value of Object.values(input)) { + if (typeof value === "string" && value.trim()) { + raw = value; + break; + } + } + } if (!raw) return ""; const oneLine = raw.replace(/\s+/g, " ").trim(); return oneLine.length > TOOL_ARGS_PREVIEW_LIMIT From b446d875da68777500cf1df6ff9fc5e07a481a06 Mon Sep 17 00:00:00 2001 From: Vojta Bartos Date: Wed, 17 Jun 2026 18:08:57 +0200 Subject: [PATCH 5/6] feat(agent): emit pre-tool assistant prose as tool_intent on _posthog/status The orchestrator uses tool_intent as the upcoming plan-block step's description when it's short enough to fit, otherwise it stays as the streamed message body. Always-emit (the orchestrator owns the threshold decision) keeps the protocol simple. Buffer is reset on every tool emit so each step's intent is just the prose since the previous tool. The MessageHandlerContext-level buffer is fresh per turn, so turn 1's trailing prose can't leak into turn 2's first step. --- .../agent/src/adapters/claude/claude-agent.ts | 3 + .../adapters/claude/conversion/sdk-to-acp.ts | 60 +++++++++++++++++-- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/agent/src/adapters/claude/claude-agent.ts b/packages/agent/src/adapters/claude/claude-agent.ts index 8df465ae26..b59a6d6fce 100644 --- a/packages/agent/src/adapters/claude/claude-agent.ts +++ b/packages/agent/src/adapters/claude/claude-agent.ts @@ -515,6 +515,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent { textIds: new Set(), thinkingIds: new Set(), }, + // Reset each turn — pre-tool prose accumulated last turn must not carry + // over into the next turn's first ``_posthog/status`` ``tool_intent``. + intentBuffer: { value: "" }, }; try { diff --git a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts index 589a7793b9..c2f6ce82cf 100644 --- a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts +++ b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts @@ -62,6 +62,16 @@ interface AnthropicMessageWithContent { }; } +/** + * Accumulates assistant-text content emitted since the last tool_use so the + * orchestrator can render the agent's pre-tool prose as the upcoming step's + * description. The mutable wrapper threads through the chunk handlers; each + * tool_use emit reads and resets ``value``. + */ +export interface IntentBuffer { + value: string; +} + type ChunkHandlerContext = { sessionId: string; toolUseCache: ToolUseCache; @@ -73,6 +83,7 @@ type ChunkHandlerContext = { registerHooks?: boolean; supportsTerminalOutput?: boolean; cwd?: string; + intentBuffer?: IntentBuffer; /** Raw MCP tool result from SDKUserMessage.tool_use_result (contains content, structuredContent, _meta) */ mcpToolUseResult?: Record; /** Per-session task list (populated by createTaskHook + tool_result handler) */ @@ -109,6 +120,13 @@ export interface MessageHandlerContext { supportsTerminalOutput?: boolean; /** Absent on replay, where the legacy drop-all text/thinking filter applies. */ streamedAssistantBlocks?: StreamedAssistantBlocks; + /** + * Mutable buffer accumulating assistant-text deltas since the last tool_use. + * Read+reset on every ``_posthog/status`` emit so the orchestrator can use + * the agent's pre-tool prose as the upcoming step's description. Optional + * (absent on replay); the chunk handler tolerates ``undefined``. + */ + intentBuffer?: IntentBuffer; } function messageUpdateType(role: Role) { @@ -194,7 +212,14 @@ function handleTextChunk( chunk: { text: string }, role: Role, parentToolCallId?: string, + intentBuffer?: IntentBuffer, ): SessionUpdate { + // Only top-level assistant prose feeds the upcoming tool's intent. Skip + // sub-agent (parentToolCallId) and user text; neither should drive a + // surrounding step's description. + if (role === "assistant" && !parentToolCallId && intentBuffer && chunk.text) { + intentBuffer.value += chunk.text; + } const update: SessionUpdate = { sessionUpdate: messageUpdateType(role), content: text(chunk.text), @@ -305,12 +330,18 @@ function handleToolUseChunk( // Broadcast a live "agent is doing X" status when a tool first starts so // downstream consumers (the Slack orchestrator) can render it as a status - // line in the thread without inferring intent from raw tool names. The - // `tool_name` + `tool_args_preview` fields let renderers show the bare tool - // name on the plan-block step and a short preview of the args (file path, - // command, query) on the `details` line — same shape as Slack's - // task_update chunk. + // line in the thread. ``tool_name`` / ``tool_args_preview`` give the bare + // tool name and a short arg preview for the plan-block step; ``tool_intent`` + // carries the assistant prose accumulated since the previous tool — the + // orchestrator uses it as the step's description when it's short enough to + // fit Slack's task_update.details field, otherwise it stays in the message + // body. Always-emit (rather than agent-side threshold) keeps the protocol + // simple — the orchestrator owns the rendering decision. if (!alreadyCached && toolInfo.title) { + const toolIntent = ctx.intentBuffer?.value ?? ""; + if (ctx.intentBuffer) { + ctx.intentBuffer.value = ""; + } void ctx.client .extNotification(POSTHOG_NOTIFICATIONS.STATUS, { sessionId: ctx.sessionId, @@ -321,6 +352,7 @@ function handleToolUseChunk( chunk, bashCommandFromToolUse(chunk), ), + tool_intent: toolIntent, }) .catch(() => { // Best-effort — a failed status broadcast must not break tool execution. @@ -541,7 +573,12 @@ function processContentChunk( switch (chunk.type) { case "text": case "text_delta": { - const update = handleTextChunk(chunk, role, ctx.parentToolCallId); + const update = handleTextChunk( + chunk, + role, + ctx.parentToolCallId, + ctx.intentBuffer, + ); return update ? [update] : []; } @@ -619,8 +656,12 @@ function toAcpNotifications( mcpToolUseResult?: Record, enrichedReadCache?: EnrichedReadCache, taskState?: TaskState, + intentBuffer?: IntentBuffer, ): SessionNotification[] { if (typeof content === "string") { + if (role === "assistant" && !parentToolCallId && intentBuffer && content) { + intentBuffer.value += content; + } const update: SessionUpdate = { sessionUpdate: messageUpdateType(role), content: text(content), @@ -648,6 +689,7 @@ function toAcpNotifications( cwd, mcpToolUseResult, taskState, + intentBuffer, }; const output: SessionNotification[] = []; @@ -674,6 +716,7 @@ function streamEventToAcpNotifications( cwd?: string, enrichedReadCache?: EnrichedReadCache, taskState?: TaskState, + intentBuffer?: IntentBuffer, ): SessionNotification[] { const event = message.event; switch (event.type) { @@ -700,6 +743,7 @@ function streamEventToAcpNotifications( undefined, enrichedReadCache, taskState, + intentBuffer, ); } case "content_block_delta": { @@ -726,6 +770,7 @@ function streamEventToAcpNotifications( undefined, enrichedReadCache, taskState, + intentBuffer, ); } case "content_block_stop": @@ -1061,6 +1106,7 @@ export async function handleStreamEvent( context.session.cwd, context.enrichedReadCache, context.session.taskState, + context.intentBuffer, )) { await client.sessionUpdate(notification); context.session.notificationHistory.push(notification); @@ -1266,6 +1312,7 @@ export async function handleUserAssistantMessage( undefined, context.enrichedReadCache, session.taskState, + context.intentBuffer, )) { await client.sessionUpdate(notification); session.notificationHistory.push(notification); @@ -1312,6 +1359,7 @@ export async function handleUserAssistantMessage( mcpToolUseResult, context.enrichedReadCache, session.taskState, + context.intentBuffer, )) { await client.sessionUpdate(notification); session.notificationHistory.push(notification); From 41f902594ddb35279f3448bcdc3c187bfc8252eb Mon Sep 17 00:00:00 2001 From: Vojta Bartos Date: Wed, 17 Jun 2026 19:54:19 +0200 Subject: [PATCH 6/6] Revert "feat(agent): emit pre-tool assistant prose as tool_intent on _posthog/status" This reverts commit b446d875da68777500cf1df6ff9fc5e07a481a06. --- .../agent/src/adapters/claude/claude-agent.ts | 3 - .../adapters/claude/conversion/sdk-to-acp.ts | 60 ++----------------- 2 files changed, 6 insertions(+), 57 deletions(-) diff --git a/packages/agent/src/adapters/claude/claude-agent.ts b/packages/agent/src/adapters/claude/claude-agent.ts index b59a6d6fce..8df465ae26 100644 --- a/packages/agent/src/adapters/claude/claude-agent.ts +++ b/packages/agent/src/adapters/claude/claude-agent.ts @@ -515,9 +515,6 @@ export class ClaudeAcpAgent extends BaseAcpAgent { textIds: new Set(), thinkingIds: new Set(), }, - // Reset each turn — pre-tool prose accumulated last turn must not carry - // over into the next turn's first ``_posthog/status`` ``tool_intent``. - intentBuffer: { value: "" }, }; try { diff --git a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts index c2f6ce82cf..589a7793b9 100644 --- a/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts +++ b/packages/agent/src/adapters/claude/conversion/sdk-to-acp.ts @@ -62,16 +62,6 @@ interface AnthropicMessageWithContent { }; } -/** - * Accumulates assistant-text content emitted since the last tool_use so the - * orchestrator can render the agent's pre-tool prose as the upcoming step's - * description. The mutable wrapper threads through the chunk handlers; each - * tool_use emit reads and resets ``value``. - */ -export interface IntentBuffer { - value: string; -} - type ChunkHandlerContext = { sessionId: string; toolUseCache: ToolUseCache; @@ -83,7 +73,6 @@ type ChunkHandlerContext = { registerHooks?: boolean; supportsTerminalOutput?: boolean; cwd?: string; - intentBuffer?: IntentBuffer; /** Raw MCP tool result from SDKUserMessage.tool_use_result (contains content, structuredContent, _meta) */ mcpToolUseResult?: Record; /** Per-session task list (populated by createTaskHook + tool_result handler) */ @@ -120,13 +109,6 @@ export interface MessageHandlerContext { supportsTerminalOutput?: boolean; /** Absent on replay, where the legacy drop-all text/thinking filter applies. */ streamedAssistantBlocks?: StreamedAssistantBlocks; - /** - * Mutable buffer accumulating assistant-text deltas since the last tool_use. - * Read+reset on every ``_posthog/status`` emit so the orchestrator can use - * the agent's pre-tool prose as the upcoming step's description. Optional - * (absent on replay); the chunk handler tolerates ``undefined``. - */ - intentBuffer?: IntentBuffer; } function messageUpdateType(role: Role) { @@ -212,14 +194,7 @@ function handleTextChunk( chunk: { text: string }, role: Role, parentToolCallId?: string, - intentBuffer?: IntentBuffer, ): SessionUpdate { - // Only top-level assistant prose feeds the upcoming tool's intent. Skip - // sub-agent (parentToolCallId) and user text; neither should drive a - // surrounding step's description. - if (role === "assistant" && !parentToolCallId && intentBuffer && chunk.text) { - intentBuffer.value += chunk.text; - } const update: SessionUpdate = { sessionUpdate: messageUpdateType(role), content: text(chunk.text), @@ -330,18 +305,12 @@ function handleToolUseChunk( // Broadcast a live "agent is doing X" status when a tool first starts so // downstream consumers (the Slack orchestrator) can render it as a status - // line in the thread. ``tool_name`` / ``tool_args_preview`` give the bare - // tool name and a short arg preview for the plan-block step; ``tool_intent`` - // carries the assistant prose accumulated since the previous tool — the - // orchestrator uses it as the step's description when it's short enough to - // fit Slack's task_update.details field, otherwise it stays in the message - // body. Always-emit (rather than agent-side threshold) keeps the protocol - // simple — the orchestrator owns the rendering decision. + // line in the thread without inferring intent from raw tool names. The + // `tool_name` + `tool_args_preview` fields let renderers show the bare tool + // name on the plan-block step and a short preview of the args (file path, + // command, query) on the `details` line — same shape as Slack's + // task_update chunk. if (!alreadyCached && toolInfo.title) { - const toolIntent = ctx.intentBuffer?.value ?? ""; - if (ctx.intentBuffer) { - ctx.intentBuffer.value = ""; - } void ctx.client .extNotification(POSTHOG_NOTIFICATIONS.STATUS, { sessionId: ctx.sessionId, @@ -352,7 +321,6 @@ function handleToolUseChunk( chunk, bashCommandFromToolUse(chunk), ), - tool_intent: toolIntent, }) .catch(() => { // Best-effort — a failed status broadcast must not break tool execution. @@ -573,12 +541,7 @@ function processContentChunk( switch (chunk.type) { case "text": case "text_delta": { - const update = handleTextChunk( - chunk, - role, - ctx.parentToolCallId, - ctx.intentBuffer, - ); + const update = handleTextChunk(chunk, role, ctx.parentToolCallId); return update ? [update] : []; } @@ -656,12 +619,8 @@ function toAcpNotifications( mcpToolUseResult?: Record, enrichedReadCache?: EnrichedReadCache, taskState?: TaskState, - intentBuffer?: IntentBuffer, ): SessionNotification[] { if (typeof content === "string") { - if (role === "assistant" && !parentToolCallId && intentBuffer && content) { - intentBuffer.value += content; - } const update: SessionUpdate = { sessionUpdate: messageUpdateType(role), content: text(content), @@ -689,7 +648,6 @@ function toAcpNotifications( cwd, mcpToolUseResult, taskState, - intentBuffer, }; const output: SessionNotification[] = []; @@ -716,7 +674,6 @@ function streamEventToAcpNotifications( cwd?: string, enrichedReadCache?: EnrichedReadCache, taskState?: TaskState, - intentBuffer?: IntentBuffer, ): SessionNotification[] { const event = message.event; switch (event.type) { @@ -743,7 +700,6 @@ function streamEventToAcpNotifications( undefined, enrichedReadCache, taskState, - intentBuffer, ); } case "content_block_delta": { @@ -770,7 +726,6 @@ function streamEventToAcpNotifications( undefined, enrichedReadCache, taskState, - intentBuffer, ); } case "content_block_stop": @@ -1106,7 +1061,6 @@ export async function handleStreamEvent( context.session.cwd, context.enrichedReadCache, context.session.taskState, - context.intentBuffer, )) { await client.sessionUpdate(notification); context.session.notificationHistory.push(notification); @@ -1312,7 +1266,6 @@ export async function handleUserAssistantMessage( undefined, context.enrichedReadCache, session.taskState, - context.intentBuffer, )) { await client.sessionUpdate(notification); session.notificationHistory.push(notification); @@ -1359,7 +1312,6 @@ export async function handleUserAssistantMessage( mcpToolUseResult, context.enrichedReadCache, session.taskState, - context.intentBuffer, )) { await client.sessionUpdate(notification); session.notificationHistory.push(notification);