@anvia/client 1.0.0-rc.6 → 1.0.0-rc.9
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 +4 -0
- package/dist/index.d.ts +28 -19
- package/dist/index.js +125 -46
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -38,6 +38,10 @@ subpath; importing Client does not load the Agent runtime or its infrastructure
|
|
|
38
38
|
- `parseUIMessage` and `parseUIMessages` validate externally loaded UI state.
|
|
39
39
|
|
|
40
40
|
Tool-call start, delta, and end events are automatic when the provider exposes streamed arguments.
|
|
41
|
+
`UIToolMessagePart` states are exact: `input-streaming` carries raw partial text,
|
|
42
|
+
`input-available` carries parsed JSON input, and terminal `output-available` or `error` parts retain
|
|
43
|
+
that input with their result. `uiMessagesToMessages()` rejects partial calls instead of replaying
|
|
44
|
+
incomplete JSON or inventing empty arguments.
|
|
41
45
|
Errors are masked by default. Use `mapError` only at the server adapter boundary when an application
|
|
42
46
|
intentionally exposes a safe error shape. Non-JSON outputs require an explicit `mapOutput`; returning
|
|
43
47
|
`undefined` intentionally omits the output, while returning `null` exposes JSON `null`.
|
package/dist/index.d.ts
CHANGED
|
@@ -72,6 +72,32 @@ type UIDataPart<Data extends ClientDataMap> = {
|
|
|
72
72
|
data: Data[Name];
|
|
73
73
|
};
|
|
74
74
|
}[keyof Data & string];
|
|
75
|
+
type UIToolMessagePartBase = {
|
|
76
|
+
id: string;
|
|
77
|
+
type: "tool";
|
|
78
|
+
toolName: string;
|
|
79
|
+
toolCallId: string;
|
|
80
|
+
callId?: string;
|
|
81
|
+
internalCallId?: string;
|
|
82
|
+
turn?: number;
|
|
83
|
+
signature?: string;
|
|
84
|
+
};
|
|
85
|
+
type UIToolMessagePart = (UIToolMessagePartBase & {
|
|
86
|
+
state: "input-streaming";
|
|
87
|
+
input: string;
|
|
88
|
+
}) | (UIToolMessagePartBase & {
|
|
89
|
+
state: "input-available";
|
|
90
|
+
input: JsonValue;
|
|
91
|
+
}) | (UIToolMessagePartBase & {
|
|
92
|
+
state: "output-available";
|
|
93
|
+
input: JsonValue;
|
|
94
|
+
output: JsonValue;
|
|
95
|
+
resultContent?: readonly ToolResultContentPart[];
|
|
96
|
+
}) | (UIToolMessagePartBase & {
|
|
97
|
+
state: "error";
|
|
98
|
+
input: JsonValue;
|
|
99
|
+
error: UIError;
|
|
100
|
+
});
|
|
75
101
|
type UIMessagePart<Data extends ClientDataMap = ClientDataMap> = {
|
|
76
102
|
id: string;
|
|
77
103
|
type: "text";
|
|
@@ -83,21 +109,7 @@ type UIMessagePart<Data extends ClientDataMap = ClientDataMap> = {
|
|
|
83
109
|
text: string;
|
|
84
110
|
reasoningId?: string;
|
|
85
111
|
content?: readonly ReasoningDetail[];
|
|
86
|
-
} | {
|
|
87
|
-
id: string;
|
|
88
|
-
type: "tool";
|
|
89
|
-
toolName: string;
|
|
90
|
-
toolCallId: string;
|
|
91
|
-
callId?: string;
|
|
92
|
-
internalCallId?: string;
|
|
93
|
-
turn?: number;
|
|
94
|
-
state: "input-streaming" | "input-available" | "output-available" | "error";
|
|
95
|
-
input?: JsonValue;
|
|
96
|
-
output?: JsonValue;
|
|
97
|
-
resultContent?: readonly ToolResultContentPart[];
|
|
98
|
-
signature?: string;
|
|
99
|
-
error?: UIError;
|
|
100
|
-
} | {
|
|
112
|
+
} | UIToolMessagePart | {
|
|
101
113
|
id: string;
|
|
102
114
|
type: "source";
|
|
103
115
|
source: CompletionSource;
|
|
@@ -110,9 +122,6 @@ type UIMessagePart<Data extends ClientDataMap = ClientDataMap> = {
|
|
|
110
122
|
type: "error";
|
|
111
123
|
error: UIError;
|
|
112
124
|
};
|
|
113
|
-
type UIToolMessagePart = Extract<UIMessagePart, {
|
|
114
|
-
type: "tool";
|
|
115
|
-
}>;
|
|
116
125
|
type ClientStreamCursor = {
|
|
117
126
|
streamId: string;
|
|
118
127
|
after: number;
|
|
@@ -243,7 +252,7 @@ type ClientStandardStreamEvent<Metadata extends JsonObject, Data extends ClientD
|
|
|
243
252
|
callId?: string;
|
|
244
253
|
internalCallId?: string;
|
|
245
254
|
toolName: string;
|
|
246
|
-
input
|
|
255
|
+
input: JsonValue;
|
|
247
256
|
result: {
|
|
248
257
|
status: "success";
|
|
249
258
|
output: JsonValue;
|
package/dist/index.js
CHANGED
|
@@ -59,11 +59,12 @@ function uiMessagesToMessages(messages) {
|
|
|
59
59
|
if (part.content !== void 0) reasoning = { ...reasoning, details: part.content };
|
|
60
60
|
content2.push(reasoning);
|
|
61
61
|
} else if (part.type === "tool") {
|
|
62
|
+
assertReplayableToolPart(part);
|
|
62
63
|
let toolCall = {
|
|
63
64
|
type: "tool-call",
|
|
64
65
|
toolCallId: part.toolCallId,
|
|
65
66
|
toolName: part.toolName,
|
|
66
|
-
input: part.input
|
|
67
|
+
input: part.input
|
|
67
68
|
};
|
|
68
69
|
if (part.callId !== void 0) toolCall = { ...toolCall, callId: part.callId };
|
|
69
70
|
if (part.signature !== void 0) toolCall = { ...toolCall, signature: part.signature };
|
|
@@ -90,9 +91,12 @@ function uiMessagesToMessages(messages) {
|
|
|
90
91
|
continue;
|
|
91
92
|
}
|
|
92
93
|
assertOnlyParts(message, ["tool", "data", "error"]);
|
|
93
|
-
const content =
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
const content = [];
|
|
95
|
+
for (const part of message.parts) {
|
|
96
|
+
if (part.type !== "tool") continue;
|
|
97
|
+
assertToolResultPart(part);
|
|
98
|
+
content.push(toolResultFromPart(part));
|
|
99
|
+
}
|
|
96
100
|
result.push({ role: "tool", content, ...metadataField(message.metadata) });
|
|
97
101
|
}
|
|
98
102
|
return result;
|
|
@@ -147,7 +151,13 @@ function messagesToUIMessages(messages) {
|
|
|
147
151
|
for (const content of message.content) {
|
|
148
152
|
if (content.type !== "tool-result") continue;
|
|
149
153
|
const location = (content.callId === void 0 ? void 0 : byCallId.get(content.callId)) ?? byToolCallId.get(content.toolCallId);
|
|
150
|
-
const
|
|
154
|
+
const ownerPart = toolPartAt(result, location);
|
|
155
|
+
if (ownerPart === void 0 || ownerPart.state === "input-streaming") {
|
|
156
|
+
throw new TypeError(
|
|
157
|
+
`Tool result "${content.toolCallId}" requires a matching completed tool call.`
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
const part = toolResultToUIMessagePart(content, ownerPart.toolName, ownerPart.input);
|
|
151
161
|
if (message.metadata === void 0 && location !== void 0) {
|
|
152
162
|
const owner = result[location.messageIndex];
|
|
153
163
|
const existing = owner?.parts[location.partIndex];
|
|
@@ -233,12 +243,12 @@ function toolResultFromPart(part) {
|
|
|
233
243
|
}
|
|
234
244
|
function toolOutputFromPart(part) {
|
|
235
245
|
if (part.state === "error") {
|
|
236
|
-
return { type: "error-text", value: part.error
|
|
246
|
+
return { type: "error-text", value: part.error.message };
|
|
237
247
|
}
|
|
238
248
|
if (part.resultContent !== void 0) {
|
|
239
249
|
return { type: "content", value: part.resultContent };
|
|
240
250
|
}
|
|
241
|
-
const output = part.output
|
|
251
|
+
const output = part.output;
|
|
242
252
|
return typeof output === "string" ? { type: "text", value: output } : { type: "json", value: output };
|
|
243
253
|
}
|
|
244
254
|
function attachmentToUserContent(attachment) {
|
|
@@ -293,13 +303,14 @@ function contentToAttachment(content) {
|
|
|
293
303
|
else attachment.text = content.data.text;
|
|
294
304
|
return attachment;
|
|
295
305
|
}
|
|
296
|
-
function toolResultToUIMessagePart(content, fallbackToolName) {
|
|
306
|
+
function toolResultToUIMessagePart(content, fallbackToolName, input) {
|
|
297
307
|
const output = content.output;
|
|
298
308
|
const common = {
|
|
299
309
|
id: toolPartId(content.toolCallId),
|
|
300
310
|
type: "tool",
|
|
301
|
-
toolName: content.toolName || fallbackToolName
|
|
302
|
-
toolCallId: content.toolCallId
|
|
311
|
+
toolName: content.toolName || fallbackToolName,
|
|
312
|
+
toolCallId: content.toolCallId,
|
|
313
|
+
input
|
|
303
314
|
};
|
|
304
315
|
if (content.callId !== void 0) Object.assign(common, { callId: content.callId });
|
|
305
316
|
if (output.type === "error-text" || output.type === "error-json") {
|
|
@@ -334,10 +345,28 @@ function toolResultOutput(output) {
|
|
|
334
345
|
(part) => part.type === "text" ? { ...part } : { ...part, data: { ...part.data } }
|
|
335
346
|
);
|
|
336
347
|
}
|
|
337
|
-
function
|
|
348
|
+
function toolPartAt(messages, location) {
|
|
338
349
|
if (location === void 0) return void 0;
|
|
339
350
|
const part = messages[location.messageIndex]?.parts[location.partIndex];
|
|
340
|
-
return part?.type === "tool" ? part
|
|
351
|
+
return part?.type === "tool" ? part : void 0;
|
|
352
|
+
}
|
|
353
|
+
function assertReplayableToolPart(part) {
|
|
354
|
+
if (part.state === "input-streaming") {
|
|
355
|
+
throw new TypeError(
|
|
356
|
+
`Tool call "${part.toolCallId}" is still streaming and cannot be converted to a model message.`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
if (!isJsonValue(part.input)) {
|
|
360
|
+
throw new TypeError(`Tool call "${part.toolCallId}" input must be a strict JSON value.`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function assertToolResultPart(part) {
|
|
364
|
+
assertReplayableToolPart(part);
|
|
365
|
+
if (part.state === "input-available") {
|
|
366
|
+
throw new TypeError(
|
|
367
|
+
`Tool message part "${part.toolCallId}" requires an output or execution error.`
|
|
368
|
+
);
|
|
369
|
+
}
|
|
341
370
|
}
|
|
342
371
|
function textFromParts(parts) {
|
|
343
372
|
return parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
@@ -612,6 +641,7 @@ function parseClientStreamEvent(value, options = {}) {
|
|
|
612
641
|
]);
|
|
613
642
|
requireStrings(event, ["messageId", "partId", "toolCallId", "toolName"], value);
|
|
614
643
|
requireOptionalStrings(event, ["callId", "internalCallId"], value);
|
|
644
|
+
if (!isJsonValue2(event.input)) invalid("tool_result.input", value);
|
|
615
645
|
if (!isRecord(event.result)) invalid("tool_result.result", value);
|
|
616
646
|
if (event.result.status === "success") {
|
|
617
647
|
if (!hasOnlyKeys(event.result, ["status", "output", "content"]) || !isJsonValue2(event.result.output) || event.result.content !== void 0 && (!Array.isArray(event.result.content) || !event.result.content.every(isToolResultContent))) {
|
|
@@ -930,7 +960,7 @@ function isUIMessagePart(value) {
|
|
|
930
960
|
if (value.type === "error") {
|
|
931
961
|
return hasOnlyKeys(value, ["id", "type", "error"]) && isClientStreamError(value.error);
|
|
932
962
|
}
|
|
933
|
-
|
|
963
|
+
if (value.type !== "tool" || !hasOnlyKeys(value, [
|
|
934
964
|
"id",
|
|
935
965
|
"type",
|
|
936
966
|
"toolName",
|
|
@@ -944,9 +974,19 @@ function isUIMessagePart(value) {
|
|
|
944
974
|
"resultContent",
|
|
945
975
|
"signature",
|
|
946
976
|
"error"
|
|
947
|
-
])
|
|
948
|
-
|
|
949
|
-
|
|
977
|
+
]) || typeof value.toolName !== "string" || typeof value.toolCallId !== "string" || value.callId !== void 0 && typeof value.callId !== "string" || value.internalCallId !== void 0 && typeof value.internalCallId !== "string" || value.turn !== void 0 && !isPositiveEventId(value.turn) || value.signature !== void 0 && typeof value.signature !== "string") {
|
|
978
|
+
return false;
|
|
979
|
+
}
|
|
980
|
+
if (value.state === "input-streaming") {
|
|
981
|
+
return typeof value.input === "string" && value.output === void 0 && value.resultContent === void 0 && value.error === void 0;
|
|
982
|
+
}
|
|
983
|
+
if (value.state === "input-available") {
|
|
984
|
+
return isJsonValue2(value.input) && value.output === void 0 && value.resultContent === void 0 && value.error === void 0;
|
|
985
|
+
}
|
|
986
|
+
if (value.state === "output-available") {
|
|
987
|
+
return isJsonValue2(value.input) && isJsonValue2(value.output) && (value.resultContent === void 0 || Array.isArray(value.resultContent) && value.resultContent.every(isToolResultContent)) && value.error === void 0;
|
|
988
|
+
}
|
|
989
|
+
return value.state === "error" && isJsonValue2(value.input) && value.output === void 0 && value.resultContent === void 0 && isClientStreamError(value.error);
|
|
950
990
|
}
|
|
951
991
|
function isReasoningContent(value) {
|
|
952
992
|
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
@@ -1759,25 +1799,43 @@ function contentToUIMessageParts(content, state) {
|
|
|
1759
1799
|
}
|
|
1760
1800
|
if (contentPart.type === "tool-call") {
|
|
1761
1801
|
const tool = getToolState(state, contentPart.toolCallId, contentPart.toolName);
|
|
1762
|
-
const
|
|
1802
|
+
const partBase = {
|
|
1763
1803
|
id: tool.partId,
|
|
1764
1804
|
type: "tool",
|
|
1765
1805
|
toolName: contentPart.toolName,
|
|
1766
|
-
toolCallId: contentPart.toolCallId
|
|
1767
|
-
state: tool.result?.status === "error" ? "error" : tool.result ? "output-available" : "input-available",
|
|
1768
|
-
input: contentPart.input
|
|
1806
|
+
toolCallId: contentPart.toolCallId
|
|
1769
1807
|
};
|
|
1770
|
-
if (contentPart.callId !== void 0)
|
|
1771
|
-
if (tool.internalCallId !== void 0)
|
|
1772
|
-
|
|
1773
|
-
|
|
1808
|
+
if (contentPart.callId !== void 0) Object.assign(partBase, { callId: contentPart.callId });
|
|
1809
|
+
if (tool.internalCallId !== void 0) {
|
|
1810
|
+
Object.assign(partBase, { internalCallId: tool.internalCallId });
|
|
1811
|
+
}
|
|
1812
|
+
if (state.turn !== void 0) Object.assign(partBase, { turn: state.turn });
|
|
1813
|
+
if (contentPart.signature !== void 0) {
|
|
1814
|
+
Object.assign(partBase, { signature: contentPart.signature });
|
|
1815
|
+
}
|
|
1774
1816
|
if (tool.result?.status === "success") {
|
|
1775
|
-
part
|
|
1817
|
+
const part = {
|
|
1818
|
+
...partBase,
|
|
1819
|
+
state: "output-available",
|
|
1820
|
+
input: contentPart.input,
|
|
1821
|
+
output: tool.result.output
|
|
1822
|
+
};
|
|
1776
1823
|
if (tool.result.content !== void 0) part.resultContent = tool.result.content;
|
|
1777
|
-
|
|
1778
|
-
part.error = tool.result.error;
|
|
1824
|
+
return part;
|
|
1779
1825
|
}
|
|
1780
|
-
|
|
1826
|
+
if (tool.result?.status === "error") {
|
|
1827
|
+
return {
|
|
1828
|
+
...partBase,
|
|
1829
|
+
state: "error",
|
|
1830
|
+
input: contentPart.input,
|
|
1831
|
+
error: tool.result.error
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1834
|
+
return {
|
|
1835
|
+
...partBase,
|
|
1836
|
+
state: "input-available",
|
|
1837
|
+
input: contentPart.input
|
|
1838
|
+
};
|
|
1781
1839
|
}
|
|
1782
1840
|
const attachment = contentAttachment(contentPart);
|
|
1783
1841
|
return {
|
|
@@ -2193,21 +2251,22 @@ function applyClientStreamEvent(messages, event) {
|
|
|
2193
2251
|
}
|
|
2194
2252
|
case "tool_call_delta":
|
|
2195
2253
|
return updatePart(messages, event.messageId, event.partId, (current) => {
|
|
2196
|
-
const part = current?.type === "tool" ?
|
|
2254
|
+
const part = current?.type === "tool" ? toolPartBase(current) : {
|
|
2197
2255
|
id: event.partId,
|
|
2198
2256
|
type: "tool",
|
|
2199
2257
|
toolName: event.toolName ?? "",
|
|
2200
|
-
toolCallId: event.toolCallId
|
|
2201
|
-
state: "input-streaming"
|
|
2258
|
+
toolCallId: event.toolCallId
|
|
2202
2259
|
};
|
|
2203
|
-
const previous = typeof
|
|
2204
|
-
part.input = event.mode === "replace" ? event.delta : `${previous}${event.delta}`;
|
|
2205
|
-
part.state = "input-streaming";
|
|
2260
|
+
const previous = current?.type === "tool" && typeof current.input === "string" ? current.input : "";
|
|
2206
2261
|
if (event.toolName !== void 0) part.toolName = event.toolName;
|
|
2207
2262
|
if (event.callId !== void 0) part.callId = event.callId;
|
|
2208
2263
|
if (event.signature !== void 0) part.signature = event.signature;
|
|
2209
2264
|
if (event.turn !== void 0) part.turn = event.turn;
|
|
2210
|
-
return
|
|
2265
|
+
return {
|
|
2266
|
+
...part,
|
|
2267
|
+
state: "input-streaming",
|
|
2268
|
+
input: event.mode === "replace" ? event.delta : `${previous}${event.delta}`
|
|
2269
|
+
};
|
|
2211
2270
|
});
|
|
2212
2271
|
case "tool_call_end": {
|
|
2213
2272
|
const part = {
|
|
@@ -2225,26 +2284,31 @@ function applyClientStreamEvent(messages, event) {
|
|
|
2225
2284
|
}
|
|
2226
2285
|
case "tool_result":
|
|
2227
2286
|
return updatePart(messages, event.messageId, event.partId, (current) => {
|
|
2228
|
-
const part = current?.type === "tool" ?
|
|
2287
|
+
const part = current?.type === "tool" ? toolPartBase(current) : {
|
|
2229
2288
|
id: event.partId,
|
|
2230
2289
|
type: "tool",
|
|
2231
2290
|
toolName: event.toolName,
|
|
2232
|
-
toolCallId: event.toolCallId
|
|
2233
|
-
state: "input-available"
|
|
2291
|
+
toolCallId: event.toolCallId
|
|
2234
2292
|
};
|
|
2235
2293
|
if (event.callId !== void 0) part.callId = event.callId;
|
|
2236
2294
|
if (event.internalCallId !== void 0) part.internalCallId = event.internalCallId;
|
|
2237
|
-
if (event.input !== void 0) part.input = event.input;
|
|
2238
2295
|
if (event.turn !== void 0) part.turn = event.turn;
|
|
2239
2296
|
if (event.result.status === "error") {
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2297
|
+
return {
|
|
2298
|
+
...part,
|
|
2299
|
+
state: "error",
|
|
2300
|
+
input: event.input,
|
|
2301
|
+
error: event.result.error
|
|
2302
|
+
};
|
|
2246
2303
|
}
|
|
2247
|
-
|
|
2304
|
+
const completed = {
|
|
2305
|
+
...part,
|
|
2306
|
+
state: "output-available",
|
|
2307
|
+
input: event.input,
|
|
2308
|
+
output: event.result.output
|
|
2309
|
+
};
|
|
2310
|
+
if (event.result.content !== void 0) completed.resultContent = event.result.content;
|
|
2311
|
+
return completed;
|
|
2248
2312
|
});
|
|
2249
2313
|
case "source":
|
|
2250
2314
|
return upsertPart(messages, event.messageId, {
|
|
@@ -2314,6 +2378,21 @@ function applyClientStreamEvent(messages, event) {
|
|
|
2314
2378
|
return messages;
|
|
2315
2379
|
}
|
|
2316
2380
|
}
|
|
2381
|
+
function toolPartBase(part) {
|
|
2382
|
+
const base = {
|
|
2383
|
+
id: part.id,
|
|
2384
|
+
type: part.type,
|
|
2385
|
+
toolName: part.toolName,
|
|
2386
|
+
toolCallId: part.toolCallId
|
|
2387
|
+
};
|
|
2388
|
+
if (part.callId !== void 0) Object.assign(base, { callId: part.callId });
|
|
2389
|
+
if (part.internalCallId !== void 0) {
|
|
2390
|
+
Object.assign(base, { internalCallId: part.internalCallId });
|
|
2391
|
+
}
|
|
2392
|
+
if (part.turn !== void 0) Object.assign(base, { turn: part.turn });
|
|
2393
|
+
if (part.signature !== void 0) Object.assign(base, { signature: part.signature });
|
|
2394
|
+
return base;
|
|
2395
|
+
}
|
|
2317
2396
|
function reconcileFinalParts(current, final) {
|
|
2318
2397
|
const clientOnly = current.filter(
|
|
2319
2398
|
(part) => part.type === "source" || part.type === "data" || part.type === "error"
|