@copilotkit/core 1.76.0 → 1.77.1

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.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function(global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tanstack/pacer'), require('@ag-ui/client'), require('@copilotkit/shared'), require('rxjs'), require('rxjs/operators'), require('phoenix'), require('zod-to-json-schema')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@tanstack/pacer', '@ag-ui/client', '@copilotkit/shared', 'rxjs', 'rxjs/operators', 'phoenix', 'zod-to-json-schema'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitCore = {}), global._tanstack_pacer,global.AgUIClient,global.CopilotKitShared,global.rxjs,global.rxjs.operators,global.phoenix,global.zodToJsonSchema));
5
- })(this, function(exports, _tanstack_pacer, _ag_ui_client, _copilotkit_shared, rxjs, rxjs_operators, phoenix, zod_to_json_schema) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tanstack/pacer'), require('@ag-ui/client'), require('@copilotkit/shared'), require('rxjs'), require('rxjs/operators'), require('phoenix'), require('zod-to-json-schema'), require('@copilotkit/learning')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@tanstack/pacer', '@ag-ui/client', '@copilotkit/shared', 'rxjs', 'rxjs/operators', 'phoenix', 'zod-to-json-schema', '@copilotkit/learning'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitCore = {}), global._tanstack_pacer,global.AgUIClient,global.CopilotKitShared,global.rxjs,global.rxjs.operators,global.phoenix,global.zodToJsonSchema,global._copilotkit_learning));
5
+ })(this, function(exports, _tanstack_pacer, _ag_ui_client, _copilotkit_shared, rxjs, rxjs_operators, phoenix, zod_to_json_schema, _copilotkit_learning) {
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
7
7
 
8
8
  //#region src/utils/http-agent.ts
@@ -194,10 +194,17 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
194
194
  *
195
195
  * The socket is constructed and connected on subscription, and disconnected on
196
196
  * teardown. Each subscription creates an isolated socket instance.
197
+ *
198
+ * Heartbeats default to every 15s: Phoenix's own 30s default matches common
199
+ * reverse-proxy WebSocket idle timeouts (e.g. Azure Application Gateway), which
200
+ * would drop the socket during a quiet run. Callers may override it.
197
201
  */
198
202
  function ɵphoenixSocket$(options) {
199
203
  return (0, rxjs.defer)(() => {
200
- const socket = new phoenix.Socket(options.url, options.options);
204
+ const socket = new phoenix.Socket(options.url, {
205
+ heartbeatIntervalMs: 15e3,
206
+ ...options.options
207
+ });
201
208
  const signals$ = ɵcreatePhoenixSocketSignals$(socket).pipe((0, rxjs_operators.shareReplay)({
202
209
  bufferSize: 1,
203
210
  refCount: true
@@ -323,6 +330,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
323
330
  const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
324
331
  const CONNECT_IDLE_WARNING_MS = 3e4;
325
332
  const MAX_UNOPENED_CREDENTIAL_REFRESHES = 2;
333
+ function isMcpResourceRead(input) {
334
+ const forwardedProps = input.forwardedProps;
335
+ const request = forwardedProps === null || forwardedProps === void 0 ? void 0 : forwardedProps.__proxiedMCPRequest;
336
+ return (forwardedProps === null || forwardedProps === void 0 ? void 0 : forwardedProps.__copilotkitMcpResourceReadOnly) === true && typeof request === "object" && request !== null && request.method === "resources/read";
337
+ }
326
338
  var AgentThreadLockedError = class extends Error {
327
339
  constructor(threadId) {
328
340
  super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
@@ -430,10 +442,22 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
430
442
  * server-pushed AG-UI events to the Observable subscriber.
431
443
  */
432
444
  run(input) {
433
- this.threadId = input.threadId;
434
- this.canonicalRunId = input.runId;
445
+ if (!isMcpResourceRead(input)) {
446
+ this.threadId = input.threadId;
447
+ this.canonicalRunId = input.runId;
448
+ }
435
449
  return (0, rxjs.defer)(() => this.requestJoinCredentials$("run", input)).pipe((0, rxjs.switchMap)((credentials) => {
436
450
  if (credentials === null) return (0, rxjs.throwError)(() => /* @__PURE__ */ new Error("REST run request returned no credentials"));
451
+ if ("kind" in credentials) return (0, rxjs.of)({
452
+ type: _ag_ui_client.EventType.RUN_STARTED,
453
+ threadId: credentials.threadId,
454
+ runId: credentials.runId
455
+ }, {
456
+ type: _ag_ui_client.EventType.RUN_FINISHED,
457
+ threadId: credentials.threadId,
458
+ runId: credentials.runId,
459
+ result: credentials.result
460
+ });
437
461
  const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: true });
438
462
  return this.observeThread$(canonicalInput, credentials, {
439
463
  completeOnRunError: false,
@@ -527,7 +551,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
527
551
  const text = await response.text().catch(() => "");
528
552
  throw new Error(text || response.statusText || String(response.status));
529
553
  }
530
- return this.normalizeJoinCredentials(await response.json(), input);
554
+ const payload = await response.json();
555
+ if (mode === "run" && isMcpResourceRead(input) && typeof payload === "object" && payload !== null && payload.kind === "mcp-resource-read") {
556
+ const resource = payload;
557
+ if (typeof resource.threadId !== "string" || !resource.threadId || typeof resource.runId !== "string" || !resource.runId) throw new Error("invalid MCP resource response identity");
558
+ return {
559
+ kind: "mcp-resource-read",
560
+ threadId: resource.threadId,
561
+ runId: resource.runId,
562
+ result: resource.result
563
+ };
564
+ }
565
+ return this.normalizeJoinCredentials(payload, input);
531
566
  } catch (error) {
532
567
  if (error instanceof AgentThreadLockedError) throw error;
533
568
  throw new Error(`REST ${mode} request failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
@@ -1268,6 +1303,22 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1268
1303
  }
1269
1304
  return cloned;
1270
1305
  }
1306
+ /** Run presentation-only MCP reads on a separate client agent so their
1307
+ * lifecycle cannot replace an in-flight approval's detach/completion state. */
1308
+ async ɵrunMcpResourceRead(parameters) {
1309
+ var _parameters$forwarded;
1310
+ const request = (_parameters$forwarded = parameters.forwardedProps) === null || _parameters$forwarded === void 0 ? void 0 : _parameters$forwarded.__proxiedMCPRequest;
1311
+ if (typeof request !== "object" || request === null || request.method !== "resources/read") throw new Error("Only MCP resources/read can use the read-only path");
1312
+ await this.ensureRuntimeConfiguration();
1313
+ const resourceParameters = {
1314
+ ...parameters,
1315
+ forwardedProps: {
1316
+ ...parameters.forwardedProps,
1317
+ __copilotkitMcpResourceReadOnly: true
1318
+ }
1319
+ };
1320
+ return this.runtimeMode === _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE ? this.clone().runAgent(resourceParameters) : this.runAgent(resourceParameters);
1321
+ }
1271
1322
  /**
1272
1323
  * Drop the delegate's cached `lastSeenEventId` for this thread so
1273
1324
  * the next connect requests a full historical replay from the
@@ -2015,6 +2066,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2015
2066
  this.applyMessageFilterToAgent(agent);
2016
2067
  });
2017
2068
  }
2069
+ /** Preserve the exact configured URL when posting to a single endpoint. */
2070
+ get runtimeEndpointUrl() {
2071
+ return this._runtimeEndpointUrl;
2072
+ }
2018
2073
  createRuntimeFetch() {
2019
2074
  if (!this.runtimeFetch) this.runtimeFetch = (async (input, init) => {
2020
2075
  const meta = () => runtimeRequestMeta(init);
@@ -3080,6 +3135,68 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3080
3135
  function isForwardedToClientPlaceholder(content) {
3081
3136
  return normalizeToolResultContent(content) === FORWARDED_TO_CLIENT;
3082
3137
  }
3138
+ const MEDIA_PART_TYPES = new Set([
3139
+ "image",
3140
+ "audio",
3141
+ "video",
3142
+ "document"
3143
+ ]);
3144
+ function isOptionalString(value) {
3145
+ return value === void 0 || typeof value === "string";
3146
+ }
3147
+ function isPartSource(value) {
3148
+ if (!value || typeof value !== "object") return false;
3149
+ const source = value;
3150
+ if (typeof source.value !== "string") return false;
3151
+ switch (source.type) {
3152
+ case "data": return typeof source.mimeType === "string";
3153
+ case "url": return isOptionalString(source.mimeType);
3154
+ case "file": return isOptionalString(source.provider) && isOptionalString(source.mimeType);
3155
+ default: return false;
3156
+ }
3157
+ }
3158
+ /**
3159
+ * Mirrors `ContentPartSchema` from `@ag-ui/core/schemas`. The runtime parses
3160
+ * the request with that schema, and one invalid part there fails the whole run.
3161
+ * Core does not import the schema because the UMD build has no global for it.
3162
+ * A test checks this function against the schema.
3163
+ */
3164
+ function isContentPart(value) {
3165
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
3166
+ const part = value;
3167
+ if (!isOptionalString(part.id) || part.metadata === null) return false;
3168
+ if (part.type === "text") return typeof part.text === "string";
3169
+ return typeof part.type === "string" && MEDIA_PART_TYPES.has(part.type) && isPartSource(part.source);
3170
+ }
3171
+ /**
3172
+ * Converts what a frontend tool handler returned into tool message content.
3173
+ * A non-empty array of AG-UI content parts passes through unchanged, so an
3174
+ * image reaches the model as media. Everything else becomes a string, as before.
3175
+ *
3176
+ * `text` is the string form, for surfaces typed as `result: string`
3177
+ * (`runTool`, `onToolExecutionEnd`). For content parts it is the JSON text they
3178
+ * received before. It is computed here, so a part that cannot be serialized
3179
+ * throws inside the caller's handler error boundary.
3180
+ */
3181
+ function toToolResultContent(result) {
3182
+ if (result === void 0 || result === null) return {
3183
+ content: "",
3184
+ text: ""
3185
+ };
3186
+ if (typeof result === "string") return {
3187
+ content: result,
3188
+ text: result
3189
+ };
3190
+ const text = JSON.stringify(result);
3191
+ if (Array.isArray(result) && result.length > 0 && result.every(isContentPart)) return {
3192
+ content: result,
3193
+ text
3194
+ };
3195
+ return {
3196
+ content: text,
3197
+ text
3198
+ };
3199
+ }
3083
3200
 
3084
3201
  //#endregion
3085
3202
  //#region src/core/tool-schema.ts
@@ -3505,7 +3622,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3505
3622
  this.processAgentResult({
3506
3623
  runAgentResult,
3507
3624
  agent,
3508
- toolExecutionMode: "human-in-the-loop",
3625
+ toolExecutionMode: "restore",
3509
3626
  signal: controller.signal
3510
3627
  }).catch(async (error) => {
3511
3628
  await this._internal.emitError({
@@ -3643,11 +3760,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3643
3760
  const threadId = agent.threadId;
3644
3761
  const executing = (_this$_executingToolC = this._executingToolCalls.get(agent)) !== null && _this$_executingToolC !== void 0 ? _this$_executingToolC : /* @__PURE__ */ new Set();
3645
3762
  this._executingToolCalls.set(agent, executing);
3646
- if (toolExecutionMode === "human-in-the-loop" && agent.messages.some((message) => {
3763
+ if (toolExecutionMode === "restore" && agent.messages.some((message) => {
3647
3764
  var _message$toolCalls;
3648
3765
  return message.role === "assistant" && ((_message$toolCalls = message.toolCalls) === null || _message$toolCalls === void 0 ? void 0 : _message$toolCalls.some((call) => executing.has(JSON.stringify([threadId, call.id])) && !agent.messages.some((result) => result.role === "tool" && result.toolCallId === call.id && !this.isFrontendPlaceholderResult(result))));
3649
3766
  })) return runAgentResult;
3650
- const messagesToProcess = toolExecutionMode === "human-in-the-loop" ? [...agent.messages] : newMessages;
3767
+ const messagesToProcess = toolExecutionMode === "restore" ? [...agent.messages] : newMessages;
3651
3768
  for (const message of messagesToProcess) if (message.role === "assistant") for (const toolCall of message.toolCalls || []) {
3652
3769
  var _agent$messages$find;
3653
3770
  const tool = this.getTool({
@@ -3664,7 +3781,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3664
3781
  return wildcardTool;
3665
3782
  };
3666
3783
  const executableTool = tool !== null && tool !== void 0 ? tool : getWildcardTool();
3667
- if (toolExecutionMode === "human-in-the-loop" && ((executableTool === null || executableTool === void 0 ? void 0 : executableTool.type) !== "human-in-the-loop" || !executableTool.handler)) continue;
3784
+ if (toolExecutionMode === "restore" && (!(executableTool === null || executableTool === void 0 ? void 0 : executableTool.handler) || executableTool.type !== "human-in-the-loop" && executableTool.reconnectBehavior !== "resume-pending")) continue;
3668
3785
  const executionKey = JSON.stringify([threadId, toolCall.id]);
3669
3786
  if ((signal === null || signal === void 0 ? void 0 : signal.aborted) || agent.threadId !== threadId || executing.has(executionKey)) continue;
3670
3787
  const existingResultIndex = newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
@@ -3696,14 +3813,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3696
3813
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) abortInteraction();
3697
3814
  }
3698
3815
  const executionSignal = (_interactionControlle = interactionController === null || interactionController === void 0 ? void 0 : interactionController.signal) !== null && _interactionControlle !== void 0 ? _interactionControlle : signal;
3699
- const discardOnAbort = toolExecutionMode === "human-in-the-loop" || !!interactionController;
3816
+ const discardOnAbort = toolExecutionMode === "restore" || !!interactionController;
3700
3817
  try {
3701
3818
  if (tool) {
3702
- if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId, executionSignal, discardOnAbort)) needsFollowUp = true;
3819
+ if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId, executionSignal, discardOnAbort, toolExecutionMode === "restore")) needsFollowUp = true;
3703
3820
  } else {
3704
3821
  const fallbackTool = getWildcardTool();
3705
3822
  if (fallbackTool) {
3706
- if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId, executionSignal, discardOnAbort)) needsFollowUp = true;
3823
+ if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId, executionSignal, discardOnAbort, toolExecutionMode === "restore")) needsFollowUp = true;
3707
3824
  }
3708
3825
  }
3709
3826
  } finally {
@@ -3740,8 +3857,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3740
3857
  async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId, signal = (() => {
3741
3858
  var _this$_runAbortContro3;
3742
3859
  return (_this$_runAbortContro3 = this._runAbortController) === null || _this$_runAbortContro3 === void 0 ? void 0 : _this$_runAbortContro3.signal;
3743
- })(), discardOnAbort = false }) {
3860
+ })(), discardOnAbort = false, isReplay = false }) {
3744
3861
  let toolCallResult = "";
3862
+ let toolCallText = "";
3745
3863
  let errorMessage;
3746
3864
  let isArgumentError = false;
3747
3865
  let parsedArgs;
@@ -3778,11 +3896,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3778
3896
  const result = await tool.handler(parsedArgs, {
3779
3897
  toolCall,
3780
3898
  agent,
3781
- signal
3899
+ signal,
3900
+ ...isReplay ? { isReplay } : {}
3782
3901
  });
3783
- if (result === void 0 || result === null) toolCallResult = "";
3784
- else if (typeof result === "string") toolCallResult = result;
3785
- else toolCallResult = JSON.stringify(result);
3902
+ ({content: toolCallResult, text: toolCallText} = toToolResultContent(result));
3786
3903
  } catch (error) {
3787
3904
  const handlerError = error instanceof Error ? error : new Error(String(error));
3788
3905
  errorMessage = handlerError.message;
@@ -3799,7 +3916,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3799
3916
  }
3800
3917
  });
3801
3918
  }
3802
- if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
3919
+ if (errorMessage) toolCallResult = toolCallText = `Error: ${errorMessage}`;
3803
3920
  await this._internal.notifySubscribers((subscriber) => {
3804
3921
  var _subscriber$onToolExe2;
3805
3922
  return (_subscriber$onToolExe2 = subscriber.onToolExecutionEnd) === null || _subscriber$onToolExe2 === void 0 ? void 0 : _subscriber$onToolExe2.call(subscriber, {
@@ -3807,12 +3924,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3807
3924
  toolCallId: toolCall.id,
3808
3925
  agentId,
3809
3926
  toolName: toolCall.function.name,
3810
- result: errorMessage ? "" : toolCallResult,
3927
+ result: errorMessage ? "" : toolCallText,
3811
3928
  error: errorMessage
3812
3929
  });
3813
3930
  }, "Subscriber onToolExecutionEnd error:");
3814
3931
  return {
3815
- result: toolCallResult,
3932
+ content: toolCallResult,
3933
+ result: toolCallText,
3816
3934
  error: errorMessage,
3817
3935
  isArgumentError
3818
3936
  };
@@ -3820,10 +3938,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3820
3938
  /**
3821
3939
  * Execute a specific tool
3822
3940
  */
3823
- async executeSpecificTool(tool, toolCall, message, agent, agentId, signal, discardOnAbort = false) {
3941
+ async executeSpecificTool(tool, toolCall, message, agent, agentId, signal, discardOnAbort = false, isReplay = false) {
3824
3942
  const threadId = agent.threadId;
3825
3943
  if ((tool === null || tool === void 0 ? void 0 : tool.agentId) && tool.agentId !== agent.agentId) return false;
3826
3944
  let handlerResult = {
3945
+ content: "",
3827
3946
  result: "",
3828
3947
  error: void 0,
3829
3948
  isArgumentError: false
@@ -3837,7 +3956,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3837
3956
  toolType: "specific",
3838
3957
  messageId: message.id,
3839
3958
  signal,
3840
- discardOnAbort
3959
+ discardOnAbort,
3960
+ isReplay
3841
3961
  });
3842
3962
  {
3843
3963
  var _agent$messages$inser;
@@ -3849,7 +3969,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3849
3969
  id: (0, _copilotkit_shared.randomUUID)(),
3850
3970
  role: "tool",
3851
3971
  toolCallId: toolCall.id,
3852
- content: handlerResult.result
3972
+ content: handlerResult.content
3853
3973
  };
3854
3974
  agent.messages.splice(insertAt, 0, toolMessage);
3855
3975
  if (!handlerResult.error && (tool === null || tool === void 0 ? void 0 : tool.followUp) !== false) return true;
@@ -3862,10 +3982,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3862
3982
  * specific tools, so this method keeps its own arg-wrapping logic rather than
3863
3983
  * delegating to `executeToolHandler`.
3864
3984
  */
3865
- async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId, signal, discardOnAbort = false) {
3985
+ async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId, signal, discardOnAbort = false, isReplay = false) {
3866
3986
  const threadId = agent.threadId;
3867
3987
  if ((wildcardTool === null || wildcardTool === void 0 ? void 0 : wildcardTool.agentId) && wildcardTool.agentId !== agent.agentId) return false;
3868
3988
  let toolCallResult = "";
3989
+ let toolCallText = "";
3869
3990
  let errorMessage;
3870
3991
  if (wildcardTool === null || wildcardTool === void 0 ? void 0 : wildcardTool.handler) {
3871
3992
  let parsedArgs;
@@ -3905,11 +4026,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3905
4026
  const result = await wildcardTool.handler(wildcardArgs, {
3906
4027
  toolCall,
3907
4028
  agent,
3908
- signal
4029
+ signal,
4030
+ ...isReplay ? { isReplay } : {}
3909
4031
  });
3910
- if (result === void 0 || result === null) toolCallResult = "";
3911
- else if (typeof result === "string") toolCallResult = result;
3912
- else toolCallResult = JSON.stringify(result);
4032
+ ({content: toolCallResult, text: toolCallText} = toToolResultContent(result));
3913
4033
  } catch (error) {
3914
4034
  const handlerError = error instanceof Error ? error : new Error(String(error));
3915
4035
  errorMessage = handlerError.message;
@@ -3926,7 +4046,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3926
4046
  }
3927
4047
  });
3928
4048
  }
3929
- if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
4049
+ if (errorMessage) toolCallResult = toolCallText = `Error: ${errorMessage}`;
3930
4050
  await this._internal.notifySubscribers((subscriber) => {
3931
4051
  var _subscriber$onToolExe4;
3932
4052
  return (_subscriber$onToolExe4 = subscriber.onToolExecutionEnd) === null || _subscriber$onToolExe4 === void 0 ? void 0 : _subscriber$onToolExe4.call(subscriber, {
@@ -3934,7 +4054,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3934
4054
  toolCallId: toolCall.id,
3935
4055
  agentId,
3936
4056
  toolName: toolCall.function.name,
3937
- result: errorMessage ? "" : toolCallResult,
4057
+ result: errorMessage ? "" : toolCallText,
3938
4058
  error: errorMessage
3939
4059
  });
3940
4060
  }, "Subscriber onToolExecutionEnd error:");
@@ -4007,6 +4127,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4007
4127
  };
4008
4128
  agent.messages.push(assistantMessage);
4009
4129
  let handlerResult = {
4130
+ content: "",
4010
4131
  result: "",
4011
4132
  error: void 0,
4012
4133
  isArgumentError: false
@@ -4023,7 +4144,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4023
4144
  id: (0, _copilotkit_shared.randomUUID)(),
4024
4145
  role: "tool",
4025
4146
  toolCallId,
4026
- content: handlerResult.result
4147
+ content: handlerResult.content
4027
4148
  };
4028
4149
  const assistantIndex = agent.messages.findIndex((m) => m.id === assistantMessage.id);
4029
4150
  if (assistantIndex !== -1) agent.messages.splice(assistantIndex + 1, 0, toolResultMessage);
@@ -4676,6 +4797,775 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4676
4797
  }
4677
4798
  };
4678
4799
 
4800
+ //#endregion
4801
+ //#region src/core/trajectory-connection.ts
4802
+ const TIMEOUT_MS = 1e4;
4803
+ const BATCH_INTERVAL_MS = 2e3;
4804
+ const MAX_BATCH_EVENTS = 50;
4805
+ const MAX_BATCH_BYTES = 64 * 1024;
4806
+ const MAX_EVENT_BYTES = 16 * 1024;
4807
+ const byteLength = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength;
4808
+ const reconnectDelay = (0, _copilotkit_shared.phoenixExponentialBackoff)(1e3, 1e4);
4809
+ function isObject(value) {
4810
+ return typeof value === "object" && value !== null;
4811
+ }
4812
+ function isNonNegativeInteger(value) {
4813
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
4814
+ }
4815
+ function isBatchAcknowledgement(value, eventCount) {
4816
+ return isObject(value) && isNonNegativeInteger(value.accepted) && isNonNegativeInteger(value.rejected) && value.accepted + value.rejected === eventCount && (value.highestSeq === null || isNonNegativeInteger(value.highestSeq)) && (value.accepted === 0 || value.highestSeq !== null);
4817
+ }
4818
+ function isGrant(value) {
4819
+ return isObject(value) && typeof value.joinToken === "string" && value.joinToken.length > 0 && isObject(value.realtime) && typeof value.realtime.clientUrl === "string" && value.realtime.clientUrl.length > 0 && typeof value.realtime.topic === "string" && value.realtime.topic.length > 0;
4820
+ }
4821
+ function errorCode(value, fallback) {
4822
+ return isObject(value) && typeof value.code === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(value.code) ? value.code : fallback;
4823
+ }
4824
+ /** Owns bounded, connected-only capture batches. Failed batches are never resent. */
4825
+ var TrajectoryConnection = class {
4826
+ constructor(core, onChange) {
4827
+ this.core = core;
4828
+ this.onChange = onChange;
4829
+ _defineProperty(this, "session", void 0);
4830
+ _defineProperty(this, "nextSeq", Math.floor(Date.now()) * 1e3);
4831
+ }
4832
+ get trajectoryId() {
4833
+ var _this$session;
4834
+ return ((_this$session = this.session) === null || _this$session === void 0 ? void 0 : _this$session.ready) ? this.session.trajectoryId : null;
4835
+ }
4836
+ start(trajectoryId, config) {
4837
+ if (this.session && (trajectoryId === void 0 || trajectoryId === this.session.trajectoryId)) return this.session.promise;
4838
+ this.stop();
4839
+ const id = trajectoryId !== null && trajectoryId !== void 0 ? trajectoryId : crypto.randomUUID();
4840
+ let resolveStart;
4841
+ const promise = new Promise((resolve) => {
4842
+ resolveStart = resolve;
4843
+ });
4844
+ const session = {
4845
+ trajectoryId: id,
4846
+ config,
4847
+ promise,
4848
+ resolve: resolveStart,
4849
+ retries: 0,
4850
+ queue: [],
4851
+ dropped: 0,
4852
+ ready: false,
4853
+ started: false,
4854
+ offline: typeof navigator !== "undefined" && navigator.onLine === false,
4855
+ onOffline: () => {
4856
+ if (this.session !== session) return;
4857
+ session.offline = true;
4858
+ if (session.connection) this.fail(session, session.connection, "CONNECTION_LOST");
4859
+ clearTimeout(session.retry);
4860
+ session.retry = void 0;
4861
+ },
4862
+ onOnline: () => {
4863
+ if (this.session !== session) return;
4864
+ session.offline = false;
4865
+ if (!session.connection) {
4866
+ clearTimeout(session.retry);
4867
+ session.retry = void 0;
4868
+ this.connect(session);
4869
+ }
4870
+ },
4871
+ linkedThreads: /* @__PURE__ */ new Set(),
4872
+ agentWatches: /* @__PURE__ */ new Map()
4873
+ };
4874
+ this.session = session;
4875
+ session.runWatch = this.core.subscribe({ onAgentRunStarted: ({ agent }) => this.watchAgent(session, agent) });
4876
+ if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
4877
+ window.addEventListener("offline", session.onOffline);
4878
+ window.addEventListener("online", session.onOnline);
4879
+ }
4880
+ if (session.offline) {
4881
+ this.report(session, "CONNECTION_LOST");
4882
+ this.end(session, {
4883
+ status: "error",
4884
+ code: "CONNECTION_LOST"
4885
+ });
4886
+ } else this.connect(session);
4887
+ return promise;
4888
+ }
4889
+ stop() {
4890
+ const session = this.session;
4891
+ if (!session) return;
4892
+ if (session.ready && session.connection) this.flush(session, session.connection);
4893
+ this.end(session, {
4894
+ status: "error",
4895
+ code: "CANCELLED"
4896
+ });
4897
+ }
4898
+ emit(name, value) {
4899
+ var _session$collector;
4900
+ const session = this.session;
4901
+ if (session === null || session === void 0 ? void 0 : session.ready) (_session$collector = session.collector) === null || _session$collector === void 0 || _session$collector.emit(name, value);
4902
+ else if (session === null || session === void 0 ? void 0 : session.started) this.addDropped(session, 1, false);
4903
+ }
4904
+ watchAgent(session, agent) {
4905
+ if (this.session !== session || session.agentWatches.has(agent)) return;
4906
+ session.agentWatches.set(agent, agent.subscribe({ onRunStartedEvent: ({ event }) => this.linkThread(session, event) }));
4907
+ }
4908
+ /** Sends one `thread.linked` per Thread. A link that cannot be sent waits for the next run. */
4909
+ linkThread(session, { threadId }) {
4910
+ const connection = session.connection;
4911
+ if (!session.ready || !connection || !threadId || session.linkedThreads.has(threadId)) return;
4912
+ session.linkedThreads.add(threadId);
4913
+ const event = {
4914
+ type: "CUSTOM",
4915
+ name: "thread.linked",
4916
+ timestamp: Date.now(),
4917
+ value: { threadId }
4918
+ };
4919
+ try {
4920
+ const { beforeSend } = session.config;
4921
+ const kept = beforeSend === void 0 ? event : beforeSend(event);
4922
+ if (kept !== null) this.send(session, connection, kept);
4923
+ } catch (_unused) {
4924
+ this.report(session, "INVALID_EVENT");
4925
+ }
4926
+ }
4927
+ report(session, code) {
4928
+ try {
4929
+ var _session$config$onErr, _session$config;
4930
+ (_session$config$onErr = (_session$config = session.config).onError) === null || _session$config$onErr === void 0 || _session$config$onErr.call(_session$config, {
4931
+ code,
4932
+ message: `Trajectory capture: ${code}.`
4933
+ });
4934
+ } catch (_unused2) {}
4935
+ }
4936
+ current(session, connection) {
4937
+ return this.session === session && session.connection === connection;
4938
+ }
4939
+ end(session, result) {
4940
+ var _session$runWatch, _session$collector2;
4941
+ if (this.session !== session) return;
4942
+ this.session = void 0;
4943
+ clearTimeout(session.retry);
4944
+ (_session$runWatch = session.runWatch) === null || _session$runWatch === void 0 || _session$runWatch.unsubscribe();
4945
+ for (const watch of session.agentWatches.values()) watch.unsubscribe();
4946
+ session.agentWatches.clear();
4947
+ (_session$collector2 = session.collector) === null || _session$collector2 === void 0 || _session$collector2.stop();
4948
+ session.ready = false;
4949
+ if (session.queue.length > 0) this.report(session, "EVENTS_DROPPED");
4950
+ this.discardQueue(session);
4951
+ if (session.connection) {
4952
+ for (const pending of session.connection.pending) {
4953
+ pending.finish("PERSISTENCE_UNKNOWN");
4954
+ this.report(session, "PERSISTENCE_UNKNOWN");
4955
+ }
4956
+ this.cleanup(session, session.connection);
4957
+ }
4958
+ if (typeof window !== "undefined" && typeof window.removeEventListener === "function") {
4959
+ window.removeEventListener("offline", session.onOffline);
4960
+ window.removeEventListener("online", session.onOnline);
4961
+ }
4962
+ session.resolve(result);
4963
+ this.onChange();
4964
+ }
4965
+ cleanup(session, connection) {
4966
+ session.connection = void 0;
4967
+ clearTimeout(connection.timer);
4968
+ connection.abort.abort();
4969
+ for (const pending of connection.pending) clearTimeout(pending.timer);
4970
+ connection.pending.clear();
4971
+ const { socket, channel } = connection;
4972
+ try {
4973
+ if (channel) {
4974
+ for (const [event, ref] of connection.channelRefs) channel.off(event, ref);
4975
+ channel.leave();
4976
+ }
4977
+ } finally {
4978
+ if (socket) {
4979
+ socket.off(connection.socketRefs);
4980
+ socket.disconnect();
4981
+ }
4982
+ }
4983
+ }
4984
+ fail(session, connection, code, retryable = true) {
4985
+ var _session$collector3;
4986
+ if (!this.current(session, connection)) return;
4987
+ (_session$collector3 = session.collector) === null || _session$collector3 === void 0 || _session$collector3.stop();
4988
+ session.collector = void 0;
4989
+ if (session.ready && session.started) session.promise = new Promise((resolve) => {
4990
+ session.resolve = resolve;
4991
+ });
4992
+ session.ready = false;
4993
+ this.discardQueue(session);
4994
+ session.linkedThreads.clear();
4995
+ for (const pending of connection.pending) pending.finish("PERSISTENCE_UNKNOWN");
4996
+ if (!this.current(session, connection)) return;
4997
+ this.cleanup(session, connection);
4998
+ this.onChange();
4999
+ this.report(session, code);
5000
+ if (this.session !== session) return;
5001
+ if (!session.started || !retryable) {
5002
+ this.end(session, {
5003
+ status: "error",
5004
+ code
5005
+ });
5006
+ return;
5007
+ }
5008
+ if (session.offline || this.session !== session) return;
5009
+ session.retry = setTimeout(() => {
5010
+ session.retry = void 0;
5011
+ if (this.session === session && !session.offline) this.connect(session);
5012
+ }, reconnectDelay(++session.retries));
5013
+ }
5014
+ async connect(session) {
5015
+ if (this.session !== session || session.offline || session.connection) return;
5016
+ const connection = {
5017
+ abort: new AbortController(),
5018
+ socketRefs: [],
5019
+ channelRefs: [],
5020
+ pending: /* @__PURE__ */ new Set()
5021
+ };
5022
+ session.connection = connection;
5023
+ connection.timer = setTimeout(() => this.fail(session, connection, "CONNECTION_TIMEOUT"), TIMEOUT_MS);
5024
+ try {
5025
+ var _this$core$ɵruntimeE;
5026
+ const runtimeUrl = this.core.runtimeUrl;
5027
+ if (!runtimeUrl) {
5028
+ this.fail(session, connection, "RUNTIME_REQUIRED", false);
5029
+ return;
5030
+ }
5031
+ let transport = this.core.runtimeTransport;
5032
+ if (transport === "auto") {
5033
+ transport = await this.detectedTransport(connection.abort.signal);
5034
+ if (!this.current(session, connection)) return;
5035
+ }
5036
+ const rest = transport === "rest";
5037
+ const response = await fetch(rest ? `${runtimeUrl}/trajectory/${encodeURIComponent(session.trajectoryId)}/connect` : (_this$core$ɵruntimeE = this.core.ɵruntimeEndpointUrl) !== null && _this$core$ɵruntimeE !== void 0 ? _this$core$ɵruntimeE : runtimeUrl, {
5038
+ method: "POST",
5039
+ redirect: "error",
5040
+ signal: connection.abort.signal,
5041
+ headers: {
5042
+ ...this.core.headers,
5043
+ "Content-Type": "application/json"
5044
+ },
5045
+ credentials: this.core.credentials,
5046
+ body: JSON.stringify(rest ? {} : {
5047
+ method: "trajectory/connect",
5048
+ params: { trajectoryId: session.trajectoryId },
5049
+ body: {}
5050
+ })
5051
+ });
5052
+ if (!this.current(session, connection)) return;
5053
+ const payload = await response.json().catch(() => void 0);
5054
+ if (!this.current(session, connection)) return;
5055
+ if (!response.ok) {
5056
+ this.fail(session, connection, errorCode(payload, "CONNECTION_FAILED"), response.status >= 500 || response.status === 408 || response.status === 429);
5057
+ return;
5058
+ }
5059
+ if (!isGrant(payload)) {
5060
+ this.fail(session, connection, "INVALID_GRANT", false);
5061
+ return;
5062
+ }
5063
+ const socket = new phoenix.Socket(payload.realtime.clientUrl, {
5064
+ params: { join_token: payload.joinToken },
5065
+ timeout: TIMEOUT_MS
5066
+ });
5067
+ connection.socket = socket;
5068
+ const lost = () => this.fail(session, connection, "CONNECTION_LOST");
5069
+ connection.socketRefs.push(socket.onError(lost), socket.onClose(lost));
5070
+ const channel = socket.channel(payload.realtime.topic, {});
5071
+ connection.channel = channel;
5072
+ connection.channelRefs.push(["phx_error", channel.onError(lost)], ["phx_close", channel.onClose(lost)]);
5073
+ socket.connect();
5074
+ if (!this.current(session, connection)) return;
5075
+ channel.join(TIMEOUT_MS).receive("ok", () => {
5076
+ if (!this.current(session, connection)) return;
5077
+ try {
5078
+ var _session$config$ignor;
5079
+ clearTimeout(connection.timer);
5080
+ session.ready = true;
5081
+ session.retries = 0;
5082
+ session.collector = (0, _copilotkit_learning.createTrajectoryCollector)({
5083
+ ...session.config,
5084
+ ignoreUrls: [
5085
+ ...(_session$config$ignor = session.config.ignoreUrls) !== null && _session$config$ignor !== void 0 ? _session$config$ignor : [],
5086
+ ...this.core.runtimeUrl ? [this.core.runtimeUrl] : [],
5087
+ ...this.core.ɵruntimeEndpointUrl ? [this.core.ɵruntimeEndpointUrl] : [],
5088
+ "https://telemetry.copilotkit.ai/",
5089
+ "https://cdn.copilotkit.ai/"
5090
+ ],
5091
+ onError: (error) => {
5092
+ if (error.code === "CAPTURE_FAILED") this.fail(session, connection, error.code, false);
5093
+ else {
5094
+ var _session$config$onErr2, _session$config2;
5095
+ if (error.code === "INVALID_EVENT" || error.code === "EVENT_TOO_LARGE") this.addDropped(session, 1);
5096
+ (_session$config$onErr2 = (_session$config2 = session.config).onError) === null || _session$config$onErr2 === void 0 || _session$config$onErr2.call(_session$config2, error);
5097
+ }
5098
+ },
5099
+ send: (event) => this.send(session, connection, event)
5100
+ });
5101
+ session.collector.start();
5102
+ if (!this.current(session, connection)) return;
5103
+ if (session.dropped > 0) this.scheduleFlush(session, connection);
5104
+ session.started = true;
5105
+ session.resolve({
5106
+ status: "started",
5107
+ trajectoryId: session.trajectoryId
5108
+ });
5109
+ this.onChange();
5110
+ } catch (_unused3) {
5111
+ this.fail(session, connection, "CAPTURE_FAILED", false);
5112
+ }
5113
+ }).receive("error", (joinError) => this.fail(session, connection, errorCode(joinError, "JOIN_FAILED"))).receive("timeout", () => this.fail(session, connection, "CONNECTION_TIMEOUT"));
5114
+ } catch (_unused4) {
5115
+ this.fail(session, connection, "CONNECTION_FAILED");
5116
+ }
5117
+ }
5118
+ /** Resolves once auto-detection picks a transport, or with "auto" when the attempt is aborted. */
5119
+ detectedTransport(signal) {
5120
+ return new Promise((resolve) => {
5121
+ const finish = () => {
5122
+ subscription.unsubscribe();
5123
+ signal.removeEventListener("abort", finish);
5124
+ resolve(this.core.runtimeTransport);
5125
+ };
5126
+ const subscription = this.core.subscribe({ onRuntimeConnectionStatusChanged: () => {
5127
+ if (this.core.runtimeTransport !== "auto") finish();
5128
+ } });
5129
+ signal.addEventListener("abort", finish, { once: true });
5130
+ });
5131
+ }
5132
+ addDropped(session, count, schedule = true) {
5133
+ session.dropped = Math.min(Number.MAX_SAFE_INTEGER, session.dropped + count);
5134
+ if (schedule && count > 0 && session.ready && session.connection) this.scheduleFlush(session, session.connection);
5135
+ }
5136
+ scheduleFlush(session, connection) {
5137
+ if (session.flushTimer !== void 0 || !this.current(session, connection)) return;
5138
+ session.flushTimer = setTimeout(() => {
5139
+ session.flushTimer = void 0;
5140
+ this.flush(session, connection);
5141
+ }, BATCH_INTERVAL_MS);
5142
+ }
5143
+ discardQueue(session) {
5144
+ clearTimeout(session.flushTimer);
5145
+ session.flushTimer = void 0;
5146
+ this.addDropped(session, session.queue.length, false);
5147
+ session.queue = [];
5148
+ }
5149
+ connected(connection) {
5150
+ var _connection$socket, _connection$channel;
5151
+ return ((_connection$socket = connection.socket) === null || _connection$socket === void 0 ? void 0 : _connection$socket.isConnected()) === true && ((_connection$channel = connection.channel) === null || _connection$channel === void 0 ? void 0 : _connection$channel.state) === "joined";
5152
+ }
5153
+ send(session, connection, event) {
5154
+ if (!this.current(session, connection) || !session.ready) return;
5155
+ if (!this.connected(connection)) {
5156
+ this.addDropped(session, 1);
5157
+ this.fail(session, connection, "CONNECTION_LOST");
5158
+ return;
5159
+ }
5160
+ if (!Number.isSafeInteger(this.nextSeq)) {
5161
+ this.addDropped(session, 1);
5162
+ this.report(session, "SEQUENCE_EXHAUSTED");
5163
+ return;
5164
+ }
5165
+ const original = event.value;
5166
+ const fields = isObject(original) && !Array.isArray(original) && !Object.hasOwn(original, "seq") ? original : { data: original };
5167
+ const wire = {
5168
+ ...event,
5169
+ value: {
5170
+ ...fields,
5171
+ seq: this.nextSeq++
5172
+ }
5173
+ };
5174
+ if (byteLength(wire) > MAX_EVENT_BYTES) {
5175
+ this.addDropped(session, 1);
5176
+ this.report(session, "EVENT_TOO_LARGE");
5177
+ return;
5178
+ }
5179
+ const fits = () => session.queue.length < MAX_BATCH_EVENTS && byteLength({
5180
+ events: [...session.queue, wire],
5181
+ dropped: Number.MAX_SAFE_INTEGER
5182
+ }) <= MAX_BATCH_BYTES;
5183
+ if (!fits()) this.flush(session, connection);
5184
+ if (!this.current(session, connection) || !session.ready) return;
5185
+ if (!fits()) {
5186
+ this.addDropped(session, 1);
5187
+ this.report(session, "EVENTS_DROPPED");
5188
+ return;
5189
+ }
5190
+ session.queue.push(wire);
5191
+ if (session.queue.length === MAX_BATCH_EVENTS) this.flush(session, connection);
5192
+ else this.scheduleFlush(session, connection);
5193
+ }
5194
+ flush(session, connection) {
5195
+ if (!this.current(session, connection) || !session.ready || session.queue.length === 0 && session.dropped === 0) return;
5196
+ if (!this.connected(connection)) {
5197
+ this.fail(session, connection, "CONNECTION_LOST");
5198
+ return;
5199
+ }
5200
+ if (connection.pending.size > 0) return;
5201
+ clearTimeout(session.flushTimer);
5202
+ session.flushTimer = void 0;
5203
+ const batch = {
5204
+ events: session.queue,
5205
+ dropped: session.dropped
5206
+ };
5207
+ session.queue = [];
5208
+ session.dropped = 0;
5209
+ let finished = false;
5210
+ const pending = {
5211
+ timer: setTimeout(() => pending.finish("PERSISTENCE_UNKNOWN"), TIMEOUT_MS),
5212
+ finish: (code, knownRollback = false, flushNext = true) => {
5213
+ if (finished) return;
5214
+ finished = true;
5215
+ clearTimeout(pending.timer);
5216
+ connection.pending.delete(pending);
5217
+ if (knownRollback) this.addDropped(session, batch.events.length + batch.dropped, false);
5218
+ if (code && this.current(session, connection)) this.report(session, code);
5219
+ if (flushNext && this.current(session, connection) && session.ready && (session.queue.length > 0 || !knownRollback && session.dropped > 0)) this.flush(session, connection);
5220
+ }
5221
+ };
5222
+ connection.pending.add(pending);
5223
+ try {
5224
+ connection.channel.push("events", batch, TIMEOUT_MS).receive("ok", (payload) => {
5225
+ pending.finish(!isBatchAcknowledgement(payload, batch.events.length) ? "PERSISTENCE_UNKNOWN" : payload.rejected > 0 ? "EVENTS_REJECTED" : void 0);
5226
+ }).receive("error", (payload) => {
5227
+ if (!this.current(session, connection)) return;
5228
+ const reason = isObject(payload) ? payload.reason : void 0;
5229
+ if (reason === "unauthorized" || reason === "trajectory_mismatch") {
5230
+ pending.finish(void 0, true, false);
5231
+ this.fail(session, connection, reason.toUpperCase(), false);
5232
+ return;
5233
+ }
5234
+ const rollback = typeof reason === "string" && [
5235
+ "invalid_batch",
5236
+ "batch_too_large",
5237
+ "batch_too_many_events",
5238
+ "trajectory_over_share",
5239
+ "trajectory_outbox_full",
5240
+ "unsupported_event"
5241
+ ].includes(reason);
5242
+ pending.finish(rollback ? reason.toUpperCase() : "PERSISTENCE_UNKNOWN", rollback);
5243
+ }).receive("timeout", () => pending.finish("PERSISTENCE_UNKNOWN"));
5244
+ } catch (_unused5) {
5245
+ pending.finish("PERSISTENCE_UNKNOWN");
5246
+ }
5247
+ }
5248
+ };
5249
+
5250
+ //#endregion
5251
+ //#region src/core/learning-bridge.ts
5252
+ const COPILOTKIT_OWN_URLS = ["https://telemetry.copilotkit.ai/", "https://cdn.copilotkit.ai/"];
5253
+ /**
5254
+ * Wires `@copilotkit/learning` into Core. Default capture uses Runtime and Phoenix;
5255
+ * explicit legacy sinks also use agent events and open-Thread attribution.
5256
+ */
5257
+ var LearningBridge = class {
5258
+ constructor(core, config, onChange = () => {}) {
5259
+ this.core = core;
5260
+ this.config = config;
5261
+ _defineProperty(this, "collector", null);
5262
+ _defineProperty(this, "agents", /* @__PURE__ */ new Map());
5263
+ _defineProperty(this, "openThreads", /* @__PURE__ */ new Set());
5264
+ _defineProperty(this, "toolCalls", /* @__PURE__ */ new Map());
5265
+ _defineProperty(this, "executingTools", /* @__PURE__ */ new Map());
5266
+ _defineProperty(this, "lastRunIds", /* @__PURE__ */ new WeakMap());
5267
+ _defineProperty(this, "lastLinkedThreadId", null);
5268
+ _defineProperty(this, "coreSubscription", null);
5269
+ _defineProperty(this, "seq", 0);
5270
+ _defineProperty(this, "activeConfig", void 0);
5271
+ _defineProperty(this, "connection", void 0);
5272
+ this.connection = new TrajectoryConnection(core, onChange);
5273
+ this.setConfig(config);
5274
+ }
5275
+ setConfig(config) {
5276
+ this.config = config;
5277
+ if (config === void 0) this.stop();
5278
+ }
5279
+ get isConfigured() {
5280
+ return this.config !== void 0;
5281
+ }
5282
+ get isLegacyCaptureActive() {
5283
+ return this.collector !== null && this.collector.trajectoryId !== null;
5284
+ }
5285
+ startTracking() {
5286
+ if (this.coreSubscription !== null || !this.isLegacyCaptureActive) return;
5287
+ this.coreSubscription = this.core.subscribe({
5288
+ onAgentsChanged: ({ agents }) => {
5289
+ for (const agent of Object.values(agents)) this.track(agent);
5290
+ },
5291
+ onAgentRunStarted: ({ agent }) => this.track(agent),
5292
+ onToolExecutionStart: ({ toolCallId, agentId, toolName }) => {
5293
+ if (!this.isLegacyCaptureActive) return;
5294
+ this.executingTools.set(toolCallId, Date.now());
5295
+ this.emitToolCall("executing", toolCallId, agentId, toolName, {});
5296
+ },
5297
+ onToolExecutionEnd: ({ toolCallId, agentId, toolName, error }) => {
5298
+ if (!this.isLegacyCaptureActive) return;
5299
+ const startedAt = this.executingTools.get(toolCallId);
5300
+ this.executingTools.delete(toolCallId);
5301
+ this.emitToolCall("completed", toolCallId, agentId, toolName, {
5302
+ durationMs: startedAt === void 0 ? void 0 : Date.now() - startedAt,
5303
+ outcome: error === void 0 ? "ok" : "error"
5304
+ });
5305
+ this.toolCalls.delete(toolCallId);
5306
+ }
5307
+ });
5308
+ for (const agent of Object.values(this.core.agents)) this.track(agent);
5309
+ }
5310
+ get trajectoryId() {
5311
+ var _ref, _this$connection$traj, _this$collector;
5312
+ return (_ref = (_this$connection$traj = this.connection.trajectoryId) !== null && _this$connection$traj !== void 0 ? _this$connection$traj : (_this$collector = this.collector) === null || _this$collector === void 0 ? void 0 : _this$collector.trajectoryId) !== null && _ref !== void 0 ? _ref : null;
5313
+ }
5314
+ start(options = {}) {
5315
+ var _ref2, _options$trajectoryId, _this$collector2;
5316
+ const config = this.config;
5317
+ if (config === void 0) {
5318
+ console.warn("[CopilotKit] startTrajectory() needs the `learning` option on CopilotKitCore (or the CopilotKitProvider `learning` prop).");
5319
+ return Promise.resolve({
5320
+ status: "error",
5321
+ code: "LEARNING_DISABLED"
5322
+ });
5323
+ }
5324
+ if (config.sink === void 0) {
5325
+ if (options.learningContainerIds !== void 0) console.warn("[CopilotKit] learningContainerIds is supported only with a custom sink. Authenticated Trajectory capture does not assign Learning Containers; remove learningContainerIds from the capture options.");
5326
+ this.stopLegacy();
5327
+ return this.connection.start(options.trajectoryId, config);
5328
+ }
5329
+ this.connection.stop();
5330
+ const trajectoryId = (_ref2 = (_options$trajectoryId = options.trajectoryId) !== null && _options$trajectoryId !== void 0 ? _options$trajectoryId : (_this$collector2 = this.collector) === null || _this$collector2 === void 0 ? void 0 : _this$collector2.trajectoryId) !== null && _ref2 !== void 0 ? _ref2 : crypto.randomUUID();
5331
+ if (this.collector === null) {
5332
+ var _config$ignoreUrls;
5333
+ this.activeConfig = config;
5334
+ const runtimeUrl = this.core.runtimeUrl;
5335
+ this.collector = (0, _copilotkit_learning.createCollector)({
5336
+ ...config,
5337
+ beforeSend: (event) => {
5338
+ const sequenced = {
5339
+ ...event,
5340
+ value: {
5341
+ ...event.value,
5342
+ seq: ++this.seq
5343
+ }
5344
+ };
5345
+ return config.beforeSend === void 0 ? sequenced : config.beforeSend(sequenced);
5346
+ },
5347
+ ignoreUrls: [
5348
+ ...(_config$ignoreUrls = config.ignoreUrls) !== null && _config$ignoreUrls !== void 0 ? _config$ignoreUrls : [],
5349
+ ...COPILOTKIT_OWN_URLS,
5350
+ ...runtimeUrl === void 0 ? [] : [runtimeUrl]
5351
+ ],
5352
+ enrich: (target) => this.enrich(target)
5353
+ });
5354
+ }
5355
+ const wasActive = this.collector.trajectoryId !== null;
5356
+ this.collector.start({
5357
+ ...options,
5358
+ trajectoryId
5359
+ });
5360
+ if (wasActive) return Promise.resolve(this.collector.trajectoryId === trajectoryId ? {
5361
+ status: "started",
5362
+ trajectoryId
5363
+ } : {
5364
+ status: "error",
5365
+ code: "TRAJECTORY_ACTIVE"
5366
+ });
5367
+ this.startTracking();
5368
+ this.lastLinkedThreadId = null;
5369
+ for (const threadId of this.distinctOpenThreadIds()) this.emitThreadLinked(threadId, "start");
5370
+ return Promise.resolve({
5371
+ status: "started",
5372
+ trajectoryId
5373
+ });
5374
+ }
5375
+ stop() {
5376
+ this.connection.stop();
5377
+ this.stopLegacy();
5378
+ }
5379
+ stopLegacy() {
5380
+ var _this$collector3, _this$coreSubscriptio;
5381
+ (_this$collector3 = this.collector) === null || _this$collector3 === void 0 || _this$collector3.stop();
5382
+ this.collector = null;
5383
+ this.activeConfig = void 0;
5384
+ (_this$coreSubscriptio = this.coreSubscription) === null || _this$coreSubscriptio === void 0 || _this$coreSubscriptio.unsubscribe();
5385
+ this.coreSubscription = null;
5386
+ for (const subscription of this.agents.values()) subscription.unsubscribe();
5387
+ this.agents.clear();
5388
+ this.toolCalls.clear();
5389
+ this.executingTools.clear();
5390
+ }
5391
+ /** A developer event. Only an explicit legacy sink adds open-Thread context. */
5392
+ emit(name, value) {
5393
+ this.connection.emit(name, value);
5394
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
5395
+ var _this$collector4;
5396
+ (_this$collector4 = this.collector) === null || _this$collector4 === void 0 || _this$collector4.emit(name, {
5397
+ ...this.openThreadContext(),
5398
+ ...value
5399
+ });
5400
+ }
5401
+ }
5402
+ registerOpenThread(params) {
5403
+ const entry = { ...params };
5404
+ const isNew = !this.distinctOpenThreadIds().includes(entry.threadId);
5405
+ this.openThreads.add(entry);
5406
+ if (isNew) this.emitThreadLinked(entry.threadId, "open");
5407
+ return {
5408
+ update: (threadId) => {
5409
+ if (threadId === entry.threadId) return;
5410
+ entry.threadId = threadId;
5411
+ if (![...this.openThreads].filter((other) => other !== entry).some((other) => other.threadId === threadId)) this.emitThreadLinked(threadId, "switch");
5412
+ },
5413
+ unregister: () => {
5414
+ this.openThreads.delete(entry);
5415
+ }
5416
+ };
5417
+ }
5418
+ distinctOpenThreadIds() {
5419
+ return [...new Set([...this.openThreads].map((open) => open.threadId))];
5420
+ }
5421
+ emitThreadLinked(threadId, reason) {
5422
+ var _this$collector5, _ref3, _owner$agentId, _agent$messages$lengt;
5423
+ if (!(this.collector !== null && this.collector.trajectoryId !== null) || threadId === this.lastLinkedThreadId) return;
5424
+ this.lastLinkedThreadId = threadId;
5425
+ const owner = [...this.openThreads].find((open) => open.threadId === threadId);
5426
+ const agent = this.findAgentForThread(threadId);
5427
+ (_this$collector5 = this.collector) === null || _this$collector5 === void 0 || _this$collector5.ɵemit("thread.linked", {
5428
+ threadId,
5429
+ agentId: (_ref3 = (_owner$agentId = owner === null || owner === void 0 ? void 0 : owner.agentId) !== null && _owner$agentId !== void 0 ? _owner$agentId : agent === null || agent === void 0 ? void 0 : agent.agentId) !== null && _ref3 !== void 0 ? _ref3 : null,
5430
+ hasMessages: ((_agent$messages$lengt = agent === null || agent === void 0 ? void 0 : agent.messages.length) !== null && _agent$messages$lengt !== void 0 ? _agent$messages$lengt : 0) > 0,
5431
+ reason
5432
+ });
5433
+ }
5434
+ findAgentForThread(threadId) {
5435
+ return [...this.agents.keys()].find((agent) => agent.threadId === threadId);
5436
+ }
5437
+ track(agent) {
5438
+ const agentId = agent.agentId;
5439
+ if (!this.isLegacyCaptureActive || this.agents.has(agent) || agentId === void 0) return;
5440
+ this.agents.set(agent, agent.subscribe(this.agentSubscriber(agent, agentId)));
5441
+ }
5442
+ agentSubscriber(agent, agentId) {
5443
+ const runIdFor = () => this.lastRunIds.get(agent);
5444
+ return {
5445
+ onRunStartedEvent: ({ event }) => {
5446
+ this.lastRunIds.set(agent, event.runId);
5447
+ this.emitRun("started", agent, event.threadId, event.runId);
5448
+ },
5449
+ onRunFinishedEvent: ({ event }) => {
5450
+ this.emitRun("finished", agent, event.threadId, event.runId);
5451
+ },
5452
+ onRunErrorEvent: () => {
5453
+ var _runIdFor;
5454
+ this.emitRun("error", agent, agent.threadId, (_runIdFor = runIdFor()) !== null && _runIdFor !== void 0 ? _runIdFor : null);
5455
+ },
5456
+ onToolCallStartEvent: ({ event }) => {
5457
+ if (!this.isLegacyCaptureActive) return;
5458
+ const origin = {
5459
+ agentId,
5460
+ threadId: agent.threadId,
5461
+ messageId: event.parentMessageId,
5462
+ runId: runIdFor()
5463
+ };
5464
+ this.toolCalls.set(event.toolCallId, origin);
5465
+ this.emitToolCall("started", event.toolCallId, origin.agentId, event.toolCallName, {});
5466
+ },
5467
+ onToolCallResultEvent: ({ event }) => {
5468
+ if (!this.executingTools.has(event.toolCallId)) this.toolCalls.delete(event.toolCallId);
5469
+ },
5470
+ onNewMessage: ({ message }) => this.emitMessage(agent, message)
5471
+ };
5472
+ }
5473
+ emitRun(phase, agent, threadId, runId) {
5474
+ var _this$collector6;
5475
+ (_this$collector6 = this.collector) === null || _this$collector6 === void 0 || _this$collector6.ɵemit("agent.run", {
5476
+ phase,
5477
+ runId,
5478
+ threadId,
5479
+ agentId: agent.agentId
5480
+ });
5481
+ }
5482
+ emitMessage(agent, message) {
5483
+ var _this$activeConfig, _this$collector7;
5484
+ const content = typeof message.content === "string" ? message.content : "";
5485
+ const includeText = ((_this$activeConfig = this.activeConfig) === null || _this$activeConfig === void 0 || (_this$activeConfig = _this$activeConfig.capture) === null || _this$activeConfig === void 0 ? void 0 : _this$activeConfig.agentText) !== false && typeof message.content === "string";
5486
+ (_this$collector7 = this.collector) === null || _this$collector7 === void 0 || _this$collector7.ɵemit("agent.message", {
5487
+ messageId: message.id,
5488
+ runId: this.runIdForMessage(agent, message.id),
5489
+ threadId: agent.threadId,
5490
+ agentId: agent.agentId,
5491
+ role: message.role,
5492
+ textLength: content.length,
5493
+ ...includeText ? { text: content } : {}
5494
+ });
5495
+ }
5496
+ emitToolCall(phase, toolCallId, agentId, toolName, extra) {
5497
+ var _this$collector8, _origin$threadId;
5498
+ const origin = this.toolCalls.get(toolCallId);
5499
+ (_this$collector8 = this.collector) === null || _this$collector8 === void 0 || _this$collector8.ɵemit("tool.call", {
5500
+ phase,
5501
+ toolCallId,
5502
+ toolName,
5503
+ agentId,
5504
+ threadId: (_origin$threadId = origin === null || origin === void 0 ? void 0 : origin.threadId) !== null && _origin$threadId !== void 0 ? _origin$threadId : null,
5505
+ messageId: origin === null || origin === void 0 ? void 0 : origin.messageId,
5506
+ runId: origin === null || origin === void 0 ? void 0 : origin.runId,
5507
+ ...extra
5508
+ });
5509
+ }
5510
+ runIdForMessage(agent, messageId) {
5511
+ var _ref4, _this$core$getRunIdFo;
5512
+ const agentId = agent.agentId;
5513
+ if (agentId === void 0) return null;
5514
+ return (_ref4 = (_this$core$getRunIdFo = this.core.getRunIdForMessage(agentId, agent.threadId, messageId)) !== null && _this$core$getRunIdFo !== void 0 ? _this$core$getRunIdFo : this.lastRunIds.get(agent)) !== null && _ref4 !== void 0 ? _ref4 : null;
5515
+ }
5516
+ findMessage(messageId) {
5517
+ for (const agent of this.agents.keys()) {
5518
+ const message = agent.messages.find((candidate) => candidate.id === messageId);
5519
+ if (message !== void 0) return {
5520
+ agent,
5521
+ message
5522
+ };
5523
+ }
5524
+ return null;
5525
+ }
5526
+ toolStatus(agent, toolCallId) {
5527
+ if (this.executingTools.has(toolCallId)) return "executing";
5528
+ return agent.messages.some((message) => message.role === "tool" && message.toolCallId === toolCallId) ? "complete" : "inProgress";
5529
+ }
5530
+ /** Adds agent context to a click: exact message first, then the single open Thread. */
5531
+ enrich(target) {
5532
+ var _target$closest$getAt, _target$closest, _target$closest$getAt2, _target$closest2;
5533
+ const messageId = (_target$closest$getAt = (_target$closest = target.closest("[data-message-id]")) === null || _target$closest === void 0 ? void 0 : _target$closest.getAttribute("data-message-id")) !== null && _target$closest$getAt !== void 0 ? _target$closest$getAt : null;
5534
+ const toolCallId = (_target$closest$getAt2 = (_target$closest2 = target.closest("[data-tool-call-id]")) === null || _target$closest2 === void 0 ? void 0 : _target$closest2.getAttribute("data-tool-call-id")) !== null && _target$closest$getAt2 !== void 0 ? _target$closest$getAt2 : null;
5535
+ const found = messageId === null ? null : this.findMessage(messageId);
5536
+ if (found !== null) {
5537
+ var _message$toolCalls;
5538
+ const { agent, message } = found;
5539
+ const toolCall = toolCallId !== null && message.role === "assistant" ? (_message$toolCalls = message.toolCalls) === null || _message$toolCalls === void 0 ? void 0 : _message$toolCalls.find((call) => call.id === toolCallId) : void 0;
5540
+ return {
5541
+ threadId: agent.threadId,
5542
+ agentId: agent.agentId,
5543
+ messageId: message.id,
5544
+ runId: this.runIdForMessage(agent, message.id),
5545
+ ...toolCall === void 0 ? {} : {
5546
+ toolCallId: toolCall.id,
5547
+ toolName: toolCall.function.name,
5548
+ toolStatus: this.toolStatus(agent, toolCall.id)
5549
+ }
5550
+ };
5551
+ }
5552
+ return this.openThreadContext();
5553
+ }
5554
+ /** The single open Thread, or `null` with the candidates when several are open. */
5555
+ openThreadContext() {
5556
+ var _openIds$;
5557
+ const openIds = this.distinctOpenThreadIds();
5558
+ if (openIds.length > 1) return {
5559
+ threadId: null,
5560
+ threadAmbiguity: {
5561
+ reason: "multiple-open",
5562
+ candidates: openIds
5563
+ }
5564
+ };
5565
+ return { threadId: (_openIds$ = openIds[0]) !== null && _openIds$ !== void 0 ? _openIds$ : null };
5566
+ }
5567
+ };
5568
+
4679
5569
  //#endregion
4680
5570
  //#region src/utils/micro-redux.ts
4681
5571
  const INTERNAL_ACTION_TYPES = {
@@ -5820,7 +6710,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5820
6710
  return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
5821
6711
  }
5822
6712
  var CopilotKitCore = class {
5823
- constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
6713
+ constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug, learning }) {
5824
6714
  _defineProperty(this, "_headers", void 0);
5825
6715
  _defineProperty(this, "_credentials", void 0);
5826
6716
  _defineProperty(this, "_messageFilter", void 0);
@@ -5834,6 +6724,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5834
6724
  _defineProperty(this, "runHandler", void 0);
5835
6725
  _defineProperty(this, "stateManager", void 0);
5836
6726
  _defineProperty(this, "threadStoreRegistry", void 0);
6727
+ _defineProperty(this, "learningBridge", void 0);
6728
+ _defineProperty(this, "notifiedTrajectoryId", null);
6729
+ _defineProperty(this, "learningConfiguredListeners", /* @__PURE__ */ new Set());
5837
6730
  _defineProperty(this, "_memoryStore", void 0);
5838
6731
  _defineProperty(this, "previousAgentIds", /* @__PURE__ */ new Set());
5839
6732
  this._headers = normalizeHeaders(headers);
@@ -5851,6 +6744,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5851
6744
  this.runHandler.initialize(tools);
5852
6745
  this.suggestionEngine.initialize(suggestionsConfig);
5853
6746
  this.stateManager.initialize();
6747
+ this.learningBridge = new LearningBridge(this, learning, () => this.notifyTrajectoryChanged());
5854
6748
  this.agentRegistry.setRuntimeTransport(runtimeTransport);
5855
6749
  this.agentRegistry.setRuntimeUrl(runtimeUrl, { deferConnection: deferInitialConnection });
5856
6750
  this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
@@ -6005,6 +6899,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
6005
6899
  get runtimeConnectionStatus() {
6006
6900
  return this.agentRegistry.runtimeConnectionStatus;
6007
6901
  }
6902
+ /** @internal The verbatim single-endpoint URL, including any trailing slash. */
6903
+ get ɵruntimeEndpointUrl() {
6904
+ return this.agentRegistry.runtimeEndpointUrl;
6905
+ }
6008
6906
  get ɵruntimeFetch() {
6009
6907
  return this.agentRegistry.createRuntimeFetch();
6010
6908
  }
@@ -6170,6 +7068,86 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
6170
7068
  getAgent(id) {
6171
7069
  return this.agentRegistry.getAgent(id);
6172
7070
  }
7071
+ /** Updates settings for the next capture. Removing the config stops capture. */
7072
+ setLearningConfig(config) {
7073
+ const wasConfigured = this.ɵlearningConfigured;
7074
+ this.learningBridge.setConfig(config);
7075
+ this.notifyTrajectoryChanged();
7076
+ if (this.ɵlearningConfigured === wasConfigured) return;
7077
+ for (const listener of this.learningConfiguredListeners) try {
7078
+ listener();
7079
+ } catch (error) {
7080
+ console.error("Learning configured listener error:", error);
7081
+ }
7082
+ }
7083
+ /**
7084
+ * @internal Whether a `learning` config is set. Unlike {@link trajectoryId},
7085
+ * it does not change with capture start, connection failures or reconnects.
7086
+ */
7087
+ get ɵlearningConfigured() {
7088
+ return this.learningBridge.isConfigured;
7089
+ }
7090
+ /** @internal Calls `listener` when {@link ɵlearningConfigured} changes. */
7091
+ ɵsubscribeToLearningConfigured(listener) {
7092
+ this.learningConfiguredListeners.add(listener);
7093
+ return () => {
7094
+ this.learningConfiguredListeners.delete(listener);
7095
+ };
7096
+ }
7097
+ /** The active capture's Trajectory ID, or null while capture is stopped. */
7098
+ get trajectoryId() {
7099
+ return this.learningBridge.trajectoryId;
7100
+ }
7101
+ notifyTrajectoryChanged() {
7102
+ const trajectoryId = this.trajectoryId;
7103
+ if (trajectoryId === this.notifiedTrajectoryId) return;
7104
+ this.notifiedTrajectoryId = trajectoryId;
7105
+ this.notifySubscribers((subscriber) => {
7106
+ var _subscriber$onTraject;
7107
+ return (_subscriber$onTraject = subscriber.onTrajectoryChanged) === null || _subscriber$onTraject === void 0 ? void 0 : _subscriber$onTraject.call(subscriber, {
7108
+ copilotkit: this,
7109
+ trajectoryId
7110
+ });
7111
+ }, "Subscriber onTrajectoryChanged error:");
7112
+ }
7113
+ /**
7114
+ * Starts one Trajectory after Runtime authorization and the Gateway join.
7115
+ * Omit the ID to create one. Repeated starts await the active connection;
7116
+ * a different ID stops the previous capture. Explicit sinks retain the
7117
+ * prototype's synchronous capture and require a stop before changing IDs.
7118
+ *
7119
+ * @example copilotkit.startTrajectory({ trajectoryId: crypto.randomUUID() })
7120
+ */
7121
+ startTrajectory(options = {}) {
7122
+ const result = this.learningBridge.start(options);
7123
+ this.notifyTrajectoryChanged();
7124
+ return result;
7125
+ }
7126
+ /** Cancels pending work and stops capture, attempting one final batch without waiting for its ACK. */
7127
+ stopTrajectory() {
7128
+ this.learningBridge.stop();
7129
+ this.notifyTrajectoryChanged();
7130
+ }
7131
+ /**
7132
+ * Records an outcome that clicks cannot show, such as a saved report or an
7133
+ * approved deal. The wire adds `value.seq`; arrays, primitives, and objects
7134
+ * already containing `seq` are preserved under `value.data`. Explicit legacy
7135
+ * sinks retain object-only events with open-Thread enrichment.
7136
+ * No-op while no Trajectory runs. Events emitted during connection recovery
7137
+ * count as dropped. Built-in names such as `click` are rejected.
7138
+ *
7139
+ * @example copilotkit.emitTrajectoryEvent("deal.approved", { dealId: "deal-1" })
7140
+ */
7141
+ emitTrajectoryEvent(name, value = {}) {
7142
+ this.learningBridge.emit(name, value);
7143
+ }
7144
+ /**
7145
+ * Tells Core that a view shows this Thread, so captured interactions can link to it.
7146
+ * Framework bindings call this; call it yourself only without a CopilotKit provider.
7147
+ */
7148
+ registerOpenThread(params) {
7149
+ return this.learningBridge.registerOpenThread(params);
7150
+ }
6173
7151
  /**
6174
7152
  * Re-apply the current headers to a single agent (delegated to
6175
7153
  * AgentRegistry). Core headers are merged on top of the agent's own