@langchain/core 1.1.43 → 1.1.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/language_models/base.cjs +1 -1
- package/dist/language_models/base.js +1 -1
- package/dist/language_models/stream.cjs +43 -1
- package/dist/language_models/stream.cjs.map +1 -1
- package/dist/language_models/stream.d.cts.map +1 -1
- package/dist/language_models/stream.d.ts.map +1 -1
- package/dist/language_models/stream.js +43 -1
- package/dist/language_models/stream.js.map +1 -1
- package/dist/load/index.cjs +19 -0
- package/dist/load/index.cjs.map +1 -1
- package/dist/load/index.d.cts +4 -0
- package/dist/load/index.d.cts.map +1 -1
- package/dist/load/index.d.ts +4 -0
- package/dist/load/index.d.ts.map +1 -1
- package/dist/load/index.js +19 -0
- package/dist/load/index.js.map +1 -1
- package/dist/runnables/base.cjs +3 -0
- package/dist/runnables/base.cjs.map +1 -1
- package/dist/runnables/base.d.cts +43 -0
- package/dist/runnables/base.d.cts.map +1 -1
- package/dist/runnables/base.d.ts +43 -0
- package/dist/runnables/base.d.ts.map +1 -1
- package/dist/runnables/base.js +3 -0
- package/dist/runnables/base.js.map +1 -1
- package/dist/runnables/history.cjs +3 -0
- package/dist/runnables/history.cjs.map +1 -1
- package/dist/runnables/history.d.cts +3 -0
- package/dist/runnables/history.d.cts.map +1 -1
- package/dist/runnables/history.d.ts +3 -0
- package/dist/runnables/history.d.ts.map +1 -1
- package/dist/runnables/history.js +3 -0
- package/dist/runnables/history.js.map +1 -1
- package/dist/utils/env.cjs.map +1 -1
- package/dist/utils/env.d.cts.map +1 -1
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @langchain/core
|
|
2
2
|
|
|
3
|
+
## 1.1.45
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#10833](https://github.com/langchain-ai/langchainjs/pull/10833) [`6cf39fe`](https://github.com/langchain-ai/langchainjs/commit/6cf39fe9636804f6280db0b98c4a4c72d5b103a0) Thanks [@colifran](https://github.com/colifran)! - chore(core): deprecate streamLog, streamEvents v1, RunnableWithMessageHistory and improve threat model verbiage for loads
|
|
8
|
+
|
|
9
|
+
- [#10835](https://github.com/langchain-ai/langchainjs/pull/10835) [`0aebe50`](https://github.com/langchain-ai/langchainjs/commit/0aebe5054cfb982f09d9775b017317a731b6576f) Thanks [@colifran](https://github.com/colifran)! - fix(core): deno re-declaration in LangSmith is causing unit test failures
|
|
10
|
+
|
|
11
|
+
## 1.1.44
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#10822](https://github.com/langchain-ai/langchainjs/pull/10822) [`922a040`](https://github.com/langchain-ai/langchainjs/commit/922a040421391700fd92e04e6f44a37e3f24710b) Thanks [@christian-bromann](https://github.com/christian-bromann)! - fix(core): translate content block delta for other models
|
|
16
|
+
|
|
3
17
|
## 1.1.43
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -139,7 +139,7 @@ var BaseLangChain = class extends require_base.Runnable {
|
|
|
139
139
|
this.callbacks = params.callbacks;
|
|
140
140
|
this.tags = params.tags ?? [];
|
|
141
141
|
this.metadata = params.metadata ?? {};
|
|
142
|
-
this._addVersion("@langchain/core", "1.1.
|
|
142
|
+
this._addVersion("@langchain/core", "1.1.45");
|
|
143
143
|
}
|
|
144
144
|
_addVersion(pkg, version) {
|
|
145
145
|
const existing = this.metadata?.versions;
|
|
@@ -138,7 +138,7 @@ var BaseLangChain = class extends Runnable {
|
|
|
138
138
|
this.callbacks = params.callbacks;
|
|
139
139
|
this.tags = params.tags ?? [];
|
|
140
140
|
this.metadata = params.metadata ?? {};
|
|
141
|
-
this._addVersion("@langchain/core", "1.1.
|
|
141
|
+
this._addVersion("@langchain/core", "1.1.45");
|
|
142
142
|
}
|
|
143
143
|
_addVersion(pkg, version) {
|
|
144
144
|
const existing = this.metadata?.versions;
|
|
@@ -108,9 +108,51 @@ function applyDelta(block, delta) {
|
|
|
108
108
|
default: throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns the typed delta carried by a content-block delta event.
|
|
113
|
+
*
|
|
114
|
+
* Stream protocol compliant language models store incremental updates in
|
|
115
|
+
* `event.delta`, e.g. `{ type: "text-delta", text: "hello" }`. Some models and
|
|
116
|
+
* adapters still emit the older content-shaped form on `event.content`, e.g.
|
|
117
|
+
* `{ type: "text", text: "hello" }`, which predates explicit delta event
|
|
118
|
+
* variants.
|
|
119
|
+
*
|
|
120
|
+
* Keep accepting that content-shaped form here so {@link ChatModelStream}
|
|
121
|
+
* remains a tolerant consumer while producers migrate to protocol compliant
|
|
122
|
+
* typed deltas.
|
|
123
|
+
*
|
|
124
|
+
* @internal
|
|
125
|
+
*/
|
|
111
126
|
function getEventDelta(event) {
|
|
112
127
|
if (event.event !== "content-block-delta") return void 0;
|
|
113
|
-
return event.delta;
|
|
128
|
+
if ("delta" in event && event.delta) return event.delta;
|
|
129
|
+
const content = event.content;
|
|
130
|
+
if (content == null || typeof content !== "object") return void 0;
|
|
131
|
+
const block = content;
|
|
132
|
+
if (block.type === "text" && typeof block.text === "string") return {
|
|
133
|
+
type: "text-delta",
|
|
134
|
+
text: block.text
|
|
135
|
+
};
|
|
136
|
+
if (block.type === "reasoning" && typeof block.reasoning === "string") return {
|
|
137
|
+
type: "reasoning-delta",
|
|
138
|
+
reasoning: block.reasoning
|
|
139
|
+
};
|
|
140
|
+
if (block.type === "thinking" && typeof block.thinking === "string") return {
|
|
141
|
+
type: "reasoning-delta",
|
|
142
|
+
reasoning: block.thinking
|
|
143
|
+
};
|
|
144
|
+
if (typeof block.data === "string") return {
|
|
145
|
+
type: "data-delta",
|
|
146
|
+
data: block.data,
|
|
147
|
+
encoding: "base64"
|
|
148
|
+
};
|
|
149
|
+
if (typeof block.type === "string") return {
|
|
150
|
+
type: "block-delta",
|
|
151
|
+
fields: {
|
|
152
|
+
...block,
|
|
153
|
+
type: block.type
|
|
154
|
+
}
|
|
155
|
+
};
|
|
114
156
|
}
|
|
115
157
|
function getReasoningDelta(content) {
|
|
116
158
|
if (content == null || typeof content !== "object") return void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.cjs","names":["AIMessage"],"sources":["../../src/language_models/stream.ts"],"sourcesContent":["/**\n * Typed stream classes for chat model streaming.\n *\n * @module\n */\n\nimport { AIMessage } from \"../messages/ai.js\";\nimport type { ContentBlock } from \"../messages/content/index.js\";\nimport type { UsageMetadata } from \"../messages/metadata.js\";\nimport type { ChatModelStreamEvent, ContentBlockDelta } from \"./event.js\";\n\ntype UsageMetadataLike = Partial<UsageMetadata>;\n\n/**\n * A buffer that caches emitted events for replay.\n *\n * Multiple consumers can independently iterate the same buffer —\n * each gets its own cursor. Events are never consumed or removed.\n *\n * @internal\n */\nclass ReplayBuffer {\n private events: ChatModelStreamEvent[] = [];\n private finished = false;\n private waiters: Array<() => void> = [];\n private error: Error | null = null;\n\n push(event: ChatModelStreamEvent): void {\n this.events.push(event);\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n finish(): void {\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n setError(err: Error): void {\n this.error = err;\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n async *iterate(): AsyncGenerator<ChatModelStreamEvent> {\n if (this.finished) {\n if (this.error) throw this.error;\n yield* this.events;\n return;\n }\n\n let cursor = 0;\n while (true) {\n while (cursor < this.events.length) {\n yield this.events[cursor]!;\n cursor++;\n }\n if (this.finished) {\n if (this.error) throw this.error;\n return;\n }\n await new Promise<void>((resolve) => {\n if (cursor < this.events.length || this.finished) {\n resolve();\n return;\n }\n this.waiters.push(resolve);\n });\n }\n }\n}\n\n/**\n * Apply a typed delta to an accumulated content block.\n *\n * - `text-delta` → append text\n * - `reasoning-delta` → append reasoning text\n * - `data-delta` → append encoded data to `data`\n * - `block-delta` → shallow merge fields\n *\n * @internal\n */\nfunction applyDelta(\n block: ContentBlock,\n delta: ContentBlockDelta\n): ContentBlock {\n switch (delta.type) {\n case \"text-delta\":\n if (block.type === \"text\") {\n return {\n ...block,\n text: (block.text ?? \"\") + delta.text,\n };\n }\n return block;\n case \"reasoning-delta\":\n if (block.type === \"thinking\") {\n return {\n ...block,\n thinking: (block.thinking ?? \"\") + delta.reasoning,\n };\n }\n if (block.type === \"reasoning\") {\n return {\n ...block,\n reasoning: (block.reasoning ?? \"\") + delta.reasoning,\n };\n }\n return block;\n case \"data-delta\":\n return {\n ...block,\n data: (block.data ?? \"\") + delta.data,\n };\n case \"block-delta\":\n return { ...block, ...delta.fields } as ContentBlock;\n default:\n throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);\n }\n}\n\nfunction getEventDelta(\n event: ChatModelStreamEvent\n): ContentBlockDelta | undefined {\n if (event.event !== \"content-block-delta\") return undefined;\n return event.delta;\n}\n\nfunction getReasoningDelta(content: unknown): string | undefined {\n if (content == null || typeof content !== \"object\") return undefined;\n const block = content as {\n type?: string;\n reasoning?: unknown;\n thinking?: unknown;\n };\n if (block.type === \"reasoning\" && typeof block.reasoning === \"string\") {\n return block.reasoning;\n }\n if (block.type === \"thinking\" && typeof block.thinking === \"string\") {\n return block.thinking;\n }\n return undefined;\n}\n\nfunction isReasoningContent(content: unknown): boolean {\n if (content == null || typeof content !== \"object\") return false;\n const type = (content as { type?: unknown }).type;\n return type === \"reasoning\" || type === \"thinking\";\n}\n\n/**\n * Normalize protocol-compatible partial usage into Core's concrete usage shape.\n *\n * Some stream sources emit usage snapshots without every aggregate token field.\n * Keep the stream event input permissive, then normalize at read time so\n * high-level Core consumers always receive a complete {@link UsageMetadata}.\n */\nfunction normalizeUsage(\n usage: UsageMetadataLike | undefined\n): UsageMetadata | undefined {\n if (!usage) return undefined;\n return {\n ...usage,\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n };\n}\n\nfunction parseToolArgs(value: unknown): Record<string, unknown> {\n if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value !== \"string\" || value.length === 0) return {};\n try {\n const parsed = JSON.parse(value);\n return parsed != null &&\n typeof parsed === \"object\" &&\n !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\nfunction standardizeToolBlock(block: ContentBlock): ContentBlock {\n const record = block as Record<string, unknown>;\n if (block.type === \"tool_call\") return block;\n if (\n block.type !== \"tool_call_chunk\" &&\n block.type !== \"tool_use\" &&\n block.type !== \"input_json_delta\"\n ) {\n return block;\n }\n\n const name = typeof record.name === \"string\" ? record.name : undefined;\n if (name == null) return block;\n\n const args = record.args ?? record.input;\n return {\n ...record,\n type: \"tool_call\",\n name,\n args: parseToolArgs(args),\n } as ContentBlock;\n}\n\n// ─── Sub-Stream: Text ───────────────────────────────────────────\n\n/**\n * Typed stream for text content.\n *\n * - **Iterate**: yields incremental text deltas.\n * - **Await**: resolves to the complete concatenated text.\n * - **`.full`**: yields the running accumulated text after each delta.\n */\nexport class TextContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n /** Yields the accumulated text so far after each delta. */\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n accumulated += delta.text;\n yield accumulated;\n }\n }\n },\n };\n }\n\n /** Yields incremental text deltas. */\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n yield delta.text;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Tool Calls ─────────────────────────────────────\n\n/**\n * Typed stream for tool calls.\n *\n * - **Iterate**: yields individual `ToolCall` objects as each completes.\n * - **Await**: resolves to the full array.\n * - **`.full`**: yields the accumulated array after each new tool call.\n */\nexport class ToolCallsStream\n implements\n AsyncIterable<ContentBlock.Tools.ToolCall>,\n PromiseLike<Array<ContentBlock.Tools.ToolCall>>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<Array<ContentBlock.Tools.ToolCall>> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n calls.push(event.content as ContentBlock.Tools.ToolCall);\n yield [...calls];\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ContentBlock.Tools.ToolCall> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n yield event.content as ContentBlock.Tools.ToolCall;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = Array<ContentBlock.Tools.ToolCall>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Array<ContentBlock.Tools.ToolCall>\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const call of this) {\n calls.push(call);\n }\n return calls;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Reasoning ──────────────────────────────────────\n\n/**\n * Typed stream for reasoning content (chain-of-thought).\n * Same interface as {@link TextContentStream} but for reasoning blocks.\n */\nexport class ReasoningContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta != null && delta.length > 0) yield delta;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta != null && delta.length > 0) yield delta;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Usage ──────────────────────────────────────────\n\n/**\n * Typed stream for usage metadata.\n */\nexport class UsageMetadataStream\n implements\n AsyncIterable<UsageMetadata>,\n PromiseLike<UsageMetadata | undefined>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<UsageMetadata> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (event.event === \"usage\") {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-start\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-finish\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = UsageMetadata | undefined, TResult2 = never>(\n onfulfilled?:\n | ((value: UsageMetadata | undefined) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let latest: UsageMetadata | undefined;\n for await (const usage of this) {\n latest = usage;\n }\n return latest;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── ChatModelStream ────────────────────────────────────────────\n\n/**\n * The main stream object returned by chat model streaming.\n *\n * Implements `AsyncIterable<ChatModelStreamEvent>` for raw event access\n * and `PromiseLike<AIMessage>` for simple `await` usage.\n */\nexport class ChatModelStream\n implements AsyncIterable<ChatModelStreamEvent>, PromiseLike<AIMessage>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(source: AsyncIterable<ChatModelStreamEvent>) {\n this._buffer = new ReplayBuffer();\n this._consume(source);\n }\n\n /** @internal */\n private async _consume(\n source: AsyncIterable<ChatModelStreamEvent>\n ): Promise<void> {\n try {\n for await (const event of source) {\n this._buffer.push(event);\n }\n this._buffer.finish();\n } catch (err) {\n this._buffer.setError(\n err instanceof Error ? err : new Error(String(err))\n );\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ChatModelStreamEvent> {\n return this._buffer.iterate();\n }\n\n get text(): TextContentStream {\n return new TextContentStream(this._buffer);\n }\n\n get toolCalls(): ToolCallsStream {\n return new ToolCallsStream(this._buffer);\n }\n\n get reasoning(): ReasoningContentStream {\n return new ReasoningContentStream(this._buffer);\n }\n\n get usage(): UsageMetadataStream {\n return new UsageMetadataStream(this._buffer);\n }\n\n get output(): PromiseLike<AIMessage> {\n return this._assembleMessage();\n }\n\n then<TResult1 = AIMessage, TResult2 = never>(\n onfulfilled?:\n | ((value: AIMessage) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n return this._assembleMessage().then(onfulfilled, onrejected);\n }\n\n /** @internal */\n private async _assembleMessage(): Promise<AIMessage> {\n const contentBlocks: Array<ContentBlock | undefined> = [];\n let id: string | undefined;\n let usage: UsageMetadata | undefined;\n let metadata: Record<string, unknown> = {};\n let finishReason: string | undefined;\n\n for await (const event of this._buffer.iterate()) {\n switch (event.event) {\n case \"message-start\":\n id = event.id ?? id;\n if (event.usage) usage = normalizeUsage(event.usage);\n break;\n\n case \"content-block-start\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"content-block-delta\": {\n const current = contentBlocks[event.index];\n const delta = getEventDelta(event);\n if (current) {\n if (delta) contentBlocks[event.index] = applyDelta(current, delta);\n }\n break;\n }\n\n case \"content-block-finish\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"usage\":\n usage = normalizeUsage(event.usage);\n break;\n\n case \"message-finish\":\n finishReason = event.reason;\n if (event.usage) usage = normalizeUsage(event.usage);\n if (event.responseMetadata) {\n metadata = {\n ...metadata,\n ...event.responseMetadata,\n };\n }\n break;\n\n default:\n break;\n }\n }\n\n const filteredBlocks = contentBlocks\n .filter((b): b is ContentBlock => b != null)\n .map(standardizeToolBlock);\n\n return new AIMessage({\n id,\n content: filteredBlocks,\n usage_metadata: usage,\n response_metadata: {\n ...metadata,\n ...(finishReason ? { finish_reason: finishReason } : {}),\n output_version: \"v1\" as const,\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stream.cjs","names":["AIMessage"],"sources":["../../src/language_models/stream.ts"],"sourcesContent":["/**\n * Typed stream classes for chat model streaming.\n *\n * @module\n */\n\nimport { AIMessage } from \"../messages/ai.js\";\nimport type { ContentBlock } from \"../messages/content/index.js\";\nimport type { UsageMetadata } from \"../messages/metadata.js\";\nimport type { ChatModelStreamEvent, ContentBlockDelta } from \"./event.js\";\n\ntype UsageMetadataLike = Partial<UsageMetadata>;\n\n/**\n * A buffer that caches emitted events for replay.\n *\n * Multiple consumers can independently iterate the same buffer —\n * each gets its own cursor. Events are never consumed or removed.\n *\n * @internal\n */\nclass ReplayBuffer {\n private events: ChatModelStreamEvent[] = [];\n private finished = false;\n private waiters: Array<() => void> = [];\n private error: Error | null = null;\n\n push(event: ChatModelStreamEvent): void {\n this.events.push(event);\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n finish(): void {\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n setError(err: Error): void {\n this.error = err;\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n async *iterate(): AsyncGenerator<ChatModelStreamEvent> {\n if (this.finished) {\n if (this.error) throw this.error;\n yield* this.events;\n return;\n }\n\n let cursor = 0;\n while (true) {\n while (cursor < this.events.length) {\n yield this.events[cursor]!;\n cursor++;\n }\n if (this.finished) {\n if (this.error) throw this.error;\n return;\n }\n await new Promise<void>((resolve) => {\n if (cursor < this.events.length || this.finished) {\n resolve();\n return;\n }\n this.waiters.push(resolve);\n });\n }\n }\n}\n\n/**\n * Apply a typed delta to an accumulated content block.\n *\n * - `text-delta` → append text\n * - `reasoning-delta` → append reasoning text\n * - `data-delta` → append encoded data to `data`\n * - `block-delta` → shallow merge fields\n *\n * @internal\n */\nfunction applyDelta(\n block: ContentBlock,\n delta: ContentBlockDelta\n): ContentBlock {\n switch (delta.type) {\n case \"text-delta\":\n if (block.type === \"text\") {\n return {\n ...block,\n text: (block.text ?? \"\") + delta.text,\n };\n }\n return block;\n case \"reasoning-delta\":\n if (block.type === \"thinking\") {\n return {\n ...block,\n thinking: (block.thinking ?? \"\") + delta.reasoning,\n };\n }\n if (block.type === \"reasoning\") {\n return {\n ...block,\n reasoning: (block.reasoning ?? \"\") + delta.reasoning,\n };\n }\n return block;\n case \"data-delta\":\n return {\n ...block,\n data: (block.data ?? \"\") + delta.data,\n };\n case \"block-delta\":\n return { ...block, ...delta.fields } as ContentBlock;\n default:\n throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);\n }\n}\n\n/**\n * Returns the typed delta carried by a content-block delta event.\n *\n * Stream protocol compliant language models store incremental updates in\n * `event.delta`, e.g. `{ type: \"text-delta\", text: \"hello\" }`. Some models and\n * adapters still emit the older content-shaped form on `event.content`, e.g.\n * `{ type: \"text\", text: \"hello\" }`, which predates explicit delta event\n * variants.\n *\n * Keep accepting that content-shaped form here so {@link ChatModelStream}\n * remains a tolerant consumer while producers migrate to protocol compliant\n * typed deltas.\n *\n * @internal\n */\nfunction getEventDelta(\n event: ChatModelStreamEvent\n): ContentBlockDelta | undefined {\n if (event.event !== \"content-block-delta\") return undefined;\n if (\"delta\" in event && event.delta) return event.delta;\n\n const content = (event as { content?: unknown }).content;\n if (content == null || typeof content !== \"object\") return undefined;\n const block = content as { type?: string } & Record<string, unknown>;\n if (block.type === \"text\" && typeof block.text === \"string\") {\n return { type: \"text-delta\", text: block.text };\n }\n if (block.type === \"reasoning\" && typeof block.reasoning === \"string\") {\n return { type: \"reasoning-delta\", reasoning: block.reasoning };\n }\n if (block.type === \"thinking\" && typeof block.thinking === \"string\") {\n return { type: \"reasoning-delta\", reasoning: block.thinking };\n }\n if (typeof block.data === \"string\") {\n return { type: \"data-delta\", data: block.data, encoding: \"base64\" };\n }\n if (typeof block.type === \"string\") {\n return { type: \"block-delta\", fields: { ...block, type: block.type } };\n }\n return undefined;\n}\n\nfunction getReasoningDelta(content: unknown): string | undefined {\n if (content == null || typeof content !== \"object\") return undefined;\n const block = content as {\n type?: string;\n reasoning?: unknown;\n thinking?: unknown;\n };\n if (block.type === \"reasoning\" && typeof block.reasoning === \"string\") {\n return block.reasoning;\n }\n if (block.type === \"thinking\" && typeof block.thinking === \"string\") {\n return block.thinking;\n }\n return undefined;\n}\n\nfunction isReasoningContent(content: unknown): boolean {\n if (content == null || typeof content !== \"object\") return false;\n const type = (content as { type?: unknown }).type;\n return type === \"reasoning\" || type === \"thinking\";\n}\n\n/**\n * Normalize protocol-compatible partial usage into Core's concrete usage shape.\n *\n * Some stream sources emit usage snapshots without every aggregate token field.\n * Keep the stream event input permissive, then normalize at read time so\n * high-level Core consumers always receive a complete {@link UsageMetadata}.\n */\nfunction normalizeUsage(\n usage: UsageMetadataLike | undefined\n): UsageMetadata | undefined {\n if (!usage) return undefined;\n return {\n ...usage,\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n };\n}\n\nfunction parseToolArgs(value: unknown): Record<string, unknown> {\n if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value !== \"string\" || value.length === 0) return {};\n try {\n const parsed = JSON.parse(value);\n return parsed != null &&\n typeof parsed === \"object\" &&\n !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\nfunction standardizeToolBlock(block: ContentBlock): ContentBlock {\n const record = block as Record<string, unknown>;\n if (block.type === \"tool_call\") return block;\n if (\n block.type !== \"tool_call_chunk\" &&\n block.type !== \"tool_use\" &&\n block.type !== \"input_json_delta\"\n ) {\n return block;\n }\n\n const name = typeof record.name === \"string\" ? record.name : undefined;\n if (name == null) return block;\n\n const args = record.args ?? record.input;\n return {\n ...record,\n type: \"tool_call\",\n name,\n args: parseToolArgs(args),\n } as ContentBlock;\n}\n\n// ─── Sub-Stream: Text ───────────────────────────────────────────\n\n/**\n * Typed stream for text content.\n *\n * - **Iterate**: yields incremental text deltas.\n * - **Await**: resolves to the complete concatenated text.\n * - **`.full`**: yields the running accumulated text after each delta.\n */\nexport class TextContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n /** Yields the accumulated text so far after each delta. */\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n accumulated += delta.text;\n yield accumulated;\n }\n }\n },\n };\n }\n\n /** Yields incremental text deltas. */\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n yield delta.text;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Tool Calls ─────────────────────────────────────\n\n/**\n * Typed stream for tool calls.\n *\n * - **Iterate**: yields individual `ToolCall` objects as each completes.\n * - **Await**: resolves to the full array.\n * - **`.full`**: yields the accumulated array after each new tool call.\n */\nexport class ToolCallsStream\n implements\n AsyncIterable<ContentBlock.Tools.ToolCall>,\n PromiseLike<Array<ContentBlock.Tools.ToolCall>>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<Array<ContentBlock.Tools.ToolCall>> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n calls.push(event.content as ContentBlock.Tools.ToolCall);\n yield [...calls];\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ContentBlock.Tools.ToolCall> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n yield event.content as ContentBlock.Tools.ToolCall;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = Array<ContentBlock.Tools.ToolCall>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Array<ContentBlock.Tools.ToolCall>\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const call of this) {\n calls.push(call);\n }\n return calls;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Reasoning ──────────────────────────────────────\n\n/**\n * Typed stream for reasoning content (chain-of-thought).\n * Same interface as {@link TextContentStream} but for reasoning blocks.\n */\nexport class ReasoningContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta != null && delta.length > 0) yield delta;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta != null && delta.length > 0) yield delta;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Usage ──────────────────────────────────────────\n\n/**\n * Typed stream for usage metadata.\n */\nexport class UsageMetadataStream\n implements\n AsyncIterable<UsageMetadata>,\n PromiseLike<UsageMetadata | undefined>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<UsageMetadata> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (event.event === \"usage\") {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-start\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-finish\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = UsageMetadata | undefined, TResult2 = never>(\n onfulfilled?:\n | ((value: UsageMetadata | undefined) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let latest: UsageMetadata | undefined;\n for await (const usage of this) {\n latest = usage;\n }\n return latest;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── ChatModelStream ────────────────────────────────────────────\n\n/**\n * The main stream object returned by chat model streaming.\n *\n * Implements `AsyncIterable<ChatModelStreamEvent>` for raw event access\n * and `PromiseLike<AIMessage>` for simple `await` usage.\n */\nexport class ChatModelStream\n implements AsyncIterable<ChatModelStreamEvent>, PromiseLike<AIMessage>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(source: AsyncIterable<ChatModelStreamEvent>) {\n this._buffer = new ReplayBuffer();\n this._consume(source);\n }\n\n /** @internal */\n private async _consume(\n source: AsyncIterable<ChatModelStreamEvent>\n ): Promise<void> {\n try {\n for await (const event of source) {\n this._buffer.push(event);\n }\n this._buffer.finish();\n } catch (err) {\n this._buffer.setError(\n err instanceof Error ? err : new Error(String(err))\n );\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ChatModelStreamEvent> {\n return this._buffer.iterate();\n }\n\n get text(): TextContentStream {\n return new TextContentStream(this._buffer);\n }\n\n get toolCalls(): ToolCallsStream {\n return new ToolCallsStream(this._buffer);\n }\n\n get reasoning(): ReasoningContentStream {\n return new ReasoningContentStream(this._buffer);\n }\n\n get usage(): UsageMetadataStream {\n return new UsageMetadataStream(this._buffer);\n }\n\n get output(): PromiseLike<AIMessage> {\n return this._assembleMessage();\n }\n\n then<TResult1 = AIMessage, TResult2 = never>(\n onfulfilled?:\n | ((value: AIMessage) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n return this._assembleMessage().then(onfulfilled, onrejected);\n }\n\n /** @internal */\n private async _assembleMessage(): Promise<AIMessage> {\n const contentBlocks: Array<ContentBlock | undefined> = [];\n let id: string | undefined;\n let usage: UsageMetadata | undefined;\n let metadata: Record<string, unknown> = {};\n let finishReason: string | undefined;\n\n for await (const event of this._buffer.iterate()) {\n switch (event.event) {\n case \"message-start\":\n id = event.id ?? id;\n if (event.usage) usage = normalizeUsage(event.usage);\n break;\n\n case \"content-block-start\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"content-block-delta\": {\n const current = contentBlocks[event.index];\n const delta = getEventDelta(event);\n if (current) {\n if (delta) contentBlocks[event.index] = applyDelta(current, delta);\n }\n break;\n }\n\n case \"content-block-finish\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"usage\":\n usage = normalizeUsage(event.usage);\n break;\n\n case \"message-finish\":\n finishReason = event.reason;\n if (event.usage) usage = normalizeUsage(event.usage);\n if (event.responseMetadata) {\n metadata = {\n ...metadata,\n ...event.responseMetadata,\n };\n }\n break;\n\n default:\n break;\n }\n }\n\n const filteredBlocks = contentBlocks\n .filter((b): b is ContentBlock => b != null)\n .map(standardizeToolBlock);\n\n return new AIMessage({\n id,\n content: filteredBlocks,\n usage_metadata: usage,\n response_metadata: {\n ...metadata,\n ...(finishReason ? { finish_reason: finishReason } : {}),\n output_version: \"v1\" as const,\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAqBA,IAAM,eAAN,MAAmB;CACjB,SAAyC,EAAE;CAC3C,WAAmB;CACnB,UAAqC,EAAE;CACvC,QAA8B;CAE9B,KAAK,OAAmC;AACtC,OAAK,OAAO,KAAK,MAAM;EACvB,MAAM,SAAS,KAAK,QAAQ,OAAO,EAAE;AACrC,OAAK,MAAM,UAAU,OACnB,SAAQ;;CAIZ,SAAe;AACb,OAAK,WAAW;EAChB,MAAM,SAAS,KAAK,QAAQ,OAAO,EAAE;AACrC,OAAK,MAAM,UAAU,OACnB,SAAQ;;CAIZ,SAAS,KAAkB;AACzB,OAAK,QAAQ;AACb,OAAK,WAAW;EAChB,MAAM,SAAS,KAAK,QAAQ,OAAO,EAAE;AACrC,OAAK,MAAM,UAAU,OACnB,SAAQ;;CAIZ,OAAO,UAAgD;AACrD,MAAI,KAAK,UAAU;AACjB,OAAI,KAAK,MAAO,OAAM,KAAK;AAC3B,UAAO,KAAK;AACZ;;EAGF,IAAI,SAAS;AACb,SAAO,MAAM;AACX,UAAO,SAAS,KAAK,OAAO,QAAQ;AAClC,UAAM,KAAK,OAAO;AAClB;;AAEF,OAAI,KAAK,UAAU;AACjB,QAAI,KAAK,MAAO,OAAM,KAAK;AAC3B;;AAEF,SAAM,IAAI,SAAe,YAAY;AACnC,QAAI,SAAS,KAAK,OAAO,UAAU,KAAK,UAAU;AAChD,cAAS;AACT;;AAEF,SAAK,QAAQ,KAAK,QAAQ;KAC1B;;;;;;;;;;;;;;AAeR,SAAS,WACP,OACA,OACc;AACd,SAAQ,MAAM,MAAd;EACE,KAAK;AACH,OAAI,MAAM,SAAS,OACjB,QAAO;IACL,GAAG;IACH,OAAO,MAAM,QAAQ,MAAM,MAAM;IAClC;AAEH,UAAO;EACT,KAAK;AACH,OAAI,MAAM,SAAS,WACjB,QAAO;IACL,GAAG;IACH,WAAW,MAAM,YAAY,MAAM,MAAM;IAC1C;AAEH,OAAI,MAAM,SAAS,YACjB,QAAO;IACL,GAAG;IACH,YAAY,MAAM,aAAa,MAAM,MAAM;IAC5C;AAEH,UAAO;EACT,KAAK,aACH,QAAO;GACL,GAAG;GACH,OAAO,MAAM,QAAQ,MAAM,MAAM;GAClC;EACH,KAAK,cACH,QAAO;GAAE,GAAG;GAAO,GAAG,MAAM;GAAQ;EACtC,QACE,OAAM,IAAI,MAAM,uBAAuB,KAAK,UAAU,MAAM,GAAG;;;;;;;;;;;;;;;;;;AAmBrE,SAAS,cACP,OAC+B;AAC/B,KAAI,MAAM,UAAU,sBAAuB,QAAO,KAAA;AAClD,KAAI,WAAW,SAAS,MAAM,MAAO,QAAO,MAAM;CAElD,MAAM,UAAW,MAAgC;AACjD,KAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO,KAAA;CAC3D,MAAM,QAAQ;AACd,KAAI,MAAM,SAAS,UAAU,OAAO,MAAM,SAAS,SACjD,QAAO;EAAE,MAAM;EAAc,MAAM,MAAM;EAAM;AAEjD,KAAI,MAAM,SAAS,eAAe,OAAO,MAAM,cAAc,SAC3D,QAAO;EAAE,MAAM;EAAmB,WAAW,MAAM;EAAW;AAEhE,KAAI,MAAM,SAAS,cAAc,OAAO,MAAM,aAAa,SACzD,QAAO;EAAE,MAAM;EAAmB,WAAW,MAAM;EAAU;AAE/D,KAAI,OAAO,MAAM,SAAS,SACxB,QAAO;EAAE,MAAM;EAAc,MAAM,MAAM;EAAM,UAAU;EAAU;AAErE,KAAI,OAAO,MAAM,SAAS,SACxB,QAAO;EAAE,MAAM;EAAe,QAAQ;GAAE,GAAG;GAAO,MAAM,MAAM;GAAM;EAAE;;AAK1E,SAAS,kBAAkB,SAAsC;AAC/D,KAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO,KAAA;CAC3D,MAAM,QAAQ;AAKd,KAAI,MAAM,SAAS,eAAe,OAAO,MAAM,cAAc,SAC3D,QAAO,MAAM;AAEf,KAAI,MAAM,SAAS,cAAc,OAAO,MAAM,aAAa,SACzD,QAAO,MAAM;;AAKjB,SAAS,mBAAmB,SAA2B;AACrD,KAAI,WAAW,QAAQ,OAAO,YAAY,SAAU,QAAO;CAC3D,MAAM,OAAQ,QAA+B;AAC7C,QAAO,SAAS,eAAe,SAAS;;;;;;;;;AAU1C,SAAS,eACP,OAC2B;AAC3B,KAAI,CAAC,MAAO,QAAO,KAAA;AACnB,QAAO;EACL,GAAG;EACH,cAAc,MAAM,gBAAgB;EACpC,eAAe,MAAM,iBAAiB;EACtC,cAAc,MAAM,gBAAgB;EACrC;;AAGH,SAAS,cAAc,OAAyC;AAC9D,KAAI,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,CACrE,QAAO;AAET,KAAI,OAAO,UAAU,YAAY,MAAM,WAAW,EAAG,QAAO,EAAE;AAC9D,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,SAAO,UAAU,QACf,OAAO,WAAW,YAClB,CAAC,MAAM,QAAQ,OAAO,GACnB,SACD,EAAE;SACA;AACN,SAAO,EAAE;;;AAIb,SAAS,qBAAqB,OAAmC;CAC/D,MAAM,SAAS;AACf,KAAI,MAAM,SAAS,YAAa,QAAO;AACvC,KACE,MAAM,SAAS,qBACf,MAAM,SAAS,cACf,MAAM,SAAS,mBAEf,QAAO;CAGT,MAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO,KAAA;AAC7D,KAAI,QAAQ,KAAM,QAAO;CAEzB,MAAM,OAAO,OAAO,QAAQ,OAAO;AACnC,QAAO;EACL,GAAG;EACH,MAAM;EACN;EACA,MAAM,cAAc,KAAK;EAC1B;;;;;;;;;AAYH,IAAa,oBAAb,MAEA;;CAEE;;CAGA,YAAY,QAAsB;AAChC,OAAK,UAAU;;;CAIjB,IAAI,OAA8B;EAChC,MAAM,SAAS,KAAK;AACpB,SAAO,EACL,QAAQ,OAAO,iBAAiB;GAC9B,IAAI,cAAc;AAClB,cAAW,MAAM,SAAS,OAAO,SAAS,EAAE;IAC1C,MAAM,QAAQ,cAAc,MAAM;AAClC,QAAI,OAAO,SAAS,cAAc;AAChC,oBAAe,MAAM;AACrB,WAAM;;;KAIb;;;CAIH,CAAC,OAAO,iBAAwC;EAC9C,MAAM,SAAS,KAAK;EACpB,gBAAgB,MAAM;AACpB,cAAW,MAAM,SAAS,OAAO,SAAS,EAAE;IAC1C,MAAM,QAAQ,cAAc,MAAM;AAClC,QAAI,OAAO,SAAS,aAClB,OAAM,MAAM;;;AAIlB,SAAO,KAAK;;CAGd,KACE,aACA,YACkC;AAQlC,UAPiB,YAAY;GAC3B,IAAI,OAAO;AACX,cAAW,MAAM,SAAS,KACxB,SAAQ;AAEV,UAAO;MACL,CACW,KAAK,aAAa,WAAW;;;;;;;;;;AAahD,IAAa,kBAAb,MAIA;;CAEE;;CAGA,YAAY,QAAsB;AAChC,OAAK,UAAU;;CAGjB,IAAI,OAA0D;EAC5D,MAAM,SAAS,KAAK;AACpB,SAAO,EACL,QAAQ,OAAO,iBAAiB;GAC9B,MAAM,QAA4C,EAAE;AACpD,cAAW,MAAM,SAAS,OAAO,SAAS,CACxC,KACE,MAAM,UAAU,0BAChB,MAAM,QAAQ,SAAS,aACvB;AACA,UAAM,KAAK,MAAM,QAAuC;AACxD,UAAM,CAAC,GAAG,MAAM;;KAIvB;;CAGH,CAAC,OAAO,iBAA6D;EACnE,MAAM,SAAS,KAAK;EACpB,gBAAgB,MAAM;AACpB,cAAW,MAAM,SAAS,OAAO,SAAS,CACxC,KACE,MAAM,UAAU,0BAChB,MAAM,QAAQ,SAAS,YAEvB,OAAM,MAAM;;AAIlB,SAAO,KAAK;;CAGd,KACE,aAKA,YACkC;AAQlC,UAPiB,YAAY;GAC3B,MAAM,QAA4C,EAAE;AACpD,cAAW,MAAM,QAAQ,KACvB,OAAM,KAAK,KAAK;AAElB,UAAO;MACL,CACW,KAAK,aAAa,WAAW;;;;;;;AAUhD,IAAa,yBAAb,MAEA;;CAEE;;CAGA,YAAY,QAAsB;AAChC,OAAK,UAAU;;CAGjB,IAAI,OAA8B;EAChC,MAAM,SAAS,KAAK;AACpB,SAAO,EACL,QAAQ,OAAO,iBAAiB;GAC9B,IAAI,cAAc;GAClB,IAAI,gBAAgB;AACpB,cAAW,MAAM,SAAS,OAAO,SAAS,CACxC,KAAI,MAAM,UAAU,uBAAuB;AACzC,QAAI,CAAC,mBAAmB,MAAM,QAAQ,EAAE;AACtC,SAAI,cAAe;AACnB;;AAEF,oBAAgB;IAChB,MAAM,QAAQ,kBAAkB,MAAM,QAAQ;AAC9C,QAAI,SAAS,QAAQ,MAAM,WAAW,EAAG;AACzC,mBAAe;AACf,UAAM;cACG,MAAM,UAAU,uBAAuB;IAChD,MAAM,aAAa,cAAc,MAAM;AACvC,QAAI,YAAY,SAAS,kBAAmB;AAC5C,oBAAgB;IAChB,MAAM,QAAQ,WAAW;AACzB,QAAI,SAAS,QAAQ,MAAM,WAAW,EAAG;AACzC,mBAAe;AACf,UAAM;cAEN,MAAM,UAAU,0BAChB,mBAAmB,MAAM,QAAQ,CAEjC;YACS,MAAM,UAAU,iBACzB;KAIP;;CAGH,CAAC,OAAO,iBAAwC;EAC9C,MAAM,SAAS,KAAK;EACpB,gBAAgB,MAAM;GACpB,IAAI,gBAAgB;AACpB,cAAW,MAAM,SAAS,OAAO,SAAS,CACxC,KAAI,MAAM,UAAU,uBAAuB;AACzC,QAAI,CAAC,mBAAmB,MAAM,QAAQ,EAAE;AACtC,SAAI,cAAe;AACnB;;AAEF,oBAAgB;IAChB,MAAM,QAAQ,kBAAkB,MAAM,QAAQ;AAC9C,QAAI,SAAS,QAAQ,MAAM,SAAS,EAAG,OAAM;cACpC,MAAM,UAAU,uBAAuB;IAChD,MAAM,aAAa,cAAc,MAAM;AACvC,QAAI,YAAY,SAAS,kBAAmB;AAC5C,oBAAgB;IAChB,MAAM,QAAQ,WAAW;AACzB,QAAI,SAAS,QAAQ,MAAM,SAAS,EAAG,OAAM;cAE7C,MAAM,UAAU,0BAChB,mBAAmB,MAAM,QAAQ,CAEjC;YACS,MAAM,UAAU,iBACzB;;AAIN,SAAO,KAAK;;CAGd,KACE,aACA,YACkC;AAQlC,UAPiB,YAAY;GAC3B,IAAI,OAAO;AACX,cAAW,MAAM,SAAS,KACxB,SAAQ;AAEV,UAAO;MACL,CACW,KAAK,aAAa,WAAW;;;;;;AAShD,IAAa,sBAAb,MAIA;;CAEE;;CAGA,YAAY,QAAsB;AAChC,OAAK,UAAU;;CAGjB,CAAC,OAAO,iBAA+C;EACrD,MAAM,SAAS,KAAK;EACpB,gBAAgB,MAAM;AACpB,cAAW,MAAM,SAAS,OAAO,SAAS,CACxC,KAAI,MAAM,UAAU,SAAS;IAC3B,MAAM,QAAQ,eAAe,MAAM,MAAM;AACzC,QAAI,MAAO,OAAM;cACR,MAAM,UAAU,mBAAmB,MAAM,OAAO;IACzD,MAAM,QAAQ,eAAe,MAAM,MAAM;AACzC,QAAI,MAAO,OAAM;cACR,MAAM,UAAU,oBAAoB,MAAM,OAAO;IAC1D,MAAM,QAAQ,eAAe,MAAM,MAAM;AACzC,QAAI,MAAO,OAAM;;;AAIvB,SAAO,KAAK;;CAGd,KACE,aAGA,YACkC;AAQlC,UAPiB,YAAY;GAC3B,IAAI;AACJ,cAAW,MAAM,SAAS,KACxB,UAAS;AAEX,UAAO;MACL,CACW,KAAK,aAAa,WAAW;;;;;;;;;AAYhD,IAAa,kBAAb,MAEA;;CAEE;;CAGA,YAAY,QAA6C;AACvD,OAAK,UAAU,IAAI,cAAc;AACjC,OAAK,SAAS,OAAO;;;CAIvB,MAAc,SACZ,QACe;AACf,MAAI;AACF,cAAW,MAAM,SAAS,OACxB,MAAK,QAAQ,KAAK,MAAM;AAE1B,QAAK,QAAQ,QAAQ;WACd,KAAK;AACZ,QAAK,QAAQ,SACX,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,CACpD;;;CAIL,CAAC,OAAO,iBAAsD;AAC5D,SAAO,KAAK,QAAQ,SAAS;;CAG/B,IAAI,OAA0B;AAC5B,SAAO,IAAI,kBAAkB,KAAK,QAAQ;;CAG5C,IAAI,YAA6B;AAC/B,SAAO,IAAI,gBAAgB,KAAK,QAAQ;;CAG1C,IAAI,YAAoC;AACtC,SAAO,IAAI,uBAAuB,KAAK,QAAQ;;CAGjD,IAAI,QAA6B;AAC/B,SAAO,IAAI,oBAAoB,KAAK,QAAQ;;CAG9C,IAAI,SAAiC;AACnC,SAAO,KAAK,kBAAkB;;CAGhC,KACE,aAGA,YACkC;AAClC,SAAO,KAAK,kBAAkB,CAAC,KAAK,aAAa,WAAW;;;CAI9D,MAAc,mBAAuC;EACnD,MAAM,gBAAiD,EAAE;EACzD,IAAI;EACJ,IAAI;EACJ,IAAI,WAAoC,EAAE;EAC1C,IAAI;AAEJ,aAAW,MAAM,SAAS,KAAK,QAAQ,SAAS,CAC9C,SAAQ,MAAM,OAAd;GACE,KAAK;AACH,SAAK,MAAM,MAAM;AACjB,QAAI,MAAM,MAAO,SAAQ,eAAe,MAAM,MAAM;AACpD;GAEF,KAAK;AACH,kBAAc,MAAM,SAAS,MAAM;AACnC;GAEF,KAAK,uBAAuB;IAC1B,MAAM,UAAU,cAAc,MAAM;IACpC,MAAM,QAAQ,cAAc,MAAM;AAClC,QAAI;SACE,MAAO,eAAc,MAAM,SAAS,WAAW,SAAS,MAAM;;AAEpE;;GAGF,KAAK;AACH,kBAAc,MAAM,SAAS,MAAM;AACnC;GAEF,KAAK;AACH,YAAQ,eAAe,MAAM,MAAM;AACnC;GAEF,KAAK;AACH,mBAAe,MAAM;AACrB,QAAI,MAAM,MAAO,SAAQ,eAAe,MAAM,MAAM;AACpD,QAAI,MAAM,iBACR,YAAW;KACT,GAAG;KACH,GAAG,MAAM;KACV;AAEH;GAEF,QACE;;EAIN,MAAM,iBAAiB,cACpB,QAAQ,MAAyB,KAAK,KAAK,CAC3C,IAAI,qBAAqB;AAE5B,SAAO,IAAIA,WAAAA,UAAU;GACnB;GACA,SAAS;GACT,gBAAgB;GAChB,mBAAmB;IACjB,GAAG;IACH,GAAI,eAAe,EAAE,eAAe,cAAc,GAAG,EAAE;IACvD,gBAAgB;IACjB;GACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.cts","names":[],"sources":["../../src/language_models/stream.ts"],"mappings":";;;;;;;;;;;;;;cAqBM,YAAA;EAAA,QACI,MAAA;EAAA,QACA,QAAA;EAAA,QACA,OAAA;EAAA,QACA,KAAA;EAER,IAAA,CAAK,KAAA,EAAO,oBAAA;EAQZ,MAAA,CAAA;EAQA,QAAA,CAAS,GAAA,EAAK,KAAA;EASP,OAAA,CAAA,GAAW,cAAA,CAAe,oBAAA;AAAA;;;;;
|
|
1
|
+
{"version":3,"file":"stream.d.cts","names":[],"sources":["../../src/language_models/stream.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.d.ts","names":[],"sources":["../../src/language_models/stream.ts"],"mappings":";;;;;;;;;;;;;;cAqBM,YAAA;EAAA,QACI,MAAA;EAAA,QACA,QAAA;EAAA,QACA,OAAA;EAAA,QACA,KAAA;EAER,IAAA,CAAK,KAAA,EAAO,oBAAA;EAQZ,MAAA,CAAA;EAQA,QAAA,CAAS,GAAA,EAAK,KAAA;EASP,OAAA,CAAA,GAAW,cAAA,CAAe,oBAAA;AAAA;;;;;
|
|
1
|
+
{"version":3,"file":"stream.d.ts","names":[],"sources":["../../src/language_models/stream.ts"],"mappings":"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"}
|
|
@@ -107,9 +107,51 @@ function applyDelta(block, delta) {
|
|
|
107
107
|
default: throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns the typed delta carried by a content-block delta event.
|
|
112
|
+
*
|
|
113
|
+
* Stream protocol compliant language models store incremental updates in
|
|
114
|
+
* `event.delta`, e.g. `{ type: "text-delta", text: "hello" }`. Some models and
|
|
115
|
+
* adapters still emit the older content-shaped form on `event.content`, e.g.
|
|
116
|
+
* `{ type: "text", text: "hello" }`, which predates explicit delta event
|
|
117
|
+
* variants.
|
|
118
|
+
*
|
|
119
|
+
* Keep accepting that content-shaped form here so {@link ChatModelStream}
|
|
120
|
+
* remains a tolerant consumer while producers migrate to protocol compliant
|
|
121
|
+
* typed deltas.
|
|
122
|
+
*
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
110
125
|
function getEventDelta(event) {
|
|
111
126
|
if (event.event !== "content-block-delta") return void 0;
|
|
112
|
-
return event.delta;
|
|
127
|
+
if ("delta" in event && event.delta) return event.delta;
|
|
128
|
+
const content = event.content;
|
|
129
|
+
if (content == null || typeof content !== "object") return void 0;
|
|
130
|
+
const block = content;
|
|
131
|
+
if (block.type === "text" && typeof block.text === "string") return {
|
|
132
|
+
type: "text-delta",
|
|
133
|
+
text: block.text
|
|
134
|
+
};
|
|
135
|
+
if (block.type === "reasoning" && typeof block.reasoning === "string") return {
|
|
136
|
+
type: "reasoning-delta",
|
|
137
|
+
reasoning: block.reasoning
|
|
138
|
+
};
|
|
139
|
+
if (block.type === "thinking" && typeof block.thinking === "string") return {
|
|
140
|
+
type: "reasoning-delta",
|
|
141
|
+
reasoning: block.thinking
|
|
142
|
+
};
|
|
143
|
+
if (typeof block.data === "string") return {
|
|
144
|
+
type: "data-delta",
|
|
145
|
+
data: block.data,
|
|
146
|
+
encoding: "base64"
|
|
147
|
+
};
|
|
148
|
+
if (typeof block.type === "string") return {
|
|
149
|
+
type: "block-delta",
|
|
150
|
+
fields: {
|
|
151
|
+
...block,
|
|
152
|
+
type: block.type
|
|
153
|
+
}
|
|
154
|
+
};
|
|
113
155
|
}
|
|
114
156
|
function getReasoningDelta(content) {
|
|
115
157
|
if (content == null || typeof content !== "object") return void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","names":[],"sources":["../../src/language_models/stream.ts"],"sourcesContent":["/**\n * Typed stream classes for chat model streaming.\n *\n * @module\n */\n\nimport { AIMessage } from \"../messages/ai.js\";\nimport type { ContentBlock } from \"../messages/content/index.js\";\nimport type { UsageMetadata } from \"../messages/metadata.js\";\nimport type { ChatModelStreamEvent, ContentBlockDelta } from \"./event.js\";\n\ntype UsageMetadataLike = Partial<UsageMetadata>;\n\n/**\n * A buffer that caches emitted events for replay.\n *\n * Multiple consumers can independently iterate the same buffer —\n * each gets its own cursor. Events are never consumed or removed.\n *\n * @internal\n */\nclass ReplayBuffer {\n private events: ChatModelStreamEvent[] = [];\n private finished = false;\n private waiters: Array<() => void> = [];\n private error: Error | null = null;\n\n push(event: ChatModelStreamEvent): void {\n this.events.push(event);\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n finish(): void {\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n setError(err: Error): void {\n this.error = err;\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n async *iterate(): AsyncGenerator<ChatModelStreamEvent> {\n if (this.finished) {\n if (this.error) throw this.error;\n yield* this.events;\n return;\n }\n\n let cursor = 0;\n while (true) {\n while (cursor < this.events.length) {\n yield this.events[cursor]!;\n cursor++;\n }\n if (this.finished) {\n if (this.error) throw this.error;\n return;\n }\n await new Promise<void>((resolve) => {\n if (cursor < this.events.length || this.finished) {\n resolve();\n return;\n }\n this.waiters.push(resolve);\n });\n }\n }\n}\n\n/**\n * Apply a typed delta to an accumulated content block.\n *\n * - `text-delta` → append text\n * - `reasoning-delta` → append reasoning text\n * - `data-delta` → append encoded data to `data`\n * - `block-delta` → shallow merge fields\n *\n * @internal\n */\nfunction applyDelta(\n block: ContentBlock,\n delta: ContentBlockDelta\n): ContentBlock {\n switch (delta.type) {\n case \"text-delta\":\n if (block.type === \"text\") {\n return {\n ...block,\n text: (block.text ?? \"\") + delta.text,\n };\n }\n return block;\n case \"reasoning-delta\":\n if (block.type === \"thinking\") {\n return {\n ...block,\n thinking: (block.thinking ?? \"\") + delta.reasoning,\n };\n }\n if (block.type === \"reasoning\") {\n return {\n ...block,\n reasoning: (block.reasoning ?? \"\") + delta.reasoning,\n };\n }\n return block;\n case \"data-delta\":\n return {\n ...block,\n data: (block.data ?? \"\") + delta.data,\n };\n case \"block-delta\":\n return { ...block, ...delta.fields } as ContentBlock;\n default:\n throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);\n }\n}\n\nfunction getEventDelta(\n event: ChatModelStreamEvent\n): ContentBlockDelta | undefined {\n if (event.event !== \"content-block-delta\") return undefined;\n return event.delta;\n}\n\nfunction getReasoningDelta(content: unknown): string | undefined {\n if (content == null || typeof content !== \"object\") return undefined;\n const block = content as {\n type?: string;\n reasoning?: unknown;\n thinking?: unknown;\n };\n if (block.type === \"reasoning\" && typeof block.reasoning === \"string\") {\n return block.reasoning;\n }\n if (block.type === \"thinking\" && typeof block.thinking === \"string\") {\n return block.thinking;\n }\n return undefined;\n}\n\nfunction isReasoningContent(content: unknown): boolean {\n if (content == null || typeof content !== \"object\") return false;\n const type = (content as { type?: unknown }).type;\n return type === \"reasoning\" || type === \"thinking\";\n}\n\n/**\n * Normalize protocol-compatible partial usage into Core's concrete usage shape.\n *\n * Some stream sources emit usage snapshots without every aggregate token field.\n * Keep the stream event input permissive, then normalize at read time so\n * high-level Core consumers always receive a complete {@link UsageMetadata}.\n */\nfunction normalizeUsage(\n usage: UsageMetadataLike | undefined\n): UsageMetadata | undefined {\n if (!usage) return undefined;\n return {\n ...usage,\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n };\n}\n\nfunction parseToolArgs(value: unknown): Record<string, unknown> {\n if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value !== \"string\" || value.length === 0) return {};\n try {\n const parsed = JSON.parse(value);\n return parsed != null &&\n typeof parsed === \"object\" &&\n !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\nfunction standardizeToolBlock(block: ContentBlock): ContentBlock {\n const record = block as Record<string, unknown>;\n if (block.type === \"tool_call\") return block;\n if (\n block.type !== \"tool_call_chunk\" &&\n block.type !== \"tool_use\" &&\n block.type !== \"input_json_delta\"\n ) {\n return block;\n }\n\n const name = typeof record.name === \"string\" ? record.name : undefined;\n if (name == null) return block;\n\n const args = record.args ?? record.input;\n return {\n ...record,\n type: \"tool_call\",\n name,\n args: parseToolArgs(args),\n } as ContentBlock;\n}\n\n// ─── Sub-Stream: Text ───────────────────────────────────────────\n\n/**\n * Typed stream for text content.\n *\n * - **Iterate**: yields incremental text deltas.\n * - **Await**: resolves to the complete concatenated text.\n * - **`.full`**: yields the running accumulated text after each delta.\n */\nexport class TextContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n /** Yields the accumulated text so far after each delta. */\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n accumulated += delta.text;\n yield accumulated;\n }\n }\n },\n };\n }\n\n /** Yields incremental text deltas. */\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n yield delta.text;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Tool Calls ─────────────────────────────────────\n\n/**\n * Typed stream for tool calls.\n *\n * - **Iterate**: yields individual `ToolCall` objects as each completes.\n * - **Await**: resolves to the full array.\n * - **`.full`**: yields the accumulated array after each new tool call.\n */\nexport class ToolCallsStream\n implements\n AsyncIterable<ContentBlock.Tools.ToolCall>,\n PromiseLike<Array<ContentBlock.Tools.ToolCall>>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<Array<ContentBlock.Tools.ToolCall>> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n calls.push(event.content as ContentBlock.Tools.ToolCall);\n yield [...calls];\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ContentBlock.Tools.ToolCall> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n yield event.content as ContentBlock.Tools.ToolCall;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = Array<ContentBlock.Tools.ToolCall>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Array<ContentBlock.Tools.ToolCall>\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const call of this) {\n calls.push(call);\n }\n return calls;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Reasoning ──────────────────────────────────────\n\n/**\n * Typed stream for reasoning content (chain-of-thought).\n * Same interface as {@link TextContentStream} but for reasoning blocks.\n */\nexport class ReasoningContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta != null && delta.length > 0) yield delta;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta != null && delta.length > 0) yield delta;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Usage ──────────────────────────────────────────\n\n/**\n * Typed stream for usage metadata.\n */\nexport class UsageMetadataStream\n implements\n AsyncIterable<UsageMetadata>,\n PromiseLike<UsageMetadata | undefined>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<UsageMetadata> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (event.event === \"usage\") {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-start\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-finish\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = UsageMetadata | undefined, TResult2 = never>(\n onfulfilled?:\n | ((value: UsageMetadata | undefined) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let latest: UsageMetadata | undefined;\n for await (const usage of this) {\n latest = usage;\n }\n return latest;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── ChatModelStream ────────────────────────────────────────────\n\n/**\n * The main stream object returned by chat model streaming.\n *\n * Implements `AsyncIterable<ChatModelStreamEvent>` for raw event access\n * and `PromiseLike<AIMessage>` for simple `await` usage.\n */\nexport class ChatModelStream\n implements AsyncIterable<ChatModelStreamEvent>, PromiseLike<AIMessage>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(source: AsyncIterable<ChatModelStreamEvent>) {\n this._buffer = new ReplayBuffer();\n this._consume(source);\n }\n\n /** @internal */\n private async _consume(\n source: AsyncIterable<ChatModelStreamEvent>\n ): Promise<void> {\n try {\n for await (const event of source) {\n this._buffer.push(event);\n }\n this._buffer.finish();\n } catch (err) {\n this._buffer.setError(\n err instanceof Error ? err : new Error(String(err))\n );\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ChatModelStreamEvent> {\n return this._buffer.iterate();\n }\n\n get text(): TextContentStream {\n return new TextContentStream(this._buffer);\n }\n\n get toolCalls(): ToolCallsStream {\n return new ToolCallsStream(this._buffer);\n }\n\n get reasoning(): ReasoningContentStream {\n return new ReasoningContentStream(this._buffer);\n }\n\n get usage(): UsageMetadataStream {\n return new UsageMetadataStream(this._buffer);\n }\n\n get output(): PromiseLike<AIMessage> {\n return this._assembleMessage();\n }\n\n then<TResult1 = AIMessage, TResult2 = never>(\n onfulfilled?:\n | ((value: AIMessage) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n return this._assembleMessage().then(onfulfilled, onrejected);\n }\n\n /** @internal */\n private async _assembleMessage(): Promise<AIMessage> {\n const contentBlocks: Array<ContentBlock | undefined> = [];\n let id: string | undefined;\n let usage: UsageMetadata | undefined;\n let metadata: Record<string, unknown> = {};\n let finishReason: string | undefined;\n\n for await (const event of this._buffer.iterate()) {\n switch (event.event) {\n case \"message-start\":\n id = event.id ?? id;\n if (event.usage) usage = normalizeUsage(event.usage);\n break;\n\n case \"content-block-start\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"content-block-delta\": {\n const current = contentBlocks[event.index];\n const delta = getEventDelta(event);\n if (current) {\n if (delta) contentBlocks[event.index] = applyDelta(current, delta);\n }\n break;\n }\n\n case \"content-block-finish\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"usage\":\n usage = normalizeUsage(event.usage);\n break;\n\n case \"message-finish\":\n finishReason = event.reason;\n if (event.usage) usage = normalizeUsage(event.usage);\n if (event.responseMetadata) {\n metadata = {\n ...metadata,\n ...event.responseMetadata,\n };\n }\n break;\n\n default:\n break;\n }\n }\n\n const filteredBlocks = contentBlocks\n .filter((b): b is ContentBlock => b != null)\n .map(standardizeToolBlock);\n\n return new AIMessage({\n id,\n content: filteredBlocks,\n usage_metadata: usage,\n response_metadata: {\n ...metadata,\n ...(finishReason ? { finish_reason: finishReason } : {}),\n output_version: \"v1\" as const,\n },\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stream.js","names":[],"sources":["../../src/language_models/stream.ts"],"sourcesContent":["/**\n * Typed stream classes for chat model streaming.\n *\n * @module\n */\n\nimport { AIMessage } from \"../messages/ai.js\";\nimport type { ContentBlock } from \"../messages/content/index.js\";\nimport type { UsageMetadata } from \"../messages/metadata.js\";\nimport type { ChatModelStreamEvent, ContentBlockDelta } from \"./event.js\";\n\ntype UsageMetadataLike = Partial<UsageMetadata>;\n\n/**\n * A buffer that caches emitted events for replay.\n *\n * Multiple consumers can independently iterate the same buffer —\n * each gets its own cursor. Events are never consumed or removed.\n *\n * @internal\n */\nclass ReplayBuffer {\n private events: ChatModelStreamEvent[] = [];\n private finished = false;\n private waiters: Array<() => void> = [];\n private error: Error | null = null;\n\n push(event: ChatModelStreamEvent): void {\n this.events.push(event);\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n finish(): void {\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n setError(err: Error): void {\n this.error = err;\n this.finished = true;\n const toWake = this.waiters.splice(0);\n for (const waiter of toWake) {\n waiter();\n }\n }\n\n async *iterate(): AsyncGenerator<ChatModelStreamEvent> {\n if (this.finished) {\n if (this.error) throw this.error;\n yield* this.events;\n return;\n }\n\n let cursor = 0;\n while (true) {\n while (cursor < this.events.length) {\n yield this.events[cursor]!;\n cursor++;\n }\n if (this.finished) {\n if (this.error) throw this.error;\n return;\n }\n await new Promise<void>((resolve) => {\n if (cursor < this.events.length || this.finished) {\n resolve();\n return;\n }\n this.waiters.push(resolve);\n });\n }\n }\n}\n\n/**\n * Apply a typed delta to an accumulated content block.\n *\n * - `text-delta` → append text\n * - `reasoning-delta` → append reasoning text\n * - `data-delta` → append encoded data to `data`\n * - `block-delta` → shallow merge fields\n *\n * @internal\n */\nfunction applyDelta(\n block: ContentBlock,\n delta: ContentBlockDelta\n): ContentBlock {\n switch (delta.type) {\n case \"text-delta\":\n if (block.type === \"text\") {\n return {\n ...block,\n text: (block.text ?? \"\") + delta.text,\n };\n }\n return block;\n case \"reasoning-delta\":\n if (block.type === \"thinking\") {\n return {\n ...block,\n thinking: (block.thinking ?? \"\") + delta.reasoning,\n };\n }\n if (block.type === \"reasoning\") {\n return {\n ...block,\n reasoning: (block.reasoning ?? \"\") + delta.reasoning,\n };\n }\n return block;\n case \"data-delta\":\n return {\n ...block,\n data: (block.data ?? \"\") + delta.data,\n };\n case \"block-delta\":\n return { ...block, ...delta.fields } as ContentBlock;\n default:\n throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);\n }\n}\n\n/**\n * Returns the typed delta carried by a content-block delta event.\n *\n * Stream protocol compliant language models store incremental updates in\n * `event.delta`, e.g. `{ type: \"text-delta\", text: \"hello\" }`. Some models and\n * adapters still emit the older content-shaped form on `event.content`, e.g.\n * `{ type: \"text\", text: \"hello\" }`, which predates explicit delta event\n * variants.\n *\n * Keep accepting that content-shaped form here so {@link ChatModelStream}\n * remains a tolerant consumer while producers migrate to protocol compliant\n * typed deltas.\n *\n * @internal\n */\nfunction getEventDelta(\n event: ChatModelStreamEvent\n): ContentBlockDelta | undefined {\n if (event.event !== \"content-block-delta\") return undefined;\n if (\"delta\" in event && event.delta) return event.delta;\n\n const content = (event as { content?: unknown }).content;\n if (content == null || typeof content !== \"object\") return undefined;\n const block = content as { type?: string } & Record<string, unknown>;\n if (block.type === \"text\" && typeof block.text === \"string\") {\n return { type: \"text-delta\", text: block.text };\n }\n if (block.type === \"reasoning\" && typeof block.reasoning === \"string\") {\n return { type: \"reasoning-delta\", reasoning: block.reasoning };\n }\n if (block.type === \"thinking\" && typeof block.thinking === \"string\") {\n return { type: \"reasoning-delta\", reasoning: block.thinking };\n }\n if (typeof block.data === \"string\") {\n return { type: \"data-delta\", data: block.data, encoding: \"base64\" };\n }\n if (typeof block.type === \"string\") {\n return { type: \"block-delta\", fields: { ...block, type: block.type } };\n }\n return undefined;\n}\n\nfunction getReasoningDelta(content: unknown): string | undefined {\n if (content == null || typeof content !== \"object\") return undefined;\n const block = content as {\n type?: string;\n reasoning?: unknown;\n thinking?: unknown;\n };\n if (block.type === \"reasoning\" && typeof block.reasoning === \"string\") {\n return block.reasoning;\n }\n if (block.type === \"thinking\" && typeof block.thinking === \"string\") {\n return block.thinking;\n }\n return undefined;\n}\n\nfunction isReasoningContent(content: unknown): boolean {\n if (content == null || typeof content !== \"object\") return false;\n const type = (content as { type?: unknown }).type;\n return type === \"reasoning\" || type === \"thinking\";\n}\n\n/**\n * Normalize protocol-compatible partial usage into Core's concrete usage shape.\n *\n * Some stream sources emit usage snapshots without every aggregate token field.\n * Keep the stream event input permissive, then normalize at read time so\n * high-level Core consumers always receive a complete {@link UsageMetadata}.\n */\nfunction normalizeUsage(\n usage: UsageMetadataLike | undefined\n): UsageMetadata | undefined {\n if (!usage) return undefined;\n return {\n ...usage,\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n };\n}\n\nfunction parseToolArgs(value: unknown): Record<string, unknown> {\n if (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n if (typeof value !== \"string\" || value.length === 0) return {};\n try {\n const parsed = JSON.parse(value);\n return parsed != null &&\n typeof parsed === \"object\" &&\n !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n}\n\nfunction standardizeToolBlock(block: ContentBlock): ContentBlock {\n const record = block as Record<string, unknown>;\n if (block.type === \"tool_call\") return block;\n if (\n block.type !== \"tool_call_chunk\" &&\n block.type !== \"tool_use\" &&\n block.type !== \"input_json_delta\"\n ) {\n return block;\n }\n\n const name = typeof record.name === \"string\" ? record.name : undefined;\n if (name == null) return block;\n\n const args = record.args ?? record.input;\n return {\n ...record,\n type: \"tool_call\",\n name,\n args: parseToolArgs(args),\n } as ContentBlock;\n}\n\n// ─── Sub-Stream: Text ───────────────────────────────────────────\n\n/**\n * Typed stream for text content.\n *\n * - **Iterate**: yields incremental text deltas.\n * - **Await**: resolves to the complete concatenated text.\n * - **`.full`**: yields the running accumulated text after each delta.\n */\nexport class TextContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n /** Yields the accumulated text so far after each delta. */\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n accumulated += delta.text;\n yield accumulated;\n }\n }\n },\n };\n }\n\n /** Yields incremental text deltas. */\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n const delta = getEventDelta(event);\n if (delta?.type === \"text-delta\") {\n yield delta.text;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Tool Calls ─────────────────────────────────────\n\n/**\n * Typed stream for tool calls.\n *\n * - **Iterate**: yields individual `ToolCall` objects as each completes.\n * - **Await**: resolves to the full array.\n * - **`.full`**: yields the accumulated array after each new tool call.\n */\nexport class ToolCallsStream\n implements\n AsyncIterable<ContentBlock.Tools.ToolCall>,\n PromiseLike<Array<ContentBlock.Tools.ToolCall>>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<Array<ContentBlock.Tools.ToolCall>> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n calls.push(event.content as ContentBlock.Tools.ToolCall);\n yield [...calls];\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ContentBlock.Tools.ToolCall> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (\n event.event === \"content-block-finish\" &&\n event.content.type === \"tool_call\"\n ) {\n yield event.content as ContentBlock.Tools.ToolCall;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = Array<ContentBlock.Tools.ToolCall>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: Array<ContentBlock.Tools.ToolCall>\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n const calls: Array<ContentBlock.Tools.ToolCall> = [];\n for await (const call of this) {\n calls.push(call);\n }\n return calls;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Reasoning ──────────────────────────────────────\n\n/**\n * Typed stream for reasoning content (chain-of-thought).\n * Same interface as {@link TextContentStream} but for reasoning blocks.\n */\nexport class ReasoningContentStream\n implements AsyncIterable<string>, PromiseLike<string>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n get full(): AsyncIterable<string> {\n const buffer = this._buffer;\n return {\n async *[Symbol.asyncIterator]() {\n let accumulated = \"\";\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta == null || delta.length === 0) continue;\n accumulated += delta;\n yield accumulated;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n },\n };\n }\n\n [Symbol.asyncIterator](): AsyncIterator<string> {\n const buffer = this._buffer;\n async function* gen() {\n let seenReasoning = false;\n for await (const event of buffer.iterate()) {\n if (event.event === \"content-block-start\") {\n if (!isReasoningContent(event.content)) {\n if (seenReasoning) return;\n continue;\n }\n seenReasoning = true;\n const delta = getReasoningDelta(event.content);\n if (delta != null && delta.length > 0) yield delta;\n } else if (event.event === \"content-block-delta\") {\n const eventDelta = getEventDelta(event);\n if (eventDelta?.type !== \"reasoning-delta\") continue;\n seenReasoning = true;\n const delta = eventDelta.reasoning;\n if (delta != null && delta.length > 0) yield delta;\n } else if (\n event.event === \"content-block-finish\" &&\n isReasoningContent(event.content)\n ) {\n return;\n } else if (event.event === \"message-finish\") {\n return;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = string, TResult2 = never>(\n onfulfilled?: ((value: string) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let text = \"\";\n for await (const delta of this) {\n text += delta;\n }\n return text;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── Sub-Stream: Usage ──────────────────────────────────────────\n\n/**\n * Typed stream for usage metadata.\n */\nexport class UsageMetadataStream\n implements\n AsyncIterable<UsageMetadata>,\n PromiseLike<UsageMetadata | undefined>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(buffer: ReplayBuffer) {\n this._buffer = buffer;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<UsageMetadata> {\n const buffer = this._buffer;\n async function* gen() {\n for await (const event of buffer.iterate()) {\n if (event.event === \"usage\") {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-start\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n } else if (event.event === \"message-finish\" && event.usage) {\n const usage = normalizeUsage(event.usage);\n if (usage) yield usage;\n }\n }\n }\n return gen();\n }\n\n then<TResult1 = UsageMetadata | undefined, TResult2 = never>(\n onfulfilled?:\n | ((value: UsageMetadata | undefined) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n const promise = (async () => {\n let latest: UsageMetadata | undefined;\n for await (const usage of this) {\n latest = usage;\n }\n return latest;\n })();\n return promise.then(onfulfilled, onrejected);\n }\n}\n\n// ─── ChatModelStream ────────────────────────────────────────────\n\n/**\n * The main stream object returned by chat model streaming.\n *\n * Implements `AsyncIterable<ChatModelStreamEvent>` for raw event access\n * and `PromiseLike<AIMessage>` for simple `await` usage.\n */\nexport class ChatModelStream\n implements AsyncIterable<ChatModelStreamEvent>, PromiseLike<AIMessage>\n{\n /** @internal */\n private _buffer: ReplayBuffer;\n\n /** @internal */\n constructor(source: AsyncIterable<ChatModelStreamEvent>) {\n this._buffer = new ReplayBuffer();\n this._consume(source);\n }\n\n /** @internal */\n private async _consume(\n source: AsyncIterable<ChatModelStreamEvent>\n ): Promise<void> {\n try {\n for await (const event of source) {\n this._buffer.push(event);\n }\n this._buffer.finish();\n } catch (err) {\n this._buffer.setError(\n err instanceof Error ? err : new Error(String(err))\n );\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<ChatModelStreamEvent> {\n return this._buffer.iterate();\n }\n\n get text(): TextContentStream {\n return new TextContentStream(this._buffer);\n }\n\n get toolCalls(): ToolCallsStream {\n return new ToolCallsStream(this._buffer);\n }\n\n get reasoning(): ReasoningContentStream {\n return new ReasoningContentStream(this._buffer);\n }\n\n get usage(): UsageMetadataStream {\n return new UsageMetadataStream(this._buffer);\n }\n\n get output(): PromiseLike<AIMessage> {\n return this._assembleMessage();\n }\n\n then<TResult1 = AIMessage, TResult2 = never>(\n onfulfilled?:\n | ((value: AIMessage) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): PromiseLike<TResult1 | TResult2> {\n return this._assembleMessage().then(onfulfilled, onrejected);\n }\n\n /** @internal */\n private async _assembleMessage(): Promise<AIMessage> {\n const contentBlocks: Array<ContentBlock | undefined> = [];\n let id: string | undefined;\n let usage: UsageMetadata | undefined;\n let metadata: Record<string, unknown> = {};\n let finishReason: string | undefined;\n\n for await (const event of this._buffer.iterate()) {\n switch (event.event) {\n case \"message-start\":\n id = event.id ?? id;\n if (event.usage) usage = normalizeUsage(event.usage);\n break;\n\n case \"content-block-start\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"content-block-delta\": {\n const current = contentBlocks[event.index];\n const delta = getEventDelta(event);\n if (current) {\n if (delta) contentBlocks[event.index] = applyDelta(current, delta);\n }\n break;\n }\n\n case \"content-block-finish\":\n contentBlocks[event.index] = event.content;\n break;\n\n case \"usage\":\n usage = normalizeUsage(event.usage);\n break;\n\n case \"message-finish\":\n finishReason = event.reason;\n if (event.usage) usage = normalizeUsage(event.usage);\n if (event.responseMetadata) {\n metadata = {\n ...metadata,\n ...event.responseMetadata,\n };\n }\n break;\n\n default:\n break;\n }\n }\n\n const filteredBlocks = contentBlocks\n .filter((b): b is ContentBlock => b != null)\n .map(standardizeToolBlock);\n\n return new AIMessage({\n id,\n content: filteredBlocks,\n usage_metadata: usage,\n response_metadata: {\n ...metadata,\n ...(finishReason ? { finish_reason: finishReason } : {}),\n output_version: \"v1\" as const,\n },\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/load/index.cjs
CHANGED
|
@@ -25,6 +25,21 @@ const require_import_map = require("./import_map.cjs");
|
|
|
25
25
|
*
|
|
26
26
|
* When deserializing, the class path is validated against supported namespaces.
|
|
27
27
|
*
|
|
28
|
+
* ## Threat model
|
|
29
|
+
*
|
|
30
|
+
* A serialized LangChain payload crosses a trust boundary because the manifest
|
|
31
|
+
* may contain serialized objects and configuration that affect runtime behavior.
|
|
32
|
+
* For example, a payload can configure a chat model with a custom `base_url`,
|
|
33
|
+
* custom headers, a different model name, or other constructor arguments. These
|
|
34
|
+
* are supported features, but they also mean the payload contents should be
|
|
35
|
+
* treated as executable configuration rather than plain text.
|
|
36
|
+
*
|
|
37
|
+
* Concretely, deserialization instantiates classes, so any constructor on an
|
|
38
|
+
* allowed class will run during `load()`. A crafted payload that is allowed to
|
|
39
|
+
* reach an unintended class — or an intended class with attacker-controlled
|
|
40
|
+
* kwargs — could cause network calls, file operations, or environment-variable
|
|
41
|
+
* access while the object is being built.
|
|
42
|
+
*
|
|
28
43
|
* ## Security model
|
|
29
44
|
*
|
|
30
45
|
* The `secretsFromEnv` parameter controls whether secrets can be loaded from environment
|
|
@@ -163,6 +178,10 @@ async function reviver(value) {
|
|
|
163
178
|
* instantiates arbitrary allowed classes with attacker-controlled arguments,
|
|
164
179
|
* potentially causing secret exfiltration, SSRF, or other side effects.
|
|
165
180
|
*
|
|
181
|
+
* A serialized payload should be treated as executable configuration — it can
|
|
182
|
+
* configure models with custom endpoints, headers, or other constructor kwargs
|
|
183
|
+
* that execute during instantiation.
|
|
184
|
+
*
|
|
166
185
|
* Only call `load()` on data you have produced yourself or received from a
|
|
167
186
|
* fully trusted origin (e.g., your own database). **Never deserialize
|
|
168
187
|
* user-supplied or network-received JSON without independent validation.**
|
package/dist/load/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["isEscapedObject","unescapeValue","getEnvironmentVariable","coreImportMap","defaultOptionalImportEntrypoints","optionalImportEntrypoints","get_lc_unique_name","mapKeys","keyFromJson"],"sources":["../../src/load/index.ts"],"sourcesContent":["/**\n * Load LangChain objects from JSON strings or objects.\n *\n * **WARNING: `load()` deserializes data by instantiating classes and invoking\n * constructors. Never call `load()` on untrusted or user-supplied input.**\n * Doing so can lead to insecure deserialization — including arbitrary class\n * instantiation, secret exfiltration, and server-side request forgery (SSRF).\n * Only deserialize data that originates from a trusted source you control.\n *\n * ## How it works\n *\n * Each `Serializable` LangChain object has a unique identifier (its \"class path\"),\n * which is a list of strings representing the module path and class name. For example:\n *\n * - `AIMessage` -> `[\"langchain_core\", \"messages\", \"ai\", \"AIMessage\"]`\n * - `ChatPromptTemplate` -> `[\"langchain_core\", \"prompts\", \"chat\", \"ChatPromptTemplate\"]`\n *\n * When deserializing, the class path is validated against supported namespaces.\n *\n * ## Security model\n *\n * The `secretsFromEnv` parameter controls whether secrets can be loaded from environment\n * variables:\n *\n * - `false` (default): Secrets must be provided in `secretsMap`. If a secret is not\n * found, `null` is returned instead of loading from environment variables.\n * - `true`: If a secret is not found in `secretsMap`, it will be loaded from\n * environment variables. Use this only in trusted environments.\n *\n * ### Hardening recommendations\n *\n * - **Never enable `secretsFromEnv`** unless the serialized data is fully trusted.\n * A crafted payload can reference arbitrary environment variable names, leaking\n * secrets to an attacker-controlled class constructor.\n * - **Keep `secretsMap` minimal.** Only include the specific secrets the serialized\n * object actually needs.\n * - **Keep `importMap` / `optionalImportsMap` as small and static as possible.**\n * Each entry widens the set of classes an attacker can instantiate. Never\n * populate these maps from user input.\n *\n * ### Injection protection (escape-based)\n *\n * During serialization, plain objects that contain an `'lc'` key are escaped by wrapping\n * them: `{\"__lc_escaped__\": {...}}`. During deserialization, escaped objects are unwrapped\n * and returned as plain objects, NOT instantiated as LC objects.\n *\n * This is an allowlist approach: only objects explicitly produced by\n * `Serializable.toJSON()` (which are NOT escaped) are treated as LC objects;\n * everything else is user data.\n *\n * @module\n */\n\nimport {\n Serializable,\n SerializedConstructor,\n SerializedNotImplemented,\n SerializedSecret,\n get_lc_unique_name,\n} from \"./serializable.js\";\nimport { optionalImportEntrypoints as defaultOptionalImportEntrypoints } from \"./import_constants.js\";\nimport * as coreImportMap from \"./import_map.js\";\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nimport { type SerializedFields, keyFromJson, mapKeys } from \"./map_keys.js\";\nimport { getEnvironmentVariable } from \"../utils/env.js\";\nimport { isEscapedObject, unescapeValue } from \"./validation.js\";\n\n/**\n * Options for loading serialized LangChain objects.\n *\n * @remarks\n * **Security considerations:**\n *\n * Deserialization can instantiate arbitrary classes from the allowed namespaces.\n * When loading untrusted data, be aware that:\n *\n * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the\n * deserializer to read environment variables, which could leak secrets if\n * the serialized data contains malicious secret references.\n *\n * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes\n * can be instantiated. Never populate these from user input. Only include\n * modules you explicitly trust.\n *\n * 3. **Class instantiation**: Allowed classes will have their constructors called\n * with the deserialized kwargs. If a class performs side effects in its\n * constructor (network calls, file I/O, etc.), those will execute.\n */\nexport interface LoadOptions {\n /**\n * A map of secrets to load. Keys are secret identifiers, values are the secret values.\n *\n * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is\n * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment\n * variables (if not found there either, an error is thrown).\n */\n secretsMap?: SecretMap;\n\n /**\n * Whether to load secrets from environment variables when not found in `secretsMap`.\n *\n * @default false\n *\n * @remarks\n * **Security warning:** Setting this to `true` allows the deserializer to read\n * environment variables, which could be a security risk if the serialized data\n * is not trusted. Only set this to `true` when deserializing data from trusted\n * sources (e.g., your own database, not user input).\n */\n secretsFromEnv?: boolean;\n\n /**\n * A map of optional imports. Keys are namespace paths (e.g., \"langchain_community/llms\"),\n * values are the imported modules.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Classes in these modules can be instantiated with attacker-controlled kwargs\n * if the serialized data is untrusted.\n */\n optionalImportsMap?: OptionalImportMap;\n\n /**\n * Additional optional import entrypoints to allow beyond the defaults.\n *\n * @remarks\n * **Security warning:** This extends which namespace paths are considered valid\n * for deserialization. Never populate this array with values derived from user\n * input. Each entrypoint you add expands the attack surface for deserialization.\n */\n optionalImportEntrypoints?: string[];\n\n /**\n * Additional import map for the \"langchain\" namespace.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Any class exposed through this map can be instantiated with attacker-controlled\n * kwargs if the serialized data is untrusted.\n */\n importMap?: Record<string, unknown>;\n\n /**\n * Maximum recursion depth allowed during deserialization.\n *\n * @default 50\n *\n * @remarks\n * This limit protects against denial-of-service attacks using deeply nested\n * JSON structures that could cause stack overflow. If your legitimate data\n * requires deeper nesting, you can increase this limit.\n */\n maxDepth?: number;\n}\n\n/**\n * Default maximum recursion depth for deserialization.\n * This provides protection against DoS attacks via deeply nested structures.\n */\nconst DEFAULT_MAX_DEPTH = 50;\n\nfunction combineAliasesAndInvert(constructor: typeof Serializable) {\n const aliases: { [key: string]: string } = {};\n for (\n let current = constructor;\n current && current.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n Object.assign(aliases, Reflect.get(current.prototype, \"lc_aliases\"));\n }\n return Object.entries(aliases).reduce(\n (acc, [key, value]) => {\n acc[value] = key;\n return acc;\n },\n {} as Record<string, string>\n );\n}\n\ninterface ReviverContext {\n optionalImportsMap: OptionalImportMap;\n optionalImportEntrypoints: string[];\n secretsMap: SecretMap;\n secretsFromEnv: boolean;\n importMap: Record<string, unknown>;\n path: string[];\n depth: number;\n maxDepth: number;\n}\n\n/**\n * Recursively revive a value, handling escape markers and LC objects.\n *\n * This function handles:\n * 1. Escaped dicts - unwrapped and returned as plain objects\n * 2. LC secret objects - resolved from secretsMap or env\n * 3. LC constructor objects - instantiated\n * 4. Regular objects/arrays - recursed into\n */\nasync function reviver(this: ReviverContext, value: unknown): Promise<unknown> {\n const {\n optionalImportsMap,\n optionalImportEntrypoints,\n importMap,\n secretsMap,\n secretsFromEnv,\n path,\n depth,\n maxDepth,\n } = this;\n const pathStr = path.join(\".\");\n\n // Check recursion depth to prevent DoS via deeply nested structures\n if (depth > maxDepth) {\n throw new Error(\n `Maximum recursion depth (${maxDepth}) exceeded during deserialization. ` +\n `This may indicate a malicious payload or you may need to increase maxDepth.`\n );\n }\n\n // If not an object, return as-is\n if (typeof value !== \"object\" || value == null) {\n return value;\n }\n\n // Handle arrays - recurse into elements\n if (Array.isArray(value)) {\n return Promise.all(\n value.map((v, i) =>\n reviver.call({ ...this, path: [...path, `${i}`], depth: depth + 1 }, v)\n )\n );\n }\n\n // It's an object - check for escape marker FIRST\n const record = value as Record<string, unknown>;\n if (isEscapedObject(record)) {\n // This is an escaped user object - unwrap and return as-is (no LC processing)\n return unescapeValue(record);\n }\n\n // Check for LC secret object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"secret\"\n ) {\n const serialized = record as unknown as SerializedSecret;\n const [key] = serialized.id;\n if (key in secretsMap) {\n return secretsMap[key as keyof SecretMap];\n } else if (secretsFromEnv) {\n const secretValueInEnv = getEnvironmentVariable(key);\n if (secretValueInEnv) {\n return secretValueInEnv;\n }\n }\n throw new Error(`Missing secret \"${key}\" at ${pathStr}`);\n }\n\n // Check for LC not_implemented object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"not_implemented\"\n ) {\n const serialized = record as unknown as SerializedNotImplemented;\n const str = JSON.stringify(serialized);\n throw new Error(\n `Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`\n );\n }\n\n // Check for LC constructor object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n \"kwargs\" in record &&\n record.lc === 1 &&\n record.type === \"constructor\"\n ) {\n const serialized = record as unknown as SerializedConstructor;\n const str = JSON.stringify(serialized);\n const [name, ...namespaceReverse] = serialized.id.slice().reverse();\n const namespace = namespaceReverse.reverse();\n const importMaps = { langchain_core: coreImportMap, langchain: importMap };\n\n let module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null = null;\n\n const optionalImportNamespaceAliases = [namespace.join(\"/\")];\n if (namespace[0] === \"langchain_community\") {\n optionalImportNamespaceAliases.push(\n [\"langchain\", ...namespace.slice(1)].join(\"/\")\n );\n }\n const matchingNamespaceAlias = optionalImportNamespaceAliases.find(\n (alias) => alias in optionalImportsMap\n );\n if (\n defaultOptionalImportEntrypoints\n .concat(optionalImportEntrypoints)\n .includes(namespace.join(\"/\")) ||\n matchingNamespaceAlias\n ) {\n if (matchingNamespaceAlias !== undefined) {\n module =\n await optionalImportsMap[\n matchingNamespaceAlias as keyof typeof optionalImportsMap\n ];\n } else {\n throw new Error(\n `Missing key \"${namespace.join(\n \"/\"\n )}\" for ${pathStr} in load(optionalImportsMap={})`\n );\n }\n } else {\n let finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"];\n // Currently, we only support langchain and langchain_core imports.\n if (namespace[0] === \"langchain\" || namespace[0] === \"langchain_core\") {\n finalImportMap = importMaps[namespace[0]];\n namespace.shift();\n } else {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // The root namespace \"langchain\" is not a valid import.\n if (namespace.length === 0) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Find the longest matching namespace.\n let importMapKey: string;\n do {\n importMapKey = namespace.join(\"__\");\n if (importMapKey in finalImportMap) {\n break;\n } else {\n namespace.pop();\n }\n } while (namespace.length > 0);\n\n // If no matching namespace is found, throw an error.\n if (importMapKey in finalImportMap) {\n module = finalImportMap[importMapKey as keyof typeof finalImportMap];\n }\n }\n\n if (typeof module !== \"object\" || module === null) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Extract the builder from the import map.\n const builder =\n // look for a named export with the same name as the class\n module[name as keyof typeof module] ??\n // look for an export with a lc_name property matching the class name\n // this is necessary for classes that are minified\n Object.values(module).find(\n (v) =>\n typeof v === \"function\" &&\n get_lc_unique_name(v as typeof Serializable) === name\n );\n if (typeof builder !== \"function\") {\n throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);\n }\n\n // Recurse on the arguments, which may be serialized objects themselves\n const kwargs = await reviver.call(\n { ...this, path: [...path, \"kwargs\"], depth: depth + 1 },\n serialized.kwargs\n );\n\n // Construct the object\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const instance = new (builder as any)(\n mapKeys(\n kwargs as SerializedFields,\n keyFromJson,\n combineAliasesAndInvert(builder)\n )\n );\n\n // Minification in severless/edge runtimes will mange the\n // name of classes presented in traces. As the names in import map\n // are present as-is even with minification, use these names instead\n Object.defineProperty(instance.constructor, \"name\", { value: name });\n\n return instance;\n }\n\n // Regular object - recurse into values\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n result[key] = await reviver.call(\n { ...this, path: [...path, key], depth: depth + 1 },\n val\n );\n }\n return result;\n}\n\n/**\n * Load a LangChain object from a JSON string.\n *\n * **WARNING — insecure deserialization risk.** This function instantiates\n * classes and invokes constructors based on the contents of `text`. If `text`\n * originates from an untrusted source, an attacker can craft a payload that\n * instantiates arbitrary allowed classes with attacker-controlled arguments,\n * potentially causing secret exfiltration, SSRF, or other side effects.\n *\n * Only call `load()` on data you have produced yourself or received from a\n * fully trusted origin (e.g., your own database). **Never deserialize\n * user-supplied or network-received JSON without independent validation.**\n *\n * @param text - The JSON string to parse and load.\n * @param options - Options for loading. See {@link LoadOptions} for security guidance.\n * @returns The loaded LangChain object.\n *\n * @example\n * ```typescript\n * import { load } from \"@langchain/core/load\";\n * import { AIMessage } from \"@langchain/core/messages\";\n *\n * // Basic usage - secrets must be provided explicitly\n * const msg = await load<AIMessage>(jsonString);\n *\n * // With secrets from a map (preferred over secretsFromEnv)\n * const msg = await load<AIMessage>(jsonString, {\n * secretsMap: { OPENAI_API_KEY: \"sk-...\" }\n * });\n *\n * // Allow loading secrets from environment — ONLY for fully trusted data\n * const msg = await load<AIMessage>(jsonString, {\n * secretsFromEnv: true\n * });\n * ```\n */\nexport async function load<T>(text: string, options?: LoadOptions): Promise<T> {\n const json = JSON.parse(text);\n\n const context: ReviverContext = {\n optionalImportsMap: options?.optionalImportsMap ?? {},\n optionalImportEntrypoints: options?.optionalImportEntrypoints ?? [],\n secretsMap: options?.secretsMap ?? {},\n secretsFromEnv: options?.secretsFromEnv ?? false,\n importMap: options?.importMap ?? {},\n path: [\"$\"],\n depth: 0,\n maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n };\n\n return reviver.call(context, json) as Promise<T>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["isEscapedObject","unescapeValue","getEnvironmentVariable","coreImportMap","defaultOptionalImportEntrypoints","optionalImportEntrypoints","get_lc_unique_name","mapKeys","keyFromJson"],"sources":["../../src/load/index.ts"],"sourcesContent":["/**\n * Load LangChain objects from JSON strings or objects.\n *\n * **WARNING: `load()` deserializes data by instantiating classes and invoking\n * constructors. Never call `load()` on untrusted or user-supplied input.**\n * Doing so can lead to insecure deserialization — including arbitrary class\n * instantiation, secret exfiltration, and server-side request forgery (SSRF).\n * Only deserialize data that originates from a trusted source you control.\n *\n * ## How it works\n *\n * Each `Serializable` LangChain object has a unique identifier (its \"class path\"),\n * which is a list of strings representing the module path and class name. For example:\n *\n * - `AIMessage` -> `[\"langchain_core\", \"messages\", \"ai\", \"AIMessage\"]`\n * - `ChatPromptTemplate` -> `[\"langchain_core\", \"prompts\", \"chat\", \"ChatPromptTemplate\"]`\n *\n * When deserializing, the class path is validated against supported namespaces.\n *\n * ## Threat model\n *\n * A serialized LangChain payload crosses a trust boundary because the manifest\n * may contain serialized objects and configuration that affect runtime behavior.\n * For example, a payload can configure a chat model with a custom `base_url`,\n * custom headers, a different model name, or other constructor arguments. These\n * are supported features, but they also mean the payload contents should be\n * treated as executable configuration rather than plain text.\n *\n * Concretely, deserialization instantiates classes, so any constructor on an\n * allowed class will run during `load()`. A crafted payload that is allowed to\n * reach an unintended class — or an intended class with attacker-controlled\n * kwargs — could cause network calls, file operations, or environment-variable\n * access while the object is being built.\n *\n * ## Security model\n *\n * The `secretsFromEnv` parameter controls whether secrets can be loaded from environment\n * variables:\n *\n * - `false` (default): Secrets must be provided in `secretsMap`. If a secret is not\n * found, `null` is returned instead of loading from environment variables.\n * - `true`: If a secret is not found in `secretsMap`, it will be loaded from\n * environment variables. Use this only in trusted environments.\n *\n * ### Hardening recommendations\n *\n * - **Never enable `secretsFromEnv`** unless the serialized data is fully trusted.\n * A crafted payload can reference arbitrary environment variable names, leaking\n * secrets to an attacker-controlled class constructor.\n * - **Keep `secretsMap` minimal.** Only include the specific secrets the serialized\n * object actually needs.\n * - **Keep `importMap` / `optionalImportsMap` as small and static as possible.**\n * Each entry widens the set of classes an attacker can instantiate. Never\n * populate these maps from user input.\n *\n * ### Injection protection (escape-based)\n *\n * During serialization, plain objects that contain an `'lc'` key are escaped by wrapping\n * them: `{\"__lc_escaped__\": {...}}`. During deserialization, escaped objects are unwrapped\n * and returned as plain objects, NOT instantiated as LC objects.\n *\n * This is an allowlist approach: only objects explicitly produced by\n * `Serializable.toJSON()` (which are NOT escaped) are treated as LC objects;\n * everything else is user data.\n *\n * @module\n */\n\nimport {\n Serializable,\n SerializedConstructor,\n SerializedNotImplemented,\n SerializedSecret,\n get_lc_unique_name,\n} from \"./serializable.js\";\nimport { optionalImportEntrypoints as defaultOptionalImportEntrypoints } from \"./import_constants.js\";\nimport * as coreImportMap from \"./import_map.js\";\nimport type { OptionalImportMap, SecretMap } from \"./import_type.js\";\nimport { type SerializedFields, keyFromJson, mapKeys } from \"./map_keys.js\";\nimport { getEnvironmentVariable } from \"../utils/env.js\";\nimport { isEscapedObject, unescapeValue } from \"./validation.js\";\n\n/**\n * Options for loading serialized LangChain objects.\n *\n * @remarks\n * **Security considerations:**\n *\n * Deserialization can instantiate arbitrary classes from the allowed namespaces.\n * When loading untrusted data, be aware that:\n *\n * 1. **`secretsFromEnv`**: Defaults to `false`. Setting to `true` allows the\n * deserializer to read environment variables, which could leak secrets if\n * the serialized data contains malicious secret references.\n *\n * 2. **`importMap` / `optionalImportsMap`**: These allow extending which classes\n * can be instantiated. Never populate these from user input. Only include\n * modules you explicitly trust.\n *\n * 3. **Class instantiation**: Allowed classes will have their constructors called\n * with the deserialized kwargs. If a class performs side effects in its\n * constructor (network calls, file I/O, etc.), those will execute.\n */\nexport interface LoadOptions {\n /**\n * A map of secrets to load. Keys are secret identifiers, values are the secret values.\n *\n * If a secret is not found in this map and `secretsFromEnv` is `false`, an error is\n * thrown. If `secretsFromEnv` is `true`, the secret will be loaded from environment\n * variables (if not found there either, an error is thrown).\n */\n secretsMap?: SecretMap;\n\n /**\n * Whether to load secrets from environment variables when not found in `secretsMap`.\n *\n * @default false\n *\n * @remarks\n * **Security warning:** Setting this to `true` allows the deserializer to read\n * environment variables, which could be a security risk if the serialized data\n * is not trusted. Only set this to `true` when deserializing data from trusted\n * sources (e.g., your own database, not user input).\n */\n secretsFromEnv?: boolean;\n\n /**\n * A map of optional imports. Keys are namespace paths (e.g., \"langchain_community/llms\"),\n * values are the imported modules.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Classes in these modules can be instantiated with attacker-controlled kwargs\n * if the serialized data is untrusted.\n */\n optionalImportsMap?: OptionalImportMap;\n\n /**\n * Additional optional import entrypoints to allow beyond the defaults.\n *\n * @remarks\n * **Security warning:** This extends which namespace paths are considered valid\n * for deserialization. Never populate this array with values derived from user\n * input. Each entrypoint you add expands the attack surface for deserialization.\n */\n optionalImportEntrypoints?: string[];\n\n /**\n * Additional import map for the \"langchain\" namespace.\n *\n * @remarks\n * **Security warning:** This extends which classes can be instantiated during\n * deserialization. Never populate this map with values derived from user input.\n * Only include modules that you explicitly trust and have reviewed.\n *\n * Any class exposed through this map can be instantiated with attacker-controlled\n * kwargs if the serialized data is untrusted.\n */\n importMap?: Record<string, unknown>;\n\n /**\n * Maximum recursion depth allowed during deserialization.\n *\n * @default 50\n *\n * @remarks\n * This limit protects against denial-of-service attacks using deeply nested\n * JSON structures that could cause stack overflow. If your legitimate data\n * requires deeper nesting, you can increase this limit.\n */\n maxDepth?: number;\n}\n\n/**\n * Default maximum recursion depth for deserialization.\n * This provides protection against DoS attacks via deeply nested structures.\n */\nconst DEFAULT_MAX_DEPTH = 50;\n\nfunction combineAliasesAndInvert(constructor: typeof Serializable) {\n const aliases: { [key: string]: string } = {};\n for (\n let current = constructor;\n current && current.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n Object.assign(aliases, Reflect.get(current.prototype, \"lc_aliases\"));\n }\n return Object.entries(aliases).reduce(\n (acc, [key, value]) => {\n acc[value] = key;\n return acc;\n },\n {} as Record<string, string>\n );\n}\n\ninterface ReviverContext {\n optionalImportsMap: OptionalImportMap;\n optionalImportEntrypoints: string[];\n secretsMap: SecretMap;\n secretsFromEnv: boolean;\n importMap: Record<string, unknown>;\n path: string[];\n depth: number;\n maxDepth: number;\n}\n\n/**\n * Recursively revive a value, handling escape markers and LC objects.\n *\n * This function handles:\n * 1. Escaped dicts - unwrapped and returned as plain objects\n * 2. LC secret objects - resolved from secretsMap or env\n * 3. LC constructor objects - instantiated\n * 4. Regular objects/arrays - recursed into\n */\nasync function reviver(this: ReviverContext, value: unknown): Promise<unknown> {\n const {\n optionalImportsMap,\n optionalImportEntrypoints,\n importMap,\n secretsMap,\n secretsFromEnv,\n path,\n depth,\n maxDepth,\n } = this;\n const pathStr = path.join(\".\");\n\n // Check recursion depth to prevent DoS via deeply nested structures\n if (depth > maxDepth) {\n throw new Error(\n `Maximum recursion depth (${maxDepth}) exceeded during deserialization. ` +\n `This may indicate a malicious payload or you may need to increase maxDepth.`\n );\n }\n\n // If not an object, return as-is\n if (typeof value !== \"object\" || value == null) {\n return value;\n }\n\n // Handle arrays - recurse into elements\n if (Array.isArray(value)) {\n return Promise.all(\n value.map((v, i) =>\n reviver.call({ ...this, path: [...path, `${i}`], depth: depth + 1 }, v)\n )\n );\n }\n\n // It's an object - check for escape marker FIRST\n const record = value as Record<string, unknown>;\n if (isEscapedObject(record)) {\n // This is an escaped user object - unwrap and return as-is (no LC processing)\n return unescapeValue(record);\n }\n\n // Check for LC secret object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"secret\"\n ) {\n const serialized = record as unknown as SerializedSecret;\n const [key] = serialized.id;\n if (key in secretsMap) {\n return secretsMap[key as keyof SecretMap];\n } else if (secretsFromEnv) {\n const secretValueInEnv = getEnvironmentVariable(key);\n if (secretValueInEnv) {\n return secretValueInEnv;\n }\n }\n throw new Error(`Missing secret \"${key}\" at ${pathStr}`);\n }\n\n // Check for LC not_implemented object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n record.lc === 1 &&\n record.type === \"not_implemented\"\n ) {\n const serialized = record as unknown as SerializedNotImplemented;\n const str = JSON.stringify(serialized);\n throw new Error(\n `Trying to load an object that doesn't implement serialization: ${pathStr} -> ${str}`\n );\n }\n\n // Check for LC constructor object\n if (\n \"lc\" in record &&\n \"type\" in record &&\n \"id\" in record &&\n \"kwargs\" in record &&\n record.lc === 1 &&\n record.type === \"constructor\"\n ) {\n const serialized = record as unknown as SerializedConstructor;\n const str = JSON.stringify(serialized);\n const [name, ...namespaceReverse] = serialized.id.slice().reverse();\n const namespace = namespaceReverse.reverse();\n const importMaps = { langchain_core: coreImportMap, langchain: importMap };\n\n let module:\n | (typeof importMaps)[\"langchain_core\"][keyof (typeof importMaps)[\"langchain_core\"]]\n | (typeof importMaps)[\"langchain\"][keyof (typeof importMaps)[\"langchain\"]]\n | OptionalImportMap[keyof OptionalImportMap]\n | null = null;\n\n const optionalImportNamespaceAliases = [namespace.join(\"/\")];\n if (namespace[0] === \"langchain_community\") {\n optionalImportNamespaceAliases.push(\n [\"langchain\", ...namespace.slice(1)].join(\"/\")\n );\n }\n const matchingNamespaceAlias = optionalImportNamespaceAliases.find(\n (alias) => alias in optionalImportsMap\n );\n if (\n defaultOptionalImportEntrypoints\n .concat(optionalImportEntrypoints)\n .includes(namespace.join(\"/\")) ||\n matchingNamespaceAlias\n ) {\n if (matchingNamespaceAlias !== undefined) {\n module =\n await optionalImportsMap[\n matchingNamespaceAlias as keyof typeof optionalImportsMap\n ];\n } else {\n throw new Error(\n `Missing key \"${namespace.join(\n \"/\"\n )}\" for ${pathStr} in load(optionalImportsMap={})`\n );\n }\n } else {\n let finalImportMap:\n | (typeof importMaps)[\"langchain\"]\n | (typeof importMaps)[\"langchain_core\"];\n // Currently, we only support langchain and langchain_core imports.\n if (namespace[0] === \"langchain\" || namespace[0] === \"langchain_core\") {\n finalImportMap = importMaps[namespace[0]];\n namespace.shift();\n } else {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // The root namespace \"langchain\" is not a valid import.\n if (namespace.length === 0) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Find the longest matching namespace.\n let importMapKey: string;\n do {\n importMapKey = namespace.join(\"__\");\n if (importMapKey in finalImportMap) {\n break;\n } else {\n namespace.pop();\n }\n } while (namespace.length > 0);\n\n // If no matching namespace is found, throw an error.\n if (importMapKey in finalImportMap) {\n module = finalImportMap[importMapKey as keyof typeof finalImportMap];\n }\n }\n\n if (typeof module !== \"object\" || module === null) {\n throw new Error(`Invalid namespace: ${pathStr} -> ${str}`);\n }\n\n // Extract the builder from the import map.\n const builder =\n // look for a named export with the same name as the class\n module[name as keyof typeof module] ??\n // look for an export with a lc_name property matching the class name\n // this is necessary for classes that are minified\n Object.values(module).find(\n (v) =>\n typeof v === \"function\" &&\n get_lc_unique_name(v as typeof Serializable) === name\n );\n if (typeof builder !== \"function\") {\n throw new Error(`Invalid identifer: ${pathStr} -> ${str}`);\n }\n\n // Recurse on the arguments, which may be serialized objects themselves\n const kwargs = await reviver.call(\n { ...this, path: [...path, \"kwargs\"], depth: depth + 1 },\n serialized.kwargs\n );\n\n // Construct the object\n // oxlint-disable-next-line @typescript-eslint/no-explicit-any\n const instance = new (builder as any)(\n mapKeys(\n kwargs as SerializedFields,\n keyFromJson,\n combineAliasesAndInvert(builder)\n )\n );\n\n // Minification in severless/edge runtimes will mange the\n // name of classes presented in traces. As the names in import map\n // are present as-is even with minification, use these names instead\n Object.defineProperty(instance.constructor, \"name\", { value: name });\n\n return instance;\n }\n\n // Regular object - recurse into values\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(record)) {\n result[key] = await reviver.call(\n { ...this, path: [...path, key], depth: depth + 1 },\n val\n );\n }\n return result;\n}\n\n/**\n * Load a LangChain object from a JSON string.\n *\n * **WARNING — insecure deserialization risk.** This function instantiates\n * classes and invokes constructors based on the contents of `text`. If `text`\n * originates from an untrusted source, an attacker can craft a payload that\n * instantiates arbitrary allowed classes with attacker-controlled arguments,\n * potentially causing secret exfiltration, SSRF, or other side effects.\n *\n * A serialized payload should be treated as executable configuration — it can\n * configure models with custom endpoints, headers, or other constructor kwargs\n * that execute during instantiation.\n *\n * Only call `load()` on data you have produced yourself or received from a\n * fully trusted origin (e.g., your own database). **Never deserialize\n * user-supplied or network-received JSON without independent validation.**\n *\n * @param text - The JSON string to parse and load.\n * @param options - Options for loading. See {@link LoadOptions} for security guidance.\n * @returns The loaded LangChain object.\n *\n * @example\n * ```typescript\n * import { load } from \"@langchain/core/load\";\n * import { AIMessage } from \"@langchain/core/messages\";\n *\n * // Basic usage - secrets must be provided explicitly\n * const msg = await load<AIMessage>(jsonString);\n *\n * // With secrets from a map (preferred over secretsFromEnv)\n * const msg = await load<AIMessage>(jsonString, {\n * secretsMap: { OPENAI_API_KEY: \"sk-...\" }\n * });\n *\n * // Allow loading secrets from environment — ONLY for fully trusted data\n * const msg = await load<AIMessage>(jsonString, {\n * secretsFromEnv: true\n * });\n * ```\n */\nexport async function load<T>(text: string, options?: LoadOptions): Promise<T> {\n const json = JSON.parse(text);\n\n const context: ReviverContext = {\n optionalImportsMap: options?.optionalImportsMap ?? {},\n optionalImportEntrypoints: options?.optionalImportEntrypoints ?? [],\n secretsMap: options?.secretsMap ?? {},\n secretsFromEnv: options?.secretsFromEnv ?? false,\n importMap: options?.importMap ?? {},\n path: [\"$\"],\n depth: 0,\n maxDepth: options?.maxDepth ?? DEFAULT_MAX_DEPTH,\n };\n\n return reviver.call(context, json) as Promise<T>;\n}\n"],"mappings":"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"}
|
package/dist/load/index.d.cts
CHANGED
|
@@ -98,6 +98,10 @@ interface LoadOptions {
|
|
|
98
98
|
* instantiates arbitrary allowed classes with attacker-controlled arguments,
|
|
99
99
|
* potentially causing secret exfiltration, SSRF, or other side effects.
|
|
100
100
|
*
|
|
101
|
+
* A serialized payload should be treated as executable configuration — it can
|
|
102
|
+
* configure models with custom endpoints, headers, or other constructor kwargs
|
|
103
|
+
* that execute during instantiation.
|
|
104
|
+
*
|
|
101
105
|
* Only call `load()` on data you have produced yourself or received from a
|
|
102
106
|
* fully trusted origin (e.g., your own database). **Never deserialize
|
|
103
107
|
* user-supplied or network-received JSON without independent validation.**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/load/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/load/index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;UAuGiB,WAAA;;;;;;;;EAQf,UAAA,GAAa,SAAA;;;;;;;;;;;;EAab,cAAA;;;;;;;;;;;;;EAcA,kBAAA,GAAqB,iBAAA;;;;;;;;;EAUrB,yBAAA;;;;;;;;;;;;EAaA,SAAA,GAAY,MAAA;;;;;;;;;;;EAYZ,QAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6SoB,IAAA,GAAA,CAAQ,IAAA,UAAc,OAAA,GAAU,WAAA,GAAc,OAAA,CAAQ,CAAA"}
|