@openai/agents-core 0.9.0 → 0.10.0

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 (84) hide show
  1. package/dist/agent.d.ts +25 -2
  2. package/dist/agent.js +45 -2
  3. package/dist/agent.js.map +1 -1
  4. package/dist/agent.mjs +46 -3
  5. package/dist/agent.mjs.map +1 -1
  6. package/dist/agentToolRunConfig.js +3 -0
  7. package/dist/agentToolRunConfig.js.map +1 -1
  8. package/dist/agentToolRunConfig.mjs +3 -0
  9. package/dist/agentToolRunConfig.mjs.map +1 -1
  10. package/dist/defaultModel.js +2 -1
  11. package/dist/defaultModel.js.map +1 -1
  12. package/dist/defaultModel.mjs +2 -1
  13. package/dist/defaultModel.mjs.map +1 -1
  14. package/dist/index.d.ts +2 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/mcp.d.ts +9 -3
  18. package/dist/mcp.js +238 -16
  19. package/dist/mcp.js.map +1 -1
  20. package/dist/mcp.mjs +238 -16
  21. package/dist/mcp.mjs.map +1 -1
  22. package/dist/memory/session.d.ts +7 -0
  23. package/dist/memory/session.js.map +1 -1
  24. package/dist/memory/session.mjs.map +1 -1
  25. package/dist/metadata.js +2 -2
  26. package/dist/metadata.js.map +1 -1
  27. package/dist/metadata.mjs +2 -2
  28. package/dist/metadata.mjs.map +1 -1
  29. package/dist/result.d.ts +1 -1
  30. package/dist/result.js.map +1 -1
  31. package/dist/result.mjs.map +1 -1
  32. package/dist/run.d.ts +17 -1
  33. package/dist/run.js +95 -11
  34. package/dist/run.js.map +1 -1
  35. package/dist/run.mjs +96 -12
  36. package/dist/run.mjs.map +1 -1
  37. package/dist/runState.d.ts +33 -6
  38. package/dist/runState.js +326 -46
  39. package/dist/runState.js.map +1 -1
  40. package/dist/runState.mjs +325 -46
  41. package/dist/runState.mjs.map +1 -1
  42. package/dist/runner/sessionPersistence.js +33 -12
  43. package/dist/runner/sessionPersistence.js.map +1 -1
  44. package/dist/runner/sessionPersistence.mjs +33 -12
  45. package/dist/runner/sessionPersistence.mjs.map +1 -1
  46. package/dist/runner/streamReconciliation.d.ts +14 -0
  47. package/dist/runner/streamReconciliation.js +80 -0
  48. package/dist/runner/streamReconciliation.js.map +1 -0
  49. package/dist/runner/streamReconciliation.mjs +72 -0
  50. package/dist/runner/streamReconciliation.mjs.map +1 -0
  51. package/dist/runner/toolExecution.js +45 -12
  52. package/dist/runner/toolExecution.js.map +1 -1
  53. package/dist/runner/toolExecution.mjs +45 -12
  54. package/dist/runner/toolExecution.mjs.map +1 -1
  55. package/dist/runner/toolUseTracker.d.ts +3 -1
  56. package/dist/runner/toolUseTracker.js +2 -2
  57. package/dist/runner/toolUseTracker.js.map +1 -1
  58. package/dist/runner/toolUseTracker.mjs +2 -2
  59. package/dist/runner/toolUseTracker.mjs.map +1 -1
  60. package/dist/runner/turnPreparation.js +1 -1
  61. package/dist/runner/turnPreparation.js.map +1 -1
  62. package/dist/runner/turnPreparation.mjs +1 -1
  63. package/dist/runner/turnPreparation.mjs.map +1 -1
  64. package/dist/sandbox/agent.d.ts +2 -2
  65. package/dist/sandbox/agent.js +1 -0
  66. package/dist/sandbox/agent.js.map +1 -1
  67. package/dist/sandbox/agent.mjs +1 -0
  68. package/dist/sandbox/agent.mjs.map +1 -1
  69. package/dist/sandbox/client.d.ts +3 -3
  70. package/dist/sandbox/client.js +6 -1
  71. package/dist/sandbox/client.js.map +1 -1
  72. package/dist/sandbox/client.mjs +7 -2
  73. package/dist/sandbox/client.mjs.map +1 -1
  74. package/dist/sandbox/manifest.d.ts +6 -5
  75. package/dist/sandbox/manifest.js +7 -0
  76. package/dist/sandbox/manifest.js.map +1 -1
  77. package/dist/sandbox/manifest.mjs +7 -0
  78. package/dist/sandbox/manifest.mjs.map +1 -1
  79. package/dist/sandbox/users.d.ts +7 -2
  80. package/dist/sandbox/users.js +1 -1
  81. package/dist/sandbox/users.js.map +1 -1
  82. package/dist/sandbox/users.mjs +1 -1
  83. package/dist/sandbox/users.mjs.map +1 -1
  84. package/package.json +1 -1
package/dist/runState.mjs CHANGED
@@ -40,8 +40,11 @@ import { getSerializedApplyPatchToolPlaceholder, getSerializedComputerToolPlaceh
40
40
  * aliasing to serialized run state payloads.
41
41
  * - 1.9: Adds optional sandbox session persistence with a versioned session-state
42
42
  * envelope for sandbox-agent resume.
43
+ * - 1.10: Adds optional stable agent identity keys so duplicate-name agent graphs can
44
+ * serialize and resume without ambiguous name resolution.
45
+ * - 1.11: Allows null maxTurns to persist runs without a turn limit.
43
46
  */
44
- export const CURRENT_SCHEMA_VERSION = '1.9';
47
+ export const CURRENT_SCHEMA_VERSION = '1.11';
45
48
  const SUPPORTED_SCHEMA_VERSIONS = [
46
49
  '1.0',
47
50
  '1.1',
@@ -52,11 +55,14 @@ const SUPPORTED_SCHEMA_VERSIONS = [
52
55
  '1.6',
53
56
  '1.7',
54
57
  '1.8',
58
+ '1.9',
59
+ '1.10',
55
60
  CURRENT_SCHEMA_VERSION,
56
61
  ];
57
62
  const $schemaVersion = z.enum(SUPPORTED_SCHEMA_VERSIONS);
58
63
  const serializedAgentSchema = z.object({
59
64
  name: z.string(),
65
+ identity: z.string().optional(),
60
66
  });
61
67
  const serializedSpanBase = z.object({
62
68
  object: z.literal('trace.span'),
@@ -307,7 +313,7 @@ export const SerializedRunState = z.object({
307
313
  toolInput: z.any().optional(),
308
314
  }),
309
315
  toolUseTracker: z.record(z.string(), z.array(z.string())),
310
- maxTurns: z.number(),
316
+ maxTurns: z.number().nullable(),
311
317
  currentAgentSpan: SerializedSpan.nullable().optional(),
312
318
  noActiveAgentRun: z.boolean(),
313
319
  inputGuardrailResults: z.array(inputGuardrailResultSchema),
@@ -470,10 +476,10 @@ export class RunState {
470
476
  */
471
477
  _trace = null;
472
478
  /**
473
- * Runtime-only tool_search-loaded tools, scoped by agent name and preserved across turns for
479
+ * Runtime-only tool_search-loaded tools, scoped by agent object and preserved across turns for
474
480
  * the lifetime of this in-memory run.
475
481
  */
476
- _toolSearchRuntimeToolsByAgentName = new Map();
482
+ _toolSearchRuntimeToolsByAgent = new Map();
477
483
  /**
478
484
  * Persisted sandbox session metadata for sandbox-agent resume.
479
485
  */
@@ -517,20 +523,20 @@ export class RunState {
517
523
  setCurrentAgentSpan(span) {
518
524
  this._currentAgentSpan = span;
519
525
  }
520
- getOrCreateToolSearchRuntimeToolState(agentName) {
521
- let state = this._toolSearchRuntimeToolsByAgentName.get(agentName);
526
+ getOrCreateToolSearchRuntimeToolState(agent) {
527
+ let state = this._toolSearchRuntimeToolsByAgent.get(agent);
522
528
  if (!state) {
523
529
  state = {
524
530
  anonymousEntries: [],
525
531
  keyedEntries: new Map(),
526
532
  nextOrder: 0,
527
533
  };
528
- this._toolSearchRuntimeToolsByAgentName.set(agentName, state);
534
+ this._toolSearchRuntimeToolsByAgent.set(agent, state);
529
535
  }
530
536
  return state;
531
537
  }
532
538
  recordToolSearchRuntimeTools(agent, toolSearchOutput, tools) {
533
- const runtimeState = this.getOrCreateToolSearchRuntimeToolState(agent.name);
539
+ const runtimeState = this.getOrCreateToolSearchRuntimeToolState(agent);
534
540
  const entry = {
535
541
  order: runtimeState.nextOrder++,
536
542
  tools,
@@ -543,7 +549,7 @@ export class RunState {
543
549
  runtimeState.anonymousEntries.push(entry);
544
550
  }
545
551
  getToolSearchRuntimeTools(agent) {
546
- const runtimeState = this._toolSearchRuntimeToolsByAgentName.get(agent.name);
552
+ const runtimeState = this._toolSearchRuntimeToolsByAgent.get(agent);
547
553
  if (!runtimeState) {
548
554
  return [];
549
555
  }
@@ -680,15 +686,13 @@ export class RunState {
680
686
  * rehydrate in a separate process that lacks the original environment variables).
681
687
  */
682
688
  toJSON(options = {}) {
683
- buildAgentMap(this.#startingAgent);
689
+ const agentIdentity = buildAgentIdentityMap(this.#startingAgent);
684
690
  const includeTracingApiKey = options.includeTracingApiKey === true;
685
691
  const contextJson = this._context.toJSON();
686
692
  const output = {
687
693
  $schemaVersion: CURRENT_SCHEMA_VERSION,
688
694
  currentTurn: this._currentTurn,
689
- currentAgent: {
690
- name: this._currentAgent.name,
691
- },
695
+ currentAgent: serializeAgentReference(this._currentAgent, agentIdentity.byAgent),
692
696
  originalInput: this._originalInput,
693
697
  modelResponses: this._modelResponses.map((response) => {
694
698
  return {
@@ -720,7 +724,9 @@ export class RunState {
720
724
  };
721
725
  }),
722
726
  context: contextJson,
723
- toolUseTracker: this._toolUseTracker.toJSON(),
727
+ toolUseTracker: this._toolUseTracker.toJSON({
728
+ agentIdentityKeys: agentIdentity.byAgent,
729
+ }),
724
730
  maxTurns: this._maxTurns,
725
731
  currentAgentSpan: this._currentAgentSpan?.toJSON(),
726
732
  noActiveAgentRun: this._noActiveAgentRun,
@@ -728,16 +734,18 @@ export class RunState {
728
734
  inputGuardrailResults: this._inputGuardrailResults,
729
735
  outputGuardrailResults: this._outputGuardrailResults.map((r) => ({
730
736
  ...r,
731
- agent: r.agent.toJSON(),
737
+ agent: serializeAgentReference(r.agent, agentIdentity.byAgent),
732
738
  })),
733
739
  toolInputGuardrailResults: this._toolInputGuardrailResults,
734
740
  toolOutputGuardrailResults: this._toolOutputGuardrailResults,
735
- currentStep: this._currentStep,
741
+ currentStep: serializeCurrentStep(this._currentStep, agentIdentity.byAgent),
736
742
  lastModelResponse: this._lastTurnResponse,
737
- generatedItems: this._generatedItems.map((item) => item.toJSON()),
743
+ generatedItems: this._generatedItems.map((item) => serializeRunItem(item, agentIdentity.byAgent)),
738
744
  pendingAgentToolRuns: Object.fromEntries(this._pendingAgentToolRuns.entries()),
739
745
  currentTurnPersistedItemCount: this._currentTurnPersistedItemCount,
740
- lastProcessedResponse: this._lastProcessedResponse,
746
+ lastProcessedResponse: this._lastProcessedResponse
747
+ ? serializeProcessedResponse(this._lastProcessedResponse, agentIdentity.byAgent)
748
+ : undefined,
741
749
  conversationId: this._conversationId,
742
750
  previousResponseId: this._previousResponseId,
743
751
  reasoningItemIdPolicy: this._reasoningItemIdPolicy,
@@ -797,7 +805,10 @@ async function buildRunStateFromString(initialAgent, str, options = {}) {
797
805
  return buildRunStateFromJson(initialAgent, stateJson, options);
798
806
  }
799
807
  function assertSchemaVersionSupportsToolSearch(schemaVersion, stateJson) {
800
- if (schemaVersion === '1.8' || schemaVersion === '1.9') {
808
+ if (schemaVersion === '1.8' ||
809
+ schemaVersion === '1.9' ||
810
+ schemaVersion === '1.10' ||
811
+ schemaVersion === CURRENT_SCHEMA_VERSION) {
801
812
  return;
802
813
  }
803
814
  if (!containsSerializedToolSearchState(stateJson)) {
@@ -805,6 +816,9 @@ function assertSchemaVersionSupportsToolSearch(schemaVersion, stateJson) {
805
816
  }
806
817
  throw new UserError(`Run state schema version ${schemaVersion} does not support tool_search items. Please reserialize the run state with schema ${CURRENT_SCHEMA_VERSION}.`);
807
818
  }
819
+ function schemaVersionSupportsAgentIdentity(schemaVersion) {
820
+ return schemaVersion === '1.10' || schemaVersion === CURRENT_SCHEMA_VERSION;
821
+ }
808
822
  function containsSerializedToolSearchState(stateJson) {
809
823
  return (containsToolSearchProtocolItems(stateJson.originalInput) ||
810
824
  containsToolSearchInModelResponses(stateJson.modelResponses) ||
@@ -908,17 +922,17 @@ function assertRuntimeToolKeysMatch(args) {
908
922
  throw new UserError(`RunState cannot resume custom client tool_search call ${callId} for agent ${agent.name} because the registered execute callback returned runtime tools [${formatRuntimeToolKeys(actualRuntimeToolKeys)}] but the serialized state expects [${formatRuntimeToolKeys(expectedRuntimeToolKeys)}].`);
909
923
  }
910
924
  async function getConfiguredAgentTools(args) {
911
- const { agent, context, configuredToolsByAgentName } = args;
912
- const existing = configuredToolsByAgentName.get(agent.name);
925
+ const { agent, context, configuredToolsByAgent } = args;
926
+ const existing = configuredToolsByAgent.get(agent);
913
927
  if (existing) {
914
928
  return existing;
915
929
  }
916
930
  const configuredTools = (await agent.getAllTools(context));
917
- configuredToolsByAgentName.set(agent.name, configuredTools);
931
+ configuredToolsByAgent.set(agent, configuredTools);
918
932
  return configuredTools;
919
933
  }
920
934
  async function rehydrateToolSearchRuntimeTools(state) {
921
- const configuredToolsByAgentName = new Map();
935
+ const configuredToolsByAgent = new Map();
922
936
  const pendingToolSearchCalls = new Map();
923
937
  for (const item of state._generatedItems) {
924
938
  if (item instanceof RunToolSearchCallItem) {
@@ -926,10 +940,14 @@ async function rehydrateToolSearchRuntimeTools(state) {
926
940
  continue;
927
941
  }
928
942
  const callId = resolveToolSearchCallId(item.rawItem);
929
- pendingToolSearchCalls.set(`${item.agent.name}:${callId}`, {
943
+ const agent = item.agent;
944
+ const pendingCallsById = pendingToolSearchCalls.get(agent) ??
945
+ new Map();
946
+ pendingCallsById.set(callId, {
930
947
  agent: item.agent,
931
948
  toolSearchCall: item.rawItem,
932
949
  });
950
+ pendingToolSearchCalls.set(agent, pendingCallsById);
933
951
  continue;
934
952
  }
935
953
  if (!(item instanceof RunToolSearchOutputItem)) {
@@ -941,7 +959,7 @@ async function rehydrateToolSearchRuntimeTools(state) {
941
959
  const configuredTools = await getConfiguredAgentTools({
942
960
  agent: item.agent,
943
961
  context: state._context,
944
- configuredToolsByAgentName,
962
+ configuredToolsByAgent,
945
963
  });
946
964
  const configuredToolKeys = getRuntimeToolKeys(configuredTools, {
947
965
  allowUnsupported: true,
@@ -951,7 +969,9 @@ async function rehydrateToolSearchRuntimeTools(state) {
951
969
  continue;
952
970
  }
953
971
  const callId = resolveToolSearchCallId(item.rawItem);
954
- const pendingCall = pendingToolSearchCalls.get(`${item.agent.name}:${callId}`);
972
+ const pendingCall = pendingToolSearchCalls
973
+ .get(item.agent)
974
+ ?.get(callId);
955
975
  if (!pendingCall) {
956
976
  throw new UserError(`RunState cannot resume custom client tool_search output ${callId} for agent ${item.agent.name} because the serialized state is missing the matching tool_search call item.`);
957
977
  }
@@ -994,7 +1014,9 @@ async function rehydrateToolSearchRuntimeTools(state) {
994
1014
  }
995
1015
  }
996
1016
  async function buildRunStateFromJson(initialAgent, stateJson, options = {}) {
997
- const agentMap = buildAgentMap(initialAgent);
1017
+ const agentMap = schemaVersionSupportsAgentIdentity(stateJson.$schemaVersion)
1018
+ ? buildAgentIdentityMap(initialAgent).byIdentity
1019
+ : buildAgentMap(initialAgent);
998
1020
  const contextOverride = options.contextOverride;
999
1021
  const contextStrategy = options.contextStrategy ?? 'merge';
1000
1022
  //
@@ -1019,10 +1041,7 @@ async function buildRunStateFromJson(initialAgent, stateJson, options = {}) {
1019
1041
  //
1020
1042
  // Find the current agent from the initial agent
1021
1043
  //
1022
- const currentAgent = agentMap.get(stateJson.currentAgent.name);
1023
- if (!currentAgent) {
1024
- throw new UserError(`Agent ${stateJson.currentAgent.name} not found`);
1025
- }
1044
+ const currentAgent = resolveSerializedAgent(stateJson.currentAgent, agentMap);
1026
1045
  const state = new RunState(context, '', initialAgent, stateJson.maxTurns);
1027
1046
  state._currentAgent = currentAgent;
1028
1047
  state._currentTurn = stateJson.currentTurn;
@@ -1033,7 +1052,13 @@ async function buildRunStateFromJson(initialAgent, stateJson, options = {}) {
1033
1052
  // rebuild tool use tracker
1034
1053
  state._toolUseTracker = new AgentToolUseTracker();
1035
1054
  for (const [agentName, toolNames] of Object.entries(stateJson.toolUseTracker)) {
1036
- state._toolUseTracker.addToolUse(agentMap.get(agentName), toolNames, { allowEmpty: true });
1055
+ const agent = agentMap.get(agentName);
1056
+ if (!agent) {
1057
+ throw new UserError(`Agent ${agentName} not found`);
1058
+ }
1059
+ state._toolUseTracker.addToolUse(agent, toolNames, {
1060
+ allowEmpty: true,
1061
+ });
1037
1062
  }
1038
1063
  state._pendingAgentToolRuns = new Map(Object.entries(stateJson.pendingAgentToolRuns ?? {}));
1039
1064
  // rebuild current agent span
@@ -1056,7 +1081,7 @@ async function buildRunStateFromJson(initialAgent, stateJson, options = {}) {
1056
1081
  stateJson.inputGuardrailResults;
1057
1082
  state._outputGuardrailResults = stateJson.outputGuardrailResults.map((r) => ({
1058
1083
  ...r,
1059
- agent: agentMap.get(r.agent.name),
1084
+ agent: resolveSerializedAgent(r.agent, agentMap),
1060
1085
  }));
1061
1086
  state._toolInputGuardrailResults =
1062
1087
  stateJson.toolInputGuardrailResults;
@@ -1079,7 +1104,7 @@ async function buildRunStateFromJson(initialAgent, stateJson, options = {}) {
1079
1104
  if (stateJson.currentStep?.type === 'next_step_handoff') {
1080
1105
  state._currentStep = {
1081
1106
  type: 'next_step_handoff',
1082
- newAgent: agentMap.get(stateJson.currentStep.newAgent.name),
1107
+ newAgent: resolveSerializedAgent(stateJson.currentStep.newAgent, agentMap),
1083
1108
  };
1084
1109
  }
1085
1110
  else if (stateJson.currentStep?.type === 'next_step_interruption') {
@@ -1100,7 +1125,9 @@ export async function rehydrateProcessedResponseTools(initialAgent, state, execu
1100
1125
  if (!state._lastProcessedResponse) {
1101
1126
  return;
1102
1127
  }
1103
- state._lastProcessedResponse = await deserializeProcessedResponse(buildAgentMap(initialAgent), state, state._lastProcessedResponse, {
1128
+ const agentIdentity = buildAgentIdentityMap(initialAgent);
1129
+ const serializedProcessedResponse = serializeProcessedResponse(state._lastProcessedResponse, agentIdentity.byAgent);
1130
+ state._lastProcessedResponse = await deserializeProcessedResponse(agentIdentity.byIdentity, state, serializedProcessedResponse, {
1104
1131
  executionTools,
1105
1132
  allowSerializedExecutionToolPlaceholder: false,
1106
1133
  });
@@ -1140,6 +1167,250 @@ export function buildAgentMap(initialAgent) {
1140
1167
  }
1141
1168
  return map;
1142
1169
  }
1170
+ /**
1171
+ * @internal
1172
+ */
1173
+ export function buildAgentIdentityMap(initialAgent) {
1174
+ const agents = collectAgentGraph(initialAgent);
1175
+ const groups = new Map();
1176
+ const literalNames = new Set();
1177
+ for (const entry of agents) {
1178
+ literalNames.add(entry.agent.name);
1179
+ const group = groups.get(entry.agent.name) ?? [];
1180
+ group.push(entry);
1181
+ groups.set(entry.agent.name, group);
1182
+ }
1183
+ const byIdentity = new Map();
1184
+ const byAgent = new Map();
1185
+ const usedIdentities = new Set();
1186
+ for (const [agentName, group] of groups) {
1187
+ const sortedGroup = group.length === 1
1188
+ ? group
1189
+ : [...group].sort((left, right) => {
1190
+ if (left.agent === initialAgent) {
1191
+ return -1;
1192
+ }
1193
+ if (right.agent === initialAgent) {
1194
+ return 1;
1195
+ }
1196
+ const leftSignature = getAgentIdentitySignature(left.agent);
1197
+ const rightSignature = getAgentIdentitySignature(right.agent);
1198
+ if (leftSignature !== rightSignature) {
1199
+ return leftSignature < rightSignature ? -1 : 1;
1200
+ }
1201
+ return left.index - right.index;
1202
+ });
1203
+ let nextSuffix = 0;
1204
+ for (const { agent } of sortedGroup) {
1205
+ let identity;
1206
+ do {
1207
+ identity =
1208
+ nextSuffix === 0 ? agentName : `${agentName}#${nextSuffix + 1}`;
1209
+ nextSuffix += 1;
1210
+ } while (usedIdentities.has(identity) ||
1211
+ (identity !== agent.name && literalNames.has(identity)));
1212
+ usedIdentities.add(identity);
1213
+ byIdentity.set(identity, agent);
1214
+ byAgent.set(agent, identity);
1215
+ }
1216
+ }
1217
+ return { byIdentity, byAgent };
1218
+ }
1219
+ function collectAgentGraph(initialAgent) {
1220
+ const agents = [];
1221
+ const visitedAgents = new Set();
1222
+ const queue = [initialAgent];
1223
+ while (queue.length > 0) {
1224
+ const currentAgent = queue.shift();
1225
+ if (visitedAgents.has(currentAgent)) {
1226
+ continue;
1227
+ }
1228
+ visitedAgents.add(currentAgent);
1229
+ agents.push({ agent: currentAgent, index: agents.length });
1230
+ for (const handoff of currentAgent.handoffs) {
1231
+ if (handoff instanceof Agent) {
1232
+ queue.push(handoff);
1233
+ }
1234
+ else if (handoff.agent) {
1235
+ queue.push(handoff.agent);
1236
+ }
1237
+ }
1238
+ for (const tool of currentAgent.tools) {
1239
+ const sourceAgent = getAgentToolSourceAgent(tool);
1240
+ if (sourceAgent) {
1241
+ queue.push(sourceAgent);
1242
+ }
1243
+ }
1244
+ }
1245
+ return agents;
1246
+ }
1247
+ function getAgentIdentitySignature(agent) {
1248
+ const sandboxAgent = agent;
1249
+ const signature = {
1250
+ type: agent.constructor?.name,
1251
+ name: agent.name,
1252
+ handoffDescription: agent.handoffDescription,
1253
+ instructions: summarizeIdentityValue(agent.instructions),
1254
+ prompt: summarizeIdentityValue(agent.prompt),
1255
+ model: summarizeIdentityValue(agent.model),
1256
+ modelSettings: summarizeIdentityValue(agent.modelSettings),
1257
+ tools: agent.tools.map(summarizeToolIdentity),
1258
+ handoffs: agent.handoffs.map((entry) => entry instanceof Agent
1259
+ ? { type: 'agent', name: entry.name }
1260
+ : {
1261
+ type: 'handoff',
1262
+ toolName: entry.toolName,
1263
+ agentName: entry.agentName,
1264
+ targetName: entry.agent?.name,
1265
+ }),
1266
+ mcpServers: agent.mcpServers.map(summarizeIdentityValue),
1267
+ mcpConfig: summarizeIdentityValue(agent.mcpConfig),
1268
+ inputGuardrails: agent.inputGuardrails.map(summarizeIdentityValue),
1269
+ outputGuardrails: agent.outputGuardrails.map(summarizeIdentityValue),
1270
+ outputType: summarizeIdentityValue(agent.outputType),
1271
+ toolUseBehavior: summarizeIdentityValue(agent.toolUseBehavior),
1272
+ resetToolChoice: agent.resetToolChoice,
1273
+ defaultManifest: summarizeIdentityValue(sandboxAgent.defaultManifest),
1274
+ baseInstructions: summarizeIdentityValue(sandboxAgent.baseInstructions),
1275
+ capabilities: sandboxAgent.capabilities?.map(summarizeIdentityValue),
1276
+ runAs: summarizeIdentityValue(sandboxAgent.runAs),
1277
+ };
1278
+ return stableStringify(signature);
1279
+ }
1280
+ function summarizeToolIdentity(tool) {
1281
+ return {
1282
+ type: tool.type,
1283
+ name: tool.name,
1284
+ namespace: tool.namespace,
1285
+ strict: tool.strict,
1286
+ parameters: summarizeIdentityValue(tool.parameters),
1287
+ };
1288
+ }
1289
+ function summarizeIdentityValue(value) {
1290
+ return normalizeForIdentity(value, new WeakSet(), 0);
1291
+ }
1292
+ function normalizeForIdentity(value, seen, depth) {
1293
+ if (value === null || typeof value === 'undefined') {
1294
+ return value;
1295
+ }
1296
+ if (typeof value === 'string' ||
1297
+ typeof value === 'number' ||
1298
+ typeof value === 'boolean') {
1299
+ return value;
1300
+ }
1301
+ if (typeof value === 'function') {
1302
+ return `[function:${value.name || 'anonymous'}]`;
1303
+ }
1304
+ if (typeof value !== 'object') {
1305
+ return String(value);
1306
+ }
1307
+ if (seen.has(value)) {
1308
+ return '[circular]';
1309
+ }
1310
+ if (depth >= 4) {
1311
+ return `[${value.constructor?.name ?? 'Object'}]`;
1312
+ }
1313
+ seen.add(value);
1314
+ if (Array.isArray(value)) {
1315
+ return value.map((item) => normalizeForIdentity(item, seen, depth + 1));
1316
+ }
1317
+ if (value instanceof Map) {
1318
+ return [...value.entries()]
1319
+ .map(([key, entryValue]) => [
1320
+ normalizeForIdentity(key, seen, depth + 1),
1321
+ normalizeForIdentity(entryValue, seen, depth + 1),
1322
+ ])
1323
+ .sort((left, right) => stableStringify(left).localeCompare(stableStringify(right)));
1324
+ }
1325
+ if (value instanceof Set) {
1326
+ return [...value.values()]
1327
+ .map((entry) => normalizeForIdentity(entry, seen, depth + 1))
1328
+ .sort((left, right) => stableStringify(left).localeCompare(stableStringify(right)));
1329
+ }
1330
+ const record = value;
1331
+ const normalized = {
1332
+ constructor: value.constructor?.name,
1333
+ };
1334
+ for (const key of Object.keys(record).sort()) {
1335
+ normalized[key] = normalizeForIdentity(record[key], seen, depth + 1);
1336
+ }
1337
+ return normalized;
1338
+ }
1339
+ function stableStringify(value) {
1340
+ return JSON.stringify(value, (_key, currentValue) => {
1341
+ if (!currentValue ||
1342
+ typeof currentValue !== 'object' ||
1343
+ Array.isArray(currentValue)) {
1344
+ return currentValue;
1345
+ }
1346
+ return Object.fromEntries(Object.entries(currentValue).sort(([left], [right]) => left.localeCompare(right)));
1347
+ });
1348
+ }
1349
+ function serializeAgentReference(agent, agentIdentityKeys) {
1350
+ const identity = agentIdentityKeys.get(agent);
1351
+ if (!identity || identity === agent.name) {
1352
+ return { name: agent.name };
1353
+ }
1354
+ return { name: agent.name, identity };
1355
+ }
1356
+ function resolveSerializedAgent(serializedAgent, agentMap, fallbackAgent) {
1357
+ const identity = serializedAgent.identity ?? serializedAgent.name;
1358
+ const agent = agentMap.get(identity);
1359
+ if (agent) {
1360
+ return agent;
1361
+ }
1362
+ if (!serializedAgent.identity && fallbackAgent) {
1363
+ return fallbackAgent;
1364
+ }
1365
+ if (serializedAgent.identity) {
1366
+ throw new UserError(`Agent identity ${serializedAgent.identity} not found`);
1367
+ }
1368
+ throw new UserError(`Agent ${serializedAgent.name} not found`);
1369
+ }
1370
+ function serializeRunItem(item, agentIdentityKeys) {
1371
+ const serialized = item.toJSON();
1372
+ switch (item.type) {
1373
+ case 'handoff_output_item':
1374
+ serialized.sourceAgent = serializeAgentReference(item.sourceAgent, agentIdentityKeys);
1375
+ serialized.targetAgent = serializeAgentReference(item.targetAgent, agentIdentityKeys);
1376
+ return serialized;
1377
+ default:
1378
+ serialized.agent = serializeAgentReference(item.agent, agentIdentityKeys);
1379
+ return serialized;
1380
+ }
1381
+ }
1382
+ function serializeCurrentStep(currentStep, agentIdentityKeys) {
1383
+ if (!currentStep) {
1384
+ return undefined;
1385
+ }
1386
+ if (currentStep.type === 'next_step_handoff') {
1387
+ return {
1388
+ ...currentStep,
1389
+ newAgent: serializeAgentReference(currentStep.newAgent, agentIdentityKeys),
1390
+ };
1391
+ }
1392
+ if (currentStep.type === 'next_step_interruption') {
1393
+ const interruptions = Array.isArray(currentStep.data?.interruptions)
1394
+ ? currentStep.data.interruptions.map((item) => item instanceof RunToolApprovalItem
1395
+ ? serializeRunItem(item, agentIdentityKeys)
1396
+ : item)
1397
+ : currentStep.data?.interruptions;
1398
+ return {
1399
+ ...currentStep,
1400
+ data: {
1401
+ ...currentStep.data,
1402
+ interruptions,
1403
+ },
1404
+ };
1405
+ }
1406
+ return currentStep;
1407
+ }
1408
+ function serializeProcessedResponse(processedResponse, agentIdentityKeys) {
1409
+ return {
1410
+ ...processedResponse,
1411
+ newItems: processedResponse.newItems.map((item) => serializeRunItem(item, agentIdentityKeys)),
1412
+ };
1413
+ }
1143
1414
  /**
1144
1415
  * @internal
1145
1416
  */
@@ -1178,23 +1449,23 @@ export function deserializeModelResponse(serializedModelResponse) {
1178
1449
  export function deserializeItem(serializedItem, agentMap) {
1179
1450
  switch (serializedItem.type) {
1180
1451
  case 'message_output_item':
1181
- return new RunMessageOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
1452
+ return new RunMessageOutputItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap));
1182
1453
  case 'tool_search_call_item':
1183
- return new RunToolSearchCallItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
1454
+ return new RunToolSearchCallItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap));
1184
1455
  case 'tool_search_output_item':
1185
- return new RunToolSearchOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
1456
+ return new RunToolSearchOutputItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap));
1186
1457
  case 'tool_call_item':
1187
- return new RunToolCallItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
1458
+ return new RunToolCallItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap));
1188
1459
  case 'tool_call_output_item':
1189
- return new RunToolCallOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name), serializedItem.output);
1460
+ return new RunToolCallOutputItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap), serializedItem.output);
1190
1461
  case 'reasoning_item':
1191
- return new RunReasoningItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
1462
+ return new RunReasoningItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap));
1192
1463
  case 'handoff_call_item':
1193
- return new RunHandoffCallItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name));
1464
+ return new RunHandoffCallItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap));
1194
1465
  case 'handoff_output_item':
1195
- return new RunHandoffOutputItem(serializedItem.rawItem, agentMap.get(serializedItem.sourceAgent.name), agentMap.get(serializedItem.targetAgent.name));
1466
+ return new RunHandoffOutputItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.sourceAgent, agentMap), resolveSerializedAgent(serializedItem.targetAgent, agentMap));
1196
1467
  case 'tool_approval_item':
1197
- return new RunToolApprovalItem(serializedItem.rawItem, agentMap.get(serializedItem.agent.name), serializedItem.toolName);
1468
+ return new RunToolApprovalItem(serializedItem.rawItem, resolveSerializedAgent(serializedItem.agent, agentMap), serializedItem.toolName);
1198
1469
  }
1199
1470
  }
1200
1471
  function deserializeInterruptionItem(serializedItem, agentMap, currentAgent) {
@@ -1204,7 +1475,7 @@ function deserializeInterruptionItem(serializedItem, agentMap, currentAgent) {
1204
1475
  const parsed = itemSchema.safeParse(serializedItem);
1205
1476
  if (parsed.success) {
1206
1477
  if (parsed.data.type === 'tool_approval_item') {
1207
- const mappedAgent = agentMap.get(parsed.data.agent.name) ?? currentAgent;
1478
+ const mappedAgent = resolveSerializedAgent(parsed.data.agent, agentMap, currentAgent);
1208
1479
  return new RunToolApprovalItem(parsed.data.rawItem, mappedAgent, parsed.data.toolName);
1209
1480
  }
1210
1481
  const item = deserializeItem(parsed.data, agentMap);
@@ -1228,7 +1499,15 @@ function deserializeInterruptionItem(serializedItem, agentMap, currentAgent) {
1228
1499
  const agentName = value.agent && typeof value.agent.name === 'string'
1229
1500
  ? value.agent.name
1230
1501
  : undefined;
1231
- const mappedAgent = (agentName ? agentMap.get(agentName) : undefined) ?? currentAgent;
1502
+ const agentIdentity = value.agent && typeof value.agent.identity === 'string'
1503
+ ? value.agent.identity
1504
+ : undefined;
1505
+ const mappedAgent = agentName || agentIdentity
1506
+ ? resolveSerializedAgent({
1507
+ name: agentName ?? currentAgent.name,
1508
+ identity: agentIdentity,
1509
+ }, agentMap, currentAgent)
1510
+ : currentAgent;
1232
1511
  const toolName = typeof value.toolName === 'string'
1233
1512
  ? value.toolName
1234
1513
  : typeof rawItem.name === 'string'