@copilotkit/core 1.75.2 → 1.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1085 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +110 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1088 -62
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1126 -66
- package/dist/index.umd.js.map +1 -1
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
import { Throttler } from "@tanstack/pacer";
|
|
2
|
-
import { AGUIConnectNotImplementedError, AbstractAgent, EventType, HttpAgent, buildResumeArray, isInterruptExpired, randomUUID, runHttpRequest, structuredClone_, transformChunks, transformHttpEventStream } from "@ag-ui/client";
|
|
3
|
-
import { RUNTIME_MODE_INTELLIGENCE, RUNTIME_MODE_SSE, logger, parseInspectorMetadataV1, partialJSONParse, phoenixExponentialBackoff, randomUUID as randomUUID$1, resolveDebugConfig, schemaToJsonSchema } from "@copilotkit/shared";
|
|
2
|
+
import { AGUIConnectNotImplementedError, AbstractAgent, CompatibilityBoundary, EventType, HttpAgent, buildResumeArray, isInterruptExpired, randomUUID, runHttpRequest, structuredClone_, transformChunks, transformHttpEventStream } from "@ag-ui/client";
|
|
3
|
+
import { RUNTIME_MODE_INTELLIGENCE, RUNTIME_MODE_SSE, logger, parseInspectorMetadataV1, partialJSONParse, phoenixExponentialBackoff, randomUUID as randomUUID$1, resolveDebugConfig, schemaToJsonSchema, stripIntelligenceRoutingFields } from "@copilotkit/shared";
|
|
4
4
|
import { BehaviorSubject, EMPTY, NEVER, Notification, Observable, Subject, Subscription, asapScheduler, combineLatest, concat, defer, dematerialize, firstValueFrom, from, lastValueFrom, merge, observeOn, of, switchMap, throwError } from "rxjs";
|
|
5
|
-
import { catchError, 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";
|
|
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
|
|
|
10
|
+
//#region src/utils/http-agent.ts
|
|
11
|
+
/**
|
|
12
|
+
* Whether an agent is an `HttpAgent`, including one built from another copy of
|
|
13
|
+
* `@ag-ui/client` (an app that pins its own 0.x version next to CopilotKit's
|
|
14
|
+
* 1.0, for example). `instanceof` is false across package copies, which made
|
|
15
|
+
* CopilotKit silently skip headers and abort wiring for those agents. The
|
|
16
|
+
* fallback checks the public fields CopilotKit uses, which every published
|
|
17
|
+
* `HttpAgent` has.
|
|
18
|
+
*/
|
|
19
|
+
function ɵisHttpAgent(agent) {
|
|
20
|
+
if (agent instanceof HttpAgent) return true;
|
|
21
|
+
if (typeof agent !== "object" || agent === null) return false;
|
|
22
|
+
const candidate = agent;
|
|
23
|
+
return typeof candidate.url === "string" && typeof candidate.headers === "object" && candidate.headers !== null && candidate.abortController instanceof AbortController && typeof candidate.runAgent === "function";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
9
27
|
//#region src/utils/connect-replay.ts
|
|
10
28
|
/**
|
|
11
29
|
* Runs an agent's `connect()` stream through the AbstractAgent apply pipeline
|
|
@@ -22,18 +40,27 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
22
40
|
* Cannot send event type 'RUN_STARTED': The run has already errored with
|
|
23
41
|
* 'RUN_ERROR'. No further events can be sent.
|
|
24
42
|
*
|
|
25
|
-
*
|
|
43
|
+
* The AG-UI 1.0 compatibility boundary still runs first, so stored 0.x history
|
|
44
|
+
* is translated (THINKING_* events, `binary` parts, legacy nulls) exactly as in
|
|
45
|
+
* the base pipeline. `enforceEvents` is omitted too: a replay is stored
|
|
46
|
+
* history, and one event that the 1.0 schema rejects (the Intelligence gateway
|
|
47
|
+
* replays RUN_STARTED without `runId`, for example) must not stop the whole
|
|
48
|
+
* thread from hydrating. That keeps the leniency this path had before 1.0.
|
|
26
49
|
*
|
|
27
50
|
* Connection-local replay hooks track the phase before applying events. An
|
|
28
51
|
* explicitly live RUN_ERROR clears busy without closing the connection;
|
|
29
52
|
* historical errors remain data. Connections without hooks retain the existing
|
|
30
|
-
* completion behavior.
|
|
53
|
+
* completion behavior.
|
|
54
|
+
*
|
|
55
|
+
* Apart from the above, this mirrors the base `AbstractAgent.connectAgent`
|
|
56
|
+
* implementation, so callers keep the same subscriber notifications, detach
|
|
57
|
+
* semantics, and `{ result, newMessages }` return shape.
|
|
31
58
|
*
|
|
32
59
|
* TODO: Remove this in favour of the base implementation once AG-UI's
|
|
33
60
|
* AbstractAgent supports opting out of `verifyEvents` for transports whose
|
|
34
61
|
* connection life-cycle isn't a single run AND preserves the connection-local
|
|
35
62
|
* replay lifecycle and running-state behavior below. Skipping verification alone
|
|
36
|
-
* is insufficient. As of `@ag-ui/client@
|
|
63
|
+
* is insufficient. As of `@ag-ui/client@1.0.1`
|
|
37
64
|
* `connectAgent(parameters?, subscriber?)` takes no such option.
|
|
38
65
|
*
|
|
39
66
|
* @param agent - The agent whose `connect()` stream should be consumed.
|
|
@@ -42,6 +69,9 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
42
69
|
*/
|
|
43
70
|
async function ɵconnectWithoutEventVerification(agent, parameters, subscriber, connect) {
|
|
44
71
|
const self = agent;
|
|
72
|
+
let finalizeRun = () => {
|
|
73
|
+
agent.isRunning = false;
|
|
74
|
+
};
|
|
45
75
|
try {
|
|
46
76
|
agent.isRunning = true;
|
|
47
77
|
agent.agentId = agent.agentId ?? randomUUID();
|
|
@@ -65,12 +95,35 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber,
|
|
|
65
95
|
...agent.subscribers,
|
|
66
96
|
subscriber ?? {}
|
|
67
97
|
];
|
|
68
|
-
|
|
69
|
-
self.activeRunDetach$ =
|
|
98
|
+
const activeRunDetach$ = new Subject();
|
|
99
|
+
self.activeRunDetach$ = activeRunDetach$;
|
|
70
100
|
let resolveCompletion;
|
|
71
101
|
self.activeRunCompletionPromise = new Promise((resolve) => {
|
|
72
102
|
resolveCompletion = resolve;
|
|
73
103
|
});
|
|
104
|
+
let detached = false;
|
|
105
|
+
let finalized = false;
|
|
106
|
+
const detachSubscription = activeRunDetach$.subscribe(() => {
|
|
107
|
+
detached = true;
|
|
108
|
+
});
|
|
109
|
+
finalizeRun = () => {
|
|
110
|
+
if (finalized) return;
|
|
111
|
+
finalized = true;
|
|
112
|
+
detachSubscription.unsubscribe();
|
|
113
|
+
if (self.activeRunDetach$ === activeRunDetach$) {
|
|
114
|
+
agent.isRunning = false;
|
|
115
|
+
self.activeRunCompletionPromise = void 0;
|
|
116
|
+
self.activeRunDetach$ = void 0;
|
|
117
|
+
self.onFinalize(input, subscribers);
|
|
118
|
+
}
|
|
119
|
+
resolveCompletion?.();
|
|
120
|
+
resolveCompletion = void 0;
|
|
121
|
+
};
|
|
122
|
+
await self.onInitialize(input, subscribers);
|
|
123
|
+
if (detached) return {
|
|
124
|
+
result: void 0,
|
|
125
|
+
newMessages: []
|
|
126
|
+
};
|
|
74
127
|
const lifecycle = {
|
|
75
128
|
onReplayStarted: () => {
|
|
76
129
|
isReplaying = true;
|
|
@@ -80,29 +133,23 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber,
|
|
|
80
133
|
isReplaying = false;
|
|
81
134
|
}
|
|
82
135
|
};
|
|
83
|
-
const source$ = defer(() => connect ? connect(input, lifecycle) : self.connect(input)).pipe(tap((event) => {
|
|
136
|
+
const source$ = defer(() => new CompatibilityBoundary().run(input, { run: () => connect ? connect(input, lifecycle) : self.connect(input) })).pipe(tap((event) => {
|
|
84
137
|
if (!isReplaying && event.type === EventType.RUN_ERROR) liveErrors.add(event);
|
|
85
|
-
}), transformChunks(self.debugLogger), takeUntil(
|
|
138
|
+
}), transformChunks(self.debugLogger), takeUntil(activeRunDetach$));
|
|
86
139
|
const applied$ = self.apply(input, source$, subscribers);
|
|
87
140
|
await lastValueFrom(self.processApplyEvents(input, applied$, subscribers).pipe(catchError((error) => {
|
|
141
|
+
if (self.activeRunDetach$ !== activeRunDetach$) return EMPTY;
|
|
88
142
|
agent.isRunning = false;
|
|
89
143
|
if (error instanceof AGUIConnectNotImplementedError) return EMPTY;
|
|
90
144
|
return self.onError(input, error, subscribers);
|
|
91
|
-
}), finalize(() => {
|
|
92
|
-
agent.isRunning = false;
|
|
93
|
-
self.onFinalize(input, subscribers);
|
|
94
|
-
resolveCompletion?.();
|
|
95
|
-
resolveCompletion = void 0;
|
|
96
|
-
self.activeRunCompletionPromise = void 0;
|
|
97
|
-
self.activeRunDetach$ = void 0;
|
|
98
|
-
})), { defaultValue: void 0 });
|
|
145
|
+
}), finalize(() => finalizeRun())), { defaultValue: void 0 });
|
|
99
146
|
const newMessages = structuredClone_(agent.messages).filter((m) => !previousMessageIds.has(m.id));
|
|
100
147
|
return {
|
|
101
148
|
result,
|
|
102
149
|
newMessages
|
|
103
150
|
};
|
|
104
151
|
} finally {
|
|
105
|
-
|
|
152
|
+
finalizeRun();
|
|
106
153
|
}
|
|
107
154
|
}
|
|
108
155
|
|
|
@@ -585,7 +632,7 @@ var IntelligenceAgent = class IntelligenceAgent extends AbstractAgent {
|
|
|
585
632
|
observeThreadEvents$(threadId, channel$, options) {
|
|
586
633
|
return channel$.pipe(switchMap$1(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), tap((payload) => {
|
|
587
634
|
this.updateLastSeenEventId(threadId, payload);
|
|
588
|
-
}), mergeMap((payload) => this.createThreadNotifications(payload, {
|
|
635
|
+
}), map((payload) => options.streamMode === "run" ? stripIntelligenceRoutingFields(payload) : payload), mergeMap((payload) => this.createThreadNotifications(payload, {
|
|
589
636
|
completeOnRunError: options.completeOnRunError,
|
|
590
637
|
completeOnRunFinished: options.streamMode === "run",
|
|
591
638
|
errorOnRunError: options.streamMode === "run"
|
|
@@ -839,6 +886,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
839
886
|
_capabilities;
|
|
840
887
|
delegate;
|
|
841
888
|
runtimeInfoPromise;
|
|
889
|
+
connectionAttempt;
|
|
842
890
|
_messageFilter;
|
|
843
891
|
/**
|
|
844
892
|
* The HTTP `run` this agent started and has not yet seen finish, as the
|
|
@@ -901,13 +949,12 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
901
949
|
this.runtimeMode = runtimeMode;
|
|
902
950
|
this.intelligence = intelligence;
|
|
903
951
|
if (unchanged) return;
|
|
952
|
+
this.connectionAttempt = void 0;
|
|
904
953
|
this.runtimeInfoPromise = void 0;
|
|
905
954
|
const staleDelegate = this.delegate;
|
|
906
955
|
this.delegate = void 0;
|
|
907
|
-
if (staleDelegate)
|
|
908
|
-
|
|
909
|
-
this.detachActiveRun();
|
|
910
|
-
}
|
|
956
|
+
if (staleDelegate) staleDelegate.abortRun();
|
|
957
|
+
this.detachActiveRun();
|
|
911
958
|
}
|
|
912
959
|
/**
|
|
913
960
|
* The agent id used for outbound runtime requests — `runtimeAgentId` when
|
|
@@ -998,8 +1045,11 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
998
1045
|
return this._capabilities ?? {};
|
|
999
1046
|
}
|
|
1000
1047
|
async detachActiveRun() {
|
|
1001
|
-
|
|
1002
|
-
|
|
1048
|
+
this.connectionAttempt = void 0;
|
|
1049
|
+
this.isRunning = false;
|
|
1050
|
+
const delegateDetach = this.delegate?.detachActiveRun();
|
|
1051
|
+
const proxyDetach = super.detachActiveRun();
|
|
1052
|
+
await Promise.all([delegateDetach, proxyDetach]);
|
|
1003
1053
|
}
|
|
1004
1054
|
abortRun() {
|
|
1005
1055
|
if (this.delegate) {
|
|
@@ -1053,41 +1103,74 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
1053
1103
|
});
|
|
1054
1104
|
}
|
|
1055
1105
|
async connectAgent(parameters, subscriber) {
|
|
1106
|
+
const detached = this.detachActiveRun();
|
|
1107
|
+
const connection = {};
|
|
1108
|
+
const threadId = this.threadId;
|
|
1109
|
+
this.connectionAttempt = connection;
|
|
1110
|
+
const isCurrentConnection = () => this.connectionAttempt === connection && this.threadId === threadId;
|
|
1111
|
+
await detached;
|
|
1112
|
+
if (!isCurrentConnection()) return {
|
|
1113
|
+
result: void 0,
|
|
1114
|
+
newMessages: []
|
|
1115
|
+
};
|
|
1116
|
+
await this.ensureRuntimeConfiguration();
|
|
1117
|
+
if (!isCurrentConnection()) return {
|
|
1118
|
+
result: void 0,
|
|
1119
|
+
newMessages: []
|
|
1120
|
+
};
|
|
1056
1121
|
if (this.runtimeMode !== RUNTIME_MODE_INTELLIGENCE) return ɵconnectWithoutEventVerification(this, parameters, subscriber, (input, lifecycle) => this.connect(input, lifecycle));
|
|
1057
|
-
if (this.delegate) await this.delegate.detachActiveRun();
|
|
1058
1122
|
await this.resolveDelegate();
|
|
1123
|
+
if (!isCurrentConnection()) return {
|
|
1124
|
+
result: void 0,
|
|
1125
|
+
newMessages: []
|
|
1126
|
+
};
|
|
1059
1127
|
const delegate = this.delegate;
|
|
1060
1128
|
const bridgeSub = delegate.subscribe({
|
|
1061
1129
|
onMessagesChanged: () => {
|
|
1130
|
+
if (!isCurrentConnection()) return;
|
|
1062
1131
|
this.setMessages([...delegate.messages]);
|
|
1063
1132
|
},
|
|
1064
1133
|
onStateChanged: () => {
|
|
1134
|
+
if (!isCurrentConnection()) return;
|
|
1065
1135
|
this.setState({ ...delegate.state });
|
|
1066
1136
|
},
|
|
1067
1137
|
onRunInitialized: () => {
|
|
1138
|
+
if (!isCurrentConnection()) return;
|
|
1068
1139
|
this.isRunning = true;
|
|
1069
1140
|
},
|
|
1070
1141
|
onRunFinalized: () => {
|
|
1142
|
+
if (!isCurrentConnection()) return;
|
|
1143
|
+
this.pendingInterrupts = structuredClone_(delegate.pendingInterrupts);
|
|
1071
1144
|
this.isRunning = false;
|
|
1072
1145
|
},
|
|
1073
1146
|
onRunFailed: () => {
|
|
1147
|
+
if (!isCurrentConnection()) return;
|
|
1074
1148
|
this.isRunning = false;
|
|
1075
1149
|
},
|
|
1076
1150
|
onRunErrorEvent: () => {
|
|
1151
|
+
if (!isCurrentConnection()) return;
|
|
1077
1152
|
this.isRunning = delegate.isRunning;
|
|
1078
1153
|
},
|
|
1079
1154
|
onRunStartedEvent: () => {
|
|
1155
|
+
if (!isCurrentConnection()) return;
|
|
1080
1156
|
this.isRunning = delegate.isRunning;
|
|
1081
1157
|
}
|
|
1082
1158
|
});
|
|
1083
|
-
const forwardedSubs = this.subscribers.map((
|
|
1159
|
+
const forwardedSubs = [...this.subscribers, ...subscriber ? [subscriber] : []].map((subscriber) => delegate.subscribe(new Proxy(subscriber, { get(target, property, receiver) {
|
|
1160
|
+
const callback = Reflect.get(target, property, receiver);
|
|
1161
|
+
if (typeof callback !== "function") return callback;
|
|
1162
|
+
return (...args) => isCurrentConnection() ? Reflect.apply(callback, target, args) : void 0;
|
|
1163
|
+
} })));
|
|
1084
1164
|
try {
|
|
1085
|
-
const result = await delegate.connectAgent(parameters
|
|
1086
|
-
|
|
1087
|
-
|
|
1165
|
+
const result = await delegate.connectAgent(parameters);
|
|
1166
|
+
if (isCurrentConnection()) {
|
|
1167
|
+
this.setMessages([...delegate.messages]);
|
|
1168
|
+
this.setState({ ...delegate.state });
|
|
1169
|
+
this.pendingInterrupts = structuredClone_(delegate.pendingInterrupts);
|
|
1170
|
+
}
|
|
1088
1171
|
return result;
|
|
1089
1172
|
} finally {
|
|
1090
|
-
this.isRunning = false;
|
|
1173
|
+
if (isCurrentConnection()) this.isRunning = false;
|
|
1091
1174
|
bridgeSub.unsubscribe();
|
|
1092
1175
|
for (const sub of forwardedSubs) sub.unsubscribe();
|
|
1093
1176
|
}
|
|
@@ -1109,14 +1192,31 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
1109
1192
|
const input = this.#applyMessageFilter(unfiltered);
|
|
1110
1193
|
this.activeRun = void 0;
|
|
1111
1194
|
const routedId = this.routedAgentId();
|
|
1195
|
+
let httpEvents;
|
|
1112
1196
|
if (this.transport === "single") {
|
|
1113
1197
|
if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
|
|
1114
1198
|
const requestInit = this.createSingleRouteRequestInit(input, "agent/connect", { agentId: routedId });
|
|
1115
|
-
|
|
1199
|
+
httpEvents = runHttpRequest(() => this.fetch(this.singleEndpointUrl, requestInit));
|
|
1200
|
+
} else {
|
|
1201
|
+
const connectUrl = `${this.runtimeUrl}/agent/${routedId}/connect`;
|
|
1202
|
+
const connectRequestInit = this.requestInit(input);
|
|
1203
|
+
httpEvents = runHttpRequest(() => this.fetch(connectUrl, connectRequestInit));
|
|
1116
1204
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1205
|
+
return withAbortErrorHandling(defer(() => {
|
|
1206
|
+
let replayStarted = false;
|
|
1207
|
+
const emptyHistory = [{
|
|
1208
|
+
type: EventType.MESSAGES_SNAPSHOT,
|
|
1209
|
+
messages: []
|
|
1210
|
+
}, {
|
|
1211
|
+
type: EventType.STATE_SNAPSHOT,
|
|
1212
|
+
snapshot: {}
|
|
1213
|
+
}];
|
|
1214
|
+
return transformHttpEventStream(httpEvents).pipe(concatMap((event) => {
|
|
1215
|
+
if (replayStarted) return of(event);
|
|
1216
|
+
replayStarted = true;
|
|
1217
|
+
return from([...emptyHistory, event]);
|
|
1218
|
+
}), concatWith(defer(() => replayStarted ? EMPTY : from(emptyHistory))));
|
|
1219
|
+
}));
|
|
1120
1220
|
}
|
|
1121
1221
|
#runViaDelegate(input) {
|
|
1122
1222
|
return defer(() => from(this.resolveDelegate())).pipe(switchMap$1((delegate) => withAbortErrorHandling(delegate.run(input))));
|
|
@@ -1159,6 +1259,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
1159
1259
|
cloned.threadId = this.threadId;
|
|
1160
1260
|
cloned.setState(this.state);
|
|
1161
1261
|
cloned.setMessages(this.messages);
|
|
1262
|
+
cloned.pendingInterrupts = structuredClone_(this.pendingInterrupts);
|
|
1162
1263
|
if (this.delegate) {
|
|
1163
1264
|
const clonedDelegate = this.delegate.clone();
|
|
1164
1265
|
cloned.delegate = clonedDelegate;
|
|
@@ -1196,6 +1297,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
1196
1297
|
if (this.runtimeMode === RUNTIME_MODE_INTELLIGENCE || this.runtimeMode !== "pending" && this.transport !== "auto") return;
|
|
1197
1298
|
if (!this.runtimeUrl) throw new Error("Runtime URL is not set");
|
|
1198
1299
|
const runtimeInfoPromise = this.runtimeInfoPromise ?? this.fetchRuntimeInfo().then((runtimeInfo) => {
|
|
1300
|
+
if (this.runtimeInfoPromise !== runtimeInfoPromise) return;
|
|
1199
1301
|
this.runtimeMode = runtimeInfo.mode ?? RUNTIME_MODE_SSE;
|
|
1200
1302
|
this.intelligence = runtimeInfo.intelligence;
|
|
1201
1303
|
});
|
|
@@ -1300,6 +1402,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends HttpAg
|
|
|
1300
1402
|
delegate.debugLogger = this.debugLogger;
|
|
1301
1403
|
delegate.setMessages(this.messages);
|
|
1302
1404
|
delegate.setState(this.state);
|
|
1405
|
+
delegate.pendingInterrupts = structuredClone_(this.pendingInterrupts);
|
|
1303
1406
|
if (hasHeaders(delegate)) delegate.headers = { ...this.headers };
|
|
1304
1407
|
if (hasCredentials(delegate)) delegate.credentials = this.credentials;
|
|
1305
1408
|
}
|
|
@@ -1735,7 +1838,7 @@ var AgentRegistry = class {
|
|
|
1735
1838
|
* because only `HttpAgent` carries a `headers` field. See #5635.
|
|
1736
1839
|
*/
|
|
1737
1840
|
applyHeadersToAgent(agent) {
|
|
1738
|
-
if (agent
|
|
1841
|
+
if (ɵisHttpAgent(agent)) {
|
|
1739
1842
|
if (!this.agentOwnHeaders.has(agent)) this.agentOwnHeaders.set(agent, { ...agent.headers });
|
|
1740
1843
|
agent.headers = {
|
|
1741
1844
|
...this.agentOwnHeaders.get(agent),
|
|
@@ -1804,6 +1907,10 @@ var AgentRegistry = class {
|
|
|
1804
1907
|
this.applyMessageFilterToAgent(agent);
|
|
1805
1908
|
});
|
|
1806
1909
|
}
|
|
1910
|
+
/** Preserve the exact configured URL when posting to a single endpoint. */
|
|
1911
|
+
get runtimeEndpointUrl() {
|
|
1912
|
+
return this._runtimeEndpointUrl;
|
|
1913
|
+
}
|
|
1807
1914
|
createRuntimeFetch() {
|
|
1808
1915
|
if (!this.runtimeFetch) this.runtimeFetch = (async (input, init) => {
|
|
1809
1916
|
const meta = () => runtimeRequestMeta(init);
|
|
@@ -2828,6 +2935,68 @@ function normalizeToolResultContent(content) {
|
|
|
2828
2935
|
function isForwardedToClientPlaceholder(content) {
|
|
2829
2936
|
return normalizeToolResultContent(content) === FORWARDED_TO_CLIENT;
|
|
2830
2937
|
}
|
|
2938
|
+
const MEDIA_PART_TYPES = new Set([
|
|
2939
|
+
"image",
|
|
2940
|
+
"audio",
|
|
2941
|
+
"video",
|
|
2942
|
+
"document"
|
|
2943
|
+
]);
|
|
2944
|
+
function isOptionalString(value) {
|
|
2945
|
+
return value === void 0 || typeof value === "string";
|
|
2946
|
+
}
|
|
2947
|
+
function isPartSource(value) {
|
|
2948
|
+
if (!value || typeof value !== "object") return false;
|
|
2949
|
+
const source = value;
|
|
2950
|
+
if (typeof source.value !== "string") return false;
|
|
2951
|
+
switch (source.type) {
|
|
2952
|
+
case "data": return typeof source.mimeType === "string";
|
|
2953
|
+
case "url": return isOptionalString(source.mimeType);
|
|
2954
|
+
case "file": return isOptionalString(source.provider) && isOptionalString(source.mimeType);
|
|
2955
|
+
default: return false;
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
/**
|
|
2959
|
+
* Mirrors `ContentPartSchema` from `@ag-ui/core/schemas`. The runtime parses
|
|
2960
|
+
* the request with that schema, and one invalid part there fails the whole run.
|
|
2961
|
+
* Core does not import the schema because the UMD build has no global for it.
|
|
2962
|
+
* A test checks this function against the schema.
|
|
2963
|
+
*/
|
|
2964
|
+
function isContentPart(value) {
|
|
2965
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2966
|
+
const part = value;
|
|
2967
|
+
if (!isOptionalString(part.id) || part.metadata === null) return false;
|
|
2968
|
+
if (part.type === "text") return typeof part.text === "string";
|
|
2969
|
+
return typeof part.type === "string" && MEDIA_PART_TYPES.has(part.type) && isPartSource(part.source);
|
|
2970
|
+
}
|
|
2971
|
+
/**
|
|
2972
|
+
* Converts what a frontend tool handler returned into tool message content.
|
|
2973
|
+
* A non-empty array of AG-UI content parts passes through unchanged, so an
|
|
2974
|
+
* image reaches the model as media. Everything else becomes a string, as before.
|
|
2975
|
+
*
|
|
2976
|
+
* `text` is the string form, for surfaces typed as `result: string`
|
|
2977
|
+
* (`runTool`, `onToolExecutionEnd`). For content parts it is the JSON text they
|
|
2978
|
+
* received before. It is computed here, so a part that cannot be serialized
|
|
2979
|
+
* throws inside the caller's handler error boundary.
|
|
2980
|
+
*/
|
|
2981
|
+
function toToolResultContent(result) {
|
|
2982
|
+
if (result === void 0 || result === null) return {
|
|
2983
|
+
content: "",
|
|
2984
|
+
text: ""
|
|
2985
|
+
};
|
|
2986
|
+
if (typeof result === "string") return {
|
|
2987
|
+
content: result,
|
|
2988
|
+
text: result
|
|
2989
|
+
};
|
|
2990
|
+
const text = JSON.stringify(result);
|
|
2991
|
+
if (Array.isArray(result) && result.length > 0 && result.every(isContentPart)) return {
|
|
2992
|
+
content: result,
|
|
2993
|
+
text
|
|
2994
|
+
};
|
|
2995
|
+
return {
|
|
2996
|
+
content: text,
|
|
2997
|
+
text
|
|
2998
|
+
};
|
|
2999
|
+
}
|
|
2831
3000
|
|
|
2832
3001
|
//#endregion
|
|
2833
3002
|
//#region src/core/tool-schema.ts
|
|
@@ -3086,6 +3255,7 @@ var RunHandler = class {
|
|
|
3086
3255
|
* inspector and intermittent "Message not found" toasts.
|
|
3087
3256
|
*/
|
|
3088
3257
|
_lastConnectedThreadIdsByAgent = /* @__PURE__ */ new Map();
|
|
3258
|
+
_lastActiveThreadIdsByAgent = /* @__PURE__ */ new Map();
|
|
3089
3259
|
_anonymousAgentIds = /* @__PURE__ */ new WeakMap();
|
|
3090
3260
|
_nextAnonymousAgentId = 0;
|
|
3091
3261
|
/** Prevent reconnects from starting an interaction already executing locally. */
|
|
@@ -3263,7 +3433,8 @@ var RunHandler = class {
|
|
|
3263
3433
|
* Connect an agent (establish initial connection)
|
|
3264
3434
|
*/
|
|
3265
3435
|
async connectAgent({ agent }) {
|
|
3266
|
-
|
|
3436
|
+
const connection = {};
|
|
3437
|
+
this._connectionGenerations.set(agent, connection);
|
|
3267
3438
|
const incomingThreadId = agent.threadId ?? null;
|
|
3268
3439
|
const previousReplay = this._interactionAbortControllers.get(agent);
|
|
3269
3440
|
if (previousReplay && previousReplay.threadId !== incomingThreadId) {
|
|
@@ -3273,12 +3444,19 @@ var RunHandler = class {
|
|
|
3273
3444
|
}
|
|
3274
3445
|
try {
|
|
3275
3446
|
const restoreKey = this.getConnectRestoreKey(agent);
|
|
3276
|
-
const
|
|
3277
|
-
this._lastConnectedThreadIdsByAgent.
|
|
3447
|
+
const previousThreadId = this._lastActiveThreadIdsByAgent.get(restoreKey);
|
|
3448
|
+
const isFreshRestore = incomingThreadId !== (previousThreadId ?? this._lastConnectedThreadIdsByAgent.get(restoreKey) ?? null);
|
|
3278
3449
|
await agent.detachActiveRun();
|
|
3450
|
+
if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return {
|
|
3451
|
+
result: void 0,
|
|
3452
|
+
newMessages: []
|
|
3453
|
+
};
|
|
3454
|
+
this._lastConnectedThreadIdsByAgent.set(restoreKey, incomingThreadId);
|
|
3455
|
+
this._lastActiveThreadIdsByAgent.set(restoreKey, incomingThreadId);
|
|
3279
3456
|
if (isFreshRestore) {
|
|
3280
3457
|
agent.setMessages([]);
|
|
3281
3458
|
agent.setState({});
|
|
3459
|
+
if (previousThreadId !== void 0 && previousThreadId !== incomingThreadId) agent.pendingInterrupts = [];
|
|
3282
3460
|
const cursorAware = agent;
|
|
3283
3461
|
if (incomingThreadId) {
|
|
3284
3462
|
if (typeof cursorAware.clearReplayCursor === "function") cursorAware.clearReplayCursor(incomingThreadId);
|
|
@@ -3290,12 +3468,16 @@ var RunHandler = class {
|
|
|
3290
3468
|
copilotkit: this.core,
|
|
3291
3469
|
agent
|
|
3292
3470
|
}), "Subscriber onAgentRunStarted error:");
|
|
3471
|
+
if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return {
|
|
3472
|
+
result: void 0,
|
|
3473
|
+
newMessages: []
|
|
3474
|
+
};
|
|
3293
3475
|
const runAgentResult = await agent.connectAgent({
|
|
3294
3476
|
forwardedProps: this._internal.properties,
|
|
3295
3477
|
tools: this.buildFrontendTools(agent.agentId),
|
|
3296
3478
|
context: this._internal.getContextForAgent(agent.agentId)
|
|
3297
3479
|
}, this.createAgentErrorSubscriber(agent));
|
|
3298
|
-
if ((agent.threadId ?? null) !== incomingThreadId) return runAgentResult;
|
|
3480
|
+
if (this._connectionGenerations.get(agent) !== connection || (agent.threadId ?? null) !== incomingThreadId) return runAgentResult;
|
|
3299
3481
|
const controller = new AbortController();
|
|
3300
3482
|
const replay = this._interactionAbortControllers.get(agent) ?? {
|
|
3301
3483
|
threadId: incomingThreadId,
|
|
@@ -3352,6 +3534,12 @@ var RunHandler = class {
|
|
|
3352
3534
|
continuationHandoff?.cancel();
|
|
3353
3535
|
throw error;
|
|
3354
3536
|
}
|
|
3537
|
+
const resumedRunId = this._internal.stateManager.getContinuationRunId(agent, {
|
|
3538
|
+
threadId: agent.threadId,
|
|
3539
|
+
resume,
|
|
3540
|
+
forwardedProps
|
|
3541
|
+
});
|
|
3542
|
+
const logicalHandoff = continuationHandoff ?? (resumedRunId ? this._internal.stateManager.markNextRunAsContinuation(agent, resumedRunId) : void 0);
|
|
3355
3543
|
const isTopLevel = this._runDepth === 0;
|
|
3356
3544
|
let originalAbortRun;
|
|
3357
3545
|
if (isTopLevel) {
|
|
@@ -3369,18 +3557,19 @@ var RunHandler = class {
|
|
|
3369
3557
|
}
|
|
3370
3558
|
this._runDepth++;
|
|
3371
3559
|
try {
|
|
3372
|
-
let logicalRunId = runId;
|
|
3560
|
+
let logicalRunId = resumedRunId ?? runId;
|
|
3373
3561
|
const agentSubscriber = this.createAgentErrorSubscriber(agent);
|
|
3374
3562
|
let started = false;
|
|
3375
3563
|
const onRunStartedEvent = agentSubscriber.onRunStartedEvent;
|
|
3376
3564
|
const onRunInitialized = agentSubscriber.onRunInitialized;
|
|
3377
3565
|
agentSubscriber.onRunInitialized = async (params) => {
|
|
3378
|
-
|
|
3566
|
+
this._lastActiveThreadIdsByAgent.set(this.getConnectRestoreKey(agent), params.input.threadId);
|
|
3567
|
+
logicalHandoff?.bind(params.input);
|
|
3379
3568
|
return onRunInitialized?.(params);
|
|
3380
3569
|
};
|
|
3381
3570
|
agentSubscriber.onRunStartedEvent = async (params) => {
|
|
3382
3571
|
started = true;
|
|
3383
|
-
if (!
|
|
3572
|
+
if (!logicalHandoff) logicalRunId = params.input.runId;
|
|
3384
3573
|
return onRunStartedEvent?.(params);
|
|
3385
3574
|
};
|
|
3386
3575
|
const pinRunIdOnWire = runId !== void 0 && !continuationHandoff;
|
|
@@ -3395,14 +3584,14 @@ var RunHandler = class {
|
|
|
3395
3584
|
context: this._internal.getContextForAgent(agent.agentId)
|
|
3396
3585
|
};
|
|
3397
3586
|
const runAgentResult = await agent.runAgent(agentRunInput, agentSubscriber);
|
|
3398
|
-
if (!started)
|
|
3587
|
+
if (!started) logicalHandoff?.cancel();
|
|
3399
3588
|
return await this.processAgentResult({
|
|
3400
3589
|
runAgentResult,
|
|
3401
3590
|
agent,
|
|
3402
3591
|
runId: logicalRunId
|
|
3403
3592
|
});
|
|
3404
3593
|
} catch (error) {
|
|
3405
|
-
|
|
3594
|
+
logicalHandoff?.cancel();
|
|
3406
3595
|
const runError = error instanceof Error ? error : new Error(String(error));
|
|
3407
3596
|
const context = {};
|
|
3408
3597
|
if (agent.agentId) context.agentId = agent.agentId;
|
|
@@ -3521,6 +3710,7 @@ var RunHandler = class {
|
|
|
3521
3710
|
*/
|
|
3522
3711
|
async executeToolHandler({ tool, toolCall, agent, agentId, handlerArgs, toolType, messageId, signal = this._runAbortController?.signal, discardOnAbort = false }) {
|
|
3523
3712
|
let toolCallResult = "";
|
|
3713
|
+
let toolCallText = "";
|
|
3524
3714
|
let errorMessage;
|
|
3525
3715
|
let isArgumentError = false;
|
|
3526
3716
|
let parsedArgs;
|
|
@@ -3556,9 +3746,7 @@ var RunHandler = class {
|
|
|
3556
3746
|
agent,
|
|
3557
3747
|
signal
|
|
3558
3748
|
});
|
|
3559
|
-
|
|
3560
|
-
else if (typeof result === "string") toolCallResult = result;
|
|
3561
|
-
else toolCallResult = JSON.stringify(result);
|
|
3749
|
+
({content: toolCallResult, text: toolCallText} = toToolResultContent(result));
|
|
3562
3750
|
} catch (error) {
|
|
3563
3751
|
const handlerError = error instanceof Error ? error : new Error(String(error));
|
|
3564
3752
|
errorMessage = handlerError.message;
|
|
@@ -3575,17 +3763,18 @@ var RunHandler = class {
|
|
|
3575
3763
|
}
|
|
3576
3764
|
});
|
|
3577
3765
|
}
|
|
3578
|
-
if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
|
|
3766
|
+
if (errorMessage) toolCallResult = toolCallText = `Error: ${errorMessage}`;
|
|
3579
3767
|
await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionEnd?.({
|
|
3580
3768
|
copilotkit: this.core,
|
|
3581
3769
|
toolCallId: toolCall.id,
|
|
3582
3770
|
agentId,
|
|
3583
3771
|
toolName: toolCall.function.name,
|
|
3584
|
-
result: errorMessage ? "" :
|
|
3772
|
+
result: errorMessage ? "" : toolCallText,
|
|
3585
3773
|
error: errorMessage
|
|
3586
3774
|
}), "Subscriber onToolExecutionEnd error:");
|
|
3587
3775
|
return {
|
|
3588
|
-
|
|
3776
|
+
content: toolCallResult,
|
|
3777
|
+
result: toolCallText,
|
|
3589
3778
|
error: errorMessage,
|
|
3590
3779
|
isArgumentError
|
|
3591
3780
|
};
|
|
@@ -3597,6 +3786,7 @@ var RunHandler = class {
|
|
|
3597
3786
|
const threadId = agent.threadId;
|
|
3598
3787
|
if (tool?.agentId && tool.agentId !== agent.agentId) return false;
|
|
3599
3788
|
let handlerResult = {
|
|
3789
|
+
content: "",
|
|
3600
3790
|
result: "",
|
|
3601
3791
|
error: void 0,
|
|
3602
3792
|
isArgumentError: false
|
|
@@ -3621,7 +3811,7 @@ var RunHandler = class {
|
|
|
3621
3811
|
id: randomUUID$1(),
|
|
3622
3812
|
role: "tool",
|
|
3623
3813
|
toolCallId: toolCall.id,
|
|
3624
|
-
content: handlerResult.
|
|
3814
|
+
content: handlerResult.content
|
|
3625
3815
|
};
|
|
3626
3816
|
agent.messages.splice(insertAt, 0, toolMessage);
|
|
3627
3817
|
if (!handlerResult.error && tool?.followUp !== false) return true;
|
|
@@ -3638,6 +3828,7 @@ var RunHandler = class {
|
|
|
3638
3828
|
const threadId = agent.threadId;
|
|
3639
3829
|
if (wildcardTool?.agentId && wildcardTool.agentId !== agent.agentId) return false;
|
|
3640
3830
|
let toolCallResult = "";
|
|
3831
|
+
let toolCallText = "";
|
|
3641
3832
|
let errorMessage;
|
|
3642
3833
|
if (wildcardTool?.handler) {
|
|
3643
3834
|
let parsedArgs;
|
|
@@ -3676,9 +3867,7 @@ var RunHandler = class {
|
|
|
3676
3867
|
agent,
|
|
3677
3868
|
signal
|
|
3678
3869
|
});
|
|
3679
|
-
|
|
3680
|
-
else if (typeof result === "string") toolCallResult = result;
|
|
3681
|
-
else toolCallResult = JSON.stringify(result);
|
|
3870
|
+
({content: toolCallResult, text: toolCallText} = toToolResultContent(result));
|
|
3682
3871
|
} catch (error) {
|
|
3683
3872
|
const handlerError = error instanceof Error ? error : new Error(String(error));
|
|
3684
3873
|
errorMessage = handlerError.message;
|
|
@@ -3695,13 +3884,13 @@ var RunHandler = class {
|
|
|
3695
3884
|
}
|
|
3696
3885
|
});
|
|
3697
3886
|
}
|
|
3698
|
-
if (errorMessage) toolCallResult = `Error: ${errorMessage}`;
|
|
3887
|
+
if (errorMessage) toolCallResult = toolCallText = `Error: ${errorMessage}`;
|
|
3699
3888
|
await this._internal.notifySubscribers((subscriber) => subscriber.onToolExecutionEnd?.({
|
|
3700
3889
|
copilotkit: this.core,
|
|
3701
3890
|
toolCallId: toolCall.id,
|
|
3702
3891
|
agentId,
|
|
3703
3892
|
toolName: toolCall.function.name,
|
|
3704
|
-
result: errorMessage ? "" :
|
|
3893
|
+
result: errorMessage ? "" : toolCallText,
|
|
3705
3894
|
error: errorMessage
|
|
3706
3895
|
}), "Subscriber onToolExecutionEnd error:");
|
|
3707
3896
|
}
|
|
@@ -3772,6 +3961,7 @@ var RunHandler = class {
|
|
|
3772
3961
|
};
|
|
3773
3962
|
agent.messages.push(assistantMessage);
|
|
3774
3963
|
let handlerResult = {
|
|
3964
|
+
content: "",
|
|
3775
3965
|
result: "",
|
|
3776
3966
|
error: void 0,
|
|
3777
3967
|
isArgumentError: false
|
|
@@ -3788,7 +3978,7 @@ var RunHandler = class {
|
|
|
3788
3978
|
id: randomUUID$1(),
|
|
3789
3979
|
role: "tool",
|
|
3790
3980
|
toolCallId,
|
|
3791
|
-
content: handlerResult.
|
|
3981
|
+
content: handlerResult.content
|
|
3792
3982
|
};
|
|
3793
3983
|
const assistantIndex = agent.messages.findIndex((m) => m.id === assistantMessage.id);
|
|
3794
3984
|
if (assistantIndex !== -1) agent.messages.splice(assistantIndex + 1, 0, toolResultMessage);
|
|
@@ -3944,6 +4134,15 @@ var StateManager = class {
|
|
|
3944
4134
|
activeRun = /* @__PURE__ */ new Map();
|
|
3945
4135
|
agentSubscriptions = /* @__PURE__ */ new Map();
|
|
3946
4136
|
pendingContinuations = /* @__PURE__ */ new WeakMap();
|
|
4137
|
+
interruptedRuns = /* @__PURE__ */ new WeakMap();
|
|
4138
|
+
/** Find the interrupted logical run without consuming its pending answers. */
|
|
4139
|
+
getContinuationRunId(agent, input) {
|
|
4140
|
+
const pending = this.interruptedRuns.get(agent)?.get(input.threadId);
|
|
4141
|
+
if (!pending) return void 0;
|
|
4142
|
+
if (pending.interruptIds === null) return input.resume === void 0 && isContinuation(input) ? pending.runId : void 0;
|
|
4143
|
+
const submitted = new Set(input.resume?.map((entry) => entry.interruptId));
|
|
4144
|
+
return submitted.size > 0 && submitted.size === input.resume?.length && submitted.size === pending.interruptIds.length && pending.interruptIds.every((id) => submitted.has(id)) ? pending.runId : void 0;
|
|
4145
|
+
}
|
|
3947
4146
|
constructor(core) {
|
|
3948
4147
|
this.core = core;
|
|
3949
4148
|
}
|
|
@@ -3987,6 +4186,7 @@ var StateManager = class {
|
|
|
3987
4186
|
}
|
|
3988
4187
|
let revoked = false;
|
|
3989
4188
|
let subRunId;
|
|
4189
|
+
let legacyInterrupted = false;
|
|
3990
4190
|
let runFinished = false;
|
|
3991
4191
|
const pendingResults = /* @__PURE__ */ new WeakMap();
|
|
3992
4192
|
const reconcilePendingResults = (historyMessages, input) => {
|
|
@@ -4052,21 +4252,43 @@ var StateManager = class {
|
|
|
4052
4252
|
if (revoked) return;
|
|
4053
4253
|
const internalContinuation = [...this.pendingContinuations.get(agent) ?? []].find((pending) => pending.expectedInput === input);
|
|
4054
4254
|
internalContinuation?.cancel();
|
|
4255
|
+
const startedInput = event.input ?? {
|
|
4256
|
+
...input,
|
|
4257
|
+
threadId: event.threadId
|
|
4258
|
+
};
|
|
4259
|
+
const resumedRunId = this.getContinuationRunId(agent, startedInput);
|
|
4260
|
+
this.interruptedRuns.get(agent)?.delete(startedInput.threadId);
|
|
4261
|
+
legacyInterrupted = false;
|
|
4055
4262
|
if (internalContinuation) subRunId = internalContinuation.expectedRunId ?? event.runId ?? input.runId;
|
|
4263
|
+
else if (resumedRunId) subRunId = resumedRunId;
|
|
4056
4264
|
else if (runFinished && input.runId === subRunId && !isContinuation(input) && (event.runId == null || event.runId === subRunId)) subRunId = randomUUID();
|
|
4057
4265
|
else subRunId = event.runId || input.runId;
|
|
4058
4266
|
runFinished = false;
|
|
4059
4267
|
this.handleRunStarted(agent, effectiveInput(input), state);
|
|
4060
4268
|
},
|
|
4061
|
-
onRunFinishedEvent: ({ input, state, messages }) => {
|
|
4269
|
+
onRunFinishedEvent: ({ event, input, state, messages }) => {
|
|
4062
4270
|
if (revoked) return;
|
|
4063
4271
|
runFinished = true;
|
|
4064
4272
|
const effective = effectiveInput(input);
|
|
4273
|
+
let interrupted = this.interruptedRuns.get(agent);
|
|
4274
|
+
if (event.outcome?.type === "interrupt" || legacyInterrupted) {
|
|
4275
|
+
if (!interrupted) {
|
|
4276
|
+
interrupted = /* @__PURE__ */ new Map();
|
|
4277
|
+
this.interruptedRuns.set(agent, interrupted);
|
|
4278
|
+
}
|
|
4279
|
+
interrupted.set(event.threadId, {
|
|
4280
|
+
runId: effective.runId,
|
|
4281
|
+
interruptIds: event.outcome?.type === "interrupt" ? event.outcome.interrupts.map((interrupt) => interrupt.id) : null
|
|
4282
|
+
});
|
|
4283
|
+
} else interrupted?.delete(event.threadId);
|
|
4065
4284
|
const mutation = reconcilePendingResults(messages, input);
|
|
4066
4285
|
clearPendingResults(input);
|
|
4067
4286
|
this.handleRunFinished(agent, effective, state);
|
|
4068
4287
|
return mutation;
|
|
4069
4288
|
},
|
|
4289
|
+
onCustomEvent: ({ event }) => {
|
|
4290
|
+
if (!revoked && event.name === "on_interrupt") legacyInterrupted = true;
|
|
4291
|
+
},
|
|
4070
4292
|
onRunErrorEvent: ({ input, state, messages }) => {
|
|
4071
4293
|
if (revoked) return;
|
|
4072
4294
|
runFinished = true;
|
|
@@ -4123,6 +4345,7 @@ var StateManager = class {
|
|
|
4123
4345
|
unsubscribe: () => {
|
|
4124
4346
|
revoked = true;
|
|
4125
4347
|
this.pendingContinuations.delete(agent);
|
|
4348
|
+
this.interruptedRuns.delete(agent);
|
|
4126
4349
|
unsubscribe();
|
|
4127
4350
|
}
|
|
4128
4351
|
});
|
|
@@ -4283,6 +4506,8 @@ var StateManager = class {
|
|
|
4283
4506
|
* Clear all state for an agent
|
|
4284
4507
|
*/
|
|
4285
4508
|
clearAgentState(agentId) {
|
|
4509
|
+
const agent = this.agentSubscriptions.get(agentId)?.agent;
|
|
4510
|
+
if (agent) this.interruptedRuns.delete(agent);
|
|
4286
4511
|
this.stateByRun.delete(agentId);
|
|
4287
4512
|
this.messageToRun.delete(agentId);
|
|
4288
4513
|
this.rawEventByMessage.delete(agentId);
|
|
@@ -4291,6 +4516,8 @@ var StateManager = class {
|
|
|
4291
4516
|
* Clear all state for a thread
|
|
4292
4517
|
*/
|
|
4293
4518
|
clearThreadState(agentId, threadId) {
|
|
4519
|
+
const agent = this.agentSubscriptions.get(agentId)?.agent;
|
|
4520
|
+
if (agent) this.interruptedRuns.get(agent)?.delete(threadId);
|
|
4294
4521
|
this.stateByRun.get(agentId)?.delete(threadId);
|
|
4295
4522
|
this.messageToRun.get(agentId)?.delete(threadId);
|
|
4296
4523
|
this.rawEventByMessage.get(agentId)?.delete(threadId);
|
|
@@ -4352,6 +4579,720 @@ var ThreadStoreRegistry = class {
|
|
|
4352
4579
|
}
|
|
4353
4580
|
};
|
|
4354
4581
|
|
|
4582
|
+
//#endregion
|
|
4583
|
+
//#region src/core/trajectory-connection.ts
|
|
4584
|
+
const TIMEOUT_MS = 1e4;
|
|
4585
|
+
const BATCH_INTERVAL_MS = 2e3;
|
|
4586
|
+
const MAX_BATCH_EVENTS = 50;
|
|
4587
|
+
const MAX_BATCH_BYTES = 64 * 1024;
|
|
4588
|
+
const MAX_EVENT_BYTES = 16 * 1024;
|
|
4589
|
+
const byteLength = (value) => new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
4590
|
+
const reconnectDelay = phoenixExponentialBackoff(1e3, 1e4);
|
|
4591
|
+
function isObject(value) {
|
|
4592
|
+
return typeof value === "object" && value !== null;
|
|
4593
|
+
}
|
|
4594
|
+
function isNonNegativeInteger(value) {
|
|
4595
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
4596
|
+
}
|
|
4597
|
+
function isBatchAcknowledgement(value, eventCount) {
|
|
4598
|
+
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);
|
|
4599
|
+
}
|
|
4600
|
+
function isGrant(value) {
|
|
4601
|
+
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;
|
|
4602
|
+
}
|
|
4603
|
+
function errorCode(value, fallback) {
|
|
4604
|
+
return isObject(value) && typeof value.code === "string" && /^[A-Z][A-Z0-9_]{0,63}$/.test(value.code) ? value.code : fallback;
|
|
4605
|
+
}
|
|
4606
|
+
/** Owns bounded, connected-only capture batches. Failed batches are never resent. */
|
|
4607
|
+
var TrajectoryConnection = class {
|
|
4608
|
+
session;
|
|
4609
|
+
nextSeq = Math.floor(Date.now()) * 1e3;
|
|
4610
|
+
constructor(core, onChange) {
|
|
4611
|
+
this.core = core;
|
|
4612
|
+
this.onChange = onChange;
|
|
4613
|
+
}
|
|
4614
|
+
get trajectoryId() {
|
|
4615
|
+
return this.session?.ready ? this.session.trajectoryId : null;
|
|
4616
|
+
}
|
|
4617
|
+
start(trajectoryId, config) {
|
|
4618
|
+
if (this.session && (trajectoryId === void 0 || trajectoryId === this.session.trajectoryId)) return this.session.promise;
|
|
4619
|
+
this.stop();
|
|
4620
|
+
const id = trajectoryId ?? crypto.randomUUID();
|
|
4621
|
+
let resolveStart;
|
|
4622
|
+
const promise = new Promise((resolve) => {
|
|
4623
|
+
resolveStart = resolve;
|
|
4624
|
+
});
|
|
4625
|
+
const session = {
|
|
4626
|
+
trajectoryId: id,
|
|
4627
|
+
config,
|
|
4628
|
+
promise,
|
|
4629
|
+
resolve: resolveStart,
|
|
4630
|
+
retries: 0,
|
|
4631
|
+
queue: [],
|
|
4632
|
+
dropped: 0,
|
|
4633
|
+
ready: false,
|
|
4634
|
+
started: false,
|
|
4635
|
+
offline: typeof navigator !== "undefined" && navigator.onLine === false,
|
|
4636
|
+
onOffline: () => {
|
|
4637
|
+
if (this.session !== session) return;
|
|
4638
|
+
session.offline = true;
|
|
4639
|
+
if (session.connection) this.fail(session, session.connection, "CONNECTION_LOST");
|
|
4640
|
+
clearTimeout(session.retry);
|
|
4641
|
+
session.retry = void 0;
|
|
4642
|
+
},
|
|
4643
|
+
onOnline: () => {
|
|
4644
|
+
if (this.session !== session) return;
|
|
4645
|
+
session.offline = false;
|
|
4646
|
+
if (!session.connection) {
|
|
4647
|
+
clearTimeout(session.retry);
|
|
4648
|
+
session.retry = void 0;
|
|
4649
|
+
this.connect(session);
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
};
|
|
4653
|
+
this.session = session;
|
|
4654
|
+
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
4655
|
+
window.addEventListener("offline", session.onOffline);
|
|
4656
|
+
window.addEventListener("online", session.onOnline);
|
|
4657
|
+
}
|
|
4658
|
+
if (session.offline) {
|
|
4659
|
+
this.report(session, "CONNECTION_LOST");
|
|
4660
|
+
this.end(session, {
|
|
4661
|
+
status: "error",
|
|
4662
|
+
code: "CONNECTION_LOST"
|
|
4663
|
+
});
|
|
4664
|
+
} else this.connect(session);
|
|
4665
|
+
return promise;
|
|
4666
|
+
}
|
|
4667
|
+
stop() {
|
|
4668
|
+
const session = this.session;
|
|
4669
|
+
if (!session) return;
|
|
4670
|
+
if (session.ready && session.connection) this.flush(session, session.connection);
|
|
4671
|
+
this.end(session, {
|
|
4672
|
+
status: "error",
|
|
4673
|
+
code: "CANCELLED"
|
|
4674
|
+
});
|
|
4675
|
+
}
|
|
4676
|
+
emit(name, value) {
|
|
4677
|
+
const session = this.session;
|
|
4678
|
+
if (session?.ready) session.collector?.emit(name, value);
|
|
4679
|
+
else if (session?.started) this.addDropped(session, 1, false);
|
|
4680
|
+
}
|
|
4681
|
+
report(session, code) {
|
|
4682
|
+
try {
|
|
4683
|
+
session.config.onError?.({
|
|
4684
|
+
code,
|
|
4685
|
+
message: `Trajectory capture: ${code}.`
|
|
4686
|
+
});
|
|
4687
|
+
} catch {}
|
|
4688
|
+
}
|
|
4689
|
+
current(session, connection) {
|
|
4690
|
+
return this.session === session && session.connection === connection;
|
|
4691
|
+
}
|
|
4692
|
+
end(session, result) {
|
|
4693
|
+
if (this.session !== session) return;
|
|
4694
|
+
this.session = void 0;
|
|
4695
|
+
clearTimeout(session.retry);
|
|
4696
|
+
session.collector?.stop();
|
|
4697
|
+
session.ready = false;
|
|
4698
|
+
if (session.queue.length > 0) this.report(session, "EVENTS_DROPPED");
|
|
4699
|
+
this.discardQueue(session);
|
|
4700
|
+
if (session.connection) {
|
|
4701
|
+
for (const pending of session.connection.pending) {
|
|
4702
|
+
pending.finish("PERSISTENCE_UNKNOWN");
|
|
4703
|
+
this.report(session, "PERSISTENCE_UNKNOWN");
|
|
4704
|
+
}
|
|
4705
|
+
this.cleanup(session, session.connection);
|
|
4706
|
+
}
|
|
4707
|
+
if (typeof window !== "undefined" && typeof window.removeEventListener === "function") {
|
|
4708
|
+
window.removeEventListener("offline", session.onOffline);
|
|
4709
|
+
window.removeEventListener("online", session.onOnline);
|
|
4710
|
+
}
|
|
4711
|
+
session.resolve(result);
|
|
4712
|
+
this.onChange();
|
|
4713
|
+
}
|
|
4714
|
+
cleanup(session, connection) {
|
|
4715
|
+
session.connection = void 0;
|
|
4716
|
+
clearTimeout(connection.timer);
|
|
4717
|
+
connection.abort.abort();
|
|
4718
|
+
for (const pending of connection.pending) clearTimeout(pending.timer);
|
|
4719
|
+
connection.pending.clear();
|
|
4720
|
+
const { socket, channel } = connection;
|
|
4721
|
+
try {
|
|
4722
|
+
if (channel) {
|
|
4723
|
+
for (const [event, ref] of connection.channelRefs) channel.off(event, ref);
|
|
4724
|
+
channel.leave();
|
|
4725
|
+
}
|
|
4726
|
+
} finally {
|
|
4727
|
+
if (socket) {
|
|
4728
|
+
socket.off(connection.socketRefs);
|
|
4729
|
+
socket.disconnect();
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
}
|
|
4733
|
+
fail(session, connection, code, retryable = true) {
|
|
4734
|
+
if (!this.current(session, connection)) return;
|
|
4735
|
+
session.collector?.stop();
|
|
4736
|
+
session.collector = void 0;
|
|
4737
|
+
if (session.ready && session.started) session.promise = new Promise((resolve) => {
|
|
4738
|
+
session.resolve = resolve;
|
|
4739
|
+
});
|
|
4740
|
+
session.ready = false;
|
|
4741
|
+
this.discardQueue(session);
|
|
4742
|
+
for (const pending of connection.pending) pending.finish("PERSISTENCE_UNKNOWN");
|
|
4743
|
+
if (!this.current(session, connection)) return;
|
|
4744
|
+
this.cleanup(session, connection);
|
|
4745
|
+
this.onChange();
|
|
4746
|
+
this.report(session, code);
|
|
4747
|
+
if (this.session !== session) return;
|
|
4748
|
+
if (!session.started || !retryable) {
|
|
4749
|
+
this.end(session, {
|
|
4750
|
+
status: "error",
|
|
4751
|
+
code
|
|
4752
|
+
});
|
|
4753
|
+
return;
|
|
4754
|
+
}
|
|
4755
|
+
if (session.offline || this.session !== session) return;
|
|
4756
|
+
session.retry = setTimeout(() => {
|
|
4757
|
+
session.retry = void 0;
|
|
4758
|
+
if (this.session === session && !session.offline) this.connect(session);
|
|
4759
|
+
}, reconnectDelay(++session.retries));
|
|
4760
|
+
}
|
|
4761
|
+
async connect(session) {
|
|
4762
|
+
if (this.session !== session || session.offline || session.connection) return;
|
|
4763
|
+
const connection = {
|
|
4764
|
+
abort: new AbortController(),
|
|
4765
|
+
socketRefs: [],
|
|
4766
|
+
channelRefs: [],
|
|
4767
|
+
pending: /* @__PURE__ */ new Set()
|
|
4768
|
+
};
|
|
4769
|
+
session.connection = connection;
|
|
4770
|
+
connection.timer = setTimeout(() => this.fail(session, connection, "CONNECTION_TIMEOUT"), TIMEOUT_MS);
|
|
4771
|
+
try {
|
|
4772
|
+
const runtimeUrl = this.core.runtimeUrl;
|
|
4773
|
+
if (!runtimeUrl) {
|
|
4774
|
+
this.fail(session, connection, "RUNTIME_REQUIRED", false);
|
|
4775
|
+
return;
|
|
4776
|
+
}
|
|
4777
|
+
let transport = this.core.runtimeTransport;
|
|
4778
|
+
if (transport === "auto") {
|
|
4779
|
+
transport = await this.detectedTransport(connection.abort.signal);
|
|
4780
|
+
if (!this.current(session, connection)) return;
|
|
4781
|
+
}
|
|
4782
|
+
const rest = transport === "rest";
|
|
4783
|
+
const response = await fetch(rest ? `${runtimeUrl}/trajectory/${encodeURIComponent(session.trajectoryId)}/connect` : this.core.ɵruntimeEndpointUrl ?? runtimeUrl, {
|
|
4784
|
+
method: "POST",
|
|
4785
|
+
redirect: "error",
|
|
4786
|
+
signal: connection.abort.signal,
|
|
4787
|
+
headers: {
|
|
4788
|
+
...this.core.headers,
|
|
4789
|
+
"Content-Type": "application/json"
|
|
4790
|
+
},
|
|
4791
|
+
credentials: this.core.credentials,
|
|
4792
|
+
body: JSON.stringify(rest ? {} : {
|
|
4793
|
+
method: "trajectory/connect",
|
|
4794
|
+
params: { trajectoryId: session.trajectoryId },
|
|
4795
|
+
body: {}
|
|
4796
|
+
})
|
|
4797
|
+
});
|
|
4798
|
+
if (!this.current(session, connection)) return;
|
|
4799
|
+
const payload = await response.json().catch(() => void 0);
|
|
4800
|
+
if (!this.current(session, connection)) return;
|
|
4801
|
+
if (!response.ok) {
|
|
4802
|
+
this.fail(session, connection, errorCode(payload, "CONNECTION_FAILED"), response.status >= 500 || response.status === 408 || response.status === 429);
|
|
4803
|
+
return;
|
|
4804
|
+
}
|
|
4805
|
+
if (!isGrant(payload)) {
|
|
4806
|
+
this.fail(session, connection, "INVALID_GRANT", false);
|
|
4807
|
+
return;
|
|
4808
|
+
}
|
|
4809
|
+
const socket = new Socket(payload.realtime.clientUrl, {
|
|
4810
|
+
params: { join_token: payload.joinToken },
|
|
4811
|
+
timeout: TIMEOUT_MS
|
|
4812
|
+
});
|
|
4813
|
+
connection.socket = socket;
|
|
4814
|
+
const lost = () => this.fail(session, connection, "CONNECTION_LOST");
|
|
4815
|
+
connection.socketRefs.push(socket.onError(lost), socket.onClose(lost));
|
|
4816
|
+
const channel = socket.channel(payload.realtime.topic, {});
|
|
4817
|
+
connection.channel = channel;
|
|
4818
|
+
connection.channelRefs.push(["phx_error", channel.onError(lost)], ["phx_close", channel.onClose(lost)]);
|
|
4819
|
+
socket.connect();
|
|
4820
|
+
if (!this.current(session, connection)) return;
|
|
4821
|
+
channel.join(TIMEOUT_MS).receive("ok", () => {
|
|
4822
|
+
if (!this.current(session, connection)) return;
|
|
4823
|
+
try {
|
|
4824
|
+
clearTimeout(connection.timer);
|
|
4825
|
+
session.ready = true;
|
|
4826
|
+
session.retries = 0;
|
|
4827
|
+
session.collector = createTrajectoryCollector({
|
|
4828
|
+
...session.config,
|
|
4829
|
+
ignoreUrls: [
|
|
4830
|
+
...session.config.ignoreUrls ?? [],
|
|
4831
|
+
...this.core.runtimeUrl ? [this.core.runtimeUrl] : [],
|
|
4832
|
+
...this.core.ɵruntimeEndpointUrl ? [this.core.ɵruntimeEndpointUrl] : [],
|
|
4833
|
+
"https://telemetry.copilotkit.ai/",
|
|
4834
|
+
"https://cdn.copilotkit.ai/"
|
|
4835
|
+
],
|
|
4836
|
+
onError: (error) => {
|
|
4837
|
+
if (error.code === "CAPTURE_FAILED") this.fail(session, connection, error.code, false);
|
|
4838
|
+
else {
|
|
4839
|
+
if (error.code === "INVALID_EVENT" || error.code === "EVENT_TOO_LARGE") this.addDropped(session, 1);
|
|
4840
|
+
session.config.onError?.(error);
|
|
4841
|
+
}
|
|
4842
|
+
},
|
|
4843
|
+
send: (event) => this.send(session, connection, event)
|
|
4844
|
+
});
|
|
4845
|
+
session.collector.start();
|
|
4846
|
+
if (!this.current(session, connection)) return;
|
|
4847
|
+
if (session.dropped > 0) this.scheduleFlush(session, connection);
|
|
4848
|
+
session.started = true;
|
|
4849
|
+
session.resolve({
|
|
4850
|
+
status: "started",
|
|
4851
|
+
trajectoryId: session.trajectoryId
|
|
4852
|
+
});
|
|
4853
|
+
this.onChange();
|
|
4854
|
+
} catch {
|
|
4855
|
+
this.fail(session, connection, "CAPTURE_FAILED", false);
|
|
4856
|
+
}
|
|
4857
|
+
}).receive("error", (joinError) => this.fail(session, connection, errorCode(joinError, "JOIN_FAILED"))).receive("timeout", () => this.fail(session, connection, "CONNECTION_TIMEOUT"));
|
|
4858
|
+
} catch {
|
|
4859
|
+
this.fail(session, connection, "CONNECTION_FAILED");
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
/** Resolves once auto-detection picks a transport, or with "auto" when the attempt is aborted. */
|
|
4863
|
+
detectedTransport(signal) {
|
|
4864
|
+
return new Promise((resolve) => {
|
|
4865
|
+
const finish = () => {
|
|
4866
|
+
subscription.unsubscribe();
|
|
4867
|
+
signal.removeEventListener("abort", finish);
|
|
4868
|
+
resolve(this.core.runtimeTransport);
|
|
4869
|
+
};
|
|
4870
|
+
const subscription = this.core.subscribe({ onRuntimeConnectionStatusChanged: () => {
|
|
4871
|
+
if (this.core.runtimeTransport !== "auto") finish();
|
|
4872
|
+
} });
|
|
4873
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
4874
|
+
});
|
|
4875
|
+
}
|
|
4876
|
+
addDropped(session, count, schedule = true) {
|
|
4877
|
+
session.dropped = Math.min(Number.MAX_SAFE_INTEGER, session.dropped + count);
|
|
4878
|
+
if (schedule && count > 0 && session.ready && session.connection) this.scheduleFlush(session, session.connection);
|
|
4879
|
+
}
|
|
4880
|
+
scheduleFlush(session, connection) {
|
|
4881
|
+
if (session.flushTimer !== void 0 || !this.current(session, connection)) return;
|
|
4882
|
+
session.flushTimer = setTimeout(() => {
|
|
4883
|
+
session.flushTimer = void 0;
|
|
4884
|
+
this.flush(session, connection);
|
|
4885
|
+
}, BATCH_INTERVAL_MS);
|
|
4886
|
+
}
|
|
4887
|
+
discardQueue(session) {
|
|
4888
|
+
clearTimeout(session.flushTimer);
|
|
4889
|
+
session.flushTimer = void 0;
|
|
4890
|
+
this.addDropped(session, session.queue.length, false);
|
|
4891
|
+
session.queue = [];
|
|
4892
|
+
}
|
|
4893
|
+
connected(connection) {
|
|
4894
|
+
return connection.socket?.isConnected() === true && connection.channel?.state === "joined";
|
|
4895
|
+
}
|
|
4896
|
+
send(session, connection, event) {
|
|
4897
|
+
if (!this.current(session, connection) || !session.ready) return;
|
|
4898
|
+
if (!this.connected(connection)) {
|
|
4899
|
+
this.addDropped(session, 1);
|
|
4900
|
+
this.fail(session, connection, "CONNECTION_LOST");
|
|
4901
|
+
return;
|
|
4902
|
+
}
|
|
4903
|
+
if (!Number.isSafeInteger(this.nextSeq)) {
|
|
4904
|
+
this.addDropped(session, 1);
|
|
4905
|
+
this.report(session, "SEQUENCE_EXHAUSTED");
|
|
4906
|
+
return;
|
|
4907
|
+
}
|
|
4908
|
+
const original = event.value;
|
|
4909
|
+
const fields = isObject(original) && !Array.isArray(original) && !Object.hasOwn(original, "seq") ? original : { data: original };
|
|
4910
|
+
const wire = {
|
|
4911
|
+
...event,
|
|
4912
|
+
value: {
|
|
4913
|
+
...fields,
|
|
4914
|
+
seq: this.nextSeq++
|
|
4915
|
+
}
|
|
4916
|
+
};
|
|
4917
|
+
if (byteLength(wire) > MAX_EVENT_BYTES) {
|
|
4918
|
+
this.addDropped(session, 1);
|
|
4919
|
+
this.report(session, "EVENT_TOO_LARGE");
|
|
4920
|
+
return;
|
|
4921
|
+
}
|
|
4922
|
+
const fits = () => session.queue.length < MAX_BATCH_EVENTS && byteLength({
|
|
4923
|
+
events: [...session.queue, wire],
|
|
4924
|
+
dropped: Number.MAX_SAFE_INTEGER
|
|
4925
|
+
}) <= MAX_BATCH_BYTES;
|
|
4926
|
+
if (!fits()) this.flush(session, connection);
|
|
4927
|
+
if (!this.current(session, connection) || !session.ready) return;
|
|
4928
|
+
if (!fits()) {
|
|
4929
|
+
this.addDropped(session, 1);
|
|
4930
|
+
this.report(session, "EVENTS_DROPPED");
|
|
4931
|
+
return;
|
|
4932
|
+
}
|
|
4933
|
+
session.queue.push(wire);
|
|
4934
|
+
if (session.queue.length === MAX_BATCH_EVENTS) this.flush(session, connection);
|
|
4935
|
+
else this.scheduleFlush(session, connection);
|
|
4936
|
+
}
|
|
4937
|
+
flush(session, connection) {
|
|
4938
|
+
if (!this.current(session, connection) || !session.ready || session.queue.length === 0 && session.dropped === 0) return;
|
|
4939
|
+
if (!this.connected(connection)) {
|
|
4940
|
+
this.fail(session, connection, "CONNECTION_LOST");
|
|
4941
|
+
return;
|
|
4942
|
+
}
|
|
4943
|
+
if (connection.pending.size > 0) return;
|
|
4944
|
+
clearTimeout(session.flushTimer);
|
|
4945
|
+
session.flushTimer = void 0;
|
|
4946
|
+
const batch = {
|
|
4947
|
+
events: session.queue,
|
|
4948
|
+
dropped: session.dropped
|
|
4949
|
+
};
|
|
4950
|
+
session.queue = [];
|
|
4951
|
+
session.dropped = 0;
|
|
4952
|
+
let finished = false;
|
|
4953
|
+
const pending = {
|
|
4954
|
+
timer: setTimeout(() => pending.finish("PERSISTENCE_UNKNOWN"), TIMEOUT_MS),
|
|
4955
|
+
finish: (code, knownRollback = false, flushNext = true) => {
|
|
4956
|
+
if (finished) return;
|
|
4957
|
+
finished = true;
|
|
4958
|
+
clearTimeout(pending.timer);
|
|
4959
|
+
connection.pending.delete(pending);
|
|
4960
|
+
if (knownRollback) this.addDropped(session, batch.events.length + batch.dropped, false);
|
|
4961
|
+
if (code && this.current(session, connection)) this.report(session, code);
|
|
4962
|
+
if (flushNext && this.current(session, connection) && session.ready && (session.queue.length > 0 || !knownRollback && session.dropped > 0)) this.flush(session, connection);
|
|
4963
|
+
}
|
|
4964
|
+
};
|
|
4965
|
+
connection.pending.add(pending);
|
|
4966
|
+
try {
|
|
4967
|
+
connection.channel.push("events", batch, TIMEOUT_MS).receive("ok", (payload) => {
|
|
4968
|
+
pending.finish(!isBatchAcknowledgement(payload, batch.events.length) ? "PERSISTENCE_UNKNOWN" : payload.rejected > 0 ? "EVENTS_REJECTED" : void 0);
|
|
4969
|
+
}).receive("error", (payload) => {
|
|
4970
|
+
if (!this.current(session, connection)) return;
|
|
4971
|
+
const reason = isObject(payload) ? payload.reason : void 0;
|
|
4972
|
+
if (reason === "unauthorized" || reason === "trajectory_mismatch") {
|
|
4973
|
+
pending.finish(void 0, true, false);
|
|
4974
|
+
this.fail(session, connection, reason.toUpperCase(), false);
|
|
4975
|
+
return;
|
|
4976
|
+
}
|
|
4977
|
+
const rollback = typeof reason === "string" && [
|
|
4978
|
+
"invalid_batch",
|
|
4979
|
+
"batch_too_large",
|
|
4980
|
+
"batch_too_many_events",
|
|
4981
|
+
"trajectory_over_share",
|
|
4982
|
+
"trajectory_outbox_full",
|
|
4983
|
+
"unsupported_event"
|
|
4984
|
+
].includes(reason);
|
|
4985
|
+
pending.finish(rollback ? reason.toUpperCase() : "PERSISTENCE_UNKNOWN", rollback);
|
|
4986
|
+
}).receive("timeout", () => pending.finish("PERSISTENCE_UNKNOWN"));
|
|
4987
|
+
} catch {
|
|
4988
|
+
pending.finish("PERSISTENCE_UNKNOWN");
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
};
|
|
4992
|
+
|
|
4993
|
+
//#endregion
|
|
4994
|
+
//#region src/core/learning-bridge.ts
|
|
4995
|
+
const COPILOTKIT_OWN_URLS = ["https://telemetry.copilotkit.ai/", "https://cdn.copilotkit.ai/"];
|
|
4996
|
+
/**
|
|
4997
|
+
* Wires `@copilotkit/learning` into Core. Default capture uses Runtime and Phoenix;
|
|
4998
|
+
* explicit legacy sinks also use agent events and open-Thread attribution.
|
|
4999
|
+
*/
|
|
5000
|
+
var LearningBridge = class {
|
|
5001
|
+
collector = null;
|
|
5002
|
+
agents = /* @__PURE__ */ new Map();
|
|
5003
|
+
openThreads = /* @__PURE__ */ new Set();
|
|
5004
|
+
toolCalls = /* @__PURE__ */ new Map();
|
|
5005
|
+
executingTools = /* @__PURE__ */ new Map();
|
|
5006
|
+
lastRunIds = /* @__PURE__ */ new WeakMap();
|
|
5007
|
+
lastLinkedThreadId = null;
|
|
5008
|
+
coreSubscription = null;
|
|
5009
|
+
seq = 0;
|
|
5010
|
+
activeConfig;
|
|
5011
|
+
connection;
|
|
5012
|
+
constructor(core, config, onChange = () => {}) {
|
|
5013
|
+
this.core = core;
|
|
5014
|
+
this.config = config;
|
|
5015
|
+
this.connection = new TrajectoryConnection(core, onChange);
|
|
5016
|
+
this.setConfig(config);
|
|
5017
|
+
}
|
|
5018
|
+
setConfig(config) {
|
|
5019
|
+
this.config = config;
|
|
5020
|
+
if (config === void 0) this.stop();
|
|
5021
|
+
}
|
|
5022
|
+
get isConfigured() {
|
|
5023
|
+
return this.config !== void 0;
|
|
5024
|
+
}
|
|
5025
|
+
get isLegacyCaptureActive() {
|
|
5026
|
+
return this.collector !== null && this.collector.trajectoryId !== null;
|
|
5027
|
+
}
|
|
5028
|
+
startTracking() {
|
|
5029
|
+
if (this.coreSubscription !== null || !this.isLegacyCaptureActive) return;
|
|
5030
|
+
this.coreSubscription = this.core.subscribe({
|
|
5031
|
+
onAgentsChanged: ({ agents }) => {
|
|
5032
|
+
for (const agent of Object.values(agents)) this.track(agent);
|
|
5033
|
+
},
|
|
5034
|
+
onAgentRunStarted: ({ agent }) => this.track(agent),
|
|
5035
|
+
onToolExecutionStart: ({ toolCallId, agentId, toolName }) => {
|
|
5036
|
+
if (!this.isLegacyCaptureActive) return;
|
|
5037
|
+
this.executingTools.set(toolCallId, Date.now());
|
|
5038
|
+
this.emitToolCall("executing", toolCallId, agentId, toolName, {});
|
|
5039
|
+
},
|
|
5040
|
+
onToolExecutionEnd: ({ toolCallId, agentId, toolName, error }) => {
|
|
5041
|
+
if (!this.isLegacyCaptureActive) return;
|
|
5042
|
+
const startedAt = this.executingTools.get(toolCallId);
|
|
5043
|
+
this.executingTools.delete(toolCallId);
|
|
5044
|
+
this.emitToolCall("completed", toolCallId, agentId, toolName, {
|
|
5045
|
+
durationMs: startedAt === void 0 ? void 0 : Date.now() - startedAt,
|
|
5046
|
+
outcome: error === void 0 ? "ok" : "error"
|
|
5047
|
+
});
|
|
5048
|
+
this.toolCalls.delete(toolCallId);
|
|
5049
|
+
}
|
|
5050
|
+
});
|
|
5051
|
+
for (const agent of Object.values(this.core.agents)) this.track(agent);
|
|
5052
|
+
}
|
|
5053
|
+
get trajectoryId() {
|
|
5054
|
+
return this.connection.trajectoryId ?? this.collector?.trajectoryId ?? null;
|
|
5055
|
+
}
|
|
5056
|
+
start(options = {}) {
|
|
5057
|
+
const config = this.config;
|
|
5058
|
+
if (config === void 0) {
|
|
5059
|
+
console.warn("[CopilotKit] startTrajectory() needs the `learning` option on CopilotKitCore (or the CopilotKitProvider `learning` prop).");
|
|
5060
|
+
return Promise.resolve({
|
|
5061
|
+
status: "error",
|
|
5062
|
+
code: "LEARNING_DISABLED"
|
|
5063
|
+
});
|
|
5064
|
+
}
|
|
5065
|
+
if (config.sink === void 0) {
|
|
5066
|
+
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.");
|
|
5067
|
+
this.stopLegacy();
|
|
5068
|
+
return this.connection.start(options.trajectoryId, config);
|
|
5069
|
+
}
|
|
5070
|
+
this.connection.stop();
|
|
5071
|
+
const trajectoryId = options.trajectoryId ?? this.collector?.trajectoryId ?? crypto.randomUUID();
|
|
5072
|
+
if (this.collector === null) {
|
|
5073
|
+
this.activeConfig = config;
|
|
5074
|
+
const runtimeUrl = this.core.runtimeUrl;
|
|
5075
|
+
this.collector = createCollector({
|
|
5076
|
+
...config,
|
|
5077
|
+
beforeSend: (event) => {
|
|
5078
|
+
const sequenced = {
|
|
5079
|
+
...event,
|
|
5080
|
+
value: {
|
|
5081
|
+
...event.value,
|
|
5082
|
+
seq: ++this.seq
|
|
5083
|
+
}
|
|
5084
|
+
};
|
|
5085
|
+
return config.beforeSend === void 0 ? sequenced : config.beforeSend(sequenced);
|
|
5086
|
+
},
|
|
5087
|
+
ignoreUrls: [
|
|
5088
|
+
...config.ignoreUrls ?? [],
|
|
5089
|
+
...COPILOTKIT_OWN_URLS,
|
|
5090
|
+
...runtimeUrl === void 0 ? [] : [runtimeUrl]
|
|
5091
|
+
],
|
|
5092
|
+
enrich: (target) => this.enrich(target)
|
|
5093
|
+
});
|
|
5094
|
+
}
|
|
5095
|
+
const wasActive = this.collector.trajectoryId !== null;
|
|
5096
|
+
this.collector.start({
|
|
5097
|
+
...options,
|
|
5098
|
+
trajectoryId
|
|
5099
|
+
});
|
|
5100
|
+
if (wasActive) return Promise.resolve(this.collector.trajectoryId === trajectoryId ? {
|
|
5101
|
+
status: "started",
|
|
5102
|
+
trajectoryId
|
|
5103
|
+
} : {
|
|
5104
|
+
status: "error",
|
|
5105
|
+
code: "TRAJECTORY_ACTIVE"
|
|
5106
|
+
});
|
|
5107
|
+
this.startTracking();
|
|
5108
|
+
this.lastLinkedThreadId = null;
|
|
5109
|
+
for (const threadId of this.distinctOpenThreadIds()) this.emitThreadLinked(threadId, "start");
|
|
5110
|
+
return Promise.resolve({
|
|
5111
|
+
status: "started",
|
|
5112
|
+
trajectoryId
|
|
5113
|
+
});
|
|
5114
|
+
}
|
|
5115
|
+
stop() {
|
|
5116
|
+
this.connection.stop();
|
|
5117
|
+
this.stopLegacy();
|
|
5118
|
+
}
|
|
5119
|
+
stopLegacy() {
|
|
5120
|
+
this.collector?.stop();
|
|
5121
|
+
this.collector = null;
|
|
5122
|
+
this.activeConfig = void 0;
|
|
5123
|
+
this.coreSubscription?.unsubscribe();
|
|
5124
|
+
this.coreSubscription = null;
|
|
5125
|
+
for (const subscription of this.agents.values()) subscription.unsubscribe();
|
|
5126
|
+
this.agents.clear();
|
|
5127
|
+
this.toolCalls.clear();
|
|
5128
|
+
this.executingTools.clear();
|
|
5129
|
+
}
|
|
5130
|
+
/** A developer event. Only an explicit legacy sink adds open-Thread context. */
|
|
5131
|
+
emit(name, value) {
|
|
5132
|
+
this.connection.emit(name, value);
|
|
5133
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) this.collector?.emit(name, {
|
|
5134
|
+
...this.openThreadContext(),
|
|
5135
|
+
...value
|
|
5136
|
+
});
|
|
5137
|
+
}
|
|
5138
|
+
registerOpenThread(params) {
|
|
5139
|
+
const entry = { ...params };
|
|
5140
|
+
const isNew = !this.distinctOpenThreadIds().includes(entry.threadId);
|
|
5141
|
+
this.openThreads.add(entry);
|
|
5142
|
+
if (isNew) this.emitThreadLinked(entry.threadId, "open");
|
|
5143
|
+
return {
|
|
5144
|
+
update: (threadId) => {
|
|
5145
|
+
if (threadId === entry.threadId) return;
|
|
5146
|
+
entry.threadId = threadId;
|
|
5147
|
+
if (![...this.openThreads].filter((other) => other !== entry).some((other) => other.threadId === threadId)) this.emitThreadLinked(threadId, "switch");
|
|
5148
|
+
},
|
|
5149
|
+
unregister: () => {
|
|
5150
|
+
this.openThreads.delete(entry);
|
|
5151
|
+
}
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
distinctOpenThreadIds() {
|
|
5155
|
+
return [...new Set([...this.openThreads].map((open) => open.threadId))];
|
|
5156
|
+
}
|
|
5157
|
+
emitThreadLinked(threadId, reason) {
|
|
5158
|
+
if (!(this.collector !== null && this.collector.trajectoryId !== null) || threadId === this.lastLinkedThreadId) return;
|
|
5159
|
+
this.lastLinkedThreadId = threadId;
|
|
5160
|
+
const owner = [...this.openThreads].find((open) => open.threadId === threadId);
|
|
5161
|
+
const agent = this.findAgentForThread(threadId);
|
|
5162
|
+
this.collector?.ɵemit("thread.linked", {
|
|
5163
|
+
threadId,
|
|
5164
|
+
agentId: owner?.agentId ?? agent?.agentId ?? null,
|
|
5165
|
+
hasMessages: (agent?.messages.length ?? 0) > 0,
|
|
5166
|
+
reason
|
|
5167
|
+
});
|
|
5168
|
+
}
|
|
5169
|
+
findAgentForThread(threadId) {
|
|
5170
|
+
return [...this.agents.keys()].find((agent) => agent.threadId === threadId);
|
|
5171
|
+
}
|
|
5172
|
+
track(agent) {
|
|
5173
|
+
const agentId = agent.agentId;
|
|
5174
|
+
if (!this.isLegacyCaptureActive || this.agents.has(agent) || agentId === void 0) return;
|
|
5175
|
+
this.agents.set(agent, agent.subscribe(this.agentSubscriber(agent, agentId)));
|
|
5176
|
+
}
|
|
5177
|
+
agentSubscriber(agent, agentId) {
|
|
5178
|
+
const runIdFor = () => this.lastRunIds.get(agent);
|
|
5179
|
+
return {
|
|
5180
|
+
onRunStartedEvent: ({ event }) => {
|
|
5181
|
+
this.lastRunIds.set(agent, event.runId);
|
|
5182
|
+
this.emitRun("started", agent, event.threadId, event.runId);
|
|
5183
|
+
},
|
|
5184
|
+
onRunFinishedEvent: ({ event }) => {
|
|
5185
|
+
this.emitRun("finished", agent, event.threadId, event.runId);
|
|
5186
|
+
},
|
|
5187
|
+
onRunErrorEvent: () => {
|
|
5188
|
+
this.emitRun("error", agent, agent.threadId, runIdFor() ?? null);
|
|
5189
|
+
},
|
|
5190
|
+
onToolCallStartEvent: ({ event }) => {
|
|
5191
|
+
if (!this.isLegacyCaptureActive) return;
|
|
5192
|
+
const origin = {
|
|
5193
|
+
agentId,
|
|
5194
|
+
threadId: agent.threadId,
|
|
5195
|
+
messageId: event.parentMessageId,
|
|
5196
|
+
runId: runIdFor()
|
|
5197
|
+
};
|
|
5198
|
+
this.toolCalls.set(event.toolCallId, origin);
|
|
5199
|
+
this.emitToolCall("started", event.toolCallId, origin.agentId, event.toolCallName, {});
|
|
5200
|
+
},
|
|
5201
|
+
onToolCallResultEvent: ({ event }) => {
|
|
5202
|
+
if (!this.executingTools.has(event.toolCallId)) this.toolCalls.delete(event.toolCallId);
|
|
5203
|
+
},
|
|
5204
|
+
onNewMessage: ({ message }) => this.emitMessage(agent, message)
|
|
5205
|
+
};
|
|
5206
|
+
}
|
|
5207
|
+
emitRun(phase, agent, threadId, runId) {
|
|
5208
|
+
this.collector?.ɵemit("agent.run", {
|
|
5209
|
+
phase,
|
|
5210
|
+
runId,
|
|
5211
|
+
threadId,
|
|
5212
|
+
agentId: agent.agentId
|
|
5213
|
+
});
|
|
5214
|
+
}
|
|
5215
|
+
emitMessage(agent, message) {
|
|
5216
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
5217
|
+
const includeText = this.activeConfig?.capture?.agentText !== false && typeof message.content === "string";
|
|
5218
|
+
this.collector?.ɵemit("agent.message", {
|
|
5219
|
+
messageId: message.id,
|
|
5220
|
+
runId: this.runIdForMessage(agent, message.id),
|
|
5221
|
+
threadId: agent.threadId,
|
|
5222
|
+
agentId: agent.agentId,
|
|
5223
|
+
role: message.role,
|
|
5224
|
+
textLength: content.length,
|
|
5225
|
+
...includeText ? { text: content } : {}
|
|
5226
|
+
});
|
|
5227
|
+
}
|
|
5228
|
+
emitToolCall(phase, toolCallId, agentId, toolName, extra) {
|
|
5229
|
+
const origin = this.toolCalls.get(toolCallId);
|
|
5230
|
+
this.collector?.ɵemit("tool.call", {
|
|
5231
|
+
phase,
|
|
5232
|
+
toolCallId,
|
|
5233
|
+
toolName,
|
|
5234
|
+
agentId,
|
|
5235
|
+
threadId: origin?.threadId ?? null,
|
|
5236
|
+
messageId: origin?.messageId,
|
|
5237
|
+
runId: origin?.runId,
|
|
5238
|
+
...extra
|
|
5239
|
+
});
|
|
5240
|
+
}
|
|
5241
|
+
runIdForMessage(agent, messageId) {
|
|
5242
|
+
const agentId = agent.agentId;
|
|
5243
|
+
if (agentId === void 0) return null;
|
|
5244
|
+
return this.core.getRunIdForMessage(agentId, agent.threadId, messageId) ?? this.lastRunIds.get(agent) ?? null;
|
|
5245
|
+
}
|
|
5246
|
+
findMessage(messageId) {
|
|
5247
|
+
for (const agent of this.agents.keys()) {
|
|
5248
|
+
const message = agent.messages.find((candidate) => candidate.id === messageId);
|
|
5249
|
+
if (message !== void 0) return {
|
|
5250
|
+
agent,
|
|
5251
|
+
message
|
|
5252
|
+
};
|
|
5253
|
+
}
|
|
5254
|
+
return null;
|
|
5255
|
+
}
|
|
5256
|
+
toolStatus(agent, toolCallId) {
|
|
5257
|
+
if (this.executingTools.has(toolCallId)) return "executing";
|
|
5258
|
+
return agent.messages.some((message) => message.role === "tool" && message.toolCallId === toolCallId) ? "complete" : "inProgress";
|
|
5259
|
+
}
|
|
5260
|
+
/** Adds agent context to a click: exact message first, then the single open Thread. */
|
|
5261
|
+
enrich(target) {
|
|
5262
|
+
const messageId = target.closest("[data-message-id]")?.getAttribute("data-message-id") ?? null;
|
|
5263
|
+
const toolCallId = target.closest("[data-tool-call-id]")?.getAttribute("data-tool-call-id") ?? null;
|
|
5264
|
+
const found = messageId === null ? null : this.findMessage(messageId);
|
|
5265
|
+
if (found !== null) {
|
|
5266
|
+
const { agent, message } = found;
|
|
5267
|
+
const toolCall = toolCallId !== null && message.role === "assistant" ? message.toolCalls?.find((call) => call.id === toolCallId) : void 0;
|
|
5268
|
+
return {
|
|
5269
|
+
threadId: agent.threadId,
|
|
5270
|
+
agentId: agent.agentId,
|
|
5271
|
+
messageId: message.id,
|
|
5272
|
+
runId: this.runIdForMessage(agent, message.id),
|
|
5273
|
+
...toolCall === void 0 ? {} : {
|
|
5274
|
+
toolCallId: toolCall.id,
|
|
5275
|
+
toolName: toolCall.function.name,
|
|
5276
|
+
toolStatus: this.toolStatus(agent, toolCall.id)
|
|
5277
|
+
}
|
|
5278
|
+
};
|
|
5279
|
+
}
|
|
5280
|
+
return this.openThreadContext();
|
|
5281
|
+
}
|
|
5282
|
+
/** The single open Thread, or `null` with the candidates when several are open. */
|
|
5283
|
+
openThreadContext() {
|
|
5284
|
+
const openIds = this.distinctOpenThreadIds();
|
|
5285
|
+
if (openIds.length > 1) return {
|
|
5286
|
+
threadId: null,
|
|
5287
|
+
threadAmbiguity: {
|
|
5288
|
+
reason: "multiple-open",
|
|
5289
|
+
candidates: openIds
|
|
5290
|
+
}
|
|
5291
|
+
};
|
|
5292
|
+
return { threadId: openIds[0] ?? null };
|
|
5293
|
+
}
|
|
5294
|
+
};
|
|
5295
|
+
|
|
4355
5296
|
//#endregion
|
|
4356
5297
|
//#region src/utils/micro-redux.ts
|
|
4357
5298
|
const INTERNAL_ACTION_TYPES = {
|
|
@@ -5504,6 +6445,9 @@ var CopilotKitCore = class {
|
|
|
5504
6445
|
runHandler;
|
|
5505
6446
|
stateManager;
|
|
5506
6447
|
threadStoreRegistry;
|
|
6448
|
+
learningBridge;
|
|
6449
|
+
notifiedTrajectoryId = null;
|
|
6450
|
+
learningConfiguredListeners = /* @__PURE__ */ new Set();
|
|
5507
6451
|
/**
|
|
5508
6452
|
* The single core-owned memory store, created lazily on first
|
|
5509
6453
|
* `getMemoryStore()` and kept user-scoped for the lifetime of the core.
|
|
@@ -5518,7 +6462,7 @@ var CopilotKitCore = class {
|
|
|
5518
6462
|
* store that was registered prior to that initial notification.
|
|
5519
6463
|
*/
|
|
5520
6464
|
previousAgentIds = /* @__PURE__ */ new Set();
|
|
5521
|
-
constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
|
|
6465
|
+
constructor({ runtimeUrl, runtimeTransport = "auto", deferInitialConnection = false, headers = {}, credentials, messageFilter, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug, learning }) {
|
|
5522
6466
|
this._headers = normalizeHeaders(headers);
|
|
5523
6467
|
this._credentials = credentials;
|
|
5524
6468
|
this._messageFilter = messageFilter;
|
|
@@ -5534,6 +6478,7 @@ var CopilotKitCore = class {
|
|
|
5534
6478
|
this.runHandler.initialize(tools);
|
|
5535
6479
|
this.suggestionEngine.initialize(suggestionsConfig);
|
|
5536
6480
|
this.stateManager.initialize();
|
|
6481
|
+
this.learningBridge = new LearningBridge(this, learning, () => this.notifyTrajectoryChanged());
|
|
5537
6482
|
this.agentRegistry.setRuntimeTransport(runtimeTransport);
|
|
5538
6483
|
this.agentRegistry.setRuntimeUrl(runtimeUrl, { deferConnection: deferInitialConnection });
|
|
5539
6484
|
this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
|
|
@@ -5685,6 +6630,10 @@ var CopilotKitCore = class {
|
|
|
5685
6630
|
get runtimeConnectionStatus() {
|
|
5686
6631
|
return this.agentRegistry.runtimeConnectionStatus;
|
|
5687
6632
|
}
|
|
6633
|
+
/** @internal The verbatim single-endpoint URL, including any trailing slash. */
|
|
6634
|
+
get ɵruntimeEndpointUrl() {
|
|
6635
|
+
return this.agentRegistry.runtimeEndpointUrl;
|
|
6636
|
+
}
|
|
5688
6637
|
get ɵruntimeFetch() {
|
|
5689
6638
|
return this.agentRegistry.createRuntimeFetch();
|
|
5690
6639
|
}
|
|
@@ -5844,6 +6793,83 @@ var CopilotKitCore = class {
|
|
|
5844
6793
|
getAgent(id) {
|
|
5845
6794
|
return this.agentRegistry.getAgent(id);
|
|
5846
6795
|
}
|
|
6796
|
+
/** Updates settings for the next capture. Removing the config stops capture. */
|
|
6797
|
+
setLearningConfig(config) {
|
|
6798
|
+
const wasConfigured = this.ɵlearningConfigured;
|
|
6799
|
+
this.learningBridge.setConfig(config);
|
|
6800
|
+
this.notifyTrajectoryChanged();
|
|
6801
|
+
if (this.ɵlearningConfigured === wasConfigured) return;
|
|
6802
|
+
for (const listener of this.learningConfiguredListeners) try {
|
|
6803
|
+
listener();
|
|
6804
|
+
} catch (error) {
|
|
6805
|
+
console.error("Learning configured listener error:", error);
|
|
6806
|
+
}
|
|
6807
|
+
}
|
|
6808
|
+
/**
|
|
6809
|
+
* @internal Whether a `learning` config is set. Unlike {@link trajectoryId},
|
|
6810
|
+
* it does not change with capture start, connection failures or reconnects.
|
|
6811
|
+
*/
|
|
6812
|
+
get ɵlearningConfigured() {
|
|
6813
|
+
return this.learningBridge.isConfigured;
|
|
6814
|
+
}
|
|
6815
|
+
/** @internal Calls `listener` when {@link ɵlearningConfigured} changes. */
|
|
6816
|
+
ɵsubscribeToLearningConfigured(listener) {
|
|
6817
|
+
this.learningConfiguredListeners.add(listener);
|
|
6818
|
+
return () => {
|
|
6819
|
+
this.learningConfiguredListeners.delete(listener);
|
|
6820
|
+
};
|
|
6821
|
+
}
|
|
6822
|
+
/** The active capture's Trajectory ID, or null while capture is stopped. */
|
|
6823
|
+
get trajectoryId() {
|
|
6824
|
+
return this.learningBridge.trajectoryId;
|
|
6825
|
+
}
|
|
6826
|
+
notifyTrajectoryChanged() {
|
|
6827
|
+
const trajectoryId = this.trajectoryId;
|
|
6828
|
+
if (trajectoryId === this.notifiedTrajectoryId) return;
|
|
6829
|
+
this.notifiedTrajectoryId = trajectoryId;
|
|
6830
|
+
this.notifySubscribers((subscriber) => subscriber.onTrajectoryChanged?.({
|
|
6831
|
+
copilotkit: this,
|
|
6832
|
+
trajectoryId
|
|
6833
|
+
}), "Subscriber onTrajectoryChanged error:");
|
|
6834
|
+
}
|
|
6835
|
+
/**
|
|
6836
|
+
* Starts one Trajectory after Runtime authorization and the Gateway join.
|
|
6837
|
+
* Omit the ID to create one. Repeated starts await the active connection;
|
|
6838
|
+
* a different ID stops the previous capture. Explicit sinks retain the
|
|
6839
|
+
* prototype's synchronous capture and require a stop before changing IDs.
|
|
6840
|
+
*
|
|
6841
|
+
* @example copilotkit.startTrajectory({ trajectoryId: crypto.randomUUID() })
|
|
6842
|
+
*/
|
|
6843
|
+
startTrajectory(options = {}) {
|
|
6844
|
+
const result = this.learningBridge.start(options);
|
|
6845
|
+
this.notifyTrajectoryChanged();
|
|
6846
|
+
return result;
|
|
6847
|
+
}
|
|
6848
|
+
/** Cancels pending work and stops capture, attempting one final batch without waiting for its ACK. */
|
|
6849
|
+
stopTrajectory() {
|
|
6850
|
+
this.learningBridge.stop();
|
|
6851
|
+
this.notifyTrajectoryChanged();
|
|
6852
|
+
}
|
|
6853
|
+
/**
|
|
6854
|
+
* Records an outcome that clicks cannot show, such as a saved report or an
|
|
6855
|
+
* approved deal. The wire adds `value.seq`; arrays, primitives, and objects
|
|
6856
|
+
* already containing `seq` are preserved under `value.data`. Explicit legacy
|
|
6857
|
+
* sinks retain object-only events with open-Thread enrichment.
|
|
6858
|
+
* No-op while no Trajectory runs. Events emitted during connection recovery
|
|
6859
|
+
* count as dropped. Built-in names such as `click` are rejected.
|
|
6860
|
+
*
|
|
6861
|
+
* @example copilotkit.emitTrajectoryEvent("deal.approved", { dealId: "deal-1" })
|
|
6862
|
+
*/
|
|
6863
|
+
emitTrajectoryEvent(name, value = {}) {
|
|
6864
|
+
this.learningBridge.emit(name, value);
|
|
6865
|
+
}
|
|
6866
|
+
/**
|
|
6867
|
+
* Tells Core that a view shows this Thread, so captured interactions can link to it.
|
|
6868
|
+
* Framework bindings call this; call it yourself only without a CopilotKit provider.
|
|
6869
|
+
*/
|
|
6870
|
+
registerOpenThread(params) {
|
|
6871
|
+
return this.learningBridge.registerOpenThread(params);
|
|
6872
|
+
}
|
|
5847
6873
|
/**
|
|
5848
6874
|
* Re-apply the current headers to a single agent (delegated to
|
|
5849
6875
|
* AgentRegistry). Core headers are merged on top of the agent's own
|
|
@@ -7355,5 +8381,5 @@ function onInspectorViewThreadResult(handler) {
|
|
|
7355
8381
|
}
|
|
7356
8382
|
|
|
7357
8383
|
//#endregion
|
|
7358
|
-
export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID, IntelligenceAgent, MEMORY_ERROR_REGISTRY, MemoryError, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, WebMCPRegistry, completePartialMarkdown, createActionGroup, createEffect, createInspectorThreadRequestId, createReducer, createSelector, createStore, emitInspectorActiveThread, emitInspectorStopViewing, emitInspectorViewThread, emitInspectorViewThreadResult, empty, ensureObjectArgs, getWebMCPModelContext, isAbortError, isInspectorThreadBridgeEnabled, isRunCompletionAware, ofType, on, onInspectorActiveThread, onInspectorStopViewing, onInspectorViewThread, onInspectorViewThreadResult, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵInterruptState, ɵMAX_SOCKET_RETRIES, ɵRUNTIME_PROBE_TIMEOUT_MS, ɵTHREAD_REQUEST_TIMEOUT_MS, createMemoryStore as ɵcreateMemoryStore, ɵcreateThreadSelectors, createThreadStore as ɵcreateThreadStore, ɵisCopilotKitFeature, isRetryableStatus as ɵisRetryableMemoryStatus, ɵjoinPhoenixChannel$, ɵmapMemoryMetadataEvent, ɵmemoryAdapterEvents, ɵmemoryDomainEvents, ɵmemoryReducer, ɵmemoryRestEvents, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectFetchMoreError, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectIsMutating, ɵselectMemories, ɵselectMemoriesAvailable, ɵselectMemoriesError, ɵselectMemoriesIsLoading, ɵselectMemoriesIsMutating, ɵselectMemoriesRealtimeStatus, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
|
|
8384
|
+
export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID, IntelligenceAgent, MEMORY_ERROR_REGISTRY, MemoryError, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, WebMCPRegistry, completePartialMarkdown, createActionGroup, createEffect, createInspectorThreadRequestId, createReducer, createSelector, createStore, emitInspectorActiveThread, emitInspectorStopViewing, emitInspectorViewThread, emitInspectorViewThreadResult, empty, ensureObjectArgs, getWebMCPModelContext, isAbortError, isInspectorThreadBridgeEnabled, isRunCompletionAware, ofType, on, onInspectorActiveThread, onInspectorStopViewing, onInspectorViewThread, onInspectorViewThreadResult, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵInterruptState, ɵMAX_SOCKET_RETRIES, ɵRUNTIME_PROBE_TIMEOUT_MS, ɵTHREAD_REQUEST_TIMEOUT_MS, createMemoryStore as ɵcreateMemoryStore, ɵcreateThreadSelectors, createThreadStore as ɵcreateThreadStore, ɵisCopilotKitFeature, ɵisHttpAgent, isRetryableStatus as ɵisRetryableMemoryStatus, ɵjoinPhoenixChannel$, ɵmapMemoryMetadataEvent, ɵmemoryAdapterEvents, ɵmemoryDomainEvents, ɵmemoryReducer, ɵmemoryRestEvents, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectFetchMoreError, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectIsMutating, ɵselectMemories, ɵselectMemoriesAvailable, ɵselectMemoriesError, ɵselectMemoriesIsLoading, ɵselectMemoriesIsMutating, ɵselectMemoriesRealtimeStatus, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
|
|
7359
8385
|
//# sourceMappingURL=index.mjs.map
|