/** * StreamingToolCallBuffer — Accumulates raw tool call argument strings * during streaming, providing a fallback when LangChain's parsePartialJson * loses data (e.g., when max_tokens truncates a tool call mid-JSON). * * Architecture: * - handleToolCallChunks feeds raw arg fragments into this buffer * - When a tool call is finalized (or truncated), the ToolNode can access * the accumulated raw string and extract field values that parsePartialJson * may have dropped * - This enables "streaming write" semantics: content that streamed to the UI * is never lost, even if the JSON wrapper was incomplete * * @example * ```ts * const buffer = new StreamingToolCallBuffer(); * * // During streaming (called by handleToolCallChunks): * buffer.append(toolCallId, '{"action":"write","content":"func'); * buffer.append(toolCallId, 'tion App() {'); * buffer.setToolName(toolCallId, 'content_tool'); * * // When ToolNode needs the content: * const content = buffer.extractFieldValue(toolCallId, 'content'); * // => 'function App() {' * ``` */ export declare class StreamingToolCallBuffer { /** Raw accumulated arg strings keyed by tool call ID */ private argBuffers; /** Tool names keyed by tool call ID */ private toolNames; /** * Maps chunk index → tool call ID for providers (e.g., Bedrock) that send * START chunks with {id, name, index} and DELTA chunks with {args, index} (no id). * Without this mapping, DELTA chunks cannot be associated with the correct buffer entry. */ private indexToIdMap; /** * Tracks the last appended args fragment per tool call ID. * Used to skip exact duplicate fragments caused by LangChain's `streamEvents` * emitting the same `on_chat_model_stream` event multiple times when the model * is wrapped in nested runnables (e.g., `.bind()`, `.withConfig()`). */ private lastChunks; /** * Append a raw argument string chunk for a tool call. * Called during streaming as each ToolCallChunk arrives. * * Skips exact duplicate fragments that arrive when LangChain emits the same * streaming event multiple times from nested runnable wrappers. Without this, * each token's args appear twice, producing malformed JSON like: * `{"action": "write"action": "write"...` * * @returns true if the chunk was appended, false if it was a duplicate */ append(toolCallId: string, argsChunk: string): boolean; /** * Record the tool name for a tool call ID. * Usually available from the first chunk. */ setToolName(toolCallId: string, name: string): void; /** * Get the tool name for a tool call ID. */ getToolName(toolCallId: string): string | undefined; /** * Get the raw accumulated argument string for a tool call. */ getRawArgs(toolCallId: string): string | undefined; /** * Extract a string field value from the raw accumulated JSON args. * * Uses simple string parsing (not JSON.parse) to handle truncated JSON. * Finds `"fieldName":"` and extracts everything after it until the next * unescaped quote or end of buffer. * * @param toolCallId - The tool call ID * @param fieldName - The JSON field name to extract (e.g., 'content') * @returns The extracted value, or undefined if the field wasn't found */ extractFieldValue(toolCallId: string, fieldName: string): string | undefined; /** * Store an index → tool call ID mapping. * Called when a START chunk arrives with both `id` and `index` (e.g., Bedrock). * Subsequent DELTA chunks that only have `index` can resolve the ID via getIdByIndex. */ setIndexMapping(index: number, toolCallId: string): void; /** * Resolve a tool call ID from a chunk index. * Returns undefined if no mapping exists (e.g., provider sends id on every chunk). */ getIdByIndex(index: number): string | undefined; /** * Check if a tool call has accumulated content. */ has(toolCallId: string): boolean; /** * Clear the buffer for a specific tool call (after processing). */ clear(toolCallId: string): void; /** * Clear all buffers (at the start of a new callModel cycle). */ clearAll(): void; }