@ai-sdk/harness-deepagents 1.0.39 → 1.0.40

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @ai-sdk/harness-deepagents
2
2
 
3
+ ## 1.0.40
4
+
5
+ ### Patch Changes
6
+
7
+ - 07c977a: chore(harness): refactor bridge code to break out stream event emission from launcher to make it testable
8
+ - 8c96d41: fix(harness-deepagents): fix Deep Agents missing model ID in telemetry
9
+ - 5c1a6af: fix(harness-deepagents): fix overly limiting override of Deep Agents recursion limit default
10
+ - Updated dependencies [a94425b]
11
+ - Updated dependencies [2de0611]
12
+ - @ai-sdk/harness@1.0.41
13
+
3
14
  ## 1.0.39
4
15
 
5
16
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  // src/bridge/index.ts
2
- import { randomUUID } from "crypto";
2
+ import { randomUUID as randomUUID2 } from "crypto";
3
3
  import { argv, env as procEnv2 } from "process";
4
4
 
5
5
  // ../harness/dist/bridge/index.js
@@ -548,6 +548,222 @@ function collectActionRequests(interrupts) {
548
548
  return out;
549
549
  }
550
550
 
551
+ // src/bridge/create-emit-stream-event.ts
552
+ import { randomUUID } from "crypto";
553
+ function createDeepAgentsStreamEventState() {
554
+ return {
555
+ streamStarted: false,
556
+ textBlockId: void 0,
557
+ reasoningBlockId: void 0,
558
+ inputTokens: 0,
559
+ outputTokens: 0,
560
+ streamedStepInput: 0,
561
+ streamedStepOutput: 0,
562
+ pendingStep: void 0,
563
+ approvedToolQueue: /* @__PURE__ */ new Map(),
564
+ approvedRunIds: /* @__PURE__ */ new Map()
565
+ };
566
+ }
567
+ var NATIVE_TO_COMMON2 = {
568
+ read_file: "read",
569
+ write_file: "write",
570
+ edit_file: "edit",
571
+ execute: "bash"
572
+ };
573
+ function toCommonName2(nativeName) {
574
+ return NATIVE_TO_COMMON2[nativeName] ?? nativeName;
575
+ }
576
+ function createEmitStreamEvent({
577
+ state,
578
+ configuredModel,
579
+ hostToolNames,
580
+ emit
581
+ }) {
582
+ return (event) => {
583
+ const kind = event.event;
584
+ const data = event.data ?? {};
585
+ const ns = event.metadata?.langgraph_checkpoint_ns ?? "";
586
+ const nested = ns.includes("|");
587
+ if (kind === "on_chat_model_start") {
588
+ if (!nested) {
589
+ if (!state.streamStarted) {
590
+ state.streamStarted = true;
591
+ const modelId = resolveDeepAgentsModelId({
592
+ configuredModel,
593
+ metadata: event.metadata
594
+ });
595
+ emit({
596
+ type: "stream-start",
597
+ ...modelId ? { modelId } : {}
598
+ });
599
+ }
600
+ flushStep({ state, emit });
601
+ }
602
+ } else if (kind === "on_chat_model_stream") {
603
+ if (nested) return;
604
+ const chunk = data.chunk;
605
+ if (!chunk) return;
606
+ const content = chunk.content;
607
+ if (typeof content === "string" && content) {
608
+ emitText({ state, emit, delta: content });
609
+ } else if (Array.isArray(content)) {
610
+ for (const block of content) {
611
+ if (block && typeof block === "object") {
612
+ const value = block;
613
+ if (value.type === "text" && value.text) {
614
+ emitText({ state, emit, delta: value.text });
615
+ } else if (value.type === "thinking" && value.thinking) {
616
+ emitReasoning({ state, emit, delta: value.thinking });
617
+ }
618
+ }
619
+ }
620
+ }
621
+ const usage = chunk.usage_metadata;
622
+ if (usage) {
623
+ state.streamedStepInput = Math.max(
624
+ state.streamedStepInput,
625
+ usage.input_tokens ?? 0
626
+ );
627
+ state.streamedStepOutput = Math.max(
628
+ state.streamedStepOutput,
629
+ usage.output_tokens ?? 0
630
+ );
631
+ }
632
+ } else if (kind === "on_chat_model_end") {
633
+ const output = data.output;
634
+ const usage = output?.usage_metadata;
635
+ const stepInput = usage?.input_tokens ?? state.streamedStepInput;
636
+ const stepOutput = usage?.output_tokens ?? state.streamedStepOutput;
637
+ state.inputTokens += stepInput;
638
+ state.outputTokens += stepOutput;
639
+ state.streamedStepInput = 0;
640
+ state.streamedStepOutput = 0;
641
+ if (!nested) {
642
+ endTextBlock({ state, emit });
643
+ endReasoningBlock({ state, emit });
644
+ state.pendingStep = { input: stepInput, output: stepOutput };
645
+ }
646
+ } else if (kind === "on_tool_start") {
647
+ const toolName = event.name ?? "unknown";
648
+ const runId = event.run_id ?? "";
649
+ if (!nested && !hostToolNames.has(toolName)) {
650
+ const queued = state.approvedToolQueue.get(toolName);
651
+ if (queued && queued.length > 0) {
652
+ const approvalId = queued.shift();
653
+ if (runId) state.approvedRunIds.set(runId, approvalId);
654
+ } else {
655
+ endTextBlock({ state, emit });
656
+ endReasoningBlock({ state, emit });
657
+ emit({
658
+ type: "tool-call",
659
+ toolCallId: runId,
660
+ toolName: toCommonName2(toolName),
661
+ input: toToolCallInput(data.input),
662
+ providerExecuted: true,
663
+ nativeName: toolName
664
+ });
665
+ }
666
+ }
667
+ } else if (kind === "on_tool_end") {
668
+ const toolName = event.name ?? "unknown";
669
+ const runId = event.run_id ?? "";
670
+ if (!nested && !hostToolNames.has(toolName)) {
671
+ let output = data.output ?? "";
672
+ if (output && typeof output === "object" && "content" in output) {
673
+ output = output.content;
674
+ }
675
+ emit({
676
+ type: "tool-result",
677
+ toolCallId: state.approvedRunIds.get(runId) ?? runId,
678
+ toolName: toCommonName2(toolName),
679
+ result: output ?? null
680
+ });
681
+ state.approvedRunIds.delete(runId);
682
+ }
683
+ }
684
+ };
685
+ }
686
+ function endTextBlock({
687
+ state,
688
+ emit
689
+ }) {
690
+ if (state.textBlockId) {
691
+ emit({ type: "text-end", id: state.textBlockId });
692
+ state.textBlockId = void 0;
693
+ }
694
+ }
695
+ function endReasoningBlock({
696
+ state,
697
+ emit
698
+ }) {
699
+ if (state.reasoningBlockId) {
700
+ emit({ type: "reasoning-end", id: state.reasoningBlockId });
701
+ state.reasoningBlockId = void 0;
702
+ }
703
+ }
704
+ function flushStep({
705
+ state,
706
+ emit
707
+ }) {
708
+ if (!state.pendingStep) return;
709
+ emit({
710
+ type: "finish-step",
711
+ finishReason: { unified: "stop" },
712
+ usage: {
713
+ inputTokens: { total: state.pendingStep.input },
714
+ outputTokens: { total: state.pendingStep.output }
715
+ }
716
+ });
717
+ state.pendingStep = void 0;
718
+ }
719
+ function ensureTextBlock({
720
+ state,
721
+ emit
722
+ }) {
723
+ if (!state.textBlockId) {
724
+ state.textBlockId = `text-${randomUUID()}`;
725
+ emit({ type: "text-start", id: state.textBlockId });
726
+ }
727
+ return state.textBlockId;
728
+ }
729
+ function emitText({
730
+ state,
731
+ emit,
732
+ delta
733
+ }) {
734
+ endReasoningBlock({ state, emit });
735
+ emit({ type: "text-delta", id: ensureTextBlock({ state, emit }), delta });
736
+ }
737
+ function emitReasoning({
738
+ state,
739
+ emit,
740
+ delta
741
+ }) {
742
+ endTextBlock({ state, emit });
743
+ if (!state.reasoningBlockId) {
744
+ state.reasoningBlockId = `reasoning-${randomUUID()}`;
745
+ emit({ type: "reasoning-start", id: state.reasoningBlockId });
746
+ }
747
+ emit({ type: "reasoning-delta", id: state.reasoningBlockId, delta });
748
+ }
749
+ function resolveDeepAgentsModelId({
750
+ configuredModel,
751
+ metadata
752
+ }) {
753
+ if (metadata && typeof metadata === "object" && !Array.isArray(metadata)) {
754
+ const modelId = metadata.ls_model_name;
755
+ if (typeof modelId === "string" && modelId.length > 0) return modelId;
756
+ }
757
+ return configuredModel;
758
+ }
759
+ function toToolCallInput(raw) {
760
+ if (raw && typeof raw === "object" && !Array.isArray(raw) && Object.keys(raw).length === 1 && typeof raw.input === "string") {
761
+ const inner = raw.input;
762
+ if (/^\s*[[{]/.test(inner)) return inner;
763
+ }
764
+ return JSON.stringify(raw ?? {});
765
+ }
766
+
551
767
  // src/bridge/json-schema-to-zod.ts
552
768
  import { z } from "zod/v4";
553
769
  function jsonSchemaToZodObject(input) {
@@ -692,16 +908,7 @@ function createBuiltinToolFilteringMiddleware(input) {
692
908
  }
693
909
 
694
910
  // src/bridge/index.ts
695
- var NATIVE_TO_COMMON2 = {
696
- read_file: "read",
697
- write_file: "write",
698
- edit_file: "edit",
699
- execute: "bash"
700
- };
701
911
  var HARNESS_CLIENT_APP = procEnv2.AI_SDK_HARNESS_CLIENT_APP;
702
- function toCommonName2(nativeName) {
703
- return NATIVE_TO_COMMON2[nativeName] ?? nativeName;
704
- }
705
912
  function parseArgs(rawArgs) {
706
913
  const out = {};
707
914
  for (let i = 0; i < rawArgs.length; i++) {
@@ -732,13 +939,6 @@ function buildModel(rawModel) {
732
939
  } : {}
733
940
  });
734
941
  }
735
- function toToolCallInput(raw) {
736
- if (raw && typeof raw === "object" && !Array.isArray(raw) && Object.keys(raw).length === 1 && typeof raw.input === "string") {
737
- const inner = raw.input;
738
- if (/^\s*[[{]/.test(inner)) return inner;
739
- }
740
- return JSON.stringify(raw ?? {});
741
- }
742
942
  var args = parseArgs(argv.slice(2));
743
943
  var workdir = args.workdir;
744
944
  var bridgeStateDir = args.bridgeStateDir;
@@ -754,7 +954,7 @@ function buildHostTools(toolSchemas) {
754
954
  async (input) => {
755
955
  const turn = currentTurn;
756
956
  if (!turn) throw new Error("no active turn");
757
- const toolCallId = `${schema.name}-${randomUUID()}`;
957
+ const toolCallId = `${schema.name}-${randomUUID2()}`;
758
958
  turn.emit({
759
959
  type: "tool-call",
760
960
  toolCallId,
@@ -807,67 +1007,18 @@ async function runTurn(start, turn) {
807
1007
  checkpointer: new MemorySaver()
808
1008
  });
809
1009
  }
810
- emit({
811
- type: "stream-start",
812
- ...start.model ? { modelId: start.model } : {}
813
- });
814
1010
  const hostToolNames = new Set((start.tools ?? []).map((t) => t.name));
815
- let textBlockId;
816
- let reasoningBlockId;
817
- let inputTokens = 0;
818
- let outputTokens = 0;
819
- let streamedStepInput = 0;
820
- let streamedStepOutput = 0;
821
- let pendingStep;
822
- const approvedToolQueue = /* @__PURE__ */ new Map();
823
- const approvedRunIds = /* @__PURE__ */ new Map();
824
- const ensureTextBlock = () => {
825
- if (!textBlockId) {
826
- textBlockId = `text-${randomUUID()}`;
827
- emit({ type: "text-start", id: textBlockId });
828
- }
829
- return textBlockId;
830
- };
831
- const endTextBlock = () => {
832
- if (textBlockId) {
833
- emit({ type: "text-end", id: textBlockId });
834
- textBlockId = void 0;
835
- }
836
- };
837
- const endReasoningBlock = () => {
838
- if (reasoningBlockId) {
839
- emit({ type: "reasoning-end", id: reasoningBlockId });
840
- reasoningBlockId = void 0;
841
- }
842
- };
843
- const emitText = (delta) => {
844
- endReasoningBlock();
845
- emit({ type: "text-delta", id: ensureTextBlock(), delta });
846
- };
847
- const emitReasoning = (delta) => {
848
- endTextBlock();
849
- if (!reasoningBlockId) {
850
- reasoningBlockId = `reasoning-${randomUUID()}`;
851
- emit({ type: "reasoning-start", id: reasoningBlockId });
852
- }
853
- emit({ type: "reasoning-delta", id: reasoningBlockId, delta });
854
- };
855
- const flushStep = () => {
856
- if (!pendingStep) return;
857
- emit({
858
- type: "finish-step",
859
- finishReason: { unified: "stop" },
860
- usage: {
861
- inputTokens: { total: pendingStep.input },
862
- outputTokens: { total: pendingStep.output }
863
- }
864
- });
865
- pendingStep = void 0;
866
- };
1011
+ const streamEventState = createDeepAgentsStreamEventState();
1012
+ const emitStreamEvent = createEmitStreamEvent({
1013
+ state: streamEventState,
1014
+ configuredModel: start.model,
1015
+ hostToolNames,
1016
+ emit
1017
+ });
867
1018
  const config = {
868
1019
  version: "v2",
869
1020
  configurable: { thread_id: "bridge-session" },
870
- recursionLimit: start.recursionLimit ?? 100,
1021
+ ...start.recursionLimit != null ? { recursionLimit: start.recursionLimit } : {},
871
1022
  signal: turn.abortSignal
872
1023
  };
873
1024
  const readPendingApprovals = async () => {
@@ -888,100 +1039,15 @@ async function runTurn(start, turn) {
888
1039
  while (true) {
889
1040
  const stream = await agent.streamEvents(resumeInput, config);
890
1041
  for await (const event of stream) {
891
- const kind = event.event;
892
- const data = event.data ?? {};
893
- const ns = event.metadata?.langgraph_checkpoint_ns ?? "";
894
- const nested = ns.includes("|");
895
- if (kind === "on_chat_model_start") {
896
- if (!nested) flushStep();
897
- } else if (kind === "on_chat_model_stream") {
898
- if (nested) continue;
899
- const chunk = data.chunk;
900
- if (!chunk) continue;
901
- const content = chunk.content;
902
- if (typeof content === "string" && content) {
903
- emitText(content);
904
- } else if (Array.isArray(content)) {
905
- for (const block of content) {
906
- if (block && typeof block === "object") {
907
- const b = block;
908
- if (b.type === "text" && b.text) emitText(b.text);
909
- else if (b.type === "thinking" && b.thinking)
910
- emitReasoning(b.thinking);
911
- }
912
- }
913
- }
914
- const usage = chunk.usage_metadata;
915
- if (usage) {
916
- streamedStepInput = Math.max(
917
- streamedStepInput,
918
- usage.input_tokens ?? 0
919
- );
920
- streamedStepOutput = Math.max(
921
- streamedStepOutput,
922
- usage.output_tokens ?? 0
923
- );
924
- }
925
- } else if (kind === "on_chat_model_end") {
926
- const output = data.output;
927
- const usage = output?.usage_metadata;
928
- const stepInput = usage?.input_tokens ?? streamedStepInput;
929
- const stepOutput = usage?.output_tokens ?? streamedStepOutput;
930
- inputTokens += stepInput;
931
- outputTokens += stepOutput;
932
- streamedStepInput = 0;
933
- streamedStepOutput = 0;
934
- if (!nested) {
935
- endTextBlock();
936
- endReasoningBlock();
937
- pendingStep = { input: stepInput, output: stepOutput };
938
- }
939
- } else if (kind === "on_tool_start") {
940
- const toolName = event.name ?? "unknown";
941
- const runId = event.run_id ?? "";
942
- if (!nested && !hostToolNames.has(toolName)) {
943
- const queued = approvedToolQueue.get(toolName);
944
- if (queued && queued.length > 0) {
945
- const approvalId = queued.shift();
946
- if (runId) approvedRunIds.set(runId, approvalId);
947
- } else {
948
- endTextBlock();
949
- endReasoningBlock();
950
- emit({
951
- type: "tool-call",
952
- toolCallId: runId,
953
- toolName: toCommonName2(toolName),
954
- input: toToolCallInput(data.input),
955
- providerExecuted: true,
956
- nativeName: toolName
957
- });
958
- }
959
- }
960
- } else if (kind === "on_tool_end") {
961
- const toolName = event.name ?? "unknown";
962
- const runId = event.run_id ?? "";
963
- if (!nested && !hostToolNames.has(toolName)) {
964
- let output = data.output ?? "";
965
- if (output && typeof output === "object" && "content" in output) {
966
- output = output.content;
967
- }
968
- emit({
969
- type: "tool-result",
970
- toolCallId: approvedRunIds.get(runId) ?? runId,
971
- toolName: toCommonName2(toolName),
972
- result: output ?? null
973
- });
974
- approvedRunIds.delete(runId);
975
- }
976
- }
1042
+ emitStreamEvent(event);
977
1043
  }
978
1044
  const actionRequests = await readPendingApprovals();
979
1045
  if (actionRequests.length === 0) break;
980
1046
  const decisions = [];
981
1047
  for (const action of actionRequests) {
982
- const approvalId = `approval-${randomUUID()}`;
983
- endTextBlock();
984
- endReasoningBlock();
1048
+ const approvalId = `approval-${randomUUID2()}`;
1049
+ endTextBlock({ state: streamEventState, emit });
1050
+ endReasoningBlock({ state: streamEventState, emit });
985
1051
  emit({
986
1052
  type: "tool-call",
987
1053
  toolCallId: approvalId,
@@ -995,12 +1061,12 @@ async function runTurn(start, turn) {
995
1061
  approvalId,
996
1062
  toolCallId: approvalId
997
1063
  });
998
- flushStep();
1064
+ flushStep({ state: streamEventState, emit });
999
1065
  const decision = await turn.requestToolApproval(approvalId);
1000
1066
  if (decision.approved) {
1001
- const queue = approvedToolQueue.get(action.name) ?? [];
1067
+ const queue = streamEventState.approvedToolQueue.get(action.name) ?? [];
1002
1068
  queue.push(approvalId);
1003
- approvedToolQueue.set(action.name, queue);
1069
+ streamEventState.approvedToolQueue.set(action.name, queue);
1004
1070
  decisions.push({ type: "approve" });
1005
1071
  } else {
1006
1072
  emit({
@@ -1017,15 +1083,15 @@ async function runTurn(start, turn) {
1017
1083
  }
1018
1084
  resumeInput = new Command({ resume: { decisions } });
1019
1085
  }
1020
- endTextBlock();
1021
- endReasoningBlock();
1022
- flushStep();
1086
+ endTextBlock({ state: streamEventState, emit });
1087
+ endReasoningBlock({ state: streamEventState, emit });
1088
+ flushStep({ state: streamEventState, emit });
1023
1089
  emit({
1024
1090
  type: "finish",
1025
1091
  finishReason: { unified: "stop" },
1026
1092
  totalUsage: {
1027
- inputTokens: { total: inputTokens },
1028
- outputTokens: { total: outputTokens }
1093
+ inputTokens: { total: streamEventState.inputTokens },
1094
+ outputTokens: { total: streamEventState.outputTokens }
1029
1095
  }
1030
1096
  });
1031
1097
  }