@aparte/provider-ai-sdk 0.24.0 → 0.26.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EACR,gBAAgB,EAChB,aAAa,EACb,4BAA4B,EAC5B,iBAAiB,EAEjB,iBAAiB,EACjB,iBAAiB,EAEpB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAI3E,MAAM,WAAW,oBAAoB;IACjC,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,aAAa,CAAC;IAC1F,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,mDAAmD;IACnD,YAAY,CAAC,EAAE,4BAA4B,CAAC;CAC/C;AAwBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,YAAY,EAAE,CAyE7E;AAED,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,GAAG,OAAO,CAQjF;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,SAAS,CAIrG;AAYD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,UAAU,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtE,cAAc,CAAC,iBAAiB,CAAC,CAoEnC;AAUD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAiDhF;AAED,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EACR,gBAAgB,EAChB,aAAa,EACb,4BAA4B,EAC5B,iBAAiB,EAEjB,iBAAiB,EACjB,iBAAiB,EAGpB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAI3E,MAAM,WAAW,oBAAoB;IACjC,6EAA6E;IAC7E,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,aAAa,CAAC;IAC1F,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,mDAAmD;IACnD,YAAY,CAAC,EAAE,4BAA4B,CAAC;CAC/C;AAwBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,YAAY,EAAE,CAyE7E;AAED,iGAAiG;AACjG,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,GAAG,OAAO,CAQjF;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,SAAS,CAIrG;AAgDD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACpC,UAAU,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtE,cAAc,CAAC,iBAAiB,CAAC,CA2EnC;AAUD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,gBAAgB,CAiDhF;AAED,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { contentToText } from "@aparte/core";
1
+ import { contentToText, AparteErrorCode } from "@aparte/core";
2
2
  import { tool, jsonSchema, streamText } from "ai";
3
3
  const LEGACY_TOOL_ROLES = /* @__PURE__ */ new Set(["tool_call", "tool_result"]);
4
4
  const warnedLegacyRoles = /* @__PURE__ */ new Set();
@@ -98,6 +98,27 @@ function toAparteUsage(u) {
98
98
  cacheReadTokens: u.inputTokenDetails?.cacheReadTokens
99
99
  };
100
100
  }
101
+ function toAparteFinishReason(reason) {
102
+ switch (reason) {
103
+ case "stop":
104
+ case "length":
105
+ case "content-filter":
106
+ case "tool-calls":
107
+ case "error":
108
+ case "other":
109
+ return reason;
110
+ case "unknown":
111
+ return "other";
112
+ default:
113
+ return void 0;
114
+ }
115
+ }
116
+ const CONTEXT_OVERFLOW = /maximum context length|context length|context size has been exceeded|exceed_context_size_error|exceeds the available context size|prompt is too long|context_length_exceeded/i;
117
+ function errorEvent(message, err) {
118
+ const body = err?.responseBody;
119
+ const overflow = CONTEXT_OVERFLOW.test(message) || typeof body === "string" && CONTEXT_OVERFLOW.test(body);
120
+ return overflow ? { type: "error", message, code: AparteErrorCode.USAGE_CONTEXT_EXCEEDED } : { type: "error", message };
121
+ }
101
122
  function fullStreamToAparteEvents(fullStream) {
102
123
  let iterator;
103
124
  return new ReadableStream({
@@ -123,18 +144,25 @@ function fullStreamToAparteEvents(fullStream) {
123
144
  });
124
145
  break;
125
146
  case "finish":
126
- controller.enqueue({ type: "done", usage: toAparteUsage(part["totalUsage"]) });
147
+ {
148
+ const finishReason = toAparteFinishReason(part["finishReason"]);
149
+ controller.enqueue({
150
+ type: "done",
151
+ usage: toAparteUsage(part["totalUsage"]),
152
+ ...finishReason ? { finishReason } : {}
153
+ });
154
+ }
127
155
  return;
128
156
  case "error": {
129
157
  const err = part["error"];
130
- controller.enqueue({ type: "error", message: err instanceof Error ? err.message : String(err) });
158
+ controller.enqueue(errorEvent(err instanceof Error ? err.message : String(err), err));
131
159
  return;
132
160
  }
133
161
  }
134
162
  }
135
163
  } catch (err) {
136
164
  if (err?.name !== "AbortError") {
137
- controller.enqueue({ type: "error", message: err?.message ?? "Stream error" });
165
+ controller.enqueue(errorEvent(err?.message ?? "Stream error", err));
138
166
  }
139
167
  } finally {
140
168
  try {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @aparte/provider-ai-sdk — bridge any Vercel AI SDK model into aparté.\n *\n * aparté's own wire concern is deliberately tiny: `@aparte/provider-openai-compat`\n * covers the one de-facto-standard format. EVERYTHING else (Anthropic, Google,\n * Bedrock, 25+ vendors) rides the AI SDK ecosystem through this bridge: you\n * bring your `@ai-sdk/*` package and hand its model to `createAiSdkProvider`;\n * the bridge runs `streamText` (single step — aparté's agent loop owns the\n * multi-turn) and maps `fullStream` parts to aparté's `AparteStreamEvent`s.\n *\n * ```ts\n * import { createAnthropic } from '@ai-sdk/anthropic';\n * import { createAiSdkProvider } from '@aparte/provider-ai-sdk';\n *\n * aparteGlobalConfig.registerAIProvider(createAiSdkProvider({\n * id: 'anthropic',\n * name: 'Anthropic',\n * models: [{ id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' }],\n * languageModel: (modelId, auth) =>\n * createAnthropic({\n * apiKey: typeof auth === 'string' ? auth : auth?.['apiKey'],\n * headers: { 'anthropic-dangerous-direct-browser-access': 'true' }, // BYOK\n * })(modelId),\n * }));\n * ```\n *\n * DEPENDENCY POLICY: `ai` is a **peerDependency pinned to the verified major**\n * (`^7`). The AI SDK moves fast (v5→v7 in about a year); this bridge is the\n * ONLY aparté module touching its types, so a breaking major costs one small\n * package bump — widened per-major after verification, never speculatively.\n *\n * The bridge is an `AparteAIProvider` with a `chat()` (it owns its I/O via the\n * SDK — same shape as `@aparte/provider-transformers`), driven by\n * `AparteDirectTransport`'s delegation branch, which forwards `ctx.signal` so a user\n * \"stop\" aborts the underlying vendor call.\n *\n * NOTE (loop contract): the bridge never sees `toolChoice: { name, input }` —\n * the agent loop (engine `runStreamAgent` / core `_streamLoop`) executes that\n * synthetic call itself and strips `toolChoice` before the transport call.\n * Only `'auto' | 'none' | { name }` reach this module.\n */\n\nimport type {\n AparteAIProvider,\n AparteAIModel,\n AparteAIProviderConfigSchema,\n AparteChatRequest,\n AparteChatResponse,\n AparteChatMessage,\n AparteStreamEvent,\n AparteUsage,\n} from '@aparte/core';\nimport { contentToText } from '@aparte/core';\nimport { streamText, jsonSchema, tool } from 'ai';\nimport type { LanguageModel, ModelMessage, ToolSet, ToolChoice } from 'ai';\n\n// ─── Options ─────────────────────────────────────────────────────────────────\n\nexport interface AiSdkProviderOptions {\n /** Provider id used across aparté (key resolution, model picker, events). */\n id: string;\n /**\n * Resolve the AI SDK model for a chat call. `auth` is the key/config the\n * aparté key-resolver produced — rebuild the vendor provider per call for\n * UI-driven BYOK, or ignore it if your factory already carries the key.\n */\n languageModel: (modelId: string, auth?: string | Record<string, string>) => LanguageModel;\n /** Display name (defaults to `id`). */\n name?: string;\n /** Brand icon (SVG string / data URI / icon-provider key). */\n icon?: string;\n /** Brand color. */\n color?: string;\n /** Short tag line. */\n description?: string;\n /** Where the user gets a key. */\n helpUrl?: string;\n /** Whether the vendor offers free models. */\n hasFreeModels?: boolean;\n /** Model runs locally (no key expected). */\n isLocal?: boolean;\n /** Model list — **consumer data** (the AI SDK has no model-listing API). */\n models?: AparteAIModel[];\n /** Override the default apiKey settings schema. */\n configSchema?: AparteAIProviderConfigSchema;\n}\n\n// ─── aparté ⇄ AI SDK shaping ─────────────────────────────────────────────────\n\n/**\n * The two roles a tool turn used to wear. `AparteChatMessage` no longer allows either, so\n * the comparison is on the role as a string: a message carrying one comes from code built\n * against an older aparté, which no type here can catch. Warned once per role, then\n * skipped — the fallthrough below maps anything unrecognised as a `user` turn, so without\n * this the model would read a tool result as something the person typed.\n */\nconst LEGACY_TOOL_ROLES = new Set(['tool_call', 'tool_result']);\nconst warnedLegacyRoles = new Set<string>();\nfunction warnLegacyToolRole(role: string): void {\n if (warnedLegacyRoles.has(role)) return;\n warnedLegacyRoles.add(role);\n console.warn(\n `[@aparte/provider-ai-sdk] Skipping a message with the removed role \"${role}\".`\n + \" A tool turn is now an assistant message carrying its calls — { role: 'assistant',\"\n + \" content: <what it said>, toolCalls } — followed by one { role: 'tool', content:\"\n + ' <result>, toolCallId, toolName } per call. This warning is removed in 0.18.',\n );\n}\n\n/**\n * AparteChatMessage[] → AI SDK ModelMessage[]. Handles a tool turn (an assistant\n * message carrying `toolCalls`, then the `tool` messages answering them); the tool\n * name for a result is the message's own `toolName`, else the call that declared it.\n */\nexport function toModelMessages(messages: AparteChatMessage[]): ModelMessage[] {\n // toolCallId → toolName, the FALLBACK for a `tool` message that names no tool of\n // its own. A hand-built history need carry no assistant turn to scan, which is\n // where the name used to become 'unknown'.\n const toolNames = new Map<string, string>();\n for (const msg of messages) {\n if (msg.role === 'assistant') {\n for (const tc of msg.toolCalls ?? []) toolNames.set(tc.id, tc.name);\n }\n }\n\n const out: ModelMessage[] = [];\n for (const msg of messages) {\n const role: string = msg.role;\n if (LEGACY_TOOL_ROLES.has(role)) {\n warnLegacyToolRole(role);\n continue;\n }\n if (msg.role === 'tool') {\n out.push({\n role: 'tool',\n content: [{\n type: 'tool-result',\n toolCallId: msg.toolCallId ?? '',\n toolName: msg.toolName ?? toolNames.get(msg.toolCallId ?? '') ?? 'unknown',\n output: { type: 'text', value: contentToText(msg.content) },\n }],\n });\n continue;\n }\n if (msg.role === 'system') {\n out.push({ role: 'system', content: contentToText(msg.content) });\n continue;\n }\n if (msg.role === 'assistant') {\n if (msg.toolCalls?.length) {\n const text = contentToText(msg.content);\n out.push({\n role: 'assistant',\n content: [\n // No empty text part: '' is what an assistant that said nothing\n // before its calls now carries, and a part saying nothing is a\n // part the model still reads.\n ...(text ? [{ type: 'text' as const, text }] : []),\n ...msg.toolCalls.map(tc => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.name,\n input: tc.input,\n })),\n ],\n });\n continue;\n }\n out.push({ role: 'assistant', content: contentToText(msg.content) });\n continue;\n }\n // user (default) — keep multimodal parts.\n if (typeof msg.content === 'string') {\n out.push({ role: 'user', content: msg.content });\n } else {\n out.push({\n role: 'user',\n // Two arms, exhaustive: a part is text or an image. A third used to answer\n // the removed `AparteFilePart` with an empty text part — a branch nothing\n // could reach, standing in for a file bridge that was never written.\n content: msg.content.map(p => (p.type === 'text'\n ? { type: 'text' as const, text: p.text }\n : { type: 'image' as const, image: p.image })),\n });\n }\n }\n return out;\n}\n\n/** AparteTool[] → AI SDK ToolSet — declaration only, NO `execute` (aparté's loop runs tools). */\nexport function toToolSet(tools: NonNullable<AparteChatRequest['tools']>): ToolSet {\n return Object.fromEntries(tools.map(t => [\n t.name,\n tool({\n description: t.description,\n inputSchema: jsonSchema(t.inputSchema as Parameters<typeof jsonSchema>[0]),\n }),\n ]));\n}\n\n/** aparté toolChoice → AI SDK toolChoice (the synthetic {name,input} never reaches here). */\nexport function toToolChoice(choice: AparteChatRequest['toolChoice']): ToolChoice<ToolSet> | undefined {\n if (choice === 'auto' || choice === 'none') return choice;\n if (choice && typeof choice === 'object') return { type: 'tool', toolName: choice.name };\n return undefined;\n}\n\n/** fullStream `finish.totalUsage` → AparteUsage. */\nfunction toAparteUsage(u: { inputTokens?: number; outputTokens?: number; totalTokens?: number; inputTokenDetails?: { cacheReadTokens?: number } }): AparteUsage {\n return {\n inputTokens: u.inputTokens ?? 0,\n outputTokens: u.outputTokens ?? 0,\n totalTokens: u.totalTokens,\n cacheReadTokens: u.inputTokenDetails?.cacheReadTokens,\n };\n}\n\n/**\n * Map the AI SDK `fullStream` to aparté's event stream:\n * `text-delta`→text · `reasoning-delta`→thinking · `tool-call`→tool_use ·\n * `finish`→done{usage} · `error`→error. Everything else (step markers,\n * tool-input deltas, sources, files) is dropped — aparté's loop consumes whole\n * tool calls, not input deltas.\n */\nexport function fullStreamToAparteEvents(\n fullStream: AsyncIterable<{ type: string } & Record<string, unknown>>,\n): ReadableStream<AparteStreamEvent> {\n // Held so `cancel()` can signal the AI SDK's iterator to stop (calling\n // `.return()` propagates cancellation the same way breaking a `for await`\n // loop would), instead of leaving `start()` draining `fullStream` to its\n // natural end after the consumer has already walked away.\n let iterator: AsyncIterator<{ type: string } & Record<string, unknown>> | undefined;\n\n return new ReadableStream<AparteStreamEvent>({\n async start(controller) {\n iterator = fullStream[Symbol.asyncIterator]();\n try {\n while (true) {\n const { value: part, done } = await iterator.next();\n if (done) break;\n\n switch (part.type) {\n case 'text-delta':\n controller.enqueue({ type: 'text', delta: part['text'] as string });\n break;\n case 'reasoning-delta':\n controller.enqueue({ type: 'thinking', delta: part['text'] as string });\n break;\n case 'tool-call':\n controller.enqueue({\n type: 'tool_use',\n id: part['toolCallId'] as string,\n name: part['toolName'] as string,\n input: (part['input'] ?? {}) as Record<string, unknown>,\n });\n break;\n case 'finish':\n controller.enqueue({ type: 'done', usage: toAparteUsage(part['totalUsage'] as Parameters<typeof toAparteUsage>[0]) });\n // Terminal: stop reading `fullStream` so a stray second\n // finish/error part (if the SDK ever emits one) can't\n // enqueue past the done event.\n return;\n case 'error': {\n const err = part['error'];\n controller.enqueue({ type: 'error', message: err instanceof Error ? err.message : String(err) });\n return;\n }\n // 'abort', step markers, tool-input-* deltas, sources… → dropped.\n }\n }\n } catch (err: unknown) {\n // AbortError surfaces here when ctx.signal fires mid-stream: the\n // consumer (agent loop) cancelled on purpose — end quietly.\n if ((err as { name?: string })?.name !== 'AbortError') {\n controller.enqueue({ type: 'error', message: (err as Error | undefined)?.message ?? 'Stream error' });\n }\n } finally {\n /*\n * Told to stop on EVERY exit, not only when the consumer cancels: the\n * `finish` and `error` branches `return` straight out of the loop, so\n * they used to reach this `finally` having said nothing to the SDK —\n * after an error part the vendor call was left to drain on its own,\n * which is the very thing `cancel()` exists to prevent. Best effort:\n * an iterator that objects to being settled must not become the\n * stream's error.\n */\n try { await iterator?.return?.(undefined); } catch { /* best effort */ }\n controller.close();\n }\n },\n async cancel(reason) {\n await iterator?.return?.(reason);\n },\n });\n}\n\n// ─── The provider factory ────────────────────────────────────────────────────\n\nconst DEFAULT_CONFIG_SCHEMA = (opts: AiSdkProviderOptions): AparteAIProviderConfigSchema => ({\n fields: opts.isLocal\n ? []\n : [{ id: 'apiKey', type: 'password', label: 'API Key', required: true }],\n});\n\n/**\n * Wrap an AI SDK model factory into an `AparteAIProvider`. The returned provider\n * owns its I/O through the SDK (`chat()` shape — `AparteDirectTransport` delegates\n * to it and forwards the abort signal).\n */\nexport function createAiSdkProvider(opts: AiSdkProviderOptions): AparteAIProvider {\n const displayName = opts.name ?? opts.id;\n\n return {\n id: opts.id,\n\n getMetadata() {\n return {\n id: opts.id,\n name: displayName,\n icon: opts.icon,\n color: opts.color,\n description: opts.description,\n helpUrl: opts.helpUrl,\n hasFreeModels: opts.hasFreeModels,\n isLocal: opts.isLocal,\n configSchema: opts.configSchema ?? DEFAULT_CONFIG_SCHEMA(opts),\n };\n },\n\n getModels(): AparteAIModel[] {\n return opts.models ?? [];\n },\n\n async chat(\n request: AparteChatRequest,\n auth?: string | Record<string, string>,\n ctx?: { providerId: string; signal?: AbortSignal },\n ): Promise<AparteChatResponse> {\n const model = opts.languageModel(request.modelId ?? '', auth);\n\n const result = streamText({\n model,\n messages: toModelMessages(request.messages),\n temperature: request.temperature,\n maxOutputTokens: request.maxTokens,\n seed: request.seed,\n abortSignal: ctx?.signal,\n ...(request.tools?.length\n ? { tools: toToolSet(request.tools), toolChoice: toToolChoice(request.toolChoice) ?? 'auto' }\n : {}),\n });\n\n if (request.stream === false) {\n return await result.text;\n }\n return fullStreamToAparteEvents(result.fullStream);\n },\n };\n}\n\nexport type { AparteAIProvider, AparteAIModel } from '@aparte/core';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * @aparte/provider-ai-sdk — bridge any Vercel AI SDK model into aparté.\n *\n * aparté's own wire concern is deliberately tiny: `@aparte/provider-openai-compat`\n * covers the one de-facto-standard format. EVERYTHING else (Anthropic, Google,\n * Bedrock, 25+ vendors) rides the AI SDK ecosystem through this bridge: you\n * bring your `@ai-sdk/*` package and hand its model to `createAiSdkProvider`;\n * the bridge runs `streamText` (single step — aparté's agent loop owns the\n * multi-turn) and maps `fullStream` parts to aparté's `AparteStreamEvent`s.\n *\n * ```ts\n * import { createAnthropic } from '@ai-sdk/anthropic';\n * import { createAiSdkProvider } from '@aparte/provider-ai-sdk';\n *\n * aparteGlobalConfig.registerAIProvider(createAiSdkProvider({\n * id: 'anthropic',\n * name: 'Anthropic',\n * models: [{ id: 'claude-sonnet-4-5', name: 'Claude Sonnet 4.5' }],\n * languageModel: (modelId, auth) =>\n * createAnthropic({\n * apiKey: typeof auth === 'string' ? auth : auth?.['apiKey'],\n * headers: { 'anthropic-dangerous-direct-browser-access': 'true' }, // BYOK\n * })(modelId),\n * }));\n * ```\n *\n * DEPENDENCY POLICY: `ai` is a **peerDependency pinned to the verified major**\n * (`^7`). The AI SDK moves fast (v5→v7 in about a year); this bridge is the\n * ONLY aparté module touching its types, so a breaking major costs one small\n * package bump — widened per-major after verification, never speculatively.\n *\n * The bridge is an `AparteAIProvider` with a `chat()` (it owns its I/O via the\n * SDK — same shape as `@aparte/provider-transformers`), driven by\n * `AparteDirectTransport`'s delegation branch, which forwards `ctx.signal` so a user\n * \"stop\" aborts the underlying vendor call.\n *\n * NOTE (loop contract): the bridge never sees `toolChoice: { name, input }` —\n * the agent loop (engine `runStreamAgent` / core `_streamLoop`) executes that\n * synthetic call itself and strips `toolChoice` before the transport call.\n * Only `'auto' | 'none' | { name }` reach this module.\n */\n\nimport type {\n AparteAIProvider,\n AparteAIModel,\n AparteAIProviderConfigSchema,\n AparteChatRequest,\n AparteChatResponse,\n AparteChatMessage,\n AparteStreamEvent,\n AparteUsage,\n AparteFinishReason,\n} from '@aparte/core';\nimport { AparteErrorCode, contentToText } from '@aparte/core';\nimport { streamText, jsonSchema, tool } from 'ai';\nimport type { LanguageModel, ModelMessage, ToolSet, ToolChoice } from 'ai';\n\n// ─── Options ─────────────────────────────────────────────────────────────────\n\nexport interface AiSdkProviderOptions {\n /** Provider id used across aparté (key resolution, model picker, events). */\n id: string;\n /**\n * Resolve the AI SDK model for a chat call. `auth` is the key/config the\n * aparté key-resolver produced — rebuild the vendor provider per call for\n * UI-driven BYOK, or ignore it if your factory already carries the key.\n */\n languageModel: (modelId: string, auth?: string | Record<string, string>) => LanguageModel;\n /** Display name (defaults to `id`). */\n name?: string;\n /** Brand icon (SVG string / data URI / icon-provider key). */\n icon?: string;\n /** Brand color. */\n color?: string;\n /** Short tag line. */\n description?: string;\n /** Where the user gets a key. */\n helpUrl?: string;\n /** Whether the vendor offers free models. */\n hasFreeModels?: boolean;\n /** Model runs locally (no key expected). */\n isLocal?: boolean;\n /** Model list — **consumer data** (the AI SDK has no model-listing API). */\n models?: AparteAIModel[];\n /** Override the default apiKey settings schema. */\n configSchema?: AparteAIProviderConfigSchema;\n}\n\n// ─── aparté ⇄ AI SDK shaping ─────────────────────────────────────────────────\n\n/**\n * The two roles a tool turn used to wear. `AparteChatMessage` no longer allows either, so\n * the comparison is on the role as a string: a message carrying one comes from code built\n * against an older aparté, which no type here can catch. Warned once per role, then\n * skipped — the fallthrough below maps anything unrecognised as a `user` turn, so without\n * this the model would read a tool result as something the person typed.\n */\nconst LEGACY_TOOL_ROLES = new Set(['tool_call', 'tool_result']);\nconst warnedLegacyRoles = new Set<string>();\nfunction warnLegacyToolRole(role: string): void {\n if (warnedLegacyRoles.has(role)) return;\n warnedLegacyRoles.add(role);\n console.warn(\n `[@aparte/provider-ai-sdk] Skipping a message with the removed role \"${role}\".`\n + \" A tool turn is now an assistant message carrying its calls — { role: 'assistant',\"\n + \" content: <what it said>, toolCalls } — followed by one { role: 'tool', content:\"\n + ' <result>, toolCallId, toolName } per call. This warning is removed in 0.18.',\n );\n}\n\n/**\n * AparteChatMessage[] → AI SDK ModelMessage[]. Handles a tool turn (an assistant\n * message carrying `toolCalls`, then the `tool` messages answering them); the tool\n * name for a result is the message's own `toolName`, else the call that declared it.\n */\nexport function toModelMessages(messages: AparteChatMessage[]): ModelMessage[] {\n // toolCallId → toolName, the FALLBACK for a `tool` message that names no tool of\n // its own. A hand-built history need carry no assistant turn to scan, which is\n // where the name used to become 'unknown'.\n const toolNames = new Map<string, string>();\n for (const msg of messages) {\n if (msg.role === 'assistant') {\n for (const tc of msg.toolCalls ?? []) toolNames.set(tc.id, tc.name);\n }\n }\n\n const out: ModelMessage[] = [];\n for (const msg of messages) {\n const role: string = msg.role;\n if (LEGACY_TOOL_ROLES.has(role)) {\n warnLegacyToolRole(role);\n continue;\n }\n if (msg.role === 'tool') {\n out.push({\n role: 'tool',\n content: [{\n type: 'tool-result',\n toolCallId: msg.toolCallId ?? '',\n toolName: msg.toolName ?? toolNames.get(msg.toolCallId ?? '') ?? 'unknown',\n output: { type: 'text', value: contentToText(msg.content) },\n }],\n });\n continue;\n }\n if (msg.role === 'system') {\n out.push({ role: 'system', content: contentToText(msg.content) });\n continue;\n }\n if (msg.role === 'assistant') {\n if (msg.toolCalls?.length) {\n const text = contentToText(msg.content);\n out.push({\n role: 'assistant',\n content: [\n // No empty text part: '' is what an assistant that said nothing\n // before its calls now carries, and a part saying nothing is a\n // part the model still reads.\n ...(text ? [{ type: 'text' as const, text }] : []),\n ...msg.toolCalls.map(tc => ({\n type: 'tool-call' as const,\n toolCallId: tc.id,\n toolName: tc.name,\n input: tc.input,\n })),\n ],\n });\n continue;\n }\n out.push({ role: 'assistant', content: contentToText(msg.content) });\n continue;\n }\n // user (default) — keep multimodal parts.\n if (typeof msg.content === 'string') {\n out.push({ role: 'user', content: msg.content });\n } else {\n out.push({\n role: 'user',\n // Two arms, exhaustive: a part is text or an image. A third used to answer\n // the removed `AparteFilePart` with an empty text part — a branch nothing\n // could reach, standing in for a file bridge that was never written.\n content: msg.content.map(p => (p.type === 'text'\n ? { type: 'text' as const, text: p.text }\n : { type: 'image' as const, image: p.image })),\n });\n }\n }\n return out;\n}\n\n/** AparteTool[] → AI SDK ToolSet — declaration only, NO `execute` (aparté's loop runs tools). */\nexport function toToolSet(tools: NonNullable<AparteChatRequest['tools']>): ToolSet {\n return Object.fromEntries(tools.map(t => [\n t.name,\n tool({\n description: t.description,\n inputSchema: jsonSchema(t.inputSchema as Parameters<typeof jsonSchema>[0]),\n }),\n ]));\n}\n\n/** aparté toolChoice → AI SDK toolChoice (the synthetic {name,input} never reaches here). */\nexport function toToolChoice(choice: AparteChatRequest['toolChoice']): ToolChoice<ToolSet> | undefined {\n if (choice === 'auto' || choice === 'none') return choice;\n if (choice && typeof choice === 'object') return { type: 'tool', toolName: choice.name };\n return undefined;\n}\n\n/** fullStream `finish.totalUsage` → AparteUsage. */\nfunction toAparteUsage(u: { inputTokens?: number; outputTokens?: number; totalTokens?: number; inputTokenDetails?: { cacheReadTokens?: number } }): AparteUsage {\n return {\n inputTokens: u.inputTokens ?? 0,\n outputTokens: u.outputTokens ?? 0,\n totalTokens: u.totalTokens,\n cacheReadTokens: u.inputTokenDetails?.cacheReadTokens,\n };\n}\n\n/**\n * fullStream `finish.finishReason` → AparteFinishReason. The SDK's own list is the same\n * but for `'unknown'`, which is \"the vendor said something we could not classify\" — the\n * `'other'` of ours. A value that is neither (a newer SDK) is left off rather than guessed.\n */\nfunction toAparteFinishReason(reason: unknown): AparteFinishReason | undefined {\n switch (reason) {\n case 'stop': case 'length': case 'content-filter': case 'tool-calls': case 'error': case 'other':\n return reason;\n case 'unknown':\n return 'other';\n default:\n return undefined;\n }\n}\n\n/**\n * What servers write when the prompt is longer than the model's window (OpenAI's \"maximum\n * context length\", LM Studio's \"Context size has been exceeded\", llama.cpp's\n * `exceed_context_size_error`, Anthropic's \"prompt is too long\"). The SDK hands a failed\n * call over as an `APICallError` whose message — and, for some vendors, response body — is\n * the vendor's own sentence, so the match is the same one `@aparte/provider-openai-compat`\n * makes on a wire body.\n */\nconst CONTEXT_OVERFLOW = /maximum context length|context length|context size has been exceeded|exceed_context_size_error|exceeds the available context size|prompt is too long|context_length_exceeded/i;\n\n/**\n * The error event for a failure the SDK reported. An overflow carries its code, so the\n * client can compact and resend instead of showing the vendor's sentence.\n */\nfunction errorEvent(message: string, err: unknown): AparteStreamEvent {\n const body = (err as { responseBody?: unknown } | null | undefined)?.responseBody;\n const overflow = CONTEXT_OVERFLOW.test(message) || (typeof body === 'string' && CONTEXT_OVERFLOW.test(body));\n return overflow ? { type: 'error', message, code: AparteErrorCode.USAGE_CONTEXT_EXCEEDED } : { type: 'error', message };\n}\n\n/**\n * Map the AI SDK `fullStream` to aparté's event stream:\n * `text-delta`→text · `reasoning-delta`→thinking · `tool-call`→tool_use ·\n * `finish`→done{usage} · `error`→error. Everything else (step markers,\n * tool-input deltas, sources, files) is dropped — aparté's loop consumes whole\n * tool calls, not input deltas.\n */\nexport function fullStreamToAparteEvents(\n fullStream: AsyncIterable<{ type: string } & Record<string, unknown>>,\n): ReadableStream<AparteStreamEvent> {\n // Held so `cancel()` can signal the AI SDK's iterator to stop (calling\n // `.return()` propagates cancellation the same way breaking a `for await`\n // loop would), instead of leaving `start()` draining `fullStream` to its\n // natural end after the consumer has already walked away.\n let iterator: AsyncIterator<{ type: string } & Record<string, unknown>> | undefined;\n\n return new ReadableStream<AparteStreamEvent>({\n async start(controller) {\n iterator = fullStream[Symbol.asyncIterator]();\n try {\n while (true) {\n const { value: part, done } = await iterator.next();\n if (done) break;\n\n switch (part.type) {\n case 'text-delta':\n controller.enqueue({ type: 'text', delta: part['text'] as string });\n break;\n case 'reasoning-delta':\n controller.enqueue({ type: 'thinking', delta: part['text'] as string });\n break;\n case 'tool-call':\n controller.enqueue({\n type: 'tool_use',\n id: part['toolCallId'] as string,\n name: part['toolName'] as string,\n input: (part['input'] ?? {}) as Record<string, unknown>,\n });\n break;\n case 'finish':\n {\n const finishReason = toAparteFinishReason(part['finishReason']);\n controller.enqueue({\n type: 'done',\n usage: toAparteUsage(part['totalUsage'] as Parameters<typeof toAparteUsage>[0]),\n ...(finishReason ? { finishReason } : {}),\n });\n }\n // Terminal: stop reading `fullStream` so a stray second\n // finish/error part (if the SDK ever emits one) can't\n // enqueue past the done event.\n return;\n case 'error': {\n const err = part['error'];\n controller.enqueue(errorEvent(err instanceof Error ? err.message : String(err), err));\n return;\n }\n // 'abort', step markers, tool-input-* deltas, sources… → dropped.\n }\n }\n } catch (err: unknown) {\n // AbortError surfaces here when ctx.signal fires mid-stream: the\n // consumer (agent loop) cancelled on purpose — end quietly.\n if ((err as { name?: string })?.name !== 'AbortError') {\n controller.enqueue(errorEvent((err as Error | undefined)?.message ?? 'Stream error', err));\n }\n } finally {\n /*\n * Told to stop on EVERY exit, not only when the consumer cancels: the\n * `finish` and `error` branches `return` straight out of the loop, so\n * they used to reach this `finally` having said nothing to the SDK —\n * after an error part the vendor call was left to drain on its own,\n * which is the very thing `cancel()` exists to prevent. Best effort:\n * an iterator that objects to being settled must not become the\n * stream's error.\n */\n try { await iterator?.return?.(undefined); } catch { /* best effort */ }\n controller.close();\n }\n },\n async cancel(reason) {\n await iterator?.return?.(reason);\n },\n });\n}\n\n// ─── The provider factory ────────────────────────────────────────────────────\n\nconst DEFAULT_CONFIG_SCHEMA = (opts: AiSdkProviderOptions): AparteAIProviderConfigSchema => ({\n fields: opts.isLocal\n ? []\n : [{ id: 'apiKey', type: 'password', label: 'API Key', required: true }],\n});\n\n/**\n * Wrap an AI SDK model factory into an `AparteAIProvider`. The returned provider\n * owns its I/O through the SDK (`chat()` shape — `AparteDirectTransport` delegates\n * to it and forwards the abort signal).\n */\nexport function createAiSdkProvider(opts: AiSdkProviderOptions): AparteAIProvider {\n const displayName = opts.name ?? opts.id;\n\n return {\n id: opts.id,\n\n getMetadata() {\n return {\n id: opts.id,\n name: displayName,\n icon: opts.icon,\n color: opts.color,\n description: opts.description,\n helpUrl: opts.helpUrl,\n hasFreeModels: opts.hasFreeModels,\n isLocal: opts.isLocal,\n configSchema: opts.configSchema ?? DEFAULT_CONFIG_SCHEMA(opts),\n };\n },\n\n getModels(): AparteAIModel[] {\n return opts.models ?? [];\n },\n\n async chat(\n request: AparteChatRequest,\n auth?: string | Record<string, string>,\n ctx?: { providerId: string; signal?: AbortSignal },\n ): Promise<AparteChatResponse> {\n const model = opts.languageModel(request.modelId ?? '', auth);\n\n const result = streamText({\n model,\n messages: toModelMessages(request.messages),\n temperature: request.temperature,\n maxOutputTokens: request.maxTokens,\n seed: request.seed,\n abortSignal: ctx?.signal,\n ...(request.tools?.length\n ? { tools: toToolSet(request.tools), toolChoice: toToolChoice(request.toolChoice) ?? 'auto' }\n : {}),\n });\n\n if (request.stream === false) {\n return await result.text;\n }\n return fullStreamToAparteEvents(result.fullStream);\n },\n };\n}\n\nexport type { AparteAIProvider, AparteAIModel } from '@aparte/core';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aparte/provider-ai-sdk",
3
- "version": "0.24.0",
3
+ "version": "0.26.0",
4
4
  "homepage": "https://apartejs.dev/providers/ai/ai-sdk/",
5
5
  "description": "Bridge any Vercel AI SDK model into aparté — bring your own @ai-sdk/* package (Anthropic, Google, OpenAI, 25+ vendors) and aparté renders it.",
6
6
  "type": "module",
@@ -25,7 +25,7 @@
25
25
  "node": ">=18"
26
26
  },
27
27
  "peerDependencies": {
28
- "@aparte/core": ">=0.24.0 <1.0.0",
28
+ "@aparte/core": ">=0.26.0 <1.0.0",
29
29
  "ai": "^7.0.0"
30
30
  },
31
31
  "devDependencies": {
@@ -35,7 +35,7 @@
35
35
  "typescript": "^5.4.0",
36
36
  "vite": "^6.0.0",
37
37
  "zod": "^4.1.8",
38
- "@aparte/core": "0.24.0"
38
+ "@aparte/core": "0.26.0"
39
39
  },
40
40
  "keywords": [
41
41
  "ai",