@mastra/client-js 1.56.0-alpha.1 → 1.56.0-alpha.11

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.
Files changed (48) hide show
  1. package/dist/client.d.ts +3 -3
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/docs/SKILL.md +2 -2
  4. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  5. package/dist/docs/references/docs-harness-agent-controller.md +11 -14
  6. package/dist/docs/references/docs-harness-schedules.md +8 -6
  7. package/dist/docs/references/docs-harness-signals.md +3 -1
  8. package/dist/docs/references/reference-client-js-agent-controller.md +15 -3
  9. package/dist/docs/references/reference-client-js-agents.md +20 -0
  10. package/dist/docs/references/reference-client-js-mastra-client.md +1 -1
  11. package/dist/docs/references/reference-client-js-observability.md +124 -9
  12. package/dist/docs/references/{reference-observability-tracing-trace-query.md → reference-observability-tracing-advanced-queries.md} +486 -158
  13. package/dist/index.cjs +913 -118
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.js +906 -111
  16. package/dist/index.js.map +1 -1
  17. package/dist/resources/agent-controller.d.ts +36 -26
  18. package/dist/resources/agent-controller.d.ts.map +1 -1
  19. package/dist/resources/agent.d.ts +54 -6
  20. package/dist/resources/agent.d.ts.map +1 -1
  21. package/dist/resources/base.d.ts.map +1 -1
  22. package/dist/resources/observability.d.ts +9 -7
  23. package/dist/resources/observability.d.ts.map +1 -1
  24. package/dist/route-types.generated.d.ts +711 -596
  25. package/dist/route-types.generated.d.ts.map +1 -1
  26. package/dist/types.d.ts +9 -9
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/utils/ai-sdk-v4/data-stream-parts.d.ts +89 -0
  29. package/dist/utils/ai-sdk-v4/data-stream-parts.d.ts.map +1 -0
  30. package/dist/utils/ai-sdk-v4/fix-json.d.ts +2 -0
  31. package/dist/utils/ai-sdk-v4/fix-json.d.ts.map +1 -0
  32. package/dist/utils/ai-sdk-v4/index.d.ts +5 -0
  33. package/dist/utils/ai-sdk-v4/index.d.ts.map +1 -0
  34. package/dist/utils/ai-sdk-v4/parse-partial-json.d.ts +6 -0
  35. package/dist/utils/ai-sdk-v4/parse-partial-json.d.ts.map +1 -0
  36. package/dist/utils/ai-sdk-v4/process-data-stream.d.ts +53 -0
  37. package/dist/utils/ai-sdk-v4/process-data-stream.d.ts.map +1 -0
  38. package/dist/utils/ai-sdk-v4/types.d.ts +93 -0
  39. package/dist/utils/ai-sdk-v4/types.d.ts.map +1 -0
  40. package/dist/utils/index.d.ts +7 -0
  41. package/dist/utils/index.d.ts.map +1 -1
  42. package/package.json +9 -11
  43. package/dist/_types/@ai-sdk_provider/dist/index.d.ts +0 -1587
  44. package/dist/_types/@ai-sdk_provider/package.json +0 -1
  45. package/dist/_types/@ai-sdk_provider-utils/dist/index.d.ts +0 -379
  46. package/dist/_types/@ai-sdk_provider-utils/package.json +0 -1
  47. package/dist/_types/@ai-sdk_ui-utils/dist/index.d.ts +0 -820
  48. package/dist/_types/@ai-sdk_ui-utils/package.json +0 -1
package/dist/index.js CHANGED
@@ -1,8 +1,7 @@
1
- import { parsePartialJson, processDataStream } from "@ai-sdk/ui-utils";
2
1
  import { v4 } from "@lukeed/uuid";
3
2
  import { getErrorFromUnknown } from "@mastra/core/error";
4
- import { standardSchemaToJSONSchema, toStandardSchema } from "@mastra/schema-compat/schema";
5
3
  import { RequestContext, RequestContext as RequestContext$1 } from "@mastra/core/request-context";
4
+ import { standardSchemaToJSONSchema, toStandardSchema } from "@mastra/schema-compat/schema";
6
5
  import { zodToJsonSchema } from "@mastra/schema-compat/zod-to-json";
7
6
  import { MastraA2AError } from "@mastra/core/a2a/client";
8
7
  import { AgentCard, CancelTaskRequest, DeleteTaskPushNotificationConfigRequest, GetTaskPushNotificationConfigRequest, GetTaskRequest, ListTaskPushNotificationConfigsRequest, ListTaskPushNotificationConfigsResponse, ListTasksRequest, ListTasksResponse, SendMessageRequest, SendMessageResponse, StreamResponse, SubscribeToTaskRequest, Task, TaskPushNotificationConfig } from "@mastra/core/a2a/v1";
@@ -60,15 +59,16 @@ function attributesToOtlp(attrs) {
60
59
  key,
61
60
  value: { boolValue: raw }
62
61
  });
63
- else if (typeof raw === "number") if (Number.isInteger(raw)) out.push({
64
- key,
65
- value: { intValue: raw }
66
- });
67
- else out.push({
68
- key,
69
- value: { doubleValue: raw }
70
- });
71
- else try {
62
+ else if (typeof raw === "number") {
63
+ if (Number.isInteger(raw)) out.push({
64
+ key,
65
+ value: { intValue: raw }
66
+ });
67
+ else out.push({
68
+ key,
69
+ value: { doubleValue: raw }
70
+ });
71
+ } else try {
72
72
  out.push({
73
73
  key,
74
74
  value: { stringValue: JSON.stringify(raw) }
@@ -377,6 +377,16 @@ function isTerminalHttpError(error) {
377
377
  return typeof status === "number" && (status >= 400 && status < 500 || status === 501);
378
378
  }
379
379
  /**
380
+ * Whether an error is the server's trace query execution timeout (504 with code
381
+ * `TRACE_QUERY_EXECUTION_TIMEOUT`). Re-sending the same query hits the same
382
+ * timeout budget, so retrying only repeats an expensive database query.
383
+ * Plain 504s from proxies or gateways do not carry this code and stay retryable.
384
+ */
385
+ function isTraceQueryTimeoutError(error) {
386
+ const { status, body } = error ?? {};
387
+ return status === 504 && body?.code === "TRACE_QUERY_EXECUTION_TIMEOUT";
388
+ }
389
+ /**
380
390
  * Whether a failed resubscribe should end a long-lived subscription instead of
381
391
  * retrying. Like {@link isTerminalHttpError}, but 408 Request Timeout and
382
392
  * 429 Too Many Requests stay retryable because they mean "try again later".
@@ -386,6 +396,571 @@ function isTerminalReconnectError(error) {
386
396
  return isTerminalHttpError(error) && status !== 408 && status !== 429;
387
397
  }
388
398
  //#endregion
399
+ //#region src/utils/ai-sdk-v4/data-stream-parts.ts
400
+ const dataStreamParts = [
401
+ {
402
+ code: "0",
403
+ name: "text",
404
+ parse: (value) => {
405
+ if (typeof value !== "string") throw new Error("\"text\" parts expect a string value.");
406
+ return {
407
+ type: "text",
408
+ value
409
+ };
410
+ }
411
+ },
412
+ {
413
+ code: "2",
414
+ name: "data",
415
+ parse: (value) => {
416
+ if (!Array.isArray(value)) throw new Error("\"data\" parts expect an array value.");
417
+ return {
418
+ type: "data",
419
+ value
420
+ };
421
+ }
422
+ },
423
+ {
424
+ code: "3",
425
+ name: "error",
426
+ parse: (value) => {
427
+ if (typeof value !== "string") throw new Error("\"error\" parts expect a string value.");
428
+ return {
429
+ type: "error",
430
+ value
431
+ };
432
+ }
433
+ },
434
+ {
435
+ code: "8",
436
+ name: "message_annotations",
437
+ parse: (value) => {
438
+ if (!Array.isArray(value)) throw new Error("\"message_annotations\" parts expect an array value.");
439
+ return {
440
+ type: "message_annotations",
441
+ value
442
+ };
443
+ }
444
+ },
445
+ {
446
+ code: "9",
447
+ name: "tool_call",
448
+ parse: (value) => {
449
+ if (value == null || typeof value !== "object" || !("toolCallId" in value) || typeof value.toolCallId !== "string" || !("toolName" in value) || typeof value.toolName !== "string" || !("args" in value) || typeof value.args !== "object") throw new Error("\"tool_call\" parts expect an object with a \"toolCallId\", \"toolName\", and \"args\" property.");
450
+ return {
451
+ type: "tool_call",
452
+ value
453
+ };
454
+ }
455
+ },
456
+ {
457
+ code: "a",
458
+ name: "tool_result",
459
+ parse: (value) => {
460
+ if (value == null || typeof value !== "object" || !("toolCallId" in value) || typeof value.toolCallId !== "string" || !("result" in value)) throw new Error("\"tool_result\" parts expect an object with a \"toolCallId\" and a \"result\" property.");
461
+ return {
462
+ type: "tool_result",
463
+ value
464
+ };
465
+ }
466
+ },
467
+ {
468
+ code: "b",
469
+ name: "tool_call_streaming_start",
470
+ parse: (value) => {
471
+ if (value == null || typeof value !== "object" || !("toolCallId" in value) || typeof value.toolCallId !== "string" || !("toolName" in value) || typeof value.toolName !== "string") throw new Error("\"tool_call_streaming_start\" parts expect an object with a \"toolCallId\" and \"toolName\" property.");
472
+ return {
473
+ type: "tool_call_streaming_start",
474
+ value
475
+ };
476
+ }
477
+ },
478
+ {
479
+ code: "c",
480
+ name: "tool_call_delta",
481
+ parse: (value) => {
482
+ if (value == null || typeof value !== "object" || !("toolCallId" in value) || typeof value.toolCallId !== "string" || !("argsTextDelta" in value) || typeof value.argsTextDelta !== "string") throw new Error("\"tool_call_delta\" parts expect an object with a \"toolCallId\" and \"argsTextDelta\" property.");
483
+ return {
484
+ type: "tool_call_delta",
485
+ value
486
+ };
487
+ }
488
+ },
489
+ {
490
+ code: "d",
491
+ name: "finish_message",
492
+ parse: (value) => {
493
+ if (value == null || typeof value !== "object" || !("finishReason" in value) || typeof value.finishReason !== "string") throw new Error("\"finish_message\" parts expect an object with a \"finishReason\" property.");
494
+ const result = { finishReason: value.finishReason };
495
+ if ("usage" in value && value.usage != null && typeof value.usage === "object" && "promptTokens" in value.usage && "completionTokens" in value.usage) result.usage = {
496
+ promptTokens: typeof value.usage.promptTokens === "number" ? value.usage.promptTokens : NaN,
497
+ completionTokens: typeof value.usage.completionTokens === "number" ? value.usage.completionTokens : NaN
498
+ };
499
+ return {
500
+ type: "finish_message",
501
+ value: result
502
+ };
503
+ }
504
+ },
505
+ {
506
+ code: "e",
507
+ name: "finish_step",
508
+ parse: (value) => {
509
+ if (value == null || typeof value !== "object" || !("finishReason" in value) || typeof value.finishReason !== "string") throw new Error("\"finish_step\" parts expect an object with a \"finishReason\" property.");
510
+ const result = {
511
+ finishReason: value.finishReason,
512
+ isContinued: false
513
+ };
514
+ if ("usage" in value && value.usage != null && typeof value.usage === "object" && "promptTokens" in value.usage && "completionTokens" in value.usage) result.usage = {
515
+ promptTokens: typeof value.usage.promptTokens === "number" ? value.usage.promptTokens : NaN,
516
+ completionTokens: typeof value.usage.completionTokens === "number" ? value.usage.completionTokens : NaN
517
+ };
518
+ if ("isContinued" in value && typeof value.isContinued === "boolean") result.isContinued = value.isContinued;
519
+ return {
520
+ type: "finish_step",
521
+ value: result
522
+ };
523
+ }
524
+ },
525
+ {
526
+ code: "f",
527
+ name: "start_step",
528
+ parse: (value) => {
529
+ if (value == null || typeof value !== "object" || !("messageId" in value) || typeof value.messageId !== "string") throw new Error("\"start_step\" parts expect an object with an \"id\" property.");
530
+ return {
531
+ type: "start_step",
532
+ value: { messageId: value.messageId }
533
+ };
534
+ }
535
+ },
536
+ {
537
+ code: "g",
538
+ name: "reasoning",
539
+ parse: (value) => {
540
+ if (typeof value !== "string") throw new Error("\"reasoning\" parts expect a string value.");
541
+ return {
542
+ type: "reasoning",
543
+ value
544
+ };
545
+ }
546
+ },
547
+ {
548
+ code: "h",
549
+ name: "source",
550
+ parse: (value) => {
551
+ if (value == null || typeof value !== "object") throw new Error("\"source\" parts expect a Source object.");
552
+ return {
553
+ type: "source",
554
+ value
555
+ };
556
+ }
557
+ },
558
+ {
559
+ code: "i",
560
+ name: "redacted_reasoning",
561
+ parse: (value) => {
562
+ if (value == null || typeof value !== "object" || !("data" in value) || typeof value.data !== "string") throw new Error("\"redacted_reasoning\" parts expect an object with a \"data\" property.");
563
+ return {
564
+ type: "redacted_reasoning",
565
+ value: { data: value.data }
566
+ };
567
+ }
568
+ },
569
+ {
570
+ code: "j",
571
+ name: "reasoning_signature",
572
+ parse: (value) => {
573
+ if (value == null || typeof value !== "object" || !("signature" in value) || typeof value.signature !== "string") throw new Error("\"reasoning_signature\" parts expect an object with a \"signature\" property.");
574
+ return {
575
+ type: "reasoning_signature",
576
+ value: { signature: value.signature }
577
+ };
578
+ }
579
+ },
580
+ {
581
+ code: "k",
582
+ name: "file",
583
+ parse: (value) => {
584
+ if (value == null || typeof value !== "object" || !("data" in value) || typeof value.data !== "string" || !("mimeType" in value) || typeof value.mimeType !== "string") throw new Error("\"file\" parts expect an object with a \"data\" and \"mimeType\" property.");
585
+ return {
586
+ type: "file",
587
+ value
588
+ };
589
+ }
590
+ }
591
+ ];
592
+ const dataStreamPartsByCode = Object.fromEntries(dataStreamParts.map((part) => [part.code, part]));
593
+ Object.fromEntries(dataStreamParts.map((part) => [part.name, part.code]));
594
+ const validCodes = dataStreamParts.map((part) => part.code);
595
+ /**
596
+ Parses a stream part from a string.
597
+
598
+ @param line The string to parse.
599
+ @returns The parsed stream part.
600
+ @throws An error if the string cannot be parsed.
601
+ */
602
+ const parseDataStreamPart = (line) => {
603
+ const firstSeparatorIndex = line.indexOf(":");
604
+ if (firstSeparatorIndex === -1) throw new Error("Failed to parse stream string. No separator found.");
605
+ const prefix = line.slice(0, firstSeparatorIndex);
606
+ if (!validCodes.includes(prefix)) throw new Error(`Failed to parse stream string. Invalid code ${prefix}.`);
607
+ const code = prefix;
608
+ const textValue = line.slice(firstSeparatorIndex + 1);
609
+ const jsonValue = JSON.parse(textValue);
610
+ return dataStreamPartsByCode[code].parse(jsonValue);
611
+ };
612
+ //#endregion
613
+ //#region src/utils/ai-sdk-v4/fix-json.ts
614
+ function fixJson(input) {
615
+ const stack = ["ROOT"];
616
+ let lastValidIndex = -1;
617
+ let literalStart = null;
618
+ function processValueStart(char, i, swapState) {
619
+ switch (char) {
620
+ case "\"":
621
+ lastValidIndex = i;
622
+ stack.pop();
623
+ stack.push(swapState);
624
+ stack.push("INSIDE_STRING");
625
+ break;
626
+ case "f":
627
+ case "t":
628
+ case "n":
629
+ lastValidIndex = i;
630
+ literalStart = i;
631
+ stack.pop();
632
+ stack.push(swapState);
633
+ stack.push("INSIDE_LITERAL");
634
+ break;
635
+ case "-":
636
+ stack.pop();
637
+ stack.push(swapState);
638
+ stack.push("INSIDE_NUMBER");
639
+ break;
640
+ case "0":
641
+ case "1":
642
+ case "2":
643
+ case "3":
644
+ case "4":
645
+ case "5":
646
+ case "6":
647
+ case "7":
648
+ case "8":
649
+ case "9":
650
+ lastValidIndex = i;
651
+ stack.pop();
652
+ stack.push(swapState);
653
+ stack.push("INSIDE_NUMBER");
654
+ break;
655
+ case "{":
656
+ lastValidIndex = i;
657
+ stack.pop();
658
+ stack.push(swapState);
659
+ stack.push("INSIDE_OBJECT_START");
660
+ break;
661
+ case "[":
662
+ lastValidIndex = i;
663
+ stack.pop();
664
+ stack.push(swapState);
665
+ stack.push("INSIDE_ARRAY_START");
666
+ }
667
+ }
668
+ function processAfterObjectValue(char, i) {
669
+ switch (char) {
670
+ case ",":
671
+ stack.pop();
672
+ stack.push("INSIDE_OBJECT_AFTER_COMMA");
673
+ break;
674
+ case "}":
675
+ lastValidIndex = i;
676
+ stack.pop();
677
+ }
678
+ }
679
+ function processAfterArrayValue(char, i) {
680
+ switch (char) {
681
+ case ",":
682
+ stack.pop();
683
+ stack.push("INSIDE_ARRAY_AFTER_COMMA");
684
+ break;
685
+ case "]":
686
+ lastValidIndex = i;
687
+ stack.pop();
688
+ }
689
+ }
690
+ for (let i = 0; i < input.length; i++) {
691
+ const char = input[i];
692
+ switch (stack[stack.length - 1]) {
693
+ case "ROOT":
694
+ processValueStart(char, i, "FINISH");
695
+ break;
696
+ case "INSIDE_OBJECT_START":
697
+ switch (char) {
698
+ case "\"":
699
+ stack.pop();
700
+ stack.push("INSIDE_OBJECT_KEY");
701
+ break;
702
+ case "}":
703
+ lastValidIndex = i;
704
+ stack.pop();
705
+ }
706
+ break;
707
+ case "INSIDE_OBJECT_AFTER_COMMA":
708
+ switch (char) {
709
+ case "\"":
710
+ stack.pop();
711
+ stack.push("INSIDE_OBJECT_KEY");
712
+ }
713
+ break;
714
+ case "INSIDE_OBJECT_KEY":
715
+ switch (char) {
716
+ case "\"":
717
+ stack.pop();
718
+ stack.push("INSIDE_OBJECT_AFTER_KEY");
719
+ }
720
+ break;
721
+ case "INSIDE_OBJECT_AFTER_KEY":
722
+ switch (char) {
723
+ case ":":
724
+ stack.pop();
725
+ stack.push("INSIDE_OBJECT_BEFORE_VALUE");
726
+ }
727
+ break;
728
+ case "INSIDE_OBJECT_BEFORE_VALUE":
729
+ processValueStart(char, i, "INSIDE_OBJECT_AFTER_VALUE");
730
+ break;
731
+ case "INSIDE_OBJECT_AFTER_VALUE":
732
+ processAfterObjectValue(char, i);
733
+ break;
734
+ case "INSIDE_STRING":
735
+ switch (char) {
736
+ case "\"":
737
+ stack.pop();
738
+ lastValidIndex = i;
739
+ break;
740
+ case "\\":
741
+ stack.push("INSIDE_STRING_ESCAPE");
742
+ break;
743
+ default: lastValidIndex = i;
744
+ }
745
+ break;
746
+ case "INSIDE_ARRAY_START":
747
+ switch (char) {
748
+ case "]":
749
+ lastValidIndex = i;
750
+ stack.pop();
751
+ break;
752
+ default:
753
+ lastValidIndex = i;
754
+ processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
755
+ }
756
+ break;
757
+ case "INSIDE_ARRAY_AFTER_VALUE":
758
+ switch (char) {
759
+ case ",":
760
+ stack.pop();
761
+ stack.push("INSIDE_ARRAY_AFTER_COMMA");
762
+ break;
763
+ case "]":
764
+ lastValidIndex = i;
765
+ stack.pop();
766
+ break;
767
+ default: lastValidIndex = i;
768
+ }
769
+ break;
770
+ case "INSIDE_ARRAY_AFTER_COMMA":
771
+ processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
772
+ break;
773
+ case "INSIDE_STRING_ESCAPE":
774
+ stack.pop();
775
+ lastValidIndex = i;
776
+ break;
777
+ case "INSIDE_NUMBER":
778
+ switch (char) {
779
+ case "0":
780
+ case "1":
781
+ case "2":
782
+ case "3":
783
+ case "4":
784
+ case "5":
785
+ case "6":
786
+ case "7":
787
+ case "8":
788
+ case "9":
789
+ lastValidIndex = i;
790
+ break;
791
+ case "e":
792
+ case "E":
793
+ case "-":
794
+ case ".": break;
795
+ case ",":
796
+ stack.pop();
797
+ if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") processAfterArrayValue(char, i);
798
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") processAfterObjectValue(char, i);
799
+ break;
800
+ case "}":
801
+ stack.pop();
802
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") processAfterObjectValue(char, i);
803
+ break;
804
+ case "]":
805
+ stack.pop();
806
+ if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") processAfterArrayValue(char, i);
807
+ break;
808
+ default: stack.pop();
809
+ }
810
+ break;
811
+ case "INSIDE_LITERAL": {
812
+ const partialLiteral = input.substring(literalStart, i + 1);
813
+ if (!"false".startsWith(partialLiteral) && !"true".startsWith(partialLiteral) && !"null".startsWith(partialLiteral)) {
814
+ stack.pop();
815
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") processAfterObjectValue(char, i);
816
+ else if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") processAfterArrayValue(char, i);
817
+ } else lastValidIndex = i;
818
+ break;
819
+ }
820
+ }
821
+ }
822
+ let result = input.slice(0, lastValidIndex + 1);
823
+ for (let i = stack.length - 1; i >= 0; i--) switch (stack[i]) {
824
+ case "INSIDE_STRING":
825
+ result += "\"";
826
+ break;
827
+ case "INSIDE_OBJECT_KEY":
828
+ case "INSIDE_OBJECT_AFTER_KEY":
829
+ case "INSIDE_OBJECT_AFTER_COMMA":
830
+ case "INSIDE_OBJECT_START":
831
+ case "INSIDE_OBJECT_BEFORE_VALUE":
832
+ case "INSIDE_OBJECT_AFTER_VALUE":
833
+ result += "}";
834
+ break;
835
+ case "INSIDE_ARRAY_START":
836
+ case "INSIDE_ARRAY_AFTER_COMMA":
837
+ case "INSIDE_ARRAY_AFTER_VALUE":
838
+ result += "]";
839
+ break;
840
+ case "INSIDE_LITERAL": {
841
+ const partialLiteral = input.substring(literalStart, input.length);
842
+ if ("true".startsWith(partialLiteral)) result += "true".slice(partialLiteral.length);
843
+ else if ("false".startsWith(partialLiteral)) result += "false".slice(partialLiteral.length);
844
+ else if ("null".startsWith(partialLiteral)) result += "null".slice(partialLiteral.length);
845
+ }
846
+ }
847
+ return result;
848
+ }
849
+ //#endregion
850
+ //#region src/utils/ai-sdk-v4/parse-partial-json.ts
851
+ function tryParse(text) {
852
+ try {
853
+ return {
854
+ success: true,
855
+ value: JSON.parse(text)
856
+ };
857
+ } catch {
858
+ return { success: false };
859
+ }
860
+ }
861
+ function parsePartialJson(jsonText) {
862
+ if (jsonText === void 0) return {
863
+ value: void 0,
864
+ state: "undefined-input"
865
+ };
866
+ let result = tryParse(jsonText);
867
+ if (result.success) return {
868
+ value: result.value,
869
+ state: "successful-parse"
870
+ };
871
+ result = tryParse(fixJson(jsonText));
872
+ if (result.success) return {
873
+ value: result.value,
874
+ state: "repaired-parse"
875
+ };
876
+ return {
877
+ value: void 0,
878
+ state: "failed-parse"
879
+ };
880
+ }
881
+ //#endregion
882
+ //#region src/utils/ai-sdk-v4/process-data-stream.ts
883
+ const NEWLINE = "\n".charCodeAt(0);
884
+ function concatChunks(chunks, totalLength) {
885
+ const concatenatedChunks = new Uint8Array(totalLength);
886
+ let offset = 0;
887
+ for (const chunk of chunks) {
888
+ concatenatedChunks.set(chunk, offset);
889
+ offset += chunk.length;
890
+ }
891
+ chunks.length = 0;
892
+ return concatenatedChunks;
893
+ }
894
+ async function processDataStream({ stream, onTextPart, onReasoningPart, onReasoningSignaturePart, onRedactedReasoningPart, onSourcePart, onFilePart, onDataPart, onErrorPart, onToolCallStreamingStartPart, onToolCallDeltaPart, onToolCallPart, onToolResultPart, onMessageAnnotationsPart, onFinishMessagePart, onFinishStepPart, onStartStepPart }) {
895
+ const reader = stream.getReader();
896
+ const decoder = new TextDecoder();
897
+ const chunks = [];
898
+ let totalLength = 0;
899
+ while (true) {
900
+ const { value } = await reader.read();
901
+ if (value) {
902
+ chunks.push(value);
903
+ totalLength += value.length;
904
+ if (value[value.length - 1] !== NEWLINE) continue;
905
+ }
906
+ if (chunks.length === 0) break;
907
+ const concatenatedChunks = concatChunks(chunks, totalLength);
908
+ totalLength = 0;
909
+ const streamParts = decoder.decode(concatenatedChunks, { stream: true }).split("\n").filter((line) => line !== "").map(parseDataStreamPart);
910
+ for (const { type, value } of streamParts) switch (type) {
911
+ case "text":
912
+ await onTextPart?.(value);
913
+ break;
914
+ case "reasoning":
915
+ await onReasoningPart?.(value);
916
+ break;
917
+ case "reasoning_signature":
918
+ await onReasoningSignaturePart?.(value);
919
+ break;
920
+ case "redacted_reasoning":
921
+ await onRedactedReasoningPart?.(value);
922
+ break;
923
+ case "file":
924
+ await onFilePart?.(value);
925
+ break;
926
+ case "source":
927
+ await onSourcePart?.(value);
928
+ break;
929
+ case "data":
930
+ await onDataPart?.(value);
931
+ break;
932
+ case "error":
933
+ await onErrorPart?.(value);
934
+ break;
935
+ case "message_annotations":
936
+ await onMessageAnnotationsPart?.(value);
937
+ break;
938
+ case "tool_call_streaming_start":
939
+ await onToolCallStreamingStartPart?.(value);
940
+ break;
941
+ case "tool_call_delta":
942
+ await onToolCallDeltaPart?.(value);
943
+ break;
944
+ case "tool_call":
945
+ await onToolCallPart?.(value);
946
+ break;
947
+ case "tool_result":
948
+ await onToolResultPart?.(value);
949
+ break;
950
+ case "finish_message":
951
+ await onFinishMessagePart?.(value);
952
+ break;
953
+ case "finish_step":
954
+ await onFinishStepPart?.(value);
955
+ break;
956
+ case "start_step":
957
+ await onStartStepPart?.(value);
958
+ break;
959
+ default: throw new Error(`Unknown stream part type: ${type}`);
960
+ }
961
+ }
962
+ }
963
+ //#endregion
389
964
  //#region src/utils/client-tool-model-output.ts
390
965
  /**
391
966
  * Normalize modelOutput from toModelOutput() to the AI SDK V2 tool result
@@ -618,7 +1193,7 @@ var BaseResource = class {
618
1193
  } catch (error) {
619
1194
  lastError = error;
620
1195
  if (signal?.aborted || error?.name === "AbortError") throw error;
621
- if (isTerminalHttpError(error)) throw error;
1196
+ if (isTerminalHttpError(error) || isTraceQueryTimeoutError(error)) throw error;
622
1197
  if (attempt === retries) break;
623
1198
  await new Promise((resolve, reject) => {
624
1199
  const timer = setTimeout(() => {
@@ -639,8 +1214,16 @@ var BaseResource = class {
639
1214
  };
640
1215
  //#endregion
641
1216
  //#region src/resources/agent.ts
642
- const SIGNAL_RUNTIME_OPTIONS_TTL_MS = 300 * 1e3;
1217
+ const SIGNAL_RUNTIME_OPTIONS_TTL_MS = 3e5;
643
1218
  const signalRuntimeOptionsByRunId = /* @__PURE__ */ new Map();
1219
+ /**
1220
+ * Client tools a resume request can execute, keyed by run. The stream that stayed open from
1221
+ * before the suspension must not run those tools again, but it must run any resumed client tool
1222
+ * the resume request cannot execute (a server-side approve sends no client tools). Held until the
1223
+ * last stream of the run closes, which is after the resume request returns.
1224
+ */
1225
+ const resumingClientToolNamesByRunKey = /* @__PURE__ */ new Map();
1226
+ const openStreamCountByRunKey = /* @__PURE__ */ new Map();
644
1227
  const latestSignalRuntimeOptionsByThread = /* @__PURE__ */ new Map();
645
1228
  const createSignalRuntimeOptionsEntry = (store, key, streamOptions) => {
646
1229
  const timeout = setTimeout(() => store.delete(key), SIGNAL_RUNTIME_OPTIONS_TTL_MS);
@@ -833,6 +1416,49 @@ var Agent = class extends BaseResource {
833
1416
  getSignalRuntimeRunKey(runId) {
834
1417
  return `${this.options.baseUrl}|${this.apiPrefix}|${this.agentId}|${runId}`;
835
1418
  }
1419
+ /**
1420
+ * Records that `runId` is being resumed by a request that can execute these client tools, so the
1421
+ * stream that is still open from before the suspension skips them. Released when the last stream
1422
+ * of the run closes, which is after this request returns.
1423
+ */
1424
+ holdResumingClientTools(runId, clientTools) {
1425
+ const names = Object.entries(clientTools ?? {}).filter(([, tool]) => typeof tool.execute === "function").map(([name]) => name);
1426
+ if (names.length === 0) return () => {};
1427
+ const key = this.getSignalRuntimeRunKey(runId);
1428
+ const held = resumingClientToolNamesByRunKey.get(key) ?? /* @__PURE__ */ new Map();
1429
+ for (const name of names) held.set(name, (held.get(name) ?? 0) + 1);
1430
+ resumingClientToolNamesByRunKey.set(key, held);
1431
+ let released = false;
1432
+ return ({ force = false } = {}) => {
1433
+ if (released || !force && openStreamCountByRunKey.has(key)) return;
1434
+ released = true;
1435
+ const current = resumingClientToolNamesByRunKey.get(key);
1436
+ if (!current) return;
1437
+ for (const name of names) {
1438
+ const count = (current.get(name) ?? 1) - 1;
1439
+ if (count > 0) current.set(name, count);
1440
+ else current.delete(name);
1441
+ }
1442
+ if (current.size === 0) resumingClientToolNamesByRunKey.delete(key);
1443
+ };
1444
+ }
1445
+ /** Drops the held tool names when the last stream of the run closes. */
1446
+ trackOpenStream(runId) {
1447
+ const key = this.getSignalRuntimeRunKey(runId);
1448
+ openStreamCountByRunKey.set(key, (openStreamCountByRunKey.get(key) ?? 0) + 1);
1449
+ let released = false;
1450
+ return () => {
1451
+ if (released) return;
1452
+ released = true;
1453
+ const remaining = (openStreamCountByRunKey.get(key) ?? 1) - 1;
1454
+ if (remaining > 0) {
1455
+ openStreamCountByRunKey.set(key, remaining);
1456
+ return;
1457
+ }
1458
+ openStreamCountByRunKey.delete(key);
1459
+ resumingClientToolNamesByRunKey.delete(key);
1460
+ };
1461
+ }
836
1462
  getSignalRuntimeThreadKey({ resourceId, threadId }) {
837
1463
  if (!threadId) return void 0;
838
1464
  return `${this.options.baseUrl}|${this.apiPrefix}|${this.agentId}|${resourceId ?? ""}|${threadId}`;
@@ -1970,7 +2596,6 @@ var Agent = class extends BaseResource {
1970
2596
  case "finish":
1971
2597
  finishReason = chunk.payload?.stepResult?.reason ?? finishReason;
1972
2598
  if (chunk.payload?.usage != null) usage = chunk.payload.usage;
1973
- break;
1974
2599
  }
1975
2600
  }
1976
2601
  });
@@ -2034,6 +2659,10 @@ var Agent = class extends BaseResource {
2034
2659
  try {
2035
2660
  let messages = [];
2036
2661
  let streamRunId = processedParams.runId;
2662
+ let finishedHistory;
2663
+ let suspended = false;
2664
+ const resumedToolCallIds = /* @__PURE__ */ new Set();
2665
+ const releaseOpenStream = streamRunId ? this.trackOpenStream(streamRunId) : () => {};
2037
2666
  const [streamForController, streamForProcessing] = response.body.tee();
2038
2667
  const decoder = new TextDecoder();
2039
2668
  let pendingText = "";
@@ -2041,6 +2670,13 @@ var Agent = class extends BaseResource {
2041
2670
  pendingText += text;
2042
2671
  const lines = pendingText.split("\n\n");
2043
2672
  pendingText = isFinal ? "" : lines.pop() ?? "";
2673
+ for (const line of lines) {
2674
+ if (!line.startsWith("data: ") || !line.includes("\"type\":\"finish\"")) continue;
2675
+ try {
2676
+ const all = JSON.parse(line.slice(6))?.payload?.messages?.all;
2677
+ if (Array.isArray(all)) finishedHistory = all;
2678
+ } catch {}
2679
+ }
2044
2680
  const readableLines = lines.filter((line) => line.trim() !== "[DONE]" && line.trim() !== "data: [DONE]").join("\n\n");
2045
2681
  if (readableLines) safeEnqueue(new TextEncoder().encode(`${readableLines}\n\n`));
2046
2682
  };
@@ -2095,6 +2731,9 @@ var Agent = class extends BaseResource {
2095
2731
  });
2096
2732
  }
2097
2733
  const executableToolCalls = [...toolInvocationsById.values()].filter((toolCall) => {
2734
+ if (resumedToolCallIds.has(toolCall.toolCallId)) {
2735
+ if ((streamRunId ? resumingClientToolNamesByRunKey.get(this.getSignalRuntimeRunKey(streamRunId)) : void 0)?.has(toolCall.toolName)) return false;
2736
+ }
2098
2737
  const clientTool = processedParams.clientTools?.[toolCall.toolName];
2099
2738
  return Boolean(clientTool?.execute);
2100
2739
  });
@@ -2194,12 +2833,12 @@ var Agent = class extends BaseResource {
2194
2833
  role: "tool",
2195
2834
  content: toolResultContents
2196
2835
  };
2197
- const updatedMessages = threadId ? [toolResultMessage] : [
2836
+ const updatedMessages = threadId ? [toolResultMessage] : (route === "resume-stream" || route === "approve-tool-call" || route === "decline-tool-call") && finishedHistory ? [...finishedHistory, toolResultMessage] : [
2198
2837
  ...Array.isArray(processedParams.messages) ? processedParams.messages : [],
2199
2838
  ...messages,
2200
2839
  toolResultMessage
2201
2840
  ];
2202
- const recursionRoute = route === "resume-stream" ? "stream" : route === "resume-stream-until-idle" ? "stream-until-idle" : route;
2841
+ const recursionRoute = route === "resume-stream" || route === "approve-tool-call" || route === "decline-tool-call" ? "stream" : route === "resume-stream-until-idle" ? "stream-until-idle" : route;
2203
2842
  if (isAborted()) return;
2204
2843
  try {
2205
2844
  await this.processStreamResponse({
@@ -2221,6 +2860,12 @@ var Agent = class extends BaseResource {
2221
2860
  },
2222
2861
  onStreamChunk: (chunk) => {
2223
2862
  if (!streamRunId && typeof chunk.runId === "string") streamRunId = chunk.runId;
2863
+ if (chunk.type === "tool-call-approval" || chunk.type === "tool-call-suspended") suspended = true;
2864
+ else if (suspended && chunk.type === "tool-call" && typeof chunk.payload?.toolCallId === "string") {
2865
+ const toolName = chunk.payload.toolName;
2866
+ const held = streamRunId ? resumingClientToolNamesByRunKey.get(this.getSignalRuntimeRunKey(streamRunId)) : void 0;
2867
+ if (typeof toolName === "string" && held?.has(toolName)) resumedToolCallIds.add(chunk.payload.toolCallId);
2868
+ }
2224
2869
  },
2225
2870
  lastMessage: void 0
2226
2871
  }).catch(async (error) => {
@@ -2231,6 +2876,7 @@ var Agent = class extends BaseResource {
2231
2876
  safeClose();
2232
2877
  }).finally(() => {
2233
2878
  signal?.removeEventListener("abort", onAbort);
2879
+ releaseOpenStream();
2234
2880
  });
2235
2881
  } catch (error) {
2236
2882
  if (!isAbortError(error)) console.error("Error processing stream response:", error);
@@ -2398,12 +3044,18 @@ var Agent = class extends BaseResource {
2398
3044
  }
2399
3045
  async approveToolCall(params) {
2400
3046
  const { requestContext, ...rest } = params;
3047
+ const executableClientTools = params.clientToolsResolver?.() ?? params.clientTools;
3048
+ const releaseHold = this.holdResumingClientTools(rest.runId, executableClientTools);
2401
3049
  const processedParams = {
2402
3050
  ...rest,
2403
- requestContext: parseClientRequestContext(requestContext)
3051
+ requestContext: parseClientRequestContext(requestContext),
3052
+ clientTools: processClientTools(executableClientTools)
2404
3053
  };
2405
3054
  const { readable, controller: readableController, signal } = this.createCancellableStream(params.abortSignal);
2406
- const response = await this.processStreamResponse(processedParams, readableController, "approve-tool-call", signal);
3055
+ const response = await this.processStreamResponse(processedParams, readableController, "approve-tool-call", signal).catch((error) => {
3056
+ releaseHold({ force: true });
3057
+ throw error;
3058
+ });
2407
3059
  const streamResponse = new Response(readable, {
2408
3060
  status: response.status,
2409
3061
  statusText: response.statusText,
@@ -2429,12 +3081,18 @@ var Agent = class extends BaseResource {
2429
3081
  }
2430
3082
  async declineToolCall(params) {
2431
3083
  const { requestContext, ...rest } = params;
3084
+ const executableClientTools = params.clientToolsResolver?.() ?? params.clientTools;
3085
+ const releaseHold = this.holdResumingClientTools(rest.runId, executableClientTools);
2432
3086
  const processedParams = {
2433
3087
  ...rest,
2434
- requestContext: parseClientRequestContext(requestContext)
3088
+ requestContext: parseClientRequestContext(requestContext),
3089
+ clientTools: processClientTools(executableClientTools)
2435
3090
  };
2436
3091
  const { readable, controller: readableController, signal } = this.createCancellableStream(params.abortSignal);
2437
- const response = await this.processStreamResponse(processedParams, readableController, "decline-tool-call", signal);
3092
+ const response = await this.processStreamResponse(processedParams, readableController, "decline-tool-call", signal).catch((error) => {
3093
+ releaseHold({ force: true });
3094
+ throw error;
3095
+ });
2438
3096
  const streamResponse = new Response(readable, {
2439
3097
  status: response.status,
2440
3098
  statusText: response.statusText,
@@ -2494,18 +3152,23 @@ var Agent = class extends BaseResource {
2494
3152
  * Used to continue execution after a suspension point (e.g., workflow suspend within an agent).
2495
3153
  */
2496
3154
  async resumeStream(resumeData, options) {
3155
+ const executableClientTools = options.clientToolsResolver?.() ?? options.clientTools;
3156
+ const releaseHold = this.holdResumingClientTools(options.runId, executableClientTools);
2497
3157
  const processedParams = {
2498
3158
  ...options,
2499
3159
  resumeData,
2500
3160
  requestContext: parseClientRequestContext(options.requestContext),
2501
- clientTools: processClientTools(options.clientToolsResolver?.() ?? options.clientTools),
3161
+ clientTools: processClientTools(executableClientTools),
2502
3162
  structuredOutput: options.structuredOutput ? {
2503
3163
  ...options.structuredOutput,
2504
3164
  schema: standardSchemaToJSONSchema(toStandardSchema(options.structuredOutput.schema))
2505
3165
  } : void 0
2506
3166
  };
2507
3167
  const { readable, controller: readableController, signal } = this.createCancellableStream(options.abortSignal);
2508
- const response = await this.processStreamResponse(processedParams, readableController, "resume-stream", signal);
3168
+ const response = await this.processStreamResponse(processedParams, readableController, "resume-stream", signal).catch((error) => {
3169
+ releaseHold({ force: true });
3170
+ throw error;
3171
+ });
2509
3172
  const streamResponse = new Response(readable, {
2510
3173
  status: response.status,
2511
3174
  statusText: response.statusText,
@@ -2558,18 +3221,23 @@ var Agent = class extends BaseResource {
2558
3221
  * Used to continue execution after a suspension point (e.g., workflow suspend within an agent).
2559
3222
  */
2560
3223
  async resumeStreamUntilIdle(resumeData, options) {
3224
+ const executableClientTools = options.clientToolsResolver?.() ?? options.clientTools;
3225
+ const releaseHold = this.holdResumingClientTools(options.runId, executableClientTools);
2561
3226
  const processedParams = {
2562
3227
  ...options,
2563
3228
  resumeData,
2564
3229
  requestContext: parseClientRequestContext(options.requestContext),
2565
- clientTools: processClientTools(options.clientToolsResolver?.() ?? options.clientTools),
3230
+ clientTools: processClientTools(executableClientTools),
2566
3231
  structuredOutput: options.structuredOutput ? {
2567
3232
  ...options.structuredOutput,
2568
3233
  schema: standardSchemaToJSONSchema(toStandardSchema(options.structuredOutput.schema))
2569
3234
  } : void 0
2570
3235
  };
2571
3236
  const { readable, controller: readableController, signal } = this.createCancellableStream(options.abortSignal);
2572
- const response = await this.processStreamResponse(processedParams, readableController, "resume-stream-until-idle", signal);
3237
+ const response = await this.processStreamResponse(processedParams, readableController, "resume-stream-until-idle", signal).catch((error) => {
3238
+ releaseHold({ force: true });
3239
+ throw error;
3240
+ });
2573
3241
  const streamResponse = new Response(readable, {
2574
3242
  status: response.status,
2575
3243
  statusText: response.statusText,
@@ -2588,27 +3256,93 @@ var Agent = class extends BaseResource {
2588
3256
  * Used when `requireToolApproval` is enabled with generate() to allow the agent to proceed.
2589
3257
  */
2590
3258
  async approveToolCallGenerate(params) {
2591
- const { requestContext, ...rest } = params;
2592
- return this.request(`/agents/${this.agentId}/approve-tool-call-generate`, {
2593
- method: "POST",
2594
- body: {
2595
- ...rest,
2596
- requestContext: parseClientRequestContext(requestContext)
2597
- }
2598
- });
3259
+ const { requestContext, clientTools, clientToolsResolver, memory, ...rest } = params;
3260
+ const executableClientTools = clientToolsResolver?.() ?? clientTools;
3261
+ const releaseHold = this.holdResumingClientTools(rest.runId, executableClientTools);
3262
+ let response;
3263
+ try {
3264
+ response = await this.request(`/agents/${this.agentId}/approve-tool-call-generate`, {
3265
+ method: "POST",
3266
+ body: {
3267
+ ...rest,
3268
+ requestContext: parseClientRequestContext(requestContext),
3269
+ clientTools: processClientTools(executableClientTools)
3270
+ }
3271
+ });
3272
+ } catch (error) {
3273
+ releaseHold({ force: true });
3274
+ throw error;
3275
+ }
3276
+ try {
3277
+ return await this.continueResumedGenerate(response, {
3278
+ requestContext,
3279
+ clientTools: executableClientTools,
3280
+ clientToolsResolver,
3281
+ memory
3282
+ });
3283
+ } finally {
3284
+ releaseHold();
3285
+ }
2599
3286
  }
2600
3287
  /**
2601
3288
  * Declines a pending tool call and returns the complete response (non-streaming).
2602
3289
  * Used when `requireToolApproval` is enabled with generate() to prevent tool execution.
2603
3290
  */
2604
3291
  async declineToolCallGenerate(params) {
2605
- const { requestContext, ...rest } = params;
2606
- return this.request(`/agents/${this.agentId}/decline-tool-call-generate`, {
2607
- method: "POST",
2608
- body: {
2609
- ...rest,
2610
- requestContext: parseClientRequestContext(requestContext)
2611
- }
3292
+ const { requestContext, clientTools, clientToolsResolver, memory, ...rest } = params;
3293
+ const executableClientTools = clientToolsResolver?.() ?? clientTools;
3294
+ const releaseHold = this.holdResumingClientTools(rest.runId, executableClientTools);
3295
+ let response;
3296
+ try {
3297
+ response = await this.request(`/agents/${this.agentId}/decline-tool-call-generate`, {
3298
+ method: "POST",
3299
+ body: {
3300
+ ...rest,
3301
+ requestContext: parseClientRequestContext(requestContext),
3302
+ clientTools: processClientTools(executableClientTools)
3303
+ }
3304
+ });
3305
+ } catch (error) {
3306
+ releaseHold({ force: true });
3307
+ throw error;
3308
+ }
3309
+ try {
3310
+ return await this.continueResumedGenerate(response, {
3311
+ requestContext,
3312
+ clientTools: executableClientTools,
3313
+ clientToolsResolver,
3314
+ memory
3315
+ });
3316
+ } finally {
3317
+ releaseHold();
3318
+ }
3319
+ }
3320
+ /**
3321
+ * Runs executable client tools the model called after an approval decision and continues on
3322
+ * /generate, like generate() does. With memory the continuation sends only the new messages to the
3323
+ * thread. Without memory it re-sends the conversation up to the last user turn, because the resume
3324
+ * routes keep the earlier history server-side and drop it once the run finishes.
3325
+ */
3326
+ async continueResumedGenerate(response, { requestContext, clientTools, clientToolsResolver, memory }) {
3327
+ if (response.finishReason !== "tool-calls") return response;
3328
+ const context = requestContext === void 0 || requestContext instanceof RequestContext$1 ? requestContext : new RequestContext$1(Object.entries(requestContext));
3329
+ const threadId = typeof memory?.thread === "string" ? memory.thread : memory?.thread?.id;
3330
+ const history = response.messages ?? [];
3331
+ const priorTurns = history.slice(0, history.findLastIndex((message) => message.role === "user") + 1);
3332
+ return executeToolCallAndRespond({
3333
+ response,
3334
+ params: {
3335
+ messages: threadId ? [] : priorTurns,
3336
+ clientTools: clientToolsResolver?.() ?? clientTools,
3337
+ clientToolsResolver,
3338
+ requestContext: context,
3339
+ memory
3340
+ },
3341
+ agentId: this.agentId,
3342
+ resourceId: memory?.resource,
3343
+ threadId,
3344
+ requestContext: context,
3345
+ respondFn: (messages, options) => this.generate(messages, options)
2612
3346
  });
2613
3347
  }
2614
3348
  /**
@@ -3806,7 +4540,8 @@ async function verifyAgentCardSignatureIfPresent(agentCard, options) {
3806
4540
  index
3807
4541
  });
3808
4542
  if (!verificationKey) throw new Error("No verification key was provided for Agent Card signature verification");
3809
- await compactVerify(compactJws, await importVerificationKey(verificationKey, protectedHeader.alg), { algorithms: allowedAlgorithms });
4543
+ const importedKey = await importVerificationKey(verificationKey, protectedHeader.alg);
4544
+ await compactVerify(compactJws, importedKey, { algorithms: allowedAlgorithms });
3810
4545
  return agentCard;
3811
4546
  } catch (error) {
3812
4547
  verificationErrors.push(error instanceof Error ? error.message : "Unknown verification failure");
@@ -4550,10 +5285,10 @@ var Observability = class extends BaseResource {
4550
5285
  });
4551
5286
  }
4552
5287
  /**
4553
- * Queries thread identities using eligible-trace and cross-trace predicates.
5288
+ * Queries full-history thread rows using a trace or thread activity window.
4554
5289
  *
4555
- * @param params - Thread query with its eligible trace selection
4556
- * @returns Matching thread identities
5290
+ * @param params - Thread query with its qualification window, filters and pagination
5291
+ * @returns Matching thread rows. Legacy requests retain their identity-only response.
4557
5292
  */
4558
5293
  queryTraceThreads(params) {
4559
5294
  return this.request("/observability/threads/query", {
@@ -6138,48 +6873,40 @@ function hydrateEventTimestamps(event) {
6138
6873
  return isKnownParsedEvent(event) ? hydrateKnownEvent(event) : event;
6139
6874
  }
6140
6875
  /**
6141
- * A session bound to a `resourceId` within one agent controller. Sessions are
6142
- * get-or-create on the server, so re-creating the same resourceId (and scope)
6143
- * resumes the existing conversation rather than forking it.
6144
- *
6145
- * Pass a `scope` to address an independent session over the same resourceId:
6146
- * two sessions with the same resourceId but different scopes have their own
6147
- * run loop, thread binding, and mode/model/state (e.g. one session per git
6148
- * worktree, with the worktree path as the scope). The scope travels on every
6149
- * request as a `sessionScope` query param.
6876
+ * A session addressed by its `sessionId` within one agent controller. Sessions
6877
+ * are get-or-create on the server, so re-creating the same sessionId resumes
6878
+ * the existing conversation rather than forking it. Many sessions can work on
6879
+ * one `resourceId` (whose threads and memory they use); each has its own run
6880
+ * loop, thread binding, and mode/model/state.
6150
6881
  */
6151
6882
  var AgentControllerSession = class extends BaseResource {
6152
6883
  controllerId;
6153
- resourceId;
6154
- scope;
6155
- constructor(options, controllerId, resourceId, scope) {
6884
+ sessionId;
6885
+ constructor(options, controllerId, sessionId) {
6156
6886
  super(options);
6157
6887
  this.controllerId = controllerId;
6158
- this.resourceId = resourceId;
6159
- this.scope = scope;
6888
+ this.sessionId = sessionId;
6160
6889
  }
6161
6890
  base() {
6162
- return `/agent-controller/${encodeURIComponent(this.controllerId)}/sessions/${encodeURIComponent(this.resourceId)}`;
6163
- }
6164
- /** Append this session's scope (if any) as a `sessionScope` query param. */
6165
- url(path) {
6166
- if (this.scope === void 0) return path;
6167
- return `${path}${path.includes("?") ? "&" : "?"}sessionScope=${encodeURIComponent(this.scope)}`;
6891
+ return `/agent-controller/${encodeURIComponent(this.controllerId)}/sessions/${encodeURIComponent(this.sessionId)}`;
6168
6892
  }
6169
6893
  /**
6170
- * Create or resume this session. Pass `tags` to scope initial thread
6171
- * selection — a thread is a resume candidate only when its metadata matches
6172
- * every tag. Pass `threadId` to bind the session to one exact thread,
6173
- * creating it with that id when it does not exist.
6894
+ * Create or resume this session. `resourceId` names whose threads and memory
6895
+ * the session works on. Without it the server resumes the session on the
6896
+ * resource it already has (the live session's, or the resource of the thread
6897
+ * with the session's id), falling back to the sessionId. Pass `tags` to scope
6898
+ * initial thread selection — a thread is a resume candidate only when its
6899
+ * metadata matches every tag. Pass `threadId` to bind the session to one
6900
+ * exact thread, creating it with that id when it does not exist.
6174
6901
  */
6175
6902
  create(options) {
6176
6903
  return this.request(`/agent-controller/${encodeURIComponent(this.controllerId)}/sessions`, {
6177
6904
  method: "POST",
6178
6905
  body: {
6179
- resourceId: this.resourceId,
6906
+ resourceId: options?.resourceId,
6907
+ sessionId: this.sessionId,
6180
6908
  tags: options?.tags,
6181
- threadId: options?.threadId,
6182
- sessionScope: this.scope
6909
+ threadId: options?.threadId
6183
6910
  }
6184
6911
  });
6185
6912
  }
@@ -6205,10 +6932,12 @@ var AgentControllerSession = class extends BaseResource {
6205
6932
  delayMs: finiteOr(options.reconnect.delayMs, 1e3),
6206
6933
  maxDelayMs: finiteOr(options.reconnect.maxDelayMs, 3e4)
6207
6934
  } : null;
6935
+ const idleTimeoutMs = finiteOr(options.idleTimeoutMs, 6e4);
6208
6936
  /** Exponential backoff for the Nth (1-based) retry of an outage streak. */
6209
6937
  const backoffDelay = (attempt) => reconnectOptions ? Math.min(reconnectOptions.delayMs * 2 ** (attempt - 1), reconnectOptions.maxDelayMs) : 0;
6210
6938
  let cancelled = false;
6211
6939
  let currentReader = null;
6940
+ let currentAbort = null;
6212
6941
  let reconnectTimer;
6213
6942
  let delayResolve;
6214
6943
  const settleDelay = () => {
@@ -6224,8 +6953,39 @@ var AgentControllerSession = class extends BaseResource {
6224
6953
  delayResolve = resolve;
6225
6954
  reconnectTimer = setTimeout(settleDelay, ms);
6226
6955
  });
6956
+ const idleTimeoutError = () => {
6957
+ const error = /* @__PURE__ */ new Error(`Agent controller session stream received no data for ${idleTimeoutMs}ms`);
6958
+ error.name = "AgentControllerStreamIdleError";
6959
+ return error;
6960
+ };
6227
6961
  const requestStream = async () => {
6228
- const response = await this.request(this.url(`${this.base()}/stream`), { stream: true });
6962
+ const abort = new AbortController();
6963
+ currentAbort = abort;
6964
+ let openTimer;
6965
+ const request = this.request(`${this.base()}/stream`, {
6966
+ stream: true,
6967
+ signal: abort.signal
6968
+ });
6969
+ request.then((response) => {
6970
+ if (abort.signal.aborted) response.body?.cancel().catch(() => {});
6971
+ }).catch(() => {});
6972
+ let response;
6973
+ try {
6974
+ if (idleTimeoutMs > 0) response = await Promise.race([request, new Promise((_resolve, reject) => {
6975
+ openTimer = setTimeout(() => {
6976
+ const error = idleTimeoutError();
6977
+ abort.abort(error);
6978
+ reject(error);
6979
+ }, idleTimeoutMs);
6980
+ })]);
6981
+ else response = await request;
6982
+ } finally {
6983
+ clearTimeout(openTimer);
6984
+ }
6985
+ if (abort.signal.aborted) {
6986
+ response.body?.cancel().catch(() => {});
6987
+ throw abort.signal.reason;
6988
+ }
6229
6989
  if (!response.body) throw new Error("No response body for agent controller session stream");
6230
6990
  return response;
6231
6991
  };
@@ -6251,12 +7011,40 @@ var AgentControllerSession = class extends BaseResource {
6251
7011
  const pump = async (response) => {
6252
7012
  const reader = response.body.getReader();
6253
7013
  currentReader = reader;
7014
+ const abort = currentAbort;
6254
7015
  const decoder = new TextDecoder();
6255
7016
  let buffer = "";
7017
+ let idleTimer;
7018
+ let timedOut = false;
7019
+ const armIdleTimer = () => {
7020
+ if (idleTimeoutMs <= 0) return;
7021
+ clearTimeout(idleTimer);
7022
+ idleTimer = setTimeout(() => {
7023
+ timedOut = true;
7024
+ reader.cancel(idleTimeoutError()).catch(() => {});
7025
+ abort?.abort(idleTimeoutError());
7026
+ }, idleTimeoutMs);
7027
+ };
6256
7028
  try {
7029
+ armIdleTimer();
6257
7030
  while (!cancelled) {
6258
- const { done, value } = await reader.read();
7031
+ let chunk;
7032
+ try {
7033
+ chunk = await reader.read();
7034
+ } catch (error) {
7035
+ if (timedOut && !cancelled) return {
7036
+ kind: "transport_error",
7037
+ error: idleTimeoutError()
7038
+ };
7039
+ throw error;
7040
+ }
7041
+ if (timedOut && !cancelled) return {
7042
+ kind: "transport_error",
7043
+ error: idleTimeoutError()
7044
+ };
7045
+ const { done, value } = chunk;
6259
7046
  if (done) return cancelled ? { kind: "cancelled" } : { kind: "done" };
7047
+ armIdleTimer();
6260
7048
  if (cancelled) return { kind: "cancelled" };
6261
7049
  buffer += decoder.decode(value, { stream: true });
6262
7050
  let separator;
@@ -6290,7 +7078,9 @@ var AgentControllerSession = class extends BaseResource {
6290
7078
  error
6291
7079
  };
6292
7080
  } finally {
7081
+ clearTimeout(idleTimer);
6293
7082
  if (currentReader === reader) currentReader = null;
7083
+ if (currentAbort === abort) currentAbort = null;
6294
7084
  reader.cancel().catch(() => {});
6295
7085
  }
6296
7086
  };
@@ -6367,6 +7157,7 @@ var AgentControllerSession = class extends BaseResource {
6367
7157
  cancelled = true;
6368
7158
  settleDelay();
6369
7159
  currentReader?.cancel().catch(() => {});
7160
+ currentAbort?.abort();
6370
7161
  } };
6371
7162
  }
6372
7163
  /**
@@ -6381,7 +7172,7 @@ var AgentControllerSession = class extends BaseResource {
6381
7172
  files: void 0
6382
7173
  } : message;
6383
7174
  const requestContext = parseClientRequestContext(options?.requestContext);
6384
- await this.request(this.url(`${this.base()}/messages`), {
7175
+ await this.request(`${this.base()}/messages`, {
6385
7176
  method: "POST",
6386
7177
  body: {
6387
7178
  message: content,
@@ -6392,7 +7183,7 @@ var AgentControllerSession = class extends BaseResource {
6392
7183
  }
6393
7184
  /** Abort the in-flight run for this session. */
6394
7185
  async abort() {
6395
- await this.request(this.url(`${this.base()}/abort`), { method: "POST" });
7186
+ await this.request(`${this.base()}/abort`, { method: "POST" });
6396
7187
  }
6397
7188
  /**
6398
7189
  * Approve or decline a pending tool call (`tool_approval_required`). Resolves
@@ -6400,12 +7191,13 @@ var AgentControllerSession = class extends BaseResource {
6400
7191
  */
6401
7192
  async approveTool(toolCallId, approved, options) {
6402
7193
  const requestContext = parseClientRequestContext(options?.requestContext);
6403
- return this.request(this.url(`${this.base()}/tool-approval`), {
7194
+ return this.request(`${this.base()}/tool-approval`, {
6404
7195
  method: "POST",
6405
7196
  retries: 0,
6406
7197
  body: {
6407
7198
  toolCallId,
6408
7199
  approved,
7200
+ ...options?.alwaysAllowCategory ? { alwaysAllowCategory: true } : {},
6409
7201
  ...requestContext ? { requestContext } : {}
6410
7202
  }
6411
7203
  });
@@ -6417,7 +7209,7 @@ var AgentControllerSession = class extends BaseResource {
6417
7209
  */
6418
7210
  async respondToToolSuspension(toolCallId, resumeData, options) {
6419
7211
  const requestContext = parseClientRequestContext(options?.requestContext);
6420
- return this.request(this.url(`${this.base()}/tool-suspension`), {
7212
+ return this.request(`${this.base()}/tool-suspension`, {
6421
7213
  method: "POST",
6422
7214
  retries: 0,
6423
7215
  body: {
@@ -6437,7 +7229,7 @@ var AgentControllerSession = class extends BaseResource {
6437
7229
  files: void 0
6438
7230
  } : message;
6439
7231
  const requestContext = parseClientRequestContext(options?.requestContext);
6440
- await this.request(this.url(`${this.base()}/steer`), {
7232
+ await this.request(`${this.base()}/steer`, {
6441
7233
  method: "POST",
6442
7234
  body: {
6443
7235
  message: content,
@@ -6449,18 +7241,18 @@ var AgentControllerSession = class extends BaseResource {
6449
7241
  /** Get the current mode, model, and thread (for initial UI hydration). */
6450
7242
  state(options) {
6451
7243
  const path = options?.threadId ? `${this.base()}?threadId=${encodeURIComponent(options.threadId)}` : this.base();
6452
- return this.request(this.url(path));
7244
+ return this.request(path);
6453
7245
  }
6454
7246
  /** Merge key-value pairs into the session state. Existing keys not in the payload are preserved. */
6455
7247
  async setState(updates) {
6456
- await this.request(this.url(`${this.base()}/state`), {
7248
+ await this.request(`${this.base()}/state`, {
6457
7249
  method: "PUT",
6458
7250
  body: { state: updates }
6459
7251
  });
6460
7252
  }
6461
7253
  /** Switch the active mode (e.g. `build`, `plan`). */
6462
7254
  async switchMode(modeId) {
6463
- await this.request(this.url(`${this.base()}/mode`), {
7255
+ await this.request(`${this.base()}/mode`, {
6464
7256
  method: "POST",
6465
7257
  body: { modeId }
6466
7258
  });
@@ -6470,7 +7262,7 @@ var AgentControllerSession = class extends BaseResource {
6470
7262
  * `thinkingLevel` is provided it is applied and persisted with the model.
6471
7263
  */
6472
7264
  async switchModel(modelId, { thinkingLevel } = {}) {
6473
- await this.request(this.url(`${this.base()}/model`), {
7265
+ await this.request(`${this.base()}/model`, {
6474
7266
  method: "POST",
6475
7267
  body: thinkingLevel !== void 0 ? {
6476
7268
  modelId,
@@ -6491,36 +7283,36 @@ var AgentControllerSession = class extends BaseResource {
6491
7283
  if (opts.limit != null) params.set("limit", String(opts.limit));
6492
7284
  if (opts.tags && Object.keys(opts.tags).length > 0) params.set("tags", JSON.stringify(opts.tags));
6493
7285
  const query = params.toString() ? `?${params.toString()}` : "";
6494
- return (await this.request(this.url(`${this.base()}/threads${query}`))).threads;
7286
+ return (await this.request(`${this.base()}/threads${query}`)).threads;
6495
7287
  }
6496
7288
  /** Switch the session to an existing thread (rebinds stream + state). */
6497
7289
  async switchThread(threadId) {
6498
- await this.request(this.url(`${this.base()}/thread`), {
7290
+ await this.request(`${this.base()}/thread`, {
6499
7291
  method: "POST",
6500
7292
  body: { threadId }
6501
7293
  });
6502
7294
  }
6503
7295
  /** Create a new thread (unbinds previous, binds the new one). */
6504
7296
  async createThread(title) {
6505
- return this.request(this.url(`${this.base()}/threads`), {
7297
+ return this.request(`${this.base()}/threads`, {
6506
7298
  method: "POST",
6507
7299
  body: { title }
6508
7300
  });
6509
7301
  }
6510
7302
  /** Delete a thread. If it's the active thread the session unbinds. */
6511
7303
  async deleteThread(threadId) {
6512
- await this.request(this.url(`${this.base()}/threads/${encodeURIComponent(threadId)}`), { method: "DELETE" });
7304
+ await this.request(`${this.base()}/threads/${encodeURIComponent(threadId)}`, { method: "DELETE" });
6513
7305
  }
6514
7306
  /** Rename a thread. */
6515
7307
  async renameThread(threadId, title) {
6516
- await this.request(this.url(`${this.base()}/threads/${encodeURIComponent(threadId)}`), {
7308
+ await this.request(`${this.base()}/threads/${encodeURIComponent(threadId)}`, {
6517
7309
  method: "PUT",
6518
7310
  body: { title }
6519
7311
  });
6520
7312
  }
6521
7313
  /** Clone a thread (and its messages). The session binds to the clone. */
6522
7314
  async cloneThread(options) {
6523
- return this.request(this.url(`${this.base()}/threads/clone`), {
7315
+ return this.request(`${this.base()}/threads/clone`, {
6524
7316
  method: "POST",
6525
7317
  body: options ?? {}
6526
7318
  });
@@ -6541,7 +7333,7 @@ var AgentControllerSession = class extends BaseResource {
6541
7333
  if (include) queryParams.set("include", JSON.stringify(include));
6542
7334
  }
6543
7335
  const query = queryParams.toString();
6544
- const body = await this.request(this.url(`${this.base()}/threads/${encodeURIComponent(threadId)}/messages${query ? `?${query}` : ""}`));
7336
+ const body = await this.request(`${this.base()}/threads/${encodeURIComponent(threadId)}/messages${query ? `?${query}` : ""}`);
6545
7337
  const messages = body.messages.map(hydrateMessage);
6546
7338
  if (legacy) return messages;
6547
7339
  return {
@@ -6560,7 +7352,7 @@ var AgentControllerSession = class extends BaseResource {
6560
7352
  files: void 0
6561
7353
  } : message;
6562
7354
  const requestContext = parseClientRequestContext(options?.requestContext);
6563
- await this.request(this.url(`${this.base()}/follow-up`), {
7355
+ await this.request(`${this.base()}/follow-up`, {
6564
7356
  method: "POST",
6565
7357
  body: {
6566
7358
  message: content,
@@ -6571,26 +7363,26 @@ var AgentControllerSession = class extends BaseResource {
6571
7363
  }
6572
7364
  /** Get the observational memory record for this session's thread. */
6573
7365
  async getOMRecord() {
6574
- return (await this.request(this.url(`${this.base()}/om`))).record;
7366
+ return (await this.request(`${this.base()}/om`)).record;
6575
7367
  }
6576
7368
  /** Change the session's resource identity. */
6577
7369
  async setResourceId(newResourceId) {
6578
- await this.request(this.url(`${this.base()}/resource`), {
7370
+ await this.request(`${this.base()}/resource`, {
6579
7371
  method: "POST",
6580
7372
  body: { newResourceId }
6581
7373
  });
6582
7374
  }
6583
7375
  /** Get known resource IDs for this session. */
6584
7376
  async getResourceIds() {
6585
- return (await this.request(this.url(`${this.base()}/resources`))).resourceIds;
7377
+ return (await this.request(`${this.base()}/resources`)).resourceIds;
6586
7378
  }
6587
7379
  /** Get the current goal for this session's thread. */
6588
7380
  async getGoal() {
6589
- return (await this.request(this.url(`${this.base()}/goal`))).goal;
7381
+ return (await this.request(`${this.base()}/goal`)).goal;
6590
7382
  }
6591
7383
  /** Set a new goal objective. The agent's in-loop judge evaluates progress after each turn. */
6592
7384
  async setGoal(objective, options) {
6593
- return (await this.request(this.url(`${this.base()}/goal`), {
7385
+ return (await this.request(`${this.base()}/goal`, {
6594
7386
  method: "POST",
6595
7387
  body: {
6596
7388
  objective,
@@ -6600,22 +7392,22 @@ var AgentControllerSession = class extends BaseResource {
6600
7392
  }
6601
7393
  /** Update goal options (judge model, max runs, status). */
6602
7394
  async updateGoal(options) {
6603
- return (await this.request(this.url(`${this.base()}/goal`), {
7395
+ return (await this.request(`${this.base()}/goal`, {
6604
7396
  method: "PUT",
6605
7397
  body: options
6606
7398
  })).goal;
6607
7399
  }
6608
7400
  /** Clear the current goal. */
6609
7401
  async clearGoal() {
6610
- await this.request(this.url(`${this.base()}/goal`), { method: "DELETE" });
7402
+ await this.request(`${this.base()}/goal`, { method: "DELETE" });
6611
7403
  }
6612
7404
  /** Get the current permission rules (per-category and per-tool policies). */
6613
7405
  async getPermissions() {
6614
- return this.request(this.url(`${this.base()}/permissions`));
7406
+ return this.request(`${this.base()}/permissions`);
6615
7407
  }
6616
7408
  /** Set the approval policy for a tool category. */
6617
7409
  async setPermissionForCategory(category, policy) {
6618
- await this.request(this.url(`${this.base()}/permissions/category`), {
7410
+ await this.request(`${this.base()}/permissions/category`, {
6619
7411
  method: "PUT",
6620
7412
  body: {
6621
7413
  category,
@@ -6625,7 +7417,7 @@ var AgentControllerSession = class extends BaseResource {
6625
7417
  }
6626
7418
  /** Set the approval policy for a specific tool. */
6627
7419
  async setPermissionForTool(toolName, policy) {
6628
- await this.request(this.url(`${this.base()}/permissions/tool`), {
7420
+ await this.request(`${this.base()}/permissions/tool`, {
6629
7421
  method: "PUT",
6630
7422
  body: {
6631
7423
  toolName,
@@ -6639,7 +7431,7 @@ var AgentControllerSession = class extends BaseResource {
6639
7431
  * or is persisted for later.
6640
7432
  */
6641
7433
  async sendNotification(input) {
6642
- return this.request(this.url(`${this.base()}/notifications`), {
7434
+ return this.request(`${this.base()}/notifications`, {
6643
7435
  method: "POST",
6644
7436
  body: input
6645
7437
  });
@@ -6672,12 +7464,11 @@ var AgentController = class extends BaseResource {
6672
7464
  return this.request(`${this.basePath()}/workspace`);
6673
7465
  }
6674
7466
  /**
6675
- * Scope to a session bound to `resourceId` (e.g. a user or conversation id).
6676
- * Pass `scope` to address an independent session over the same resourceId
6677
- * (e.g. one session per git worktree, with the worktree path as the scope).
7467
+ * Address the session with this `sessionId`. Sessions created without an
7468
+ * explicit id are addressed by their `resourceId`.
6678
7469
  */
6679
- session(resourceId, scope) {
6680
- return new AgentControllerSession(this.options, this.controllerId, resourceId, scope);
7470
+ session(sessionId) {
7471
+ return new AgentControllerSession(this.options, this.controllerId, sessionId);
6681
7472
  }
6682
7473
  };
6683
7474
  /** Pull the plain text out of an assistant message's nested content parts. */
@@ -6751,7 +7542,7 @@ var MastraClient = class extends BaseResource {
6751
7542
  }
6752
7543
  /**
6753
7544
  * Scopes to an agent controller hosted on the connected Mastra instance. Use
6754
- * `getAgentController(id).session(resourceId)` to create/resume a session,
7545
+ * `getAgentController(id).session(sessionId)` to create/resume a session,
6755
7546
  * stream its events, and send messages.
6756
7547
  * @param controllerId - The id the agent controller is registered under on Mastra
6757
7548
  */
@@ -7002,8 +7793,10 @@ var MastraClient = class extends BaseResource {
7002
7793
  if (logLevel) searchParams.set("logLevel", logLevel);
7003
7794
  if (page !== void 0) searchParams.set("page", String(page));
7004
7795
  if (perPage !== void 0) searchParams.set("perPage", String(perPage));
7005
- if (_filters) if (Array.isArray(_filters)) for (const filter of _filters) searchParams.append("filters", filter);
7006
- else searchParams.set("filters", _filters);
7796
+ if (_filters) {
7797
+ if (Array.isArray(_filters)) for (const filter of _filters) searchParams.append("filters", filter);
7798
+ else searchParams.set("filters", _filters);
7799
+ }
7007
7800
  if (searchParams.size) return this.request(`/logs?${searchParams}`);
7008
7801
  else return this.request(`/logs`);
7009
7802
  }
@@ -7023,8 +7816,10 @@ var MastraClient = class extends BaseResource {
7023
7816
  if (logLevel) searchParams.set("logLevel", logLevel);
7024
7817
  if (page !== void 0) searchParams.set("page", String(page));
7025
7818
  if (perPage !== void 0) searchParams.set("perPage", String(perPage));
7026
- if (_filters) if (Array.isArray(_filters)) for (const filter of _filters) searchParams.append("filters", filter);
7027
- else searchParams.set("filters", _filters);
7819
+ if (_filters) {
7820
+ if (Array.isArray(_filters)) for (const filter of _filters) searchParams.append("filters", filter);
7821
+ else searchParams.set("filters", _filters);
7822
+ }
7028
7823
  if (searchParams.size) return this.request(`/logs/${runId}?${searchParams}`);
7029
7824
  else return this.request(`/logs/${runId}`);
7030
7825
  }
@@ -7272,7 +8067,7 @@ var MastraClient = class extends BaseResource {
7272
8067
  getTraceQueryValues(params, options) {
7273
8068
  return this.observability.getTraceQueryValues(params, options);
7274
8069
  }
7275
- /** Queries thread identities using eligible-trace and cross-trace predicates. */
8070
+ /** Queries full-history thread rows using a trace or thread activity window. */
7276
8071
  queryTraceThreads(params) {
7277
8072
  return this.observability.queryTraceThreads(params);
7278
8073
  }