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