Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
const require_ai = require("../messages/ai.cjs");
//#region src/language_models/stream.ts
/**
* Typed stream classes for chat model streaming.
*
* @module
*/
var stream_exports = /* @__PURE__ */ require_runtime.__exportAll({
	ChatModelStream: () => ChatModelStream,
	ReasoningContentStream: () => ReasoningContentStream,
	TextContentStream: () => TextContentStream,
	ToolCallsStream: () => ToolCallsStream,
	UsageMetadataStream: () => UsageMetadataStream
});
/**
* A buffer that caches emitted events for replay.
*
* Multiple consumers can independently iterate the same buffer —
* each gets its own cursor. Events are never consumed or removed.
*
* @internal
*/
var ReplayBuffer = class {
	events = [];
	finished = false;
	waiters = [];
	error = null;
	push(event) {
		this.events.push(event);
		const toWake = this.waiters.splice(0);
		for (const waiter of toWake) waiter();
	}
	finish() {
		this.finished = true;
		const toWake = this.waiters.splice(0);
		for (const waiter of toWake) waiter();
	}
	setError(err) {
		this.error = err;
		this.finished = true;
		const toWake = this.waiters.splice(0);
		for (const waiter of toWake) waiter();
	}
	async *iterate() {
		if (this.finished) {
			if (this.error) throw this.error;
			yield* this.events;
			return;
		}
		let cursor = 0;
		while (true) {
			while (cursor < this.events.length) {
				yield this.events[cursor];
				cursor++;
			}
			if (this.finished) {
				if (this.error) throw this.error;
				return;
			}
			await new Promise((resolve) => {
				if (cursor < this.events.length || this.finished) {
					resolve();
					return;
				}
				this.waiters.push(resolve);
			});
		}
	}
};
/**
* Apply a typed delta to an accumulated content block.
*
* - `text-delta` → append text
* - `reasoning-delta` → append reasoning text
* - `data-delta` → append encoded data to `data`
* - `block-delta` → shallow merge fields
*
* @internal
*/
function applyDelta(block, delta) {
	switch (delta.type) {
		case "text-delta":
			if (block.type === "text") return {
				...block,
				text: (block.text ?? "") + delta.text
			};
			return block;
		case "reasoning-delta":
			if (block.type === "thinking") return {
				...block,
				thinking: (block.thinking ?? "") + delta.reasoning
			};
			if (block.type === "reasoning") return {
				...block,
				reasoning: (block.reasoning ?? "") + delta.reasoning
			};
			return block;
		case "data-delta": return {
			...block,
			data: (block.data ?? "") + delta.data
		};
		case "block-delta": return {
			...block,
			...delta.fields
		};
		default: throw new Error(`Unknown delta type: ${JSON.stringify(delta)}`);
	}
}
/**
* Returns the typed delta carried by a content-block delta event.
*
* Stream protocol compliant language models store incremental updates in
* `event.delta`, e.g. `{ type: "text-delta", text: "hello" }`. Some models and
* adapters still emit the older content-shaped form on `event.content`, e.g.
* `{ type: "text", text: "hello" }`, which predates explicit delta event
* variants.
*
* Keep accepting that content-shaped form here so {@link ChatModelStream}
* remains a tolerant consumer while producers migrate to protocol compliant
* typed deltas.
*
* @internal
*/
function getEventDelta(event) {
	if (event.event !== "content-block-delta") return void 0;
	if ("delta" in event && event.delta) return event.delta;
	const content = event.content;
	if (content == null || typeof content !== "object") return void 0;
	const block = content;
	if (block.type === "text" && typeof block.text === "string") return {
		type: "text-delta",
		text: block.text
	};
	if (block.type === "reasoning" && typeof block.reasoning === "string") return {
		type: "reasoning-delta",
		reasoning: block.reasoning
	};
	if (block.type === "thinking" && typeof block.thinking === "string") return {
		type: "reasoning-delta",
		reasoning: block.thinking
	};
	if (typeof block.data === "string") return {
		type: "data-delta",
		data: block.data,
		encoding: "base64"
	};
	if (typeof block.type === "string") return {
		type: "block-delta",
		fields: {
			...block,
			type: block.type
		}
	};
}
function getReasoningDelta(content) {
	if (content == null || typeof content !== "object") return void 0;
	const block = content;
	if (block.type === "reasoning" && typeof block.reasoning === "string") return block.reasoning;
	if (block.type === "thinking" && typeof block.thinking === "string") return block.thinking;
}
function isReasoningContent(content) {
	if (content == null || typeof content !== "object") return false;
	const type = content.type;
	return type === "reasoning" || type === "thinking";
}
/**
* Normalize protocol-compatible partial usage into Core's concrete usage shape.
*
* Some stream sources emit usage snapshots without every aggregate token field.
* Keep the stream event input permissive, then normalize at read time so
* high-level Core consumers always receive a complete {@link UsageMetadata}.
*/
function normalizeUsage(usage) {
	if (!usage) return void 0;
	return {
		...usage,
		input_tokens: usage.input_tokens ?? 0,
		output_tokens: usage.output_tokens ?? 0,
		total_tokens: usage.total_tokens ?? 0
	};
}
function parseToolArgs(value) {
	if (value != null && typeof value === "object" && !Array.isArray(value)) return value;
	if (typeof value !== "string" || value.length === 0) return {};
	try {
		const parsed = JSON.parse(value);
		return parsed != null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
	} catch {
		return {};
	}
}
function standardizeToolBlock(block) {
	const record = block;
	if (block.type === "tool_call") return block;
	if (block.type !== "tool_call_chunk" && block.type !== "tool_use" && block.type !== "input_json_delta") return block;
	const name = typeof record.name === "string" ? record.name : void 0;
	if (name == null) return block;
	const args = record.args ?? record.input;
	return {
		...record,
		type: "tool_call",
		name,
		args: parseToolArgs(args)
	};
}
/**
* Typed stream for text content.
*
* - **Iterate**: yields incremental text deltas.
* - **Await**: resolves to the complete concatenated text.
* - **`.full`**: yields the running accumulated text after each delta.
*/
var TextContentStream = class {
	/** @internal */
	_buffer;
	/** @internal */
	constructor(buffer) {
		this._buffer = buffer;
	}
	/** Yields the accumulated text so far after each delta. */
	get full() {
		const buffer = this._buffer;
		return { async *[Symbol.asyncIterator]() {
			let accumulated = "";
			for await (const event of buffer.iterate()) {
				const delta = getEventDelta(event);
				if (delta?.type === "text-delta") {
					accumulated += delta.text;
					yield accumulated;
				}
			}
		} };
	}
	/** Yields incremental text deltas. */
	[Symbol.asyncIterator]() {
		const buffer = this._buffer;
		async function* gen() {
			for await (const event of buffer.iterate()) {
				const delta = getEventDelta(event);
				if (delta?.type === "text-delta") yield delta.text;
			}
		}
		return gen();
	}
	then(onfulfilled, onrejected) {
		return (async () => {
			let text = "";
			for await (const delta of this) text += delta;
			return text;
		})().then(onfulfilled, onrejected);
	}
};
/**
* Typed stream for tool calls.
*
* - **Iterate**: yields individual `ToolCall` objects as each completes.
* - **Await**: resolves to the full array.
* - **`.full`**: yields the accumulated array after each new tool call.
*/
var ToolCallsStream = class {
	/** @internal */
	_buffer;
	/** @internal */
	constructor(buffer) {
		this._buffer = buffer;
	}
	get full() {
		const buffer = this._buffer;
		return { async *[Symbol.asyncIterator]() {
			const calls = [];
			for await (const event of buffer.iterate()) if (event.event === "content-block-finish" && event.content.type === "tool_call") {
				calls.push(event.content);
				yield [...calls];
			}
		} };
	}
	[Symbol.asyncIterator]() {
		const buffer = this._buffer;
		async function* gen() {
			for await (const event of buffer.iterate()) if (event.event === "content-block-finish" && event.content.type === "tool_call") yield event.content;
		}
		return gen();
	}
	then(onfulfilled, onrejected) {
		return (async () => {
			const calls = [];
			for await (const call of this) calls.push(call);
			return calls;
		})().then(onfulfilled, onrejected);
	}
};
/**
* Typed stream for reasoning content (chain-of-thought).
* Same interface as {@link TextContentStream} but for reasoning blocks.
*/
var ReasoningContentStream = class {
	/** @internal */
	_buffer;
	/** @internal */
	constructor(buffer) {
		this._buffer = buffer;
	}
	get full() {
		const buffer = this._buffer;
		return { async *[Symbol.asyncIterator]() {
			let accumulated = "";
			let seenReasoning = false;
			for await (const event of buffer.iterate()) if (event.event === "content-block-start") {
				if (!isReasoningContent(event.content)) {
					if (seenReasoning) return;
					continue;
				}
				seenReasoning = true;
				const delta = getReasoningDelta(event.content);
				if (delta == null || delta.length === 0) continue;
				accumulated += delta;
				yield accumulated;
			} else if (event.event === "content-block-delta") {
				const eventDelta = getEventDelta(event);
				if (eventDelta?.type !== "reasoning-delta") continue;
				seenReasoning = true;
				const delta = eventDelta.reasoning;
				if (delta == null || delta.length === 0) continue;
				accumulated += delta;
				yield accumulated;
			} else if (event.event === "content-block-finish" && isReasoningContent(event.content)) return;
			else if (event.event === "message-finish") return;
		} };
	}
	[Symbol.asyncIterator]() {
		const buffer = this._buffer;
		async function* gen() {
			let seenReasoning = false;
			for await (const event of buffer.iterate()) if (event.event === "content-block-start") {
				if (!isReasoningContent(event.content)) {
					if (seenReasoning) return;
					continue;
				}
				seenReasoning = true;
				const delta = getReasoningDelta(event.content);
				if (delta != null && delta.length > 0) yield delta;
			} else if (event.event === "content-block-delta") {
				const eventDelta = getEventDelta(event);
				if (eventDelta?.type !== "reasoning-delta") continue;
				seenReasoning = true;
				const delta = eventDelta.reasoning;
				if (delta != null && delta.length > 0) yield delta;
			} else if (event.event === "content-block-finish" && isReasoningContent(event.content)) return;
			else if (event.event === "message-finish") return;
		}
		return gen();
	}
	then(onfulfilled, onrejected) {
		return (async () => {
			let text = "";
			for await (const delta of this) text += delta;
			return text;
		})().then(onfulfilled, onrejected);
	}
};
/**
* Typed stream for usage metadata.
*/
var UsageMetadataStream = class {
	/** @internal */
	_buffer;
	/** @internal */
	constructor(buffer) {
		this._buffer = buffer;
	}
	[Symbol.asyncIterator]() {
		const buffer = this._buffer;
		async function* gen() {
			for await (const event of buffer.iterate()) if (event.event === "usage") {
				const usage = normalizeUsage(event.usage);
				if (usage) yield usage;
			} else if (event.event === "message-start" && event.usage) {
				const usage = normalizeUsage(event.usage);
				if (usage) yield usage;
			} else if (event.event === "message-finish" && event.usage) {
				const usage = normalizeUsage(event.usage);
				if (usage) yield usage;
			}
		}
		return gen();
	}
	then(onfulfilled, onrejected) {
		return (async () => {
			let latest;
			for await (const usage of this) latest = usage;
			return latest;
		})().then(onfulfilled, onrejected);
	}
};
/**
* The main stream object returned by chat model streaming.
*
* Implements `AsyncIterable<ChatModelStreamEvent>` for raw event access
* and `PromiseLike<AIMessage>` for simple `await` usage.
*/
var ChatModelStream = class {
	/** @internal */
	_buffer;
	/** @internal */
	constructor(source) {
		this._buffer = new ReplayBuffer();
		this._consume(source);
	}
	/** @internal */
	async _consume(source) {
		try {
			for await (const event of source) this._buffer.push(event);
			this._buffer.finish();
		} catch (err) {
			this._buffer.setError(err instanceof Error ? err : new Error(String(err)));
		}
	}
	[Symbol.asyncIterator]() {
		return this._buffer.iterate();
	}
	get text() {
		return new TextContentStream(this._buffer);
	}
	get toolCalls() {
		return new ToolCallsStream(this._buffer);
	}
	get reasoning() {
		return new ReasoningContentStream(this._buffer);
	}
	get usage() {
		return new UsageMetadataStream(this._buffer);
	}
	get output() {
		return this._assembleMessage();
	}
	then(onfulfilled, onrejected) {
		return this._assembleMessage().then(onfulfilled, onrejected);
	}
	/** @internal */
	async _assembleMessage() {
		const contentBlocks = [];
		let id;
		let usage;
		let metadata = {};
		let finishReason;
		for await (const event of this._buffer.iterate()) switch (event.event) {
			case "message-start":
				id = event.id ?? id;
				if (event.usage) usage = normalizeUsage(event.usage);
				break;
			case "content-block-start":
				contentBlocks[event.index] = event.content;
				break;
			case "content-block-delta": {
				const current = contentBlocks[event.index];
				const delta = getEventDelta(event);
				if (current) {
					if (delta) contentBlocks[event.index] = applyDelta(current, delta);
				}
				break;
			}
			case "content-block-finish":
				contentBlocks[event.index] = event.content;
				break;
			case "usage":
				usage = normalizeUsage(event.usage);
				break;
			case "message-finish":
				finishReason = event.reason;
				if (event.usage) usage = normalizeUsage(event.usage);
				if (event.responseMetadata) metadata = {
					...metadata,
					...event.responseMetadata
				};
				break;
			default: break;
		}
		const filteredBlocks = contentBlocks.filter((b) => b != null).map(standardizeToolBlock);
		return new require_ai.AIMessage({
			id,
			content: filteredBlocks,
			usage_metadata: usage,
			response_metadata: {
				...metadata,
				...finishReason ? { finish_reason: finishReason } : {},
				output_version: "v1"
			}
		});
	}
};
//#endregion
exports.ChatModelStream = ChatModelStream;
exports.ReasoningContentStream = ReasoningContentStream;
exports.TextContentStream = TextContentStream;
exports.ToolCallsStream = ToolCallsStream;
exports.UsageMetadataStream = UsageMetadataStream;
Object.defineProperty(exports, "stream_exports", {
	enumerable: true,
	get: function() {
		return stream_exports;
	}
});

//# sourceMappingURL=stream.cjs.map