@tanstack/ai
Version:
Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.
254 lines (253 loc) • 7.31 kB
JavaScript
import { parsePartialJSON } from "./json-parser.js";
function updateTextPart(messages, messageId, content) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const lastPart = parts.length > 0 ? parts[parts.length - 1] : null;
if (lastPart && lastPart.type === "text") {
parts[parts.length - 1] = { type: "text", content };
} else {
parts.push({ type: "text", content });
}
return { ...msg, parts };
});
}
function updateToolCallPart(messages, messageId, toolCall) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const existing = parts.find(
(p) => p.type === "tool-call" && p.id === toolCall.id
);
const metadata = toolCall.metadata ?? existing?.metadata;
const toolCallPart = {
type: "tool-call",
id: toolCall.id,
name: toolCall.name,
arguments: toolCall.arguments,
state: toolCall.state,
// Carry forward approval and output from the existing part
...existing?.approval && { approval: { ...existing.approval } },
...existing?.output !== void 0 && { output: existing.output },
...metadata !== void 0 && { metadata }
};
if (existing) {
parts[parts.indexOf(existing)] = toolCallPart;
} else {
parts.push(toolCallPart);
}
return { ...msg, parts };
});
}
function updateToolResultPart(messages, messageId, toolCallId, content, state, error) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const resultPartIndex = parts.findIndex(
(p) => p.type === "tool-result" && p.toolCallId === toolCallId
);
const toolResultPart = {
type: "tool-result",
toolCallId,
content,
state,
...error && { error }
};
if (resultPartIndex >= 0) {
parts[resultPartIndex] = toolResultPart;
} else {
parts.push(toolResultPart);
}
return { ...msg, parts };
});
}
function updateToolCallApproval(messages, messageId, toolCallId, approvalId) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const toolCallPart = parts.find(
(p) => p.type === "tool-call" && p.id === toolCallId
);
if (toolCallPart) {
const index = parts.indexOf(toolCallPart);
parts[index] = {
...toolCallPart,
state: "approval-requested",
approval: {
id: approvalId,
needsApproval: true
}
};
}
return { ...msg, parts };
});
}
function updateToolCallWithOutput(messages, toolCallId, output, state, errorText) {
return messages.map((msg) => {
const parts = [...msg.parts];
const toolCallPart = parts.find(
(p) => p.type === "tool-call" && p.id === toolCallId
);
if (toolCallPart) {
const index = parts.indexOf(toolCallPart);
parts[index] = {
...toolCallPart,
output: errorText ? { error: errorText } : output,
state: state ?? (errorText ? "error" : "complete")
};
}
return { ...msg, parts };
});
}
function updateToolCallApprovalResponse(messages, approvalId, approved) {
return messages.map((msg) => {
const parts = [...msg.parts];
const toolCallPart = parts.find(
(p) => p.type === "tool-call" && p.approval?.id === approvalId
);
if (toolCallPart && toolCallPart.approval) {
const index = parts.indexOf(toolCallPart);
parts[index] = {
...toolCallPart,
approval: { ...toolCallPart.approval, approved },
state: "approval-responded"
};
}
return { ...msg, parts };
});
}
function appendStructuredOutputDelta(messages, messageId, delta) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const existingIndex = parts.findIndex(
(p) => p.type === "structured-output"
);
const existing = existingIndex >= 0 ? parts[existingIndex] : null;
const nextRaw = (existing?.raw ?? "") + delta;
const progressive = parsePartialJSON(nextRaw);
const nextPartial = progressive !== void 0 && progressive !== null ? progressive : existing?.partial;
const nextPart = {
type: "structured-output",
status: "streaming",
raw: nextRaw,
...nextPartial !== void 0 ? { partial: nextPartial } : {},
...existing?.reasoning !== void 0 ? { reasoning: existing.reasoning } : {}
};
if (existingIndex >= 0) {
parts[existingIndex] = nextPart;
} else {
parts.push(nextPart);
}
return { ...msg, parts };
});
}
function completeStructuredOutputPart(messages, messageId, data, raw, reasoning) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const existingIndex = parts.findIndex(
(p) => p.type === "structured-output"
);
const existingRaw = existingIndex >= 0 ? parts[existingIndex].raw : "";
let resolvedRaw = raw || existingRaw;
if (resolvedRaw === "" && data !== void 0) {
try {
resolvedRaw = JSON.stringify(data);
} catch {
}
}
const nextPart = {
type: "structured-output",
status: "complete",
data,
partial: data,
raw: resolvedRaw,
...reasoning !== void 0 ? { reasoning } : {}
};
if (existingIndex >= 0) {
parts[existingIndex] = nextPart;
} else {
parts.push(nextPart);
}
return { ...msg, parts };
});
}
function errorStructuredOutputPart(messages, messageId, errorMessage) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const existingIndex = parts.findIndex(
(p) => p.type === "structured-output"
);
if (existingIndex < 0) {
parts.push({
type: "structured-output",
status: "error",
raw: "",
errorMessage
});
return { ...msg, parts };
}
const existing = parts[existingIndex];
if (existing.status === "complete") {
return msg;
}
parts[existingIndex] = {
...existing,
status: "error",
errorMessage
};
return { ...msg, parts };
});
}
function updateThinkingPart(messages, messageId, stepId, content, signature) {
return messages.map((msg) => {
if (msg.id !== messageId) {
return msg;
}
const parts = [...msg.parts];
const thinkingPartIndex = parts.findIndex(
(p) => p.type === "thinking" && p.stepId === stepId
);
const thinkingPart = {
type: "thinking",
content,
stepId,
...signature && { signature }
};
if (thinkingPartIndex >= 0) {
parts[thinkingPartIndex] = thinkingPart;
} else {
parts.push(thinkingPart);
}
return { ...msg, parts };
});
}
export {
appendStructuredOutputDelta,
completeStructuredOutputPart,
errorStructuredOutputPart,
updateTextPart,
updateThinkingPart,
updateToolCallApproval,
updateToolCallApprovalResponse,
updateToolCallPart,
updateToolCallWithOutput,
updateToolResultPart
};
//# sourceMappingURL=message-updaters.js.map