/** * Streaming Response Translation * * Provides utilities for parsing Server-Sent Events (SSE) streams from * different LLM providers and normalizing them to AgentRouter's StreamChunk format. * * Supported providers: * - Anthropic: message_start, content_block_start, content_block_delta, message_stop events * - OpenAI: data: {"choices":[{"delta":{...}}]} format * - Gemini: data: {"candidates":[{"content":{"parts":[...]}}]} format * * All streams are normalized to the common StreamChunk interface. */ import { type StreamChunk } from '../types.js'; /** * Anthropic SSE event types. */ export type AnthropicStreamEvent = AnthropicMessageStartEvent | AnthropicContentBlockStartEvent | AnthropicContentBlockDeltaEvent | AnthropicContentBlockStopEvent | AnthropicMessageDeltaEvent | AnthropicMessageStopEvent | AnthropicPingEvent | AnthropicErrorEvent; interface AnthropicMessageStartEvent { type: 'message_start'; message: { id: string; type: 'message'; role: 'assistant'; content: AnthropicContentBlock[]; model: string; stop_reason: string | null; stop_sequence: string | null; usage: { input_tokens: number; output_tokens: number; }; }; } interface AnthropicContentBlockStartEvent { type: 'content_block_start'; index: number; content_block: AnthropicContentBlock; } interface AnthropicContentBlockDeltaEvent { type: 'content_block_delta'; index: number; delta: { type: 'text_delta' | 'input_json_delta'; text?: string; partial_json?: string; }; } interface AnthropicContentBlockStopEvent { type: 'content_block_stop'; index: number; } interface AnthropicMessageDeltaEvent { type: 'message_delta'; delta: { stop_reason: string; stop_sequence: string | null; }; usage: { output_tokens: number; }; } interface AnthropicMessageStopEvent { type: 'message_stop'; } interface AnthropicPingEvent { type: 'ping'; } interface AnthropicErrorEvent { type: 'error'; error: { type: string; message: string; }; } interface AnthropicContentBlock { type: 'text' | 'tool_use' | 'tool_result'; text?: string; id?: string; name?: string; input?: Record; tool_use_id?: string; content?: string; } /** * OpenAI streaming chunk format. */ export interface OpenAIStreamChunk { id: string; object: 'chat.completion.chunk'; created: number; model: string; choices: { index: number; delta: { role?: 'assistant'; content?: string | null; tool_calls?: { index: number; id?: string; type?: 'function'; function?: { name?: string; arguments?: string; }; }[]; }; finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null; }[]; } /** * Gemini streaming chunk format. */ export interface GeminiStreamChunk { candidates?: { content?: { parts?: { text?: string; functionCall?: { name: string; args: Record; }; }[]; role?: 'model'; }; finishReason?: 'STOP' | 'MAX_TOKENS' | 'SAFETY' | 'RECITATION' | 'OTHER'; safetyRatings?: { category: string; probability: string; }[]; }[]; usageMetadata?: { promptTokenCount: number; candidatesTokenCount: number; totalTokenCount: number; }; } /** * Parse SSE (Server-Sent Events) data from a ReadableStream. * Handles buffering of partial lines and yields complete events. * * @param stream - The ReadableStream to parse * @param options - Parser options * @returns AsyncIterable yielding parsed event data strings */ export declare function parseSSE(stream: ReadableStream, options?: { /** Event data prefix (default: 'data: ') */ dataPrefix?: string; /** Stream end marker (default: '[DONE]') */ doneMarker?: string; }): AsyncIterable; /** * Parse Anthropic SSE stream and yield normalized StreamChunks. * * Anthropic streaming events: * - message_start: Contains initial message metadata * - content_block_start: Starts a new content block (text or tool_use) * - content_block_delta: Incremental content updates * - content_block_stop: Marks end of a content block * - message_delta: Final message metadata (stop_reason, usage) * - message_stop: Marks end of the message * - ping: Keep-alive (ignored) * - error: Stream error * * @param stream - ReadableStream from Anthropic API response * @returns AsyncIterable of normalized StreamChunks */ export declare function parseAnthropicStream(stream: ReadableStream): AsyncIterable; /** * Parse OpenAI SSE stream and yield normalized StreamChunks. * * OpenAI streams JSON objects with this structure: * - data: {"choices":[{"delta":{"content":"..."}}]} * - data: {"choices":[{"delta":{"tool_calls":[...]}}]} * - data: [DONE] * * Key differences from Anthropic: * - Content comes in delta.content field * - Tool calls are accumulated across chunks * - No explicit content_block_start/stop events * * @param stream - ReadableStream from OpenAI API response * @returns AsyncIterable of normalized StreamChunks */ export declare function parseOpenAIStream(stream: ReadableStream): AsyncIterable; /** * Parse Gemini SSE stream and yield normalized StreamChunks. * * Gemini streams JSON objects with this structure: * - data: {"candidates":[{"content":{"parts":[{"text":"..."}]}}]} * - data: {"candidates":[{"content":{"parts":[{"functionCall":{...}}]}}]} * * Key differences from Anthropic: * - Content comes in parts array * - Function calls use "functionCall" with "args" (not "arguments") * - Gemini may send cumulative text (full content each chunk) - we need to deduplicate * * @param stream - ReadableStream from Gemini API response * @returns AsyncIterable of normalized StreamChunks */ export declare function parseGeminiStream(stream: ReadableStream): AsyncIterable; /** * Create a TransformStream that converts raw SSE bytes to StreamChunks. * * @param provider - The provider type ('anthropic', 'openai', 'gemini') * @returns TransformStream that outputs StreamChunks */ export declare function createStreamTransformer(provider: 'anthropic' | 'openai' | 'gemini'): TransformStream; /** * Collect all text content from a stream of StreamChunks. * Useful for testing or when you need the full response text. * * @param stream - AsyncIterable of StreamChunks * @returns Promise resolving to the complete text content */ export declare function collectStreamText(stream: AsyncIterable): Promise; /** * Collect all StreamChunks from an async iterable into an array. * Useful for testing. * * @param stream - AsyncIterable of StreamChunks * @returns Promise resolving to array of all chunks */ export declare function collectStreamChunks(stream: AsyncIterable): Promise; export {}; //# sourceMappingURL=streaming.d.ts.map