@truefoundry/trueforge-core 0.2.0-rc.0 → 0.2.0-rc.2

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.
Files changed (63) hide show
  1. package/dist/agent-session/SessionHandle.d.ts +1 -0
  2. package/dist/agent-session/SessionHandle.d.ts.map +1 -1
  3. package/dist/agent-session/SessionHandle.js +3 -0
  4. package/dist/agent-session/SessionHandle.js.map +1 -1
  5. package/dist/agent-session/SessionHandle.mjs +3 -0
  6. package/dist/agent-session/SessionHandle.mjs.map +1 -1
  7. package/dist/agent-session/Sessions.d.ts +21 -6
  8. package/dist/agent-session/Sessions.d.ts.map +1 -1
  9. package/dist/agent-session/Sessions.js +46 -1
  10. package/dist/agent-session/Sessions.js.map +1 -1
  11. package/dist/agent-session/Sessions.mjs +46 -1
  12. package/dist/agent-session/Sessions.mjs.map +1 -1
  13. package/dist/agent-session/index.d.ts +6 -4
  14. package/dist/agent-session/index.d.ts.map +1 -1
  15. package/dist/agent-session/index.js +15 -0
  16. package/dist/agent-session/index.js.map +1 -1
  17. package/dist/agent-session/index.mjs +17 -1
  18. package/dist/agent-session/index.mjs.map +1 -1
  19. package/dist/agent-session/models/SessionRecord.d.ts +14 -2
  20. package/dist/agent-session/models/SessionRecord.d.ts.map +1 -1
  21. package/dist/agent-session/models/SessionRecord.js.map +1 -1
  22. package/dist/agent-session/schemas/session.d.ts +43 -1
  23. package/dist/agent-session/schemas/session.d.ts.map +1 -1
  24. package/dist/agent-session/schemas/session.js +43 -5
  25. package/dist/agent-session/schemas/session.js.map +1 -1
  26. package/dist/agent-session/schemas/session.mjs +37 -4
  27. package/dist/agent-session/schemas/session.mjs.map +1 -1
  28. package/dist/agent-session/schemas/subject.d.ts +9 -0
  29. package/dist/agent-session/schemas/subject.d.ts.map +1 -0
  30. package/dist/agent-session/schemas/subject.js +36 -0
  31. package/dist/agent-session/schemas/subject.js.map +1 -0
  32. package/dist/agent-session/schemas/subject.mjs +11 -0
  33. package/dist/agent-session/schemas/subject.mjs.map +1 -0
  34. package/dist/agent-session/store/ISessionStore.d.ts +44 -20
  35. package/dist/agent-session/store/ISessionStore.d.ts.map +1 -1
  36. package/dist/agent-session/store/ISessionStore.js.map +1 -1
  37. package/dist/agent-session/store/InMemorySessionStore.d.ts +4 -1
  38. package/dist/agent-session/store/InMemorySessionStore.d.ts.map +1 -1
  39. package/dist/agent-session/store/InMemorySessionStore.js +66 -2
  40. package/dist/agent-session/store/InMemorySessionStore.js.map +1 -1
  41. package/dist/agent-session/store/InMemorySessionStore.mjs +67 -2
  42. package/dist/agent-session/store/InMemorySessionStore.mjs.map +1 -1
  43. package/dist/agent-session/store/SessionStoreErrors.d.ts +4 -0
  44. package/dist/agent-session/store/SessionStoreErrors.d.ts.map +1 -1
  45. package/dist/agent-session/store/SessionStoreErrors.js +10 -0
  46. package/dist/agent-session/store/SessionStoreErrors.js.map +1 -1
  47. package/dist/agent-session/store/SessionStoreErrors.mjs +9 -0
  48. package/dist/agent-session/store/SessionStoreErrors.mjs.map +1 -1
  49. package/dist/core/llm/VercelAILLM.d.ts +1 -1
  50. package/dist/core/llm/VercelAILLM.d.ts.map +1 -1
  51. package/dist/core/llm/VercelAILLM.js +4 -2
  52. package/dist/core/llm/VercelAILLM.js.map +1 -1
  53. package/dist/core/llm/VercelAILLM.mjs +4 -2
  54. package/dist/core/llm/VercelAILLM.mjs.map +1 -1
  55. package/dist/core/mcp/remoteMcpClient.js +1 -1
  56. package/dist/core/mcp/remoteMcpClient.js.map +1 -1
  57. package/dist/core/mcp/remoteMcpClient.mjs +1 -1
  58. package/dist/core/mcp/remoteMcpClient.mjs.map +1 -1
  59. package/dist/core/sandbox/Sandbox.js +5 -5
  60. package/dist/core/sandbox/Sandbox.js.map +1 -1
  61. package/dist/core/sandbox/Sandbox.mjs +1 -1
  62. package/dist/core/sandbox/Sandbox.mjs.map +1 -1
  63. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/llm/VercelAILLM.ts"],"sourcesContent":["import { createAlibaba } from '@ai-sdk/alibaba';\nimport { createAnthropic } from '@ai-sdk/anthropic';\nimport { createGoogle } from '@ai-sdk/google';\nimport type { MoonshotAIProviderOptions } from '@ai-sdk/moonshotai';\nimport { createMoonshotAI } from '@ai-sdk/moonshotai';\nimport type { OpenAIResponsesProviderOptions } from '@ai-sdk/openai';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport type { OpenAICompatibleProviderOptions } from '@ai-sdk/openai-compatible';\nimport { createOpenAICompatible } from '@ai-sdk/openai-compatible';\nimport type { JSONObject } from '@ai-sdk/provider';\nimport type { ProviderOptions, ReasoningPart } from '@ai-sdk/provider-utils';\nimport type {\n AssistantContent,\n CallWarning,\n FilePart,\n FinishReason,\n JSONValue,\n LanguageModel,\n LanguageModelCallOptions,\n ModelMessage,\n ProviderMetadata,\n TextPart,\n TextStreamPart,\n ToolCallPart,\n ToolContent,\n ToolSet,\n UserContent,\n} from 'ai';\nimport { APICallError, jsonSchema, Output, streamText } from 'ai';\nimport type {\n ChatCompletionContentPart,\n ChatCompletionCreateParamsStreaming,\n ChatCompletionMessageParam,\n ChatCompletionTool,\n} from 'openai/resources/chat';\nimport type { Logger } from 'winston';\nimport { describeUnknownError, extractErrorLogFields } from '../util/errorLogFields';\nimport type { ILLM, LLMCreateParams, LLMCreateParamsStreaming } from './ILLM';\nimport {\n type CompletionUsage,\n type ExtendedChatCompletionChunk,\n getEmptyUsage,\n type RawAssistantMessage,\n type RawAssistantMessageWithUsage,\n type ThinkingBlock,\n} from './LLMTypes';\n\n// ---------------------------------------------------------------------------\n// Public config\n// ---------------------------------------------------------------------------\n\n/**\n * Providers with a case in {@link buildLanguageModel}. Canonical: the server derives the provider\n * types it will configure from this, so anything it accepts has an adapter behind it.\n */\nexport const VERCEL_AI_PROVIDER_NAMES = [\n 'openai',\n 'anthropic',\n 'google-gemini',\n 'fireworks',\n 'zai',\n 'moonshot',\n 'alibaba',\n 'together',\n 'custom',\n] as const;\n\nexport type VercelAIProviderName = (typeof VERCEL_AI_PROVIDER_NAMES)[number];\n\n/**\n * Adapter-facing config, camelCase throughout. Callers translate from the snake_case wire and\n * storage shapes, which stay as they are because they are the published contract.\n */\nexport interface VercelAIProviderConfig {\n /** Adapter discriminator plus configured resource name (source `type/name/...`). */\n provider: {\n type: VercelAIProviderName;\n name: string;\n };\n /** Provider-facing model identifier and configured model name. */\n model: {\n id: string;\n name: string;\n };\n /** Display name / alias, used for logs and chunk labels. */\n name: string;\n /** Optional base URL override. Explicitly includes `undefined` for Zod-derived type compat. */\n baseUrl?: string | undefined;\n apiKey: string;\n headers: Record<string, string>;\n}\n\nexport interface VercelAILLMConfig {\n providerConfig: VercelAIProviderConfig;\n logger: Logger;\n signal?: AbortSignal;\n}\n\n// ---------------------------------------------------------------------------\n// Shared predicates\n// ---------------------------------------------------------------------------\n\n/** Narrows to an indexable record. */\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** OpenAI SDK v7 unions function + custom tools; harness only emits function tools. */\nfunction isFunctionTool(tool: ChatCompletionTool): tool is Extract<ChatCompletionTool, { type: 'function' }> {\n return tool.type === 'function';\n}\n\n/** OpenAI SDK v7 unions function + custom tool calls; harness only consumes function calls. */\nfunction isFunctionToolCall<T extends { type: string }>(toolCall: T): toolCall is Extract<T, { type: 'function' }> {\n return toolCall.type === 'function';\n}\n\n// ---------------------------------------------------------------------------\n// Model construction\n// ---------------------------------------------------------------------------\n\n/**\n * Shared by every OpenAI-compatible provider, which differ only by endpoint. The provider type\n * doubles as the `providerOptions` key. Fireworks, Together and Z AI stay here rather than on their\n * own packages: those drop `json_schema`, and Fireworks also clamps efforts its models do accept.\n * TODO: move Z AI to @ai-sdk/zai once https://github.com/vercel/ai/pull/17340 ships.\n */\nfunction compatibleModel(config: VercelAIProviderConfig): LanguageModel {\n const { provider, model, apiKey, headers, baseUrl } = config;\n if (baseUrl === undefined) {\n throw new Error(`Provider \"${provider.type}\" requires a baseUrl`);\n }\n const client = createOpenAICompatible({\n name: provider.type,\n baseURL: baseUrl,\n apiKey,\n // Without this the adapter silently downgrades json_schema to a schema-less json_object.\n supportsStructuredOutputs: true,\n // These endpoints omit token counts from streamed responses unless asked.\n includeUsage: true,\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n });\n return client(model.id);\n}\n\nexport function buildLanguageModel(config: VercelAIProviderConfig): LanguageModel {\n const { provider, model, baseUrl, apiKey, headers } = config;\n const extraHeaders = Object.keys(headers).length > 0 ? headers : undefined;\n\n switch (provider.type) {\n case 'openai': {\n const client = createOpenAI({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client.responses(model.id);\n }\n case 'anthropic': {\n const client = createAnthropic({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'google-gemini': {\n const client = createGoogle({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'moonshot': {\n const client = createMoonshotAI({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'alibaba': {\n // Endpoints are workspace-scoped, so the package default would address the wrong tenant.\n if (baseUrl === undefined) {\n throw new Error(`Provider \"alibaba\" requires a baseUrl`);\n }\n const client = createAlibaba({\n apiKey,\n baseURL: baseUrl,\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'fireworks':\n case 'zai':\n case 'together':\n case 'custom': {\n return compatibleModel(config);\n }\n default: {\n const _exhaustive: never = provider.type;\n throw new Error(`Unknown provider \"${String(_exhaustive)}\"`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Reasoning effort\n// ---------------------------------------------------------------------------\n\n/**\n * The cross-provider `streamText({ reasoning })` setting, distinct from `providerOptions`. Derived\n * from the SDK's own type rather than mirrored by hand.\n */\ntype ReasoningLevel = NonNullable<LanguageModelCallOptions['reasoning']>;\n\nconst COMMON_REASONING_LEVELS = [\n 'none',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n] as const satisfies readonly ReasoningLevel[];\n\nconst VERCEL_AI_REASONING_LEVELS = [\n 'provider-default',\n ...COMMON_REASONING_LEVELS,\n] as const satisfies readonly ReasoningLevel[];\n\n// Fails if any union member is missing.\ntrue satisfies Exclude<ReasoningLevel, (typeof VERCEL_AI_REASONING_LEVELS)[number]> extends never ? true : never;\n\nfunction isReasoningLevel(v: string): v is ReasoningLevel {\n return VERCEL_AI_REASONING_LEVELS.some(level => level === v);\n}\n\n/**\n * Efforts the SDK's union cannot express. `xhigh` is its ceiling, so `max` rides in as `xhigh`;\n * Anthropic's adapter raises that back, and {@link maxEffortOption} covers the rest.\n * Keys here must also appear in {@link SUPPORTED_REASONING_EFFORTS}.\n */\nconst EFFORT_ALIASES: Readonly<Record<string, ReasoningLevel>> = { max: 'xhigh' };\n\n/** What a model may advertise in `reasoning_efforts`; anything else resolves to the provider default. */\nexport const SUPPORTED_REASONING_EFFORTS = [...COMMON_REASONING_LEVELS, 'max'] as const;\n\n/**\n * The effort travels on the top-level `reasoning` setting, which each adapter translates per model:\n * an effort string for OpenAI-shaped APIs, a thinking shape for Anthropic, a level or budget for\n * Gemini. A reasoning `providerOptions` entry replaces that path rather than merging with it.\n */\nexport function toReasoningLevel(reasoningEffort: string | undefined): ReasoningLevel | undefined {\n if (reasoningEffort === undefined) {\n return undefined;\n }\n const aliased = EFFORT_ALIASES[reasoningEffort];\n if (aliased !== undefined) {\n return aliased;\n }\n return isReasoningLevel(reasoningEffort) ? reasoningEffort : undefined;\n}\n\n/**\n * `max` needs each adapter's own option, which wins over the top-level setting; the callers below\n * say why. The intersection resolves to `'max'`, so a package dropping it breaks the build.\n */\ntype MaxEffortOption = Pick<OpenAIResponsesProviderOptions, 'reasoningEffort'> &\n Pick<OpenAICompatibleProviderOptions, 'reasoningEffort'> &\n Pick<MoonshotAIProviderOptions, 'reasoningEffort'>;\n\nfunction maxEffortOption(reasoningEffort: string | undefined): MaxEffortOption {\n return reasoningEffort === 'max' ? { reasoningEffort: 'max' } : {};\n}\n\n// ---------------------------------------------------------------------------\n// Structured output\n// ---------------------------------------------------------------------------\n\n/**\n * Kept as plain data rather than an SDK `Output` instance, since `Output` isn't a nameable\n * exported type from `ai` — see `buildOutput`.\n */\nexport type StructuredOutputSpec =\n | { mode: 'text' }\n | { mode: 'json' }\n | {\n mode: 'json_schema';\n schema: Record<string, unknown>;\n name: string;\n description: string | undefined;\n /** Mirrors `response_format.json_schema.strict`; consumed by `buildProviderOptions`. */\n strict: boolean | undefined;\n };\n\n/** Converts an OpenAI-format `response_format` into a normalized `StructuredOutputSpec`. */\nexport function toStructuredOutputSpec(\n responseFormat: ChatCompletionCreateParamsStreaming['response_format'],\n): StructuredOutputSpec {\n if (responseFormat === undefined || responseFormat.type === 'text') {\n return { mode: 'text' };\n }\n if (responseFormat.type === 'json_object') {\n return { mode: 'json' };\n }\n const { json_schema } = responseFormat;\n return {\n mode: 'json_schema',\n schema: json_schema.schema ?? { type: 'object', properties: {} },\n name: json_schema.name,\n description: json_schema.description,\n strict: json_schema.strict ?? undefined,\n };\n}\n\n/** Not exported: `Output`'s type isn't nameable outside `ai`, so a return type can't be declared. */\nfunction buildOutput(spec: StructuredOutputSpec) {\n switch (spec.mode) {\n case 'text':\n return undefined;\n case 'json':\n return Output.json();\n case 'json_schema':\n return Output.object({\n schema: jsonSchema(spec.schema),\n name: spec.name,\n ...(spec.description !== undefined ? { description: spec.description } : {}),\n });\n default: {\n const _exhaustive: never = spec;\n throw new Error(`Unknown structured output mode: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Provider options\n// ---------------------------------------------------------------------------\n\n/** `rawBody` is a parsed JSON request body, so any value present is a valid JSONValue. */\nfunction readBodyField({ rawBody, key }: { rawBody: unknown; key: string }): JSONValue | undefined {\n const val: unknown = Reflect.get(Object(rawBody), key);\n return val !== undefined ? (val as JSONValue) : undefined;\n}\n\nfunction openaiProviderOptions({\n rawBody,\n strictJsonSchema,\n reasoningEffort,\n}: {\n rawBody: unknown;\n strictJsonSchema: boolean | undefined;\n reasoningEffort: string | undefined;\n}): JSONObject {\n const serviceTier = readBodyField({ rawBody, key: 'service_tier' });\n const user = readBodyField({ rawBody, key: 'user' });\n const promptCacheKey = readBodyField({ rawBody, key: 'prompt_cache_key' });\n const parallelToolCalls = readBodyField({ rawBody, key: 'parallel_tool_calls' });\n const reasoningSummary = readBodyField({ rawBody, key: 'reasoning_summary' });\n // No server-side storage, and request the encrypted reasoning token so replay stays stateless.\n return {\n store: false,\n include: ['reasoning.encrypted_content'],\n reasoningSummary: 'auto',\n // gpt-5.6 serves both xhigh and max, so the aliased top-level level asks for one rung less.\n ...maxEffortOption(reasoningEffort),\n ...(reasoningSummary !== undefined ? { reasoningSummary } : {}),\n ...(strictJsonSchema !== undefined ? { strictJsonSchema } : {}),\n ...(serviceTier !== undefined ? { serviceTier } : {}),\n ...(user !== undefined ? { user } : {}),\n ...(promptCacheKey !== undefined ? { promptCacheKey } : {}),\n ...(parallelToolCalls !== undefined ? { parallelToolCalls } : {}),\n };\n}\n\n/**\n * Forwards but never pins `thinking` and `effort`: both replace the adapter's per-model resolution\n * and no single value fits every model. This is the caller's only route to disabling thinking, or to\n * the `display: 'summarized'` that makes Claude 5 return reasoning text instead of an empty block.\n *\n * Prompt caching defaults on: Anthropic bills a write once, then cheaper reads on stable prefixes\n * (system / tools / early messages). Callers can override via `cache_control` in the request body.\n */\nfunction anthropicProviderOptions(rawBody: unknown): JSONObject | undefined {\n const cacheControl = readBodyField({ rawBody, key: 'cache_control' }) ?? { type: 'ephemeral' };\n const disableParallelToolUse = readBodyField({ rawBody, key: 'disable_parallel_tool_use' });\n const thinking = readBodyField({ rawBody, key: 'thinking' });\n const effort = readBodyField({ rawBody, key: 'effort' });\n const opts: JSONObject = {\n cacheControl,\n ...(disableParallelToolUse !== undefined ? { disableParallelToolUse } : {}),\n ...(thinking !== undefined ? { thinking } : {}),\n ...(effort !== undefined ? { effort } : {}),\n };\n return opts;\n}\n\n/**\n * Gemini returns thought summaries only when `includeThoughts` is set, and `@ai-sdk/google` omits it\n * — without this the model bills reasoning tokens and returns none. The effort itself rides in the\n * top-level `reasoning` setting. An explicit `thinking_config` in the request body wins.\n */\nfunction googleGeminiThinkingConfig({\n rawBody,\n reasoningRequested,\n}: {\n rawBody: unknown;\n reasoningRequested: boolean;\n}): JSONValue | undefined {\n const fromBody = readBodyField({ rawBody, key: 'thinking_config' });\n if (!reasoningRequested) {\n return fromBody;\n }\n if (typeof fromBody === 'object' && fromBody !== null && !Array.isArray(fromBody)) {\n return { includeThoughts: true, ...fromBody };\n }\n return { includeThoughts: true };\n}\n\nfunction googleGeminiProviderOptions({\n rawBody,\n reasoningRequested,\n}: {\n rawBody: unknown;\n reasoningRequested: boolean;\n}): JSONObject | undefined {\n const safetySettings = readBodyField({ rawBody, key: 'safety_settings' });\n const thinkingConfig = googleGeminiThinkingConfig({ rawBody, reasoningRequested });\n const cachedContent = readBodyField({ rawBody, key: 'cached_content' });\n const opts: JSONObject = {\n ...(safetySettings !== undefined ? { safetySettings } : {}),\n ...(thinkingConfig !== undefined ? { thinkingConfig } : {}),\n ...(cachedContent !== undefined ? { cachedContent } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/**\n * `thinking` and `reasoning_history` are forwarded but never pinned: they are the caller's route to\n * turning thinking off, or to replaying it verbatim.\n */\nfunction moonshotProviderOptions({\n rawBody,\n reasoningEffort,\n}: {\n rawBody: unknown;\n reasoningEffort: string | undefined;\n}): JSONObject | undefined {\n const thinking = readBodyField({ rawBody, key: 'thinking' });\n const reasoningHistory = readBodyField({ rawBody, key: 'reasoning_history' });\n const opts: JSONObject = {\n // Moonshot's own ceiling is `max`; the aliased `xhigh` is not one of its levels.\n ...maxEffortOption(reasoningEffort),\n ...(thinking !== undefined ? { thinking } : {}),\n ...(reasoningHistory !== undefined ? { reasoningHistory } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/** Qwen resolves the top-level effort into a thinking budget; these override that resolution. */\nfunction alibabaProviderOptions(rawBody: unknown): JSONObject | undefined {\n const enableThinking = readBodyField({ rawBody, key: 'enable_thinking' });\n const thinkingBudget = readBodyField({ rawBody, key: 'thinking_budget' });\n const parallelToolCalls = readBodyField({ rawBody, key: 'parallel_tool_calls' });\n const opts: JSONObject = {\n ...(enableThinking !== undefined ? { enableThinking } : {}),\n ...(thinkingBudget !== undefined ? { thinkingBudget } : {}),\n ...(parallelToolCalls !== undefined ? { parallelToolCalls } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/**\n * The adapter copies options outside its own schema into the body under the same key, so these are\n * wire names, not camelCase. Unvalidated: a field the endpoint rejects fails loudly.\n */\nconst COMPATIBLE_BODY_FIELDS = [\n 'service_tier',\n 'user',\n 'prompt_cache_key',\n 'parallel_tool_calls',\n 'thinking',\n 'thinking_budget',\n 'enable_thinking',\n 'reasoning_history',\n] as const;\n\nfunction compatibleProviderOptions({\n strictJsonSchema,\n reasoningEffort,\n rawBody,\n}: {\n strictJsonSchema: boolean | undefined;\n reasoningEffort: string | undefined;\n rawBody: unknown;\n}): JSONObject | undefined {\n const forwarded: JSONObject = Object.fromEntries(\n COMPATIBLE_BODY_FIELDS.flatMap(key => {\n const value = readBodyField({ rawBody, key });\n return value === undefined ? [] : [[key, value] as const];\n }),\n );\n const opts: JSONObject = {\n // These endpoints discard an effort they do not recognise, and `xhigh` is one of those.\n ...maxEffortOption(reasoningEffort),\n ...forwarded,\n ...(strictJsonSchema !== undefined ? { strictJsonSchema } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/**\n * Provider-specific fields in `rawBody` (`cache_control`, `service_tier`, `safety_settings`, …)\n * are forwarded by snake_case key with no validation.\n */\nexport function buildProviderOptions({\n config,\n reasoningEffort,\n structuredOutputSpec,\n rawBody,\n}: {\n config: VercelAIProviderConfig;\n /** The requested effort, which rides in the top-level `reasoning` setting for every provider. */\n reasoningEffort: string | undefined;\n structuredOutputSpec: StructuredOutputSpec;\n rawBody: unknown;\n}): ProviderOptions {\n const strictJsonSchema = structuredOutputSpec.mode === 'json_schema' ? structuredOutputSpec.strict : undefined;\n if (config.provider.type === 'openai') {\n return { openai: openaiProviderOptions({ rawBody, strictJsonSchema, reasoningEffort }) };\n } else if (config.provider.type === 'anthropic') {\n const anthropic = anthropicProviderOptions(rawBody);\n return anthropic !== undefined ? { anthropic } : {};\n } else if (config.provider.type === 'google-gemini') {\n const google = googleGeminiProviderOptions({ rawBody, reasoningRequested: reasoningEffort !== undefined });\n return google !== undefined ? { google } : {};\n } else if (config.provider.type === 'moonshot') {\n // The package names its options key after itself, not after the provider.\n const moonshotai = moonshotProviderOptions({ rawBody, reasoningEffort });\n return moonshotai !== undefined ? { moonshotai } : {};\n } else if (config.provider.type === 'alibaba') {\n const alibaba = alibabaProviderOptions(rawBody);\n return alibaba !== undefined ? { alibaba } : {};\n } else {\n // The remaining providers all share the compatible adapter, which reads its options from a key\n // matching the `name` it was built with — the provider type itself.\n const compatible = compatibleProviderOptions({ strictJsonSchema, reasoningEffort, rawBody });\n return compatible !== undefined ? { [config.provider.type]: compatible } : {};\n }\n}\n\n// ---------------------------------------------------------------------------\n// Request conversion (OpenAI → SDK)\n// ---------------------------------------------------------------------------\n\n/** Prefers `max_completion_tokens`, falling back to the deprecated `max_tokens`. */\nexport function resolveMaxOutputTokens(\n body: Pick<ChatCompletionCreateParamsStreaming, 'max_completion_tokens'>,\n): number | undefined {\n const limit: unknown = body.max_completion_tokens ?? Reflect.get(body, 'max_tokens');\n return typeof limit === 'number' ? limit : undefined;\n}\n\n/** Parses the MIME type from a data URI (`data:<mime>;base64,...`). */\nexport function parseMimeFromDataUri(uri: string): string | undefined {\n const match = /^data:([^;,]+)/.exec(uri);\n return match?.[1];\n}\n\n/** Returns `undefined` for parts with no inline data, e.g. `file_id` only. */\nexport function toFilePart(file: {\n file_data?: string | undefined;\n filename?: string | undefined;\n}): FilePart | undefined {\n const { file_data, filename } = file;\n if (!file_data) {\n return undefined;\n }\n const mediaType = parseMimeFromDataUri(file_data) ?? 'application/octet-stream';\n return {\n type: 'file',\n data: file_data,\n mediaType,\n ...(filename !== undefined ? { filename } : {}),\n };\n}\n\n/** Converts a user content array from OpenAI format to Vercel AI SDK UserContent. */\nexport function toUserContent(content: string | ChatCompletionContentPart[]): UserContent {\n if (typeof content === 'string') {\n return content;\n }\n const parts: UserContent = [];\n for (const part of content) {\n if (part.type === 'text') {\n parts.push({ type: 'text', text: part.text });\n continue;\n }\n if (part.type === 'image_url') {\n // ImagePart is deprecated in favour of FilePart.\n const url = part.image_url.url;\n const mediaType = parseMimeFromDataUri(url) ?? 'image/*';\n parts.push({ type: 'file', data: url, mediaType });\n continue;\n }\n if (part.type === 'file') {\n const filePart = toFilePart(part.file);\n if (filePart !== undefined) {\n parts.push(filePart);\n }\n // file_id-only parts are unsupported (require server-side lookup); skip.\n continue;\n }\n // input_audio — not universally supported across providers; omit.\n }\n return parts;\n}\n\n/**\n * Converts an assistant message to the SDK shape for multi-turn replay.\n *\n * Each adapter reads its reasoning-replay token from a different key, and a mismatch fails\n * silently: the adapter drops the reasoning part and the model loses its chain.\n * - `'openai'` → `openai.reasoningEncryptedContent`\n * - `'anthropic'` → `anthropic.signature`\n * - `'google-gemini'` → per-tool-call `google.thoughtSignature`, no standalone reasoning block\n * - `'custom'` → OpenAI-compatible ignores providerOptions, so the token has nowhere to go\n *\n * Signatures attach when `source` (`type/name/model`) matches both provider type and\n * provider name. Missing/foreign source → reasoning text only.\n */\nexport function toAssistantModelMessage({\n msg,\n provider,\n providerName,\n logger,\n}: {\n msg: Extract<ChatCompletionMessageParam, { role: 'assistant' }>;\n provider: VercelAIProviderName;\n /** Configured provider resource name. */\n providerName: string;\n logger?: Logger | undefined;\n}): ModelMessage {\n const parts: AssistantContent = [];\n\n // `thinking_blocks` / `source` are attached at runtime by AgentThread and absent from the OpenAI SDK type.\n const rawThinking: unknown = Reflect.get(msg, 'thinking_blocks');\n const attachSignature = shouldAttachReasoningSignature({\n source: Reflect.get(msg, 'source'),\n provider,\n providerName,\n logger,\n });\n // Alibaba appends replayed thinking to the visible answer, and Qwen signs nothing to preserve.\n if (Array.isArray(rawThinking) && provider !== 'alibaba') {\n // Widen any[] → unknown[] so the in-guards below narrow safely.\n const blocks: unknown[] = rawThinking;\n for (const tb of blocks) {\n if (\n typeof tb === 'object' &&\n tb !== null &&\n 'type' in tb &&\n 'thinking' in tb &&\n tb.type === 'thinking' &&\n typeof tb.thinking === 'string'\n ) {\n const signature = 'signature' in tb && typeof tb.signature === 'string' ? tb.signature : undefined;\n let reasoningProviderOptions: ProviderOptions | undefined;\n if (signature !== undefined && attachSignature) {\n if (provider === 'openai') {\n reasoningProviderOptions = { openai: { reasoningEncryptedContent: signature } };\n } else if (provider === 'anthropic') {\n reasoningProviderOptions = { anthropic: { signature } };\n }\n }\n const reasoningPart: ReasoningPart = {\n type: 'reasoning',\n text: tb.thinking,\n ...(reasoningProviderOptions !== undefined ? { providerOptions: reasoningProviderOptions } : {}),\n };\n parts.push(reasoningPart);\n }\n }\n }\n\n const rawContent = msg.content;\n if (rawContent) {\n const text =\n typeof rawContent === 'string'\n ? rawContent\n : rawContent\n .filter((p): p is { type: 'text'; text: string } => p.type === 'text')\n .map(p => p.text)\n .join('');\n if (text) {\n const textPart: TextPart = { type: 'text', text };\n parts.push(textPart);\n }\n }\n\n if (msg.tool_calls?.length) {\n for (const tc of msg.tool_calls) {\n if (!isFunctionToolCall(tc)) {\n continue;\n }\n let input: Record<string, unknown> = {};\n try {\n const parsed: unknown = JSON.parse(tc.function.arguments);\n if (isPlainObject(parsed)) {\n input = parsed;\n }\n } catch {\n // malformed arguments — leave empty record\n }\n const rawProviderFields: unknown = Reflect.get(tc, 'provider_specific_fields');\n const thoughtSignature =\n isPlainObject(rawProviderFields) && typeof rawProviderFields['thought_signature'] === 'string'\n ? rawProviderFields['thought_signature']\n : undefined;\n const toolCallPart: ToolCallPart = {\n type: 'tool-call',\n toolCallId: tc.id,\n toolName: tc.function.name,\n input,\n ...(thoughtSignature !== undefined\n ? { providerOptions: { google: { thoughtSignature } } satisfies ProviderOptions }\n : {}),\n };\n parts.push(toolCallPart);\n }\n }\n\n return {\n role: 'assistant',\n content: parts.length > 0 ? parts : [{ type: 'text', text: '' }],\n };\n}\n\n/** Parse `provider_type/provider_name/model_name`. */\nfunction parseAssistantMessageSource(\n source: string,\n): { providerType: string; providerName: string; modelName: string } | undefined {\n const [providerType, providerName, modelName, ...rest] = source.split('/');\n if (rest.length > 0 || !providerType || !providerName || !modelName) {\n return undefined;\n }\n return { providerType, providerName, modelName };\n}\n\n/** Attach when both provider type and configured provider name match `source`. */\nexport function shouldAttachReasoningSignature({\n source,\n provider,\n providerName,\n logger,\n}: {\n source: unknown;\n provider: VercelAIProviderName;\n providerName: string;\n logger?: Logger | undefined;\n}): boolean {\n if (source === undefined) {\n return false;\n }\n if (typeof source !== 'string') {\n logger?.warn('Ignoring non-string assistant message source; skipping reasoning signature replay', { source });\n return false;\n }\n const parsed = parseAssistantMessageSource(source);\n if (parsed === undefined) {\n logger?.warn('Ignoring malformed assistant message source; skipping reasoning signature replay', { source });\n return false;\n }\n return parsed.providerType === provider && parsed.providerName === providerName;\n}\n\nexport interface ConvertedMessages {\n instructions: string | undefined;\n messages: ModelMessage[];\n}\n\n/**\n * System messages are extracted into `instructions`, since SDK v7 no longer accepts\n * `{ role: 'system' }` in the messages array. The toolCallId → toolName lookup is built first\n * because tool result messages carry only the id.\n */\nexport function convertMessages({\n messages,\n provider,\n providerName,\n logger,\n}: {\n messages: ChatCompletionMessageParam[];\n provider: VercelAIProviderName;\n providerName: string;\n logger?: Logger | undefined;\n}): ConvertedMessages {\n const toolNameById = new Map<string, string>();\n for (const msg of messages) {\n if (msg.role === 'assistant' && msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n if (!isFunctionToolCall(tc)) {\n continue;\n }\n toolNameById.set(tc.id, tc.function.name);\n }\n }\n }\n\n const systemParts: string[] = [];\n const result: ModelMessage[] = [];\n for (const msg of messages) {\n if (msg.role === 'system') {\n const content = typeof msg.content === 'string' ? msg.content : msg.content.map(p => p.text).join('');\n systemParts.push(content);\n continue;\n }\n if (msg.role === 'user') {\n result.push({ role: 'user', content: toUserContent(msg.content) });\n continue;\n }\n if (msg.role === 'assistant') {\n result.push(toAssistantModelMessage({ msg, provider, providerName, logger }));\n continue;\n }\n if (msg.role === 'tool') {\n const toolName = toolNameById.get(msg.tool_call_id) ?? '';\n const toolContent: ToolContent = [\n {\n type: 'tool-result',\n toolCallId: msg.tool_call_id,\n toolName,\n output: {\n type: 'text',\n value: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),\n },\n },\n ];\n result.push({ role: 'tool', content: toolContent });\n continue;\n }\n // 'developer' / 'function' roles — not used in the harness pipeline; skip.\n }\n return { instructions: systemParts.length > 0 ? systemParts.join('\\n\\n') : undefined, messages: result };\n}\n\n/** Converts OpenAI tool definitions to the Vercel AI SDK ToolSet. */\nexport function convertTools(tools: ChatCompletionTool[] | undefined): ToolSet | undefined {\n if (!tools?.length) {\n return undefined;\n }\n const toolSet: ToolSet = {};\n for (const t of tools) {\n if (!isFunctionTool(t)) {\n continue;\n }\n toolSet[t.function.name] = {\n inputSchema: jsonSchema(t.function.parameters ?? { type: 'object', properties: {} }),\n ...(t.function.description !== undefined ? { description: t.function.description } : {}),\n };\n }\n return Object.keys(toolSet).length > 0 ? toolSet : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// streamText args\n// ---------------------------------------------------------------------------\n\n/**\n * Pure-data subset of `streamText(...)`'s call args. Uses `?` rather than this file's usual\n * explicit `| undefined`, to match `streamText`'s own signature under `exactOptionalPropertyTypes`.\n */\nexport type StreamTextArgs = LanguageModelCallOptions & {\n model: LanguageModel;\n instructions?: string;\n messages: ModelMessage[];\n tools?: ToolSet;\n providerOptions?: ProviderOptions;\n abortSignal?: AbortSignal;\n maxRetries: number;\n};\n\n/**\n * Exported so the final wiring is unit-testable: a value computed correctly but never spread into\n * this object would pass every sub-function test. `output` is excluded and spread by the caller,\n * since its unnameable type would make this function's return type unnameable too.\n */\nexport function buildStreamTextArgs(input: {\n model: LanguageModel;\n instructions: string | undefined;\n messages: ModelMessage[];\n tools: ToolSet | undefined;\n reasoning: ReasoningLevel | undefined;\n providerOptions: ProviderOptions;\n maxOutputTokens: number | undefined;\n temperature: number | null | undefined;\n topP: number | null | undefined;\n topK: number | null | undefined;\n presencePenalty: number | null | undefined;\n frequencyPenalty: number | null | undefined;\n stopSequences: string[] | null | undefined;\n seed: number | null | undefined;\n abortSignal: AbortSignal | undefined;\n}): StreamTextArgs {\n const {\n model,\n instructions,\n messages,\n tools,\n reasoning,\n providerOptions,\n maxOutputTokens,\n temperature,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n stopSequences,\n seed,\n abortSignal,\n } = input;\n return {\n model,\n ...(instructions !== undefined ? { instructions } : {}),\n messages,\n ...(tools !== undefined ? { tools } : {}),\n ...(reasoning !== undefined ? { reasoning } : {}),\n ...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { topP } : {}),\n ...(topK != null ? { topK } : {}),\n ...(presencePenalty != null ? { presencePenalty } : {}),\n ...(frequencyPenalty != null ? { frequencyPenalty } : {}),\n ...(stopSequences != null ? { stopSequences } : {}),\n ...(seed != null ? { seed } : {}),\n ...(Object.keys(providerOptions).length > 0 ? { providerOptions } : {}),\n ...(abortSignal !== undefined ? { abortSignal } : {}),\n maxRetries: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stream mapping (SDK → harness chunks)\n// ---------------------------------------------------------------------------\n\n/** Maps Vercel AI SDK LanguageModelUsage → harness CompletionUsage. */\nexport function normalizeUsage(usage: {\n inputTokens: number | undefined;\n outputTokens: number | undefined;\n inputTokenDetails: {\n cacheReadTokens: number | undefined;\n cacheWriteTokens: number | undefined;\n noCacheTokens: number | undefined;\n };\n outputTokenDetails: {\n reasoningTokens: number | undefined;\n textTokens: number | undefined;\n };\n // LanguageModelUsage.raw: AI SDK has no cost field; extras like gateway costInUSD live here.\n raw?: JSONObject;\n}): CompletionUsage {\n const input = usage.inputTokens ?? 0;\n const output = usage.outputTokens ?? 0;\n const costInUsd = usage.raw?.['costInUSD'];\n return {\n input_tokens: input,\n output_tokens: output,\n total_tokens: input + output,\n cache_read_tokens: usage.inputTokenDetails.cacheReadTokens ?? undefined,\n cache_write_tokens: usage.inputTokenDetails.cacheWriteTokens ?? undefined,\n reasoning_tokens: usage.outputTokenDetails.reasoningTokens ?? undefined,\n cost_in_usd: typeof costInUsd === 'number' && costInUsd >= 0 ? costInUsd : undefined,\n };\n}\n\n/**\n * Prefer AI SDK `APICallError` (`message` / `statusCode`):\n * https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-api-call-error#properties\n * Fallback is required because stream `error` parts are typed `unknown` (not only\n * `APICallError`) — plain objects would otherwise stringify to \"[object Object]\".\n */\nexport function describeStreamError(raw: unknown): string {\n if (APICallError.isInstance(raw)) {\n if (raw.statusCode != null) {\n return `Request failed (${String(raw.statusCode)}): ${raw.message}`;\n }\n return raw.message;\n }\n return describeUnknownError(raw);\n}\n\nexport function toStreamError(raw: unknown): Error {\n if (raw instanceof Error) {\n return raw;\n }\n return new Error(describeStreamError(raw), { cause: raw });\n}\n\nexport function mapFinishReason(reason: FinishReason): RawAssistantMessageWithUsage['finish_reason'] {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool-calls':\n return 'tool_calls';\n case 'content-filter':\n return 'content_filter';\n // No harness equivalent for these — fall back to 'stop'.\n case 'error':\n case 'other':\n return 'stop';\n default: {\n const _exhaustive: never = reason;\n throw new Error(`Unknown finish reason: ${String(_exhaustive)}`);\n }\n }\n}\n\ninterface ToolCallState {\n index: number;\n id: string;\n name: string;\n arguments: string;\n /** Gemini `thoughtSignature` from `providerMetadata.google` on the `tool-input-start` part. */\n thoughtSignature: string | undefined;\n}\n\n/**\n * Copies the reasoning-replay token onto the block, scanning every provider namespace since only\n * the active one is populated. Providers disagree on where it arrives: OpenAI attaches it to\n * `reasoning-end`, Anthropic to a text-less `reasoning-delta`. Missing either silently loses the\n * chain, since unsigned thinking blocks are dropped on replay.\n */\nfunction applyReasoningSignature({\n block,\n providerMetadata,\n}: {\n block: ThinkingBlock;\n providerMetadata: ProviderMetadata | undefined;\n}): void {\n if (providerMetadata === undefined) {\n return;\n }\n for (const meta of Object.values(providerMetadata)) {\n if ('reasoningEncryptedContent' in meta && typeof meta['reasoningEncryptedContent'] === 'string') {\n block.signature = meta['reasoningEncryptedContent'];\n return;\n }\n if ('signature' in meta && typeof meta['signature'] === 'string') {\n block.signature = meta['signature'];\n return;\n }\n }\n}\n\n/**\n * Which reasoning item a stream part belongs to. OpenAI is alone in splitting one item across\n * several parts, so elsewhere this is absent and every part stands on its own.\n */\nfunction reasoningItemId(providerMetadata: ProviderMetadata | undefined): string | undefined {\n if (providerMetadata === undefined) {\n return undefined;\n }\n for (const meta of Object.values(providerMetadata)) {\n if ('itemId' in meta && typeof meta['itemId'] === 'string') {\n return meta['itemId'];\n }\n }\n return undefined;\n}\n\n/**\n * Where the SDK reports what it changed about our request: an effort a model cannot honour and so\n * was coerced, a setting the provider ignored. Nothing else surfaces these.\n */\nexport function describeCallWarning(warning: CallWarning): string {\n switch (warning.type) {\n case 'unsupported':\n case 'compatibility':\n return warning.details !== undefined\n ? `${warning.type}: ${warning.feature} (${warning.details})`\n : `${warning.type}: ${warning.feature}`;\n case 'deprecated':\n return `deprecated: ${warning.setting} - ${warning.message}`;\n case 'other':\n return `other: ${warning.message}`;\n default: {\n const _exhaustive: never = warning;\n throw new Error(`Unknown call warning: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n/** Synthetic chunk fields shared by every chunk emitted for a single stream. */\ninterface ChunkMeta {\n id: string;\n created: number;\n model: string;\n}\n\n/**\n * Converts an SDK stream into harness chunks, returning the aggregated assistant message.\n * Takes a plain `AsyncIterable` so hand-built fixtures work in tests.\n */\nexport async function* mapStreamToChunks({\n stream,\n chunkMeta,\n}: {\n stream: AsyncIterable<TextStreamPart<ToolSet>>;\n chunkMeta: ChunkMeta;\n}): AsyncGenerator<ExtendedChatCompletionChunk, RawAssistantMessageWithUsage, unknown> {\n const makeBase = (): Omit<ExtendedChatCompletionChunk, 'choices' | 'usage'> => ({\n id: chunkMeta.id,\n object: 'chat.completion.chunk' as const,\n created: chunkMeta.created,\n model: chunkMeta.model,\n });\n\n const toolCallStates = new Map<string, ToolCallState>();\n let nextToolIndex = 0;\n let accumulatedText = '';\n const accumulatedThinking: ThinkingBlock[] = [];\n const thinkingByReasoningItem = new Map<string, ThinkingBlock>();\n let currentThinkingBlock: ThinkingBlock | null = null;\n\n /**\n * The block this reasoning part belongs to: the one already open for its item, or a new one.\n *\n * OpenAI streams a single reasoning item as several summary parts, and hands every part the one\n * token that identifies the item. A block per part would therefore replay that item once per\n * part, every copy presenting the same token with a different piece of the reasoning. Grouping by\n * item keeps one block per token, which is the only shape the provider can be replayed.\n */\n const openThinkingBlock = (providerMetadata: ProviderMetadata | undefined): ThinkingBlock => {\n const itemId = reasoningItemId(providerMetadata);\n const started = itemId !== undefined ? thinkingByReasoningItem.get(itemId) : undefined;\n if (started !== undefined) {\n // Each part is its own titled paragraph, and a part can be empty.\n if (started.thinking.length > 0) {\n started.thinking += '\\n\\n';\n }\n return started;\n }\n const block: ThinkingBlock = { type: 'thinking', thinking: '' };\n accumulatedThinking.push(block);\n if (itemId !== undefined) {\n thinkingByReasoningItem.set(itemId, block);\n }\n return block;\n };\n let finalUsage: CompletionUsage = getEmptyUsage();\n let finalFinishReason: RawAssistantMessageWithUsage['finish_reason'] = 'stop';\n\n for await (const part of stream) {\n switch (part.type) {\n case 'text-delta': {\n accumulatedText += part.text;\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: { content: part.text, role: 'assistant' },\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'reasoning-start': {\n currentThinkingBlock = openThinkingBlock(part.providerMetadata);\n break;\n }\n\n case 'reasoning-delta': {\n // A delta with no preceding `reasoning-start` would otherwise drop the block and its\n // signature, breaking replay while the text still streams out.\n currentThinkingBlock ??= openThinkingBlock(part.providerMetadata);\n currentThinkingBlock.thinking += part.text;\n applyReasoningSignature({ block: currentThinkingBlock, providerMetadata: part.providerMetadata });\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {\n thinking_blocks: [{ type: 'thinking', thinking: part.text }],\n reasoning_content: part.text,\n } satisfies ExtendedChatCompletionChunk['choices'][0]['delta'],\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'reasoning-end': {\n if (currentThinkingBlock !== null) {\n applyReasoningSignature({ block: currentThinkingBlock, providerMetadata: part.providerMetadata });\n }\n currentThinkingBlock = null;\n break;\n }\n\n case 'tool-input-start': {\n const idx = nextToolIndex++;\n // Gemini's replay token arrives here, and only here, for thinking models.\n const googleMeta = part.providerMetadata?.['google'];\n const thoughtSignature =\n googleMeta !== undefined && typeof googleMeta['thoughtSignature'] === 'string'\n ? googleMeta['thoughtSignature']\n : undefined;\n toolCallStates.set(part.id, {\n index: idx,\n id: part.id,\n name: part.toolName,\n arguments: '',\n thoughtSignature,\n });\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [\n {\n index: idx,\n id: part.id,\n type: 'function',\n function: { name: part.toolName, arguments: '' },\n },\n ],\n },\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'tool-input-delta': {\n const state = toolCallStates.get(part.id);\n // With no matching `tool-input-start` there is no index to attribute this to; emitting it\n // anyway would append the arguments to an unrelated tool call.\n if (state === undefined) {\n break;\n }\n state.arguments += part.delta;\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [{ index: state.index, function: { arguments: part.delta } }],\n },\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'finish-step': {\n finalUsage = normalizeUsage(part.usage);\n finalFinishReason = mapFinishReason(part.finishReason);\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {},\n finish_reason: finalFinishReason,\n logprobs: null,\n },\n ],\n usage: finalUsage,\n };\n break;\n }\n\n case 'error': {\n const raw = part.error;\n const message = describeStreamError(raw);\n // Preserve the original stream error as cause; toast/turn use .message only.\n const cause = raw instanceof Error ? raw : new Error(message);\n throw new Error(message, { cause });\n }\n\n case 'abort': {\n const aborted = new Error('LLM stream aborted');\n aborted.name = 'AbortError';\n throw aborted;\n }\n\n case 'start':\n case 'text-start':\n case 'text-end':\n case 'custom':\n case 'tool-input-end':\n case 'source':\n case 'file':\n case 'reasoning-file':\n case 'tool-call':\n case 'tool-result':\n case 'tool-error':\n case 'tool-output-denied':\n case 'tool-approval-request':\n case 'tool-approval-response':\n case 'start-step':\n case 'finish':\n case 'raw':\n // Structural/bookkeeping events — no harness chunk is emitted for these.\n break;\n\n default: {\n const _exhaustive: never = part;\n throw new Error(`Unknown stream part type: ${JSON.stringify(_exhaustive)}`);\n }\n }\n }\n\n const toolCalls = [...toolCallStates.values()]\n .sort((a, b) => a.index - b.index)\n .map(tc => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: tc.arguments },\n ...(tc.thoughtSignature !== undefined\n ? { provider_specific_fields: { thought_signature: tc.thoughtSignature } }\n : {}),\n }));\n\n const output: RawAssistantMessage = {\n role: 'assistant',\n content: accumulatedText || null,\n ...(accumulatedThinking.length > 0 ? { thinking_blocks: accumulatedThinking } : {}),\n ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n };\n\n return { usage: finalUsage, output, finish_reason: finalFinishReason };\n}\n\n// ---------------------------------------------------------------------------\n// VercelAILLM\n// ---------------------------------------------------------------------------\n\n/** ILLM implementation backed by Vercel AI SDK, supporting multiple LLM providers. */\nexport class VercelAILLM implements ILLM {\n private readonly config: VercelAILLMConfig;\n private readonly logger: Logger;\n private readonly signal: AbortSignal | undefined;\n\n constructor(config: VercelAILLMConfig) {\n this.config = config;\n this.logger = config.logger;\n this.signal = config.signal;\n }\n\n async *create(\n body: LLMCreateParamsStreaming,\n ): AsyncGenerator<ExtendedChatCompletionChunk, RawAssistantMessageWithUsage, unknown> {\n const { providerConfig } = this.config;\n const languageModel = buildLanguageModel(providerConfig);\n const { provider, model } = providerConfig;\n\n const { instructions, messages } = convertMessages({\n messages: body.messages,\n provider: provider.type,\n providerName: provider.name,\n logger: this.logger,\n });\n const tools = convertTools(body.tools ?? undefined);\n const structuredOutputSpec = toStructuredOutputSpec(body.response_format);\n const output = buildOutput(structuredOutputSpec);\n\n // reasoning_effort is injected by AgentThread via Object.assign; not in the SDK type.\n const rawReasoningEffort: unknown = Reflect.get(body, 'reasoning_effort');\n const reasoningEffort = typeof rawReasoningEffort === 'string' ? rawReasoningEffort : undefined;\n const providerOptions = buildProviderOptions({\n config: providerConfig,\n reasoningEffort,\n structuredOutputSpec,\n rawBody: body,\n });\n const reasoning = toReasoningLevel(reasoningEffort);\n\n // top_k is injected by AgentThread via Object.assign; not in the SDK type.\n const rawTopK: unknown = Reflect.get(body, 'top_k');\n // seed is still accepted by providers but marked @deprecated on the OpenAI request type.\n const rawSeed: unknown = Reflect.get(body, 'seed');\n const streamTextArgs = buildStreamTextArgs({\n model: languageModel,\n instructions,\n messages,\n tools,\n reasoning,\n providerOptions,\n maxOutputTokens: resolveMaxOutputTokens(body),\n temperature: body.temperature,\n topP: body.top_p,\n topK: typeof rawTopK === 'number' ? rawTopK : null,\n presencePenalty: body.presence_penalty,\n frequencyPenalty: body.frequency_penalty,\n stopSequences: typeof body.stop === 'string' ? [body.stop] : (body.stop ?? null),\n seed: typeof rawSeed === 'number' ? rawSeed : null,\n abortSignal: this.signal,\n });\n\n let streamResult;\n try {\n streamResult = streamText({\n ...streamTextArgs,\n ...(output !== undefined ? { output } : {}),\n });\n } catch (error) {\n if (this.signal?.aborted) {\n this.logger.debug('LLM call aborted', extractErrorLogFields(error));\n } else {\n this.logger.error('Error creating streaming chat completion', extractErrorLogFields(error));\n }\n throw toStreamError(error);\n }\n\n // Detached: warnings resolve at stream start, and a pending or rejected promise must never\n // stall the stream. Stream failures are reported by the error paths below.\n void streamResult.warnings.then(\n warnings => {\n if (warnings !== undefined && warnings.length > 0) {\n this.logger.warn('Provider adjusted the request', {\n model: providerConfig.name,\n warnings: warnings.map(describeCallWarning),\n });\n }\n },\n (reason: unknown) => {\n // Rejects with the same failure the stream throws, which the error paths below already log.\n this.logger.debug('Provider warnings unavailable', extractErrorLogFields(reason));\n },\n );\n\n // Synthetic chunk fields; id is unique per stream instance.\n // Label chunks with the display name — model.id is the wire id.\n const chunkMeta: ChunkMeta = {\n id: `vc-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,\n created: Math.floor(Date.now() / 1000),\n model: providerConfig.name,\n };\n\n try {\n const result = yield* mapStreamToChunks({ stream: streamResult.stream, chunkMeta });\n result.output.source = `${provider.type}/${provider.name}/${model.name}`;\n return result;\n } catch (error) {\n if (this.signal?.aborted) {\n this.logger.debug('LLM stream aborted', extractErrorLogFields(error));\n } else {\n this.logger.error('Error reading LLM stream', extractErrorLogFields(error));\n }\n throw toStreamError(error);\n }\n }\n\n async createNonStream(body: LLMCreateParams): Promise<RawAssistantMessageWithUsage> {\n // Drain the streaming generator — reuses the same accumulation and error handling path.\n const llmStream = this.create({ ...body, stream: true });\n let result = await llmStream.next();\n while (!result.done) {\n result = await llmStream.next();\n }\n return result.value;\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/llm/VercelAILLM.ts"],"sourcesContent":["import { createAlibaba } from '@ai-sdk/alibaba';\nimport { createAnthropic } from '@ai-sdk/anthropic';\nimport { createGoogle } from '@ai-sdk/google';\nimport type { MoonshotAIProviderOptions } from '@ai-sdk/moonshotai';\nimport { createMoonshotAI } from '@ai-sdk/moonshotai';\nimport type { OpenAIResponsesProviderOptions } from '@ai-sdk/openai';\nimport { createOpenAI } from '@ai-sdk/openai';\nimport type { OpenAICompatibleProviderOptions } from '@ai-sdk/openai-compatible';\nimport { createOpenAICompatible } from '@ai-sdk/openai-compatible';\nimport type { JSONObject } from '@ai-sdk/provider';\nimport type { ProviderOptions, ReasoningPart } from '@ai-sdk/provider-utils';\nimport type {\n AssistantContent,\n CallWarning,\n FilePart,\n FinishReason,\n JSONValue,\n LanguageModel,\n LanguageModelCallOptions,\n ModelMessage,\n ProviderMetadata,\n TextPart,\n TextStreamPart,\n ToolCallPart,\n ToolContent,\n ToolSet,\n UserContent,\n} from 'ai';\nimport { APICallError, jsonSchema, Output, streamText } from 'ai';\nimport type {\n ChatCompletionContentPart,\n ChatCompletionCreateParamsStreaming,\n ChatCompletionMessageParam,\n ChatCompletionTool,\n} from 'openai/resources/chat';\nimport type { Logger } from 'winston';\nimport { describeUnknownError, extractErrorLogFields } from '../util/errorLogFields';\nimport type { ILLM, LLMCreateParams, LLMCreateParamsStreaming } from './ILLM';\nimport {\n type CompletionUsage,\n type ExtendedChatCompletionChunk,\n getEmptyUsage,\n type RawAssistantMessage,\n type RawAssistantMessageWithUsage,\n type ThinkingBlock,\n} from './LLMTypes';\n\n// ---------------------------------------------------------------------------\n// Public config\n// ---------------------------------------------------------------------------\n\n/**\n * Providers with a case in {@link buildLanguageModel}. Canonical: the server derives the provider\n * types it will configure from this, so anything it accepts has an adapter behind it.\n */\nexport const VERCEL_AI_PROVIDER_NAMES = [\n 'openai',\n 'anthropic',\n 'google-gemini',\n 'fireworks',\n 'zai',\n 'moonshot',\n 'alibaba',\n 'together',\n 'custom',\n 'truefoundry',\n] as const;\n\nexport type VercelAIProviderName = (typeof VERCEL_AI_PROVIDER_NAMES)[number];\n\n/**\n * Adapter-facing config, camelCase throughout. Callers translate from the snake_case wire and\n * storage shapes, which stay as they are because they are the published contract.\n */\nexport interface VercelAIProviderConfig {\n /** Adapter discriminator plus configured resource name (source `type/name/...`). */\n provider: {\n type: VercelAIProviderName;\n name: string;\n };\n /** Provider-facing model identifier and configured model name. */\n model: {\n id: string;\n name: string;\n };\n /** Display name / alias, used for logs and chunk labels. */\n name: string;\n /** Optional base URL override. Explicitly includes `undefined` for Zod-derived type compat. */\n baseUrl?: string | undefined;\n apiKey: string;\n headers: Record<string, string>;\n}\n\nexport interface VercelAILLMConfig {\n providerConfig: VercelAIProviderConfig;\n logger: Logger;\n signal?: AbortSignal;\n}\n\n// ---------------------------------------------------------------------------\n// Shared predicates\n// ---------------------------------------------------------------------------\n\n/** Narrows to an indexable record. */\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** OpenAI SDK v7 unions function + custom tools; harness only emits function tools. */\nfunction isFunctionTool(tool: ChatCompletionTool): tool is Extract<ChatCompletionTool, { type: 'function' }> {\n return tool.type === 'function';\n}\n\n/** OpenAI SDK v7 unions function + custom tool calls; harness only consumes function calls. */\nfunction isFunctionToolCall<T extends { type: string }>(toolCall: T): toolCall is Extract<T, { type: 'function' }> {\n return toolCall.type === 'function';\n}\n\n// ---------------------------------------------------------------------------\n// Model construction\n// ---------------------------------------------------------------------------\n\n/**\n * Shared by every OpenAI-compatible provider, which differ only by endpoint. The provider type\n * doubles as the `providerOptions` key. Fireworks, Together and Z AI stay here rather than on their\n * own packages: those drop `json_schema`, and Fireworks also clamps efforts its models do accept.\n * TODO: move Z AI to @ai-sdk/zai once https://github.com/vercel/ai/pull/17340 ships.\n */\nfunction compatibleModel(config: VercelAIProviderConfig): LanguageModel {\n const { provider, model, apiKey, headers, baseUrl } = config;\n if (baseUrl === undefined) {\n throw new Error(`Provider \"${provider.type}\" requires a baseUrl`);\n }\n const client = createOpenAICompatible({\n name: provider.type,\n baseURL: baseUrl,\n apiKey,\n // Without this the adapter silently downgrades json_schema to a schema-less json_object.\n supportsStructuredOutputs: true,\n // These endpoints omit token counts from streamed responses unless asked.\n includeUsage: true,\n ...(Object.keys(headers).length > 0 ? { headers } : {}),\n });\n return client(model.id);\n}\n\nexport function buildLanguageModel(config: VercelAIProviderConfig): LanguageModel {\n const { provider, model, baseUrl, apiKey, headers } = config;\n const extraHeaders = Object.keys(headers).length > 0 ? headers : undefined;\n\n switch (provider.type) {\n case 'openai': {\n const client = createOpenAI({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client.responses(model.id);\n }\n case 'anthropic': {\n const client = createAnthropic({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'google-gemini': {\n const client = createGoogle({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'moonshot': {\n const client = createMoonshotAI({\n apiKey,\n ...(baseUrl !== undefined ? { baseURL: baseUrl } : {}),\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'alibaba': {\n // Endpoints are workspace-scoped, so the package default would address the wrong tenant.\n if (baseUrl === undefined) {\n throw new Error(`Provider \"alibaba\" requires a baseUrl`);\n }\n const client = createAlibaba({\n apiKey,\n baseURL: baseUrl,\n ...(extraHeaders !== undefined ? { headers: extraHeaders } : {}),\n });\n return client(model.id);\n }\n case 'fireworks':\n case 'zai':\n case 'together':\n case 'custom':\n case 'truefoundry': {\n return compatibleModel(config);\n }\n default: {\n const _exhaustive: never = provider.type;\n throw new Error(`Unknown provider \"${String(_exhaustive)}\"`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Reasoning effort\n// ---------------------------------------------------------------------------\n\n/**\n * The cross-provider `streamText({ reasoning })` setting, distinct from `providerOptions`. Derived\n * from the SDK's own type rather than mirrored by hand.\n */\ntype ReasoningLevel = NonNullable<LanguageModelCallOptions['reasoning']>;\n\nconst COMMON_REASONING_LEVELS = [\n 'none',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n] as const satisfies readonly ReasoningLevel[];\n\nconst VERCEL_AI_REASONING_LEVELS = [\n 'provider-default',\n ...COMMON_REASONING_LEVELS,\n] as const satisfies readonly ReasoningLevel[];\n\n// Fails if any union member is missing.\ntrue satisfies Exclude<ReasoningLevel, (typeof VERCEL_AI_REASONING_LEVELS)[number]> extends never ? true : never;\n\nfunction isReasoningLevel(v: string): v is ReasoningLevel {\n return VERCEL_AI_REASONING_LEVELS.some(level => level === v);\n}\n\n/**\n * Efforts the SDK's union cannot express. `xhigh` is its ceiling, so `max` rides in as `xhigh`;\n * Anthropic's adapter raises that back, and {@link maxEffortOption} covers the rest.\n * Keys here must also appear in {@link SUPPORTED_REASONING_EFFORTS}.\n */\nconst EFFORT_ALIASES: Readonly<Record<string, ReasoningLevel>> = { max: 'xhigh' };\n\n/** What a model may advertise in `reasoning_efforts`; anything else resolves to the provider default. */\nexport const SUPPORTED_REASONING_EFFORTS = [...COMMON_REASONING_LEVELS, 'max'] as const;\n\n/**\n * The effort travels on the top-level `reasoning` setting, which each adapter translates per model:\n * an effort string for OpenAI-shaped APIs, a thinking shape for Anthropic, a level or budget for\n * Gemini. A reasoning `providerOptions` entry replaces that path rather than merging with it.\n */\nexport function toReasoningLevel(reasoningEffort: string | undefined): ReasoningLevel | undefined {\n if (reasoningEffort === undefined) {\n return undefined;\n }\n const aliased = EFFORT_ALIASES[reasoningEffort];\n if (aliased !== undefined) {\n return aliased;\n }\n return isReasoningLevel(reasoningEffort) ? reasoningEffort : undefined;\n}\n\n/**\n * `max` needs each adapter's own option, which wins over the top-level setting; the callers below\n * say why. The intersection resolves to `'max'`, so a package dropping it breaks the build.\n */\ntype MaxEffortOption = Pick<OpenAIResponsesProviderOptions, 'reasoningEffort'> &\n Pick<OpenAICompatibleProviderOptions, 'reasoningEffort'> &\n Pick<MoonshotAIProviderOptions, 'reasoningEffort'>;\n\nfunction maxEffortOption(reasoningEffort: string | undefined): MaxEffortOption {\n return reasoningEffort === 'max' ? { reasoningEffort: 'max' } : {};\n}\n\n// ---------------------------------------------------------------------------\n// Structured output\n// ---------------------------------------------------------------------------\n\n/**\n * Kept as plain data rather than an SDK `Output` instance, since `Output` isn't a nameable\n * exported type from `ai` — see `buildOutput`.\n */\nexport type StructuredOutputSpec =\n | { mode: 'text' }\n | { mode: 'json' }\n | {\n mode: 'json_schema';\n schema: Record<string, unknown>;\n name: string;\n description: string | undefined;\n /** Mirrors `response_format.json_schema.strict`; consumed by `buildProviderOptions`. */\n strict: boolean | undefined;\n };\n\n/** Converts an OpenAI-format `response_format` into a normalized `StructuredOutputSpec`. */\nexport function toStructuredOutputSpec(\n responseFormat: ChatCompletionCreateParamsStreaming['response_format'],\n): StructuredOutputSpec {\n if (responseFormat === undefined || responseFormat.type === 'text') {\n return { mode: 'text' };\n }\n if (responseFormat.type === 'json_object') {\n return { mode: 'json' };\n }\n const { json_schema } = responseFormat;\n return {\n mode: 'json_schema',\n schema: json_schema.schema ?? { type: 'object', properties: {} },\n name: json_schema.name,\n description: json_schema.description,\n strict: json_schema.strict ?? undefined,\n };\n}\n\n/** Not exported: `Output`'s type isn't nameable outside `ai`, so a return type can't be declared. */\nfunction buildOutput(spec: StructuredOutputSpec) {\n switch (spec.mode) {\n case 'text':\n return undefined;\n case 'json':\n return Output.json();\n case 'json_schema':\n return Output.object({\n schema: jsonSchema(spec.schema),\n name: spec.name,\n ...(spec.description !== undefined ? { description: spec.description } : {}),\n });\n default: {\n const _exhaustive: never = spec;\n throw new Error(`Unknown structured output mode: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Provider options\n// ---------------------------------------------------------------------------\n\n/** `rawBody` is a parsed JSON request body, so any value present is a valid JSONValue. */\nfunction readBodyField({ rawBody, key }: { rawBody: unknown; key: string }): JSONValue | undefined {\n const val: unknown = Reflect.get(Object(rawBody), key);\n return val !== undefined ? (val as JSONValue) : undefined;\n}\n\nfunction openaiProviderOptions({\n rawBody,\n strictJsonSchema,\n reasoningEffort,\n}: {\n rawBody: unknown;\n strictJsonSchema: boolean | undefined;\n reasoningEffort: string | undefined;\n}): JSONObject {\n const serviceTier = readBodyField({ rawBody, key: 'service_tier' });\n const user = readBodyField({ rawBody, key: 'user' });\n const promptCacheKey = readBodyField({ rawBody, key: 'prompt_cache_key' });\n const parallelToolCalls = readBodyField({ rawBody, key: 'parallel_tool_calls' });\n const reasoningSummary = readBodyField({ rawBody, key: 'reasoning_summary' });\n // No server-side storage, and request the encrypted reasoning token so replay stays stateless.\n return {\n store: false,\n include: ['reasoning.encrypted_content'],\n reasoningSummary: 'auto',\n // gpt-5.6 serves both xhigh and max, so the aliased top-level level asks for one rung less.\n ...maxEffortOption(reasoningEffort),\n ...(reasoningSummary !== undefined ? { reasoningSummary } : {}),\n ...(strictJsonSchema !== undefined ? { strictJsonSchema } : {}),\n ...(serviceTier !== undefined ? { serviceTier } : {}),\n ...(user !== undefined ? { user } : {}),\n ...(promptCacheKey !== undefined ? { promptCacheKey } : {}),\n ...(parallelToolCalls !== undefined ? { parallelToolCalls } : {}),\n };\n}\n\n/**\n * Forwards but never pins `thinking` and `effort`: both replace the adapter's per-model resolution\n * and no single value fits every model. This is the caller's only route to disabling thinking, or to\n * the `display: 'summarized'` that makes Claude 5 return reasoning text instead of an empty block.\n *\n * Prompt caching defaults on: Anthropic bills a write once, then cheaper reads on stable prefixes\n * (system / tools / early messages). Callers can override via `cache_control` in the request body.\n */\nfunction anthropicProviderOptions(rawBody: unknown): JSONObject | undefined {\n const cacheControl = readBodyField({ rawBody, key: 'cache_control' }) ?? { type: 'ephemeral' };\n const disableParallelToolUse = readBodyField({ rawBody, key: 'disable_parallel_tool_use' });\n const thinking = readBodyField({ rawBody, key: 'thinking' });\n const effort = readBodyField({ rawBody, key: 'effort' });\n const opts: JSONObject = {\n cacheControl,\n ...(disableParallelToolUse !== undefined ? { disableParallelToolUse } : {}),\n ...(thinking !== undefined ? { thinking } : {}),\n ...(effort !== undefined ? { effort } : {}),\n };\n return opts;\n}\n\n/**\n * Gemini returns thought summaries only when `includeThoughts` is set, and `@ai-sdk/google` omits it\n * — without this the model bills reasoning tokens and returns none. The effort itself rides in the\n * top-level `reasoning` setting. An explicit `thinking_config` in the request body wins.\n */\nfunction googleGeminiThinkingConfig({\n rawBody,\n reasoningRequested,\n}: {\n rawBody: unknown;\n reasoningRequested: boolean;\n}): JSONValue | undefined {\n const fromBody = readBodyField({ rawBody, key: 'thinking_config' });\n if (!reasoningRequested) {\n return fromBody;\n }\n if (typeof fromBody === 'object' && fromBody !== null && !Array.isArray(fromBody)) {\n return { includeThoughts: true, ...fromBody };\n }\n return { includeThoughts: true };\n}\n\nfunction googleGeminiProviderOptions({\n rawBody,\n reasoningRequested,\n}: {\n rawBody: unknown;\n reasoningRequested: boolean;\n}): JSONObject | undefined {\n const safetySettings = readBodyField({ rawBody, key: 'safety_settings' });\n const thinkingConfig = googleGeminiThinkingConfig({ rawBody, reasoningRequested });\n const cachedContent = readBodyField({ rawBody, key: 'cached_content' });\n const opts: JSONObject = {\n ...(safetySettings !== undefined ? { safetySettings } : {}),\n ...(thinkingConfig !== undefined ? { thinkingConfig } : {}),\n ...(cachedContent !== undefined ? { cachedContent } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/**\n * `thinking` and `reasoning_history` are forwarded but never pinned: they are the caller's route to\n * turning thinking off, or to replaying it verbatim.\n */\nfunction moonshotProviderOptions({\n rawBody,\n reasoningEffort,\n}: {\n rawBody: unknown;\n reasoningEffort: string | undefined;\n}): JSONObject | undefined {\n const thinking = readBodyField({ rawBody, key: 'thinking' });\n const reasoningHistory = readBodyField({ rawBody, key: 'reasoning_history' });\n const opts: JSONObject = {\n // Moonshot's own ceiling is `max`; the aliased `xhigh` is not one of its levels.\n ...maxEffortOption(reasoningEffort),\n ...(thinking !== undefined ? { thinking } : {}),\n ...(reasoningHistory !== undefined ? { reasoningHistory } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/** Qwen resolves the top-level effort into a thinking budget; these override that resolution. */\nfunction alibabaProviderOptions(rawBody: unknown): JSONObject | undefined {\n const enableThinking = readBodyField({ rawBody, key: 'enable_thinking' });\n const thinkingBudget = readBodyField({ rawBody, key: 'thinking_budget' });\n const parallelToolCalls = readBodyField({ rawBody, key: 'parallel_tool_calls' });\n const opts: JSONObject = {\n ...(enableThinking !== undefined ? { enableThinking } : {}),\n ...(thinkingBudget !== undefined ? { thinkingBudget } : {}),\n ...(parallelToolCalls !== undefined ? { parallelToolCalls } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/**\n * The adapter copies options outside its own schema into the body under the same key, so these are\n * wire names, not camelCase. Unvalidated: a field the endpoint rejects fails loudly.\n */\nconst COMPATIBLE_BODY_FIELDS = [\n 'service_tier',\n 'user',\n 'prompt_cache_key',\n 'parallel_tool_calls',\n 'thinking',\n 'thinking_budget',\n 'enable_thinking',\n 'reasoning_history',\n] as const;\n\nfunction compatibleProviderOptions({\n strictJsonSchema,\n reasoningEffort,\n rawBody,\n}: {\n strictJsonSchema: boolean | undefined;\n reasoningEffort: string | undefined;\n rawBody: unknown;\n}): JSONObject | undefined {\n const forwarded: JSONObject = Object.fromEntries(\n COMPATIBLE_BODY_FIELDS.flatMap(key => {\n const value = readBodyField({ rawBody, key });\n return value === undefined ? [] : [[key, value] as const];\n }),\n );\n const opts: JSONObject = {\n // These endpoints discard an effort they do not recognise, and `xhigh` is one of those.\n ...maxEffortOption(reasoningEffort),\n ...forwarded,\n ...(strictJsonSchema !== undefined ? { strictJsonSchema } : {}),\n };\n return Object.keys(opts).length > 0 ? opts : undefined;\n}\n\n/**\n * Provider-specific fields in `rawBody` (`cache_control`, `service_tier`, `safety_settings`, …)\n * are forwarded by snake_case key with no validation.\n */\nexport function buildProviderOptions({\n config,\n reasoningEffort,\n structuredOutputSpec,\n rawBody,\n}: {\n config: VercelAIProviderConfig;\n /** The requested effort, which rides in the top-level `reasoning` setting for every provider. */\n reasoningEffort: string | undefined;\n structuredOutputSpec: StructuredOutputSpec;\n rawBody: unknown;\n}): ProviderOptions {\n const strictJsonSchema = structuredOutputSpec.mode === 'json_schema' ? structuredOutputSpec.strict : undefined;\n if (config.provider.type === 'openai') {\n return { openai: openaiProviderOptions({ rawBody, strictJsonSchema, reasoningEffort }) };\n } else if (config.provider.type === 'anthropic') {\n const anthropic = anthropicProviderOptions(rawBody);\n return anthropic !== undefined ? { anthropic } : {};\n } else if (config.provider.type === 'google-gemini') {\n const google = googleGeminiProviderOptions({ rawBody, reasoningRequested: reasoningEffort !== undefined });\n return google !== undefined ? { google } : {};\n } else if (config.provider.type === 'moonshot') {\n // The package names its options key after itself, not after the provider.\n const moonshotai = moonshotProviderOptions({ rawBody, reasoningEffort });\n return moonshotai !== undefined ? { moonshotai } : {};\n } else if (config.provider.type === 'alibaba') {\n const alibaba = alibabaProviderOptions(rawBody);\n return alibaba !== undefined ? { alibaba } : {};\n } else {\n // The remaining providers all share the compatible adapter, which reads its options from a key\n // matching the `name` it was built with — the provider type itself.\n const compatible = compatibleProviderOptions({ strictJsonSchema, reasoningEffort, rawBody });\n return compatible !== undefined ? { [config.provider.type]: compatible } : {};\n }\n}\n\n// ---------------------------------------------------------------------------\n// Request conversion (OpenAI → SDK)\n// ---------------------------------------------------------------------------\n\n/** Prefers `max_completion_tokens`, falling back to the deprecated `max_tokens`. */\nexport function resolveMaxOutputTokens(\n body: Pick<ChatCompletionCreateParamsStreaming, 'max_completion_tokens'>,\n): number | undefined {\n const limit: unknown = body.max_completion_tokens ?? Reflect.get(body, 'max_tokens');\n return typeof limit === 'number' ? limit : undefined;\n}\n\n/** Parses the MIME type from a data URI (`data:<mime>;base64,...`). */\nexport function parseMimeFromDataUri(uri: string): string | undefined {\n const match = /^data:([^;,]+)/.exec(uri);\n return match?.[1];\n}\n\n/** Returns `undefined` for parts with no inline data, e.g. `file_id` only. */\nexport function toFilePart(file: {\n file_data?: string | undefined;\n filename?: string | undefined;\n}): FilePart | undefined {\n const { file_data, filename } = file;\n if (!file_data) {\n return undefined;\n }\n const mediaType = parseMimeFromDataUri(file_data) ?? 'application/octet-stream';\n return {\n type: 'file',\n data: file_data,\n mediaType,\n ...(filename !== undefined ? { filename } : {}),\n };\n}\n\n/** Converts a user content array from OpenAI format to Vercel AI SDK UserContent. */\nexport function toUserContent(content: string | ChatCompletionContentPart[]): UserContent {\n if (typeof content === 'string') {\n return content;\n }\n const parts: UserContent = [];\n for (const part of content) {\n if (part.type === 'text') {\n parts.push({ type: 'text', text: part.text });\n continue;\n }\n if (part.type === 'image_url') {\n // ImagePart is deprecated in favour of FilePart.\n const url = part.image_url.url;\n const mediaType = parseMimeFromDataUri(url) ?? 'image/*';\n parts.push({ type: 'file', data: url, mediaType });\n continue;\n }\n if (part.type === 'file') {\n const filePart = toFilePart(part.file);\n if (filePart !== undefined) {\n parts.push(filePart);\n }\n // file_id-only parts are unsupported (require server-side lookup); skip.\n continue;\n }\n // input_audio — not universally supported across providers; omit.\n }\n return parts;\n}\n\n/**\n * Converts an assistant message to the SDK shape for multi-turn replay.\n *\n * Each adapter reads its reasoning-replay token from a different key, and a mismatch fails\n * silently: the adapter drops the reasoning part and the model loses its chain.\n * - `'openai'` → `openai.reasoningEncryptedContent`\n * - `'anthropic'` → `anthropic.signature`\n * - `'google-gemini'` → per-tool-call `google.thoughtSignature`, no standalone reasoning block\n * - `'custom'` → OpenAI-compatible ignores providerOptions, so the token has nowhere to go\n *\n * Signatures attach when `source` (`type/name/model`) matches both provider type and\n * provider name. Missing/foreign source → reasoning text only.\n */\nexport function toAssistantModelMessage({\n msg,\n provider,\n providerName,\n logger,\n}: {\n msg: Extract<ChatCompletionMessageParam, { role: 'assistant' }>;\n provider: VercelAIProviderName;\n /** Configured provider resource name. */\n providerName: string;\n logger?: Logger | undefined;\n}): ModelMessage {\n const parts: AssistantContent = [];\n\n // `thinking_blocks` / `source` are attached at runtime by AgentThread and absent from the OpenAI SDK type.\n const rawThinking: unknown = Reflect.get(msg, 'thinking_blocks');\n const attachSignature = shouldAttachReasoningSignature({\n source: Reflect.get(msg, 'source'),\n provider,\n providerName,\n logger,\n });\n // Alibaba appends replayed thinking to the visible answer, and Qwen signs nothing to preserve.\n if (Array.isArray(rawThinking) && provider !== 'alibaba') {\n // Widen any[] → unknown[] so the in-guards below narrow safely.\n const blocks: unknown[] = rawThinking;\n for (const tb of blocks) {\n if (\n typeof tb === 'object' &&\n tb !== null &&\n 'type' in tb &&\n 'thinking' in tb &&\n tb.type === 'thinking' &&\n typeof tb.thinking === 'string'\n ) {\n const signature = 'signature' in tb && typeof tb.signature === 'string' ? tb.signature : undefined;\n let reasoningProviderOptions: ProviderOptions | undefined;\n if (signature !== undefined && attachSignature) {\n if (provider === 'openai') {\n reasoningProviderOptions = { openai: { reasoningEncryptedContent: signature } };\n } else if (provider === 'anthropic') {\n reasoningProviderOptions = { anthropic: { signature } };\n }\n }\n const reasoningPart: ReasoningPart = {\n type: 'reasoning',\n text: tb.thinking,\n ...(reasoningProviderOptions !== undefined ? { providerOptions: reasoningProviderOptions } : {}),\n };\n parts.push(reasoningPart);\n }\n }\n }\n\n const rawContent = msg.content;\n if (rawContent) {\n const text =\n typeof rawContent === 'string'\n ? rawContent\n : rawContent\n .filter((p): p is { type: 'text'; text: string } => p.type === 'text')\n .map(p => p.text)\n .join('');\n if (text) {\n const textPart: TextPart = { type: 'text', text };\n parts.push(textPart);\n }\n }\n\n if (msg.tool_calls?.length) {\n for (const tc of msg.tool_calls) {\n if (!isFunctionToolCall(tc)) {\n continue;\n }\n let input: Record<string, unknown> = {};\n try {\n const parsed: unknown = JSON.parse(tc.function.arguments);\n if (isPlainObject(parsed)) {\n input = parsed;\n }\n } catch {\n // malformed arguments — leave empty record\n }\n const rawProviderFields: unknown = Reflect.get(tc, 'provider_specific_fields');\n const thoughtSignature =\n isPlainObject(rawProviderFields) && typeof rawProviderFields['thought_signature'] === 'string'\n ? rawProviderFields['thought_signature']\n : undefined;\n const toolCallPart: ToolCallPart = {\n type: 'tool-call',\n toolCallId: tc.id,\n toolName: tc.function.name,\n input,\n ...(thoughtSignature !== undefined\n ? { providerOptions: { google: { thoughtSignature } } satisfies ProviderOptions }\n : {}),\n };\n parts.push(toolCallPart);\n }\n }\n\n return {\n role: 'assistant',\n content: parts.length > 0 ? parts : [{ type: 'text', text: '' }],\n };\n}\n\n/** Parse `provider_type/provider_name/model_name`. */\nfunction parseAssistantMessageSource(\n source: string,\n): { providerType: string; providerName: string; modelName: string } | undefined {\n const [providerType, providerName, modelName, ...rest] = source.split('/');\n if (rest.length > 0 || !providerType || !providerName || !modelName) {\n return undefined;\n }\n return { providerType, providerName, modelName };\n}\n\n/** Attach when both provider type and configured provider name match `source`. */\nexport function shouldAttachReasoningSignature({\n source,\n provider,\n providerName,\n logger,\n}: {\n source: unknown;\n provider: VercelAIProviderName;\n providerName: string;\n logger?: Logger | undefined;\n}): boolean {\n if (source === undefined) {\n return false;\n }\n if (typeof source !== 'string') {\n logger?.warn('Ignoring non-string assistant message source; skipping reasoning signature replay', { source });\n return false;\n }\n const parsed = parseAssistantMessageSource(source);\n if (parsed === undefined) {\n logger?.warn('Ignoring malformed assistant message source; skipping reasoning signature replay', { source });\n return false;\n }\n return parsed.providerType === provider && parsed.providerName === providerName;\n}\n\nexport interface ConvertedMessages {\n instructions: string | undefined;\n messages: ModelMessage[];\n}\n\n/**\n * System messages are extracted into `instructions`, since SDK v7 no longer accepts\n * `{ role: 'system' }` in the messages array. The toolCallId → toolName lookup is built first\n * because tool result messages carry only the id.\n */\nexport function convertMessages({\n messages,\n provider,\n providerName,\n logger,\n}: {\n messages: ChatCompletionMessageParam[];\n provider: VercelAIProviderName;\n providerName: string;\n logger?: Logger | undefined;\n}): ConvertedMessages {\n const toolNameById = new Map<string, string>();\n for (const msg of messages) {\n if (msg.role === 'assistant' && msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n if (!isFunctionToolCall(tc)) {\n continue;\n }\n toolNameById.set(tc.id, tc.function.name);\n }\n }\n }\n\n const systemParts: string[] = [];\n const result: ModelMessage[] = [];\n for (const msg of messages) {\n if (msg.role === 'system') {\n const content = typeof msg.content === 'string' ? msg.content : msg.content.map(p => p.text).join('');\n systemParts.push(content);\n continue;\n }\n if (msg.role === 'user') {\n result.push({ role: 'user', content: toUserContent(msg.content) });\n continue;\n }\n if (msg.role === 'assistant') {\n result.push(toAssistantModelMessage({ msg, provider, providerName, logger }));\n continue;\n }\n if (msg.role === 'tool') {\n const toolName = toolNameById.get(msg.tool_call_id) ?? '';\n const toolContent: ToolContent = [\n {\n type: 'tool-result',\n toolCallId: msg.tool_call_id,\n toolName,\n output: {\n type: 'text',\n value: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),\n },\n },\n ];\n result.push({ role: 'tool', content: toolContent });\n continue;\n }\n // 'developer' / 'function' roles — not used in the harness pipeline; skip.\n }\n return { instructions: systemParts.length > 0 ? systemParts.join('\\n\\n') : undefined, messages: result };\n}\n\n/** Converts OpenAI tool definitions to the Vercel AI SDK ToolSet. */\nexport function convertTools(tools: ChatCompletionTool[] | undefined): ToolSet | undefined {\n if (!tools?.length) {\n return undefined;\n }\n const toolSet: ToolSet = {};\n for (const t of tools) {\n if (!isFunctionTool(t)) {\n continue;\n }\n toolSet[t.function.name] = {\n inputSchema: jsonSchema(t.function.parameters ?? { type: 'object', properties: {} }),\n ...(t.function.description !== undefined ? { description: t.function.description } : {}),\n };\n }\n return Object.keys(toolSet).length > 0 ? toolSet : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// streamText args\n// ---------------------------------------------------------------------------\n\n/**\n * Pure-data subset of `streamText(...)`'s call args. Uses `?` rather than this file's usual\n * explicit `| undefined`, to match `streamText`'s own signature under `exactOptionalPropertyTypes`.\n */\nexport type StreamTextArgs = LanguageModelCallOptions & {\n model: LanguageModel;\n instructions?: string;\n messages: ModelMessage[];\n tools?: ToolSet;\n providerOptions?: ProviderOptions;\n abortSignal?: AbortSignal;\n maxRetries: number;\n};\n\n/**\n * Exported so the final wiring is unit-testable: a value computed correctly but never spread into\n * this object would pass every sub-function test. `output` is excluded and spread by the caller,\n * since its unnameable type would make this function's return type unnameable too.\n */\nexport function buildStreamTextArgs(input: {\n model: LanguageModel;\n instructions: string | undefined;\n messages: ModelMessage[];\n tools: ToolSet | undefined;\n reasoning: ReasoningLevel | undefined;\n providerOptions: ProviderOptions;\n maxOutputTokens: number | undefined;\n temperature: number | null | undefined;\n topP: number | null | undefined;\n topK: number | null | undefined;\n presencePenalty: number | null | undefined;\n frequencyPenalty: number | null | undefined;\n stopSequences: string[] | null | undefined;\n seed: number | null | undefined;\n abortSignal: AbortSignal | undefined;\n}): StreamTextArgs {\n const {\n model,\n instructions,\n messages,\n tools,\n reasoning,\n providerOptions,\n maxOutputTokens,\n temperature,\n topP,\n topK,\n presencePenalty,\n frequencyPenalty,\n stopSequences,\n seed,\n abortSignal,\n } = input;\n return {\n model,\n ...(instructions !== undefined ? { instructions } : {}),\n messages,\n ...(tools !== undefined ? { tools } : {}),\n ...(reasoning !== undefined ? { reasoning } : {}),\n ...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { topP } : {}),\n ...(topK != null ? { topK } : {}),\n ...(presencePenalty != null ? { presencePenalty } : {}),\n ...(frequencyPenalty != null ? { frequencyPenalty } : {}),\n ...(stopSequences != null ? { stopSequences } : {}),\n ...(seed != null ? { seed } : {}),\n ...(Object.keys(providerOptions).length > 0 ? { providerOptions } : {}),\n ...(abortSignal !== undefined ? { abortSignal } : {}),\n maxRetries: 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stream mapping (SDK → harness chunks)\n// ---------------------------------------------------------------------------\n\n/** Maps Vercel AI SDK LanguageModelUsage → harness CompletionUsage. */\nexport function normalizeUsage(usage: {\n inputTokens: number | undefined;\n outputTokens: number | undefined;\n inputTokenDetails: {\n cacheReadTokens: number | undefined;\n cacheWriteTokens: number | undefined;\n noCacheTokens: number | undefined;\n };\n outputTokenDetails: {\n reasoningTokens: number | undefined;\n textTokens: number | undefined;\n };\n // LanguageModelUsage.raw: AI SDK has no cost field; extras like gateway costInUSD live here.\n raw?: JSONObject;\n}): CompletionUsage {\n const input = usage.inputTokens ?? 0;\n const output = usage.outputTokens ?? 0;\n const costInUsd = usage.raw?.['costInUSD'];\n return {\n input_tokens: input,\n output_tokens: output,\n total_tokens: input + output,\n cache_read_tokens: usage.inputTokenDetails.cacheReadTokens ?? undefined,\n cache_write_tokens: usage.inputTokenDetails.cacheWriteTokens ?? undefined,\n reasoning_tokens: usage.outputTokenDetails.reasoningTokens ?? undefined,\n cost_in_usd: typeof costInUsd === 'number' && costInUsd >= 0 ? costInUsd : undefined,\n };\n}\n\n/**\n * Prefer AI SDK `APICallError` (`message` / `statusCode`):\n * https://ai-sdk.dev/docs/reference/ai-sdk-errors/ai-api-call-error#properties\n * Fallback is required because stream `error` parts are typed `unknown` (not only\n * `APICallError`) — plain objects would otherwise stringify to \"[object Object]\".\n */\nexport function describeStreamError(raw: unknown): string {\n if (APICallError.isInstance(raw)) {\n if (raw.statusCode != null) {\n return `Request failed (${String(raw.statusCode)}): ${raw.message}`;\n }\n return raw.message;\n }\n return describeUnknownError(raw);\n}\n\nexport function toStreamError(raw: unknown): Error {\n if (raw instanceof Error) {\n return raw;\n }\n return new Error(describeStreamError(raw), { cause: raw });\n}\n\nexport function mapFinishReason(reason: FinishReason): RawAssistantMessageWithUsage['finish_reason'] {\n switch (reason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool-calls':\n return 'tool_calls';\n case 'content-filter':\n return 'content_filter';\n // No harness equivalent for these — fall back to 'stop'.\n case 'error':\n case 'other':\n return 'stop';\n default: {\n const _exhaustive: never = reason;\n throw new Error(`Unknown finish reason: ${String(_exhaustive)}`);\n }\n }\n}\n\ninterface ToolCallState {\n index: number;\n id: string;\n name: string;\n arguments: string;\n /** Gemini `thoughtSignature` from `providerMetadata.google` on the `tool-input-start` part. */\n thoughtSignature: string | undefined;\n}\n\n/**\n * Copies the reasoning-replay token onto the block, scanning every provider namespace since only\n * the active one is populated. Providers disagree on where it arrives: OpenAI attaches it to\n * `reasoning-end`, Anthropic to a text-less `reasoning-delta`. Missing either silently loses the\n * chain, since unsigned thinking blocks are dropped on replay.\n */\nfunction applyReasoningSignature({\n block,\n providerMetadata,\n}: {\n block: ThinkingBlock;\n providerMetadata: ProviderMetadata | undefined;\n}): void {\n if (providerMetadata === undefined) {\n return;\n }\n for (const meta of Object.values(providerMetadata)) {\n if ('reasoningEncryptedContent' in meta && typeof meta['reasoningEncryptedContent'] === 'string') {\n block.signature = meta['reasoningEncryptedContent'];\n return;\n }\n if ('signature' in meta && typeof meta['signature'] === 'string') {\n block.signature = meta['signature'];\n return;\n }\n }\n}\n\n/**\n * Which reasoning item a stream part belongs to. OpenAI is alone in splitting one item across\n * several parts, so elsewhere this is absent and every part stands on its own.\n */\nfunction reasoningItemId(providerMetadata: ProviderMetadata | undefined): string | undefined {\n if (providerMetadata === undefined) {\n return undefined;\n }\n for (const meta of Object.values(providerMetadata)) {\n if ('itemId' in meta && typeof meta['itemId'] === 'string') {\n return meta['itemId'];\n }\n }\n return undefined;\n}\n\n/**\n * Where the SDK reports what it changed about our request: an effort a model cannot honour and so\n * was coerced, a setting the provider ignored. Nothing else surfaces these.\n */\nexport function describeCallWarning(warning: CallWarning): string {\n switch (warning.type) {\n case 'unsupported':\n case 'compatibility':\n return warning.details !== undefined\n ? `${warning.type}: ${warning.feature} (${warning.details})`\n : `${warning.type}: ${warning.feature}`;\n case 'deprecated':\n return `deprecated: ${warning.setting} - ${warning.message}`;\n case 'other':\n return `other: ${warning.message}`;\n default: {\n const _exhaustive: never = warning;\n throw new Error(`Unknown call warning: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n/** Synthetic chunk fields shared by every chunk emitted for a single stream. */\ninterface ChunkMeta {\n id: string;\n created: number;\n model: string;\n}\n\n/**\n * Converts an SDK stream into harness chunks, returning the aggregated assistant message.\n * Takes a plain `AsyncIterable` so hand-built fixtures work in tests.\n */\nexport async function* mapStreamToChunks({\n stream,\n chunkMeta,\n}: {\n stream: AsyncIterable<TextStreamPart<ToolSet>>;\n chunkMeta: ChunkMeta;\n}): AsyncGenerator<ExtendedChatCompletionChunk, RawAssistantMessageWithUsage, unknown> {\n const makeBase = (): Omit<ExtendedChatCompletionChunk, 'choices' | 'usage'> => ({\n id: chunkMeta.id,\n object: 'chat.completion.chunk' as const,\n created: chunkMeta.created,\n model: chunkMeta.model,\n });\n\n const toolCallStates = new Map<string, ToolCallState>();\n let nextToolIndex = 0;\n let accumulatedText = '';\n const accumulatedThinking: ThinkingBlock[] = [];\n const thinkingByReasoningItem = new Map<string, ThinkingBlock>();\n let currentThinkingBlock: ThinkingBlock | null = null;\n\n /**\n * The block this reasoning part belongs to: the one already open for its item, or a new one.\n *\n * OpenAI streams a single reasoning item as several summary parts, and hands every part the one\n * token that identifies the item. A block per part would therefore replay that item once per\n * part, every copy presenting the same token with a different piece of the reasoning. Grouping by\n * item keeps one block per token, which is the only shape the provider can be replayed.\n */\n const openThinkingBlock = (providerMetadata: ProviderMetadata | undefined): ThinkingBlock => {\n const itemId = reasoningItemId(providerMetadata);\n const started = itemId !== undefined ? thinkingByReasoningItem.get(itemId) : undefined;\n if (started !== undefined) {\n // Each part is its own titled paragraph, and a part can be empty.\n if (started.thinking.length > 0) {\n started.thinking += '\\n\\n';\n }\n return started;\n }\n const block: ThinkingBlock = { type: 'thinking', thinking: '' };\n accumulatedThinking.push(block);\n if (itemId !== undefined) {\n thinkingByReasoningItem.set(itemId, block);\n }\n return block;\n };\n let finalUsage: CompletionUsage = getEmptyUsage();\n let finalFinishReason: RawAssistantMessageWithUsage['finish_reason'] = 'stop';\n\n for await (const part of stream) {\n switch (part.type) {\n case 'text-delta': {\n accumulatedText += part.text;\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: { content: part.text, role: 'assistant' },\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'reasoning-start': {\n currentThinkingBlock = openThinkingBlock(part.providerMetadata);\n break;\n }\n\n case 'reasoning-delta': {\n // A delta with no preceding `reasoning-start` would otherwise drop the block and its\n // signature, breaking replay while the text still streams out.\n currentThinkingBlock ??= openThinkingBlock(part.providerMetadata);\n currentThinkingBlock.thinking += part.text;\n applyReasoningSignature({ block: currentThinkingBlock, providerMetadata: part.providerMetadata });\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {\n thinking_blocks: [{ type: 'thinking', thinking: part.text }],\n reasoning_content: part.text,\n } satisfies ExtendedChatCompletionChunk['choices'][0]['delta'],\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'reasoning-end': {\n if (currentThinkingBlock !== null) {\n applyReasoningSignature({ block: currentThinkingBlock, providerMetadata: part.providerMetadata });\n }\n currentThinkingBlock = null;\n break;\n }\n\n case 'tool-input-start': {\n const idx = nextToolIndex++;\n // Gemini's replay token arrives here, and only here, for thinking models.\n const googleMeta = part.providerMetadata?.['google'];\n const thoughtSignature =\n googleMeta !== undefined && typeof googleMeta['thoughtSignature'] === 'string'\n ? googleMeta['thoughtSignature']\n : undefined;\n toolCallStates.set(part.id, {\n index: idx,\n id: part.id,\n name: part.toolName,\n arguments: '',\n thoughtSignature,\n });\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [\n {\n index: idx,\n id: part.id,\n type: 'function',\n function: { name: part.toolName, arguments: '' },\n },\n ],\n },\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'tool-input-delta': {\n const state = toolCallStates.get(part.id);\n // With no matching `tool-input-start` there is no index to attribute this to; emitting it\n // anyway would append the arguments to an unrelated tool call.\n if (state === undefined) {\n break;\n }\n state.arguments += part.delta;\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {\n tool_calls: [{ index: state.index, function: { arguments: part.delta } }],\n },\n finish_reason: null,\n logprobs: null,\n },\n ],\n };\n break;\n }\n\n case 'finish-step': {\n finalUsage = normalizeUsage(part.usage);\n finalFinishReason = mapFinishReason(part.finishReason);\n yield {\n ...makeBase(),\n choices: [\n {\n index: 0,\n delta: {},\n finish_reason: finalFinishReason,\n logprobs: null,\n },\n ],\n usage: finalUsage,\n };\n break;\n }\n\n case 'error': {\n const raw = part.error;\n const message = describeStreamError(raw);\n // Preserve the original stream error as cause; toast/turn use .message only.\n const cause = raw instanceof Error ? raw : new Error(message);\n throw new Error(message, { cause });\n }\n\n case 'abort': {\n const aborted = new Error('LLM stream aborted');\n aborted.name = 'AbortError';\n throw aborted;\n }\n\n case 'start':\n case 'text-start':\n case 'text-end':\n case 'custom':\n case 'tool-input-end':\n case 'source':\n case 'file':\n case 'reasoning-file':\n case 'tool-call':\n case 'tool-result':\n case 'tool-error':\n case 'tool-output-denied':\n case 'tool-approval-request':\n case 'tool-approval-response':\n case 'start-step':\n case 'finish':\n case 'raw':\n // Structural/bookkeeping events — no harness chunk is emitted for these.\n break;\n\n default: {\n const _exhaustive: never = part;\n throw new Error(`Unknown stream part type: ${JSON.stringify(_exhaustive)}`);\n }\n }\n }\n\n const toolCalls = [...toolCallStates.values()]\n .sort((a, b) => a.index - b.index)\n .map(tc => ({\n id: tc.id,\n type: 'function' as const,\n function: { name: tc.name, arguments: tc.arguments },\n ...(tc.thoughtSignature !== undefined\n ? { provider_specific_fields: { thought_signature: tc.thoughtSignature } }\n : {}),\n }));\n\n const output: RawAssistantMessage = {\n role: 'assistant',\n content: accumulatedText || null,\n ...(accumulatedThinking.length > 0 ? { thinking_blocks: accumulatedThinking } : {}),\n ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),\n };\n\n return { usage: finalUsage, output, finish_reason: finalFinishReason };\n}\n\n// ---------------------------------------------------------------------------\n// VercelAILLM\n// ---------------------------------------------------------------------------\n\n/** ILLM implementation backed by Vercel AI SDK, supporting multiple LLM providers. */\nexport class VercelAILLM implements ILLM {\n private readonly config: VercelAILLMConfig;\n private readonly logger: Logger;\n private readonly signal: AbortSignal | undefined;\n\n constructor(config: VercelAILLMConfig) {\n this.config = config;\n this.logger = config.logger;\n this.signal = config.signal;\n }\n\n async *create(\n body: LLMCreateParamsStreaming,\n ): AsyncGenerator<ExtendedChatCompletionChunk, RawAssistantMessageWithUsage, unknown> {\n const { providerConfig } = this.config;\n const languageModel = buildLanguageModel(providerConfig);\n const { provider, model } = providerConfig;\n\n const { instructions, messages } = convertMessages({\n messages: body.messages,\n provider: provider.type,\n providerName: provider.name,\n logger: this.logger,\n });\n const tools = convertTools(body.tools ?? undefined);\n const structuredOutputSpec = toStructuredOutputSpec(body.response_format);\n const output = buildOutput(structuredOutputSpec);\n\n // reasoning_effort is injected by AgentThread via Object.assign; not in the SDK type.\n const rawReasoningEffort: unknown = Reflect.get(body, 'reasoning_effort');\n const reasoningEffort = typeof rawReasoningEffort === 'string' ? rawReasoningEffort : undefined;\n const providerOptions = buildProviderOptions({\n config: providerConfig,\n reasoningEffort,\n structuredOutputSpec,\n rawBody: body,\n });\n const reasoning = toReasoningLevel(reasoningEffort);\n\n // top_k is injected by AgentThread via Object.assign; not in the SDK type.\n const rawTopK: unknown = Reflect.get(body, 'top_k');\n // seed is still accepted by providers but marked @deprecated on the OpenAI request type.\n const rawSeed: unknown = Reflect.get(body, 'seed');\n const streamTextArgs = buildStreamTextArgs({\n model: languageModel,\n instructions,\n messages,\n tools,\n reasoning,\n providerOptions,\n maxOutputTokens: resolveMaxOutputTokens(body),\n temperature: body.temperature,\n topP: body.top_p,\n topK: typeof rawTopK === 'number' ? rawTopK : null,\n presencePenalty: body.presence_penalty,\n frequencyPenalty: body.frequency_penalty,\n stopSequences: typeof body.stop === 'string' ? [body.stop] : (body.stop ?? null),\n seed: typeof rawSeed === 'number' ? rawSeed : null,\n abortSignal: this.signal,\n });\n\n let streamResult;\n try {\n streamResult = streamText({\n ...streamTextArgs,\n ...(output !== undefined ? { output } : {}),\n });\n } catch (error) {\n if (this.signal?.aborted) {\n this.logger.debug('LLM call aborted', extractErrorLogFields(error));\n } else {\n this.logger.error('Error creating streaming chat completion', extractErrorLogFields(error));\n }\n throw toStreamError(error);\n }\n\n // Detached: warnings resolve at stream start, and a pending or rejected promise must never\n // stall the stream. Stream failures are reported by the error paths below.\n void streamResult.warnings.then(\n warnings => {\n if (warnings !== undefined && warnings.length > 0) {\n this.logger.warn('Provider adjusted the request', {\n model: providerConfig.name,\n warnings: warnings.map(describeCallWarning),\n });\n }\n },\n (reason: unknown) => {\n // Rejects with the same failure the stream throws, which the error paths below already log.\n this.logger.debug('Provider warnings unavailable', extractErrorLogFields(reason));\n },\n );\n\n // Synthetic chunk fields; id is unique per stream instance.\n // Label chunks with the display name — model.id is the wire id.\n const chunkMeta: ChunkMeta = {\n id: `vc-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,\n created: Math.floor(Date.now() / 1000),\n model: providerConfig.name,\n };\n\n try {\n const result = yield* mapStreamToChunks({ stream: streamResult.stream, chunkMeta });\n result.output.source = `${provider.type}/${provider.name}/${model.name}`;\n return result;\n } catch (error) {\n if (this.signal?.aborted) {\n this.logger.debug('LLM stream aborted', extractErrorLogFields(error));\n } else {\n this.logger.error('Error reading LLM stream', extractErrorLogFields(error));\n }\n throw toStreamError(error);\n }\n }\n\n async createNonStream(body: LLMCreateParams): Promise<RawAssistantMessageWithUsage> {\n // Drain the streaming generator — reuses the same accumulation and error handling path.\n const llmStream = this.create({ ...body, stream: true });\n let result = await llmStream.next();\n while (!result.done) {\n result = await llmStream.next();\n }\n return result.value;\n }\n}\n"],"mappings":"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","names":[]}
@@ -80,7 +80,7 @@ function toConnectError(error) {
80
80
  return error;
81
81
  }
82
82
  if (isAuthError(error)) {
83
- return new import_errors.McpConnectionError("upstream returned 401 Unauthorized (check x-tfy-mcp-headers credentials)", 401, {
83
+ return new import_errors.McpConnectionError("upstream returned 401 Unauthorized", 401, {
84
84
  cause: error
85
85
  });
86
86
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/mcp/remoteMcpClient.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n// SSE remains required during the Streamable HTTP migration (some servers still speak SSE only).\n\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { context, propagation } from '@opentelemetry/api';\nimport { McpConnectionError } from '../errors';\nimport { withTimeout } from '../util/promiseUtils';\nimport type { ToolSchema } from './IMCPServer';\n\n/** Networking for remote (url-based) MCP servers, kept separate so it can be mocked in tests. */\n\nexport type RemoteMcpTransportType = 'streamable-http' | 'sse';\n\nexport interface RemoteMcpConnection {\n readonly transportType: RemoteMcpTransportType;\n /** Session id for a stateful server, or null for a stateless one. */\n readonly sessionId: string | null;\n listTools(cursor?: string): Promise<{ tools: ToolSchema[]; nextCursor?: string | undefined }>;\n callTool(params: CallToolRequest['params']): Promise<CallToolResult>;\n close(): Promise<void>;\n}\n\n// SSE transport type kept for dual-probe support during migration.\n// eslint-disable-next-line @typescript-eslint/no-deprecated -- see TRANSPORT_PROBE_ORDER\ntype McpTransport = StreamableHTTPClientTransport | SSEClientTransport;\n\nconst CLIENT_INFO = { name: 'tfy-agent-mcp-client', version: '1.0.0' } as const;\nconst TRANSPORT_PROBE_ORDER: RemoteMcpTransportType[] = ['streamable-http', 'sse'];\n\nclass McpClientWithTimeout extends Client {\n constructor(private readonly requestTimeoutMs: number) {\n super(CLIENT_INFO, { capabilities: {} });\n }\n\n // SDK Client.request is loosely typed; forward with an explicit timeout.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK request typing\n override request(req: any, schema: any, options?: any): Promise<any> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- MCP SDK request typing\n return super.request(req, schema, { ...options, timeout: this.requestTimeoutMs });\n }\n}\n\nfunction createTransport(\n type: RemoteMcpTransportType,\n url: URL,\n headers: Record<string, string>,\n sessionId?: string,\n): McpTransport {\n const requestInit = { headers };\n if (type === 'streamable-http') {\n return new StreamableHTTPClientTransport(url, { requestInit, ...(sessionId !== undefined ? { sessionId } : {}) });\n }\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- dual-transport probe; see TRANSPORT_PROBE_ORDER\n return new SSEClientTransport(url, { requestInit });\n}\n\nexport function isSessionExpiredError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 404) {\n return true;\n }\n return error.message.includes('HTTP 404') || error.message.toLowerCase().includes('session');\n}\n\nfunction isAuthError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 401) {\n return true;\n }\n return error.message.includes('HTTP 401');\n}\n\n/** Inject the active otel trace context so each request propagates its span. */\nfunction stampTraceHeaders(headers: Record<string, string>): void {\n propagation.inject(context.active(), headers);\n}\n\nfunction getTransportSessionId(transport: McpTransport): string | null {\n return transport instanceof StreamableHTTPClientTransport ? (transport.sessionId ?? null) : null;\n}\n\nfunction toConnectError(error: unknown): McpConnectionError {\n if (error instanceof McpConnectionError) {\n return error;\n }\n if (isAuthError(error)) {\n return new McpConnectionError('upstream returned 401 Unauthorized (check x-tfy-mcp-headers credentials)', 401, {\n cause: error,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new McpConnectionError(message, 502, { cause: error });\n}\n\nfunction buildConnection(\n client: McpClientWithTimeout,\n transport: McpTransport,\n transportType: RemoteMcpTransportType,\n headers: Record<string, string>,\n requestOptions: { signal: AbortSignal },\n): RemoteMcpConnection {\n return {\n transportType,\n sessionId: getTransportSessionId(transport),\n listTools: async (cursor?: string) => {\n stampTraceHeaders(headers);\n const response = await client.listTools(cursor ? { cursor } : undefined, requestOptions);\n return {\n tools: response.tools,\n nextCursor: response.nextCursor,\n };\n },\n callTool: async (callParams: CallToolRequest['params']): Promise<CallToolResult> => {\n stampTraceHeaders(headers);\n return (await client.callTool(callParams, undefined, requestOptions)) as CallToolResult;\n },\n close: async (): Promise<void> => {\n await client.close().catch(() => {\n /* no-op */\n });\n },\n };\n}\n\n/**\n * Connect to a remote MCP server, keeping the first transport that connects. `sessionId` is passed to\n * every attempt so a stateful session resumes in place instead of opening a throwaway one.\n *\n * `knownTransportType` is a hint (from a prior connect / persisted state): it's tried first for a fast\n * path, but on failure we still fall back to probing the remaining transports, so a stale or wrong\n * hint (server switched transports, bad resume data) self-heals instead of failing every turn.\n */\nexport async function connectRemoteMcp(params: {\n url: string;\n headers: Record<string, string>;\n sessionId?: string | undefined;\n knownTransportType?: RemoteMcpTransportType | undefined;\n requestTimeoutMs: number;\n connectTimeoutMs: number;\n signal: AbortSignal;\n onClose?: (() => void) | undefined;\n onError?: ((error: Error) => void) | undefined;\n}): Promise<RemoteMcpConnection> {\n const url = new URL(params.url);\n const requestOptions = { signal: params.signal };\n const candidates = params.knownTransportType\n ? [params.knownTransportType, ...TRANSPORT_PROBE_ORDER.filter(t => t !== params.knownTransportType)]\n : TRANSPORT_PROBE_ORDER;\n const failures: { transport: RemoteMcpTransportType; error: string }[] = [];\n\n for (const transportType of candidates) {\n const transport = createTransport(transportType, url, params.headers, params.sessionId);\n const client = new McpClientWithTimeout(params.requestTimeoutMs);\n try {\n stampTraceHeaders(params.headers);\n await withTimeout(\n // Concrete transports use sessionId: string|undefined; Transport uses an optional\n // property — exactOptionalPropertyTypes rejects assignability without this cast.\n client.connect(transport as Parameters<Client['connect']>[0], requestOptions),\n params.connectTimeoutMs,\n transportType,\n );\n } catch (error) {\n await client.close().catch(() => {\n /* no-op */\n });\n if (isAuthError(error)) {\n throw toConnectError(error);\n }\n // A session-expired error means the transport is right but the session is stale: surface it so\n // the caller reconnects fresh instead of falling through to a different transport.\n if (params.sessionId && isSessionExpiredError(error)) {\n throw toConnectError(error);\n }\n failures.push({ transport: transportType, error: error instanceof Error ? error.message.trim() : String(error) });\n continue;\n }\n\n // Set on the client (not the transport) so the SDK's own onclose/onerror cleanup still runs; the\n // SDK invokes these from inside it. Only wired on the kept connection, so failed attempts stay quiet.\n client.onclose = () => params.onClose?.();\n client.onerror = error => params.onError?.(error);\n return buildConnection(client, transport, transportType, params.headers, requestOptions);\n }\n\n throw new McpConnectionError(`failed to connect (tried ${candidates.join(', ')}): ${JSON.stringify(failures)}`, 502);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/mcp/remoteMcpClient.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n// SSE remains required during the Streamable HTTP migration (some servers still speak SSE only).\n\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { context, propagation } from '@opentelemetry/api';\nimport { McpConnectionError } from '../errors';\nimport { withTimeout } from '../util/promiseUtils';\nimport type { ToolSchema } from './IMCPServer';\n\n/** Networking for remote (url-based) MCP servers, kept separate so it can be mocked in tests. */\n\nexport type RemoteMcpTransportType = 'streamable-http' | 'sse';\n\nexport interface RemoteMcpConnection {\n readonly transportType: RemoteMcpTransportType;\n /** Session id for a stateful server, or null for a stateless one. */\n readonly sessionId: string | null;\n listTools(cursor?: string): Promise<{ tools: ToolSchema[]; nextCursor?: string | undefined }>;\n callTool(params: CallToolRequest['params']): Promise<CallToolResult>;\n close(): Promise<void>;\n}\n\n// SSE transport type kept for dual-probe support during migration.\n// eslint-disable-next-line @typescript-eslint/no-deprecated -- see TRANSPORT_PROBE_ORDER\ntype McpTransport = StreamableHTTPClientTransport | SSEClientTransport;\n\nconst CLIENT_INFO = { name: 'tfy-agent-mcp-client', version: '1.0.0' } as const;\nconst TRANSPORT_PROBE_ORDER: RemoteMcpTransportType[] = ['streamable-http', 'sse'];\n\nclass McpClientWithTimeout extends Client {\n constructor(private readonly requestTimeoutMs: number) {\n super(CLIENT_INFO, { capabilities: {} });\n }\n\n // SDK Client.request is loosely typed; forward with an explicit timeout.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK request typing\n override request(req: any, schema: any, options?: any): Promise<any> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- MCP SDK request typing\n return super.request(req, schema, { ...options, timeout: this.requestTimeoutMs });\n }\n}\n\nfunction createTransport(\n type: RemoteMcpTransportType,\n url: URL,\n headers: Record<string, string>,\n sessionId?: string,\n): McpTransport {\n const requestInit = { headers };\n if (type === 'streamable-http') {\n return new StreamableHTTPClientTransport(url, { requestInit, ...(sessionId !== undefined ? { sessionId } : {}) });\n }\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- dual-transport probe; see TRANSPORT_PROBE_ORDER\n return new SSEClientTransport(url, { requestInit });\n}\n\nexport function isSessionExpiredError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 404) {\n return true;\n }\n return error.message.includes('HTTP 404') || error.message.toLowerCase().includes('session');\n}\n\nfunction isAuthError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 401) {\n return true;\n }\n return error.message.includes('HTTP 401');\n}\n\n/** Inject the active otel trace context so each request propagates its span. */\nfunction stampTraceHeaders(headers: Record<string, string>): void {\n propagation.inject(context.active(), headers);\n}\n\nfunction getTransportSessionId(transport: McpTransport): string | null {\n return transport instanceof StreamableHTTPClientTransport ? (transport.sessionId ?? null) : null;\n}\n\nfunction toConnectError(error: unknown): McpConnectionError {\n if (error instanceof McpConnectionError) {\n return error;\n }\n if (isAuthError(error)) {\n return new McpConnectionError('upstream returned 401 Unauthorized', 401, {\n cause: error,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new McpConnectionError(message, 502, { cause: error });\n}\n\nfunction buildConnection(\n client: McpClientWithTimeout,\n transport: McpTransport,\n transportType: RemoteMcpTransportType,\n headers: Record<string, string>,\n requestOptions: { signal: AbortSignal },\n): RemoteMcpConnection {\n return {\n transportType,\n sessionId: getTransportSessionId(transport),\n listTools: async (cursor?: string) => {\n stampTraceHeaders(headers);\n const response = await client.listTools(cursor ? { cursor } : undefined, requestOptions);\n return {\n tools: response.tools,\n nextCursor: response.nextCursor,\n };\n },\n callTool: async (callParams: CallToolRequest['params']): Promise<CallToolResult> => {\n stampTraceHeaders(headers);\n return (await client.callTool(callParams, undefined, requestOptions)) as CallToolResult;\n },\n close: async (): Promise<void> => {\n await client.close().catch(() => {\n /* no-op */\n });\n },\n };\n}\n\n/**\n * Connect to a remote MCP server, keeping the first transport that connects. `sessionId` is passed to\n * every attempt so a stateful session resumes in place instead of opening a throwaway one.\n *\n * `knownTransportType` is a hint (from a prior connect / persisted state): it's tried first for a fast\n * path, but on failure we still fall back to probing the remaining transports, so a stale or wrong\n * hint (server switched transports, bad resume data) self-heals instead of failing every turn.\n */\nexport async function connectRemoteMcp(params: {\n url: string;\n headers: Record<string, string>;\n sessionId?: string | undefined;\n knownTransportType?: RemoteMcpTransportType | undefined;\n requestTimeoutMs: number;\n connectTimeoutMs: number;\n signal: AbortSignal;\n onClose?: (() => void) | undefined;\n onError?: ((error: Error) => void) | undefined;\n}): Promise<RemoteMcpConnection> {\n const url = new URL(params.url);\n const requestOptions = { signal: params.signal };\n const candidates = params.knownTransportType\n ? [params.knownTransportType, ...TRANSPORT_PROBE_ORDER.filter(t => t !== params.knownTransportType)]\n : TRANSPORT_PROBE_ORDER;\n const failures: { transport: RemoteMcpTransportType; error: string }[] = [];\n\n for (const transportType of candidates) {\n const transport = createTransport(transportType, url, params.headers, params.sessionId);\n const client = new McpClientWithTimeout(params.requestTimeoutMs);\n try {\n stampTraceHeaders(params.headers);\n await withTimeout(\n // Concrete transports use sessionId: string|undefined; Transport uses an optional\n // property — exactOptionalPropertyTypes rejects assignability without this cast.\n client.connect(transport as Parameters<Client['connect']>[0], requestOptions),\n params.connectTimeoutMs,\n transportType,\n );\n } catch (error) {\n await client.close().catch(() => {\n /* no-op */\n });\n if (isAuthError(error)) {\n throw toConnectError(error);\n }\n // A session-expired error means the transport is right but the session is stale: surface it so\n // the caller reconnects fresh instead of falling through to a different transport.\n if (params.sessionId && isSessionExpiredError(error)) {\n throw toConnectError(error);\n }\n failures.push({ transport: transportType, error: error instanceof Error ? error.message.trim() : String(error) });\n continue;\n }\n\n // Set on the client (not the transport) so the SDK's own onclose/onerror cleanup still runs; the\n // SDK invokes these from inside it. Only wired on the kept connection, so failed attempts stay quiet.\n client.onclose = () => params.onClose?.();\n client.onerror = error => params.onError?.(error);\n return buildConnection(client, transport, transportType, params.headers, requestOptions);\n }\n\n throw new McpConnectionError(`failed to connect (tried ${candidates.join(', ')}): ${JSON.stringify(failures)}`, 502);\n}\n"],"mappings":"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","names":[]}
@@ -55,7 +55,7 @@ function toConnectError(error) {
55
55
  return error;
56
56
  }
57
57
  if (isAuthError(error)) {
58
- return new McpConnectionError("upstream returned 401 Unauthorized (check x-tfy-mcp-headers credentials)", 401, {
58
+ return new McpConnectionError("upstream returned 401 Unauthorized", 401, {
59
59
  cause: error
60
60
  });
61
61
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/mcp/remoteMcpClient.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n// SSE remains required during the Streamable HTTP migration (some servers still speak SSE only).\n\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { context, propagation } from '@opentelemetry/api';\nimport { McpConnectionError } from '../errors';\nimport { withTimeout } from '../util/promiseUtils';\nimport type { ToolSchema } from './IMCPServer';\n\n/** Networking for remote (url-based) MCP servers, kept separate so it can be mocked in tests. */\n\nexport type RemoteMcpTransportType = 'streamable-http' | 'sse';\n\nexport interface RemoteMcpConnection {\n readonly transportType: RemoteMcpTransportType;\n /** Session id for a stateful server, or null for a stateless one. */\n readonly sessionId: string | null;\n listTools(cursor?: string): Promise<{ tools: ToolSchema[]; nextCursor?: string | undefined }>;\n callTool(params: CallToolRequest['params']): Promise<CallToolResult>;\n close(): Promise<void>;\n}\n\n// SSE transport type kept for dual-probe support during migration.\n// eslint-disable-next-line @typescript-eslint/no-deprecated -- see TRANSPORT_PROBE_ORDER\ntype McpTransport = StreamableHTTPClientTransport | SSEClientTransport;\n\nconst CLIENT_INFO = { name: 'tfy-agent-mcp-client', version: '1.0.0' } as const;\nconst TRANSPORT_PROBE_ORDER: RemoteMcpTransportType[] = ['streamable-http', 'sse'];\n\nclass McpClientWithTimeout extends Client {\n constructor(private readonly requestTimeoutMs: number) {\n super(CLIENT_INFO, { capabilities: {} });\n }\n\n // SDK Client.request is loosely typed; forward with an explicit timeout.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK request typing\n override request(req: any, schema: any, options?: any): Promise<any> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- MCP SDK request typing\n return super.request(req, schema, { ...options, timeout: this.requestTimeoutMs });\n }\n}\n\nfunction createTransport(\n type: RemoteMcpTransportType,\n url: URL,\n headers: Record<string, string>,\n sessionId?: string,\n): McpTransport {\n const requestInit = { headers };\n if (type === 'streamable-http') {\n return new StreamableHTTPClientTransport(url, { requestInit, ...(sessionId !== undefined ? { sessionId } : {}) });\n }\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- dual-transport probe; see TRANSPORT_PROBE_ORDER\n return new SSEClientTransport(url, { requestInit });\n}\n\nexport function isSessionExpiredError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 404) {\n return true;\n }\n return error.message.includes('HTTP 404') || error.message.toLowerCase().includes('session');\n}\n\nfunction isAuthError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 401) {\n return true;\n }\n return error.message.includes('HTTP 401');\n}\n\n/** Inject the active otel trace context so each request propagates its span. */\nfunction stampTraceHeaders(headers: Record<string, string>): void {\n propagation.inject(context.active(), headers);\n}\n\nfunction getTransportSessionId(transport: McpTransport): string | null {\n return transport instanceof StreamableHTTPClientTransport ? (transport.sessionId ?? null) : null;\n}\n\nfunction toConnectError(error: unknown): McpConnectionError {\n if (error instanceof McpConnectionError) {\n return error;\n }\n if (isAuthError(error)) {\n return new McpConnectionError('upstream returned 401 Unauthorized (check x-tfy-mcp-headers credentials)', 401, {\n cause: error,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new McpConnectionError(message, 502, { cause: error });\n}\n\nfunction buildConnection(\n client: McpClientWithTimeout,\n transport: McpTransport,\n transportType: RemoteMcpTransportType,\n headers: Record<string, string>,\n requestOptions: { signal: AbortSignal },\n): RemoteMcpConnection {\n return {\n transportType,\n sessionId: getTransportSessionId(transport),\n listTools: async (cursor?: string) => {\n stampTraceHeaders(headers);\n const response = await client.listTools(cursor ? { cursor } : undefined, requestOptions);\n return {\n tools: response.tools,\n nextCursor: response.nextCursor,\n };\n },\n callTool: async (callParams: CallToolRequest['params']): Promise<CallToolResult> => {\n stampTraceHeaders(headers);\n return (await client.callTool(callParams, undefined, requestOptions)) as CallToolResult;\n },\n close: async (): Promise<void> => {\n await client.close().catch(() => {\n /* no-op */\n });\n },\n };\n}\n\n/**\n * Connect to a remote MCP server, keeping the first transport that connects. `sessionId` is passed to\n * every attempt so a stateful session resumes in place instead of opening a throwaway one.\n *\n * `knownTransportType` is a hint (from a prior connect / persisted state): it's tried first for a fast\n * path, but on failure we still fall back to probing the remaining transports, so a stale or wrong\n * hint (server switched transports, bad resume data) self-heals instead of failing every turn.\n */\nexport async function connectRemoteMcp(params: {\n url: string;\n headers: Record<string, string>;\n sessionId?: string | undefined;\n knownTransportType?: RemoteMcpTransportType | undefined;\n requestTimeoutMs: number;\n connectTimeoutMs: number;\n signal: AbortSignal;\n onClose?: (() => void) | undefined;\n onError?: ((error: Error) => void) | undefined;\n}): Promise<RemoteMcpConnection> {\n const url = new URL(params.url);\n const requestOptions = { signal: params.signal };\n const candidates = params.knownTransportType\n ? [params.knownTransportType, ...TRANSPORT_PROBE_ORDER.filter(t => t !== params.knownTransportType)]\n : TRANSPORT_PROBE_ORDER;\n const failures: { transport: RemoteMcpTransportType; error: string }[] = [];\n\n for (const transportType of candidates) {\n const transport = createTransport(transportType, url, params.headers, params.sessionId);\n const client = new McpClientWithTimeout(params.requestTimeoutMs);\n try {\n stampTraceHeaders(params.headers);\n await withTimeout(\n // Concrete transports use sessionId: string|undefined; Transport uses an optional\n // property — exactOptionalPropertyTypes rejects assignability without this cast.\n client.connect(transport as Parameters<Client['connect']>[0], requestOptions),\n params.connectTimeoutMs,\n transportType,\n );\n } catch (error) {\n await client.close().catch(() => {\n /* no-op */\n });\n if (isAuthError(error)) {\n throw toConnectError(error);\n }\n // A session-expired error means the transport is right but the session is stale: surface it so\n // the caller reconnects fresh instead of falling through to a different transport.\n if (params.sessionId && isSessionExpiredError(error)) {\n throw toConnectError(error);\n }\n failures.push({ transport: transportType, error: error instanceof Error ? error.message.trim() : String(error) });\n continue;\n }\n\n // Set on the client (not the transport) so the SDK's own onclose/onerror cleanup still runs; the\n // SDK invokes these from inside it. Only wired on the kept connection, so failed attempts stay quiet.\n client.onclose = () => params.onClose?.();\n client.onerror = error => params.onError?.(error);\n return buildConnection(client, transport, transportType, params.headers, requestOptions);\n }\n\n throw new McpConnectionError(`failed to connect (tried ${candidates.join(', ')}): ${JSON.stringify(failures)}`, 502);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/mcp/remoteMcpClient.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n// SSE remains required during the Streamable HTTP migration (some servers still speak SSE only).\n\nimport { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';\nimport type { CallToolRequest, CallToolResult } from '@modelcontextprotocol/sdk/types.js';\nimport { context, propagation } from '@opentelemetry/api';\nimport { McpConnectionError } from '../errors';\nimport { withTimeout } from '../util/promiseUtils';\nimport type { ToolSchema } from './IMCPServer';\n\n/** Networking for remote (url-based) MCP servers, kept separate so it can be mocked in tests. */\n\nexport type RemoteMcpTransportType = 'streamable-http' | 'sse';\n\nexport interface RemoteMcpConnection {\n readonly transportType: RemoteMcpTransportType;\n /** Session id for a stateful server, or null for a stateless one. */\n readonly sessionId: string | null;\n listTools(cursor?: string): Promise<{ tools: ToolSchema[]; nextCursor?: string | undefined }>;\n callTool(params: CallToolRequest['params']): Promise<CallToolResult>;\n close(): Promise<void>;\n}\n\n// SSE transport type kept for dual-probe support during migration.\n// eslint-disable-next-line @typescript-eslint/no-deprecated -- see TRANSPORT_PROBE_ORDER\ntype McpTransport = StreamableHTTPClientTransport | SSEClientTransport;\n\nconst CLIENT_INFO = { name: 'tfy-agent-mcp-client', version: '1.0.0' } as const;\nconst TRANSPORT_PROBE_ORDER: RemoteMcpTransportType[] = ['streamable-http', 'sse'];\n\nclass McpClientWithTimeout extends Client {\n constructor(private readonly requestTimeoutMs: number) {\n super(CLIENT_INFO, { capabilities: {} });\n }\n\n // SDK Client.request is loosely typed; forward with an explicit timeout.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK request typing\n override request(req: any, schema: any, options?: any): Promise<any> {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- MCP SDK request typing\n return super.request(req, schema, { ...options, timeout: this.requestTimeoutMs });\n }\n}\n\nfunction createTransport(\n type: RemoteMcpTransportType,\n url: URL,\n headers: Record<string, string>,\n sessionId?: string,\n): McpTransport {\n const requestInit = { headers };\n if (type === 'streamable-http') {\n return new StreamableHTTPClientTransport(url, { requestInit, ...(sessionId !== undefined ? { sessionId } : {}) });\n }\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- dual-transport probe; see TRANSPORT_PROBE_ORDER\n return new SSEClientTransport(url, { requestInit });\n}\n\nexport function isSessionExpiredError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 404) {\n return true;\n }\n return error.message.includes('HTTP 404') || error.message.toLowerCase().includes('session');\n}\n\nfunction isAuthError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if ('code' in error && error.code === 401) {\n return true;\n }\n return error.message.includes('HTTP 401');\n}\n\n/** Inject the active otel trace context so each request propagates its span. */\nfunction stampTraceHeaders(headers: Record<string, string>): void {\n propagation.inject(context.active(), headers);\n}\n\nfunction getTransportSessionId(transport: McpTransport): string | null {\n return transport instanceof StreamableHTTPClientTransport ? (transport.sessionId ?? null) : null;\n}\n\nfunction toConnectError(error: unknown): McpConnectionError {\n if (error instanceof McpConnectionError) {\n return error;\n }\n if (isAuthError(error)) {\n return new McpConnectionError('upstream returned 401 Unauthorized', 401, {\n cause: error,\n });\n }\n const message = error instanceof Error ? error.message : String(error);\n return new McpConnectionError(message, 502, { cause: error });\n}\n\nfunction buildConnection(\n client: McpClientWithTimeout,\n transport: McpTransport,\n transportType: RemoteMcpTransportType,\n headers: Record<string, string>,\n requestOptions: { signal: AbortSignal },\n): RemoteMcpConnection {\n return {\n transportType,\n sessionId: getTransportSessionId(transport),\n listTools: async (cursor?: string) => {\n stampTraceHeaders(headers);\n const response = await client.listTools(cursor ? { cursor } : undefined, requestOptions);\n return {\n tools: response.tools,\n nextCursor: response.nextCursor,\n };\n },\n callTool: async (callParams: CallToolRequest['params']): Promise<CallToolResult> => {\n stampTraceHeaders(headers);\n return (await client.callTool(callParams, undefined, requestOptions)) as CallToolResult;\n },\n close: async (): Promise<void> => {\n await client.close().catch(() => {\n /* no-op */\n });\n },\n };\n}\n\n/**\n * Connect to a remote MCP server, keeping the first transport that connects. `sessionId` is passed to\n * every attempt so a stateful session resumes in place instead of opening a throwaway one.\n *\n * `knownTransportType` is a hint (from a prior connect / persisted state): it's tried first for a fast\n * path, but on failure we still fall back to probing the remaining transports, so a stale or wrong\n * hint (server switched transports, bad resume data) self-heals instead of failing every turn.\n */\nexport async function connectRemoteMcp(params: {\n url: string;\n headers: Record<string, string>;\n sessionId?: string | undefined;\n knownTransportType?: RemoteMcpTransportType | undefined;\n requestTimeoutMs: number;\n connectTimeoutMs: number;\n signal: AbortSignal;\n onClose?: (() => void) | undefined;\n onError?: ((error: Error) => void) | undefined;\n}): Promise<RemoteMcpConnection> {\n const url = new URL(params.url);\n const requestOptions = { signal: params.signal };\n const candidates = params.knownTransportType\n ? [params.knownTransportType, ...TRANSPORT_PROBE_ORDER.filter(t => t !== params.knownTransportType)]\n : TRANSPORT_PROBE_ORDER;\n const failures: { transport: RemoteMcpTransportType; error: string }[] = [];\n\n for (const transportType of candidates) {\n const transport = createTransport(transportType, url, params.headers, params.sessionId);\n const client = new McpClientWithTimeout(params.requestTimeoutMs);\n try {\n stampTraceHeaders(params.headers);\n await withTimeout(\n // Concrete transports use sessionId: string|undefined; Transport uses an optional\n // property — exactOptionalPropertyTypes rejects assignability without this cast.\n client.connect(transport as Parameters<Client['connect']>[0], requestOptions),\n params.connectTimeoutMs,\n transportType,\n );\n } catch (error) {\n await client.close().catch(() => {\n /* no-op */\n });\n if (isAuthError(error)) {\n throw toConnectError(error);\n }\n // A session-expired error means the transport is right but the session is stale: surface it so\n // the caller reconnects fresh instead of falling through to a different transport.\n if (params.sessionId && isSessionExpiredError(error)) {\n throw toConnectError(error);\n }\n failures.push({ transport: transportType, error: error instanceof Error ? error.message.trim() : String(error) });\n continue;\n }\n\n // Set on the client (not the transport) so the SDK's own onclose/onerror cleanup still runs; the\n // SDK invokes these from inside it. Only wired on the kept connection, so failed attempts stay quiet.\n client.onclose = () => params.onClose?.();\n client.onerror = error => params.onError?.(error);\n return buildConnection(client, transport, transportType, params.headers, requestOptions);\n }\n\n throw new McpConnectionError(`failed to connect (tried ${candidates.join(', ')}): ${JSON.stringify(failures)}`, 502);\n}\n"],"mappings":"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","names":[]}
@@ -53,11 +53,11 @@ var import_CodeModeTransport = require("./codeMode/CodeModeTransport.js");
53
53
  var import_Provider = require("./provider/Provider.js");
54
54
  var import_SandboxErrors = require("./SandboxErrors.js");
55
55
  var import_sandboxRef = require("./sandboxRef.js");
56
- var import_node_path = require("path");
56
+ var import_posix = require("path/posix");
57
57
  function mcpClientLayout(remotePath) {
58
- const pythonPath = (0, import_node_path.dirname)(remotePath);
59
- const binDir = (0, import_node_path.join)(pythonPath, "bin");
60
- return { pythonPath, binDir, binLink: (0, import_node_path.join)(binDir, "mcp-client") };
58
+ const pythonPath = (0, import_posix.dirname)(remotePath);
59
+ const binDir = (0, import_posix.join)(pythonPath, "bin");
60
+ return { pythonPath, binDir, binLink: (0, import_posix.join)(binDir, "mcp-client") };
61
61
  }
62
62
  var SKILL_DOWNLOAD_TIMEOUT_SECONDS = 180;
63
63
  var NATS_REQUEST_TIMEOUT_BUFFER_SECONDS = 30;
@@ -599,7 +599,7 @@ var Sandbox = class extends import_LocalToolMCP.LocalToolMCP {
599
599
  initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)(install.remotePath)} ${(0, import_Provider.shellEscape)(install.pathBinSymlink)}`);
600
600
  } else {
601
601
  const { binDir, binLink } = mcpClientLayout(install.remotePath);
602
- initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)((0, import_node_path.relative)(binDir, install.remotePath))} ${(0, import_Provider.shellEscape)(binLink)}`);
602
+ initSteps.push(`ln -sf ${(0, import_Provider.shellEscape)((0, import_posix.relative)(binDir, install.remotePath))} ${(0, import_Provider.shellEscape)(binLink)}`);
603
603
  }
604
604
  }
605
605
  const skillInit = this.skillMounter?.getSandboxInit({