@sema-agent/core
Version:
Stateless, task-oriented AI agent core
662 lines (661 loc) • 35.3 kB
JavaScript
import {} from "../internal/llm.js";
import { repairTextToolCalls } from "./tool-call-repair.js";
import { DEGENERATE_MESSAGE, trimDegenerateTail } from "./repetition.js";
import { STREAM_TORN_WARNING, createRepetitionPoll, noteResponseModel, parseStreamedToolArgs, placeTurnNotes, truncationCauseClause } from "./stream-shared.js";
import { admitToolCallId, providerResultIds, providerToolCallId, responseToolCallIds } from "./tool-call-id.js";
import { emitBrainTelemetry } from "./status-sink.js";
import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imagesOmittedNoVisionNote, modelSupportsVision, sendableImages } from "./media-degrade.js";
import { OPENAI_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, effectiveOutputCap, lockHeader, mergeHeaders } from "./request-params.js";
import { BrainError } from "./errors.js";
import { adjudicateModelRoute, applyRouteCredentialHeaders, assertServableRequestRoot, createBrainRouteJudge, joinRequestUrl, resolveRequestRoot, resolveRouteCredential, routeRefusalText } from "./route-adjudicator.js";
import { declaredOffSpelling, mintEffortWireValue, reasoningRequestCarried } from "./reasoning.js";
import { runStreamingBrain } from "./stream-engine.js";
import { refuseRetiredTimeoutKnobs } from "./timeout.js";
import { resolveFetch } from "./transport.js";
function closeToolCallAccum(acc, responseIds) {
if (acc.closedTc)
return acc.closedTc;
if (!acc.name)
return undefined;
const args = parseStreamedToolArgs(acc.args);
if (args === undefined)
return undefined;
const { engineId, wireId } = admitToolCallId(acc.id, "call_", responseIds);
acc.closedTc = { type: "toolCall", id: engineId, ...(wireId !== engineId ? { wireId } : {}), name: acc.name, arguments: args };
return acc.closedTc;
}
function textOf(content) {
if (typeof content === "string") {
return content;
}
return content
.filter((c) => c.type === "text" && typeof c.text === "string")
.map((c) => c.text)
.join("");
}
const NO_CONTENT = "(no content)";
const DOCUMENT_OMITTED = "[PDF document omitted: PDF direct read requires an Anthropic-family model; re-Read the file (the engine will extract text/render pages when possible) or extract the text via Bash instead (e.g. `pdftotext`).]";
function toUserContent(content, supportsVision = true) {
if (typeof content === "string") {
return content;
}
const hasImage = content.some((c) => c.type === "image");
const nDocs = content.filter((c) => c.type === "document").length;
if (nDocs > 0)
emitBrainTelemetry({ kind: "document_placeholder", count: nDocs });
if (!hasImage) {
const base = textOf(content);
if (nDocs === 0)
return base;
return base ? `${base}\n${DOCUMENT_OMITTED}` : DOCUMENT_OMITTED;
}
if (!supportsVision) {
const n = content.filter((c) => c.type === "image").length;
emitBrainTelemetry({ kind: "vision_placeholder", count: n });
const base = textOf(content);
const note = imagesOmittedNoVisionNote(n);
const withNote = base ? `${base}\n${note}` : note;
return nDocs > 0 ? `${withNote}\n${DOCUMENT_OMITTED}` : withNote;
}
const parts = [];
for (const c of content) {
if (c.type === "text" && typeof c.text === "string" && c.text.length > 0) {
parts.push({ type: "text", text: c.text });
}
else if (c.type === "image" && c.data && c.mimeType) {
parts.push({
type: "image_url",
image_url: { url: `data:${c.mimeType};base64,${c.data}` },
});
}
else if (c.type === "document") {
parts.push({ type: "text", text: DOCUMENT_OMITTED });
}
}
return parts;
}
function thinkingCompat(model) {
return (model.compat ?? {});
}
function applyThinking(body, model, reasoning) {
if (model.reasoning && reasoning === "off") {
const offCompat = thinkingCompat(model);
const offFormat = offCompat.thinkingFormat ?? "openai";
switch (offFormat) {
case "qwen":
case "zai":
body.enable_thinking = false;
break;
case "qwen-chat-template": {
const k = (typeof body.chat_template_kwargs === "object" && body.chat_template_kwargs) || {};
body.chat_template_kwargs = { ...k, enable_thinking: false };
break;
}
case "deepseek":
body.thinking = { type: "disabled" };
break;
case "openrouter":
case "together":
body.reasoning = { enabled: false };
break;
case "openai": {
const offSpelling = declaredOffSpelling(model);
if (offSpelling !== undefined)
body.reasoning_effort = offSpelling;
break;
}
default: {
const _exhaustive = offFormat;
void _exhaustive;
break;
}
}
return;
}
if (!reasoningRequestCarried(model, reasoning))
return;
const compat = thinkingCompat(model);
const supportsEffort = compat.supportsReasoningEffort ?? true;
const effortWire = mintEffortWireValue(reasoning, model, compat.reasoningEffortLevels).wireValue;
const format = compat.thinkingFormat ?? "openai";
switch (format) {
case "openai":
if (supportsEffort && effortWire !== undefined)
body.reasoning_effort = effortWire;
break;
case "openrouter":
body.reasoning = { effort: effortWire };
break;
case "deepseek":
body.thinking = { type: "enabled" };
if (supportsEffort && effortWire !== undefined)
body.reasoning_effort = effortWire;
break;
case "together":
body.reasoning = { enabled: true };
if (supportsEffort && effortWire !== undefined)
body.reasoning_effort = effortWire;
break;
case "qwen":
case "zai":
body.enable_thinking = true;
break;
case "qwen-chat-template": {
const k = (typeof body.chat_template_kwargs === "object" && body.chat_template_kwargs) || {};
body.chat_template_kwargs = { ...k, enable_thinking: true };
break;
}
default: {
const _exhaustive = format;
void _exhaustive;
break;
}
}
}
function toOpenAIMessages(ctx, replayThinking = true, model) {
const supportsVision = modelSupportsVision(model);
const out = [];
const needsEmptyReasoningField = !!model?.reasoning && thinkingCompat(model).requiresReasoningContentOnAssistantMessages === true;
if (ctx.systemPrompt) {
out.push({ role: "system", content: ctx.systemPrompt });
}
let pendingImages = [];
const flushImages = () => {
if (pendingImages.length === 0)
return;
const ids = [...new Set(pendingImages.map((i) => i.toolCallId))].join(", ");
out.push({
role: "user",
content: [
{ type: "text", text: `[Image${pendingImages.length > 1 ? "s" : ""} from tool result ${ids}]` },
...pendingImages.map((i) => ({ type: "image_url", image_url: { url: `data:${i.mimeType};base64,${i.data}` } })),
],
});
pendingImages = [];
};
const resultWireId = providerResultIds(ctx.messages);
for (const m of ctx.messages) {
if (m.role !== "toolResult")
flushImages();
if (m.role === "user") {
const uc = toUserContent(m.content, supportsVision);
const empty = uc === "" || (Array.isArray(uc) && uc.length === 0);
out.push({ role: "user", content: empty ? NO_CONTENT : uc });
}
else if (m.role === "assistant") {
const text = m.content
.filter((c) => c.type === "text")
.map((c) => c.text)
.join("");
const toolCalls = m.content.filter((c) => c.type === "toolCall");
const msg = { role: "assistant", content: text };
const reasoning = m.content
.filter((c) => c.type === "thinking")
.map((c) => c.thinking)
.join("");
if (replayThinking && reasoning && toolCalls.length > 0) {
msg.reasoning_content = reasoning;
}
else if (needsEmptyReasoningField) {
msg.reasoning_content = "";
}
if (toolCalls.length > 0) {
msg.tool_calls = toolCalls.map((tc) => ({
id: providerToolCallId(tc),
type: "function",
function: { name: tc.name, arguments: JSON.stringify(tc.arguments ?? {}) },
}));
}
out.push(msg);
}
else if (m.role === "toolResult") {
const mediaImages = sendableImages(Array.isArray(m.content) ? m.content : []);
const rawImages = m.isError ? [] : mediaImages;
const images = supportsVision ? rawImages : [];
if (!supportsVision && rawImages.length > 0)
emitBrainTelemetry({ kind: "vision_placeholder", count: rawImages.length });
const nDocs = Array.isArray(m.content) ? m.content.filter((c) => c.type === "document").length : 0;
if (nDocs > 0)
emitBrainTelemetry({ kind: "document_placeholder", count: nDocs });
const baseText0 = textOf(m.content);
const baseText = nDocs > 0 ? (baseText0 ? `${baseText0}\n${DOCUMENT_OMITTED}` : DOCUMENT_OMITTED) : baseText0;
const text = !supportsVision && rawImages.length > 0 ? (baseText ? `${baseText}\n${IMAGE_OMITTED_NO_VISION}` : IMAGE_OMITTED_NO_VISION) : baseText;
const errorNote = m.isError ? errorResultMediaNote({ images: mediaImages.length, documents: 0 }) : undefined;
const finalText = errorNote === undefined ? text : text ? `${text}\n${errorNote}` : errorNote;
out.push({
role: "tool",
tool_call_id: resultWireId(m.toolCallId),
content: toolResultText(finalText, images.length > 0, m.content),
});
for (const img of images)
pendingImages.push({ toolCallId: resultWireId(m.toolCallId), data: img.data, mimeType: img.mimeType });
}
}
flushImages();
return out;
}
function toolResultText(text, hasCarriedImages, original) {
if (text !== "")
return text;
if (hasCarriedImages)
return "(image attached below)";
return Array.isArray(original) && original.length > 0 ? "(non-text tool result omitted)" : "";
}
function toOpenAITools(ctx) {
if (!ctx.tools || ctx.tools.length === 0) {
return undefined;
}
return ctx.tools.map((t) => ({
type: "function",
function: { name: t.name, description: t.description, parameters: t.parameters },
}));
}
function mapFinishReason(reason, hadToolCalls) {
if (hadToolCalls) {
return "toolUse";
}
if (reason === "length") {
return "length";
}
return "stop";
}
function computeUsage(model, raw) {
const input = raw?.prompt_tokens ?? 0;
const output = raw?.completion_tokens ?? 0;
const total = raw?.total_tokens ?? input + output;
const cacheRead = raw?.prompt_tokens_details?.cached_tokens ?? raw?.prompt_cache_hit_tokens ?? 0;
const c = model.cost;
const costInput = (input / 1e6) * (c?.input ?? 0);
const costOutput = (output / 1e6) * (c?.output ?? 0);
return {
input,
output,
cacheRead,
cacheWrite: 0,
totalTokens: total,
cost: { input: costInput, output: costOutput, cacheRead: 0, cacheWrite: 0, total: costInput + costOutput },
};
}
export function inferMaxTokensField(modelId) {
const id = modelId.toLowerCase();
if (/^gpt-5/.test(id) || /^chatgpt-4o/.test(id) || /^o[134](?:$|[-.])/.test(id))
return "max_completion_tokens";
return "max_tokens";
}
export function createOpenAIBrain(config = {}) {
assertServableRequestRoot(config.baseUrl, "config.baseUrl");
refuseRetiredTimeoutKnobs(config, "construction", "createOpenAIBrain config");
const doFetch = resolveFetch(config);
const stream = (model, context, options) => {
let sentMaxTokens;
let sentMaxTokensLane = "unset";
let builtMaxTokens;
let builtMaxTokensLane = "unset";
return runStreamingBrain({
model,
doFetch,
signal: options?.signal,
config,
httpLabel: "gateway",
maxRetries: options?.maxRetries,
stallTimeouts: options?.stallTimeouts,
buildRequest: (overrides) => {
const root = resolveRequestRoot(model.baseUrl, config.baseUrl);
if (!root) {
throw new Error("createOpenAIBrain: no baseUrl configured (set config.baseUrl or model.baseUrl)");
}
const routeCredential = resolveRouteCredential({
optionsApiKey: options?.apiKey,
optionsHeaders: options?.headers,
modelHeaders: model.headers,
configApiKey: config.apiKey,
configHeaders: config.headers,
});
const routeVerdict = adjudicateModelRoute(model, routeCredential, { baseUrl: config.baseUrl });
if (!routeVerdict.ok)
throw new BrainError("invalid_request", routeRefusalText(routeVerdict));
const apiKey = routeCredential.apiKey;
const body = {
model: model.id,
messages: toOpenAIMessages(context, config.replayThinking, model),
stream: true,
stream_options: { include_usage: true },
};
const tools = toOpenAITools(context);
if (tools)
body.tools = tools;
if (options?.temperature !== undefined)
body.temperature = options.temperature;
const requestedMaxTokens = overrides?.maxOutputTokens ?? options?.maxTokens ?? model.maxTokens;
const declared = (model.compat ?? {}).maxTokensField;
const mtField = declared ?? inferMaxTokensField(model.id);
if (requestedMaxTokens !== undefined) {
const capped = Math.max(1, requestedMaxTokens);
body[mtField] = capped;
builtMaxTokens = capped;
builtMaxTokensLane =
overrides?.maxOutputTokens !== undefined ? "engine" : options?.maxTokens !== undefined ? "options" : "model";
}
else {
builtMaxTokens = undefined;
builtMaxTokensLane = "unset";
}
if (options?.stop)
body.stop = options.stop;
applyThinking(body, model, options?.reasoning);
const headers = mergeHeaders(model.headers, config.headers, options?.headers);
applyRouteCredentialHeaders(headers, routeCredential, { model: model.headers, options: options?.headers });
lockHeader(headers, "content-type", "application/json");
if (apiKey)
headers["authorization"] = `Bearer ${apiKey}`;
const wire = applyExtraBody(body, model.extraBody, OPENAI_RESERVED);
return {
url: joinRequestUrl(root, "/chat/completions"),
headers,
body: JSON.stringify(wire),
outputCapTokens: effectiveOutputCap(wire, OUTPUT_CAP_KEYS.openai),
capDerivedPaths: [mtField],
onCommitted: () => {
sentMaxTokens = builtMaxTokens;
sentMaxTokensLane = builtMaxTokensLane;
},
};
},
makeParser: (ctrl) => {
const { out, partial } = ctrl;
let accumText = "";
let accumReasoning = "";
let accumRefusal = "";
let degenerate = false;
let degenFace;
const rep = createRepetitionPoll();
let lastDegenCheck = 0;
let lastDegenCheckReasoning = 0;
const detectRep = config.detectRepetition !== false;
let emittedTextStart = false;
let emittedThinkingStart = false;
let thinkingClosed = false;
let textIndex = 0;
const toolAccum = new Map();
const responseIds = responseToolCallIds();
let finishReason = null;
const terminalFrameSeen = () => finishReason != null;
let usageRaw;
let malformedFrames = 0;
let malformedSample;
const thinkingBlock = { type: "thinking", thinking: "" };
const textBlock = { type: "text", text: "" };
const pushReasoningDelta = (delta) => {
if (!delta)
return;
ctrl.sawContentToken();
if (thinkingClosed)
return;
if (!emittedThinkingStart) {
emittedThinkingStart = true;
partial.content = [thinkingBlock];
out.push({ type: "thinking_start", contentIndex: 0, partial: { ...partial } });
}
accumReasoning += delta;
thinkingBlock.thinking = accumReasoning;
out.push({ type: "thinking_delta", contentIndex: 0, delta, partial: { ...partial } });
if (detectRep && !degenerate && accumReasoning.length - lastDegenCheckReasoning >= 64) {
lastDegenCheckReasoning = accumReasoning.length;
if (rep.poll(accumReasoning)) {
degenerate = true;
degenFace = "reasoning";
ctrl.cancel();
}
}
};
const closeThinking = () => {
if (emittedThinkingStart && !thinkingClosed) {
thinkingClosed = true;
out.push({ type: "thinking_end", contentIndex: 0, content: accumReasoning, partial: { ...partial } });
}
};
const pushTextDelta = (delta) => {
if (!delta)
return;
ctrl.sawContentToken();
if (!emittedTextStart) {
closeThinking();
emittedTextStart = true;
textIndex = emittedThinkingStart ? 1 : 0;
partial.content = [textBlock];
out.push({ type: "text_start", contentIndex: textIndex, partial: { ...partial } });
}
accumText += delta;
textBlock.text = accumText;
out.push({ type: "text_delta", contentIndex: textIndex, delta, partial: { ...partial } });
if (detectRep && !degenerate && accumText.length - lastDegenCheck >= 64) {
lastDegenCheck = accumText.length;
if (rep.poll(accumText)) {
degenerate = true;
degenFace = "text";
ctrl.cancel();
}
}
};
return {
snapshot() {
const hasCompletedToolCall = [...toolAccum.values()].some((a) => a.closedTc !== undefined);
const hasSubstantiveText = accumText.trim() !== "" || accumRefusal.trim() !== "";
return {
hasSubstantiveText,
hasCompletedToolCall,
hasOnlyThinking: accumReasoning.length > 0 && !hasSubstantiveText && !hasCompletedToolCall,
terminalFrameSeen: terminalFrameSeen(),
};
},
sealForRetry() {
closeThinking();
},
onLine(rawLine) {
const line = rawLine.trim();
if (!line.startsWith("data:"))
return;
const data = line.slice(5).trim();
if (!data || data === "[DONE]")
return;
let chunk;
try {
chunk = JSON.parse(data);
}
catch {
malformedFrames++;
malformedSample ??= data.slice(0, 160);
return;
}
if (chunk.usage)
usageRaw = chunk.usage;
noteResponseModel(partial, chunk.model, model.id);
const choice = chunk.choices?.[0];
if (!choice)
return;
if (choice.finish_reason)
finishReason = choice.finish_reason;
const delta = choice.delta;
if (delta?.reasoning)
pushReasoningDelta(delta.reasoning);
else if (delta?.reasoning_content)
pushReasoningDelta(delta.reasoning_content);
if (delta?.refusal) {
ctrl.sawContentToken();
accumRefusal += delta.refusal;
}
if (delta?.content)
pushTextDelta(delta.content);
if (delta?.tool_calls) {
ctrl.sawContentToken();
for (const tc of delta.tool_calls) {
const idx = tc.index ?? (tc.id ? toolAccum.size : Math.max(0, toolAccum.size - 1));
if (!toolAccum.has(idx)) {
for (const [prevIdx, prevAcc] of [...toolAccum.entries()].sort((a, b) => a[0] - b[0])) {
if (prevIdx >= idx || prevAcc.closedTc)
continue;
if (prevAcc.args === "")
continue;
const closed = closeToolCallAccum(prevAcc, responseIds);
if (closed) {
out.push({ type: "toolcall_end", contentIndex: prevIdx, toolCall: closed, partial: { ...partial } });
}
}
}
const acc = toolAccum.get(idx) ?? { id: "", name: "", args: "" };
if (tc.id)
acc.id = tc.id;
if (tc.function?.name)
acc.name = tc.function.name;
if (tc.function?.arguments && !acc.closedTc)
acc.args += tc.function.arguments;
toolAccum.set(idx, acc);
}
}
},
finalize(opts) {
closeThinking();
const textFace = degenerate && degenFace === "text" && rep.cut !== undefined ? trimDegenerateTail(accumText, rep.cut) : accumText;
if (emittedTextStart && (opts?.truncated !== true || finishReason != null)) {
out.push({ type: "text_end", contentIndex: textIndex, content: textFace, partial: { ...partial } });
}
const finalContent = [];
if (accumReasoning)
finalContent.push({ type: "thinking", thinking: accumReasoning });
if (textFace)
finalContent.push({ type: "text", text: textFace });
const toolCalls = [];
const malformed = [];
const unnamed = [];
let emptyPlaceholders = 0;
for (const acc of [...toolAccum.entries()].sort((a, b) => a[0] - b[0]).map((e) => e[1])) {
if (!acc.name) {
if (!acc.id && acc.args === "") {
emptyPlaceholders++;
continue;
}
unnamed.push(`id="${acc.id || "?"}"(${acc.args.slice(0, 200)})`);
continue;
}
const tc = closeToolCallAccum(acc, responseIds);
if (tc) {
toolCalls.push(tc);
finalContent.push(tc);
}
else {
malformed.push(`${acc.name}(${acc.args.slice(0, 200)})`);
}
}
if (config.repairTextToolCalls && toolCalls.length === 0 && textFace && context.tools && context.tools.length > 0) {
const names = new Set(context.tools.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
const repaired = repairTextToolCalls(textFace, names);
if (repaired.toolCalls.length > 0) {
finalContent.length = 0;
if (accumReasoning)
finalContent.push({ type: "thinking", thinking: accumReasoning });
if (repaired.cleanedText)
finalContent.push({ type: "text", text: repaired.cleanedText });
for (const tc of repaired.toolCalls) {
finalContent.push(tc);
toolCalls.push(tc);
}
}
}
const emptySlots = `<empty slot>${emptyPlaceholders > 1 ? ` ×${emptyPlaceholders}` : ""}`;
const sawRealAction = toolCalls.length > 0 || malformed.length > 0 || unnamed.length > 0;
if (emptyPlaceholders > 0 && sawRealAction) {
unnamed.push(emptySlots);
}
else if (!sawRealAction && finishReason === "tool_calls") {
unnamed.push(emptyPlaceholders > 0 ? emptySlots : "<no tool_call delta arrived on the stream>");
}
const toolErrorParts = [];
if (malformed.length > 0) {
toolErrorParts.push(`tool call argument(s) not valid JSON (likely truncated, finish_reason="${finishReason ?? "?"}"${truncationCauseClause({ capStop: finishReason === "length", outputTokens: usageRaw?.completion_tokens, capTokens: sentMaxTokens, terminalFrameSeen: terminalFrameSeen() })}): ${malformed.join("; ")}`);
}
if (unnamed.length > 0) {
toolErrorParts.push(`tool call(s) arrived with no tool name and cannot be executed (finish_reason="${finishReason ?? "?"}"): ${unnamed.join("; ")}`);
}
const toolError = toolErrorParts.length > 0 ? toolErrorParts.join(" | ") : undefined;
const noUsableContent = toolCalls.length === 0 && !accumText.trim();
const notes = [];
if (malformed.length > 0) {
notes.push({ cause: "truncated", count: malformed.length, text: `\n[note: ${malformed.length} tool call(s) were truncated (finish_reason="${finishReason ?? "?"}") and dropped — re-issue them next turn: ${malformed.join("; ")}]` });
}
if (unnamed.length > 0) {
notes.push({ cause: "unnamed", count: unnamed.length, text: `\n[note: ${unnamed.length} tool call(s) arrived with no tool name and were dropped — re-issue them next turn with an explicit tool name: ${unnamed.join("; ")}]` });
}
if (malformedFrames > 0) {
notes.push({ cause: "bad_frame", count: malformedFrames, text: `\n[note: ${malformedFrames} provider stream frame(s) were not valid JSON and were dropped — the streamed output may be missing content (first sample: ${JSON.stringify(malformedSample)})]` });
}
placeTurnNotes(partial, finalContent, notes);
const truncatedEmpty = finishReason === "length" && noUsableContent && !toolError;
const dynamicCut = truncatedEmpty && options?.maxTokensDynamic === true;
const safetyCut = finishReason === "content_filter";
const refused = accumRefusal.trim().length > 0;
const emptyNoFinish = noUsableContent && finishReason == null && !degenerate;
const maxTokensNote = sentMaxTokens !== undefined
? `effective max_tokens=${sentMaxTokens} (from ${sentMaxTokensLane === "options"
? "options.maxTokens"
: sentMaxTokensLane === "engine"
? "the engine's context-overflow recovery"
: "model.maxTokens"})`
: "max_tokens not set (neither options.maxTokens nor model.maxTokens — the provider's default cap applied)";
const errorMessage = degenerate
? DEGENERATE_MESSAGE
: safetyCut
? `[refusal] response cut by the provider content filter (finish_reason="content_filter") — the output was censored/truncated for policy and is unreliable`
: refused
? `[refusal] response refused by the model for policy reasons: ${accumRefusal.trim()}`
: (toolError ??
(truncatedEmpty && !dynamicCut
? accumReasoning.trim()
? `[length_empty] response truncated at max_tokens (finish_reason="length", ${maxTokensNote}) with no answer text — the model spent the whole budget on reasoning (${accumReasoning.length} reasoning chars). Raise max_tokens, or disable thinking for this task.`
: `[length_empty] response truncated at max_tokens (finish_reason="length", ${maxTokensNote}) with no answer text — raise max_tokens`
: emptyNoFinish
? `[stream_torn] model stream ended with no content and no finish_reason — the response was lost (a torn stream or an in-band provider error frame)${malformedFrames > 0 ? ` — ${malformedFrames} unparseable data frame(s) were dropped on this stream (first sample: ${JSON.stringify(malformedSample)})` : ""}`
: undefined));
const errored = degenerate ||
safetyCut ||
refused ||
emptyNoFinish ||
(toolError !== undefined && noUsableContent) ||
(truncatedEmpty && !dynamicCut);
const tornWithContent = !errored && opts?.truncated !== true && !terminalFrameSeen() && !noUsableContent && !degenerate;
const errorMessageOut = tornWithContent ? (errorMessage ? `${errorMessage}\n${STREAM_TORN_WARNING}` : STREAM_TORN_WARNING) : errorMessage;
const errorKind = degenerate
? "degenerate"
: !safetyCut && !refused && toolError === undefined && truncatedEmpty && !dynamicCut
? "length_empty"
: undefined;
const finalMessage = {
...partial,
content: finalContent.length > 0 ? finalContent : [{ type: "text", text: "" }],
stopReason: errored ? "error" : mapFinishReason(finishReason, toolCalls.length > 0),
usage: computeUsage(model, usageRaw),
...(usageRaw === undefined ? { usageMissing: true } : {}),
timestamp: Date.now(),
...(errorMessageOut ? { errorMessage: errorMessageOut } : {}),
...(errorKind ? { errorKind } : {}),
...(tornWithContent ? { partialFinalized: true } : {}),
...(rep.cut !== undefined || rep.spared.length > 0
? { repetition: { ...(rep.cut !== undefined ? { cut: rep.cut } : {}), ...(rep.spared.length > 0 ? { spared: rep.spared } : {}) } }
: {}),
};
if (errored) {
out.push({ type: "error", reason: "error", error: finalMessage });
}
else {
out.push({
type: "done",
reason: finalMessage.stopReason,
message: finalMessage,
});
}
},
};
},
});
};
return { stream, adjudicateRoute: createBrainRouteJudge(config) };
}