@copilotkit/core 1.62.1 → 1.62.2-canary.1784333495
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 +1766 -729
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +525 -4
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +525 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1758 -738
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1767 -727
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -131,6 +131,7 @@ const CLIENT_AG_UI_EVENT = "ag_ui_event";
|
|
|
131
131
|
const REPLAY_COMPLETE_EVENT = "replay_complete";
|
|
132
132
|
const STREAM_IDLE_EVENT = "stream_idle";
|
|
133
133
|
const STOP_RUN_EVENT = "stop_run";
|
|
134
|
+
const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
|
|
134
135
|
var AgentThreadLockedError = class extends Error {
|
|
135
136
|
constructor(threadId) {
|
|
136
137
|
super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
|
|
@@ -280,12 +281,14 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
280
281
|
connect(input) {
|
|
281
282
|
this.threadId = input.threadId;
|
|
282
283
|
this.canonicalRunId = null;
|
|
283
|
-
|
|
284
|
+
const replayCursor = this.getReconnectCursor(input);
|
|
285
|
+
return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input, replayCursor)).pipe((0, rxjs.switchMap)((credentials) => {
|
|
284
286
|
if (credentials === null) return rxjs.EMPTY;
|
|
285
287
|
const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: false });
|
|
286
288
|
return this.observeThread$(canonicalInput, credentials, {
|
|
287
289
|
completeOnRunError: false,
|
|
288
|
-
streamMode: "connect"
|
|
290
|
+
streamMode: "connect",
|
|
291
|
+
replayCursor
|
|
289
292
|
});
|
|
290
293
|
}));
|
|
291
294
|
}
|
|
@@ -308,7 +311,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
308
311
|
cleanup() {
|
|
309
312
|
this.cleanupOwned(this.activeChannel, this.socket);
|
|
310
313
|
}
|
|
311
|
-
requestJoinCredentials$(mode, input) {
|
|
314
|
+
requestJoinCredentials$(mode, input, replayCursor) {
|
|
312
315
|
return (0, rxjs.defer)(async () => {
|
|
313
316
|
try {
|
|
314
317
|
const response = await fetch(this.buildRuntimeUrl(mode), {
|
|
@@ -325,7 +328,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
325
328
|
context: input.context,
|
|
326
329
|
state: input.state,
|
|
327
330
|
forwardedProps: input.forwardedProps,
|
|
328
|
-
...mode === "connect" ? { lastSeenEventId: this.getReconnectCursor(input) } : {}
|
|
331
|
+
...mode === "connect" ? { lastSeenEventId: replayCursor === void 0 ? this.getReconnectCursor(input) : replayCursor } : {}
|
|
329
332
|
}),
|
|
330
333
|
...this.config.credentials ? { credentials: this.config.credentials } : {}
|
|
331
334
|
});
|
|
@@ -361,10 +364,11 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
361
364
|
observeThread$(input, credentials, options) {
|
|
362
365
|
return this.observeThreadSession$(input, credentials, options).pipe((0, rxjs_operators.catchError)((error) => {
|
|
363
366
|
if (!this.isSocketReconnectExhaustedError(error)) return (0, rxjs.throwError)(() => error);
|
|
364
|
-
|
|
367
|
+
const replayCursor = this.getReconnectCursor(input);
|
|
368
|
+
return this.requestJoinCredentials$("connect", input, replayCursor).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
|
|
365
369
|
...options,
|
|
366
370
|
channelMode: "connect",
|
|
367
|
-
replayCursor
|
|
371
|
+
replayCursor
|
|
368
372
|
})));
|
|
369
373
|
}));
|
|
370
374
|
}
|
|
@@ -401,15 +405,23 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
401
405
|
bufferSize: 1,
|
|
402
406
|
refCount: true
|
|
403
407
|
}));
|
|
404
|
-
const
|
|
405
|
-
|
|
408
|
+
const reconnectCursor = this.readDurableEventId(options.replayCursor ?? this.getReconnectCursor(input));
|
|
409
|
+
let latestObservedReplayCursor = null;
|
|
410
|
+
const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.tap)((payload) => {
|
|
411
|
+
latestObservedReplayCursor = this.readEventId(payload) ?? latestObservedReplayCursor;
|
|
412
|
+
}), (0, rxjs_operators.share)());
|
|
413
|
+
const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.shareReplay)({
|
|
414
|
+
bufferSize: 1,
|
|
415
|
+
refCount: true
|
|
416
|
+
}));
|
|
406
417
|
const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT).pipe((0, rxjs_operators.shareReplay)({
|
|
407
418
|
bufferSize: 1,
|
|
408
419
|
refCount: true
|
|
409
420
|
}));
|
|
410
|
-
const streamIdleCompletion$ = options.streamMode === "connect" ? streamIdle$.pipe((0, rxjs_operators.take)(1)) : rxjs.EMPTY;
|
|
411
|
-
const
|
|
412
|
-
|
|
421
|
+
const streamIdleCompletion$ = options.streamMode === "connect" ? (0, rxjs.merge)((0, rxjs.combineLatest)([replayComplete$.pipe((0, rxjs_operators.take)(1)), streamIdle$.pipe((0, rxjs_operators.take)(1))]), streamIdle$.pipe((0, rxjs_operators.take)(1), (0, rxjs_operators.filter)((payload) => this.canFallbackCompleteConnect(payload, reconnectCursor, latestObservedReplayCursor)), (0, rxjs_operators.delay)(CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS))).pipe((0, rxjs_operators.take)(1)) : rxjs.EMPTY;
|
|
422
|
+
const threadCompleted$ = threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1));
|
|
423
|
+
const terminal$ = (0, rxjs.merge)(threadCompleted$, streamIdleCompletion$);
|
|
424
|
+
return (0, rxjs.merge)(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$).pipe((0, rxjs_operators.takeUntil)(terminal$)), threadEvents$.pipe((0, rxjs_operators.takeUntil)(streamIdleCompletion$)), replayComplete$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(terminal$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(threadCompleted$))).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
|
|
413
425
|
});
|
|
414
426
|
}
|
|
415
427
|
joinThreadChannel$(channel$) {
|
|
@@ -475,23 +487,36 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
|
|
|
475
487
|
updateLastSeenEventId(threadId, payload) {
|
|
476
488
|
const eventId = this.readEventId(payload);
|
|
477
489
|
if (!eventId) return;
|
|
478
|
-
this.
|
|
490
|
+
this.advanceLastSeenEventId(threadId, eventId);
|
|
479
491
|
}
|
|
480
492
|
updateLastSeenEventIdFromControl(threadId, payload) {
|
|
481
493
|
const eventId = this.readControlEventId(payload);
|
|
482
494
|
if (!eventId) return;
|
|
495
|
+
this.advanceLastSeenEventId(threadId, eventId);
|
|
496
|
+
}
|
|
497
|
+
advanceLastSeenEventId(threadId, eventId) {
|
|
483
498
|
this.sharedState.lastSeenEventIds.set(threadId, eventId);
|
|
484
499
|
}
|
|
485
500
|
readEventId(payload) {
|
|
486
501
|
const metadata = payload.metadata;
|
|
487
502
|
if (!metadata || typeof metadata !== "object") return null;
|
|
488
|
-
const
|
|
489
|
-
return
|
|
503
|
+
const eventMetadata = metadata;
|
|
504
|
+
return this.readDurableEventId(eventMetadata.cpki_event_id);
|
|
490
505
|
}
|
|
491
506
|
readControlEventId(payload) {
|
|
492
507
|
if (!payload || typeof payload !== "object") return null;
|
|
493
|
-
const
|
|
494
|
-
|
|
508
|
+
const controlPayload = payload;
|
|
509
|
+
const latestEventId = controlPayload.latestEventId ?? controlPayload.latest_event_id;
|
|
510
|
+
return this.readDurableEventId(latestEventId);
|
|
511
|
+
}
|
|
512
|
+
readDurableEventId(eventId) {
|
|
513
|
+
if (typeof eventId !== "string" || eventId.trim() === "") return null;
|
|
514
|
+
return eventId.startsWith("cpki_ingested") ? null : eventId;
|
|
515
|
+
}
|
|
516
|
+
canFallbackCompleteConnect(streamIdlePayload, reconnectCursor, latestObservedReplayCursor) {
|
|
517
|
+
const idleCursor = this.readControlEventId(streamIdlePayload);
|
|
518
|
+
if (!idleCursor) return true;
|
|
519
|
+
return idleCursor === reconnectCursor || idleCursor === latestObservedReplayCursor;
|
|
495
520
|
}
|
|
496
521
|
applyCanonicalRunIdentity(input, credentials, options) {
|
|
497
522
|
this.threadId = credentials.threadId;
|
|
@@ -1660,7 +1685,9 @@ var RunHandler = class {
|
|
|
1660
1685
|
* downstream churn into duplicate `cpki_event_id` rows in the
|
|
1661
1686
|
* inspector and intermittent "Message not found" toasts.
|
|
1662
1687
|
*/
|
|
1663
|
-
|
|
1688
|
+
_lastConnectedThreadIdsByAgent = /* @__PURE__ */ new Map();
|
|
1689
|
+
_anonymousAgentIds = /* @__PURE__ */ new WeakMap();
|
|
1690
|
+
_nextAnonymousAgentId = 0;
|
|
1664
1691
|
constructor(core) {
|
|
1665
1692
|
this.core = core;
|
|
1666
1693
|
}
|
|
@@ -1680,6 +1707,20 @@ var RunHandler = class {
|
|
|
1680
1707
|
return this.core;
|
|
1681
1708
|
}
|
|
1682
1709
|
/**
|
|
1710
|
+
* Return a stable restore-tracking key for the logical agent being
|
|
1711
|
+
* connected. Named agents share their last-thread marker across proxy
|
|
1712
|
+
* instances; anonymous agents fall back to object identity.
|
|
1713
|
+
*/
|
|
1714
|
+
getConnectRestoreKey(agent) {
|
|
1715
|
+
if (agent.agentId) return `agent:${agent.agentId}`;
|
|
1716
|
+
const existing = this._anonymousAgentIds.get(agent);
|
|
1717
|
+
if (existing) return existing;
|
|
1718
|
+
const anonymousId = `anonymous:${this._nextAnonymousAgentId}`;
|
|
1719
|
+
this._nextAnonymousAgentId += 1;
|
|
1720
|
+
this._anonymousAgentIds.set(agent, anonymousId);
|
|
1721
|
+
return anonymousId;
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1683
1724
|
* Get all tools as a readonly array
|
|
1684
1725
|
*/
|
|
1685
1726
|
get tools() {
|
|
@@ -1735,14 +1776,18 @@ var RunHandler = class {
|
|
|
1735
1776
|
async connectAgent({ agent }) {
|
|
1736
1777
|
try {
|
|
1737
1778
|
const incomingThreadId = agent.threadId ?? null;
|
|
1738
|
-
const
|
|
1739
|
-
this.
|
|
1779
|
+
const restoreKey = this.getConnectRestoreKey(agent);
|
|
1780
|
+
const isFreshRestore = incomingThreadId !== (this._lastConnectedThreadIdsByAgent.get(restoreKey) ?? null);
|
|
1781
|
+
this._lastConnectedThreadIdsByAgent.set(restoreKey, incomingThreadId);
|
|
1740
1782
|
await agent.detachActiveRun();
|
|
1741
1783
|
if (isFreshRestore) {
|
|
1742
1784
|
agent.setMessages([]);
|
|
1743
1785
|
agent.setState({});
|
|
1744
|
-
const
|
|
1745
|
-
if (incomingThreadId
|
|
1786
|
+
const cursorAware = agent;
|
|
1787
|
+
if (incomingThreadId) {
|
|
1788
|
+
if (typeof cursorAware.clearReplayCursor === "function") cursorAware.clearReplayCursor(incomingThreadId);
|
|
1789
|
+
if (typeof cursorAware.clearReconnectCursor === "function") cursorAware.clearReconnectCursor(incomingThreadId);
|
|
1790
|
+
}
|
|
1746
1791
|
}
|
|
1747
1792
|
this._internal.applyHeadersToAgent(agent);
|
|
1748
1793
|
await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
|
|
@@ -1756,7 +1801,8 @@ var RunHandler = class {
|
|
|
1756
1801
|
}, this.createAgentErrorSubscriber(agent));
|
|
1757
1802
|
return this.processAgentResult({
|
|
1758
1803
|
runAgentResult,
|
|
1759
|
-
agent
|
|
1804
|
+
agent,
|
|
1805
|
+
executeFrontendTools: false
|
|
1760
1806
|
});
|
|
1761
1807
|
} catch (error) {
|
|
1762
1808
|
const connectError = error instanceof Error ? error : new Error(String(error));
|
|
@@ -1778,7 +1824,7 @@ var RunHandler = class {
|
|
|
1778
1824
|
/**
|
|
1779
1825
|
* Run an agent
|
|
1780
1826
|
*/
|
|
1781
|
-
async runAgent({ agent, forwardedProps, resume }) {
|
|
1827
|
+
async runAgent({ agent, forwardedProps, resume, runId }) {
|
|
1782
1828
|
if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
|
|
1783
1829
|
this._internal.applyHeadersToAgent(agent);
|
|
1784
1830
|
if (agent.detachActiveRun) await agent.detachActiveRun();
|
|
@@ -1805,6 +1851,7 @@ var RunHandler = class {
|
|
|
1805
1851
|
...forwardedProps
|
|
1806
1852
|
},
|
|
1807
1853
|
...resume !== void 0 ? { resume } : {},
|
|
1854
|
+
...runId !== void 0 ? { runId } : {},
|
|
1808
1855
|
tools: this.buildFrontendTools(agent.agentId),
|
|
1809
1856
|
context: this._internal.getContextForAgent(agent.agentId)
|
|
1810
1857
|
}, this.createAgentErrorSubscriber(agent));
|
|
@@ -1833,25 +1880,27 @@ var RunHandler = class {
|
|
|
1833
1880
|
/**
|
|
1834
1881
|
* Process agent result and execute tools
|
|
1835
1882
|
*/
|
|
1836
|
-
async processAgentResult({ runAgentResult, agent }) {
|
|
1883
|
+
async processAgentResult({ runAgentResult, agent, executeFrontendTools = true }) {
|
|
1837
1884
|
const { newMessages } = runAgentResult;
|
|
1838
1885
|
const agentId = agent.agentId;
|
|
1839
1886
|
let needsFollowUp = false;
|
|
1840
|
-
|
|
1841
|
-
for (const
|
|
1842
|
-
const tool
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
});
|
|
1846
|
-
if (tool) {
|
|
1847
|
-
if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
|
|
1848
|
-
} else {
|
|
1849
|
-
const wildcardTool = this.getTool({
|
|
1850
|
-
toolName: "*",
|
|
1887
|
+
if (executeFrontendTools) {
|
|
1888
|
+
for (const message of newMessages) if (message.role === "assistant") {
|
|
1889
|
+
for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
|
|
1890
|
+
const tool = this.getTool({
|
|
1891
|
+
toolName: toolCall.function.name,
|
|
1851
1892
|
agentId: agent.agentId
|
|
1852
1893
|
});
|
|
1853
|
-
if (
|
|
1854
|
-
if (await this.
|
|
1894
|
+
if (tool) {
|
|
1895
|
+
if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
|
|
1896
|
+
} else {
|
|
1897
|
+
const wildcardTool = this.getTool({
|
|
1898
|
+
toolName: "*",
|
|
1899
|
+
agentId: agent.agentId
|
|
1900
|
+
});
|
|
1901
|
+
if (wildcardTool) {
|
|
1902
|
+
if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
|
|
1903
|
+
}
|
|
1855
1904
|
}
|
|
1856
1905
|
}
|
|
1857
1906
|
}
|
|
@@ -2461,6 +2510,124 @@ var StateManager = class {
|
|
|
2461
2510
|
}
|
|
2462
2511
|
};
|
|
2463
2512
|
|
|
2513
|
+
//#endregion
|
|
2514
|
+
//#region src/core/subagent-registry.ts
|
|
2515
|
+
/**
|
|
2516
|
+
* Tracks subagent lifecycle events (SUBAGENT_STARTED / FINISHED / ERROR) per
|
|
2517
|
+
* owning agent so consumers can resolve a message's `subagentId` to a name,
|
|
2518
|
+
* description, and running status.
|
|
2519
|
+
*
|
|
2520
|
+
* Modeled on {@link SuggestionEngine}: an in-memory `Record` keyed by (owning)
|
|
2521
|
+
* agentId, mutated from streamed AG-UI events, made reactive by calling
|
|
2522
|
+
* `notifySubscribers(onSubagentsChanged)` after every change. It owns its own
|
|
2523
|
+
* per-agent `agent.subscribe` (like {@link StateManager}) so it is fully
|
|
2524
|
+
* self-contained and adds no coupling to the state/message tracking path.
|
|
2525
|
+
*
|
|
2526
|
+
* No-op for runs without subagents (a normal LangGraph run never emits
|
|
2527
|
+
* SUBAGENT_* events), so the registry simply stays empty.
|
|
2528
|
+
*/
|
|
2529
|
+
var SubagentRegistry = class {
|
|
2530
|
+
_subagents = {};
|
|
2531
|
+
agentSubscriptions = /* @__PURE__ */ new Map();
|
|
2532
|
+
constructor(core) {
|
|
2533
|
+
this.core = core;
|
|
2534
|
+
}
|
|
2535
|
+
/**
|
|
2536
|
+
* Subscribe to an agent's subagent lifecycle events. Idempotent per agentId:
|
|
2537
|
+
* an existing subscription for the same agent is revoked and replaced.
|
|
2538
|
+
*/
|
|
2539
|
+
subscribeToAgent(agent) {
|
|
2540
|
+
if (!agent.agentId) return;
|
|
2541
|
+
const agentId = agent.agentId;
|
|
2542
|
+
const existingUnsubscribe = this.agentSubscriptions.get(agentId);
|
|
2543
|
+
if (existingUnsubscribe) {
|
|
2544
|
+
existingUnsubscribe();
|
|
2545
|
+
this.agentSubscriptions.delete(agentId);
|
|
2546
|
+
}
|
|
2547
|
+
let revoked = false;
|
|
2548
|
+
const { unsubscribe } = agent.subscribe({
|
|
2549
|
+
onSubagentStartedEvent: ({ event }) => {
|
|
2550
|
+
if (revoked) return;
|
|
2551
|
+
this.handleStarted(agentId, event);
|
|
2552
|
+
},
|
|
2553
|
+
onSubagentFinishedEvent: ({ event }) => {
|
|
2554
|
+
if (revoked) return;
|
|
2555
|
+
this.handleFinished(agentId, event);
|
|
2556
|
+
},
|
|
2557
|
+
onSubagentErrorEvent: ({ event }) => {
|
|
2558
|
+
if (revoked) return;
|
|
2559
|
+
this.handleError(agentId, event);
|
|
2560
|
+
}
|
|
2561
|
+
});
|
|
2562
|
+
this.agentSubscriptions.set(agentId, () => {
|
|
2563
|
+
revoked = true;
|
|
2564
|
+
unsubscribe();
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
/**
|
|
2568
|
+
* Unsubscribe an agent's subscription (symmetric with StateManager cleanup).
|
|
2569
|
+
*/
|
|
2570
|
+
unsubscribeFromAgent(agentId) {
|
|
2571
|
+
const unsubscribe = this.agentSubscriptions.get(agentId);
|
|
2572
|
+
if (unsubscribe) {
|
|
2573
|
+
unsubscribe();
|
|
2574
|
+
this.agentSubscriptions.delete(agentId);
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* Get the subagents observed for an owning agent, keyed by subagentId.
|
|
2579
|
+
* Returns a fresh shallow copy each call so consumers (and React state) see
|
|
2580
|
+
* a new reference when anything changed.
|
|
2581
|
+
*/
|
|
2582
|
+
getSubagents(agentId) {
|
|
2583
|
+
return { ...this._subagents[agentId] };
|
|
2584
|
+
}
|
|
2585
|
+
handleStarted(agentId, event) {
|
|
2586
|
+
const bucket = this._subagents[agentId] ??= {};
|
|
2587
|
+
bucket[event.subagentId] = {
|
|
2588
|
+
subagentId: event.subagentId,
|
|
2589
|
+
name: event.name,
|
|
2590
|
+
description: event.description,
|
|
2591
|
+
parentSubagentId: event.parentSubagentId,
|
|
2592
|
+
status: "running"
|
|
2593
|
+
};
|
|
2594
|
+
this.notifySubagentsChanged(agentId);
|
|
2595
|
+
}
|
|
2596
|
+
handleFinished(agentId, event) {
|
|
2597
|
+
const bucket = this._subagents[agentId];
|
|
2598
|
+
const existing = bucket?.[event.subagentId];
|
|
2599
|
+
if (!bucket || !existing) return;
|
|
2600
|
+
bucket[event.subagentId] = {
|
|
2601
|
+
...existing,
|
|
2602
|
+
status: "finished"
|
|
2603
|
+
};
|
|
2604
|
+
this.notifySubagentsChanged(agentId);
|
|
2605
|
+
}
|
|
2606
|
+
handleError(agentId, event) {
|
|
2607
|
+
const bucket = this._subagents[agentId] ??= {};
|
|
2608
|
+
const existing = bucket[event.subagentId];
|
|
2609
|
+
bucket[event.subagentId] = existing ? {
|
|
2610
|
+
...existing,
|
|
2611
|
+
status: "error",
|
|
2612
|
+
error: event.message
|
|
2613
|
+
} : {
|
|
2614
|
+
subagentId: event.subagentId,
|
|
2615
|
+
name: event.subagentId,
|
|
2616
|
+
status: "error",
|
|
2617
|
+
error: event.message
|
|
2618
|
+
};
|
|
2619
|
+
this.notifySubagentsChanged(agentId);
|
|
2620
|
+
}
|
|
2621
|
+
async notifySubagentsChanged(agentId) {
|
|
2622
|
+
const subagents = this.getSubagents(agentId);
|
|
2623
|
+
await this.core.notifySubscribers((subscriber) => subscriber.onSubagentsChanged?.({
|
|
2624
|
+
copilotkit: this.core,
|
|
2625
|
+
agentId,
|
|
2626
|
+
subagents
|
|
2627
|
+
}), "Subscriber onSubagentsChanged error:");
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
|
|
2464
2631
|
//#endregion
|
|
2465
2632
|
//#region src/core/thread-store-registry.ts
|
|
2466
2633
|
var ThreadStoreRegistry = class {
|
|
@@ -2517,210 +2684,1204 @@ var ThreadStoreRegistry = class {
|
|
|
2517
2684
|
};
|
|
2518
2685
|
|
|
2519
2686
|
//#endregion
|
|
2520
|
-
//#region src/
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
|
|
2528
|
-
CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
|
|
2529
|
-
CopilotKitCoreErrorCode["TOOL_NOT_FOUND"] = "tool_not_found";
|
|
2530
|
-
CopilotKitCoreErrorCode["AGENT_NOT_FOUND"] = "agent_not_found";
|
|
2531
|
-
/**
|
|
2532
|
-
* Emitted when an agent run fails because the thread is already locked
|
|
2533
|
-
* by another active run.
|
|
2534
|
-
*
|
|
2535
|
-
* @example
|
|
2536
|
-
* ```tsx
|
|
2537
|
-
* <CopilotKitProvider
|
|
2538
|
-
* onError={({ code, error, context }) => {
|
|
2539
|
-
* if (code === "agent_thread_locked") {
|
|
2540
|
-
* // Show "Agent is busy, retry?" UI
|
|
2541
|
-
* }
|
|
2542
|
-
* }}
|
|
2543
|
-
* />
|
|
2544
|
-
* ```
|
|
2545
|
-
*/
|
|
2546
|
-
CopilotKitCoreErrorCode["AGENT_THREAD_LOCKED"] = "agent_thread_locked";
|
|
2547
|
-
CopilotKitCoreErrorCode["TRANSCRIPTION_FAILED"] = "transcription_failed";
|
|
2548
|
-
CopilotKitCoreErrorCode["TRANSCRIPTION_SERVICE_NOT_CONFIGURED"] = "transcription_service_not_configured";
|
|
2549
|
-
CopilotKitCoreErrorCode["TRANSCRIPTION_INVALID_AUDIO"] = "transcription_invalid_audio";
|
|
2550
|
-
CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
|
|
2551
|
-
CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
|
|
2552
|
-
CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
|
|
2553
|
-
CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
|
|
2554
|
-
return CopilotKitCoreErrorCode;
|
|
2555
|
-
}({});
|
|
2687
|
+
//#region src/utils/micro-redux.ts
|
|
2688
|
+
const INTERNAL_ACTION_TYPES = {
|
|
2689
|
+
boot: "@@micro-redux/boot",
|
|
2690
|
+
init: "@@micro-redux/init",
|
|
2691
|
+
stop: "@@micro-redux/stop"
|
|
2692
|
+
};
|
|
2693
|
+
const INTERNAL_BOOT_ACTION = { type: INTERNAL_ACTION_TYPES.boot };
|
|
2556
2694
|
/**
|
|
2557
|
-
*
|
|
2558
|
-
* to module scope so the Set is allocated once, not per-subscription.
|
|
2695
|
+
* Builds a typed action creator from a type string and payload factory.
|
|
2559
2696
|
*/
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
|
|
2570
|
-
CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
|
|
2571
|
-
CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
|
|
2572
|
-
CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
|
|
2573
|
-
return CopilotKitCoreRuntimeConnectionStatus;
|
|
2574
|
-
}({});
|
|
2697
|
+
function createTypedActionCreator(type, factory) {
|
|
2698
|
+
const creator = ((...args) => ({
|
|
2699
|
+
...factory(...args),
|
|
2700
|
+
type
|
|
2701
|
+
}));
|
|
2702
|
+
creator.type = type;
|
|
2703
|
+
creator.match = (action) => action.type === type;
|
|
2704
|
+
return creator;
|
|
2705
|
+
}
|
|
2575
2706
|
/**
|
|
2576
|
-
*
|
|
2577
|
-
*
|
|
2578
|
-
*
|
|
2579
|
-
*
|
|
2707
|
+
* Declares a payload-based action config for `createActionGroup`.
|
|
2708
|
+
*
|
|
2709
|
+
* @example
|
|
2710
|
+
* ```ts
|
|
2711
|
+
* const actions = createActionGroup("User", {
|
|
2712
|
+
* loaded: props<{ id: string }>(),
|
|
2713
|
+
* });
|
|
2714
|
+
* ```
|
|
2580
2715
|
*/
|
|
2581
|
-
function
|
|
2582
|
-
return
|
|
2716
|
+
function props() {
|
|
2717
|
+
return { kind: "props" };
|
|
2583
2718
|
}
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
this.stateManager = new StateManager(this);
|
|
2614
|
-
this.threadStoreRegistry = new ThreadStoreRegistry(this);
|
|
2615
|
-
this.agentRegistry.initialize(agents__unsafe_dev_only);
|
|
2616
|
-
this.runHandler.initialize(tools);
|
|
2617
|
-
this.suggestionEngine.initialize(suggestionsConfig);
|
|
2618
|
-
this.stateManager.initialize();
|
|
2619
|
-
this.agentRegistry.setRuntimeTransport(runtimeTransport);
|
|
2620
|
-
this.agentRegistry.setRuntimeUrl(runtimeUrl);
|
|
2621
|
-
this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
|
|
2622
|
-
this.subscribe({ onAgentsChanged: ({ agents }) => {
|
|
2623
|
-
Object.values(agents).forEach((agent) => {
|
|
2624
|
-
if (agent.agentId) this.stateManager.subscribeToAgent(agent);
|
|
2625
|
-
});
|
|
2626
|
-
const currentAgentIds = new Set(Object.keys(agents));
|
|
2627
|
-
for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) try {
|
|
2628
|
-
this.threadStoreRegistry.unregister(agentId);
|
|
2629
|
-
} catch (err) {
|
|
2630
|
-
console.error(`CopilotKitCore.onAgentsChanged: threadStoreRegistry.unregister failed for "${agentId}":`, err);
|
|
2631
|
-
}
|
|
2632
|
-
for (const agentId of this.previousAgentIds) if (!currentAgentIds.has(agentId)) try {
|
|
2633
|
-
this.stateManager.unsubscribeFromAgent(agentId);
|
|
2634
|
-
} catch (err) {
|
|
2635
|
-
console.error(`CopilotKitCore.onAgentsChanged: stateManager.unsubscribeFromAgent failed for "${agentId}":`, err);
|
|
2636
|
-
}
|
|
2637
|
-
this.previousAgentIds = currentAgentIds;
|
|
2638
|
-
} });
|
|
2639
|
-
}
|
|
2640
|
-
/**
|
|
2641
|
-
* Internal method used by delegate classes and subclasses to notify subscribers
|
|
2642
|
-
*/
|
|
2643
|
-
async notifySubscribers(handler, errorMessage) {
|
|
2644
|
-
await Promise.all(Array.from(this.subscribers).map(async (subscriber) => {
|
|
2645
|
-
try {
|
|
2646
|
-
await handler(subscriber);
|
|
2647
|
-
} catch (error) {
|
|
2648
|
-
console.error(errorMessage, error);
|
|
2649
|
-
}
|
|
2650
|
-
}));
|
|
2719
|
+
/**
|
|
2720
|
+
* Declares a no-payload action config for `createActionGroup`.
|
|
2721
|
+
*
|
|
2722
|
+
* @example
|
|
2723
|
+
* ```ts
|
|
2724
|
+
* const actions = createActionGroup("User", {
|
|
2725
|
+
* reset: empty(),
|
|
2726
|
+
* });
|
|
2727
|
+
* ```
|
|
2728
|
+
*/
|
|
2729
|
+
function empty() {
|
|
2730
|
+
return { kind: "empty" };
|
|
2731
|
+
}
|
|
2732
|
+
/**
|
|
2733
|
+
* Creates a namespaced group of typed action creators.
|
|
2734
|
+
*
|
|
2735
|
+
* Action types are formatted as: `[Source] actionName`.
|
|
2736
|
+
*/
|
|
2737
|
+
function createActionGroup(source, config) {
|
|
2738
|
+
const group = {};
|
|
2739
|
+
for (const eventName of Object.keys(config)) {
|
|
2740
|
+
const eventConfig = config[eventName];
|
|
2741
|
+
if (!eventConfig) continue;
|
|
2742
|
+
const actionType = `[${source}] ${eventName}`;
|
|
2743
|
+
if (eventConfig.kind === "props") {
|
|
2744
|
+
group[eventName] = createTypedActionCreator(actionType, (payload) => ({ ...payload }));
|
|
2745
|
+
continue;
|
|
2746
|
+
}
|
|
2747
|
+
group[eventName] = createTypedActionCreator(actionType, () => ({}));
|
|
2651
2748
|
}
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
}
|
|
2679
|
-
get agents() {
|
|
2680
|
-
return this.agentRegistry.agents;
|
|
2681
|
-
}
|
|
2682
|
-
get tools() {
|
|
2683
|
-
return this.runHandler.tools;
|
|
2684
|
-
}
|
|
2685
|
-
get runtimeUrl() {
|
|
2686
|
-
return this.agentRegistry.runtimeUrl;
|
|
2687
|
-
}
|
|
2688
|
-
setRuntimeUrl(runtimeUrl) {
|
|
2689
|
-
this.agentRegistry.setRuntimeUrl(runtimeUrl);
|
|
2690
|
-
}
|
|
2691
|
-
get runtimeTransport() {
|
|
2692
|
-
return this.agentRegistry.runtimeTransport;
|
|
2693
|
-
}
|
|
2694
|
-
setRuntimeTransport(runtimeTransport) {
|
|
2695
|
-
this.agentRegistry.setRuntimeTransport(runtimeTransport);
|
|
2696
|
-
}
|
|
2697
|
-
get runtimeVersion() {
|
|
2698
|
-
return this.agentRegistry.runtimeVersion;
|
|
2699
|
-
}
|
|
2700
|
-
get headers() {
|
|
2701
|
-
return this._headers;
|
|
2749
|
+
return group;
|
|
2750
|
+
}
|
|
2751
|
+
/**
|
|
2752
|
+
* Registers one reducer handler for one or more action creators.
|
|
2753
|
+
*
|
|
2754
|
+
* @throws Error when called without at least one action creator and reducer.
|
|
2755
|
+
*/
|
|
2756
|
+
function on(...args) {
|
|
2757
|
+
if (args.length < 2) throw new Error("on requires at least one action creator and one reducer");
|
|
2758
|
+
const reducer = args[args.length - 1];
|
|
2759
|
+
return {
|
|
2760
|
+
creators: args.slice(0, -1),
|
|
2761
|
+
reducer
|
|
2762
|
+
};
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Creates a reducer from an initial state and `on(...)` handler entries.
|
|
2766
|
+
*
|
|
2767
|
+
* Unknown action types return the current state unchanged.
|
|
2768
|
+
*/
|
|
2769
|
+
function createReducer(initialState, ...entries) {
|
|
2770
|
+
const reducerMap = /* @__PURE__ */ new Map();
|
|
2771
|
+
for (const entry of entries) for (const creator of entry.creators) {
|
|
2772
|
+
const handlers = reducerMap.get(creator.type) ?? [];
|
|
2773
|
+
handlers.push(entry.reducer);
|
|
2774
|
+
reducerMap.set(creator.type, handlers);
|
|
2702
2775
|
}
|
|
2703
|
-
|
|
2704
|
-
|
|
2776
|
+
return (state, action) => {
|
|
2777
|
+
const currentState = state ?? initialState;
|
|
2778
|
+
const handlers = reducerMap.get(action.type);
|
|
2779
|
+
if (!handlers || handlers.length === 0) return currentState;
|
|
2780
|
+
let nextState = currentState;
|
|
2781
|
+
for (const handler of handlers) nextState = handler(nextState, action);
|
|
2782
|
+
return nextState;
|
|
2783
|
+
};
|
|
2784
|
+
}
|
|
2785
|
+
/**
|
|
2786
|
+
* Creates a selector that caches and reuses the last computed result
|
|
2787
|
+
* when all input references are unchanged.
|
|
2788
|
+
*/
|
|
2789
|
+
function createSelector(...args) {
|
|
2790
|
+
if (args.length === 1) {
|
|
2791
|
+
const projector = args[0];
|
|
2792
|
+
let hasCached = false;
|
|
2793
|
+
let lastState;
|
|
2794
|
+
let lastResult;
|
|
2795
|
+
return (state) => {
|
|
2796
|
+
if (hasCached && state === lastState) return lastResult;
|
|
2797
|
+
lastState = state;
|
|
2798
|
+
lastResult = projector(state);
|
|
2799
|
+
hasCached = true;
|
|
2800
|
+
return lastResult;
|
|
2801
|
+
};
|
|
2705
2802
|
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2803
|
+
const projector = args[args.length - 1];
|
|
2804
|
+
const selectors = args.slice(0, -1);
|
|
2805
|
+
let hasCached = false;
|
|
2806
|
+
let lastInputs = [];
|
|
2807
|
+
let lastResult;
|
|
2808
|
+
return (state) => {
|
|
2809
|
+
const inputs = selectors.map((selector) => selector(state));
|
|
2810
|
+
if (hasCached && inputs.length === lastInputs.length && inputs.every((value, index) => value === lastInputs[index])) return lastResult;
|
|
2811
|
+
lastInputs = inputs;
|
|
2812
|
+
lastResult = projector(...inputs);
|
|
2813
|
+
hasCached = true;
|
|
2814
|
+
return lastResult;
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
/**
|
|
2818
|
+
* RxJS operator that maps state emissions through a selector and suppresses
|
|
2819
|
+
* unchanged projected values via reference equality.
|
|
2820
|
+
*/
|
|
2821
|
+
function select(selector) {
|
|
2822
|
+
return (source$) => source$.pipe((0, rxjs_operators.map)(selector), (0, rxjs_operators.distinctUntilChanged)());
|
|
2823
|
+
}
|
|
2824
|
+
/**
|
|
2825
|
+
* RxJS operator that filters an action stream by action creators and narrows
|
|
2826
|
+
* the output action type to the matched creator union.
|
|
2827
|
+
*
|
|
2828
|
+
* @throws Error when called without at least one action creator.
|
|
2829
|
+
*/
|
|
2830
|
+
function ofType(...creators) {
|
|
2831
|
+
if (creators.length === 0) throw new Error("ofType requires at least one action creator");
|
|
2832
|
+
const actionTypes = new Set(creators.map((creator) => creator.type));
|
|
2833
|
+
return (source$) => {
|
|
2834
|
+
return source$.pipe((0, rxjs_operators.filter)((action) => {
|
|
2835
|
+
return actionTypes.has(action.type);
|
|
2836
|
+
}));
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
/**
|
|
2840
|
+
* Creates an effect descriptor consumed by `createStore`.
|
|
2841
|
+
*/
|
|
2842
|
+
function createEffect(factory, options = {}) {
|
|
2843
|
+
if (options.dispatch === false) return {
|
|
2844
|
+
run: factory,
|
|
2845
|
+
dispatch: false
|
|
2846
|
+
};
|
|
2847
|
+
return {
|
|
2848
|
+
run: factory,
|
|
2849
|
+
dispatch: true
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
/**
|
|
2853
|
+
* Creates a small observable store with reducer + effects.
|
|
2854
|
+
*
|
|
2855
|
+
* Behavior:
|
|
2856
|
+
* - `init()` starts effects and dispatches `@@micro-redux/init`.
|
|
2857
|
+
* - `stop()` dispatches `@@micro-redux/stop` and unsubscribes all effects.
|
|
2858
|
+
* - Effect action observation is scheduled on `asapScheduler` to avoid
|
|
2859
|
+
* synchronous re-entrancy in the effect loop.
|
|
2860
|
+
* - Any effect error triggers fail-fast teardown and errors both `actions$`
|
|
2861
|
+
* and `state$`.
|
|
2862
|
+
*/
|
|
2863
|
+
function createStore(options) {
|
|
2864
|
+
const reducer = options.reducer;
|
|
2865
|
+
const effects = options.effects ?? [];
|
|
2866
|
+
let hasFatalError = false;
|
|
2867
|
+
let isRunning = false;
|
|
2868
|
+
let effectSubscriptions = new rxjs.Subscription();
|
|
2869
|
+
let currentState = reducer(void 0, INTERNAL_BOOT_ACTION);
|
|
2870
|
+
const stateSubject = new rxjs.BehaviorSubject(currentState);
|
|
2871
|
+
const actionsSubject = new rxjs.Subject();
|
|
2872
|
+
const dispatchInternal = (action) => {
|
|
2873
|
+
if (hasFatalError) throw new Error("Store is in a failed state due to an effect error");
|
|
2874
|
+
currentState = reducer(currentState, action);
|
|
2875
|
+
stateSubject.next(currentState);
|
|
2876
|
+
actionsSubject.next(action);
|
|
2877
|
+
};
|
|
2878
|
+
const failFast = (error) => {
|
|
2879
|
+
if (hasFatalError) return;
|
|
2880
|
+
hasFatalError = true;
|
|
2881
|
+
isRunning = false;
|
|
2882
|
+
effectSubscriptions.unsubscribe();
|
|
2883
|
+
effectSubscriptions = new rxjs.Subscription();
|
|
2884
|
+
actionsSubject.error(error);
|
|
2885
|
+
stateSubject.error(error);
|
|
2886
|
+
};
|
|
2887
|
+
const startEffects = () => {
|
|
2888
|
+
for (const effect of effects) {
|
|
2889
|
+
const scheduledActions$ = actionsSubject.asObservable().pipe((0, rxjs_operators.observeOn)(rxjs.asapScheduler));
|
|
2890
|
+
const state$ = stateSubject.asObservable();
|
|
2891
|
+
if (effect.dispatch) {
|
|
2892
|
+
const subscription = effect.run(scheduledActions$, state$).subscribe({
|
|
2893
|
+
next: (effectAction) => {
|
|
2894
|
+
if (hasFatalError) return;
|
|
2895
|
+
dispatchInternal(effectAction);
|
|
2896
|
+
},
|
|
2897
|
+
error: (error) => {
|
|
2898
|
+
failFast(error);
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
effectSubscriptions.add(subscription);
|
|
2902
|
+
continue;
|
|
2903
|
+
}
|
|
2904
|
+
const subscription = effect.run(scheduledActions$, state$).subscribe({ error: (error) => {
|
|
2905
|
+
failFast(error);
|
|
2906
|
+
} });
|
|
2907
|
+
effectSubscriptions.add(subscription);
|
|
2908
|
+
}
|
|
2909
|
+
};
|
|
2910
|
+
return {
|
|
2911
|
+
dispatch(action) {
|
|
2912
|
+
dispatchInternal(action);
|
|
2913
|
+
},
|
|
2914
|
+
getState() {
|
|
2915
|
+
return currentState;
|
|
2916
|
+
},
|
|
2917
|
+
get state$() {
|
|
2918
|
+
return stateSubject.asObservable();
|
|
2919
|
+
},
|
|
2920
|
+
get actions$() {
|
|
2921
|
+
return actionsSubject.asObservable();
|
|
2922
|
+
},
|
|
2923
|
+
select(selector) {
|
|
2924
|
+
return stateSubject.asObservable().pipe(select(selector));
|
|
2925
|
+
},
|
|
2926
|
+
init() {
|
|
2927
|
+
if (hasFatalError || isRunning) return;
|
|
2928
|
+
isRunning = true;
|
|
2929
|
+
startEffects();
|
|
2930
|
+
if (hasFatalError) return;
|
|
2931
|
+
dispatchInternal({ type: INTERNAL_ACTION_TYPES.init });
|
|
2932
|
+
},
|
|
2933
|
+
stop() {
|
|
2934
|
+
if (hasFatalError || !isRunning) return;
|
|
2935
|
+
dispatchInternal({ type: INTERNAL_ACTION_TYPES.stop });
|
|
2936
|
+
effectSubscriptions.unsubscribe();
|
|
2937
|
+
effectSubscriptions = new rxjs.Subscription();
|
|
2938
|
+
isRunning = false;
|
|
2939
|
+
}
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
//#endregion
|
|
2944
|
+
//#region src/memory-errors.ts
|
|
2945
|
+
/**
|
|
2946
|
+
* The memory error registry: the single source of truth for memory error
|
|
2947
|
+
* metadata. Keyed by `code` so a code maps to exactly one category/retryable
|
|
2948
|
+
* default.
|
|
2949
|
+
*
|
|
2950
|
+
* Categories/retryable rationale:
|
|
2951
|
+
* - List/credentials/mutation failures are `dependency` (the runtime/platform
|
|
2952
|
+
* the store calls failed). A 5xx is transient (`retryable: true`); a 4xx is
|
|
2953
|
+
* caller-caused, so the helpers below downgrade those to non-retryable.
|
|
2954
|
+
* - Timeouts are `dependency` and `retryable: true` (the request may simply be
|
|
2955
|
+
* slow).
|
|
2956
|
+
*/
|
|
2957
|
+
const MEMORY_ERROR_REGISTRY = Object.freeze({
|
|
2958
|
+
MEMORY_LIST_FAILED: {
|
|
2959
|
+
code: "MEMORY_LIST_FAILED",
|
|
2960
|
+
category: "dependency",
|
|
2961
|
+
retryable: true,
|
|
2962
|
+
message: "Failed to fetch memories",
|
|
2963
|
+
docsPath: "docs/errors/memory.md#memory_list_failed"
|
|
2964
|
+
},
|
|
2965
|
+
MEMORY_CREDENTIALS_FAILED: {
|
|
2966
|
+
code: "MEMORY_CREDENTIALS_FAILED",
|
|
2967
|
+
category: "dependency",
|
|
2968
|
+
retryable: true,
|
|
2969
|
+
message: "Failed to fetch memory subscribe credentials",
|
|
2970
|
+
docsPath: "docs/errors/memory.md#memory_credentials_failed"
|
|
2971
|
+
},
|
|
2972
|
+
MEMORY_MUTATION_FAILED: {
|
|
2973
|
+
code: "MEMORY_MUTATION_FAILED",
|
|
2974
|
+
category: "dependency",
|
|
2975
|
+
retryable: true,
|
|
2976
|
+
message: "Memory mutation request failed",
|
|
2977
|
+
docsPath: "docs/errors/memory.md#memory_mutation_failed"
|
|
2978
|
+
},
|
|
2979
|
+
MEMORY_REQUEST_TIMEOUT: {
|
|
2980
|
+
code: "MEMORY_REQUEST_TIMEOUT",
|
|
2981
|
+
category: "dependency",
|
|
2982
|
+
retryable: true,
|
|
2983
|
+
message: "Request timed out",
|
|
2984
|
+
docsPath: "docs/errors/memory.md#memory_request_timeout"
|
|
2708
2985
|
}
|
|
2986
|
+
});
|
|
2987
|
+
/**
|
|
2988
|
+
* An `Error` carrying a stable memory error `code`, `category`, and `retryable`
|
|
2989
|
+
* flag so consumers and observability can branch on it without string-matching
|
|
2990
|
+
* the message.
|
|
2991
|
+
*
|
|
2992
|
+
* It is a real `Error` subclass: `instanceof Error` is true, so the public
|
|
2993
|
+
* `MemoryState.error: Error | null` contract (and the `error: Error | null`
|
|
2994
|
+
* surfaced by `useMemories` / `injectMemories`) holds unchanged. Existing
|
|
2995
|
+
* consumers that only read `.message` keep working; the richer fields are
|
|
2996
|
+
* additive.
|
|
2997
|
+
*/
|
|
2998
|
+
var MemoryError = class MemoryError extends Error {
|
|
2999
|
+
/** Stable, machine-readable error identifier. */
|
|
3000
|
+
code;
|
|
3001
|
+
/** Coarse error category for grouping/observability. */
|
|
3002
|
+
category;
|
|
3003
|
+
/** Whether retrying the operation could plausibly succeed. */
|
|
3004
|
+
retryable;
|
|
2709
3005
|
/**
|
|
2710
|
-
*
|
|
2711
|
-
*
|
|
2712
|
-
* `
|
|
3006
|
+
* @param code - Registry code identifying this error.
|
|
3007
|
+
* @param options - Optional overrides:
|
|
3008
|
+
* - `message`: human-readable message (defaults to the registry message;
|
|
3009
|
+
* callers pass a status-bearing string to preserve prior wording).
|
|
3010
|
+
* - `retryable`: overrides the registry default (e.g. a 4xx list failure is
|
|
3011
|
+
* not retryable even though the code's default is).
|
|
3012
|
+
* - `cause`: the underlying error, preserved for debugging.
|
|
2713
3013
|
*/
|
|
2714
|
-
|
|
2715
|
-
|
|
3014
|
+
constructor(code, options) {
|
|
3015
|
+
const entry = MEMORY_ERROR_REGISTRY[code];
|
|
3016
|
+
super(options?.message ?? entry.message, { cause: options?.cause });
|
|
3017
|
+
this.name = "MemoryError";
|
|
3018
|
+
this.code = code;
|
|
3019
|
+
this.category = entry.category;
|
|
3020
|
+
this.retryable = options?.retryable ?? entry.retryable;
|
|
3021
|
+
Object.setPrototypeOf(this, MemoryError.prototype);
|
|
2716
3022
|
}
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
3023
|
+
};
|
|
3024
|
+
/**
|
|
3025
|
+
* Narrows an HTTP status to whether the failure is worth retrying: a 5xx (or a
|
|
3026
|
+
* missing/0 status) is a transient dependency failure and retryable; a 4xx is
|
|
3027
|
+
* caller-caused and not. Used so a `MEMORY_LIST_FAILED`/`MEMORY_MUTATION_FAILED`
|
|
3028
|
+
* carries an accurate `retryable` flag derived from the response status.
|
|
3029
|
+
*/
|
|
3030
|
+
function isRetryableStatus(status) {
|
|
3031
|
+
return !(Number.isInteger(status) && status >= 400 && status <= 499);
|
|
3032
|
+
}
|
|
3033
|
+
|
|
3034
|
+
//#endregion
|
|
3035
|
+
//#region src/memory.ts
|
|
3036
|
+
const MEMORIES_PATH = "/memories";
|
|
3037
|
+
const MEMORIES_SUBSCRIBE_PATH = "/memories/subscribe";
|
|
3038
|
+
const REQUEST_TIMEOUT_MS$1 = 15e3;
|
|
3039
|
+
/** Consecutive socket errors tolerated before the realtime stream gives up. */
|
|
3040
|
+
const MAX_SOCKET_RETRIES$1 = 5;
|
|
3041
|
+
/**
|
|
3042
|
+
* HTTP status codes that indicate memory routes are not configured (non-fatal).
|
|
3043
|
+
* 404/501 mean the route is absent/unimplemented; 422 is the runtime's
|
|
3044
|
+
* MISSING_INTELLIGENCE signal (intelligence not configured on the deployment —
|
|
3045
|
+
* see packages/runtime/.../handlers/intelligence/memories.ts). All three map to
|
|
3046
|
+
* the graceful "not available" locked-teaser path, not a hard error.
|
|
3047
|
+
*/
|
|
3048
|
+
const ROUTE_UNAVAILABLE_STATUSES = new Set([
|
|
3049
|
+
404,
|
|
3050
|
+
422,
|
|
3051
|
+
501
|
|
3052
|
+
]);
|
|
3053
|
+
/**
|
|
3054
|
+
* Thrown when a memory route returns a 404/422/501 — treated as "not
|
|
3055
|
+
* configured" (422 is the runtime's MISSING_INTELLIGENCE signal).
|
|
3056
|
+
*/
|
|
3057
|
+
var MemoryRouteUnavailableError = class extends Error {};
|
|
3058
|
+
const initialMemoryState = Object.freeze({
|
|
3059
|
+
memories: Object.freeze([]),
|
|
3060
|
+
isLoading: false,
|
|
3061
|
+
inFlightMutationCount: 0,
|
|
3062
|
+
error: null,
|
|
3063
|
+
context: null,
|
|
3064
|
+
sessionId: 0,
|
|
3065
|
+
available: true,
|
|
3066
|
+
realtimeStatus: "connecting"
|
|
3067
|
+
});
|
|
3068
|
+
const memoryAdapterEvents = createActionGroup("Memory Adapter", {
|
|
3069
|
+
started: empty(),
|
|
3070
|
+
stopped: empty(),
|
|
3071
|
+
contextChanged: props(),
|
|
3072
|
+
addRequested: props(),
|
|
3073
|
+
updateRequested: props(),
|
|
3074
|
+
removeRequested: props()
|
|
3075
|
+
});
|
|
3076
|
+
const memoryRestEvents = createActionGroup("Memory REST", {
|
|
3077
|
+
listRequested: props(),
|
|
3078
|
+
listSucceeded: props(),
|
|
3079
|
+
listFailed: props(),
|
|
3080
|
+
listUnavailable: props(),
|
|
3081
|
+
mutationFinished: props(),
|
|
3082
|
+
credentialsRequested: props(),
|
|
3083
|
+
credentialsSucceeded: props(),
|
|
3084
|
+
credentialsFailed: props(),
|
|
3085
|
+
credentialsUnavailable: props()
|
|
3086
|
+
});
|
|
3087
|
+
const memoryDomainEvents = createActionGroup("Memory Domain", {
|
|
3088
|
+
memoryUpserted: props(),
|
|
3089
|
+
memoryInvalidated: props(),
|
|
3090
|
+
realtimeConnecting: props(),
|
|
3091
|
+
realtimeConnected: props(),
|
|
3092
|
+
realtimeUnavailable: props()
|
|
3093
|
+
});
|
|
3094
|
+
/** Projects a wire memory to the public {@link Memory} shape (drops tenant ids). */
|
|
3095
|
+
function toMemory(memory) {
|
|
3096
|
+
return {
|
|
3097
|
+
id: memory.id,
|
|
3098
|
+
kind: memory.kind,
|
|
3099
|
+
scope: memory.scope,
|
|
3100
|
+
content: memory.content,
|
|
3101
|
+
sourceThreadIds: memory.sourceThreadIds,
|
|
3102
|
+
invalidatedAt: memory.invalidatedAt
|
|
3103
|
+
};
|
|
3104
|
+
}
|
|
3105
|
+
/**
|
|
3106
|
+
* Maps a realtime `memory_metadata` event to the domain action that applies it:
|
|
3107
|
+
* `created`/`updated` upsert the projected memory, `invalidated` removes it by
|
|
3108
|
+
* id. Carries the current `sessionId` so the reducer's session guard can drop
|
|
3109
|
+
* deltas left over from a previous context.
|
|
3110
|
+
*/
|
|
3111
|
+
function mapMemoryMetadataEvent(event, sessionId) {
|
|
3112
|
+
if (event.operation === "invalidated") return memoryDomainEvents.memoryInvalidated({
|
|
3113
|
+
sessionId,
|
|
3114
|
+
memoryId: event.invalidated.id
|
|
3115
|
+
});
|
|
3116
|
+
return memoryDomainEvents.memoryUpserted({
|
|
3117
|
+
sessionId,
|
|
3118
|
+
memory: toMemory(event.memory)
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
/**
|
|
3122
|
+
* Inserts or replaces a memory by id. A new memory is prepended (newest first,
|
|
3123
|
+
* matching the REST list's `created_at DESC` ordering without needing a date
|
|
3124
|
+
* field on the public projection); an existing memory is replaced in place.
|
|
3125
|
+
*/
|
|
3126
|
+
function upsertMemory(memories, memory) {
|
|
3127
|
+
const existingIndex = memories.findIndex((item) => item.id === memory.id);
|
|
3128
|
+
if (existingIndex === -1) return [memory, ...memories];
|
|
3129
|
+
const next = [...memories];
|
|
3130
|
+
next[existingIndex] = memory;
|
|
3131
|
+
return next;
|
|
3132
|
+
}
|
|
3133
|
+
const memoryReducer = createReducer(initialMemoryState, on(memoryAdapterEvents.contextChanged, (state, { context }) => ({
|
|
3134
|
+
...state,
|
|
3135
|
+
context,
|
|
3136
|
+
sessionId: state.sessionId + 1,
|
|
3137
|
+
memories: [],
|
|
3138
|
+
isLoading: Boolean(context),
|
|
3139
|
+
inFlightMutationCount: 0,
|
|
3140
|
+
error: null,
|
|
3141
|
+
available: true,
|
|
3142
|
+
realtimeStatus: "connecting"
|
|
3143
|
+
})), on(memoryAdapterEvents.stopped, (state) => ({
|
|
3144
|
+
...state,
|
|
3145
|
+
memories: [],
|
|
3146
|
+
isLoading: false,
|
|
3147
|
+
inFlightMutationCount: 0,
|
|
3148
|
+
error: null,
|
|
3149
|
+
available: true,
|
|
3150
|
+
realtimeStatus: "connecting"
|
|
3151
|
+
})), on(memoryRestEvents.listRequested, (state, { sessionId }) => {
|
|
3152
|
+
if (sessionId !== state.sessionId || !state.context) return state;
|
|
3153
|
+
return {
|
|
3154
|
+
...state,
|
|
3155
|
+
isLoading: true,
|
|
3156
|
+
error: null,
|
|
3157
|
+
available: true
|
|
3158
|
+
};
|
|
3159
|
+
}), on(memoryRestEvents.listFailed, (state, { sessionId, error }) => {
|
|
3160
|
+
if (sessionId !== state.sessionId) return state;
|
|
3161
|
+
return {
|
|
3162
|
+
...state,
|
|
3163
|
+
isLoading: false,
|
|
3164
|
+
error
|
|
3165
|
+
};
|
|
3166
|
+
}), on(memoryRestEvents.listUnavailable, (state, { sessionId }) => {
|
|
3167
|
+
if (sessionId !== state.sessionId) return state;
|
|
3168
|
+
return {
|
|
3169
|
+
...state,
|
|
3170
|
+
memories: [],
|
|
3171
|
+
isLoading: false,
|
|
3172
|
+
error: null,
|
|
3173
|
+
available: false
|
|
3174
|
+
};
|
|
3175
|
+
}), on(memoryAdapterEvents.addRequested, memoryAdapterEvents.updateRequested, memoryAdapterEvents.removeRequested, (state) => ({
|
|
3176
|
+
...state,
|
|
3177
|
+
inFlightMutationCount: state.inFlightMutationCount + 1
|
|
3178
|
+
})), on(memoryRestEvents.mutationFinished, (state, { outcome }) => {
|
|
3179
|
+
if (outcome.sessionId !== state.sessionId) return state;
|
|
3180
|
+
return {
|
|
3181
|
+
...state,
|
|
3182
|
+
inFlightMutationCount: Math.max(0, state.inFlightMutationCount - 1),
|
|
3183
|
+
error: outcome.ok ? null : outcome.error
|
|
3184
|
+
};
|
|
3185
|
+
}), on(memoryRestEvents.listSucceeded, (state, { sessionId, memories }) => {
|
|
3186
|
+
if (sessionId !== state.sessionId) return state;
|
|
3187
|
+
return {
|
|
3188
|
+
...state,
|
|
3189
|
+
memories,
|
|
3190
|
+
isLoading: false,
|
|
3191
|
+
error: null,
|
|
3192
|
+
available: true
|
|
3193
|
+
};
|
|
3194
|
+
}), on(memoryDomainEvents.memoryUpserted, (state, { sessionId, memory }) => {
|
|
3195
|
+
if (sessionId !== state.sessionId) return state;
|
|
3196
|
+
return {
|
|
3197
|
+
...state,
|
|
3198
|
+
memories: upsertMemory(state.memories, memory)
|
|
3199
|
+
};
|
|
3200
|
+
}), on(memoryDomainEvents.memoryInvalidated, (state, { sessionId, memoryId }) => {
|
|
3201
|
+
if (sessionId !== state.sessionId) return state;
|
|
3202
|
+
return {
|
|
3203
|
+
...state,
|
|
3204
|
+
memories: state.memories.filter((memory) => memory.id !== memoryId)
|
|
3205
|
+
};
|
|
3206
|
+
}), on(memoryDomainEvents.realtimeConnecting, (state, { sessionId }) => {
|
|
3207
|
+
if (sessionId !== state.sessionId) return state;
|
|
3208
|
+
return {
|
|
3209
|
+
...state,
|
|
3210
|
+
realtimeStatus: "connecting"
|
|
3211
|
+
};
|
|
3212
|
+
}), on(memoryDomainEvents.realtimeConnected, (state, { sessionId }) => {
|
|
3213
|
+
if (sessionId !== state.sessionId) return state;
|
|
3214
|
+
return {
|
|
3215
|
+
...state,
|
|
3216
|
+
realtimeStatus: "connected"
|
|
3217
|
+
};
|
|
3218
|
+
}), on(memoryDomainEvents.realtimeUnavailable, (state, { sessionId }) => {
|
|
3219
|
+
if (sessionId !== state.sessionId) return state;
|
|
3220
|
+
return {
|
|
3221
|
+
...state,
|
|
3222
|
+
realtimeStatus: "unavailable"
|
|
3223
|
+
};
|
|
3224
|
+
}));
|
|
3225
|
+
const selectMemories = createSelector((state) => state.memories);
|
|
3226
|
+
const selectMemoriesIsLoading = createSelector((state) => state.isLoading);
|
|
3227
|
+
const selectMemoriesError = createSelector((state) => state.error);
|
|
3228
|
+
/**
|
|
3229
|
+
* Reports whether at least one mutation is in flight. Derived from
|
|
3230
|
+
* `inFlightMutationCount` so concurrent mutations stay correct: the boolean
|
|
3231
|
+
* only clears once every in-flight mutation has settled.
|
|
3232
|
+
*/
|
|
3233
|
+
const selectMemoriesIsMutating = createSelector((state) => state.inFlightMutationCount > 0);
|
|
3234
|
+
/**
|
|
3235
|
+
* Reports whether the memory routes are available. Becomes `false` after a
|
|
3236
|
+
* 404, 422 (the runtime's MISSING_INTELLIGENCE signal), or 501 response during
|
|
3237
|
+
* an auto-activation read; defaults to `true`.
|
|
3238
|
+
*/
|
|
3239
|
+
const selectMemoriesAvailable = createSelector((state) => state.available);
|
|
3240
|
+
/**
|
|
3241
|
+
* Reports the realtime-connection health (see {@link MemoryRealtimeStatus}).
|
|
3242
|
+
* Distinct from `available`/`error`: it reflects ONLY the live socket/channel,
|
|
3243
|
+
* so the UI can suppress a "live" indicator once realtime permanently dies even
|
|
3244
|
+
* while the REST list route stays healthy. Defaults to `"connecting"`.
|
|
3245
|
+
*/
|
|
3246
|
+
const selectMemoriesRealtimeStatus = createSelector((state) => state.realtimeStatus);
|
|
3247
|
+
const MEMORY_METADATA_EVENT = "memory_metadata";
|
|
3248
|
+
function memoryFromFetch(input, init) {
|
|
3249
|
+
return (0, rxjs_fetch.fromFetch)(input, init);
|
|
3250
|
+
}
|
|
3251
|
+
/**
|
|
3252
|
+
* Fetches the memory snapshot and maps it to a success/failure action. Keeps
|
|
3253
|
+
* only user-scoped memories (v1 surfaces user scope only; the realtime stream
|
|
3254
|
+
* is user-scoped too), so project-scoped rows visible to the caller are
|
|
3255
|
+
* dropped from the store.
|
|
3256
|
+
*/
|
|
3257
|
+
function createMemoryFetchObservable(environment, context, sessionId) {
|
|
3258
|
+
return (0, rxjs.defer)(() => {
|
|
3259
|
+
const qs = context.includeInvalidated ? "?includeInvalidated=true" : "";
|
|
3260
|
+
return memoryFromFetch(`${context.runtimeUrl}${MEMORIES_PATH}${qs}`, {
|
|
3261
|
+
selector: (response) => {
|
|
3262
|
+
if (!response.ok) {
|
|
3263
|
+
if (ROUTE_UNAVAILABLE_STATUSES.has(response.status)) throw new MemoryRouteUnavailableError(String(response.status));
|
|
3264
|
+
throw new MemoryError("MEMORY_LIST_FAILED", {
|
|
3265
|
+
message: `Failed to fetch memories: ${response.status}`,
|
|
3266
|
+
retryable: isRetryableStatus(response.status)
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
return response.json();
|
|
3270
|
+
},
|
|
3271
|
+
fetch: environment.fetch,
|
|
3272
|
+
method: "GET",
|
|
3273
|
+
headers: { ...context.headers }
|
|
3274
|
+
}).pipe((0, rxjs_operators.timeout)({
|
|
3275
|
+
first: REQUEST_TIMEOUT_MS$1,
|
|
3276
|
+
with: () => {
|
|
3277
|
+
throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
|
|
3278
|
+
}
|
|
3279
|
+
}), (0, rxjs_operators.map)((data) => memoryRestEvents.listSucceeded({
|
|
3280
|
+
sessionId,
|
|
3281
|
+
memories: data.memories.filter((memory) => memory.scope === "user")
|
|
3282
|
+
})), (0, rxjs_operators.catchError)((error) => {
|
|
3283
|
+
if (error instanceof MemoryRouteUnavailableError) return (0, rxjs.of)(memoryRestEvents.listUnavailable({ sessionId }));
|
|
3284
|
+
return (0, rxjs.of)(memoryRestEvents.listFailed({
|
|
3285
|
+
sessionId,
|
|
3286
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
3287
|
+
}));
|
|
3288
|
+
}));
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3291
|
+
/**
|
|
3292
|
+
* Fetches join credentials from the `/memories/subscribe` endpoint and maps
|
|
3293
|
+
* the response to a success/failure action. Requires both `joinToken` and
|
|
3294
|
+
* `joinCode` to be non-empty strings; throws otherwise so the `catchError`
|
|
3295
|
+
* path emits `credentialsFailed`.
|
|
3296
|
+
*/
|
|
3297
|
+
function createMemoryCredentialsFetchObservable(environment, context, sessionId) {
|
|
3298
|
+
return (0, rxjs.defer)(() => memoryFromFetch(`${context.runtimeUrl}${MEMORIES_SUBSCRIBE_PATH}`, {
|
|
3299
|
+
selector: async (response) => {
|
|
3300
|
+
if (!response.ok) {
|
|
3301
|
+
if (ROUTE_UNAVAILABLE_STATUSES.has(response.status)) throw new MemoryRouteUnavailableError(String(response.status));
|
|
3302
|
+
throw new MemoryError("MEMORY_CREDENTIALS_FAILED", {
|
|
3303
|
+
message: `Failed to fetch memory subscribe credentials: ${response.status}`,
|
|
3304
|
+
retryable: isRetryableStatus(response.status)
|
|
3305
|
+
});
|
|
3306
|
+
}
|
|
3307
|
+
return response.json();
|
|
3308
|
+
},
|
|
3309
|
+
fetch: environment.fetch,
|
|
3310
|
+
method: "POST",
|
|
3311
|
+
headers: {
|
|
3312
|
+
...context.headers,
|
|
3313
|
+
"Content-Type": "application/json"
|
|
3314
|
+
},
|
|
3315
|
+
body: JSON.stringify({})
|
|
3316
|
+
}).pipe((0, rxjs_operators.timeout)({
|
|
3317
|
+
first: REQUEST_TIMEOUT_MS$1,
|
|
3318
|
+
with: () => {
|
|
3319
|
+
throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
|
|
3320
|
+
}
|
|
3321
|
+
}), (0, rxjs_operators.map)((data) => {
|
|
3322
|
+
if (typeof data.joinToken !== "string" || data.joinToken.length === 0) throw new Error("missing joinToken");
|
|
3323
|
+
if (typeof data.joinCode !== "string" || data.joinCode.length === 0) throw new Error("missing joinCode");
|
|
3324
|
+
return memoryRestEvents.credentialsSucceeded({
|
|
3325
|
+
sessionId,
|
|
3326
|
+
joinToken: data.joinToken,
|
|
3327
|
+
joinCode: data.joinCode
|
|
3328
|
+
});
|
|
3329
|
+
}), (0, rxjs_operators.catchError)((error) => {
|
|
3330
|
+
if (error instanceof MemoryRouteUnavailableError) return (0, rxjs.of)(memoryRestEvents.credentialsUnavailable({ sessionId }));
|
|
3331
|
+
return (0, rxjs.of)(memoryRestEvents.credentialsFailed({
|
|
3332
|
+
sessionId,
|
|
3333
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
3334
|
+
}));
|
|
3335
|
+
})));
|
|
3336
|
+
}
|
|
3337
|
+
/** Projects a REST mutation response to the public {@link Memory} shape. */
|
|
3338
|
+
function responseToMemory(data) {
|
|
3339
|
+
return {
|
|
3340
|
+
id: data.id,
|
|
3341
|
+
kind: data.kind,
|
|
3342
|
+
scope: data.scope,
|
|
3343
|
+
content: data.content,
|
|
3344
|
+
sourceThreadIds: data.sourceThreadIds,
|
|
3345
|
+
invalidatedAt: data.invalidatedAt
|
|
3346
|
+
};
|
|
3347
|
+
}
|
|
3348
|
+
const MEMORY_KINDS = new Set([
|
|
3349
|
+
"topical",
|
|
3350
|
+
"episodic",
|
|
3351
|
+
"operational"
|
|
3352
|
+
]);
|
|
3353
|
+
const MEMORY_SCOPES = new Set(["user", "project"]);
|
|
3354
|
+
/**
|
|
3355
|
+
* Validates the required fields of a create/supersede REST response before it is
|
|
3356
|
+
* projected to a {@link Memory}. Returns an `Error` describing the first
|
|
3357
|
+
* missing/invalid field, or `null` when the body is well-formed. Without this a
|
|
3358
|
+
* malformed 200 body yields a Memory with undefined fields that gets upserted.
|
|
3359
|
+
*/
|
|
3360
|
+
function validateMutationResponse(data) {
|
|
3361
|
+
if (!data || typeof data !== "object") return /* @__PURE__ */ new Error("memory mutation response missing/invalid body");
|
|
3362
|
+
if (typeof data.id !== "string" || data.id.length === 0) return /* @__PURE__ */ new Error("memory mutation response missing/invalid id");
|
|
3363
|
+
if (typeof data.kind !== "string" || !MEMORY_KINDS.has(data.kind)) return /* @__PURE__ */ new Error("memory mutation response missing/invalid kind");
|
|
3364
|
+
if (typeof data.scope !== "string" || !MEMORY_SCOPES.has(data.scope)) return /* @__PURE__ */ new Error("memory mutation response missing/invalid scope");
|
|
3365
|
+
if (typeof data.content !== "string") return /* @__PURE__ */ new Error("memory mutation response missing/invalid content");
|
|
3366
|
+
if (!Array.isArray(data.sourceThreadIds) || !data.sourceThreadIds.every((id) => typeof id === "string")) return /* @__PURE__ */ new Error("memory mutation response missing/invalid sourceThreadIds");
|
|
3367
|
+
if (data.invalidatedAt !== null && typeof data.invalidatedAt !== "string") return /* @__PURE__ */ new Error("memory mutation response missing/invalid invalidatedAt");
|
|
3368
|
+
return null;
|
|
3369
|
+
}
|
|
3370
|
+
/**
|
|
3371
|
+
* Request body for create/supersede. `scope` is forwarded only when the caller
|
|
3372
|
+
* supplies it: the platform owns the default (`scope` defaults to `"user"` in
|
|
3373
|
+
* the `/api/memories` schema), so the store does not second-guess it here —
|
|
3374
|
+
* one default, at the contract owner. `sourceThreadIds` defaults to `[]`.
|
|
3375
|
+
*/
|
|
3376
|
+
function toMutationBody(input) {
|
|
3377
|
+
return {
|
|
3378
|
+
content: input.content,
|
|
3379
|
+
kind: input.kind,
|
|
3380
|
+
...input.scope !== void 0 ? { scope: input.scope } : {},
|
|
3381
|
+
sourceThreadIds: input.sourceThreadIds ?? []
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
/**
|
|
3385
|
+
* Builds the actions a successful mutation dispatches (server-authoritative):
|
|
3386
|
+
* the REST response is applied to local state immediately, and the realtime
|
|
3387
|
+
* event reconciles idempotently (upsert-by-id). `mutationFinished` resolves the
|
|
3388
|
+
* caller's promise.
|
|
3389
|
+
*/
|
|
3390
|
+
function buildMutationSuccessActions(request, data) {
|
|
3391
|
+
const { requestId, sessionId } = request;
|
|
3392
|
+
if (request.kind === "remove") return [memoryDomainEvents.memoryInvalidated({
|
|
3393
|
+
sessionId,
|
|
3394
|
+
memoryId: request.id
|
|
3395
|
+
}), memoryRestEvents.mutationFinished({ outcome: {
|
|
3396
|
+
requestId,
|
|
3397
|
+
sessionId,
|
|
3398
|
+
ok: true,
|
|
3399
|
+
memory: null
|
|
3400
|
+
} })];
|
|
3401
|
+
const validationError = validateMutationResponse(data);
|
|
3402
|
+
if (validationError) return [memoryRestEvents.mutationFinished({ outcome: {
|
|
3403
|
+
requestId,
|
|
3404
|
+
sessionId,
|
|
3405
|
+
ok: false,
|
|
3406
|
+
error: validationError
|
|
3407
|
+
} })];
|
|
3408
|
+
const memory = responseToMemory(data);
|
|
3409
|
+
if (request.kind === "update") {
|
|
3410
|
+
const retiredId = data.retiredId;
|
|
3411
|
+
if (typeof retiredId !== "string" || retiredId.length === 0) return [memoryRestEvents.mutationFinished({ outcome: {
|
|
3412
|
+
requestId,
|
|
3413
|
+
sessionId,
|
|
3414
|
+
ok: false,
|
|
3415
|
+
error: /* @__PURE__ */ new Error("supersede response missing retiredId")
|
|
3416
|
+
} })];
|
|
3417
|
+
return [
|
|
3418
|
+
memoryDomainEvents.memoryInvalidated({
|
|
3419
|
+
sessionId,
|
|
3420
|
+
memoryId: retiredId
|
|
3421
|
+
}),
|
|
3422
|
+
memoryDomainEvents.memoryUpserted({
|
|
3423
|
+
sessionId,
|
|
3424
|
+
memory
|
|
3425
|
+
}),
|
|
3426
|
+
memoryRestEvents.mutationFinished({ outcome: {
|
|
3427
|
+
requestId,
|
|
3428
|
+
sessionId,
|
|
3429
|
+
ok: true,
|
|
3430
|
+
memory
|
|
3431
|
+
} })
|
|
3432
|
+
];
|
|
3433
|
+
}
|
|
3434
|
+
return [memoryDomainEvents.memoryUpserted({
|
|
3435
|
+
sessionId,
|
|
3436
|
+
memory
|
|
3437
|
+
}), memoryRestEvents.mutationFinished({ outcome: {
|
|
3438
|
+
requestId,
|
|
3439
|
+
sessionId,
|
|
3440
|
+
ok: true,
|
|
3441
|
+
memory
|
|
3442
|
+
} })];
|
|
3443
|
+
}
|
|
3444
|
+
/** Performs a create/supersede/retire HTTP call and emits its resulting actions. */
|
|
3445
|
+
function createMemoryMutationObservable(environment, context, request) {
|
|
3446
|
+
const method = request.kind === "add" ? "POST" : request.kind === "update" ? "PATCH" : "DELETE";
|
|
3447
|
+
const path = request.kind === "add" ? MEMORIES_PATH : `${MEMORIES_PATH}/${encodeURIComponent(request.id)}`;
|
|
3448
|
+
return (0, rxjs.defer)(() => memoryFromFetch(`${context.runtimeUrl}${path}`, {
|
|
3449
|
+
selector: async (response) => {
|
|
3450
|
+
if (!response.ok) throw new MemoryError("MEMORY_MUTATION_FAILED", {
|
|
3451
|
+
message: `Request failed: ${response.status}`,
|
|
3452
|
+
retryable: isRetryableStatus(response.status)
|
|
3453
|
+
});
|
|
3454
|
+
return request.kind === "remove" ? null : await response.json();
|
|
3455
|
+
},
|
|
3456
|
+
fetch: environment.fetch,
|
|
3457
|
+
method,
|
|
3458
|
+
headers: {
|
|
3459
|
+
...context.headers,
|
|
3460
|
+
"Content-Type": "application/json"
|
|
3461
|
+
},
|
|
3462
|
+
body: request.kind === "remove" ? void 0 : JSON.stringify(request.body)
|
|
3463
|
+
}).pipe((0, rxjs_operators.timeout)({
|
|
3464
|
+
first: REQUEST_TIMEOUT_MS$1,
|
|
3465
|
+
with: () => {
|
|
3466
|
+
throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
|
|
3467
|
+
}
|
|
3468
|
+
}), (0, rxjs_operators.mergeMap)((data) => (0, rxjs.of)(...buildMutationSuccessActions(request, data))), (0, rxjs_operators.catchError)((error) => (0, rxjs.of)(memoryRestEvents.mutationFinished({ outcome: {
|
|
3469
|
+
requestId: request.requestId,
|
|
3470
|
+
sessionId: request.sessionId,
|
|
3471
|
+
ok: false,
|
|
3472
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
3473
|
+
} })))));
|
|
3474
|
+
}
|
|
3475
|
+
/**
|
|
3476
|
+
* Creates the framework-agnostic memory store: a REST snapshot on `setContext`,
|
|
3477
|
+
* server-authoritative add/update/remove mutations, and realtime
|
|
3478
|
+
* `memory_metadata` deltas off the injected `user_meta` event source — all
|
|
3479
|
+
* reduced into observable state.
|
|
3480
|
+
*/
|
|
3481
|
+
function createMemoryStore(environment) {
|
|
3482
|
+
let memoryRequestId = 0;
|
|
3483
|
+
const createMemoryRequestId = () => {
|
|
3484
|
+
memoryRequestId += 1;
|
|
3485
|
+
return `memory-request-${memoryRequestId}`;
|
|
3486
|
+
};
|
|
3487
|
+
const bootstrapEffect = createEffect((actions$, state$) => actions$.pipe(ofType(memoryAdapterEvents.contextChanged), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.filter)(([, state]) => Boolean(state.context)), (0, rxjs_operators.map)(([, state]) => memoryRestEvents.listRequested({ sessionId: state.sessionId }))));
|
|
3488
|
+
const credentialsBootstrapEffect = createEffect((actions$, state$) => actions$.pipe(ofType(memoryAdapterEvents.contextChanged), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.filter)(([, state]) => Boolean(state.context)), (0, rxjs_operators.map)(([, state]) => memoryRestEvents.credentialsRequested({ sessionId: state.sessionId }))));
|
|
3489
|
+
const credentialsFetchEffect = createEffect((actions$, state$) => actions$.pipe(ofType(memoryRestEvents.credentialsRequested), (0, rxjs_operators.switchMap)((action) => state$.pipe((0, rxjs_operators.map)((state) => state.context), (0, rxjs_operators.filter)((context) => Boolean(context)), (0, rxjs_operators.take)(1), (0, rxjs_operators.map)((context) => ({
|
|
3490
|
+
action,
|
|
3491
|
+
context
|
|
3492
|
+
})), (0, rxjs_operators.takeUntil)(actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped))), (0, rxjs_operators.switchMap)(({ action: currentAction, context }) => createMemoryCredentialsFetchObservable(environment, context, currentAction.sessionId))))));
|
|
3493
|
+
const store = createStore({
|
|
3494
|
+
reducer: memoryReducer,
|
|
3495
|
+
effects: [
|
|
3496
|
+
bootstrapEffect,
|
|
3497
|
+
credentialsBootstrapEffect,
|
|
3498
|
+
createEffect((actions$, state$) => actions$.pipe(ofType(memoryRestEvents.listRequested), (0, rxjs_operators.switchMap)((action) => state$.pipe((0, rxjs_operators.map)((state) => state.context), (0, rxjs_operators.filter)((context) => Boolean(context)), (0, rxjs_operators.take)(1), (0, rxjs_operators.map)((context) => ({
|
|
3499
|
+
action,
|
|
3500
|
+
context
|
|
3501
|
+
})), (0, rxjs_operators.takeUntil)(actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped))), (0, rxjs_operators.switchMap)(({ action: currentAction, context }) => createMemoryFetchObservable(environment, context, currentAction.sessionId)))))),
|
|
3502
|
+
credentialsFetchEffect,
|
|
3503
|
+
createEffect((actions$, state$) => actions$.pipe(ofType(memoryAdapterEvents.addRequested, memoryAdapterEvents.updateRequested, memoryAdapterEvents.removeRequested), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.mergeMap)(([action, state]) => {
|
|
3504
|
+
const context = state.context;
|
|
3505
|
+
const sessionId = state.sessionId;
|
|
3506
|
+
if (!context?.runtimeUrl) return (0, rxjs.of)(memoryRestEvents.mutationFinished({ outcome: {
|
|
3507
|
+
requestId: action.requestId,
|
|
3508
|
+
sessionId,
|
|
3509
|
+
ok: false,
|
|
3510
|
+
error: /* @__PURE__ */ new Error("Runtime URL is not configured")
|
|
3511
|
+
} }));
|
|
3512
|
+
if (memoryAdapterEvents.addRequested.match(action)) return createMemoryMutationObservable(environment, context, {
|
|
3513
|
+
requestId: action.requestId,
|
|
3514
|
+
sessionId,
|
|
3515
|
+
kind: "add",
|
|
3516
|
+
body: toMutationBody(action.input)
|
|
3517
|
+
});
|
|
3518
|
+
if (memoryAdapterEvents.updateRequested.match(action)) return createMemoryMutationObservable(environment, context, {
|
|
3519
|
+
requestId: action.requestId,
|
|
3520
|
+
sessionId,
|
|
3521
|
+
kind: "update",
|
|
3522
|
+
id: action.id,
|
|
3523
|
+
body: toMutationBody(action.changes)
|
|
3524
|
+
});
|
|
3525
|
+
return createMemoryMutationObservable(environment, context, {
|
|
3526
|
+
requestId: action.requestId,
|
|
3527
|
+
sessionId,
|
|
3528
|
+
kind: "remove",
|
|
3529
|
+
id: action.id
|
|
3530
|
+
});
|
|
3531
|
+
}))),
|
|
3532
|
+
createEffect((actions$, state$) => actions$.pipe(ofType(memoryRestEvents.credentialsSucceeded), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.filter)(([action, state]) => {
|
|
3533
|
+
return action.sessionId === state.sessionId && Boolean(state.context?.wsUrl);
|
|
3534
|
+
}), (0, rxjs_operators.switchMap)(([action, state]) => {
|
|
3535
|
+
const context = state.context;
|
|
3536
|
+
const { joinToken, joinCode } = action;
|
|
3537
|
+
const sessionId = action.sessionId;
|
|
3538
|
+
const shutdown$ = actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped));
|
|
3539
|
+
return (0, rxjs.defer)(() => {
|
|
3540
|
+
const socket$ = ɵphoenixSocket$({
|
|
3541
|
+
url: context.wsUrl,
|
|
3542
|
+
options: {
|
|
3543
|
+
params: { join_token: joinToken },
|
|
3544
|
+
reconnectAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(100, 1e4),
|
|
3545
|
+
rejoinAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(1e3, 3e4)
|
|
3546
|
+
}
|
|
3547
|
+
}).pipe((0, rxjs_operators.shareReplay)({
|
|
3548
|
+
bufferSize: 1,
|
|
3549
|
+
refCount: true
|
|
3550
|
+
}));
|
|
3551
|
+
const channel$ = ɵphoenixChannel$({
|
|
3552
|
+
socket$,
|
|
3553
|
+
topic: `user_meta:memories:${joinCode}`
|
|
3554
|
+
}).pipe((0, rxjs_operators.shareReplay)({
|
|
3555
|
+
bufferSize: 1,
|
|
3556
|
+
refCount: true
|
|
3557
|
+
}));
|
|
3558
|
+
const fatalSocketShutdown$ = ɵobservePhoenixSocketHealth$(ɵobservePhoenixSocketSignals$(socket$).pipe((0, rxjs_operators.share)()), MAX_SOCKET_RETRIES$1).pipe((0, rxjs_operators.catchError)(() => {
|
|
3559
|
+
console.warn(`[memory] WebSocket failed after ${MAX_SOCKET_RETRIES$1} attempts, giving up`);
|
|
3560
|
+
return (0, rxjs.of)(void 0);
|
|
3561
|
+
}), (0, rxjs_operators.share)());
|
|
3562
|
+
const fatalStatus$ = fatalSocketShutdown$.pipe((0, rxjs_operators.map)(() => memoryDomainEvents.realtimeUnavailable({ sessionId })));
|
|
3563
|
+
const metadata$ = channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => ɵobservePhoenixEvent$(channel, MEMORY_METADATA_EVENT)), (0, rxjs_operators.map)((event) => mapMemoryMetadataEvent(event, action.sessionId)));
|
|
3564
|
+
const join$ = ɵjoinPhoenixChannel$(channel$).pipe((0, rxjs_operators.concatWith)((0, rxjs.of)(memoryDomainEvents.realtimeConnected({ sessionId }))), (0, rxjs_operators.catchError)((error) => {
|
|
3565
|
+
console.warn(`[memory] failed to join user_meta:memories:${joinCode}`, error);
|
|
3566
|
+
return (0, rxjs.of)(memoryDomainEvents.realtimeUnavailable({ sessionId }));
|
|
3567
|
+
}));
|
|
3568
|
+
return (0, rxjs.merge)((0, rxjs.of)(memoryDomainEvents.realtimeConnecting({ sessionId })), metadata$, join$, fatalStatus$).pipe((0, rxjs_operators.takeUntil)((0, rxjs.merge)(shutdown$, fatalSocketShutdown$.pipe((0, rxjs.observeOn)(rxjs.asapScheduler)))), (0, rxjs_operators.finalize)(() => {}));
|
|
3569
|
+
});
|
|
3570
|
+
})))
|
|
3571
|
+
]
|
|
3572
|
+
});
|
|
3573
|
+
function trackMutation(dispatchAction, extract) {
|
|
3574
|
+
const { requestId } = dispatchAction;
|
|
3575
|
+
const resultPromise = (0, rxjs.firstValueFrom)((0, rxjs.merge)(store.actions$.pipe(ofType(memoryRestEvents.mutationFinished), (0, rxjs_operators.filter)((action) => action.outcome.requestId === requestId), (0, rxjs_operators.map)((action) => action.outcome)), store.actions$.pipe(ofType(memoryAdapterEvents.stopped), (0, rxjs_operators.map)(() => ({
|
|
3576
|
+
requestId,
|
|
3577
|
+
sessionId: store.getState().sessionId,
|
|
3578
|
+
ok: false,
|
|
3579
|
+
error: /* @__PURE__ */ new Error("Memory store stopped before mutation completed")
|
|
3580
|
+
})))).pipe((0, rxjs_operators.take)(1))).then((outcome) => {
|
|
3581
|
+
if (!outcome.ok) throw outcome.error;
|
|
3582
|
+
return extract(outcome);
|
|
3583
|
+
});
|
|
3584
|
+
store.dispatch(dispatchAction);
|
|
3585
|
+
return resultPromise;
|
|
3586
|
+
}
|
|
3587
|
+
return {
|
|
3588
|
+
start() {
|
|
3589
|
+
store.init();
|
|
3590
|
+
store.dispatch(memoryAdapterEvents.started());
|
|
3591
|
+
},
|
|
3592
|
+
stop() {
|
|
3593
|
+
store.dispatch(memoryAdapterEvents.stopped());
|
|
3594
|
+
store.stop();
|
|
3595
|
+
},
|
|
3596
|
+
setContext(context) {
|
|
3597
|
+
store.dispatch(memoryAdapterEvents.contextChanged({ context }));
|
|
3598
|
+
},
|
|
3599
|
+
refresh() {
|
|
3600
|
+
const { sessionId, context } = store.getState();
|
|
3601
|
+
if (!context) return Promise.resolve();
|
|
3602
|
+
const done = (0, rxjs.firstValueFrom)((0, rxjs.merge)(store.actions$.pipe(ofType(memoryRestEvents.listSucceeded, memoryRestEvents.listFailed, memoryRestEvents.listUnavailable), (0, rxjs_operators.filter)((action) => action.sessionId === sessionId)), store.actions$.pipe(ofType(memoryAdapterEvents.stopped)), store.actions$.pipe(ofType(memoryAdapterEvents.contextChanged))).pipe((0, rxjs_operators.take)(1))).then((action) => {
|
|
3603
|
+
if (memoryRestEvents.listFailed.match(action)) throw action.error;
|
|
3604
|
+
if (memoryAdapterEvents.stopped.match(action)) throw new Error("Memory store stopped before refresh completed");
|
|
3605
|
+
if (memoryAdapterEvents.contextChanged.match(action)) return;
|
|
3606
|
+
});
|
|
3607
|
+
store.dispatch(memoryRestEvents.listRequested({ sessionId }));
|
|
3608
|
+
return done;
|
|
3609
|
+
},
|
|
3610
|
+
addMemory(input) {
|
|
3611
|
+
return trackMutation(memoryAdapterEvents.addRequested({
|
|
3612
|
+
requestId: createMemoryRequestId(),
|
|
3613
|
+
input
|
|
3614
|
+
}), (outcome) => {
|
|
3615
|
+
if (outcome.memory == null) throw new Error("add resolved without a memory");
|
|
3616
|
+
return outcome.memory;
|
|
3617
|
+
});
|
|
3618
|
+
},
|
|
3619
|
+
updateMemory(id, changes) {
|
|
3620
|
+
return trackMutation(memoryAdapterEvents.updateRequested({
|
|
3621
|
+
requestId: createMemoryRequestId(),
|
|
3622
|
+
id,
|
|
3623
|
+
changes
|
|
3624
|
+
}), (outcome) => {
|
|
3625
|
+
if (outcome.memory == null) throw new Error("update resolved without a memory");
|
|
3626
|
+
return outcome.memory;
|
|
3627
|
+
});
|
|
3628
|
+
},
|
|
3629
|
+
removeMemory(id) {
|
|
3630
|
+
return trackMutation(memoryAdapterEvents.removeRequested({
|
|
3631
|
+
requestId: createMemoryRequestId(),
|
|
3632
|
+
id
|
|
3633
|
+
}), () => void 0);
|
|
3634
|
+
},
|
|
3635
|
+
getState() {
|
|
3636
|
+
return store.getState();
|
|
3637
|
+
},
|
|
3638
|
+
getServerState() {
|
|
3639
|
+
return initialMemoryState;
|
|
3640
|
+
},
|
|
3641
|
+
select: store.select.bind(store)
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3644
|
+
const ɵmemoryAdapterEvents = memoryAdapterEvents;
|
|
3645
|
+
const ɵmemoryRestEvents = memoryRestEvents;
|
|
3646
|
+
const ɵmemoryDomainEvents = memoryDomainEvents;
|
|
3647
|
+
const ɵmemoryReducer = memoryReducer;
|
|
3648
|
+
const ɵmapMemoryMetadataEvent = mapMemoryMetadataEvent;
|
|
3649
|
+
const ɵselectMemories = selectMemories;
|
|
3650
|
+
const ɵselectMemoriesIsLoading = selectMemoriesIsLoading;
|
|
3651
|
+
const ɵselectMemoriesError = selectMemoriesError;
|
|
3652
|
+
const ɵselectMemoriesIsMutating = selectMemoriesIsMutating;
|
|
3653
|
+
const ɵselectMemoriesAvailable = selectMemoriesAvailable;
|
|
3654
|
+
const ɵselectMemoriesRealtimeStatus = selectMemoriesRealtimeStatus;
|
|
3655
|
+
|
|
3656
|
+
//#endregion
|
|
3657
|
+
//#region src/core/core.ts
|
|
3658
|
+
let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode) {
|
|
3659
|
+
CopilotKitCoreErrorCode["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
|
|
3660
|
+
CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
|
|
3661
|
+
CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
|
|
3662
|
+
CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
|
|
3663
|
+
CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
|
|
3664
|
+
CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
|
|
3665
|
+
CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
|
|
3666
|
+
CopilotKitCoreErrorCode["TOOL_NOT_FOUND"] = "tool_not_found";
|
|
3667
|
+
CopilotKitCoreErrorCode["AGENT_NOT_FOUND"] = "agent_not_found";
|
|
3668
|
+
/**
|
|
3669
|
+
* Emitted when an agent run fails because the thread is already locked
|
|
3670
|
+
* by another active run.
|
|
3671
|
+
*
|
|
3672
|
+
* @example
|
|
3673
|
+
* ```tsx
|
|
3674
|
+
* <CopilotKitProvider
|
|
3675
|
+
* onError={({ code, error, context }) => {
|
|
3676
|
+
* if (code === "agent_thread_locked") {
|
|
3677
|
+
* // Show "Agent is busy, retry?" UI
|
|
3678
|
+
* }
|
|
3679
|
+
* }}
|
|
3680
|
+
* />
|
|
3681
|
+
* ```
|
|
3682
|
+
*/
|
|
3683
|
+
CopilotKitCoreErrorCode["AGENT_THREAD_LOCKED"] = "agent_thread_locked";
|
|
3684
|
+
CopilotKitCoreErrorCode["TRANSCRIPTION_FAILED"] = "transcription_failed";
|
|
3685
|
+
CopilotKitCoreErrorCode["TRANSCRIPTION_SERVICE_NOT_CONFIGURED"] = "transcription_service_not_configured";
|
|
3686
|
+
CopilotKitCoreErrorCode["TRANSCRIPTION_INVALID_AUDIO"] = "transcription_invalid_audio";
|
|
3687
|
+
CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
|
|
3688
|
+
CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
|
|
3689
|
+
CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
|
|
3690
|
+
CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
|
|
3691
|
+
return CopilotKitCoreErrorCode;
|
|
3692
|
+
}({});
|
|
3693
|
+
/**
|
|
3694
|
+
* Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
|
|
3695
|
+
* to module scope so the Set is allocated once, not per-subscription.
|
|
3696
|
+
*/
|
|
3697
|
+
const ALLOWED_KEYS = new Set([
|
|
3698
|
+
"onMessagesChanged",
|
|
3699
|
+
"onStateChanged",
|
|
3700
|
+
"onRunInitialized",
|
|
3701
|
+
"onRunFinalized",
|
|
3702
|
+
"onRunFailed",
|
|
3703
|
+
"onRunErrorEvent"
|
|
3704
|
+
]);
|
|
3705
|
+
let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
|
|
3706
|
+
CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
|
|
3707
|
+
CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
|
|
3708
|
+
CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
|
|
3709
|
+
CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
|
|
3710
|
+
return CopilotKitCoreRuntimeConnectionStatus;
|
|
3711
|
+
}({});
|
|
3712
|
+
/**
|
|
3713
|
+
* Normalize a header map to the internal invariant: a `Record<string, string>`
|
|
3714
|
+
* with no `null`/`undefined` values. Entries whose value is `null`/`undefined`
|
|
3715
|
+
* are dropped (this is how a header is cleared). Shared by the constructor and
|
|
3716
|
+
* `setHeaders` so both write paths into `_headers` enforce the same invariant.
|
|
3717
|
+
*/
|
|
3718
|
+
function normalizeHeaders(headers) {
|
|
3719
|
+
return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
|
|
3720
|
+
}
|
|
3721
|
+
var CopilotKitCore = class {
|
|
3722
|
+
_headers;
|
|
3723
|
+
_credentials;
|
|
3724
|
+
_properties;
|
|
3725
|
+
_defaultThrottleMs;
|
|
3726
|
+
_debug;
|
|
3727
|
+
subscribers = /* @__PURE__ */ new Set();
|
|
3728
|
+
agentRegistry;
|
|
3729
|
+
contextStore;
|
|
3730
|
+
suggestionEngine;
|
|
3731
|
+
runHandler;
|
|
3732
|
+
stateManager;
|
|
3733
|
+
subagentRegistry;
|
|
3734
|
+
threadStoreRegistry;
|
|
3735
|
+
/**
|
|
3736
|
+
* The single core-owned memory store, created lazily on first
|
|
3737
|
+
* `getMemoryStore()` and kept user-scoped for the lifetime of the core.
|
|
3738
|
+
* Its runtime context is wired by the core itself (see `syncMemoryContext`),
|
|
3739
|
+
* so callers never register or look it up by `agentId`.
|
|
3740
|
+
*/
|
|
3741
|
+
_memoryStore;
|
|
3742
|
+
/**
|
|
3743
|
+
* Tracks the agent IDs from the most recent `onAgentsChanged` notification.
|
|
3744
|
+
* Used to gate thread-store auto-unregister so the FIRST empty-agents
|
|
3745
|
+
* notification (before published agents are merged in) does not rip out a
|
|
3746
|
+
* store that was registered prior to that initial notification.
|
|
3747
|
+
*/
|
|
3748
|
+
previousAgentIds = /* @__PURE__ */ new Set();
|
|
3749
|
+
constructor({ runtimeUrl, runtimeTransport = "auto", headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
|
|
3750
|
+
this._headers = normalizeHeaders(headers);
|
|
3751
|
+
this._credentials = credentials;
|
|
3752
|
+
this._properties = properties;
|
|
3753
|
+
this._debug = debug;
|
|
3754
|
+
this.agentRegistry = new AgentRegistry(this);
|
|
3755
|
+
this.contextStore = new ContextStore(this);
|
|
3756
|
+
this.suggestionEngine = new SuggestionEngine(this);
|
|
3757
|
+
this.runHandler = new RunHandler(this);
|
|
3758
|
+
this.stateManager = new StateManager(this);
|
|
3759
|
+
this.subagentRegistry = new SubagentRegistry(this);
|
|
3760
|
+
this.threadStoreRegistry = new ThreadStoreRegistry(this);
|
|
3761
|
+
this.agentRegistry.initialize(agents__unsafe_dev_only);
|
|
3762
|
+
this.runHandler.initialize(tools);
|
|
3763
|
+
this.suggestionEngine.initialize(suggestionsConfig);
|
|
3764
|
+
this.stateManager.initialize();
|
|
3765
|
+
this.agentRegistry.setRuntimeTransport(runtimeTransport);
|
|
3766
|
+
this.agentRegistry.setRuntimeUrl(runtimeUrl);
|
|
3767
|
+
this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
|
|
3768
|
+
this.subscribe({
|
|
3769
|
+
onRuntimeConnectionStatusChanged: () => {
|
|
3770
|
+
if (this._memoryStore) this.syncMemoryContext();
|
|
3771
|
+
},
|
|
3772
|
+
onAgentsChanged: ({ agents }) => {
|
|
3773
|
+
Object.values(agents).forEach((agent) => {
|
|
3774
|
+
if (agent.agentId) {
|
|
3775
|
+
this.stateManager.subscribeToAgent(agent);
|
|
3776
|
+
this.subagentRegistry.subscribeToAgent(agent);
|
|
3777
|
+
}
|
|
3778
|
+
});
|
|
3779
|
+
const currentAgentIds = new Set(Object.keys(agents));
|
|
3780
|
+
for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) try {
|
|
3781
|
+
this.threadStoreRegistry.unregister(agentId);
|
|
3782
|
+
} catch (err) {
|
|
3783
|
+
console.error(`CopilotKitCore.onAgentsChanged: threadStoreRegistry.unregister failed for "${agentId}":`, err);
|
|
3784
|
+
}
|
|
3785
|
+
for (const agentId of this.previousAgentIds) if (!currentAgentIds.has(agentId)) {
|
|
3786
|
+
try {
|
|
3787
|
+
this.stateManager.unsubscribeFromAgent(agentId);
|
|
3788
|
+
} catch (err) {
|
|
3789
|
+
console.error(`CopilotKitCore.onAgentsChanged: stateManager.unsubscribeFromAgent failed for "${agentId}":`, err);
|
|
3790
|
+
}
|
|
3791
|
+
try {
|
|
3792
|
+
this.subagentRegistry.unsubscribeFromAgent(agentId);
|
|
3793
|
+
} catch (err) {
|
|
3794
|
+
console.error(`CopilotKitCore.onAgentsChanged: subagentRegistry.unsubscribeFromAgent failed for "${agentId}":`, err);
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
this.previousAgentIds = currentAgentIds;
|
|
3798
|
+
}
|
|
3799
|
+
});
|
|
3800
|
+
}
|
|
3801
|
+
/**
|
|
3802
|
+
* Internal method used by delegate classes and subclasses to notify subscribers
|
|
3803
|
+
*/
|
|
3804
|
+
async notifySubscribers(handler, errorMessage) {
|
|
3805
|
+
await Promise.all(Array.from(this.subscribers).map(async (subscriber) => {
|
|
3806
|
+
try {
|
|
3807
|
+
await handler(subscriber);
|
|
3808
|
+
} catch (error) {
|
|
3809
|
+
console.error(errorMessage, error);
|
|
3810
|
+
}
|
|
3811
|
+
}));
|
|
3812
|
+
}
|
|
3813
|
+
/**
|
|
3814
|
+
* Internal method used by delegate classes to emit errors
|
|
3815
|
+
*/
|
|
3816
|
+
async emitError({ error, code, context = {} }) {
|
|
3817
|
+
await this.notifySubscribers((subscriber) => subscriber.onError?.({
|
|
3818
|
+
copilotkit: this,
|
|
3819
|
+
error,
|
|
3820
|
+
code,
|
|
3821
|
+
context
|
|
3822
|
+
}), "Subscriber onError error:");
|
|
3823
|
+
}
|
|
3824
|
+
/**
|
|
3825
|
+
* Log a message to the console and emit an error to subscribers.
|
|
3826
|
+
* Catches failures from `emitError` itself to prevent unhandled rejections.
|
|
3827
|
+
*/
|
|
3828
|
+
logAndEmitError(message, params, logLevel = "error") {
|
|
3829
|
+
console[logLevel](message, params.error);
|
|
3830
|
+
this.emitError(params).catch((emitErr) => {
|
|
3831
|
+
console.error(message + " — emitError itself failed:", emitErr);
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
/**
|
|
3835
|
+
* Snapshot accessors
|
|
3836
|
+
*/
|
|
3837
|
+
get context() {
|
|
3838
|
+
return this.contextStore.context;
|
|
3839
|
+
}
|
|
3840
|
+
get agents() {
|
|
3841
|
+
return this.agentRegistry.agents;
|
|
3842
|
+
}
|
|
3843
|
+
get tools() {
|
|
3844
|
+
return this.runHandler.tools;
|
|
3845
|
+
}
|
|
3846
|
+
get runtimeUrl() {
|
|
3847
|
+
return this.agentRegistry.runtimeUrl;
|
|
3848
|
+
}
|
|
3849
|
+
setRuntimeUrl(runtimeUrl) {
|
|
3850
|
+
this.agentRegistry.setRuntimeUrl(runtimeUrl);
|
|
3851
|
+
}
|
|
3852
|
+
get runtimeTransport() {
|
|
3853
|
+
return this.agentRegistry.runtimeTransport;
|
|
3854
|
+
}
|
|
3855
|
+
setRuntimeTransport(runtimeTransport) {
|
|
3856
|
+
this.agentRegistry.setRuntimeTransport(runtimeTransport);
|
|
3857
|
+
}
|
|
3858
|
+
get runtimeVersion() {
|
|
3859
|
+
return this.agentRegistry.runtimeVersion;
|
|
3860
|
+
}
|
|
3861
|
+
get headers() {
|
|
3862
|
+
return this._headers;
|
|
3863
|
+
}
|
|
3864
|
+
get credentials() {
|
|
3865
|
+
return this._credentials;
|
|
3866
|
+
}
|
|
3867
|
+
get properties() {
|
|
3868
|
+
return this._properties;
|
|
3869
|
+
}
|
|
3870
|
+
/**
|
|
3871
|
+
* Default throttle interval (ms) used by `subscribeToAgentWithOptions()`
|
|
3872
|
+
* when the caller does not specify an explicit `throttleMs`.
|
|
3873
|
+
* `undefined` means no default is configured; `0` means no throttling.
|
|
3874
|
+
*/
|
|
3875
|
+
get defaultThrottleMs() {
|
|
3876
|
+
return this._defaultThrottleMs;
|
|
3877
|
+
}
|
|
3878
|
+
/**
|
|
3879
|
+
* Set the default throttle interval (ms) for `subscribeToAgentWithOptions()`.
|
|
3880
|
+
*
|
|
3881
|
+
* Accepts a non-negative finite number or `undefined` (to clear the
|
|
3882
|
+
* default). Invalid values (NaN, Infinity, negative) are logged as
|
|
3883
|
+
* errors and ignored — the previous valid value is preserved.
|
|
3884
|
+
*/
|
|
2724
3885
|
setDefaultThrottleMs(value) {
|
|
2725
3886
|
if (value !== void 0 && (!Number.isFinite(value) || value < 0)) {
|
|
2726
3887
|
this.logAndEmitError(`CopilotKitCore.setDefaultThrottleMs: value must be a non-negative finite number or undefined, got ${value}. Keeping current value (${this._defaultThrottleMs}).`, {
|
|
@@ -2809,6 +3970,7 @@ var CopilotKitCore = class {
|
|
|
2809
3970
|
*/
|
|
2810
3971
|
setHeaders(headers) {
|
|
2811
3972
|
this._headers = normalizeHeaders(headers);
|
|
3973
|
+
if (this._memoryStore) this.syncMemoryContext();
|
|
2812
3974
|
this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
|
|
2813
3975
|
this.notifySubscribers((subscriber) => subscriber.onHeadersChanged?.({
|
|
2814
3976
|
copilotkit: this,
|
|
@@ -2914,6 +4076,46 @@ var CopilotKitCore = class {
|
|
|
2914
4076
|
return this.threadStoreRegistry.getAll();
|
|
2915
4077
|
}
|
|
2916
4078
|
/**
|
|
4079
|
+
* Returns the single core-owned, user-scoped memory store, creating and
|
|
4080
|
+
* starting it on first access. Unlike thread stores, memory is not scoped per
|
|
4081
|
+
* agent: there is exactly one store whose runtime context the core wires
|
|
4082
|
+
* itself (see `syncMemoryContext`), so consumers (e.g. a `useMemories`
|
|
4083
|
+
* binding) just read this store rather than registering one.
|
|
4084
|
+
*/
|
|
4085
|
+
getMemoryStore() {
|
|
4086
|
+
return this.ensureMemoryStore();
|
|
4087
|
+
}
|
|
4088
|
+
/**
|
|
4089
|
+
* Lazily creates, starts, and context-syncs the core-owned memory store on
|
|
4090
|
+
* first access, then returns it. Subsequent calls return the existing store.
|
|
4091
|
+
* The store is constructed with a bound `globalThis.fetch` and immediately
|
|
4092
|
+
* has its runtime context synced from the current connection state.
|
|
4093
|
+
*/
|
|
4094
|
+
ensureMemoryStore() {
|
|
4095
|
+
if (!this._memoryStore) {
|
|
4096
|
+
this._memoryStore = createMemoryStore({ fetch: globalThis.fetch.bind(globalThis) });
|
|
4097
|
+
this._memoryStore.start();
|
|
4098
|
+
this.syncMemoryContext();
|
|
4099
|
+
}
|
|
4100
|
+
return this._memoryStore;
|
|
4101
|
+
}
|
|
4102
|
+
/**
|
|
4103
|
+
* Pushes the current runtime wiring into the memory store. When the runtime
|
|
4104
|
+
* is connected and both the intelligence WebSocket URL and runtime URL are
|
|
4105
|
+
* available, the store receives a context (runtime URL, WebSocket URL, and a
|
|
4106
|
+
* copy of the current headers); otherwise its context is cleared. No-op when
|
|
4107
|
+
* the store has not been created yet.
|
|
4108
|
+
*/
|
|
4109
|
+
syncMemoryContext() {
|
|
4110
|
+
if (!this._memoryStore) return;
|
|
4111
|
+
if (this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected && this.intelligence?.wsUrl && this.runtimeUrl) this._memoryStore.setContext({
|
|
4112
|
+
runtimeUrl: this.runtimeUrl,
|
|
4113
|
+
wsUrl: this.intelligence.wsUrl,
|
|
4114
|
+
headers: { ...this.headers }
|
|
4115
|
+
});
|
|
4116
|
+
else this._memoryStore.setContext(null);
|
|
4117
|
+
}
|
|
4118
|
+
/**
|
|
2917
4119
|
* Suggestions management (delegated to SuggestionEngine)
|
|
2918
4120
|
*/
|
|
2919
4121
|
addSuggestionsConfig(config) {
|
|
@@ -2932,6 +4134,16 @@ var CopilotKitCore = class {
|
|
|
2932
4134
|
return this.suggestionEngine.getSuggestions(agentId);
|
|
2933
4135
|
}
|
|
2934
4136
|
/**
|
|
4137
|
+
* Subagent registry (delegated to SubagentRegistry).
|
|
4138
|
+
*
|
|
4139
|
+
* Returns the subagents observed for an owning agent during its run(s),
|
|
4140
|
+
* keyed by `subagentId`, each carrying `name` / `description` / `status`.
|
|
4141
|
+
* Empty for runs that never emit SUBAGENT_* events.
|
|
4142
|
+
*/
|
|
4143
|
+
getSubagents(agentId) {
|
|
4144
|
+
return this.subagentRegistry.getSubagents(agentId);
|
|
4145
|
+
}
|
|
4146
|
+
/**
|
|
2935
4147
|
* Tool management (delegated to RunHandler)
|
|
2936
4148
|
*/
|
|
2937
4149
|
addTool(tool) {
|
|
@@ -3076,515 +4288,259 @@ var CopilotKitCore = class {
|
|
|
3076
4288
|
throttler.maybeExecute();
|
|
3077
4289
|
};
|
|
3078
4290
|
if (subscriber.onStateChanged) wrappedSubscriber.onStateChanged = (params) => {
|
|
3079
|
-
latestStateParams = params;
|
|
3080
|
-
throttler.maybeExecute();
|
|
3081
|
-
};
|
|
3082
|
-
const subscription = agent.subscribe(wrappedSubscriber);
|
|
3083
|
-
return { unsubscribe: () => {
|
|
3084
|
-
active = false;
|
|
3085
|
-
throttler.cancel();
|
|
3086
|
-
subscription.unsubscribe();
|
|
3087
|
-
} };
|
|
3088
|
-
}
|
|
3089
|
-
/**
|
|
3090
|
-
* Agent connectivity (delegated to RunHandler)
|
|
3091
|
-
*/
|
|
3092
|
-
async connectAgent(params) {
|
|
3093
|
-
return this.runHandler.connectAgent(params);
|
|
3094
|
-
}
|
|
3095
|
-
stopAgent(params) {
|
|
3096
|
-
this.runHandler.abortCurrentRun();
|
|
3097
|
-
params.agent.abortRun();
|
|
3098
|
-
}
|
|
3099
|
-
async runAgent(params) {
|
|
3100
|
-
return this.runHandler.runAgent(params);
|
|
3101
|
-
}
|
|
3102
|
-
/**
|
|
3103
|
-
* Programmatically execute a registered frontend tool without going through an LLM turn.
|
|
3104
|
-
* The handler runs, render components show up in the UI, and both the tool call and
|
|
3105
|
-
* result messages are added to `agent.messages`.
|
|
3106
|
-
*/
|
|
3107
|
-
async runTool(params) {
|
|
3108
|
-
return this.runHandler.runTool(params);
|
|
3109
|
-
}
|
|
3110
|
-
/**
|
|
3111
|
-
* State management (delegated to StateManager)
|
|
3112
|
-
*/
|
|
3113
|
-
getStateByRun(agentId, threadId, runId) {
|
|
3114
|
-
return this.stateManager.getStateByRun(agentId, threadId, runId);
|
|
3115
|
-
}
|
|
3116
|
-
getRunIdForMessage(agentId, threadId, messageId) {
|
|
3117
|
-
return this.stateManager.getRunIdForMessage(agentId, threadId, messageId);
|
|
3118
|
-
}
|
|
3119
|
-
getRunIdsForThread(agentId, threadId) {
|
|
3120
|
-
return this.stateManager.getRunIdsForThread(agentId, threadId);
|
|
3121
|
-
}
|
|
3122
|
-
/**
|
|
3123
|
-
* Internal method used by RunHandler to build frontend tools
|
|
3124
|
-
*/
|
|
3125
|
-
buildFrontendTools(agentId) {
|
|
3126
|
-
return this.runHandler.buildFrontendTools(agentId);
|
|
3127
|
-
}
|
|
3128
|
-
/**
|
|
3129
|
-
* Called before each follow-up agent run (after tool execution).
|
|
3130
|
-
*
|
|
3131
|
-
* When a frontend tool handler calls framework state setters (e.g. React's
|
|
3132
|
-
* setState), those updates are batched and deferred — they do not take effect
|
|
3133
|
-
* until the framework's scheduler runs (React uses MessageChannel).
|
|
3134
|
-
* useAgentContext registers context via useLayoutEffect, which runs
|
|
3135
|
-
* synchronously after React commits that deferred batch.
|
|
3136
|
-
*
|
|
3137
|
-
* Without yielding here, the follow-up runAgent reads the context store
|
|
3138
|
-
* synchronously while the deferred updates are still pending, producing stale
|
|
3139
|
-
* context for the next agent turn.
|
|
3140
|
-
*
|
|
3141
|
-
* Override in framework-specific subclasses to yield to the framework
|
|
3142
|
-
* scheduler before the follow-up run. The base implementation is a no-op
|
|
3143
|
-
* because non-React environments have no deferred state to flush.
|
|
3144
|
-
*/
|
|
3145
|
-
async waitForPendingFrameworkUpdates() {}
|
|
3146
|
-
};
|
|
3147
|
-
|
|
3148
|
-
//#endregion
|
|
3149
|
-
//#region src/types.ts
|
|
3150
|
-
/**
|
|
3151
|
-
* Status of a tool call execution
|
|
3152
|
-
*/
|
|
3153
|
-
let ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
|
|
3154
|
-
ToolCallStatus["InProgress"] = "inProgress";
|
|
3155
|
-
ToolCallStatus["Executing"] = "executing";
|
|
3156
|
-
ToolCallStatus["Complete"] = "complete";
|
|
3157
|
-
return ToolCallStatus;
|
|
3158
|
-
}({});
|
|
3159
|
-
|
|
3160
|
-
//#endregion
|
|
3161
|
-
//#region src/utils/markdown.ts
|
|
3162
|
-
function completePartialMarkdown(input) {
|
|
3163
|
-
let s = input;
|
|
3164
|
-
const fenceMatches = Array.from(s.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
|
|
3165
|
-
if (fenceMatches.length % 2 === 1) {
|
|
3166
|
-
const [, indent, fence] = fenceMatches[0];
|
|
3167
|
-
s += `\n${indent}${fence}`;
|
|
3168
|
-
}
|
|
3169
|
-
if (s.match(/\[([^\]]*)\]\(([^)]*)$/)) s += ")";
|
|
3170
|
-
const openElements = [];
|
|
3171
|
-
const chars = Array.from(s);
|
|
3172
|
-
const codeBlockRanges = [];
|
|
3173
|
-
const inlineCodeRanges = [];
|
|
3174
|
-
let tempCodeFenceCount = 0;
|
|
3175
|
-
let currentCodeBlockStart = -1;
|
|
3176
|
-
for (let i = 0; i < chars.length; i++) if (i === 0 || chars[i - 1] === "\n") {
|
|
3177
|
-
const lineMatch = s.substring(i).match(/^(\s*)(`{3,}|~{3,})/);
|
|
3178
|
-
if (lineMatch) {
|
|
3179
|
-
tempCodeFenceCount++;
|
|
3180
|
-
if (tempCodeFenceCount % 2 === 1) currentCodeBlockStart = i;
|
|
3181
|
-
else if (currentCodeBlockStart !== -1) {
|
|
3182
|
-
codeBlockRanges.push({
|
|
3183
|
-
start: currentCodeBlockStart,
|
|
3184
|
-
end: i + lineMatch[0].length
|
|
3185
|
-
});
|
|
3186
|
-
currentCodeBlockStart = -1;
|
|
3187
|
-
}
|
|
3188
|
-
i += lineMatch[0].length - 1;
|
|
3189
|
-
}
|
|
3190
|
-
}
|
|
3191
|
-
for (let i = 0; i < chars.length; i++) if (chars[i] === "`") {
|
|
3192
|
-
let backslashCount = 0;
|
|
3193
|
-
for (let j = i - 1; j >= 0 && chars[j] === "\\"; j--) backslashCount++;
|
|
3194
|
-
if (backslashCount % 2 === 0) {
|
|
3195
|
-
for (let j = i + 1; j < chars.length; j++) if (chars[j] === "`") {
|
|
3196
|
-
let closingBackslashCount = 0;
|
|
3197
|
-
for (let k = j - 1; k >= 0 && chars[k] === "\\"; k--) closingBackslashCount++;
|
|
3198
|
-
if (closingBackslashCount % 2 === 0) {
|
|
3199
|
-
inlineCodeRanges.push({
|
|
3200
|
-
start: i,
|
|
3201
|
-
end: j + 1
|
|
3202
|
-
});
|
|
3203
|
-
i = j;
|
|
3204
|
-
break;
|
|
3205
|
-
}
|
|
3206
|
-
}
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
const isInCode = (pos) => {
|
|
3210
|
-
return codeBlockRanges.some((range) => pos >= range.start && pos < range.end) || inlineCodeRanges.some((range) => pos >= range.start && pos < range.end);
|
|
3211
|
-
};
|
|
3212
|
-
for (let i = 0; i < chars.length; i++) {
|
|
3213
|
-
const char = chars[i];
|
|
3214
|
-
const nextChar = chars[i + 1];
|
|
3215
|
-
const prevChar = chars[i - 1];
|
|
3216
|
-
if (isInCode(i)) continue;
|
|
3217
|
-
if (char === "[") {
|
|
3218
|
-
let isCompleteLink = false;
|
|
3219
|
-
let bracketDepth = 1;
|
|
3220
|
-
let j = i + 1;
|
|
3221
|
-
while (j < chars.length && bracketDepth > 0) {
|
|
3222
|
-
if (chars[j] === "[" && !isInCode(j)) bracketDepth++;
|
|
3223
|
-
if (chars[j] === "]" && !isInCode(j)) bracketDepth--;
|
|
3224
|
-
j++;
|
|
3225
|
-
}
|
|
3226
|
-
if (bracketDepth === 0 && chars[j] === "(") {
|
|
3227
|
-
let parenDepth = 1;
|
|
3228
|
-
j++;
|
|
3229
|
-
while (j < chars.length && parenDepth > 0) {
|
|
3230
|
-
if (chars[j] === "(" && !isInCode(j)) parenDepth++;
|
|
3231
|
-
if (chars[j] === ")" && !isInCode(j)) parenDepth--;
|
|
3232
|
-
j++;
|
|
3233
|
-
}
|
|
3234
|
-
if (parenDepth === 0) {
|
|
3235
|
-
isCompleteLink = true;
|
|
3236
|
-
i = j - 1;
|
|
3237
|
-
continue;
|
|
3238
|
-
}
|
|
3239
|
-
}
|
|
3240
|
-
if (!isCompleteLink) {
|
|
3241
|
-
const existingIndex = openElements.findIndex((el) => el.type === "bracket");
|
|
3242
|
-
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
3243
|
-
else openElements.push({
|
|
3244
|
-
type: "bracket",
|
|
3245
|
-
marker: "[",
|
|
3246
|
-
position: i
|
|
3247
|
-
});
|
|
3248
|
-
}
|
|
3249
|
-
} else if (char === "*" && nextChar === "*") {
|
|
3250
|
-
const existingIndex = openElements.findIndex((el) => el.type === "bold_star");
|
|
3251
|
-
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
3252
|
-
else openElements.push({
|
|
3253
|
-
type: "bold_star",
|
|
3254
|
-
marker: "**",
|
|
3255
|
-
position: i
|
|
3256
|
-
});
|
|
3257
|
-
i++;
|
|
3258
|
-
} else if (char === "_" && nextChar === "_") {
|
|
3259
|
-
const existingIndex = openElements.findIndex((el) => el.type === "bold_underscore");
|
|
3260
|
-
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
3261
|
-
else openElements.push({
|
|
3262
|
-
type: "bold_underscore",
|
|
3263
|
-
marker: "__",
|
|
3264
|
-
position: i
|
|
3265
|
-
});
|
|
3266
|
-
i++;
|
|
3267
|
-
} else if (char === "~" && nextChar === "~") {
|
|
3268
|
-
const existingIndex = openElements.findIndex((el) => el.type === "strike");
|
|
3269
|
-
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
3270
|
-
else openElements.push({
|
|
3271
|
-
type: "strike",
|
|
3272
|
-
marker: "~~",
|
|
3273
|
-
position: i
|
|
3274
|
-
});
|
|
3275
|
-
i++;
|
|
3276
|
-
} else if (char === "*" && prevChar !== "*" && nextChar !== "*") {
|
|
3277
|
-
const existingIndex = openElements.findIndex((el) => el.type === "italic_star");
|
|
3278
|
-
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
3279
|
-
else openElements.push({
|
|
3280
|
-
type: "italic_star",
|
|
3281
|
-
marker: "*",
|
|
3282
|
-
position: i
|
|
3283
|
-
});
|
|
3284
|
-
} else if (char === "_" && prevChar !== "_" && nextChar !== "_") {
|
|
3285
|
-
const existingIndex = openElements.findIndex((el) => el.type === "italic_underscore");
|
|
3286
|
-
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
3287
|
-
else openElements.push({
|
|
3288
|
-
type: "italic_underscore",
|
|
3289
|
-
marker: "_",
|
|
3290
|
-
position: i
|
|
3291
|
-
});
|
|
3292
|
-
}
|
|
3293
|
-
}
|
|
3294
|
-
let backtickCount = 0;
|
|
3295
|
-
for (let i = 0; i < chars.length; i++) if (chars[i] === "`" && !isInCode(i)) backtickCount++;
|
|
3296
|
-
if (backtickCount % 2 === 1) s += "`";
|
|
3297
|
-
openElements.sort((a, b) => b.position - a.position);
|
|
3298
|
-
const closers = openElements.map((el) => {
|
|
3299
|
-
switch (el.type) {
|
|
3300
|
-
case "bracket": return "]";
|
|
3301
|
-
case "bold_star": return "**";
|
|
3302
|
-
case "bold_underscore": return "__";
|
|
3303
|
-
case "strike": return "~~";
|
|
3304
|
-
case "italic_star": return "*";
|
|
3305
|
-
case "italic_underscore": return "_";
|
|
3306
|
-
default: return "";
|
|
3307
|
-
}
|
|
3308
|
-
});
|
|
3309
|
-
let result = s + closers.join("");
|
|
3310
|
-
const finalFenceMatches = Array.from(result.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
|
|
3311
|
-
const hasUnclosedBacktick = (result.match(/`/g) || []).length % 2 === 1;
|
|
3312
|
-
const hasUnclosedCodeFence = finalFenceMatches.length % 2 === 1;
|
|
3313
|
-
let shouldCloseParens = !hasUnclosedBacktick && !hasUnclosedCodeFence;
|
|
3314
|
-
if (shouldCloseParens) {
|
|
3315
|
-
const lastOpenParen = result.lastIndexOf("(");
|
|
3316
|
-
if (lastOpenParen !== -1) {
|
|
3317
|
-
if ((result.substring(0, lastOpenParen).match(/`/g) || []).length % 2 === 1) shouldCloseParens = false;
|
|
3318
|
-
}
|
|
4291
|
+
latestStateParams = params;
|
|
4292
|
+
throttler.maybeExecute();
|
|
4293
|
+
};
|
|
4294
|
+
const subscription = agent.subscribe(wrappedSubscriber);
|
|
4295
|
+
return { unsubscribe: () => {
|
|
4296
|
+
active = false;
|
|
4297
|
+
throttler.cancel();
|
|
4298
|
+
subscription.unsubscribe();
|
|
4299
|
+
} };
|
|
3319
4300
|
}
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
4301
|
+
/**
|
|
4302
|
+
* Agent connectivity (delegated to RunHandler)
|
|
4303
|
+
*/
|
|
4304
|
+
async connectAgent(params) {
|
|
4305
|
+
return this.runHandler.connectAgent(params);
|
|
3324
4306
|
}
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
//#endregion
|
|
3329
|
-
//#region src/utils/micro-redux.ts
|
|
3330
|
-
const INTERNAL_ACTION_TYPES = {
|
|
3331
|
-
boot: "@@micro-redux/boot",
|
|
3332
|
-
init: "@@micro-redux/init",
|
|
3333
|
-
stop: "@@micro-redux/stop"
|
|
3334
|
-
};
|
|
3335
|
-
const INTERNAL_BOOT_ACTION = { type: INTERNAL_ACTION_TYPES.boot };
|
|
3336
|
-
/**
|
|
3337
|
-
* Builds a typed action creator from a type string and payload factory.
|
|
3338
|
-
*/
|
|
3339
|
-
function createTypedActionCreator(type, factory) {
|
|
3340
|
-
const creator = ((...args) => ({
|
|
3341
|
-
...factory(...args),
|
|
3342
|
-
type
|
|
3343
|
-
}));
|
|
3344
|
-
creator.type = type;
|
|
3345
|
-
creator.match = (action) => action.type === type;
|
|
3346
|
-
return creator;
|
|
3347
|
-
}
|
|
3348
|
-
/**
|
|
3349
|
-
* Declares a payload-based action config for `createActionGroup`.
|
|
3350
|
-
*
|
|
3351
|
-
* @example
|
|
3352
|
-
* ```ts
|
|
3353
|
-
* const actions = createActionGroup("User", {
|
|
3354
|
-
* loaded: props<{ id: string }>(),
|
|
3355
|
-
* });
|
|
3356
|
-
* ```
|
|
3357
|
-
*/
|
|
3358
|
-
function props() {
|
|
3359
|
-
return { kind: "props" };
|
|
3360
|
-
}
|
|
3361
|
-
/**
|
|
3362
|
-
* Declares a no-payload action config for `createActionGroup`.
|
|
3363
|
-
*
|
|
3364
|
-
* @example
|
|
3365
|
-
* ```ts
|
|
3366
|
-
* const actions = createActionGroup("User", {
|
|
3367
|
-
* reset: empty(),
|
|
3368
|
-
* });
|
|
3369
|
-
* ```
|
|
3370
|
-
*/
|
|
3371
|
-
function empty() {
|
|
3372
|
-
return { kind: "empty" };
|
|
3373
|
-
}
|
|
3374
|
-
/**
|
|
3375
|
-
* Creates a namespaced group of typed action creators.
|
|
3376
|
-
*
|
|
3377
|
-
* Action types are formatted as: `[Source] actionName`.
|
|
3378
|
-
*/
|
|
3379
|
-
function createActionGroup(source, config) {
|
|
3380
|
-
const group = {};
|
|
3381
|
-
for (const eventName of Object.keys(config)) {
|
|
3382
|
-
const eventConfig = config[eventName];
|
|
3383
|
-
if (!eventConfig) continue;
|
|
3384
|
-
const actionType = `[${source}] ${eventName}`;
|
|
3385
|
-
if (eventConfig.kind === "props") {
|
|
3386
|
-
group[eventName] = createTypedActionCreator(actionType, (payload) => ({ ...payload }));
|
|
3387
|
-
continue;
|
|
3388
|
-
}
|
|
3389
|
-
group[eventName] = createTypedActionCreator(actionType, () => ({}));
|
|
4307
|
+
stopAgent(params) {
|
|
4308
|
+
this.runHandler.abortCurrentRun();
|
|
4309
|
+
params.agent.abortRun();
|
|
3390
4310
|
}
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
/**
|
|
3394
|
-
* Registers one reducer handler for one or more action creators.
|
|
3395
|
-
*
|
|
3396
|
-
* @throws Error when called without at least one action creator and reducer.
|
|
3397
|
-
*/
|
|
3398
|
-
function on(...args) {
|
|
3399
|
-
if (args.length < 2) throw new Error("on requires at least one action creator and one reducer");
|
|
3400
|
-
const reducer = args[args.length - 1];
|
|
3401
|
-
return {
|
|
3402
|
-
creators: args.slice(0, -1),
|
|
3403
|
-
reducer
|
|
3404
|
-
};
|
|
3405
|
-
}
|
|
3406
|
-
/**
|
|
3407
|
-
* Creates a reducer from an initial state and `on(...)` handler entries.
|
|
3408
|
-
*
|
|
3409
|
-
* Unknown action types return the current state unchanged.
|
|
3410
|
-
*/
|
|
3411
|
-
function createReducer(initialState, ...entries) {
|
|
3412
|
-
const reducerMap = /* @__PURE__ */ new Map();
|
|
3413
|
-
for (const entry of entries) for (const creator of entry.creators) {
|
|
3414
|
-
const handlers = reducerMap.get(creator.type) ?? [];
|
|
3415
|
-
handlers.push(entry.reducer);
|
|
3416
|
-
reducerMap.set(creator.type, handlers);
|
|
4311
|
+
async runAgent(params) {
|
|
4312
|
+
return this.runHandler.runAgent(params);
|
|
3417
4313
|
}
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
return
|
|
3425
|
-
};
|
|
3426
|
-
}
|
|
3427
|
-
/**
|
|
3428
|
-
* Creates a selector that caches and reuses the last computed result
|
|
3429
|
-
* when all input references are unchanged.
|
|
3430
|
-
*/
|
|
3431
|
-
function createSelector(...args) {
|
|
3432
|
-
if (args.length === 1) {
|
|
3433
|
-
const projector = args[0];
|
|
3434
|
-
let hasCached = false;
|
|
3435
|
-
let lastState;
|
|
3436
|
-
let lastResult;
|
|
3437
|
-
return (state) => {
|
|
3438
|
-
if (hasCached && state === lastState) return lastResult;
|
|
3439
|
-
lastState = state;
|
|
3440
|
-
lastResult = projector(state);
|
|
3441
|
-
hasCached = true;
|
|
3442
|
-
return lastResult;
|
|
3443
|
-
};
|
|
4314
|
+
/**
|
|
4315
|
+
* Programmatically execute a registered frontend tool without going through an LLM turn.
|
|
4316
|
+
* The handler runs, render components show up in the UI, and both the tool call and
|
|
4317
|
+
* result messages are added to `agent.messages`.
|
|
4318
|
+
*/
|
|
4319
|
+
async runTool(params) {
|
|
4320
|
+
return this.runHandler.runTool(params);
|
|
3444
4321
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
*
|
|
3468
|
-
* the
|
|
3469
|
-
*
|
|
3470
|
-
*
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
}
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
}
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
const
|
|
3507
|
-
const
|
|
3508
|
-
|
|
3509
|
-
let
|
|
3510
|
-
let
|
|
3511
|
-
let
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
const failFast = (error) => {
|
|
3521
|
-
if (hasFatalError) return;
|
|
3522
|
-
hasFatalError = true;
|
|
3523
|
-
isRunning = false;
|
|
3524
|
-
effectSubscriptions.unsubscribe();
|
|
3525
|
-
effectSubscriptions = new rxjs.Subscription();
|
|
3526
|
-
actionsSubject.error(error);
|
|
3527
|
-
stateSubject.error(error);
|
|
3528
|
-
};
|
|
3529
|
-
const startEffects = () => {
|
|
3530
|
-
for (const effect of effects) {
|
|
3531
|
-
const scheduledActions$ = actionsSubject.asObservable().pipe((0, rxjs_operators.observeOn)(rxjs.asapScheduler));
|
|
3532
|
-
const state$ = stateSubject.asObservable();
|
|
3533
|
-
if (effect.dispatch) {
|
|
3534
|
-
const subscription = effect.run(scheduledActions$, state$).subscribe({
|
|
3535
|
-
next: (effectAction) => {
|
|
3536
|
-
if (hasFatalError) return;
|
|
3537
|
-
dispatchInternal(effectAction);
|
|
3538
|
-
},
|
|
3539
|
-
error: (error) => {
|
|
3540
|
-
failFast(error);
|
|
3541
|
-
}
|
|
4322
|
+
/**
|
|
4323
|
+
* State management (delegated to StateManager)
|
|
4324
|
+
*/
|
|
4325
|
+
getStateByRun(agentId, threadId, runId) {
|
|
4326
|
+
return this.stateManager.getStateByRun(agentId, threadId, runId);
|
|
4327
|
+
}
|
|
4328
|
+
getRunIdForMessage(agentId, threadId, messageId) {
|
|
4329
|
+
return this.stateManager.getRunIdForMessage(agentId, threadId, messageId);
|
|
4330
|
+
}
|
|
4331
|
+
getRunIdsForThread(agentId, threadId) {
|
|
4332
|
+
return this.stateManager.getRunIdsForThread(agentId, threadId);
|
|
4333
|
+
}
|
|
4334
|
+
/**
|
|
4335
|
+
* Internal method used by RunHandler to build frontend tools
|
|
4336
|
+
*/
|
|
4337
|
+
buildFrontendTools(agentId) {
|
|
4338
|
+
return this.runHandler.buildFrontendTools(agentId);
|
|
4339
|
+
}
|
|
4340
|
+
/**
|
|
4341
|
+
* Called before each follow-up agent run (after tool execution).
|
|
4342
|
+
*
|
|
4343
|
+
* When a frontend tool handler calls framework state setters (e.g. React's
|
|
4344
|
+
* setState), those updates are batched and deferred — they do not take effect
|
|
4345
|
+
* until the framework's scheduler runs (React uses MessageChannel).
|
|
4346
|
+
* useAgentContext registers context via useLayoutEffect, which runs
|
|
4347
|
+
* synchronously after React commits that deferred batch.
|
|
4348
|
+
*
|
|
4349
|
+
* Without yielding here, the follow-up runAgent reads the context store
|
|
4350
|
+
* synchronously while the deferred updates are still pending, producing stale
|
|
4351
|
+
* context for the next agent turn.
|
|
4352
|
+
*
|
|
4353
|
+
* Override in framework-specific subclasses to yield to the framework
|
|
4354
|
+
* scheduler before the follow-up run. The base implementation is a no-op
|
|
4355
|
+
* because non-React environments have no deferred state to flush.
|
|
4356
|
+
*/
|
|
4357
|
+
async waitForPendingFrameworkUpdates() {}
|
|
4358
|
+
};
|
|
4359
|
+
|
|
4360
|
+
//#endregion
|
|
4361
|
+
//#region src/types.ts
|
|
4362
|
+
/**
|
|
4363
|
+
* Status of a tool call execution
|
|
4364
|
+
*/
|
|
4365
|
+
let ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
|
|
4366
|
+
ToolCallStatus["InProgress"] = "inProgress";
|
|
4367
|
+
ToolCallStatus["Executing"] = "executing";
|
|
4368
|
+
ToolCallStatus["Complete"] = "complete";
|
|
4369
|
+
return ToolCallStatus;
|
|
4370
|
+
}({});
|
|
4371
|
+
|
|
4372
|
+
//#endregion
|
|
4373
|
+
//#region src/utils/markdown.ts
|
|
4374
|
+
function completePartialMarkdown(input) {
|
|
4375
|
+
let s = input;
|
|
4376
|
+
const fenceMatches = Array.from(s.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
|
|
4377
|
+
if (fenceMatches.length % 2 === 1) {
|
|
4378
|
+
const [, indent, fence] = fenceMatches[0];
|
|
4379
|
+
s += `\n${indent}${fence}`;
|
|
4380
|
+
}
|
|
4381
|
+
if (s.match(/\[([^\]]*)\]\(([^)]*)$/)) s += ")";
|
|
4382
|
+
const openElements = [];
|
|
4383
|
+
const chars = Array.from(s);
|
|
4384
|
+
const codeBlockRanges = [];
|
|
4385
|
+
const inlineCodeRanges = [];
|
|
4386
|
+
let tempCodeFenceCount = 0;
|
|
4387
|
+
let currentCodeBlockStart = -1;
|
|
4388
|
+
for (let i = 0; i < chars.length; i++) if (i === 0 || chars[i - 1] === "\n") {
|
|
4389
|
+
const lineMatch = s.substring(i).match(/^(\s*)(`{3,}|~{3,})/);
|
|
4390
|
+
if (lineMatch) {
|
|
4391
|
+
tempCodeFenceCount++;
|
|
4392
|
+
if (tempCodeFenceCount % 2 === 1) currentCodeBlockStart = i;
|
|
4393
|
+
else if (currentCodeBlockStart !== -1) {
|
|
4394
|
+
codeBlockRanges.push({
|
|
4395
|
+
start: currentCodeBlockStart,
|
|
4396
|
+
end: i + lineMatch[0].length
|
|
3542
4397
|
});
|
|
3543
|
-
|
|
3544
|
-
continue;
|
|
4398
|
+
currentCodeBlockStart = -1;
|
|
3545
4399
|
}
|
|
3546
|
-
|
|
3547
|
-
failFast(error);
|
|
3548
|
-
} });
|
|
3549
|
-
effectSubscriptions.add(subscription);
|
|
4400
|
+
i += lineMatch[0].length - 1;
|
|
3550
4401
|
}
|
|
3551
|
-
}
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
init() {
|
|
3569
|
-
if (hasFatalError || isRunning) return;
|
|
3570
|
-
isRunning = true;
|
|
3571
|
-
startEffects();
|
|
3572
|
-
if (hasFatalError) return;
|
|
3573
|
-
dispatchInternal({ type: INTERNAL_ACTION_TYPES.init });
|
|
3574
|
-
},
|
|
3575
|
-
stop() {
|
|
3576
|
-
if (hasFatalError || !isRunning) return;
|
|
3577
|
-
dispatchInternal({ type: INTERNAL_ACTION_TYPES.stop });
|
|
3578
|
-
effectSubscriptions.unsubscribe();
|
|
3579
|
-
effectSubscriptions = new rxjs.Subscription();
|
|
3580
|
-
isRunning = false;
|
|
4402
|
+
}
|
|
4403
|
+
for (let i = 0; i < chars.length; i++) if (chars[i] === "`") {
|
|
4404
|
+
let backslashCount = 0;
|
|
4405
|
+
for (let j = i - 1; j >= 0 && chars[j] === "\\"; j--) backslashCount++;
|
|
4406
|
+
if (backslashCount % 2 === 0) {
|
|
4407
|
+
for (let j = i + 1; j < chars.length; j++) if (chars[j] === "`") {
|
|
4408
|
+
let closingBackslashCount = 0;
|
|
4409
|
+
for (let k = j - 1; k >= 0 && chars[k] === "\\"; k--) closingBackslashCount++;
|
|
4410
|
+
if (closingBackslashCount % 2 === 0) {
|
|
4411
|
+
inlineCodeRanges.push({
|
|
4412
|
+
start: i,
|
|
4413
|
+
end: j + 1
|
|
4414
|
+
});
|
|
4415
|
+
i = j;
|
|
4416
|
+
break;
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
3581
4419
|
}
|
|
4420
|
+
}
|
|
4421
|
+
const isInCode = (pos) => {
|
|
4422
|
+
return codeBlockRanges.some((range) => pos >= range.start && pos < range.end) || inlineCodeRanges.some((range) => pos >= range.start && pos < range.end);
|
|
3582
4423
|
};
|
|
4424
|
+
for (let i = 0; i < chars.length; i++) {
|
|
4425
|
+
const char = chars[i];
|
|
4426
|
+
const nextChar = chars[i + 1];
|
|
4427
|
+
const prevChar = chars[i - 1];
|
|
4428
|
+
if (isInCode(i)) continue;
|
|
4429
|
+
if (char === "[") {
|
|
4430
|
+
let isCompleteLink = false;
|
|
4431
|
+
let bracketDepth = 1;
|
|
4432
|
+
let j = i + 1;
|
|
4433
|
+
while (j < chars.length && bracketDepth > 0) {
|
|
4434
|
+
if (chars[j] === "[" && !isInCode(j)) bracketDepth++;
|
|
4435
|
+
if (chars[j] === "]" && !isInCode(j)) bracketDepth--;
|
|
4436
|
+
j++;
|
|
4437
|
+
}
|
|
4438
|
+
if (bracketDepth === 0 && chars[j] === "(") {
|
|
4439
|
+
let parenDepth = 1;
|
|
4440
|
+
j++;
|
|
4441
|
+
while (j < chars.length && parenDepth > 0) {
|
|
4442
|
+
if (chars[j] === "(" && !isInCode(j)) parenDepth++;
|
|
4443
|
+
if (chars[j] === ")" && !isInCode(j)) parenDepth--;
|
|
4444
|
+
j++;
|
|
4445
|
+
}
|
|
4446
|
+
if (parenDepth === 0) {
|
|
4447
|
+
isCompleteLink = true;
|
|
4448
|
+
i = j - 1;
|
|
4449
|
+
continue;
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
if (!isCompleteLink) {
|
|
4453
|
+
const existingIndex = openElements.findIndex((el) => el.type === "bracket");
|
|
4454
|
+
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
4455
|
+
else openElements.push({
|
|
4456
|
+
type: "bracket",
|
|
4457
|
+
marker: "[",
|
|
4458
|
+
position: i
|
|
4459
|
+
});
|
|
4460
|
+
}
|
|
4461
|
+
} else if (char === "*" && nextChar === "*") {
|
|
4462
|
+
const existingIndex = openElements.findIndex((el) => el.type === "bold_star");
|
|
4463
|
+
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
4464
|
+
else openElements.push({
|
|
4465
|
+
type: "bold_star",
|
|
4466
|
+
marker: "**",
|
|
4467
|
+
position: i
|
|
4468
|
+
});
|
|
4469
|
+
i++;
|
|
4470
|
+
} else if (char === "_" && nextChar === "_") {
|
|
4471
|
+
const existingIndex = openElements.findIndex((el) => el.type === "bold_underscore");
|
|
4472
|
+
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
4473
|
+
else openElements.push({
|
|
4474
|
+
type: "bold_underscore",
|
|
4475
|
+
marker: "__",
|
|
4476
|
+
position: i
|
|
4477
|
+
});
|
|
4478
|
+
i++;
|
|
4479
|
+
} else if (char === "~" && nextChar === "~") {
|
|
4480
|
+
const existingIndex = openElements.findIndex((el) => el.type === "strike");
|
|
4481
|
+
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
4482
|
+
else openElements.push({
|
|
4483
|
+
type: "strike",
|
|
4484
|
+
marker: "~~",
|
|
4485
|
+
position: i
|
|
4486
|
+
});
|
|
4487
|
+
i++;
|
|
4488
|
+
} else if (char === "*" && prevChar !== "*" && nextChar !== "*") {
|
|
4489
|
+
const existingIndex = openElements.findIndex((el) => el.type === "italic_star");
|
|
4490
|
+
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
4491
|
+
else openElements.push({
|
|
4492
|
+
type: "italic_star",
|
|
4493
|
+
marker: "*",
|
|
4494
|
+
position: i
|
|
4495
|
+
});
|
|
4496
|
+
} else if (char === "_" && prevChar !== "_" && nextChar !== "_") {
|
|
4497
|
+
const existingIndex = openElements.findIndex((el) => el.type === "italic_underscore");
|
|
4498
|
+
if (existingIndex !== -1) openElements.splice(existingIndex, 1);
|
|
4499
|
+
else openElements.push({
|
|
4500
|
+
type: "italic_underscore",
|
|
4501
|
+
marker: "_",
|
|
4502
|
+
position: i
|
|
4503
|
+
});
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
let backtickCount = 0;
|
|
4507
|
+
for (let i = 0; i < chars.length; i++) if (chars[i] === "`" && !isInCode(i)) backtickCount++;
|
|
4508
|
+
if (backtickCount % 2 === 1) s += "`";
|
|
4509
|
+
openElements.sort((a, b) => b.position - a.position);
|
|
4510
|
+
const closers = openElements.map((el) => {
|
|
4511
|
+
switch (el.type) {
|
|
4512
|
+
case "bracket": return "]";
|
|
4513
|
+
case "bold_star": return "**";
|
|
4514
|
+
case "bold_underscore": return "__";
|
|
4515
|
+
case "strike": return "~~";
|
|
4516
|
+
case "italic_star": return "*";
|
|
4517
|
+
case "italic_underscore": return "_";
|
|
4518
|
+
default: return "";
|
|
4519
|
+
}
|
|
4520
|
+
});
|
|
4521
|
+
let result = s + closers.join("");
|
|
4522
|
+
const finalFenceMatches = Array.from(result.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
|
|
4523
|
+
const hasUnclosedBacktick = (result.match(/`/g) || []).length % 2 === 1;
|
|
4524
|
+
const hasUnclosedCodeFence = finalFenceMatches.length % 2 === 1;
|
|
4525
|
+
let shouldCloseParens = !hasUnclosedBacktick && !hasUnclosedCodeFence;
|
|
4526
|
+
if (shouldCloseParens) {
|
|
4527
|
+
const lastOpenParen = result.lastIndexOf("(");
|
|
4528
|
+
if (lastOpenParen !== -1) {
|
|
4529
|
+
if ((result.substring(0, lastOpenParen).match(/`/g) || []).length % 2 === 1) shouldCloseParens = false;
|
|
4530
|
+
}
|
|
4531
|
+
}
|
|
4532
|
+
if (shouldCloseParens) {
|
|
4533
|
+
const openParens = (result.match(/\(/g) || []).length;
|
|
4534
|
+
const closeParens = (result.match(/\)/g) || []).length;
|
|
4535
|
+
if (openParens > closeParens) result += ")".repeat(openParens - closeParens);
|
|
4536
|
+
}
|
|
4537
|
+
return result;
|
|
3583
4538
|
}
|
|
3584
4539
|
|
|
3585
4540
|
//#endregion
|
|
3586
4541
|
//#region src/threads.ts
|
|
3587
4542
|
const THREADS_CHANNEL_EVENT = "thread_metadata";
|
|
4543
|
+
const THREAD_RUN_ACTIVITY_CHANNEL_EVENT = "thread_run_activity";
|
|
3588
4544
|
const THREAD_SUBSCRIBE_PATH = "/threads/subscribe";
|
|
3589
4545
|
const MAX_SOCKET_RETRIES = 5;
|
|
3590
4546
|
const REQUEST_TIMEOUT_MS = 15e3;
|
|
@@ -3593,6 +4549,7 @@ const initialThreadState = {
|
|
|
3593
4549
|
isLoading: false,
|
|
3594
4550
|
isFetchingNextPage: false,
|
|
3595
4551
|
error: null,
|
|
4552
|
+
fetchMoreError: null,
|
|
3596
4553
|
context: null,
|
|
3597
4554
|
sessionId: 0,
|
|
3598
4555
|
metadataCredentialsRequested: false,
|
|
@@ -3628,7 +4585,8 @@ const threadSocketEvents = createActionGroup("Thread Socket", {
|
|
|
3628
4585
|
errored: props(),
|
|
3629
4586
|
joinFailed: props(),
|
|
3630
4587
|
joinTimedOut: props(),
|
|
3631
|
-
metadataReceived: props()
|
|
4588
|
+
metadataReceived: props(),
|
|
4589
|
+
runActivityReceived: props()
|
|
3632
4590
|
});
|
|
3633
4591
|
const threadDomainEvents = createActionGroup("Thread Domain", {
|
|
3634
4592
|
threadUpserted: props(),
|
|
@@ -3647,6 +4605,28 @@ function upsertThread(threads, thread) {
|
|
|
3647
4605
|
next[existingIndex] = thread;
|
|
3648
4606
|
return sortThreadsByRecency(next);
|
|
3649
4607
|
}
|
|
4608
|
+
/**
|
|
4609
|
+
* Returns a non-empty string payload field or undefined for absent fields.
|
|
4610
|
+
*/
|
|
4611
|
+
function optionalString(value) {
|
|
4612
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
4613
|
+
}
|
|
4614
|
+
/**
|
|
4615
|
+
* Converts gateway run-activity payloads into the internal TypeScript shape.
|
|
4616
|
+
*/
|
|
4617
|
+
function normalizeThreadRunActivityNotification(payload) {
|
|
4618
|
+
const threadId = optionalString(payload.threadId ?? payload.thread_id);
|
|
4619
|
+
const eventType = optionalString(payload.eventType ?? payload.event_type);
|
|
4620
|
+
if (!threadId || !eventType) return null;
|
|
4621
|
+
return {
|
|
4622
|
+
type: "thread_run_activity",
|
|
4623
|
+
threadId,
|
|
4624
|
+
agentId: optionalString(payload.agentId ?? payload.agent_id),
|
|
4625
|
+
runId: optionalString(payload.runId ?? payload.run_id),
|
|
4626
|
+
eventType,
|
|
4627
|
+
latestEventId: optionalString(payload.latestEventId ?? payload.latest_event_id)
|
|
4628
|
+
};
|
|
4629
|
+
}
|
|
3650
4630
|
const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
|
|
3651
4631
|
...state,
|
|
3652
4632
|
context,
|
|
@@ -3655,6 +4635,7 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3655
4635
|
isLoading: Boolean(context),
|
|
3656
4636
|
isFetchingNextPage: false,
|
|
3657
4637
|
error: null,
|
|
4638
|
+
fetchMoreError: null,
|
|
3658
4639
|
metadataCredentialsRequested: false,
|
|
3659
4640
|
metadataJoinCode: null,
|
|
3660
4641
|
nextCursor: null,
|
|
@@ -3666,6 +4647,7 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3666
4647
|
isLoading: false,
|
|
3667
4648
|
isFetchingNextPage: false,
|
|
3668
4649
|
error: null,
|
|
4650
|
+
fetchMoreError: null,
|
|
3669
4651
|
metadataCredentialsRequested: false,
|
|
3670
4652
|
metadataJoinCode: null,
|
|
3671
4653
|
nextCursor: null,
|
|
@@ -3676,16 +4658,20 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3676
4658
|
return {
|
|
3677
4659
|
...state,
|
|
3678
4660
|
isLoading: true,
|
|
3679
|
-
error: null
|
|
4661
|
+
error: null,
|
|
4662
|
+
fetchMoreError: null
|
|
3680
4663
|
};
|
|
3681
4664
|
}), on(threadRestEvents.listSucceeded, (state, { sessionId, threads, joinCode, nextCursor }) => {
|
|
3682
4665
|
if (sessionId !== state.sessionId) return state;
|
|
4666
|
+
const joinCodeChanged = joinCode !== state.metadataJoinCode;
|
|
3683
4667
|
return {
|
|
3684
4668
|
...state,
|
|
3685
4669
|
threads: sortThreadsByRecency(threads),
|
|
3686
4670
|
isLoading: false,
|
|
3687
4671
|
error: null,
|
|
4672
|
+
fetchMoreError: null,
|
|
3688
4673
|
metadataJoinCode: joinCode,
|
|
4674
|
+
metadataCredentialsRequested: joinCodeChanged ? false : state.metadataCredentialsRequested,
|
|
3689
4675
|
nextCursor
|
|
3690
4676
|
};
|
|
3691
4677
|
}), on(threadRestEvents.listFailed, (state, { sessionId, error }) => {
|
|
@@ -3703,6 +4689,7 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3703
4689
|
...state,
|
|
3704
4690
|
threads: merged,
|
|
3705
4691
|
isFetchingNextPage: false,
|
|
4692
|
+
fetchMoreError: null,
|
|
3706
4693
|
nextCursor
|
|
3707
4694
|
};
|
|
3708
4695
|
}), on(threadRestEvents.nextPageFailed, (state, { sessionId, error }) => {
|
|
@@ -3710,11 +4697,14 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3710
4697
|
return {
|
|
3711
4698
|
...state,
|
|
3712
4699
|
isFetchingNextPage: false,
|
|
3713
|
-
error
|
|
4700
|
+
fetchMoreError: error
|
|
3714
4701
|
};
|
|
3715
4702
|
}), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId }) => {
|
|
3716
4703
|
if (sessionId !== state.sessionId) return state;
|
|
3717
|
-
return
|
|
4704
|
+
return {
|
|
4705
|
+
...state,
|
|
4706
|
+
metadataCredentialsRequested: false
|
|
4707
|
+
};
|
|
3718
4708
|
}), on(threadRestEvents.metadataCredentialsRequested, (state, { sessionId }) => {
|
|
3719
4709
|
if (sessionId !== state.sessionId) return state;
|
|
3720
4710
|
return {
|
|
@@ -3725,7 +4715,8 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
|
|
|
3725
4715
|
if (!state.nextCursor || state.isFetchingNextPage) return state;
|
|
3726
4716
|
return {
|
|
3727
4717
|
...state,
|
|
3728
|
-
isFetchingNextPage: true
|
|
4718
|
+
isFetchingNextPage: true,
|
|
4719
|
+
fetchMoreError: null
|
|
3729
4720
|
};
|
|
3730
4721
|
}), on(threadAdapterEvents.renameRequested, (state, { threadId, name }) => {
|
|
3731
4722
|
const existing = state.threads.find((thread) => thread.id === threadId);
|
|
@@ -3854,6 +4845,7 @@ function createThreadSelectors() {
|
|
|
3854
4845
|
threads: createSelector((state) => state.threads),
|
|
3855
4846
|
isLoading: createSelector((state) => state.isLoading),
|
|
3856
4847
|
error: createSelector((state) => state.error),
|
|
4848
|
+
fetchMoreError: createSelector((state) => state.fetchMoreError),
|
|
3857
4849
|
hasNextPage: createSelector((state) => state.nextCursor != null),
|
|
3858
4850
|
isFetchingNextPage: createSelector((state) => state.isFetchingNextPage),
|
|
3859
4851
|
isMutating: createSelector((state) => state.inFlightMutationCount > 0)
|
|
@@ -3863,6 +4855,7 @@ const standaloneSelectors = createThreadSelectors();
|
|
|
3863
4855
|
const selectThreads = standaloneSelectors.threads;
|
|
3864
4856
|
const selectThreadsIsLoading = standaloneSelectors.isLoading;
|
|
3865
4857
|
const selectThreadsError = standaloneSelectors.error;
|
|
4858
|
+
const selectFetchMoreError = standaloneSelectors.fetchMoreError;
|
|
3866
4859
|
const selectHasNextPage = standaloneSelectors.hasNextPage;
|
|
3867
4860
|
const selectIsFetchingNextPage = standaloneSelectors.isFetchingNextPage;
|
|
3868
4861
|
const selectIsMutating = standaloneSelectors.isMutating;
|
|
@@ -3872,7 +4865,27 @@ function createThreadRequestId() {
|
|
|
3872
4865
|
return `thread-request-${threadRequestId}`;
|
|
3873
4866
|
}
|
|
3874
4867
|
function threadFromFetch(input, init) {
|
|
3875
|
-
return
|
|
4868
|
+
return new rxjs.Observable((subscriber) => {
|
|
4869
|
+
const { fetch: fetchImpl, selector, signal, ...requestInit } = init;
|
|
4870
|
+
const controller = new AbortController();
|
|
4871
|
+
const abortRequest = () => controller.abort();
|
|
4872
|
+
if (signal?.aborted) abortRequest();
|
|
4873
|
+
else signal?.addEventListener("abort", abortRequest, { once: true });
|
|
4874
|
+
fetchImpl(input, {
|
|
4875
|
+
...requestInit,
|
|
4876
|
+
signal: controller.signal
|
|
4877
|
+
}).then((response) => selector(response)).then((value) => {
|
|
4878
|
+
if (subscriber.closed) return;
|
|
4879
|
+
subscriber.next(value);
|
|
4880
|
+
subscriber.complete();
|
|
4881
|
+
}).catch((error) => {
|
|
4882
|
+
if (!subscriber.closed) subscriber.error(error);
|
|
4883
|
+
});
|
|
4884
|
+
return () => {
|
|
4885
|
+
signal?.removeEventListener("abort", abortRequest);
|
|
4886
|
+
abortRequest();
|
|
4887
|
+
};
|
|
4888
|
+
});
|
|
3876
4889
|
}
|
|
3877
4890
|
function createThreadFetchObservable(environment, context, sessionId) {
|
|
3878
4891
|
return (0, rxjs.defer)(() => {
|
|
@@ -4018,6 +5031,9 @@ function createThreadStore(environment) {
|
|
|
4018
5031
|
return (0, rxjs.merge)(socketSignals$.pipe((0, rxjs_operators.map)((signal) => signal.type === "open" ? threadSocketEvents.opened({ sessionId: action.sessionId }) : threadSocketEvents.errored({ sessionId: action.sessionId }))), channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => ɵobservePhoenixEvent$(channel, THREADS_CHANNEL_EVENT)), (0, rxjs_operators.map)((payload) => threadSocketEvents.metadataReceived({
|
|
4019
5032
|
sessionId: action.sessionId,
|
|
4020
5033
|
payload
|
|
5034
|
+
}))), channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => ɵobservePhoenixEvent$(channel, THREAD_RUN_ACTIVITY_CHANNEL_EVENT)), (0, rxjs_operators.map)((payload) => normalizeThreadRunActivityNotification(payload)), (0, rxjs_operators.filter)((notification) => notification !== null), (0, rxjs_operators.map)((notification) => threadSocketEvents.runActivityReceived({
|
|
5035
|
+
sessionId: action.sessionId,
|
|
5036
|
+
notification
|
|
4021
5037
|
}))), ɵobservePhoenixJoinOutcome$(channel$).pipe((0, rxjs_operators.filter)((outcome) => outcome.type !== "joined"), (0, rxjs_operators.map)((outcome) => outcome.type === "timeout" ? threadSocketEvents.joinTimedOut({ sessionId: action.sessionId }) : threadSocketEvents.joinFailed({ sessionId: action.sessionId })))).pipe((0, rxjs_operators.takeUntil)((0, rxjs.merge)(shutdown$, fatalSocketShutdown$)));
|
|
4022
5038
|
});
|
|
4023
5039
|
}))),
|
|
@@ -4195,6 +5211,9 @@ function createThreadStore(environment) {
|
|
|
4195
5211
|
threadId
|
|
4196
5212
|
}));
|
|
4197
5213
|
},
|
|
5214
|
+
subscribeToRunActivity(callback) {
|
|
5215
|
+
return store.actions$.pipe(ofType(threadSocketEvents.runActivityReceived), (0, rxjs_operators.filter)((action) => action.sessionId === store.getState().sessionId), (0, rxjs_operators.map)((action) => action.notification)).subscribe(callback);
|
|
5216
|
+
},
|
|
4198
5217
|
getState() {
|
|
4199
5218
|
return store.getState();
|
|
4200
5219
|
},
|
|
@@ -4210,6 +5229,7 @@ const ɵcreateThreadSelectors = createThreadSelectors;
|
|
|
4210
5229
|
const ɵselectThreads = selectThreads;
|
|
4211
5230
|
const ɵselectThreadsIsLoading = selectThreadsIsLoading;
|
|
4212
5231
|
const ɵselectThreadsError = selectThreadsError;
|
|
5232
|
+
const ɵselectFetchMoreError = selectFetchMoreError;
|
|
4213
5233
|
const ɵselectHasNextPage = selectHasNextPage;
|
|
4214
5234
|
const ɵselectIsFetchingNextPage = selectIsFetchingNextPage;
|
|
4215
5235
|
const ɵselectIsMutating = selectIsMutating;
|
|
@@ -4274,9 +5294,12 @@ exports.CopilotKitCore = CopilotKitCore;
|
|
|
4274
5294
|
exports.CopilotKitCoreErrorCode = CopilotKitCoreErrorCode;
|
|
4275
5295
|
exports.CopilotKitCoreRuntimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus;
|
|
4276
5296
|
exports.IntelligenceAgent = IntelligenceAgent;
|
|
5297
|
+
exports.MEMORY_ERROR_REGISTRY = MEMORY_ERROR_REGISTRY;
|
|
5298
|
+
exports.MemoryError = MemoryError;
|
|
4277
5299
|
exports.ProxiedCopilotRuntimeAgent = ProxiedCopilotRuntimeAgent;
|
|
4278
5300
|
exports.RunHandler = RunHandler;
|
|
4279
5301
|
exports.StateManager = StateManager;
|
|
5302
|
+
exports.SubagentRegistry = SubagentRegistry;
|
|
4280
5303
|
exports.SuggestionEngine = SuggestionEngine;
|
|
4281
5304
|
exports.ToolCallStatus = ToolCallStatus;
|
|
4282
5305
|
exports.completePartialMarkdown = completePartialMarkdown;
|
|
@@ -4295,19 +5318,33 @@ exports.props = props;
|
|
|
4295
5318
|
exports.select = select;
|
|
4296
5319
|
exports.ɵCOPILOTKIT_FEATURES = ɵCOPILOTKIT_FEATURES;
|
|
4297
5320
|
exports.ɵMAX_SOCKET_RETRIES = ɵMAX_SOCKET_RETRIES;
|
|
5321
|
+
exports.ɵcreateMemoryStore = createMemoryStore;
|
|
4298
5322
|
exports.ɵcreateThreadSelectors = ɵcreateThreadSelectors;
|
|
4299
5323
|
exports.ɵcreateThreadStore = createThreadStore;
|
|
4300
5324
|
exports.ɵisCopilotKitFeature = ɵisCopilotKitFeature;
|
|
5325
|
+
exports.ɵisRetryableMemoryStatus = isRetryableStatus;
|
|
4301
5326
|
exports.ɵjoinPhoenixChannel$ = ɵjoinPhoenixChannel$;
|
|
5327
|
+
exports.ɵmapMemoryMetadataEvent = ɵmapMemoryMetadataEvent;
|
|
5328
|
+
exports.ɵmemoryAdapterEvents = ɵmemoryAdapterEvents;
|
|
5329
|
+
exports.ɵmemoryDomainEvents = ɵmemoryDomainEvents;
|
|
5330
|
+
exports.ɵmemoryReducer = ɵmemoryReducer;
|
|
5331
|
+
exports.ɵmemoryRestEvents = ɵmemoryRestEvents;
|
|
4302
5332
|
exports.ɵobservePhoenixEvent$ = ɵobservePhoenixEvent$;
|
|
4303
5333
|
exports.ɵobservePhoenixJoinOutcome$ = ɵobservePhoenixJoinOutcome$;
|
|
4304
5334
|
exports.ɵobservePhoenixSocketHealth$ = ɵobservePhoenixSocketHealth$;
|
|
4305
5335
|
exports.ɵobservePhoenixSocketSignals$ = ɵobservePhoenixSocketSignals$;
|
|
4306
5336
|
exports.ɵphoenixChannel$ = ɵphoenixChannel$;
|
|
4307
5337
|
exports.ɵphoenixSocket$ = ɵphoenixSocket$;
|
|
5338
|
+
exports.ɵselectFetchMoreError = ɵselectFetchMoreError;
|
|
4308
5339
|
exports.ɵselectHasNextPage = ɵselectHasNextPage;
|
|
4309
5340
|
exports.ɵselectIsFetchingNextPage = ɵselectIsFetchingNextPage;
|
|
4310
5341
|
exports.ɵselectIsMutating = ɵselectIsMutating;
|
|
5342
|
+
exports.ɵselectMemories = ɵselectMemories;
|
|
5343
|
+
exports.ɵselectMemoriesAvailable = ɵselectMemoriesAvailable;
|
|
5344
|
+
exports.ɵselectMemoriesError = ɵselectMemoriesError;
|
|
5345
|
+
exports.ɵselectMemoriesIsLoading = ɵselectMemoriesIsLoading;
|
|
5346
|
+
exports.ɵselectMemoriesIsMutating = ɵselectMemoriesIsMutating;
|
|
5347
|
+
exports.ɵselectMemoriesRealtimeStatus = ɵselectMemoriesRealtimeStatus;
|
|
4311
5348
|
exports.ɵselectThreads = ɵselectThreads;
|
|
4312
5349
|
exports.ɵselectThreadsError = ɵselectThreadsError;
|
|
4313
5350
|
exports.ɵselectThreadsIsLoading = ɵselectThreadsIsLoading;
|