@fgv/ts-extras 5.1.0-56 → 5.1.0-57
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/CAPABILITIES.md +3 -2
- package/dist/packlets/ai-assist/chatRequestBuilders.js +2 -2
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/dist/packlets/ai-assist/completionClient.js +74 -14
- package/dist/packlets/ai-assist/completionClient.js.map +1 -1
- package/dist/packlets/ai-assist/converters.js +54 -0
- package/dist/packlets/ai-assist/converters.js.map +1 -1
- package/dist/packlets/ai-assist/embeddingClient.js +16 -1
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -1
- package/dist/packlets/ai-assist/imageGenerationClient.js +16 -1
- package/dist/packlets/ai-assist/imageGenerationClient.js.map +1 -1
- package/dist/packlets/ai-assist/listModelsClient.js +19 -1
- package/dist/packlets/ai-assist/listModelsClient.js.map +1 -1
- package/dist/packlets/ai-assist/model.js.map +1 -1
- package/dist/packlets/ai-assist/streamUsageCapability.js +16 -6
- package/dist/packlets/ai-assist/streamUsageCapability.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +8 -4
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +22 -7
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +17 -9
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +12 -9
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +62 -4
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/dist/packlets/ai-assist/streamingClient.js +20 -6
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -1
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +5 -2
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/dist/packlets/ai-assist/toolTypes.js.map +1 -1
- package/dist/ts-extras.d.ts +223 -24
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +2 -2
- package/lib/packlets/ai-assist/chatRequestBuilders.js +2 -2
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -1
- package/lib/packlets/ai-assist/completionClient.d.ts +13 -0
- package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/completionClient.js +74 -14
- package/lib/packlets/ai-assist/completionClient.js.map +1 -1
- package/lib/packlets/ai-assist/converters.d.ts +46 -0
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -1
- package/lib/packlets/ai-assist/converters.js +55 -1
- package/lib/packlets/ai-assist/converters.js.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.d.ts +9 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/embeddingClient.js +16 -1
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -1
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts +9 -0
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/imageGenerationClient.js +16 -1
- package/lib/packlets/ai-assist/imageGenerationClient.js.map +1 -1
- package/lib/packlets/ai-assist/listModelsClient.d.ts +12 -0
- package/lib/packlets/ai-assist/listModelsClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/listModelsClient.js +19 -1
- package/lib/packlets/ai-assist/listModelsClient.js.map +1 -1
- package/lib/packlets/ai-assist/model.d.ts +22 -7
- package/lib/packlets/ai-assist/model.d.ts.map +1 -1
- package/lib/packlets/ai-assist/model.js.map +1 -1
- package/lib/packlets/ai-assist/streamUsageCapability.d.ts +16 -6
- package/lib/packlets/ai-assist/streamUsageCapability.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamUsageCapability.js +16 -6
- package/lib/packlets/ai-assist/streamUsageCapability.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +2 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +6 -2
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +37 -2
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +21 -6
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +17 -3
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +2 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +15 -7
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +2 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +10 -7
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +22 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +62 -4
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.d.ts +5 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -1
- package/lib/packlets/ai-assist/streamingClient.js +19 -5
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +11 -3
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -1
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +5 -2
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -1
- package/lib/packlets/ai-assist/toolTypes.d.ts +61 -3
- package/lib/packlets/ai-assist/toolTypes.d.ts.map +1 -1
- package/lib/packlets/ai-assist/toolTypes.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../../src/packlets/ai-assist/streamingAdapters/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Streaming adapter for the Anthropic Messages API. Handles server tool\n * use (e.g. `web_search`) as unified `tool-event` markers and client-defined\n * tool calls (type `tool_use`) with B4 thinking-block accumulation.\n *\n * The ordered accumulation buffer preserves all content blocks from the\n * assistant turn in their original stream positions. The C3 continuation\n * builder reads this buffer to reconstruct the assistant turn for the\n * follow-up request.\n *\n * @packageDocumentation\n */\n\nimport { type Logging, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\nimport { type JsonObject } from '@fgv/ts-json-base';\n\nimport { buildAnthropicMessages } from '../chatRequestBuilders';\nimport { anthropicAuthHeaders } from '../endpoint';\nimport {\n AiPrompt,\n DEFAULT_ANTHROPIC_MAX_TOKENS,\n type AiToolConfig,\n type IAiStreamEvent,\n type IChatMessage\n} from '../model';\nimport { parseSseEventJson, readSseEvents } from '../sseParser';\nimport { toAnthropicTools } from '../toolFormats';\nimport { anthropicEffortToBudgetTokens, type IResolvedThinkingConfig } from '../thinkingOptionsResolver';\nimport { normalizeAnthropicUsage } from '../usageNormalization';\nimport {\n IStreamApiConfig,\n MALFORMED_TOOL_USE_WARN_TAG,\n UNRECOGNIZED_EVENT_WARN_TAG,\n formatUnrecognizedEventPayloadPreview,\n jsonObjectValidator,\n openSseConnection,\n validateEventPayload\n} from './common';\n\n// ============================================================================\n// Accumulated block types (internal — used by C3 continuation builder)\n// ============================================================================\n\n/**\n * An accumulated `thinking` block from the assistant turn. The `thinking` text\n * and `signature` are both concatenated across their respective delta events.\n * The full block is passed to the C3 continuation builder for round-trip preservation.\n * @internal\n */\nexport interface IAccumulatedThinkingBlock {\n readonly type: 'thinking';\n thinking: string;\n signature: string;\n}\n\n/**\n * An accumulated `redacted_thinking` block from the assistant turn. The `data`\n * field is opaque and arrives complete in the `content_block_start` event — no\n * delta events follow. Passed through unmodified to the C3 continuation builder.\n * @internal\n */\nexport interface IAccumulatedRedactedThinkingBlock {\n readonly type: 'redacted_thinking';\n readonly data: string;\n}\n\n/**\n * An accumulated `text` block from the assistant turn.\n * @internal\n */\nexport interface IAccumulatedTextBlock {\n readonly type: 'text';\n text: string;\n}\n\n/**\n * An accumulated `tool_use` block from the assistant turn (client-defined tool call).\n * The `argsBuffer` is the concatenation of all `input_json_delta` chunks.\n * @internal\n */\nexport interface IAccumulatedToolUseBlock {\n readonly type: 'tool_use';\n readonly id: string;\n readonly name: string;\n argsBuffer: string;\n}\n\n/**\n * Discriminated union of all accumulated Anthropic content block types.\n * The ordered accumulation buffer is a `Map<number, IAccumulatedBlock>` keyed\n * by the SSE `index` field from `content_block_start` events.\n * @internal\n */\nexport type IAccumulatedBlock =\n | IAccumulatedThinkingBlock\n | IAccumulatedRedactedThinkingBlock\n | IAccumulatedTextBlock\n | IAccumulatedToolUseBlock;\n\n// ============================================================================\n// Event payload shapes\n// ============================================================================\n\n/**\n * Payload of a `content_block_start` SSE event with the `index` field.\n * The `index` field is optional for backward compatibility with providers that\n * omit it; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStartPayload {\n readonly index?: number;\n readonly content_block: {\n readonly type?: string;\n readonly name?: string;\n readonly id?: string;\n readonly data?: string;\n };\n}\n\n/**\n * Payload of a `content_block_delta` SSE event. Various delta types are\n * discriminated on `delta.type`:\n * - `text_delta`: text content\n * - `input_json_delta`: tool argument accumulation\n * - `thinking_delta`: thinking text accumulation\n * - `signature_delta`: thinking signature accumulation (MUST be appended, not overwritten)\n *\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockDeltaPayload {\n readonly index?: number;\n readonly delta: {\n readonly type?: string;\n readonly text?: string;\n readonly partial_json?: string;\n readonly thinking?: string;\n readonly signature?: string;\n };\n}\n\n/**\n * Payload of a `content_block_stop` SSE event.\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStopPayload {\n readonly index?: number;\n}\n\n/**\n * Payload of a `message_delta` SSE event carrying the final stop reason and,\n * on the terminal `message_delta`, the completed output-token count.\n * @internal\n */\ninterface IAnthropicMessageDeltaPayload {\n readonly delta: { readonly stop_reason?: string };\n readonly usage?: JsonObject;\n}\n\n/**\n * Payload of a `message_start` SSE event. Carries the initial `usage` block —\n * `input_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens` —\n * which does not repeat on later events.\n * @internal\n */\ninterface IAnthropicMessageStartPayload {\n readonly message: { readonly usage?: JsonObject };\n}\n\n/**\n * Payload of an `error` SSE event.\n * @internal\n */\ninterface IAnthropicErrorPayload {\n readonly error?: { readonly message?: string };\n}\n\nconst anthropicContentBlockInner: Validator<{\n type?: string;\n name?: string;\n id?: string;\n data?: string;\n}> = Validators.object<{ type?: string; name?: string; id?: string; data?: string }>(\n {\n type: Validators.string.optional(),\n name: Validators.string.optional(),\n id: Validators.string.optional(),\n data: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'name', 'id', 'data'] } }\n);\n\nconst anthropicContentBlockStartPayload: Validator<IAnthropicContentBlockStartPayload> =\n Validators.object<IAnthropicContentBlockStartPayload>(\n {\n index: Validators.number.optional(),\n content_block: anthropicContentBlockInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockDeltaInner: Validator<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}> = Validators.object<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}>(\n {\n type: Validators.string.optional(),\n text: Validators.string.optional(),\n partial_json: Validators.string.optional(),\n thinking: Validators.string.optional(),\n signature: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'text', 'partial_json', 'thinking', 'signature'] } }\n);\n\nconst anthropicContentBlockDeltaPayload: Validator<IAnthropicContentBlockDeltaPayload> =\n Validators.object<IAnthropicContentBlockDeltaPayload>(\n {\n index: Validators.number.optional(),\n delta: anthropicContentBlockDeltaInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockStopPayload: Validator<IAnthropicContentBlockStopPayload> =\n Validators.object<IAnthropicContentBlockStopPayload>(\n { index: Validators.number.optional() },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicMessageDeltaInner: Validator<{ stop_reason?: string }> = Validators.object<{\n stop_reason?: string;\n}>({ stop_reason: Validators.string.optional() }, { options: { optionalFields: ['stop_reason'] } });\n\nconst anthropicMessageDeltaPayload: Validator<IAnthropicMessageDeltaPayload> =\n Validators.object<IAnthropicMessageDeltaPayload>({\n delta: anthropicMessageDeltaInner,\n usage: jsonObjectValidator.optional()\n });\n\nconst anthropicMessageStartPayload: Validator<IAnthropicMessageStartPayload> =\n Validators.object<IAnthropicMessageStartPayload>({\n message: Validators.object<{ usage?: JsonObject }>({ usage: jsonObjectValidator.optional() })\n });\n\nconst anthropicErrorInner: Validator<{ message?: string }> = Validators.object<{ message?: string }>(\n { message: Validators.string.optional() },\n { options: { optionalFields: ['message'] } }\n);\n\nconst anthropicErrorPayload: Validator<IAnthropicErrorPayload> = Validators.object<IAnthropicErrorPayload>(\n { error: anthropicErrorInner.optional() },\n { options: { optionalFields: ['error'] } }\n);\n\n// ============================================================================\n// Stream translator\n// ============================================================================\n\n/**\n * Recognized Anthropic Messages API SSE event names. Anything not in this set surfaces a\n * one-time `logger.warn` per stream — same rationale as the OpenAI Responses adapter's\n * `RECOGNIZED_OPENAI_RESPONSES_EVENTS` allowlist in `openaiResponses.ts`. Add to this set\n * when a new event type is observed and confirmed safe to ignore.\n *\n * @internal\n */\nconst RECOGNIZED_ANTHROPIC_EVENTS: ReadonlySet<string> = new Set<string>([\n // ---- handled by the translator ----\n 'message_start',\n 'content_block_start',\n 'content_block_delta',\n 'content_block_stop',\n 'message_delta',\n 'message_stop',\n 'error',\n // ---- lifecycle / heartbeats: intentionally silent ----\n 'ping'\n]);\n\n/**\n * Translates an Anthropic Messages API SSE stream into unified events.\n *\n * Maintains an ordered accumulation buffer (keyed by SSE `index`) for all\n * content blocks: `thinking`, `redacted_thinking`, `text`, and `tool_use`.\n * The buffer is available on the returned generator via `.accumulationBuffer`.\n *\n * Unrecognized event names are reported once per stream via `logger?.warn` —\n * see {@link RECOGNIZED_ANTHROPIC_EVENTS}.\n *\n * @internal\n */\nasync function* translateAnthropicStream(\n response: Response,\n accumulationBuffer: Map<number, IAccumulatedBlock>,\n logger?: Logging.ILogger\n): AsyncGenerator<IAiStreamEvent> {\n let fullText = '';\n let truncated = false;\n let stopped = false;\n // Anthropic splits the usage block across two events: `message_start` carries\n // input/cache tokens (once, not repeated), `message_delta` carries the final\n // output-token count. Merged here so `done` can normalize a single object.\n let usageRaw: JsonObject | undefined;\n // Track unrecognized event names we have already warned about, so a hot stream of\n // an unknown event type produces exactly one log line per name per stream.\n const warnedEvents = new Set<string>();\n\n try {\n /* c8 ignore next - body is non-null at this point per openSseConnection */\n if (!response.body) return;\n for await (const message of readSseEvents(response.body)) {\n const eventName = message.event;\n\n if (eventName === 'message_start') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicMessageStartPayload);\n if (payload?.message.usage !== undefined) {\n usageRaw = { ...usageRaw, ...payload.message.usage };\n }\n } else if (eventName === 'content_block_start') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStartPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawIndex, content_block: block } = payload;\n const index = rawIndex ?? 0;\n\n if (block.type === 'thinking') {\n accumulationBuffer.set(index, { type: 'thinking', thinking: '', signature: '' });\n } else if (block.type === 'redacted_thinking') {\n accumulationBuffer.set(index, {\n type: 'redacted_thinking',\n /* c8 ignore next 1 - defensive: Anthropic always provides data for redacted_thinking */\n data: block.data ?? ''\n });\n } else if (block.type === 'text') {\n accumulationBuffer.set(index, { type: 'text', text: '' });\n } else if (block.type === 'tool_use') {\n // A tool_use block_start MUST carry a non-empty id and name: the id is the\n // sole correlation key for the follow-up tool_result, and dropping the block\n // silently (then ignoring its input_json_delta chunks at the delta handler\n // below) is exactly how an orphaned block leaves the harness without a clean\n // id and corrupts the continuation. Surface it loudly instead of dropping it.\n if (block.id && block.name) {\n accumulationBuffer.set(index, {\n type: 'tool_use',\n id: block.id,\n name: block.name,\n argsBuffer: ''\n });\n yield { type: 'client-tool-call-start', toolName: block.name, callId: block.id };\n } else {\n logger?.warn(\n `${MALFORMED_TOOL_USE_WARN_TAG} Anthropic streaming adapter: tool_use content_block_start ` +\n `at index ${index} is missing a usable id and/or name ` +\n `(id=${JSON.stringify(block.id)}, name=${JSON.stringify(block.name)}). ` +\n `No client tool call will be issued for this block; its argument deltas are dropped. ` +\n `This usually indicates provider drift or a truncated stream.`\n );\n }\n } else if (block.type === 'server_tool_use' && block.name === 'web_search') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'started' };\n } else if (block.type === 'web_search_tool_result') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'completed' };\n }\n } else if (eventName === 'content_block_delta') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockDeltaPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawDeltaIndex, delta } = payload;\n const index = rawDeltaIndex ?? 0;\n const block = accumulationBuffer.get(index);\n\n if (delta.type === 'text_delta' && typeof delta.text === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'text') {\n block.text += delta.text;\n }\n if (delta.text.length > 0) {\n fullText += delta.text;\n yield { type: 'text-delta', delta: delta.text };\n }\n } else if (delta.type === 'input_json_delta' && typeof delta.partial_json === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'tool_use') {\n block.argsBuffer += delta.partial_json;\n }\n } else if (delta.type === 'thinking_delta' && typeof delta.thinking === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.thinking += delta.thinking;\n }\n } else if (delta.type === 'signature_delta' && typeof delta.signature === 'string') {\n // CRITICAL (E5): signature must be APPENDED, not overwritten.\n // The signature is base64 arriving in multiple chunks.\n // Overwriting produces a truncated signature that Anthropic rejects with HTTP 400.\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.signature += delta.signature;\n }\n }\n } else if (eventName === 'content_block_stop') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStopPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n /* c8 ignore next 1 - defensive: payload.index ?? 0 null branch is unreachable */\n const block = accumulationBuffer.get(payload.index ?? 0);\n /* c8 ignore next 1 - defensive: block always exists when block_stop follows block_start */\n if (block?.type === 'tool_use') {\n let args: JsonObject;\n try {\n /* c8 ignore next 1 - defensive: argsBuffer || '{}' empty-string branch unreachable in tests */\n const parsed = JSON.parse(block.argsBuffer || '{}') as unknown;\n /* c8 ignore start - defensive: non-object/malformed parse defaults to empty object */\n args =\n parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as JsonObject)\n : {};\n } catch {\n args = {};\n }\n /* c8 ignore stop */\n yield { type: 'client-tool-call-done', toolName: block.name, callId: block.id, args };\n }\n } else if (eventName === 'message_delta') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicMessageDeltaPayload);\n /* c8 ignore next 1 - defensive: payload?.delta null branch unreachable after validation */\n if (payload?.delta.stop_reason === 'max_tokens') {\n truncated = true;\n }\n if (payload?.usage !== undefined) {\n usageRaw = { ...usageRaw, ...payload.usage };\n }\n } else if (eventName === 'message_stop') {\n stopped = true;\n } else if (eventName === 'error') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicErrorPayload);\n yield {\n type: 'error',\n /* c8 ignore next 1 - defensive: payload?.error null branch unreachable after validation */\n message: payload?.error?.message ?? 'Anthropic stream returned an error event'\n };\n return;\n } else if (\n typeof eventName === 'string' &&\n !RECOGNIZED_ANTHROPIC_EVENTS.has(eventName) &&\n !warnedEvents.has(eventName)\n ) {\n // Empirical drift instrument: an unrecognized Anthropic event surfaces as a one-time\n // warning per stream. Update RECOGNIZED_ANTHROPIC_EVENTS once the new event is either\n // handled or confirmed safe to ignore.\n warnedEvents.add(eventName);\n logger?.warn(\n `${UNRECOGNIZED_EVENT_WARN_TAG} Anthropic streaming adapter: unrecognized SSE event ` +\n `'${eventName}'. ` +\n `payload preview: ${formatUnrecognizedEventPayloadPreview(message.data)}. ` +\n `This may indicate provider drift — if the new event carries data the adapter ` +\n `should surface, add a handler; otherwise add the name to ` +\n `RECOGNIZED_ANTHROPIC_EVENTS.`\n );\n }\n }\n } catch (err: unknown) /* c8 ignore start - defensive: stream errors are always Error instances */ {\n yield { type: 'error', message: err instanceof Error ? err.message : String(err) };\n return;\n } /* c8 ignore stop */\n\n if (stopped) {\n const usage = normalizeAnthropicUsage(usageRaw);\n yield { type: 'done', truncated, fullText, ...(usage !== undefined ? { usage } : {}) };\n } else {\n yield { type: 'error', message: 'Anthropic stream ended without a message_stop event' };\n }\n}\n\n// ============================================================================\n// Per-format request caller\n// ============================================================================\n\n/**\n * Issues a streaming Anthropic Messages request and returns the\n * unified-event iterable on success.\n *\n * @internal\n */\nexport async function callAnthropicStream(\n config: IStreamApiConfig,\n prompt: AiPrompt,\n messagesBefore: ReadonlyArray<IChatMessage> | undefined,\n temperature: number | undefined,\n tools: ReadonlyArray<AiToolConfig> | undefined,\n logger?: Logging.ILogger,\n signal?: AbortSignal,\n resolvedThinking?: IResolvedThinkingConfig,\n accumulationBuffer?: Map<number, IAccumulatedBlock>,\n continuationMessages?: ReadonlyArray<JsonObject>,\n useAdaptiveThinking: boolean = false,\n maxTokens?: number\n): Promise<Result<AsyncIterable<IAiStreamEvent>>> {\n const url = `${config.baseUrl}/messages`;\n const messages = buildAnthropicMessages(prompt, {\n head: messagesBefore,\n rawTail: continuationMessages\n });\n const body: Record<string, unknown> = {\n model: config.model,\n system: prompt.system,\n messages,\n // Anthropic's Messages API requires max_tokens on every request — see\n // AiAssist.DEFAULT_ANTHROPIC_MAX_TOKENS for why only this provider defaults it.\n max_tokens: maxTokens ?? DEFAULT_ANTHROPIC_MAX_TOKENS,\n stream: true\n };\n // Temperature is sent only when explicitly provided (Claude-5 rejects any temperature). When\n // thinking is active it is also rejected — the completion/streaming paths validate this upstream,\n // and the effort gate here is the safety net for the (unguarded) client-tool path.\n if (resolvedThinking?.anthropicEffort === undefined) {\n if (temperature !== undefined) {\n body.temperature = temperature;\n }\n }\n if (resolvedThinking?.anthropicEffort !== undefined) {\n if (useAdaptiveThinking) {\n // Claude 5 family: adaptive thinking — no budget_tokens; effort moves to the\n // top-level output_config block. See AiAssist.isAdaptiveThinkingModel.\n body.thinking = { type: 'adaptive' };\n body.output_config = { effort: resolvedThinking.anthropicEffort };\n } else {\n body.thinking = {\n type: 'enabled',\n budget_tokens: anthropicEffortToBudgetTokens(resolvedThinking.anthropicEffort)\n };\n }\n }\n if (resolvedThinking?.otherParams !== undefined) {\n Object.assign(body, resolvedThinking.otherParams);\n }\n if (tools && tools.length > 0) {\n body.tools = toAnthropicTools(tools);\n }\n const headers: Record<string, string> = anthropicAuthHeaders(config.apiKey);\n /* c8 ignore next 4 - optional logger diagnostic output */\n if (logger) {\n const toolTypes = tools && tools.length > 0 ? tools.map((t) => t.type).join(',') : 'none';\n logger.info(`Anthropic streaming: model=${config.model}, tools=${toolTypes}`);\n }\n const buffer = accumulationBuffer ?? new Map<number, IAccumulatedBlock>();\n const conn = await openSseConnection(url, headers, body, logger, signal);\n return conn.onSuccess((response) => succeed(translateAnthropicStream(response, buffer, logger)));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../../src/packlets/ai-assist/streamingAdapters/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Streaming adapter for the Anthropic Messages API. Handles server tool\n * use (e.g. `web_search`) as unified `tool-event` markers and client-defined\n * tool calls (type `tool_use`) with B4 thinking-block accumulation.\n *\n * The ordered accumulation buffer preserves all content blocks from the\n * assistant turn in their original stream positions. The C3 continuation\n * builder reads this buffer to reconstruct the assistant turn for the\n * follow-up request.\n *\n * @packageDocumentation\n */\n\nimport { fail, type Logging, Result, succeed, type Validator, Validators } from '@fgv/ts-utils';\nimport { type JsonObject } from '@fgv/ts-json-base';\n\nimport { buildAnthropicMessages, buildAnthropicSystem } from '../chatRequestBuilders';\nimport { type IAiCacheRequest } from '../cacheRequest';\nimport { anthropicAuthHeaders } from '../endpoint';\nimport {\n AiPrompt,\n DEFAULT_ANTHROPIC_MAX_TOKENS,\n type AiToolConfig,\n type IAiStreamEvent,\n type IChatMessage\n} from '../model';\nimport { parseSseEventJson, readSseEvents } from '../sseParser';\nimport { toAnthropicTools } from '../toolFormats';\nimport { anthropicEffortToBudgetTokens, type IResolvedThinkingConfig } from '../thinkingOptionsResolver';\nimport { normalizeAnthropicUsage } from '../usageNormalization';\nimport {\n IStreamApiConfig,\n MALFORMED_TOOL_USE_WARN_TAG,\n UNRECOGNIZED_EVENT_WARN_TAG,\n formatUnrecognizedEventPayloadPreview,\n jsonObjectValidator,\n openSseConnection,\n validateEventPayload\n} from './common';\n\n// ============================================================================\n// Accumulated block types (internal — used by C3 continuation builder)\n// ============================================================================\n\n/**\n * An accumulated `thinking` block from the assistant turn. The `thinking` text\n * and `signature` are both concatenated across their respective delta events.\n * The full block is passed to the C3 continuation builder for round-trip preservation.\n * @internal\n */\nexport interface IAccumulatedThinkingBlock {\n readonly type: 'thinking';\n thinking: string;\n signature: string;\n}\n\n/**\n * An accumulated `redacted_thinking` block from the assistant turn. The `data`\n * field is opaque and arrives complete in the `content_block_start` event — no\n * delta events follow. Passed through unmodified to the C3 continuation builder.\n * @internal\n */\nexport interface IAccumulatedRedactedThinkingBlock {\n readonly type: 'redacted_thinking';\n readonly data: string;\n}\n\n/**\n * An accumulated `text` block from the assistant turn.\n * @internal\n */\nexport interface IAccumulatedTextBlock {\n readonly type: 'text';\n text: string;\n}\n\n/**\n * An accumulated `tool_use` block from the assistant turn (client-defined tool call).\n * The `argsBuffer` is the concatenation of all `input_json_delta` chunks.\n * @internal\n */\nexport interface IAccumulatedToolUseBlock {\n readonly type: 'tool_use';\n readonly id: string;\n readonly name: string;\n argsBuffer: string;\n}\n\n/**\n * Discriminated union of all accumulated Anthropic content block types.\n * The ordered accumulation buffer is a `Map<number, IAccumulatedBlock>` keyed\n * by the SSE `index` field from `content_block_start` events.\n * @internal\n */\nexport type IAccumulatedBlock =\n | IAccumulatedThinkingBlock\n | IAccumulatedRedactedThinkingBlock\n | IAccumulatedTextBlock\n | IAccumulatedToolUseBlock;\n\n// ============================================================================\n// Event payload shapes\n// ============================================================================\n\n/**\n * Payload of a `content_block_start` SSE event with the `index` field.\n * The `index` field is optional for backward compatibility with providers that\n * omit it; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStartPayload {\n readonly index?: number;\n readonly content_block: {\n readonly type?: string;\n readonly name?: string;\n readonly id?: string;\n readonly data?: string;\n };\n}\n\n/**\n * Payload of a `content_block_delta` SSE event. Various delta types are\n * discriminated on `delta.type`:\n * - `text_delta`: text content\n * - `input_json_delta`: tool argument accumulation\n * - `thinking_delta`: thinking text accumulation\n * - `signature_delta`: thinking signature accumulation (MUST be appended, not overwritten)\n *\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockDeltaPayload {\n readonly index?: number;\n readonly delta: {\n readonly type?: string;\n readonly text?: string;\n readonly partial_json?: string;\n readonly thinking?: string;\n readonly signature?: string;\n };\n}\n\n/**\n * Payload of a `content_block_stop` SSE event.\n * The `index` field is optional; absent index defaults to 0 in the stream translator.\n * @internal\n */\ninterface IAnthropicContentBlockStopPayload {\n readonly index?: number;\n}\n\n/**\n * Payload of a `message_delta` SSE event carrying the final stop reason and,\n * on the terminal `message_delta`, the completed output-token count.\n * @internal\n */\ninterface IAnthropicMessageDeltaPayload {\n readonly delta: { readonly stop_reason?: string };\n readonly usage?: JsonObject;\n}\n\n/**\n * Payload of a `message_start` SSE event. Carries the initial `usage` block —\n * `input_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens` —\n * which does not repeat on later events.\n * @internal\n */\ninterface IAnthropicMessageStartPayload {\n readonly message: { readonly usage?: JsonObject };\n}\n\n/**\n * Payload of an `error` SSE event.\n * @internal\n */\ninterface IAnthropicErrorPayload {\n readonly error?: { readonly message?: string };\n}\n\nconst anthropicContentBlockInner: Validator<{\n type?: string;\n name?: string;\n id?: string;\n data?: string;\n}> = Validators.object<{ type?: string; name?: string; id?: string; data?: string }>(\n {\n type: Validators.string.optional(),\n name: Validators.string.optional(),\n id: Validators.string.optional(),\n data: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'name', 'id', 'data'] } }\n);\n\nconst anthropicContentBlockStartPayload: Validator<IAnthropicContentBlockStartPayload> =\n Validators.object<IAnthropicContentBlockStartPayload>(\n {\n index: Validators.number.optional(),\n content_block: anthropicContentBlockInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockDeltaInner: Validator<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}> = Validators.object<{\n type?: string;\n text?: string;\n partial_json?: string;\n thinking?: string;\n signature?: string;\n}>(\n {\n type: Validators.string.optional(),\n text: Validators.string.optional(),\n partial_json: Validators.string.optional(),\n thinking: Validators.string.optional(),\n signature: Validators.string.optional()\n },\n { options: { optionalFields: ['type', 'text', 'partial_json', 'thinking', 'signature'] } }\n);\n\nconst anthropicContentBlockDeltaPayload: Validator<IAnthropicContentBlockDeltaPayload> =\n Validators.object<IAnthropicContentBlockDeltaPayload>(\n {\n index: Validators.number.optional(),\n delta: anthropicContentBlockDeltaInner\n },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicContentBlockStopPayload: Validator<IAnthropicContentBlockStopPayload> =\n Validators.object<IAnthropicContentBlockStopPayload>(\n { index: Validators.number.optional() },\n { options: { optionalFields: ['index'] } }\n );\n\nconst anthropicMessageDeltaInner: Validator<{ stop_reason?: string }> = Validators.object<{\n stop_reason?: string;\n}>({ stop_reason: Validators.string.optional() }, { options: { optionalFields: ['stop_reason'] } });\n\nconst anthropicMessageDeltaPayload: Validator<IAnthropicMessageDeltaPayload> =\n Validators.object<IAnthropicMessageDeltaPayload>({\n delta: anthropicMessageDeltaInner,\n usage: jsonObjectValidator.optional()\n });\n\nconst anthropicMessageStartPayload: Validator<IAnthropicMessageStartPayload> =\n Validators.object<IAnthropicMessageStartPayload>({\n message: Validators.object<{ usage?: JsonObject }>({ usage: jsonObjectValidator.optional() })\n });\n\nconst anthropicErrorInner: Validator<{ message?: string }> = Validators.object<{ message?: string }>(\n { message: Validators.string.optional() },\n { options: { optionalFields: ['message'] } }\n);\n\nconst anthropicErrorPayload: Validator<IAnthropicErrorPayload> = Validators.object<IAnthropicErrorPayload>(\n { error: anthropicErrorInner.optional() },\n { options: { optionalFields: ['error'] } }\n);\n\n// ============================================================================\n// Stream translator\n// ============================================================================\n\n/**\n * Recognized Anthropic Messages API SSE event names. Anything not in this set surfaces a\n * one-time `logger.warn` per stream — same rationale as the OpenAI Responses adapter's\n * `RECOGNIZED_OPENAI_RESPONSES_EVENTS` allowlist in `openaiResponses.ts`. Add to this set\n * when a new event type is observed and confirmed safe to ignore.\n *\n * @internal\n */\nconst RECOGNIZED_ANTHROPIC_EVENTS: ReadonlySet<string> = new Set<string>([\n // ---- handled by the translator ----\n 'message_start',\n 'content_block_start',\n 'content_block_delta',\n 'content_block_stop',\n 'message_delta',\n 'message_stop',\n 'error',\n // ---- lifecycle / heartbeats: intentionally silent ----\n 'ping'\n]);\n\n/**\n * Translates an Anthropic Messages API SSE stream into unified events.\n *\n * Maintains an ordered accumulation buffer (keyed by SSE `index`) for all\n * content blocks: `thinking`, `redacted_thinking`, `text`, and `tool_use`.\n * The buffer is available on the returned generator via `.accumulationBuffer`.\n *\n * Unrecognized event names are reported once per stream via `logger?.warn` —\n * see {@link RECOGNIZED_ANTHROPIC_EVENTS}.\n *\n * @internal\n */\nasync function* translateAnthropicStream(\n response: Response,\n accumulationBuffer: Map<number, IAccumulatedBlock>,\n logger?: Logging.ILogger\n): AsyncGenerator<IAiStreamEvent> {\n let fullText = '';\n let truncated = false;\n let stopped = false;\n // Anthropic splits the usage block across two events: `message_start` carries\n // input/cache tokens (once, not repeated), `message_delta` carries the final\n // output-token count. Merged here so `done` can normalize a single object.\n let usageRaw: JsonObject | undefined;\n // Track unrecognized event names we have already warned about, so a hot stream of\n // an unknown event type produces exactly one log line per name per stream.\n const warnedEvents = new Set<string>();\n\n try {\n /* c8 ignore next - body is non-null at this point per openSseConnection */\n if (!response.body) return;\n for await (const message of readSseEvents(response.body)) {\n const eventName = message.event;\n\n if (eventName === 'message_start') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicMessageStartPayload);\n if (payload?.message.usage !== undefined) {\n usageRaw = { ...usageRaw, ...payload.message.usage };\n }\n } else if (eventName === 'content_block_start') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStartPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawIndex, content_block: block } = payload;\n const index = rawIndex ?? 0;\n\n if (block.type === 'thinking') {\n accumulationBuffer.set(index, { type: 'thinking', thinking: '', signature: '' });\n } else if (block.type === 'redacted_thinking') {\n accumulationBuffer.set(index, {\n type: 'redacted_thinking',\n /* c8 ignore next 1 - defensive: Anthropic always provides data for redacted_thinking */\n data: block.data ?? ''\n });\n } else if (block.type === 'text') {\n accumulationBuffer.set(index, { type: 'text', text: '' });\n } else if (block.type === 'tool_use') {\n // A tool_use block_start MUST carry a non-empty id and name: the id is the\n // sole correlation key for the follow-up tool_result, and dropping the block\n // silently (then ignoring its input_json_delta chunks at the delta handler\n // below) is exactly how an orphaned block leaves the harness without a clean\n // id and corrupts the continuation. Surface it loudly instead of dropping it.\n if (block.id && block.name) {\n accumulationBuffer.set(index, {\n type: 'tool_use',\n id: block.id,\n name: block.name,\n argsBuffer: ''\n });\n yield { type: 'client-tool-call-start', toolName: block.name, callId: block.id };\n } else {\n logger?.warn(\n `${MALFORMED_TOOL_USE_WARN_TAG} Anthropic streaming adapter: tool_use content_block_start ` +\n `at index ${index} is missing a usable id and/or name ` +\n `(id=${JSON.stringify(block.id)}, name=${JSON.stringify(block.name)}). ` +\n `No client tool call will be issued for this block; its argument deltas are dropped. ` +\n `This usually indicates provider drift or a truncated stream.`\n );\n }\n } else if (block.type === 'server_tool_use' && block.name === 'web_search') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'started' };\n } else if (block.type === 'web_search_tool_result') {\n yield { type: 'tool-event', toolType: 'web_search', phase: 'completed' };\n }\n } else if (eventName === 'content_block_delta') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockDeltaPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n const { index: rawDeltaIndex, delta } = payload;\n const index = rawDeltaIndex ?? 0;\n const block = accumulationBuffer.get(index);\n\n if (delta.type === 'text_delta' && typeof delta.text === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'text') {\n block.text += delta.text;\n }\n if (delta.text.length > 0) {\n fullText += delta.text;\n yield { type: 'text-delta', delta: delta.text };\n }\n } else if (delta.type === 'input_json_delta' && typeof delta.partial_json === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'tool_use') {\n block.argsBuffer += delta.partial_json;\n }\n } else if (delta.type === 'thinking_delta' && typeof delta.thinking === 'string') {\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.thinking += delta.thinking;\n }\n } else if (delta.type === 'signature_delta' && typeof delta.signature === 'string') {\n // CRITICAL (E5): signature must be APPENDED, not overwritten.\n // The signature is base64 arriving in multiple chunks.\n // Overwriting produces a truncated signature that Anthropic rejects with HTTP 400.\n /* c8 ignore next 1 - defensive: delta arrives only after block_start sets buffer entry */\n if (block?.type === 'thinking') {\n block.signature += delta.signature;\n }\n }\n } else if (eventName === 'content_block_stop') {\n const payload = validateEventPayload(\n parseSseEventJson(message.data),\n anthropicContentBlockStopPayload\n );\n /* c8 ignore next 1 - defensive: payload null branch unreachable after validation */\n if (!payload) continue;\n /* c8 ignore next 1 - defensive: payload.index ?? 0 null branch is unreachable */\n const block = accumulationBuffer.get(payload.index ?? 0);\n /* c8 ignore next 1 - defensive: block always exists when block_stop follows block_start */\n if (block?.type === 'tool_use') {\n let args: JsonObject;\n try {\n /* c8 ignore next 1 - defensive: argsBuffer || '{}' empty-string branch unreachable in tests */\n const parsed = JSON.parse(block.argsBuffer || '{}') as unknown;\n /* c8 ignore start - defensive: non-object/malformed parse defaults to empty object */\n args =\n parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as JsonObject)\n : {};\n } catch {\n args = {};\n }\n /* c8 ignore stop */\n yield { type: 'client-tool-call-done', toolName: block.name, callId: block.id, args };\n }\n } else if (eventName === 'message_delta') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicMessageDeltaPayload);\n /* c8 ignore next 1 - defensive: payload?.delta null branch unreachable after validation */\n if (payload?.delta.stop_reason === 'max_tokens') {\n truncated = true;\n }\n if (payload?.usage !== undefined) {\n usageRaw = { ...usageRaw, ...payload.usage };\n }\n } else if (eventName === 'message_stop') {\n stopped = true;\n } else if (eventName === 'error') {\n const payload = validateEventPayload(parseSseEventJson(message.data), anthropicErrorPayload);\n yield {\n type: 'error',\n /* c8 ignore next 1 - defensive: payload?.error null branch unreachable after validation */\n message: payload?.error?.message ?? 'Anthropic stream returned an error event'\n };\n return;\n } else if (\n typeof eventName === 'string' &&\n !RECOGNIZED_ANTHROPIC_EVENTS.has(eventName) &&\n !warnedEvents.has(eventName)\n ) {\n // Empirical drift instrument: an unrecognized Anthropic event surfaces as a one-time\n // warning per stream. Update RECOGNIZED_ANTHROPIC_EVENTS once the new event is either\n // handled or confirmed safe to ignore.\n warnedEvents.add(eventName);\n logger?.warn(\n `${UNRECOGNIZED_EVENT_WARN_TAG} Anthropic streaming adapter: unrecognized SSE event ` +\n `'${eventName}'. ` +\n `payload preview: ${formatUnrecognizedEventPayloadPreview(message.data)}. ` +\n `This may indicate provider drift — if the new event carries data the adapter ` +\n `should surface, add a handler; otherwise add the name to ` +\n `RECOGNIZED_ANTHROPIC_EVENTS.`\n );\n }\n }\n } catch (err: unknown) /* c8 ignore start - defensive: stream errors are always Error instances */ {\n yield { type: 'error', message: err instanceof Error ? err.message : String(err) };\n return;\n } /* c8 ignore stop */\n\n if (stopped) {\n const usage = normalizeAnthropicUsage(usageRaw);\n yield { type: 'done', truncated, fullText, ...(usage !== undefined ? { usage } : {}) };\n } else {\n yield { type: 'error', message: 'Anthropic stream ended without a message_stop event' };\n }\n}\n\n// ============================================================================\n// Per-format request caller\n// ============================================================================\n\n/**\n * Issues a streaming Anthropic Messages request and returns the\n * unified-event iterable on success.\n *\n * @internal\n */\nexport async function callAnthropicStream(\n config: IStreamApiConfig,\n prompt: AiPrompt,\n messagesBefore: ReadonlyArray<IChatMessage> | undefined,\n temperature: number | undefined,\n tools: ReadonlyArray<AiToolConfig> | undefined,\n logger?: Logging.ILogger,\n signal?: AbortSignal,\n resolvedThinking?: IResolvedThinkingConfig,\n accumulationBuffer?: Map<number, IAccumulatedBlock>,\n continuationMessages?: ReadonlyArray<JsonObject>,\n useAdaptiveThinking: boolean = false,\n maxTokens?: number,\n cache?: IAiCacheRequest\n): Promise<Result<AsyncIterable<IAiStreamEvent>>> {\n const url = `${config.baseUrl}/messages`;\n const messages = buildAnthropicMessages(prompt, {\n head: messagesBefore,\n rawTail: continuationMessages\n });\n const systemResult = buildAnthropicSystem(prompt.system, cache);\n if (systemResult.isFailure()) {\n return fail(systemResult.message);\n }\n const body: Record<string, unknown> = {\n model: config.model,\n system: systemResult.value,\n messages,\n // Anthropic's Messages API requires max_tokens on every request — see\n // AiAssist.DEFAULT_ANTHROPIC_MAX_TOKENS for why only this provider defaults it.\n max_tokens: maxTokens ?? DEFAULT_ANTHROPIC_MAX_TOKENS,\n stream: true\n };\n // Temperature is sent only when explicitly provided (Claude-5 rejects any temperature). When\n // thinking is active it is also rejected — the completion/streaming paths validate this upstream,\n // and the effort gate here is the safety net for the (unguarded) client-tool path.\n if (resolvedThinking?.anthropicEffort === undefined) {\n if (temperature !== undefined) {\n body.temperature = temperature;\n }\n }\n if (resolvedThinking?.anthropicEffort !== undefined) {\n if (useAdaptiveThinking) {\n // Claude 5 family: adaptive thinking — no budget_tokens; effort moves to the\n // top-level output_config block. See AiAssist.isAdaptiveThinkingModel.\n body.thinking = { type: 'adaptive' };\n body.output_config = { effort: resolvedThinking.anthropicEffort };\n } else {\n body.thinking = {\n type: 'enabled',\n budget_tokens: anthropicEffortToBudgetTokens(resolvedThinking.anthropicEffort)\n };\n }\n }\n if (resolvedThinking?.otherParams !== undefined) {\n Object.assign(body, resolvedThinking.otherParams);\n }\n if (tools && tools.length > 0) {\n body.tools = toAnthropicTools(tools);\n }\n const headers: Record<string, string> = anthropicAuthHeaders(config.apiKey);\n /* c8 ignore next 4 - optional logger diagnostic output */\n if (logger) {\n const toolTypes = tools && tools.length > 0 ? tools.map((t) => t.type).join(',') : 'none';\n logger.info(`Anthropic streaming: model=${config.model}, tools=${toolTypes}`);\n }\n const buffer = accumulationBuffer ?? new Map<number, IAccumulatedBlock>();\n const conn = await openSseConnection(url, headers, body, logger, signal);\n return conn.onSuccess((response) => succeed(translateAnthropicStream(response, buffer, logger)));\n}\n"]}
|
|
@@ -62,7 +62,7 @@ import { resolveEffectiveBaseUrl } from '../endpoint';
|
|
|
62
62
|
import { callAnthropicStream } from './anthropic';
|
|
63
63
|
import { callOpenAiResponsesStream } from './openaiResponses';
|
|
64
64
|
import { callGeminiStream } from './gemini';
|
|
65
|
-
import { supportsCacheUsageReporting } from '../streamUsageCapability';
|
|
65
|
+
import { supportsCacheUsageReporting, supportsPromptCacheBreakpoints, supportsPromptCacheRouting } from '../streamUsageCapability';
|
|
66
66
|
// ============================================================================
|
|
67
67
|
// Anthropic continuation builder
|
|
68
68
|
// ============================================================================
|
|
@@ -367,7 +367,7 @@ export function buildGeminiContinuation(calls, toolResults) {
|
|
|
367
367
|
* @public
|
|
368
368
|
*/
|
|
369
369
|
export function executeClientToolTurn(params) {
|
|
370
|
-
const { descriptor, apiKey, system, messages, continuationMessages, temperature, tools, clientTools, signal, logger, resolvedThinking, model, endpoint, onBeforeToolExecute, maxTokens, toolConflictPolicy } = params;
|
|
370
|
+
const { descriptor, apiKey, system, messages, continuationMessages, temperature, tools, clientTools, signal, logger, resolvedThinking, model, endpoint, onBeforeToolExecute, maxTokens, toolConflictPolicy, cache } = params;
|
|
371
371
|
const splitResult = splitChatRequest(system, messages);
|
|
372
372
|
if (splitResult.isFailure()) {
|
|
373
373
|
return fail(splitResult.message);
|
|
@@ -446,11 +446,22 @@ export function executeClientToolTurn(params) {
|
|
|
446
446
|
const streamPromise = (() => {
|
|
447
447
|
switch (descriptor.apiFormat) {
|
|
448
448
|
case 'anthropic':
|
|
449
|
-
return callAnthropicStream(config, prompt, head, temperature, effectiveTools, logger, signal, resolvedThinking, anthropicBuffer, continuationMessages, isAdaptiveThinkingModel(descriptor, config.model), maxTokens);
|
|
450
|
-
case 'openai':
|
|
449
|
+
return callAnthropicStream(config, prompt, head, temperature, effectiveTools, logger, signal, resolvedThinking, anthropicBuffer, continuationMessages, isAdaptiveThinkingModel(descriptor, config.model), maxTokens, cache);
|
|
450
|
+
case 'openai': {
|
|
451
|
+
// Same gating as callProviderCompletion's 'openai' case in completionClient.ts — see the
|
|
452
|
+
// comment there for why breakpoints and the routing key are gated independently. Client-tool
|
|
453
|
+
// turns always route OpenAI through the Responses API, which takes the routing key as a body
|
|
454
|
+
// field on every supporting provider, so there is no chatCompletionsHeader to thread here.
|
|
455
|
+
const routing = supportsPromptCacheRouting(descriptor);
|
|
456
|
+
const breakpoints = supportsPromptCacheBreakpoints(descriptor) ? cache === null || cache === void 0 ? void 0 : cache.systemBreakpoints : undefined;
|
|
457
|
+
const routedKey = routing !== undefined ? cache === null || cache === void 0 ? void 0 : cache.cacheKey : undefined;
|
|
458
|
+
const gatedCache = breakpoints !== undefined || routedKey !== undefined
|
|
459
|
+
? { systemBreakpoints: breakpoints, cacheKey: routedKey }
|
|
460
|
+
: undefined;
|
|
451
461
|
return callOpenAiResponsesStream(config, prompt,
|
|
452
462
|
/* c8 ignore next 1 - defensive: openai path requires tools; empty array fallback unreachable in practice */
|
|
453
|
-
effectiveTools !== null && effectiveTools !== void 0 ? effectiveTools : [], head, temperature, logger, signal, resolvedThinking, openAiCallMap, continuationMessages, maxTokens, supportsCacheUsageReporting(descriptor));
|
|
463
|
+
effectiveTools !== null && effectiveTools !== void 0 ? effectiveTools : [], head, temperature, logger, signal, resolvedThinking, openAiCallMap, continuationMessages, maxTokens, supportsCacheUsageReporting(descriptor), gatedCache);
|
|
464
|
+
}
|
|
454
465
|
case 'gemini':
|
|
455
466
|
return callGeminiStream(config, prompt, head, temperature, effectiveTools, logger, signal, resolvedThinking, geminiCalls, continuationMessages, maxTokens);
|
|
456
467
|
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
@@ -477,6 +488,7 @@ export function executeClientToolTurn(params) {
|
|
|
477
488
|
}
|
|
478
489
|
let truncated = false;
|
|
479
490
|
let fullText = '';
|
|
491
|
+
let usage;
|
|
480
492
|
let streamError;
|
|
481
493
|
try {
|
|
482
494
|
for (var _d = true, _e = __asyncValues(streamResult.value), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
|
|
@@ -486,6 +498,9 @@ export function executeClientToolTurn(params) {
|
|
|
486
498
|
if (event.type === 'done') {
|
|
487
499
|
truncated = event.truncated;
|
|
488
500
|
fullText = event.fullText;
|
|
501
|
+
// Absent when the provider reported nothing — carried through as absent
|
|
502
|
+
// rather than defaulted, so a caller can tell "not reported" from zero.
|
|
503
|
+
usage = event.usage;
|
|
489
504
|
yield yield __await(event);
|
|
490
505
|
continue;
|
|
491
506
|
}
|
|
@@ -666,7 +681,7 @@ export function executeClientToolTurn(params) {
|
|
|
666
681
|
return yield __await(void 0);
|
|
667
682
|
}
|
|
668
683
|
if (toolResults.length === 0) {
|
|
669
|
-
resolveNextTurn(succeed({ continuation: undefined, truncated, fullText, toolConflicts }));
|
|
684
|
+
resolveNextTurn(succeed({ continuation: undefined, truncated, fullText, toolConflicts, usage }));
|
|
670
685
|
return yield __await(void 0);
|
|
671
686
|
}
|
|
672
687
|
let continuationResult;
|
|
@@ -707,7 +722,7 @@ export function executeClientToolTurn(params) {
|
|
|
707
722
|
if (continuationMessages && continuationMessages.length > 0) {
|
|
708
723
|
continuation = Object.assign(Object.assign({}, continuation), { messages: [...continuationMessages, ...continuation.messages] });
|
|
709
724
|
}
|
|
710
|
-
resolveNextTurn(succeed({ continuation, truncated, fullText, toolConflicts }));
|
|
725
|
+
resolveNextTurn(succeed({ continuation, truncated, fullText, toolConflicts, usage }));
|
|
711
726
|
});
|
|
712
727
|
}
|
|
713
728
|
return succeed({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clientToolContinuationBuilder.js","sourceRoot":"","sources":["../../../../src/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Per-provider continuation message builders and the `executeClientToolTurn`\n * helper for orchestrating a single client-tool round-trip.\n *\n * Each provider requires a different wire format for the follow-up request:\n * - **Anthropic**: assistant turn reconstructed from the ordered accumulation\n * buffer (thinking / redacted_thinking / text / tool_use in original stream\n * order) + user turn with `tool_result` blocks. When thinking is active, the\n * follow-up request must NOT set `tool_choice: { type: 'any' }` or\n * `tool_choice: { type: 'tool', ... }` (E3 / §5.4 of b4-spike-findings).\n * - **OpenAI / xAI Responses API**: `function_call` input items +\n * `function_call_output` input items.\n * - **Gemini**: model turn with `functionCall` parts + user turn with\n * `functionResponse` parts (correlation by tool name).\n *\n * @packageDocumentation\n */\n\nimport { captureAsyncResult, fail, type Logging, Result, succeed } from '@fgv/ts-utils';\nimport { type JsonArray, type JsonObject } from '@fgv/ts-json-base';\n\nimport {\n type AiServerToolConfig,\n type AiToolConfig,\n type AiToolConflictPolicy,\n type IAiClientTool,\n type IAiClientToolContinuation,\n type IAiClientToolTurnResult,\n type IAiStreamEvent,\n type IChatRequest,\n type IAiProviderDescriptor,\n isAdaptiveThinkingModel,\n resolveProviderModel\n} from '../model';\nimport { resolveToolConflicts } from '../toolFormats';\nimport { type IResolvedThinkingConfig } from '../thinkingOptionsResolver';\nimport { splitChatRequest } from '../chatRequestBuilders';\nimport { resolveEffectiveBaseUrl } from '../endpoint';\nimport { type IAccumulatedBlock } from './anthropic';\nimport { type IAccumulatedFunctionCall } from './openaiResponses';\nimport { type IAccumulatedGeminiFunctionCall } from './gemini';\nimport { callAnthropicStream } from './anthropic';\nimport { callOpenAiResponsesStream } from './openaiResponses';\nimport { callGeminiStream } from './gemini';\nimport { type IStreamApiConfig } from './common';\nimport { supportsCacheUsageReporting } from '../streamUsageCapability';\n\n// ============================================================================\n// Tool-result accumulation (internal)\n// ============================================================================\n\n/**\n * Accumulated result for a single tool call, collected during stream iteration.\n * @internal\n */\ninterface IToolCallResult {\n readonly toolName: string;\n readonly callId?: string;\n readonly args: JsonObject;\n readonly result: string;\n readonly isError: boolean;\n}\n\n// ============================================================================\n// Anthropic continuation builder\n// ============================================================================\n\n/**\n * Returns `true` when `id` is a usable correlation id — present and non-empty.\n *\n * `??` is NOT sufficient for this check: an empty string is a *bad* id (a\n * `tool_use_id: ''` is rejected by Anthropic as a \"malformed identifier\") but\n * `'' ?? fallback` yields `''`, silently passing the empty id through. Every id\n * correlation in this module must use this predicate, never `??`.\n *\n * @internal\n */\nfunction isUsableId(id: string | undefined): id is string {\n return id !== undefined && id.length > 0;\n}\n\n/**\n * Builds the Anthropic follow-up messages for a client-tool round-trip.\n *\n * Reconstructs the assistant turn from the ordered accumulation buffer\n * (all block types in original stream order) and appends a user turn\n * with `tool_result` blocks for each executed tool call.\n *\n * **Single source of truth for the id (id-correlation fix).** Each\n * `tool_result.tool_use_id` is drawn from — and validated against — the set of\n * assistant `tool_use.id`s actually present in the accumulation buffer. The id\n * is NEVER derived from the tool name: a tool name can never match a `toolu_*`\n * id, so a name fallback produces exactly the \"malformed identifier\" the\n * provider rejects. If any tool result cannot be correlated to a buffered\n * `tool_use` block with a non-empty id, the build fails loud (naming the tool)\n * rather than emitting a malformed continuation.\n *\n * **Constraint (E3):** The returned continuation does NOT include a forced\n * `tool_choice` field. When thinking is active, Anthropic rejects\n * `tool_choice: { type: 'any' }` and `tool_choice: { type: 'tool', ... }`\n * with an HTTP 400 error. Only `tool_choice: { type: 'auto' }` (the default,\n * i.e. omitted) is compatible with extended thinking.\n *\n * @internal\n */\nexport function buildAnthropicContinuation(\n accBuffer: Map<number, IAccumulatedBlock>,\n toolResults: IToolCallResult[],\n logger?: Logging.ILogger\n): Result<IAiClientToolContinuation> {\n // Reconstruct the assistant turn from the ordered accumulation buffer.\n // Sort by buffer key (SSE index) to restore original stream order.\n const sortedKeys = Array.from(accBuffer.keys()).sort((a, b) => a - b);\n const assistantContent: JsonArray = [];\n // The set of assistant tool_use ids — the single source of truth every\n // tool_result.tool_use_id must be drawn from.\n const bufferedToolUseIds = new Set<string>();\n\n for (const key of sortedKeys) {\n const block = accBuffer.get(key);\n /* c8 ignore next 1 - defensive: key always exists in map since we iterate its keys */\n if (!block) continue;\n if (block.type === 'thinking') {\n assistantContent.push({\n type: 'thinking',\n thinking: block.thinking,\n signature: block.signature\n });\n } else if (block.type === 'redacted_thinking') {\n assistantContent.push({\n type: 'redacted_thinking',\n data: block.data\n });\n } else if (block.type === 'text') {\n if (block.text.length > 0) {\n assistantContent.push({ type: 'text', text: block.text });\n }\n } else if (block.type === 'tool_use') {\n // A buffered tool_use with an empty id can never be referenced by a valid\n // tool_result; emitting it would corrupt the assistant turn. Fail loud.\n if (!isUsableId(block.id)) {\n return fail(\n `Anthropic continuation: buffered tool_use block for tool '${block.name}' has an empty id; ` +\n `cannot build a valid continuation`\n );\n }\n let parsedInput: JsonObject;\n try {\n /* c8 ignore next 1 - defensive: argsBuffer is JSON-parsed in the adapter before emitting client-tool-call-done */\n parsedInput = JSON.parse(block.argsBuffer || '{}') as JsonObject;\n /* c8 ignore start - defensive: malformed argsBuffer defaults to empty object */\n } catch {\n parsedInput = {};\n }\n /* c8 ignore stop */\n bufferedToolUseIds.add(block.id);\n assistantContent.push({\n type: 'tool_use',\n id: block.id,\n name: block.name,\n input: parsedInput\n });\n }\n }\n\n // Build user turn with tool_result blocks for each tool call. Correlate each\n // result to a buffered tool_use id — the SAME id that keys the assistant\n // tool_use block — and fail loud on a missing / empty / mismatched id. A\n // missing callId is a bug to surface, not paper over with a name fallback.\n const userContent: JsonArray = [];\n for (const r of toolResults) {\n if (!isUsableId(r.callId)) {\n return fail(\n `Anthropic continuation: tool '${r.toolName}' result has no call id (missing or empty); ` +\n `cannot correlate it to an assistant tool_use block`\n );\n }\n if (!bufferedToolUseIds.has(r.callId)) {\n return fail(\n `Anthropic continuation: tool '${r.toolName}' call id '${r.callId}' does not match any ` +\n `buffered assistant tool_use block id`\n );\n }\n const block: JsonObject = {\n type: 'tool_result',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n tool_use_id: r.callId,\n content: r.result\n };\n userContent.push(r.isError ? { ...block, is_error: true } : block);\n }\n\n // Decisive diagnostic: the tool_use.id ↔ tool_result.tool_use_id pairing for\n // the outgoing continuation. A failing turn is field-confirmable by capturing\n // this line (the pairing is by construction matched here — divergence fails\n // loud above, before reaching this point).\n if (logger) {\n const pairing = toolResults.map((r) => `${r.toolName}:${r.callId}`).join(', ');\n logger.detail(`ai-assist:anthropic-continuation tool_use.id↔tool_result.tool_use_id [${pairing}]`);\n }\n\n const assistantMessage: JsonObject = {\n role: 'assistant',\n content: assistantContent\n };\n const userMessage: JsonObject = {\n role: 'user',\n content: userContent\n };\n\n return succeed({\n messages: [assistantMessage, userMessage],\n toolCallsSummary: toolResults.map((r) => ({\n toolName: r.toolName,\n callId: r.callId,\n args: r.args,\n result: r.result,\n isError: r.isError\n }))\n });\n}\n\n// ============================================================================\n// OpenAI / xAI Responses API continuation builder\n// ============================================================================\n\n/**\n * Builds the OpenAI / xAI Responses API follow-up input items for a\n * client-tool round-trip.\n *\n * Emits `function_call` items (the model's call) followed by\n * `function_call_output` items (the harness execution result), one pair\n * per executed tool call.\n *\n * **Single source of truth for the id (id-correlation fix).** Each\n * `function_call_output.call_id` is drawn from — and validated against — the\n * set of `function_call.call_id`s in the accumulation map. It is NEVER derived\n * from the tool name (the OpenAI parity of the Anthropic `tool_use_id` fix). A\n * missing / empty / unmatched call id fails the build loud rather than emitting\n * a continuation the provider would reject.\n *\n * @internal\n */\nexport function buildOpenAiContinuation(\n calls: Map<string, IAccumulatedFunctionCall>,\n toolResults: IToolCallResult[],\n logger?: Logging.ILogger\n): Result<IAiClientToolContinuation> {\n const items: JsonObject[] = [];\n\n // Emit function_call items for each call (model's side). Per the Responses API spec\n // (ResponseFunctionToolCall), `call_id` is the required correlation field — it must\n // match the matching function_call_output's `call_id` below. The optional `id` field\n // is the output-item id (`fc_*`) used to reference the streamed item; we omit it\n // because it is not load-bearing for input items.\n const bufferedCallIds = new Set<string>();\n for (const [callId, call] of calls) {\n bufferedCallIds.add(callId);\n items.push({\n type: 'function_call',\n call_id: callId,\n name: call.name,\n arguments: call.argsBuffer\n });\n }\n\n // Emit function_call_output items (harness execution results). Correlate each\n // to a buffered function_call call_id — never the tool name — and fail loud on\n // a missing / empty / mismatched id.\n for (const r of toolResults) {\n if (!isUsableId(r.callId)) {\n return fail(\n `OpenAI continuation: tool '${r.toolName}' result has no call id (missing or empty); ` +\n `cannot correlate it to a function_call item`\n );\n }\n if (!bufferedCallIds.has(r.callId)) {\n return fail(\n `OpenAI continuation: tool '${r.toolName}' call id '${r.callId}' does not match any ` +\n `accumulated function_call call_id`\n );\n }\n items.push({\n type: 'function_call_output',\n call_id: r.callId,\n output: r.result\n });\n }\n\n // Decisive diagnostic: the function_call.call_id ↔ function_call_output.call_id\n // pairing for the outgoing continuation (matched by construction here).\n if (logger) {\n const pairing = toolResults.map((r) => `${r.toolName}:${r.callId}`).join(', ');\n logger.detail(`ai-assist:openai-continuation function_call.call_id↔output.call_id [${pairing}]`);\n }\n\n return succeed({\n messages: items,\n toolCallsSummary: toolResults.map((r) => ({\n toolName: r.toolName,\n callId: r.callId,\n args: r.args,\n result: r.result,\n isError: r.isError\n }))\n });\n}\n\n// ============================================================================\n// Gemini continuation builder\n// ============================================================================\n\n/**\n * Builds the Gemini follow-up contents for a client-tool round-trip.\n *\n * Emits a model turn with `functionCall` parts (one per tool call) and a\n * user turn with `functionResponse` parts (correlation by tool name, since\n * Gemini does not assign call IDs).\n *\n * When thinking is enabled, Gemini stamps an opaque `thoughtSignature` on each\n * `functionCall` part and requires it echoed back, verbatim, as a sibling of\n * `functionCall` on the continuation's model turn — otherwise the follow-up is\n * rejected with \"Function call is missing a thought_signature in functionCall\n * parts\". The captured signature (see {@link IAccumulatedGeminiFunctionCall})\n * is replayed here only when present; the key is omitted entirely when thinking\n * was disabled. See https://ai.google.dev/gemini-api/docs/thought-signatures.\n *\n * @internal\n */\nexport function buildGeminiContinuation(\n calls: IAccumulatedGeminiFunctionCall[],\n toolResults: IToolCallResult[]\n): IAiClientToolContinuation {\n // Model turn: functionCall parts for each call. Replay the part-level\n // thoughtSignature as a sibling of functionCall only when present.\n const modelParts: JsonArray = calls.map(\n (call): JsonObject => ({\n functionCall: {\n name: call.name,\n args: call.args\n },\n ...(call.thoughtSignature !== undefined ? { thoughtSignature: call.thoughtSignature } : {})\n })\n );\n\n // User turn: functionResponse parts for each executed result.\n // Correlation is by name since Gemini has no call IDs.\n const userParts: JsonArray = toolResults.map(\n (r): JsonObject => ({\n functionResponse: {\n name: r.toolName,\n response: {\n content: r.result,\n ...(r.isError ? { error: true } : {})\n }\n }\n })\n );\n\n const modelMessage: JsonObject = {\n role: 'model',\n parts: modelParts\n };\n const userMessage: JsonObject = {\n role: 'user',\n parts: userParts\n };\n\n return {\n messages: [modelMessage, userMessage],\n toolCallsSummary: toolResults.map((r) => ({\n toolName: r.toolName,\n callId: r.callId,\n args: r.args,\n result: r.result,\n isError: r.isError\n }))\n };\n}\n\n// ============================================================================\n// executeClientToolTurn parameters\n// ============================================================================\n\n/**\n * Decision returned by an {@link IExecuteClientToolTurnParams.onBeforeToolExecute}\n * gate for a single client-tool call.\n *\n * @remarks\n * - `{ action: 'proceed' }` — run the tool's `execute` normally.\n * - `{ action: 'deny', reason }` — do NOT run `execute`; a synthesized tool-result\n * carrying `reason` is fed into the continuation exactly like a normal result so\n * the model can react, and a `client-tool-result` event is emitted for the call.\n * The turn continues.\n *\n * A gate that wants to signal a hard error (as opposed to a deliberate deny) should\n * return `Result.fail` (or reject) from the callback. Note this is NOT the same as a\n * `tool.execute` failure: an `execute` failure yields an `isError` tool-result and the\n * **turn continues**, whereas a gate `fail`/reject **terminates the turn** — it fails\n * `nextTurn` (and emits an inline `error` event) rather than synthesizing a deny.\n *\n * @public\n */\nexport type IToolExecutionDecision =\n | { readonly action: 'proceed' }\n | { readonly action: 'deny'; readonly reason: string };\n\n/**\n * Parameters for {@link AiAssist.executeClientToolTurn}.\n *\n * @remarks\n * Carries the unified {@link AiAssist.IChatRequest} shape (`system?` + ordered\n * `messages`): the last message is the current user turn and the preceding\n * messages are history, linearized before the current turn — identically to the\n * completion and streaming paths. {@link IExecuteClientToolTurnParams.continuationMessages}\n * remains a distinct post-current-turn axis (see below).\n *\n * @public\n */\nexport interface IExecuteClientToolTurnParams extends IChatRequest {\n /** The provider descriptor for routing (Anthropic / OpenAI / Gemini). */\n readonly descriptor: IAiProviderDescriptor;\n /** API key for authentication. */\n readonly apiKey: string;\n /**\n * The cumulative provider-native wire tail from the previous turn's\n * {@link AiAssist.IAiClientToolContinuation.messages}. Supply this as-is\n * each round — `messages` is already cumulative, so **replace** rather\n * than manually concatenate:\n *\n * ```ts\n * tail = outcome.continuation.messages; // replace — already cumulative\n * ```\n *\n * On the first turn this should be `undefined` (or omitted).\n *\n * Each provider applies its own shape guard to the supplied wire objects:\n * - Anthropic: projects each entry to `{ role, content }` (sufficient for\n * thinking blocks and `tool_result` arrays).\n * - OpenAI / xAI Responses: passes each item verbatim (`function_call` /\n * `function_call_output` items carry distinct fields per `type`); only\n * guards that each entry is a JSON object.\n * - Gemini: projects each entry to `{ role, parts }`.\n *\n * Entries that fail their provider's shape check are silently skipped.\n * Do NOT place these objects in the `messages` parameter — the\n * normalized-message path strips provider-native fields.\n */\n readonly continuationMessages?: ReadonlyArray<JsonObject>;\n /**\n * Sampling temperature. Sent to the provider only when explicitly provided; omitted otherwise\n * so the provider's own default applies (current-gen models reject a caller-supplied default).\n */\n readonly temperature?: number;\n /** Server-side tools to include. */\n readonly tools?: ReadonlyArray<AiServerToolConfig>;\n /** Client-defined tools available for the model to call. */\n readonly clientTools: ReadonlyArray<IAiClientTool>;\n /** Optional abort signal. */\n readonly signal?: AbortSignal;\n /**\n * Optional override of the descriptor's default base URL. Same semantics as\n * the non-streaming completion path and `callProviderCompletionStream`: a\n * well-formed `http`/`https` URL is substituted for `descriptor.baseUrl`\n * when composing the per-format request, with the per-format suffix appended\n * unchanged. Validated at the dispatcher; auth shape is unaffected. Use this\n * to point a client-tool turn at a local / LAN OpenAI-compatible server\n * (Ollama, LM Studio, llama.cpp).\n */\n readonly endpoint?: string;\n /** Optional logger for diagnostics. */\n readonly logger?: Logging.ILogger;\n /** Optional resolved thinking config (pre-resolved by the caller). */\n readonly resolvedThinking?: IResolvedThinkingConfig;\n /** Resolved model string (pre-resolved by the caller). When omitted, uses the descriptor's default model. */\n readonly model?: string;\n /**\n * Optional host gate invoked for each client-tool call **after** the model's raw\n * args have been validated against the tool's `parametersSchema` and **before**\n * `tool.execute(...)` runs. The full `tool` (including `tool.config.annotations`)\n * and the validated `args` are passed so gate logic can key off a tool's behavior\n * annotations (e.g. deny a `destructiveHint` call pending confirmation).\n *\n * Returning `{ action: 'proceed' }` (or omitting the callback) runs `execute`\n * normally. Returning `{ action: 'deny', reason }` skips `execute` and synthesizes\n * a denial tool-result carrying `reason` into the continuation (the model sees the\n * denial and can react); **the turn continues**. A callback that returns `Result.fail`\n * or rejects is a hard error that **terminates the turn** (fails `nextTurn` + emits an\n * inline `error` event) — distinct from a `tool.execute` failure, which continues the\n * turn with an `isError` result. A deny must therefore be explicit.\n */\n readonly onBeforeToolExecute?: (\n tool: IAiClientTool,\n args: unknown\n ) => Promise<Result<IToolExecutionDecision>>;\n /**\n * Optional cap on generated output tokens, mapped to each provider's native field:\n * Anthropic `max_tokens`, OpenAI/xAI Responses `max_output_tokens` (client-tool turns always\n * route OpenAI through the Responses API), Gemini `generationConfig.maxOutputTokens`. When\n * unset, every provider except Anthropic omits the field and applies its own default;\n * Anthropic's Messages API requires the field, so it falls back to\n * `DEFAULT_ANTHROPIC_MAX_TOKENS`.\n */\n readonly maxTokens?: number;\n /**\n * What to do when this provider declares one of the requested server tools\n * mutually exclusive with client tools (see\n * {@link AiAssist.IAiProviderDescriptor.serverToolsExclusiveWithClientTools}). Defaults to\n * `'drop-server-tools'` — the client tools this host registered for the turn are\n * kept and the server tool is dropped.\n *\n * @remarks\n * Whatever the policy, the turn result's `toolConflicts` says what actually\n * happened, so a degraded turn is never a silent one. Pass `'fail'` for the\n * pre-policy behavior: a `Result.fail` up front, before any wire call.\n */\n readonly toolConflictPolicy?: AiToolConflictPolicy;\n}\n\n/**\n * Return value of {@link AiAssist.executeClientToolTurn}.\n * @public\n */\nexport interface IExecuteClientToolTurnResult {\n /**\n * The unified-event iterable. Callers iterate this to drive the streaming UI.\n * The iterable forwards `text-delta`, `tool-event`, `client-tool-call-start`,\n * `client-tool-call-done`, and `client-tool-result` events through.\n */\n readonly events: AsyncIterable<IAiStreamEvent>;\n /**\n * Resolves when the stream terminates. On success, carries the\n * {@link AiAssist.IAiClientToolTurnResult} with the optional continuation for the\n * next round. On failure, carries the error message.\n */\n readonly nextTurn: Promise<Result<IAiClientToolTurnResult>>;\n}\n\n// ============================================================================\n// executeClientToolTurn\n// ============================================================================\n\n/**\n * Orchestrates a single client-tool streaming turn for any supported provider.\n *\n * Starts a streaming request, iterates the underlying provider stream, and:\n * - Forwards `text-delta`, `tool-event`, `client-tool-call-start`, and\n * `client-tool-call-done` events through to the consumer.\n * - For each `client-tool-call-done` event: validates the raw args against the\n * tool's `parametersSchema`, invokes `execute(typedArgs)`, and emits a\n * `client-tool-result` event.\n * - After stream completion: builds the per-provider continuation (or\n * `{ continuation: undefined }` when no tool calls occurred) and resolves\n * `nextTurn`.\n *\n * **Anthropic constraint (E3):** The continuation for Anthropic does not set\n * a forced `tool_choice`. Only `tool_choice: 'auto'` (the default, i.e.\n * omitted) is compatible with extended thinking.\n *\n * **Provider tool exclusions:** when the descriptor declares a server tool\n * mutually exclusive with client tools (today only Gemini, for `web_search`),\n * `toolConflictPolicy` decides — by default the server tool is dropped and the\n * turn proceeds. The turn result's `toolConflicts` always says what happened, so\n * a host can tell the person that e.g. web search was unavailable this turn.\n * Pass `'fail'` to refuse the request up front instead.\n *\n * @param params - Turn parameters\n * @returns `{ events, nextTurn }` — stream iterable + completion promise\n * @public\n */\nexport function executeClientToolTurn(\n params: IExecuteClientToolTurnParams\n): Result<IExecuteClientToolTurnResult> {\n const {\n descriptor,\n apiKey,\n system,\n messages,\n continuationMessages,\n temperature,\n tools,\n clientTools,\n signal,\n logger,\n resolvedThinking,\n model,\n endpoint,\n onBeforeToolExecute,\n maxTokens,\n toolConflictPolicy\n } = params;\n\n const splitResult = splitChatRequest(system, messages);\n if (splitResult.isFailure()) {\n return fail(splitResult.message);\n }\n const { prompt, head } = splitResult.value;\n if (prompt.attachments.length > 0 && !descriptor.acceptsImageInput) {\n return fail(`provider \"${descriptor.id}\" does not accept image input`);\n }\n\n // Apply whatever server-tool/client-tool exclusions this provider declares. The\n // rule itself lives on the descriptor, so nothing here branches on provider\n // identity; under the default policy an exclusive server tool is dropped and the\n // turn proceeds, where it used to be refused outright. `'fail'` reproduces that\n // refusal for hosts that would rather choose for themselves.\n const conflictResult = resolveToolConflicts(descriptor, tools, clientTools, toolConflictPolicy);\n if (conflictResult.isFailure()) {\n return fail(`executeClientToolTurn: ${conflictResult.message}`);\n }\n const {\n serverTools: resolvedServerTools,\n clientTools: resolvedClientTools,\n report: toolConflicts\n } = conflictResult.value;\n\n // Fail fast on duplicate names — silently overwriting would cause one tool to\n // shadow another with no observable signal.\n //\n // Scanned over the caller's ORIGINAL list, not the post-conflict survivors. A\n // duplicate name is a defect in the host's tool registration, not a property of\n // this turn; reporting it only on the turns that happen to keep both tools would\n // make a deterministic bug look intermittent — it would go quiet exactly when a\n // policy dropped the colliding pair and reappear on the next provider.\n const seen = new Set<string>();\n for (const tool of clientTools) {\n if (seen.has(tool.config.name)) {\n return fail(`executeClientToolTurn: duplicate client tool name '${tool.config.name}'`);\n }\n seen.add(tool.config.name);\n }\n\n // The dispatch map holds only the tools actually offered this turn, so a tool a\n // policy dropped is genuinely unavailable rather than merely unadvertised.\n const toolsByName = new Map<string, IAiClientTool>(\n resolvedClientTools.map((tool) => [tool.config.name, tool])\n );\n\n // Merge server tools and client tool configs into a single array for the provider.\n // This is the fix for P1-1: client tools were never sent to the provider because\n // the adapters only received `tools` (server tools). Both must coexist per design §2.5.\n //\n // With no client tools to merge, pass the caller's own `tools` through when the\n // resolution changed nothing, so a caller who sent `undefined` still sends\n // `undefined` — an absent `tools` field and an empty one are not the same request\n // on every provider.\n let effectiveTools: ReadonlyArray<AiToolConfig> | undefined;\n if (resolvedClientTools.length > 0) {\n effectiveTools = [...resolvedServerTools, ...resolvedClientTools.map((t) => t.config)];\n } else if (tools === undefined) {\n effectiveTools = undefined;\n } else {\n effectiveTools = resolvedServerTools;\n }\n\n const modelResult = resolveProviderModel(descriptor, model);\n if (modelResult.isFailure()) {\n return fail(modelResult.message);\n }\n const resolvedModel = modelResult.value;\n const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);\n if (baseUrlResult.isFailure()) {\n return fail(baseUrlResult.message);\n }\n const config: IStreamApiConfig = {\n baseUrl: baseUrlResult.value,\n apiKey,\n model: resolvedModel\n };\n\n // Accumulation buffers — populated by the adapter, read by the builder.\n const anthropicBuffer = new Map<number, IAccumulatedBlock>();\n const openAiCallMap = new Map<string, IAccumulatedFunctionCall>();\n const geminiCalls: IAccumulatedGeminiFunctionCall[] = [];\n\n // Collected tool results, populated as each client-tool-call-done is processed.\n const toolResults: IToolCallResult[] = [];\n\n // Stream start: open the underlying adapter stream.\n const streamPromise: Promise<Result<AsyncIterable<IAiStreamEvent>>> = (() => {\n switch (descriptor.apiFormat) {\n case 'anthropic':\n return callAnthropicStream(\n config,\n prompt,\n head,\n temperature,\n effectiveTools,\n logger,\n signal,\n resolvedThinking,\n anthropicBuffer,\n continuationMessages,\n isAdaptiveThinkingModel(descriptor, config.model),\n maxTokens\n );\n case 'openai':\n return callOpenAiResponsesStream(\n config,\n prompt,\n /* c8 ignore next 1 - defensive: openai path requires tools; empty array fallback unreachable in practice */\n effectiveTools ?? [],\n head,\n temperature,\n logger,\n signal,\n resolvedThinking,\n openAiCallMap,\n continuationMessages,\n maxTokens,\n supportsCacheUsageReporting(descriptor)\n );\n case 'gemini':\n return callGeminiStream(\n config,\n prompt,\n head,\n temperature,\n effectiveTools,\n logger,\n signal,\n resolvedThinking,\n geminiCalls,\n continuationMessages,\n maxTokens\n );\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = descriptor.apiFormat;\n return Promise.resolve(fail(`unsupported API format: ${String(_exhaustive)}`));\n }\n }\n })();\n\n // Resolve controls for `nextTurn`.\n let resolveNextTurn!: (result: Result<IAiClientToolTurnResult>) => void;\n const nextTurn = new Promise<Result<IAiClientToolTurnResult>>((resolve) => {\n resolveNextTurn = resolve;\n });\n\n // The unified-event generator: opens the stream, proxies events, executes tools.\n async function* eventGenerator(): AsyncGenerator<IAiStreamEvent> {\n const streamResult = await streamPromise;\n if (streamResult.isFailure()) {\n resolveNextTurn(fail(streamResult.message));\n yield { type: 'error', message: streamResult.message };\n return;\n }\n\n let truncated = false;\n let fullText = '';\n let streamError: string | undefined;\n\n for await (const event of streamResult.value) {\n if (event.type === 'done') {\n truncated = event.truncated;\n fullText = event.fullText;\n yield event;\n continue;\n }\n\n if (event.type === 'error') {\n streamError = event.message;\n yield event;\n continue;\n }\n\n if (event.type === 'text-delta') {\n yield event;\n continue;\n }\n\n if (event.type === 'tool-event') {\n yield event;\n continue;\n }\n\n if (event.type === 'client-tool-call-start') {\n yield event;\n continue;\n }\n\n if (event.type === 'client-tool-call-done') {\n yield event;\n\n const { toolName, callId, args } = event;\n const tool = toolsByName.get(toolName);\n\n if (!tool) {\n const errMsg = `model called unknown tool: ${toolName}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n // A model naming a tool the host never registered is a *model* error, and this\n // module's taxonomy (see IToolExecutionDecision's remarks) puts model errors on the\n // continue side: an arg-validation failure, an `execute` failure and a gate `deny`\n // all yield an isError tool-result and let the model react. Only host-machinery\n // errors — a gate `fail`/reject — terminate the turn. This branch used to terminate,\n // which cost a recoverable turn: a model that emits one bad tool name (for instance,\n // reading a prose trailer in the prompt as a tool) ended the stream instead of being\n // told and trying again.\n //\n // Safe on the wire: both continuation builders correlate results by call id and\n // explicitly never by tool name, so an unrecognized name cannot malform the\n // continuation — the id is the one the model just emitted.\n continue;\n }\n\n const validationResult = tool.config.parametersSchema.validate(args);\n if (validationResult.isFailure()) {\n const errMsg = `${toolName} (callId=${callId}): ${validationResult.message}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n\n // Host gate: run after arg-validation, before execute. A `deny` decision\n // synthesizes a denial tool-result and continues the turn; a `fail`/reject\n // from the gate itself is a hard error (mirrors an execute failure), never\n // a silent deny.\n if (onBeforeToolExecute !== undefined) {\n const decisionResult: Result<IToolExecutionDecision> = (\n await captureAsyncResult(async () => onBeforeToolExecute(tool, validationResult.value))\n ).onSuccess((decision) => decision);\n\n if (decisionResult.isFailure()) {\n const errMsg = `${toolName} (callId=${callId}): ${decisionResult.message}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n // Gate-fail is a hard, turn-terminating error (unlike a non-fatal `deny`, whose\n // generator continues). Emit an explicit `error` event so a consumer watching only\n // `events` sees the fatal failure inline and can distinguish it from a deny — matching\n // the stream-open / continuation hard-error paths.\n yield { type: 'error', message: errMsg };\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n resolveNextTurn(fail(errMsg));\n return;\n }\n\n if (decisionResult.value.action === 'deny') {\n const denialMsg = `${toolName} (callId=${callId}): tool execution denied: ${decisionResult.value.reason}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: denialMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: denialMsg, isError: true });\n continue;\n }\n }\n\n const executeResult = await captureAsyncResult(async () => tool.execute(validationResult.value));\n const executionResult: Result<unknown> = executeResult.isSuccess()\n ? executeResult.value\n : executeResult;\n\n if (executionResult.isFailure()) {\n const errMsg = `${toolName} (callId=${callId}): ${executionResult.message}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n\n // JSON.stringify can throw (circular references) or return undefined\n // (e.g. for a bare `undefined` value, or a value of type `function`).\n // Either outcome violates the client-tool-result event contract, so\n // emit an isError result with diagnostic context instead.\n let resultStr: string;\n try {\n const stringified = JSON.stringify(executionResult.value);\n if (stringified === undefined) {\n const errMsg = `${toolName} (callId=${callId}): tool returned a non-serializable value (JSON.stringify produced undefined)`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n resultStr = stringified;\n } catch (e) {\n const errMsg = `${toolName} (callId=${callId}): failed to serialize tool result: ${\n (e as Error).message\n }`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: resultStr,\n isError: false\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: resultStr, isError: false });\n continue;\n }\n\n // client-tool-result events are emitted by this layer, not the adapters — no passthrough needed.\n }\n\n // Stream has ended. Build the continuation.\n if (streamError !== undefined) {\n resolveNextTurn(fail(streamError));\n return;\n }\n\n if (toolResults.length === 0) {\n resolveNextTurn(succeed({ continuation: undefined, truncated, fullText, toolConflicts }));\n return;\n }\n\n let continuationResult: Result<IAiClientToolContinuation>;\n switch (descriptor.apiFormat) {\n case 'anthropic':\n continuationResult = buildAnthropicContinuation(anthropicBuffer, toolResults, logger);\n break;\n case 'openai':\n continuationResult = buildOpenAiContinuation(openAiCallMap, toolResults, logger);\n break;\n case 'gemini':\n // Gemini correlates by tool name by design (no call ids) — its builder\n // cannot mis-key and stays non-fallible.\n continuationResult = succeed(buildGeminiContinuation(geminiCalls, toolResults));\n break;\n /* c8 ignore next 5 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = descriptor.apiFormat;\n resolveNextTurn(fail(`unsupported API format: ${String(_exhaustive)}`));\n return;\n }\n }\n\n // A bad id-correlation fails loud here rather than emitting a malformed\n // continuation the provider would reject as a \"malformed identifier\". Mirror\n // the stream-open-failure path above: surface an `error` event so a consumer\n // iterating `events` sees the failure inline, not only via `nextTurn`.\n if (continuationResult.isFailure()) {\n resolveNextTurn(fail(continuationResult.message));\n yield { type: 'error', message: continuationResult.message };\n return;\n }\n let continuation = continuationResult.value;\n\n // Prepend inbound continuationMessages so the returned continuation is cumulative.\n // A consumer that does `tail = outcome.continuation.messages` (replace) is then\n // correct for all N rounds — messages always contains the full wire tail from\n // round 1 through the current round. toolCallsSummary stays per-round (this\n // round's calls only); messages is the accumulated tail to re-send.\n if (continuationMessages && continuationMessages.length > 0) {\n continuation = { ...continuation, messages: [...continuationMessages, ...continuation.messages] };\n }\n\n resolveNextTurn(succeed({ continuation, truncated, fullText, toolConflicts }));\n }\n\n return succeed({\n events: { [Symbol.asyncIterator]: () => eventGenerator() },\n nextTurn\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"clientToolContinuationBuilder.js","sourceRoot":"","sources":["../../../../src/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;;;;;;;;;;;;;;;;;;;;;AAEZ;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAwB,OAAO,EAAE,MAAM,eAAe,CAAC;AAIxF,OAAO,EAUL,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAItD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,0BAA0B,EAC3B,MAAM,0BAA0B,CAAC;AAkBlC,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,SAAS,UAAU,CAAC,EAAsB;IACxC,OAAO,EAAE,KAAK,SAAS,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,0BAA0B,CACxC,SAAyC,EACzC,WAA8B,EAC9B,MAAwB;IAExB,uEAAuE;IACvE,mEAAmE;IACnE,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACtE,MAAM,gBAAgB,GAAc,EAAE,CAAC;IACvC,uEAAuE;IACvE,8CAA8C;IAC9C,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;IAE7C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,sFAAsF;QACtF,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,gBAAgB,CAAC,IAAI,CAAC;gBACpB,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,SAAS,EAAE,KAAK,CAAC,SAAS;aAC3B,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC9C,gBAAgB,CAAC,IAAI,CAAC;gBACpB,IAAI,EAAE,mBAAmB;gBACzB,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACjC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACrC,0EAA0E;YAC1E,wEAAwE;YACxE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC1B,OAAO,IAAI,CACT,6DAA6D,KAAK,CAAC,IAAI,qBAAqB;oBAC1F,mCAAmC,CACtC,CAAC;YACJ,CAAC;YACD,IAAI,WAAuB,CAAC;YAC5B,IAAI,CAAC;gBACH,kHAAkH;gBAClH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAe,CAAC;gBACjE,gFAAgF;YAClF,CAAC;YAAC,WAAM,CAAC;gBACP,WAAW,GAAG,EAAE,CAAC;YACnB,CAAC;YACD,oBAAoB;YACpB,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACjC,gBAAgB,CAAC,IAAI,CAAC;gBACpB,IAAI,EAAE,UAAU;gBAChB,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,KAAK,EAAE,WAAW;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,yEAAyE;IACzE,yEAAyE;IACzE,2EAA2E;IAC3E,MAAM,WAAW,GAAc,EAAE,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CACT,iCAAiC,CAAC,CAAC,QAAQ,8CAA8C;gBACvF,oDAAoD,CACvD,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACtC,OAAO,IAAI,CACT,iCAAiC,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,MAAM,uBAAuB;gBACtF,sCAAsC,CACzC,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAe;YACxB,IAAI,EAAE,aAAa;YACnB,gEAAgE;YAChE,WAAW,EAAE,CAAC,CAAC,MAAM;YACrB,OAAO,EAAE,CAAC,CAAC,MAAM;SAClB,CAAC;QACF,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,iCAAM,KAAK,KAAE,QAAQ,EAAE,IAAI,IAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACrE,CAAC;IAED,6EAA6E;IAC7E,8EAA8E;IAC9E,4EAA4E;IAC5E,2CAA2C;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,CAAC,MAAM,CAAC,yEAAyE,OAAO,GAAG,CAAC,CAAC;IACrG,CAAC;IAED,MAAM,gBAAgB,GAAe;QACnC,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,gBAAgB;KAC1B,CAAC;IACF,MAAM,WAAW,GAAe;QAC9B,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,WAAW;KACrB,CAAC;IAEF,OAAO,OAAO,CAAC;QACb,QAAQ,EAAE,CAAC,gBAAgB,EAAE,WAAW,CAAC;QACzC,gBAAgB,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB,CAAC,CAAC;KACJ,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,kDAAkD;AAClD,+EAA+E;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAA4C,EAC5C,WAA8B,EAC9B,MAAwB;IAExB,MAAM,KAAK,GAAiB,EAAE,CAAC;IAE/B,oFAAoF;IACpF,oFAAoF;IACpF,qFAAqF;IACrF,iFAAiF;IACjF,kDAAkD;IAClD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;QACnC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,MAAM;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,UAAU;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAC9E,+EAA+E;IAC/E,qCAAqC;IACrC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,IAAI,CACT,8BAA8B,CAAC,CAAC,QAAQ,8CAA8C;gBACpF,6CAA6C,CAChD,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACnC,OAAO,IAAI,CACT,8BAA8B,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,MAAM,uBAAuB;gBACnF,mCAAmC,CACtC,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,sBAAsB;YAC5B,OAAO,EAAE,CAAC,CAAC,MAAM;YACjB,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAED,gFAAgF;IAChF,wEAAwE;IACxE,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,MAAM,CAAC,MAAM,CAAC,uEAAuE,OAAO,GAAG,CAAC,CAAC;IACnG,CAAC;IAED,OAAO,OAAO,CAAC;QACb,QAAQ,EAAE,KAAK;QACf,gBAAgB,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB,CAAC,CAAC;KACJ,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,8BAA8B;AAC9B,+EAA+E;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAuC,EACvC,WAA8B;IAE9B,sEAAsE;IACtE,mEAAmE;IACnE,MAAM,UAAU,GAAc,KAAK,CAAC,GAAG,CACrC,CAAC,IAAI,EAAc,EAAE,CAAC,iBACpB,YAAY,EAAE;YACZ,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,IACE,CAAC,IAAI,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAC3F,CACH,CAAC;IAEF,8DAA8D;IAC9D,uDAAuD;IACvD,MAAM,SAAS,GAAc,WAAW,CAAC,GAAG,CAC1C,CAAC,CAAC,EAAc,EAAE,CAAC,CAAC;QAClB,gBAAgB,EAAE;YAChB,IAAI,EAAE,CAAC,CAAC,QAAQ;YAChB,QAAQ,kBACN,OAAO,EAAE,CAAC,CAAC,MAAM,IACd,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACtC;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,YAAY,GAAe;QAC/B,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,UAAU;KAClB,CAAC;IACF,MAAM,WAAW,GAAe;QAC9B,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,SAAS;KACjB,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;QACrC,gBAAgB,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACxC,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAkMD,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAoC;IAEpC,MAAM,EACJ,UAAU,EACV,MAAM,EACN,MAAM,EACN,QAAQ,EACR,oBAAoB,EACpB,WAAW,EACX,KAAK,EACL,WAAW,EACX,MAAM,EACN,MAAM,EACN,gBAAgB,EAChB,KAAK,EACL,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,kBAAkB,EAClB,KAAK,EACN,GAAG,MAAM,CAAC;IAEX,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC;IAC3C,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC;QACnE,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,+BAA+B,CAAC,CAAC;IACzE,CAAC;IAED,gFAAgF;IAChF,4EAA4E;IAC5E,iFAAiF;IACjF,gFAAgF;IAChF,6DAA6D;IAC7D,MAAM,cAAc,GAAG,oBAAoB,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;IAChG,IAAI,cAAc,CAAC,SAAS,EAAE,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,0BAA0B,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,EACJ,WAAW,EAAE,mBAAmB,EAChC,WAAW,EAAE,mBAAmB,EAChC,MAAM,EAAE,aAAa,EACtB,GAAG,cAAc,CAAC,KAAK,CAAC;IAEzB,8EAA8E;IAC9E,4CAA4C;IAC5C,EAAE;IACF,8EAA8E;IAC9E,gFAAgF;IAChF,iFAAiF;IACjF,gFAAgF;IAChF,uEAAuE;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,sDAAsD,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,gFAAgF;IAChF,2EAA2E;IAC3E,MAAM,WAAW,GAAG,IAAI,GAAG,CACzB,mBAAmB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAC5D,CAAC;IAEF,mFAAmF;IACnF,iFAAiF;IACjF,wFAAwF;IACxF,EAAE;IACF,gFAAgF;IAChF,2EAA2E;IAC3E,kFAAkF;IAClF,qBAAqB;IACrB,IAAI,cAAuD,CAAC;IAC5D,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,cAAc,GAAG,CAAC,GAAG,mBAAmB,EAAE,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACzF,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,cAAc,GAAG,SAAS,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,cAAc,GAAG,mBAAmB,CAAC;IACvC,CAAC;IAED,MAAM,WAAW,GAAG,oBAAoB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC5D,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC;IACxC,MAAM,aAAa,GAAG,uBAAuB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACpE,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,MAAM,GAAqB;QAC/B,OAAO,EAAE,aAAa,CAAC,KAAK;QAC5B,MAAM;QACN,KAAK,EAAE,aAAa;KACrB,CAAC;IAEF,wEAAwE;IACxE,MAAM,eAAe,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC7D,MAAM,aAAa,GAAG,IAAI,GAAG,EAAoC,CAAC;IAClE,MAAM,WAAW,GAAqC,EAAE,CAAC;IAEzD,gFAAgF;IAChF,MAAM,WAAW,GAAsB,EAAE,CAAC;IAE1C,oDAAoD;IACpD,MAAM,aAAa,GAAmD,CAAC,GAAG,EAAE;QAC1E,QAAQ,UAAU,CAAC,SAAS,EAAE,CAAC;YAC7B,KAAK,WAAW;gBACd,OAAO,mBAAmB,CACxB,MAAM,EACN,MAAM,EACN,IAAI,EACJ,WAAW,EACX,cAAc,EACd,MAAM,EACN,MAAM,EACN,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,uBAAuB,CAAC,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,EACjD,SAAS,EACT,KAAK,CACN,CAAC;YACJ,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,yFAAyF;gBACzF,6FAA6F;gBAC7F,6FAA6F;gBAC7F,2FAA2F;gBAC3F,MAAM,OAAO,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;gBACvD,MAAM,WAAW,GAAG,8BAA8B,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC;gBACtG,MAAM,SAAS,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;gBACtE,MAAM,UAAU,GACd,WAAW,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS;oBAClD,CAAC,CAAC,EAAE,iBAAiB,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE;oBACzD,CAAC,CAAC,SAAS,CAAC;gBAChB,OAAO,yBAAyB,CAC9B,MAAM,EACN,MAAM;gBACN,4GAA4G;gBAC5G,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,EAAE,EACpB,IAAI,EACJ,WAAW,EACX,MAAM,EACN,MAAM,EACN,gBAAgB,EAChB,aAAa,EACb,oBAAoB,EACpB,SAAS,EACT,2BAA2B,CAAC,UAAU,CAAC,EACvC,UAAU,CACX,CAAC;YACJ,CAAC;YACD,KAAK,QAAQ;gBACX,OAAO,gBAAgB,CACrB,MAAM,EACN,MAAM,EACN,IAAI,EACJ,WAAW,EACX,cAAc,EACd,MAAM,EACN,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,oBAAoB,EACpB,SAAS,CACV,CAAC;YACJ,qFAAqF;YACrF,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,WAAW,GAAU,UAAU,CAAC,SAAS,CAAC;gBAChD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,mCAAmC;IACnC,IAAI,eAAmE,CAAC;IACxE,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAkC,CAAC,OAAO,EAAE,EAAE;QACxE,eAAe,GAAG,OAAO,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,iFAAiF;IACjF,SAAgB,cAAc;;;YAC5B,MAAM,YAAY,GAAG,cAAM,aAAa,CAAA,CAAC;YACzC,IAAI,YAAY,CAAC,SAAS,EAAE,EAAE,CAAC;gBAC7B,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC5C,oBAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,CAAA,CAAC;gBACvD,6BAAO;YACT,CAAC;YAED,IAAI,SAAS,GAAG,KAAK,CAAC;YACtB,IAAI,QAAQ,GAAG,EAAE,CAAC;YAClB,IAAI,KAAqC,CAAC;YAC1C,IAAI,WAA+B,CAAC;;gBAEpC,KAA0B,eAAA,KAAA,cAAA,YAAY,CAAC,KAAK,CAAA,IAAA,+DAAE,CAAC;oBAArB,cAAkB;oBAAlB,WAAkB;oBAAjC,MAAM,KAAK,KAAA,CAAA;oBACpB,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;wBAC1B,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;wBAC5B,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;wBAC1B,wEAAwE;wBACxE,wEAAwE;wBACxE,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;wBACpB,oBAAM,KAAK,CAAA,CAAC;wBACZ,SAAS;oBACX,CAAC;oBAED,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;wBAC3B,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC;wBAC5B,oBAAM,KAAK,CAAA,CAAC;wBACZ,SAAS;oBACX,CAAC;oBAED,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBAChC,oBAAM,KAAK,CAAA,CAAC;wBACZ,SAAS;oBACX,CAAC;oBAED,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBAChC,oBAAM,KAAK,CAAA,CAAC;wBACZ,SAAS;oBACX,CAAC;oBAED,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;wBAC5C,oBAAM,KAAK,CAAA,CAAC;wBACZ,SAAS;oBACX,CAAC;oBAED,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;wBAC3C,oBAAM,KAAK,CAAA,CAAC;wBAEZ,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;wBACzC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;wBAEvC,IAAI,CAAC,IAAI,EAAE,CAAC;4BACV,MAAM,MAAM,GAAG,8BAA8B,QAAQ,EAAE,CAAC;4BACxD,MAAM,WAAW,GAAmB;gCAClC,IAAI,EAAE,oBAAoB;gCAC1B,QAAQ;gCACR,MAAM;gCACN,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,IAAI;6BACd,CAAC;4BACF,oBAAM,WAAW,CAAA,CAAC;4BAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;4BAC5E,+EAA+E;4BAC/E,oFAAoF;4BACpF,mFAAmF;4BACnF,gFAAgF;4BAChF,qFAAqF;4BACrF,qFAAqF;4BACrF,qFAAqF;4BACrF,yBAAyB;4BACzB,EAAE;4BACF,gFAAgF;4BAChF,4EAA4E;4BAC5E,2DAA2D;4BAC3D,SAAS;wBACX,CAAC;wBAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;wBACrE,IAAI,gBAAgB,CAAC,SAAS,EAAE,EAAE,CAAC;4BACjC,MAAM,MAAM,GAAG,GAAG,QAAQ,YAAY,MAAM,MAAM,gBAAgB,CAAC,OAAO,EAAE,CAAC;4BAC7E,MAAM,WAAW,GAAmB;gCAClC,IAAI,EAAE,oBAAoB;gCAC1B,QAAQ;gCACR,MAAM;gCACN,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,IAAI;6BACd,CAAC;4BACF,oBAAM,WAAW,CAAA,CAAC;4BAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;4BAC5E,SAAS;wBACX,CAAC;wBAED,yEAAyE;wBACzE,2EAA2E;wBAC3E,2EAA2E;wBAC3E,iBAAiB;wBACjB,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;4BACtC,MAAM,cAAc,GAAmC,CACrD,cAAM,kBAAkB,CAAC,KAAK,IAAI,EAAE,CAAC,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA,CACxF,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC;4BAEpC,IAAI,cAAc,CAAC,SAAS,EAAE,EAAE,CAAC;gCAC/B,MAAM,MAAM,GAAG,GAAG,QAAQ,YAAY,MAAM,MAAM,cAAc,CAAC,OAAO,EAAE,CAAC;gCAC3E,MAAM,WAAW,GAAmB;oCAClC,IAAI,EAAE,oBAAoB;oCAC1B,QAAQ;oCACR,MAAM;oCACN,MAAM,EAAE,MAAM;oCACd,OAAO,EAAE,IAAI;iCACd,CAAC;gCACF,oBAAM,WAAW,CAAA,CAAC;gCAClB,gFAAgF;gCAChF,mFAAmF;gCACnF,uFAAuF;gCACvF,mDAAmD;gCACnD,oBAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA,CAAC;gCACzC,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gCAC5E,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;gCAC9B,6BAAO;4BACT,CAAC;4BAED,IAAI,cAAc,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gCAC3C,MAAM,SAAS,GAAG,GAAG,QAAQ,YAAY,MAAM,6BAA6B,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;gCAC1G,MAAM,WAAW,GAAmB;oCAClC,IAAI,EAAE,oBAAoB;oCAC1B,QAAQ;oCACR,MAAM;oCACN,MAAM,EAAE,SAAS;oCACjB,OAAO,EAAE,IAAI;iCACd,CAAC;gCACF,oBAAM,WAAW,CAAA,CAAC;gCAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gCAC/E,SAAS;4BACX,CAAC;wBACH,CAAC;wBAED,MAAM,aAAa,GAAG,cAAM,kBAAkB,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA,CAAC;wBACjG,MAAM,eAAe,GAAoB,aAAa,CAAC,SAAS,EAAE;4BAChE,CAAC,CAAC,aAAa,CAAC,KAAK;4BACrB,CAAC,CAAC,aAAa,CAAC;wBAElB,IAAI,eAAe,CAAC,SAAS,EAAE,EAAE,CAAC;4BAChC,MAAM,MAAM,GAAG,GAAG,QAAQ,YAAY,MAAM,MAAM,eAAe,CAAC,OAAO,EAAE,CAAC;4BAC5E,MAAM,WAAW,GAAmB;gCAClC,IAAI,EAAE,oBAAoB;gCAC1B,QAAQ;gCACR,MAAM;gCACN,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,IAAI;6BACd,CAAC;4BACF,oBAAM,WAAW,CAAA,CAAC;4BAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;4BAC5E,SAAS;wBACX,CAAC;wBAED,qEAAqE;wBACrE,sEAAsE;wBACtE,oEAAoE;wBACpE,0DAA0D;wBAC1D,IAAI,SAAiB,CAAC;wBACtB,IAAI,CAAC;4BACH,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;4BAC1D,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gCAC9B,MAAM,MAAM,GAAG,GAAG,QAAQ,YAAY,MAAM,+EAA+E,CAAC;gCAC5H,MAAM,WAAW,GAAmB;oCAClC,IAAI,EAAE,oBAAoB;oCAC1B,QAAQ;oCACR,MAAM;oCACN,MAAM,EAAE,MAAM;oCACd,OAAO,EAAE,IAAI;iCACd,CAAC;gCACF,oBAAM,WAAW,CAAA,CAAC;gCAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gCAC5E,SAAS;4BACX,CAAC;4BACD,SAAS,GAAG,WAAW,CAAC;wBAC1B,CAAC;wBAAC,OAAO,CAAC,EAAE,CAAC;4BACX,MAAM,MAAM,GAAG,GAAG,QAAQ,YAAY,MAAM,uCACzC,CAAW,CAAC,OACf,EAAE,CAAC;4BACH,MAAM,WAAW,GAAmB;gCAClC,IAAI,EAAE,oBAAoB;gCAC1B,QAAQ;gCACR,MAAM;gCACN,MAAM,EAAE,MAAM;gCACd,OAAO,EAAE,IAAI;6BACd,CAAC;4BACF,oBAAM,WAAW,CAAA,CAAC;4BAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;4BAC5E,SAAS;wBACX,CAAC;wBACD,MAAM,WAAW,GAAmB;4BAClC,IAAI,EAAE,oBAAoB;4BAC1B,QAAQ;4BACR,MAAM;4BACN,MAAM,EAAE,SAAS;4BACjB,OAAO,EAAE,KAAK;yBACf,CAAC;wBACF,oBAAM,WAAW,CAAA,CAAC;wBAClB,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;wBAChF,SAAS;oBACX,CAAC;gBAGH,CAAC;;;;;;;;;YAED,4CAA4C;YAC5C,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;gBACnC,6BAAO;YACT,CAAC;YAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC7B,eAAe,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;gBACjG,6BAAO;YACT,CAAC;YAED,IAAI,kBAAqD,CAAC;YAC1D,QAAQ,UAAU,CAAC,SAAS,EAAE,CAAC;gBAC7B,KAAK,WAAW;oBACd,kBAAkB,GAAG,0BAA0B,CAAC,eAAe,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;oBACtF,MAAM;gBACR,KAAK,QAAQ;oBACX,kBAAkB,GAAG,uBAAuB,CAAC,aAAa,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;oBACjF,MAAM;gBACR,KAAK,QAAQ;oBACX,uEAAuE;oBACvE,yCAAyC;oBACzC,kBAAkB,GAAG,OAAO,CAAC,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;oBAChF,MAAM;gBACR,qFAAqF;gBACrF,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,WAAW,GAAU,UAAU,CAAC,SAAS,CAAC;oBAChD,eAAe,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;oBACxE,6BAAO;gBACT,CAAC;YACH,CAAC;YAED,wEAAwE;YACxE,6EAA6E;YAC7E,6EAA6E;YAC7E,uEAAuE;YACvE,IAAI,kBAAkB,CAAC,SAAS,EAAE,EAAE,CAAC;gBACnC,eAAe,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;gBAClD,oBAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,CAAC,OAAO,EAAE,CAAA,CAAC;gBAC7D,6BAAO;YACT,CAAC;YACD,IAAI,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC;YAE5C,mFAAmF;YACnF,gFAAgF;YAChF,8EAA8E;YAC9E,4EAA4E;YAC5E,oEAAoE;YACpE,IAAI,oBAAoB,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5D,YAAY,mCAAQ,YAAY,KAAE,QAAQ,EAAE,CAAC,GAAG,oBAAoB,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAE,CAAC;YACpG,CAAC;YAED,eAAe,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;KAAA;IAED,OAAO,OAAO,CAAC;QACb,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,CAAC,cAAc,EAAE,EAAE;QAC1D,QAAQ;KACT,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Per-provider continuation message builders and the `executeClientToolTurn`\n * helper for orchestrating a single client-tool round-trip.\n *\n * Each provider requires a different wire format for the follow-up request:\n * - **Anthropic**: assistant turn reconstructed from the ordered accumulation\n * buffer (thinking / redacted_thinking / text / tool_use in original stream\n * order) + user turn with `tool_result` blocks. When thinking is active, the\n * follow-up request must NOT set `tool_choice: { type: 'any' }` or\n * `tool_choice: { type: 'tool', ... }` (E3 / §5.4 of b4-spike-findings).\n * - **OpenAI / xAI Responses API**: `function_call` input items +\n * `function_call_output` input items.\n * - **Gemini**: model turn with `functionCall` parts + user turn with\n * `functionResponse` parts (correlation by tool name).\n *\n * @packageDocumentation\n */\n\nimport { captureAsyncResult, fail, type Logging, Result, succeed } from '@fgv/ts-utils';\nimport { type JsonArray, type JsonObject } from '@fgv/ts-json-base';\n\nimport { type IAiCacheRequest } from '../cacheRequest';\nimport {\n type AiServerToolConfig,\n type AiToolConfig,\n type AiToolConflictPolicy,\n type IAiClientTool,\n type IAiClientToolContinuation,\n type IAiClientToolTurnResult,\n type IAiStreamEvent,\n type IChatRequest,\n type IAiProviderDescriptor,\n isAdaptiveThinkingModel,\n resolveProviderModel\n} from '../model';\nimport { resolveToolConflicts } from '../toolFormats';\nimport type { IAiCompletionUsage } from '../usageTypes';\nimport { type IResolvedThinkingConfig } from '../thinkingOptionsResolver';\nimport { splitChatRequest } from '../chatRequestBuilders';\nimport { resolveEffectiveBaseUrl } from '../endpoint';\nimport { type IAccumulatedBlock } from './anthropic';\nimport { type IAccumulatedFunctionCall } from './openaiResponses';\nimport { type IAccumulatedGeminiFunctionCall } from './gemini';\nimport { callAnthropicStream } from './anthropic';\nimport { callOpenAiResponsesStream } from './openaiResponses';\nimport { callGeminiStream } from './gemini';\nimport { type IStreamApiConfig } from './common';\nimport {\n supportsCacheUsageReporting,\n supportsPromptCacheBreakpoints,\n supportsPromptCacheRouting\n} from '../streamUsageCapability';\n\n// ============================================================================\n// Tool-result accumulation (internal)\n// ============================================================================\n\n/**\n * Accumulated result for a single tool call, collected during stream iteration.\n * @internal\n */\ninterface IToolCallResult {\n readonly toolName: string;\n readonly callId?: string;\n readonly args: JsonObject;\n readonly result: string;\n readonly isError: boolean;\n}\n\n// ============================================================================\n// Anthropic continuation builder\n// ============================================================================\n\n/**\n * Returns `true` when `id` is a usable correlation id — present and non-empty.\n *\n * `??` is NOT sufficient for this check: an empty string is a *bad* id (a\n * `tool_use_id: ''` is rejected by Anthropic as a \"malformed identifier\") but\n * `'' ?? fallback` yields `''`, silently passing the empty id through. Every id\n * correlation in this module must use this predicate, never `??`.\n *\n * @internal\n */\nfunction isUsableId(id: string | undefined): id is string {\n return id !== undefined && id.length > 0;\n}\n\n/**\n * Builds the Anthropic follow-up messages for a client-tool round-trip.\n *\n * Reconstructs the assistant turn from the ordered accumulation buffer\n * (all block types in original stream order) and appends a user turn\n * with `tool_result` blocks for each executed tool call.\n *\n * **Single source of truth for the id (id-correlation fix).** Each\n * `tool_result.tool_use_id` is drawn from — and validated against — the set of\n * assistant `tool_use.id`s actually present in the accumulation buffer. The id\n * is NEVER derived from the tool name: a tool name can never match a `toolu_*`\n * id, so a name fallback produces exactly the \"malformed identifier\" the\n * provider rejects. If any tool result cannot be correlated to a buffered\n * `tool_use` block with a non-empty id, the build fails loud (naming the tool)\n * rather than emitting a malformed continuation.\n *\n * **Constraint (E3):** The returned continuation does NOT include a forced\n * `tool_choice` field. When thinking is active, Anthropic rejects\n * `tool_choice: { type: 'any' }` and `tool_choice: { type: 'tool', ... }`\n * with an HTTP 400 error. Only `tool_choice: { type: 'auto' }` (the default,\n * i.e. omitted) is compatible with extended thinking.\n *\n * @internal\n */\nexport function buildAnthropicContinuation(\n accBuffer: Map<number, IAccumulatedBlock>,\n toolResults: IToolCallResult[],\n logger?: Logging.ILogger\n): Result<IAiClientToolContinuation> {\n // Reconstruct the assistant turn from the ordered accumulation buffer.\n // Sort by buffer key (SSE index) to restore original stream order.\n const sortedKeys = Array.from(accBuffer.keys()).sort((a, b) => a - b);\n const assistantContent: JsonArray = [];\n // The set of assistant tool_use ids — the single source of truth every\n // tool_result.tool_use_id must be drawn from.\n const bufferedToolUseIds = new Set<string>();\n\n for (const key of sortedKeys) {\n const block = accBuffer.get(key);\n /* c8 ignore next 1 - defensive: key always exists in map since we iterate its keys */\n if (!block) continue;\n if (block.type === 'thinking') {\n assistantContent.push({\n type: 'thinking',\n thinking: block.thinking,\n signature: block.signature\n });\n } else if (block.type === 'redacted_thinking') {\n assistantContent.push({\n type: 'redacted_thinking',\n data: block.data\n });\n } else if (block.type === 'text') {\n if (block.text.length > 0) {\n assistantContent.push({ type: 'text', text: block.text });\n }\n } else if (block.type === 'tool_use') {\n // A buffered tool_use with an empty id can never be referenced by a valid\n // tool_result; emitting it would corrupt the assistant turn. Fail loud.\n if (!isUsableId(block.id)) {\n return fail(\n `Anthropic continuation: buffered tool_use block for tool '${block.name}' has an empty id; ` +\n `cannot build a valid continuation`\n );\n }\n let parsedInput: JsonObject;\n try {\n /* c8 ignore next 1 - defensive: argsBuffer is JSON-parsed in the adapter before emitting client-tool-call-done */\n parsedInput = JSON.parse(block.argsBuffer || '{}') as JsonObject;\n /* c8 ignore start - defensive: malformed argsBuffer defaults to empty object */\n } catch {\n parsedInput = {};\n }\n /* c8 ignore stop */\n bufferedToolUseIds.add(block.id);\n assistantContent.push({\n type: 'tool_use',\n id: block.id,\n name: block.name,\n input: parsedInput\n });\n }\n }\n\n // Build user turn with tool_result blocks for each tool call. Correlate each\n // result to a buffered tool_use id — the SAME id that keys the assistant\n // tool_use block — and fail loud on a missing / empty / mismatched id. A\n // missing callId is a bug to surface, not paper over with a name fallback.\n const userContent: JsonArray = [];\n for (const r of toolResults) {\n if (!isUsableId(r.callId)) {\n return fail(\n `Anthropic continuation: tool '${r.toolName}' result has no call id (missing or empty); ` +\n `cannot correlate it to an assistant tool_use block`\n );\n }\n if (!bufferedToolUseIds.has(r.callId)) {\n return fail(\n `Anthropic continuation: tool '${r.toolName}' call id '${r.callId}' does not match any ` +\n `buffered assistant tool_use block id`\n );\n }\n const block: JsonObject = {\n type: 'tool_result',\n // eslint-disable-next-line @typescript-eslint/naming-convention\n tool_use_id: r.callId,\n content: r.result\n };\n userContent.push(r.isError ? { ...block, is_error: true } : block);\n }\n\n // Decisive diagnostic: the tool_use.id ↔ tool_result.tool_use_id pairing for\n // the outgoing continuation. A failing turn is field-confirmable by capturing\n // this line (the pairing is by construction matched here — divergence fails\n // loud above, before reaching this point).\n if (logger) {\n const pairing = toolResults.map((r) => `${r.toolName}:${r.callId}`).join(', ');\n logger.detail(`ai-assist:anthropic-continuation tool_use.id↔tool_result.tool_use_id [${pairing}]`);\n }\n\n const assistantMessage: JsonObject = {\n role: 'assistant',\n content: assistantContent\n };\n const userMessage: JsonObject = {\n role: 'user',\n content: userContent\n };\n\n return succeed({\n messages: [assistantMessage, userMessage],\n toolCallsSummary: toolResults.map((r) => ({\n toolName: r.toolName,\n callId: r.callId,\n args: r.args,\n result: r.result,\n isError: r.isError\n }))\n });\n}\n\n// ============================================================================\n// OpenAI / xAI Responses API continuation builder\n// ============================================================================\n\n/**\n * Builds the OpenAI / xAI Responses API follow-up input items for a\n * client-tool round-trip.\n *\n * Emits `function_call` items (the model's call) followed by\n * `function_call_output` items (the harness execution result), one pair\n * per executed tool call.\n *\n * **Single source of truth for the id (id-correlation fix).** Each\n * `function_call_output.call_id` is drawn from — and validated against — the\n * set of `function_call.call_id`s in the accumulation map. It is NEVER derived\n * from the tool name (the OpenAI parity of the Anthropic `tool_use_id` fix). A\n * missing / empty / unmatched call id fails the build loud rather than emitting\n * a continuation the provider would reject.\n *\n * @internal\n */\nexport function buildOpenAiContinuation(\n calls: Map<string, IAccumulatedFunctionCall>,\n toolResults: IToolCallResult[],\n logger?: Logging.ILogger\n): Result<IAiClientToolContinuation> {\n const items: JsonObject[] = [];\n\n // Emit function_call items for each call (model's side). Per the Responses API spec\n // (ResponseFunctionToolCall), `call_id` is the required correlation field — it must\n // match the matching function_call_output's `call_id` below. The optional `id` field\n // is the output-item id (`fc_*`) used to reference the streamed item; we omit it\n // because it is not load-bearing for input items.\n const bufferedCallIds = new Set<string>();\n for (const [callId, call] of calls) {\n bufferedCallIds.add(callId);\n items.push({\n type: 'function_call',\n call_id: callId,\n name: call.name,\n arguments: call.argsBuffer\n });\n }\n\n // Emit function_call_output items (harness execution results). Correlate each\n // to a buffered function_call call_id — never the tool name — and fail loud on\n // a missing / empty / mismatched id.\n for (const r of toolResults) {\n if (!isUsableId(r.callId)) {\n return fail(\n `OpenAI continuation: tool '${r.toolName}' result has no call id (missing or empty); ` +\n `cannot correlate it to a function_call item`\n );\n }\n if (!bufferedCallIds.has(r.callId)) {\n return fail(\n `OpenAI continuation: tool '${r.toolName}' call id '${r.callId}' does not match any ` +\n `accumulated function_call call_id`\n );\n }\n items.push({\n type: 'function_call_output',\n call_id: r.callId,\n output: r.result\n });\n }\n\n // Decisive diagnostic: the function_call.call_id ↔ function_call_output.call_id\n // pairing for the outgoing continuation (matched by construction here).\n if (logger) {\n const pairing = toolResults.map((r) => `${r.toolName}:${r.callId}`).join(', ');\n logger.detail(`ai-assist:openai-continuation function_call.call_id↔output.call_id [${pairing}]`);\n }\n\n return succeed({\n messages: items,\n toolCallsSummary: toolResults.map((r) => ({\n toolName: r.toolName,\n callId: r.callId,\n args: r.args,\n result: r.result,\n isError: r.isError\n }))\n });\n}\n\n// ============================================================================\n// Gemini continuation builder\n// ============================================================================\n\n/**\n * Builds the Gemini follow-up contents for a client-tool round-trip.\n *\n * Emits a model turn with `functionCall` parts (one per tool call) and a\n * user turn with `functionResponse` parts (correlation by tool name, since\n * Gemini does not assign call IDs).\n *\n * When thinking is enabled, Gemini stamps an opaque `thoughtSignature` on each\n * `functionCall` part and requires it echoed back, verbatim, as a sibling of\n * `functionCall` on the continuation's model turn — otherwise the follow-up is\n * rejected with \"Function call is missing a thought_signature in functionCall\n * parts\". The captured signature (see {@link IAccumulatedGeminiFunctionCall})\n * is replayed here only when present; the key is omitted entirely when thinking\n * was disabled. See https://ai.google.dev/gemini-api/docs/thought-signatures.\n *\n * @internal\n */\nexport function buildGeminiContinuation(\n calls: IAccumulatedGeminiFunctionCall[],\n toolResults: IToolCallResult[]\n): IAiClientToolContinuation {\n // Model turn: functionCall parts for each call. Replay the part-level\n // thoughtSignature as a sibling of functionCall only when present.\n const modelParts: JsonArray = calls.map(\n (call): JsonObject => ({\n functionCall: {\n name: call.name,\n args: call.args\n },\n ...(call.thoughtSignature !== undefined ? { thoughtSignature: call.thoughtSignature } : {})\n })\n );\n\n // User turn: functionResponse parts for each executed result.\n // Correlation is by name since Gemini has no call IDs.\n const userParts: JsonArray = toolResults.map(\n (r): JsonObject => ({\n functionResponse: {\n name: r.toolName,\n response: {\n content: r.result,\n ...(r.isError ? { error: true } : {})\n }\n }\n })\n );\n\n const modelMessage: JsonObject = {\n role: 'model',\n parts: modelParts\n };\n const userMessage: JsonObject = {\n role: 'user',\n parts: userParts\n };\n\n return {\n messages: [modelMessage, userMessage],\n toolCallsSummary: toolResults.map((r) => ({\n toolName: r.toolName,\n callId: r.callId,\n args: r.args,\n result: r.result,\n isError: r.isError\n }))\n };\n}\n\n// ============================================================================\n// executeClientToolTurn parameters\n// ============================================================================\n\n/**\n * Decision returned by an {@link IExecuteClientToolTurnParams.onBeforeToolExecute}\n * gate for a single client-tool call.\n *\n * @remarks\n * - `{ action: 'proceed' }` — run the tool's `execute` normally.\n * - `{ action: 'deny', reason }` — do NOT run `execute`; a synthesized tool-result\n * carrying `reason` is fed into the continuation exactly like a normal result so\n * the model can react, and a `client-tool-result` event is emitted for the call.\n * The turn continues.\n *\n * A gate that wants to signal a hard error (as opposed to a deliberate deny) should\n * return `Result.fail` (or reject) from the callback. Note this is NOT the same as a\n * `tool.execute` failure: an `execute` failure yields an `isError` tool-result and the\n * **turn continues**, whereas a gate `fail`/reject **terminates the turn** — it fails\n * `nextTurn` (and emits an inline `error` event) rather than synthesizing a deny.\n *\n * @public\n */\nexport type IToolExecutionDecision =\n | { readonly action: 'proceed' }\n | { readonly action: 'deny'; readonly reason: string };\n\n/**\n * Parameters for {@link AiAssist.executeClientToolTurn}.\n *\n * @remarks\n * Carries the unified {@link AiAssist.IChatRequest} shape (`system?` + ordered\n * `messages`): the last message is the current user turn and the preceding\n * messages are history, linearized before the current turn — identically to the\n * completion and streaming paths. {@link IExecuteClientToolTurnParams.continuationMessages}\n * remains a distinct post-current-turn axis (see below).\n *\n * @public\n */\nexport interface IExecuteClientToolTurnParams extends IChatRequest {\n /** The provider descriptor for routing (Anthropic / OpenAI / Gemini). */\n readonly descriptor: IAiProviderDescriptor;\n /** API key for authentication. */\n readonly apiKey: string;\n /**\n * The cumulative provider-native wire tail from the previous turn's\n * {@link AiAssist.IAiClientToolContinuation.messages}. Supply this as-is\n * each round — `messages` is already cumulative, so **replace** rather\n * than manually concatenate:\n *\n * ```ts\n * tail = outcome.continuation.messages; // replace — already cumulative\n * ```\n *\n * On the first turn this should be `undefined` (or omitted).\n *\n * Each provider applies its own shape guard to the supplied wire objects:\n * - Anthropic: projects each entry to `{ role, content }` (sufficient for\n * thinking blocks and `tool_result` arrays).\n * - OpenAI / xAI Responses: passes each item verbatim (`function_call` /\n * `function_call_output` items carry distinct fields per `type`); only\n * guards that each entry is a JSON object.\n * - Gemini: projects each entry to `{ role, parts }`.\n *\n * Entries that fail their provider's shape check are silently skipped.\n * Do NOT place these objects in the `messages` parameter — the\n * normalized-message path strips provider-native fields.\n */\n readonly continuationMessages?: ReadonlyArray<JsonObject>;\n /**\n * Sampling temperature. Sent to the provider only when explicitly provided; omitted otherwise\n * so the provider's own default applies (current-gen models reject a caller-supplied default).\n */\n readonly temperature?: number;\n /** Server-side tools to include. */\n readonly tools?: ReadonlyArray<AiServerToolConfig>;\n /** Client-defined tools available for the model to call. */\n readonly clientTools: ReadonlyArray<IAiClientTool>;\n /** Optional abort signal. */\n readonly signal?: AbortSignal;\n /**\n * Optional override of the descriptor's default base URL. Same semantics as\n * the non-streaming completion path and `callProviderCompletionStream`: a\n * well-formed `http`/`https` URL is substituted for `descriptor.baseUrl`\n * when composing the per-format request, with the per-format suffix appended\n * unchanged. Validated at the dispatcher; auth shape is unaffected. Use this\n * to point a client-tool turn at a local / LAN OpenAI-compatible server\n * (Ollama, LM Studio, llama.cpp).\n */\n readonly endpoint?: string;\n /** Optional logger for diagnostics. */\n readonly logger?: Logging.ILogger;\n /** Optional resolved thinking config (pre-resolved by the caller). */\n readonly resolvedThinking?: IResolvedThinkingConfig;\n /** Resolved model string (pre-resolved by the caller). When omitted, uses the descriptor's default model. */\n readonly model?: string;\n /**\n * Optional host gate invoked for each client-tool call **after** the model's raw\n * args have been validated against the tool's `parametersSchema` and **before**\n * `tool.execute(...)` runs. The full `tool` (including `tool.config.annotations`)\n * and the validated `args` are passed so gate logic can key off a tool's behavior\n * annotations (e.g. deny a `destructiveHint` call pending confirmation).\n *\n * Returning `{ action: 'proceed' }` (or omitting the callback) runs `execute`\n * normally. Returning `{ action: 'deny', reason }` skips `execute` and synthesizes\n * a denial tool-result carrying `reason` into the continuation (the model sees the\n * denial and can react); **the turn continues**. A callback that returns `Result.fail`\n * or rejects is a hard error that **terminates the turn** (fails `nextTurn` + emits an\n * inline `error` event) — distinct from a `tool.execute` failure, which continues the\n * turn with an `isError` result. A deny must therefore be explicit.\n */\n readonly onBeforeToolExecute?: (\n tool: IAiClientTool,\n args: unknown\n ) => Promise<Result<IToolExecutionDecision>>;\n /**\n * Optional cap on generated output tokens, mapped to each provider's native field:\n * Anthropic `max_tokens`, OpenAI/xAI Responses `max_output_tokens` (client-tool turns always\n * route OpenAI through the Responses API), Gemini `generationConfig.maxOutputTokens`. When\n * unset, every provider except Anthropic omits the field and applies its own default;\n * Anthropic's Messages API requires the field, so it falls back to\n * `DEFAULT_ANTHROPIC_MAX_TOKENS`.\n */\n readonly maxTokens?: number;\n /**\n * What to do when this provider declares one of the requested server tools\n * mutually exclusive with client tools (see\n * {@link AiAssist.IAiProviderDescriptor.serverToolsExclusiveWithClientTools}). Defaults to\n * `'drop-server-tools'` — the client tools this host registered for the turn are\n * kept and the server tool is dropped.\n *\n * @remarks\n * Whatever the policy, the turn result's `toolConflicts` says what actually\n * happened, so a degraded turn is never a silent one. Pass `'fail'` for the\n * pre-policy behavior: a `Result.fail` up front, before any wire call.\n */\n readonly toolConflictPolicy?: AiToolConflictPolicy;\n /**\n * Prompt-caching plan for this request. Omitted, nothing cache-related is sent — the request\n * body is byte-identical to a build predating this feature. See {@link AiAssist.IAiCacheRequest}.\n *\n * @remarks\n * `executeClientToolTurn` represents a single round of a multi-round tool loop; a caller\n * driving several rounds passes this on **each** call, and it is validated against — and\n * applied to — that round's own `system` each time, never cached across rounds. Gated per\n * provider exactly as `IProviderCompletionParams.cache` is on the non-streaming path.\n */\n readonly cache?: IAiCacheRequest;\n}\n\n/**\n * Return value of {@link AiAssist.executeClientToolTurn}.\n * @public\n */\nexport interface IExecuteClientToolTurnResult {\n /**\n * The unified-event iterable. Callers iterate this to drive the streaming UI.\n *\n * @remarks\n * Forwards every event the underlying adapter emits: `text-delta`,\n * `tool-event`, `done` and `error` come through from the provider stream, and\n * `client-tool-call-start`, `client-tool-call-done` and `client-tool-result`\n * are the tool-dispatch events this layer adds.\n *\n * The `done` event is the terminal one and carries\n * {@link AiAssist.IAiStreamDone.usage} when the provider reports it — this\n * iterable is not a text-only view. A caller that only wants the token counts\n * can read them off {@link AiAssist.IAiClientToolTurnResult.usage} instead of\n * matching on events — but it must still iterate this to completion, because\n * that is what drives `nextTurn` to resolve at all.\n *\n * (An earlier version of this comment listed only the five non-terminal\n * events. It was describing the tool-dispatch subset, but it read as the\n * complete set, and at least one consumer reasonably concluded from it that\n * usage never crossed the package boundary on this path. It always did.)\n */\n readonly events: AsyncIterable<IAiStreamEvent>;\n /**\n * Resolves when the stream terminates. On success, carries the\n * {@link AiAssist.IAiClientToolTurnResult} with the optional continuation for the\n * next round. On failure, carries the error message.\n *\n * @remarks\n * **You must drive `events` for this to resolve.** It is settled from inside\n * the generator backing `events`, and an async generator does not start until\n * something iterates it — so `await nextTurn` on its own waits forever, and\n * the response body is never drained. Iterate `events` to completion (ignore\n * the events if you do not want them) and then await this.\n */\n readonly nextTurn: Promise<Result<IAiClientToolTurnResult>>;\n}\n\n// ============================================================================\n// executeClientToolTurn\n// ============================================================================\n\n/**\n * Orchestrates a single client-tool streaming turn for any supported provider.\n *\n * Starts a streaming request, iterates the underlying provider stream, and:\n * - Forwards `text-delta`, `tool-event`, `client-tool-call-start`, and\n * `client-tool-call-done` events through to the consumer.\n * - For each `client-tool-call-done` event: validates the raw args against the\n * tool's `parametersSchema`, invokes `execute(typedArgs)`, and emits a\n * `client-tool-result` event.\n * - After stream completion: builds the per-provider continuation (or\n * `{ continuation: undefined }` when no tool calls occurred) and resolves\n * `nextTurn`.\n *\n * **Anthropic constraint (E3):** The continuation for Anthropic does not set\n * a forced `tool_choice`. Only `tool_choice: 'auto'` (the default, i.e.\n * omitted) is compatible with extended thinking.\n *\n * **Provider tool exclusions:** when the descriptor declares a server tool\n * mutually exclusive with client tools (today only Gemini, for `web_search`),\n * `toolConflictPolicy` decides — by default the server tool is dropped and the\n * turn proceeds. The turn result's `toolConflicts` always says what happened, so\n * a host can tell the person that e.g. web search was unavailable this turn.\n * Pass `'fail'` to refuse the request up front instead.\n *\n * @param params - Turn parameters\n * @returns `{ events, nextTurn }` — stream iterable + completion promise\n * @public\n */\nexport function executeClientToolTurn(\n params: IExecuteClientToolTurnParams\n): Result<IExecuteClientToolTurnResult> {\n const {\n descriptor,\n apiKey,\n system,\n messages,\n continuationMessages,\n temperature,\n tools,\n clientTools,\n signal,\n logger,\n resolvedThinking,\n model,\n endpoint,\n onBeforeToolExecute,\n maxTokens,\n toolConflictPolicy,\n cache\n } = params;\n\n const splitResult = splitChatRequest(system, messages);\n if (splitResult.isFailure()) {\n return fail(splitResult.message);\n }\n const { prompt, head } = splitResult.value;\n if (prompt.attachments.length > 0 && !descriptor.acceptsImageInput) {\n return fail(`provider \"${descriptor.id}\" does not accept image input`);\n }\n\n // Apply whatever server-tool/client-tool exclusions this provider declares. The\n // rule itself lives on the descriptor, so nothing here branches on provider\n // identity; under the default policy an exclusive server tool is dropped and the\n // turn proceeds, where it used to be refused outright. `'fail'` reproduces that\n // refusal for hosts that would rather choose for themselves.\n const conflictResult = resolveToolConflicts(descriptor, tools, clientTools, toolConflictPolicy);\n if (conflictResult.isFailure()) {\n return fail(`executeClientToolTurn: ${conflictResult.message}`);\n }\n const {\n serverTools: resolvedServerTools,\n clientTools: resolvedClientTools,\n report: toolConflicts\n } = conflictResult.value;\n\n // Fail fast on duplicate names — silently overwriting would cause one tool to\n // shadow another with no observable signal.\n //\n // Scanned over the caller's ORIGINAL list, not the post-conflict survivors. A\n // duplicate name is a defect in the host's tool registration, not a property of\n // this turn; reporting it only on the turns that happen to keep both tools would\n // make a deterministic bug look intermittent — it would go quiet exactly when a\n // policy dropped the colliding pair and reappear on the next provider.\n const seen = new Set<string>();\n for (const tool of clientTools) {\n if (seen.has(tool.config.name)) {\n return fail(`executeClientToolTurn: duplicate client tool name '${tool.config.name}'`);\n }\n seen.add(tool.config.name);\n }\n\n // The dispatch map holds only the tools actually offered this turn, so a tool a\n // policy dropped is genuinely unavailable rather than merely unadvertised.\n const toolsByName = new Map<string, IAiClientTool>(\n resolvedClientTools.map((tool) => [tool.config.name, tool])\n );\n\n // Merge server tools and client tool configs into a single array for the provider.\n // This is the fix for P1-1: client tools were never sent to the provider because\n // the adapters only received `tools` (server tools). Both must coexist per design §2.5.\n //\n // With no client tools to merge, pass the caller's own `tools` through when the\n // resolution changed nothing, so a caller who sent `undefined` still sends\n // `undefined` — an absent `tools` field and an empty one are not the same request\n // on every provider.\n let effectiveTools: ReadonlyArray<AiToolConfig> | undefined;\n if (resolvedClientTools.length > 0) {\n effectiveTools = [...resolvedServerTools, ...resolvedClientTools.map((t) => t.config)];\n } else if (tools === undefined) {\n effectiveTools = undefined;\n } else {\n effectiveTools = resolvedServerTools;\n }\n\n const modelResult = resolveProviderModel(descriptor, model);\n if (modelResult.isFailure()) {\n return fail(modelResult.message);\n }\n const resolvedModel = modelResult.value;\n const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);\n if (baseUrlResult.isFailure()) {\n return fail(baseUrlResult.message);\n }\n const config: IStreamApiConfig = {\n baseUrl: baseUrlResult.value,\n apiKey,\n model: resolvedModel\n };\n\n // Accumulation buffers — populated by the adapter, read by the builder.\n const anthropicBuffer = new Map<number, IAccumulatedBlock>();\n const openAiCallMap = new Map<string, IAccumulatedFunctionCall>();\n const geminiCalls: IAccumulatedGeminiFunctionCall[] = [];\n\n // Collected tool results, populated as each client-tool-call-done is processed.\n const toolResults: IToolCallResult[] = [];\n\n // Stream start: open the underlying adapter stream.\n const streamPromise: Promise<Result<AsyncIterable<IAiStreamEvent>>> = (() => {\n switch (descriptor.apiFormat) {\n case 'anthropic':\n return callAnthropicStream(\n config,\n prompt,\n head,\n temperature,\n effectiveTools,\n logger,\n signal,\n resolvedThinking,\n anthropicBuffer,\n continuationMessages,\n isAdaptiveThinkingModel(descriptor, config.model),\n maxTokens,\n cache\n );\n case 'openai': {\n // Same gating as callProviderCompletion's 'openai' case in completionClient.ts — see the\n // comment there for why breakpoints and the routing key are gated independently. Client-tool\n // turns always route OpenAI through the Responses API, which takes the routing key as a body\n // field on every supporting provider, so there is no chatCompletionsHeader to thread here.\n const routing = supportsPromptCacheRouting(descriptor);\n const breakpoints = supportsPromptCacheBreakpoints(descriptor) ? cache?.systemBreakpoints : undefined;\n const routedKey = routing !== undefined ? cache?.cacheKey : undefined;\n const gatedCache: IAiCacheRequest | undefined =\n breakpoints !== undefined || routedKey !== undefined\n ? { systemBreakpoints: breakpoints, cacheKey: routedKey }\n : undefined;\n return callOpenAiResponsesStream(\n config,\n prompt,\n /* c8 ignore next 1 - defensive: openai path requires tools; empty array fallback unreachable in practice */\n effectiveTools ?? [],\n head,\n temperature,\n logger,\n signal,\n resolvedThinking,\n openAiCallMap,\n continuationMessages,\n maxTokens,\n supportsCacheUsageReporting(descriptor),\n gatedCache\n );\n }\n case 'gemini':\n return callGeminiStream(\n config,\n prompt,\n head,\n temperature,\n effectiveTools,\n logger,\n signal,\n resolvedThinking,\n geminiCalls,\n continuationMessages,\n maxTokens\n );\n /* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = descriptor.apiFormat;\n return Promise.resolve(fail(`unsupported API format: ${String(_exhaustive)}`));\n }\n }\n })();\n\n // Resolve controls for `nextTurn`.\n let resolveNextTurn!: (result: Result<IAiClientToolTurnResult>) => void;\n const nextTurn = new Promise<Result<IAiClientToolTurnResult>>((resolve) => {\n resolveNextTurn = resolve;\n });\n\n // The unified-event generator: opens the stream, proxies events, executes tools.\n async function* eventGenerator(): AsyncGenerator<IAiStreamEvent> {\n const streamResult = await streamPromise;\n if (streamResult.isFailure()) {\n resolveNextTurn(fail(streamResult.message));\n yield { type: 'error', message: streamResult.message };\n return;\n }\n\n let truncated = false;\n let fullText = '';\n let usage: IAiCompletionUsage | undefined;\n let streamError: string | undefined;\n\n for await (const event of streamResult.value) {\n if (event.type === 'done') {\n truncated = event.truncated;\n fullText = event.fullText;\n // Absent when the provider reported nothing — carried through as absent\n // rather than defaulted, so a caller can tell \"not reported\" from zero.\n usage = event.usage;\n yield event;\n continue;\n }\n\n if (event.type === 'error') {\n streamError = event.message;\n yield event;\n continue;\n }\n\n if (event.type === 'text-delta') {\n yield event;\n continue;\n }\n\n if (event.type === 'tool-event') {\n yield event;\n continue;\n }\n\n if (event.type === 'client-tool-call-start') {\n yield event;\n continue;\n }\n\n if (event.type === 'client-tool-call-done') {\n yield event;\n\n const { toolName, callId, args } = event;\n const tool = toolsByName.get(toolName);\n\n if (!tool) {\n const errMsg = `model called unknown tool: ${toolName}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n // A model naming a tool the host never registered is a *model* error, and this\n // module's taxonomy (see IToolExecutionDecision's remarks) puts model errors on the\n // continue side: an arg-validation failure, an `execute` failure and a gate `deny`\n // all yield an isError tool-result and let the model react. Only host-machinery\n // errors — a gate `fail`/reject — terminate the turn. This branch used to terminate,\n // which cost a recoverable turn: a model that emits one bad tool name (for instance,\n // reading a prose trailer in the prompt as a tool) ended the stream instead of being\n // told and trying again.\n //\n // Safe on the wire: both continuation builders correlate results by call id and\n // explicitly never by tool name, so an unrecognized name cannot malform the\n // continuation — the id is the one the model just emitted.\n continue;\n }\n\n const validationResult = tool.config.parametersSchema.validate(args);\n if (validationResult.isFailure()) {\n const errMsg = `${toolName} (callId=${callId}): ${validationResult.message}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n\n // Host gate: run after arg-validation, before execute. A `deny` decision\n // synthesizes a denial tool-result and continues the turn; a `fail`/reject\n // from the gate itself is a hard error (mirrors an execute failure), never\n // a silent deny.\n if (onBeforeToolExecute !== undefined) {\n const decisionResult: Result<IToolExecutionDecision> = (\n await captureAsyncResult(async () => onBeforeToolExecute(tool, validationResult.value))\n ).onSuccess((decision) => decision);\n\n if (decisionResult.isFailure()) {\n const errMsg = `${toolName} (callId=${callId}): ${decisionResult.message}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n // Gate-fail is a hard, turn-terminating error (unlike a non-fatal `deny`, whose\n // generator continues). Emit an explicit `error` event so a consumer watching only\n // `events` sees the fatal failure inline and can distinguish it from a deny — matching\n // the stream-open / continuation hard-error paths.\n yield { type: 'error', message: errMsg };\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n resolveNextTurn(fail(errMsg));\n return;\n }\n\n if (decisionResult.value.action === 'deny') {\n const denialMsg = `${toolName} (callId=${callId}): tool execution denied: ${decisionResult.value.reason}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: denialMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: denialMsg, isError: true });\n continue;\n }\n }\n\n const executeResult = await captureAsyncResult(async () => tool.execute(validationResult.value));\n const executionResult: Result<unknown> = executeResult.isSuccess()\n ? executeResult.value\n : executeResult;\n\n if (executionResult.isFailure()) {\n const errMsg = `${toolName} (callId=${callId}): ${executionResult.message}`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n\n // JSON.stringify can throw (circular references) or return undefined\n // (e.g. for a bare `undefined` value, or a value of type `function`).\n // Either outcome violates the client-tool-result event contract, so\n // emit an isError result with diagnostic context instead.\n let resultStr: string;\n try {\n const stringified = JSON.stringify(executionResult.value);\n if (stringified === undefined) {\n const errMsg = `${toolName} (callId=${callId}): tool returned a non-serializable value (JSON.stringify produced undefined)`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n resultStr = stringified;\n } catch (e) {\n const errMsg = `${toolName} (callId=${callId}): failed to serialize tool result: ${\n (e as Error).message\n }`;\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: errMsg,\n isError: true\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: errMsg, isError: true });\n continue;\n }\n const resultEvent: IAiStreamEvent = {\n type: 'client-tool-result',\n toolName,\n callId,\n result: resultStr,\n isError: false\n };\n yield resultEvent;\n toolResults.push({ toolName, callId, args, result: resultStr, isError: false });\n continue;\n }\n\n // client-tool-result events are emitted by this layer, not the adapters — no passthrough needed.\n }\n\n // Stream has ended. Build the continuation.\n if (streamError !== undefined) {\n resolveNextTurn(fail(streamError));\n return;\n }\n\n if (toolResults.length === 0) {\n resolveNextTurn(succeed({ continuation: undefined, truncated, fullText, toolConflicts, usage }));\n return;\n }\n\n let continuationResult: Result<IAiClientToolContinuation>;\n switch (descriptor.apiFormat) {\n case 'anthropic':\n continuationResult = buildAnthropicContinuation(anthropicBuffer, toolResults, logger);\n break;\n case 'openai':\n continuationResult = buildOpenAiContinuation(openAiCallMap, toolResults, logger);\n break;\n case 'gemini':\n // Gemini correlates by tool name by design (no call ids) — its builder\n // cannot mis-key and stays non-fallible.\n continuationResult = succeed(buildGeminiContinuation(geminiCalls, toolResults));\n break;\n /* c8 ignore next 5 - defensive coding: exhaustive switch guaranteed by TypeScript */\n default: {\n const _exhaustive: never = descriptor.apiFormat;\n resolveNextTurn(fail(`unsupported API format: ${String(_exhaustive)}`));\n return;\n }\n }\n\n // A bad id-correlation fails loud here rather than emitting a malformed\n // continuation the provider would reject as a \"malformed identifier\". Mirror\n // the stream-open-failure path above: surface an `error` event so a consumer\n // iterating `events` sees the failure inline, not only via `nextTurn`.\n if (continuationResult.isFailure()) {\n resolveNextTurn(fail(continuationResult.message));\n yield { type: 'error', message: continuationResult.message };\n return;\n }\n let continuation = continuationResult.value;\n\n // Prepend inbound continuationMessages so the returned continuation is cumulative.\n // A consumer that does `tail = outcome.continuation.messages` (replace) is then\n // correct for all N rounds — messages always contains the full wire tail from\n // round 1 through the current round. toolCallsSummary stays per-round (this\n // round's calls only); messages is the accumulated tail to re-send.\n if (continuationMessages && continuationMessages.length > 0) {\n continuation = { ...continuation, messages: [...continuationMessages, ...continuation.messages] };\n }\n\n resolveNextTurn(succeed({ continuation, truncated, fullText, toolConflicts, usage }));\n }\n\n return succeed({\n events: { [Symbol.asyncIterator]: () => eventGenerator() },\n nextTurn\n });\n}\n"]}
|