@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.cjs +981 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +135 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +135 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +981 -31
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1013 -35
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -4
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { BehaviorSubject, EMPTY, NEVER, Notification, Observable, Subject, Subsc
|
|
|
5
5
|
import { catchError, concatMap, concatWith, delay, distinctUntilChanged, endWith, filter, finalize, ignoreElements, map, mergeMap, observeOn as observeOn$1, scan, share, shareReplay, startWith, switchMap as switchMap$1, take, takeUntil, tap, timeout, withLatestFrom } from "rxjs/operators";
|
|
6
6
|
import { Socket } from "phoenix";
|
|
7
7
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
8
|
+
import { createCollector, createTrajectoryCollector } from "@copilotkit/learning";
|
|
8
9
|
|
|
9
10
|
//#region src/utils/http-agent.ts
|
|
10
11
|
/**
|
|
@@ -194,10 +195,17 @@ function ɵcreatePhoenixJoinOutcome$(channel) {
|
|
|
194
195
|
*
|
|
195
196
|
* The socket is constructed and connected on subscription, and disconnected on
|
|
196
197
|
* teardown. Each subscription creates an isolated socket instance.
|
|
198
|
+
*
|
|
199
|
+
* Heartbeats default to every 15s: Phoenix's own 30s default matches common
|
|
200
|
+
* reverse-proxy WebSocket idle timeouts (e.g. Azure Application Gateway), which
|
|
201
|
+
* would drop the socket during a quiet run. Callers may override it.
|
|
197
202
|
*/
|
|
198
203
|
function ɵphoenixSocket$(options) {
|
|
199
204
|
return defer(() => {
|
|
200
|
-
const socket = new Socket(options.url,
|
|
205
|
+
const socket = new Socket(options.url, {
|
|
206
|
+
heartbeatIntervalMs: 15e3,
|
|
207
|
+
...options.options
|
|
208
|
+
});
|
|
201
209
|
const signals$ = ɵcreatePhoenixSocketSignals$(socket).pipe(shareReplay({
|
|
202
210
|
bufferSize: 1,
|
|
203
211
|
refCount: true
|
|
@@ -281,6 +289,11 @@ const STOP_RUN_EVENT = "stop_run";
|
|
|
281
289
|
const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
|
|
282
290
|
const CONNECT_IDLE_WARNING_MS = 3e4;
|
|
283
291
|
const MAX_UNOPENED_CREDENTIAL_REFRESHES = 2;
|
|
292
|
+
function isMcpResourceRead(input) {
|
|
293
|
+
const forwardedProps = input.forwardedProps;
|
|
294
|
+
const request = forwardedProps?.__proxiedMCPRequest;
|
|
295
|
+
return forwardedProps?.__copilotkitMcpResourceReadOnly === true && typeof request === "object" && request !== null && request.method === "resources/read";
|
|
296
|
+
}
|
|
284
297
|
var AgentThreadLockedError = class extends Error {
|
|
285
298
|
constructor(threadId) {
|
|
286
299
|
super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
|
|
@@ -388,10 +401,22 @@ var IntelligenceAgent = class IntelligenceAgent extends AbstractAgent {
|
|
|
388
401
|
* server-pushed AG-UI events to the Observable subscriber.
|
|
389
402
|
*/
|
|
390
403
|
run(input) {
|
|
391
|
-
|
|
392
|
-
|
|
404
|
+
if (!isMcpResourceRead(input)) {
|
|
405
|
+
this.threadId = input.threadId;
|
|
406
|
+
this.canonicalRunId = input.runId;
|
|
407
|
+
}
|
|
393
408
|
return defer(() => this.requestJoinCredentials$("run", input)).pipe(switchMap((credentials) => {
|
|
394
409
|
if (credentials === null) return throwError(() => /* @__PURE__ */ new Error("REST run request returned no credentials"));
|
|
410
|
+
if ("kind" in credentials) return of({
|
|
411
|
+
type: EventType.RUN_STARTED,
|
|
412
|
+
threadId: credentials.threadId,
|
|
413
|
+
runId: credentials.runId
|
|
414
|
+
}, {
|
|
415
|
+
type: EventType.RUN_FINISHED,
|
|
416
|
+
threadId: credentials.threadId,
|
|
417
|
+
runId: credentials.runId,
|
|
418
|
+
result: credentials.result
|
|
419
|
+
});
|
|
395
420
|
const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: true });
|
|
396
421
|
return this.observeThread$(canonicalInput, credentials, {
|
|
397
422
|
completeOnRunError: false,
|
|
@@ -483,7 +508,18 @@ var IntelligenceAgent = class IntelligenceAgent extends AbstractAgent {
|
|
|
483
508
|
const text = await response.text().catch(() => "");
|
|
484
509
|
throw new Error(text || response.statusText || String(response.status));
|
|
485
510
|
}
|
|
486
|
-
|
|
511
|
+
const payload = await response.json();
|
|
512
|
+
if (mode === "run" && isMcpResourceRead(input) && typeof payload === "object" && payload !== null && payload.kind === "mcp-resource-read") {
|
|
513
|
+
const resource = payload;
|
|
514
|
+
if (typeof resource.threadId !== "string" || !resource.threadId || typeof resource.runId !== "string" || !resource.runId) throw new Error("invalid MCP resource response identity");
|
|
515
|
+
return {
|
|
516
|
+
kind: "mcp-resource-read",
|
|
517
|
+
threadId: resource.threadId,
|
|
518
|
+
runId: resource.runId,
|
|
519
|
+
result: resource.result
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
return this.normalizeJoinCredentials(payload, input);
|
|
487
523
|
} catch (error) {
|
|
488
524
|
if (error instanceof AgentThreadLockedError) throw error;
|
|
489
525
|
throw new Error(`REST ${mode} request failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
@@ -1266,6 +1302,21 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
1266
1302
|
}
|
|
1267
1303
|
return cloned;
|
|
1268
1304
|
}
|
|
1305
|
+
/** Run presentation-only MCP reads on a separate client agent so their
|
|
1306
|
+
* lifecycle cannot replace an in-flight approval's detach/completion state. */
|
|
1307
|
+
async ɵrunMcpResourceRead(parameters) {
|
|
1308
|
+
const request = parameters.forwardedProps?.__proxiedMCPRequest;
|
|
1309
|
+
if (typeof request !== "object" || request === null || request.method !== "resources/read") throw new Error("Only MCP resources/read can use the read-only path");
|
|
1310
|
+
await this.ensureRuntimeConfiguration();
|
|
1311
|
+
const resourceParameters = {
|
|
1312
|
+
...parameters,
|
|
1313
|
+
forwardedProps: {
|
|
1314
|
+
...parameters.forwardedProps,
|
|
1315
|
+
__copilotkitMcpResourceReadOnly: true
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
return this.runtimeMode === RUNTIME_MODE_INTELLIGENCE ? this.clone().runAgent(resourceParameters) : this.runAgent(resourceParameters);
|
|
1319
|
+
}
|
|
1269
1320
|
/**
|
|
1270
1321
|
* Drop the delegate's cached `lastSeenEventId` for this thread so
|
|
1271
1322
|
* the next connect requests a full historical replay from the
|
|
@@ -1906,6 +1957,10 @@ var AgentRegistry = class {
|
|
|
1906
1957
|
this.applyMessageFilterToAgent(agent);
|
|
1907
1958
|
});
|
|
1908
1959
|
}
|
|
1960
|
+
/** Preserve the exact configured URL when posting to a single endpoint. */
|
|
1961
|
+
get runtimeEndpointUrl() {
|
|
1962
|
+
return this._runtimeEndpointUrl;
|
|
1963
|
+
}
|
|
1909
1964
|
createRuntimeFetch() {
|
|
1910
1965
|
if (!this.runtimeFetch) this.runtimeFetch = (async (input, init) => {
|
|
1911
1966
|
const meta = () => runtimeRequestMeta(init);
|
|
@@ -2930,6 +2985,68 @@ function normalizeToolResultContent(content) {
|
|
|
2930
2985
|
function isForwardedToClientPlaceholder(content) {
|
|
2931
2986
|
return normalizeToolResultContent(content) === FORWARDED_TO_CLIENT;
|
|
2932
2987
|
}
|
|
2988
|
+
const MEDIA_PART_TYPES = new Set([
|
|
2989
|
+
"image",
|
|
2990
|
+
"audio",
|
|
2991
|
+
"video",
|
|
2992
|
+
"document"
|
|
2993
|
+
]);
|
|
2994
|
+
function isOptionalString(value) {
|
|
2995
|
+
return value === void 0 || typeof value === "string";
|
|
2996
|
+
}
|
|
2997
|
+
function isPartSource(value) {
|
|
2998
|
+
if (!value || typeof value !== "object") return false;
|
|
2999
|
+
const source = value;
|
|
3000
|
+
if (typeof source.value !== "string") return false;
|
|
3001
|
+
switch (source.type) {
|
|
3002
|
+
case "data": return typeof source.mimeType === "string";
|
|
3003
|
+
case "url": return isOptionalString(source.mimeType);
|
|
3004
|
+
case "file": return isOptionalString(source.provider) && isOptionalString(source.mimeType);
|
|
3005
|
+
default: return false;
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
/**
|
|
3009
|
+
* Mirrors `ContentPartSchema` from `@ag-ui/core/schemas`. The runtime parses
|
|
3010
|
+
* the request with that schema, and one invalid part there fails the whole run.
|
|
3011
|
+
* Core does not import the schema because the UMD build has no global for it.
|
|
3012
|
+
* A test checks this function against the schema.
|
|
3013
|
+
*/
|
|
3014
|
+
function isContentPart(value) {
|
|
3015
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
3016
|
+
const part = value;
|
|
3017
|
+
if (!isOptionalString(part.id) || part.metadata === null) return false;
|
|
3018
|
+
if (part.type === "text") return typeof part.text === "string";
|
|
3019
|
+
return typeof part.type === "string" && MEDIA_PART_TYPES.has(part.type) && isPartSource(part.source);
|
|
3020
|
+
}
|
|
3021
|
+
/**
|
|
3022
|
+
* Converts what a frontend tool handler returned into tool message content.
|
|
3023
|
+
* A non-empty array of AG-UI content parts passes through unchanged, so an
|
|
3024
|
+
* image reaches the model as media. Everything else becomes a string, as before.
|
|
3025
|
+
*
|
|
3026
|
+
* `text` is the string form, for surfaces typed as `result: string`
|
|
3027
|
+
* (`runTool`, `onToolExecutionEnd`). For content parts it is the JSON text they
|
|
3028
|
+
* received before. It is computed here, so a part that cannot be serialized
|
|
3029
|
+
* throws inside the caller's handler error boundary.
|
|
3030
|
+
*/
|
|
3031
|
+
function toToolResultContent(result) {
|
|
3032
|
+
if (result === void 0 || result === null) return {
|
|
3033
|
+
content: "",
|
|
3034
|
+
text: ""
|
|
3035
|
+
};
|
|
3036
|
+
if (typeof result === "string") return {
|
|
3037
|
+
content: result,
|
|
3038
|
+
text: result
|
|
3039
|
+
};
|
|
3040
|
+
const text = JSON.stringify(result);
|
|
3041
|
+
if (Array.isArray(result) && result.length > 0 && result.every(isContentPart)) return {
|
|
3042
|
+
content: result,
|
|
3043
|
+
text
|
|
3044
|
+
};
|
|
3045
|
+
return {
|
|
3046
|
+
content: text,
|
|
3047
|
+
text
|
|
3048
|
+
};
|
|
3049
|
+
}
|
|
2933
3050
|
|
|
2934
3051
|
//#endregion
|
|
2935
3052
|
//#region src/core/tool-schema.ts
|
|
@@ -3421,7 +3538,7 @@ var RunHandler = class {
|
|
|
3421
3538
|
this.processAgentResult({
|
|
3422
3539
|
runAgentResult,
|
|
3423
3540
|
agent,
|
|
3424
|
-
toolExecutionMode: "
|
|
3541
|
+
toolExecutionMode: "restore",
|
|
3425
3542
|
signal: controller.signal
|
|
3426
3543
|
}).catch(async (error) => {
|
|
3427
3544
|
await this._internal.emitError({
|
|
@@ -3552,8 +3669,8 @@ var RunHandler = class {
|
|
|
3552
3669
|
const threadId = agent.threadId;
|
|
3553
3670
|
const executing = this._executingToolCalls.get(agent) ?? /* @__PURE__ */ new Set();
|
|
3554
3671
|
this._executingToolCalls.set(agent, executing);
|
|
3555
|
-
if (toolExecutionMode === "
|
|
3556
|
-
const messagesToProcess = toolExecutionMode === "
|
|
3672
|
+
if (toolExecutionMode === "restore" && agent.messages.some((message) => message.role === "assistant" && 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))))) return runAgentResult;
|
|
3673
|
+
const messagesToProcess = toolExecutionMode === "restore" ? [...agent.messages] : newMessages;
|
|
3557
3674
|
for (const message of messagesToProcess) if (message.role === "assistant") for (const toolCall of message.toolCalls || []) {
|
|
3558
3675
|
const tool = this.getTool({
|
|
3559
3676
|
toolName: toolCall.function.name,
|
|
@@ -3569,7 +3686,7 @@ var RunHandler = class {
|
|
|
3569
3686
|
return wildcardTool;
|
|
3570
3687
|
};
|
|
3571
3688
|
const executableTool = tool ?? getWildcardTool();
|
|
3572
|
-
if (toolExecutionMode === "
|
|
3689
|
+
if (toolExecutionMode === "restore" && (!executableTool?.handler || executableTool.type !== "human-in-the-loop" && executableTool.reconnectBehavior !== "resume-pending")) continue;
|
|
3573
3690
|
const executionKey = JSON.stringify([threadId, toolCall.id]);
|
|
3574
3691
|
if (signal?.aborted || agent.threadId !== threadId || executing.has(executionKey)) continue;
|
|
3575
3692
|
const existingResultIndex = newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
|
|
@@ -3600,14 +3717,14 @@ var RunHandler = class {
|
|
|
3600
3717
|
if (signal?.aborted) abortInteraction();
|
|
3601
3718
|
}
|
|
3602
3719
|
const executionSignal = interactionController?.signal ?? signal;
|
|
3603
|
-
const discardOnAbort = toolExecutionMode === "
|
|
3720
|
+
const discardOnAbort = toolExecutionMode === "restore" || !!interactionController;
|
|
3604
3721
|
try {
|
|
3605
3722
|
if (tool) {
|
|
3606
|
-
if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId, executionSignal, discardOnAbort)) needsFollowUp = true;
|
|
3723
|
+
if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId, executionSignal, discardOnAbort, toolExecutionMode === "restore")) needsFollowUp = true;
|
|
3607
3724
|
} else {
|
|
3608
3725
|
const fallbackTool = getWildcardTool();
|
|
3609
3726
|
if (fallbackTool) {
|
|
3610
|
-
if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId, executionSignal, discardOnAbort)) needsFollowUp = true;
|
|
3727
|
+
if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId, executionSignal, discardOnAbort, toolExecutionMode === "restore")) needsFollowUp = true;
|
|
3611
3728
|
}
|
|
3612
3729
|
}
|
|
3613
3730
|
} finally {
|
|
@@ -3641,8 +3758,9 @@ var RunHandler = class {
|
|
|
3641
3758
|
* Handles arg parsing, subscriber notifications, handler invocation, result stringification,
|
|
3642
3759
|
* and error handling.
|
|
3643
3760
|
*/
|
|
3644
|
-
async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId, signal = this._runAbortController?.signal, discardOnAbort = false }) {
|
|
3761
|
+
async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId, signal = this._runAbortController?.signal, discardOnAbort = false, isReplay = false }) {
|
|
3645
3762
|
let toolCallResult = "";
|
|
3763
|
+
let toolCallText = "";
|
|
3646
3764
|
let errorMessage;
|
|
3647
3765
|
let isArgumentError = false;
|
|
3648
3766
|
let parsedArgs;
|
|
@@ -3676,11 +3794,10 @@ var RunHandler = class {
|
|
|
3676
3794
|
const result = await tool.handler(parsedArgs, {
|
|
3677
3795
|
toolCall,
|
|
3678
3796
|
agent,
|
|
3679
|
-
signal
|
|
3797
|
+
signal,
|
|
3798
|
+
...isReplay ? { isReplay } : {}
|
|
3680
3799
|
});
|
|
3681
|
-
|
|
3682
|
-
else if (typeof result === "string") toolCallResult = result;
|
|
3683
|
-
else toolCallResult = JSON.stringify(result);
|
|
3800
|
+
({content: toolCallResult, text: toolCallText} = toToolResultContent(result));
|
|
3684
3801
|
} catch (error) {
|
|
3685
3802
|
const handlerError = error instanceof Error ? error : new Error(String(error));
|
|
3686
3803
|
errorMessage = handlerError.message;
|
|
@@ -3697,17 +3814,18 @@ var RunHandler = class {
|
|
|
3697
3814
|
}
|
|
3698
3815
|
});
|
|
3699
3816
|
}
|
|
3700
|
-
if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
|
|
3817
|
+
if (errorMessage) toolCallResult = toolCallText = `Error: ${errorMessage}`;
|
|
3701
3818
|
await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionEnd?.({
|
|
3702
3819
|
copilotkit: this.core,
|
|
3703
3820
|
toolCallId: toolCall.id,
|
|
3704
3821
|
agentId,
|
|
3705
3822
|
toolName: toolCall.function.name,
|
|
3706
|
-
result: errorMessage ? "" :
|
|
3823
|
+
result: errorMessage ? "" : toolCallText,
|
|
3707
3824
|
error: errorMessage
|
|
3708
3825
|
}), "Subscriber onToolExecutionEnd error:");
|
|
3709
3826
|
return {
|
|
3710
|
-
|
|
3827
|
+
content: toolCallResult,
|
|
3828
|
+
result: toolCallText,
|
|
3711
3829
|
error: errorMessage,
|
|
3712
3830
|
isArgumentError
|
|
3713
3831
|
};
|
|
@@ -3715,10 +3833,11 @@ var RunHandler = class {
|
|
|
3715
3833
|
/**
|
|
3716
3834
|
* Execute a specific tool
|
|
3717
3835
|
*/
|
|
3718
|
-
async executeSpecificTool(tool, toolCall, message, agent, agentId, signal, discardOnAbort = false) {
|
|
3836
|
+
async executeSpecificTool(tool, toolCall, message, agent, agentId, signal, discardOnAbort = false, isReplay = false) {
|
|
3719
3837
|
const threadId = agent.threadId;
|
|
3720
3838
|
if (tool?.agentId && tool.agentId !== agent.agentId) return false;
|
|
3721
3839
|
let handlerResult = {
|
|
3840
|
+
content: "",
|
|
3722
3841
|
result: "",
|
|
3723
3842
|
error: void 0,
|
|
3724
3843
|
isArgumentError: false
|
|
@@ -3732,7 +3851,8 @@ var RunHandler = class {
|
|
|
3732
3851
|
toolType: "specific",
|
|
3733
3852
|
messageId: message.id,
|
|
3734
3853
|
signal,
|
|
3735
|
-
discardOnAbort
|
|
3854
|
+
discardOnAbort,
|
|
3855
|
+
isReplay
|
|
3736
3856
|
});
|
|
3737
3857
|
{
|
|
3738
3858
|
const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
|
|
@@ -3743,7 +3863,7 @@ var RunHandler = class {
|
|
|
3743
3863
|
id: randomUUID$1(),
|
|
3744
3864
|
role: "tool",
|
|
3745
3865
|
toolCallId: toolCall.id,
|
|
3746
|
-
content: handlerResult.
|
|
3866
|
+
content: handlerResult.content
|
|
3747
3867
|
};
|
|
3748
3868
|
agent.messages.splice(insertAt, 0, toolMessage);
|
|
3749
3869
|
if (!handlerResult.error && tool?.followUp !== false) return true;
|
|
@@ -3756,10 +3876,11 @@ var RunHandler = class {
|
|
|
3756
3876
|
* specific tools, so this method keeps its own arg-wrapping logic rather than
|
|
3757
3877
|
* delegating to `executeToolHandler`.
|
|
3758
3878
|
*/
|
|
3759
|
-
async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId, signal, discardOnAbort = false) {
|
|
3879
|
+
async executeWildcardTool(wildcardTool, toolCall, message, agent, agentId, signal, discardOnAbort = false, isReplay = false) {
|
|
3760
3880
|
const threadId = agent.threadId;
|
|
3761
3881
|
if (wildcardTool?.agentId && wildcardTool.agentId !== agent.agentId) return false;
|
|
3762
3882
|
let toolCallResult = "";
|
|
3883
|
+
let toolCallText = "";
|
|
3763
3884
|
let errorMessage;
|
|
3764
3885
|
if (wildcardTool?.handler) {
|
|
3765
3886
|
let parsedArgs;
|
|
@@ -3796,11 +3917,10 @@ var RunHandler = class {
|
|
|
3796
3917
|
const result = await wildcardTool.handler(wildcardArgs, {
|
|
3797
3918
|
toolCall,
|
|
3798
3919
|
agent,
|
|
3799
|
-
signal
|
|
3920
|
+
signal,
|
|
3921
|
+
...isReplay ? { isReplay } : {}
|
|
3800
3922
|
});
|
|
3801
|
-
|
|
3802
|
-
else if (typeof result === "string") toolCallResult = result;
|
|
3803
|
-
else toolCallResult = JSON.stringify(result);
|
|
3923
|
+
({content: toolCallResult, text: toolCallText} = toToolResultContent(result));
|
|
3804
3924
|
} catch (error) {
|
|
3805
3925
|
const handlerError = error instanceof Error ? error : new Error(String(error));
|
|
3806
3926
|
errorMessage = handlerError.message;
|
|
@@ -3817,13 +3937,13 @@ var RunHandler = class {
|
|
|
3817
3937
|
}
|
|
3818
3938
|
});
|
|
3819
3939
|
}
|
|
3820
|
-
if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
|
|
3940
|
+
if (errorMessage) toolCallResult = toolCallText = `Error: ${errorMessage}`;
|
|
3821
3941
|
await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionEnd?.({
|
|
3822
3942
|
copilotkit: this.core,
|
|
3823
3943
|
toolCallId: toolCall.id,
|
|
3824
3944
|
agentId,
|
|
3825
3945
|
toolName: toolCall.function.name,
|
|
3826
|
-
result: errorMessage ? "" :
|
|
3946
|
+
result: errorMessage ? "" : toolCallText,
|
|
3827
3947
|
error: errorMessage
|
|
3828
3948
|
}), "Subscriber onToolExecutionEnd error:");
|
|
3829
3949
|
}
|
|
@@ -3894,6 +4014,7 @@ var RunHandler = class {
|
|
|
3894
4014
|
};
|
|
3895
4015
|
agent.messages.push(assistantMessage);
|
|
3896
4016
|
let handlerResult = {
|
|
4017
|
+
content: "",
|
|
3897
4018
|
result: "",
|
|
3898
4019
|
error: void 0,
|
|
3899
4020
|
isArgumentError: false
|
|
@@ -3910,7 +4031,7 @@ var RunHandler = class {
|
|
|
3910
4031
|
id: randomUUID$1(),
|
|
3911
4032
|
role: "tool",
|
|
3912
4033
|
toolCallId,
|
|
3913
|
-
content: handlerResult.
|
|
4034
|
+
content: handlerResult.content
|
|
3914
4035
|
};
|
|
3915
4036
|
const assistantIndex = agent.messages.findIndex((m) => m.id === assistantMessage.id);
|
|
3916
4037
|
if (assistantIndex !== -1) agent.messages.splice(assistantIndex + 1, 0, toolResultMessage);
|
|
@@ -4511,6 +4632,750 @@ var ThreadStoreRegistry = class {
|
|
|
4511
4632
|
}
|
|
4512
4633
|
};
|
|
4513
4634
|
|
|
4635
|
+
//#endregion
|
|
4636
|
+
//#region src/core/trajectory-connection.ts
|
|
4637
|
+
const TIMEOUT_MS = 1e4;
|
|
4638
|
+
const BATCH_INTERVAL_MS = 2e3;
|
|
4639
|
+
const MAX_BATCH_EVENTS = 50;
|
|
4640
|
+
const MAX_BATCH_BYTES = 64 * 1024;
|
|
4641
|
+
const MAX_EVENT_BYTES = 16 * 1024;
|
|
4642
|
+
const byteLength = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
4643
|
+
const reconnectDelay = phoenixExponentialBackoff(1e3, 1e4);
|
|
4644
|
+
function isObject(value) {
|
|
4645
|
+
return typeof value === "object" && value !== null;
|
|
4646
|
+
}
|
|
4647
|
+
function isNonNegativeInteger(value) {
|
|
4648
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
4649
|
+
}
|
|
4650
|
+
function isBatchAcknowledgement(value, eventCount) {
|
|
4651
|
+
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);
|
|
4652
|
+
}
|
|
4653
|
+
function isGrant(value) {
|
|
4654
|
+
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;
|
|
4655
|
+
}
|
|
4656
|
+
function errorCode(value, fallback) {
|
|
4657
|
+
return isObject(value) && typeof value.code === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(value.code) ? value.code : fallback;
|
|
4658
|
+
}
|
|
4659
|
+
/** Owns bounded, connected-only capture batches. Failed batches are never resent. */
|
|
4660
|
+
var TrajectoryConnection = class {
|
|
4661
|
+
session;
|
|
4662
|
+
nextSeq = Math.floor(Date.now()) * 1e3;
|
|
4663
|
+
constructor(core, onChange) {
|
|
4664
|
+
this.core = core;
|
|
4665
|
+
this.onChange = onChange;
|
|
4666
|
+
}
|
|
4667
|
+
get trajectoryId() {
|
|
4668
|
+
return this.session?.ready ? this.session.trajectoryId : null;
|
|
4669
|
+
}
|
|
4670
|
+
start(trajectoryId, config) {
|
|
4671
|
+
if (this.session && (trajectoryId === void 0 || trajectoryId === this.session.trajectoryId)) return this.session.promise;
|
|
4672
|
+
this.stop();
|
|
4673
|
+
const id = trajectoryId ?? crypto.randomUUID();
|
|
4674
|
+
let resolveStart;
|
|
4675
|
+
const promise = new Promise((resolve) => {
|
|
4676
|
+
resolveStart = resolve;
|
|
4677
|
+
});
|
|
4678
|
+
const session = {
|
|
4679
|
+
trajectoryId: id,
|
|
4680
|
+
config,
|
|
4681
|
+
promise,
|
|
4682
|
+
resolve: resolveStart,
|
|
4683
|
+
retries: 0,
|
|
4684
|
+
queue: [],
|
|
4685
|
+
dropped: 0,
|
|
4686
|
+
ready: false,
|
|
4687
|
+
started: false,
|
|
4688
|
+
offline: typeof navigator !== "undefined" && navigator.onLine === false,
|
|
4689
|
+
onOffline: () => {
|
|
4690
|
+
if (this.session !== session) return;
|
|
4691
|
+
session.offline = true;
|
|
4692
|
+
if (session.connection) this.fail(session, session.connection, "CONNECTION_LOST");
|
|
4693
|
+
clearTimeout(session.retry);
|
|
4694
|
+
session.retry = void 0;
|
|
4695
|
+
},
|
|
4696
|
+
onOnline: () => {
|
|
4697
|
+
if (this.session !== session) return;
|
|
4698
|
+
session.offline = false;
|
|
4699
|
+
if (!session.connection) {
|
|
4700
|
+
clearTimeout(session.retry);
|
|
4701
|
+
session.retry = void 0;
|
|
4702
|
+
this.connect(session);
|
|
4703
|
+
}
|
|
4704
|
+
},
|
|
4705
|
+
linkedThreads: /* @__PURE__ */ new Set(),
|
|
4706
|
+
agentWatches: /* @__PURE__ */ new Map()
|
|
4707
|
+
};
|
|
4708
|
+
this.session = session;
|
|
4709
|
+
session.runWatch = this.core.subscribe({ onAgentRunStarted: ({ agent }) => this.watchAgent(session, agent) });
|
|
4710
|
+
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
4711
|
+
window.addEventListener("offline", session.onOffline);
|
|
4712
|
+
window.addEventListener("online", session.onOnline);
|
|
4713
|
+
}
|
|
4714
|
+
if (session.offline) {
|
|
4715
|
+
this.report(session, "CONNECTION_LOST");
|
|
4716
|
+
this.end(session, {
|
|
4717
|
+
status: "error",
|
|
4718
|
+
code: "CONNECTION_LOST"
|
|
4719
|
+
});
|
|
4720
|
+
} else this.connect(session);
|
|
4721
|
+
return promise;
|
|
4722
|
+
}
|
|
4723
|
+
stop() {
|
|
4724
|
+
const session = this.session;
|
|
4725
|
+
if (!session) return;
|
|
4726
|
+
if (session.ready && session.connection) this.flush(session, session.connection);
|
|
4727
|
+
this.end(session, {
|
|
4728
|
+
status: "error",
|
|
4729
|
+
code: "CANCELLED"
|
|
4730
|
+
});
|
|
4731
|
+
}
|
|
4732
|
+
emit(name, value) {
|
|
4733
|
+
const session = this.session;
|
|
4734
|
+
if (session?.ready) session.collector?.emit(name, value);
|
|
4735
|
+
else if (session?.started) this.addDropped(session, 1, false);
|
|
4736
|
+
}
|
|
4737
|
+
watchAgent(session, agent) {
|
|
4738
|
+
if (this.session !== session || session.agentWatches.has(agent)) return;
|
|
4739
|
+
session.agentWatches.set(agent, agent.subscribe({ onRunStartedEvent: ({ event }) => this.linkThread(session, event) }));
|
|
4740
|
+
}
|
|
4741
|
+
/** Sends one `thread.linked` per Thread. A link that cannot be sent waits for the next run. */
|
|
4742
|
+
linkThread(session, { threadId }) {
|
|
4743
|
+
const connection = session.connection;
|
|
4744
|
+
if (!session.ready || !connection || !threadId || session.linkedThreads.has(threadId)) return;
|
|
4745
|
+
session.linkedThreads.add(threadId);
|
|
4746
|
+
const event = {
|
|
4747
|
+
type: "CUSTOM",
|
|
4748
|
+
name: "thread.linked",
|
|
4749
|
+
timestamp: Date.now(),
|
|
4750
|
+
value: { threadId }
|
|
4751
|
+
};
|
|
4752
|
+
try {
|
|
4753
|
+
const { beforeSend } = session.config;
|
|
4754
|
+
const kept = beforeSend === void 0 ? event : beforeSend(event);
|
|
4755
|
+
if (kept !== null) this.send(session, connection, kept);
|
|
4756
|
+
} catch {
|
|
4757
|
+
this.report(session, "INVALID_EVENT");
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
report(session, code) {
|
|
4761
|
+
try {
|
|
4762
|
+
session.config.onError?.({
|
|
4763
|
+
code,
|
|
4764
|
+
message: `Trajectory capture: ${code}.`
|
|
4765
|
+
});
|
|
4766
|
+
} catch {}
|
|
4767
|
+
}
|
|
4768
|
+
current(session, connection) {
|
|
4769
|
+
return this.session === session && session.connection === connection;
|
|
4770
|
+
}
|
|
4771
|
+
end(session, result) {
|
|
4772
|
+
if (this.session !== session) return;
|
|
4773
|
+
this.session = void 0;
|
|
4774
|
+
clearTimeout(session.retry);
|
|
4775
|
+
session.runWatch?.unsubscribe();
|
|
4776
|
+
for (const watch of session.agentWatches.values()) watch.unsubscribe();
|
|
4777
|
+
session.agentWatches.clear();
|
|
4778
|
+
session.collector?.stop();
|
|
4779
|
+
session.ready = false;
|
|
4780
|
+
if (session.queue.length > 0) this.report(session, "EVENTS_DROPPED");
|
|
4781
|
+
this.discardQueue(session);
|
|
4782
|
+
if (session.connection) {
|
|
4783
|
+
for (const pending of session.connection.pending) {
|
|
4784
|
+
pending.finish("PERSISTENCE_UNKNOWN");
|
|
4785
|
+
this.report(session, "PERSISTENCE_UNKNOWN");
|
|
4786
|
+
}
|
|
4787
|
+
this.cleanup(session, session.connection);
|
|
4788
|
+
}
|
|
4789
|
+
if (typeof window !== "undefined" && typeof window.removeEventListener === "function") {
|
|
4790
|
+
window.removeEventListener("offline", session.onOffline);
|
|
4791
|
+
window.removeEventListener("online", session.onOnline);
|
|
4792
|
+
}
|
|
4793
|
+
session.resolve(result);
|
|
4794
|
+
this.onChange();
|
|
4795
|
+
}
|
|
4796
|
+
cleanup(session, connection) {
|
|
4797
|
+
session.connection = void 0;
|
|
4798
|
+
clearTimeout(connection.timer);
|
|
4799
|
+
connection.abort.abort();
|
|
4800
|
+
for (const pending of connection.pending) clearTimeout(pending.timer);
|
|
4801
|
+
connection.pending.clear();
|
|
4802
|
+
const { socket, channel } = connection;
|
|
4803
|
+
try {
|
|
4804
|
+
if (channel) {
|
|
4805
|
+
for (const [event, ref] of connection.channelRefs) channel.off(event, ref);
|
|
4806
|
+
channel.leave();
|
|
4807
|
+
}
|
|
4808
|
+
} finally {
|
|
4809
|
+
if (socket) {
|
|
4810
|
+
socket.off(connection.socketRefs);
|
|
4811
|
+
socket.disconnect();
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
}
|
|
4815
|
+
fail(session, connection, code, retryable = true) {
|
|
4816
|
+
if (!this.current(session, connection)) return;
|
|
4817
|
+
session.collector?.stop();
|
|
4818
|
+
session.collector = void 0;
|
|
4819
|
+
if (session.ready && session.started) session.promise = new Promise((resolve) => {
|
|
4820
|
+
session.resolve = resolve;
|
|
4821
|
+
});
|
|
4822
|
+
session.ready = false;
|
|
4823
|
+
this.discardQueue(session);
|
|
4824
|
+
session.linkedThreads.clear();
|
|
4825
|
+
for (const pending of connection.pending) pending.finish("PERSISTENCE_UNKNOWN");
|
|
4826
|
+
if (!this.current(session, connection)) return;
|
|
4827
|
+
this.cleanup(session, connection);
|
|
4828
|
+
this.onChange();
|
|
4829
|
+
this.report(session, code);
|
|
4830
|
+
if (this.session !== session) return;
|
|
4831
|
+
if (!session.started || !retryable) {
|
|
4832
|
+
this.end(session, {
|
|
4833
|
+
status: "error",
|
|
4834
|
+
code
|
|
4835
|
+
});
|
|
4836
|
+
return;
|
|
4837
|
+
}
|
|
4838
|
+
if (session.offline || this.session !== session) return;
|
|
4839
|
+
session.retry = setTimeout(() => {
|
|
4840
|
+
session.retry = void 0;
|
|
4841
|
+
if (this.session === session && !session.offline) this.connect(session);
|
|
4842
|
+
}, reconnectDelay(++session.retries));
|
|
4843
|
+
}
|
|
4844
|
+
async connect(session) {
|
|
4845
|
+
if (this.session !== session || session.offline || session.connection) return;
|
|
4846
|
+
const connection = {
|
|
4847
|
+
abort: new AbortController(),
|
|
4848
|
+
socketRefs: [],
|
|
4849
|
+
channelRefs: [],
|
|
4850
|
+
pending: /* @__PURE__ */ new Set()
|
|
4851
|
+
};
|
|
4852
|
+
session.connection = connection;
|
|
4853
|
+
connection.timer = setTimeout(() => this.fail(session, connection, "CONNECTION_TIMEOUT"), TIMEOUT_MS);
|
|
4854
|
+
try {
|
|
4855
|
+
const runtimeUrl = this.core.runtimeUrl;
|
|
4856
|
+
if (!runtimeUrl) {
|
|
4857
|
+
this.fail(session, connection, "RUNTIME_REQUIRED", false);
|
|
4858
|
+
return;
|
|
4859
|
+
}
|
|
4860
|
+
let transport = this.core.runtimeTransport;
|
|
4861
|
+
if (transport === "auto") {
|
|
4862
|
+
transport = await this.detectedTransport(connection.abort.signal);
|
|
4863
|
+
if (!this.current(session, connection)) return;
|
|
4864
|
+
}
|
|
4865
|
+
const rest = transport === "rest";
|
|
4866
|
+
const response = await fetch(rest ? `${runtimeUrl}/trajectory/${encodeURIComponent(session.trajectoryId)}/connect` : this.core.ɵruntimeEndpointUrl ?? runtimeUrl, {
|
|
4867
|
+
method: "POST",
|
|
4868
|
+
redirect: "error",
|
|
4869
|
+
signal: connection.abort.signal,
|
|
4870
|
+
headers: {
|
|
4871
|
+
...this.core.headers,
|
|
4872
|
+
"Content-Type": "application/json"
|
|
4873
|
+
},
|
|
4874
|
+
credentials: this.core.credentials,
|
|
4875
|
+
body: JSON.stringify(rest ? {} : {
|
|
4876
|
+
method: "trajectory/connect",
|
|
4877
|
+
params: { trajectoryId: session.trajectoryId },
|
|
4878
|
+
body: {}
|
|
4879
|
+
})
|
|
4880
|
+
});
|
|
4881
|
+
if (!this.current(session, connection)) return;
|
|
4882
|
+
const payload = await response.json().catch(() => void 0);
|
|
4883
|
+
if (!this.current(session, connection)) return;
|
|
4884
|
+
if (!response.ok) {
|
|
4885
|
+
this.fail(session, connection, errorCode(payload, "CONNECTION_FAILED"), response.status >= 500 || response.status === 408 || response.status === 429);
|
|
4886
|
+
return;
|
|
4887
|
+
}
|
|
4888
|
+
if (!isGrant(payload)) {
|
|
4889
|
+
this.fail(session, connection, "INVALID_GRANT", false);
|
|
4890
|
+
return;
|
|
4891
|
+
}
|
|
4892
|
+
const socket = new Socket(payload.realtime.clientUrl, {
|
|
4893
|
+
params: { join_token: payload.joinToken },
|
|
4894
|
+
timeout: TIMEOUT_MS
|
|
4895
|
+
});
|
|
4896
|
+
connection.socket = socket;
|
|
4897
|
+
const lost = () => this.fail(session, connection, "CONNECTION_LOST");
|
|
4898
|
+
connection.socketRefs.push(socket.onError(lost), socket.onClose(lost));
|
|
4899
|
+
const channel = socket.channel(payload.realtime.topic, {});
|
|
4900
|
+
connection.channel = channel;
|
|
4901
|
+
connection.channelRefs.push(["phx_error", channel.onError(lost)], ["phx_close", channel.onClose(lost)]);
|
|
4902
|
+
socket.connect();
|
|
4903
|
+
if (!this.current(session, connection)) return;
|
|
4904
|
+
channel.join(TIMEOUT_MS).receive("ok", () => {
|
|
4905
|
+
if (!this.current(session, connection)) return;
|
|
4906
|
+
try {
|
|
4907
|
+
clearTimeout(connection.timer);
|
|
4908
|
+
session.ready = true;
|
|
4909
|
+
session.retries = 0;
|
|
4910
|
+
session.collector = createTrajectoryCollector({
|
|
4911
|
+
...session.config,
|
|
4912
|
+
ignoreUrls: [
|
|
4913
|
+
...session.config.ignoreUrls ?? [],
|
|
4914
|
+
...this.core.runtimeUrl ? [this.core.runtimeUrl] : [],
|
|
4915
|
+
...this.core.ɵruntimeEndpointUrl ? [this.core.ɵruntimeEndpointUrl] : [],
|
|
4916
|
+
"https://telemetry.copilotkit.ai/",
|
|
4917
|
+
"https://cdn.copilotkit.ai/"
|
|
4918
|
+
],
|
|
4919
|
+
onError: (error) => {
|
|
4920
|
+
if (error.code === "CAPTURE_FAILED") this.fail(session, connection, error.code, false);
|
|
4921
|
+
else {
|
|
4922
|
+
if (error.code === "INVALID_EVENT" || error.code === "EVENT_TOO_LARGE") this.addDropped(session, 1);
|
|
4923
|
+
session.config.onError?.(error);
|
|
4924
|
+
}
|
|
4925
|
+
},
|
|
4926
|
+
send: (event) => this.send(session, connection, event)
|
|
4927
|
+
});
|
|
4928
|
+
session.collector.start();
|
|
4929
|
+
if (!this.current(session, connection)) return;
|
|
4930
|
+
if (session.dropped > 0) this.scheduleFlush(session, connection);
|
|
4931
|
+
session.started = true;
|
|
4932
|
+
session.resolve({
|
|
4933
|
+
status: "started",
|
|
4934
|
+
trajectoryId: session.trajectoryId
|
|
4935
|
+
});
|
|
4936
|
+
this.onChange();
|
|
4937
|
+
} catch {
|
|
4938
|
+
this.fail(session, connection, "CAPTURE_FAILED", false);
|
|
4939
|
+
}
|
|
4940
|
+
}).receive("error", (joinError) => this.fail(session, connection, errorCode(joinError, "JOIN_FAILED"))).receive("timeout", () => this.fail(session, connection, "CONNECTION_TIMEOUT"));
|
|
4941
|
+
} catch {
|
|
4942
|
+
this.fail(session, connection, "CONNECTION_FAILED");
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
/** Resolves once auto-detection picks a transport, or with "auto" when the attempt is aborted. */
|
|
4946
|
+
detectedTransport(signal) {
|
|
4947
|
+
return new Promise((resolve) => {
|
|
4948
|
+
const finish = () => {
|
|
4949
|
+
subscription.unsubscribe();
|
|
4950
|
+
signal.removeEventListener("abort", finish);
|
|
4951
|
+
resolve(this.core.runtimeTransport);
|
|
4952
|
+
};
|
|
4953
|
+
const subscription = this.core.subscribe({ onRuntimeConnectionStatusChanged: () => {
|
|
4954
|
+
if (this.core.runtimeTransport !== "auto") finish();
|
|
4955
|
+
} });
|
|
4956
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
4957
|
+
});
|
|
4958
|
+
}
|
|
4959
|
+
addDropped(session, count, schedule = true) {
|
|
4960
|
+
session.dropped = Math.min(Number.MAX_SAFE_INTEGER, session.dropped + count);
|
|
4961
|
+
if (schedule && count > 0 && session.ready && session.connection) this.scheduleFlush(session, session.connection);
|
|
4962
|
+
}
|
|
4963
|
+
scheduleFlush(session, connection) {
|
|
4964
|
+
if (session.flushTimer !== void 0 || !this.current(session, connection)) return;
|
|
4965
|
+
session.flushTimer = setTimeout(() => {
|
|
4966
|
+
session.flushTimer = void 0;
|
|
4967
|
+
this.flush(session, connection);
|
|
4968
|
+
}, BATCH_INTERVAL_MS);
|
|
4969
|
+
}
|
|
4970
|
+
discardQueue(session) {
|
|
4971
|
+
clearTimeout(session.flushTimer);
|
|
4972
|
+
session.flushTimer = void 0;
|
|
4973
|
+
this.addDropped(session, session.queue.length, false);
|
|
4974
|
+
session.queue = [];
|
|
4975
|
+
}
|
|
4976
|
+
connected(connection) {
|
|
4977
|
+
return connection.socket?.isConnected() === true && connection.channel?.state === "joined";
|
|
4978
|
+
}
|
|
4979
|
+
send(session, connection, event) {
|
|
4980
|
+
if (!this.current(session, connection) || !session.ready) return;
|
|
4981
|
+
if (!this.connected(connection)) {
|
|
4982
|
+
this.addDropped(session, 1);
|
|
4983
|
+
this.fail(session, connection, "CONNECTION_LOST");
|
|
4984
|
+
return;
|
|
4985
|
+
}
|
|
4986
|
+
if (!Number.isSafeInteger(this.nextSeq)) {
|
|
4987
|
+
this.addDropped(session, 1);
|
|
4988
|
+
this.report(session, "SEQUENCE_EXHAUSTED");
|
|
4989
|
+
return;
|
|
4990
|
+
}
|
|
4991
|
+
const original = event.value;
|
|
4992
|
+
const fields = isObject(original) && !Array.isArray(original) && !Object.hasOwn(original, "seq") ? original : { data: original };
|
|
4993
|
+
const wire = {
|
|
4994
|
+
...event,
|
|
4995
|
+
value: {
|
|
4996
|
+
...fields,
|
|
4997
|
+
seq: this.nextSeq++
|
|
4998
|
+
}
|
|
4999
|
+
};
|
|
5000
|
+
if (byteLength(wire) > MAX_EVENT_BYTES) {
|
|
5001
|
+
this.addDropped(session, 1);
|
|
5002
|
+
this.report(session, "EVENT_TOO_LARGE");
|
|
5003
|
+
return;
|
|
5004
|
+
}
|
|
5005
|
+
const fits = () => session.queue.length < MAX_BATCH_EVENTS && byteLength({
|
|
5006
|
+
events: [...session.queue, wire],
|
|
5007
|
+
dropped: Number.MAX_SAFE_INTEGER
|
|
5008
|
+
}) <= MAX_BATCH_BYTES;
|
|
5009
|
+
if (!fits()) this.flush(session, connection);
|
|
5010
|
+
if (!this.current(session, connection) || !session.ready) return;
|
|
5011
|
+
if (!fits()) {
|
|
5012
|
+
this.addDropped(session, 1);
|
|
5013
|
+
this.report(session, "EVENTS_DROPPED");
|
|
5014
|
+
return;
|
|
5015
|
+
}
|
|
5016
|
+
session.queue.push(wire);
|
|
5017
|
+
if (session.queue.length === MAX_BATCH_EVENTS) this.flush(session, connection);
|
|
5018
|
+
else this.scheduleFlush(session, connection);
|
|
5019
|
+
}
|
|
5020
|
+
flush(session, connection) {
|
|
5021
|
+
if (!this.current(session, connection) || !session.ready || session.queue.length === 0 && session.dropped === 0) return;
|
|
5022
|
+
if (!this.connected(connection)) {
|
|
5023
|
+
this.fail(session, connection, "CONNECTION_LOST");
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
5026
|
+
if (connection.pending.size > 0) return;
|
|
5027
|
+
clearTimeout(session.flushTimer);
|
|
5028
|
+
session.flushTimer = void 0;
|
|
5029
|
+
const batch = {
|
|
5030
|
+
events: session.queue,
|
|
5031
|
+
dropped: session.dropped
|
|
5032
|
+
};
|
|
5033
|
+
session.queue = [];
|
|
5034
|
+
session.dropped = 0;
|
|
5035
|
+
let finished = false;
|
|
5036
|
+
const pending = {
|
|
5037
|
+
timer: setTimeout(() => pending.finish("PERSISTENCE_UNKNOWN"), TIMEOUT_MS),
|
|
5038
|
+
finish: (code, knownRollback = false, flushNext = true) => {
|
|
5039
|
+
if (finished) return;
|
|
5040
|
+
finished = true;
|
|
5041
|
+
clearTimeout(pending.timer);
|
|
5042
|
+
connection.pending.delete(pending);
|
|
5043
|
+
if (knownRollback) this.addDropped(session, batch.events.length + batch.dropped, false);
|
|
5044
|
+
if (code && this.current(session, connection)) this.report(session, code);
|
|
5045
|
+
if (flushNext && this.current(session, connection) && session.ready && (session.queue.length > 0 || !knownRollback && session.dropped > 0)) this.flush(session, connection);
|
|
5046
|
+
}
|
|
5047
|
+
};
|
|
5048
|
+
connection.pending.add(pending);
|
|
5049
|
+
try {
|
|
5050
|
+
connection.channel.push("events", batch, TIMEOUT_MS).receive("ok", (payload) => {
|
|
5051
|
+
pending.finish(!isBatchAcknowledgement(payload, batch.events.length) ? "PERSISTENCE_UNKNOWN" : payload.rejected > 0 ? "EVENTS_REJECTED" : void 0);
|
|
5052
|
+
}).receive("error", (payload) => {
|
|
5053
|
+
if (!this.current(session, connection)) return;
|
|
5054
|
+
const reason = isObject(payload) ? payload.reason : void 0;
|
|
5055
|
+
if (reason === "unauthorized" || reason === "trajectory_mismatch") {
|
|
5056
|
+
pending.finish(void 0, true, false);
|
|
5057
|
+
this.fail(session, connection, reason.toUpperCase(), false);
|
|
5058
|
+
return;
|
|
5059
|
+
}
|
|
5060
|
+
const rollback = typeof reason === "string" && [
|
|
5061
|
+
"invalid_batch",
|
|
5062
|
+
"batch_too_large",
|
|
5063
|
+
"batch_too_many_events",
|
|
5064
|
+
"trajectory_over_share",
|
|
5065
|
+
"trajectory_outbox_full",
|
|
5066
|
+
"unsupported_event"
|
|
5067
|
+
].includes(reason);
|
|
5068
|
+
pending.finish(rollback ? reason.toUpperCase() : "PERSISTENCE_UNKNOWN", rollback);
|
|
5069
|
+
}).receive("timeout", () => pending.finish("PERSISTENCE_UNKNOWN"));
|
|
5070
|
+
} catch {
|
|
5071
|
+
pending.finish("PERSISTENCE_UNKNOWN");
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
};
|
|
5075
|
+
|
|
5076
|
+
//#endregion
|
|
5077
|
+
//#region src/core/learning-bridge.ts
|
|
5078
|
+
const COPILOTKIT_OWN_URLS = ["https://telemetry.copilotkit.ai/", "https://cdn.copilotkit.ai/"];
|
|
5079
|
+
/**
|
|
5080
|
+
* Wires `@copilotkit/learning` into Core. Default capture uses Runtime and Phoenix;
|
|
5081
|
+
* explicit legacy sinks also use agent events and open-Thread attribution.
|
|
5082
|
+
*/
|
|
5083
|
+
var LearningBridge = class {
|
|
5084
|
+
collector = null;
|
|
5085
|
+
agents = /* @__PURE__ */ new Map();
|
|
5086
|
+
openThreads = /* @__PURE__ */ new Set();
|
|
5087
|
+
toolCalls = /* @__PURE__ */ new Map();
|
|
5088
|
+
executingTools = /* @__PURE__ */ new Map();
|
|
5089
|
+
lastRunIds = /* @__PURE__ */ new WeakMap();
|
|
5090
|
+
lastLinkedThreadId = null;
|
|
5091
|
+
coreSubscription = null;
|
|
5092
|
+
seq = 0;
|
|
5093
|
+
activeConfig;
|
|
5094
|
+
connection;
|
|
5095
|
+
constructor(core, config, onChange = () => {}) {
|
|
5096
|
+
this.core = core;
|
|
5097
|
+
this.config = config;
|
|
5098
|
+
this.connection = new TrajectoryConnection(core, onChange);
|
|
5099
|
+
this.setConfig(config);
|
|
5100
|
+
}
|
|
5101
|
+
setConfig(config) {
|
|
5102
|
+
this.config = config;
|
|
5103
|
+
if (config === void 0) this.stop();
|
|
5104
|
+
}
|
|
5105
|
+
get isConfigured() {
|
|
5106
|
+
return this.config !== void 0;
|
|
5107
|
+
}
|
|
5108
|
+
get isLegacyCaptureActive() {
|
|
5109
|
+
return this.collector !== null && this.collector.trajectoryId !== null;
|
|
5110
|
+
}
|
|
5111
|
+
startTracking() {
|
|
5112
|
+
if (this.coreSubscription !== null || !this.isLegacyCaptureActive) return;
|
|
5113
|
+
this.coreSubscription = this.core.subscribe({
|
|
5114
|
+
onAgentsChanged: ({ agents }) => {
|
|
5115
|
+
for (const agent of Object.values(agents)) this.track(agent);
|
|
5116
|
+
},
|
|
5117
|
+
onAgentRunStarted: ({ agent }) => this.track(agent),
|
|
5118
|
+
onToolExecutionStart: ({ toolCallId, agentId, toolName }) => {
|
|
5119
|
+
if (!this.isLegacyCaptureActive) return;
|
|
5120
|
+
this.executingTools.set(toolCallId, Date.now());
|
|
5121
|
+
this.emitToolCall("executing", toolCallId, agentId, toolName, {});
|
|
5122
|
+
},
|
|
5123
|
+
onToolExecutionEnd: ({ toolCallId, agentId, toolName, error }) => {
|
|
5124
|
+
if (!this.isLegacyCaptureActive) return;
|
|
5125
|
+
const startedAt = this.executingTools.get(toolCallId);
|
|
5126
|
+
this.executingTools.delete(toolCallId);
|
|
5127
|
+
this.emitToolCall("completed", toolCallId, agentId, toolName, {
|
|
5128
|
+
durationMs: startedAt === void 0 ? void 0 : Date.now() - startedAt,
|
|
5129
|
+
outcome: error === void 0 ? "ok" : "error"
|
|
5130
|
+
});
|
|
5131
|
+
this.toolCalls.delete(toolCallId);
|
|
5132
|
+
}
|
|
5133
|
+
});
|
|
5134
|
+
for (const agent of Object.values(this.core.agents)) this.track(agent);
|
|
5135
|
+
}
|
|
5136
|
+
get trajectoryId() {
|
|
5137
|
+
return this.connection.trajectoryId ?? this.collector?.trajectoryId ?? null;
|
|
5138
|
+
}
|
|
5139
|
+
start(options = {}) {
|
|
5140
|
+
const config = this.config;
|
|
5141
|
+
if (config === void 0) {
|
|
5142
|
+
console.warn("[CopilotKit] startTrajectory() needs the `learning` option on CopilotKitCore (or the CopilotKitProvider `learning` prop).");
|
|
5143
|
+
return Promise.resolve({
|
|
5144
|
+
status: "error",
|
|
5145
|
+
code: "LEARNING_DISABLED"
|
|
5146
|
+
});
|
|
5147
|
+
}
|
|
5148
|
+
if (config.sink === void 0) {
|
|
5149
|
+
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.");
|
|
5150
|
+
this.stopLegacy();
|
|
5151
|
+
return this.connection.start(options.trajectoryId, config);
|
|
5152
|
+
}
|
|
5153
|
+
this.connection.stop();
|
|
5154
|
+
const trajectoryId = options.trajectoryId ?? this.collector?.trajectoryId ?? crypto.randomUUID();
|
|
5155
|
+
if (this.collector === null) {
|
|
5156
|
+
this.activeConfig = config;
|
|
5157
|
+
const runtimeUrl = this.core.runtimeUrl;
|
|
5158
|
+
this.collector = createCollector({
|
|
5159
|
+
...config,
|
|
5160
|
+
beforeSend: (event) => {
|
|
5161
|
+
const sequenced = {
|
|
5162
|
+
...event,
|
|
5163
|
+
value: {
|
|
5164
|
+
...event.value,
|
|
5165
|
+
seq: ++this.seq
|
|
5166
|
+
}
|
|
5167
|
+
};
|
|
5168
|
+
return config.beforeSend === void 0 ? sequenced : config.beforeSend(sequenced);
|
|
5169
|
+
},
|
|
5170
|
+
ignoreUrls: [
|
|
5171
|
+
...config.ignoreUrls ?? [],
|
|
5172
|
+
...COPILOTKIT_OWN_URLS,
|
|
5173
|
+
...runtimeUrl === void 0 ? [] : [runtimeUrl]
|
|
5174
|
+
],
|
|
5175
|
+
enrich: (target) => this.enrich(target)
|
|
5176
|
+
});
|
|
5177
|
+
}
|
|
5178
|
+
const wasActive = this.collector.trajectoryId !== null;
|
|
5179
|
+
this.collector.start({
|
|
5180
|
+
...options,
|
|
5181
|
+
trajectoryId
|
|
5182
|
+
});
|
|
5183
|
+
if (wasActive) return Promise.resolve(this.collector.trajectoryId === trajectoryId ? {
|
|
5184
|
+
status: "started",
|
|
5185
|
+
trajectoryId
|
|
5186
|
+
} : {
|
|
5187
|
+
status: "error",
|
|
5188
|
+
code: "TRAJECTORY_ACTIVE"
|
|
5189
|
+
});
|
|
5190
|
+
this.startTracking();
|
|
5191
|
+
this.lastLinkedThreadId = null;
|
|
5192
|
+
for (const threadId of this.distinctOpenThreadIds()) this.emitThreadLinked(threadId, "start");
|
|
5193
|
+
return Promise.resolve({
|
|
5194
|
+
status: "started",
|
|
5195
|
+
trajectoryId
|
|
5196
|
+
});
|
|
5197
|
+
}
|
|
5198
|
+
stop() {
|
|
5199
|
+
this.connection.stop();
|
|
5200
|
+
this.stopLegacy();
|
|
5201
|
+
}
|
|
5202
|
+
stopLegacy() {
|
|
5203
|
+
this.collector?.stop();
|
|
5204
|
+
this.collector = null;
|
|
5205
|
+
this.activeConfig = void 0;
|
|
5206
|
+
this.coreSubscription?.unsubscribe();
|
|
5207
|
+
this.coreSubscription = null;
|
|
5208
|
+
for (const subscription of this.agents.values()) subscription.unsubscribe();
|
|
5209
|
+
this.agents.clear();
|
|
5210
|
+
this.toolCalls.clear();
|
|
5211
|
+
this.executingTools.clear();
|
|
5212
|
+
}
|
|
5213
|
+
/** A developer event. Only an explicit legacy sink adds open-Thread context. */
|
|
5214
|
+
emit(name, value) {
|
|
5215
|
+
this.connection.emit(name, value);
|
|
5216
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) this.collector?.emit(name, {
|
|
5217
|
+
...this.openThreadContext(),
|
|
5218
|
+
...value
|
|
5219
|
+
});
|
|
5220
|
+
}
|
|
5221
|
+
registerOpenThread(params) {
|
|
5222
|
+
const entry = { ...params };
|
|
5223
|
+
const isNew = !this.distinctOpenThreadIds().includes(entry.threadId);
|
|
5224
|
+
this.openThreads.add(entry);
|
|
5225
|
+
if (isNew) this.emitThreadLinked(entry.threadId, "open");
|
|
5226
|
+
return {
|
|
5227
|
+
update: (threadId) => {
|
|
5228
|
+
if (threadId === entry.threadId) return;
|
|
5229
|
+
entry.threadId = threadId;
|
|
5230
|
+
if (![...this.openThreads].filter((other) => other !== entry).some((other) => other.threadId === threadId)) this.emitThreadLinked(threadId, "switch");
|
|
5231
|
+
},
|
|
5232
|
+
unregister: () => {
|
|
5233
|
+
this.openThreads.delete(entry);
|
|
5234
|
+
}
|
|
5235
|
+
};
|
|
5236
|
+
}
|
|
5237
|
+
distinctOpenThreadIds() {
|
|
5238
|
+
return [...new Set([...this.openThreads].map((open) => open.threadId))];
|
|
5239
|
+
}
|
|
5240
|
+
emitThreadLinked(threadId, reason) {
|
|
5241
|
+
if (!(this.collector !== null && this.collector.trajectoryId !== null) || threadId === this.lastLinkedThreadId) return;
|
|
5242
|
+
this.lastLinkedThreadId = threadId;
|
|
5243
|
+
const owner = [...this.openThreads].find((open) => open.threadId === threadId);
|
|
5244
|
+
const agent = this.findAgentForThread(threadId);
|
|
5245
|
+
this.collector?.ɵemit("thread.linked", {
|
|
5246
|
+
threadId,
|
|
5247
|
+
agentId: owner?.agentId ?? agent?.agentId ?? null,
|
|
5248
|
+
hasMessages: (agent?.messages.length ?? 0) > 0,
|
|
5249
|
+
reason
|
|
5250
|
+
});
|
|
5251
|
+
}
|
|
5252
|
+
findAgentForThread(threadId) {
|
|
5253
|
+
return [...this.agents.keys()].find((agent) => agent.threadId === threadId);
|
|
5254
|
+
}
|
|
5255
|
+
track(agent) {
|
|
5256
|
+
const agentId = agent.agentId;
|
|
5257
|
+
if (!this.isLegacyCaptureActive || this.agents.has(agent) || agentId === void 0) return;
|
|
5258
|
+
this.agents.set(agent, agent.subscribe(this.agentSubscriber(agent, agentId)));
|
|
5259
|
+
}
|
|
5260
|
+
agentSubscriber(agent, agentId) {
|
|
5261
|
+
const runIdFor = () => this.lastRunIds.get(agent);
|
|
5262
|
+
return {
|
|
5263
|
+
onRunStartedEvent: ({ event }) => {
|
|
5264
|
+
this.lastRunIds.set(agent, event.runId);
|
|
5265
|
+
this.emitRun("started", agent, event.threadId, event.runId);
|
|
5266
|
+
},
|
|
5267
|
+
onRunFinishedEvent: ({ event }) => {
|
|
5268
|
+
this.emitRun("finished", agent, event.threadId, event.runId);
|
|
5269
|
+
},
|
|
5270
|
+
onRunErrorEvent: () => {
|
|
5271
|
+
this.emitRun("error", agent, agent.threadId, runIdFor() ?? null);
|
|
5272
|
+
},
|
|
5273
|
+
onToolCallStartEvent: ({ event }) => {
|
|
5274
|
+
if (!this.isLegacyCaptureActive) return;
|
|
5275
|
+
const origin = {
|
|
5276
|
+
agentId,
|
|
5277
|
+
threadId: agent.threadId,
|
|
5278
|
+
messageId: event.parentMessageId,
|
|
5279
|
+
runId: runIdFor()
|
|
5280
|
+
};
|
|
5281
|
+
this.toolCalls.set(event.toolCallId, origin);
|
|
5282
|
+
this.emitToolCall("started", event.toolCallId, origin.agentId, event.toolCallName, {});
|
|
5283
|
+
},
|
|
5284
|
+
onToolCallResultEvent: ({ event }) => {
|
|
5285
|
+
if (!this.executingTools.has(event.toolCallId)) this.toolCalls.delete(event.toolCallId);
|
|
5286
|
+
},
|
|
5287
|
+
onNewMessage: ({ message }) => this.emitMessage(agent, message)
|
|
5288
|
+
};
|
|
5289
|
+
}
|
|
5290
|
+
emitRun(phase, agent, threadId, runId) {
|
|
5291
|
+
this.collector?.ɵemit("agent.run", {
|
|
5292
|
+
phase,
|
|
5293
|
+
runId,
|
|
5294
|
+
threadId,
|
|
5295
|
+
agentId: agent.agentId
|
|
5296
|
+
});
|
|
5297
|
+
}
|
|
5298
|
+
emitMessage(agent, message) {
|
|
5299
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
5300
|
+
const includeText = this.activeConfig?.capture?.agentText !== false && typeof message.content === "string";
|
|
5301
|
+
this.collector?.ɵemit("agent.message", {
|
|
5302
|
+
messageId: message.id,
|
|
5303
|
+
runId: this.runIdForMessage(agent, message.id),
|
|
5304
|
+
threadId: agent.threadId,
|
|
5305
|
+
agentId: agent.agentId,
|
|
5306
|
+
role: message.role,
|
|
5307
|
+
textLength: content.length,
|
|
5308
|
+
...includeText ? { text: content } : {}
|
|
5309
|
+
});
|
|
5310
|
+
}
|
|
5311
|
+
emitToolCall(phase, toolCallId, agentId, toolName, extra) {
|
|
5312
|
+
const origin = this.toolCalls.get(toolCallId);
|
|
5313
|
+
this.collector?.ɵemit("tool.call", {
|
|
5314
|
+
phase,
|
|
5315
|
+
toolCallId,
|
|
5316
|
+
toolName,
|
|
5317
|
+
agentId,
|
|
5318
|
+
threadId: origin?.threadId ?? null,
|
|
5319
|
+
messageId: origin?.messageId,
|
|
5320
|
+
runId: origin?.runId,
|
|
5321
|
+
...extra
|
|
5322
|
+
});
|
|
5323
|
+
}
|
|
5324
|
+
runIdForMessage(agent, messageId) {
|
|
5325
|
+
const agentId = agent.agentId;
|
|
5326
|
+
if (agentId === void 0) return null;
|
|
5327
|
+
return this.core.getRunIdForMessage(agentId, agent.threadId, messageId) ?? this.lastRunIds.get(agent) ?? null;
|
|
5328
|
+
}
|
|
5329
|
+
findMessage(messageId) {
|
|
5330
|
+
for (const agent of this.agents.keys()) {
|
|
5331
|
+
const message = agent.messages.find((candidate) => candidate.id === messageId);
|
|
5332
|
+
if (message !== void 0) return {
|
|
5333
|
+
agent,
|
|
5334
|
+
message
|
|
5335
|
+
};
|
|
5336
|
+
}
|
|
5337
|
+
return null;
|
|
5338
|
+
}
|
|
5339
|
+
toolStatus(agent, toolCallId) {
|
|
5340
|
+
if (this.executingTools.has(toolCallId)) return "executing";
|
|
5341
|
+
return agent.messages.some((message) => message.role === "tool" && message.toolCallId === toolCallId) ? "complete" : "inProgress";
|
|
5342
|
+
}
|
|
5343
|
+
/** Adds agent context to a click: exact message first, then the single open Thread. */
|
|
5344
|
+
enrich(target) {
|
|
5345
|
+
const messageId = target.closest("[data-message-id]")?.getAttribute("data-message-id") ?? null;
|
|
5346
|
+
const toolCallId = target.closest("[data-tool-call-id]")?.getAttribute("data-tool-call-id") ?? null;
|
|
5347
|
+
const found = messageId === null ? null : this.findMessage(messageId);
|
|
5348
|
+
if (found !== null) {
|
|
5349
|
+
const { agent, message } = found;
|
|
5350
|
+
const toolCall = toolCallId !== null && message.role === "assistant" ? message.toolCalls?.find((call) => call.id === toolCallId) : void 0;
|
|
5351
|
+
return {
|
|
5352
|
+
threadId: agent.threadId,
|
|
5353
|
+
agentId: agent.agentId,
|
|
5354
|
+
messageId: message.id,
|
|
5355
|
+
runId: this.runIdForMessage(agent, message.id),
|
|
5356
|
+
...toolCall === void 0 ? {} : {
|
|
5357
|
+
toolCallId: toolCall.id,
|
|
5358
|
+
toolName: toolCall.function.name,
|
|
5359
|
+
toolStatus: this.toolStatus(agent, toolCall.id)
|
|
5360
|
+
}
|
|
5361
|
+
};
|
|
5362
|
+
}
|
|
5363
|
+
return this.openThreadContext();
|
|
5364
|
+
}
|
|
5365
|
+
/** The single open Thread, or `null` with the candidates when several are open. */
|
|
5366
|
+
openThreadContext() {
|
|
5367
|
+
const openIds = this.distinctOpenThreadIds();
|
|
5368
|
+
if (openIds.length > 1) return {
|
|
5369
|
+
threadId: null,
|
|
5370
|
+
threadAmbiguity: {
|
|
5371
|
+
reason: "multiple-open",
|
|
5372
|
+
candidates: openIds
|
|
5373
|
+
}
|
|
5374
|
+
};
|
|
5375
|
+
return { threadId: openIds[0] ?? null };
|
|
5376
|
+
}
|
|
5377
|
+
};
|
|
5378
|
+
|
|
4514
5379
|
//#endregion
|
|
4515
5380
|
//#region src/utils/micro-redux.ts
|
|
4516
5381
|
const INTERNAL_ACTION_TYPES = {
|
|
@@ -5663,6 +6528,9 @@ var CopilotKitCore = class {
|
|
|
5663
6528
|
runHandler;
|
|
5664
6529
|
stateManager;
|
|
5665
6530
|
threadStoreRegistry;
|
|
6531
|
+
learningBridge;
|
|
6532
|
+
notifiedTrajectoryId = null;
|
|
6533
|
+
learningConfiguredListeners = /* @__PURE__ */ new Set();
|
|
5666
6534
|
/**
|
|
5667
6535
|
* The single core-owned memory store, created lazily on first
|
|
5668
6536
|
* `getMemoryStore()` and kept user-scoped for the lifetime of the core.
|
|
@@ -5677,7 +6545,7 @@ var CopilotKitCore = class {
|
|
|
5677
6545
|
* store that was registered prior to that initial notification.
|
|
5678
6546
|
*/
|
|
5679
6547
|
previousAgentIds = /* @__PURE__ */ new Set();
|
|
5680
|
-
constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
|
|
6548
|
+
constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug, learning }) {
|
|
5681
6549
|
this._headers = normalizeHeaders(headers);
|
|
5682
6550
|
this._credentials = credentials;
|
|
5683
6551
|
this._messageFilter = messageFilter;
|
|
@@ -5693,6 +6561,7 @@ var CopilotKitCore = class {
|
|
|
5693
6561
|
this.runHandler.initialize(tools);
|
|
5694
6562
|
this.suggestionEngine.initialize(suggestionsConfig);
|
|
5695
6563
|
this.stateManager.initialize();
|
|
6564
|
+
this.learningBridge = new LearningBridge(this, learning, () => this.notifyTrajectoryChanged());
|
|
5696
6565
|
this.agentRegistry.setRuntimeTransport(runtimeTransport);
|
|
5697
6566
|
this.agentRegistry.setRuntimeUrl(runtimeUrl, { deferConnection: deferInitialConnection });
|
|
5698
6567
|
this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
|
|
@@ -5844,6 +6713,10 @@ var CopilotKitCore = class {
|
|
|
5844
6713
|
get runtimeConnectionStatus() {
|
|
5845
6714
|
return this.agentRegistry.runtimeConnectionStatus;
|
|
5846
6715
|
}
|
|
6716
|
+
/** @internal The verbatim single-endpoint URL, including any trailing slash. */
|
|
6717
|
+
get ɵruntimeEndpointUrl() {
|
|
6718
|
+
return this.agentRegistry.runtimeEndpointUrl;
|
|
6719
|
+
}
|
|
5847
6720
|
get ɵruntimeFetch() {
|
|
5848
6721
|
return this.agentRegistry.createRuntimeFetch();
|
|
5849
6722
|
}
|
|
@@ -6003,6 +6876,83 @@ var CopilotKitCore = class {
|
|
|
6003
6876
|
getAgent(id) {
|
|
6004
6877
|
return this.agentRegistry.getAgent(id);
|
|
6005
6878
|
}
|
|
6879
|
+
/** Updates settings for the next capture. Removing the config stops capture. */
|
|
6880
|
+
setLearningConfig(config) {
|
|
6881
|
+
const wasConfigured = this.ɵlearningConfigured;
|
|
6882
|
+
this.learningBridge.setConfig(config);
|
|
6883
|
+
this.notifyTrajectoryChanged();
|
|
6884
|
+
if (this.ɵlearningConfigured === wasConfigured) return;
|
|
6885
|
+
for (const listener of this.learningConfiguredListeners) try {
|
|
6886
|
+
listener();
|
|
6887
|
+
} catch (error) {
|
|
6888
|
+
console.error("Learning configured listener error:", error);
|
|
6889
|
+
}
|
|
6890
|
+
}
|
|
6891
|
+
/**
|
|
6892
|
+
* @internal Whether a `learning` config is set. Unlike {@link trajectoryId},
|
|
6893
|
+
* it does not change with capture start, connection failures or reconnects.
|
|
6894
|
+
*/
|
|
6895
|
+
get ɵlearningConfigured() {
|
|
6896
|
+
return this.learningBridge.isConfigured;
|
|
6897
|
+
}
|
|
6898
|
+
/** @internal Calls `listener` when {@link ɵlearningConfigured} changes. */
|
|
6899
|
+
ɵsubscribeToLearningConfigured(listener) {
|
|
6900
|
+
this.learningConfiguredListeners.add(listener);
|
|
6901
|
+
return () => {
|
|
6902
|
+
this.learningConfiguredListeners.delete(listener);
|
|
6903
|
+
};
|
|
6904
|
+
}
|
|
6905
|
+
/** The active capture's Trajectory ID, or null while capture is stopped. */
|
|
6906
|
+
get trajectoryId() {
|
|
6907
|
+
return this.learningBridge.trajectoryId;
|
|
6908
|
+
}
|
|
6909
|
+
notifyTrajectoryChanged() {
|
|
6910
|
+
const trajectoryId = this.trajectoryId;
|
|
6911
|
+
if (trajectoryId === this.notifiedTrajectoryId) return;
|
|
6912
|
+
this.notifiedTrajectoryId = trajectoryId;
|
|
6913
|
+
this.notifySubscribers((subscriber) => subscriber.onTrajectoryChanged?.({
|
|
6914
|
+
copilotkit: this,
|
|
6915
|
+
trajectoryId
|
|
6916
|
+
}), "Subscriber onTrajectoryChanged error:");
|
|
6917
|
+
}
|
|
6918
|
+
/**
|
|
6919
|
+
* Starts one Trajectory after Runtime authorization and the Gateway join.
|
|
6920
|
+
* Omit the ID to create one. Repeated starts await the active connection;
|
|
6921
|
+
* a different ID stops the previous capture. Explicit sinks retain the
|
|
6922
|
+
* prototype's synchronous capture and require a stop before changing IDs.
|
|
6923
|
+
*
|
|
6924
|
+
* @example copilotkit.startTrajectory({ trajectoryId: crypto.randomUUID() })
|
|
6925
|
+
*/
|
|
6926
|
+
startTrajectory(options = {}) {
|
|
6927
|
+
const result = this.learningBridge.start(options);
|
|
6928
|
+
this.notifyTrajectoryChanged();
|
|
6929
|
+
return result;
|
|
6930
|
+
}
|
|
6931
|
+
/** Cancels pending work and stops capture, attempting one final batch without waiting for its ACK. */
|
|
6932
|
+
stopTrajectory() {
|
|
6933
|
+
this.learningBridge.stop();
|
|
6934
|
+
this.notifyTrajectoryChanged();
|
|
6935
|
+
}
|
|
6936
|
+
/**
|
|
6937
|
+
* Records an outcome that clicks cannot show, such as a saved report or an
|
|
6938
|
+
* approved deal. The wire adds `value.seq`; arrays, primitives, and objects
|
|
6939
|
+
* already containing `seq` are preserved under `value.data`. Explicit legacy
|
|
6940
|
+
* sinks retain object-only events with open-Thread enrichment.
|
|
6941
|
+
* No-op while no Trajectory runs. Events emitted during connection recovery
|
|
6942
|
+
* count as dropped. Built-in names such as `click` are rejected.
|
|
6943
|
+
*
|
|
6944
|
+
* @example copilotkit.emitTrajectoryEvent("deal.approved", { dealId: "deal-1" })
|
|
6945
|
+
*/
|
|
6946
|
+
emitTrajectoryEvent(name, value = {}) {
|
|
6947
|
+
this.learningBridge.emit(name, value);
|
|
6948
|
+
}
|
|
6949
|
+
/**
|
|
6950
|
+
* Tells Core that a view shows this Thread, so captured interactions can link to it.
|
|
6951
|
+
* Framework bindings call this; call it yourself only without a CopilotKit provider.
|
|
6952
|
+
*/
|
|
6953
|
+
registerOpenThread(params) {
|
|
6954
|
+
return this.learningBridge.registerOpenThread(params);
|
|
6955
|
+
}
|
|
6006
6956
|
/**
|
|
6007
6957
|
* Re-apply the current headers to a single agent (delegated to
|
|
6008
6958
|
* AgentRegistry). Core headers are merged on top of the agent's own
|