@tanstack/ai 0.47.3 → 0.49.1
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/README.md +2 -1
- package/dist/esm/activities/chat/adapter.d.ts +5 -4
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/index.d.ts +4 -7
- package/dist/esm/activities/chat/index.js +201 -243
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/messages.js +115 -25
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +38 -17
- package/dist/esm/activities/chat/stream/processor.js +186 -101
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +3 -2
- package/dist/esm/activities/chat/tools/tool-calls.js +15 -10
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.js +6 -6
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/stream-generation-result.js +7 -8
- package/dist/esm/activities/stream-generation-result.js.map +1 -1
- package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +2 -1
- package/dist/esm/activities/summarize/chat-stream-summarize.js +56 -53
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +2 -0
- package/dist/esm/adapter-internals.js +3 -1
- package/dist/esm/byok/define-provider.d.ts +23 -0
- package/dist/esm/byok/define-provider.js +19 -0
- package/dist/esm/byok/define-provider.js.map +1 -0
- package/dist/esm/byok/errors.d.ts +13 -0
- package/dist/esm/byok/errors.js +29 -0
- package/dist/esm/byok/errors.js.map +1 -0
- package/dist/esm/byok/get-key.d.ts +10 -0
- package/dist/esm/byok/get-key.js +26 -0
- package/dist/esm/byok/get-key.js.map +1 -0
- package/dist/esm/byok/missing.d.ts +11 -0
- package/dist/esm/byok/missing.js +30 -0
- package/dist/esm/byok/missing.js.map +1 -0
- package/dist/esm/byok/providers.d.ts +13 -0
- package/dist/esm/byok/providers.js +18 -0
- package/dist/esm/byok/providers.js.map +1 -0
- package/dist/esm/byok/scrub.d.ts +2 -0
- package/dist/esm/byok/scrub.js +17 -0
- package/dist/esm/byok/scrub.js.map +1 -0
- package/dist/esm/byok/server.d.ts +3 -0
- package/dist/esm/byok/server.js +3 -0
- package/dist/esm/byok.d.ts +8 -0
- package/dist/esm/byok.js +6 -0
- package/dist/esm/client.d.ts +8 -1
- package/dist/esm/client.js +7 -2
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.js +6 -2
- package/dist/esm/interrupt-resume.js +4 -4
- package/dist/esm/interrupt-resume.js.map +1 -1
- package/dist/esm/middlewares/otel.js +11 -4
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/stream-to-response.js +8 -5
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/stream-to-websocket.js +4 -2
- package/dist/esm/stream-to-websocket.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.d.ts +10 -13
- package/dist/esm/strip-to-spec-middleware.js +24 -22
- package/dist/esm/strip-to-spec-middleware.js.map +1 -1
- package/dist/esm/types.d.ts +82 -305
- package/dist/esm/utilities/adapter-yield-chunk.d.ts +31 -0
- package/dist/esm/utilities/ag-ui-usage.d.ts +24 -0
- package/dist/esm/utilities/ag-ui-usage.js +66 -0
- package/dist/esm/utilities/ag-ui-usage.js.map +1 -0
- package/dist/esm/utilities/ag-ui-wire.d.ts +14 -7
- package/dist/esm/utilities/ag-ui-wire.js +71 -30
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +3 -3
- package/dist/esm/utilities/chat-params.js +10 -30
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/chunk-ids.d.ts +5 -0
- package/dist/esm/utilities/chunk-ids.js +25 -0
- package/dist/esm/utilities/chunk-ids.js.map +1 -0
- package/dist/esm/utilities/merge-metadata.d.ts +14 -0
- package/dist/esm/utilities/merge-metadata.js +43 -0
- package/dist/esm/utilities/merge-metadata.js.map +1 -0
- package/dist/esm/utilities/normalize-stream-chunk.d.ts +3 -0
- package/dist/esm/utilities/normalize-stream-chunk.js +100 -0
- package/dist/esm/utilities/normalize-stream-chunk.js.map +1 -0
- package/dist/esm/utilities/reasoning-encrypted-value.d.ts +8 -0
- package/dist/esm/utilities/reasoning-encrypted-value.js +16 -0
- package/dist/esm/utilities/reasoning-encrypted-value.js.map +1 -0
- package/dist/esm/utilities/restore-inbound-chunk.d.ts +15 -0
- package/dist/esm/utilities/restore-inbound-chunk.js +43 -0
- package/dist/esm/utilities/restore-inbound-chunk.js.map +1 -0
- package/dist/esm/utilities/spec-event-keys.d.ts +2 -0
- package/dist/esm/utilities/spec-event-keys.js +56 -0
- package/dist/esm/utilities/spec-event-keys.js.map +1 -0
- package/dist/esm/utilities/structured-output-events.d.ts +3 -3
- package/dist/esm/utilities/structured-output-events.js.map +1 -1
- package/package.json +10 -2
- package/skills/ai-core/chat-experience/SKILL.md +2 -2
- package/src/activities/chat/adapter.ts +4 -4
- package/src/activities/chat/index.ts +398 -400
- package/src/activities/chat/messages.ts +174 -34
- package/src/activities/chat/stream/processor.ts +289 -218
- package/src/activities/chat/tools/tool-calls.ts +23 -22
- package/src/activities/generateVideo/index.ts +7 -6
- package/src/activities/stream-generation-result.ts +8 -12
- package/src/activities/summarize/chat-stream-summarize.ts +94 -70
- package/src/adapter-internals.ts +2 -0
- package/src/byok/define-provider.ts +46 -0
- package/src/byok/errors.ts +36 -0
- package/src/byok/get-key.ts +27 -0
- package/src/byok/missing.ts +43 -0
- package/src/byok/providers.ts +27 -0
- package/src/byok/scrub.ts +16 -0
- package/src/byok/server.ts +3 -0
- package/src/byok.ts +17 -0
- package/src/client.ts +13 -0
- package/src/index.ts +6 -0
- package/src/interrupt-resume.ts +14 -13
- package/src/middlewares/otel.ts +16 -8
- package/src/stream-to-response.ts +11 -4
- package/src/stream-to-websocket.ts +3 -1
- package/src/strip-to-spec-middleware.ts +48 -24
- package/src/types.ts +109 -393
- package/src/utilities/adapter-yield-chunk.ts +30 -0
- package/src/utilities/ag-ui-usage.test.ts +194 -0
- package/src/utilities/ag-ui-usage.ts +148 -0
- package/src/utilities/ag-ui-wire.ts +149 -31
- package/src/utilities/chat-params.ts +22 -39
- package/src/utilities/chunk-ids.ts +24 -0
- package/src/utilities/merge-metadata.test.ts +117 -0
- package/src/utilities/merge-metadata.ts +59 -0
- package/src/utilities/normalize-stream-chunk.test.ts +423 -0
- package/src/utilities/normalize-stream-chunk.ts +186 -0
- package/src/utilities/reasoning-encrypted-value.ts +18 -0
- package/src/utilities/restore-inbound-chunk.test.ts +133 -0
- package/src/utilities/restore-inbound-chunk.ts +72 -0
- package/src/utilities/spec-event-keys.test.ts +34 -0
- package/src/utilities/spec-event-keys.ts +74 -0
- package/src/utilities/structured-output-events.ts +3 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AdapterYieldChunk } from '../../utilities/adapter-yield-chunk.js';
|
|
1
2
|
import { BaseSummarizeAdapter } from './adapter.js';
|
|
2
3
|
import { StreamChunk, SummarizationOptions, SummarizationResult, TextOptions } from '../../types.js';
|
|
3
4
|
/**
|
|
@@ -12,7 +13,7 @@ import { StreamChunk, SummarizationOptions, SummarizationResult, TextOptions } f
|
|
|
12
13
|
* `SummarizationOptions<TProviderOptions>` on the wrapper itself.
|
|
13
14
|
*/
|
|
14
15
|
export interface ChatStreamCapable {
|
|
15
|
-
chatStream: (options: TextOptions<any>) => AsyncIterable<
|
|
16
|
+
chatStream: (options: TextOptions<any>) => AsyncIterable<AdapterYieldChunk>;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
18
19
|
* Extract the per-model `modelOptions` type a text adapter accepts. Used by
|
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
import { toRunErrorPayload } from "../error-payload.js";
|
|
2
|
+
import { rebuildTokenUsage } from "../../utilities/ag-ui-usage.js";
|
|
3
|
+
import { tanstackMetadata } from "../../utilities/merge-metadata.js";
|
|
4
|
+
import { normalizeStreamChunk } from "../../utilities/normalize-stream-chunk.js";
|
|
2
5
|
import { BaseSummarizeAdapter } from "./adapter.js";
|
|
3
6
|
import { MAX_TOKENS_KEYS } from "../../utilities/sampling-keys.js";
|
|
4
7
|
import { EventType } from "@ag-ui/core";
|
|
5
8
|
//#region src/activities/summarize/chat-stream-summarize.ts
|
|
9
|
+
function consumeSpecSummarizeChunk(chunk, state) {
|
|
10
|
+
if (chunk.type === EventType.TEXT_MESSAGE_CONTENT) {
|
|
11
|
+
if (chunk.delta) state.summary += chunk.delta;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const tanstack = tanstackMetadata(chunk);
|
|
15
|
+
if ((chunk.type === EventType.RUN_STARTED || chunk.type === EventType.RUN_FINISHED || chunk.type === EventType.TEXT_MESSAGE_START) && typeof tanstack?.model === "string") state.model = tanstack.model;
|
|
16
|
+
if (chunk.type === EventType.RUN_FINISHED) {
|
|
17
|
+
const rebuilt = rebuildTokenUsage(chunk.usage, tanstack?.usage);
|
|
18
|
+
if (rebuilt) state.usage = rebuilt;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function throwRunError(chunk) {
|
|
22
|
+
const message = typeof chunk.message === "string" && chunk.message.length > 0 ? chunk.message : "Summarization failed";
|
|
23
|
+
const err = new Error(message);
|
|
24
|
+
if (typeof chunk.code === "string") err.code = chunk.code;
|
|
25
|
+
throw err;
|
|
26
|
+
}
|
|
6
27
|
/**
|
|
7
28
|
* Provider-native max-output-tokens key per summarize-adapter `name`. summarize
|
|
8
29
|
* is provider-agnostic and forwards `modelOptions` opaquely to the wrapped text
|
|
@@ -118,35 +139,24 @@ var ChatStreamSummarizeAdapter = class extends BaseSummarizeAdapter {
|
|
|
118
139
|
}
|
|
119
140
|
async summarize(options) {
|
|
120
141
|
const systemPrompt = this.buildSummarizationPrompt(options);
|
|
121
|
-
let summary = "";
|
|
122
142
|
const id = this.generateId();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
143
|
+
const state = {
|
|
144
|
+
summary: "",
|
|
145
|
+
model: options.model,
|
|
146
|
+
usage: {
|
|
147
|
+
promptTokens: 0,
|
|
148
|
+
completionTokens: 0,
|
|
149
|
+
totalTokens: 0
|
|
150
|
+
}
|
|
128
151
|
};
|
|
129
152
|
options.logger.request(`activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? "unset"}`, {
|
|
130
153
|
provider: this.name,
|
|
131
154
|
model: options.model
|
|
132
155
|
});
|
|
133
156
|
try {
|
|
134
|
-
for await (const
|
|
135
|
-
if (chunk.type ===
|
|
136
|
-
|
|
137
|
-
else if (chunk.delta) summary += chunk.delta;
|
|
138
|
-
model = chunk.model || model;
|
|
139
|
-
}
|
|
140
|
-
if (chunk.type === "RUN_FINISHED") {
|
|
141
|
-
if (chunk.usage) usage = chunk.usage;
|
|
142
|
-
}
|
|
143
|
-
if (chunk.type === "RUN_ERROR") {
|
|
144
|
-
const message = (chunk.error && typeof chunk.error.message === "string" ? chunk.error.message : null) ?? "Summarization failed";
|
|
145
|
-
const code = chunk.error && typeof chunk.error.code === "string" ? chunk.error.code : void 0;
|
|
146
|
-
const err = new Error(message);
|
|
147
|
-
if (code) err.code = code;
|
|
148
|
-
throw err;
|
|
149
|
-
}
|
|
157
|
+
for await (const raw of this.textAdapter.chatStream(this.buildTextOptions(options, systemPrompt))) for (const chunk of normalizeStreamChunk(raw)) {
|
|
158
|
+
if (chunk.type === EventType.RUN_ERROR) throwRunError(chunk);
|
|
159
|
+
consumeSpecSummarizeChunk(chunk, state);
|
|
150
160
|
}
|
|
151
161
|
} catch (error) {
|
|
152
162
|
options.logger.errors(`${this.name}.summarize fatal`, {
|
|
@@ -157,9 +167,9 @@ var ChatStreamSummarizeAdapter = class extends BaseSummarizeAdapter {
|
|
|
157
167
|
}
|
|
158
168
|
return {
|
|
159
169
|
id,
|
|
160
|
-
model,
|
|
161
|
-
summary,
|
|
162
|
-
usage
|
|
170
|
+
model: state.model,
|
|
171
|
+
summary: state.summary,
|
|
172
|
+
usage: state.usage
|
|
163
173
|
};
|
|
164
174
|
}
|
|
165
175
|
async *summarizeStream(options) {
|
|
@@ -169,36 +179,29 @@ var ChatStreamSummarizeAdapter = class extends BaseSummarizeAdapter {
|
|
|
169
179
|
model: options.model
|
|
170
180
|
});
|
|
171
181
|
const id = this.generateId();
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
const state = {
|
|
183
|
+
summary: "",
|
|
184
|
+
model: options.model,
|
|
185
|
+
usage: {
|
|
186
|
+
promptTokens: 0,
|
|
187
|
+
completionTokens: 0,
|
|
188
|
+
totalTokens: 0
|
|
189
|
+
}
|
|
178
190
|
};
|
|
179
191
|
try {
|
|
180
|
-
for await (const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
id,
|
|
194
|
-
model,
|
|
195
|
-
summary,
|
|
196
|
-
usage
|
|
197
|
-
},
|
|
198
|
-
model,
|
|
199
|
-
timestamp: Date.now()
|
|
200
|
-
};
|
|
201
|
-
}
|
|
192
|
+
for await (const raw of this.textAdapter.chatStream(this.buildTextOptions(options, systemPrompt))) for (const chunk of normalizeStreamChunk(raw)) {
|
|
193
|
+
consumeSpecSummarizeChunk(chunk, state);
|
|
194
|
+
if (chunk.type === EventType.RUN_FINISHED) yield {
|
|
195
|
+
type: EventType.CUSTOM,
|
|
196
|
+
name: "generation:result",
|
|
197
|
+
value: {
|
|
198
|
+
id,
|
|
199
|
+
model: state.model,
|
|
200
|
+
summary: state.summary,
|
|
201
|
+
usage: state.usage
|
|
202
|
+
},
|
|
203
|
+
timestamp: Date.now()
|
|
204
|
+
};
|
|
202
205
|
yield chunk;
|
|
203
206
|
}
|
|
204
207
|
} catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-stream-summarize.js","names":[],"sources":["../../../../src/activities/summarize/chat-stream-summarize.ts"],"sourcesContent":["import { EventType } from '@ag-ui/core'\nimport { toRunErrorPayload } from '../error-payload'\nimport { MAX_TOKENS_KEYS } from '../../utilities/sampling-keys'\nimport { BaseSummarizeAdapter } from './adapter'\nimport type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n TextOptions,\n} from '../../types'\n\n/**\n * Minimal contract for a text adapter that supports `chatStream`. Lets\n * `ChatStreamSummarizeAdapter` work with any text adapter without coupling\n * to a specific implementation.\n *\n * The provider-options shape is intentionally `any` here — the wrapper only\n * forwards `modelOptions` straight through, so a text adapter with a richer\n * per-model options type (e.g. `ResolveProviderOptions<TModel>`) is still\n * acceptable. Summarize-level type safety is enforced via\n * `SummarizationOptions<TProviderOptions>` on the wrapper itself.\n */\nexport interface ChatStreamCapable {\n chatStream: (options: TextOptions<any>) => AsyncIterable<StreamChunk>\n}\n\n/**\n * Provider-native max-output-tokens key per summarize-adapter `name`. summarize\n * is provider-agnostic and forwards `modelOptions` opaquely to the wrapped text\n * adapter, so `maxLength` must be written under the exact key the underlying\n * provider reads — no adapter reads a generic `maxTokens`. Ollama is the one\n * exception: it nests sampling under `options`, so it has no entry here and is\n * handled as a special nested case in `applyMaxLength`/`applyDefaultTemperature`.\n *\n * Keep in sync with each adapter's wire mapping:\n * - OpenAI (Responses): `max_output_tokens`\n * - Anthropic / Grok: `max_tokens`\n * - Groq: `max_completion_tokens`\n * - Gemini: `maxOutputTokens`\n * - OpenRouter: `maxCompletionTokens`\n * - LLM Gateway: `max_tokens`\n * - Ollama: nested `options.num_predict` (no entry — see `applyMaxLength`)\n */\nconst MAX_TOKENS_KEY_BY_ADAPTER: Record<string, string> = {\n openai: 'max_output_tokens',\n anthropic: 'max_tokens',\n grok: 'max_tokens',\n groq: 'max_completion_tokens',\n gemini: 'maxOutputTokens',\n openrouter: 'maxCompletionTokens',\n // LLM Gateway exposes an OpenAI-compatible Chat Completions surface whose\n // only output cap is `max_tokens` — it does not read `max_completion_tokens`.\n llmgateway: 'max_tokens',\n}\n\n/**\n * Every flat key any supported provider uses to cap output tokens (plus the\n * generic `maxTokens` spelling no adapter reads). Used to detect a\n * caller-supplied token limit so the summarize default never overrides an\n * explicit caller value. Shared with the OTel middleware via\n * `MAX_TOKENS_KEYS` so the two spelling sets cannot drift.\n */\nconst KNOWN_MAX_TOKENS_KEYS = MAX_TOKENS_KEYS\n\n/**\n * Whether `applyMaxLength` knows how to place a token limit for this adapter\n * `name` (either the nested Ollama shape or a flat provider-native key).\n * Used to surface a warning when `maxLength` would otherwise be silently\n * dropped for an unrecognised adapter name.\n */\nfunction isKnownMaxTokensAdapter(adapterName: string): boolean {\n return (\n adapterName === 'ollama' ||\n MAX_TOKENS_KEY_BY_ADAPTER[adapterName] !== undefined\n )\n}\n\n/**\n * Apply the low-temperature summarize default to a working copy of the\n * caller's `modelOptions`, placed where the wrapped provider actually reads\n * it (nested under `options` for Ollama, flat otherwise). The caller always\n * wins: if they already set `temperature` in that location, it is untouched.\n */\nfunction applyDefaultTemperature(\n adapterName: string,\n temperature: number,\n modelOptions: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...modelOptions }\n\n if (adapterName === 'ollama') {\n const existing =\n merged.options && typeof merged.options === 'object'\n ? (merged.options as Record<string, unknown>)\n : undefined\n if (existing && 'temperature' in existing) return merged\n merged.options = { temperature, ...existing }\n return merged\n }\n\n if ('temperature' in merged) return merged\n merged.temperature = temperature\n return merged\n}\n\n/**\n * Resolve `maxLength` to the provider-native max-output-tokens key for the\n * given summarize-adapter `name` (this wrapper's OWN `name`, not the wrapped\n * text adapter's) and merge it into a working copy of the caller's\n * `modelOptions`. The caller always wins: if they already set any recognised\n * token-limit key (flat or, for Ollama, nested `options.num_predict`), the\n * default is left untouched. Unknown/unrecognised adapter names fall back to\n * NOT setting a token key (the prompt hint still asks the model to stay under\n * `maxLength`) rather than writing a dead key no provider reads.\n *\n * Caveat (intentional): \"caller wins\" keys off ANY recognised spelling in\n * `KNOWN_MAX_TOKENS_KEYS`, but only the adapter's native key is read on the\n * wire. So a caller who sets a NON-native spelling for this provider — e.g.\n * `maxTokens`, or Anthropic's `max_tokens` against an OpenAI adapter — suppresses\n * the summarize default WITHOUT getting their own value applied either: neither\n * cap reaches the wire. This favours never clobbering a migration leftover over\n * guaranteeing a cap; the prompt-level hint still asks the model to stay under\n * `maxLength`. Rename the key to the provider-native spelling to forward it.\n */\nfunction applyMaxLength(\n adapterName: string,\n maxLength: number,\n modelOptions: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...modelOptions }\n\n if (adapterName === 'ollama') {\n // Honor a caller-set limit in either shape: a recognised flat key (e.g.\n // left over from a migration) or the nested `options.num_predict`.\n const callerSetFlatLimit = KNOWN_MAX_TOKENS_KEYS.some(\n (k) => typeof merged[k] === 'number',\n )\n const existing =\n merged.options && typeof merged.options === 'object'\n ? (merged.options as Record<string, unknown>)\n : undefined\n if (\n callerSetFlatLimit ||\n (existing && typeof existing.num_predict === 'number')\n ) {\n return merged\n }\n merged.options = { num_predict: maxLength, ...existing }\n return merged\n }\n\n const key = MAX_TOKENS_KEY_BY_ADAPTER[adapterName]\n if (key === undefined) return merged\n\n const callerSetLimit = KNOWN_MAX_TOKENS_KEYS.some(\n (k) => typeof merged[k] === 'number',\n )\n if (callerSetLimit) return merged\n\n merged[key] = maxLength\n return merged\n}\n\n/**\n * Extract the per-model `modelOptions` type a text adapter accepts. Used by\n * provider summarize factories so their `modelOptions` IntelliSense matches\n * what the underlying text adapter actually understands.\n */\nexport type InferTextProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P }\n}\n ? P extends object\n ? P\n : object\n : object\n\n/**\n * Summarize adapter that wraps any `ChatStreamCapable` text adapter and\n * prompts it for summarization. Not tied to any wire format.\n */\nexport class ChatStreamSummarizeAdapter<\n TModel extends string,\n TProviderOptions extends object = Record<string, unknown>,\n> extends BaseSummarizeAdapter<TModel, TProviderOptions> {\n readonly name: string\n\n private readonly textAdapter: ChatStreamCapable\n\n constructor(\n textAdapter: ChatStreamCapable,\n model: TModel,\n name: string = 'chat-stream-summarize',\n ) {\n super({}, model)\n this.name = name\n this.textAdapter = textAdapter\n }\n\n async summarize(\n options: SummarizationOptions<TProviderOptions>,\n ): Promise<SummarizationResult> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n let summary = ''\n const id = this.generateId()\n let model = options.model\n let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 }\n\n options.logger.request(\n `activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n try {\n for await (const chunk of this.textAdapter.chatStream(\n this.buildTextOptions(options, systemPrompt),\n )) {\n if (chunk.type === 'TEXT_MESSAGE_CONTENT') {\n if (chunk.content) {\n summary = chunk.content\n } else if (chunk.delta) {\n // Append delta only when present — a content-less chunk with no\n // delta would otherwise concat literal `'undefined'`.\n summary += chunk.delta\n }\n model = chunk.model || model\n }\n if (chunk.type === 'RUN_FINISHED') {\n if (chunk.usage) {\n usage = chunk.usage\n }\n }\n // Surface failures: the underlying chatStream emits RUN_ERROR instead\n // of throwing, so without this branch summarize() would return an\n // empty summary and pretend a failed run succeeded.\n if (chunk.type === 'RUN_ERROR') {\n const message =\n (chunk.error && typeof chunk.error.message === 'string'\n ? chunk.error.message\n : null) ?? 'Summarization failed'\n const code =\n chunk.error && typeof chunk.error.code === 'string'\n ? chunk.error.code\n : undefined\n const err = new Error(message)\n if (code) {\n ;(err as Error & { code?: string }).code = code\n }\n throw err\n }\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n options.logger.errors(`${this.name}.summarize fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarize failed`),\n source: `${this.name}.summarize`,\n })\n throw error\n }\n\n return { id, model, summary, usage }\n }\n\n override async *summarizeStream(\n options: SummarizationOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n options.logger.request(\n `activity=summarizeStream provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n const id = this.generateId()\n let summary = ''\n let model = options.model\n let usage: SummarizationResult['usage'] = {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n }\n\n try {\n for await (const chunk of this.textAdapter.chatStream(\n this.buildTextOptions(options, systemPrompt),\n )) {\n // Accumulate the same way `summarize()` does so consumers see deltas\n // AND the terminal `generation:result` event below carries the same\n // final summary that non-streaming returns.\n if (chunk.type === 'TEXT_MESSAGE_CONTENT') {\n if (chunk.content) {\n summary = chunk.content\n } else if (chunk.delta) {\n summary += chunk.delta\n }\n if (chunk.model) model = chunk.model\n }\n\n // Emit the GenerationClient-shaped result event just before the\n // terminal RUN_FINISHED so subscribers (useSummarize) populate\n // `result` before flipping `status` to success.\n if (chunk.type === 'RUN_FINISHED') {\n if (chunk.usage) usage = chunk.usage\n if (chunk.model) model = chunk.model\n yield {\n type: EventType.CUSTOM,\n name: 'generation:result',\n value: { id, model, summary, usage } satisfies SummarizationResult,\n model,\n timestamp: Date.now(),\n }\n }\n\n yield chunk\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.summarizeStream fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarizeStream failed`),\n source: `${this.name}.summarizeStream`,\n })\n throw error\n }\n }\n\n /**\n * Build the TextOptions passed to the underlying chatStream. Provider\n * `modelOptions` from the summarize call are forwarded as-is so knobs like\n * Anthropic cache headers, Gemini safety settings, or Ollama tuning params\n * still reach the wire layer.\n */\n protected buildTextOptions(\n options: SummarizationOptions<TProviderOptions>,\n systemPrompt: string,\n ): TextOptions<TProviderOptions> {\n // Sampling knobs now live in provider-native `modelOptions`. Apply the\n // low-temperature default where the wrapped provider actually reads it\n // (nested under `options` for Ollama, flat otherwise) so callers can still\n // override it. Resolving the placement from this summarize adapter's OWN\n // `name` keeps the default off the wire correctly per provider — a flat\n // `temperature` would be silently dropped by Ollama while still showing up\n // in OTel.\n let working: Record<string, unknown> = {\n ...(options.modelOptions as Record<string, unknown> | undefined),\n }\n working = applyDefaultTemperature(this.name, 0.3, working)\n // `maxLength` must reach the wire under the provider-native token key (it\n // differs per provider, and no adapter reads a generic `maxTokens`).\n // Resolve it from this summarize adapter's `name` (the constructor arg,\n // not the wrapped text adapter's name), never overriding a caller-supplied\n // token limit.\n if (options.maxLength !== undefined) {\n if (!isKnownMaxTokensAdapter(this.name)) {\n options.logger.warn(\n `summarize: maxLength=${options.maxLength} could not be mapped to a provider token key for adapter name \"${this.name}\" — it was dropped from modelOptions (the prompt still asks the model to stay under it). Construct ChatStreamSummarizeAdapter with a recognised provider name to forward the cap.`,\n { provider: this.name },\n )\n }\n working = applyMaxLength(this.name, options.maxLength, working)\n }\n const modelOptions = working as TProviderOptions\n\n return {\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n systemPrompts: [systemPrompt],\n modelOptions,\n logger: options.logger,\n // Forward the run identity so the wrapped chat stamps it onto RUN_STARTED\n // (chat uses `runId` as its `runIdOverride`). Conditional spreads keep the\n // fields absent when unset, under `exactOptionalPropertyTypes`.\n ...(options.runId !== undefined ? { runId: options.runId } : {}),\n ...(options.threadId !== undefined ? { threadId: options.threadId } : {}),\n }\n }\n\n protected buildSummarizationPrompt(\n options: SummarizationOptions<TProviderOptions>,\n ): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n case undefined:\n prompt += 'Provide a clear and concise summary. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n if (options.maxLength) {\n prompt += `Keep the summary under ${options.maxLength} tokens. `\n }\n\n return prompt\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat-stream-summarize.js","names":[],"sources":["../../../../src/activities/summarize/chat-stream-summarize.ts"],"sourcesContent":["import { EventType } from '@ag-ui/core'\nimport { toRunErrorPayload } from '../error-payload'\nimport { MAX_TOKENS_KEYS } from '../../utilities/sampling-keys'\nimport { rebuildTokenUsage } from '../../utilities/ag-ui-usage'\nimport type { AdapterYieldChunk } from '../../utilities/adapter-yield-chunk'\nimport { tanstackMetadata } from '../../utilities/merge-metadata'\nimport { normalizeStreamChunk } from '../../utilities/normalize-stream-chunk'\nimport { BaseSummarizeAdapter } from './adapter'\nimport type {\n StreamChunk,\n SummarizationOptions,\n SummarizationResult,\n TextOptions,\n TokenUsage,\n} from '../../types'\n\nfunction consumeSpecSummarizeChunk(\n chunk: StreamChunk,\n state: { summary: string; model: string; usage: TokenUsage },\n): void {\n if (chunk.type === EventType.TEXT_MESSAGE_CONTENT) {\n if (chunk.delta) state.summary += chunk.delta\n return\n }\n\n const tanstack = tanstackMetadata(chunk)\n if (\n (chunk.type === EventType.RUN_STARTED ||\n chunk.type === EventType.RUN_FINISHED ||\n chunk.type === EventType.TEXT_MESSAGE_START) &&\n typeof tanstack?.model === 'string'\n ) {\n state.model = tanstack.model\n }\n\n if (chunk.type === EventType.RUN_FINISHED) {\n const rebuilt = rebuildTokenUsage(chunk.usage, tanstack?.usage)\n if (rebuilt) state.usage = rebuilt\n }\n}\n\nfunction throwRunError(\n chunk: Extract<StreamChunk, { type: 'RUN_ERROR' }>,\n): never {\n const message =\n typeof chunk.message === 'string' && chunk.message.length > 0\n ? chunk.message\n : 'Summarization failed'\n const err = new Error(message)\n if (typeof chunk.code === 'string') {\n ;(err as Error & { code?: string }).code = chunk.code\n }\n throw err\n}\n\n/**\n * Minimal contract for a text adapter that supports `chatStream`. Lets\n * `ChatStreamSummarizeAdapter` work with any text adapter without coupling\n * to a specific implementation.\n *\n * The provider-options shape is intentionally `any` here — the wrapper only\n * forwards `modelOptions` straight through, so a text adapter with a richer\n * per-model options type (e.g. `ResolveProviderOptions<TModel>`) is still\n * acceptable. Summarize-level type safety is enforced via\n * `SummarizationOptions<TProviderOptions>` on the wrapper itself.\n */\nexport interface ChatStreamCapable {\n chatStream: (options: TextOptions<any>) => AsyncIterable<AdapterYieldChunk>\n}\n\n/**\n * Provider-native max-output-tokens key per summarize-adapter `name`. summarize\n * is provider-agnostic and forwards `modelOptions` opaquely to the wrapped text\n * adapter, so `maxLength` must be written under the exact key the underlying\n * provider reads — no adapter reads a generic `maxTokens`. Ollama is the one\n * exception: it nests sampling under `options`, so it has no entry here and is\n * handled as a special nested case in `applyMaxLength`/`applyDefaultTemperature`.\n *\n * Keep in sync with each adapter's wire mapping:\n * - OpenAI (Responses): `max_output_tokens`\n * - Anthropic / Grok: `max_tokens`\n * - Groq: `max_completion_tokens`\n * - Gemini: `maxOutputTokens`\n * - OpenRouter: `maxCompletionTokens`\n * - LLM Gateway: `max_tokens`\n * - Ollama: nested `options.num_predict` (no entry — see `applyMaxLength`)\n */\nconst MAX_TOKENS_KEY_BY_ADAPTER: Record<string, string> = {\n openai: 'max_output_tokens',\n anthropic: 'max_tokens',\n grok: 'max_tokens',\n groq: 'max_completion_tokens',\n gemini: 'maxOutputTokens',\n openrouter: 'maxCompletionTokens',\n // LLM Gateway exposes an OpenAI-compatible Chat Completions surface whose\n // only output cap is `max_tokens` — it does not read `max_completion_tokens`.\n llmgateway: 'max_tokens',\n}\n\n/**\n * Every flat key any supported provider uses to cap output tokens (plus the\n * generic `maxTokens` spelling no adapter reads). Used to detect a\n * caller-supplied token limit so the summarize default never overrides an\n * explicit caller value. Shared with the OTel middleware via\n * `MAX_TOKENS_KEYS` so the two spelling sets cannot drift.\n */\nconst KNOWN_MAX_TOKENS_KEYS = MAX_TOKENS_KEYS\n\n/**\n * Whether `applyMaxLength` knows how to place a token limit for this adapter\n * `name` (either the nested Ollama shape or a flat provider-native key).\n * Used to surface a warning when `maxLength` would otherwise be silently\n * dropped for an unrecognised adapter name.\n */\nfunction isKnownMaxTokensAdapter(adapterName: string): boolean {\n return (\n adapterName === 'ollama' ||\n MAX_TOKENS_KEY_BY_ADAPTER[adapterName] !== undefined\n )\n}\n\n/**\n * Apply the low-temperature summarize default to a working copy of the\n * caller's `modelOptions`, placed where the wrapped provider actually reads\n * it (nested under `options` for Ollama, flat otherwise). The caller always\n * wins: if they already set `temperature` in that location, it is untouched.\n */\nfunction applyDefaultTemperature(\n adapterName: string,\n temperature: number,\n modelOptions: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...modelOptions }\n\n if (adapterName === 'ollama') {\n const existing =\n merged.options && typeof merged.options === 'object'\n ? (merged.options as Record<string, unknown>)\n : undefined\n if (existing && 'temperature' in existing) return merged\n merged.options = { temperature, ...existing }\n return merged\n }\n\n if ('temperature' in merged) return merged\n merged.temperature = temperature\n return merged\n}\n\n/**\n * Resolve `maxLength` to the provider-native max-output-tokens key for the\n * given summarize-adapter `name` (this wrapper's OWN `name`, not the wrapped\n * text adapter's) and merge it into a working copy of the caller's\n * `modelOptions`. The caller always wins: if they already set any recognised\n * token-limit key (flat or, for Ollama, nested `options.num_predict`), the\n * default is left untouched. Unknown/unrecognised adapter names fall back to\n * NOT setting a token key (the prompt hint still asks the model to stay under\n * `maxLength`) rather than writing a dead key no provider reads.\n *\n * Caveat (intentional): \"caller wins\" keys off ANY recognised spelling in\n * `KNOWN_MAX_TOKENS_KEYS`, but only the adapter's native key is read on the\n * wire. So a caller who sets a NON-native spelling for this provider — e.g.\n * `maxTokens`, or Anthropic's `max_tokens` against an OpenAI adapter — suppresses\n * the summarize default WITHOUT getting their own value applied either: neither\n * cap reaches the wire. This favours never clobbering a migration leftover over\n * guaranteeing a cap; the prompt-level hint still asks the model to stay under\n * `maxLength`. Rename the key to the provider-native spelling to forward it.\n */\nfunction applyMaxLength(\n adapterName: string,\n maxLength: number,\n modelOptions: Record<string, unknown>,\n): Record<string, unknown> {\n const merged: Record<string, unknown> = { ...modelOptions }\n\n if (adapterName === 'ollama') {\n // Honor a caller-set limit in either shape: a recognised flat key (e.g.\n // left over from a migration) or the nested `options.num_predict`.\n const callerSetFlatLimit = KNOWN_MAX_TOKENS_KEYS.some(\n (k) => typeof merged[k] === 'number',\n )\n const existing =\n merged.options && typeof merged.options === 'object'\n ? (merged.options as Record<string, unknown>)\n : undefined\n if (\n callerSetFlatLimit ||\n (existing && typeof existing.num_predict === 'number')\n ) {\n return merged\n }\n merged.options = { num_predict: maxLength, ...existing }\n return merged\n }\n\n const key = MAX_TOKENS_KEY_BY_ADAPTER[adapterName]\n if (key === undefined) return merged\n\n const callerSetLimit = KNOWN_MAX_TOKENS_KEYS.some(\n (k) => typeof merged[k] === 'number',\n )\n if (callerSetLimit) return merged\n\n merged[key] = maxLength\n return merged\n}\n\n/**\n * Extract the per-model `modelOptions` type a text adapter accepts. Used by\n * provider summarize factories so their `modelOptions` IntelliSense matches\n * what the underlying text adapter actually understands.\n */\nexport type InferTextProviderOptions<TAdapter> = TAdapter extends {\n '~types': { providerOptions: infer P }\n}\n ? P extends object\n ? P\n : object\n : object\n\n/**\n * Summarize adapter that wraps any `ChatStreamCapable` text adapter and\n * prompts it for summarization. Not tied to any wire format.\n */\nexport class ChatStreamSummarizeAdapter<\n TModel extends string,\n TProviderOptions extends object = Record<string, unknown>,\n> extends BaseSummarizeAdapter<TModel, TProviderOptions> {\n readonly name: string\n\n private readonly textAdapter: ChatStreamCapable\n\n constructor(\n textAdapter: ChatStreamCapable,\n model: TModel,\n name: string = 'chat-stream-summarize',\n ) {\n super({}, model)\n this.name = name\n this.textAdapter = textAdapter\n }\n\n async summarize(\n options: SummarizationOptions<TProviderOptions>,\n ): Promise<SummarizationResult> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n const id = this.generateId()\n const state = {\n summary: '',\n model: options.model,\n usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n }\n\n options.logger.request(\n `activity=summarize provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n try {\n for await (const raw of this.textAdapter.chatStream(\n this.buildTextOptions(options, systemPrompt),\n )) {\n for (const chunk of normalizeStreamChunk(raw as AdapterYieldChunk)) {\n // Surface failures: the underlying chatStream emits RUN_ERROR instead\n // of throwing, so without this branch summarize() would return an\n // empty summary and pretend a failed run succeeded.\n if (chunk.type === EventType.RUN_ERROR) throwRunError(chunk)\n consumeSpecSummarizeChunk(chunk, state)\n }\n }\n } catch (error: unknown) {\n // Narrow before logging: raw SDK errors can carry request metadata\n // (including auth headers) which we must never surface to user loggers.\n options.logger.errors(`${this.name}.summarize fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarize failed`),\n source: `${this.name}.summarize`,\n })\n throw error\n }\n\n return {\n id,\n model: state.model,\n summary: state.summary,\n usage: state.usage,\n }\n }\n\n override async *summarizeStream(\n options: SummarizationOptions<TProviderOptions>,\n ): AsyncIterable<StreamChunk> {\n const systemPrompt = this.buildSummarizationPrompt(options)\n\n options.logger.request(\n `activity=summarizeStream provider=${this.name} model=${options.model} text-length=${options.text.length} maxLength=${options.maxLength ?? 'unset'}`,\n { provider: this.name, model: options.model },\n )\n\n const id = this.generateId()\n const state = {\n summary: '',\n model: options.model,\n usage: {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n } satisfies SummarizationResult['usage'],\n }\n\n try {\n for await (const raw of this.textAdapter.chatStream(\n this.buildTextOptions(options, systemPrompt),\n )) {\n for (const chunk of normalizeStreamChunk(raw as AdapterYieldChunk)) {\n // Accumulate the same way `summarize()` does so consumers see deltas\n // AND the terminal `generation:result` event below carries the same\n // final summary that non-streaming returns.\n consumeSpecSummarizeChunk(chunk, state)\n\n // Emit the GenerationClient-shaped result event just before the\n // terminal RUN_FINISHED so subscribers (useSummarize) populate\n // `result` before flipping `status` to success.\n if (chunk.type === EventType.RUN_FINISHED) {\n yield {\n type: EventType.CUSTOM,\n name: 'generation:result',\n value: {\n id,\n model: state.model,\n summary: state.summary,\n usage: state.usage,\n } satisfies SummarizationResult,\n timestamp: Date.now(),\n }\n }\n\n yield chunk\n }\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.summarizeStream fatal`, {\n error: toRunErrorPayload(error, `${this.name}.summarizeStream failed`),\n source: `${this.name}.summarizeStream`,\n })\n throw error\n }\n }\n\n /**\n * Build the TextOptions passed to the underlying chatStream. Provider\n * `modelOptions` from the summarize call are forwarded as-is so knobs like\n * Anthropic cache headers, Gemini safety settings, or Ollama tuning params\n * still reach the wire layer.\n */\n protected buildTextOptions(\n options: SummarizationOptions<TProviderOptions>,\n systemPrompt: string,\n ): TextOptions<TProviderOptions> {\n // Sampling knobs now live in provider-native `modelOptions`. Apply the\n // low-temperature default where the wrapped provider actually reads it\n // (nested under `options` for Ollama, flat otherwise) so callers can still\n // override it. Resolving the placement from this summarize adapter's OWN\n // `name` keeps the default off the wire correctly per provider — a flat\n // `temperature` would be silently dropped by Ollama while still showing up\n // in OTel.\n let working: Record<string, unknown> = {\n ...(options.modelOptions as Record<string, unknown> | undefined),\n }\n working = applyDefaultTemperature(this.name, 0.3, working)\n // `maxLength` must reach the wire under the provider-native token key (it\n // differs per provider, and no adapter reads a generic `maxTokens`).\n // Resolve it from this summarize adapter's `name` (the constructor arg,\n // not the wrapped text adapter's name), never overriding a caller-supplied\n // token limit.\n if (options.maxLength !== undefined) {\n if (!isKnownMaxTokensAdapter(this.name)) {\n options.logger.warn(\n `summarize: maxLength=${options.maxLength} could not be mapped to a provider token key for adapter name \"${this.name}\" — it was dropped from modelOptions (the prompt still asks the model to stay under it). Construct ChatStreamSummarizeAdapter with a recognised provider name to forward the cap.`,\n { provider: this.name },\n )\n }\n working = applyMaxLength(this.name, options.maxLength, working)\n }\n const modelOptions = working as TProviderOptions\n\n return {\n model: options.model,\n messages: [{ role: 'user', content: options.text }],\n systemPrompts: [systemPrompt],\n modelOptions,\n logger: options.logger,\n // Forward the run identity so the wrapped chat stamps it onto RUN_STARTED\n // (chat uses `runId` as its `runIdOverride`). Conditional spreads keep the\n // fields absent when unset, under `exactOptionalPropertyTypes`.\n ...(options.runId !== undefined ? { runId: options.runId } : {}),\n ...(options.threadId !== undefined ? { threadId: options.threadId } : {}),\n }\n }\n\n protected buildSummarizationPrompt(\n options: SummarizationOptions<TProviderOptions>,\n ): string {\n let prompt = 'You are a professional summarizer. '\n\n switch (options.style) {\n case 'bullet-points':\n prompt += 'Provide a summary in bullet point format. '\n break\n case 'paragraph':\n prompt += 'Provide a summary in paragraph format. '\n break\n case 'concise':\n prompt += 'Provide a very concise summary in 1-2 sentences. '\n break\n case undefined:\n prompt += 'Provide a clear and concise summary. '\n break\n default:\n prompt += 'Provide a clear and concise summary. '\n }\n\n if (options.focus && options.focus.length > 0) {\n prompt += `Focus on the following aspects: ${options.focus.join(', ')}. `\n }\n\n if (options.maxLength) {\n prompt += `Keep the summary under ${options.maxLength} tokens. `\n }\n\n return prompt\n }\n}\n"],"mappings":"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"}
|
|
@@ -15,3 +15,5 @@ export type { PendingInterruptResumeRecord } from './interrupt-resume.js';
|
|
|
15
15
|
export { assertUniqueToolNames, DuplicateToolNameError, } from './activities/chat/tools/unique-tool-names.js';
|
|
16
16
|
export { appendOutputSchemaInstruction, parseJsonFromAssistantText, } from './utilities/structured-output-text.js';
|
|
17
17
|
export { structuredOutputCompleteChunk, structuredOutputStartChunk, } from './utilities/structured-output-events.js';
|
|
18
|
+
export { tanstackMetadata } from './utilities/merge-metadata.js';
|
|
19
|
+
export { isSpecTopLevelKey } from './utilities/spec-event-keys.js';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { toRunErrorPayload, toRunErrorRawEvent } from "./activities/error-payload.js";
|
|
2
|
+
import { tanstackMetadata } from "./utilities/merge-metadata.js";
|
|
3
|
+
import { isSpecTopLevelKey } from "./utilities/spec-event-keys.js";
|
|
2
4
|
import { InternalLogger } from "./logger/internal-logger.js";
|
|
3
5
|
import { resolveDebugOption } from "./logger/resolve.js";
|
|
4
6
|
import { readInterruptBinding, validateInterruptResumeBatch } from "./interrupt-resume.js";
|
|
@@ -10,4 +12,4 @@ import { GenericInterruptDefinitionRegistryCapability, getGenericInterruptDefini
|
|
|
10
12
|
import { PendingTurnCapability, getPendingTurn, providePendingTurn } from "./activities/chat/middleware/pending-turn.js";
|
|
11
13
|
import { appendOutputSchemaInstruction, parseJsonFromAssistantText } from "./utilities/structured-output-text.js";
|
|
12
14
|
import { structuredOutputCompleteChunk, structuredOutputStartChunk } from "./utilities/structured-output-events.js";
|
|
13
|
-
export { DuplicateToolNameError, GenericInterruptDefinitionRegistryCapability, InternalLogger, PendingTurnCapability, RunDisconnectCapability, SandboxRuntimeCapability, appendOutputSchemaInstruction, assertUniqueToolNames, createInterruptBinding, getGenericInterruptDefinitionRegistry, getInterruptRequestInput, getPendingTurn, getRunDisconnect, getSandboxRuntime, parseJsonFromAssistantText, provideGenericInterruptDefinitionRegistry, providePendingTurn, provideRunDisconnect, provideSandboxRuntime, readInterruptBinding, rehydrateInterruptRequest, resolveDebugOption, structuredOutputCompleteChunk, structuredOutputStartChunk, toRunErrorPayload, toRunErrorRawEvent, validateInterruptResumeBatch };
|
|
15
|
+
export { DuplicateToolNameError, GenericInterruptDefinitionRegistryCapability, InternalLogger, PendingTurnCapability, RunDisconnectCapability, SandboxRuntimeCapability, appendOutputSchemaInstruction, assertUniqueToolNames, createInterruptBinding, getGenericInterruptDefinitionRegistry, getInterruptRequestInput, getPendingTurn, getRunDisconnect, getSandboxRuntime, isSpecTopLevelKey, parseJsonFromAssistantText, provideGenericInterruptDefinitionRegistry, providePendingTurn, provideRunDisconnect, provideSandboxRuntime, readInterruptBinding, rehydrateInterruptRequest, resolveDebugOption, structuredOutputCompleteChunk, structuredOutputStartChunk, tanstackMetadata, toRunErrorPayload, toRunErrorRawEvent, validateInterruptResumeBatch };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A BYOK provider declared by an adapter. `id` is the `x-byok-<id>` slug and
|
|
3
|
+
* is required — `{ id?: string }` is not a {@link ByokProvider}.
|
|
4
|
+
*/
|
|
5
|
+
export interface ByokProvider<TId extends string = string> {
|
|
6
|
+
readonly id: TId;
|
|
7
|
+
readonly label: string;
|
|
8
|
+
/**
|
|
9
|
+
* Env var names the relay may read. Names only — never put `process.env`
|
|
10
|
+
* values here. This object is imported on the client.
|
|
11
|
+
*/
|
|
12
|
+
readonly env?: ReadonlyArray<string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Input for {@link defineByokProvider}. `id` cannot be optional: if `TId`
|
|
16
|
+
* includes `undefined`, `id` becomes `never` and the object is unassignable.
|
|
17
|
+
*/
|
|
18
|
+
export type ByokProviderInit<TId extends string> = {
|
|
19
|
+
readonly id: undefined extends TId ? never : TId;
|
|
20
|
+
readonly label: string;
|
|
21
|
+
readonly env?: string | ReadonlyArray<string>;
|
|
22
|
+
};
|
|
23
|
+
export declare function defineByokProvider<const TId extends string>(provider: ByokProviderInit<TId>): ByokProvider<TId>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isProviderId } from "./providers.js";
|
|
2
|
+
//#region src/byok/define-provider.ts
|
|
3
|
+
function normalizeEnv(env) {
|
|
4
|
+
if (env === void 0) return void 0;
|
|
5
|
+
return typeof env === "string" ? [env] : env;
|
|
6
|
+
}
|
|
7
|
+
function defineByokProvider(provider) {
|
|
8
|
+
if (!isProviderId(provider.id)) throw new Error(`Invalid BYOK provider id: ${String(provider.id)}`);
|
|
9
|
+
const env = normalizeEnv(provider.env);
|
|
10
|
+
return {
|
|
11
|
+
id: provider.id,
|
|
12
|
+
label: provider.label,
|
|
13
|
+
...env ? { env } : {}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { defineByokProvider };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=define-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-provider.js","names":[],"sources":["../../../src/byok/define-provider.ts"],"sourcesContent":["import { isProviderId } from './providers'\n\n/**\n * A BYOK provider declared by an adapter. `id` is the `x-byok-<id>` slug and\n * is required — `{ id?: string }` is not a {@link ByokProvider}.\n */\nexport interface ByokProvider<TId extends string = string> {\n readonly id: TId\n readonly label: string\n /**\n * Env var names the relay may read. Names only — never put `process.env`\n * values here. This object is imported on the client.\n */\n readonly env?: ReadonlyArray<string>\n}\n\n/**\n * Input for {@link defineByokProvider}. `id` cannot be optional: if `TId`\n * includes `undefined`, `id` becomes `never` and the object is unassignable.\n */\nexport type ByokProviderInit<TId extends string> = {\n readonly id: undefined extends TId ? never : TId\n readonly label: string\n readonly env?: string | ReadonlyArray<string>\n}\n\nfunction normalizeEnv(\n env: string | ReadonlyArray<string> | undefined,\n): ReadonlyArray<string> | undefined {\n if (env === undefined) return undefined\n return typeof env === 'string' ? [env] : env\n}\n\nexport function defineByokProvider<const TId extends string>(\n provider: ByokProviderInit<TId>,\n): ByokProvider<TId> {\n if (!isProviderId(provider.id)) {\n throw new Error(`Invalid BYOK provider id: ${String(provider.id)}`)\n }\n const env = normalizeEnv(provider.env)\n return {\n id: provider.id,\n label: provider.label,\n ...(env ? { env } : {}),\n }\n}\n"],"mappings":";;AA0BA,SAAS,aACP,KACmC;CACnC,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;CAC9B,OAAO,OAAO,QAAQ,WAAW,CAAC,GAAG,IAAI;AAC3C;AAEA,SAAgB,mBACd,UACmB;CACnB,IAAI,CAAC,aAAa,SAAS,EAAE,GAC3B,MAAM,IAAI,MAAM,6BAA6B,OAAO,SAAS,EAAE,GAAG;CAEpE,MAAM,MAAM,aAAa,SAAS,GAAG;CACrC,OAAO;EACL,IAAI,SAAS;EACb,OAAO,SAAS;EAChB,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;CACvB;AACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ProviderId } from './providers.js';
|
|
2
|
+
export declare class ByokMissingError extends Error {
|
|
3
|
+
readonly provider: ProviderId;
|
|
4
|
+
constructor(provider: ProviderId);
|
|
5
|
+
}
|
|
6
|
+
export declare class ByokBlockedError extends Error {
|
|
7
|
+
readonly provider: ProviderId;
|
|
8
|
+
readonly reason: 'missing' | 'locked';
|
|
9
|
+
constructor(provider: ProviderId, reason: 'missing' | 'locked');
|
|
10
|
+
}
|
|
11
|
+
export declare class ByokUnresolvedProviderError extends Error {
|
|
12
|
+
constructor();
|
|
13
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/byok/errors.ts
|
|
2
|
+
var ByokMissingError = class extends Error {
|
|
3
|
+
provider;
|
|
4
|
+
constructor(provider) {
|
|
5
|
+
super(`Missing ${provider} API key`);
|
|
6
|
+
this.name = "ByokMissingError";
|
|
7
|
+
this.provider = provider;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var ByokBlockedError = class extends Error {
|
|
11
|
+
provider;
|
|
12
|
+
reason;
|
|
13
|
+
constructor(provider, reason) {
|
|
14
|
+
super(reason === "locked" ? `${provider} key is locked` : `Missing ${provider} API key`);
|
|
15
|
+
this.name = "ByokBlockedError";
|
|
16
|
+
this.provider = provider;
|
|
17
|
+
this.reason = reason;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var ByokUnresolvedProviderError = class extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super("BYOK is enabled but no provider slug was resolved. Pass byokProvider or forwardedProps.provider.");
|
|
23
|
+
this.name = "ByokUnresolvedProviderError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { ByokBlockedError, ByokMissingError, ByokUnresolvedProviderError };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../../src/byok/errors.ts"],"sourcesContent":["import type { ProviderId } from './providers'\n\nexport class ByokMissingError extends Error {\n readonly provider: ProviderId\n\n constructor(provider: ProviderId) {\n super(`Missing ${provider} API key`)\n this.name = 'ByokMissingError'\n this.provider = provider\n }\n}\n\nexport class ByokBlockedError extends Error {\n readonly provider: ProviderId\n readonly reason: 'missing' | 'locked'\n\n constructor(provider: ProviderId, reason: 'missing' | 'locked') {\n super(\n reason === 'locked'\n ? `${provider} key is locked`\n : `Missing ${provider} API key`,\n )\n this.name = 'ByokBlockedError'\n this.provider = provider\n this.reason = reason\n }\n}\n\nexport class ByokUnresolvedProviderError extends Error {\n constructor() {\n super(\n 'BYOK is enabled but no provider slug was resolved. Pass byokProvider or forwardedProps.provider.',\n )\n this.name = 'ByokUnresolvedProviderError'\n }\n}\n"],"mappings":";AAEA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CAEA,YAAY,UAAsB;EAChC,MAAM,WAAW,SAAS,SAAS;EACnC,KAAK,OAAO;EACZ,KAAK,WAAW;CAClB;AACF;AAEA,IAAa,mBAAb,cAAsC,MAAM;CAC1C;CACA;CAEA,YAAY,UAAsB,QAA8B;EAC9D,MACE,WAAW,WACP,GAAG,SAAS,kBACZ,WAAW,SAAS,SAC1B;EACA,KAAK,OAAO;EACZ,KAAK,WAAW;EAChB,KAAK,SAAS;CAChB;AACF;AAEA,IAAa,8BAAb,cAAiD,MAAM;CACrD,cAAc;EACZ,MACE,kGACF;EACA,KAAK,OAAO;CACd;AACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ByokProvider } from './define-provider.js';
|
|
2
|
+
import { ProviderId } from './providers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Read a key on the relay. Import from `@tanstack/ai/byok/server` so this
|
|
5
|
+
* `process.env` access is not in the client graph.
|
|
6
|
+
*
|
|
7
|
+
* The header wins. A {@link ByokProvider} then tries `provider.env` in order.
|
|
8
|
+
* A slug is header-only.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getByokKey(request: Request, provider: ProviderId | ByokProvider): string | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { byokHeaderName, resolveProviderId } from "./providers.js";
|
|
2
|
+
//#region src/byok/get-key.ts
|
|
3
|
+
/**
|
|
4
|
+
* Read a key on the relay. Import from `@tanstack/ai/byok/server` so this
|
|
5
|
+
* `process.env` access is not in the client graph.
|
|
6
|
+
*
|
|
7
|
+
* The header wins. A {@link ByokProvider} then tries `provider.env` in order.
|
|
8
|
+
* A slug is header-only.
|
|
9
|
+
*/
|
|
10
|
+
function getByokKey(request, provider) {
|
|
11
|
+
const value = request.headers.get(byokHeaderName(resolveProviderId(provider)));
|
|
12
|
+
if (typeof value === "string") {
|
|
13
|
+
const trimmed = value.trim();
|
|
14
|
+
if (trimmed.length > 0) return trimmed;
|
|
15
|
+
}
|
|
16
|
+
if (typeof provider === "string") return null;
|
|
17
|
+
for (const name of provider.env ?? []) {
|
|
18
|
+
const envValue = process.env[name];
|
|
19
|
+
if (typeof envValue === "string" && envValue.length > 0) return envValue;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { getByokKey };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=get-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-key.js","names":[],"sources":["../../../src/byok/get-key.ts"],"sourcesContent":["import { byokHeaderName, resolveProviderId } from './providers'\nimport type { ByokProvider } from './define-provider'\nimport type { ProviderId } from './providers'\n\n/**\n * Read a key on the relay. Import from `@tanstack/ai/byok/server` so this\n * `process.env` access is not in the client graph.\n *\n * The header wins. A {@link ByokProvider} then tries `provider.env` in order.\n * A slug is header-only.\n */\nexport function getByokKey(\n request: Request,\n provider: ProviderId | ByokProvider,\n): string | null {\n const value = request.headers.get(byokHeaderName(resolveProviderId(provider)))\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed.length > 0) return trimmed\n }\n if (typeof provider === 'string') return null\n for (const name of provider.env ?? []) {\n const envValue = process.env[name]\n if (typeof envValue === 'string' && envValue.length > 0) return envValue\n }\n return null\n}\n"],"mappings":";;;;;;;;;AAWA,SAAgB,WACd,SACA,UACe;CACf,MAAM,QAAQ,QAAQ,QAAQ,IAAI,eAAe,kBAAkB,QAAQ,CAAC,CAAC;CAC7E,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,UAAU,MAAM,KAAK;EAC3B,IAAI,QAAQ,SAAS,GAAG,OAAO;CACjC;CACA,IAAI,OAAO,aAAa,UAAU,OAAO;CACzC,KAAK,MAAM,QAAQ,SAAS,OAAO,CAAC,GAAG;EACrC,MAAM,WAAW,QAAQ,IAAI;EAC7B,IAAI,OAAO,aAAa,YAAY,SAAS,SAAS,GAAG,OAAO;CAClE;CACA,OAAO;AACT"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ByokProvider } from './define-provider.js';
|
|
2
|
+
import { ProviderId } from './providers.js';
|
|
3
|
+
export interface ByokMissingBody {
|
|
4
|
+
error: {
|
|
5
|
+
type: 'byok_missing';
|
|
6
|
+
provider: ProviderId;
|
|
7
|
+
message: string;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare function isByokMissingBody(value: unknown): value is ByokMissingBody;
|
|
11
|
+
export declare function byokMissing(provider: ProviderId | ByokProvider): Response;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isProviderId, resolveProviderId } from "./providers.js";
|
|
2
|
+
//#region src/byok/missing.ts
|
|
3
|
+
function isByokMissingBody(value) {
|
|
4
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5
|
+
if (!("error" in value)) return false;
|
|
6
|
+
const error = value.error;
|
|
7
|
+
if (typeof error !== "object" || error === null) return false;
|
|
8
|
+
if (!("type" in error) || error.type !== "byok_missing") return false;
|
|
9
|
+
if (!("provider" in error) || typeof error.provider !== "string") return false;
|
|
10
|
+
if (!isProviderId(error.provider)) return false;
|
|
11
|
+
if (!("message" in error) || typeof error.message !== "string") return false;
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
function byokMissing(provider) {
|
|
15
|
+
const id = resolveProviderId(provider);
|
|
16
|
+
if (!isProviderId(id)) throw new Error(`Invalid BYOK provider id: ${id}`);
|
|
17
|
+
const body = { error: {
|
|
18
|
+
type: "byok_missing",
|
|
19
|
+
provider: id,
|
|
20
|
+
message: `Missing ${id} API key`
|
|
21
|
+
} };
|
|
22
|
+
return new Response(JSON.stringify(body), {
|
|
23
|
+
status: 401,
|
|
24
|
+
headers: { "content-type": "application/json" }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { byokMissing, isByokMissingBody };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=missing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing.js","names":[],"sources":["../../../src/byok/missing.ts"],"sourcesContent":["import { isProviderId, resolveProviderId } from './providers'\nimport type { ByokProvider } from './define-provider'\nimport type { ProviderId } from './providers'\n\nexport interface ByokMissingBody {\n error: {\n type: 'byok_missing'\n provider: ProviderId\n message: string\n }\n}\n\nexport function isByokMissingBody(value: unknown): value is ByokMissingBody {\n if (typeof value !== 'object' || value === null) return false\n if (!('error' in value)) return false\n const error = value.error\n if (typeof error !== 'object' || error === null) return false\n if (!('type' in error) || error.type !== 'byok_missing') return false\n if (!('provider' in error) || typeof error.provider !== 'string') {\n return false\n }\n if (!isProviderId(error.provider)) return false\n if (!('message' in error) || typeof error.message !== 'string') return false\n return true\n}\n\nexport function byokMissing(provider: ProviderId | ByokProvider): Response {\n const id = resolveProviderId(provider)\n if (!isProviderId(id)) {\n throw new Error(`Invalid BYOK provider id: ${id}`)\n }\n const body: ByokMissingBody = {\n error: {\n type: 'byok_missing',\n provider: id,\n message: `Missing ${id} API key`,\n },\n }\n return new Response(JSON.stringify(body), {\n status: 401,\n headers: { 'content-type': 'application/json' },\n })\n}\n"],"mappings":";;AAYA,SAAgB,kBAAkB,OAA0C;CAC1E,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,IAAI,EAAE,WAAW,QAAQ,OAAO;CAChC,MAAM,QAAQ,MAAM;CACpB,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,IAAI,EAAE,UAAU,UAAU,MAAM,SAAS,gBAAgB,OAAO;CAChE,IAAI,EAAE,cAAc,UAAU,OAAO,MAAM,aAAa,UACtD,OAAO;CAET,IAAI,CAAC,aAAa,MAAM,QAAQ,GAAG,OAAO;CAC1C,IAAI,EAAE,aAAa,UAAU,OAAO,MAAM,YAAY,UAAU,OAAO;CACvE,OAAO;AACT;AAEA,SAAgB,YAAY,UAA+C;CACzE,MAAM,KAAK,kBAAkB,QAAQ;CACrC,IAAI,CAAC,aAAa,EAAE,GAClB,MAAM,IAAI,MAAM,6BAA6B,IAAI;CAEnD,MAAM,OAAwB,EAC5B,OAAO;EACL,MAAM;EACN,UAAU;EACV,SAAS,WAAW,GAAG;CACzB,EACF;CACA,OAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;EACxC,QAAQ;EACR,SAAS,EAAE,gBAAgB,mBAAmB;CAChD,CAAC;AACH"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider ids are open slugs, not a closed catalog. `@tanstack/ai` does not
|
|
3
|
+
* list adapters. Any matching string is a valid id and becomes `x-byok-<id>`.
|
|
4
|
+
*/
|
|
5
|
+
export type ProviderId = string;
|
|
6
|
+
/** `[a-z][a-z0-9-]{0,63}` — lowercase, no underscores, max 64 chars. */
|
|
7
|
+
export declare const BYOK_PROVIDER_ID_PATTERN: RegExp;
|
|
8
|
+
export declare const BYOK_HEADER_PREFIX = "x-byok-";
|
|
9
|
+
export declare function isProviderId(value: unknown): value is ProviderId;
|
|
10
|
+
export declare function resolveProviderId(provider: string | {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function byokHeaderName(provider: string): string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/byok/providers.ts
|
|
2
|
+
/** `[a-z][a-z0-9-]{0,63}` — lowercase, no underscores, max 64 chars. */
|
|
3
|
+
var BYOK_PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
|
|
4
|
+
var BYOK_HEADER_PREFIX = "x-byok-";
|
|
5
|
+
function isProviderId(value) {
|
|
6
|
+
return typeof value === "string" && BYOK_PROVIDER_ID_PATTERN.test(value);
|
|
7
|
+
}
|
|
8
|
+
function resolveProviderId(provider) {
|
|
9
|
+
return typeof provider === "string" ? provider : provider.id;
|
|
10
|
+
}
|
|
11
|
+
function byokHeaderName(provider) {
|
|
12
|
+
if (!isProviderId(provider)) throw new Error(`Invalid BYOK provider id: ${provider}`);
|
|
13
|
+
return `${BYOK_HEADER_PREFIX}${provider}`;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { BYOK_HEADER_PREFIX, BYOK_PROVIDER_ID_PATTERN, byokHeaderName, isProviderId, resolveProviderId };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","names":[],"sources":["../../../src/byok/providers.ts"],"sourcesContent":["/**\n * Provider ids are open slugs, not a closed catalog. `@tanstack/ai` does not\n * list adapters. Any matching string is a valid id and becomes `x-byok-<id>`.\n */\nexport type ProviderId = string\n\n/** `[a-z][a-z0-9-]{0,63}` — lowercase, no underscores, max 64 chars. */\nexport const BYOK_PROVIDER_ID_PATTERN = /^[a-z][a-z0-9-]{0,63}$/\n\nexport const BYOK_HEADER_PREFIX = 'x-byok-'\n\nexport function isProviderId(value: unknown): value is ProviderId {\n return typeof value === 'string' && BYOK_PROVIDER_ID_PATTERN.test(value)\n}\n\nexport function resolveProviderId(\n provider: string | { readonly id: string },\n): string {\n return typeof provider === 'string' ? provider : provider.id\n}\n\nexport function byokHeaderName(provider: string): string {\n if (!isProviderId(provider)) {\n throw new Error(`Invalid BYOK provider id: ${provider}`)\n }\n return `${BYOK_HEADER_PREFIX}${provider}`\n}\n"],"mappings":";;AAOA,IAAa,2BAA2B;AAExC,IAAa,qBAAqB;AAElC,SAAgB,aAAa,OAAqC;CAChE,OAAO,OAAO,UAAU,YAAY,yBAAyB,KAAK,KAAK;AACzE;AAEA,SAAgB,kBACd,UACQ;CACR,OAAO,OAAO,aAAa,WAAW,WAAW,SAAS;AAC5D;AAEA,SAAgB,eAAe,UAA0B;CACvD,IAAI,CAAC,aAAa,QAAQ,GACxB,MAAM,IAAI,MAAM,6BAA6B,UAAU;CAEzD,OAAO,GAAG,qBAAqB;AACjC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/byok/scrub.ts
|
|
2
|
+
function maskKey(key) {
|
|
3
|
+
if (key.length <= 4) return "••";
|
|
4
|
+
return key.slice(-4);
|
|
5
|
+
}
|
|
6
|
+
function scrubSecrets(input, secrets) {
|
|
7
|
+
let next = input;
|
|
8
|
+
for (const secret of secrets) {
|
|
9
|
+
if (secret.length === 0) continue;
|
|
10
|
+
next = next.split(secret).join("[redacted]");
|
|
11
|
+
}
|
|
12
|
+
return next;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { maskKey, scrubSecrets };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=scrub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrub.js","names":[],"sources":["../../../src/byok/scrub.ts"],"sourcesContent":["export function maskKey(key: string): string {\n if (key.length <= 4) return '••'\n return key.slice(-4)\n}\n\nexport function scrubSecrets(\n input: string,\n secrets: ReadonlyArray<string>,\n): string {\n let next = input\n for (const secret of secrets) {\n if (secret.length === 0) continue\n next = next.split(secret).join('[redacted]')\n }\n return next\n}\n"],"mappings":";AAAA,SAAgB,QAAQ,KAAqB;CAC3C,IAAI,IAAI,UAAU,GAAG,OAAO;CAC5B,OAAO,IAAI,MAAM,EAAE;AACrB;AAEA,SAAgB,aACd,OACA,SACQ;CACR,IAAI,OAAO;CACX,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,OAAO,WAAW,GAAG;EACzB,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,KAAK,YAAY;CAC7C;CACA,OAAO;AACT"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { BYOK_PROVIDER_ID_PATTERN, BYOK_HEADER_PREFIX, byokHeaderName, isProviderId, } from './byok/providers.js';
|
|
2
|
+
export type { ProviderId } from './byok/providers.js';
|
|
3
|
+
export { defineByokProvider } from './byok/define-provider.js';
|
|
4
|
+
export type { ByokProvider, ByokProviderInit } from './byok/define-provider.js';
|
|
5
|
+
export { isByokMissingBody, byokMissing } from './byok/missing.js';
|
|
6
|
+
export type { ByokMissingBody } from './byok/missing.js';
|
|
7
|
+
export { ByokMissingError, ByokBlockedError, ByokUnresolvedProviderError, } from './byok/errors.js';
|
|
8
|
+
export { maskKey, scrubSecrets } from './byok/scrub.js';
|
package/dist/esm/byok.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BYOK_HEADER_PREFIX, BYOK_PROVIDER_ID_PATTERN, byokHeaderName, isProviderId } from "./byok/providers.js";
|
|
2
|
+
import { defineByokProvider } from "./byok/define-provider.js";
|
|
3
|
+
import { byokMissing, isByokMissingBody } from "./byok/missing.js";
|
|
4
|
+
import { ByokBlockedError, ByokMissingError, ByokUnresolvedProviderError } from "./byok/errors.js";
|
|
5
|
+
import { maskKey, scrubSecrets } from "./byok/scrub.js";
|
|
6
|
+
export { BYOK_HEADER_PREFIX, BYOK_PROVIDER_ID_PATTERN, ByokBlockedError, ByokMissingError, ByokUnresolvedProviderError, byokHeaderName, byokMissing, defineByokProvider, isByokMissingBody, isProviderId, maskKey, scrubSecrets };
|
package/dist/esm/client.d.ts
CHANGED
|
@@ -58,8 +58,15 @@ export { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMess
|
|
|
58
58
|
export { BatchStrategy, CompositeStrategy, defaultJSONParser, ImmediateStrategy, parsePartialJSON, PartialJSONParser, PunctuationStrategy, StreamProcessor, WordBoundaryStrategy, } from './activities/chat/stream/index.js';
|
|
59
59
|
export type { ChunkRecording, ChunkStrategy, InternalToolCallState, JSONParser, ProcessorResult, ProcessorState, StreamProcessorEvents, StreamProcessorOptions, ToolCallState, ToolResultState, } from './activities/chat/stream/index.js';
|
|
60
60
|
export { uiMessagesToWire } from './utilities/ag-ui-wire.js';
|
|
61
|
+
export { mergeMetadata, tanstackMetadata, withTanstackMetadata, } from './utilities/merge-metadata.js';
|
|
62
|
+
export { fromSpecTokenUsage, toSpecTokenUsage } from './utilities/ag-ui-usage.js';
|
|
63
|
+
export type { SpecTokenUsage } from './utilities/ag-ui-usage.js';
|
|
64
|
+
export { normalizeStreamChunk } from './utilities/normalize-stream-chunk.js';
|
|
65
|
+
export { restoreInboundChunk } from './utilities/restore-inbound-chunk.js';
|
|
66
|
+
export type { AdapterYieldChunk } from './utilities/adapter-yield-chunk.js';
|
|
67
|
+
export { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids.js';
|
|
61
68
|
export type { WireMessage } from './utilities/ag-ui-wire.js';
|
|
62
|
-
export type { AudioPart, ContentPart, ContentPartDataSource, ContentPartSource, ContentPartUrlSource, CustomEvent, DocumentPart, ImagePart, MediaInputMetadata, MediaInputRole, MediaPrompt, MediaPromptPart, MessagePart, ModelMessage, PersistedArtifactActivity, PersistedArtifactRef, PersistedArtifactRole, Interrupt, RunAgentResumeItem, RunErrorEvent, RunFinishedEvent, RunFinishedOutcome, SchemaInput, StreamChunk, StructuredOutputPart, TextPart, ThinkingPart, ToolCall, ToolCallPart, ToolResultPart, UIMessage, UIResourcePart, VideoPart, InferSchemaType, } from './types.js';
|
|
69
|
+
export type { AudioPart, ContentPart, ContentPartDataSource, ContentPartSource, ContentPartUrlSource, CustomEvent, DocumentPart, ImagePart, MediaInputMetadata, MediaInputRole, MediaPrompt, MediaPromptPart, MessagePart, ModelMessage, PersistedArtifactActivity, PersistedArtifactRef, PersistedArtifactRole, Interrupt, RunAgentResumeItem, RunErrorEvent, RunFinishedEvent, RunFinishedOutcome, SchemaInput, StreamChunk, StructuredOutputPart, TextPart, TanStackMessageMetadata, TanStackRunMetadata, ThinkingPart, ToolCall, ToolCallPart, ToolResultPart, UIMessage, UIResourcePart, VideoPart, InferSchemaType, } from './types.js';
|
|
63
70
|
export { INTERRUPT_BINDING_VERSION, canonicalizeInterruptResolutions, } from './interrupts.js';
|
|
64
71
|
export { defineInterrupt, hashInterruptDefinitionSchema, INTERRUPT_PAYLOAD_METADATA_KEY, } from './interrupt-definition.js';
|
|
65
72
|
export { INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, genericInterruptContinuationFromDescriptor, readGenericInterruptContinuation, wrapGenericInterruptContinuation, } from './generic-interrupt-continuation.js';
|