@tanstack/ai 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/esm/base-adapter.d.ts +35 -0
- package/dist/esm/base-adapter.js +12 -0
- package/dist/esm/base-adapter.js.map +1 -0
- package/dist/esm/core/chat-common-options.d.ts +52 -0
- package/dist/esm/core/chat.d.ts +30 -0
- package/dist/esm/core/chat.js +533 -0
- package/dist/esm/core/chat.js.map +1 -0
- package/dist/esm/core/embedding.d.ts +8 -0
- package/dist/esm/core/embedding.js +33 -0
- package/dist/esm/core/embedding.js.map +1 -0
- package/dist/esm/core/summarize.d.ts +9 -0
- package/dist/esm/core/summarize.js +36 -0
- package/dist/esm/core/summarize.js.map +1 -0
- package/dist/esm/event-client.d.ts +311 -0
- package/dist/esm/event-client.js +62 -0
- package/dist/esm/event-client.js.map +1 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.js +50 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/message-converters.d.ts +52 -0
- package/dist/esm/message-converters.js +162 -0
- package/dist/esm/message-converters.js.map +1 -0
- package/dist/esm/stream/index.d.ts +11 -0
- package/dist/esm/stream/json-parser.d.ts +38 -0
- package/dist/esm/stream/json-parser.js +28 -0
- package/dist/esm/stream/json-parser.js.map +1 -0
- package/dist/esm/stream/message-updaters.d.ts +44 -0
- package/dist/esm/stream/message-updaters.js +141 -0
- package/dist/esm/stream/message-updaters.js.map +1 -0
- package/dist/esm/stream/processor.d.ts +242 -0
- package/dist/esm/stream/processor.js +693 -0
- package/dist/esm/stream/processor.js.map +1 -0
- package/dist/esm/stream/strategies.d.ts +43 -0
- package/dist/esm/stream/strategies.js +54 -0
- package/dist/esm/stream/strategies.js.map +1 -0
- package/dist/esm/stream/types.d.ts +71 -0
- package/dist/esm/tools/tool-calls.d.ts +112 -0
- package/dist/esm/tools/tool-calls.js +302 -0
- package/dist/esm/tools/tool-calls.js.map +1 -0
- package/dist/esm/tools/tool-definition.d.ts +125 -0
- package/dist/esm/tools/tool-definition.js +25 -0
- package/dist/esm/tools/tool-definition.js.map +1 -0
- package/dist/esm/tools/zod-converter.d.ts +30 -0
- package/dist/esm/tools/zod-converter.js +36 -0
- package/dist/esm/tools/zod-converter.js.map +1 -0
- package/dist/esm/types.d.ts +619 -0
- package/dist/esm/utilities/agent-loop-strategies.d.ts +59 -0
- package/dist/esm/utilities/agent-loop-strategies.js +23 -0
- package/dist/esm/utilities/agent-loop-strategies.js.map +1 -0
- package/dist/esm/utilities/chat-options.d.ts +6 -0
- package/dist/esm/utilities/chat-options.js +7 -0
- package/dist/esm/utilities/chat-options.js.map +1 -0
- package/dist/esm/utilities/messages.d.ts +30 -0
- package/dist/esm/utilities/messages.js +7 -0
- package/dist/esm/utilities/messages.js.map +1 -0
- package/dist/esm/utilities/stream-to-response.d.ts +48 -0
- package/dist/esm/utilities/stream-to-response.js +62 -0
- package/dist/esm/utilities/stream-to-response.js.map +1 -0
- package/package.json +65 -0
- package/src/base-adapter.ts +85 -0
- package/src/core/chat-common-options.ts +55 -0
- package/src/core/chat.ts +771 -0
- package/src/core/embedding.ts +54 -0
- package/src/core/summarize.ts +56 -0
- package/src/event-client.ts +389 -0
- package/src/index.ts +68 -0
- package/src/message-converters.ts +285 -0
- package/src/stream/index.ts +41 -0
- package/src/stream/json-parser.ts +58 -0
- package/src/stream/message-updaters.ts +275 -0
- package/src/stream/processor.ts +1092 -0
- package/src/stream/strategies.ts +78 -0
- package/src/stream/types.ts +94 -0
- package/src/tools/tool-calls.ts +471 -0
- package/src/tools/tool-definition.ts +206 -0
- package/src/tools/zod-converter.ts +85 -0
- package/src/types.ts +872 -0
- package/src/utilities/agent-loop-strategies.ts +85 -0
- package/src/utilities/chat-options.ts +35 -0
- package/src/utilities/messages.ts +63 -0
- package/src/utilities/stream-to-response.ts +116 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
function getTextContent(content) {
|
|
2
|
+
if (content === null) {
|
|
3
|
+
return "";
|
|
4
|
+
}
|
|
5
|
+
if (typeof content === "string") {
|
|
6
|
+
return content;
|
|
7
|
+
}
|
|
8
|
+
return content.filter((part) => part.type === "text").map((part) => part.content).join("");
|
|
9
|
+
}
|
|
10
|
+
function convertMessagesToModelMessages(messages) {
|
|
11
|
+
const modelMessages = [];
|
|
12
|
+
for (const msg of messages) {
|
|
13
|
+
if ("parts" in msg) {
|
|
14
|
+
modelMessages.push(...uiMessageToModelMessages(msg));
|
|
15
|
+
} else {
|
|
16
|
+
modelMessages.push(msg);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return modelMessages;
|
|
20
|
+
}
|
|
21
|
+
function uiMessageToModelMessages(uiMessage) {
|
|
22
|
+
const messages = [];
|
|
23
|
+
if (uiMessage.role === "system") {
|
|
24
|
+
return messages;
|
|
25
|
+
}
|
|
26
|
+
const textParts = [];
|
|
27
|
+
const toolCallParts = [];
|
|
28
|
+
const toolResultParts = [];
|
|
29
|
+
for (const part of uiMessage.parts) {
|
|
30
|
+
if (part.type === "text") {
|
|
31
|
+
textParts.push(part);
|
|
32
|
+
} else if (part.type === "tool-call") {
|
|
33
|
+
toolCallParts.push(part);
|
|
34
|
+
} else if (part.type === "tool-result") {
|
|
35
|
+
toolResultParts.push(part);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const content = textParts.map((p) => p.content).join("") || null;
|
|
39
|
+
const toolCalls = toolCallParts.length > 0 ? toolCallParts.filter(
|
|
40
|
+
(p) => p.state === "input-complete" || p.state === "approval-responded" || p.output !== void 0
|
|
41
|
+
// Include if has output (client tool result)
|
|
42
|
+
).map((p) => ({
|
|
43
|
+
id: p.id,
|
|
44
|
+
type: "function",
|
|
45
|
+
function: {
|
|
46
|
+
name: p.name,
|
|
47
|
+
arguments: p.arguments
|
|
48
|
+
}
|
|
49
|
+
})) : void 0;
|
|
50
|
+
if (uiMessage.role !== "assistant" || content || !toolCalls) {
|
|
51
|
+
messages.push({
|
|
52
|
+
role: uiMessage.role,
|
|
53
|
+
content,
|
|
54
|
+
...toolCalls && toolCalls.length > 0 && { toolCalls }
|
|
55
|
+
});
|
|
56
|
+
} else if (toolCalls.length > 0) {
|
|
57
|
+
messages.push({
|
|
58
|
+
role: "assistant",
|
|
59
|
+
content,
|
|
60
|
+
toolCalls
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
for (const toolResultPart of toolResultParts) {
|
|
64
|
+
if (toolResultPart.state === "complete" || toolResultPart.state === "error") {
|
|
65
|
+
messages.push({
|
|
66
|
+
role: "tool",
|
|
67
|
+
content: toolResultPart.content,
|
|
68
|
+
toolCallId: toolResultPart.toolCallId
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return messages;
|
|
73
|
+
}
|
|
74
|
+
function modelMessageToUIMessage(modelMessage, id) {
|
|
75
|
+
const parts = [];
|
|
76
|
+
const textContent = getTextContent(modelMessage.content);
|
|
77
|
+
if (textContent) {
|
|
78
|
+
parts.push({
|
|
79
|
+
type: "text",
|
|
80
|
+
content: textContent
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (modelMessage.toolCalls && modelMessage.toolCalls.length > 0) {
|
|
84
|
+
for (const toolCall of modelMessage.toolCalls) {
|
|
85
|
+
parts.push({
|
|
86
|
+
type: "tool-call",
|
|
87
|
+
id: toolCall.id,
|
|
88
|
+
name: toolCall.function.name,
|
|
89
|
+
arguments: toolCall.function.arguments,
|
|
90
|
+
state: "input-complete"
|
|
91
|
+
// Model messages have complete arguments
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (modelMessage.role === "tool" && modelMessage.toolCallId) {
|
|
96
|
+
parts.push({
|
|
97
|
+
type: "tool-result",
|
|
98
|
+
toolCallId: modelMessage.toolCallId,
|
|
99
|
+
content: getTextContent(modelMessage.content),
|
|
100
|
+
state: "complete"
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
id: id || generateMessageId(),
|
|
105
|
+
role: modelMessage.role === "tool" ? "assistant" : modelMessage.role,
|
|
106
|
+
parts
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function modelMessagesToUIMessages(modelMessages) {
|
|
110
|
+
const uiMessages = [];
|
|
111
|
+
let currentAssistantMessage = null;
|
|
112
|
+
for (const msg of modelMessages) {
|
|
113
|
+
if (msg.role === "tool") {
|
|
114
|
+
if (currentAssistantMessage && currentAssistantMessage.role === "assistant") {
|
|
115
|
+
currentAssistantMessage.parts.push({
|
|
116
|
+
type: "tool-result",
|
|
117
|
+
toolCallId: msg.toolCallId,
|
|
118
|
+
content: getTextContent(msg.content),
|
|
119
|
+
state: "complete"
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
const toolResultUIMessage = modelMessageToUIMessage(msg);
|
|
123
|
+
uiMessages.push(toolResultUIMessage);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
const uiMessage = modelMessageToUIMessage(msg);
|
|
127
|
+
uiMessages.push(uiMessage);
|
|
128
|
+
if (msg.role === "assistant") {
|
|
129
|
+
currentAssistantMessage = uiMessage;
|
|
130
|
+
} else {
|
|
131
|
+
currentAssistantMessage = null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return uiMessages;
|
|
136
|
+
}
|
|
137
|
+
function normalizeToUIMessage(message, generateId) {
|
|
138
|
+
if ("parts" in message) {
|
|
139
|
+
return {
|
|
140
|
+
...message,
|
|
141
|
+
id: message.id || generateId(),
|
|
142
|
+
createdAt: message.createdAt || /* @__PURE__ */ new Date()
|
|
143
|
+
};
|
|
144
|
+
} else {
|
|
145
|
+
return {
|
|
146
|
+
...modelMessageToUIMessage(message, generateId()),
|
|
147
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function generateMessageId() {
|
|
152
|
+
return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`;
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
convertMessagesToModelMessages,
|
|
156
|
+
generateMessageId,
|
|
157
|
+
modelMessageToUIMessage,
|
|
158
|
+
modelMessagesToUIMessages,
|
|
159
|
+
normalizeToUIMessage,
|
|
160
|
+
uiMessageToModelMessages
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=message-converters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-converters.js","sources":["../../src/message-converters.ts"],"sourcesContent":["/**\n * Message Converters\n *\n * Functions for converting between UIMessage and ModelMessage formats.\n */\n\nimport type {\n ContentPart,\n MessagePart,\n ModelMessage,\n TextPart,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n} from './types'\n\n/**\n * Helper to extract text content from string or ContentPart array\n * For multimodal content, this extracts only the text parts\n */\nfunction getTextContent(content: string | null | Array<ContentPart>): string {\n if (content === null) {\n return ''\n }\n if (typeof content === 'string') {\n return content\n }\n // Extract text from ContentPart array\n return content\n .filter((part) => part.type === 'text')\n .map((part) => part.content)\n .join('')\n}\n\n/**\n * Convert UIMessages or ModelMessages to ModelMessages\n */\nexport function convertMessagesToModelMessages(\n messages: Array<UIMessage | ModelMessage>,\n): Array<ModelMessage> {\n const modelMessages: Array<ModelMessage> = []\n for (const msg of messages) {\n if ('parts' in msg) {\n // UIMessage - convert to ModelMessages\n modelMessages.push(...uiMessageToModelMessages(msg))\n } else {\n // Already ModelMessage\n modelMessages.push(msg)\n }\n }\n return modelMessages\n}\n\n/**\n * Convert a UIMessage to ModelMessage(s)\n *\n * This conversion handles the parts-based structure:\n * - Text parts → content field\n * - ToolCall parts → toolCalls array\n * - ToolResult parts → separate role=\"tool\" messages\n *\n * @param uiMessage - The UIMessage to convert\n * @returns An array of ModelMessages (may be multiple if tool results are present)\n */\nexport function uiMessageToModelMessages(\n uiMessage: UIMessage,\n): Array<ModelMessage> {\n const messages: Array<ModelMessage> = []\n\n // Skip system messages - they're handled via systemPrompts, not ModelMessages\n if (uiMessage.role === 'system') {\n return messages\n }\n\n // Separate parts by type\n // Note: thinking parts are UI-only and not included in ModelMessages\n const textParts: Array<TextPart> = []\n const toolCallParts: Array<ToolCallPart> = []\n const toolResultParts: Array<ToolResultPart> = []\n\n for (const part of uiMessage.parts) {\n if (part.type === 'text') {\n textParts.push(part)\n } else if (part.type === 'tool-call') {\n toolCallParts.push(part)\n } else if (part.type === 'tool-result') {\n toolResultParts.push(part)\n }\n // thinking parts are skipped - they're UI-only\n }\n\n // Build the main message (user or assistant)\n const content = textParts.map((p) => p.content).join('') || null\n const toolCalls =\n toolCallParts.length > 0\n ? toolCallParts\n .filter(\n (p) =>\n p.state === 'input-complete' ||\n p.state === 'approval-responded' ||\n p.output !== undefined, // Include if has output (client tool result)\n )\n .map((p) => ({\n id: p.id,\n type: 'function' as const,\n function: {\n name: p.name,\n arguments: p.arguments,\n },\n }))\n : undefined\n\n // Create the main message\n if (uiMessage.role !== 'assistant' || content || !toolCalls) {\n messages.push({\n role: uiMessage.role,\n content,\n ...(toolCalls && toolCalls.length > 0 && { toolCalls }),\n })\n } else if (toolCalls.length > 0) {\n // Assistant message with only tool calls\n messages.push({\n role: 'assistant',\n content,\n toolCalls,\n })\n }\n\n // Add tool result messages (only completed ones)\n for (const toolResultPart of toolResultParts) {\n if (\n toolResultPart.state === 'complete' ||\n toolResultPart.state === 'error'\n ) {\n messages.push({\n role: 'tool',\n content: toolResultPart.content,\n toolCallId: toolResultPart.toolCallId,\n })\n }\n }\n\n return messages\n}\n\n/**\n * Convert a ModelMessage to UIMessage\n *\n * This conversion creates a parts-based structure:\n * - content field → TextPart\n * - toolCalls array → ToolCallPart[]\n * - role=\"tool\" messages should be converted separately and merged\n *\n * @param modelMessage - The ModelMessage to convert\n * @param id - Optional ID for the UIMessage (generated if not provided)\n * @returns A UIMessage with parts\n */\nexport function modelMessageToUIMessage(\n modelMessage: ModelMessage,\n id?: string,\n): UIMessage {\n const parts: Array<MessagePart> = []\n\n // Handle content (convert multimodal content to text for UI)\n const textContent = getTextContent(modelMessage.content)\n if (textContent) {\n parts.push({\n type: 'text',\n content: textContent,\n })\n }\n\n // Handle tool calls\n if (modelMessage.toolCalls && modelMessage.toolCalls.length > 0) {\n for (const toolCall of modelMessage.toolCalls) {\n parts.push({\n type: 'tool-call',\n id: toolCall.id,\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n state: 'input-complete', // Model messages have complete arguments\n })\n }\n }\n\n // Handle tool results (when role is \"tool\")\n if (modelMessage.role === 'tool' && modelMessage.toolCallId) {\n parts.push({\n type: 'tool-result',\n toolCallId: modelMessage.toolCallId,\n content: getTextContent(modelMessage.content),\n state: 'complete',\n })\n }\n\n return {\n id: id || generateMessageId(),\n role: modelMessage.role === 'tool' ? 'assistant' : modelMessage.role,\n parts,\n }\n}\n\n/**\n * Convert an array of ModelMessages to UIMessages\n *\n * This handles merging tool result messages with their corresponding assistant messages\n *\n * @param modelMessages - Array of ModelMessages to convert\n * @returns Array of UIMessages\n */\nexport function modelMessagesToUIMessages(\n modelMessages: Array<ModelMessage>,\n): Array<UIMessage> {\n const uiMessages: Array<UIMessage> = []\n let currentAssistantMessage: UIMessage | null = null\n\n for (const msg of modelMessages) {\n if (msg.role === 'tool') {\n // Tool result - merge into the last assistant message if possible\n if (\n currentAssistantMessage &&\n currentAssistantMessage.role === 'assistant'\n ) {\n currentAssistantMessage.parts.push({\n type: 'tool-result',\n toolCallId: msg.toolCallId!,\n content: getTextContent(msg.content),\n state: 'complete',\n })\n } else {\n // No assistant message to merge into, create a standalone one\n const toolResultUIMessage = modelMessageToUIMessage(msg)\n uiMessages.push(toolResultUIMessage)\n }\n } else {\n // Regular message\n const uiMessage = modelMessageToUIMessage(msg)\n uiMessages.push(uiMessage)\n\n // Track assistant messages for potential tool result merging\n if (msg.role === 'assistant') {\n currentAssistantMessage = uiMessage\n } else {\n currentAssistantMessage = null\n }\n }\n }\n\n return uiMessages\n}\n\n/**\n * Normalize a message (UIMessage or ModelMessage) to a UIMessage\n * Ensures the message has an ID and createdAt timestamp\n *\n * @param message - Either a UIMessage or ModelMessage\n * @param generateId - Function to generate a message ID if needed\n * @returns A UIMessage with guaranteed id and createdAt\n */\nexport function normalizeToUIMessage(\n message: UIMessage | ModelMessage,\n generateId: () => string,\n): UIMessage {\n if ('parts' in message) {\n // Already a UIMessage\n return {\n ...message,\n id: message.id || generateId(),\n createdAt: message.createdAt || new Date(),\n }\n } else {\n // ModelMessage - convert to UIMessage\n return {\n ...modelMessageToUIMessage(message, generateId()),\n createdAt: new Date(),\n }\n }\n}\n\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId(): string {\n return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream Processing Module
|
|
3
|
+
*
|
|
4
|
+
* Unified stream processing for both server and client.
|
|
5
|
+
*/
|
|
6
|
+
export { StreamProcessor, createReplayStream } from './processor.js';
|
|
7
|
+
export type { StreamProcessorEvents, StreamProcessorHandlers, StreamProcessorOptions, } from './processor.js';
|
|
8
|
+
export { ImmediateStrategy, PunctuationStrategy, BatchStrategy, WordBoundaryStrategy, CompositeStrategy, } from './strategies.js';
|
|
9
|
+
export { PartialJSONParser, defaultJSONParser, parsePartialJSON, } from './json-parser.js';
|
|
10
|
+
export type { JSONParser } from './json-parser.js';
|
|
11
|
+
export type { ChunkStrategy, ChunkRecording, InternalToolCallState, ProcessorResult, ProcessorState, ToolCallState, ToolResultState, } from './types.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Parser for partial/incomplete JSON strings
|
|
3
|
+
*
|
|
4
|
+
* Used during streaming to parse tool call arguments that may be incomplete.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* JSON Parser interface - allows for custom parser implementations
|
|
8
|
+
*/
|
|
9
|
+
export interface JSONParser {
|
|
10
|
+
/**
|
|
11
|
+
* Parse a JSON string (may be incomplete/partial)
|
|
12
|
+
* @param jsonString - The JSON string to parse
|
|
13
|
+
* @returns The parsed object, or undefined if parsing fails
|
|
14
|
+
*/
|
|
15
|
+
parse: (jsonString: string) => any;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Partial JSON Parser implementation using the partial-json library
|
|
19
|
+
* This parser can handle incomplete JSON strings during streaming
|
|
20
|
+
*/
|
|
21
|
+
export declare class PartialJSONParser implements JSONParser {
|
|
22
|
+
/**
|
|
23
|
+
* Parse a potentially incomplete JSON string
|
|
24
|
+
* @param jsonString - The JSON string to parse (may be incomplete)
|
|
25
|
+
* @returns The parsed object, or undefined if parsing fails
|
|
26
|
+
*/
|
|
27
|
+
parse(jsonString: string): any;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Default parser instance
|
|
31
|
+
*/
|
|
32
|
+
export declare const defaultJSONParser: PartialJSONParser;
|
|
33
|
+
/**
|
|
34
|
+
* Parse partial JSON string (convenience function)
|
|
35
|
+
* @param jsonString - The JSON string to parse (may be incomplete)
|
|
36
|
+
* @returns The parsed object, or undefined if parsing fails
|
|
37
|
+
*/
|
|
38
|
+
export declare function parsePartialJSON(jsonString: string): any;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { parse } from "partial-json";
|
|
2
|
+
class PartialJSONParser {
|
|
3
|
+
/**
|
|
4
|
+
* Parse a potentially incomplete JSON string
|
|
5
|
+
* @param jsonString - The JSON string to parse (may be incomplete)
|
|
6
|
+
* @returns The parsed object, or undefined if parsing fails
|
|
7
|
+
*/
|
|
8
|
+
parse(jsonString) {
|
|
9
|
+
if (!jsonString || jsonString.trim() === "") {
|
|
10
|
+
return void 0;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
return parse(jsonString);
|
|
14
|
+
} catch {
|
|
15
|
+
return void 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const defaultJSONParser = new PartialJSONParser();
|
|
20
|
+
function parsePartialJSON(jsonString) {
|
|
21
|
+
return defaultJSONParser.parse(jsonString);
|
|
22
|
+
}
|
|
23
|
+
export {
|
|
24
|
+
PartialJSONParser,
|
|
25
|
+
defaultJSONParser,
|
|
26
|
+
parsePartialJSON
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=json-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-parser.js","sources":["../../../src/stream/json-parser.ts"],"sourcesContent":["/**\n * JSON Parser for partial/incomplete JSON strings\n *\n * Used during streaming to parse tool call arguments that may be incomplete.\n */\n\nimport { parse as parsePartialJSONLib } from 'partial-json'\n\n/**\n * JSON Parser interface - allows for custom parser implementations\n */\nexport interface JSONParser {\n /**\n * Parse a JSON string (may be incomplete/partial)\n * @param jsonString - The JSON string to parse\n * @returns The parsed object, or undefined if parsing fails\n */\n parse: (jsonString: string) => any\n}\n\n/**\n * Partial JSON Parser implementation using the partial-json library\n * This parser can handle incomplete JSON strings during streaming\n */\nexport class PartialJSONParser implements JSONParser {\n /**\n * Parse a potentially incomplete JSON string\n * @param jsonString - The JSON string to parse (may be incomplete)\n * @returns The parsed object, or undefined if parsing fails\n */\n parse(jsonString: string): any {\n if (!jsonString || jsonString.trim() === '') {\n return undefined\n }\n\n try {\n return parsePartialJSONLib(jsonString)\n } catch {\n // If partial parsing fails, return undefined\n // This is expected during early streaming when we have very little data\n return undefined\n }\n }\n}\n\n/**\n * Default parser instance\n */\nexport const defaultJSONParser = new PartialJSONParser()\n\n/**\n * Parse partial JSON string (convenience function)\n * @param jsonString - The JSON string to parse (may be incomplete)\n * @returns The parsed object, or undefined if parsing fails\n */\nexport function parsePartialJSON(jsonString: string): any {\n return defaultJSONParser.parse(jsonString)\n}\n"],"names":["parsePartialJSONLib"],"mappings":";AAwBO,MAAM,kBAAwC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnD,MAAM,YAAyB;AAC7B,QAAI,CAAC,cAAc,WAAW,KAAA,MAAW,IAAI;AAC3C,aAAO;AAAA,IACT;AAEA,QAAI;AACF,aAAOA,MAAoB,UAAU;AAAA,IACvC,QAAQ;AAGN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAKO,MAAM,oBAAoB,IAAI,kBAAA;AAO9B,SAAS,iBAAiB,YAAyB;AACxD,SAAO,kBAAkB,MAAM,UAAU;AAC3C;"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { UIMessage } from '../types.js';
|
|
2
|
+
import { ToolCallState, ToolResultState } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Update or add a text part to a message.
|
|
5
|
+
*
|
|
6
|
+
* If the last part is a text part, update it (continuing the same text segment).
|
|
7
|
+
* Otherwise, create a new text part (starting a new text segment after tool calls).
|
|
8
|
+
*/
|
|
9
|
+
export declare function updateTextPart(messages: Array<UIMessage>, messageId: string, content: string): Array<UIMessage>;
|
|
10
|
+
/**
|
|
11
|
+
* Update or add a tool call part to a message.
|
|
12
|
+
*/
|
|
13
|
+
export declare function updateToolCallPart(messages: Array<UIMessage>, messageId: string, toolCall: {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
arguments: string;
|
|
17
|
+
state: ToolCallState;
|
|
18
|
+
}): Array<UIMessage>;
|
|
19
|
+
/**
|
|
20
|
+
* Update or add a tool result part to a message.
|
|
21
|
+
*/
|
|
22
|
+
export declare function updateToolResultPart(messages: Array<UIMessage>, messageId: string, toolCallId: string, content: string, state: ToolResultState, error?: string): Array<UIMessage>;
|
|
23
|
+
/**
|
|
24
|
+
* Update a tool call part with approval request metadata.
|
|
25
|
+
*/
|
|
26
|
+
export declare function updateToolCallApproval(messages: Array<UIMessage>, messageId: string, toolCallId: string, approvalId: string): Array<UIMessage>;
|
|
27
|
+
/**
|
|
28
|
+
* Update a tool call part's state (e.g., to "input-complete").
|
|
29
|
+
*/
|
|
30
|
+
export declare function updateToolCallState(messages: Array<UIMessage>, messageId: string, toolCallId: string, state: ToolCallState): Array<UIMessage>;
|
|
31
|
+
/**
|
|
32
|
+
* Update a tool call part with output.
|
|
33
|
+
* Searches all messages to find the tool call by ID.
|
|
34
|
+
*/
|
|
35
|
+
export declare function updateToolCallWithOutput(messages: Array<UIMessage>, toolCallId: string, output: any, state?: ToolCallState, errorText?: string): Array<UIMessage>;
|
|
36
|
+
/**
|
|
37
|
+
* Update a tool call part with approval response.
|
|
38
|
+
* Searches all messages to find the tool call by approval ID.
|
|
39
|
+
*/
|
|
40
|
+
export declare function updateToolCallApprovalResponse(messages: Array<UIMessage>, approvalId: string, approved: boolean): Array<UIMessage>;
|
|
41
|
+
/**
|
|
42
|
+
* Update or add a thinking part to a message.
|
|
43
|
+
*/
|
|
44
|
+
export declare function updateThinkingPart(messages: Array<UIMessage>, messageId: string, content: string): Array<UIMessage>;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
function updateTextPart(messages, messageId, content) {
|
|
2
|
+
return messages.map((msg) => {
|
|
3
|
+
if (msg.id !== messageId) {
|
|
4
|
+
return msg;
|
|
5
|
+
}
|
|
6
|
+
const parts = [...msg.parts];
|
|
7
|
+
const lastPart = parts.length > 0 ? parts[parts.length - 1] : null;
|
|
8
|
+
if (lastPart && lastPart.type === "text") {
|
|
9
|
+
parts[parts.length - 1] = { type: "text", content };
|
|
10
|
+
} else {
|
|
11
|
+
parts.push({ type: "text", content });
|
|
12
|
+
}
|
|
13
|
+
return { ...msg, parts };
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function updateToolCallPart(messages, messageId, toolCall) {
|
|
17
|
+
return messages.map((msg) => {
|
|
18
|
+
if (msg.id !== messageId) {
|
|
19
|
+
return msg;
|
|
20
|
+
}
|
|
21
|
+
const parts = [...msg.parts];
|
|
22
|
+
const existingPartIndex = parts.findIndex(
|
|
23
|
+
(p) => p.type === "tool-call" && p.id === toolCall.id
|
|
24
|
+
);
|
|
25
|
+
const toolCallPart = {
|
|
26
|
+
type: "tool-call",
|
|
27
|
+
id: toolCall.id,
|
|
28
|
+
name: toolCall.name,
|
|
29
|
+
arguments: toolCall.arguments,
|
|
30
|
+
state: toolCall.state
|
|
31
|
+
};
|
|
32
|
+
if (existingPartIndex >= 0) {
|
|
33
|
+
parts[existingPartIndex] = toolCallPart;
|
|
34
|
+
} else {
|
|
35
|
+
parts.push(toolCallPart);
|
|
36
|
+
}
|
|
37
|
+
return { ...msg, parts };
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function updateToolResultPart(messages, messageId, toolCallId, content, state, error) {
|
|
41
|
+
return messages.map((msg) => {
|
|
42
|
+
if (msg.id !== messageId) {
|
|
43
|
+
return msg;
|
|
44
|
+
}
|
|
45
|
+
const parts = [...msg.parts];
|
|
46
|
+
const resultPartIndex = parts.findIndex(
|
|
47
|
+
(p) => p.type === "tool-result" && p.toolCallId === toolCallId
|
|
48
|
+
);
|
|
49
|
+
const toolResultPart = {
|
|
50
|
+
type: "tool-result",
|
|
51
|
+
toolCallId,
|
|
52
|
+
content,
|
|
53
|
+
state,
|
|
54
|
+
...error && { error }
|
|
55
|
+
};
|
|
56
|
+
if (resultPartIndex >= 0) {
|
|
57
|
+
parts[resultPartIndex] = toolResultPart;
|
|
58
|
+
} else {
|
|
59
|
+
parts.push(toolResultPart);
|
|
60
|
+
}
|
|
61
|
+
return { ...msg, parts };
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function updateToolCallApproval(messages, messageId, toolCallId, approvalId) {
|
|
65
|
+
return messages.map((msg) => {
|
|
66
|
+
if (msg.id !== messageId) {
|
|
67
|
+
return msg;
|
|
68
|
+
}
|
|
69
|
+
const parts = [...msg.parts];
|
|
70
|
+
const toolCallPart = parts.find(
|
|
71
|
+
(p) => p.type === "tool-call" && p.id === toolCallId
|
|
72
|
+
);
|
|
73
|
+
if (toolCallPart) {
|
|
74
|
+
toolCallPart.state = "approval-requested";
|
|
75
|
+
toolCallPart.approval = {
|
|
76
|
+
id: approvalId,
|
|
77
|
+
needsApproval: true
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { ...msg, parts };
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function updateToolCallWithOutput(messages, toolCallId, output, state, errorText) {
|
|
84
|
+
return messages.map((msg) => {
|
|
85
|
+
const parts = [...msg.parts];
|
|
86
|
+
const toolCallPart = parts.find(
|
|
87
|
+
(p) => p.type === "tool-call" && p.id === toolCallId
|
|
88
|
+
);
|
|
89
|
+
if (toolCallPart) {
|
|
90
|
+
toolCallPart.output = errorText ? { error: errorText } : output;
|
|
91
|
+
if (state) {
|
|
92
|
+
toolCallPart.state = state;
|
|
93
|
+
} else {
|
|
94
|
+
toolCallPart.state = "input-complete";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return { ...msg, parts };
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function updateToolCallApprovalResponse(messages, approvalId, approved) {
|
|
101
|
+
return messages.map((msg) => {
|
|
102
|
+
const parts = [...msg.parts];
|
|
103
|
+
const toolCallPart = parts.find(
|
|
104
|
+
(p) => p.type === "tool-call" && p.approval?.id === approvalId
|
|
105
|
+
);
|
|
106
|
+
if (toolCallPart && toolCallPart.approval) {
|
|
107
|
+
toolCallPart.approval.approved = approved;
|
|
108
|
+
toolCallPart.state = "approval-responded";
|
|
109
|
+
}
|
|
110
|
+
return { ...msg, parts };
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function updateThinkingPart(messages, messageId, content) {
|
|
114
|
+
return messages.map((msg) => {
|
|
115
|
+
if (msg.id !== messageId) {
|
|
116
|
+
return msg;
|
|
117
|
+
}
|
|
118
|
+
const parts = [...msg.parts];
|
|
119
|
+
const thinkingPartIndex = parts.findIndex((p) => p.type === "thinking");
|
|
120
|
+
const thinkingPart = {
|
|
121
|
+
type: "thinking",
|
|
122
|
+
content
|
|
123
|
+
};
|
|
124
|
+
if (thinkingPartIndex >= 0) {
|
|
125
|
+
parts[thinkingPartIndex] = thinkingPart;
|
|
126
|
+
} else {
|
|
127
|
+
parts.push(thinkingPart);
|
|
128
|
+
}
|
|
129
|
+
return { ...msg, parts };
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
updateTextPart,
|
|
134
|
+
updateThinkingPart,
|
|
135
|
+
updateToolCallApproval,
|
|
136
|
+
updateToolCallApprovalResponse,
|
|
137
|
+
updateToolCallPart,
|
|
138
|
+
updateToolCallWithOutput,
|
|
139
|
+
updateToolResultPart
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=message-updaters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-updaters.js","sources":["../../../src/stream/message-updaters.ts"],"sourcesContent":["/**\n * Message Updaters (Internal)\n *\n * Internal helper functions for updating UIMessage parts.\n * These are used by StreamProcessor to manage the message array.\n */\n\nimport type {\n ThinkingPart,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n} from '../types'\nimport type { ToolCallState, ToolResultState } from './types'\n\n/**\n * Update or add a text part to a message.\n *\n * If the last part is a text part, update it (continuing the same text segment).\n * Otherwise, create a new text part (starting a new text segment after tool calls).\n */\nexport function updateTextPart(\n messages: Array<UIMessage>,\n messageId: string,\n content: string,\n): Array<UIMessage> {\n return messages.map((msg) => {\n if (msg.id !== messageId) {\n return msg\n }\n\n const parts = [...msg.parts]\n const lastPart = parts.length > 0 ? parts[parts.length - 1] : null\n\n if (lastPart && lastPart.type === 'text') {\n // Update the last text part (continuing same text segment)\n parts[parts.length - 1] = { type: 'text', content }\n } else {\n // Create new text part (starting new text segment after tool calls/results)\n parts.push({ type: 'text', content })\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update or add a tool call part to a message.\n */\nexport function updateToolCallPart(\n messages: Array<UIMessage>,\n messageId: string,\n toolCall: {\n id: string\n name: string\n arguments: string\n state: ToolCallState\n },\n): Array<UIMessage> {\n return messages.map((msg) => {\n if (msg.id !== messageId) {\n return msg\n }\n\n const parts = [...msg.parts]\n // Find by ID, not index!\n const existingPartIndex = parts.findIndex(\n (p): p is ToolCallPart => p.type === 'tool-call' && p.id === toolCall.id,\n )\n\n const toolCallPart: ToolCallPart = {\n type: 'tool-call',\n id: toolCall.id,\n name: toolCall.name,\n arguments: toolCall.arguments,\n state: toolCall.state,\n }\n\n if (existingPartIndex >= 0) {\n // Update existing tool call\n parts[existingPartIndex] = toolCallPart\n } else {\n // Add new tool call at the end (preserve natural streaming order)\n parts.push(toolCallPart)\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update or add a tool result part to a message.\n */\nexport function updateToolResultPart(\n messages: Array<UIMessage>,\n messageId: string,\n toolCallId: string,\n content: string,\n state: ToolResultState,\n error?: string,\n): Array<UIMessage> {\n return messages.map((msg) => {\n if (msg.id !== messageId) {\n return msg\n }\n\n const parts = [...msg.parts]\n const resultPartIndex = parts.findIndex(\n (p): p is ToolResultPart =>\n p.type === 'tool-result' && p.toolCallId === toolCallId,\n )\n\n const toolResultPart: ToolResultPart = {\n type: 'tool-result',\n toolCallId,\n content,\n state,\n ...(error && { error }),\n }\n\n if (resultPartIndex >= 0) {\n parts[resultPartIndex] = toolResultPart\n } else {\n parts.push(toolResultPart)\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update a tool call part with approval request metadata.\n */\nexport function updateToolCallApproval(\n messages: Array<UIMessage>,\n messageId: string,\n toolCallId: string,\n approvalId: string,\n): Array<UIMessage> {\n return messages.map((msg) => {\n if (msg.id !== messageId) {\n return msg\n }\n\n const parts = [...msg.parts]\n const toolCallPart = parts.find(\n (p): p is ToolCallPart => p.type === 'tool-call' && p.id === toolCallId,\n )\n\n if (toolCallPart) {\n toolCallPart.state = 'approval-requested'\n toolCallPart.approval = {\n id: approvalId,\n needsApproval: true,\n }\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update a tool call part's state (e.g., to \"input-complete\").\n */\nexport function updateToolCallState(\n messages: Array<UIMessage>,\n messageId: string,\n toolCallId: string,\n state: ToolCallState,\n): Array<UIMessage> {\n return messages.map((msg) => {\n if (msg.id !== messageId) {\n return msg\n }\n\n const parts = [...msg.parts]\n const toolCallPart = parts.find(\n (p): p is ToolCallPart => p.type === 'tool-call' && p.id === toolCallId,\n )\n\n if (toolCallPart) {\n toolCallPart.state = state\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update a tool call part with output.\n * Searches all messages to find the tool call by ID.\n */\nexport function updateToolCallWithOutput(\n messages: Array<UIMessage>,\n toolCallId: string,\n output: any,\n state?: ToolCallState,\n errorText?: string,\n): Array<UIMessage> {\n return messages.map((msg) => {\n const parts = [...msg.parts]\n const toolCallPart = parts.find(\n (p): p is ToolCallPart => p.type === 'tool-call' && p.id === toolCallId,\n )\n\n if (toolCallPart) {\n toolCallPart.output = errorText ? { error: errorText } : output\n if (state) {\n toolCallPart.state = state\n } else {\n toolCallPart.state = 'input-complete'\n }\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update a tool call part with approval response.\n * Searches all messages to find the tool call by approval ID.\n */\nexport function updateToolCallApprovalResponse(\n messages: Array<UIMessage>,\n approvalId: string,\n approved: boolean,\n): Array<UIMessage> {\n return messages.map((msg) => {\n const parts = [...msg.parts]\n const toolCallPart = parts.find(\n (p): p is ToolCallPart =>\n p.type === 'tool-call' && p.approval?.id === approvalId,\n )\n\n if (toolCallPart && toolCallPart.approval) {\n toolCallPart.approval.approved = approved\n toolCallPart.state = 'approval-responded'\n }\n\n return { ...msg, parts }\n })\n}\n\n/**\n * Update or add a thinking part to a message.\n */\nexport function updateThinkingPart(\n messages: Array<UIMessage>,\n messageId: string,\n content: string,\n): Array<UIMessage> {\n return messages.map((msg) => {\n if (msg.id !== messageId) {\n return msg\n }\n\n const parts = [...msg.parts]\n const thinkingPartIndex = parts.findIndex((p) => p.type === 'thinking')\n\n const thinkingPart: ThinkingPart = {\n type: 'thinking',\n content,\n }\n\n if (thinkingPartIndex >= 0) {\n // Update existing thinking part\n parts[thinkingPartIndex] = thinkingPart\n } else {\n // Add new thinking part at the end (preserve natural streaming order)\n parts.push(thinkingPart)\n }\n\n return { ...msg, parts }\n })\n}\n"],"names":[],"mappings":"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"}
|