@ai-sdk/harness-acp 1.0.9 → 1.0.10

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ai-sdk/harness-acp
2
2
 
3
+ ## 1.0.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 8d05a55: fix(harness-acp): fix incorrect `finish-step` emission timing
8
+
3
9
  ## 1.0.9
4
10
 
5
11
  ### Patch Changes
@@ -12,7 +12,7 @@ import {
12
12
  ListToolsRequestSchema,
13
13
  McpError
14
14
  } from "@modelcontextprotocol/sdk/types.js";
15
- var VERSION = true ? "1.0.9" : "0.0.0-test";
15
+ var VERSION = true ? "1.0.10" : "0.0.0-test";
16
16
  function createHostToolMCPServer({
17
17
  tools: tools2,
18
18
  revision = 1,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/v1/bridge/host-tool-mcp.ts","../../src/v1/bridge/host-tool-mcp-server.ts","../../src/v1/bridge/host-tool-relay-client.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { env } from 'node:process';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { HarnessV1BridgeToolWire } from '@ai-sdk/harness';\nimport {\n createHostToolMCPServer,\n type HostToolMCPInvocationResult,\n} from './host-tool-mcp-server';\nimport { postHostToolRelay } from './host-tool-relay-client';\n\nconst catalogPath = requireEnvironmentVariable({\n name: 'AI_SDK_ACP_HOST_TOOLS_FILE',\n});\nconst relayUrl = requireEnvironmentVariable({\n name: 'AI_SDK_ACP_HOST_TOOL_RELAY_URL',\n});\nconst relayCredential = requireEnvironmentVariable({\n name: 'AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL',\n});\nconst tools = await readToolCatalog({ path: catalogPath });\nconst hostToolServer = createHostToolMCPServer({\n tools,\n invoke: async ({ toolName, input, catalogRevision }) =>\n validateInvocationResult({\n value: await postRelay({\n path: '/invoke',\n body: {\n requestId: randomUUID(),\n toolName,\n input,\n catalogRevision,\n },\n }),\n }),\n onListTools: async ({ revision }) => {\n await postRelay({\n path: '/catalog/seen',\n body: { revision },\n });\n },\n});\n\nawait hostToolServer.server.connect(new StdioServerTransport());\nvoid watchCatalog({\n initialRevision: 1,\n updateCatalog: hostToolServer.updateCatalog,\n}).catch(error => {\n process.stderr.write(\n `Host tool catalog synchronization failed: ${\n error instanceof Error ? error.message : String(error)\n }\\n`,\n );\n void hostToolServer.server.close();\n process.exitCode = 1;\n});\n\nasync function watchCatalog({\n initialRevision,\n updateCatalog,\n}: {\n initialRevision: number;\n updateCatalog: (options: {\n revision: number;\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n }) => Promise<void>;\n}): Promise<void> {\n let revision = initialRevision;\n for (;;) {\n const value = await postRelay({\n path: '/catalog/next',\n body: { afterRevision: revision },\n });\n if (isRecord(value) && value.closed === true) return;\n if (\n !isRecord(value) ||\n !Number.isSafeInteger(value.revision) ||\n (value.revision as number) < revision\n ) {\n throw new Error('Invalid host tool catalog poll response.');\n }\n const nextRevision = value.revision as number;\n if (nextRevision === revision) continue;\n const nextTools = validateToolCatalog({ value: value.tools });\n await updateCatalog({ revision: nextRevision, tools: nextTools });\n revision = nextRevision;\n }\n}\n\nasync function postRelay({\n path,\n body,\n}: {\n path: string;\n body: Readonly<Record<string, unknown>>;\n}): Promise<unknown> {\n const response = await postHostToolRelay({\n relayUrl,\n relayCredential,\n path,\n body,\n });\n const { value } = response;\n if (!response.ok) {\n throw new Error(readErrorMessage({ value, status: response.status }));\n }\n return value;\n}\n\nfunction validateToolCatalog({\n value,\n}: {\n value: unknown;\n}): ReadonlyArray<HarnessV1BridgeToolWire> {\n if (!Array.isArray(value) || !value.every(isTool)) {\n throw new Error('Invalid host tool catalog.');\n }\n return value;\n}\n\nasync function readToolCatalog({\n path,\n}: {\n path: string;\n}): Promise<ReadonlyArray<HarnessV1BridgeToolWire>> {\n const text = await readFile(path, 'utf8');\n const value = await new Response(text, {\n headers: { 'content-type': 'application/json' },\n }).json();\n return validateToolCatalog({ value });\n}\n\nfunction isTool(value: unknown): value is HarnessV1BridgeToolWire {\n return (\n isRecord(value) &&\n typeof value.name === 'string' &&\n (value.description === undefined ||\n typeof value.description === 'string') &&\n (value.inputSchema === undefined ||\n (isRecord(value.inputSchema) && !Array.isArray(value.inputSchema)))\n );\n}\n\nfunction validateInvocationResult({\n value,\n}: {\n value: unknown;\n}): HostToolMCPInvocationResult {\n if (\n !isRecord(value) ||\n typeof value.correlationToken !== 'string' ||\n (value.isError !== undefined && typeof value.isError !== 'boolean')\n ) {\n throw new Error('Invalid host tool relay response.');\n }\n return {\n output: value.output,\n ...(value.isError ? { isError: true } : {}),\n correlationToken: value.correlationToken,\n };\n}\n\nfunction readErrorMessage({\n value,\n status,\n}: {\n value: unknown;\n status: number;\n}): string {\n return isRecord(value) && typeof value.error === 'string'\n ? value.error\n : `Host tool relay returned HTTP ${status}.`;\n}\n\nfunction requireEnvironmentVariable({ name }: { name: string }): string {\n const value = env[name];\n if (value == null || value.length === 0) {\n throw new Error(`Missing ${name}.`);\n }\n return value;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n","import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n type CallToolResult,\n type Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport type { HarnessV1BridgeToolWire } from '@ai-sdk/harness';\n\ndeclare const __PACKAGE_VERSION__: string | undefined;\n\nconst VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n\nexport type HostToolMCPInvocationResult = {\n readonly output: unknown;\n readonly isError?: boolean;\n readonly correlationToken: string;\n};\n\nexport type HostToolMCPServer = {\n readonly server: Server;\n updateCatalog(options: {\n revision: number;\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n }): Promise<void>;\n};\n\nexport function createHostToolMCPServer({\n tools,\n revision = 1,\n invoke,\n onListTools,\n}: {\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n revision?: number;\n invoke: (options: {\n toolName: string;\n input: Readonly<Record<string, unknown>>;\n catalogRevision: number;\n }) => Promise<HostToolMCPInvocationResult>;\n onListTools?: (options: { revision: number }) => Promise<void>;\n}): HostToolMCPServer {\n let catalog = createCatalog({ revision, tools });\n let catalogAcknowledgmentError: unknown;\n const server = new Server(\n {\n name: '@ai-sdk/harness-acp-host-tools',\n version: VERSION,\n },\n { capabilities: { tools: { listChanged: true } } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n if (catalogAcknowledgmentError != null) {\n throw catalogAcknowledgmentError;\n }\n const current = catalog;\n if (onListTools != null) {\n setImmediate(() => {\n void onListTools({ revision: current.revision }).catch(error => {\n catalogAcknowledgmentError = error;\n });\n });\n }\n return { tools: current.tools.map(toMCPTool) };\n });\n server.setRequestHandler(CallToolRequestSchema, async request => {\n const current = catalog;\n const tool = current.byName.get(request.params.name);\n if (tool == null) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `Unknown host tool: ${request.params.name}`,\n );\n }\n const input = request.params.arguments ?? {};\n const result = await invoke({\n toolName: tool.name,\n input,\n catalogRevision: current.revision,\n });\n return toCallToolResult({ result });\n });\n\n return {\n server,\n updateCatalog: async ({ revision: nextRevision, tools: nextTools }) => {\n catalog = createCatalog({\n revision: nextRevision,\n tools: nextTools,\n });\n await server.sendToolListChanged();\n },\n };\n}\n\nfunction createCatalog({\n revision,\n tools,\n}: {\n revision: number;\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n}): {\n readonly revision: number;\n readonly tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n readonly byName: ReadonlyMap<string, HarnessV1BridgeToolWire>;\n} {\n return {\n revision,\n tools: [...tools],\n byName: new Map(tools.map(tool => [tool.name, tool])),\n };\n}\n\nfunction toMCPTool(tool: HarnessV1BridgeToolWire): Tool {\n return {\n name: tool.name,\n ...(tool.description == null ? {} : { description: tool.description }),\n inputSchema: requireObjectSchema({\n toolName: tool.name,\n schema: tool.inputSchema ?? { type: 'object' },\n }),\n };\n}\n\nfunction requireObjectSchema({\n toolName,\n schema,\n}: {\n toolName: string;\n schema: unknown;\n}): Tool['inputSchema'] {\n if (\n schema == null ||\n typeof schema !== 'object' ||\n Array.isArray(schema) ||\n (Reflect.get(schema, 'type') !== undefined &&\n Reflect.get(schema, 'type') !== 'object')\n ) {\n throw new Error(\n `Host tool ${toolName} must use an object JSON Schema for MCP.`,\n );\n }\n return schema as Tool['inputSchema'];\n}\n\nfunction toCallToolResult({\n result,\n}: {\n result: HostToolMCPInvocationResult;\n}): CallToolResult {\n return {\n content: [\n {\n type: 'text',\n text: stringifyOutput({ output: result.output }),\n },\n ],\n ...(result.isError ? { isError: true } : {}),\n _meta: {\n 'ai-sdk-harness-acp-correlation': result.correlationToken,\n },\n };\n}\n\nfunction stringifyOutput({ output }: { output: unknown }): string {\n if (output === undefined) return 'null';\n try {\n return JSON.stringify(output);\n } catch {\n return JSON.stringify({\n error: 'Host tool output could not be serialized as JSON.',\n });\n }\n}\n","import { Agent, request } from 'node:http';\n\n/*\n * A host-tool call can remain pending while a person reviews an approval.\n * The loopback connection therefore must not impose an inactivity deadline.\n */\nconst relayAgent = new Agent({ keepAlive: true, timeout: 0 });\n\nexport async function postHostToolRelay({\n relayUrl,\n relayCredential,\n path,\n body,\n}: {\n relayUrl: string;\n relayCredential: string;\n path: string;\n body: Readonly<Record<string, unknown>>;\n}): Promise<{ status: number; ok: boolean; value: unknown }> {\n const serializedBody = JSON.stringify(body);\n\n return new Promise((resolve, reject) => {\n const relayRequest = request(\n new URL(path, relayUrl),\n {\n agent: relayAgent,\n method: 'POST',\n headers: {\n authorization: `Bearer ${relayCredential}`,\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(serializedBody),\n },\n },\n response => {\n const chunks: Buffer[] = [];\n response.on('data', (chunk: Buffer) => chunks.push(chunk));\n response.on('error', reject);\n response.on('end', () => {\n void new Response(Buffer.concat(chunks)).json().then(value => {\n const status = response.statusCode ?? 0;\n resolve({\n status,\n ok: status >= 200 && status < 300,\n value,\n });\n }, reject);\n });\n },\n );\n relayRequest.on('error', reject);\n relayRequest.end(serializedBody);\n });\n}\n"],"mappings":"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","names":["tools","request","relayUrl","relayCredential"]}
1
+ {"version":3,"sources":["../../src/v1/bridge/host-tool-mcp.ts","../../src/v1/bridge/host-tool-mcp-server.ts","../../src/v1/bridge/host-tool-relay-client.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { env } from 'node:process';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { HarnessV1BridgeToolWire } from '@ai-sdk/harness';\nimport {\n createHostToolMCPServer,\n type HostToolMCPInvocationResult,\n} from './host-tool-mcp-server';\nimport { postHostToolRelay } from './host-tool-relay-client';\n\nconst catalogPath = requireEnvironmentVariable({\n name: 'AI_SDK_ACP_HOST_TOOLS_FILE',\n});\nconst relayUrl = requireEnvironmentVariable({\n name: 'AI_SDK_ACP_HOST_TOOL_RELAY_URL',\n});\nconst relayCredential = requireEnvironmentVariable({\n name: 'AI_SDK_ACP_HOST_TOOL_RELAY_CREDENTIAL',\n});\nconst tools = await readToolCatalog({ path: catalogPath });\nconst hostToolServer = createHostToolMCPServer({\n tools,\n invoke: async ({ toolName, input, catalogRevision }) =>\n validateInvocationResult({\n value: await postRelay({\n path: '/invoke',\n body: {\n requestId: randomUUID(),\n toolName,\n input,\n catalogRevision,\n },\n }),\n }),\n onListTools: async ({ revision }) => {\n await postRelay({\n path: '/catalog/seen',\n body: { revision },\n });\n },\n});\n\nawait hostToolServer.server.connect(new StdioServerTransport());\nvoid watchCatalog({\n initialRevision: 1,\n updateCatalog: hostToolServer.updateCatalog,\n}).catch(error => {\n process.stderr.write(\n `Host tool catalog synchronization failed: ${\n error instanceof Error ? error.message : String(error)\n }\\n`,\n );\n void hostToolServer.server.close();\n process.exitCode = 1;\n});\n\nasync function watchCatalog({\n initialRevision,\n updateCatalog,\n}: {\n initialRevision: number;\n updateCatalog: (options: {\n revision: number;\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n }) => Promise<void>;\n}): Promise<void> {\n let revision = initialRevision;\n for (;;) {\n const value = await postRelay({\n path: '/catalog/next',\n body: { afterRevision: revision },\n });\n if (isRecord(value) && value.closed === true) return;\n if (\n !isRecord(value) ||\n !Number.isSafeInteger(value.revision) ||\n (value.revision as number) < revision\n ) {\n throw new Error('Invalid host tool catalog poll response.');\n }\n const nextRevision = value.revision as number;\n if (nextRevision === revision) continue;\n const nextTools = validateToolCatalog({ value: value.tools });\n await updateCatalog({ revision: nextRevision, tools: nextTools });\n revision = nextRevision;\n }\n}\n\nasync function postRelay({\n path,\n body,\n}: {\n path: string;\n body: Readonly<Record<string, unknown>>;\n}): Promise<unknown> {\n const response = await postHostToolRelay({\n relayUrl,\n relayCredential,\n path,\n body,\n });\n const { value } = response;\n if (!response.ok) {\n throw new Error(readErrorMessage({ value, status: response.status }));\n }\n return value;\n}\n\nfunction validateToolCatalog({\n value,\n}: {\n value: unknown;\n}): ReadonlyArray<HarnessV1BridgeToolWire> {\n if (!Array.isArray(value) || !value.every(isTool)) {\n throw new Error('Invalid host tool catalog.');\n }\n return value;\n}\n\nasync function readToolCatalog({\n path,\n}: {\n path: string;\n}): Promise<ReadonlyArray<HarnessV1BridgeToolWire>> {\n const text = await readFile(path, 'utf8');\n const value = await new Response(text, {\n headers: { 'content-type': 'application/json' },\n }).json();\n return validateToolCatalog({ value });\n}\n\nfunction isTool(value: unknown): value is HarnessV1BridgeToolWire {\n return (\n isRecord(value) &&\n typeof value.name === 'string' &&\n (value.description === undefined ||\n typeof value.description === 'string') &&\n (value.inputSchema === undefined ||\n (isRecord(value.inputSchema) && !Array.isArray(value.inputSchema)))\n );\n}\n\nfunction validateInvocationResult({\n value,\n}: {\n value: unknown;\n}): HostToolMCPInvocationResult {\n if (\n !isRecord(value) ||\n typeof value.correlationToken !== 'string' ||\n (value.isError !== undefined && typeof value.isError !== 'boolean')\n ) {\n throw new Error('Invalid host tool relay response.');\n }\n return {\n output: value.output,\n ...(value.isError ? { isError: true } : {}),\n correlationToken: value.correlationToken,\n };\n}\n\nfunction readErrorMessage({\n value,\n status,\n}: {\n value: unknown;\n status: number;\n}): string {\n return isRecord(value) && typeof value.error === 'string'\n ? value.error\n : `Host tool relay returned HTTP ${status}.`;\n}\n\nfunction requireEnvironmentVariable({ name }: { name: string }): string {\n const value = env[name];\n if (value == null || value.length === 0) {\n throw new Error(`Missing ${name}.`);\n }\n return value;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return value != null && typeof value === 'object' && !Array.isArray(value);\n}\n","import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ErrorCode,\n ListToolsRequestSchema,\n McpError,\n type CallToolResult,\n type Tool,\n} from '@modelcontextprotocol/sdk/types.js';\nimport type { HarnessV1BridgeToolWire } from '@ai-sdk/harness';\n\ndeclare const __PACKAGE_VERSION__: string | undefined;\n\nconst VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n\nexport type HostToolMCPInvocationResult = {\n readonly output: unknown;\n readonly isError?: boolean;\n readonly correlationToken: string;\n};\n\nexport type HostToolMCPServer = {\n readonly server: Server;\n updateCatalog(options: {\n revision: number;\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n }): Promise<void>;\n};\n\nexport function createHostToolMCPServer({\n tools,\n revision = 1,\n invoke,\n onListTools,\n}: {\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n revision?: number;\n invoke: (options: {\n toolName: string;\n input: Readonly<Record<string, unknown>>;\n catalogRevision: number;\n }) => Promise<HostToolMCPInvocationResult>;\n onListTools?: (options: { revision: number }) => Promise<void>;\n}): HostToolMCPServer {\n let catalog = createCatalog({ revision, tools });\n let catalogAcknowledgmentError: unknown;\n const server = new Server(\n {\n name: '@ai-sdk/harness-acp-host-tools',\n version: VERSION,\n },\n { capabilities: { tools: { listChanged: true } } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n if (catalogAcknowledgmentError != null) {\n throw catalogAcknowledgmentError;\n }\n const current = catalog;\n if (onListTools != null) {\n setImmediate(() => {\n void onListTools({ revision: current.revision }).catch(error => {\n catalogAcknowledgmentError = error;\n });\n });\n }\n return { tools: current.tools.map(toMCPTool) };\n });\n server.setRequestHandler(CallToolRequestSchema, async request => {\n const current = catalog;\n const tool = current.byName.get(request.params.name);\n if (tool == null) {\n throw new McpError(\n ErrorCode.InvalidParams,\n `Unknown host tool: ${request.params.name}`,\n );\n }\n const input = request.params.arguments ?? {};\n const result = await invoke({\n toolName: tool.name,\n input,\n catalogRevision: current.revision,\n });\n return toCallToolResult({ result });\n });\n\n return {\n server,\n updateCatalog: async ({ revision: nextRevision, tools: nextTools }) => {\n catalog = createCatalog({\n revision: nextRevision,\n tools: nextTools,\n });\n await server.sendToolListChanged();\n },\n };\n}\n\nfunction createCatalog({\n revision,\n tools,\n}: {\n revision: number;\n tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n}): {\n readonly revision: number;\n readonly tools: ReadonlyArray<HarnessV1BridgeToolWire>;\n readonly byName: ReadonlyMap<string, HarnessV1BridgeToolWire>;\n} {\n return {\n revision,\n tools: [...tools],\n byName: new Map(tools.map(tool => [tool.name, tool])),\n };\n}\n\nfunction toMCPTool(tool: HarnessV1BridgeToolWire): Tool {\n return {\n name: tool.name,\n ...(tool.description == null ? {} : { description: tool.description }),\n inputSchema: requireObjectSchema({\n toolName: tool.name,\n schema: tool.inputSchema ?? { type: 'object' },\n }),\n };\n}\n\nfunction requireObjectSchema({\n toolName,\n schema,\n}: {\n toolName: string;\n schema: unknown;\n}): Tool['inputSchema'] {\n if (\n schema == null ||\n typeof schema !== 'object' ||\n Array.isArray(schema) ||\n (Reflect.get(schema, 'type') !== undefined &&\n Reflect.get(schema, 'type') !== 'object')\n ) {\n throw new Error(\n `Host tool ${toolName} must use an object JSON Schema for MCP.`,\n );\n }\n return schema as Tool['inputSchema'];\n}\n\nfunction toCallToolResult({\n result,\n}: {\n result: HostToolMCPInvocationResult;\n}): CallToolResult {\n return {\n content: [\n {\n type: 'text',\n text: stringifyOutput({ output: result.output }),\n },\n ],\n ...(result.isError ? { isError: true } : {}),\n _meta: {\n 'ai-sdk-harness-acp-correlation': result.correlationToken,\n },\n };\n}\n\nfunction stringifyOutput({ output }: { output: unknown }): string {\n if (output === undefined) return 'null';\n try {\n return JSON.stringify(output);\n } catch {\n return JSON.stringify({\n error: 'Host tool output could not be serialized as JSON.',\n });\n }\n}\n","import { Agent, request } from 'node:http';\n\n/*\n * A host-tool call can remain pending while a person reviews an approval.\n * The loopback connection therefore must not impose an inactivity deadline.\n */\nconst relayAgent = new Agent({ keepAlive: true, timeout: 0 });\n\nexport async function postHostToolRelay({\n relayUrl,\n relayCredential,\n path,\n body,\n}: {\n relayUrl: string;\n relayCredential: string;\n path: string;\n body: Readonly<Record<string, unknown>>;\n}): Promise<{ status: number; ok: boolean; value: unknown }> {\n const serializedBody = JSON.stringify(body);\n\n return new Promise((resolve, reject) => {\n const relayRequest = request(\n new URL(path, relayUrl),\n {\n agent: relayAgent,\n method: 'POST',\n headers: {\n authorization: `Bearer ${relayCredential}`,\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(serializedBody),\n },\n },\n response => {\n const chunks: Buffer[] = [];\n response.on('data', (chunk: Buffer) => chunks.push(chunk));\n response.on('error', reject);\n response.on('end', () => {\n void new Response(Buffer.concat(chunks)).json().then(value => {\n const status = response.statusCode ?? 0;\n resolve({\n status,\n ok: status >= 200 && status < 300,\n value,\n });\n }, reject);\n });\n },\n );\n relayRequest.on('error', reject);\n relayRequest.end(serializedBody);\n });\n}\n"],"mappings":"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","names":["tools","request","relayUrl","relayCredential"]}
@@ -897,7 +897,6 @@ function createACPStreamTranslator({
897
897
  let openBlock;
898
898
  let blockCounter = 0;
899
899
  let stepOpen = false;
900
- let completedToolStepEligible = false;
901
900
  let finished = false;
902
901
  const blockIdCounts = /* @__PURE__ */ new Map();
903
902
  const toolStates = /* @__PURE__ */ new Map();
@@ -953,10 +952,9 @@ function createACPStreamTranslator({
953
952
  harnessMetadata: { acp: { inferredStep: true } }
954
953
  });
955
954
  stepOpen = false;
956
- completedToolStepEligible = false;
957
955
  };
958
- const flushCompletedToolStep = () => {
959
- if (!stepOpen || !completedToolStepEligible || pendingToolCallIds.size > 0) {
956
+ const finishCompletedToolStep = () => {
957
+ if (!stepOpen || pendingToolCallIds.size > 0) {
960
958
  return;
961
959
  }
962
960
  emitInferredStep({
@@ -1020,7 +1018,6 @@ function createACPStreamTranslator({
1020
1018
  state.emittedCall = true;
1021
1019
  stepOpen = true;
1022
1020
  pendingToolCallIds.add(state.toolCallId);
1023
- completedToolStepEligible = false;
1024
1021
  }
1025
1022
  emitFileChanges({ state, emit });
1026
1023
  if (!state.emittedResult && (state.values.status === "completed" || state.values.status === "failed")) {
@@ -1033,7 +1030,7 @@ function createACPStreamTranslator({
1033
1030
  });
1034
1031
  state.emittedResult = true;
1035
1032
  pendingToolCallIds.delete(state.toolCallId);
1036
- completedToolStepEligible = pendingToolCallIds.size === 0;
1033
+ finishCompletedToolStep();
1037
1034
  }
1038
1035
  };
1039
1036
  const hostToolCall = ({
@@ -1051,7 +1048,6 @@ function createACPStreamTranslator({
1051
1048
  });
1052
1049
  stepOpen = true;
1053
1050
  pendingToolCallIds.add(toolCallId);
1054
- completedToolStepEligible = false;
1055
1051
  };
1056
1052
  const hostToolResult = ({
1057
1053
  toolCallId,
@@ -1068,7 +1064,7 @@ function createACPStreamTranslator({
1068
1064
  ...isError ? { isError: true } : {}
1069
1065
  });
1070
1066
  pendingToolCallIds.delete(toolCallId);
1071
- completedToolStepEligible = pendingToolCallIds.size === 0;
1067
+ finishCompletedToolStep();
1072
1068
  };
1073
1069
  return {
1074
1070
  update: (options) => {
@@ -1082,7 +1078,6 @@ function createACPStreamTranslator({
1082
1078
  emit({ type: "raw", rawValue: preservedUpdate });
1083
1079
  }
1084
1080
  if (update.sessionUpdate === "agent_message_chunk" && update.content?.type === "text" && typeof update.content.text === "string") {
1085
- flushCompletedToolStep();
1086
1081
  emitContent({
1087
1082
  type: "text",
1088
1083
  text: update.content.text,
@@ -1091,7 +1086,6 @@ function createACPStreamTranslator({
1091
1086
  return;
1092
1087
  }
1093
1088
  if (update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string") {
1094
- flushCompletedToolStep();
1095
1089
  emitContent({
1096
1090
  type: "reasoning",
1097
1091
  text: update.content.text,