@copilotkit/core 1.75.1 → 1.76.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.
package/dist/index.cjs CHANGED
@@ -7,6 +7,23 @@ let rxjs_operators = require("rxjs/operators");
7
7
  let phoenix = require("phoenix");
8
8
  let zod_to_json_schema = require("zod-to-json-schema");
9
9
 
10
+ //#region src/utils/http-agent.ts
11
+ /**
12
+ * Whether an agent is an `HttpAgent`, including one built from another copy of
13
+ * `@ag-ui/client` (an app that pins its own 0.x version next to CopilotKit's
14
+ * 1.0, for example). `instanceof` is false across package copies, which made
15
+ * CopilotKit silently skip headers and abort wiring for those agents. The
16
+ * fallback checks the public fields CopilotKit uses, which every published
17
+ * `HttpAgent` has.
18
+ */
19
+ function ɵisHttpAgent(agent) {
20
+ if (agent instanceof _ag_ui_client.HttpAgent) return true;
21
+ if (typeof agent !== "object" || agent === null) return false;
22
+ const candidate = agent;
23
+ return typeof candidate.url === "string" && typeof candidate.headers === "object" && candidate.headers !== null && candidate.abortController instanceof AbortController && typeof candidate.runAgent === "function";
24
+ }
25
+
26
+ //#endregion
10
27
  //#region src/utils/connect-replay.ts
11
28
  /**
12
29
  * Runs an agent's `connect()` stream through the AbstractAgent apply pipeline
@@ -23,18 +40,27 @@ let zod_to_json_schema = require("zod-to-json-schema");
23
40
  * Cannot send event type 'RUN_STARTED': The run has already errored with
24
41
  * 'RUN_ERROR'. No further events can be sent.
25
42
  *
26
- * `transformChunks` is still applied — message reassembly is needed either way.
43
+ * The AG-UI 1.0 compatibility boundary still runs first, so stored 0.x history
44
+ * is translated (THINKING_* events, `binary` parts, legacy nulls) exactly as in
45
+ * the base pipeline. `enforceEvents` is omitted too: a replay is stored
46
+ * history, and one event that the 1.0 schema rejects (the Intelligence gateway
47
+ * replays RUN_STARTED without `runId`, for example) must not stop the whole
48
+ * thread from hydrating. That keeps the leniency this path had before 1.0.
27
49
  *
28
50
  * Connection-local replay hooks track the phase before applying events. An
29
51
  * explicitly live RUN_ERROR clears busy without closing the connection;
30
52
  * historical errors remain data. Connections without hooks retain the existing
31
- * completion behavior. Subscriber, detach, and result contracts are preserved.
53
+ * completion behavior.
54
+ *
55
+ * Apart from the above, this mirrors the base `AbstractAgent.connectAgent`
56
+ * implementation, so callers keep the same subscriber notifications, detach
57
+ * semantics, and `{ result, newMessages }` return shape.
32
58
  *
33
59
  * TODO: Remove this in favour of the base implementation once AG-UI's
34
60
  * AbstractAgent supports opting out of `verifyEvents` for transports whose
35
61
  * connection life-cycle isn't a single run AND preserves the connection-local
36
62
  * replay lifecycle and running-state behavior below. Skipping verification alone
37
- * is insufficient. As of `@ag-ui/client@0.0.57`
63
+ * is insufficient. As of `@ag-ui/client@1.0.1`
38
64
  * `connectAgent(parameters?, subscriber?)` takes no such option.
39
65
  *
40
66
  * @param agent - The agent whose `connect()` stream should be consumed.
@@ -43,6 +69,9 @@ let zod_to_json_schema = require("zod-to-json-schema");
43
69
  */
44
70
  async function ɵconnectWithoutEventVerification(agent, parameters, subscriber, connect) {
45
71
  const self = agent;
72
+ let finalizeRun = () => {
73
+ agent.isRunning = false;
74
+ };
46
75
  try {
47
76
  agent.isRunning = true;
48
77
  agent.agentId = agent.agentId ?? (0, _ag_ui_client.randomUUID)();
@@ -66,12 +95,35 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber,
66
95
  ...agent.subscribers,
67
96
  subscriber ?? {}
68
97
  ];
69
- await self.onInitialize(input, subscribers);
70
- self.activeRunDetach$ = new rxjs.Subject();
98
+ const activeRunDetach$ = new rxjs.Subject();
99
+ self.activeRunDetach$ = activeRunDetach$;
71
100
  let resolveCompletion;
72
101
  self.activeRunCompletionPromise = new Promise((resolve) => {
73
102
  resolveCompletion = resolve;
74
103
  });
104
+ let detached = false;
105
+ let finalized = false;
106
+ const detachSubscription = activeRunDetach$.subscribe(() => {
107
+ detached = true;
108
+ });
109
+ finalizeRun = () => {
110
+ if (finalized) return;
111
+ finalized = true;
112
+ detachSubscription.unsubscribe();
113
+ if (self.activeRunDetach$ === activeRunDetach$) {
114
+ agent.isRunning = false;
115
+ self.activeRunCompletionPromise = void 0;
116
+ self.activeRunDetach$ = void 0;
117
+ self.onFinalize(input, subscribers);
118
+ }
119
+ resolveCompletion?.();
120
+ resolveCompletion = void 0;
121
+ };
122
+ await self.onInitialize(input, subscribers);
123
+ if (detached) return {
124
+ result: void 0,
125
+ newMessages: []
126
+ };
75
127
  const lifecycle = {
76
128
  onReplayStarted: () => {
77
129
  isReplaying = true;
@@ -81,29 +133,23 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber,
81
133
  isReplaying = false;
82
134
  }
83
135
  };
84
- const source$ = (0, rxjs.defer)(() => connect ? connect(input, lifecycle) : self.connect(input)).pipe((0, rxjs_operators.tap)((event) => {
136
+ const source$ = (0, rxjs.defer)(() => new _ag_ui_client.CompatibilityBoundary().run(input, { run: () => connect ? connect(input, lifecycle) : self.connect(input) })).pipe((0, rxjs_operators.tap)((event) => {
85
137
  if (!isReplaying && event.type === _ag_ui_client.EventType.RUN_ERROR) liveErrors.add(event);
86
- }), (0, _ag_ui_client.transformChunks)(self.debugLogger), (0, rxjs_operators.takeUntil)(self.activeRunDetach$));
138
+ }), (0, _ag_ui_client.transformChunks)(self.debugLogger), (0, rxjs_operators.takeUntil)(activeRunDetach$));
87
139
  const applied$ = self.apply(input, source$, subscribers);
88
140
  await (0, rxjs.lastValueFrom)(self.processApplyEvents(input, applied$, subscribers).pipe((0, rxjs_operators.catchError)((error) => {
141
+ if (self.activeRunDetach$ !== activeRunDetach$) return rxjs.EMPTY;
89
142
  agent.isRunning = false;
90
143
  if (error instanceof _ag_ui_client.AGUIConnectNotImplementedError) return rxjs.EMPTY;
91
144
  return self.onError(input, error, subscribers);
92
- }), (0, rxjs_operators.finalize)(() => {
93
- agent.isRunning = false;
94
- self.onFinalize(input, subscribers);
95
- resolveCompletion?.();
96
- resolveCompletion = void 0;
97
- self.activeRunCompletionPromise = void 0;
98
- self.activeRunDetach$ = void 0;
99
- })), { defaultValue: void 0 });
145
+ }), (0, rxjs_operators.finalize)(() => finalizeRun())), { defaultValue: void 0 });
100
146
  const newMessages = (0, _ag_ui_client.structuredClone_)(agent.messages).filter((m) => !previousMessageIds.has(m.id));
101
147
  return {
102
148
  result,
103
149
  newMessages
104
150
  };
105
151
  } finally {
106
- agent.isRunning = false;
152
+ finalizeRun();
107
153
  }
108
154
  }
109
155
 
@@ -586,7 +632,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
586
632
  observeThreadEvents$(threadId, channel$, options) {
587
633
  return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), (0, rxjs_operators.tap)((payload) => {
588
634
  this.updateLastSeenEventId(threadId, payload);
589
- }), (0, rxjs_operators.mergeMap)((payload) => this.createThreadNotifications(payload, {
635
+ }), (0, rxjs_operators.map)((payload) => options.streamMode === "run" ? (0, _copilotkit_shared.stripIntelligenceRoutingFields)(payload) : payload), (0, rxjs_operators.mergeMap)((payload) => this.createThreadNotifications(payload, {
590
636
  completeOnRunError: options.completeOnRunError,
591
637
  completeOnRunFinished: options.streamMode === "run",
592
638
  errorOnRunError: options.streamMode === "run"
@@ -840,6 +886,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
840
886
  _capabilities;
841
887
  delegate;
842
888
  runtimeInfoPromise;
889
+ connectionAttempt;
843
890
  _messageFilter;
844
891
  /**
845
892
  * The HTTP `run` this agent started and has not yet seen finish, as the
@@ -902,13 +949,12 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
902
949
  this.runtimeMode = runtimeMode;
903
950
  this.intelligence = intelligence;
904
951
  if (unchanged) return;
952
+ this.connectionAttempt = void 0;
905
953
  this.runtimeInfoPromise = void 0;
906
954
  const staleDelegate = this.delegate;
907
955
  this.delegate = void 0;
908
- if (staleDelegate) {
909
- staleDelegate.abortRun();
910
- this.detachActiveRun();
911
- }
956
+ if (staleDelegate) staleDelegate.abortRun();
957
+ this.detachActiveRun();
912
958
  }
913
959
  /**
914
960
  * The agent id used for outbound runtime requests — `runtimeAgentId` when
@@ -999,8 +1045,11 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
999
1045
  return this._capabilities ?? {};
1000
1046
  }
1001
1047
  async detachActiveRun() {
1002
- if (this.delegate) await this.delegate.detachActiveRun();
1003
- await super.detachActiveRun();
1048
+ this.connectionAttempt = void 0;
1049
+ this.isRunning = false;
1050
+ const delegateDetach = this.delegate?.detachActiveRun();
1051
+ const proxyDetach = super.detachActiveRun();
1052
+ await Promise.all([delegateDetach, proxyDetach]);
1004
1053
  }
1005
1054
  abortRun() {
1006
1055
  if (this.delegate) {
@@ -1054,41 +1103,74 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1054
1103
  });
1055
1104
  }
1056
1105
  async connectAgent(parameters, subscriber) {
1106
+ const detached = this.detachActiveRun();
1107
+ const connection = {};
1108
+ const threadId = this.threadId;
1109
+ this.connectionAttempt = connection;
1110
+ const isCurrentConnection = () => this.connectionAttempt === connection && this.threadId === threadId;
1111
+ await detached;
1112
+ if (!isCurrentConnection()) return {
1113
+ result: void 0,
1114
+ newMessages: []
1115
+ };
1116
+ await this.ensureRuntimeConfiguration();
1117
+ if (!isCurrentConnection()) return {
1118
+ result: void 0,
1119
+ newMessages: []
1120
+ };
1057
1121
  if (this.runtimeMode !== _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return ɵconnectWithoutEventVerification(this, parameters, subscriber, (input, lifecycle) => this.connect(input, lifecycle));
1058
- if (this.delegate) await this.delegate.detachActiveRun();
1059
1122
  await this.resolveDelegate();
1123
+ if (!isCurrentConnection()) return {
1124
+ result: void 0,
1125
+ newMessages: []
1126
+ };
1060
1127
  const delegate = this.delegate;
1061
1128
  const bridgeSub = delegate.subscribe({
1062
1129
  onMessagesChanged: () => {
1130
+ if (!isCurrentConnection()) return;
1063
1131
  this.setMessages([...delegate.messages]);
1064
1132
  },
1065
1133
  onStateChanged: () => {
1134
+ if (!isCurrentConnection()) return;
1066
1135
  this.setState({ ...delegate.state });
1067
1136
  },
1068
1137
  onRunInitialized: () => {
1138
+ if (!isCurrentConnection()) return;
1069
1139
  this.isRunning = true;
1070
1140
  },
1071
1141
  onRunFinalized: () => {
1142
+ if (!isCurrentConnection()) return;
1143
+ this.pendingInterrupts = (0, _ag_ui_client.structuredClone_)(delegate.pendingInterrupts);
1072
1144
  this.isRunning = false;
1073
1145
  },
1074
1146
  onRunFailed: () => {
1147
+ if (!isCurrentConnection()) return;
1075
1148
  this.isRunning = false;
1076
1149
  },
1077
1150
  onRunErrorEvent: () => {
1151
+ if (!isCurrentConnection()) return;
1078
1152
  this.isRunning = delegate.isRunning;
1079
1153
  },
1080
1154
  onRunStartedEvent: () => {
1155
+ if (!isCurrentConnection()) return;
1081
1156
  this.isRunning = delegate.isRunning;
1082
1157
  }
1083
1158
  });
1084
- const forwardedSubs = this.subscribers.map((s) => delegate.subscribe(s));
1159
+ const forwardedSubs = [...this.subscribers, ...subscriber ? [subscriber] : []].map((subscriber) => delegate.subscribe(new Proxy(subscriber, { get(target, property, receiver) {
1160
+ const callback = Reflect.get(target, property, receiver);
1161
+ if (typeof callback !== "function") return callback;
1162
+ return (...args) => isCurrentConnection() ? Reflect.apply(callback, target, args) : void 0;
1163
+ } })));
1085
1164
  try {
1086
- const result = await delegate.connectAgent(parameters, subscriber);
1087
- this.setMessages([...delegate.messages]);
1088
- this.setState({ ...delegate.state });
1165
+ const result = await delegate.connectAgent(parameters);
1166
+ if (isCurrentConnection()) {
1167
+ this.setMessages([...delegate.messages]);
1168
+ this.setState({ ...delegate.state });
1169
+ this.pendingInterrupts = (0, _ag_ui_client.structuredClone_)(delegate.pendingInterrupts);
1170
+ }
1089
1171
  return result;
1090
1172
  } finally {
1091
- this.isRunning = false;
1173
+ if (isCurrentConnection()) this.isRunning = false;
1092
1174
  bridgeSub.unsubscribe();
1093
1175
  for (const sub of forwardedSubs) sub.unsubscribe();
1094
1176
  }
@@ -1110,14 +1192,31 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1110
1192
  const input = this.#applyMessageFilter(unfiltered);
1111
1193
  this.activeRun = void 0;
1112
1194
  const routedId = this.routedAgentId();
1195
+ let httpEvents;
1113
1196
  if (this.transport === "single") {
1114
1197
  if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
1115
1198
  const requestInit = this.createSingleRouteRequestInit(input, "agent/connect", { agentId: routedId });
1116
- return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(() => this.fetch(this.singleEndpointUrl, requestInit))));
1199
+ httpEvents = (0, _ag_ui_client.runHttpRequest)(() => this.fetch(this.singleEndpointUrl, requestInit));
1200
+ } else {
1201
+ const connectUrl = `${this.runtimeUrl}/agent/${routedId}/connect`;
1202
+ const connectRequestInit = this.requestInit(input);
1203
+ httpEvents = (0, _ag_ui_client.runHttpRequest)(() => this.fetch(connectUrl, connectRequestInit));
1117
1204
  }
1118
- const connectUrl = `${this.runtimeUrl}/agent/${routedId}/connect`;
1119
- const connectRequestInit = this.requestInit(input);
1120
- return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(() => this.fetch(connectUrl, connectRequestInit))));
1205
+ return withAbortErrorHandling((0, rxjs.defer)(() => {
1206
+ let replayStarted = false;
1207
+ const emptyHistory = [{
1208
+ type: _ag_ui_client.EventType.MESSAGES_SNAPSHOT,
1209
+ messages: []
1210
+ }, {
1211
+ type: _ag_ui_client.EventType.STATE_SNAPSHOT,
1212
+ snapshot: {}
1213
+ }];
1214
+ return (0, _ag_ui_client.transformHttpEventStream)(httpEvents).pipe((0, rxjs_operators.concatMap)((event) => {
1215
+ if (replayStarted) return (0, rxjs.of)(event);
1216
+ replayStarted = true;
1217
+ return (0, rxjs.from)([...emptyHistory, event]);
1218
+ }), (0, rxjs_operators.concatWith)((0, rxjs.defer)(() => replayStarted ? rxjs.EMPTY : (0, rxjs.from)(emptyHistory))));
1219
+ }));
1121
1220
  }
1122
1221
  #runViaDelegate(input) {
1123
1222
  return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.run(input))));
@@ -1160,6 +1259,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1160
1259
  cloned.threadId = this.threadId;
1161
1260
  cloned.setState(this.state);
1162
1261
  cloned.setMessages(this.messages);
1262
+ cloned.pendingInterrupts = (0, _ag_ui_client.structuredClone_)(this.pendingInterrupts);
1163
1263
  if (this.delegate) {
1164
1264
  const clonedDelegate = this.delegate.clone();
1165
1265
  cloned.delegate = clonedDelegate;
@@ -1197,6 +1297,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1197
1297
  if (this.runtimeMode === _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE || this.runtimeMode !== "pending" && this.transport !== "auto") return;
1198
1298
  if (!this.runtimeUrl) throw new Error("Runtime URL is not set");
1199
1299
  const runtimeInfoPromise = this.runtimeInfoPromise ?? this.fetchRuntimeInfo().then((runtimeInfo) => {
1300
+ if (this.runtimeInfoPromise !== runtimeInfoPromise) return;
1200
1301
  this.runtimeMode = runtimeInfo.mode ?? _copilotkit_shared.RUNTIME_MODE_SSE;
1201
1302
  this.intelligence = runtimeInfo.intelligence;
1202
1303
  });
@@ -1301,6 +1402,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1301
1402
  delegate.debugLogger = this.debugLogger;
1302
1403
  delegate.setMessages(this.messages);
1303
1404
  delegate.setState(this.state);
1405
+ delegate.pendingInterrupts = (0, _ag_ui_client.structuredClone_)(this.pendingInterrupts);
1304
1406
  if (hasHeaders(delegate)) delegate.headers = { ...this.headers };
1305
1407
  if (hasCredentials(delegate)) delegate.credentials = this.credentials;
1306
1408
  }
@@ -1736,7 +1838,7 @@ var AgentRegistry = class {
1736
1838
  * because only `HttpAgent` carries a `headers` field. See #5635.
1737
1839
  */
1738
1840
  applyHeadersToAgent(agent) {
1739
- if (agent instanceof _ag_ui_client.HttpAgent) {
1841
+ if (ɵisHttpAgent(agent)) {
1740
1842
  if (!this.agentOwnHeaders.has(agent)) this.agentOwnHeaders.set(agent, { ...agent.headers });
1741
1843
  agent.headers = {
1742
1844
  ...this.agentOwnHeaders.get(agent),
@@ -3087,6 +3189,7 @@ var RunHandler = class {
3087
3189
  * inspector and intermittent "Message not found" toasts.
3088
3190
  */
3089
3191
  _lastConnectedThreadIdsByAgent = /* @__PURE__ */ new Map();
3192
+ _lastActiveThreadIdsByAgent = /* @__PURE__ */ new Map();
3090
3193
  _anonymousAgentIds = /* @__PURE__ */ new WeakMap();
3091
3194
  _nextAnonymousAgentId = 0;
3092
3195
  /** Prevent reconnects from starting an interaction already executing locally. */
@@ -3264,7 +3367,8 @@ var RunHandler = class {
3264
3367
  * Connect an agent (establish initial connection)
3265
3368
  */
3266
3369
  async connectAgent({ agent }) {
3267
- this._connectionGenerations.set(agent, {});
3370
+ const connection = {};
3371
+ this._connectionGenerations.set(agent, connection);
3268
3372
  const incomingThreadId = agent.threadId ?? null;
3269
3373
  const previousReplay = this._interactionAbortControllers.get(agent);
3270
3374
  if (previousReplay && previousReplay.threadId !== incomingThreadId) {
@@ -3274,12 +3378,19 @@ var RunHandler = class {
3274
3378
  }
3275
3379
  try {
3276
3380
  const restoreKey = this.getConnectRestoreKey(agent);
3277
- const isFreshRestore = incomingThreadId !== (this._lastConnectedThreadIdsByAgent.get(restoreKey) ?? null);
3278
- this._lastConnectedThreadIdsByAgent.set(restoreKey, incomingThreadId);
3381
+ const previousThreadId = this._lastActiveThreadIdsByAgent.get(restoreKey);
3382
+ const isFreshRestore = incomingThreadId !== (previousThreadId ?? this._lastConnectedThreadIdsByAgent.get(restoreKey) ?? null);
3279
3383
  await agent.detachActiveRun();
3384
+ if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return {
3385
+ result: void 0,
3386
+ newMessages: []
3387
+ };
3388
+ this._lastConnectedThreadIdsByAgent.set(restoreKey, incomingThreadId);
3389
+ this._lastActiveThreadIdsByAgent.set(restoreKey, incomingThreadId);
3280
3390
  if (isFreshRestore) {
3281
3391
  agent.setMessages([]);
3282
3392
  agent.setState({});
3393
+ if (previousThreadId !== void 0 && previousThreadId !== incomingThreadId) agent.pendingInterrupts = [];
3283
3394
  const cursorAware = agent;
3284
3395
  if (incomingThreadId) {
3285
3396
  if (typeof cursorAware.clearReplayCursor === "function") cursorAware.clearReplayCursor(incomingThreadId);
@@ -3291,12 +3402,16 @@ var RunHandler = class {
3291
3402
  copilotkit: this.core,
3292
3403
  agent
3293
3404
  }), "Subscriber onAgentRunStarted error:");
3405
+ if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return {
3406
+ result: void 0,
3407
+ newMessages: []
3408
+ };
3294
3409
  const runAgentResult = await agent.connectAgent({
3295
3410
  forwardedProps: this._internal.properties,
3296
3411
  tools: this.buildFrontendTools(agent.agentId),
3297
3412
  context: this._internal.getContextForAgent(agent.agentId)
3298
3413
  }, this.createAgentErrorSubscriber(agent));
3299
- if ((agent.threadId ?? null) !== incomingThreadId) return runAgentResult;
3414
+ if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return runAgentResult;
3300
3415
  const controller = new AbortController();
3301
3416
  const replay = this._interactionAbortControllers.get(agent) ?? {
3302
3417
  threadId: incomingThreadId,
@@ -3353,6 +3468,12 @@ var RunHandler = class {
3353
3468
  continuationHandoff?.cancel();
3354
3469
  throw error;
3355
3470
  }
3471
+ const resumedRunId = this._internal.stateManager.getContinuationRunId(agent, {
3472
+ threadId: agent.threadId,
3473
+ resume,
3474
+ forwardedProps
3475
+ });
3476
+ const logicalHandoff = continuationHandoff ?? (resumedRunId ? this._internal.stateManager.markNextRunAsContinuation(agent, resumedRunId) : void 0);
3356
3477
  const isTopLevel = this._runDepth === 0;
3357
3478
  let originalAbortRun;
3358
3479
  if (isTopLevel) {
@@ -3370,18 +3491,19 @@ var RunHandler = class {
3370
3491
  }
3371
3492
  this._runDepth++;
3372
3493
  try {
3373
- let logicalRunId = runId;
3494
+ let logicalRunId = resumedRunId ?? runId;
3374
3495
  const agentSubscriber = this.createAgentErrorSubscriber(agent);
3375
3496
  let started = false;
3376
3497
  const onRunStartedEvent = agentSubscriber.onRunStartedEvent;
3377
3498
  const onRunInitialized = agentSubscriber.onRunInitialized;
3378
3499
  agentSubscriber.onRunInitialized = async (params) => {
3379
- continuationHandoff?.bind(params.input);
3500
+ this._lastActiveThreadIdsByAgent.set(this.getConnectRestoreKey(agent), params.input.threadId);
3501
+ logicalHandoff?.bind(params.input);
3380
3502
  return onRunInitialized?.(params);
3381
3503
  };
3382
3504
  agentSubscriber.onRunStartedEvent = async (params) => {
3383
3505
  started = true;
3384
- if (!continuationHandoff) logicalRunId = params.input.runId;
3506
+ if (!logicalHandoff) logicalRunId = params.input.runId;
3385
3507
  return onRunStartedEvent?.(params);
3386
3508
  };
3387
3509
  const pinRunIdOnWire = runId !== void 0 && !continuationHandoff;
@@ -3396,14 +3518,14 @@ var RunHandler = class {
3396
3518
  context: this._internal.getContextForAgent(agent.agentId)
3397
3519
  };
3398
3520
  const runAgentResult = await agent.runAgent(agentRunInput, agentSubscriber);
3399
- if (!started) continuationHandoff?.cancel();
3521
+ if (!started) logicalHandoff?.cancel();
3400
3522
  return await this.processAgentResult({
3401
3523
  runAgentResult,
3402
3524
  agent,
3403
3525
  runId: logicalRunId
3404
3526
  });
3405
3527
  } catch (error) {
3406
- continuationHandoff?.cancel();
3528
+ logicalHandoff?.cancel();
3407
3529
  const runError = error instanceof Error ? error : new Error(String(error));
3408
3530
  const context = {};
3409
3531
  if (agent.agentId) context.agentId = agent.agentId;
@@ -3945,6 +4067,15 @@ var StateManager = class {
3945
4067
  activeRun = /* @__PURE__ */ new Map();
3946
4068
  agentSubscriptions = /* @__PURE__ */ new Map();
3947
4069
  pendingContinuations = /* @__PURE__ */ new WeakMap();
4070
+ interruptedRuns = /* @__PURE__ */ new WeakMap();
4071
+ /** Find the interrupted logical run without consuming its pending answers. */
4072
+ getContinuationRunId(agent, input) {
4073
+ const pending = this.interruptedRuns.get(agent)?.get(input.threadId);
4074
+ if (!pending) return void 0;
4075
+ if (pending.interruptIds === null) return input.resume === void 0 && isContinuation(input) ? pending.runId : void 0;
4076
+ const submitted = new Set(input.resume?.map((entry) => entry.interruptId));
4077
+ return submitted.size > 0 && submitted.size === input.resume?.length && submitted.size === pending.interruptIds.length && pending.interruptIds.every((id) => submitted.has(id)) ? pending.runId : void 0;
4078
+ }
3948
4079
  constructor(core) {
3949
4080
  this.core = core;
3950
4081
  }
@@ -3988,6 +4119,7 @@ var StateManager = class {
3988
4119
  }
3989
4120
  let revoked = false;
3990
4121
  let subRunId;
4122
+ let legacyInterrupted = false;
3991
4123
  let runFinished = false;
3992
4124
  const pendingResults = /* @__PURE__ */ new WeakMap();
3993
4125
  const reconcilePendingResults = (historyMessages, input) => {
@@ -4053,21 +4185,43 @@ var StateManager = class {
4053
4185
  if (revoked) return;
4054
4186
  const internalContinuation = [...this.pendingContinuations.get(agent) ?? []].find((pending) => pending.expectedInput === input);
4055
4187
  internalContinuation?.cancel();
4188
+ const startedInput = event.input ?? {
4189
+ ...input,
4190
+ threadId: event.threadId
4191
+ };
4192
+ const resumedRunId = this.getContinuationRunId(agent, startedInput);
4193
+ this.interruptedRuns.get(agent)?.delete(startedInput.threadId);
4194
+ legacyInterrupted = false;
4056
4195
  if (internalContinuation) subRunId = internalContinuation.expectedRunId ?? event.runId ?? input.runId;
4196
+ else if (resumedRunId) subRunId = resumedRunId;
4057
4197
  else if (runFinished && input.runId === subRunId && !isContinuation(input) && (event.runId == null || event.runId === subRunId)) subRunId = (0, _ag_ui_client.randomUUID)();
4058
4198
  else subRunId = event.runId || input.runId;
4059
4199
  runFinished = false;
4060
4200
  this.handleRunStarted(agent, effectiveInput(input), state);
4061
4201
  },
4062
- onRunFinishedEvent: ({ input, state, messages }) => {
4202
+ onRunFinishedEvent: ({ event, input, state, messages }) => {
4063
4203
  if (revoked) return;
4064
4204
  runFinished = true;
4065
4205
  const effective = effectiveInput(input);
4206
+ let interrupted = this.interruptedRuns.get(agent);
4207
+ if (event.outcome?.type === "interrupt" || legacyInterrupted) {
4208
+ if (!interrupted) {
4209
+ interrupted = /* @__PURE__ */ new Map();
4210
+ this.interruptedRuns.set(agent, interrupted);
4211
+ }
4212
+ interrupted.set(event.threadId, {
4213
+ runId: effective.runId,
4214
+ interruptIds: event.outcome?.type === "interrupt" ? event.outcome.interrupts.map((interrupt) => interrupt.id) : null
4215
+ });
4216
+ } else interrupted?.delete(event.threadId);
4066
4217
  const mutation = reconcilePendingResults(messages, input);
4067
4218
  clearPendingResults(input);
4068
4219
  this.handleRunFinished(agent, effective, state);
4069
4220
  return mutation;
4070
4221
  },
4222
+ onCustomEvent: ({ event }) => {
4223
+ if (!revoked && event.name === "on_interrupt") legacyInterrupted = true;
4224
+ },
4071
4225
  onRunErrorEvent: ({ input, state, messages }) => {
4072
4226
  if (revoked) return;
4073
4227
  runFinished = true;
@@ -4124,6 +4278,7 @@ var StateManager = class {
4124
4278
  unsubscribe: () => {
4125
4279
  revoked = true;
4126
4280
  this.pendingContinuations.delete(agent);
4281
+ this.interruptedRuns.delete(agent);
4127
4282
  unsubscribe();
4128
4283
  }
4129
4284
  });
@@ -4284,6 +4439,8 @@ var StateManager = class {
4284
4439
  * Clear all state for an agent
4285
4440
  */
4286
4441
  clearAgentState(agentId) {
4442
+ const agent = this.agentSubscriptions.get(agentId)?.agent;
4443
+ if (agent) this.interruptedRuns.delete(agent);
4287
4444
  this.stateByRun.delete(agentId);
4288
4445
  this.messageToRun.delete(agentId);
4289
4446
  this.rawEventByMessage.delete(agentId);
@@ -4292,6 +4449,8 @@ var StateManager = class {
4292
4449
  * Clear all state for a thread
4293
4450
  */
4294
4451
  clearThreadState(agentId, threadId) {
4452
+ const agent = this.agentSubscriptions.get(agentId)?.agent;
4453
+ if (agent) this.interruptedRuns.get(agent)?.delete(threadId);
4295
4454
  this.stateByRun.get(agentId)?.delete(threadId);
4296
4455
  this.messageToRun.get(agentId)?.delete(threadId);
4297
4456
  this.rawEventByMessage.get(agentId)?.delete(threadId);
@@ -7407,6 +7566,7 @@ exports.ɵcreateMemoryStore = createMemoryStore;
7407
7566
  exports.ɵcreateThreadSelectors = ɵcreateThreadSelectors;
7408
7567
  exports.ɵcreateThreadStore = createThreadStore;
7409
7568
  exports.ɵisCopilotKitFeature = ɵisCopilotKitFeature;
7569
+ exports.ɵisHttpAgent = ɵisHttpAgent;
7410
7570
  exports.ɵisRetryableMemoryStatus = isRetryableStatus;
7411
7571
  exports.ɵjoinPhoenixChannel$ = ɵjoinPhoenixChannel$;
7412
7572
  exports.ɵmapMemoryMetadataEvent = ɵmapMemoryMetadataEvent;