assistant-stream 0.1.3 → 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 {
14
+ getPartialJsonObjectFieldState,
13
15
  parsePartialJsonObject
14
- } from "./chunk-LHNPFNMI.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
- };
16
+ } from "./chunk-PQLDKUPN.mjs";
131
17
 
132
18
  // src/core/accumulators/assistant-message-accumulator.ts
133
19
  var createInitialMessage = () => ({
@@ -521,7 +407,7 @@ var AssistantMessageStream = class _AssistantMessageStream {
521
407
  }
522
408
  };
523
409
 
524
- // src/core/ToolResponse.ts
410
+ // src/core/tool/ToolResponse.ts
525
411
  var TOOL_RESPONSE_SYMBOL = Symbol.for("aui.tool-response");
526
412
  var ToolResponse = class {
527
413
  get [TOOL_RESPONSE_SYMBOL]() {
@@ -539,6 +425,505 @@ var ToolResponse = class {
539
425
  return typeof obj === "object" && obj !== null && TOOL_RESPONSE_SYMBOL in obj;
540
426
  }
541
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
+ }
542
927
  export {
543
928
  AssistantMessageAccumulator,
544
929
  AssistantMessageStream,
@@ -550,6 +935,8 @@ export {
550
935
  ToolExecutionStream,
551
936
  ToolResponse,
552
937
  createAssistantStream,
553
- createAssistantStreamResponse
938
+ createAssistantStreamResponse,
939
+ unstable_runPendingTools,
940
+ toolResultStream as unstable_toolResultStream
554
941
  };
555
942
  //# sourceMappingURL=index.mjs.map