@graphorin/provider 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +8 -3
- package/dist/adapters/llamacpp-server.d.ts +1 -1
- package/dist/adapters/llamacpp-server.js.map +1 -1
- package/dist/adapters/ollama.d.ts.map +1 -1
- package/dist/adapters/ollama.js +19 -6
- package/dist/adapters/ollama.js.map +1 -1
- package/dist/adapters/vercel.d.ts +1 -1
- package/dist/adapters/vercel.d.ts.map +1 -1
- package/dist/adapters/vercel.js +111 -33
- package/dist/adapters/vercel.js.map +1 -1
- package/dist/errors/errors.d.ts +1 -1
- package/dist/errors/errors.js +1 -1
- package/dist/errors/errors.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -8
- package/dist/index.js.map +1 -1
- package/dist/internal/http.js +111 -7
- package/dist/internal/http.js.map +1 -1
- package/dist/internal/openai-shaped.js +21 -4
- package/dist/internal/openai-shaped.js.map +1 -1
- package/dist/middleware/with-fallback.js +1 -1
- package/dist/middleware/with-rate-limit.d.ts +21 -8
- package/dist/middleware/with-rate-limit.d.ts.map +1 -1
- package/dist/middleware/with-rate-limit.js +65 -12
- package/dist/middleware/with-rate-limit.js.map +1 -1
- package/dist/middleware/with-retry.js +1 -1
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/package.json +18 -16
- package/src/adapters/index.ts +14 -0
- package/src/adapters/llamacpp-server.ts +102 -0
- package/src/adapters/ollama.ts +382 -0
- package/src/adapters/openai-compatible.ts +95 -0
- package/src/adapters/vercel-messages.ts +308 -0
- package/src/adapters/vercel.ts +706 -0
- package/src/counters/anthropic-wire.ts +199 -0
- package/src/counters/anthropic.ts +114 -0
- package/src/counters/bedrock.ts +46 -0
- package/src/counters/dispatcher.ts +127 -0
- package/src/counters/global.ts +39 -0
- package/src/counters/google.ts +46 -0
- package/src/counters/heuristic.ts +107 -0
- package/src/counters/index.ts +35 -0
- package/src/counters/js-tiktoken.ts +135 -0
- package/src/counters/serialize.ts +85 -0
- package/src/errors/errors.ts +316 -0
- package/src/errors/index.ts +20 -0
- package/src/index.ts +42 -0
- package/src/internal/abort.ts +30 -0
- package/src/internal/http.ts +388 -0
- package/src/internal/openai-shaped.ts +555 -0
- package/src/internal/sse.ts +112 -0
- package/src/internal/url-utils.ts +20 -0
- package/src/middleware/compose.ts +213 -0
- package/src/middleware/index.ts +37 -0
- package/src/middleware/production-hook.ts +47 -0
- package/src/middleware/with-cost-limit.ts +131 -0
- package/src/middleware/with-cost-tracking.ts +216 -0
- package/src/middleware/with-fallback.ts +157 -0
- package/src/middleware/with-rate-limit.ts +306 -0
- package/src/middleware/with-redaction.ts +671 -0
- package/src/middleware/with-retry.ts +274 -0
- package/src/middleware/with-tracing.ts +117 -0
- package/src/model-tier/classify.ts +125 -0
- package/src/model-tier/index.ts +11 -0
- package/src/provider.ts +121 -0
- package/src/reasoning/apply-policy.ts +89 -0
- package/src/reasoning/classify-contract.ts +120 -0
- package/src/reasoning/index.ts +21 -0
- package/src/reasoning/retention.ts +64 -0
- package/src/tool-examples.ts +54 -0
- package/src/trust/classify-local-provider.ts +254 -0
- package/src/trust/index.ts +14 -0
- package/dist/adapters/index.js +0 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel.js","names":["DEFAULT_CAPABILITIES: Omit<ProviderCapabilities, 'reasoningContract'>","capabilities: ProviderCapabilities","stream: AsyncIterable<AISDKChunk>","finalUsage: Usage | undefined","finishReason: FinishReason","result: Awaited<ReturnType<VercelRuntimeOverrides['generateText']>>","picked: Record<string, string>","cachedRuntime: VercelRuntimeOverrides | null","mod: { streamText?: unknown; generateText?: unknown }"],"sources":["../../src/adapters/vercel.ts"],"sourcesContent":["/**\n * `vercelAdapter` - wraps a Vercel AI SDK `LanguageModel`-shaped value\n * into a Graphorin {@link Provider}. The adapter is the default cloud\n * path: it speaks the AI SDK's `streamText` / `generateText` API and\n * maps the resulting events onto the canonical\n * {@link import('@graphorin/core').ProviderEvent} discriminated union.\n *\n * Outbound, the adapter converts Graphorin messages / tools onto the\n * AI SDK call contract (see `vercel-messages.ts`): tool definitions\n * become a name-keyed record with `jsonSchema()`-shaped input schemas,\n * assistant `toolCalls` become `tool-call` content parts, and\n * `ToolMessage`s become `tool-result` messages - the SDK zod-validates\n * all of these and rejects the raw Graphorin shapes.\n *\n * The AI SDK is an **optional peer dependency** of `@graphorin/provider`.\n * Production callers leave `runtimeOverrides` unset and the adapter\n * dynamically imports the package on first use; test fixtures pass a\n * `runtimeOverrides` value to short-circuit the import and feed\n * fixture chunks directly. The overrides shape is intentionally\n * structural so users can supply hand-rolled stubs or any compatible\n * library.\n *\n * @packageDocumentation\n */\n\nimport type {\n FinishReason,\n Provider,\n ProviderCapabilities,\n ProviderEvent,\n ProviderRequest,\n ProviderResponse,\n Usage,\n} from '@graphorin/core';\n\nimport { ProviderHttpError, ProviderStreamParseError } from '../errors/errors.js';\nimport { applyReasoningPolicy } from '../reasoning/apply-policy.js';\nimport { inferReasoningContract } from '../reasoning/classify-contract.js';\nimport { resolveReasoningRetention } from '../reasoning/retention.js';\nimport { foldToolExamples } from '../tool-examples.js';\nimport {\n applyCacheAnchors,\n toAiSdkPrompt,\n toAiSdkToolChoice,\n toAiSdkTools,\n} from './vercel-messages.js';\n\n/**\n * Structural shape the adapter expects from the AI SDK language model\n * value. The real `LanguageModelV4` matches this shape. Re-declared\n * here so we do not pin a hard dependency on `@ai-sdk/provider`.\n *\n * @stable\n */\nexport interface LanguageModelLike {\n readonly provider: string;\n readonly modelId: string;\n readonly specificationVersion?: string | number;\n /**\n * Optional capability flags carried by the AI SDK model. The adapter\n * forwards them onto the canonical `ProviderCapabilities` shape;\n * missing values are filled in with conservative defaults.\n */\n readonly supportedToolCallTypes?: readonly string[];\n}\n\n/**\n * Loose chunk shape emitted by the AI SDK's `streamText`. The shape is\n * intentionally permissive - we accept anything that carries the\n * fields we use and ignore the rest. This keeps the adapter tolerant\n * of additive AI SDK schema changes.\n *\n * The fields we read are normalized in the adapter via narrow helper\n * functions, so we deliberately type each as `unknown` and gate\n * access behind `typeof` checks at runtime.\n *\n * @stable\n */\nexport interface AISDKChunk {\n readonly type: string;\n readonly [extra: string]: unknown;\n}\n\n/**\n * Subset of the AI SDK surface used by the adapter.\n *\n * @stable\n */\nexport interface VercelRuntimeOverrides {\n readonly streamText: (args: {\n model: LanguageModelLike;\n /** AI SDK `ModelMessage`-shaped values (converted, NOT Graphorin `Message`s). */\n messages: ReadonlyArray<Readonly<Record<string, unknown>>>;\n system?: string;\n tools?: unknown;\n toolChoice?: unknown;\n temperature?: number;\n maxTokens?: number;\n abortSignal?: AbortSignal;\n providerOptions?: Readonly<Record<string, unknown>>;\n }) => {\n readonly fullStream: AsyncIterable<AISDKChunk>;\n };\n readonly generateText: (args: {\n model: LanguageModelLike;\n /** AI SDK `ModelMessage`-shaped values (converted, NOT Graphorin `Message`s). */\n messages: ReadonlyArray<Readonly<Record<string, unknown>>>;\n system?: string;\n tools?: unknown;\n toolChoice?: unknown;\n temperature?: number;\n maxTokens?: number;\n abortSignal?: AbortSignal;\n providerOptions?: Readonly<Record<string, unknown>>;\n }) => Promise<{\n readonly text?: string;\n readonly toolCalls?: ReadonlyArray<{\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: unknown;\n }>;\n readonly usage?: Partial<Usage> & {\n readonly inputTokens?: number;\n readonly outputTokens?: number;\n readonly totalTokens?: number;\n };\n readonly finishReason?: string;\n readonly providerMetadata?: Readonly<Record<string, unknown>>;\n }>;\n}\n\n/**\n * Options accepted by {@link vercelAdapter}.\n *\n * @stable\n */\nexport interface VercelAdapterOptions {\n /**\n * Fully-qualified provider name, used for span / log labelling.\n * Defaults to `${model.provider}-${model.modelId}`.\n */\n readonly name?: string;\n /**\n * Capability declaration. The adapter merges these on top of a\n * conservative defaults table (`streaming: true`, `toolCalling: true`,\n * `multimodal: true`, …); supply explicit values to narrow them.\n */\n readonly capabilities?: Partial<ProviderCapabilities>;\n /**\n * Runtime override for the AI SDK functions. When unset, the adapter\n * lazily `await import('ai')` on first call. Test suites pass a\n * fixture-driven implementation directly.\n */\n readonly runtimeOverrides?: VercelRuntimeOverrides;\n}\n\nconst DEFAULT_CAPABILITIES: Omit<ProviderCapabilities, 'reasoningContract'> = {\n streaming: true,\n toolCalling: true,\n parallelToolCalls: true,\n multimodal: true,\n structuredOutput: true,\n reasoning: true,\n contextWindow: 200_000,\n maxOutput: 16_384,\n};\n\n/**\n * Wrap a Vercel AI SDK language-model value in a Graphorin\n * {@link Provider}. Outbound requests are converted onto the AI SDK\n * call contract (name-keyed tools, `tool-call` / `tool-result` content\n * parts - see `vercel-messages.ts`); the streaming chunks emitted by\n * the AI SDK are translated back onto Graphorin `ProviderEvent`s.\n *\n * The adapter auto-detects the model's\n * {@link import('@graphorin/core').ReasoningContract} from its\n * `modelId` (e.g. Anthropic Claude → `'round-trip-required'`,\n * OpenAI o1 / o3 → `'hidden'`, Gemini reasoning variants →\n * `'hidden'`, everything else → `'optional'`). Callers can override\n * the inferred value via `options.capabilities.reasoningContract`.\n *\n * @stable\n */\nexport function vercelAdapter(\n model: LanguageModelLike,\n options: VercelAdapterOptions = {},\n): Provider {\n const name = options.name ?? `${model.provider}-${model.modelId}`;\n const inferredContract = inferReasoningContract({\n modelId: model.modelId,\n provider: model.provider,\n });\n const capabilities: ProviderCapabilities = {\n ...DEFAULT_CAPABILITIES,\n reasoningContract: inferredContract,\n ...options.capabilities,\n };\n const runtime = options.runtimeOverrides;\n\n return {\n name,\n modelId: model.modelId,\n capabilities,\n stream(req) {\n return streamFromVercel(model, name, capabilities, req, runtime);\n },\n async generate(req) {\n return generateFromVercel(model, name, capabilities, req, runtime);\n },\n };\n}\n\nasync function* streamFromVercel(\n model: LanguageModelLike,\n providerName: string,\n capabilities: ProviderCapabilities,\n req: ProviderRequest,\n overrides: VercelRuntimeOverrides | undefined,\n): AsyncIterable<ProviderEvent> {\n const sdk = await loadRuntime(overrides);\n const callArgs = buildCallArgs(model, applyRequestPreflight(req, capabilities));\n let stream: AsyncIterable<AISDKChunk>;\n try {\n const result = sdk.streamText(callArgs);\n stream = result.fullStream;\n } catch (cause) {\n const headers = headersFromCause(cause);\n throw new ProviderHttpError({\n providerName,\n status: statusFromCause(cause),\n message: 'streamText() failed before yielding any chunks',\n cause,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n\n yield {\n type: 'stream-start',\n metadata: {\n providerName,\n modelId: model.modelId,\n },\n };\n\n let finalUsage: Usage | undefined;\n let finishReason: FinishReason = 'stop';\n\n for await (const chunk of stream) {\n if (req.signal?.aborted) {\n // PS-12: an aborted stream must report 'aborted', not the initial 'stop'\n // - mirrors the openai-shaped and ollama adapters.\n finishReason = 'aborted';\n break;\n }\n switch (chunk.type) {\n case 'text-delta': {\n const delta = pickString(chunk.textDelta) ?? pickString(chunk.text) ?? '';\n if (delta.length > 0) {\n yield { type: 'text-delta', delta };\n }\n break;\n }\n case 'reasoning':\n case 'reasoning-delta': {\n const delta =\n pickString(chunk.textDelta) ?? pickString(chunk.delta) ?? pickString(chunk.text) ?? '';\n if (delta.length > 0) {\n yield { type: 'reasoning-delta', delta };\n }\n break;\n }\n // PS-6 dual-shape: AI SDK v4 streams `tool-call-streaming-start` /\n // `tool-call-delta` keyed by `toolCallId`/`argsTextDelta`; v7 streams\n // `tool-input-start` / `tool-input-delta` keyed by `id`/`delta`.\n case 'tool-call-streaming-start':\n case 'tool-input-start': {\n const toolCallId = pickString(chunk.toolCallId) ?? pickString(chunk.id);\n const toolName = pickString(chunk.toolName);\n if (toolCallId !== undefined && toolName !== undefined) {\n yield {\n type: 'tool-call-start',\n toolCallId,\n toolName,\n };\n }\n break;\n }\n case 'tool-call-delta':\n case 'tool-input-delta': {\n const toolCallId = pickString(chunk.toolCallId) ?? pickString(chunk.id);\n const argsDelta =\n pickString(chunk.argsTextDelta) ??\n pickString(chunk.delta) ??\n pickString(chunk.inputTextDelta);\n if (toolCallId !== undefined && argsDelta !== undefined && argsDelta.length > 0) {\n yield {\n type: 'tool-call-input-delta',\n toolCallId,\n argsDelta,\n };\n }\n break;\n }\n case 'tool-call': {\n const toolCallId = pickString(chunk.toolCallId) ?? pickString(chunk.id);\n if (toolCallId !== undefined) {\n yield {\n type: 'tool-call-end',\n toolCallId,\n // v4 carries `args`; v7 carries `input`.\n finalArgs: chunk.args ?? chunk.input,\n };\n }\n break;\n }\n case 'finish': {\n finishReason = mapFinishReason(pickString(chunk.finishReason));\n // v4 carries `usage`; v7 carries `totalUsage` (zeroing the v4\n // read nulled cost tracking on streaming).\n finalUsage = mapUsage(chunk.totalUsage ?? chunk.usage);\n break;\n }\n case 'error': {\n const errorField = chunk.error;\n const message =\n typeof errorField === 'string'\n ? errorField\n : typeof errorField === 'object' && errorField !== null\n ? (pickString((errorField as { message?: unknown }).message) ?? 'unknown error')\n : 'unknown error';\n yield {\n type: 'error',\n error: { kind: 'unknown', message },\n };\n break;\n }\n default:\n // Unknown chunk types are forward-compatible no-ops; we keep\n // streaming so additive AI SDK upgrades do not break callers.\n break;\n }\n }\n\n yield {\n type: 'finish',\n finishReason,\n usage: finalUsage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n}\n\nasync function generateFromVercel(\n model: LanguageModelLike,\n providerName: string,\n capabilities: ProviderCapabilities,\n req: ProviderRequest,\n overrides: VercelRuntimeOverrides | undefined,\n): Promise<ProviderResponse> {\n const sdk = await loadRuntime(overrides);\n const callArgs = buildCallArgs(model, applyRequestPreflight(req, capabilities));\n let result: Awaited<ReturnType<VercelRuntimeOverrides['generateText']>>;\n try {\n result = await sdk.generateText(callArgs);\n } catch (cause) {\n const headers = headersFromCause(cause);\n throw new ProviderHttpError({\n providerName,\n status: statusFromCause(cause),\n message: 'generateText() rejected',\n cause,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n const usage = mapUsage(result.usage) ?? {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n const finishReason = mapFinishReason(result.finishReason);\n const response: ProviderResponse = {\n usage,\n finishReason,\n ...(result.text !== undefined ? { text: result.text } : {}),\n ...(result.toolCalls !== undefined\n ? { toolCalls: result.toolCalls.map(normalizeToolCall) }\n : {}),\n ...(result.providerMetadata !== undefined ? { providerMetadata: result.providerMetadata } : {}),\n };\n return response;\n}\n\nfunction applyRequestPreflight(\n req: ProviderRequest,\n capabilities: ProviderCapabilities,\n): ProviderRequest {\n const retention = resolveReasoningRetention({\n ...(req.reasoningRetention !== undefined ? { requested: req.reasoningRetention } : {}),\n ...(capabilities.reasoningContract !== undefined\n ? { contract: capabilities.reasoningContract }\n : {}),\n });\n if (retention === 'pass-through-all') return req;\n const filtered = applyReasoningPolicy({ messages: req.messages, retention });\n if (filtered === req.messages) return req;\n return { ...req, messages: filtered };\n}\n\nfunction buildCallArgs(model: LanguageModelLike, req: ProviderRequest) {\n const prompt = toAiSdkPrompt(req.messages);\n // System-role transcript messages are hoisted here - the SDK rejects\n // them inside `messages`. The request-level systemMessage leads.\n const system = [req.systemMessage, prompt.system]\n .filter((s): s is string => s !== undefined && s.length > 0)\n .join('\\n\\n');\n const messages =\n req.cachePolicy?.breakpoints === 'auto'\n ? applyCacheAnchors(prompt.messages, req.cachePolicy.ttl)\n : prompt.messages;\n return {\n model,\n messages,\n ...(system.length > 0 ? { system } : {}),\n // C2: fold worked examples in the adapter itself, so raw-adapter use\n // (no createProvider wrapper) still puts them in front of the model.\n // Idempotent: an upstream fold already dropped the structured field.\n ...(req.tools !== undefined && req.tools.length > 0\n ? { tools: toAiSdkTools(foldToolExamples(req.tools)) }\n : {}),\n ...(req.toolChoice !== undefined ? { toolChoice: toAiSdkToolChoice(req.toolChoice) } : {}),\n ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),\n // v4 reads `maxTokens`; v7 renamed it `maxOutputTokens` - send both\n // so the cap is honoured against either peer (PS-6).\n ...(req.maxTokens !== undefined\n ? { maxTokens: req.maxTokens, maxOutputTokens: req.maxTokens }\n : {}),\n ...(req.signal !== undefined ? { abortSignal: req.signal } : {}),\n ...(req.providerOptions !== undefined ? { providerOptions: req.providerOptions } : {}),\n } as const;\n}\n\nfunction pickString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Normalize a generate() tool call across peers: AI SDK v4 carries\n * `args`, v7 carries `input` (PS-6). The framework shape is `args`.\n */\nfunction normalizeToolCall(tc: unknown): { toolCallId: string; toolName: string; args: unknown } {\n const t = tc as {\n toolCallId?: unknown;\n id?: unknown;\n toolName?: unknown;\n args?: unknown;\n input?: unknown;\n };\n return {\n toolCallId: pickString(t.toolCallId) ?? pickString(t.id) ?? '',\n toolName: pickString(t.toolName) ?? '',\n args: t.args ?? t.input,\n };\n}\n\n/**\n * Lift a real HTTP status from a rejected AI SDK call (PS-2). The SDK's\n * `APICallError` carries a numeric `statusCode`; surfacing it lets\n * `withRetry` / `withFallback` see a genuine 429 / 5xx instead of the\n * `status: 0` network-error placeholder. Returns `0` when no status is\n * present (a true transport-level failure or an abort) - `0` is itself\n * retryable / fallback-eligible by default, while an abort is excluded by\n * the predicates via the wrapped `cause`.\n */\nfunction statusFromCause(cause: unknown): number {\n if (cause !== null && typeof cause === 'object') {\n const c = cause as { statusCode?: unknown; status?: unknown };\n if (typeof c.statusCode === 'number' && Number.isFinite(c.statusCode)) return c.statusCode;\n if (typeof c.status === 'number' && Number.isFinite(c.status)) return c.status;\n }\n return 0;\n}\n\n/**\n * Lift backoff-relevant response headers from a rejected AI SDK call.\n * `APICallError` carries `responseHeaders: Record<string, string>`;\n * forwarding `retry-after` / `x-ratelimit-*` lets `withRetry` honour\n * server-provided delays on 429s.\n */\nfunction headersFromCause(cause: unknown): Readonly<Record<string, string>> | undefined {\n if (cause === null || typeof cause !== 'object') return undefined;\n const raw = (cause as { responseHeaders?: unknown }).responseHeaders;\n if (raw === null || typeof raw !== 'object') return undefined;\n const picked: Record<string, string> = {};\n for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {\n const lower = key.toLowerCase();\n if (\n (lower === 'retry-after' || lower.startsWith('x-ratelimit-')) &&\n typeof value === 'string'\n ) {\n picked[lower] = value;\n }\n }\n return Object.keys(picked).length > 0 ? picked : undefined;\n}\n\nfunction mapFinishReason(value: string | undefined): FinishReason {\n switch (value) {\n case 'stop':\n case 'length':\n case 'tool-calls':\n case 'content-filter':\n case 'error':\n return value;\n case 'aborted':\n case 'cancelled':\n return 'aborted';\n default:\n return 'stop';\n }\n}\n\nfunction mapUsage(input: unknown): Usage | undefined {\n if (input === undefined || input === null || typeof input !== 'object') return undefined;\n const u = input as {\n promptTokens?: number;\n completionTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n reasoningTokens?: number;\n totalTokens?: number;\n // v7 runtime-normalized detail splits (core-provider-02): inputTokens\n // is the TOTAL including cache reads/writes; outputTokens the TOTAL\n // including reasoning.\n inputTokenDetails?: {\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n noCacheTokens?: number;\n };\n outputTokenDetails?: { reasoningTokens?: number; textTokens?: number };\n };\n const promptTokens = u.promptTokens ?? u.inputTokens ?? 0;\n const rawCompletion = u.completionTokens ?? u.outputTokens ?? 0;\n const totalTokens = u.totalTokens ?? promptTokens + rawCompletion;\n const cachedReadTokens = numberOrUndefined(u.inputTokenDetails?.cacheReadTokens);\n const cacheWriteTokens = numberOrUndefined(u.inputTokenDetails?.cacheWriteTokens);\n // The v7 detail reports reasoning as a SUBSET of outputTokens; core Usage\n // declares reasoningTokens EXCLUSIVE of completionTokens, so split the\n // total (sum unchanged). The flat field (v4/v5 peers) is already exclusive.\n const detailReasoning = numberOrUndefined(u.outputTokenDetails?.reasoningTokens);\n let completionTokens = rawCompletion;\n let reasoningTokens = u.reasoningTokens;\n if (reasoningTokens === undefined && detailReasoning !== undefined && detailReasoning > 0) {\n reasoningTokens = detailReasoning;\n completionTokens = Math.max(0, rawCompletion - detailReasoning);\n }\n const usage: Usage = {\n promptTokens,\n completionTokens,\n totalTokens,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n ...(cachedReadTokens !== undefined && cachedReadTokens > 0 ? { cachedReadTokens } : {}),\n ...(cacheWriteTokens !== undefined && cacheWriteTokens > 0 ? { cacheWriteTokens } : {}),\n };\n return usage;\n}\n\nfunction numberOrUndefined(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nlet cachedRuntime: VercelRuntimeOverrides | null = null;\n\nasync function loadRuntime(\n overrides: VercelRuntimeOverrides | undefined,\n): Promise<VercelRuntimeOverrides> {\n if (overrides !== undefined) return overrides;\n if (cachedRuntime !== null) return cachedRuntime;\n let mod: { streamText?: unknown; generateText?: unknown };\n try {\n mod = (await import('ai')) as { streamText?: unknown; generateText?: unknown };\n } catch (cause) {\n throw new ProviderStreamParseError(\n 'vercel',\n \"Failed to import the 'ai' peer dependency. Install it with `pnpm add ai` or pass a runtimeOverrides value.\",\n cause,\n );\n }\n if (typeof mod.streamText !== 'function' || typeof mod.generateText !== 'function') {\n throw new ProviderStreamParseError(\n 'vercel',\n \"The installed 'ai' package does not expose streamText / generateText functions.\",\n );\n }\n cachedRuntime = {\n streamText: mod.streamText as VercelRuntimeOverrides['streamText'],\n generateText: mod.generateText as VercelRuntimeOverrides['generateText'],\n };\n return cachedRuntime;\n}\n\n/**\n * Test-only hook that resets the cached AI SDK runtime. Provider tests\n * that mutate the cache (e.g. by injecting a mock then verifying the\n * default loader runs) call this between scenarios.\n *\n * @internal\n */\nexport function __resetVercelRuntimeCache(): void {\n cachedRuntime = null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vercel.js","names":["DEFAULT_CAPABILITIES: Omit<ProviderCapabilities, 'reasoningContract'>","capabilities: ProviderCapabilities","stream: AsyncIterable<AISDKChunk>","finalUsage: Usage | undefined","finishReason: FinishReason","result: Awaited<ReturnType<VercelRuntimeOverrides['generateText']>>","picked: Record<string, string>","cachedRuntime: VercelRuntimeOverrides | null","mod: { streamText?: unknown; generateText?: unknown }"],"sources":["../../src/adapters/vercel.ts"],"sourcesContent":["/**\n * `vercelAdapter` - wraps a Vercel AI SDK `LanguageModel`-shaped value\n * into a Graphorin {@link Provider}. The adapter is the default cloud\n * path: it speaks the AI SDK's `streamText` / `generateText` API and\n * maps the resulting events onto the canonical\n * `ProviderEvent` discriminated union.\n *\n * Outbound, the adapter converts Graphorin messages / tools onto the\n * AI SDK call contract (see `vercel-messages.ts`): tool definitions\n * become a name-keyed record with `jsonSchema()`-shaped input schemas,\n * assistant `toolCalls` become `tool-call` content parts, and\n * `ToolMessage`s become `tool-result` messages - the SDK zod-validates\n * all of these and rejects the raw Graphorin shapes.\n *\n * The AI SDK is an **optional peer dependency** of `@graphorin/provider`.\n * Production callers leave `runtimeOverrides` unset and the adapter\n * dynamically imports the package on first use; test fixtures pass a\n * `runtimeOverrides` value to short-circuit the import and feed\n * fixture chunks directly. The overrides shape is intentionally\n * structural so users can supply hand-rolled stubs or any compatible\n * library.\n *\n * @packageDocumentation\n */\n\nimport type {\n FinishReason,\n Provider,\n ProviderCapabilities,\n ProviderEvent,\n ProviderRequest,\n ProviderResponse,\n Usage,\n} from '@graphorin/core';\n\nimport {\n classifyHttpStatus,\n ProviderHttpError,\n ProviderStreamParseError,\n} from '../errors/errors.js';\nimport { isAbortError } from '../internal/abort.js';\nimport { applyReasoningPolicy } from '../reasoning/apply-policy.js';\nimport { inferReasoningContract } from '../reasoning/classify-contract.js';\nimport { resolveReasoningRetention } from '../reasoning/retention.js';\nimport { foldToolExamples } from '../tool-examples.js';\nimport {\n applyCacheAnchors,\n toAiSdkPrompt,\n toAiSdkToolChoice,\n toAiSdkTools,\n} from './vercel-messages.js';\n\n/**\n * Structural shape the adapter expects from the AI SDK language model\n * value. The real `LanguageModelV4` matches this shape. Re-declared\n * here so we do not pin a hard dependency on `@ai-sdk/provider`.\n *\n * @stable\n */\nexport interface LanguageModelLike {\n readonly provider: string;\n readonly modelId: string;\n readonly specificationVersion?: string | number;\n /**\n * Optional capability flags carried by the AI SDK model. The adapter\n * forwards them onto the canonical `ProviderCapabilities` shape;\n * missing values are filled in with conservative defaults.\n */\n readonly supportedToolCallTypes?: readonly string[];\n}\n\n/**\n * Loose chunk shape emitted by the AI SDK's `streamText`. The shape is\n * intentionally permissive - we accept anything that carries the\n * fields we use and ignore the rest. This keeps the adapter tolerant\n * of additive AI SDK schema changes.\n *\n * The fields we read are normalized in the adapter via narrow helper\n * functions, so we deliberately type each as `unknown` and gate\n * access behind `typeof` checks at runtime.\n *\n * @stable\n */\nexport interface AISDKChunk {\n readonly type: string;\n readonly [extra: string]: unknown;\n}\n\n/**\n * Subset of the AI SDK surface used by the adapter.\n *\n * @stable\n */\nexport interface VercelRuntimeOverrides {\n readonly streamText: (args: {\n model: LanguageModelLike;\n /** AI SDK `ModelMessage`-shaped values (converted, NOT Graphorin `Message`s). */\n messages: ReadonlyArray<Readonly<Record<string, unknown>>>;\n system?: string;\n tools?: unknown;\n toolChoice?: unknown;\n temperature?: number;\n maxTokens?: number;\n abortSignal?: AbortSignal;\n providerOptions?: Readonly<Record<string, unknown>>;\n }) => {\n readonly fullStream: AsyncIterable<AISDKChunk>;\n };\n readonly generateText: (args: {\n model: LanguageModelLike;\n /** AI SDK `ModelMessage`-shaped values (converted, NOT Graphorin `Message`s). */\n messages: ReadonlyArray<Readonly<Record<string, unknown>>>;\n system?: string;\n tools?: unknown;\n toolChoice?: unknown;\n temperature?: number;\n maxTokens?: number;\n abortSignal?: AbortSignal;\n providerOptions?: Readonly<Record<string, unknown>>;\n }) => Promise<{\n readonly text?: string;\n readonly toolCalls?: ReadonlyArray<{\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: unknown;\n }>;\n readonly usage?: Partial<Usage> & {\n readonly inputTokens?: number;\n readonly outputTokens?: number;\n readonly totalTokens?: number;\n };\n readonly finishReason?: string;\n readonly providerMetadata?: Readonly<Record<string, unknown>>;\n }>;\n}\n\n/**\n * Options accepted by {@link vercelAdapter}.\n *\n * @stable\n */\nexport interface VercelAdapterOptions {\n /**\n * Fully-qualified provider name, used for span / log labelling.\n * Defaults to `${model.provider}-${model.modelId}`.\n */\n readonly name?: string;\n /**\n * Capability declaration. The adapter merges these on top of a\n * conservative defaults table (`streaming: true`, `toolCalling: true`,\n * `multimodal: true`, …); supply explicit values to narrow them.\n */\n readonly capabilities?: Partial<ProviderCapabilities>;\n /**\n * Runtime override for the AI SDK functions. When unset, the adapter\n * lazily `await import('ai')` on first call. Test suites pass a\n * fixture-driven implementation directly.\n */\n readonly runtimeOverrides?: VercelRuntimeOverrides;\n}\n\nconst DEFAULT_CAPABILITIES: Omit<ProviderCapabilities, 'reasoningContract'> = {\n streaming: true,\n toolCalling: true,\n parallelToolCalls: true,\n multimodal: true,\n structuredOutput: true,\n reasoning: true,\n contextWindow: 200_000,\n maxOutput: 16_384,\n};\n\n/**\n * Wrap a Vercel AI SDK language-model value in a Graphorin\n * {@link Provider}. Outbound requests are converted onto the AI SDK\n * call contract (name-keyed tools, `tool-call` / `tool-result` content\n * parts - see `vercel-messages.ts`); the streaming chunks emitted by\n * the AI SDK are translated back onto Graphorin `ProviderEvent`s.\n *\n * The adapter auto-detects the model's\n * `ReasoningContract` from its\n * `modelId` (e.g. Anthropic Claude → `'round-trip-required'`,\n * OpenAI o1 / o3 → `'hidden'`, Gemini reasoning variants →\n * `'hidden'`, everything else → `'optional'`). Callers can override\n * the inferred value via `options.capabilities.reasoningContract`.\n *\n * @stable\n */\nexport function vercelAdapter(\n model: LanguageModelLike,\n options: VercelAdapterOptions = {},\n): Provider {\n const name = options.name ?? `${model.provider}-${model.modelId}`;\n const inferredContract = inferReasoningContract({\n modelId: model.modelId,\n provider: model.provider,\n });\n const capabilities: ProviderCapabilities = {\n ...DEFAULT_CAPABILITIES,\n reasoningContract: inferredContract,\n ...options.capabilities,\n };\n const runtime = options.runtimeOverrides;\n\n return {\n name,\n modelId: model.modelId,\n capabilities,\n stream(req) {\n return streamFromVercel(model, name, capabilities, req, runtime);\n },\n async generate(req) {\n return generateFromVercel(model, name, capabilities, req, runtime);\n },\n };\n}\n\nasync function* streamFromVercel(\n model: LanguageModelLike,\n providerName: string,\n capabilities: ProviderCapabilities,\n req: ProviderRequest,\n overrides: VercelRuntimeOverrides | undefined,\n): AsyncIterable<ProviderEvent> {\n const sdk = await loadRuntime(overrides);\n const callArgs = buildCallArgs(model, applyRequestPreflight(req, capabilities));\n let stream: AsyncIterable<AISDKChunk>;\n try {\n const result = sdk.streamText(callArgs);\n stream = result.fullStream;\n } catch (cause) {\n const headers = headersFromCause(cause);\n throw new ProviderHttpError({\n providerName,\n status: statusFromCause(cause),\n message: 'streamText() failed before yielding any chunks',\n cause,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n\n // W-023: the AI SDK never throws from streamText() synchronously -\n // transport/HTTP failures (429/500/529) arrive as in-band\n // `{type:'error'}` chunks. Emitting `stream-start` eagerly made every\n // such failure post-yield, which forbids `withRetry`/`withFallback`\n // from restarting the stream (PS-1). Defer it until the first REAL\n // mapped event, so a pre-content failure can be THROWN as a typed\n // `ProviderHttpError` (retryable / fallback-eligible) instead.\n let emittedStart = false;\n const startEvent = (): ProviderEvent => {\n emittedStart = true;\n return {\n type: 'stream-start',\n metadata: {\n providerName,\n modelId: model.modelId,\n },\n };\n };\n\n let finalUsage: Usage | undefined;\n let finishReason: FinishReason = 'stop';\n let sawError = false;\n\n for await (const chunk of stream) {\n if (req.signal?.aborted) {\n // PS-12: an aborted stream must report 'aborted', not the initial 'stop'\n // - mirrors the openai-shaped and ollama adapters.\n finishReason = 'aborted';\n break;\n }\n switch (chunk.type) {\n case 'text-delta': {\n const delta = pickString(chunk.textDelta) ?? pickString(chunk.text) ?? '';\n if (delta.length > 0) {\n if (!emittedStart) yield startEvent();\n yield { type: 'text-delta', delta };\n }\n break;\n }\n case 'reasoning':\n case 'reasoning-delta': {\n const delta =\n pickString(chunk.textDelta) ?? pickString(chunk.delta) ?? pickString(chunk.text) ?? '';\n if (delta.length > 0) {\n if (!emittedStart) yield startEvent();\n yield { type: 'reasoning-delta', delta };\n }\n break;\n }\n // W-024: per-block reasoning terminators. AI SDK v4 streams a\n // separate 'reasoning-signature' chunk ({signature}) and\n // 'redacted-reasoning' ({data}); v7 closes each block with\n // 'reasoning-end' carrying providerMetadata.anthropic.signature /\n // .redactedData. All three become the Graphorin 'reasoning-end'\n // event whose meta the retention pipeline round-trips\n // ('pass-through-claude' -> providerOptions.anthropic.signature).\n case 'reasoning-signature': {\n const signature = pickString(chunk.signature);\n if (!emittedStart) yield startEvent();\n yield {\n type: 'reasoning-end',\n meta: { provider: 'anthropic', ...(signature !== undefined ? { signature } : {}) },\n };\n break;\n }\n case 'redacted-reasoning': {\n const data = pickString(chunk.data);\n if (!emittedStart) yield startEvent();\n yield {\n type: 'reasoning-end',\n meta: { provider: 'anthropic', ...(data !== undefined ? { data } : {}) },\n };\n break;\n }\n case 'reasoning-end': {\n const anthropicMeta =\n typeof chunk.providerMetadata === 'object' && chunk.providerMetadata !== null\n ? ((chunk.providerMetadata as { anthropic?: unknown }).anthropic as\n | { signature?: unknown; redactedData?: unknown }\n | undefined)\n : undefined;\n const signature = pickString(anthropicMeta?.signature);\n const data = pickString(anthropicMeta?.redactedData);\n if (!emittedStart) yield startEvent();\n yield {\n type: 'reasoning-end',\n meta: {\n provider: 'anthropic',\n ...(signature !== undefined ? { signature } : {}),\n ...(data !== undefined ? { data } : {}),\n },\n };\n break;\n }\n // PS-6 dual-shape: AI SDK v4 streams `tool-call-streaming-start` /\n // `tool-call-delta` keyed by `toolCallId`/`argsTextDelta`; v7 streams\n // `tool-input-start` / `tool-input-delta` keyed by `id`/`delta`.\n case 'tool-call-streaming-start':\n case 'tool-input-start': {\n const toolCallId = pickString(chunk.toolCallId) ?? pickString(chunk.id);\n const toolName = pickString(chunk.toolName);\n if (toolCallId !== undefined && toolName !== undefined) {\n if (!emittedStart) yield startEvent();\n yield {\n type: 'tool-call-start',\n toolCallId,\n toolName,\n };\n }\n break;\n }\n case 'tool-call-delta':\n case 'tool-input-delta': {\n const toolCallId = pickString(chunk.toolCallId) ?? pickString(chunk.id);\n const argsDelta =\n pickString(chunk.argsTextDelta) ??\n pickString(chunk.delta) ??\n pickString(chunk.inputTextDelta);\n if (toolCallId !== undefined && argsDelta !== undefined && argsDelta.length > 0) {\n if (!emittedStart) yield startEvent();\n yield {\n type: 'tool-call-input-delta',\n toolCallId,\n argsDelta,\n };\n }\n break;\n }\n case 'tool-call': {\n const toolCallId = pickString(chunk.toolCallId) ?? pickString(chunk.id);\n if (toolCallId !== undefined) {\n if (!emittedStart) yield startEvent();\n yield {\n type: 'tool-call-end',\n toolCallId,\n // v4 carries `args`; v7 carries `input`.\n finalArgs: chunk.args ?? chunk.input,\n };\n }\n break;\n }\n case 'finish': {\n finishReason = mapFinishReason(pickString(chunk.finishReason));\n // v4 carries `usage`; v7 carries `totalUsage` (zeroing the v4\n // read nulled cost tracking on streaming).\n finalUsage = mapUsage(chunk.totalUsage ?? chunk.usage);\n break;\n }\n case 'error': {\n const errorField = chunk.error;\n const message =\n typeof errorField === 'string'\n ? errorField\n : typeof errorField === 'object' && errorField !== null\n ? (pickString((errorField as { message?: unknown }).message) ?? 'unknown error')\n : 'unknown error';\n // W-023: an abort surfacing as an error chunk is a cancellation,\n // never a retryable failure (mirrors PS-12).\n if (isAbortError(errorField) || req.signal?.aborted === true) {\n finishReason = 'aborted';\n break;\n }\n const status = statusFromCause(errorField);\n if (!emittedStart) {\n // Pre-content failure: nothing was yielded, so by PS-1 the\n // middleware may restart this stream. Throw the classified\n // typed error - `withRetry` retries 429/5xx pre-yield,\n // `withFallback` switches providers, and the agent-level\n // fallback chain reads `errorKind` off the throw.\n const headers = headersFromCause(errorField);\n throw new ProviderHttpError({\n providerName,\n status,\n message,\n cause: errorField,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n // Mid-stream failure: a restart is forbidden (PS-1) - surface a\n // structural error event with the canonical kind so the\n // agent-level per-step fallback can act on rate-limit/capacity\n // instead of an inert 'unknown'. Status 0 classifies as\n // 'transient' by the PS-2 network policy.\n sawError = true;\n yield {\n type: 'error',\n error: { kind: classifyHttpStatus(status, message), message },\n };\n break;\n }\n default:\n // Unknown chunk types are forward-compatible no-ops; we keep\n // streaming so additive AI SDK upgrades do not break callers.\n break;\n }\n }\n\n if (!emittedStart) yield startEvent();\n yield {\n type: 'finish',\n // W-023: a stream that surfaced an error event must not end with a\n // synthetic 'stop' + zero usage - parity with llamacpp-node (PS-4).\n finishReason: sawError ? 'error' : finishReason,\n usage: finalUsage ?? { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n };\n}\n\nasync function generateFromVercel(\n model: LanguageModelLike,\n providerName: string,\n capabilities: ProviderCapabilities,\n req: ProviderRequest,\n overrides: VercelRuntimeOverrides | undefined,\n): Promise<ProviderResponse> {\n const sdk = await loadRuntime(overrides);\n const callArgs = buildCallArgs(model, applyRequestPreflight(req, capabilities));\n let result: Awaited<ReturnType<VercelRuntimeOverrides['generateText']>>;\n try {\n result = await sdk.generateText(callArgs);\n } catch (cause) {\n const headers = headersFromCause(cause);\n throw new ProviderHttpError({\n providerName,\n status: statusFromCause(cause),\n message: 'generateText() rejected',\n cause,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n const usage = mapUsage(result.usage) ?? {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n };\n const finishReason = mapFinishReason(result.finishReason);\n const response: ProviderResponse = {\n usage,\n finishReason,\n ...(result.text !== undefined ? { text: result.text } : {}),\n ...(result.toolCalls !== undefined\n ? { toolCalls: result.toolCalls.map(normalizeToolCall) }\n : {}),\n ...(result.providerMetadata !== undefined ? { providerMetadata: result.providerMetadata } : {}),\n };\n return response;\n}\n\nfunction applyRequestPreflight(\n req: ProviderRequest,\n capabilities: ProviderCapabilities,\n): ProviderRequest {\n const retention = resolveReasoningRetention({\n ...(req.reasoningRetention !== undefined ? { requested: req.reasoningRetention } : {}),\n ...(capabilities.reasoningContract !== undefined\n ? { contract: capabilities.reasoningContract }\n : {}),\n });\n if (retention === 'pass-through-all') return req;\n const filtered = applyReasoningPolicy({ messages: req.messages, retention });\n if (filtered === req.messages) return req;\n return { ...req, messages: filtered };\n}\n\nfunction buildCallArgs(model: LanguageModelLike, req: ProviderRequest) {\n const prompt = toAiSdkPrompt(req.messages);\n // System-role transcript messages are hoisted here - the SDK rejects\n // them inside `messages`. The request-level systemMessage leads.\n const system = [req.systemMessage, prompt.system]\n .filter((s): s is string => s !== undefined && s.length > 0)\n .join('\\n\\n');\n const messages =\n req.cachePolicy?.breakpoints === 'auto'\n ? applyCacheAnchors(prompt.messages, req.cachePolicy.ttl)\n : prompt.messages;\n return {\n model,\n messages,\n ...(system.length > 0 ? { system } : {}),\n // C2: fold worked examples in the adapter itself, so raw-adapter use\n // (no createProvider wrapper) still puts them in front of the model.\n // Idempotent: an upstream fold already dropped the structured field.\n ...(req.tools !== undefined && req.tools.length > 0\n ? { tools: toAiSdkTools(foldToolExamples(req.tools)) }\n : {}),\n ...(req.toolChoice !== undefined ? { toolChoice: toAiSdkToolChoice(req.toolChoice) } : {}),\n ...(req.temperature !== undefined ? { temperature: req.temperature } : {}),\n // v4 reads `maxTokens`; v7 renamed it `maxOutputTokens` - send both\n // so the cap is honoured against either peer (PS-6).\n ...(req.maxTokens !== undefined\n ? { maxTokens: req.maxTokens, maxOutputTokens: req.maxTokens }\n : {}),\n ...(req.signal !== undefined ? { abortSignal: req.signal } : {}),\n ...(req.providerOptions !== undefined ? { providerOptions: req.providerOptions } : {}),\n } as const;\n}\n\nfunction pickString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Normalize a generate() tool call across peers: AI SDK v4 carries\n * `args`, v7 carries `input` (PS-6). The framework shape is `args`.\n */\nfunction normalizeToolCall(tc: unknown): { toolCallId: string; toolName: string; args: unknown } {\n const t = tc as {\n toolCallId?: unknown;\n id?: unknown;\n toolName?: unknown;\n args?: unknown;\n input?: unknown;\n };\n return {\n toolCallId: pickString(t.toolCallId) ?? pickString(t.id) ?? '',\n toolName: pickString(t.toolName) ?? '',\n args: t.args ?? t.input,\n };\n}\n\n/**\n * Lift a real HTTP status from a rejected AI SDK call (PS-2). The SDK's\n * `APICallError` carries a numeric `statusCode`; surfacing it lets\n * `withRetry` / `withFallback` see a genuine 429 / 5xx instead of the\n * `status: 0` network-error placeholder. Returns `0` when no status is\n * present (a true transport-level failure or an abort) - `0` is itself\n * retryable / fallback-eligible by default, while an abort is excluded by\n * the predicates via the wrapped `cause`.\n */\nfunction statusFromCause(cause: unknown): number {\n if (cause !== null && typeof cause === 'object') {\n const c = cause as { statusCode?: unknown; status?: unknown };\n if (typeof c.statusCode === 'number' && Number.isFinite(c.statusCode)) return c.statusCode;\n if (typeof c.status === 'number' && Number.isFinite(c.status)) return c.status;\n }\n return 0;\n}\n\n/**\n * Lift backoff-relevant response headers from a rejected AI SDK call.\n * `APICallError` carries `responseHeaders: Record<string, string>`;\n * forwarding `retry-after` / `x-ratelimit-*` lets `withRetry` honour\n * server-provided delays on 429s.\n */\nfunction headersFromCause(cause: unknown): Readonly<Record<string, string>> | undefined {\n if (cause === null || typeof cause !== 'object') return undefined;\n const raw = (cause as { responseHeaders?: unknown }).responseHeaders;\n if (raw === null || typeof raw !== 'object') return undefined;\n const picked: Record<string, string> = {};\n for (const [key, value] of Object.entries(raw as Record<string, unknown>)) {\n const lower = key.toLowerCase();\n if (\n (lower === 'retry-after' || lower.startsWith('x-ratelimit-')) &&\n typeof value === 'string'\n ) {\n picked[lower] = value;\n }\n }\n return Object.keys(picked).length > 0 ? picked : undefined;\n}\n\nfunction mapFinishReason(value: string | undefined): FinishReason {\n switch (value) {\n case 'stop':\n case 'length':\n case 'tool-calls':\n case 'content-filter':\n case 'error':\n return value;\n case 'aborted':\n case 'cancelled':\n return 'aborted';\n default:\n return 'stop';\n }\n}\n\nfunction mapUsage(input: unknown): Usage | undefined {\n if (input === undefined || input === null || typeof input !== 'object') return undefined;\n const u = input as {\n promptTokens?: number;\n completionTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n reasoningTokens?: number;\n totalTokens?: number;\n // v7 runtime-normalized detail splits (core-provider-02): inputTokens\n // is the TOTAL including cache reads/writes; outputTokens the TOTAL\n // including reasoning.\n inputTokenDetails?: {\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n noCacheTokens?: number;\n };\n outputTokenDetails?: { reasoningTokens?: number; textTokens?: number };\n };\n const promptTokens = u.promptTokens ?? u.inputTokens ?? 0;\n const rawCompletion = u.completionTokens ?? u.outputTokens ?? 0;\n const totalTokens = u.totalTokens ?? promptTokens + rawCompletion;\n const cachedReadTokens = numberOrUndefined(u.inputTokenDetails?.cacheReadTokens);\n const cacheWriteTokens = numberOrUndefined(u.inputTokenDetails?.cacheWriteTokens);\n // The v7 detail reports reasoning as a SUBSET of outputTokens; core Usage\n // declares reasoningTokens EXCLUSIVE of completionTokens, so split the\n // total (sum unchanged). The flat field (v4/v5 peers) is already exclusive.\n const detailReasoning = numberOrUndefined(u.outputTokenDetails?.reasoningTokens);\n let completionTokens = rawCompletion;\n let reasoningTokens = u.reasoningTokens;\n if (reasoningTokens === undefined && detailReasoning !== undefined && detailReasoning > 0) {\n reasoningTokens = detailReasoning;\n completionTokens = Math.max(0, rawCompletion - detailReasoning);\n }\n const usage: Usage = {\n promptTokens,\n completionTokens,\n totalTokens,\n ...(reasoningTokens !== undefined ? { reasoningTokens } : {}),\n ...(cachedReadTokens !== undefined && cachedReadTokens > 0 ? { cachedReadTokens } : {}),\n ...(cacheWriteTokens !== undefined && cacheWriteTokens > 0 ? { cacheWriteTokens } : {}),\n };\n return usage;\n}\n\nfunction numberOrUndefined(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nlet cachedRuntime: VercelRuntimeOverrides | null = null;\n\nasync function loadRuntime(\n overrides: VercelRuntimeOverrides | undefined,\n): Promise<VercelRuntimeOverrides> {\n if (overrides !== undefined) return overrides;\n if (cachedRuntime !== null) return cachedRuntime;\n let mod: { streamText?: unknown; generateText?: unknown };\n try {\n mod = (await import('ai')) as { streamText?: unknown; generateText?: unknown };\n } catch (cause) {\n throw new ProviderStreamParseError(\n 'vercel',\n \"Failed to import the 'ai' peer dependency. Install it with `pnpm add ai` or pass a runtimeOverrides value.\",\n cause,\n );\n }\n if (typeof mod.streamText !== 'function' || typeof mod.generateText !== 'function') {\n throw new ProviderStreamParseError(\n 'vercel',\n \"The installed 'ai' package does not expose streamText / generateText functions.\",\n );\n }\n cachedRuntime = {\n streamText: mod.streamText as VercelRuntimeOverrides['streamText'],\n generateText: mod.generateText as VercelRuntimeOverrides['generateText'],\n };\n return cachedRuntime;\n}\n\n/**\n * Test-only hook that resets the cached AI SDK runtime. Provider tests\n * that mutate the cache (e.g. by injecting a mock then verifying the\n * default loader runs) call this between scenarios.\n *\n * @internal\n */\nexport function __resetVercelRuntimeCache(): void {\n cachedRuntime = null;\n}\n"],"mappings":"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"}
|
package/dist/errors/errors.d.ts
CHANGED
|
@@ -121,7 +121,7 @@ declare const OllamaInsecureTransportError: typeof LocalProviderInsecureTranspor
|
|
|
121
121
|
type OllamaInsecureTransportError = LocalProviderInsecureTransportError;
|
|
122
122
|
/**
|
|
123
123
|
* Map an HTTP status (plus optional error-body text) onto the
|
|
124
|
-
* canonical
|
|
124
|
+
* canonical `ProviderErrorKind`. One
|
|
125
125
|
* shared table so `withRetry` / `withFallback` and consumers switching
|
|
126
126
|
* on the documented kinds see consistent values from every HTTP
|
|
127
127
|
* adapter:
|
package/dist/errors/errors.js
CHANGED
|
@@ -136,7 +136,7 @@ const OllamaInsecureTransportError = LocalProviderInsecureTransportError;
|
|
|
136
136
|
const CONTEXT_LENGTH_BODY_RE = /context[_ -]?length|context window|prompt is too long|maximum context|too many tokens|exceeds? the (?:model'?s? )?max/i;
|
|
137
137
|
/**
|
|
138
138
|
* Map an HTTP status (plus optional error-body text) onto the
|
|
139
|
-
* canonical
|
|
139
|
+
* canonical `ProviderErrorKind`. One
|
|
140
140
|
* shared table so `withRetry` / `withFallback` and consumers switching
|
|
141
141
|
* on the documented kinds see consistent values from every HTTP
|
|
142
142
|
* adapter:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../../src/errors/errors.ts"],"sourcesContent":["/**\n * Typed error hierarchy for `@graphorin/provider`. Every error class\n * carries a stable `kind` discriminant (lowercase, kebab-case) plus an\n * optional `hint` string pointing the user at the recommended fix.\n *\n * @packageDocumentation\n */\n\nimport type { ProviderErrorKind } from '@graphorin/core';\n\n/**\n * Base class for every error thrown by `@graphorin/provider`. Consumers\n * narrow on the discriminant `kind` rather than `instanceof` - both\n * work, but discriminants are subclass-friendly.\n *\n * @stable\n */\nexport class GraphorinProviderError extends Error {\n override readonly name: string = 'GraphorinProviderError';\n /** Stable discriminant - `'middleware-ordering'`, `'rate-limit-exceeded'`, … */\n readonly kind: string;\n /** Optional remediation hint shown alongside the message. */\n readonly hint?: string;\n\n constructor(kind: string, message: string, options?: { cause?: unknown; hint?: string }) {\n super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n this.kind = kind;\n if (options?.hint !== undefined) {\n this.hint = options.hint;\n }\n }\n}\n\n/**\n * The middleware composer detected an out-of-order middleware. The\n * `offendingPair` field carries the `[outer, inner]` middleware names\n * that violated the canonical order so consumers can surface a precise\n * fix in IDE diagnostics.\n *\n * @stable\n */\nexport class MiddlewareOrderingError extends GraphorinProviderError {\n override readonly name = 'MiddlewareOrderingError';\n readonly offendingPair: readonly [string, string];\n readonly canonicalOrder: readonly string[];\n\n constructor(args: {\n offendingPair: readonly [string, string];\n canonicalOrder: readonly string[];\n message?: string;\n }) {\n super(\n 'middleware-ordering',\n args.message ??\n `Middleware order violation: '${args.offendingPair[0]}' must not wrap '${args.offendingPair[1]}'. ` +\n `Canonical order (outer → inner): ${args.canonicalOrder.join(' → ')}.`,\n {\n hint:\n 'Reorder the middleware array passed to composeProviderMiddleware([...]) to match the canonical order; ' +\n 'see @graphorin/provider/middleware for documentation.',\n },\n );\n this.offendingPair = args.offendingPair;\n this.canonicalOrder = args.canonicalOrder;\n }\n}\n\n/**\n * `withRedaction` was missing at production startup. Thrown by the\n * production hook applied to every composed provider when\n * `process.env.NODE_ENV === 'production'`.\n *\n * @stable\n */\nexport class MissingProductionMiddlewareError extends GraphorinProviderError {\n override readonly name = 'MissingProductionMiddlewareError';\n readonly missing: string;\n\n constructor(missing: string) {\n super(\n 'missing-production-middleware',\n `Production startup hook: required middleware '${missing}' is missing from the provider chain.`,\n {\n hint:\n `Compose '${missing}' as the innermost layer (closest to the underlying provider) before deploying. ` +\n 'See @graphorin/provider/middleware for the canonical composition order.',\n },\n );\n this.missing = missing;\n }\n}\n\n/**\n * `withCostLimit` exceeded its configured ceiling. Carries the\n * triggering scope (`session`, `agent`, `run`, …) so the caller can\n * decide how to surface the breach.\n *\n * @stable\n */\nexport class CostBudgetExceededError extends GraphorinProviderError {\n override readonly name = 'CostBudgetExceededError';\n readonly scope: string;\n readonly limit: number;\n readonly observed: number;\n\n constructor(args: { scope: string; limit: number; observed: number; currency?: string }) {\n super(\n 'cost-budget-exceeded',\n `Cost budget exceeded for '${args.scope}': observed ${args.observed.toFixed(4)} ${args.currency ?? 'USD'} ` +\n `> limit ${args.limit.toFixed(4)} ${args.currency ?? 'USD'}.`,\n {\n hint: 'Raise the limit in withCostLimit({...}), tighten the prompt, or switch to a cheaper model tier.',\n },\n );\n this.scope = args.scope;\n this.limit = args.limit;\n this.observed = args.observed;\n }\n}\n\n/**\n * `withRateLimit` exhausted its bucket and the caller did not opt\n * into `'queue'` mode.\n *\n * @stable\n */\nexport class RateLimitExceededError extends GraphorinProviderError {\n override readonly name = 'RateLimitExceededError';\n readonly retryAfterMs: number;\n\n constructor(retryAfterMs: number) {\n super('rate-limit-exceeded', `Rate limit exceeded; retry after ${retryAfterMs}ms.`, {\n hint: 'Slow down the request rate, raise the bucket size in withRateLimit({...}), or switch to mode: \"queue\".',\n });\n this.retryAfterMs = retryAfterMs;\n }\n}\n\n/**\n * `withRedaction` detected a hit AND the policy is configured for\n * `failClosed: true`. The matched value is **never** part of the\n * message - only the pattern name and field path.\n *\n * @stable\n */\nexport class PromptRedactionError extends GraphorinProviderError {\n override readonly name = 'PromptRedactionError';\n readonly patternName: string;\n readonly fieldPath: string;\n readonly role?: string;\n\n constructor(args: { patternName: string; fieldPath: string; role?: string }) {\n super(\n 'prompt-redaction-fail-closed',\n `Outbound prompt-redaction policy is fail-closed and matched pattern '${args.patternName}' ` +\n `at '${args.fieldPath}'${args.role ? ` (role: ${args.role})` : ''}.`,\n {\n hint: 'Sanitize the prompt before calling the provider, or disable failClosed in withRedaction({...}) for this environment.',\n },\n );\n this.patternName = args.patternName;\n this.fieldPath = args.fieldPath;\n if (args.role !== undefined) this.role = args.role;\n }\n}\n\n/**\n * Raised when a `baseUrl`-driven local adapter is configured against\n * a public host over plaintext HTTP. Adapters refuse to start unless\n * `allowInsecureTransport: true` is supplied (and the override is\n * audit-logged).\n *\n * @stable\n */\nexport class LocalProviderInsecureTransportError extends GraphorinProviderError {\n override readonly name = 'LocalProviderInsecureTransportError';\n readonly baseUrl: string;\n\n constructor(baseUrl: string) {\n super(\n 'local-provider-insecure-transport',\n `Refusing to start: the provider baseUrl '${baseUrl}' is public AND plaintext (http://). ` +\n `Switch to https:// or set allowInsecureTransport: true to acknowledge the risk.`,\n {\n hint:\n 'Public local-LLM endpoints must be served over TLS. Acceptable alternatives: terminate TLS in front of the model server, ' +\n 'tunnel through SSH / WireGuard / Tailscale, or pass allowInsecureTransport: true (audit-logged).',\n },\n );\n this.baseUrl = baseUrl;\n }\n}\n\n/**\n * Legacy alias preserved for one minor; prefer\n * {@link LocalProviderInsecureTransportError}. Removed in v0.2.\n *\n * @deprecated Use {@link LocalProviderInsecureTransportError} instead.\n */\nexport const OllamaInsecureTransportError = LocalProviderInsecureTransportError;\nexport type OllamaInsecureTransportError = LocalProviderInsecureTransportError;\n\n/**\n * Body phrasings used by the major providers when the request blew the\n * model's context window. Sniffed by {@link classifyHttpStatus} so a\n * 400 that is really a context overflow surfaces as `'context-length'`\n * (the kind the compaction / emergency tiers key on), not a generic\n * `'invalid-request'`.\n */\nconst CONTEXT_LENGTH_BODY_RE =\n /context[_ -]?length|context window|prompt is too long|maximum context|too many tokens|exceeds? the (?:model'?s? )?max/i;\n\n/**\n * Map an HTTP status (plus optional error-body text) onto the\n * canonical {@link import('@graphorin/core').ProviderErrorKind}. One\n * shared table so `withRetry` / `withFallback` and consumers switching\n * on the documented kinds see consistent values from every HTTP\n * adapter:\n *\n * - `429` → `'rate-limit'`\n * - `401` / `403` → `'unauthorized'`\n * - `400` / `404` / `422` → `'invalid-request'` (or\n * `'context-length'` when the body says so)\n * - `503` / `529` → `'capacity'` (529 is Anthropic's overloaded code)\n * - other `5xx` and `0` (network failure) → `'transient'`\n *\n * @stable\n */\nexport function classifyHttpStatus(status: number, bodyText?: string): ProviderErrorKind {\n if (status === 429) return 'rate-limit';\n if (status === 401 || status === 403) return 'unauthorized';\n if (status === 400 || status === 404 || status === 422) {\n if (bodyText !== undefined && CONTEXT_LENGTH_BODY_RE.test(bodyText)) return 'context-length';\n return 'invalid-request';\n }\n if (status === 503 || status === 529) return 'capacity';\n if (status >= 500 || status === 0) return 'transient';\n return 'unknown';\n}\n\n/**\n * Wrapped HTTP error returned by an adapter. Carries the original\n * status code so middleware (`withRetry`, `withFallback`) can decide\n * whether the error is retryable.\n *\n * @stable\n */\nexport class ProviderHttpError extends GraphorinProviderError {\n override readonly name = 'ProviderHttpError';\n readonly status: number;\n readonly providerName: string;\n /**\n * The canonical `ProviderErrorKind` mapped from the HTTP status via\n * {@link classifyHttpStatus} (the `kind` field keeps its stable\n * `'provider-http'` discriminant). Middleware predicates consult\n * this so a 429 fails over / retries as a rate limit.\n */\n readonly errorKind: ProviderErrorKind;\n /**\n * Backoff-relevant response headers captured from the failed\n * response (`retry-after`, `x-ratelimit-*`), lowercased.\n * `withRetry`'s Retry-After hint reader consumes them.\n */\n readonly headers?: Readonly<Record<string, string>>;\n\n constructor(args: {\n providerName: string;\n status: number;\n message: string;\n cause?: unknown;\n errorKind?: ProviderErrorKind;\n headers?: Readonly<Record<string, string>>;\n }) {\n super('provider-http', `[${args.providerName}] HTTP ${args.status}: ${args.message}`, {\n ...(args.cause !== undefined ? { cause: args.cause } : {}),\n });\n this.providerName = args.providerName;\n this.status = args.status;\n this.errorKind = args.errorKind ?? classifyHttpStatus(args.status, args.message);\n if (args.headers !== undefined) this.headers = args.headers;\n }\n}\n\n/**\n * The streaming response did not match the documented wire format\n * (e.g. malformed SSE chunk, truncated JSON).\n *\n * @stable\n */\nexport class ProviderStreamParseError extends GraphorinProviderError {\n override readonly name = 'ProviderStreamParseError';\n readonly providerName: string;\n\n constructor(providerName: string, message: string, cause?: unknown) {\n super('provider-stream-parse', `[${providerName}] ${message}`, {\n ...(cause !== undefined ? { cause } : {}),\n });\n this.providerName = providerName;\n }\n}\n\n/**\n * The classifier dispatcher was given a non-Provider value. Programming\n * error; fail-fast at the boundary.\n *\n * @stable\n */\nexport class InvalidProviderError extends GraphorinProviderError {\n override readonly name = 'InvalidProviderError';\n\n constructor(message: string) {\n super('invalid-provider', message, {\n hint: 'Pass the value returned by createProvider(...) (or any adapter factory) instead of a raw object.',\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../src/errors/errors.ts"],"sourcesContent":["/**\n * Typed error hierarchy for `@graphorin/provider`. Every error class\n * carries a stable `kind` discriminant (lowercase, kebab-case) plus an\n * optional `hint` string pointing the user at the recommended fix.\n *\n * @packageDocumentation\n */\n\nimport type { ProviderErrorKind } from '@graphorin/core';\n\n/**\n * Base class for every error thrown by `@graphorin/provider`. Consumers\n * narrow on the discriminant `kind` rather than `instanceof` - both\n * work, but discriminants are subclass-friendly.\n *\n * @stable\n */\nexport class GraphorinProviderError extends Error {\n override readonly name: string = 'GraphorinProviderError';\n /** Stable discriminant - `'middleware-ordering'`, `'rate-limit-exceeded'`, … */\n readonly kind: string;\n /** Optional remediation hint shown alongside the message. */\n readonly hint?: string;\n\n constructor(kind: string, message: string, options?: { cause?: unknown; hint?: string }) {\n super(message, options?.cause !== undefined ? { cause: options.cause } : undefined);\n this.kind = kind;\n if (options?.hint !== undefined) {\n this.hint = options.hint;\n }\n }\n}\n\n/**\n * The middleware composer detected an out-of-order middleware. The\n * `offendingPair` field carries the `[outer, inner]` middleware names\n * that violated the canonical order so consumers can surface a precise\n * fix in IDE diagnostics.\n *\n * @stable\n */\nexport class MiddlewareOrderingError extends GraphorinProviderError {\n override readonly name = 'MiddlewareOrderingError';\n readonly offendingPair: readonly [string, string];\n readonly canonicalOrder: readonly string[];\n\n constructor(args: {\n offendingPair: readonly [string, string];\n canonicalOrder: readonly string[];\n message?: string;\n }) {\n super(\n 'middleware-ordering',\n args.message ??\n `Middleware order violation: '${args.offendingPair[0]}' must not wrap '${args.offendingPair[1]}'. ` +\n `Canonical order (outer → inner): ${args.canonicalOrder.join(' → ')}.`,\n {\n hint:\n 'Reorder the middleware array passed to composeProviderMiddleware([...]) to match the canonical order; ' +\n 'see @graphorin/provider/middleware for documentation.',\n },\n );\n this.offendingPair = args.offendingPair;\n this.canonicalOrder = args.canonicalOrder;\n }\n}\n\n/**\n * `withRedaction` was missing at production startup. Thrown by the\n * production hook applied to every composed provider when\n * `process.env.NODE_ENV === 'production'`.\n *\n * @stable\n */\nexport class MissingProductionMiddlewareError extends GraphorinProviderError {\n override readonly name = 'MissingProductionMiddlewareError';\n readonly missing: string;\n\n constructor(missing: string) {\n super(\n 'missing-production-middleware',\n `Production startup hook: required middleware '${missing}' is missing from the provider chain.`,\n {\n hint:\n `Compose '${missing}' as the innermost layer (closest to the underlying provider) before deploying. ` +\n 'See @graphorin/provider/middleware for the canonical composition order.',\n },\n );\n this.missing = missing;\n }\n}\n\n/**\n * `withCostLimit` exceeded its configured ceiling. Carries the\n * triggering scope (`session`, `agent`, `run`, …) so the caller can\n * decide how to surface the breach.\n *\n * @stable\n */\nexport class CostBudgetExceededError extends GraphorinProviderError {\n override readonly name = 'CostBudgetExceededError';\n readonly scope: string;\n readonly limit: number;\n readonly observed: number;\n\n constructor(args: { scope: string; limit: number; observed: number; currency?: string }) {\n super(\n 'cost-budget-exceeded',\n `Cost budget exceeded for '${args.scope}': observed ${args.observed.toFixed(4)} ${args.currency ?? 'USD'} ` +\n `> limit ${args.limit.toFixed(4)} ${args.currency ?? 'USD'}.`,\n {\n hint: 'Raise the limit in withCostLimit({...}), tighten the prompt, or switch to a cheaper model tier.',\n },\n );\n this.scope = args.scope;\n this.limit = args.limit;\n this.observed = args.observed;\n }\n}\n\n/**\n * `withRateLimit` exhausted its bucket and the caller did not opt\n * into `'queue'` mode.\n *\n * @stable\n */\nexport class RateLimitExceededError extends GraphorinProviderError {\n override readonly name = 'RateLimitExceededError';\n readonly retryAfterMs: number;\n\n constructor(retryAfterMs: number) {\n super('rate-limit-exceeded', `Rate limit exceeded; retry after ${retryAfterMs}ms.`, {\n hint: 'Slow down the request rate, raise the bucket size in withRateLimit({...}), or switch to mode: \"queue\".',\n });\n this.retryAfterMs = retryAfterMs;\n }\n}\n\n/**\n * `withRedaction` detected a hit AND the policy is configured for\n * `failClosed: true`. The matched value is **never** part of the\n * message - only the pattern name and field path.\n *\n * @stable\n */\nexport class PromptRedactionError extends GraphorinProviderError {\n override readonly name = 'PromptRedactionError';\n readonly patternName: string;\n readonly fieldPath: string;\n readonly role?: string;\n\n constructor(args: { patternName: string; fieldPath: string; role?: string }) {\n super(\n 'prompt-redaction-fail-closed',\n `Outbound prompt-redaction policy is fail-closed and matched pattern '${args.patternName}' ` +\n `at '${args.fieldPath}'${args.role ? ` (role: ${args.role})` : ''}.`,\n {\n hint: 'Sanitize the prompt before calling the provider, or disable failClosed in withRedaction({...}) for this environment.',\n },\n );\n this.patternName = args.patternName;\n this.fieldPath = args.fieldPath;\n if (args.role !== undefined) this.role = args.role;\n }\n}\n\n/**\n * Raised when a `baseUrl`-driven local adapter is configured against\n * a public host over plaintext HTTP. Adapters refuse to start unless\n * `allowInsecureTransport: true` is supplied (and the override is\n * audit-logged).\n *\n * @stable\n */\nexport class LocalProviderInsecureTransportError extends GraphorinProviderError {\n override readonly name = 'LocalProviderInsecureTransportError';\n readonly baseUrl: string;\n\n constructor(baseUrl: string) {\n super(\n 'local-provider-insecure-transport',\n `Refusing to start: the provider baseUrl '${baseUrl}' is public AND plaintext (http://). ` +\n `Switch to https:// or set allowInsecureTransport: true to acknowledge the risk.`,\n {\n hint:\n 'Public local-LLM endpoints must be served over TLS. Acceptable alternatives: terminate TLS in front of the model server, ' +\n 'tunnel through SSH / WireGuard / Tailscale, or pass allowInsecureTransport: true (audit-logged).',\n },\n );\n this.baseUrl = baseUrl;\n }\n}\n\n/**\n * Legacy alias preserved for one minor; prefer\n * {@link LocalProviderInsecureTransportError}. Removed in v0.2.\n *\n * @deprecated Use {@link LocalProviderInsecureTransportError} instead.\n */\nexport const OllamaInsecureTransportError = LocalProviderInsecureTransportError;\nexport type OllamaInsecureTransportError = LocalProviderInsecureTransportError;\n\n/**\n * Body phrasings used by the major providers when the request blew the\n * model's context window. Sniffed by {@link classifyHttpStatus} so a\n * 400 that is really a context overflow surfaces as `'context-length'`\n * (the kind the compaction / emergency tiers key on), not a generic\n * `'invalid-request'`.\n */\nconst CONTEXT_LENGTH_BODY_RE =\n /context[_ -]?length|context window|prompt is too long|maximum context|too many tokens|exceeds? the (?:model'?s? )?max/i;\n\n/**\n * Map an HTTP status (plus optional error-body text) onto the\n * canonical `ProviderErrorKind`. One\n * shared table so `withRetry` / `withFallback` and consumers switching\n * on the documented kinds see consistent values from every HTTP\n * adapter:\n *\n * - `429` → `'rate-limit'`\n * - `401` / `403` → `'unauthorized'`\n * - `400` / `404` / `422` → `'invalid-request'` (or\n * `'context-length'` when the body says so)\n * - `503` / `529` → `'capacity'` (529 is Anthropic's overloaded code)\n * - other `5xx` and `0` (network failure) → `'transient'`\n *\n * @stable\n */\nexport function classifyHttpStatus(status: number, bodyText?: string): ProviderErrorKind {\n if (status === 429) return 'rate-limit';\n if (status === 401 || status === 403) return 'unauthorized';\n if (status === 400 || status === 404 || status === 422) {\n if (bodyText !== undefined && CONTEXT_LENGTH_BODY_RE.test(bodyText)) return 'context-length';\n return 'invalid-request';\n }\n if (status === 503 || status === 529) return 'capacity';\n if (status >= 500 || status === 0) return 'transient';\n return 'unknown';\n}\n\n/**\n * Wrapped HTTP error returned by an adapter. Carries the original\n * status code so middleware (`withRetry`, `withFallback`) can decide\n * whether the error is retryable.\n *\n * @stable\n */\nexport class ProviderHttpError extends GraphorinProviderError {\n override readonly name = 'ProviderHttpError';\n readonly status: number;\n readonly providerName: string;\n /**\n * The canonical `ProviderErrorKind` mapped from the HTTP status via\n * {@link classifyHttpStatus} (the `kind` field keeps its stable\n * `'provider-http'` discriminant). Middleware predicates consult\n * this so a 429 fails over / retries as a rate limit.\n */\n readonly errorKind: ProviderErrorKind;\n /**\n * Backoff-relevant response headers captured from the failed\n * response (`retry-after`, `x-ratelimit-*`), lowercased.\n * `withRetry`'s Retry-After hint reader consumes them.\n */\n readonly headers?: Readonly<Record<string, string>>;\n\n constructor(args: {\n providerName: string;\n status: number;\n message: string;\n cause?: unknown;\n errorKind?: ProviderErrorKind;\n headers?: Readonly<Record<string, string>>;\n }) {\n super('provider-http', `[${args.providerName}] HTTP ${args.status}: ${args.message}`, {\n ...(args.cause !== undefined ? { cause: args.cause } : {}),\n });\n this.providerName = args.providerName;\n this.status = args.status;\n this.errorKind = args.errorKind ?? classifyHttpStatus(args.status, args.message);\n if (args.headers !== undefined) this.headers = args.headers;\n }\n}\n\n/**\n * The streaming response did not match the documented wire format\n * (e.g. malformed SSE chunk, truncated JSON).\n *\n * @stable\n */\nexport class ProviderStreamParseError extends GraphorinProviderError {\n override readonly name = 'ProviderStreamParseError';\n readonly providerName: string;\n\n constructor(providerName: string, message: string, cause?: unknown) {\n super('provider-stream-parse', `[${providerName}] ${message}`, {\n ...(cause !== undefined ? { cause } : {}),\n });\n this.providerName = providerName;\n }\n}\n\n/**\n * The classifier dispatcher was given a non-Provider value. Programming\n * error; fail-fast at the boundary.\n *\n * @stable\n */\nexport class InvalidProviderError extends GraphorinProviderError {\n override readonly name = 'InvalidProviderError';\n\n constructor(message: string) {\n super('invalid-provider', message, {\n hint: 'Pass the value returned by createProvider(...) (or any adapter factory) instead of a raw object.',\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -63,8 +63,7 @@ import { LocalProviderTrust, OllamaTrust } from "./trust/index.js";
|
|
|
63
63
|
*
|
|
64
64
|
* @packageDocumentation
|
|
65
65
|
*/
|
|
66
|
-
|
|
67
|
-
declare const VERSION = "0.6.0";
|
|
66
|
+
declare const VERSION: string;
|
|
68
67
|
//#endregion
|
|
69
68
|
export { AnthropicAPICounter, AnthropicAPICounterOptions, ApplyReasoningPolicyInput, BedrockAPICounter, BedrockAPICounterOptions, CANONICAL_MIDDLEWARE_ORDER, CLASSIFIER_RULES, ClassifierRule, CostAccumulator, CostBudgetExceededError, CostTrackingTotals, CreateDefaultCounterOptions, CreateProviderOptions, GoogleAPICounter, GoogleAPICounterOptions, GraphorinProviderError, HeuristicCounter, HeuristicCounterOptions, InferReasoningContractInput, InvalidProviderError, JsTiktokenCounter, JsTiktokenCounterOptions, LlamaCppServerAdapterOptions, LocalProviderClassification, LocalProviderInsecureTransportError, LocalProviderTrust, MIDDLEWARE_KIND, MiddlewareOrderingError, MissingProductionMiddlewareError, OllamaAdapterOptions, OllamaInsecureTransportError, OllamaTrust, OpenAICompatibleAdapterOptions, PERMANENT_LOOPBACK_CLASSIFICATION, ProductionStartupHookOptions, PromptRedactionError, PromptRedactionPolicy, PromptRedactionScanScope, PromptRedactionViolation, ProviderHttpError, ProviderStreamParseError, REASONING_CONTRACT_RULES, REASONING_RETENTION_DEFAULTS, RateLimitExceededError, ReasoningContractRule, ResolveReasoningRetentionInput, SENSITIVITY_DEFAULTS_PER_TRUST, SerializedMessage, VERSION, VercelAdapterOptions, WithCostLimitOptions, WithCostTrackingOptions, WithFallbackOptions, WithRateLimitOptions, WithRetryOptions, WithTracingOptions, __resetGlobalTokenCounter, __resetTiktokenCache, applyReasoningPolicy, assertProductionMiddleware, classifyHttpStatus, classifyLocalProvider, classifyModelTier, composeProviderMiddleware, createCostAccumulator, createDefaultCounter, createProvider, defineProviderMiddleware, foldToolExamples, getGlobalTokenCounter, getMiddlewareKind, inferReasoningContract, llamaCppServerAdapter, ollamaAdapter, openAICompatibleAdapter, providerHasMiddleware, resolveReasoningRetention, serialiseMessageForCount, serializedToString, setGlobalTokenCounter, vercelAdapter, withCostLimit, withCostTracking, withFallback, withRateLimit, withRedaction, withRetry, withTracing };
|
|
70
69
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA+Ba"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { version } from "./package.js";
|
|
1
2
|
import { CostBudgetExceededError, GraphorinProviderError, InvalidProviderError, LocalProviderInsecureTransportError, MiddlewareOrderingError, MissingProductionMiddlewareError, OllamaInsecureTransportError, PromptRedactionError, ProviderHttpError, ProviderStreamParseError, RateLimitExceededError, classifyHttpStatus } from "./errors/errors.js";
|
|
2
3
|
import { applyReasoningPolicy } from "./reasoning/apply-policy.js";
|
|
3
4
|
import { REASONING_RETENTION_DEFAULTS, resolveReasoningRetention } from "./reasoning/retention.js";
|
|
@@ -8,7 +9,6 @@ import { ollamaAdapter } from "./adapters/ollama.js";
|
|
|
8
9
|
import { openAICompatibleAdapter } from "./adapters/openai-compatible.js";
|
|
9
10
|
import { REASONING_CONTRACT_RULES, inferReasoningContract } from "./reasoning/classify-contract.js";
|
|
10
11
|
import { vercelAdapter } from "./adapters/vercel.js";
|
|
11
|
-
import "./adapters/index.js";
|
|
12
12
|
import { serialiseMessageForCount, serializedToString } from "./counters/serialize.js";
|
|
13
13
|
import { JsTiktokenCounter, __resetTiktokenCache } from "./counters/js-tiktoken.js";
|
|
14
14
|
import { AnthropicAPICounter } from "./counters/anthropic.js";
|
|
@@ -17,7 +17,6 @@ import { GoogleAPICounter } from "./counters/google.js";
|
|
|
17
17
|
import { HeuristicCounter } from "./counters/heuristic.js";
|
|
18
18
|
import { createDefaultCounter } from "./counters/dispatcher.js";
|
|
19
19
|
import { __resetGlobalTokenCounter, getGlobalTokenCounter, setGlobalTokenCounter } from "./counters/global.js";
|
|
20
|
-
import "./counters/index.js";
|
|
21
20
|
import { CANONICAL_MIDDLEWARE_ORDER, MIDDLEWARE_KIND, composeProviderMiddleware, defineProviderMiddleware, getMiddlewareKind, providerHasMiddleware } from "./middleware/compose.js";
|
|
22
21
|
import { assertProductionMiddleware } from "./middleware/production-hook.js";
|
|
23
22
|
import { withCostLimit } from "./middleware/with-cost-limit.js";
|
|
@@ -27,12 +26,8 @@ import { withRateLimit } from "./middleware/with-rate-limit.js";
|
|
|
27
26
|
import { withRedaction } from "./middleware/with-redaction.js";
|
|
28
27
|
import { withRetry } from "./middleware/with-retry.js";
|
|
29
28
|
import { withTracing } from "./middleware/with-tracing.js";
|
|
30
|
-
import "./middleware/index.js";
|
|
31
29
|
import { CLASSIFIER_RULES, classifyModelTier } from "./model-tier/classify.js";
|
|
32
|
-
import "./model-tier/index.js";
|
|
33
30
|
import { createProvider } from "./provider.js";
|
|
34
|
-
import "./reasoning/index.js";
|
|
35
|
-
import "./trust/index.js";
|
|
36
31
|
|
|
37
32
|
//#region src/index.ts
|
|
38
33
|
/**
|
|
@@ -62,8 +57,8 @@ import "./trust/index.js";
|
|
|
62
57
|
*
|
|
63
58
|
* @packageDocumentation
|
|
64
59
|
*/
|
|
65
|
-
/** Canonical version constant
|
|
66
|
-
const VERSION =
|
|
60
|
+
/** Canonical version constant, derived from `package.json` at build time. */
|
|
61
|
+
const VERSION = version;
|
|
67
62
|
|
|
68
63
|
//#endregion
|
|
69
64
|
export { AnthropicAPICounter, BedrockAPICounter, CANONICAL_MIDDLEWARE_ORDER, CLASSIFIER_RULES, CostBudgetExceededError, GoogleAPICounter, GraphorinProviderError, HeuristicCounter, InvalidProviderError, JsTiktokenCounter, LocalProviderInsecureTransportError, MIDDLEWARE_KIND, MiddlewareOrderingError, MissingProductionMiddlewareError, OllamaInsecureTransportError, PERMANENT_LOOPBACK_CLASSIFICATION, PromptRedactionError, ProviderHttpError, ProviderStreamParseError, REASONING_CONTRACT_RULES, REASONING_RETENTION_DEFAULTS, RateLimitExceededError, SENSITIVITY_DEFAULTS_PER_TRUST, VERSION, __resetGlobalTokenCounter, __resetTiktokenCache, applyReasoningPolicy, assertProductionMiddleware, classifyHttpStatus, classifyLocalProvider, classifyModelTier, composeProviderMiddleware, createCostAccumulator, createDefaultCounter, createProvider, defineProviderMiddleware, foldToolExamples, getGlobalTokenCounter, getMiddlewareKind, inferReasoningContract, llamaCppServerAdapter, ollamaAdapter, openAICompatibleAdapter, providerHasMiddleware, resolveReasoningRetention, serialiseMessageForCount, serializedToString, setGlobalTokenCounter, vercelAdapter, withCostLimit, withCostTracking, withFallback, withRateLimit, withRedaction, withRetry, withTracing };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @graphorin/provider - vendor-neutral LLM provider layer for the\n * Graphorin framework.\n *\n * The package owns:\n *\n * - The `createProvider(...)` factory for wrapping adapter modules in\n * a stable `Provider` shape.\n * - Four adapters out of the box: the Vercel AI SDK adapter for the\n * default cloud path, plus three local-LLM adapters (Ollama HTTP,\n * llama-server HTTP, and a generic OpenAI-compatible adapter for\n * LMStudio / LocalAI / vLLM / Together-style endpoints). All three\n * `baseUrl`-driven adapters share the same {@link LocalProviderTrust}\n * classifier.\n * - The canonical-order middleware composer\n * ({@link composeProviderMiddleware}) and the seven built-in\n * middlewares (`withTracing`, `withRetry`, `withRateLimit`,\n * `withCostLimit`, `withCostTracking`, `withFallback`,\n * `withRedaction`).\n * - The pluggable `TokenCounter` dispatcher (`createDefaultCounter`)\n * plus the per-vendor strategies and a heuristic fallback.\n * - The per-provider model-tier auto-classifier\n * ({@link classifyModelTier}) that maps a `Provider`'s `modelId` to\n * one of `'fast' | 'balanced' | 'smart'`.\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant
|
|
1
|
+
{"version":3,"file":"index.js","names":["VERSION: string","pkg.version"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @graphorin/provider - vendor-neutral LLM provider layer for the\n * Graphorin framework.\n *\n * The package owns:\n *\n * - The `createProvider(...)` factory for wrapping adapter modules in\n * a stable `Provider` shape.\n * - Four adapters out of the box: the Vercel AI SDK adapter for the\n * default cloud path, plus three local-LLM adapters (Ollama HTTP,\n * llama-server HTTP, and a generic OpenAI-compatible adapter for\n * LMStudio / LocalAI / vLLM / Together-style endpoints). All three\n * `baseUrl`-driven adapters share the same {@link LocalProviderTrust}\n * classifier.\n * - The canonical-order middleware composer\n * ({@link composeProviderMiddleware}) and the seven built-in\n * middlewares (`withTracing`, `withRetry`, `withRateLimit`,\n * `withCostLimit`, `withCostTracking`, `withFallback`,\n * `withRedaction`).\n * - The pluggable `TokenCounter` dispatcher (`createDefaultCounter`)\n * plus the per-vendor strategies and a heuristic fallback.\n * - The per-provider model-tier auto-classifier\n * ({@link classifyModelTier}) that maps a `Provider`'s `modelId` to\n * one of `'fast' | 'balanced' | 'smart'`.\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant, derived from `package.json` at build time. */\nimport pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION: string = pkg.version;\n\nexport * from './adapters/index.js';\nexport * from './counters/index.js';\nexport * from './errors/index.js';\nexport * from './middleware/index.js';\nexport * from './model-tier/index.js';\nexport * from './provider.js';\nexport * from './reasoning/index.js';\nexport { foldToolExamples } from './tool-examples.js';\nexport * from './trust/index.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAaA,UAAkBC"}
|
package/dist/internal/http.js
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import { ProviderHttpError } from "../errors/errors.js";
|
|
2
2
|
|
|
3
3
|
//#region src/internal/http.ts
|
|
4
|
+
const TEXT_ONLY = { multimodal: false };
|
|
4
5
|
/**
|
|
5
6
|
* Convert a graphorin `Message` to the OpenAI-compatible chat-completion
|
|
6
7
|
* shape. The shape is the lingua-franca of the bundled local adapters
|
|
7
8
|
* (`llamaCppServerAdapter` and `openAICompatibleAdapter`); the
|
|
8
9
|
* native-Ollama path uses its own conversion.
|
|
9
10
|
*
|
|
11
|
+
* W-095: with `opts.multimodal === true` image parts are emitted as
|
|
12
|
+
* OpenAI `image_url` content parts (bytes as a data URI, `URL`s passed
|
|
13
|
+
* through as strings - the server dereferences; this adapter never
|
|
14
|
+
* fetches). Audio/file parts have no portable wire form on
|
|
15
|
+
* OpenAI-compatible servers and are dropped LOUDLY. With
|
|
16
|
+
* `multimodal: false` (the default) content flattens to a plain string
|
|
17
|
+
* exactly as before, and any dropped non-text part triggers the warn.
|
|
18
|
+
*
|
|
10
19
|
* @internal
|
|
11
20
|
*/
|
|
12
|
-
function toOpenAIChatMessages(messages) {
|
|
13
|
-
|
|
21
|
+
function toOpenAIChatMessages(messages, opts = TEXT_ONLY) {
|
|
22
|
+
const dropped = /* @__PURE__ */ new Set();
|
|
23
|
+
const converted = messages.map((msg) => {
|
|
14
24
|
const out = {
|
|
15
25
|
role: msg.role,
|
|
16
|
-
content: typeof msg.content === "string" ? msg.content : flattenContent(msg.content)
|
|
26
|
+
content: typeof msg.content === "string" ? msg.content : opts.multimodal ? toOpenAIParts(msg.content, dropped) : flattenContent(msg.content, dropped)
|
|
17
27
|
};
|
|
18
28
|
if (msg.toolCalls !== void 0 && msg.toolCalls.length > 0) out.tool_calls = msg.toolCalls.map((tc) => ({
|
|
19
29
|
id: tc.toolCallId,
|
|
@@ -26,6 +36,57 @@ function toOpenAIChatMessages(messages) {
|
|
|
26
36
|
if (msg.role === "tool" && msg.toolCallId !== void 0) out.tool_call_id = msg.toolCallId;
|
|
27
37
|
return out;
|
|
28
38
|
});
|
|
39
|
+
warnDropped(opts, dropped);
|
|
40
|
+
return converted;
|
|
41
|
+
}
|
|
42
|
+
/** W-095: build the OpenAI `content` parts array for a vision model. */
|
|
43
|
+
function toOpenAIParts(parts, dropped) {
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const part of parts) {
|
|
46
|
+
if (typeof part === "string") {
|
|
47
|
+
out.push({
|
|
48
|
+
type: "text",
|
|
49
|
+
text: part
|
|
50
|
+
});
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (typeof part !== "object" || part === null) continue;
|
|
54
|
+
const obj = part;
|
|
55
|
+
if (obj.type === "text" && typeof obj.text === "string") {
|
|
56
|
+
out.push({
|
|
57
|
+
type: "text",
|
|
58
|
+
text: obj.text
|
|
59
|
+
});
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (obj.type === "image") {
|
|
63
|
+
const url = imageToUrl(obj.image, obj.mimeType);
|
|
64
|
+
if (url !== void 0) {
|
|
65
|
+
out.push({
|
|
66
|
+
type: "image_url",
|
|
67
|
+
image_url: { url }
|
|
68
|
+
});
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (typeof obj.type === "string") dropped.add(obj.type);
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* W-095: bytes become a `data:` URI (default mime `image/png`); `URL`s
|
|
78
|
+
* pass through as strings - the SERVER dereferences, the adapter makes
|
|
79
|
+
* no network call of its own.
|
|
80
|
+
*/
|
|
81
|
+
function imageToUrl(image, mimeType) {
|
|
82
|
+
if (image instanceof URL) return image.toString();
|
|
83
|
+
if (image instanceof Uint8Array) return `data:${mimeType ?? "image/png"};base64,${Buffer.from(image).toString("base64")}`;
|
|
84
|
+
}
|
|
85
|
+
/** W-095: one honest WARN per convert call when parts were dropped. */
|
|
86
|
+
function warnDropped(opts, dropped) {
|
|
87
|
+
if (dropped.size === 0 || opts.warn === void 0) return;
|
|
88
|
+
const kinds = [...dropped].sort().join(", ");
|
|
89
|
+
opts.warn(opts.multimodal ? `content parts of kind [${kinds}] have no wire mapping on this adapter and were dropped` : `non-text content parts of kind [${kinds}] were dropped - this adapter instance has capabilities.multimodal=false; pass capabilities: { multimodal: true } if the model supports vision`);
|
|
29
90
|
}
|
|
30
91
|
/**
|
|
31
92
|
* Convert a graphorin `Message` to Ollama's **native** `/api/chat` shape
|
|
@@ -36,18 +97,60 @@ function toOpenAIChatMessages(messages) {
|
|
|
36
97
|
*
|
|
37
98
|
* @internal
|
|
38
99
|
*/
|
|
39
|
-
function toOllamaChatMessages(messages) {
|
|
40
|
-
|
|
100
|
+
function toOllamaChatMessages(messages, opts = TEXT_ONLY) {
|
|
101
|
+
const dropped = /* @__PURE__ */ new Set();
|
|
102
|
+
const converted = messages.map((msg) => {
|
|
103
|
+
let content;
|
|
104
|
+
let images;
|
|
105
|
+
if (typeof msg.content === "string") content = msg.content;
|
|
106
|
+
else if (opts.multimodal) {
|
|
107
|
+
const split = toOllamaContent(msg.content, dropped);
|
|
108
|
+
content = split.text;
|
|
109
|
+
images = split.images.length > 0 ? split.images : void 0;
|
|
110
|
+
} else content = flattenContent(msg.content, dropped);
|
|
41
111
|
const out = {
|
|
42
112
|
role: msg.role,
|
|
43
|
-
content
|
|
113
|
+
content
|
|
44
114
|
};
|
|
115
|
+
if (images !== void 0) out.images = images;
|
|
45
116
|
if (msg.toolCalls !== void 0 && msg.toolCalls.length > 0) out.tool_calls = msg.toolCalls.map((tc) => ({ function: {
|
|
46
117
|
name: tc.toolName,
|
|
47
118
|
arguments: toArgsObject(tc.args)
|
|
48
119
|
} }));
|
|
49
120
|
return out;
|
|
50
121
|
});
|
|
122
|
+
warnDropped(opts, dropped);
|
|
123
|
+
return converted;
|
|
124
|
+
}
|
|
125
|
+
/** W-095: split parts into flattened text + raw-base64 image payloads. */
|
|
126
|
+
function toOllamaContent(parts, dropped) {
|
|
127
|
+
const buffer = [];
|
|
128
|
+
const images = [];
|
|
129
|
+
for (const part of parts) {
|
|
130
|
+
if (typeof part === "string") {
|
|
131
|
+
buffer.push(part);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (typeof part !== "object" || part === null) continue;
|
|
135
|
+
const obj = part;
|
|
136
|
+
if (obj.type === "text" && typeof obj.text === "string") {
|
|
137
|
+
buffer.push(obj.text);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (obj.type === "image" && obj.image instanceof Uint8Array) {
|
|
141
|
+
images.push(Buffer.from(obj.image).toString("base64"));
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (obj.type === "image") {
|
|
145
|
+
dropped.add("image (URL - the native Ollama API needs inline bytes)");
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (typeof obj.type === "string") dropped.add(obj.type);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
text: buffer.join(""),
|
|
152
|
+
images
|
|
153
|
+
};
|
|
51
154
|
}
|
|
52
155
|
/**
|
|
53
156
|
* Coerce a tool-call `args` value into the object map Ollama expects. Strings
|
|
@@ -63,7 +166,7 @@ function toArgsObject(args) {
|
|
|
63
166
|
}
|
|
64
167
|
return typeof args === "object" && args !== null ? args : {};
|
|
65
168
|
}
|
|
66
|
-
function flattenContent(parts) {
|
|
169
|
+
function flattenContent(parts, dropped) {
|
|
67
170
|
const buffer = [];
|
|
68
171
|
for (const part of parts) {
|
|
69
172
|
if (typeof part === "string") {
|
|
@@ -73,6 +176,7 @@ function flattenContent(parts) {
|
|
|
73
176
|
if (typeof part === "object" && part !== null) {
|
|
74
177
|
const obj = part;
|
|
75
178
|
if (obj.type === "text" && typeof obj.text === "string") buffer.push(obj.text);
|
|
179
|
+
else if (typeof obj.type === "string") dropped?.add(obj.type);
|
|
76
180
|
}
|
|
77
181
|
}
|
|
78
182
|
return buffer.join("");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","names":["out: Record<string, unknown>","parsed: unknown","buffer: string[]","resp: Response","picked: Record<string, string>"],"sources":["../../src/internal/http.ts"],"sourcesContent":["/**\n * Internal HTTP helpers shared across the local-LLM adapters.\n *\n * @internal\n */\n\nimport type { ProviderEvent } from '@graphorin/core';\n\nimport { ProviderHttpError } from '../errors/errors.js';\n\n/**\n * Convert a graphorin `Message` to the OpenAI-compatible chat-completion\n * shape. The shape is the lingua-franca of the bundled local adapters\n * (`llamaCppServerAdapter` and `openAICompatibleAdapter`); the\n * native-Ollama path uses its own conversion.\n *\n * @internal\n */\nexport function toOpenAIChatMessages(\n messages: ReadonlyArray<{\n readonly role: 'system' | 'user' | 'assistant' | 'tool';\n readonly content: string | ReadonlyArray<unknown>;\n readonly toolCalls?: ReadonlyArray<{\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: unknown;\n }>;\n readonly toolCallId?: string;\n }>,\n): ReadonlyArray<Record<string, unknown>> {\n return messages.map((msg) => {\n const out: Record<string, unknown> = {\n role: msg.role,\n content: typeof msg.content === 'string' ? msg.content : flattenContent(msg.content),\n };\n if (msg.toolCalls !== undefined && msg.toolCalls.length > 0) {\n out.tool_calls = msg.toolCalls.map((tc) => ({\n id: tc.toolCallId,\n type: 'function',\n function: {\n name: tc.toolName,\n arguments: typeof tc.args === 'string' ? tc.args : JSON.stringify(tc.args),\n },\n }));\n }\n if (msg.role === 'tool' && msg.toolCallId !== undefined) {\n out.tool_call_id = msg.toolCallId;\n }\n return out;\n });\n}\n\n/**\n * Convert a graphorin `Message` to Ollama's **native** `/api/chat` shape\n * (PS-13). Unlike the OpenAI form, Ollama's Go server expects `tool_calls`\n * with object `arguments` (a `map[string]any`, never a JSON string) and no\n * `id` / `type` fields - sending those breaks its unmarshaller and any\n * multi-turn replay of assistant tool calls.\n *\n * @internal\n */\nexport function toOllamaChatMessages(\n messages: ReadonlyArray<{\n readonly role: 'system' | 'user' | 'assistant' | 'tool';\n readonly content: string | ReadonlyArray<unknown>;\n readonly toolCalls?: ReadonlyArray<{\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: unknown;\n }>;\n readonly toolCallId?: string;\n }>,\n): ReadonlyArray<Record<string, unknown>> {\n return messages.map((msg) => {\n const out: Record<string, unknown> = {\n role: msg.role,\n content: typeof msg.content === 'string' ? msg.content : flattenContent(msg.content),\n };\n if (msg.toolCalls !== undefined && msg.toolCalls.length > 0) {\n out.tool_calls = msg.toolCalls.map((tc) => ({\n function: {\n name: tc.toolName,\n arguments: toArgsObject(tc.args),\n },\n }));\n }\n return out;\n });\n}\n\n/**\n * Coerce a tool-call `args` value into the object map Ollama expects. Strings\n * (e.g. an OpenAI-style JSON blob produced upstream) are parsed leniently;\n * anything that isn't a JSON object becomes `{}`.\n */\nfunction toArgsObject(args: unknown): Record<string, unknown> {\n if (typeof args === 'string') {\n try {\n const parsed: unknown = JSON.parse(args);\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n return typeof args === 'object' && args !== null ? (args as Record<string, unknown>) : {};\n}\n\nfunction flattenContent(parts: ReadonlyArray<unknown>): string {\n const buffer: string[] = [];\n for (const part of parts) {\n if (typeof part === 'string') {\n buffer.push(part);\n continue;\n }\n if (typeof part === 'object' && part !== null) {\n const obj = part as { type?: string; text?: string };\n if (obj.type === 'text' && typeof obj.text === 'string') {\n buffer.push(obj.text);\n }\n }\n }\n return buffer.join('');\n}\n\n/**\n * Wrap a `fetch` call with HTTP error mapping. The helper does not\n * assume any particular streaming format - callers receive the raw\n * `Response` and dispatch on its body.\n *\n * @internal\n */\n/**\n * Default per-request timeout for the baseUrl adapters (PS-24). Scoped\n * to time-to-response (headers): the timer is cleared the moment the\n * server answers, so long streaming bodies are never killed - only a\n * hung server that never responds. Generous because a cold local\n * llama-server can take tens of seconds to load a model.\n *\n * @stable\n */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 120_000;\n\nexport async function callJsonHttp(args: {\n readonly providerName: string;\n readonly url: string;\n readonly headers: Record<string, string>;\n readonly body: unknown;\n readonly signal?: AbortSignal;\n readonly fetchImpl?: typeof fetch;\n /**\n * Time-to-response budget (PS-24). Default\n * {@link DEFAULT_REQUEST_TIMEOUT_MS}; `0` disables.\n */\n readonly timeoutMs?: number;\n}): Promise<Response> {\n const fetchImpl = args.fetchImpl ?? globalThis.fetch.bind(globalThis);\n const timeoutMs = args.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const timeoutCtl = timeoutMs > 0 ? new AbortController() : undefined;\n const timer =\n timeoutCtl !== undefined ? setTimeout(() => timeoutCtl.abort(), timeoutMs) : undefined;\n const signal =\n args.signal !== undefined && timeoutCtl !== undefined\n ? AbortSignal.any([args.signal, timeoutCtl.signal])\n : (args.signal ?? timeoutCtl?.signal);\n let resp: Response;\n try {\n resp = await fetchImpl(args.url, {\n method: 'POST',\n headers: args.headers,\n body: JSON.stringify(args.body),\n ...(signal !== undefined ? { signal } : {}),\n });\n } catch (cause) {\n if (timeoutCtl?.signal.aborted === true && args.signal?.aborted !== true) {\n throw new ProviderHttpError({\n providerName: args.providerName,\n status: 0,\n message: `request timed out after ${timeoutMs}ms reaching ${args.url}`,\n cause,\n });\n }\n throw new ProviderHttpError({\n providerName: args.providerName,\n status: 0,\n message: `network error reaching ${args.url}`,\n cause,\n });\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n if (!resp.ok) {\n const detail = await safeReadText(resp);\n const headers = pickBackoffHeaders(resp.headers);\n throw new ProviderHttpError({\n providerName: args.providerName,\n status: resp.status,\n message: detail.length > 0 ? detail : resp.statusText,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n return resp;\n}\n\n/**\n * Capture the backoff-relevant response headers (`retry-after`,\n * `x-ratelimit-*`) so `withRetry`'s Retry-After hint reader can honour\n * server-provided delays. Returns `undefined` when none are present.\n */\nfunction pickBackoffHeaders(headers: Headers): Readonly<Record<string, string>> | undefined {\n const picked: Record<string, string> = {};\n headers.forEach((value, key) => {\n const lower = key.toLowerCase();\n if (lower === 'retry-after' || lower.startsWith('x-ratelimit-')) {\n picked[lower] = value;\n }\n });\n return Object.keys(picked).length > 0 ? picked : undefined;\n}\n\nasync function safeReadText(resp: Response): Promise<string> {\n try {\n return await resp.text();\n } catch {\n return '';\n }\n}\n\n/**\n * Yield a `stream-start` `ProviderEvent` for an HTTP adapter.\n *\n * @internal\n */\nexport function makeStreamStartEvent(args: {\n readonly providerName: string;\n readonly modelId: string;\n readonly responseId?: string;\n}): ProviderEvent {\n return {\n type: 'stream-start',\n metadata: {\n providerName: args.providerName,\n modelId: args.modelId,\n ...(args.responseId !== undefined ? { responseId: args.responseId } : {}),\n createdAt: new Date().toISOString(),\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"http.js","names":["TEXT_ONLY: ChatMessageConversionOptions","out: Record<string, unknown>","out: Record<string, unknown>[]","content: string","images: string[] | undefined","buffer: string[]","images: string[]","parsed: unknown","resp: Response","picked: Record<string, string>"],"sources":["../../src/internal/http.ts"],"sourcesContent":["/**\n * Internal HTTP helpers shared across the local-LLM adapters.\n *\n * @internal\n */\n\nimport type { ProviderEvent } from '@graphorin/core';\n\nimport { ProviderHttpError } from '../errors/errors.js';\n\n/**\n * W-095: conversion options for the local-adapter message converters.\n * `multimodal` mirrors the adapter instance's effective\n * `capabilities.multimodal`; `warn` receives ONE message per convert\n * call when parts were dropped (adapters dedupe it to once per\n * instance).\n *\n * @internal\n */\nexport interface ChatMessageConversionOptions {\n readonly multimodal: boolean;\n readonly warn?: (message: string) => void;\n}\n\nconst TEXT_ONLY: ChatMessageConversionOptions = { multimodal: false };\n\n/**\n * Convert a graphorin `Message` to the OpenAI-compatible chat-completion\n * shape. The shape is the lingua-franca of the bundled local adapters\n * (`llamaCppServerAdapter` and `openAICompatibleAdapter`); the\n * native-Ollama path uses its own conversion.\n *\n * W-095: with `opts.multimodal === true` image parts are emitted as\n * OpenAI `image_url` content parts (bytes as a data URI, `URL`s passed\n * through as strings - the server dereferences; this adapter never\n * fetches). Audio/file parts have no portable wire form on\n * OpenAI-compatible servers and are dropped LOUDLY. With\n * `multimodal: false` (the default) content flattens to a plain string\n * exactly as before, and any dropped non-text part triggers the warn.\n *\n * @internal\n */\nexport function toOpenAIChatMessages(\n messages: ReadonlyArray<{\n readonly role: 'system' | 'user' | 'assistant' | 'tool';\n readonly content: string | ReadonlyArray<unknown>;\n readonly toolCalls?: ReadonlyArray<{\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: unknown;\n }>;\n readonly toolCallId?: string;\n }>,\n opts: ChatMessageConversionOptions = TEXT_ONLY,\n): ReadonlyArray<Record<string, unknown>> {\n const dropped = new Set<string>();\n const converted = messages.map((msg) => {\n const out: Record<string, unknown> = {\n role: msg.role,\n content:\n typeof msg.content === 'string'\n ? msg.content\n : opts.multimodal\n ? toOpenAIParts(msg.content, dropped)\n : flattenContent(msg.content, dropped),\n };\n if (msg.toolCalls !== undefined && msg.toolCalls.length > 0) {\n out.tool_calls = msg.toolCalls.map((tc) => ({\n id: tc.toolCallId,\n type: 'function',\n function: {\n name: tc.toolName,\n arguments: typeof tc.args === 'string' ? tc.args : JSON.stringify(tc.args),\n },\n }));\n }\n if (msg.role === 'tool' && msg.toolCallId !== undefined) {\n out.tool_call_id = msg.toolCallId;\n }\n return out;\n });\n warnDropped(opts, dropped);\n return converted;\n}\n\n/** W-095: build the OpenAI `content` parts array for a vision model. */\nfunction toOpenAIParts(\n parts: ReadonlyArray<unknown>,\n dropped: Set<string>,\n): ReadonlyArray<Record<string, unknown>> {\n const out: Record<string, unknown>[] = [];\n for (const part of parts) {\n if (typeof part === 'string') {\n out.push({ type: 'text', text: part });\n continue;\n }\n if (typeof part !== 'object' || part === null) continue;\n const obj = part as { type?: string; text?: string; image?: unknown; mimeType?: string };\n if (obj.type === 'text' && typeof obj.text === 'string') {\n out.push({ type: 'text', text: obj.text });\n continue;\n }\n if (obj.type === 'image') {\n const url = imageToUrl(obj.image, obj.mimeType);\n if (url !== undefined) {\n out.push({ type: 'image_url', image_url: { url } });\n continue;\n }\n }\n if (typeof obj.type === 'string') dropped.add(obj.type);\n }\n return out;\n}\n\n/**\n * W-095: bytes become a `data:` URI (default mime `image/png`); `URL`s\n * pass through as strings - the SERVER dereferences, the adapter makes\n * no network call of its own.\n */\nfunction imageToUrl(image: unknown, mimeType?: string): string | undefined {\n if (image instanceof URL) return image.toString();\n if (image instanceof Uint8Array) {\n const mime = mimeType ?? 'image/png';\n return `data:${mime};base64,${Buffer.from(image).toString('base64')}`;\n }\n return undefined;\n}\n\n/** W-095: one honest WARN per convert call when parts were dropped. */\nfunction warnDropped(opts: ChatMessageConversionOptions, dropped: Set<string>): void {\n if (dropped.size === 0 || opts.warn === undefined) return;\n const kinds = [...dropped].sort().join(', ');\n opts.warn(\n opts.multimodal\n ? `content parts of kind [${kinds}] have no wire mapping on this adapter and were dropped`\n : `non-text content parts of kind [${kinds}] were dropped - this adapter instance has capabilities.multimodal=false; pass capabilities: { multimodal: true } if the model supports vision`,\n );\n}\n\n/**\n * Convert a graphorin `Message` to Ollama's **native** `/api/chat` shape\n * (PS-13). Unlike the OpenAI form, Ollama's Go server expects `tool_calls`\n * with object `arguments` (a `map[string]any`, never a JSON string) and no\n * `id` / `type` fields - sending those breaks its unmarshaller and any\n * multi-turn replay of assistant tool calls.\n *\n * @internal\n */\nexport function toOllamaChatMessages(\n messages: ReadonlyArray<{\n readonly role: 'system' | 'user' | 'assistant' | 'tool';\n readonly content: string | ReadonlyArray<unknown>;\n readonly toolCalls?: ReadonlyArray<{\n readonly toolCallId: string;\n readonly toolName: string;\n readonly args: unknown;\n }>;\n readonly toolCallId?: string;\n }>,\n opts: ChatMessageConversionOptions = TEXT_ONLY,\n): ReadonlyArray<Record<string, unknown>> {\n const dropped = new Set<string>();\n const converted = messages.map((msg) => {\n let content: string;\n let images: string[] | undefined;\n if (typeof msg.content === 'string') {\n content = msg.content;\n } else if (opts.multimodal) {\n // W-095: Ollama's native API takes a per-message `images` array\n // of RAW base64 strings (no data: prefix). URL images cannot be\n // inlined on this path (the adapter never fetches) - dropped\n // loudly.\n const split = toOllamaContent(msg.content, dropped);\n content = split.text;\n images = split.images.length > 0 ? split.images : undefined;\n } else {\n content = flattenContent(msg.content, dropped);\n }\n const out: Record<string, unknown> = { role: msg.role, content };\n if (images !== undefined) out.images = images;\n if (msg.toolCalls !== undefined && msg.toolCalls.length > 0) {\n out.tool_calls = msg.toolCalls.map((tc) => ({\n function: {\n name: tc.toolName,\n arguments: toArgsObject(tc.args),\n },\n }));\n }\n return out;\n });\n warnDropped(opts, dropped);\n return converted;\n}\n\n/** W-095: split parts into flattened text + raw-base64 image payloads. */\nfunction toOllamaContent(\n parts: ReadonlyArray<unknown>,\n dropped: Set<string>,\n): { readonly text: string; readonly images: string[] } {\n const buffer: string[] = [];\n const images: string[] = [];\n for (const part of parts) {\n if (typeof part === 'string') {\n buffer.push(part);\n continue;\n }\n if (typeof part !== 'object' || part === null) continue;\n const obj = part as { type?: string; text?: string; image?: unknown };\n if (obj.type === 'text' && typeof obj.text === 'string') {\n buffer.push(obj.text);\n continue;\n }\n if (obj.type === 'image' && obj.image instanceof Uint8Array) {\n images.push(Buffer.from(obj.image).toString('base64'));\n continue;\n }\n if (obj.type === 'image') {\n dropped.add('image (URL - the native Ollama API needs inline bytes)');\n continue;\n }\n if (typeof obj.type === 'string') dropped.add(obj.type);\n }\n return { text: buffer.join(''), images };\n}\n\n/**\n * Coerce a tool-call `args` value into the object map Ollama expects. Strings\n * (e.g. an OpenAI-style JSON blob produced upstream) are parsed leniently;\n * anything that isn't a JSON object becomes `{}`.\n */\nfunction toArgsObject(args: unknown): Record<string, unknown> {\n if (typeof args === 'string') {\n try {\n const parsed: unknown = JSON.parse(args);\n return typeof parsed === 'object' && parsed !== null\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n return typeof args === 'object' && args !== null ? (args as Record<string, unknown>) : {};\n}\n\nfunction flattenContent(parts: ReadonlyArray<unknown>, dropped?: Set<string>): string {\n const buffer: string[] = [];\n for (const part of parts) {\n if (typeof part === 'string') {\n buffer.push(part);\n continue;\n }\n if (typeof part === 'object' && part !== null) {\n const obj = part as { type?: string; text?: string };\n if (obj.type === 'text' && typeof obj.text === 'string') {\n buffer.push(obj.text);\n } else if (typeof obj.type === 'string') {\n // W-095: silently vanishing multimodal content was the bug -\n // collect the kind so the caller can WARN once.\n dropped?.add(obj.type);\n }\n }\n }\n return buffer.join('');\n}\n\n/**\n * Wrap a `fetch` call with HTTP error mapping. The helper does not\n * assume any particular streaming format - callers receive the raw\n * `Response` and dispatch on its body.\n *\n * @internal\n */\n/**\n * Default per-request timeout for the baseUrl adapters (PS-24). Scoped\n * to time-to-response (headers): the timer is cleared the moment the\n * server answers, so long streaming bodies are never killed - only a\n * hung server that never responds. Generous because a cold local\n * llama-server can take tens of seconds to load a model.\n *\n * @stable\n */\nexport const DEFAULT_REQUEST_TIMEOUT_MS = 120_000;\n\nexport async function callJsonHttp(args: {\n readonly providerName: string;\n readonly url: string;\n readonly headers: Record<string, string>;\n readonly body: unknown;\n readonly signal?: AbortSignal;\n readonly fetchImpl?: typeof fetch;\n /**\n * Time-to-response budget (PS-24). Default\n * {@link DEFAULT_REQUEST_TIMEOUT_MS}; `0` disables.\n */\n readonly timeoutMs?: number;\n}): Promise<Response> {\n const fetchImpl = args.fetchImpl ?? globalThis.fetch.bind(globalThis);\n const timeoutMs = args.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n const timeoutCtl = timeoutMs > 0 ? new AbortController() : undefined;\n const timer =\n timeoutCtl !== undefined ? setTimeout(() => timeoutCtl.abort(), timeoutMs) : undefined;\n const signal =\n args.signal !== undefined && timeoutCtl !== undefined\n ? AbortSignal.any([args.signal, timeoutCtl.signal])\n : (args.signal ?? timeoutCtl?.signal);\n let resp: Response;\n try {\n resp = await fetchImpl(args.url, {\n method: 'POST',\n headers: args.headers,\n body: JSON.stringify(args.body),\n ...(signal !== undefined ? { signal } : {}),\n });\n } catch (cause) {\n if (timeoutCtl?.signal.aborted === true && args.signal?.aborted !== true) {\n throw new ProviderHttpError({\n providerName: args.providerName,\n status: 0,\n message: `request timed out after ${timeoutMs}ms reaching ${args.url}`,\n cause,\n });\n }\n throw new ProviderHttpError({\n providerName: args.providerName,\n status: 0,\n message: `network error reaching ${args.url}`,\n cause,\n });\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n if (!resp.ok) {\n const detail = await safeReadText(resp);\n const headers = pickBackoffHeaders(resp.headers);\n throw new ProviderHttpError({\n providerName: args.providerName,\n status: resp.status,\n message: detail.length > 0 ? detail : resp.statusText,\n ...(headers !== undefined ? { headers } : {}),\n });\n }\n return resp;\n}\n\n/**\n * Capture the backoff-relevant response headers (`retry-after`,\n * `x-ratelimit-*`) so `withRetry`'s Retry-After hint reader can honour\n * server-provided delays. Returns `undefined` when none are present.\n */\nfunction pickBackoffHeaders(headers: Headers): Readonly<Record<string, string>> | undefined {\n const picked: Record<string, string> = {};\n headers.forEach((value, key) => {\n const lower = key.toLowerCase();\n if (lower === 'retry-after' || lower.startsWith('x-ratelimit-')) {\n picked[lower] = value;\n }\n });\n return Object.keys(picked).length > 0 ? picked : undefined;\n}\n\nasync function safeReadText(resp: Response): Promise<string> {\n try {\n return await resp.text();\n } catch {\n return '';\n }\n}\n\n/**\n * Yield a `stream-start` `ProviderEvent` for an HTTP adapter.\n *\n * @internal\n */\nexport function makeStreamStartEvent(args: {\n readonly providerName: string;\n readonly modelId: string;\n readonly responseId?: string;\n}): ProviderEvent {\n return {\n type: 'stream-start',\n metadata: {\n providerName: args.providerName,\n modelId: args.modelId,\n ...(args.responseId !== undefined ? { responseId: args.responseId } : {}),\n createdAt: new Date().toISOString(),\n },\n };\n}\n"],"mappings":"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"}
|