diff --git a/src/services/auto-capture.ts b/src/services/auto-capture.ts index db756431..62894621 100644 --- a/src/services/auto-capture.ts +++ b/src/services/auto-capture.ts @@ -271,7 +271,7 @@ function getAIResponseMessages(messages: any[], promptMessageId: string): any[] return responseMessages; } -function extractAIContent(messages: any[]): { +export function extractAIContent(messages: any[]): { textResponses: string[]; toolCalls: ToolCallInfo[]; } { @@ -293,7 +293,7 @@ function extractAIContent(messages: any[]): { const toolParts = msg.parts.filter((p: any) => p.type === "tool"); for (const tool of toolParts) { - const name = tool.tool || "unknown"; + const name = tool.name || tool.tool || "unknown"; let input = ""; if (tool.state?.input) { diff --git a/tests/auto-capture-context.test.ts b/tests/auto-capture-context.test.ts index 681df4b4..aea35914 100644 --- a/tests/auto-capture-context.test.ts +++ b/tests/auto-capture-context.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "bun:test"; import { buildBoundedSummaryPrompt, buildMarkdownContext, + extractAIContent, getAutoCaptureMarkdownBudget, } from "../src/services/auto-capture.js"; import { utf8ByteLength } from "../src/utils/context-limit.js"; @@ -96,3 +97,54 @@ describe("buildMarkdownContext budgeting (#232)", () => { expect(userPrompt).toContain("truncated to autoCaptureMaxContextBytes"); }); }); + +describe("extractAIContent tool calls", () => { + it("extracts tool names from v2-shaped parts", () => { + const { toolCalls } = extractAIContent([ + { + info: { role: "assistant" }, + parts: [ + { + type: "tool", + id: "t1", + name: "bash", + state: { status: "completed", input: { command: "ls" } }, + }, + ], + }, + ]); + + expect(toolCalls).toHaveLength(1); + expect(toolCalls[0]?.name).toBe("bash"); + expect(toolCalls[0]?.input).toContain('command: "ls"'); + }); + + it("keeps extracting tool names from v1-shaped parts", () => { + const { toolCalls } = extractAIContent([ + { + info: { role: "assistant" }, + parts: [ + { + type: "tool", + callID: "call_1", + tool: "read", + state: { input: { path: "/tmp/x" } }, + }, + ], + }, + ]); + + expect(toolCalls[0]?.name).toBe("read"); + }); + + it("falls back to unknown when a tool part has no name", () => { + const { toolCalls } = extractAIContent([ + { + info: { role: "assistant" }, + parts: [{ type: "tool", state: { input: {} } }], + }, + ]); + + expect(toolCalls[0]?.name).toBe("unknown"); + }); +});