@posthog/agent 2.3.1 → 2.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,11 +45,10 @@ function getMcpToolMetadata(toolName) {
45
45
  }
46
46
 
47
47
  // src/adapters/claude/conversion/tool-use-to-acp.ts
48
- var SYSTEM_REMINDER = `
49
-
50
- <system-reminder>
51
- Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.
52
- </system-reminder>`;
48
+ var SYSTEM_REMINDER_REGEX = /\s*<system-reminder>[\s\S]*?<\/system-reminder>/g;
49
+ function stripSystemReminders(value) {
50
+ return value.replace(SYSTEM_REMINDER_REGEX, "");
51
+ }
53
52
  function toDisplayPath(filePath, cwd) {
54
53
  if (!cwd) return filePath;
55
54
  const resolvedCwd = path.resolve(cwd);
@@ -387,9 +386,7 @@ function toolUpdateFromToolResult(toolResult, toolUse, options) {
387
386
  return {
388
387
  type: "content",
389
388
  content: text(
390
- markdownEscape(
391
- (itemObj.text ?? "").replace(SYSTEM_REMINDER, "")
392
- )
389
+ markdownEscape(stripSystemReminders(itemObj.text ?? ""))
393
390
  )
394
391
  };
395
392
  }
@@ -411,9 +408,7 @@ function toolUpdateFromToolResult(toolResult, toolUse, options) {
411
408
  };
412
409
  } else if (typeof toolResult.content === "string" && toolResult.content.length > 0) {
413
410
  return {
414
- content: toolContent().text(
415
- markdownEscape(toolResult.content.replace(SYSTEM_REMINDER, ""))
416
- ).build()
411
+ content: toolContent().text(markdownEscape(stripSystemReminders(toolResult.content))).build()
417
412
  };
418
413
  }
419
414
  return {};
@@ -513,7 +508,7 @@ function itemToText(item) {
513
508
  if (!item || typeof item !== "object") return null;
514
509
  const obj = item;
515
510
  if (obj.type === "text" && typeof obj.text === "string") {
516
- return obj.text;
511
+ return stripSystemReminders(obj.text);
517
512
  }
518
513
  try {
519
514
  return JSON.stringify(obj, null, 2);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/adapters/claude/conversion/tool-use-to-acp.ts","../../../../src/utils/acp-content.ts","../../../../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import path from \"node:path\";\nimport type {\n PlanEntry,\n ToolCall,\n ToolCallContent,\n ToolCallLocation,\n ToolCallUpdate,\n ToolKind,\n} from \"@agentclientprotocol/sdk\";\nimport type {\n ToolResultBlockParam,\n ToolUseBlock,\n WebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources\";\nimport type {\n BetaBashCodeExecutionToolResultBlockParam,\n BetaCodeExecutionToolResultBlockParam,\n BetaRequestMCPToolResultBlockParam,\n BetaTextEditorCodeExecutionToolResultBlockParam,\n BetaToolSearchToolResultBlockParam,\n BetaWebFetchToolResultBlockParam,\n BetaWebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources/beta.mjs\";\n\nconst SYSTEM_REMINDER = `\n\n<system-reminder>\nWhenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.\n</system-reminder>`;\n\nimport { resourceLink, text, toolContent } from \"../../../utils/acp-content.js\";\nimport { getMcpToolMetadata } from \"../mcp/tool-metadata.js\";\n\ntype ToolInfo = Pick<ToolCall, \"title\" | \"kind\" | \"content\" | \"locations\">;\n\n/**\n * Convert an absolute file path to a project-relative path for display.\n * Returns the original path if it's outside the project directory or if no cwd is provided.\n */\nexport function toDisplayPath(filePath: string, cwd?: string): string {\n if (!cwd) return filePath;\n const resolvedCwd = path.resolve(cwd);\n const resolvedFile = path.resolve(filePath);\n if (\n resolvedFile.startsWith(resolvedCwd + path.sep) ||\n resolvedFile === resolvedCwd\n ) {\n return path.relative(resolvedCwd, resolvedFile);\n }\n return filePath;\n}\n\nexport function toolInfoFromToolUse(\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\">,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n cwd?: string;\n },\n): ToolInfo {\n const name = toolUse.name;\n const input = toolUse.input as Record<string, unknown> | undefined;\n\n switch (name) {\n case \"Task\":\n case \"Agent\":\n return {\n title: input?.description ? String(input.description) : name,\n kind: \"think\",\n content: input?.prompt\n ? toolContent().text(String(input.prompt)).build()\n : [],\n };\n\n case \"NotebookRead\":\n return {\n title: input?.notebook_path\n ? `Read Notebook ${String(input.notebook_path)}`\n : \"Read Notebook\",\n kind: \"read\",\n content: [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"NotebookEdit\":\n return {\n title: input?.notebook_path\n ? `Edit Notebook ${String(input.notebook_path)}`\n : \"Edit Notebook\",\n kind: \"edit\",\n content: input?.new_source\n ? toolContent().text(String(input.new_source)).build()\n : [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"Bash\":\n if (options?.supportsTerminalOutput && options?.toolUseId) {\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: [{ type: \"terminal\", terminalId: options.toolUseId }],\n };\n }\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: input?.command\n ? toolContent().text(String(input.command)).build()\n : [],\n };\n\n case \"BashOutput\":\n return {\n title: \"Tail Logs\",\n kind: \"execute\",\n content: [],\n };\n\n case \"KillShell\":\n return {\n title: \"Kill Process\",\n kind: \"execute\",\n content: [],\n };\n\n case \"Read\": {\n let limit = \"\";\n const inputLimit = input?.limit as number | undefined;\n const inputOffset = (input?.offset as number | undefined) ?? 1;\n if (inputLimit) {\n limit = ` (${inputOffset} - ${inputOffset + inputLimit - 1})`;\n } else if (inputOffset > 1) {\n limit = ` (from line ${inputOffset})`;\n }\n const displayPath = input?.file_path\n ? toDisplayPath(String(input.file_path), options?.cwd)\n : \"File\";\n return {\n title: `Read ${displayPath}${limit}`,\n kind: \"read\",\n locations: input?.file_path\n ? [\n {\n path: String(input.file_path),\n line: inputOffset,\n },\n ]\n : [],\n content: [],\n };\n }\n\n case \"LS\":\n return {\n title: `List the ${input?.path ? `\\`${String(input.path)}\\`` : \"current\"} directory's contents`,\n kind: \"search\",\n content: [],\n locations: [],\n };\n\n case \"Edit\": {\n const filePath = input?.file_path ? String(input.file_path) : undefined;\n const displayPath = filePath\n ? toDisplayPath(filePath, options?.cwd)\n : undefined;\n let oldText: string | null = input?.old_string\n ? String(input.old_string)\n : null;\n let newText: string = input?.new_string ? String(input.new_string) : \"\";\n\n // If we have cached file content, show a full-file diff\n if (\n filePath &&\n options?.cachedFileContent &&\n filePath in options.cachedFileContent\n ) {\n const oldContent = options.cachedFileContent[filePath];\n const newContent = input?.replace_all\n ? oldContent.replaceAll(oldText ?? \"\", newText)\n : oldContent.replace(oldText ?? \"\", newText);\n oldText = oldContent;\n newText = newContent;\n }\n\n return {\n title: displayPath ? `Edit \\`${displayPath}\\`` : \"Edit\",\n kind: \"edit\",\n content:\n input && filePath\n ? [\n {\n type: \"diff\",\n path: filePath,\n oldText,\n newText,\n },\n ]\n : [],\n locations: filePath ? [{ path: filePath }] : [],\n };\n }\n\n case \"Write\": {\n let contentResult: ToolCallContent[] = [];\n const writeFilePath = input?.file_path\n ? String(input.file_path)\n : undefined;\n const writeDisplayPath = writeFilePath\n ? toDisplayPath(writeFilePath, options?.cwd)\n : undefined;\n const contentStr = input?.content ? String(input.content) : undefined;\n if (writeFilePath) {\n const oldContent =\n options?.cachedFileContent &&\n writeFilePath in options.cachedFileContent\n ? options.cachedFileContent[writeFilePath]\n : null;\n contentResult = toolContent()\n .diff(writeFilePath, oldContent, contentStr ?? \"\")\n .build();\n } else if (contentStr) {\n contentResult = toolContent().text(contentStr).build();\n }\n return {\n title: writeDisplayPath ? `Write ${writeDisplayPath}` : \"Write\",\n kind: \"edit\",\n content: contentResult,\n locations: writeFilePath ? [{ path: writeFilePath }] : [],\n };\n }\n\n case \"Glob\": {\n let label = \"Find\";\n const pathStr = input?.path ? String(input.path) : undefined;\n if (pathStr) {\n label += ` \"${pathStr}\"`;\n }\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n return {\n title: label,\n kind: \"search\",\n content: [],\n locations: pathStr ? [{ path: pathStr }] : [],\n };\n }\n\n case \"Grep\": {\n let label = \"grep\";\n\n if (input?.[\"-i\"]) {\n label += \" -i\";\n }\n if (input?.[\"-n\"]) {\n label += \" -n\";\n }\n\n if (input?.[\"-A\"] !== undefined) {\n label += ` -A ${input[\"-A\"]}`;\n }\n if (input?.[\"-B\"] !== undefined) {\n label += ` -B ${input[\"-B\"]}`;\n }\n if (input?.[\"-C\"] !== undefined) {\n label += ` -C ${input[\"-C\"]}`;\n }\n\n if (input?.output_mode) {\n switch (input.output_mode) {\n case \"files_with_matches\":\n label += \" -l\";\n break;\n case \"count\":\n label += \" -c\";\n break;\n default:\n break;\n }\n }\n\n if (input?.head_limit !== undefined) {\n label += ` | head -${input.head_limit}`;\n }\n\n if (input?.glob) {\n label += ` --include=\"${String(input.glob)}\"`;\n }\n\n if (input?.type) {\n label += ` --type=${String(input.type)}`;\n }\n\n if (input?.multiline) {\n label += \" -P\";\n }\n\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n\n if (input?.path) {\n label += ` ${String(input.path)}`;\n }\n\n return {\n title: label,\n kind: \"search\",\n content: [],\n };\n }\n\n case \"WebFetch\":\n return {\n title: \"Fetch\",\n kind: \"fetch\",\n content: input?.url\n ? [\n {\n type: \"content\",\n content: resourceLink(String(input.url), String(input.url), {\n description: input?.prompt ? String(input.prompt) : undefined,\n }),\n },\n ]\n : [],\n };\n\n case \"WebSearch\": {\n let label = `\"${input?.query ? String(input.query) : \"\"}\"`;\n const allowedDomains = input?.allowed_domains as string[] | undefined;\n const blockedDomains = input?.blocked_domains as string[] | undefined;\n\n if (allowedDomains && allowedDomains.length > 0) {\n label += ` (allowed: ${allowedDomains.join(\", \")})`;\n }\n\n if (blockedDomains && blockedDomains.length > 0) {\n label += ` (blocked: ${blockedDomains.join(\", \")})`;\n }\n\n return {\n title: label,\n kind: \"fetch\",\n content: [],\n };\n }\n\n case \"TodoWrite\":\n return {\n title: Array.isArray(input?.todos)\n ? `Update TODOs: ${input.todos.map((todo: { content?: string }) => todo.content).join(\", \")}`\n : \"Update TODOs\",\n kind: \"think\",\n content: [],\n };\n\n case \"ExitPlanMode\":\n return {\n title: \"Ready to code?\",\n kind: \"switch_mode\",\n content: input?.plan\n ? toolContent().text(String(input.plan)).build()\n : [],\n };\n\n case \"AskUserQuestion\": {\n const questions = input?.questions as\n | Array<{ question?: string }>\n | undefined;\n return {\n title: questions?.[0]?.question || \"Question\",\n kind: \"other\" as ToolKind,\n content: questions\n ? toolContent()\n .text(JSON.stringify(questions, null, 2))\n .build()\n : [],\n };\n }\n\n case \"Other\": {\n let output: string;\n try {\n output = JSON.stringify(input, null, 2);\n } catch {\n output = typeof input === \"string\" ? input : \"{}\";\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: toolContent().text(`\\`\\`\\`json\\n${output}\\`\\`\\``).build(),\n };\n }\n\n default: {\n if (name?.startsWith(\"mcp__\")) {\n return mcpToolInfo(name, input);\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: [],\n };\n }\n }\n}\n\nfunction mcpToolInfo(\n name: string,\n _input: Record<string, unknown> | undefined,\n): ToolInfo {\n const metadata = getMcpToolMetadata(name);\n // Fallback: parse tool name from mcp__<server>__<tool> prefix\n const title =\n metadata?.name ?? (name.split(\"__\").slice(2).join(\"__\") || name);\n\n return {\n title,\n kind: \"other\",\n content: [],\n };\n}\n\ninterface StructuredPatchHunk {\n oldStart: number;\n oldLines: number;\n newStart: number;\n newLines: number;\n lines: string[];\n}\n\ninterface StructuredPatch {\n oldFileName: string;\n newFileName: string;\n hunks: StructuredPatchHunk[];\n}\n\nexport function toolUpdateFromEditToolResponse(\n toolResponse: unknown,\n): { content: ToolCallContent[]; locations: ToolCallLocation[] } | null {\n if (!toolResponse || typeof toolResponse !== \"object\") return null;\n const response = toolResponse as Record<string, unknown>;\n\n const patches = response.structuredPatch as StructuredPatch[] | undefined;\n if (!Array.isArray(patches) || patches.length === 0) return null;\n\n const content: ToolCallContent[] = [];\n const locations: ToolCallLocation[] = [];\n\n for (const patch of patches) {\n if (!patch.hunks || patch.hunks.length === 0) continue;\n\n const filePath = patch.newFileName || patch.oldFileName;\n\n const oldLines: string[] = [];\n const newLines: string[] = [];\n for (const hunk of patch.hunks) {\n for (const line of hunk.lines) {\n if (line.startsWith(\"-\")) {\n oldLines.push(line.slice(1));\n } else if (line.startsWith(\"+\")) {\n newLines.push(line.slice(1));\n } else if (line.startsWith(\" \")) {\n oldLines.push(line.slice(1));\n newLines.push(line.slice(1));\n }\n }\n }\n\n content.push({\n type: \"diff\",\n path: filePath,\n oldText: oldLines.join(\"\\n\"),\n newText: newLines.join(\"\\n\"),\n });\n\n const firstHunk = patch.hunks[0];\n locations.push({\n path: filePath,\n line: firstHunk.newStart,\n });\n }\n\n if (content.length === 0) return null;\n return { content, locations };\n}\n\nexport function toolUpdateFromToolResult(\n toolResult:\n | ToolResultBlockParam\n | BetaWebSearchToolResultBlockParam\n | BetaWebFetchToolResultBlockParam\n | WebSearchToolResultBlockParam\n | BetaCodeExecutionToolResultBlockParam\n | BetaBashCodeExecutionToolResultBlockParam\n | BetaTextEditorCodeExecutionToolResultBlockParam\n | BetaRequestMCPToolResultBlockParam\n | BetaToolSearchToolResultBlockParam,\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\"> | undefined,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n },\n): Pick<ToolCallUpdate, \"title\" | \"content\" | \"locations\" | \"_meta\"> {\n if (\n \"is_error\" in toolResult &&\n toolResult.is_error &&\n toolResult.content &&\n (toolResult.content as unknown[]).length > 0\n ) {\n return toAcpContentUpdate(toolResult.content, true);\n }\n\n switch (toolUse?.name) {\n case \"Read\":\n if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {\n return {\n content: toolResult.content.map((item) => {\n const itemObj = item as {\n type?: string;\n text?: string;\n source?: { data?: string; media_type?: string };\n };\n if (itemObj.type === \"text\") {\n return {\n type: \"content\" as const,\n content: text(\n markdownEscape(\n (itemObj.text ?? \"\").replace(SYSTEM_REMINDER, \"\"),\n ),\n ),\n };\n }\n if (itemObj.type === \"image\" && itemObj.source) {\n return {\n type: \"content\" as const,\n content: {\n type: \"image\" as const,\n data: itemObj.source.data ?? \"\",\n mimeType: itemObj.source.media_type ?? \"image/png\",\n },\n };\n }\n return {\n type: \"content\" as const,\n content: item as { type: \"text\"; text: string },\n };\n }),\n };\n } else if (\n typeof toolResult.content === \"string\" &&\n toolResult.content.length > 0\n ) {\n return {\n content: toolContent()\n .text(\n markdownEscape(toolResult.content.replace(SYSTEM_REMINDER, \"\")),\n )\n .build(),\n };\n }\n return {};\n\n case \"Bash\": {\n const result = toolResult.content;\n const terminalId =\n \"tool_use_id\" in toolResult ? String(toolResult.tool_use_id) : \"\";\n const isError = \"is_error\" in toolResult && toolResult.is_error;\n\n let output = \"\";\n let exitCode = isError ? 1 : 0;\n\n if (\n result &&\n typeof result === \"object\" &&\n \"type\" in result &&\n (result as { type: string }).type === \"bash_code_execution_result\"\n ) {\n const bashResult = result as {\n stdout?: string;\n stderr?: string;\n return_code: number;\n };\n output = [bashResult.stdout, bashResult.stderr]\n .filter(Boolean)\n .join(\"\\n\");\n exitCode = bashResult.return_code;\n } else if (typeof result === \"string\") {\n output = result;\n } else if (\n Array.isArray(result) &&\n result.length > 0 &&\n \"text\" in result[0] &&\n typeof result[0].text === \"string\"\n ) {\n output = result.map((c: { text?: string }) => c.text ?? \"\").join(\"\\n\");\n }\n\n if (options?.supportsTerminalOutput) {\n return {\n content: [{ type: \"terminal\" as const, terminalId }],\n _meta: {\n terminal_info: {\n terminal_id: terminalId,\n },\n terminal_output: {\n terminal_id: terminalId,\n data: output,\n },\n terminal_exit: {\n terminal_id: terminalId,\n exit_code: exitCode,\n signal: null,\n },\n },\n };\n }\n if (output.trim()) {\n return {\n content: toolContent()\n .text(`\\`\\`\\`console\\n${output.trimEnd()}\\n\\`\\`\\``)\n .build(),\n };\n }\n return {};\n }\n case \"Edit\":\n case \"Write\":\n return {};\n\n case \"ExitPlanMode\": {\n return { title: \"Exited Plan Mode\" };\n }\n case \"AskUserQuestion\": {\n const content = toolResult.content;\n if (Array.isArray(content) && content.length > 0) {\n const firstItem = content[0];\n if (\n typeof firstItem === \"object\" &&\n firstItem !== null &&\n \"text\" in firstItem\n ) {\n return {\n title: \"Answer received\",\n content: toolContent().text(String(firstItem.text)).build(),\n };\n }\n }\n return { title: \"Question answered\" };\n }\n case \"WebFetch\": {\n const input = toolUse?.input as Record<string, unknown> | undefined;\n const url = input?.url ? String(input.url) : \"\";\n const prompt = input?.prompt ? String(input.prompt) : undefined;\n\n const resultContent = toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n\n const content: ToolCallContent[] = [];\n if (url) {\n content.push({\n type: \"content\",\n content: resourceLink(url, url, {\n description: prompt,\n }),\n });\n }\n if (resultContent.content) {\n content.push(...resultContent.content);\n }\n\n return { content };\n }\n default: {\n return toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n }\n }\n}\n\nfunction itemToText(item: unknown): string | null {\n if (!item || typeof item !== \"object\") return null;\n const obj = item as Record<string, unknown>;\n // Standard text block\n if (obj.type === \"text\" && typeof obj.text === \"string\") {\n return obj.text;\n }\n // Any other structured object — serialize it\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return null;\n }\n}\n\nfunction toAcpContentUpdate(\n content: unknown,\n isError: boolean = false,\n): Pick<ToolCallUpdate, \"content\"> {\n if (Array.isArray(content) && content.length > 0) {\n const texts: string[] = [];\n for (const item of content) {\n const t = itemToText(item);\n if (t) texts.push(t);\n }\n if (texts.length > 0) {\n const combined = texts.join(\"\\n\");\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${combined}\\n\\`\\`\\`` : combined)\n .build(),\n };\n }\n } else if (typeof content === \"string\" && content.length > 0) {\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${content}\\n\\`\\`\\`` : content)\n .build(),\n };\n } else if (content && typeof content === \"object\") {\n try {\n const json = JSON.stringify(content, null, 2);\n if (json && json !== \"{}\") {\n return {\n content: toolContent().text(json).build(),\n };\n }\n } catch {\n // ignore serialization errors\n }\n }\n return {};\n}\n\nexport type ClaudePlanEntry = {\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n activeForm: string;\n};\n\nexport function planEntries(input: { todos: ClaudePlanEntry[] }): PlanEntry[] {\n return input.todos.map((input) => ({\n content: input.content,\n status: input.status,\n priority: \"medium\",\n }));\n}\n\nfunction markdownEscape(text: string): string {\n let escapedText = \"```\";\n for (const [m] of text.matchAll(/^```+/gm)) {\n while (m.length >= escapedText.length) {\n escapedText += \"`\";\n }\n }\n return `${escapedText}\\n${text}${text.endsWith(\"\\n\") ? \"\" : \"\\n\"}${escapedText}`;\n}\n","import type { ContentBlock, ToolCallContent } from \"@agentclientprotocol/sdk\";\n\nexport function text(value: string): ContentBlock {\n return { type: \"text\", text: value };\n}\n\nexport function image(\n data: string,\n mimeType: string,\n uri?: string,\n): ContentBlock {\n return { type: \"image\", data, mimeType, uri };\n}\n\nexport function resourceLink(\n uri: string,\n name: string,\n options?: {\n mimeType?: string;\n title?: string;\n description?: string;\n size?: number | null;\n },\n): ContentBlock {\n return {\n type: \"resource_link\",\n uri,\n name,\n ...options,\n };\n}\n\nclass ToolContentBuilder {\n private items: ToolCallContent[] = [];\n\n text(value: string): this {\n this.items.push({ type: \"content\", content: text(value) });\n return this;\n }\n\n image(data: string, mimeType: string, uri?: string): this {\n this.items.push({ type: \"content\", content: image(data, mimeType, uri) });\n return this;\n }\n\n diff(path: string, oldText: string | null, newText: string): this {\n this.items.push({ type: \"diff\", path, oldText, newText });\n return this;\n }\n\n build(): ToolCallContent[] {\n return this.items;\n }\n}\n\nexport function toolContent(): ToolContentBuilder {\n return new ToolContentBuilder();\n}\n","import type { McpServerStatus, Query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Logger } from \"../../../utils/logger.js\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n name: string;\n description?: string;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nconst PENDING_RETRY_INTERVAL_MS = 1_000;\nconst PENDING_MAX_RETRIES = 10;\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function fetchMcpToolMetadata(\n q: Query,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n let retries = 0;\n\n while (retries <= PENDING_MAX_RETRIES) {\n let statuses: McpServerStatus[];\n try {\n statuses = await q.mcpServerStatus();\n } catch (error) {\n logger.error(\"Failed to fetch MCP server status\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n const pendingServers = statuses.filter((s) => s.status === \"pending\");\n\n for (const server of statuses) {\n if (server.status !== \"connected\" || !server.tools) {\n continue;\n }\n\n let readOnlyCount = 0;\n for (const tool of server.tools) {\n const toolKey = buildToolKey(server.name, tool.name);\n const readOnly = tool.annotations?.readOnly === true;\n mcpToolMetadataCache.set(toolKey, {\n readOnly,\n name: tool.name,\n description: tool.description,\n });\n if (readOnly) readOnlyCount++;\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName: server.name,\n toolCount: server.tools.length,\n readOnlyCount,\n });\n }\n\n if (pendingServers.length === 0) {\n return;\n }\n\n retries++;\n if (retries > PENDING_MAX_RETRIES) {\n logger.warn(\"Gave up waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n });\n return;\n }\n\n logger.info(\"Waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n retry: retries,\n });\n await delay(PENDING_RETRY_INTERVAL_MS);\n }\n}\n\nexport function getMcpToolMetadata(\n toolName: string,\n): McpToolMetadata | undefined {\n return mcpToolMetadataCache.get(toolName);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":"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","names":["path","input","text"]}
1
+ {"version":3,"sources":["../../../../src/adapters/claude/conversion/tool-use-to-acp.ts","../../../../src/utils/acp-content.ts","../../../../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import path from \"node:path\";\nimport type {\n PlanEntry,\n ToolCall,\n ToolCallContent,\n ToolCallLocation,\n ToolCallUpdate,\n ToolKind,\n} from \"@agentclientprotocol/sdk\";\nimport type {\n ToolResultBlockParam,\n ToolUseBlock,\n WebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources\";\nimport type {\n BetaBashCodeExecutionToolResultBlockParam,\n BetaCodeExecutionToolResultBlockParam,\n BetaRequestMCPToolResultBlockParam,\n BetaTextEditorCodeExecutionToolResultBlockParam,\n BetaToolSearchToolResultBlockParam,\n BetaWebFetchToolResultBlockParam,\n BetaWebSearchToolResultBlockParam,\n} from \"@anthropic-ai/sdk/resources/beta.mjs\";\n\nconst SYSTEM_REMINDER_REGEX =\n /\\s*<system-reminder>[\\s\\S]*?<\\/system-reminder>/g;\n\nfunction stripSystemReminders(value: string): string {\n return value.replace(SYSTEM_REMINDER_REGEX, \"\");\n}\n\nimport { resourceLink, text, toolContent } from \"../../../utils/acp-content.js\";\nimport { getMcpToolMetadata } from \"../mcp/tool-metadata.js\";\n\ntype ToolInfo = Pick<ToolCall, \"title\" | \"kind\" | \"content\" | \"locations\">;\n\n/**\n * Convert an absolute file path to a project-relative path for display.\n * Returns the original path if it's outside the project directory or if no cwd is provided.\n */\nexport function toDisplayPath(filePath: string, cwd?: string): string {\n if (!cwd) return filePath;\n const resolvedCwd = path.resolve(cwd);\n const resolvedFile = path.resolve(filePath);\n if (\n resolvedFile.startsWith(resolvedCwd + path.sep) ||\n resolvedFile === resolvedCwd\n ) {\n return path.relative(resolvedCwd, resolvedFile);\n }\n return filePath;\n}\n\nexport function toolInfoFromToolUse(\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\">,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n cwd?: string;\n },\n): ToolInfo {\n const name = toolUse.name;\n const input = toolUse.input as Record<string, unknown> | undefined;\n\n switch (name) {\n case \"Task\":\n case \"Agent\":\n return {\n title: input?.description ? String(input.description) : name,\n kind: \"think\",\n content: input?.prompt\n ? toolContent().text(String(input.prompt)).build()\n : [],\n };\n\n case \"NotebookRead\":\n return {\n title: input?.notebook_path\n ? `Read Notebook ${String(input.notebook_path)}`\n : \"Read Notebook\",\n kind: \"read\",\n content: [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"NotebookEdit\":\n return {\n title: input?.notebook_path\n ? `Edit Notebook ${String(input.notebook_path)}`\n : \"Edit Notebook\",\n kind: \"edit\",\n content: input?.new_source\n ? toolContent().text(String(input.new_source)).build()\n : [],\n locations: input?.notebook_path\n ? [{ path: String(input.notebook_path) }]\n : [],\n };\n\n case \"Bash\":\n if (options?.supportsTerminalOutput && options?.toolUseId) {\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: [{ type: \"terminal\", terminalId: options.toolUseId }],\n };\n }\n return {\n title: input?.description\n ? String(input.description)\n : \"Execute command\",\n kind: \"execute\",\n content: input?.command\n ? toolContent().text(String(input.command)).build()\n : [],\n };\n\n case \"BashOutput\":\n return {\n title: \"Tail Logs\",\n kind: \"execute\",\n content: [],\n };\n\n case \"KillShell\":\n return {\n title: \"Kill Process\",\n kind: \"execute\",\n content: [],\n };\n\n case \"Read\": {\n let limit = \"\";\n const inputLimit = input?.limit as number | undefined;\n const inputOffset = (input?.offset as number | undefined) ?? 1;\n if (inputLimit) {\n limit = ` (${inputOffset} - ${inputOffset + inputLimit - 1})`;\n } else if (inputOffset > 1) {\n limit = ` (from line ${inputOffset})`;\n }\n const displayPath = input?.file_path\n ? toDisplayPath(String(input.file_path), options?.cwd)\n : \"File\";\n return {\n title: `Read ${displayPath}${limit}`,\n kind: \"read\",\n locations: input?.file_path\n ? [\n {\n path: String(input.file_path),\n line: inputOffset,\n },\n ]\n : [],\n content: [],\n };\n }\n\n case \"LS\":\n return {\n title: `List the ${input?.path ? `\\`${String(input.path)}\\`` : \"current\"} directory's contents`,\n kind: \"search\",\n content: [],\n locations: [],\n };\n\n case \"Edit\": {\n const filePath = input?.file_path ? String(input.file_path) : undefined;\n const displayPath = filePath\n ? toDisplayPath(filePath, options?.cwd)\n : undefined;\n let oldText: string | null = input?.old_string\n ? String(input.old_string)\n : null;\n let newText: string = input?.new_string ? String(input.new_string) : \"\";\n\n // If we have cached file content, show a full-file diff\n if (\n filePath &&\n options?.cachedFileContent &&\n filePath in options.cachedFileContent\n ) {\n const oldContent = options.cachedFileContent[filePath];\n const newContent = input?.replace_all\n ? oldContent.replaceAll(oldText ?? \"\", newText)\n : oldContent.replace(oldText ?? \"\", newText);\n oldText = oldContent;\n newText = newContent;\n }\n\n return {\n title: displayPath ? `Edit \\`${displayPath}\\`` : \"Edit\",\n kind: \"edit\",\n content:\n input && filePath\n ? [\n {\n type: \"diff\",\n path: filePath,\n oldText,\n newText,\n },\n ]\n : [],\n locations: filePath ? [{ path: filePath }] : [],\n };\n }\n\n case \"Write\": {\n let contentResult: ToolCallContent[] = [];\n const writeFilePath = input?.file_path\n ? String(input.file_path)\n : undefined;\n const writeDisplayPath = writeFilePath\n ? toDisplayPath(writeFilePath, options?.cwd)\n : undefined;\n const contentStr = input?.content ? String(input.content) : undefined;\n if (writeFilePath) {\n const oldContent =\n options?.cachedFileContent &&\n writeFilePath in options.cachedFileContent\n ? options.cachedFileContent[writeFilePath]\n : null;\n contentResult = toolContent()\n .diff(writeFilePath, oldContent, contentStr ?? \"\")\n .build();\n } else if (contentStr) {\n contentResult = toolContent().text(contentStr).build();\n }\n return {\n title: writeDisplayPath ? `Write ${writeDisplayPath}` : \"Write\",\n kind: \"edit\",\n content: contentResult,\n locations: writeFilePath ? [{ path: writeFilePath }] : [],\n };\n }\n\n case \"Glob\": {\n let label = \"Find\";\n const pathStr = input?.path ? String(input.path) : undefined;\n if (pathStr) {\n label += ` \"${pathStr}\"`;\n }\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n return {\n title: label,\n kind: \"search\",\n content: [],\n locations: pathStr ? [{ path: pathStr }] : [],\n };\n }\n\n case \"Grep\": {\n let label = \"grep\";\n\n if (input?.[\"-i\"]) {\n label += \" -i\";\n }\n if (input?.[\"-n\"]) {\n label += \" -n\";\n }\n\n if (input?.[\"-A\"] !== undefined) {\n label += ` -A ${input[\"-A\"]}`;\n }\n if (input?.[\"-B\"] !== undefined) {\n label += ` -B ${input[\"-B\"]}`;\n }\n if (input?.[\"-C\"] !== undefined) {\n label += ` -C ${input[\"-C\"]}`;\n }\n\n if (input?.output_mode) {\n switch (input.output_mode) {\n case \"files_with_matches\":\n label += \" -l\";\n break;\n case \"count\":\n label += \" -c\";\n break;\n default:\n break;\n }\n }\n\n if (input?.head_limit !== undefined) {\n label += ` | head -${input.head_limit}`;\n }\n\n if (input?.glob) {\n label += ` --include=\"${String(input.glob)}\"`;\n }\n\n if (input?.type) {\n label += ` --type=${String(input.type)}`;\n }\n\n if (input?.multiline) {\n label += \" -P\";\n }\n\n if (input?.pattern) {\n label += ` \"${String(input.pattern)}\"`;\n }\n\n if (input?.path) {\n label += ` ${String(input.path)}`;\n }\n\n return {\n title: label,\n kind: \"search\",\n content: [],\n };\n }\n\n case \"WebFetch\":\n return {\n title: \"Fetch\",\n kind: \"fetch\",\n content: input?.url\n ? [\n {\n type: \"content\",\n content: resourceLink(String(input.url), String(input.url), {\n description: input?.prompt ? String(input.prompt) : undefined,\n }),\n },\n ]\n : [],\n };\n\n case \"WebSearch\": {\n let label = `\"${input?.query ? String(input.query) : \"\"}\"`;\n const allowedDomains = input?.allowed_domains as string[] | undefined;\n const blockedDomains = input?.blocked_domains as string[] | undefined;\n\n if (allowedDomains && allowedDomains.length > 0) {\n label += ` (allowed: ${allowedDomains.join(\", \")})`;\n }\n\n if (blockedDomains && blockedDomains.length > 0) {\n label += ` (blocked: ${blockedDomains.join(\", \")})`;\n }\n\n return {\n title: label,\n kind: \"fetch\",\n content: [],\n };\n }\n\n case \"TodoWrite\":\n return {\n title: Array.isArray(input?.todos)\n ? `Update TODOs: ${input.todos.map((todo: { content?: string }) => todo.content).join(\", \")}`\n : \"Update TODOs\",\n kind: \"think\",\n content: [],\n };\n\n case \"ExitPlanMode\":\n return {\n title: \"Ready to code?\",\n kind: \"switch_mode\",\n content: input?.plan\n ? toolContent().text(String(input.plan)).build()\n : [],\n };\n\n case \"AskUserQuestion\": {\n const questions = input?.questions as\n | Array<{ question?: string }>\n | undefined;\n return {\n title: questions?.[0]?.question || \"Question\",\n kind: \"other\" as ToolKind,\n content: questions\n ? toolContent()\n .text(JSON.stringify(questions, null, 2))\n .build()\n : [],\n };\n }\n\n case \"Other\": {\n let output: string;\n try {\n output = JSON.stringify(input, null, 2);\n } catch {\n output = typeof input === \"string\" ? input : \"{}\";\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: toolContent().text(`\\`\\`\\`json\\n${output}\\`\\`\\``).build(),\n };\n }\n\n default: {\n if (name?.startsWith(\"mcp__\")) {\n return mcpToolInfo(name, input);\n }\n return {\n title: name || \"Unknown Tool\",\n kind: \"other\",\n content: [],\n };\n }\n }\n}\n\nfunction mcpToolInfo(\n name: string,\n _input: Record<string, unknown> | undefined,\n): ToolInfo {\n const metadata = getMcpToolMetadata(name);\n // Fallback: parse tool name from mcp__<server>__<tool> prefix\n const title =\n metadata?.name ?? (name.split(\"__\").slice(2).join(\"__\") || name);\n\n return {\n title,\n kind: \"other\",\n content: [],\n };\n}\n\ninterface StructuredPatchHunk {\n oldStart: number;\n oldLines: number;\n newStart: number;\n newLines: number;\n lines: string[];\n}\n\ninterface StructuredPatch {\n oldFileName: string;\n newFileName: string;\n hunks: StructuredPatchHunk[];\n}\n\nexport function toolUpdateFromEditToolResponse(\n toolResponse: unknown,\n): { content: ToolCallContent[]; locations: ToolCallLocation[] } | null {\n if (!toolResponse || typeof toolResponse !== \"object\") return null;\n const response = toolResponse as Record<string, unknown>;\n\n const patches = response.structuredPatch as StructuredPatch[] | undefined;\n if (!Array.isArray(patches) || patches.length === 0) return null;\n\n const content: ToolCallContent[] = [];\n const locations: ToolCallLocation[] = [];\n\n for (const patch of patches) {\n if (!patch.hunks || patch.hunks.length === 0) continue;\n\n const filePath = patch.newFileName || patch.oldFileName;\n\n const oldLines: string[] = [];\n const newLines: string[] = [];\n for (const hunk of patch.hunks) {\n for (const line of hunk.lines) {\n if (line.startsWith(\"-\")) {\n oldLines.push(line.slice(1));\n } else if (line.startsWith(\"+\")) {\n newLines.push(line.slice(1));\n } else if (line.startsWith(\" \")) {\n oldLines.push(line.slice(1));\n newLines.push(line.slice(1));\n }\n }\n }\n\n content.push({\n type: \"diff\",\n path: filePath,\n oldText: oldLines.join(\"\\n\"),\n newText: newLines.join(\"\\n\"),\n });\n\n const firstHunk = patch.hunks[0];\n locations.push({\n path: filePath,\n line: firstHunk.newStart,\n });\n }\n\n if (content.length === 0) return null;\n return { content, locations };\n}\n\nexport function toolUpdateFromToolResult(\n toolResult:\n | ToolResultBlockParam\n | BetaWebSearchToolResultBlockParam\n | BetaWebFetchToolResultBlockParam\n | WebSearchToolResultBlockParam\n | BetaCodeExecutionToolResultBlockParam\n | BetaBashCodeExecutionToolResultBlockParam\n | BetaTextEditorCodeExecutionToolResultBlockParam\n | BetaRequestMCPToolResultBlockParam\n | BetaToolSearchToolResultBlockParam,\n toolUse: Pick<ToolUseBlock, \"name\" | \"input\"> | undefined,\n options?: {\n supportsTerminalOutput?: boolean;\n toolUseId?: string;\n cachedFileContent?: Record<string, string>;\n },\n): Pick<ToolCallUpdate, \"title\" | \"content\" | \"locations\" | \"_meta\"> {\n if (\n \"is_error\" in toolResult &&\n toolResult.is_error &&\n toolResult.content &&\n (toolResult.content as unknown[]).length > 0\n ) {\n return toAcpContentUpdate(toolResult.content, true);\n }\n\n switch (toolUse?.name) {\n case \"Read\":\n if (Array.isArray(toolResult.content) && toolResult.content.length > 0) {\n return {\n content: toolResult.content.map((item) => {\n const itemObj = item as {\n type?: string;\n text?: string;\n source?: { data?: string; media_type?: string };\n };\n if (itemObj.type === \"text\") {\n return {\n type: \"content\" as const,\n content: text(\n markdownEscape(stripSystemReminders(itemObj.text ?? \"\")),\n ),\n };\n }\n if (itemObj.type === \"image\" && itemObj.source) {\n return {\n type: \"content\" as const,\n content: {\n type: \"image\" as const,\n data: itemObj.source.data ?? \"\",\n mimeType: itemObj.source.media_type ?? \"image/png\",\n },\n };\n }\n return {\n type: \"content\" as const,\n content: item as { type: \"text\"; text: string },\n };\n }),\n };\n } else if (\n typeof toolResult.content === \"string\" &&\n toolResult.content.length > 0\n ) {\n return {\n content: toolContent()\n .text(markdownEscape(stripSystemReminders(toolResult.content)))\n .build(),\n };\n }\n return {};\n\n case \"Bash\": {\n const result = toolResult.content;\n const terminalId =\n \"tool_use_id\" in toolResult ? String(toolResult.tool_use_id) : \"\";\n const isError = \"is_error\" in toolResult && toolResult.is_error;\n\n let output = \"\";\n let exitCode = isError ? 1 : 0;\n\n if (\n result &&\n typeof result === \"object\" &&\n \"type\" in result &&\n (result as { type: string }).type === \"bash_code_execution_result\"\n ) {\n const bashResult = result as {\n stdout?: string;\n stderr?: string;\n return_code: number;\n };\n output = [bashResult.stdout, bashResult.stderr]\n .filter(Boolean)\n .join(\"\\n\");\n exitCode = bashResult.return_code;\n } else if (typeof result === \"string\") {\n output = result;\n } else if (\n Array.isArray(result) &&\n result.length > 0 &&\n \"text\" in result[0] &&\n typeof result[0].text === \"string\"\n ) {\n output = result.map((c: { text?: string }) => c.text ?? \"\").join(\"\\n\");\n }\n\n if (options?.supportsTerminalOutput) {\n return {\n content: [{ type: \"terminal\" as const, terminalId }],\n _meta: {\n terminal_info: {\n terminal_id: terminalId,\n },\n terminal_output: {\n terminal_id: terminalId,\n data: output,\n },\n terminal_exit: {\n terminal_id: terminalId,\n exit_code: exitCode,\n signal: null,\n },\n },\n };\n }\n if (output.trim()) {\n return {\n content: toolContent()\n .text(`\\`\\`\\`console\\n${output.trimEnd()}\\n\\`\\`\\``)\n .build(),\n };\n }\n return {};\n }\n case \"Edit\":\n case \"Write\":\n return {};\n\n case \"ExitPlanMode\": {\n return { title: \"Exited Plan Mode\" };\n }\n case \"AskUserQuestion\": {\n const content = toolResult.content;\n if (Array.isArray(content) && content.length > 0) {\n const firstItem = content[0];\n if (\n typeof firstItem === \"object\" &&\n firstItem !== null &&\n \"text\" in firstItem\n ) {\n return {\n title: \"Answer received\",\n content: toolContent().text(String(firstItem.text)).build(),\n };\n }\n }\n return { title: \"Question answered\" };\n }\n case \"WebFetch\": {\n const input = toolUse?.input as Record<string, unknown> | undefined;\n const url = input?.url ? String(input.url) : \"\";\n const prompt = input?.prompt ? String(input.prompt) : undefined;\n\n const resultContent = toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n\n const content: ToolCallContent[] = [];\n if (url) {\n content.push({\n type: \"content\",\n content: resourceLink(url, url, {\n description: prompt,\n }),\n });\n }\n if (resultContent.content) {\n content.push(...resultContent.content);\n }\n\n return { content };\n }\n default: {\n return toAcpContentUpdate(\n toolResult.content,\n \"is_error\" in toolResult ? toolResult.is_error : false,\n );\n }\n }\n}\n\nfunction itemToText(item: unknown): string | null {\n if (!item || typeof item !== \"object\") return null;\n const obj = item as Record<string, unknown>;\n // Standard text block\n if (obj.type === \"text\" && typeof obj.text === \"string\") {\n return stripSystemReminders(obj.text);\n }\n // Any other structured object — serialize it\n try {\n return JSON.stringify(obj, null, 2);\n } catch {\n return null;\n }\n}\n\nfunction toAcpContentUpdate(\n content: unknown,\n isError: boolean = false,\n): Pick<ToolCallUpdate, \"content\"> {\n if (Array.isArray(content) && content.length > 0) {\n const texts: string[] = [];\n for (const item of content) {\n const t = itemToText(item);\n if (t) texts.push(t);\n }\n if (texts.length > 0) {\n const combined = texts.join(\"\\n\");\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${combined}\\n\\`\\`\\`` : combined)\n .build(),\n };\n }\n } else if (typeof content === \"string\" && content.length > 0) {\n return {\n content: toolContent()\n .text(isError ? `\\`\\`\\`\\n${content}\\n\\`\\`\\`` : content)\n .build(),\n };\n } else if (content && typeof content === \"object\") {\n try {\n const json = JSON.stringify(content, null, 2);\n if (json && json !== \"{}\") {\n return {\n content: toolContent().text(json).build(),\n };\n }\n } catch {\n // ignore serialization errors\n }\n }\n return {};\n}\n\nexport type ClaudePlanEntry = {\n content: string;\n status: \"pending\" | \"in_progress\" | \"completed\";\n activeForm: string;\n};\n\nexport function planEntries(input: { todos: ClaudePlanEntry[] }): PlanEntry[] {\n return input.todos.map((input) => ({\n content: input.content,\n status: input.status,\n priority: \"medium\",\n }));\n}\n\nfunction markdownEscape(text: string): string {\n let escapedText = \"```\";\n for (const [m] of text.matchAll(/^```+/gm)) {\n while (m.length >= escapedText.length) {\n escapedText += \"`\";\n }\n }\n return `${escapedText}\\n${text}${text.endsWith(\"\\n\") ? \"\" : \"\\n\"}${escapedText}`;\n}\n","import type { ContentBlock, ToolCallContent } from \"@agentclientprotocol/sdk\";\n\nexport function text(value: string): ContentBlock {\n return { type: \"text\", text: value };\n}\n\nexport function image(\n data: string,\n mimeType: string,\n uri?: string,\n): ContentBlock {\n return { type: \"image\", data, mimeType, uri };\n}\n\nexport function resourceLink(\n uri: string,\n name: string,\n options?: {\n mimeType?: string;\n title?: string;\n description?: string;\n size?: number | null;\n },\n): ContentBlock {\n return {\n type: \"resource_link\",\n uri,\n name,\n ...options,\n };\n}\n\nclass ToolContentBuilder {\n private items: ToolCallContent[] = [];\n\n text(value: string): this {\n this.items.push({ type: \"content\", content: text(value) });\n return this;\n }\n\n image(data: string, mimeType: string, uri?: string): this {\n this.items.push({ type: \"content\", content: image(data, mimeType, uri) });\n return this;\n }\n\n diff(path: string, oldText: string | null, newText: string): this {\n this.items.push({ type: \"diff\", path, oldText, newText });\n return this;\n }\n\n build(): ToolCallContent[] {\n return this.items;\n }\n}\n\nexport function toolContent(): ToolContentBuilder {\n return new ToolContentBuilder();\n}\n","import type { McpServerStatus, Query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Logger } from \"../../../utils/logger.js\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n name: string;\n description?: string;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nconst PENDING_RETRY_INTERVAL_MS = 1_000;\nconst PENDING_MAX_RETRIES = 10;\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function fetchMcpToolMetadata(\n q: Query,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n let retries = 0;\n\n while (retries <= PENDING_MAX_RETRIES) {\n let statuses: McpServerStatus[];\n try {\n statuses = await q.mcpServerStatus();\n } catch (error) {\n logger.error(\"Failed to fetch MCP server status\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n const pendingServers = statuses.filter((s) => s.status === \"pending\");\n\n for (const server of statuses) {\n if (server.status !== \"connected\" || !server.tools) {\n continue;\n }\n\n let readOnlyCount = 0;\n for (const tool of server.tools) {\n const toolKey = buildToolKey(server.name, tool.name);\n const readOnly = tool.annotations?.readOnly === true;\n mcpToolMetadataCache.set(toolKey, {\n readOnly,\n name: tool.name,\n description: tool.description,\n });\n if (readOnly) readOnlyCount++;\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName: server.name,\n toolCount: server.tools.length,\n readOnlyCount,\n });\n }\n\n if (pendingServers.length === 0) {\n return;\n }\n\n retries++;\n if (retries > PENDING_MAX_RETRIES) {\n logger.warn(\"Gave up waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n });\n return;\n }\n\n logger.info(\"Waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n retry: retries,\n });\n await delay(PENDING_RETRY_INTERVAL_MS);\n }\n}\n\nexport function getMcpToolMetadata(\n toolName: string,\n): McpToolMetadata | undefined {\n return mcpToolMetadataCache.get(toolName);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":"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","names":["path","input","text"]}
package/dist/agent.js CHANGED
@@ -279,7 +279,7 @@ import { v7 as uuidv7 } from "uuid";
279
279
  // package.json
280
280
  var package_default = {
281
281
  name: "@posthog/agent",
282
- version: "2.3.1",
282
+ version: "2.3.5",
283
283
  repository: "https://github.com/PostHog/code",
284
284
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
285
285
  exports: {
@@ -867,11 +867,10 @@ function isMcpToolReadOnly(toolName) {
867
867
  }
868
868
 
869
869
  // src/adapters/claude/conversion/tool-use-to-acp.ts
870
- var SYSTEM_REMINDER = `
871
-
872
- <system-reminder>
873
- Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.
874
- </system-reminder>`;
870
+ var SYSTEM_REMINDER_REGEX = /\s*<system-reminder>[\s\S]*?<\/system-reminder>/g;
871
+ function stripSystemReminders(value) {
872
+ return value.replace(SYSTEM_REMINDER_REGEX, "");
873
+ }
875
874
  function toDisplayPath(filePath, cwd) {
876
875
  if (!cwd) return filePath;
877
876
  const resolvedCwd = path.resolve(cwd);
@@ -1209,9 +1208,7 @@ function toolUpdateFromToolResult(toolResult, toolUse, options) {
1209
1208
  return {
1210
1209
  type: "content",
1211
1210
  content: text(
1212
- markdownEscape(
1213
- (itemObj.text ?? "").replace(SYSTEM_REMINDER, "")
1214
- )
1211
+ markdownEscape(stripSystemReminders(itemObj.text ?? ""))
1215
1212
  )
1216
1213
  };
1217
1214
  }
@@ -1233,9 +1230,7 @@ function toolUpdateFromToolResult(toolResult, toolUse, options) {
1233
1230
  };
1234
1231
  } else if (typeof toolResult.content === "string" && toolResult.content.length > 0) {
1235
1232
  return {
1236
- content: toolContent().text(
1237
- markdownEscape(toolResult.content.replace(SYSTEM_REMINDER, ""))
1238
- ).build()
1233
+ content: toolContent().text(markdownEscape(stripSystemReminders(toolResult.content))).build()
1239
1234
  };
1240
1235
  }
1241
1236
  return {};
@@ -1335,7 +1330,7 @@ function itemToText(item) {
1335
1330
  if (!item || typeof item !== "object") return null;
1336
1331
  const obj = item;
1337
1332
  if (obj.type === "text" && typeof obj.text === "string") {
1338
- return obj.text;
1333
+ return stripSystemReminders(obj.text);
1339
1334
  }
1340
1335
  try {
1341
1336
  return JSON.stringify(obj, null, 2);