@tanstack/ai 0.42.0 → 0.43.0
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/README.md +15 -1
- package/dist/esm/activities/chat/adapter.js +23 -16
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/agent-loop-strategies.d.ts +5 -36
- package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
- package/dist/esm/activities/chat/cancel.d.ts +40 -0
- package/dist/esm/activities/chat/cancel.js +54 -0
- package/dist/esm/activities/chat/cancel.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +28 -21
- package/dist/esm/activities/chat/index.js +2100 -1813
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
- package/dist/esm/activities/chat/mcp/manager.js +90 -77
- package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
- package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
- package/dist/esm/activities/chat/messages.js +397 -346
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/builder.js +17 -15
- package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
- package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
- package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
- package/dist/esm/activities/chat/middleware/compose.js +623 -531
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/middleware/define.js +12 -5
- package/dist/esm/activities/chat/middleware/define.js.map +1 -1
- package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
- package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
- package/dist/esm/activities/chat/middleware/locks.js +71 -0
- package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
- package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
- package/dist/esm/activities/chat/middleware/run-store.js +176 -0
- package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
- package/dist/esm/activities/chat/middleware/validate.js +23 -28
- package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
- package/dist/esm/activities/chat/stream/json-parser.js +39 -25
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
- package/dist/esm/activities/chat/stream/processor.js +1341 -1542
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/stream/strategies.js +69 -53
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
- package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
- package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
- package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
- package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
- package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
- package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
- package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
- package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/error-payload.js +85 -47
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/activities/generateAudio/adapter.js +22 -15
- package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +4 -0
- package/dist/esm/activities/generateAudio/index.js +141 -105
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/adapter.js +22 -15
- package/dist/esm/activities/generateImage/adapter.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +4 -0
- package/dist/esm/activities/generateImage/index.js +155 -111
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/adapter.js +22 -15
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
- package/dist/esm/activities/generateSpeech/index.js +159 -110
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/adapter.js +22 -15
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
- package/dist/esm/activities/generateTranscription/index.js +159 -100
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/adapter.js +36 -29
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +143 -19
- package/dist/esm/activities/generateVideo/index.js +456 -279
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/snap.js +60 -48
- package/dist/esm/activities/generateVideo/snap.js.map +1 -1
- package/dist/esm/activities/index.js +8 -34
- package/dist/esm/activities/middleware/index.d.ts +1 -1
- package/dist/esm/activities/middleware/run.d.ts +10 -0
- package/dist/esm/activities/middleware/run.js +53 -29
- package/dist/esm/activities/middleware/run.js.map +1 -1
- package/dist/esm/activities/middleware/types.d.ts +44 -6
- package/dist/esm/activities/stream-generation-result.d.ts +4 -1
- package/dist/esm/activities/stream-generation-result.js +79 -44
- package/dist/esm/activities/stream-generation-result.js.map +1 -1
- package/dist/esm/activities/summarize/adapter.js +22 -15
- package/dist/esm/activities/summarize/adapter.js.map +1 -1
- package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
- package/dist/esm/activities/summarize/index.d.ts +27 -0
- package/dist/esm/activities/summarize/index.js +268 -102
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +2 -1
- package/dist/esm/adapter-internals.js +4 -11
- package/dist/esm/client.d.ts +25 -3
- package/dist/esm/client.js +131 -64
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/custom-events.d.ts +76 -0
- package/dist/esm/custom-events.js +37 -0
- package/dist/esm/custom-events.js.map +1 -0
- package/dist/esm/delivery-detach.d.ts +50 -0
- package/dist/esm/delivery-detach.js +71 -0
- package/dist/esm/delivery-detach.js.map +1 -0
- package/dist/esm/delivery-disconnect.d.ts +62 -0
- package/dist/esm/delivery-disconnect.js +81 -0
- package/dist/esm/delivery-disconnect.js.map +1 -0
- package/dist/esm/extend-adapter.js +19 -17
- package/dist/esm/extend-adapter.js.map +1 -1
- package/dist/esm/index.d.ts +24 -6
- package/dist/esm/index.js +30 -98
- package/dist/esm/interrupt-resume.d.ts +71 -0
- package/dist/esm/interrupt-resume.js +438 -0
- package/dist/esm/interrupt-resume.js.map +1 -0
- package/dist/esm/interrupt-serialization.d.ts +12 -0
- package/dist/esm/interrupt-serialization.js +178 -0
- package/dist/esm/interrupt-serialization.js.map +1 -0
- package/dist/esm/interrupts.d.ts +84 -0
- package/dist/esm/interrupts.js +31 -0
- package/dist/esm/interrupts.js.map +1 -0
- package/dist/esm/locks.d.ts +10 -0
- package/dist/esm/locks.js +2 -0
- package/dist/esm/logger/console-logger.js +101 -78
- package/dist/esm/logger/console-logger.js.map +1 -1
- package/dist/esm/logger/internal-logger.js +104 -89
- package/dist/esm/logger/internal-logger.js.map +1 -1
- package/dist/esm/logger/resolve.js +54 -49
- package/dist/esm/logger/resolve.js.map +1 -1
- package/dist/esm/logger/types.d.ts +1 -1
- package/dist/esm/middlewares/content-guard.js +142 -148
- package/dist/esm/middlewares/content-guard.js.map +1 -1
- package/dist/esm/middlewares/index.js +2 -6
- package/dist/esm/middlewares/otel.js +598 -732
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/middlewares/usage-attributes.js +47 -40
- package/dist/esm/middlewares/usage-attributes.js.map +1 -1
- package/dist/esm/realtime/event-emitter.js +24 -25
- package/dist/esm/realtime/event-emitter.js.map +1 -1
- package/dist/esm/realtime/index.d.ts +5 -9
- package/dist/esm/realtime/index.js +29 -6
- package/dist/esm/realtime/index.js.map +1 -1
- package/dist/esm/scope.d.ts +47 -0
- package/dist/esm/stream-durability.d.ts +171 -0
- package/dist/esm/stream-durability.js +295 -0
- package/dist/esm/stream-durability.js.map +1 -0
- package/dist/esm/stream-to-response.d.ts +178 -13
- package/dist/esm/stream-to-response.js +663 -115
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.js +30 -16
- package/dist/esm/strip-to-spec-middleware.js.map +1 -1
- package/dist/esm/system-prompts.js +27 -21
- package/dist/esm/system-prompts.js.map +1 -1
- package/dist/esm/tool-registry.js +72 -45
- package/dist/esm/tool-registry.js.map +1 -1
- package/dist/esm/tools/provider-tool.js +14 -5
- package/dist/esm/tools/provider-tool.js.map +1 -1
- package/dist/esm/types.d.ts +321 -42
- package/dist/esm/types.js +2 -0
- package/dist/esm/utilities/ag-ui-wire.js +79 -93
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +26 -4
- package/dist/esm/utilities/chat-params.js +218 -92
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/errors.js +28 -18
- package/dist/esm/utilities/errors.js.map +1 -1
- package/dist/esm/utilities/media-prompt.js +46 -41
- package/dist/esm/utilities/media-prompt.js.map +1 -1
- package/dist/esm/utilities/numbers.js +13 -10
- package/dist/esm/utilities/numbers.js.map +1 -1
- package/dist/esm/utilities/provider-executed.js +20 -11
- package/dist/esm/utilities/provider-executed.js.map +1 -1
- package/dist/esm/utilities/sampling-keys.js +31 -19
- package/dist/esm/utilities/sampling-keys.js.map +1 -1
- package/dist/esm/utilities/tool-result.js +42 -30
- package/dist/esm/utilities/tool-result.js.map +1 -1
- package/dist/esm/utilities/usage.js +27 -9
- package/dist/esm/utilities/usage.js.map +1 -1
- package/dist/esm/utils.js +26 -18
- package/dist/esm/utils.js.map +1 -1
- package/package.json +10 -6
- package/skills/ai-core/SKILL.md +69 -18
- package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
- package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
- package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
- package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
- package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
- package/skills/ai-core/chat-experience/SKILL.md +98 -11
- package/skills/ai-core/client-persistence/SKILL.md +277 -0
- package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
- package/skills/ai-core/debug-logging/SKILL.md +1 -1
- package/skills/ai-core/locks/SKILL.md +143 -0
- package/skills/ai-core/media-generation/SKILL.md +144 -12
- package/skills/ai-core/middleware/SKILL.md +258 -33
- package/skills/ai-core/structured-outputs/SKILL.md +1 -1
- package/skills/ai-core/tool-calling/SKILL.md +54 -61
- package/src/activities/chat/agent-loop-strategies.ts +5 -39
- package/src/activities/chat/cancel.ts +81 -0
- package/src/activities/chat/index.ts +1091 -200
- package/src/activities/chat/mcp/manager.ts +4 -4
- package/src/activities/chat/mcp/types.ts +2 -2
- package/src/activities/chat/messages.ts +5 -3
- package/src/activities/chat/middleware/builder.ts +1 -1
- package/src/activities/chat/middleware/compose.ts +186 -9
- package/src/activities/chat/middleware/index.ts +26 -0
- package/src/activities/chat/middleware/locks.ts +102 -0
- package/src/activities/chat/middleware/pending-turn.ts +47 -0
- package/src/activities/chat/middleware/run-disconnect.ts +62 -0
- package/src/activities/chat/middleware/run-store.ts +412 -0
- package/src/activities/chat/middleware/types.ts +62 -1
- package/src/activities/chat/stream/processor.ts +189 -5
- package/src/activities/chat/tools/approval-schema.ts +205 -0
- package/src/activities/chat/tools/tool-calls.ts +106 -13
- package/src/activities/chat/tools/tool-definition.ts +210 -39
- package/src/activities/generateAudio/index.ts +20 -3
- package/src/activities/generateImage/index.ts +20 -3
- package/src/activities/generateSpeech/index.ts +25 -3
- package/src/activities/generateTranscription/index.ts +26 -3
- package/src/activities/generateVideo/index.ts +345 -82
- package/src/activities/middleware/index.ts +2 -0
- package/src/activities/middleware/run.ts +31 -0
- package/src/activities/middleware/types.ts +49 -5
- package/src/activities/stream-generation-result.ts +30 -2
- package/src/activities/summarize/chat-stream-summarize.ts +5 -0
- package/src/activities/summarize/index.ts +200 -10
- package/src/adapter-internals.ts +10 -1
- package/src/client.ts +244 -0
- package/src/custom-events.ts +107 -0
- package/src/delivery-detach.ts +72 -0
- package/src/delivery-disconnect.ts +84 -0
- package/src/index.ts +138 -1
- package/src/interrupt-resume.ts +824 -0
- package/src/interrupt-serialization.ts +183 -0
- package/src/interrupts.ts +146 -0
- package/src/locks.ts +17 -0
- package/src/logger/types.ts +1 -1
- package/src/middlewares/otel.ts +1 -0
- package/src/realtime/index.ts +5 -9
- package/src/scope.ts +47 -0
- package/src/stream-durability.ts +598 -0
- package/src/stream-to-response.ts +1051 -95
- package/src/strip-to-spec-middleware.ts +3 -3
- package/src/types.ts +405 -45
- package/src/utilities/chat-params.ts +245 -55
- package/dist/esm/activities/index.js.map +0 -1
- package/dist/esm/adapter-internals.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/middlewares/index.js.map +0 -1
|
@@ -1,107 +1,93 @@
|
|
|
1
|
+
//#region src/utilities/ag-ui-wire.ts
|
|
2
|
+
/**
|
|
3
|
+
* Serialize TanStack `UIMessage`s into the AG-UI `RunAgentInput.messages`
|
|
4
|
+
* wire shape. Each anchor (system/user/assistant) carries the canonical
|
|
5
|
+
* `parts` array verbatim plus AG-UI mirror fields (`content`, `toolCalls`)
|
|
6
|
+
* so AG-UI Zod parsing succeeds. Tool results and thinking parts on
|
|
7
|
+
* assistant messages are additionally emitted as fan-out
|
|
8
|
+
* `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict
|
|
9
|
+
* AG-UI server consumers.
|
|
10
|
+
*/
|
|
1
11
|
function uiMessagesToWire(messages) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
wire.push({
|
|
41
|
-
role: "tool",
|
|
42
|
-
id: deriveToolMessageId(part.toolCallId),
|
|
43
|
-
toolCallId: part.toolCallId,
|
|
44
|
-
content: typeof part.content === "string" ? part.content : JSON.stringify(part.content),
|
|
45
|
-
...part.error !== void 0 && { error: part.error }
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return wire;
|
|
12
|
+
const wire = [];
|
|
13
|
+
for (const msg of messages) {
|
|
14
|
+
const parts = msg.parts ?? [];
|
|
15
|
+
if (msg.role === "system") {
|
|
16
|
+
wire.push({
|
|
17
|
+
...msg,
|
|
18
|
+
content: parts.length > 0 ? collectText(parts) : msg.content ?? ""
|
|
19
|
+
});
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (msg.role === "user") {
|
|
23
|
+
wire.push({
|
|
24
|
+
...msg,
|
|
25
|
+
content: parts.length > 0 ? collectUserContent(parts) : msg.content ?? ""
|
|
26
|
+
});
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
for (const part of parts) if (part.type === "thinking") wire.push({
|
|
30
|
+
role: "reasoning",
|
|
31
|
+
id: deriveReasoningId(msg.id, part),
|
|
32
|
+
content: part.content
|
|
33
|
+
});
|
|
34
|
+
const text = collectText(parts);
|
|
35
|
+
const toolCalls = collectToolCalls(parts);
|
|
36
|
+
wire.push({
|
|
37
|
+
...msg,
|
|
38
|
+
...text !== "" && { content: text },
|
|
39
|
+
...toolCalls && { toolCalls }
|
|
40
|
+
});
|
|
41
|
+
for (const part of parts) if (part.type === "tool-result") wire.push({
|
|
42
|
+
role: "tool",
|
|
43
|
+
id: deriveToolMessageId(part.toolCallId),
|
|
44
|
+
toolCallId: part.toolCallId,
|
|
45
|
+
content: typeof part.content === "string" ? part.content : JSON.stringify(part.content),
|
|
46
|
+
...part.error !== void 0 && { error: part.error }
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return wire;
|
|
51
50
|
}
|
|
52
51
|
function collectText(parts) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} else if (p.type === "structured-output" && p.status === "complete" && p.raw !== "") {
|
|
58
|
-
out.push(p.raw);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return out.join("");
|
|
52
|
+
const out = [];
|
|
53
|
+
for (const p of parts) if (p.type === "text") out.push(p.content);
|
|
54
|
+
else if (p.type === "structured-output" && p.status === "complete" && p.raw !== "") out.push(p.raw);
|
|
55
|
+
return out.join("");
|
|
62
56
|
}
|
|
63
57
|
function collectUserContent(parts) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (p.type === "text") {
|
|
73
|
-
out.push({ type: "text", text: p.content });
|
|
74
|
-
} else if (p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document") {
|
|
75
|
-
out.push(p);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return out;
|
|
58
|
+
if (!parts.some((p) => p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document")) return collectText(parts);
|
|
59
|
+
const out = [];
|
|
60
|
+
for (const p of parts) if (p.type === "text") out.push({
|
|
61
|
+
type: "text",
|
|
62
|
+
text: p.content
|
|
63
|
+
});
|
|
64
|
+
else if (p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document") out.push(p);
|
|
65
|
+
return out;
|
|
79
66
|
}
|
|
80
67
|
function collectToolCalls(parts) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
return calls.length > 0 ? calls : void 0;
|
|
68
|
+
const calls = [];
|
|
69
|
+
for (const p of parts) if (p.type === "tool-call") calls.push({
|
|
70
|
+
id: p.id,
|
|
71
|
+
type: "function",
|
|
72
|
+
function: {
|
|
73
|
+
name: p.name,
|
|
74
|
+
arguments: p.arguments
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return calls.length > 0 ? calls : void 0;
|
|
92
78
|
}
|
|
93
79
|
function deriveReasoningId(messageId, part) {
|
|
94
|
-
|
|
80
|
+
return `${messageId}-reasoning-${part.id ?? hashContent(part.content)}`;
|
|
95
81
|
}
|
|
96
82
|
function deriveToolMessageId(toolCallId) {
|
|
97
|
-
|
|
83
|
+
return `tool-${toolCallId}`;
|
|
98
84
|
}
|
|
99
85
|
function hashContent(s) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
let h = 0;
|
|
87
|
+
for (let i = 0; i < s.length; i++) h = h * 31 + s.charCodeAt(i) | 0;
|
|
88
|
+
return Math.abs(h).toString(36);
|
|
103
89
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
//# sourceMappingURL=ag-ui-wire.js.map
|
|
90
|
+
//#endregion
|
|
91
|
+
export { uiMessagesToWire };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=ag-ui-wire.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ag-ui-wire.js","sources":["../../../src/utilities/ag-ui-wire.ts"],"sourcesContent":["import type { ContentPart, MessagePart, UIMessage } from '../types'\n\ntype AGUITextInputContent = { type: 'text'; text: string }\ntype AGUIInputContent =\n | AGUITextInputContent\n | (ContentPart & { type: 'image' | 'audio' | 'video' | 'document' })\n\ntype AGUIToolCallMirror = {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\ntype AGUIToolMessage = {\n role: 'tool'\n id: string\n toolCallId: string\n content: string\n error?: string\n}\n\ntype AGUIReasoningMessage = {\n role: 'reasoning'\n id: string\n content: string\n}\n\ntype WireAnchorMessage = UIMessage & {\n content?: string | Array<AGUIInputContent>\n toolCalls?: Array<AGUIToolCallMirror>\n}\n\nexport type WireMessage =\n | WireAnchorMessage\n | AGUIToolMessage\n | AGUIReasoningMessage\n\n/**\n * Serialize TanStack `UIMessage`s into the AG-UI `RunAgentInput.messages`\n * wire shape. Each anchor (system/user/assistant) carries the canonical\n * `parts` array verbatim plus AG-UI mirror fields (`content`, `toolCalls`)\n * so AG-UI Zod parsing succeeds. Tool results and thinking parts on\n * assistant messages are additionally emitted as fan-out\n * `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict\n * AG-UI server consumers.\n */\nexport function uiMessagesToWire(\n messages: Array<UIMessage>,\n): Array<WireMessage> {\n const wire: Array<WireMessage> = []\n\n for (const msg of messages) {\n // Defensive: if parts is missing (ModelMessage-shaped input), pass through as-is.\n // UIMessage always has parts; ModelMessage uses content directly.\n const parts: ReadonlyArray<MessagePart> =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- runtime input may be ModelMessage-shaped (no `parts`); cast forces the optional-chain fallback below to remain in scope\n (msg.parts as ReadonlyArray<MessagePart> | undefined) ?? []\n\n if (msg.role === 'system') {\n wire.push({\n ...msg,\n content:\n parts.length > 0\n ? collectText(parts)\n : ((msg as { content?: string }).content ?? ''),\n })\n continue\n }\n\n if (msg.role === 'user') {\n wire.push({\n ...msg,\n content:\n parts.length > 0\n ? collectUserContent(parts)\n : ((msg as { content?: string }).content ?? ''),\n })\n continue\n }\n\n // assistant: emit reasoning fan-outs first, then anchor, then tool fan-outs\n for (const part of parts) {\n if (part.type === 'thinking') {\n wire.push({\n role: 'reasoning',\n id: deriveReasoningId(msg.id, part),\n content: part.content,\n })\n }\n }\n\n const text = collectText(parts)\n const toolCalls = collectToolCalls(parts)\n wire.push({\n ...msg,\n ...(text !== '' && { content: text }),\n ...(toolCalls && { toolCalls }),\n })\n\n for (const part of parts) {\n if (part.type === 'tool-result') {\n wire.push({\n role: 'tool',\n id: deriveToolMessageId(part.toolCallId),\n toolCallId: part.toolCallId,\n content:\n typeof part.content === 'string'\n ? part.content\n : JSON.stringify(part.content),\n ...(part.error !== undefined && { error: part.error }),\n })\n }\n }\n }\n\n return wire\n}\n\nfunction collectText(parts: ReadonlyArray<MessagePart>): string {\n // The streamed JSON of a completed structured-output part is the source of\n // truth for multi-turn coherence — emitting it back as assistant content\n // lets the LLM see its own prior structured response. Streaming/errored\n // parts are skipped: they'd ship malformed JSON fragments and confuse the\n // model. `completeStructuredOutputPart` tries hard to populate `raw`\n // (caller → existing buffer → `JSON.stringify(data)`), but the stringify\n // fallback can leave it empty when `data` is unserializable (BigInt,\n // circular). The `p.raw !== ''` guard below is what enforces \"no malformed\n // round-trip\" in that case — without it we'd ship `''` and the model would\n // see an empty assistant turn.\n const out: Array<string> = []\n for (const p of parts) {\n if (p.type === 'text') {\n out.push(p.content)\n } else if (\n p.type === 'structured-output' &&\n p.status === 'complete' &&\n p.raw !== ''\n ) {\n out.push(p.raw)\n }\n }\n return out.join('')\n}\n\nfunction collectUserContent(\n parts: ReadonlyArray<MessagePart>,\n): string | Array<AGUIInputContent> {\n const hasMultimodal = parts.some(\n (p) =>\n p.type === 'image' ||\n p.type === 'audio' ||\n p.type === 'video' ||\n p.type === 'document',\n )\n if (!hasMultimodal) {\n return collectText(parts)\n }\n const out: Array<AGUIInputContent> = []\n for (const p of parts) {\n if (p.type === 'text') {\n out.push({ type: 'text', text: p.content })\n } else if (\n p.type === 'image' ||\n p.type === 'audio' ||\n p.type === 'video' ||\n p.type === 'document'\n ) {\n out.push(p)\n }\n }\n return out\n}\n\nfunction collectToolCalls(\n parts: ReadonlyArray<MessagePart>,\n): Array<AGUIToolCallMirror> | undefined {\n const calls: Array<AGUIToolCallMirror> = []\n for (const p of parts) {\n if (p.type === 'tool-call') {\n calls.push({\n id: p.id,\n type: 'function',\n function: { name: p.name, arguments: p.arguments },\n })\n }\n }\n return calls.length > 0 ? calls : undefined\n}\n\nfunction deriveReasoningId(messageId: string, part: MessagePart): string {\n return `${messageId}-reasoning-${(part as { id?: string }).id ?? hashContent((part as { content: string }).content)}`\n}\n\nfunction deriveToolMessageId(toolCallId: string): string {\n return `tool-${toolCallId}`\n}\n\nfunction hashContent(s: string): string {\n // Cheap deterministic id suffix; collisions are tolerable since\n // reasoning ids only matter for AG-UI server consumers, not for our\n // own server's dedup logic (which keys on toolCallId, not reasoning id).\n let h = 0\n for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0\n return Math.abs(h).toString(36)\n}\n"],"
|
|
1
|
+
{"version":3,"file":"ag-ui-wire.js","names":[],"sources":["../../../src/utilities/ag-ui-wire.ts"],"sourcesContent":["import type { ContentPart, MessagePart, UIMessage } from '../types'\n\ntype AGUITextInputContent = { type: 'text'; text: string }\ntype AGUIInputContent =\n | AGUITextInputContent\n | (ContentPart & { type: 'image' | 'audio' | 'video' | 'document' })\n\ntype AGUIToolCallMirror = {\n id: string\n type: 'function'\n function: { name: string; arguments: string }\n}\n\ntype AGUIToolMessage = {\n role: 'tool'\n id: string\n toolCallId: string\n content: string\n error?: string\n}\n\ntype AGUIReasoningMessage = {\n role: 'reasoning'\n id: string\n content: string\n}\n\ntype WireAnchorMessage = UIMessage & {\n content?: string | Array<AGUIInputContent>\n toolCalls?: Array<AGUIToolCallMirror>\n}\n\nexport type WireMessage =\n | WireAnchorMessage\n | AGUIToolMessage\n | AGUIReasoningMessage\n\n/**\n * Serialize TanStack `UIMessage`s into the AG-UI `RunAgentInput.messages`\n * wire shape. Each anchor (system/user/assistant) carries the canonical\n * `parts` array verbatim plus AG-UI mirror fields (`content`, `toolCalls`)\n * so AG-UI Zod parsing succeeds. Tool results and thinking parts on\n * assistant messages are additionally emitted as fan-out\n * `{role:'tool',...}` and `{role:'reasoning',...}` entries for strict\n * AG-UI server consumers.\n */\nexport function uiMessagesToWire(\n messages: Array<UIMessage>,\n): Array<WireMessage> {\n const wire: Array<WireMessage> = []\n\n for (const msg of messages) {\n // Defensive: if parts is missing (ModelMessage-shaped input), pass through as-is.\n // UIMessage always has parts; ModelMessage uses content directly.\n const parts: ReadonlyArray<MessagePart> =\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- runtime input may be ModelMessage-shaped (no `parts`); cast forces the optional-chain fallback below to remain in scope\n (msg.parts as ReadonlyArray<MessagePart> | undefined) ?? []\n\n if (msg.role === 'system') {\n wire.push({\n ...msg,\n content:\n parts.length > 0\n ? collectText(parts)\n : ((msg as { content?: string }).content ?? ''),\n })\n continue\n }\n\n if (msg.role === 'user') {\n wire.push({\n ...msg,\n content:\n parts.length > 0\n ? collectUserContent(parts)\n : ((msg as { content?: string }).content ?? ''),\n })\n continue\n }\n\n // assistant: emit reasoning fan-outs first, then anchor, then tool fan-outs\n for (const part of parts) {\n if (part.type === 'thinking') {\n wire.push({\n role: 'reasoning',\n id: deriveReasoningId(msg.id, part),\n content: part.content,\n })\n }\n }\n\n const text = collectText(parts)\n const toolCalls = collectToolCalls(parts)\n wire.push({\n ...msg,\n ...(text !== '' && { content: text }),\n ...(toolCalls && { toolCalls }),\n })\n\n for (const part of parts) {\n if (part.type === 'tool-result') {\n wire.push({\n role: 'tool',\n id: deriveToolMessageId(part.toolCallId),\n toolCallId: part.toolCallId,\n content:\n typeof part.content === 'string'\n ? part.content\n : JSON.stringify(part.content),\n ...(part.error !== undefined && { error: part.error }),\n })\n }\n }\n }\n\n return wire\n}\n\nfunction collectText(parts: ReadonlyArray<MessagePart>): string {\n // The streamed JSON of a completed structured-output part is the source of\n // truth for multi-turn coherence — emitting it back as assistant content\n // lets the LLM see its own prior structured response. Streaming/errored\n // parts are skipped: they'd ship malformed JSON fragments and confuse the\n // model. `completeStructuredOutputPart` tries hard to populate `raw`\n // (caller → existing buffer → `JSON.stringify(data)`), but the stringify\n // fallback can leave it empty when `data` is unserializable (BigInt,\n // circular). The `p.raw !== ''` guard below is what enforces \"no malformed\n // round-trip\" in that case — without it we'd ship `''` and the model would\n // see an empty assistant turn.\n const out: Array<string> = []\n for (const p of parts) {\n if (p.type === 'text') {\n out.push(p.content)\n } else if (\n p.type === 'structured-output' &&\n p.status === 'complete' &&\n p.raw !== ''\n ) {\n out.push(p.raw)\n }\n }\n return out.join('')\n}\n\nfunction collectUserContent(\n parts: ReadonlyArray<MessagePart>,\n): string | Array<AGUIInputContent> {\n const hasMultimodal = parts.some(\n (p) =>\n p.type === 'image' ||\n p.type === 'audio' ||\n p.type === 'video' ||\n p.type === 'document',\n )\n if (!hasMultimodal) {\n return collectText(parts)\n }\n const out: Array<AGUIInputContent> = []\n for (const p of parts) {\n if (p.type === 'text') {\n out.push({ type: 'text', text: p.content })\n } else if (\n p.type === 'image' ||\n p.type === 'audio' ||\n p.type === 'video' ||\n p.type === 'document'\n ) {\n out.push(p)\n }\n }\n return out\n}\n\nfunction collectToolCalls(\n parts: ReadonlyArray<MessagePart>,\n): Array<AGUIToolCallMirror> | undefined {\n const calls: Array<AGUIToolCallMirror> = []\n for (const p of parts) {\n if (p.type === 'tool-call') {\n calls.push({\n id: p.id,\n type: 'function',\n function: { name: p.name, arguments: p.arguments },\n })\n }\n }\n return calls.length > 0 ? calls : undefined\n}\n\nfunction deriveReasoningId(messageId: string, part: MessagePart): string {\n return `${messageId}-reasoning-${(part as { id?: string }).id ?? hashContent((part as { content: string }).content)}`\n}\n\nfunction deriveToolMessageId(toolCallId: string): string {\n return `tool-${toolCallId}`\n}\n\nfunction hashContent(s: string): string {\n // Cheap deterministic id suffix; collisions are tolerable since\n // reasoning ids only matter for AG-UI server consumers, not for our\n // own server's dedup logic (which keys on toolCallId, not reasoning id).\n let h = 0\n for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0\n return Math.abs(h).toString(36)\n}\n"],"mappings":";;;;;;;;;;AA8CA,SAAgB,iBACd,UACoB;CACpB,MAAM,OAA2B,CAAC;CAElC,KAAK,MAAM,OAAO,UAAU;EAG1B,MAAM,QAEH,IAAI,SAAoD,CAAC;EAE5D,IAAI,IAAI,SAAS,UAAU;GACzB,KAAK,KAAK;IACR,GAAG;IACH,SACE,MAAM,SAAS,IACX,YAAY,KAAK,IACf,IAA6B,WAAW;GAClD,CAAC;GACD;EACF;EAEA,IAAI,IAAI,SAAS,QAAQ;GACvB,KAAK,KAAK;IACR,GAAG;IACH,SACE,MAAM,SAAS,IACX,mBAAmB,KAAK,IACtB,IAA6B,WAAW;GAClD,CAAC;GACD;EACF;EAGA,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,YAChB,KAAK,KAAK;GACR,MAAM;GACN,IAAI,kBAAkB,IAAI,IAAI,IAAI;GAClC,SAAS,KAAK;EAChB,CAAC;EAIL,MAAM,OAAO,YAAY,KAAK;EAC9B,MAAM,YAAY,iBAAiB,KAAK;EACxC,KAAK,KAAK;GACR,GAAG;GACH,GAAI,SAAS,MAAM,EAAE,SAAS,KAAK;GACnC,GAAI,aAAa,EAAE,UAAU;EAC/B,CAAC;EAED,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,eAChB,KAAK,KAAK;GACR,MAAM;GACN,IAAI,oBAAoB,KAAK,UAAU;GACvC,YAAY,KAAK;GACjB,SACE,OAAO,KAAK,YAAY,WACpB,KAAK,UACL,KAAK,UAAU,KAAK,OAAO;GACjC,GAAI,KAAK,UAAU,KAAA,KAAa,EAAE,OAAO,KAAK,MAAM;EACtD,CAAC;CAGP;CAEA,OAAO;AACT;AAEA,SAAS,YAAY,OAA2C;CAW9D,MAAM,MAAqB,CAAC;CAC5B,KAAK,MAAM,KAAK,OACd,IAAI,EAAE,SAAS,QACb,IAAI,KAAK,EAAE,OAAO;MACb,IACL,EAAE,SAAS,uBACX,EAAE,WAAW,cACb,EAAE,QAAQ,IAEV,IAAI,KAAK,EAAE,GAAG;CAGlB,OAAO,IAAI,KAAK,EAAE;AACpB;AAEA,SAAS,mBACP,OACkC;CAQlC,IAAI,CAPkB,MAAM,MACzB,MACC,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,UAEV,GACH,OAAO,YAAY,KAAK;CAE1B,MAAM,MAA+B,CAAC;CACtC,KAAK,MAAM,KAAK,OACd,IAAI,EAAE,SAAS,QACb,IAAI,KAAK;EAAE,MAAM;EAAQ,MAAM,EAAE;CAAQ,CAAC;MACrC,IACL,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,WACX,EAAE,SAAS,YAEX,IAAI,KAAK,CAAC;CAGd,OAAO;AACT;AAEA,SAAS,iBACP,OACuC;CACvC,MAAM,QAAmC,CAAC;CAC1C,KAAK,MAAM,KAAK,OACd,IAAI,EAAE,SAAS,aACb,MAAM,KAAK;EACT,IAAI,EAAE;EACN,MAAM;EACN,UAAU;GAAE,MAAM,EAAE;GAAM,WAAW,EAAE;EAAU;CACnD,CAAC;CAGL,OAAO,MAAM,SAAS,IAAI,QAAQ,KAAA;AACpC;AAEA,SAAS,kBAAkB,WAAmB,MAA2B;CACvE,OAAO,GAAG,UAAU,aAAc,KAAyB,MAAM,YAAa,KAA6B,OAAO;AACpH;AAEA,SAAS,oBAAoB,YAA4B;CACvD,OAAO,QAAQ;AACjB;AAEA,SAAS,YAAY,GAAmB;CAItC,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK,IAAK,IAAI,KAAK,EAAE,WAAW,CAAC,IAAK;CACpE,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE;AAChC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Context as AGUIContext } from '@ag-ui/core';
|
|
2
|
-
import { JSONSchema, ModelMessage,
|
|
2
|
+
import { AnyTool, JSONSchema, ModelMessage, RunAgentResumeItem, UIMessage } from '../types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Parse and validate an HTTP request body as an AG-UI `RunAgentInput`.
|
|
5
5
|
*
|
|
@@ -8,8 +8,11 @@ import { JSONSchema, ModelMessage, SchemaInput, Tool, UIMessage } from '../types
|
|
|
8
8
|
* `convertMessagesToModelMessages` handles AG-UI fan-out dedup and
|
|
9
9
|
* reasoning/activity/developer-role normalization internally.
|
|
10
10
|
*
|
|
11
|
+
* Validated structurally against the AG-UI `RunAgentInput` contract without a
|
|
12
|
+
* schema library, so this package pulls in no validation runtime of its own.
|
|
13
|
+
*
|
|
11
14
|
* @throws An error with a migration-pointing message when the body does
|
|
12
|
-
* not conform to AG-UI
|
|
15
|
+
* not conform to AG-UI `RunAgentInput`. Surface this as a
|
|
13
16
|
* 400 Bad Request to the client.
|
|
14
17
|
*/
|
|
15
18
|
export declare function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
@@ -24,6 +27,7 @@ export declare function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
24
27
|
}>;
|
|
25
28
|
forwardedProps: Record<string, unknown>;
|
|
26
29
|
state: unknown;
|
|
30
|
+
resume?: Array<RunAgentResumeItem>;
|
|
27
31
|
/**
|
|
28
32
|
* @deprecated Use `aguiContext` instead. This alias will be removed in a
|
|
29
33
|
* future release.
|
|
@@ -57,6 +61,17 @@ export declare function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
57
61
|
* @throws {Response} 400 on malformed JSON or invalid AG-UI shape.
|
|
58
62
|
*/
|
|
59
63
|
export declare function chatParamsFromRequest(req: Request): Promise<Awaited<ReturnType<typeof chatParamsFromRequestBody>>>;
|
|
64
|
+
/**
|
|
65
|
+
* Client-declared tool stub (no execute). `name` is `string`, so arrays that
|
|
66
|
+
* include these stubs intentionally widen `TypedStreamChunk` tool-name
|
|
67
|
+
* discrimination — pass server tools alone when you need a closed name union.
|
|
68
|
+
*/
|
|
69
|
+
export type ClientToolDeclaration = {
|
|
70
|
+
name: string;
|
|
71
|
+
description: string;
|
|
72
|
+
inputSchema: JSONSchema;
|
|
73
|
+
};
|
|
74
|
+
export type MergedAgentTools<TServerTools extends ReadonlyArray<AnyTool>> = ReadonlyArray<TServerTools[number] | ClientToolDeclaration>;
|
|
60
75
|
/**
|
|
61
76
|
* Merge a server-side tool array with the AG-UI client-declared tools
|
|
62
77
|
* received in the request body.
|
|
@@ -72,14 +87,21 @@ export declare function chatParamsFromRequest(req: Request): Promise<Awaited<Ret
|
|
|
72
87
|
* them — server emits a tool-call request, client executes via its
|
|
73
88
|
* registered handler, client posts back the result.
|
|
74
89
|
*
|
|
90
|
+
* Typing:
|
|
91
|
+
* - Empty `clientTools` preserves the server tuple (closed name union).
|
|
92
|
+
* - Non-empty `clientTools` returns a widened array that honestly includes
|
|
93
|
+
* client stubs, so `TypedStreamChunk` does not claim a closed server-only
|
|
94
|
+
* name union.
|
|
95
|
+
*
|
|
75
96
|
* @param serverTools - The server's tool array (e.g. from
|
|
76
97
|
* `[myToolDef.server(...)]`). Pass directly to `chat({ tools })`.
|
|
77
98
|
* @param clientTools - The `tools` array received from
|
|
78
99
|
* `chatParamsFromRequest(...)` / `chatParamsFromRequestBody(...)`.
|
|
79
100
|
* @returns A merged array suitable for `chat({ tools })`.
|
|
80
101
|
*/
|
|
81
|
-
export declare function mergeAgentTools<
|
|
102
|
+
export declare function mergeAgentTools<const TServerTools extends ReadonlyArray<AnyTool>>(serverTools: TServerTools, clientTools: readonly []): TServerTools;
|
|
103
|
+
export declare function mergeAgentTools<const TServerTools extends ReadonlyArray<AnyTool>>(serverTools: TServerTools, clientTools: ReadonlyArray<{
|
|
82
104
|
name: string;
|
|
83
105
|
description: string;
|
|
84
106
|
parameters: JSONSchema;
|
|
85
|
-
}>):
|
|
107
|
+
}>): MergedAgentTools<TServerTools>;
|
|
@@ -1,100 +1,226 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { AGUIError } from "@ag-ui/core";
|
|
2
|
+
//#region src/utilities/chat-params.ts
|
|
3
|
+
var KNOWN_PART_TYPES = /* @__PURE__ */ new Set([
|
|
4
|
+
"text",
|
|
5
|
+
"image",
|
|
6
|
+
"audio",
|
|
7
|
+
"video",
|
|
8
|
+
"document",
|
|
9
|
+
"tool-call",
|
|
10
|
+
"tool-result",
|
|
11
|
+
"thinking"
|
|
11
12
|
]);
|
|
12
13
|
function isValidParts(value) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
if (!Array.isArray(value)) return false;
|
|
15
|
+
for (const p of value) {
|
|
16
|
+
if (!p || typeof p !== "object") return false;
|
|
17
|
+
const type = p.type;
|
|
18
|
+
if (typeof type !== "string" || !KNOWN_PART_TYPES.has(type)) return false;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Keyed by `AGUIRole` so a role added upstream fails to compile here until it
|
|
24
|
+
* is handled, rather than silently falling through as an unknown role.
|
|
25
|
+
*/
|
|
26
|
+
var AGUI_ROLES = {
|
|
27
|
+
developer: true,
|
|
28
|
+
system: true,
|
|
29
|
+
assistant: true,
|
|
30
|
+
user: true,
|
|
31
|
+
tool: true,
|
|
32
|
+
activity: true,
|
|
33
|
+
reasoning: true
|
|
34
|
+
};
|
|
35
|
+
function isAGUIRole(value) {
|
|
36
|
+
return typeof value === "string" && value in AGUI_ROLES;
|
|
37
|
+
}
|
|
38
|
+
function isRecord(value) {
|
|
39
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reject the request body, pointing at the migration guide. Mirrors the
|
|
43
|
+
* message the previous `RunAgentInputSchema.safeParse` failure produced.
|
|
44
|
+
*/
|
|
45
|
+
function invalidBody(reason) {
|
|
46
|
+
throw new AGUIError(`Request body is not a valid AG-UI RunAgentInput. If you're upgrading from a previous @tanstack/ai-client release, see docs/migration/ag-ui-compliance.md. Validation errors: ${reason}`);
|
|
47
|
+
}
|
|
48
|
+
function requireString(value, at) {
|
|
49
|
+
if (typeof value !== "string") invalidBody(`${at} must be a string`);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
function requireArray(value, at) {
|
|
53
|
+
if (!Array.isArray(value)) invalidBody(`${at} must be an array`);
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Assert one AG-UI `Message`, discriminating on `role` exactly as the upstream
|
|
58
|
+
* `MessageSchema` discriminated union does. The record view is retained on the
|
|
59
|
+
* asserted type so callers can still inspect non-AG-UI extras like `parts`.
|
|
60
|
+
*/
|
|
61
|
+
function assertAGUIMessage(value, at) {
|
|
62
|
+
requireString(value.id, `${at}.id`);
|
|
63
|
+
const role = value.role;
|
|
64
|
+
if (!isAGUIRole(role)) invalidBody(`${at}.role must be one of ${Object.keys(AGUI_ROLES).join(" | ")}`);
|
|
65
|
+
switch (role) {
|
|
66
|
+
case "assistant":
|
|
67
|
+
if (value.content !== void 0) requireString(value.content, `${at}.content`);
|
|
68
|
+
if (value.toolCalls !== void 0) requireArray(value.toolCalls, `${at}.toolCalls`);
|
|
69
|
+
break;
|
|
70
|
+
case "user":
|
|
71
|
+
if (typeof value.content !== "string" && !Array.isArray(value.content)) invalidBody(`${at}.content must be a string or an array of content parts`);
|
|
72
|
+
break;
|
|
73
|
+
case "tool":
|
|
74
|
+
requireString(value.content, `${at}.content`);
|
|
75
|
+
requireString(value.toolCallId, `${at}.toolCallId`);
|
|
76
|
+
break;
|
|
77
|
+
case "activity":
|
|
78
|
+
requireString(value.activityType, `${at}.activityType`);
|
|
79
|
+
if (!isRecord(value.content)) invalidBody(`${at}.content must be an object`);
|
|
80
|
+
break;
|
|
81
|
+
case "developer":
|
|
82
|
+
case "system":
|
|
83
|
+
case "reasoning":
|
|
84
|
+
requireString(value.content, `${at}.content`);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
51
87
|
}
|
|
88
|
+
function validateMessage(value, index) {
|
|
89
|
+
const at = `messages[${index}]`;
|
|
90
|
+
if (!isRecord(value)) invalidBody(`${at} must be an object`);
|
|
91
|
+
assertAGUIMessage(value, at);
|
|
92
|
+
if ("parts" in value && !isValidParts(value.parts)) {
|
|
93
|
+
const withoutParts = { ...value };
|
|
94
|
+
Reflect.deleteProperty(withoutParts, "parts");
|
|
95
|
+
return withoutParts;
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
function validateTool(value, index) {
|
|
100
|
+
const at = `tools[${index}]`;
|
|
101
|
+
if (!isRecord(value)) invalidBody(`${at} must be an object`);
|
|
102
|
+
return {
|
|
103
|
+
name: requireString(value.name, `${at}.name`),
|
|
104
|
+
description: requireString(value.description, `${at}.description`),
|
|
105
|
+
parameters: value.parameters
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function validateContext(value, index) {
|
|
109
|
+
const at = `context[${index}]`;
|
|
110
|
+
if (!isRecord(value)) invalidBody(`${at} must be an object`);
|
|
111
|
+
return {
|
|
112
|
+
description: requireString(value.description, `${at}.description`),
|
|
113
|
+
value: requireString(value.value, `${at}.value`)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function validateResumeEntry(value, index) {
|
|
117
|
+
const at = `resume[${index}]`;
|
|
118
|
+
if (!isRecord(value)) invalidBody(`${at} must be an object`);
|
|
119
|
+
const status = value.status;
|
|
120
|
+
if (status !== "resolved" && status !== "cancelled") invalidBody(`${at}.status must be "resolved" or "cancelled"`);
|
|
121
|
+
const entry = {
|
|
122
|
+
interruptId: requireString(value.interruptId, `${at}.interruptId`),
|
|
123
|
+
status
|
|
124
|
+
};
|
|
125
|
+
if (value.payload !== void 0) entry.payload = value.payload;
|
|
126
|
+
return entry;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parse and validate an HTTP request body as an AG-UI `RunAgentInput`.
|
|
130
|
+
*
|
|
131
|
+
* Returns a spread-friendly object whose `messages` field is suitable for
|
|
132
|
+
* passing directly to `chat({ messages })`. The existing
|
|
133
|
+
* `convertMessagesToModelMessages` handles AG-UI fan-out dedup and
|
|
134
|
+
* reasoning/activity/developer-role normalization internally.
|
|
135
|
+
*
|
|
136
|
+
* Validated structurally against the AG-UI `RunAgentInput` contract without a
|
|
137
|
+
* schema library, so this package pulls in no validation runtime of its own.
|
|
138
|
+
*
|
|
139
|
+
* @throws An error with a migration-pointing message when the body does
|
|
140
|
+
* not conform to AG-UI `RunAgentInput`. Surface this as a
|
|
141
|
+
* 400 Bad Request to the client.
|
|
142
|
+
*/
|
|
143
|
+
async function chatParamsFromRequestBody(body) {
|
|
144
|
+
if (!isRecord(body)) invalidBody("body must be a JSON object");
|
|
145
|
+
const threadId = requireString(body.threadId, "threadId");
|
|
146
|
+
const runId = requireString(body.runId, "runId");
|
|
147
|
+
const parentRunId = body.parentRunId === void 0 ? void 0 : requireString(body.parentRunId, "parentRunId");
|
|
148
|
+
const messages = requireArray(body.messages, "messages").map(validateMessage);
|
|
149
|
+
const tools = requireArray(body.tools, "tools").map(validateTool);
|
|
150
|
+
const aguiContext = requireArray(body.context, "context").map(validateContext);
|
|
151
|
+
const resume = body.resume === void 0 ? void 0 : requireArray(body.resume, "resume").map(validateResumeEntry);
|
|
152
|
+
if (body.forwardedProps !== void 0 && !isRecord(body.forwardedProps)) invalidBody("forwardedProps must be an object");
|
|
153
|
+
return {
|
|
154
|
+
messages,
|
|
155
|
+
threadId,
|
|
156
|
+
runId,
|
|
157
|
+
parentRunId,
|
|
158
|
+
tools,
|
|
159
|
+
forwardedProps: body.forwardedProps ?? {},
|
|
160
|
+
state: body.state,
|
|
161
|
+
resume,
|
|
162
|
+
context: aguiContext,
|
|
163
|
+
aguiContext
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Read an HTTP `Request`, parse its JSON body, and validate it as an
|
|
168
|
+
* AG-UI `RunAgentInput` — collapsing the standard `req.json()` +
|
|
169
|
+
* `chatParamsFromRequestBody(...)` pair into a single call.
|
|
170
|
+
*
|
|
171
|
+
* On a malformed body or invalid AG-UI shape, this **throws a
|
|
172
|
+
* `Response`** with status 400 and a migration-pointing message in the
|
|
173
|
+
* body. Frameworks that natively handle thrown `Response` objects
|
|
174
|
+
* (TanStack Start, SolidStart, Remix, React Router 7) will return the
|
|
175
|
+
* 400 to the client automatically, so the handler reduces to:
|
|
176
|
+
*
|
|
177
|
+
* ```ts
|
|
178
|
+
* export async function POST(req: Request) {
|
|
179
|
+
* const params = await chatParamsFromRequest(req)
|
|
180
|
+
* // ...use params
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* In frameworks that do not auto-handle thrown `Response` objects
|
|
185
|
+
* (Next.js Route Handlers, SvelteKit, Hono, raw Node), wrap the call
|
|
186
|
+
* with try/catch and return the caught Response yourself, or use
|
|
187
|
+
* `chatParamsFromRequestBody` directly with your own JSON-parsing.
|
|
188
|
+
*
|
|
189
|
+
* @throws {Response} 400 on malformed JSON or invalid AG-UI shape.
|
|
190
|
+
*/
|
|
52
191
|
async function chatParamsFromRequest(req) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"Invalid AG-UI request body. See docs/migration/ag-ui-compliance.md.",
|
|
69
|
-
{ status: 400 }
|
|
70
|
-
);
|
|
71
|
-
res.cause = cause;
|
|
72
|
-
throw res;
|
|
73
|
-
}
|
|
192
|
+
let body;
|
|
193
|
+
try {
|
|
194
|
+
body = await req.json();
|
|
195
|
+
} catch (cause) {
|
|
196
|
+
const res = new Response("Invalid AG-UI request body. See docs/migration/ag-ui-compliance.md.", { status: 400 });
|
|
197
|
+
res.cause = cause;
|
|
198
|
+
throw res;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
return await chatParamsFromRequestBody(body);
|
|
202
|
+
} catch (cause) {
|
|
203
|
+
const res = new Response("Invalid AG-UI request body. See docs/migration/ag-ui-compliance.md.", { status: 400 });
|
|
204
|
+
res.cause = cause;
|
|
205
|
+
throw res;
|
|
206
|
+
}
|
|
74
207
|
}
|
|
75
208
|
function mergeAgentTools(serverTools, clientTools) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// No `execute` — runtime treats this as a client-side tool and
|
|
90
|
-
// emits ClientToolRequest events.
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return merged;
|
|
209
|
+
if (clientTools.length === 0) return serverTools;
|
|
210
|
+
const seen = new Set(serverTools.map((t) => t.name));
|
|
211
|
+
const merged = [...serverTools];
|
|
212
|
+
for (const ct of clientTools) {
|
|
213
|
+
if (seen.has(ct.name)) continue;
|
|
214
|
+
seen.add(ct.name);
|
|
215
|
+
merged.push({
|
|
216
|
+
name: ct.name,
|
|
217
|
+
description: ct.description,
|
|
218
|
+
inputSchema: ct.parameters
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return merged;
|
|
94
222
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
};
|
|
100
|
-
//# sourceMappingURL=chat-params.js.map
|
|
223
|
+
//#endregion
|
|
224
|
+
export { chatParamsFromRequest, chatParamsFromRequestBody, mergeAgentTools };
|
|
225
|
+
|
|
226
|
+
//# sourceMappingURL=chat-params.js.map
|