assistant-stream 0.1.2 → 0.1.4

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/index.mjs CHANGED
@@ -7,127 +7,13 @@ import {
7
7
  PipeableTransformStream,
8
8
  createAssistantStream,
9
9
  createAssistantStreamResponse,
10
- generateId
11
- } from "./chunk-OONTWUTM.mjs";
10
+ generateId,
11
+ promiseWithResolvers
12
+ } from "./chunk-EDE6WQ2R.mjs";
12
13
  import {
13
- parsePartialJson
14
- } from "./chunk-C7JS3OBQ.mjs";
15
-
16
- // src/core/effects/ToolExecutionStream.ts
17
- import sjson from "secure-json-parse";
18
-
19
- // src/core/utils/withPromiseOrValue.ts
20
- function withPromiseOrValue(callback, thenHandler, catchHandler) {
21
- try {
22
- const promiseOrValue = callback();
23
- if (typeof promiseOrValue === "object" && promiseOrValue !== null && "then" in promiseOrValue) {
24
- return promiseOrValue.then(thenHandler, catchHandler);
25
- } else {
26
- thenHandler(promiseOrValue);
27
- }
28
- } catch (e) {
29
- catchHandler(e);
30
- }
31
- }
32
-
33
- // src/core/effects/ToolExecutionStream.ts
34
- var ToolExecutionStream = class extends PipeableTransformStream {
35
- constructor(toolCallback) {
36
- const toolCallPromises = /* @__PURE__ */ new Map();
37
- const toolCallArgsText = {};
38
- super((readable) => {
39
- const transform = new TransformStream({
40
- transform(chunk, controller) {
41
- if (chunk.type !== "part-finish" || chunk.meta.type !== "tool-call") {
42
- controller.enqueue(chunk);
43
- }
44
- const type = chunk.type;
45
- switch (type) {
46
- case "text-delta": {
47
- if (chunk.meta.type === "tool-call") {
48
- const toolCallId = chunk.meta.toolCallId;
49
- if (toolCallArgsText[toolCallId] === void 0) {
50
- toolCallArgsText[toolCallId] = chunk.textDelta;
51
- } else {
52
- toolCallArgsText[toolCallId] += chunk.textDelta;
53
- }
54
- }
55
- break;
56
- }
57
- case "tool-call-args-text-finish": {
58
- if (chunk.meta.type !== "tool-call") break;
59
- const { toolCallId, toolName } = chunk.meta;
60
- const argsText = toolCallArgsText[toolCallId];
61
- const promise = withPromiseOrValue(
62
- () => {
63
- if (!argsText) {
64
- console.log(
65
- "Encountered tool call without argsText, this should never happen"
66
- );
67
- throw new Error(
68
- "Encountered tool call without argsText, this is unexpected."
69
- );
70
- }
71
- let args;
72
- try {
73
- args = sjson.parse(argsText);
74
- } catch (e) {
75
- throw new Error(
76
- `Function parameter parsing failed. ${JSON.stringify(e.message)}`
77
- );
78
- }
79
- return toolCallback({
80
- toolCallId,
81
- toolName,
82
- args
83
- });
84
- },
85
- (c) => {
86
- if (c === void 0) return;
87
- controller.enqueue({
88
- type: "result",
89
- path: chunk.path,
90
- artifact: c.artifact,
91
- result: c.result,
92
- isError: c.isError
93
- });
94
- },
95
- (e) => {
96
- controller.enqueue({
97
- type: "result",
98
- path: chunk.path,
99
- result: String(e),
100
- isError: true
101
- });
102
- }
103
- );
104
- if (promise) {
105
- toolCallPromises.set(toolCallId, promise);
106
- }
107
- break;
108
- }
109
- case "part-finish": {
110
- if (chunk.meta.type !== "tool-call") break;
111
- const { toolCallId } = chunk.meta;
112
- const toolCallPromise = toolCallPromises.get(toolCallId);
113
- if (toolCallPromise) {
114
- toolCallPromise.then(() => {
115
- controller.enqueue(chunk);
116
- });
117
- } else {
118
- controller.enqueue(chunk);
119
- }
120
- }
121
- }
122
- },
123
- async flush() {
124
- await Promise.all(toolCallPromises.values());
125
- }
126
- });
127
- return readable.pipeThrough(new AssistantMetaTransformStream()).pipeThrough(transform);
128
- });
129
- }
130
- };
14
+ getPartialJsonObjectFieldState,
15
+ parsePartialJsonObject
16
+ } from "./chunk-PQLDKUPN.mjs";
131
17
 
132
18
  // src/core/accumulators/assistant-message-accumulator.ts
133
19
  var createInitialMessage = () => ({
@@ -251,12 +137,7 @@ var handleTextDelta = (message, chunk) => {
251
137
  return { ...part, text: part.text + chunk.textDelta };
252
138
  } else if (part.type === "tool-call") {
253
139
  const newArgsText = part.argsText + chunk.textDelta;
254
- let newArgs;
255
- try {
256
- newArgs = parsePartialJson(newArgsText);
257
- } catch (err) {
258
- newArgs = part.args;
259
- }
140
+ const newArgs = parsePartialJsonObject(newArgsText) ?? part.args;
260
141
  return { ...part, argsText: newArgsText, args: newArgs };
261
142
  } else {
262
143
  throw new Error(
@@ -526,7 +407,7 @@ var AssistantMessageStream = class _AssistantMessageStream {
526
407
  }
527
408
  };
528
409
 
529
- // src/core/ToolResponse.ts
410
+ // src/core/tool/ToolResponse.ts
530
411
  var TOOL_RESPONSE_SYMBOL = Symbol.for("aui.tool-response");
531
412
  var ToolResponse = class {
532
413
  get [TOOL_RESPONSE_SYMBOL]() {
@@ -544,6 +425,505 @@ var ToolResponse = class {
544
425
  return typeof obj === "object" && obj !== null && TOOL_RESPONSE_SYMBOL in obj;
545
426
  }
546
427
  };
428
+
429
+ // src/core/tool/ToolExecutionStream.ts
430
+ import sjson from "secure-json-parse";
431
+
432
+ // src/core/utils/withPromiseOrValue.ts
433
+ function withPromiseOrValue(callback, thenHandler, catchHandler) {
434
+ try {
435
+ const promiseOrValue = callback();
436
+ if (typeof promiseOrValue === "object" && promiseOrValue !== null && "then" in promiseOrValue) {
437
+ return promiseOrValue.then(thenHandler, catchHandler);
438
+ } else {
439
+ thenHandler(promiseOrValue);
440
+ }
441
+ } catch (e) {
442
+ catchHandler(e);
443
+ }
444
+ }
445
+
446
+ // src/core/tool/ToolCallReader.ts
447
+ function getField(obj, fieldPath) {
448
+ let current = obj;
449
+ for (const key of fieldPath) {
450
+ if (current === void 0 || current === null) {
451
+ return void 0;
452
+ }
453
+ current = current[key];
454
+ }
455
+ return current;
456
+ }
457
+ var GetHandle = class {
458
+ resolve;
459
+ reject;
460
+ disposed = false;
461
+ fieldPath;
462
+ constructor(resolve, reject, fieldPath) {
463
+ this.resolve = resolve;
464
+ this.reject = reject;
465
+ this.fieldPath = fieldPath;
466
+ }
467
+ update(args) {
468
+ if (this.disposed) return;
469
+ try {
470
+ if (getPartialJsonObjectFieldState(
471
+ args,
472
+ this.fieldPath
473
+ ) === "complete") {
474
+ const value = getField(args, this.fieldPath);
475
+ if (value !== void 0) {
476
+ this.resolve(value);
477
+ this.dispose();
478
+ }
479
+ }
480
+ } catch (e) {
481
+ this.reject(e);
482
+ this.dispose();
483
+ }
484
+ }
485
+ dispose() {
486
+ this.disposed = true;
487
+ }
488
+ };
489
+ var StreamValuesHandle = class {
490
+ controller;
491
+ disposed = false;
492
+ fieldPath;
493
+ constructor(controller, fieldPath) {
494
+ this.controller = controller;
495
+ this.fieldPath = fieldPath;
496
+ }
497
+ update(args) {
498
+ if (this.disposed) return;
499
+ try {
500
+ const value = getField(args, this.fieldPath);
501
+ if (value !== void 0) {
502
+ this.controller.enqueue(value);
503
+ }
504
+ if (getPartialJsonObjectFieldState(
505
+ args,
506
+ this.fieldPath
507
+ ) === "complete") {
508
+ this.controller.close();
509
+ this.dispose();
510
+ }
511
+ } catch (e) {
512
+ this.controller.error(e);
513
+ this.dispose();
514
+ }
515
+ }
516
+ dispose() {
517
+ this.disposed = true;
518
+ }
519
+ };
520
+ var StreamTextHandle = class {
521
+ controller;
522
+ disposed = false;
523
+ fieldPath;
524
+ lastValue = void 0;
525
+ constructor(controller, fieldPath) {
526
+ this.controller = controller;
527
+ this.fieldPath = fieldPath;
528
+ }
529
+ update(args) {
530
+ if (this.disposed) return;
531
+ try {
532
+ const value = getField(args, this.fieldPath);
533
+ if (value !== void 0 && typeof value === "string") {
534
+ const delta = value.substring(this.lastValue?.length || 0);
535
+ this.lastValue = value;
536
+ this.controller.enqueue(delta);
537
+ }
538
+ if (getPartialJsonObjectFieldState(
539
+ args,
540
+ this.fieldPath
541
+ ) === "complete") {
542
+ this.controller.close();
543
+ this.dispose();
544
+ }
545
+ } catch (e) {
546
+ this.controller.error(e);
547
+ this.dispose();
548
+ }
549
+ }
550
+ dispose() {
551
+ this.disposed = true;
552
+ }
553
+ };
554
+ var ForEachHandle = class {
555
+ controller;
556
+ disposed = false;
557
+ fieldPath;
558
+ processedIndexes = /* @__PURE__ */ new Set();
559
+ constructor(controller, fieldPath) {
560
+ this.controller = controller;
561
+ this.fieldPath = fieldPath;
562
+ }
563
+ update(args) {
564
+ if (this.disposed) return;
565
+ try {
566
+ const array = getField(args, this.fieldPath);
567
+ if (!Array.isArray(array)) {
568
+ return;
569
+ }
570
+ for (let i = 0; i < array.length; i++) {
571
+ if (!this.processedIndexes.has(i)) {
572
+ const elementPath = [...this.fieldPath, i];
573
+ if (getPartialJsonObjectFieldState(
574
+ args,
575
+ elementPath
576
+ ) === "complete") {
577
+ this.controller.enqueue(array[i]);
578
+ this.processedIndexes.add(i);
579
+ }
580
+ }
581
+ }
582
+ if (getPartialJsonObjectFieldState(
583
+ args,
584
+ this.fieldPath
585
+ ) === "complete") {
586
+ this.controller.close();
587
+ this.dispose();
588
+ }
589
+ } catch (e) {
590
+ this.controller.error(e);
591
+ this.dispose();
592
+ }
593
+ }
594
+ dispose() {
595
+ this.disposed = true;
596
+ }
597
+ };
598
+ var ToolCallArgsReaderImpl = class {
599
+ argTextDeltas;
600
+ handles = /* @__PURE__ */ new Set();
601
+ args = parsePartialJsonObject("");
602
+ constructor(argTextDeltas) {
603
+ this.argTextDeltas = argTextDeltas;
604
+ this.processStream();
605
+ }
606
+ async processStream() {
607
+ try {
608
+ let accumulatedText = "";
609
+ const reader = this.argTextDeltas.getReader();
610
+ while (true) {
611
+ const { value, done } = await reader.read();
612
+ if (done) break;
613
+ accumulatedText += value;
614
+ const parsedArgs = parsePartialJsonObject(accumulatedText);
615
+ if (parsedArgs !== void 0) {
616
+ this.args = parsedArgs;
617
+ for (const handle of this.handles) {
618
+ handle.update(parsedArgs);
619
+ }
620
+ }
621
+ }
622
+ } catch (error) {
623
+ console.error("Error processing argument stream:", error);
624
+ for (const handle of this.handles) {
625
+ handle.dispose();
626
+ }
627
+ }
628
+ }
629
+ get(...fieldPath) {
630
+ return new Promise((resolve, reject) => {
631
+ const handle = new GetHandle(resolve, reject, fieldPath);
632
+ if (this.args && getPartialJsonObjectFieldState(
633
+ this.args,
634
+ fieldPath
635
+ ) === "complete") {
636
+ const value = getField(this.args, fieldPath);
637
+ if (value !== void 0) {
638
+ resolve(value);
639
+ return;
640
+ }
641
+ }
642
+ this.handles.add(handle);
643
+ handle.update(this.args);
644
+ });
645
+ }
646
+ streamValues(...fieldPath) {
647
+ const simplePath = fieldPath;
648
+ const stream = new ReadableStream({
649
+ start: (controller) => {
650
+ const handle = new StreamValuesHandle(controller, simplePath);
651
+ this.handles.add(handle);
652
+ handle.update(this.args);
653
+ },
654
+ cancel: () => {
655
+ for (const handle of this.handles) {
656
+ if (handle instanceof StreamValuesHandle) {
657
+ handle.dispose();
658
+ this.handles.delete(handle);
659
+ break;
660
+ }
661
+ }
662
+ }
663
+ });
664
+ return stream;
665
+ }
666
+ streamText(...fieldPath) {
667
+ const simplePath = fieldPath;
668
+ const stream = new ReadableStream({
669
+ start: (controller) => {
670
+ const handle = new StreamTextHandle(controller, simplePath);
671
+ this.handles.add(handle);
672
+ handle.update(this.args);
673
+ },
674
+ cancel: () => {
675
+ for (const handle of this.handles) {
676
+ if (handle instanceof StreamTextHandle) {
677
+ handle.dispose();
678
+ this.handles.delete(handle);
679
+ break;
680
+ }
681
+ }
682
+ }
683
+ });
684
+ return stream;
685
+ }
686
+ forEach(...fieldPath) {
687
+ const simplePath = fieldPath;
688
+ const stream = new ReadableStream({
689
+ start: (controller) => {
690
+ const handle = new ForEachHandle(controller, simplePath);
691
+ this.handles.add(handle);
692
+ handle.update(this.args);
693
+ },
694
+ cancel: () => {
695
+ for (const handle of this.handles) {
696
+ if (handle instanceof ForEachHandle) {
697
+ handle.dispose();
698
+ this.handles.delete(handle);
699
+ break;
700
+ }
701
+ }
702
+ }
703
+ });
704
+ return stream;
705
+ }
706
+ };
707
+ var ToolCallResultReaderImpl = class {
708
+ constructor(resultPromise) {
709
+ this.resultPromise = resultPromise;
710
+ }
711
+ get() {
712
+ return this.resultPromise;
713
+ }
714
+ };
715
+ var ToolCallReaderImpl = class {
716
+ args;
717
+ result;
718
+ writable;
719
+ resolve;
720
+ argsText = "";
721
+ constructor() {
722
+ const stream = new TransformStream();
723
+ this.writable = stream.writable;
724
+ this.args = new ToolCallArgsReaderImpl(stream.readable);
725
+ const { promise, resolve } = promiseWithResolvers();
726
+ this.resolve = resolve;
727
+ this.result = new ToolCallResultReaderImpl(promise);
728
+ }
729
+ async appendArgsTextDelta(text) {
730
+ const writer = this.writable.getWriter();
731
+ try {
732
+ await writer.write(text);
733
+ } catch (err) {
734
+ console.warn(err);
735
+ } finally {
736
+ writer.releaseLock();
737
+ }
738
+ this.argsText += text;
739
+ }
740
+ setResult(value) {
741
+ this.resolve(value);
742
+ }
743
+ };
744
+
745
+ // src/core/tool/ToolExecutionStream.ts
746
+ var ToolExecutionStream = class extends PipeableTransformStream {
747
+ constructor(options) {
748
+ const toolCallPromises = /* @__PURE__ */ new Map();
749
+ const toolCallControllers = /* @__PURE__ */ new Map();
750
+ super((readable) => {
751
+ const transform = new TransformStream({
752
+ transform(chunk, controller) {
753
+ if (chunk.type !== "part-finish" || chunk.meta.type !== "tool-call") {
754
+ controller.enqueue(chunk);
755
+ }
756
+ const type = chunk.type;
757
+ switch (type) {
758
+ case "part-start":
759
+ if (chunk.part.type === "tool-call") {
760
+ const reader = new ToolCallReaderImpl();
761
+ toolCallControllers.set(chunk.part.toolCallId, reader);
762
+ options.streamCall({
763
+ reader,
764
+ toolCallId: chunk.part.toolCallId,
765
+ toolName: chunk.part.toolName
766
+ });
767
+ }
768
+ break;
769
+ case "text-delta": {
770
+ if (chunk.meta.type === "tool-call") {
771
+ const toolCallId = chunk.meta.toolCallId;
772
+ const controller2 = toolCallControllers.get(toolCallId);
773
+ if (!controller2)
774
+ throw new Error("No controller found for tool call");
775
+ controller2.appendArgsTextDelta(chunk.textDelta);
776
+ }
777
+ break;
778
+ }
779
+ case "tool-call-args-text-finish": {
780
+ if (chunk.meta.type !== "tool-call") break;
781
+ const { toolCallId, toolName } = chunk.meta;
782
+ const promise = withPromiseOrValue(
783
+ () => {
784
+ const controller2 = toolCallControllers.get(toolCallId);
785
+ if (!controller2) {
786
+ console.log(
787
+ "Encountered tool call without controller, this should never happen"
788
+ );
789
+ throw new Error(
790
+ "Encountered tool call without controller, this is unexpected."
791
+ );
792
+ }
793
+ let args;
794
+ try {
795
+ args = sjson.parse(controller2.argsText);
796
+ } catch (e) {
797
+ throw new Error(
798
+ `Function parameter parsing failed. ${JSON.stringify(e.message)}`
799
+ );
800
+ }
801
+ return options.execute({
802
+ toolCallId,
803
+ toolName,
804
+ args
805
+ });
806
+ },
807
+ (c) => {
808
+ if (c === void 0) return;
809
+ controller.enqueue({
810
+ type: "result",
811
+ path: chunk.path,
812
+ artifact: c.artifact,
813
+ result: c.result,
814
+ isError: c.isError
815
+ });
816
+ },
817
+ (e) => {
818
+ controller.enqueue({
819
+ type: "result",
820
+ path: chunk.path,
821
+ result: String(e),
822
+ isError: true
823
+ });
824
+ }
825
+ );
826
+ if (promise) {
827
+ toolCallPromises.set(toolCallId, promise);
828
+ }
829
+ break;
830
+ }
831
+ case "part-finish": {
832
+ if (chunk.meta.type !== "tool-call") break;
833
+ const { toolCallId } = chunk.meta;
834
+ const toolCallPromise = toolCallPromises.get(toolCallId);
835
+ if (toolCallPromise) {
836
+ toolCallPromise.then(() => {
837
+ toolCallPromises.delete(toolCallId);
838
+ toolCallControllers.delete(toolCallId);
839
+ controller.enqueue(chunk);
840
+ });
841
+ } else {
842
+ controller.enqueue(chunk);
843
+ }
844
+ }
845
+ }
846
+ },
847
+ async flush() {
848
+ await Promise.all(toolCallPromises.values());
849
+ }
850
+ });
851
+ return readable.pipeThrough(new AssistantMetaTransformStream()).pipeThrough(transform);
852
+ });
853
+ }
854
+ };
855
+
856
+ // src/core/tool/toolResultStream.ts
857
+ var isStandardSchemaV1 = (schema) => {
858
+ return typeof schema === "object" && schema !== null && "~standard" in schema && schema["~standard"].version === 1;
859
+ };
860
+ function getToolResponse(tools, abortSignal, toolCall) {
861
+ const tool = tools?.[toolCall.toolName];
862
+ if (!tool || !tool.execute) return void 0;
863
+ const getResult = async (toolExecute) => {
864
+ let executeFn = toolExecute;
865
+ if (isStandardSchemaV1(tool.parameters)) {
866
+ let result2 = tool.parameters["~standard"].validate(toolCall.args);
867
+ if (result2 instanceof Promise) result2 = await result2;
868
+ if (result2.issues) {
869
+ executeFn = tool.experimental_onSchemaValidationError ?? (() => {
870
+ throw new Error(
871
+ `Function parameter validation failed. ${JSON.stringify(result2.issues)}`
872
+ );
873
+ });
874
+ }
875
+ }
876
+ const result = await executeFn(toolCall.args, {
877
+ toolCallId: toolCall.toolCallId,
878
+ abortSignal
879
+ });
880
+ if (result instanceof ToolResponse) return result;
881
+ return new ToolResponse({
882
+ result: result === void 0 ? "<no result>" : result
883
+ });
884
+ };
885
+ return getResult(tool.execute);
886
+ }
887
+ function getToolStreamResponse(tools, abortSignal, reader, context) {
888
+ tools?.[context.toolName]?.streamCall?.(reader, {
889
+ toolCallId: context.toolCallId,
890
+ abortSignal
891
+ });
892
+ }
893
+ async function unstable_runPendingTools(message, tools, abortSignal) {
894
+ for (const part of message.parts) {
895
+ if (part.type === "tool-call") {
896
+ const promiseOrUndefined = getToolResponse(tools, abortSignal, part);
897
+ if (promiseOrUndefined) {
898
+ const result = await promiseOrUndefined;
899
+ const updatedParts = message.parts.map((p) => {
900
+ if (p.type === "tool-call" && p.toolCallId === part.toolCallId) {
901
+ return {
902
+ ...p,
903
+ state: "result",
904
+ artifact: result.artifact,
905
+ result: result.result,
906
+ isError: result.isError
907
+ };
908
+ }
909
+ return p;
910
+ });
911
+ message = {
912
+ ...message,
913
+ parts: updatedParts,
914
+ content: updatedParts
915
+ };
916
+ }
917
+ }
918
+ }
919
+ return message;
920
+ }
921
+ function toolResultStream(tools, abortSignal) {
922
+ return new ToolExecutionStream({
923
+ execute: (toolCall) => getToolResponse(tools, abortSignal, toolCall),
924
+ streamCall: ({ reader, ...context }) => getToolStreamResponse(tools, abortSignal, reader, context)
925
+ });
926
+ }
547
927
  export {
548
928
  AssistantMessageAccumulator,
549
929
  AssistantMessageStream,
@@ -555,6 +935,8 @@ export {
555
935
  ToolExecutionStream,
556
936
  ToolResponse,
557
937
  createAssistantStream,
558
- createAssistantStreamResponse
938
+ createAssistantStreamResponse,
939
+ unstable_runPendingTools,
940
+ toolResultStream as unstable_toolResultStream
559
941
  };
560
942
  //# sourceMappingURL=index.mjs.map