UNPKG

@mastra/core

Version:
1,350 lines (1,344 loc) • 155 kB
'use strict'; var chunk7ISY3K4R_cjs = require('./chunk-7ISY3K4R.cjs'); var chunk2LBT6OZS_cjs = require('./chunk-2LBT6OZS.cjs'); var chunkXB4FLS7A_cjs = require('./chunk-XB4FLS7A.cjs'); var chunkYGTB7A25_cjs = require('./chunk-YGTB7A25.cjs'); var chunkLP4WZA6D_cjs = require('./chunk-LP4WZA6D.cjs'); var chunkWSD4JNMB_cjs = require('./chunk-WSD4JNMB.cjs'); var chunkRWGBZBPV_cjs = require('./chunk-RWGBZBPV.cjs'); var chunkZQADKFIL_cjs = require('./chunk-ZQADKFIL.cjs'); var chunkXSOONORA_cjs = require('./chunk-XSOONORA.cjs'); var crypto = require('crypto'); var web = require('stream/web'); var events = require('events'); var schemaCompat = require('@mastra/schema-compat'); // src/stream/aisdk/v5/compat/delayed-promise.ts var DelayedPromise = class { status = { type: "pending" }; _promise; _resolve = void 0; _reject = void 0; get promise() { if (this._promise) { return this._promise; } this._promise = new Promise((resolve, reject) => { if (this.status.type === "resolved") { resolve(this.status.value); } else if (this.status.type === "rejected") { reject(this.status.error); } this._resolve = resolve; this._reject = reject; }); return this._promise; } resolve(value) { this.status = { type: "resolved", value }; if (this._promise) { this._resolve?.(value); } } reject(error) { this.status = { type: "rejected", error }; if (this._promise) { this._reject?.(error); } } }; // src/stream/aisdk/v5/compat/consume-stream.ts async function consumeStream({ stream, onError, logger }) { const reader = stream.getReader(); try { while (true) { const { done } = await reader.read(); if (done) break; } } catch (error) { logger?.error("consumeStream error", error); onError?.(error); } finally { reader.releaseLock(); } } // src/stream/base/input.ts function safeEnqueue(controller, chunk) { try { controller.enqueue(chunk); return true; } catch { return false; } } function safeClose(controller) { try { controller.close(); return true; } catch { return false; } } function safeError(controller, error) { try { controller.error(error); return true; } catch { return false; } } var MastraModelInput = class extends chunkWSD4JNMB_cjs.MastraBase { initialize({ runId, createStream, onResult }) { const self = this; let outputStream; outputStream = new ReadableStream({ async start(controller) { try { const stream = await createStream(); chunk2LBT6OZS_cjs.attachModelStreamTransport(outputStream, chunk2LBT6OZS_cjs.readModelStreamTransport(stream)); const initialChunks = onResult({ warnings: stream.warnings, request: stream.request, rawResponse: stream.rawResponse || stream.response || {} }); if (initialChunks) { for (const chunk of Array.isArray(initialChunks) ? initialChunks : [initialChunks]) { controller.enqueue(chunk); } } await self.transform({ runId, stream: stream.stream, controller }); safeClose(controller); } catch (error) { safeError(controller, error); } } }); return outputStream; } }; function asJsonSchema(schema) { if (!schema) { return void 0; } if (chunkXB4FLS7A_cjs.isStandardSchemaWithJSON(schema)) { const jsonSchema = chunkXB4FLS7A_cjs.standardSchemaToJSONSchema(schema, { io: "input", target: "draft-07" }); return jsonSchema; } return schema; } function getTransformedSchema(schema, options) { if (!schema) { return void 0; } const jsonSchema = options?.model ? schemaCompat.applyCompatLayer({ schema, compatLayers: [new schemaCompat.AnthropicSchemaCompatLayer(options.model)], mode: "jsonSchema" }) : asJsonSchema(schema); if (!jsonSchema) { return void 0; } const { $schema, ...itemSchema } = jsonSchema; if (itemSchema.type === "array") { const innerElement = itemSchema.items; const arrayOutputSchema = { $schema, type: "object", properties: { elements: { type: "array", items: innerElement } }, required: ["elements"], additionalProperties: false }; return { jsonSchema: arrayOutputSchema, outputFormat: "array" }; } if (itemSchema.enum && Array.isArray(itemSchema.enum)) { const enumOutputSchema = { $schema, type: "object", properties: { result: { type: itemSchema.type || "string", enum: itemSchema.enum } }, required: ["result"], additionalProperties: false }; return { jsonSchema: enumOutputSchema, outputFormat: "enum" }; } return { jsonSchema, outputFormat: jsonSchema.type // 'object' }; } function getResponseFormat(schema, options) { if (schema) { const transformedSchema = getTransformedSchema(schema, options); return { type: "json", schema: transformedSchema?.jsonSchema }; } return { type: "text" }; } // src/stream/base/output-format-handlers.ts function escapeUnescapedControlCharsInJsonStrings(text) { let result = ""; let inString = false; let i = 0; while (i < text.length) { const char = text[i]; if (char === "\\" && i + 1 < text.length) { result += char + text[i + 1]; i += 2; continue; } if (char === '"') { inString = !inString; result += char; i++; continue; } if (inString) { if (char === "\n") { result += "\\n"; i++; continue; } if (char === "\r") { result += "\\r"; i++; continue; } if (char === " ") { result += "\\t"; i++; continue; } } result += char; i++; } return result; } var BaseFormatHandler = class { /** * The original user-provided schema (Zod, JSON Schema, or AI SDK Schema). */ schema; /** * Validate partial chunks as they are streamed. @planned */ validatePartialChunks = false; partialSchema; constructor(schema, options = {}) { this.schema = schema; if (options.validatePartialChunks && this.isZodSchema(schema) && "partial" in schema && typeof schema.partial === "function") { this.partialSchema = schema.partial(); this.validatePartialChunks = true; } } /** * Checks if the original schema is a Zod schema with safeParse method. */ isZodSchema(schema) { return schemaCompat.isZodType(schema); } /** * Validates a value against the schema using StandardSchemaWithJSON's validate method. */ async validateValue(value) { if (!this.schema) { return { success: true, value }; } if (this.isZodSchema(this.schema)) { try { const ssResult = await this.schema["~standard"].validate(value); if (!ssResult.issues) { return { success: true, value: ssResult.value }; } const errorMessages = ssResult.issues.map((e) => `- ${e.path?.join(".") || "root"}: ${e.message}`).join("\n"); const zodResult = this.schema.safeParse(value); const zodError = !zodResult.success ? zodResult.error : void 0; return { success: false, error: new chunkXSOONORA_cjs.MastraError( { domain: chunkXSOONORA_cjs.ErrorDomain.AGENT, category: chunkXSOONORA_cjs.ErrorCategory.SYSTEM, id: "STRUCTURED_OUTPUT_SCHEMA_VALIDATION_FAILED", text: `Structured output validation failed: ${errorMessages}`, details: { value: typeof value === "object" ? JSON.stringify(value) : String(value) } }, zodError ) }; } catch (error) { return { success: false, error: error instanceof Error ? error : new Error("Zod validation failed", { cause: error }) }; } } try { const ssResult = await this.schema["~standard"].validate(value); if (!ssResult.issues) { return { success: true, value: ssResult.value }; } const errorMessages = ssResult.issues.map((e) => `- ${e.path?.join(".") || "root"}: ${e.message}`).join("\n"); return { success: false, error: new chunkXSOONORA_cjs.MastraError({ domain: chunkXSOONORA_cjs.ErrorDomain.AGENT, category: chunkXSOONORA_cjs.ErrorCategory.SYSTEM, id: "STRUCTURED_OUTPUT_SCHEMA_VALIDATION_FAILED", text: `Structured output validation failed: ${errorMessages}`, details: { value: typeof value === "object" ? JSON.stringify(value) : String(value) } }) }; } catch (error) { return { success: false, error: error instanceof Error ? error : new Error("Validation failed", { cause: error }) }; } } /** * Preprocesses accumulated text to handle LLMs that wrap JSON in code blocks * and fix common JSON formatting issues like unescaped newlines in strings. * Extracts content from the first complete valid ```json...``` code block or removes opening ```json prefix if no complete code block is found (streaming chunks). * @param accumulatedText - Raw accumulated text from streaming * @returns Processed text ready for JSON parsing */ preprocessText(accumulatedText) { let processedText = accumulatedText; if (processedText.includes("<|message|>")) { const match = processedText.match(/<\|message\|>([\s\S]+)$/); if (match && match[1]) { processedText = match[1]; } } const trimmedStart = processedText.trimStart(); if (/^```json\b/.test(trimmedStart)) { const match = trimmedStart.match(/^```json\s*\n?([\s\S]*?)\n?\s*```\s*$/); if (match && match[1]) { processedText = match[1].trim(); } else { processedText = trimmedStart.replace(/^```json\s*\n?/, ""); } } processedText = escapeUnescapedControlCharsInJsonStrings(processedText); return processedText; } }; var ObjectFormatHandler = class extends BaseFormatHandler { type = "object"; async processPartialChunk({ accumulatedText, previousObject }) { const processedAccumulatedText = this.preprocessText(accumulatedText); const { value: currentObjectJson, state } = await chunkZQADKFIL_cjs.parsePartialJson(processedAccumulatedText); if (this.validatePartialChunks && this.partialSchema) { const result = this.partialSchema?.safeParse(currentObjectJson); if (result.success && result.data && result.data !== void 0 && !chunkZQADKFIL_cjs.isDeepEqualData(previousObject, result.data)) { return { shouldEmit: true, emitValue: result.data, newPreviousResult: result.data }; } return { shouldEmit: false }; } if (currentObjectJson !== void 0 && currentObjectJson !== null && typeof currentObjectJson === "object" && !chunkZQADKFIL_cjs.isDeepEqualData(previousObject, currentObjectJson)) { return { shouldEmit: ["successful-parse", "repaired-parse"].includes(state), emitValue: currentObjectJson, newPreviousResult: currentObjectJson }; } return { shouldEmit: false }; } async validateAndTransformFinal(finalRawValue) { if (!finalRawValue) { return { success: false, error: new Error("No object generated: could not parse the response.") }; } const rawValue = this.preprocessText(finalRawValue); const { value } = await chunkZQADKFIL_cjs.parsePartialJson(rawValue); return this.validateValue(value); } }; var ArrayFormatHandler = class extends BaseFormatHandler { type = "array"; /** Previously filtered array to track changes */ textPreviousFilteredArray = []; /** Whether we've emitted the initial empty array */ hasEmittedInitialArray = false; async processPartialChunk({ accumulatedText, previousObject }) { const processedAccumulatedText = this.preprocessText(accumulatedText); const { value: currentObjectJson, state: parseState } = await chunkZQADKFIL_cjs.parsePartialJson(processedAccumulatedText); if (currentObjectJson !== void 0 && !chunkZQADKFIL_cjs.isDeepEqualData(previousObject, currentObjectJson)) { const rawElements = currentObjectJson && typeof currentObjectJson === "object" && "elements" in currentObjectJson && Array.isArray(currentObjectJson.elements) ? currentObjectJson.elements : []; const filteredElements = []; for (let i = 0; i < rawElements.length; i++) { const element = rawElements[i]; if (i === rawElements.length - 1 && parseState !== "successful-parse") { if (element && typeof element === "object" && Object.keys(element).length > 0) { filteredElements.push(element); } } else { if (element && typeof element === "object" && Object.keys(element).length > 0) { filteredElements.push(element); } } } if (!this.hasEmittedInitialArray) { this.hasEmittedInitialArray = true; if (filteredElements.length === 0) { this.textPreviousFilteredArray = []; return { shouldEmit: true, emitValue: [], newPreviousResult: currentObjectJson }; } } if (!chunkZQADKFIL_cjs.isDeepEqualData(this.textPreviousFilteredArray, filteredElements)) { this.textPreviousFilteredArray = [...filteredElements]; return { shouldEmit: true, emitValue: filteredElements, newPreviousResult: currentObjectJson }; } } return { shouldEmit: false }; } async validateAndTransformFinal(_finalValue) { const resultValue = this.textPreviousFilteredArray; if (!resultValue) { return { success: false, error: new Error("No object generated: could not parse the response.") }; } return this.validateValue(resultValue); } }; var EnumFormatHandler = class extends BaseFormatHandler { type = "enum"; /** Previously emitted enum result to avoid duplicate emissions */ textPreviousEnumResult; /** * Finds the best matching enum value for a partial result string. * If multiple values match, returns the partial string. If only one matches, returns that value. * @param partialResult - Partial enum string from streaming * @returns Best matching enum value or undefined if no matches */ findBestEnumMatch(partialResult) { if (!this.schema) { return void 0; } const outputJsonSchema = chunkXB4FLS7A_cjs.standardSchemaToJSONSchema(this.schema); const enumValues = outputJsonSchema?.enum; if (!enumValues) { return void 0; } const possibleEnumValues = enumValues.filter((value) => typeof value === "string").filter((enumValue) => enumValue.startsWith(partialResult)); if (possibleEnumValues.length === 0) { return void 0; } const firstMatch = possibleEnumValues[0]; return possibleEnumValues.length === 1 && firstMatch !== void 0 ? firstMatch : partialResult; } async processPartialChunk({ accumulatedText, previousObject }) { const processedAccumulatedText = this.preprocessText(accumulatedText); const { value: currentObjectJson } = await chunkZQADKFIL_cjs.parsePartialJson(processedAccumulatedText); if (currentObjectJson !== void 0 && currentObjectJson !== null && typeof currentObjectJson === "object" && !Array.isArray(currentObjectJson) && "result" in currentObjectJson && typeof currentObjectJson.result === "string" && !chunkZQADKFIL_cjs.isDeepEqualData(previousObject, currentObjectJson)) { const partialResult = currentObjectJson.result; const bestMatch = this.findBestEnumMatch(partialResult); if (partialResult.length > 0 && bestMatch && bestMatch !== this.textPreviousEnumResult) { this.textPreviousEnumResult = bestMatch; return { shouldEmit: true, emitValue: bestMatch, newPreviousResult: currentObjectJson }; } } return { shouldEmit: false }; } async validateAndTransformFinal(rawFinalValue) { const processedValue = this.preprocessText(rawFinalValue); const { value } = await chunkZQADKFIL_cjs.parsePartialJson(processedValue); if (!(typeof value === "object" && value !== null && "result" in value)) { return { success: false, error: new Error("Invalid enum format: expected object with result property") }; } const finalValue = value; if (!finalValue || typeof finalValue !== "object" || typeof finalValue.result !== "string") { return { success: false, error: new Error("Invalid enum format: expected object with result property") }; } return this.validateValue(finalValue.result); } }; function createOutputHandler({ schema }) { const normalizedSchema = schema ? chunkXB4FLS7A_cjs.toStandardSchema(schema) : void 0; const transformedSchema = getTransformedSchema(normalizedSchema); switch (transformedSchema?.outputFormat) { case "array": return new ArrayFormatHandler(normalizedSchema); case "enum": return new EnumFormatHandler(normalizedSchema); case "object": default: return new ObjectFormatHandler(normalizedSchema); } } function createObjectStreamTransformer({ structuredOutput, logger }) { const handler = createOutputHandler({ schema: structuredOutput?.schema }); let accumulatedText = ""; let previousObject = void 0; let currentRunId; let finalResult; return new web.TransformStream({ async transform(chunk, controller) { if (chunk.runId) { currentRunId = chunk.runId; } if (chunk.type === "text-delta" && typeof chunk.payload?.text === "string") { accumulatedText += chunk.payload.text; const result = await handler.processPartialChunk({ accumulatedText, previousObject }); if (result.shouldEmit) { previousObject = result.newPreviousResult ?? previousObject; const chunkData = { from: chunk.from, runId: chunk.runId, type: "object", object: result.emitValue // TODO: handle partial runtime type validation of json chunks }; controller.enqueue(chunkData); } } if (chunk.type === "text-end") { controller.enqueue(chunk); if (accumulatedText?.trim() && !finalResult) { finalResult = await handler.validateAndTransformFinal(accumulatedText); if (finalResult.success) { controller.enqueue({ from: "AGENT" /* AGENT */, runId: currentRunId ?? "", type: "object-result", object: finalResult.value }); } } return; } controller.enqueue(chunk); }, async flush(controller) { if (finalResult && !finalResult.success) { handleValidationError(finalResult.error, controller); } if (accumulatedText?.trim() && !finalResult) { finalResult = await handler.validateAndTransformFinal(accumulatedText); if (finalResult.success) { controller.enqueue({ from: "AGENT" /* AGENT */, runId: currentRunId ?? "", type: "object-result", object: finalResult.value }); } else { handleValidationError(finalResult.error, controller); } } } }); function handleValidationError(error, controller) { if (structuredOutput?.errorStrategy === "warn") { logger?.warn(error.message); } else if (structuredOutput?.errorStrategy === "fallback") { controller.enqueue({ from: "AGENT" /* AGENT */, runId: currentRunId ?? "", type: "object-result", object: structuredOutput.fallbackValue }); } else { controller.enqueue({ from: "AGENT" /* AGENT */, runId: currentRunId ?? "", type: "error", payload: { error } }); } } } function createJsonTextStreamTransformer(schema) { let previousArrayLength = 0; let hasStartedArray = false; let chunkCount = 0; const outputSchema = getTransformedSchema(schema); return new web.TransformStream({ transform(chunk, controller) { if (chunk.type !== "object" || !chunk.object) { return; } if (outputSchema?.outputFormat === "array" && Array.isArray(chunk.object)) { chunkCount++; if (chunkCount === 1) { if (chunk.object.length > 0) { controller.enqueue(JSON.stringify(chunk.object)); previousArrayLength = chunk.object.length; hasStartedArray = true; return; } } if (!hasStartedArray) { controller.enqueue("["); hasStartedArray = true; } for (let i = previousArrayLength; i < chunk.object.length; i++) { const elementJson = JSON.stringify(chunk.object[i]); if (i > 0) { controller.enqueue("," + elementJson); } else { controller.enqueue(elementJson); } } previousArrayLength = chunk.object.length; } else { controller.enqueue(JSON.stringify(chunk.object)); } }, flush(controller) { if (hasStartedArray && outputSchema?.outputFormat === "array" && chunkCount > 1) { controller.enqueue("]"); } } }); } // src/stream/base/output.ts var STRUCTURED_OUTPUT_PROCESSOR_NAME = "structured-output"; function createDestructurableOutput(output) { return new Proxy(output, { get(target, prop, _receiver) { const originalValue = Reflect.get(target, prop, target); if (typeof originalValue === "function") { return originalValue.bind(target); } return originalValue; } }); } var MastraModelOutput = class extends chunkWSD4JNMB_cjs.MastraBase { #status = "running"; #error; #baseStream; #bufferedChunks = []; #streamFinished = false; #finishCallbackSent = false; #emitter = new events.EventEmitter(); #bufferedSteps = []; #bufferedReasoningDetails = {}; #bufferedByStep = { text: "", reasoning: [], sources: [], files: [], toolCalls: [], toolResults: [], dynamicToolCalls: [], dynamicToolResults: [], staticToolCalls: [], staticToolResults: [], content: [], usage: { inputTokens: void 0, outputTokens: void 0, totalTokens: void 0 }, warnings: [], request: {}, response: { id: "", timestamp: /* @__PURE__ */ new Date(), modelId: "", messages: [], uiMessages: [] }, reasoningText: "", providerMetadata: void 0, finishReason: void 0 }; #bufferedText = []; #bufferedObject; #bufferedTextChunks = {}; #bufferedSources = []; #bufferedReasoning = []; #bufferedFiles = []; #toolCallArgsDeltas = {}; #toolCallDeltaIdNameMap = {}; #toolCallStreamingMeta = {}; #toolCalls = []; #toolResults = []; #warnings = []; #finishReason = void 0; /** * Provider-specific metadata captured from the most recent step `finish` * chunk (e.g. AWS Bedrock guardrail trace under * `providerMetadata.bedrock.trace`). Exposed via {@link _getImmediateProviderMetadata} * so output-step processors can attribute content-filter blocks, for which * the completed-steps array is empty. */ #stepProviderMetadata = void 0; #request = {}; #usageCount = { inputTokens: void 0, outputTokens: void 0, totalTokens: void 0 }; #tripwire = void 0; #transportRef; #transportClosed = false; #delayedPromises = { suspendPayload: new DelayedPromise(), resumeSchema: new DelayedPromise(), object: new DelayedPromise(), finishReason: new DelayedPromise(), usage: new DelayedPromise(), warnings: new DelayedPromise(), providerMetadata: new DelayedPromise(), response: new DelayedPromise(), request: new DelayedPromise(), text: new DelayedPromise(), reasoning: new DelayedPromise(), reasoningText: new DelayedPromise(), sources: new DelayedPromise(), files: new DelayedPromise(), toolCalls: new DelayedPromise(), toolResults: new DelayedPromise(), steps: new DelayedPromise(), totalUsage: new DelayedPromise(), content: new DelayedPromise() }; #consumptionStarted = false; #consumeStreamPromise; #consumeStreamErrored = false; #consumeStreamError; #returnScorerData = false; #structuredOutputMode = void 0; #model; /** * Unique identifier for this execution run. */ runId; #options; /** * The processor runner for this stream. */ processorRunner; /** * The message list for this stream. */ messageList; /** * Trace ID for this execution. */ traceId; /** * Root span ID for this execution, identifying the top-level span in the trace. */ spanId; messageId; constructor({ model: _model, stream, messageList, options, messageId, initialState }) { super({ component: "LLM", name: "MastraModelOutput" }); this.#options = options; this.#transportRef = options.transportRef; this.#returnScorerData = !!options.returnScorerData; this.runId = options.runId; const resultSpan = chunkLP4WZA6D_cjs.getRootExportSpan(options.tracingContext?.currentSpan); this.traceId = resultSpan?.externalTraceId; this.spanId = resultSpan?.id; this.#model = _model; this.messageId = messageId; if (options.structuredOutput?.schema) { this.#structuredOutputMode = options.structuredOutput.model ? "processor" : "direct"; } if (options.outputProcessors?.length) { this.processorRunner = new ProcessorRunner({ inputProcessors: [], outputProcessors: options.outputProcessors, logger: this.logger, agentName: "MastraModelOutput", processorStates: options.processorStates }); } this.messageList = messageList; const self = this; let processedStream = stream; const processorRunner = this.processorRunner; if (processorRunner && options.isLLMExecutionStep) { const processorStates = options.processorStates || /* @__PURE__ */ new Map(); processedStream = stream.pipeThrough( new web.TransformStream({ async transform(chunk, controller) { if (chunk.type === "finish" && chunk.payload?.stepResult?.reason === "tool-calls") { controller.enqueue(chunk); return; } else { if (!processorStates.has(STRUCTURED_OUTPUT_PROCESSOR_NAME)) { const processorIndex = processorRunner.outputProcessors.findIndex( (p) => p.id === STRUCTURED_OUTPUT_PROCESSOR_NAME ); if (processorIndex !== -1) { const structuredOutputProcessor = processorRunner.outputProcessors[processorIndex]; const structuredOutputProcessorState = new ProcessorState({ processorName: structuredOutputProcessor?.name ?? STRUCTURED_OUTPUT_PROCESSOR_NAME, tracingContext: options.tracingContext, processorIndex, createSpan: true }); structuredOutputProcessorState.customState = { controller }; processorStates.set(STRUCTURED_OUTPUT_PROCESSOR_NAME, structuredOutputProcessorState); } } else { const structuredOutputProcessorState = processorStates.get(STRUCTURED_OUTPUT_PROCESSOR_NAME); if (structuredOutputProcessorState) { structuredOutputProcessorState.customState.controller = controller; } } const streamWriter = { custom: async (data) => controller.enqueue(data) }; const { part: processed, blocked, reason, tripwireOptions, processorId } = await processorRunner.processPart( chunk, processorStates, chunkYGTB7A25_cjs.resolveObservabilityContext(options), options.requestContext, self.messageList, 0, streamWriter ); const enqueueTripwire = (r, opts, pid) => { controller.enqueue({ type: "tripwire", payload: { reason: r || "Output processor blocked content", retry: opts?.retry, metadata: opts?.metadata, processorId: pid } }); }; if (blocked) { enqueueTripwire(reason, tripwireOptions, processorId); return; } if (processed) { controller.enqueue(processed); } const reprocessed = await processorRunner.drainReprocessParts( processorStates, chunkYGTB7A25_cjs.resolveObservabilityContext(options), options.requestContext, self.messageList, 0, streamWriter ); for (const r of reprocessed) { if (r.blocked) { enqueueTripwire(r.reason, r.tripwireOptions, r.processorId); return; } if (r.part != null) { controller.enqueue(r.part); } } } } }) ); } if (self.#structuredOutputMode === "direct" && self.#options.isLLMExecutionStep) { processedStream = processedStream.pipeThrough( createObjectStreamTransformer({ structuredOutput: self.#options.structuredOutput, logger: self.logger }) ); } this.#baseStream = processedStream.pipeThrough( new web.TransformStream({ transform: async (chunk, controller) => { switch (chunk.type) { case "tool-call-suspended": case "tool-call-approval": self.#status = "suspended"; self.#delayedPromises.suspendPayload.resolve(chunk.payload); self.#delayedPromises.resumeSchema.resolve(chunk.payload.resumeSchema); if (!self.#finishCallbackSent) { self.#finishCallbackSent = true; await options?.onFinish?.(self.#createSuspendedOnFinishPayload(chunk)); } break; case "abort": self.#status = "canceled"; if (!self.#finishCallbackSent) { self.#finishCallbackSent = true; await options?.onFinish?.(self.#createAbortedOnFinishPayload()); } self.#closeTransportIfNeeded(); break; case "raw": if (!self.#options.includeRawChunks) { return; } break; case "object-result": self.#bufferedObject = chunk.object; if (self.#delayedPromises.object.status.type === "pending") { self.#delayedPromises.object.resolve(chunk.object); } break; case "source": self.#bufferedSources.push(chunk); self.#bufferedByStep.sources.push(chunk); break; case "text-delta": self.#bufferedText.push(chunk.payload.text); self.#bufferedByStep.text += chunk.payload.text; if (chunk.payload.id) { const ary = self.#bufferedTextChunks[chunk.payload.id] ?? []; ary.push(chunk.payload.text); self.#bufferedTextChunks[chunk.payload.id] = ary; } break; case "tool-call-input-streaming-start": self.#toolCallDeltaIdNameMap[chunk.payload.toolCallId] = chunk.payload.toolName; self.#toolCallStreamingMeta[chunk.payload.toolCallId] = { toolName: chunk.payload.toolName, providerExecuted: chunk.payload.providerExecuted, providerMetadata: chunk.payload.providerMetadata, dynamic: chunk.payload.dynamic, ...chunk.payload.observability ? { observability: chunk.payload.observability } : {} }; break; case "tool-call-input-streaming-end": { const toolCallId = chunk.payload.toolCallId; const meta = self.#toolCallStreamingMeta[toolCallId]; const deltaParts = self.#toolCallArgsDeltas[toolCallId]; let args = {}; if (deltaParts?.length) { try { const merged = deltaParts.join(""); args = typeof merged === "string" && merged.length > 0 ? JSON.parse(merged) : {}; } catch { args = {}; } } delete self.#toolCallStreamingMeta[toolCallId]; delete self.#toolCallArgsDeltas[toolCallId]; delete self.#toolCallDeltaIdNameMap[toolCallId]; if (meta) { const synthetic = { type: "tool-call", runId: chunk.runId, from: chunk.from, payload: { toolCallId, toolName: meta.toolName, args, providerExecuted: meta.providerExecuted, providerMetadata: meta.providerMetadata, dynamic: meta.dynamic, ...meta.observability ? { observability: meta.observability } : {} } }; self.#toolCalls.push(synthetic); self.#bufferedByStep.toolCalls.push(synthetic); self.#emitChunk(chunk); controller.enqueue(chunk); self.#emitChunk(synthetic); controller.enqueue(synthetic); return; } break; } case "tool-call-delta": if (!self.#toolCallArgsDeltas[chunk.payload.toolCallId]) { self.#toolCallArgsDeltas[chunk.payload.toolCallId] = []; } self.#toolCallArgsDeltas?.[chunk.payload.toolCallId]?.push(chunk.payload.argsTextDelta); chunk.payload.toolName ||= self.#toolCallDeltaIdNameMap[chunk.payload.toolCallId]; break; case "file": self.#bufferedFiles.push(chunk); self.#bufferedByStep.files.push(chunk); break; case "reasoning-start": self.#bufferedReasoningDetails[chunk.payload.id] = { type: "reasoning", runId: chunk.runId, from: chunk.from, payload: { id: chunk.payload.id, providerMetadata: chunk.payload.providerMetadata, text: "" } }; break; case "reasoning-delta": { self.#bufferedReasoning.push({ type: "reasoning", runId: chunk.runId, from: chunk.from, payload: chunk.payload }); self.#bufferedByStep.reasoning.push({ type: "reasoning", runId: chunk.runId, from: chunk.from, payload: chunk.payload }); const bufferedReasoning = self.#bufferedReasoningDetails[chunk.payload.id]; if (bufferedReasoning) { bufferedReasoning.payload.text += chunk.payload.text; if (chunk.payload.providerMetadata) { bufferedReasoning.payload.providerMetadata = chunk.payload.providerMetadata; } } break; } case "reasoning-end": { const bufferedReasoning = self.#bufferedReasoningDetails[chunk.payload.id]; if (chunk.payload.providerMetadata && bufferedReasoning) { bufferedReasoning.payload.providerMetadata = chunk.payload.providerMetadata; } break; } case "tool-call": { const existingSynthetic = self.#toolCalls.find((tc) => tc.payload.toolCallId === chunk.payload.toolCallId); if (existingSynthetic) { if (chunk.payload.args && Object.keys(existingSynthetic.payload.args || {}).length === 0) { existingSynthetic.payload.args = chunk.payload.args; } if (chunk.payload.providerMetadata && !existingSynthetic.payload.providerMetadata) { existingSynthetic.payload.providerMetadata = chunk.payload.providerMetadata; } if (chunk.payload.dynamic != null && existingSynthetic.payload.dynamic == null) { existingSynthetic.payload.dynamic = chunk.payload.dynamic; } if (chunk.payload.observability && !existingSynthetic.payload.observability) { existingSynthetic.payload.observability = chunk.payload.observability; } return; } self.#toolCalls.push(chunk); self.#bufferedByStep.toolCalls.push(chunk); const toolCallPayload = chunk.payload; if (toolCallPayload?.output?.from === "AGENT" && toolCallPayload?.output?.type === "finish") { const finishPayload = toolCallPayload.output.payload; if (finishPayload?.usage) { self.updateUsageCount(finishPayload.usage); } } break; } case "tool-result": self.#toolResults.push(chunk); self.#bufferedByStep.toolResults.push(chunk); break; case "step-finish": { self.updateUsageCount(chunk.payload.output.usage); self.#warnings = chunk.payload.stepResult.warnings || []; if (chunk.payload.metadata.request) { self.#request = chunk.payload.metadata.request; } const { providerMetadata, request, ...otherMetadata } = chunk.payload.metadata; const payloadSteps = chunk.payload.output?.steps || []; const currentPayloadStep = payloadSteps[payloadSteps.length - 1]; const stepTripwire = currentPayloadStep?.tripwire; const stepText = stepTripwire ? "" : self.#bufferedByStep.text; const stepResult = { stepType: self.#bufferedSteps.length === 0 ? "initial" : "tool-result", sources: self.#bufferedByStep.sources, files: self.#bufferedByStep.files, toolCalls: self.#bufferedByStep.toolCalls, toolResults: self.#bufferedByStep.toolResults, // Durable agents attach pre-computed step content on the // step-finish chunk because the stream adapter's messageList // may be a stale reference (each workflow step deserializes // a fresh instance). Fall back to the live messageList for // non-durable agents. content: chunk.payload?._durableStepContent ?? messageList.get.response.aiV5.modelContent(-1), text: stepText, // Include tripwire data if present tripwire: stepTripwire, reasoningText: self.#bufferedReasoning.map((reasoningPart) => reasoningPart.payload.text).join(""), reasoning: Object.values(self.#bufferedReasoningDetails), get staticToolCalls() { return self.#bufferedByStep.toolCalls.filter( (part) => part.type === "tool-call" && part.payload?.dynamic === false ); }, get dynamicToolCalls() { return self.#bufferedByStep.toolCalls.filter( (part) => part.type === "tool-call" && part.payload?.dynamic === true ); }, get staticToolResults() { return self.#bufferedByStep.toolResults.filter( (part) => part.type === "tool-result" && part.payload?.dynamic === false ); }, get dynamicToolResults() { return self.#bufferedByStep.toolResults.filter( (part) => part.type === "tool-result" && part.payload?.dynamic === true ); }, finishReason: chunk.payload.stepResult.reason, usage: chunk.payload.output.usage, warnings: self.#warnings, request: request || {}, response: { id: chunk.payload.id || "", timestamp: chunk.payload.metadata?.timestamp || /* @__PURE__ */ new Date(), ...otherMetadata, modelId: chunk.payload.metadata?.modelId || chunk.payload.metadata?.model || "", messages: chunk.payload.messages?.nonUser || [], dbMessages: self.messageList.get.response.db(), // We have to cast this until messageList can take generics also and type metadata, it was too // complicated to do this in this PR, it will require a much bigger change. uiMessages: messageList.get.response.aiV5.ui() }, providerMetadata: providerMetadata ?? chunk.payload.providerMetadata }; await options?.onStepFinish?.({ ...self.#model.modelId && self.#model.provider && self.#model.version ? { model: self.#model } : {}, ...stepResult }); self.#bufferedSteps.push(stepResult); self.#bufferedByStep = { text: "", reasoning: [], sources: [], files: [], toolCalls: [], toolResults: [], dynamicToolCalls: [], dynamicToolResults: [], staticToolCalls: [], staticToolResults: [], content: [], usage: { inputTokens: void 0, outputTokens: void 0, totalTokens: void 0 }, warnings: [], request: {}, response: { id: "", timestamp: /* @__PURE__ */ new Date(), modelId: "", messages: [], uiMessages: [] }, reasoningText: "", providerMetadata: void 0, finishReason: void 0 }; break; } case "tripwire": self.#tripwire = { reason: chunk.payload?.reason || "Content blocked", retry: chunk.payload?.retry, metadata: chunk.payload?.metadata, processorId: chunk.payload?.processorId }; self.#finishReason = "other"; self.#streamFinished = true; self.resolvePromises({ text: self.#bufferedText.join(""), finishReason: "other", object: void 0, usage: self.#usageCount, warnings: self.#warnings, providerMetadata: void 0, response: { dbMessages: self.messageList.get.response.db() }, request: {}, reasoning: [], reasoningText: void 0, sources: [], files: [], toolCalls: [], toolResults: [], steps: self.#bufferedSteps, totalUsage: self.#usageCount, content: [], suspendPayload: void 0, // Tripwire doesn't suspend, so resolve to undefined resumeSchema: void 0 }); self.#closeTransportIfNeeded(); self.#emitChunk(chunk); controller.enqueue(chunk); self.#emitter.emit("finish"); controller.terminate(); return; case "finish": self.#status = "success"; if (chunk.payload.stepResult.reason) { self.#finishReason = chunk.payload.stepResult.reason; } const finalProviderMetadata = chunk.payload.metadata?.providerMetadata ?? chunk.payload.providerMetadata; if (finalProviderMetadata) { self.#stepProviderMetadata = finalProviderMetadata; } if (chunk.payload.stepResult.reason === "tripwire") { const outputSteps = chunk.payload.output?.steps; const lastStep = outputSteps?.[outputSteps?.length - 1]; const stepTripwire = lastStep?.tripwire; self.#tripwire = { reason: stepTripwire?.reason || "Processor tripwire triggered", retry: stepTripwire?.retry, metadata: stepTripwire?.metadata, processorId: stepTripwire?.processorId }; } if (self.#bufferedObject !== void 0) { const responseMessages = messageList.get.response.db(); const lastAssistantMessage = [...responseMessages].reverse().find((m) => m.role === "assistant"); if (lastAssistantMessage) { if (!lastAssistantMessage.content.metadata) { lastAssistantMessage.content.metadata = {}; } lastAssistantMessage.content.metadata.structuredOutput = self.#bufferedObject; } } let response = {}; if (chunk.payload.metadata) { const { providerMetadata, request, ...otherMetadata } = chunk.payload.metadata; response = { ...otherMetadata, messages: messageList.get.response.aiV5.model(), uiMessages: messageList.get.response.aiV5.ui() }; } this.populateUsageCount(chunk.payload.output.usage); chunk.payload.output.usage = { inputTokens: self.#usageCount.inputTokens ?? 0, outputTokens: self.#usageCount.outputTokens ?? 0, totalTokens: self.#usageCount.totalTokens ?? 0, ...self.#usageCount.reasoningTokens !== void 0 && { reasoningTokens: self.#usageCount.reasoningTokens }, ...self.#usageCount.cachedInputTokens !== void 0 && { cachedInputTokens: self.#usageCount.cachedInputTokens }, ...self.#usageCount.cacheCreationInputTokens !== void 0 && { cacheCreationInputTokens: self.#usageCount.cacheCreationInputTokens }, ...self.#usageCount.raw !== void 0 && { raw: self.#usageCount.raw } }; try { if (self.processorRunner && !self.#options.isLLMExecutionStep) { const lastStep = self.#bufferedSteps[self.#bufferedSteps.length - 1]; const originalText = lastStep?.text || ""; const outputResultWriter = { custom: async (data) => { self.#emitChunk(data); controller.enqueue(data); } }; const outputResult = { text: self.#bufferedText.join(""), usage: chunk.payload.output.usage, finishReason: self.#finishReason || "unknown", steps: [...self.#bufferedSteps] }; self.messageList = await self.processorRunner.runOutputProcessors( self.messageList, chunkYGTB7A25_cjs.resolveObservabilityContext(options), self.#options.requestContext, 0, outputResultWriter, outputResult ); const responseMessages = self.messageList.get.response.aiV4.core(); const lastResponseMessage = responseMessages[responseMessages.length - 1]; const outputText = lastResponseMessage ? chunkRWGBZBPV_cjs.coreContentToString(lastResponseMessage.content) : ""; if (lastStep && outputText && outputText !== originalText) { lastStep.text = outputText; } this.resolvePromises({ text: outputText || originalText, finishReason: self.#finishReason }); if (chunk.payload.metadata) { const { providerMetadata, re