@assistant-ui/react 0.11.24 → 0.11.25
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/dist/legacy-runtime/hooks/AttachmentContext.d.ts +48 -48
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.d.ts.map +1 -1
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js +58 -56
- package/dist/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.js.map +1 -1
- package/dist/types/MessagePartTypes.d.ts +2 -0
- package/dist/types/MessagePartTypes.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts +66 -58
- package/src/types/MessagePartTypes.ts +2 -0
@@ -278,8 +278,8 @@ export declare const useEditComposerAttachment: {
|
|
278
278
|
file?: File;
|
279
279
|
content?: import("../..").ThreadUserMessagePart[];
|
280
280
|
} & {
|
281
|
-
status: import("../../types/AttachmentTypes").
|
282
|
-
|
281
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
282
|
+
content: import("../..").ThreadUserMessagePart[];
|
283
283
|
} & {
|
284
284
|
readonly source: "edit-composer";
|
285
285
|
} & {
|
@@ -292,8 +292,8 @@ export declare const useEditComposerAttachment: {
|
|
292
292
|
file?: File;
|
293
293
|
content?: import("../..").ThreadUserMessagePart[];
|
294
294
|
} & {
|
295
|
-
status: import("../../types/AttachmentTypes").
|
296
|
-
|
295
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
296
|
+
file: File;
|
297
297
|
} & {
|
298
298
|
readonly source: "edit-composer";
|
299
299
|
} & {
|
@@ -307,8 +307,8 @@ export declare const useEditComposerAttachment: {
|
|
307
307
|
file?: File;
|
308
308
|
content?: import("../..").ThreadUserMessagePart[];
|
309
309
|
} & {
|
310
|
-
status: import("../../types/AttachmentTypes").
|
311
|
-
|
310
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
311
|
+
content: import("../..").ThreadUserMessagePart[];
|
312
312
|
} & {
|
313
313
|
readonly source: "edit-composer";
|
314
314
|
} & {
|
@@ -321,8 +321,8 @@ export declare const useEditComposerAttachment: {
|
|
321
321
|
file?: File;
|
322
322
|
content?: import("../..").ThreadUserMessagePart[];
|
323
323
|
} & {
|
324
|
-
status: import("../../types/AttachmentTypes").
|
325
|
-
|
324
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
325
|
+
file: File;
|
326
326
|
} & {
|
327
327
|
readonly source: "edit-composer";
|
328
328
|
} & {
|
@@ -336,8 +336,8 @@ export declare const useEditComposerAttachment: {
|
|
336
336
|
file?: File;
|
337
337
|
content?: import("../..").ThreadUserMessagePart[];
|
338
338
|
} & {
|
339
|
-
status: import("../../types/AttachmentTypes").
|
340
|
-
|
339
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
340
|
+
content: import("../..").ThreadUserMessagePart[];
|
341
341
|
} & {
|
342
342
|
readonly source: "edit-composer";
|
343
343
|
} & {
|
@@ -350,8 +350,8 @@ export declare const useEditComposerAttachment: {
|
|
350
350
|
file?: File;
|
351
351
|
content?: import("../..").ThreadUserMessagePart[];
|
352
352
|
} & {
|
353
|
-
status: import("../../types/AttachmentTypes").
|
354
|
-
|
353
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
354
|
+
file: File;
|
355
355
|
} & {
|
356
356
|
readonly source: "edit-composer";
|
357
357
|
} & {
|
@@ -364,8 +364,8 @@ export declare const useEditComposerAttachment: {
|
|
364
364
|
file?: File;
|
365
365
|
content?: import("../..").ThreadUserMessagePart[];
|
366
366
|
} & {
|
367
|
-
status: import("../../types/AttachmentTypes").
|
368
|
-
|
367
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
368
|
+
content: import("../..").ThreadUserMessagePart[];
|
369
369
|
} & {
|
370
370
|
readonly source: "edit-composer";
|
371
371
|
} & {
|
@@ -378,8 +378,8 @@ export declare const useEditComposerAttachment: {
|
|
378
378
|
file?: File;
|
379
379
|
content?: import("../..").ThreadUserMessagePart[];
|
380
380
|
} & {
|
381
|
-
status: import("../../types/AttachmentTypes").
|
382
|
-
|
381
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
382
|
+
file: File;
|
383
383
|
} & {
|
384
384
|
readonly source: "edit-composer";
|
385
385
|
} & {
|
@@ -395,8 +395,8 @@ export declare const useEditComposerAttachment: {
|
|
395
395
|
file?: File;
|
396
396
|
content?: import("../..").ThreadUserMessagePart[];
|
397
397
|
} & {
|
398
|
-
status: import("../../types/AttachmentTypes").
|
399
|
-
|
398
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
399
|
+
content: import("../..").ThreadUserMessagePart[];
|
400
400
|
} & {
|
401
401
|
readonly source: "edit-composer";
|
402
402
|
} & {
|
@@ -409,8 +409,8 @@ export declare const useEditComposerAttachment: {
|
|
409
409
|
file?: File;
|
410
410
|
content?: import("../..").ThreadUserMessagePart[];
|
411
411
|
} & {
|
412
|
-
status: import("../../types/AttachmentTypes").
|
413
|
-
|
412
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
413
|
+
file: File;
|
414
414
|
} & {
|
415
415
|
readonly source: "edit-composer";
|
416
416
|
} & {
|
@@ -426,8 +426,8 @@ export declare const useEditComposerAttachment: {
|
|
426
426
|
file?: File;
|
427
427
|
content?: import("../..").ThreadUserMessagePart[];
|
428
428
|
} & {
|
429
|
-
status: import("../../types/AttachmentTypes").
|
430
|
-
|
429
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
430
|
+
content: import("../..").ThreadUserMessagePart[];
|
431
431
|
} & {
|
432
432
|
readonly source: "edit-composer";
|
433
433
|
} & {
|
@@ -440,8 +440,8 @@ export declare const useEditComposerAttachment: {
|
|
440
440
|
file?: File;
|
441
441
|
content?: import("../..").ThreadUserMessagePart[];
|
442
442
|
} & {
|
443
|
-
status: import("../../types/AttachmentTypes").
|
444
|
-
|
443
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
444
|
+
file: File;
|
445
445
|
} & {
|
446
446
|
readonly source: "edit-composer";
|
447
447
|
} & {
|
@@ -457,8 +457,8 @@ export declare const useEditComposerAttachment: {
|
|
457
457
|
file?: File;
|
458
458
|
content?: import("../..").ThreadUserMessagePart[];
|
459
459
|
} & {
|
460
|
-
status: import("../../types/AttachmentTypes").
|
461
|
-
|
460
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
461
|
+
content: import("../..").ThreadUserMessagePart[];
|
462
462
|
} & {
|
463
463
|
readonly source: "edit-composer";
|
464
464
|
} & {
|
@@ -471,8 +471,8 @@ export declare const useEditComposerAttachment: {
|
|
471
471
|
file?: File;
|
472
472
|
content?: import("../..").ThreadUserMessagePart[];
|
473
473
|
} & {
|
474
|
-
status: import("../../types/AttachmentTypes").
|
475
|
-
|
474
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
475
|
+
file: File;
|
476
476
|
} & {
|
477
477
|
readonly source: "edit-composer";
|
478
478
|
} & {
|
@@ -489,8 +489,8 @@ export declare const useEditComposerAttachment: {
|
|
489
489
|
file?: File;
|
490
490
|
content?: import("../..").ThreadUserMessagePart[];
|
491
491
|
} & {
|
492
|
-
status: import("../../types/AttachmentTypes").
|
493
|
-
|
492
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
493
|
+
content: import("../..").ThreadUserMessagePart[];
|
494
494
|
} & {
|
495
495
|
readonly source: "edit-composer";
|
496
496
|
} & {
|
@@ -503,8 +503,8 @@ export declare const useEditComposerAttachment: {
|
|
503
503
|
file?: File;
|
504
504
|
content?: import("../..").ThreadUserMessagePart[];
|
505
505
|
} & {
|
506
|
-
status: import("../../types/AttachmentTypes").
|
507
|
-
|
506
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
507
|
+
file: File;
|
508
508
|
} & {
|
509
509
|
readonly source: "edit-composer";
|
510
510
|
} & {
|
@@ -518,8 +518,8 @@ export declare const useEditComposerAttachment: {
|
|
518
518
|
file?: File;
|
519
519
|
content?: import("../..").ThreadUserMessagePart[];
|
520
520
|
} & {
|
521
|
-
status: import("../../types/AttachmentTypes").
|
522
|
-
|
521
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
522
|
+
content: import("../..").ThreadUserMessagePart[];
|
523
523
|
} & {
|
524
524
|
readonly source: "edit-composer";
|
525
525
|
} & {
|
@@ -532,8 +532,8 @@ export declare const useEditComposerAttachment: {
|
|
532
532
|
file?: File;
|
533
533
|
content?: import("../..").ThreadUserMessagePart[];
|
534
534
|
} & {
|
535
|
-
status: import("../../types/AttachmentTypes").
|
536
|
-
|
535
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
536
|
+
file: File;
|
537
537
|
} & {
|
538
538
|
readonly source: "edit-composer";
|
539
539
|
} & {
|
@@ -549,8 +549,8 @@ export declare const useEditComposerAttachment: {
|
|
549
549
|
file?: File;
|
550
550
|
content?: import("../..").ThreadUserMessagePart[];
|
551
551
|
} & {
|
552
|
-
status: import("../../types/AttachmentTypes").
|
553
|
-
|
552
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
553
|
+
content: import("../..").ThreadUserMessagePart[];
|
554
554
|
} & {
|
555
555
|
readonly source: "edit-composer";
|
556
556
|
} & {
|
@@ -563,8 +563,8 @@ export declare const useEditComposerAttachment: {
|
|
563
563
|
file?: File;
|
564
564
|
content?: import("../..").ThreadUserMessagePart[];
|
565
565
|
} & {
|
566
|
-
status: import("../../types/AttachmentTypes").
|
567
|
-
|
566
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
567
|
+
file: File;
|
568
568
|
} & {
|
569
569
|
readonly source: "edit-composer";
|
570
570
|
} & {
|
@@ -581,8 +581,8 @@ export declare const useEditComposerAttachment: {
|
|
581
581
|
file?: File;
|
582
582
|
content?: import("../..").ThreadUserMessagePart[];
|
583
583
|
} & {
|
584
|
-
status: import("../../types/AttachmentTypes").
|
585
|
-
|
584
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
585
|
+
content: import("../..").ThreadUserMessagePart[];
|
586
586
|
} & {
|
587
587
|
readonly source: "edit-composer";
|
588
588
|
} & {
|
@@ -595,8 +595,8 @@ export declare const useEditComposerAttachment: {
|
|
595
595
|
file?: File;
|
596
596
|
content?: import("../..").ThreadUserMessagePart[];
|
597
597
|
} & {
|
598
|
-
status: import("../../types/AttachmentTypes").
|
599
|
-
|
598
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
599
|
+
file: File;
|
600
600
|
} & {
|
601
601
|
readonly source: "edit-composer";
|
602
602
|
} & {
|
@@ -610,8 +610,8 @@ export declare const useEditComposerAttachment: {
|
|
610
610
|
file?: File;
|
611
611
|
content?: import("../..").ThreadUserMessagePart[];
|
612
612
|
} & {
|
613
|
-
status: import("../../types/AttachmentTypes").
|
614
|
-
|
613
|
+
status: import("../../types/AttachmentTypes").CompleteAttachmentStatus;
|
614
|
+
content: import("../..").ThreadUserMessagePart[];
|
615
615
|
} & {
|
616
616
|
readonly source: "edit-composer";
|
617
617
|
} & {
|
@@ -624,8 +624,8 @@ export declare const useEditComposerAttachment: {
|
|
624
624
|
file?: File;
|
625
625
|
content?: import("../..").ThreadUserMessagePart[];
|
626
626
|
} & {
|
627
|
-
status: import("../../types/AttachmentTypes").
|
628
|
-
|
627
|
+
status: import("../../types/AttachmentTypes").PendingAttachmentStatus;
|
628
|
+
file: File;
|
629
629
|
} & {
|
630
630
|
readonly source: "edit-composer";
|
631
631
|
} & {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"useToolInvocations.d.ts","sourceRoot":"","sources":["../../../../src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,IAAI,EACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAejB,KAAK,wBAAwB,GAAG;IAC9B,KAAK,EAAE,uBAAuB,CAAC;IAC/B,QAAQ,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC;IACjD,QAAQ,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACvD,eAAe,EAAE,CACf,OAAO,EACH,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GACnC,CAAC,CACC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,KACtC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,KAC1C,IAAI,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC;AAExE,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB;;;
|
1
|
+
{"version":3,"file":"useToolInvocations.d.ts","sourceRoot":"","sources":["../../../../src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,IAAI,EACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAejB,KAAK,wBAAwB,GAAG;IAC9B,KAAK,EAAE,uBAAuB,CAAC;IAC/B,QAAQ,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC;IACjD,QAAQ,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACvD,eAAe,EAAE,CACf,OAAO,EACH,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GACnC,CAAC,CACC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,KACtC,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,KAC1C,IAAI,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAC3B;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC;AAExE,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB;;;yBA2LF,MAAM,WAAW,OAAO;EAiBhD"}
|
@@ -77,72 +77,74 @@ function useToolInvocations({
|
|
77
77
|
const ignoredToolIds = useRef(/* @__PURE__ */ new Set());
|
78
78
|
const isInititialState = useRef(true);
|
79
79
|
useEffect(() => {
|
80
|
-
|
81
|
-
|
82
|
-
message.content.forEach((content) => {
|
83
|
-
if (content.type === "tool-call") {
|
84
|
-
ignoredToolIds.current.add(content.toolCallId);
|
85
|
-
}
|
86
|
-
});
|
87
|
-
});
|
88
|
-
isInititialState.current = false;
|
89
|
-
} else {
|
90
|
-
state.messages.forEach((message) => {
|
80
|
+
const processMessages = (messages) => {
|
81
|
+
messages.forEach((message) => {
|
91
82
|
message.content.forEach((content) => {
|
92
83
|
if (content.type === "tool-call") {
|
93
|
-
if (
|
94
|
-
|
95
|
-
}
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
84
|
+
if (isInititialState.current) {
|
85
|
+
ignoredToolIds.current.add(content.toolCallId);
|
86
|
+
} else {
|
87
|
+
if (ignoredToolIds.current.has(content.toolCallId)) {
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
let lastState = lastToolStates.current[content.toolCallId];
|
91
|
+
if (!lastState) {
|
92
|
+
const toolCallController = controller.addToolCallPart({
|
93
|
+
toolName: content.toolName,
|
94
|
+
toolCallId: content.toolCallId
|
95
|
+
});
|
96
|
+
lastState = {
|
97
|
+
argsText: "",
|
98
|
+
hasResult: false,
|
99
|
+
controller: toolCallController
|
100
|
+
};
|
101
|
+
lastToolStates.current[content.toolCallId] = lastState;
|
102
|
+
}
|
103
|
+
if (content.argsText !== lastState.argsText) {
|
104
|
+
if (!content.argsText.startsWith(lastState.argsText)) {
|
105
|
+
throw new Error(
|
106
|
+
`Tool call argsText can only be appended, not updated: ${content.argsText} does not start with ${lastState.argsText}`
|
107
|
+
);
|
108
|
+
}
|
109
|
+
const argsTextDelta = content.argsText.slice(
|
110
|
+
lastState.argsText.length
|
113
111
|
);
|
112
|
+
lastState.controller.argsText.append(argsTextDelta);
|
113
|
+
if (isArgsTextComplete(content.argsText)) {
|
114
|
+
lastState.controller.argsText.close();
|
115
|
+
}
|
116
|
+
lastToolStates.current[content.toolCallId] = {
|
117
|
+
argsText: content.argsText,
|
118
|
+
hasResult: lastState.hasResult,
|
119
|
+
controller: lastState.controller
|
120
|
+
};
|
114
121
|
}
|
115
|
-
|
116
|
-
lastState.
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
122
|
+
if (content.result !== void 0 && !lastState.hasResult) {
|
123
|
+
lastState.controller.setResponse(
|
124
|
+
new ToolResponse({
|
125
|
+
result: content.result,
|
126
|
+
artifact: content.artifact,
|
127
|
+
isError: content.isError
|
128
|
+
})
|
129
|
+
);
|
130
|
+
lastState.controller.close();
|
131
|
+
lastToolStates.current[content.toolCallId] = {
|
132
|
+
hasResult: true,
|
133
|
+
argsText: lastState.argsText,
|
134
|
+
controller: lastState.controller
|
135
|
+
};
|
121
136
|
}
|
122
|
-
lastToolStates.current[content.toolCallId] = {
|
123
|
-
argsText: content.argsText,
|
124
|
-
hasResult: lastState.hasResult,
|
125
|
-
controller: lastState.controller
|
126
|
-
};
|
127
137
|
}
|
128
|
-
if (content.
|
129
|
-
|
130
|
-
new ToolResponse({
|
131
|
-
result: content.result,
|
132
|
-
artifact: content.artifact,
|
133
|
-
isError: content.isError
|
134
|
-
})
|
135
|
-
);
|
136
|
-
lastState.controller.close();
|
137
|
-
lastToolStates.current[content.toolCallId] = {
|
138
|
-
hasResult: true,
|
139
|
-
argsText: lastState.argsText,
|
140
|
-
controller: lastState.controller
|
141
|
-
};
|
138
|
+
if (content.messages) {
|
139
|
+
processMessages(content.messages);
|
142
140
|
}
|
143
141
|
}
|
144
142
|
});
|
145
143
|
});
|
144
|
+
};
|
145
|
+
processMessages(state.messages);
|
146
|
+
if (isInititialState.current) {
|
147
|
+
isInititialState.current = false;
|
146
148
|
}
|
147
149
|
}, [state, controller, onResult]);
|
148
150
|
const abort = () => {
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../../../../src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n createAssistantStreamController,\n ToolCallStreamController,\n ToolResponse,\n unstable_toolResultStream,\n type Tool,\n} from \"assistant-stream\";\nimport type {\n AssistantTransportCommand,\n AssistantTransportState,\n} from \"./types\";\nimport {\n AssistantMetaTransformStream,\n type ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\n\nconst isArgsTextComplete = (argsText: string) => {\n try {\n JSON.parse(argsText);\n return true;\n } catch {\n return false;\n }\n};\n\ntype UseToolInvocationsParams = {\n state: AssistantTransportState;\n getTools: () => Record<string, Tool> | undefined;\n onResult: (command: AssistantTransportCommand) => void;\n setToolStatuses: (\n updater:\n | Record<string, ToolExecutionStatus>\n | ((\n prev: Record<string, ToolExecutionStatus>,\n ) => Record<string, ToolExecutionStatus>),\n ) => void;\n};\n\nexport type ToolExecutionStatus =\n | { type: \"executing\" }\n | { type: \"interrupt\"; payload: { type: \"human\"; payload: unknown } };\n\nexport function useToolInvocations({\n state,\n getTools,\n onResult,\n setToolStatuses,\n}: UseToolInvocationsParams) {\n const lastToolStates = useRef<\n Record<\n string,\n {\n argsText: string;\n hasResult: boolean;\n controller: ToolCallStreamController;\n }\n >\n >({});\n\n const humanInputRef = useRef<\n Map<\n string,\n {\n resolve: (payload: unknown) => void;\n reject: (reason: unknown) => void;\n }\n >\n >(new Map());\n\n const acRef = useRef<AbortController>(new AbortController());\n const [controller] = useState(() => {\n const [stream, controller] = createAssistantStreamController();\n const transform = unstable_toolResultStream(\n getTools,\n () => acRef.current?.signal ?? new AbortController().signal,\n (toolCallId: string, payload: unknown) => {\n return new Promise<unknown>((resolve, reject) => {\n // Reject previous human input request if it exists\n const previous = humanInputRef.current.get(toolCallId);\n if (previous) {\n previous.reject(\n new Error(\"Human input request was superseded by a new request\"),\n );\n }\n\n humanInputRef.current.set(toolCallId, { resolve, reject });\n setToolStatuses((prev) => ({\n ...prev,\n [toolCallId]: {\n type: \"interrupt\",\n payload: { type: \"human\", payload },\n },\n }));\n });\n },\n );\n stream\n .pipeThrough(transform)\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeTo(\n new WritableStream({\n write(chunk) {\n if (chunk.type === \"result\") {\n // the tool call result was already set by the backend\n if (lastToolStates.current[chunk.meta.toolCallId]?.hasResult)\n return;\n\n onResult({\n type: \"add-tool-result\",\n toolCallId: chunk.meta.toolCallId,\n toolName: chunk.meta.toolName,\n result: chunk.result,\n isError: chunk.isError,\n ...(chunk.artifact && { artifact: chunk.artifact }),\n });\n\n // Clear status when result is set\n setToolStatuses((prev) => {\n const next = { ...prev };\n delete next[chunk.meta.toolCallId];\n return next;\n });\n }\n },\n }),\n );\n\n return controller;\n });\n\n const ignoredToolIds = useRef<Set<string>>(new Set());\n const isInititialState = useRef(true);\n\n useEffect(() => {\n if (isInititialState.current) {\n state.messages.forEach((message) => {\n message.content.forEach((content) => {\n if (content.type === \"tool-call\") {\n ignoredToolIds.current.add(content.toolCallId);\n }\n });\n });\n isInititialState.current = false;\n } else {\n state.messages.forEach((message) => {\n message.content.forEach((content) => {\n if (content.type === \"tool-call\") {\n if (ignoredToolIds.current.has(content.toolCallId)) {\n return;\n }\n let lastState = lastToolStates.current[content.toolCallId];\n if (!lastState) {\n const toolCallController = controller.addToolCallPart({\n toolName: content.toolName,\n toolCallId: content.toolCallId,\n });\n lastState = {\n argsText: \"\",\n hasResult: false,\n controller: toolCallController,\n };\n lastToolStates.current[content.toolCallId] = lastState;\n }\n\n if (content.argsText !== lastState.argsText) {\n if (!content.argsText.startsWith(lastState.argsText)) {\n throw new Error(\n `Tool call argsText can only be appended, not updated: ${content.argsText} does not start with ${lastState.argsText}`,\n );\n }\n\n const argsTextDelta = content.argsText.slice(\n lastState.argsText.length,\n );\n lastState.controller.argsText.append(argsTextDelta);\n\n if (isArgsTextComplete(content.argsText)) {\n lastState.controller.argsText.close();\n }\n\n lastToolStates.current[content.toolCallId] = {\n argsText: content.argsText,\n hasResult: lastState.hasResult,\n controller: lastState.controller,\n };\n }\n\n if (content.result !== undefined && !lastState.hasResult) {\n lastState.controller.setResponse(\n new ToolResponse({\n result: content.result as ReadonlyJSONValue,\n artifact: content.artifact as ReadonlyJSONValue | undefined,\n isError: content.isError,\n }),\n );\n lastState.controller.close();\n\n lastToolStates.current[content.toolCallId] = {\n hasResult: true,\n argsText: lastState.argsText,\n controller: lastState.controller,\n };\n }\n }\n });\n });\n }\n }, [state, controller, onResult]);\n\n const abort = () => {\n humanInputRef.current.forEach(({ reject }) => {\n reject(new Error(\"Tool execution aborted\"));\n });\n humanInputRef.current.clear();\n setToolStatuses({});\n\n acRef.current.abort();\n acRef.current = new AbortController();\n };\n\n return {\n reset: () => {\n abort();\n isInititialState.current = true;\n },\n abort,\n resume: (toolCallId: string, payload: unknown) => {\n const handlers = humanInputRef.current.get(toolCallId);\n if (handlers) {\n humanInputRef.current.delete(toolCallId);\n setToolStatuses((prev) => {\n const next = { ...prev };\n delete next[toolCallId];\n return next;\n });\n handlers.resolve(payload);\n } else {\n throw new Error(\n `Tool call ${toolCallId} is not waiting for human input`,\n );\n }\n },\n };\n}\n"],"mappings":"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","names":["controller"]}
|
1
|
+
{"version":3,"sources":["../../../../src/legacy-runtime/runtime-cores/assistant-transport/useToolInvocations.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport {\n createAssistantStreamController,\n ToolCallStreamController,\n ToolResponse,\n unstable_toolResultStream,\n type Tool,\n} from \"assistant-stream\";\nimport type {\n AssistantTransportCommand,\n AssistantTransportState,\n} from \"./types\";\nimport {\n AssistantMetaTransformStream,\n type ReadonlyJSONValue,\n} from \"assistant-stream/utils\";\n\nconst isArgsTextComplete = (argsText: string) => {\n try {\n JSON.parse(argsText);\n return true;\n } catch {\n return false;\n }\n};\n\ntype UseToolInvocationsParams = {\n state: AssistantTransportState;\n getTools: () => Record<string, Tool> | undefined;\n onResult: (command: AssistantTransportCommand) => void;\n setToolStatuses: (\n updater:\n | Record<string, ToolExecutionStatus>\n | ((\n prev: Record<string, ToolExecutionStatus>,\n ) => Record<string, ToolExecutionStatus>),\n ) => void;\n};\n\nexport type ToolExecutionStatus =\n | { type: \"executing\" }\n | { type: \"interrupt\"; payload: { type: \"human\"; payload: unknown } };\n\nexport function useToolInvocations({\n state,\n getTools,\n onResult,\n setToolStatuses,\n}: UseToolInvocationsParams) {\n const lastToolStates = useRef<\n Record<\n string,\n {\n argsText: string;\n hasResult: boolean;\n controller: ToolCallStreamController;\n }\n >\n >({});\n\n const humanInputRef = useRef<\n Map<\n string,\n {\n resolve: (payload: unknown) => void;\n reject: (reason: unknown) => void;\n }\n >\n >(new Map());\n\n const acRef = useRef<AbortController>(new AbortController());\n const [controller] = useState(() => {\n const [stream, controller] = createAssistantStreamController();\n const transform = unstable_toolResultStream(\n getTools,\n () => acRef.current?.signal ?? new AbortController().signal,\n (toolCallId: string, payload: unknown) => {\n return new Promise<unknown>((resolve, reject) => {\n // Reject previous human input request if it exists\n const previous = humanInputRef.current.get(toolCallId);\n if (previous) {\n previous.reject(\n new Error(\"Human input request was superseded by a new request\"),\n );\n }\n\n humanInputRef.current.set(toolCallId, { resolve, reject });\n setToolStatuses((prev) => ({\n ...prev,\n [toolCallId]: {\n type: \"interrupt\",\n payload: { type: \"human\", payload },\n },\n }));\n });\n },\n );\n stream\n .pipeThrough(transform)\n .pipeThrough(new AssistantMetaTransformStream())\n .pipeTo(\n new WritableStream({\n write(chunk) {\n if (chunk.type === \"result\") {\n // the tool call result was already set by the backend\n if (lastToolStates.current[chunk.meta.toolCallId]?.hasResult)\n return;\n\n onResult({\n type: \"add-tool-result\",\n toolCallId: chunk.meta.toolCallId,\n toolName: chunk.meta.toolName,\n result: chunk.result,\n isError: chunk.isError,\n ...(chunk.artifact && { artifact: chunk.artifact }),\n });\n\n // Clear status when result is set\n setToolStatuses((prev) => {\n const next = { ...prev };\n delete next[chunk.meta.toolCallId];\n return next;\n });\n }\n },\n }),\n );\n\n return controller;\n });\n\n const ignoredToolIds = useRef<Set<string>>(new Set());\n const isInititialState = useRef(true);\n\n useEffect(() => {\n const processMessages = (\n messages: readonly (typeof state.messages)[number][],\n ) => {\n messages.forEach((message) => {\n message.content.forEach((content) => {\n if (content.type === \"tool-call\") {\n if (isInititialState.current) {\n ignoredToolIds.current.add(content.toolCallId);\n } else {\n if (ignoredToolIds.current.has(content.toolCallId)) {\n return;\n }\n let lastState = lastToolStates.current[content.toolCallId];\n if (!lastState) {\n const toolCallController = controller.addToolCallPart({\n toolName: content.toolName,\n toolCallId: content.toolCallId,\n });\n lastState = {\n argsText: \"\",\n hasResult: false,\n controller: toolCallController,\n };\n lastToolStates.current[content.toolCallId] = lastState;\n }\n\n if (content.argsText !== lastState.argsText) {\n if (!content.argsText.startsWith(lastState.argsText)) {\n throw new Error(\n `Tool call argsText can only be appended, not updated: ${content.argsText} does not start with ${lastState.argsText}`,\n );\n }\n\n const argsTextDelta = content.argsText.slice(\n lastState.argsText.length,\n );\n lastState.controller.argsText.append(argsTextDelta);\n\n if (isArgsTextComplete(content.argsText)) {\n lastState.controller.argsText.close();\n }\n\n lastToolStates.current[content.toolCallId] = {\n argsText: content.argsText,\n hasResult: lastState.hasResult,\n controller: lastState.controller,\n };\n }\n\n if (content.result !== undefined && !lastState.hasResult) {\n lastState.controller.setResponse(\n new ToolResponse({\n result: content.result as ReadonlyJSONValue,\n artifact: content.artifact as ReadonlyJSONValue | undefined,\n isError: content.isError,\n }),\n );\n lastState.controller.close();\n\n lastToolStates.current[content.toolCallId] = {\n hasResult: true,\n argsText: lastState.argsText,\n controller: lastState.controller,\n };\n }\n }\n\n // Recursively process nested messages\n if (content.messages) {\n processMessages(content.messages);\n }\n }\n });\n });\n };\n\n processMessages(state.messages);\n\n if (isInititialState.current) {\n isInititialState.current = false;\n }\n }, [state, controller, onResult]);\n\n const abort = () => {\n humanInputRef.current.forEach(({ reject }) => {\n reject(new Error(\"Tool execution aborted\"));\n });\n humanInputRef.current.clear();\n setToolStatuses({});\n\n acRef.current.abort();\n acRef.current = new AbortController();\n };\n\n return {\n reset: () => {\n abort();\n isInititialState.current = true;\n },\n abort,\n resume: (toolCallId: string, payload: unknown) => {\n const handlers = humanInputRef.current.get(toolCallId);\n if (handlers) {\n humanInputRef.current.delete(toolCallId);\n setToolStatuses((prev) => {\n const next = { ...prev };\n delete next[toolCallId];\n return next;\n });\n handlers.resolve(payload);\n } else {\n throw new Error(\n `Tool call ${toolCallId} is not waiting for human input`,\n );\n }\n },\n };\n}\n"],"mappings":"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","names":["controller"]}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { ReadonlyJSONObject } from "assistant-stream/utils";
|
2
|
+
import type { ThreadMessage } from "./AssistantTypes";
|
2
3
|
export type TextMessagePart = {
|
3
4
|
readonly type: "text";
|
4
5
|
readonly text: string;
|
@@ -49,6 +50,7 @@ export type ToolCallMessagePart<TArgs = ReadonlyJSONObject, TResult = unknown> =
|
|
49
50
|
payload: unknown;
|
50
51
|
};
|
51
52
|
readonly parentId?: string;
|
53
|
+
readonly messages?: readonly ThreadMessage[];
|
52
54
|
};
|
53
55
|
export type ThreadUserMessagePart = TextMessagePart | ImageMessagePart | FileMessagePart | Unstable_AudioMessagePart;
|
54
56
|
export type ThreadAssistantMessagePart = TextMessagePart | ReasoningMessagePart | ToolCallMessagePart | SourceMessagePart | FileMessagePart | ImageMessagePart;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"MessagePartTypes.d.ts","sourceRoot":"","sources":["../../src/types/MessagePartTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;
|
1
|
+
{"version":3,"file":"MessagePartTypes.d.ts","sourceRoot":"","sources":["../../src/types/MessagePartTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAC7B,KAAK,GAAG,kBAAkB,EAC1B,OAAO,GAAG,OAAO,IACf;IACF,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAC7B,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,yBAAyB,CAAC;AAE9B,MAAM,MAAM,0BAA0B,GAClC,eAAe,GACf,oBAAoB,GACpB,mBAAmB,GACnB,iBAAiB,GACjB,eAAe,GACf,gBAAgB,CAAC"}
|
package/package.json
CHANGED
@@ -133,78 +133,86 @@ export function useToolInvocations({
|
|
133
133
|
const isInititialState = useRef(true);
|
134
134
|
|
135
135
|
useEffect(() => {
|
136
|
-
|
137
|
-
state.messages
|
136
|
+
const processMessages = (
|
137
|
+
messages: readonly (typeof state.messages)[number][],
|
138
|
+
) => {
|
139
|
+
messages.forEach((message) => {
|
138
140
|
message.content.forEach((content) => {
|
139
141
|
if (content.type === "tool-call") {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
142
|
+
if (isInititialState.current) {
|
143
|
+
ignoredToolIds.current.add(content.toolCallId);
|
144
|
+
} else {
|
145
|
+
if (ignoredToolIds.current.has(content.toolCallId)) {
|
146
|
+
return;
|
147
|
+
}
|
148
|
+
let lastState = lastToolStates.current[content.toolCallId];
|
149
|
+
if (!lastState) {
|
150
|
+
const toolCallController = controller.addToolCallPart({
|
151
|
+
toolName: content.toolName,
|
152
|
+
toolCallId: content.toolCallId,
|
153
|
+
});
|
154
|
+
lastState = {
|
155
|
+
argsText: "",
|
156
|
+
hasResult: false,
|
157
|
+
controller: toolCallController,
|
158
|
+
};
|
159
|
+
lastToolStates.current[content.toolCallId] = lastState;
|
160
|
+
}
|
161
|
+
|
162
|
+
if (content.argsText !== lastState.argsText) {
|
163
|
+
if (!content.argsText.startsWith(lastState.argsText)) {
|
164
|
+
throw new Error(
|
165
|
+
`Tool call argsText can only be appended, not updated: ${content.argsText} does not start with ${lastState.argsText}`,
|
166
|
+
);
|
167
|
+
}
|
165
168
|
|
166
|
-
|
167
|
-
|
168
|
-
throw new Error(
|
169
|
-
`Tool call argsText can only be appended, not updated: ${content.argsText} does not start with ${lastState.argsText}`,
|
169
|
+
const argsTextDelta = content.argsText.slice(
|
170
|
+
lastState.argsText.length,
|
170
171
|
);
|
171
|
-
|
172
|
+
lastState.controller.argsText.append(argsTextDelta);
|
172
173
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
lastState.controller.argsText.append(argsTextDelta);
|
174
|
+
if (isArgsTextComplete(content.argsText)) {
|
175
|
+
lastState.controller.argsText.close();
|
176
|
+
}
|
177
177
|
|
178
|
-
|
179
|
-
|
178
|
+
lastToolStates.current[content.toolCallId] = {
|
179
|
+
argsText: content.argsText,
|
180
|
+
hasResult: lastState.hasResult,
|
181
|
+
controller: lastState.controller,
|
182
|
+
};
|
180
183
|
}
|
181
184
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
185
|
+
if (content.result !== undefined && !lastState.hasResult) {
|
186
|
+
lastState.controller.setResponse(
|
187
|
+
new ToolResponse({
|
188
|
+
result: content.result as ReadonlyJSONValue,
|
189
|
+
artifact: content.artifact as ReadonlyJSONValue | undefined,
|
190
|
+
isError: content.isError,
|
191
|
+
}),
|
192
|
+
);
|
193
|
+
lastState.controller.close();
|
194
|
+
|
195
|
+
lastToolStates.current[content.toolCallId] = {
|
196
|
+
hasResult: true,
|
197
|
+
argsText: lastState.argsText,
|
198
|
+
controller: lastState.controller,
|
199
|
+
};
|
200
|
+
}
|
187
201
|
}
|
188
202
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
result: content.result as ReadonlyJSONValue,
|
193
|
-
artifact: content.artifact as ReadonlyJSONValue | undefined,
|
194
|
-
isError: content.isError,
|
195
|
-
}),
|
196
|
-
);
|
197
|
-
lastState.controller.close();
|
198
|
-
|
199
|
-
lastToolStates.current[content.toolCallId] = {
|
200
|
-
hasResult: true,
|
201
|
-
argsText: lastState.argsText,
|
202
|
-
controller: lastState.controller,
|
203
|
-
};
|
203
|
+
// Recursively process nested messages
|
204
|
+
if (content.messages) {
|
205
|
+
processMessages(content.messages);
|
204
206
|
}
|
205
207
|
}
|
206
208
|
});
|
207
209
|
});
|
210
|
+
};
|
211
|
+
|
212
|
+
processMessages(state.messages);
|
213
|
+
|
214
|
+
if (isInititialState.current) {
|
215
|
+
isInititialState.current = false;
|
208
216
|
}
|
209
217
|
}, [state, controller, onResult]);
|
210
218
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { ReadonlyJSONObject } from "assistant-stream/utils";
|
2
|
+
import type { ThreadMessage } from "./AssistantTypes";
|
2
3
|
|
3
4
|
export type TextMessagePart = {
|
4
5
|
readonly type: "text";
|
@@ -56,6 +57,7 @@ export type ToolCallMessagePart<
|
|
56
57
|
readonly artifact?: unknown;
|
57
58
|
readonly interrupt?: { type: "human"; payload: unknown };
|
58
59
|
readonly parentId?: string;
|
60
|
+
readonly messages?: readonly ThreadMessage[];
|
59
61
|
};
|
60
62
|
|
61
63
|
export type ThreadUserMessagePart =
|