@copilotkit/core 1.56.0 → 1.56.2-canary.pin-to-send
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 +196 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -20
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +84 -20
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +196 -38
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +201 -43
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
let _tanstack_pacer = require("@tanstack/pacer");
|
|
2
3
|
let _ag_ui_client = require("@ag-ui/client");
|
|
3
4
|
let _copilotkit_shared = require("@copilotkit/shared");
|
|
4
5
|
let rxjs = require("rxjs");
|
|
@@ -138,7 +139,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
138
139
|
config;
|
|
139
140
|
socket = null;
|
|
140
141
|
activeChannel = null;
|
|
141
|
-
|
|
142
|
+
canonicalRunId = null;
|
|
142
143
|
sharedState;
|
|
143
144
|
constructor(config, sharedState = { lastSeenEventIds: /* @__PURE__ */ new Map() }) {
|
|
144
145
|
super();
|
|
@@ -176,7 +177,11 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
176
177
|
try {
|
|
177
178
|
this.isRunning = true;
|
|
178
179
|
this.agentId = this.agentId ?? (0, _ag_ui_client.randomUUID)();
|
|
179
|
-
const
|
|
180
|
+
const effectiveParameters = parameters?.runId || !this.canonicalRunId ? parameters : {
|
|
181
|
+
...parameters,
|
|
182
|
+
runId: this.canonicalRunId
|
|
183
|
+
};
|
|
184
|
+
const input = this.prepareRunAgentInput(effectiveParameters);
|
|
180
185
|
let result;
|
|
181
186
|
const previousMessageIds = new Set(this.messages.map((m) => m.id));
|
|
182
187
|
const subscribers = [
|
|
@@ -215,14 +220,14 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
215
220
|
}
|
|
216
221
|
}
|
|
217
222
|
abortRun() {
|
|
218
|
-
if (this.activeChannel && this.
|
|
223
|
+
if (this.activeChannel && this.canonicalRunId) {
|
|
219
224
|
const fallback = setTimeout(() => clear(), 5e3);
|
|
220
225
|
const clear = () => {
|
|
221
226
|
clearTimeout(fallback);
|
|
222
227
|
this.detachActiveRun();
|
|
223
228
|
this.cleanup();
|
|
224
229
|
};
|
|
225
|
-
this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.
|
|
230
|
+
this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.canonicalRunId }).receive("ok", clear).receive("error", clear).receive("timeout", clear);
|
|
226
231
|
} else {
|
|
227
232
|
this.detachActiveRun();
|
|
228
233
|
this.cleanup();
|
|
@@ -234,7 +239,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
234
239
|
*/
|
|
235
240
|
run(input) {
|
|
236
241
|
this.threadId = input.threadId;
|
|
237
|
-
this.
|
|
242
|
+
this.canonicalRunId = input.runId;
|
|
238
243
|
return (0, rxjs.defer)(() => this.requestJoinCredentials$("run", input)).pipe((0, rxjs.switchMap)((credentials) => this.observeThread$(input, credentials, {
|
|
239
244
|
completeOnRunError: false,
|
|
240
245
|
streamMode: "run"
|
|
@@ -246,16 +251,14 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
246
251
|
*/
|
|
247
252
|
connect(input) {
|
|
248
253
|
this.threadId = input.threadId;
|
|
249
|
-
this.
|
|
254
|
+
this.canonicalRunId = input.runId;
|
|
250
255
|
return (0, rxjs.defer)(() => this.requestConnectPlan$(input)).pipe((0, rxjs.switchMap)((plan) => {
|
|
251
256
|
if (plan === null) return rxjs.EMPTY;
|
|
252
257
|
if (plan.mode === "bootstrap") {
|
|
253
258
|
this.setLastSeenEventId(input.threadId, plan.latestEventId);
|
|
254
|
-
for (const event of plan.events) this.updateRunIdFromEvent(event);
|
|
255
259
|
return (0, rxjs.from)(plan.events);
|
|
256
260
|
}
|
|
257
261
|
this.setLastSeenEventId(input.threadId, plan.joinFromEventId);
|
|
258
|
-
for (const event of plan.events) this.updateRunIdFromEvent(event);
|
|
259
262
|
return (0, rxjs.concat)((0, rxjs.from)(plan.events), this.observeThread$(input, { joinToken: plan.joinToken }, {
|
|
260
263
|
completeOnRunError: true,
|
|
261
264
|
streamMode: "connect",
|
|
@@ -278,7 +281,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
278
281
|
if (this.socket === ownSocket) this.socket = null;
|
|
279
282
|
}
|
|
280
283
|
if (this.threadId) this.sharedState.lastSeenEventIds.delete(this.threadId);
|
|
281
|
-
this.
|
|
284
|
+
this.canonicalRunId = null;
|
|
282
285
|
}
|
|
283
286
|
cleanup() {
|
|
284
287
|
this.cleanupOwned(this.activeChannel, this.socket);
|
|
@@ -414,7 +417,6 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
414
417
|
observeThreadEvents$(threadId, channel$, options) {
|
|
415
418
|
return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), (0, rxjs_operators.tap)((payload) => {
|
|
416
419
|
this.updateLastSeenEventId(threadId, payload);
|
|
417
|
-
this.updateRunIdFromEvent(payload);
|
|
418
420
|
}), (0, rxjs_operators.mergeMap)((payload) => (0, rxjs.from)(this.createThreadNotifications(payload, options.completeOnRunError))), (0, rxjs.dematerialize)());
|
|
419
421
|
}
|
|
420
422
|
observeChannelEvent$(channel, eventName) {
|
|
@@ -464,23 +466,6 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
464
466
|
if (!eventId) return;
|
|
465
467
|
this.sharedState.lastSeenEventIds.set(threadId, eventId);
|
|
466
468
|
}
|
|
467
|
-
/**
|
|
468
|
-
* Keep `this.runId` in sync with the backend's actual run ID.
|
|
469
|
-
*
|
|
470
|
-
* During a `connect` (resume) flow the client generates a fresh `runId`
|
|
471
|
-
* via `prepareRunAgentInput`, but the backend is running under its own
|
|
472
|
-
* run ID. If the client later sends `STOP_RUN_EVENT` with the wrong
|
|
473
|
-
* `runId`, the gateway's runner channel will not match it and the agent
|
|
474
|
-
* keeps running. Extracting the run ID from live events fixes this.
|
|
475
|
-
*
|
|
476
|
-
* The runner normalises events to `run_id` (snake_case) before pushing
|
|
477
|
-
* to the gateway, so we check both `runId` and `run_id`.
|
|
478
|
-
*/
|
|
479
|
-
updateRunIdFromEvent(payload) {
|
|
480
|
-
const record = payload;
|
|
481
|
-
const eventRunId = record.runId ?? record.run_id;
|
|
482
|
-
if (typeof eventRunId === "string" && eventRunId.length > 0) this.runId = eventRunId;
|
|
483
|
-
}
|
|
484
469
|
readEventId(payload) {
|
|
485
470
|
const metadata = payload.metadata;
|
|
486
471
|
if (!metadata || typeof metadata !== "object") return null;
|
|
@@ -858,6 +843,7 @@ var AgentRegistry = class {
|
|
|
858
843
|
initialize(agents) {
|
|
859
844
|
this.localAgents = this.assignAgentIds(agents);
|
|
860
845
|
this.applyHeadersToAgents(this.localAgents);
|
|
846
|
+
this.applyCredentialsToAgents(this.localAgents);
|
|
861
847
|
this._agents = this.localAgents;
|
|
862
848
|
}
|
|
863
849
|
/**
|
|
@@ -887,6 +873,7 @@ var AgentRegistry = class {
|
|
|
887
873
|
...this.remoteAgents
|
|
888
874
|
};
|
|
889
875
|
this.applyHeadersToAgents(this._agents);
|
|
876
|
+
this.applyCredentialsToAgents(this._agents);
|
|
890
877
|
this.notifyAgentsChanged();
|
|
891
878
|
}
|
|
892
879
|
/**
|
|
@@ -896,6 +883,7 @@ var AgentRegistry = class {
|
|
|
896
883
|
this.validateAndAssignAgentId(id, agent);
|
|
897
884
|
this.localAgents[id] = agent;
|
|
898
885
|
this.applyHeadersToAgent(agent);
|
|
886
|
+
this.applyCredentialsToAgent(agent);
|
|
899
887
|
this._agents = {
|
|
900
888
|
...this.localAgents,
|
|
901
889
|
...this.remoteAgents
|
|
@@ -1956,7 +1944,7 @@ var RunHandler = class {
|
|
|
1956
1944
|
* Build frontend tools for an agent
|
|
1957
1945
|
*/
|
|
1958
1946
|
buildFrontendTools(agentId) {
|
|
1959
|
-
return this._tools.filter((tool) => tool.available !== false && (!tool.agentId || tool.agentId === agentId)).map((tool) => ({
|
|
1947
|
+
return this._tools.filter((tool) => tool.available !== false && tool.available !== "disabled" && (!tool.agentId || tool.agentId === agentId)).map((tool) => ({
|
|
1960
1948
|
name: tool.name,
|
|
1961
1949
|
description: tool.description ?? "",
|
|
1962
1950
|
parameters: createToolSchema(tool)
|
|
@@ -2306,8 +2294,21 @@ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode)
|
|
|
2306
2294
|
CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
|
|
2307
2295
|
CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
|
|
2308
2296
|
CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
|
|
2297
|
+
CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
|
|
2309
2298
|
return CopilotKitCoreErrorCode;
|
|
2310
2299
|
}({});
|
|
2300
|
+
/**
|
|
2301
|
+
* Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
|
|
2302
|
+
* to module scope so the Set is allocated once, not per-subscription.
|
|
2303
|
+
*/
|
|
2304
|
+
const ALLOWED_KEYS = new Set([
|
|
2305
|
+
"onMessagesChanged",
|
|
2306
|
+
"onStateChanged",
|
|
2307
|
+
"onRunInitialized",
|
|
2308
|
+
"onRunFinalized",
|
|
2309
|
+
"onRunFailed",
|
|
2310
|
+
"onRunErrorEvent"
|
|
2311
|
+
]);
|
|
2311
2312
|
let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
|
|
2312
2313
|
CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
|
|
2313
2314
|
CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
|
|
@@ -2373,6 +2374,16 @@ var CopilotKitCore = class {
|
|
|
2373
2374
|
}), "Subscriber onError error:");
|
|
2374
2375
|
}
|
|
2375
2376
|
/**
|
|
2377
|
+
* Log a message to the console and emit an error to subscribers.
|
|
2378
|
+
* Catches failures from `emitError` itself to prevent unhandled rejections.
|
|
2379
|
+
*/
|
|
2380
|
+
logAndEmitError(message, params, logLevel = "error") {
|
|
2381
|
+
console[logLevel](message, params.error);
|
|
2382
|
+
this.emitError(params).catch((emitErr) => {
|
|
2383
|
+
console.error(message + " — emitError itself failed:", emitErr);
|
|
2384
|
+
});
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2376
2387
|
* Snapshot accessors
|
|
2377
2388
|
*/
|
|
2378
2389
|
get context() {
|
|
@@ -2409,17 +2420,30 @@ var CopilotKitCore = class {
|
|
|
2409
2420
|
return this._properties;
|
|
2410
2421
|
}
|
|
2411
2422
|
/**
|
|
2412
|
-
* Default throttle interval (ms)
|
|
2413
|
-
*
|
|
2414
|
-
* `
|
|
2415
|
-
* or `<CopilotChat>` overrides this default and disables throttling.
|
|
2423
|
+
* Default throttle interval (ms) used by `subscribeToAgentWithOptions()`
|
|
2424
|
+
* when the caller does not specify an explicit `throttleMs`.
|
|
2425
|
+
* `undefined` means no default is configured; `0` means no throttling.
|
|
2416
2426
|
*/
|
|
2417
2427
|
get defaultThrottleMs() {
|
|
2418
2428
|
return this._defaultThrottleMs;
|
|
2419
2429
|
}
|
|
2430
|
+
/**
|
|
2431
|
+
* Set the default throttle interval (ms) for `subscribeToAgentWithOptions()`.
|
|
2432
|
+
*
|
|
2433
|
+
* Accepts a non-negative finite number or `undefined` (to clear the
|
|
2434
|
+
* default). Invalid values (NaN, Infinity, negative) are logged as
|
|
2435
|
+
* errors and ignored — the previous valid value is preserved.
|
|
2436
|
+
*/
|
|
2420
2437
|
setDefaultThrottleMs(value) {
|
|
2421
2438
|
if (value !== void 0 && (!Number.isFinite(value) || value < 0)) {
|
|
2422
|
-
this.
|
|
2439
|
+
this.logAndEmitError(`CopilotKitCore.setDefaultThrottleMs: value must be a non-negative finite number or undefined, got ${value}. Keeping current value (${this._defaultThrottleMs}).`, {
|
|
2440
|
+
error: /* @__PURE__ */ new Error(`setDefaultThrottleMs: invalid value (${value}), keeping current value (${this._defaultThrottleMs})`),
|
|
2441
|
+
code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
|
|
2442
|
+
context: {
|
|
2443
|
+
value,
|
|
2444
|
+
currentValue: this._defaultThrottleMs
|
|
2445
|
+
}
|
|
2446
|
+
});
|
|
2423
2447
|
return;
|
|
2424
2448
|
}
|
|
2425
2449
|
this._defaultThrottleMs = value;
|
|
@@ -2540,6 +2564,137 @@ var CopilotKitCore = class {
|
|
|
2540
2564
|
} };
|
|
2541
2565
|
}
|
|
2542
2566
|
/**
|
|
2567
|
+
* Subscribe to an agent's notification and lifecycle events with
|
|
2568
|
+
* optional configuration (e.g. throttling).
|
|
2569
|
+
*
|
|
2570
|
+
* Wraps every callback with error protection (`safeCall`) and applies
|
|
2571
|
+
* the options before delegating to `agent.subscribe()`.
|
|
2572
|
+
*
|
|
2573
|
+
* See {@link SubscribeToAgentSubscriber} for the accepted callback subset
|
|
2574
|
+
* and the rationale for excluding AG-UI event handlers.
|
|
2575
|
+
*/
|
|
2576
|
+
subscribeToAgentWithOptions(agent, subscriber, options) {
|
|
2577
|
+
const resolved = options?.throttleMs ?? this._defaultThrottleMs ?? 0;
|
|
2578
|
+
let effectiveMs = 0;
|
|
2579
|
+
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
2580
|
+
const source = options?.throttleMs !== void 0 ? "throttleMs" : "defaultThrottleMs";
|
|
2581
|
+
this.logAndEmitError(`CopilotKitCore.subscribeToAgentWithOptions: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`, {
|
|
2582
|
+
error: /* @__PURE__ */ new Error(`subscribeToAgentWithOptions: invalid ${source} (${resolved}), falling back to unthrottled`),
|
|
2583
|
+
code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
|
|
2584
|
+
context: {
|
|
2585
|
+
agentId: agent.agentId,
|
|
2586
|
+
source,
|
|
2587
|
+
value: resolved
|
|
2588
|
+
}
|
|
2589
|
+
});
|
|
2590
|
+
} else effectiveMs = resolved;
|
|
2591
|
+
const agentLabel = agent.agentId || "(unknown agent)";
|
|
2592
|
+
const safeCall = (label, fn, ...args) => {
|
|
2593
|
+
const reportError = (err, verb) => {
|
|
2594
|
+
this.logAndEmitError(`CopilotKitCore.subscribeToAgentWithOptions[${agentLabel}]: ${label} callback ${verb}:`, {
|
|
2595
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
2596
|
+
code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
|
|
2597
|
+
context: {
|
|
2598
|
+
agentId: agent.agentId,
|
|
2599
|
+
callback: label
|
|
2600
|
+
}
|
|
2601
|
+
});
|
|
2602
|
+
};
|
|
2603
|
+
try {
|
|
2604
|
+
const result = fn(...args);
|
|
2605
|
+
if (result instanceof Promise) return result.catch((err) => {
|
|
2606
|
+
reportError(err, "rejected");
|
|
2607
|
+
});
|
|
2608
|
+
return result;
|
|
2609
|
+
} catch (err) {
|
|
2610
|
+
reportError(err, "threw");
|
|
2611
|
+
}
|
|
2612
|
+
};
|
|
2613
|
+
const guardAll = (sub) => {
|
|
2614
|
+
const guarded = {};
|
|
2615
|
+
if (sub.onMessagesChanged) {
|
|
2616
|
+
const fn = sub.onMessagesChanged;
|
|
2617
|
+
guarded.onMessagesChanged = (params) => safeCall("onMessagesChanged", fn, params);
|
|
2618
|
+
}
|
|
2619
|
+
if (sub.onStateChanged) {
|
|
2620
|
+
const fn = sub.onStateChanged;
|
|
2621
|
+
guarded.onStateChanged = (params) => safeCall("onStateChanged", fn, params);
|
|
2622
|
+
}
|
|
2623
|
+
if (sub.onRunInitialized) {
|
|
2624
|
+
const fn = sub.onRunInitialized;
|
|
2625
|
+
guarded.onRunInitialized = (params) => safeCall("onRunInitialized", fn, params);
|
|
2626
|
+
}
|
|
2627
|
+
if (sub.onRunFinalized) {
|
|
2628
|
+
const fn = sub.onRunFinalized;
|
|
2629
|
+
guarded.onRunFinalized = (params) => safeCall("onRunFinalized", fn, params);
|
|
2630
|
+
}
|
|
2631
|
+
if (sub.onRunFailed) {
|
|
2632
|
+
const fn = sub.onRunFailed;
|
|
2633
|
+
guarded.onRunFailed = (params) => safeCall("onRunFailed", fn, params);
|
|
2634
|
+
}
|
|
2635
|
+
if (sub.onRunErrorEvent) {
|
|
2636
|
+
const fn = sub.onRunErrorEvent;
|
|
2637
|
+
guarded.onRunErrorEvent = (params) => safeCall("onRunErrorEvent", fn, params);
|
|
2638
|
+
}
|
|
2639
|
+
return guarded;
|
|
2640
|
+
};
|
|
2641
|
+
for (const key of Object.keys(subscriber)) if (typeof subscriber[key] === "function" && !ALLOWED_KEYS.has(key)) {
|
|
2642
|
+
const message = `CopilotKitCore.subscribeToAgentWithOptions[${agentLabel}]: callback "${key}" is not supported and was dropped. Supported callbacks: ${Array.from(ALLOWED_KEYS).join(", ")}. Use agent.subscribe() directly for event handlers and per-item notifications.`;
|
|
2643
|
+
this.logAndEmitError(message, {
|
|
2644
|
+
error: new Error(message),
|
|
2645
|
+
code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
|
|
2646
|
+
context: {
|
|
2647
|
+
agentId: agent.agentId,
|
|
2648
|
+
droppedCallback: key
|
|
2649
|
+
}
|
|
2650
|
+
}, "warn");
|
|
2651
|
+
}
|
|
2652
|
+
if (effectiveMs <= 0) {
|
|
2653
|
+
const subscription = agent.subscribe(guardAll(subscriber));
|
|
2654
|
+
return { unsubscribe: () => subscription.unsubscribe() };
|
|
2655
|
+
}
|
|
2656
|
+
let active = true;
|
|
2657
|
+
let latestMessagesParams = null;
|
|
2658
|
+
let latestStateParams = null;
|
|
2659
|
+
const flushPending = () => {
|
|
2660
|
+
if (active && subscriber.onMessagesChanged && latestMessagesParams) {
|
|
2661
|
+
const params = latestMessagesParams;
|
|
2662
|
+
latestMessagesParams = null;
|
|
2663
|
+
safeCall("onMessagesChanged", subscriber.onMessagesChanged, params);
|
|
2664
|
+
}
|
|
2665
|
+
if (active && subscriber.onStateChanged && latestStateParams) {
|
|
2666
|
+
const params = latestStateParams;
|
|
2667
|
+
latestStateParams = null;
|
|
2668
|
+
safeCall("onStateChanged", subscriber.onStateChanged, params);
|
|
2669
|
+
}
|
|
2670
|
+
};
|
|
2671
|
+
const throttler = new _tanstack_pacer.Throttler(flushPending, {
|
|
2672
|
+
wait: effectiveMs,
|
|
2673
|
+
leading: true,
|
|
2674
|
+
trailing: true
|
|
2675
|
+
});
|
|
2676
|
+
const lifecycleOnly = {};
|
|
2677
|
+
if (subscriber.onRunInitialized) lifecycleOnly.onRunInitialized = subscriber.onRunInitialized;
|
|
2678
|
+
if (subscriber.onRunFinalized) lifecycleOnly.onRunFinalized = subscriber.onRunFinalized;
|
|
2679
|
+
if (subscriber.onRunFailed) lifecycleOnly.onRunFailed = subscriber.onRunFailed;
|
|
2680
|
+
if (subscriber.onRunErrorEvent) lifecycleOnly.onRunErrorEvent = subscriber.onRunErrorEvent;
|
|
2681
|
+
const wrappedSubscriber = guardAll(lifecycleOnly);
|
|
2682
|
+
if (subscriber.onMessagesChanged) wrappedSubscriber.onMessagesChanged = (params) => {
|
|
2683
|
+
latestMessagesParams = params;
|
|
2684
|
+
throttler.maybeExecute();
|
|
2685
|
+
};
|
|
2686
|
+
if (subscriber.onStateChanged) wrappedSubscriber.onStateChanged = (params) => {
|
|
2687
|
+
latestStateParams = params;
|
|
2688
|
+
throttler.maybeExecute();
|
|
2689
|
+
};
|
|
2690
|
+
const subscription = agent.subscribe(wrappedSubscriber);
|
|
2691
|
+
return { unsubscribe: () => {
|
|
2692
|
+
active = false;
|
|
2693
|
+
throttler.cancel();
|
|
2694
|
+
subscription.unsubscribe();
|
|
2695
|
+
} };
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2543
2698
|
* Agent connectivity (delegated to RunHandler)
|
|
2544
2699
|
*/
|
|
2545
2700
|
async connectAgent(params) {
|
|
@@ -3086,15 +3241,18 @@ const threadDomainEvents = createActionGroup("Thread Domain", {
|
|
|
3086
3241
|
threadUpserted: props(),
|
|
3087
3242
|
threadDeleted: props()
|
|
3088
3243
|
});
|
|
3089
|
-
function
|
|
3090
|
-
return [...threads].sort((left, right) =>
|
|
3244
|
+
function sortThreadsByRecency(threads) {
|
|
3245
|
+
return [...threads].sort((left, right) => {
|
|
3246
|
+
const leftKey = left.lastRunAt ?? left.updatedAt ?? left.createdAt;
|
|
3247
|
+
return (right.lastRunAt ?? right.updatedAt ?? right.createdAt).localeCompare(leftKey);
|
|
3248
|
+
});
|
|
3091
3249
|
}
|
|
3092
3250
|
function upsertThread(threads, thread) {
|
|
3093
3251
|
const existingIndex = threads.findIndex((item) => item.id === thread.id);
|
|
3094
|
-
if (existingIndex === -1) return
|
|
3252
|
+
if (existingIndex === -1) return sortThreadsByRecency([...threads, thread]);
|
|
3095
3253
|
const next = [...threads];
|
|
3096
3254
|
next[existingIndex] = thread;
|
|
3097
|
-
return
|
|
3255
|
+
return sortThreadsByRecency(next);
|
|
3098
3256
|
}
|
|
3099
3257
|
const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
|
|
3100
3258
|
...state,
|
|
@@ -3127,7 +3285,7 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3127
3285
|
if (sessionId !== state.sessionId) return state;
|
|
3128
3286
|
return {
|
|
3129
3287
|
...state,
|
|
3130
|
-
threads:
|
|
3288
|
+
threads: sortThreadsByRecency(threads),
|
|
3131
3289
|
isLoading: false,
|
|
3132
3290
|
error: null,
|
|
3133
3291
|
metadataJoinCode: joinCode,
|