@copilotkit/core 1.62.1 → 1.62.2-canary.1783457132

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 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
- return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input)).pipe((0, rxjs.switchMap)((credentials) => {
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
- return this.requestJoinCredentials$("connect", input).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
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: this.getReconnectCursor(input)
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 threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.share)());
405
- const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.share)());
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 terminal$ = (0, rxjs.merge)(threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1)), streamIdleCompletion$);
412
- 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.takeUntil)(terminal$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)())).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
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.sharedState.lastSeenEventIds.set(threadId, eventId);
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 runnerEventId = metadata.cpki_event_id;
489
- return typeof runnerEventId === "string" ? runnerEventId : null;
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 latestEventId = payload.latestEventId;
494
- return typeof latestEventId === "string" ? latestEventId : null;
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
- _lastConnectedThreadId = null;
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 isFreshRestore = incomingThreadId !== this._lastConnectedThreadId;
1739
- this._lastConnectedThreadId = incomingThreadId;
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 proxied = agent;
1745
- if (incomingThreadId && typeof proxied.clearReplayCursor === "function") proxied.clearReplayCursor(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
- for (const message of newMessages) if (message.role === "assistant") {
1841
- for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
1842
- const tool = this.getTool({
1843
- toolName: toolCall.function.name,
1844
- agentId: agent.agentId
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 (wildcardTool) {
1854
- if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
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
  }
@@ -2517,156 +2566,1138 @@ var ThreadStoreRegistry = class {
2517
2566
  };
2518
2567
 
2519
2568
  //#endregion
2520
- //#region src/core/core.ts
2521
- let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode) {
2522
- CopilotKitCoreErrorCode["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
2523
- CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
2524
- CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
2525
- CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
2526
- CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
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
- }({});
2569
+ //#region src/utils/micro-redux.ts
2570
+ const INTERNAL_ACTION_TYPES = {
2571
+ boot: "@@micro-redux/boot",
2572
+ init: "@@micro-redux/init",
2573
+ stop: "@@micro-redux/stop"
2574
+ };
2575
+ const INTERNAL_BOOT_ACTION = { type: INTERNAL_ACTION_TYPES.boot };
2556
2576
  /**
2557
- * Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
2558
- * to module scope so the Set is allocated once, not per-subscription.
2577
+ * Builds a typed action creator from a type string and payload factory.
2559
2578
  */
2560
- const ALLOWED_KEYS = new Set([
2561
- "onMessagesChanged",
2562
- "onStateChanged",
2563
- "onRunInitialized",
2564
- "onRunFinalized",
2565
- "onRunFailed",
2566
- "onRunErrorEvent"
2567
- ]);
2568
- let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
2569
- CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
2570
- CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
2571
- CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
2572
- CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
2573
- return CopilotKitCoreRuntimeConnectionStatus;
2574
- }({});
2579
+ function createTypedActionCreator(type, factory) {
2580
+ const creator = ((...args) => ({
2581
+ ...factory(...args),
2582
+ type
2583
+ }));
2584
+ creator.type = type;
2585
+ creator.match = (action) => action.type === type;
2586
+ return creator;
2587
+ }
2575
2588
  /**
2576
- * Normalize a header map to the internal invariant: a `Record<string, string>`
2577
- * with no `null`/`undefined` values. Entries whose value is `null`/`undefined`
2578
- * are dropped (this is how a header is cleared). Shared by the constructor and
2579
- * `setHeaders` so both write paths into `_headers` enforce the same invariant.
2589
+ * Declares a payload-based action config for `createActionGroup`.
2590
+ *
2591
+ * @example
2592
+ * ```ts
2593
+ * const actions = createActionGroup("User", {
2594
+ * loaded: props<{ id: string }>(),
2595
+ * });
2596
+ * ```
2580
2597
  */
2581
- function normalizeHeaders(headers) {
2582
- return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
2598
+ function props() {
2599
+ return { kind: "props" };
2583
2600
  }
2584
- var CopilotKitCore = class {
2585
- _headers;
2586
- _credentials;
2587
- _properties;
2588
- _defaultThrottleMs;
2589
- _debug;
2590
- subscribers = /* @__PURE__ */ new Set();
2591
- agentRegistry;
2592
- contextStore;
2593
- suggestionEngine;
2594
- runHandler;
2595
- stateManager;
2596
- threadStoreRegistry;
2597
- /**
2598
- * Tracks the agent IDs from the most recent `onAgentsChanged` notification.
2599
- * Used to gate thread-store auto-unregister so the FIRST empty-agents
2600
- * notification (before published agents are merged in) does not rip out a
2601
- * store that was registered prior to that initial notification.
2602
- */
2603
- previousAgentIds = /* @__PURE__ */ new Set();
2604
- constructor({ runtimeUrl, runtimeTransport = "auto", headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
2605
- this._headers = normalizeHeaders(headers);
2606
- this._credentials = credentials;
2607
- this._properties = properties;
2608
- this._debug = debug;
2609
- this.agentRegistry = new AgentRegistry(this);
2610
- this.contextStore = new ContextStore(this);
2611
- this.suggestionEngine = new SuggestionEngine(this);
2612
- this.runHandler = new RunHandler(this);
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
- } });
2601
+ /**
2602
+ * Declares a no-payload action config for `createActionGroup`.
2603
+ *
2604
+ * @example
2605
+ * ```ts
2606
+ * const actions = createActionGroup("User", {
2607
+ * reset: empty(),
2608
+ * });
2609
+ * ```
2610
+ */
2611
+ function empty() {
2612
+ return { kind: "empty" };
2613
+ }
2614
+ /**
2615
+ * Creates a namespaced group of typed action creators.
2616
+ *
2617
+ * Action types are formatted as: `[Source] actionName`.
2618
+ */
2619
+ function createActionGroup(source, config) {
2620
+ const group = {};
2621
+ for (const eventName of Object.keys(config)) {
2622
+ const eventConfig = config[eventName];
2623
+ if (!eventConfig) continue;
2624
+ const actionType = `[${source}] ${eventName}`;
2625
+ if (eventConfig.kind === "props") {
2626
+ group[eventName] = createTypedActionCreator(actionType, (payload) => ({ ...payload }));
2627
+ continue;
2628
+ }
2629
+ group[eventName] = createTypedActionCreator(actionType, () => ({}));
2639
2630
  }
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
- }));
2631
+ return group;
2632
+ }
2633
+ /**
2634
+ * Registers one reducer handler for one or more action creators.
2635
+ *
2636
+ * @throws Error when called without at least one action creator and reducer.
2637
+ */
2638
+ function on(...args) {
2639
+ if (args.length < 2) throw new Error("on requires at least one action creator and one reducer");
2640
+ const reducer = args[args.length - 1];
2641
+ return {
2642
+ creators: args.slice(0, -1),
2643
+ reducer
2644
+ };
2645
+ }
2646
+ /**
2647
+ * Creates a reducer from an initial state and `on(...)` handler entries.
2648
+ *
2649
+ * Unknown action types return the current state unchanged.
2650
+ */
2651
+ function createReducer(initialState, ...entries) {
2652
+ const reducerMap = /* @__PURE__ */ new Map();
2653
+ for (const entry of entries) for (const creator of entry.creators) {
2654
+ const handlers = reducerMap.get(creator.type) ?? [];
2655
+ handlers.push(entry.reducer);
2656
+ reducerMap.set(creator.type, handlers);
2651
2657
  }
2652
- /**
2653
- * Internal method used by delegate classes to emit errors
2654
- */
2655
- async emitError({ error, code, context = {} }) {
2656
- await this.notifySubscribers((subscriber) => subscriber.onError?.({
2657
- copilotkit: this,
2658
- error,
2659
- code,
2660
- context
2661
- }), "Subscriber onError error:");
2658
+ return (state, action) => {
2659
+ const currentState = state ?? initialState;
2660
+ const handlers = reducerMap.get(action.type);
2661
+ if (!handlers || handlers.length === 0) return currentState;
2662
+ let nextState = currentState;
2663
+ for (const handler of handlers) nextState = handler(nextState, action);
2664
+ return nextState;
2665
+ };
2666
+ }
2667
+ /**
2668
+ * Creates a selector that caches and reuses the last computed result
2669
+ * when all input references are unchanged.
2670
+ */
2671
+ function createSelector(...args) {
2672
+ if (args.length === 1) {
2673
+ const projector = args[0];
2674
+ let hasCached = false;
2675
+ let lastState;
2676
+ let lastResult;
2677
+ return (state) => {
2678
+ if (hasCached && state === lastState) return lastResult;
2679
+ lastState = state;
2680
+ lastResult = projector(state);
2681
+ hasCached = true;
2682
+ return lastResult;
2683
+ };
2662
2684
  }
2663
- /**
2664
- * Log a message to the console and emit an error to subscribers.
2665
- * Catches failures from `emitError` itself to prevent unhandled rejections.
2666
- */
2667
- logAndEmitError(message, params, logLevel = "error") {
2668
- console[logLevel](message, params.error);
2669
- this.emitError(params).catch((emitErr) => {
2685
+ const projector = args[args.length - 1];
2686
+ const selectors = args.slice(0, -1);
2687
+ let hasCached = false;
2688
+ let lastInputs = [];
2689
+ let lastResult;
2690
+ return (state) => {
2691
+ const inputs = selectors.map((selector) => selector(state));
2692
+ if (hasCached && inputs.length === lastInputs.length && inputs.every((value, index) => value === lastInputs[index])) return lastResult;
2693
+ lastInputs = inputs;
2694
+ lastResult = projector(...inputs);
2695
+ hasCached = true;
2696
+ return lastResult;
2697
+ };
2698
+ }
2699
+ /**
2700
+ * RxJS operator that maps state emissions through a selector and suppresses
2701
+ * unchanged projected values via reference equality.
2702
+ */
2703
+ function select(selector) {
2704
+ return (source$) => source$.pipe((0, rxjs_operators.map)(selector), (0, rxjs_operators.distinctUntilChanged)());
2705
+ }
2706
+ /**
2707
+ * RxJS operator that filters an action stream by action creators and narrows
2708
+ * the output action type to the matched creator union.
2709
+ *
2710
+ * @throws Error when called without at least one action creator.
2711
+ */
2712
+ function ofType(...creators) {
2713
+ if (creators.length === 0) throw new Error("ofType requires at least one action creator");
2714
+ const actionTypes = new Set(creators.map((creator) => creator.type));
2715
+ return (source$) => {
2716
+ return source$.pipe((0, rxjs_operators.filter)((action) => {
2717
+ return actionTypes.has(action.type);
2718
+ }));
2719
+ };
2720
+ }
2721
+ /**
2722
+ * Creates an effect descriptor consumed by `createStore`.
2723
+ */
2724
+ function createEffect(factory, options = {}) {
2725
+ if (options.dispatch === false) return {
2726
+ run: factory,
2727
+ dispatch: false
2728
+ };
2729
+ return {
2730
+ run: factory,
2731
+ dispatch: true
2732
+ };
2733
+ }
2734
+ /**
2735
+ * Creates a small observable store with reducer + effects.
2736
+ *
2737
+ * Behavior:
2738
+ * - `init()` starts effects and dispatches `@@micro-redux/init`.
2739
+ * - `stop()` dispatches `@@micro-redux/stop` and unsubscribes all effects.
2740
+ * - Effect action observation is scheduled on `asapScheduler` to avoid
2741
+ * synchronous re-entrancy in the effect loop.
2742
+ * - Any effect error triggers fail-fast teardown and errors both `actions$`
2743
+ * and `state$`.
2744
+ */
2745
+ function createStore(options) {
2746
+ const reducer = options.reducer;
2747
+ const effects = options.effects ?? [];
2748
+ let hasFatalError = false;
2749
+ let isRunning = false;
2750
+ let effectSubscriptions = new rxjs.Subscription();
2751
+ let currentState = reducer(void 0, INTERNAL_BOOT_ACTION);
2752
+ const stateSubject = new rxjs.BehaviorSubject(currentState);
2753
+ const actionsSubject = new rxjs.Subject();
2754
+ const dispatchInternal = (action) => {
2755
+ if (hasFatalError) throw new Error("Store is in a failed state due to an effect error");
2756
+ currentState = reducer(currentState, action);
2757
+ stateSubject.next(currentState);
2758
+ actionsSubject.next(action);
2759
+ };
2760
+ const failFast = (error) => {
2761
+ if (hasFatalError) return;
2762
+ hasFatalError = true;
2763
+ isRunning = false;
2764
+ effectSubscriptions.unsubscribe();
2765
+ effectSubscriptions = new rxjs.Subscription();
2766
+ actionsSubject.error(error);
2767
+ stateSubject.error(error);
2768
+ };
2769
+ const startEffects = () => {
2770
+ for (const effect of effects) {
2771
+ const scheduledActions$ = actionsSubject.asObservable().pipe((0, rxjs_operators.observeOn)(rxjs.asapScheduler));
2772
+ const state$ = stateSubject.asObservable();
2773
+ if (effect.dispatch) {
2774
+ const subscription = effect.run(scheduledActions$, state$).subscribe({
2775
+ next: (effectAction) => {
2776
+ if (hasFatalError) return;
2777
+ dispatchInternal(effectAction);
2778
+ },
2779
+ error: (error) => {
2780
+ failFast(error);
2781
+ }
2782
+ });
2783
+ effectSubscriptions.add(subscription);
2784
+ continue;
2785
+ }
2786
+ const subscription = effect.run(scheduledActions$, state$).subscribe({ error: (error) => {
2787
+ failFast(error);
2788
+ } });
2789
+ effectSubscriptions.add(subscription);
2790
+ }
2791
+ };
2792
+ return {
2793
+ dispatch(action) {
2794
+ dispatchInternal(action);
2795
+ },
2796
+ getState() {
2797
+ return currentState;
2798
+ },
2799
+ get state$() {
2800
+ return stateSubject.asObservable();
2801
+ },
2802
+ get actions$() {
2803
+ return actionsSubject.asObservable();
2804
+ },
2805
+ select(selector) {
2806
+ return stateSubject.asObservable().pipe(select(selector));
2807
+ },
2808
+ init() {
2809
+ if (hasFatalError || isRunning) return;
2810
+ isRunning = true;
2811
+ startEffects();
2812
+ if (hasFatalError) return;
2813
+ dispatchInternal({ type: INTERNAL_ACTION_TYPES.init });
2814
+ },
2815
+ stop() {
2816
+ if (hasFatalError || !isRunning) return;
2817
+ dispatchInternal({ type: INTERNAL_ACTION_TYPES.stop });
2818
+ effectSubscriptions.unsubscribe();
2819
+ effectSubscriptions = new rxjs.Subscription();
2820
+ isRunning = false;
2821
+ }
2822
+ };
2823
+ }
2824
+
2825
+ //#endregion
2826
+ //#region src/memory-errors.ts
2827
+ /**
2828
+ * The memory error registry: the single source of truth for memory error
2829
+ * metadata. Keyed by `code` so a code maps to exactly one category/retryable
2830
+ * default.
2831
+ *
2832
+ * Categories/retryable rationale:
2833
+ * - List/credentials/mutation failures are `dependency` (the runtime/platform
2834
+ * the store calls failed). A 5xx is transient (`retryable: true`); a 4xx is
2835
+ * caller-caused, so the helpers below downgrade those to non-retryable.
2836
+ * - Timeouts are `dependency` and `retryable: true` (the request may simply be
2837
+ * slow).
2838
+ */
2839
+ const MEMORY_ERROR_REGISTRY = Object.freeze({
2840
+ MEMORY_LIST_FAILED: {
2841
+ code: "MEMORY_LIST_FAILED",
2842
+ category: "dependency",
2843
+ retryable: true,
2844
+ message: "Failed to fetch memories",
2845
+ docsPath: "docs/errors/memory.md#memory_list_failed"
2846
+ },
2847
+ MEMORY_CREDENTIALS_FAILED: {
2848
+ code: "MEMORY_CREDENTIALS_FAILED",
2849
+ category: "dependency",
2850
+ retryable: true,
2851
+ message: "Failed to fetch memory subscribe credentials",
2852
+ docsPath: "docs/errors/memory.md#memory_credentials_failed"
2853
+ },
2854
+ MEMORY_MUTATION_FAILED: {
2855
+ code: "MEMORY_MUTATION_FAILED",
2856
+ category: "dependency",
2857
+ retryable: true,
2858
+ message: "Memory mutation request failed",
2859
+ docsPath: "docs/errors/memory.md#memory_mutation_failed"
2860
+ },
2861
+ MEMORY_REQUEST_TIMEOUT: {
2862
+ code: "MEMORY_REQUEST_TIMEOUT",
2863
+ category: "dependency",
2864
+ retryable: true,
2865
+ message: "Request timed out",
2866
+ docsPath: "docs/errors/memory.md#memory_request_timeout"
2867
+ }
2868
+ });
2869
+ /**
2870
+ * An `Error` carrying a stable memory error `code`, `category`, and `retryable`
2871
+ * flag so consumers and observability can branch on it without string-matching
2872
+ * the message.
2873
+ *
2874
+ * It is a real `Error` subclass: `instanceof Error` is true, so the public
2875
+ * `MemoryState.error: Error | null` contract (and the `error: Error | null`
2876
+ * surfaced by `useMemories` / `injectMemories`) holds unchanged. Existing
2877
+ * consumers that only read `.message` keep working; the richer fields are
2878
+ * additive.
2879
+ */
2880
+ var MemoryError = class MemoryError extends Error {
2881
+ /** Stable, machine-readable error identifier. */
2882
+ code;
2883
+ /** Coarse error category for grouping/observability. */
2884
+ category;
2885
+ /** Whether retrying the operation could plausibly succeed. */
2886
+ retryable;
2887
+ /**
2888
+ * @param code - Registry code identifying this error.
2889
+ * @param options - Optional overrides:
2890
+ * - `message`: human-readable message (defaults to the registry message;
2891
+ * callers pass a status-bearing string to preserve prior wording).
2892
+ * - `retryable`: overrides the registry default (e.g. a 4xx list failure is
2893
+ * not retryable even though the code's default is).
2894
+ * - `cause`: the underlying error, preserved for debugging.
2895
+ */
2896
+ constructor(code, options) {
2897
+ const entry = MEMORY_ERROR_REGISTRY[code];
2898
+ super(options?.message ?? entry.message, { cause: options?.cause });
2899
+ this.name = "MemoryError";
2900
+ this.code = code;
2901
+ this.category = entry.category;
2902
+ this.retryable = options?.retryable ?? entry.retryable;
2903
+ Object.setPrototypeOf(this, MemoryError.prototype);
2904
+ }
2905
+ };
2906
+ /**
2907
+ * Narrows an HTTP status to whether the failure is worth retrying: a 5xx (or a
2908
+ * missing/0 status) is a transient dependency failure and retryable; a 4xx is
2909
+ * caller-caused and not. Used so a `MEMORY_LIST_FAILED`/`MEMORY_MUTATION_FAILED`
2910
+ * carries an accurate `retryable` flag derived from the response status.
2911
+ */
2912
+ function isRetryableStatus(status) {
2913
+ return !(Number.isInteger(status) && status >= 400 && status <= 499);
2914
+ }
2915
+
2916
+ //#endregion
2917
+ //#region src/memory.ts
2918
+ const MEMORIES_PATH = "/memories";
2919
+ const MEMORIES_SUBSCRIBE_PATH = "/memories/subscribe";
2920
+ const REQUEST_TIMEOUT_MS$1 = 15e3;
2921
+ /** Consecutive socket errors tolerated before the realtime stream gives up. */
2922
+ const MAX_SOCKET_RETRIES$1 = 5;
2923
+ /**
2924
+ * HTTP status codes that indicate memory routes are not configured (non-fatal).
2925
+ * 404/501 mean the route is absent/unimplemented; 422 is the runtime's
2926
+ * MISSING_INTELLIGENCE signal (intelligence not configured on the deployment —
2927
+ * see packages/runtime/.../handlers/intelligence/memories.ts). All three map to
2928
+ * the graceful "not available" locked-teaser path, not a hard error.
2929
+ */
2930
+ const ROUTE_UNAVAILABLE_STATUSES = new Set([
2931
+ 404,
2932
+ 422,
2933
+ 501
2934
+ ]);
2935
+ /**
2936
+ * Thrown when a memory route returns a 404/422/501 — treated as "not
2937
+ * configured" (422 is the runtime's MISSING_INTELLIGENCE signal).
2938
+ */
2939
+ var MemoryRouteUnavailableError = class extends Error {};
2940
+ const initialMemoryState = Object.freeze({
2941
+ memories: Object.freeze([]),
2942
+ isLoading: false,
2943
+ inFlightMutationCount: 0,
2944
+ error: null,
2945
+ context: null,
2946
+ sessionId: 0,
2947
+ available: true,
2948
+ realtimeStatus: "connecting"
2949
+ });
2950
+ const memoryAdapterEvents = createActionGroup("Memory Adapter", {
2951
+ started: empty(),
2952
+ stopped: empty(),
2953
+ contextChanged: props(),
2954
+ addRequested: props(),
2955
+ updateRequested: props(),
2956
+ removeRequested: props()
2957
+ });
2958
+ const memoryRestEvents = createActionGroup("Memory REST", {
2959
+ listRequested: props(),
2960
+ listSucceeded: props(),
2961
+ listFailed: props(),
2962
+ listUnavailable: props(),
2963
+ mutationFinished: props(),
2964
+ credentialsRequested: props(),
2965
+ credentialsSucceeded: props(),
2966
+ credentialsFailed: props(),
2967
+ credentialsUnavailable: props()
2968
+ });
2969
+ const memoryDomainEvents = createActionGroup("Memory Domain", {
2970
+ memoryUpserted: props(),
2971
+ memoryInvalidated: props(),
2972
+ realtimeConnecting: props(),
2973
+ realtimeConnected: props(),
2974
+ realtimeUnavailable: props()
2975
+ });
2976
+ /** Projects a wire memory to the public {@link Memory} shape (drops tenant ids). */
2977
+ function toMemory(memory) {
2978
+ return {
2979
+ id: memory.id,
2980
+ kind: memory.kind,
2981
+ scope: memory.scope,
2982
+ content: memory.content,
2983
+ sourceThreadIds: memory.sourceThreadIds,
2984
+ invalidatedAt: memory.invalidatedAt
2985
+ };
2986
+ }
2987
+ /**
2988
+ * Maps a realtime `memory_metadata` event to the domain action that applies it:
2989
+ * `created`/`updated` upsert the projected memory, `invalidated` removes it by
2990
+ * id. Carries the current `sessionId` so the reducer's session guard can drop
2991
+ * deltas left over from a previous context.
2992
+ */
2993
+ function mapMemoryMetadataEvent(event, sessionId) {
2994
+ if (event.operation === "invalidated") return memoryDomainEvents.memoryInvalidated({
2995
+ sessionId,
2996
+ memoryId: event.invalidated.id
2997
+ });
2998
+ return memoryDomainEvents.memoryUpserted({
2999
+ sessionId,
3000
+ memory: toMemory(event.memory)
3001
+ });
3002
+ }
3003
+ /**
3004
+ * Inserts or replaces a memory by id. A new memory is prepended (newest first,
3005
+ * matching the REST list's `created_at DESC` ordering without needing a date
3006
+ * field on the public projection); an existing memory is replaced in place.
3007
+ */
3008
+ function upsertMemory(memories, memory) {
3009
+ const existingIndex = memories.findIndex((item) => item.id === memory.id);
3010
+ if (existingIndex === -1) return [memory, ...memories];
3011
+ const next = [...memories];
3012
+ next[existingIndex] = memory;
3013
+ return next;
3014
+ }
3015
+ const memoryReducer = createReducer(initialMemoryState, on(memoryAdapterEvents.contextChanged, (state, { context }) => ({
3016
+ ...state,
3017
+ context,
3018
+ sessionId: state.sessionId + 1,
3019
+ memories: [],
3020
+ isLoading: Boolean(context),
3021
+ inFlightMutationCount: 0,
3022
+ error: null,
3023
+ available: true,
3024
+ realtimeStatus: "connecting"
3025
+ })), on(memoryAdapterEvents.stopped, (state) => ({
3026
+ ...state,
3027
+ memories: [],
3028
+ isLoading: false,
3029
+ inFlightMutationCount: 0,
3030
+ error: null,
3031
+ available: true,
3032
+ realtimeStatus: "connecting"
3033
+ })), on(memoryRestEvents.listRequested, (state, { sessionId }) => {
3034
+ if (sessionId !== state.sessionId || !state.context) return state;
3035
+ return {
3036
+ ...state,
3037
+ isLoading: true,
3038
+ error: null,
3039
+ available: true
3040
+ };
3041
+ }), on(memoryRestEvents.listFailed, (state, { sessionId, error }) => {
3042
+ if (sessionId !== state.sessionId) return state;
3043
+ return {
3044
+ ...state,
3045
+ isLoading: false,
3046
+ error
3047
+ };
3048
+ }), on(memoryRestEvents.listUnavailable, (state, { sessionId }) => {
3049
+ if (sessionId !== state.sessionId) return state;
3050
+ return {
3051
+ ...state,
3052
+ memories: [],
3053
+ isLoading: false,
3054
+ error: null,
3055
+ available: false
3056
+ };
3057
+ }), on(memoryAdapterEvents.addRequested, memoryAdapterEvents.updateRequested, memoryAdapterEvents.removeRequested, (state) => ({
3058
+ ...state,
3059
+ inFlightMutationCount: state.inFlightMutationCount + 1
3060
+ })), on(memoryRestEvents.mutationFinished, (state, { outcome }) => {
3061
+ if (outcome.sessionId !== state.sessionId) return state;
3062
+ return {
3063
+ ...state,
3064
+ inFlightMutationCount: Math.max(0, state.inFlightMutationCount - 1),
3065
+ error: outcome.ok ? null : outcome.error
3066
+ };
3067
+ }), on(memoryRestEvents.listSucceeded, (state, { sessionId, memories }) => {
3068
+ if (sessionId !== state.sessionId) return state;
3069
+ return {
3070
+ ...state,
3071
+ memories,
3072
+ isLoading: false,
3073
+ error: null,
3074
+ available: true
3075
+ };
3076
+ }), on(memoryDomainEvents.memoryUpserted, (state, { sessionId, memory }) => {
3077
+ if (sessionId !== state.sessionId) return state;
3078
+ return {
3079
+ ...state,
3080
+ memories: upsertMemory(state.memories, memory)
3081
+ };
3082
+ }), on(memoryDomainEvents.memoryInvalidated, (state, { sessionId, memoryId }) => {
3083
+ if (sessionId !== state.sessionId) return state;
3084
+ return {
3085
+ ...state,
3086
+ memories: state.memories.filter((memory) => memory.id !== memoryId)
3087
+ };
3088
+ }), on(memoryDomainEvents.realtimeConnecting, (state, { sessionId }) => {
3089
+ if (sessionId !== state.sessionId) return state;
3090
+ return {
3091
+ ...state,
3092
+ realtimeStatus: "connecting"
3093
+ };
3094
+ }), on(memoryDomainEvents.realtimeConnected, (state, { sessionId }) => {
3095
+ if (sessionId !== state.sessionId) return state;
3096
+ return {
3097
+ ...state,
3098
+ realtimeStatus: "connected"
3099
+ };
3100
+ }), on(memoryDomainEvents.realtimeUnavailable, (state, { sessionId }) => {
3101
+ if (sessionId !== state.sessionId) return state;
3102
+ return {
3103
+ ...state,
3104
+ realtimeStatus: "unavailable"
3105
+ };
3106
+ }));
3107
+ const selectMemories = createSelector((state) => state.memories);
3108
+ const selectMemoriesIsLoading = createSelector((state) => state.isLoading);
3109
+ const selectMemoriesError = createSelector((state) => state.error);
3110
+ /**
3111
+ * Reports whether at least one mutation is in flight. Derived from
3112
+ * `inFlightMutationCount` so concurrent mutations stay correct: the boolean
3113
+ * only clears once every in-flight mutation has settled.
3114
+ */
3115
+ const selectMemoriesIsMutating = createSelector((state) => state.inFlightMutationCount > 0);
3116
+ /**
3117
+ * Reports whether the memory routes are available. Becomes `false` after a
3118
+ * 404, 422 (the runtime's MISSING_INTELLIGENCE signal), or 501 response during
3119
+ * an auto-activation read; defaults to `true`.
3120
+ */
3121
+ const selectMemoriesAvailable = createSelector((state) => state.available);
3122
+ /**
3123
+ * Reports the realtime-connection health (see {@link MemoryRealtimeStatus}).
3124
+ * Distinct from `available`/`error`: it reflects ONLY the live socket/channel,
3125
+ * so the UI can suppress a "live" indicator once realtime permanently dies even
3126
+ * while the REST list route stays healthy. Defaults to `"connecting"`.
3127
+ */
3128
+ const selectMemoriesRealtimeStatus = createSelector((state) => state.realtimeStatus);
3129
+ const MEMORY_METADATA_EVENT = "memory_metadata";
3130
+ function memoryFromFetch(input, init) {
3131
+ return (0, rxjs_fetch.fromFetch)(input, init);
3132
+ }
3133
+ /**
3134
+ * Fetches the memory snapshot and maps it to a success/failure action. Keeps
3135
+ * only user-scoped memories (v1 surfaces user scope only; the realtime stream
3136
+ * is user-scoped too), so project-scoped rows visible to the caller are
3137
+ * dropped from the store.
3138
+ */
3139
+ function createMemoryFetchObservable(environment, context, sessionId) {
3140
+ return (0, rxjs.defer)(() => {
3141
+ const qs = context.includeInvalidated ? "?includeInvalidated=true" : "";
3142
+ return memoryFromFetch(`${context.runtimeUrl}${MEMORIES_PATH}${qs}`, {
3143
+ selector: (response) => {
3144
+ if (!response.ok) {
3145
+ if (ROUTE_UNAVAILABLE_STATUSES.has(response.status)) throw new MemoryRouteUnavailableError(String(response.status));
3146
+ throw new MemoryError("MEMORY_LIST_FAILED", {
3147
+ message: `Failed to fetch memories: ${response.status}`,
3148
+ retryable: isRetryableStatus(response.status)
3149
+ });
3150
+ }
3151
+ return response.json();
3152
+ },
3153
+ fetch: environment.fetch,
3154
+ method: "GET",
3155
+ headers: { ...context.headers }
3156
+ }).pipe((0, rxjs_operators.timeout)({
3157
+ first: REQUEST_TIMEOUT_MS$1,
3158
+ with: () => {
3159
+ throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
3160
+ }
3161
+ }), (0, rxjs_operators.map)((data) => memoryRestEvents.listSucceeded({
3162
+ sessionId,
3163
+ memories: data.memories.filter((memory) => memory.scope === "user")
3164
+ })), (0, rxjs_operators.catchError)((error) => {
3165
+ if (error instanceof MemoryRouteUnavailableError) return (0, rxjs.of)(memoryRestEvents.listUnavailable({ sessionId }));
3166
+ return (0, rxjs.of)(memoryRestEvents.listFailed({
3167
+ sessionId,
3168
+ error: error instanceof Error ? error : new Error(String(error))
3169
+ }));
3170
+ }));
3171
+ });
3172
+ }
3173
+ /**
3174
+ * Fetches join credentials from the `/memories/subscribe` endpoint and maps
3175
+ * the response to a success/failure action. Requires both `joinToken` and
3176
+ * `joinCode` to be non-empty strings; throws otherwise so the `catchError`
3177
+ * path emits `credentialsFailed`.
3178
+ */
3179
+ function createMemoryCredentialsFetchObservable(environment, context, sessionId) {
3180
+ return (0, rxjs.defer)(() => memoryFromFetch(`${context.runtimeUrl}${MEMORIES_SUBSCRIBE_PATH}`, {
3181
+ selector: async (response) => {
3182
+ if (!response.ok) {
3183
+ if (ROUTE_UNAVAILABLE_STATUSES.has(response.status)) throw new MemoryRouteUnavailableError(String(response.status));
3184
+ throw new MemoryError("MEMORY_CREDENTIALS_FAILED", {
3185
+ message: `Failed to fetch memory subscribe credentials: ${response.status}`,
3186
+ retryable: isRetryableStatus(response.status)
3187
+ });
3188
+ }
3189
+ return response.json();
3190
+ },
3191
+ fetch: environment.fetch,
3192
+ method: "POST",
3193
+ headers: {
3194
+ ...context.headers,
3195
+ "Content-Type": "application/json"
3196
+ },
3197
+ body: JSON.stringify({})
3198
+ }).pipe((0, rxjs_operators.timeout)({
3199
+ first: REQUEST_TIMEOUT_MS$1,
3200
+ with: () => {
3201
+ throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
3202
+ }
3203
+ }), (0, rxjs_operators.map)((data) => {
3204
+ if (typeof data.joinToken !== "string" || data.joinToken.length === 0) throw new Error("missing joinToken");
3205
+ if (typeof data.joinCode !== "string" || data.joinCode.length === 0) throw new Error("missing joinCode");
3206
+ return memoryRestEvents.credentialsSucceeded({
3207
+ sessionId,
3208
+ joinToken: data.joinToken,
3209
+ joinCode: data.joinCode
3210
+ });
3211
+ }), (0, rxjs_operators.catchError)((error) => {
3212
+ if (error instanceof MemoryRouteUnavailableError) return (0, rxjs.of)(memoryRestEvents.credentialsUnavailable({ sessionId }));
3213
+ return (0, rxjs.of)(memoryRestEvents.credentialsFailed({
3214
+ sessionId,
3215
+ error: error instanceof Error ? error : new Error(String(error))
3216
+ }));
3217
+ })));
3218
+ }
3219
+ /** Projects a REST mutation response to the public {@link Memory} shape. */
3220
+ function responseToMemory(data) {
3221
+ return {
3222
+ id: data.id,
3223
+ kind: data.kind,
3224
+ scope: data.scope,
3225
+ content: data.content,
3226
+ sourceThreadIds: data.sourceThreadIds,
3227
+ invalidatedAt: data.invalidatedAt
3228
+ };
3229
+ }
3230
+ const MEMORY_KINDS = new Set([
3231
+ "topical",
3232
+ "episodic",
3233
+ "operational"
3234
+ ]);
3235
+ const MEMORY_SCOPES = new Set(["user", "project"]);
3236
+ /**
3237
+ * Validates the required fields of a create/supersede REST response before it is
3238
+ * projected to a {@link Memory}. Returns an `Error` describing the first
3239
+ * missing/invalid field, or `null` when the body is well-formed. Without this a
3240
+ * malformed 200 body yields a Memory with undefined fields that gets upserted.
3241
+ */
3242
+ function validateMutationResponse(data) {
3243
+ if (!data || typeof data !== "object") return /* @__PURE__ */ new Error("memory mutation response missing/invalid body");
3244
+ if (typeof data.id !== "string" || data.id.length === 0) return /* @__PURE__ */ new Error("memory mutation response missing/invalid id");
3245
+ if (typeof data.kind !== "string" || !MEMORY_KINDS.has(data.kind)) return /* @__PURE__ */ new Error("memory mutation response missing/invalid kind");
3246
+ if (typeof data.scope !== "string" || !MEMORY_SCOPES.has(data.scope)) return /* @__PURE__ */ new Error("memory mutation response missing/invalid scope");
3247
+ if (typeof data.content !== "string") return /* @__PURE__ */ new Error("memory mutation response missing/invalid content");
3248
+ if (!Array.isArray(data.sourceThreadIds) || !data.sourceThreadIds.every((id) => typeof id === "string")) return /* @__PURE__ */ new Error("memory mutation response missing/invalid sourceThreadIds");
3249
+ if (data.invalidatedAt !== null && typeof data.invalidatedAt !== "string") return /* @__PURE__ */ new Error("memory mutation response missing/invalid invalidatedAt");
3250
+ return null;
3251
+ }
3252
+ /**
3253
+ * Request body for create/supersede. `scope` is forwarded only when the caller
3254
+ * supplies it: the platform owns the default (`scope` defaults to `"user"` in
3255
+ * the `/api/memories` schema), so the store does not second-guess it here —
3256
+ * one default, at the contract owner. `sourceThreadIds` defaults to `[]`.
3257
+ */
3258
+ function toMutationBody(input) {
3259
+ return {
3260
+ content: input.content,
3261
+ kind: input.kind,
3262
+ ...input.scope !== void 0 ? { scope: input.scope } : {},
3263
+ sourceThreadIds: input.sourceThreadIds ?? []
3264
+ };
3265
+ }
3266
+ /**
3267
+ * Builds the actions a successful mutation dispatches (server-authoritative):
3268
+ * the REST response is applied to local state immediately, and the realtime
3269
+ * event reconciles idempotently (upsert-by-id). `mutationFinished` resolves the
3270
+ * caller's promise.
3271
+ */
3272
+ function buildMutationSuccessActions(request, data) {
3273
+ const { requestId, sessionId } = request;
3274
+ if (request.kind === "remove") return [memoryDomainEvents.memoryInvalidated({
3275
+ sessionId,
3276
+ memoryId: request.id
3277
+ }), memoryRestEvents.mutationFinished({ outcome: {
3278
+ requestId,
3279
+ sessionId,
3280
+ ok: true,
3281
+ memory: null
3282
+ } })];
3283
+ const validationError = validateMutationResponse(data);
3284
+ if (validationError) return [memoryRestEvents.mutationFinished({ outcome: {
3285
+ requestId,
3286
+ sessionId,
3287
+ ok: false,
3288
+ error: validationError
3289
+ } })];
3290
+ const memory = responseToMemory(data);
3291
+ if (request.kind === "update") {
3292
+ const retiredId = data.retiredId;
3293
+ if (typeof retiredId !== "string" || retiredId.length === 0) return [memoryRestEvents.mutationFinished({ outcome: {
3294
+ requestId,
3295
+ sessionId,
3296
+ ok: false,
3297
+ error: /* @__PURE__ */ new Error("supersede response missing retiredId")
3298
+ } })];
3299
+ return [
3300
+ memoryDomainEvents.memoryInvalidated({
3301
+ sessionId,
3302
+ memoryId: retiredId
3303
+ }),
3304
+ memoryDomainEvents.memoryUpserted({
3305
+ sessionId,
3306
+ memory
3307
+ }),
3308
+ memoryRestEvents.mutationFinished({ outcome: {
3309
+ requestId,
3310
+ sessionId,
3311
+ ok: true,
3312
+ memory
3313
+ } })
3314
+ ];
3315
+ }
3316
+ return [memoryDomainEvents.memoryUpserted({
3317
+ sessionId,
3318
+ memory
3319
+ }), memoryRestEvents.mutationFinished({ outcome: {
3320
+ requestId,
3321
+ sessionId,
3322
+ ok: true,
3323
+ memory
3324
+ } })];
3325
+ }
3326
+ /** Performs a create/supersede/retire HTTP call and emits its resulting actions. */
3327
+ function createMemoryMutationObservable(environment, context, request) {
3328
+ const method = request.kind === "add" ? "POST" : request.kind === "update" ? "PATCH" : "DELETE";
3329
+ const path = request.kind === "add" ? MEMORIES_PATH : `${MEMORIES_PATH}/${encodeURIComponent(request.id)}`;
3330
+ return (0, rxjs.defer)(() => memoryFromFetch(`${context.runtimeUrl}${path}`, {
3331
+ selector: async (response) => {
3332
+ if (!response.ok) throw new MemoryError("MEMORY_MUTATION_FAILED", {
3333
+ message: `Request failed: ${response.status}`,
3334
+ retryable: isRetryableStatus(response.status)
3335
+ });
3336
+ return request.kind === "remove" ? null : await response.json();
3337
+ },
3338
+ fetch: environment.fetch,
3339
+ method,
3340
+ headers: {
3341
+ ...context.headers,
3342
+ "Content-Type": "application/json"
3343
+ },
3344
+ body: request.kind === "remove" ? void 0 : JSON.stringify(request.body)
3345
+ }).pipe((0, rxjs_operators.timeout)({
3346
+ first: REQUEST_TIMEOUT_MS$1,
3347
+ with: () => {
3348
+ throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
3349
+ }
3350
+ }), (0, rxjs_operators.mergeMap)((data) => (0, rxjs.of)(...buildMutationSuccessActions(request, data))), (0, rxjs_operators.catchError)((error) => (0, rxjs.of)(memoryRestEvents.mutationFinished({ outcome: {
3351
+ requestId: request.requestId,
3352
+ sessionId: request.sessionId,
3353
+ ok: false,
3354
+ error: error instanceof Error ? error : new Error(String(error))
3355
+ } })))));
3356
+ }
3357
+ /**
3358
+ * Creates the framework-agnostic memory store: a REST snapshot on `setContext`,
3359
+ * server-authoritative add/update/remove mutations, and realtime
3360
+ * `memory_metadata` deltas off the injected `user_meta` event source — all
3361
+ * reduced into observable state.
3362
+ */
3363
+ function createMemoryStore(environment) {
3364
+ let memoryRequestId = 0;
3365
+ const createMemoryRequestId = () => {
3366
+ memoryRequestId += 1;
3367
+ return `memory-request-${memoryRequestId}`;
3368
+ };
3369
+ 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 }))));
3370
+ 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 }))));
3371
+ 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) => ({
3372
+ action,
3373
+ context
3374
+ })), (0, rxjs_operators.takeUntil)(actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped))), (0, rxjs_operators.switchMap)(({ action: currentAction, context }) => createMemoryCredentialsFetchObservable(environment, context, currentAction.sessionId))))));
3375
+ const store = createStore({
3376
+ reducer: memoryReducer,
3377
+ effects: [
3378
+ bootstrapEffect,
3379
+ credentialsBootstrapEffect,
3380
+ 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) => ({
3381
+ action,
3382
+ context
3383
+ })), (0, rxjs_operators.takeUntil)(actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped))), (0, rxjs_operators.switchMap)(({ action: currentAction, context }) => createMemoryFetchObservable(environment, context, currentAction.sessionId)))))),
3384
+ credentialsFetchEffect,
3385
+ createEffect((actions$, state$) => actions$.pipe(ofType(memoryAdapterEvents.addRequested, memoryAdapterEvents.updateRequested, memoryAdapterEvents.removeRequested), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.mergeMap)(([action, state]) => {
3386
+ const context = state.context;
3387
+ const sessionId = state.sessionId;
3388
+ if (!context?.runtimeUrl) return (0, rxjs.of)(memoryRestEvents.mutationFinished({ outcome: {
3389
+ requestId: action.requestId,
3390
+ sessionId,
3391
+ ok: false,
3392
+ error: /* @__PURE__ */ new Error("Runtime URL is not configured")
3393
+ } }));
3394
+ if (memoryAdapterEvents.addRequested.match(action)) return createMemoryMutationObservable(environment, context, {
3395
+ requestId: action.requestId,
3396
+ sessionId,
3397
+ kind: "add",
3398
+ body: toMutationBody(action.input)
3399
+ });
3400
+ if (memoryAdapterEvents.updateRequested.match(action)) return createMemoryMutationObservable(environment, context, {
3401
+ requestId: action.requestId,
3402
+ sessionId,
3403
+ kind: "update",
3404
+ id: action.id,
3405
+ body: toMutationBody(action.changes)
3406
+ });
3407
+ return createMemoryMutationObservable(environment, context, {
3408
+ requestId: action.requestId,
3409
+ sessionId,
3410
+ kind: "remove",
3411
+ id: action.id
3412
+ });
3413
+ }))),
3414
+ createEffect((actions$, state$) => actions$.pipe(ofType(memoryRestEvents.credentialsSucceeded), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.filter)(([action, state]) => {
3415
+ return action.sessionId === state.sessionId && Boolean(state.context?.wsUrl);
3416
+ }), (0, rxjs_operators.switchMap)(([action, state]) => {
3417
+ const context = state.context;
3418
+ const { joinToken, joinCode } = action;
3419
+ const sessionId = action.sessionId;
3420
+ const shutdown$ = actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped));
3421
+ return (0, rxjs.defer)(() => {
3422
+ const socket$ = ɵphoenixSocket$({
3423
+ url: context.wsUrl,
3424
+ options: {
3425
+ params: { join_token: joinToken },
3426
+ reconnectAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(100, 1e4),
3427
+ rejoinAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(1e3, 3e4)
3428
+ }
3429
+ }).pipe((0, rxjs_operators.shareReplay)({
3430
+ bufferSize: 1,
3431
+ refCount: true
3432
+ }));
3433
+ const channel$ = ɵphoenixChannel$({
3434
+ socket$,
3435
+ topic: `user_meta:memories:${joinCode}`
3436
+ }).pipe((0, rxjs_operators.shareReplay)({
3437
+ bufferSize: 1,
3438
+ refCount: true
3439
+ }));
3440
+ const fatalSocketShutdown$ = ɵobservePhoenixSocketHealth$(ɵobservePhoenixSocketSignals$(socket$).pipe((0, rxjs_operators.share)()), MAX_SOCKET_RETRIES$1).pipe((0, rxjs_operators.catchError)(() => {
3441
+ console.warn(`[memory] WebSocket failed after ${MAX_SOCKET_RETRIES$1} attempts, giving up`);
3442
+ return (0, rxjs.of)(void 0);
3443
+ }), (0, rxjs_operators.share)());
3444
+ const fatalStatus$ = fatalSocketShutdown$.pipe((0, rxjs_operators.map)(() => memoryDomainEvents.realtimeUnavailable({ sessionId })));
3445
+ const metadata$ = channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => ɵobservePhoenixEvent$(channel, MEMORY_METADATA_EVENT)), (0, rxjs_operators.map)((event) => mapMemoryMetadataEvent(event, action.sessionId)));
3446
+ const join$ = ɵjoinPhoenixChannel$(channel$).pipe((0, rxjs_operators.concatWith)((0, rxjs.of)(memoryDomainEvents.realtimeConnected({ sessionId }))), (0, rxjs_operators.catchError)((error) => {
3447
+ console.warn(`[memory] failed to join user_meta:memories:${joinCode}`, error);
3448
+ return (0, rxjs.of)(memoryDomainEvents.realtimeUnavailable({ sessionId }));
3449
+ }));
3450
+ 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)(() => {}));
3451
+ });
3452
+ })))
3453
+ ]
3454
+ });
3455
+ function trackMutation(dispatchAction, extract) {
3456
+ const { requestId } = dispatchAction;
3457
+ 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)(() => ({
3458
+ requestId,
3459
+ sessionId: store.getState().sessionId,
3460
+ ok: false,
3461
+ error: /* @__PURE__ */ new Error("Memory store stopped before mutation completed")
3462
+ })))).pipe((0, rxjs_operators.take)(1))).then((outcome) => {
3463
+ if (!outcome.ok) throw outcome.error;
3464
+ return extract(outcome);
3465
+ });
3466
+ store.dispatch(dispatchAction);
3467
+ return resultPromise;
3468
+ }
3469
+ return {
3470
+ start() {
3471
+ store.init();
3472
+ store.dispatch(memoryAdapterEvents.started());
3473
+ },
3474
+ stop() {
3475
+ store.dispatch(memoryAdapterEvents.stopped());
3476
+ store.stop();
3477
+ },
3478
+ setContext(context) {
3479
+ store.dispatch(memoryAdapterEvents.contextChanged({ context }));
3480
+ },
3481
+ refresh() {
3482
+ const { sessionId, context } = store.getState();
3483
+ if (!context) return Promise.resolve();
3484
+ 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) => {
3485
+ if (memoryRestEvents.listFailed.match(action)) throw action.error;
3486
+ if (memoryAdapterEvents.stopped.match(action)) throw new Error("Memory store stopped before refresh completed");
3487
+ if (memoryAdapterEvents.contextChanged.match(action)) return;
3488
+ });
3489
+ store.dispatch(memoryRestEvents.listRequested({ sessionId }));
3490
+ return done;
3491
+ },
3492
+ addMemory(input) {
3493
+ return trackMutation(memoryAdapterEvents.addRequested({
3494
+ requestId: createMemoryRequestId(),
3495
+ input
3496
+ }), (outcome) => {
3497
+ if (outcome.memory == null) throw new Error("add resolved without a memory");
3498
+ return outcome.memory;
3499
+ });
3500
+ },
3501
+ updateMemory(id, changes) {
3502
+ return trackMutation(memoryAdapterEvents.updateRequested({
3503
+ requestId: createMemoryRequestId(),
3504
+ id,
3505
+ changes
3506
+ }), (outcome) => {
3507
+ if (outcome.memory == null) throw new Error("update resolved without a memory");
3508
+ return outcome.memory;
3509
+ });
3510
+ },
3511
+ removeMemory(id) {
3512
+ return trackMutation(memoryAdapterEvents.removeRequested({
3513
+ requestId: createMemoryRequestId(),
3514
+ id
3515
+ }), () => void 0);
3516
+ },
3517
+ getState() {
3518
+ return store.getState();
3519
+ },
3520
+ getServerState() {
3521
+ return initialMemoryState;
3522
+ },
3523
+ select: store.select.bind(store)
3524
+ };
3525
+ }
3526
+ const ɵmemoryAdapterEvents = memoryAdapterEvents;
3527
+ const ɵmemoryRestEvents = memoryRestEvents;
3528
+ const ɵmemoryDomainEvents = memoryDomainEvents;
3529
+ const ɵmemoryReducer = memoryReducer;
3530
+ const ɵmapMemoryMetadataEvent = mapMemoryMetadataEvent;
3531
+ const ɵselectMemories = selectMemories;
3532
+ const ɵselectMemoriesIsLoading = selectMemoriesIsLoading;
3533
+ const ɵselectMemoriesError = selectMemoriesError;
3534
+ const ɵselectMemoriesIsMutating = selectMemoriesIsMutating;
3535
+ const ɵselectMemoriesAvailable = selectMemoriesAvailable;
3536
+ const ɵselectMemoriesRealtimeStatus = selectMemoriesRealtimeStatus;
3537
+
3538
+ //#endregion
3539
+ //#region src/core/core.ts
3540
+ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode) {
3541
+ CopilotKitCoreErrorCode["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
3542
+ CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
3543
+ CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
3544
+ CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
3545
+ CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
3546
+ CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
3547
+ CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
3548
+ CopilotKitCoreErrorCode["TOOL_NOT_FOUND"] = "tool_not_found";
3549
+ CopilotKitCoreErrorCode["AGENT_NOT_FOUND"] = "agent_not_found";
3550
+ /**
3551
+ * Emitted when an agent run fails because the thread is already locked
3552
+ * by another active run.
3553
+ *
3554
+ * @example
3555
+ * ```tsx
3556
+ * <CopilotKitProvider
3557
+ * onError={({ code, error, context }) => {
3558
+ * if (code === "agent_thread_locked") {
3559
+ * // Show "Agent is busy, retry?" UI
3560
+ * }
3561
+ * }}
3562
+ * />
3563
+ * ```
3564
+ */
3565
+ CopilotKitCoreErrorCode["AGENT_THREAD_LOCKED"] = "agent_thread_locked";
3566
+ CopilotKitCoreErrorCode["TRANSCRIPTION_FAILED"] = "transcription_failed";
3567
+ CopilotKitCoreErrorCode["TRANSCRIPTION_SERVICE_NOT_CONFIGURED"] = "transcription_service_not_configured";
3568
+ CopilotKitCoreErrorCode["TRANSCRIPTION_INVALID_AUDIO"] = "transcription_invalid_audio";
3569
+ CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
3570
+ CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
3571
+ CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
3572
+ CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
3573
+ return CopilotKitCoreErrorCode;
3574
+ }({});
3575
+ /**
3576
+ * Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
3577
+ * to module scope so the Set is allocated once, not per-subscription.
3578
+ */
3579
+ const ALLOWED_KEYS = new Set([
3580
+ "onMessagesChanged",
3581
+ "onStateChanged",
3582
+ "onRunInitialized",
3583
+ "onRunFinalized",
3584
+ "onRunFailed",
3585
+ "onRunErrorEvent"
3586
+ ]);
3587
+ let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
3588
+ CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
3589
+ CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
3590
+ CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
3591
+ CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
3592
+ return CopilotKitCoreRuntimeConnectionStatus;
3593
+ }({});
3594
+ /**
3595
+ * Normalize a header map to the internal invariant: a `Record<string, string>`
3596
+ * with no `null`/`undefined` values. Entries whose value is `null`/`undefined`
3597
+ * are dropped (this is how a header is cleared). Shared by the constructor and
3598
+ * `setHeaders` so both write paths into `_headers` enforce the same invariant.
3599
+ */
3600
+ function normalizeHeaders(headers) {
3601
+ return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
3602
+ }
3603
+ var CopilotKitCore = class {
3604
+ _headers;
3605
+ _credentials;
3606
+ _properties;
3607
+ _defaultThrottleMs;
3608
+ _debug;
3609
+ subscribers = /* @__PURE__ */ new Set();
3610
+ agentRegistry;
3611
+ contextStore;
3612
+ suggestionEngine;
3613
+ runHandler;
3614
+ stateManager;
3615
+ threadStoreRegistry;
3616
+ /**
3617
+ * The single core-owned memory store, created lazily on first
3618
+ * `getMemoryStore()` and kept user-scoped for the lifetime of the core.
3619
+ * Its runtime context is wired by the core itself (see `syncMemoryContext`),
3620
+ * so callers never register or look it up by `agentId`.
3621
+ */
3622
+ _memoryStore;
3623
+ /**
3624
+ * Tracks the agent IDs from the most recent `onAgentsChanged` notification.
3625
+ * Used to gate thread-store auto-unregister so the FIRST empty-agents
3626
+ * notification (before published agents are merged in) does not rip out a
3627
+ * store that was registered prior to that initial notification.
3628
+ */
3629
+ previousAgentIds = /* @__PURE__ */ new Set();
3630
+ constructor({ runtimeUrl, runtimeTransport = "auto", headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
3631
+ this._headers = normalizeHeaders(headers);
3632
+ this._credentials = credentials;
3633
+ this._properties = properties;
3634
+ this._debug = debug;
3635
+ this.agentRegistry = new AgentRegistry(this);
3636
+ this.contextStore = new ContextStore(this);
3637
+ this.suggestionEngine = new SuggestionEngine(this);
3638
+ this.runHandler = new RunHandler(this);
3639
+ this.stateManager = new StateManager(this);
3640
+ this.threadStoreRegistry = new ThreadStoreRegistry(this);
3641
+ this.agentRegistry.initialize(agents__unsafe_dev_only);
3642
+ this.runHandler.initialize(tools);
3643
+ this.suggestionEngine.initialize(suggestionsConfig);
3644
+ this.stateManager.initialize();
3645
+ this.agentRegistry.setRuntimeTransport(runtimeTransport);
3646
+ this.agentRegistry.setRuntimeUrl(runtimeUrl);
3647
+ this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
3648
+ this.subscribe({
3649
+ onRuntimeConnectionStatusChanged: () => {
3650
+ if (this._memoryStore) this.syncMemoryContext();
3651
+ },
3652
+ onAgentsChanged: ({ agents }) => {
3653
+ Object.values(agents).forEach((agent) => {
3654
+ if (agent.agentId) this.stateManager.subscribeToAgent(agent);
3655
+ });
3656
+ const currentAgentIds = new Set(Object.keys(agents));
3657
+ for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) try {
3658
+ this.threadStoreRegistry.unregister(agentId);
3659
+ } catch (err) {
3660
+ console.error(`CopilotKitCore.onAgentsChanged: threadStoreRegistry.unregister failed for "${agentId}":`, err);
3661
+ }
3662
+ for (const agentId of this.previousAgentIds) if (!currentAgentIds.has(agentId)) try {
3663
+ this.stateManager.unsubscribeFromAgent(agentId);
3664
+ } catch (err) {
3665
+ console.error(`CopilotKitCore.onAgentsChanged: stateManager.unsubscribeFromAgent failed for "${agentId}":`, err);
3666
+ }
3667
+ this.previousAgentIds = currentAgentIds;
3668
+ }
3669
+ });
3670
+ }
3671
+ /**
3672
+ * Internal method used by delegate classes and subclasses to notify subscribers
3673
+ */
3674
+ async notifySubscribers(handler, errorMessage) {
3675
+ await Promise.all(Array.from(this.subscribers).map(async (subscriber) => {
3676
+ try {
3677
+ await handler(subscriber);
3678
+ } catch (error) {
3679
+ console.error(errorMessage, error);
3680
+ }
3681
+ }));
3682
+ }
3683
+ /**
3684
+ * Internal method used by delegate classes to emit errors
3685
+ */
3686
+ async emitError({ error, code, context = {} }) {
3687
+ await this.notifySubscribers((subscriber) => subscriber.onError?.({
3688
+ copilotkit: this,
3689
+ error,
3690
+ code,
3691
+ context
3692
+ }), "Subscriber onError error:");
3693
+ }
3694
+ /**
3695
+ * Log a message to the console and emit an error to subscribers.
3696
+ * Catches failures from `emitError` itself to prevent unhandled rejections.
3697
+ */
3698
+ logAndEmitError(message, params, logLevel = "error") {
3699
+ console[logLevel](message, params.error);
3700
+ this.emitError(params).catch((emitErr) => {
2670
3701
  console.error(message + " — emitError itself failed:", emitErr);
2671
3702
  });
2672
3703
  }
@@ -2809,6 +3840,7 @@ var CopilotKitCore = class {
2809
3840
  */
2810
3841
  setHeaders(headers) {
2811
3842
  this._headers = normalizeHeaders(headers);
3843
+ if (this._memoryStore) this.syncMemoryContext();
2812
3844
  this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
2813
3845
  this.notifySubscribers((subscriber) => subscriber.onHeadersChanged?.({
2814
3846
  copilotkit: this,
@@ -2914,6 +3946,46 @@ var CopilotKitCore = class {
2914
3946
  return this.threadStoreRegistry.getAll();
2915
3947
  }
2916
3948
  /**
3949
+ * Returns the single core-owned, user-scoped memory store, creating and
3950
+ * starting it on first access. Unlike thread stores, memory is not scoped per
3951
+ * agent: there is exactly one store whose runtime context the core wires
3952
+ * itself (see `syncMemoryContext`), so consumers (e.g. a `useMemories`
3953
+ * binding) just read this store rather than registering one.
3954
+ */
3955
+ getMemoryStore() {
3956
+ return this.ensureMemoryStore();
3957
+ }
3958
+ /**
3959
+ * Lazily creates, starts, and context-syncs the core-owned memory store on
3960
+ * first access, then returns it. Subsequent calls return the existing store.
3961
+ * The store is constructed with a bound `globalThis.fetch` and immediately
3962
+ * has its runtime context synced from the current connection state.
3963
+ */
3964
+ ensureMemoryStore() {
3965
+ if (!this._memoryStore) {
3966
+ this._memoryStore = createMemoryStore({ fetch: globalThis.fetch.bind(globalThis) });
3967
+ this._memoryStore.start();
3968
+ this.syncMemoryContext();
3969
+ }
3970
+ return this._memoryStore;
3971
+ }
3972
+ /**
3973
+ * Pushes the current runtime wiring into the memory store. When the runtime
3974
+ * is connected and both the intelligence WebSocket URL and runtime URL are
3975
+ * available, the store receives a context (runtime URL, WebSocket URL, and a
3976
+ * copy of the current headers); otherwise its context is cleared. No-op when
3977
+ * the store has not been created yet.
3978
+ */
3979
+ syncMemoryContext() {
3980
+ if (!this._memoryStore) return;
3981
+ if (this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected && this.intelligence?.wsUrl && this.runtimeUrl) this._memoryStore.setContext({
3982
+ runtimeUrl: this.runtimeUrl,
3983
+ wsUrl: this.intelligence.wsUrl,
3984
+ headers: { ...this.headers }
3985
+ });
3986
+ else this._memoryStore.setContext(null);
3987
+ }
3988
+ /**
2917
3989
  * Suggestions management (delegated to SuggestionEngine)
2918
3990
  */
2919
3991
  addSuggestionsConfig(config) {
@@ -3074,517 +4146,261 @@ var CopilotKitCore = class {
3074
4146
  if (subscriber.onMessagesChanged) wrappedSubscriber.onMessagesChanged = (params) => {
3075
4147
  latestMessagesParams = params;
3076
4148
  throttler.maybeExecute();
3077
- };
3078
- 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
- }
4149
+ };
4150
+ if (subscriber.onStateChanged) wrappedSubscriber.onStateChanged = (params) => {
4151
+ latestStateParams = params;
4152
+ throttler.maybeExecute();
4153
+ };
4154
+ const subscription = agent.subscribe(wrappedSubscriber);
4155
+ return { unsubscribe: () => {
4156
+ active = false;
4157
+ throttler.cancel();
4158
+ subscription.unsubscribe();
4159
+ } };
3319
4160
  }
3320
- if (shouldCloseParens) {
3321
- const openParens = (result.match(/\(/g) || []).length;
3322
- const closeParens = (result.match(/\)/g) || []).length;
3323
- if (openParens > closeParens) result += ")".repeat(openParens - closeParens);
4161
+ /**
4162
+ * Agent connectivity (delegated to RunHandler)
4163
+ */
4164
+ async connectAgent(params) {
4165
+ return this.runHandler.connectAgent(params);
3324
4166
  }
3325
- return result;
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, () => ({}));
4167
+ stopAgent(params) {
4168
+ this.runHandler.abortCurrentRun();
4169
+ params.agent.abortRun();
3390
4170
  }
3391
- return group;
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);
4171
+ async runAgent(params) {
4172
+ return this.runHandler.runAgent(params);
3417
4173
  }
3418
- return (state, action) => {
3419
- const currentState = state ?? initialState;
3420
- const handlers = reducerMap.get(action.type);
3421
- if (!handlers || handlers.length === 0) return currentState;
3422
- let nextState = currentState;
3423
- for (const handler of handlers) nextState = handler(nextState, action);
3424
- return nextState;
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
- };
4174
+ /**
4175
+ * Programmatically execute a registered frontend tool without going through an LLM turn.
4176
+ * The handler runs, render components show up in the UI, and both the tool call and
4177
+ * result messages are added to `agent.messages`.
4178
+ */
4179
+ async runTool(params) {
4180
+ return this.runHandler.runTool(params);
3444
4181
  }
3445
- const projector = args[args.length - 1];
3446
- const selectors = args.slice(0, -1);
3447
- let hasCached = false;
3448
- let lastInputs = [];
3449
- let lastResult;
3450
- return (state) => {
3451
- const inputs = selectors.map((selector) => selector(state));
3452
- if (hasCached && inputs.length === lastInputs.length && inputs.every((value, index) => value === lastInputs[index])) return lastResult;
3453
- lastInputs = inputs;
3454
- lastResult = projector(...inputs);
3455
- hasCached = true;
3456
- return lastResult;
3457
- };
3458
- }
3459
- /**
3460
- * RxJS operator that maps state emissions through a selector and suppresses
3461
- * unchanged projected values via reference equality.
3462
- */
3463
- function select(selector) {
3464
- return (source$) => source$.pipe((0, rxjs_operators.map)(selector), (0, rxjs_operators.distinctUntilChanged)());
3465
- }
3466
- /**
3467
- * RxJS operator that filters an action stream by action creators and narrows
3468
- * the output action type to the matched creator union.
3469
- *
3470
- * @throws Error when called without at least one action creator.
3471
- */
3472
- function ofType(...creators) {
3473
- if (creators.length === 0) throw new Error("ofType requires at least one action creator");
3474
- const actionTypes = new Set(creators.map((creator) => creator.type));
3475
- return (source$) => {
3476
- return source$.pipe((0, rxjs_operators.filter)((action) => {
3477
- return actionTypes.has(action.type);
3478
- }));
3479
- };
3480
- }
3481
- /**
3482
- * Creates an effect descriptor consumed by `createStore`.
3483
- */
3484
- function createEffect(factory, options = {}) {
3485
- if (options.dispatch === false) return {
3486
- run: factory,
3487
- dispatch: false
3488
- };
3489
- return {
3490
- run: factory,
3491
- dispatch: true
3492
- };
3493
- }
3494
- /**
3495
- * Creates a small observable store with reducer + effects.
3496
- *
3497
- * Behavior:
3498
- * - `init()` starts effects and dispatches `@@micro-redux/init`.
3499
- * - `stop()` dispatches `@@micro-redux/stop` and unsubscribes all effects.
3500
- * - Effect action observation is scheduled on `asapScheduler` to avoid
3501
- * synchronous re-entrancy in the effect loop.
3502
- * - Any effect error triggers fail-fast teardown and errors both `actions$`
3503
- * and `state$`.
3504
- */
3505
- function createStore(options) {
3506
- const reducer = options.reducer;
3507
- const effects = options.effects ?? [];
3508
- let hasFatalError = false;
3509
- let isRunning = false;
3510
- let effectSubscriptions = new rxjs.Subscription();
3511
- let currentState = reducer(void 0, INTERNAL_BOOT_ACTION);
3512
- const stateSubject = new rxjs.BehaviorSubject(currentState);
3513
- const actionsSubject = new rxjs.Subject();
3514
- const dispatchInternal = (action) => {
3515
- if (hasFatalError) throw new Error("Store is in a failed state due to an effect error");
3516
- currentState = reducer(currentState, action);
3517
- stateSubject.next(currentState);
3518
- actionsSubject.next(action);
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
- }
4182
+ /**
4183
+ * State management (delegated to StateManager)
4184
+ */
4185
+ getStateByRun(agentId, threadId, runId) {
4186
+ return this.stateManager.getStateByRun(agentId, threadId, runId);
4187
+ }
4188
+ getRunIdForMessage(agentId, threadId, messageId) {
4189
+ return this.stateManager.getRunIdForMessage(agentId, threadId, messageId);
4190
+ }
4191
+ getRunIdsForThread(agentId, threadId) {
4192
+ return this.stateManager.getRunIdsForThread(agentId, threadId);
4193
+ }
4194
+ /**
4195
+ * Internal method used by RunHandler to build frontend tools
4196
+ */
4197
+ buildFrontendTools(agentId) {
4198
+ return this.runHandler.buildFrontendTools(agentId);
4199
+ }
4200
+ /**
4201
+ * Called before each follow-up agent run (after tool execution).
4202
+ *
4203
+ * When a frontend tool handler calls framework state setters (e.g. React's
4204
+ * setState), those updates are batched and deferred — they do not take effect
4205
+ * until the framework's scheduler runs (React uses MessageChannel).
4206
+ * useAgentContext registers context via useLayoutEffect, which runs
4207
+ * synchronously after React commits that deferred batch.
4208
+ *
4209
+ * Without yielding here, the follow-up runAgent reads the context store
4210
+ * synchronously while the deferred updates are still pending, producing stale
4211
+ * context for the next agent turn.
4212
+ *
4213
+ * Override in framework-specific subclasses to yield to the framework
4214
+ * scheduler before the follow-up run. The base implementation is a no-op
4215
+ * because non-React environments have no deferred state to flush.
4216
+ */
4217
+ async waitForPendingFrameworkUpdates() {}
4218
+ };
4219
+
4220
+ //#endregion
4221
+ //#region src/types.ts
4222
+ /**
4223
+ * Status of a tool call execution
4224
+ */
4225
+ let ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
4226
+ ToolCallStatus["InProgress"] = "inProgress";
4227
+ ToolCallStatus["Executing"] = "executing";
4228
+ ToolCallStatus["Complete"] = "complete";
4229
+ return ToolCallStatus;
4230
+ }({});
4231
+
4232
+ //#endregion
4233
+ //#region src/utils/markdown.ts
4234
+ function completePartialMarkdown(input) {
4235
+ let s = input;
4236
+ const fenceMatches = Array.from(s.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
4237
+ if (fenceMatches.length % 2 === 1) {
4238
+ const [, indent, fence] = fenceMatches[0];
4239
+ s += `\n${indent}${fence}`;
4240
+ }
4241
+ if (s.match(/\[([^\]]*)\]\(([^)]*)$/)) s += ")";
4242
+ const openElements = [];
4243
+ const chars = Array.from(s);
4244
+ const codeBlockRanges = [];
4245
+ const inlineCodeRanges = [];
4246
+ let tempCodeFenceCount = 0;
4247
+ let currentCodeBlockStart = -1;
4248
+ for (let i = 0; i < chars.length; i++) if (i === 0 || chars[i - 1] === "\n") {
4249
+ const lineMatch = s.substring(i).match(/^(\s*)(`{3,}|~{3,})/);
4250
+ if (lineMatch) {
4251
+ tempCodeFenceCount++;
4252
+ if (tempCodeFenceCount % 2 === 1) currentCodeBlockStart = i;
4253
+ else if (currentCodeBlockStart !== -1) {
4254
+ codeBlockRanges.push({
4255
+ start: currentCodeBlockStart,
4256
+ end: i + lineMatch[0].length
3542
4257
  });
3543
- effectSubscriptions.add(subscription);
3544
- continue;
4258
+ currentCodeBlockStart = -1;
3545
4259
  }
3546
- const subscription = effect.run(scheduledActions$, state$).subscribe({ error: (error) => {
3547
- failFast(error);
3548
- } });
3549
- effectSubscriptions.add(subscription);
4260
+ i += lineMatch[0].length - 1;
3550
4261
  }
3551
- };
3552
- return {
3553
- dispatch(action) {
3554
- dispatchInternal(action);
3555
- },
3556
- getState() {
3557
- return currentState;
3558
- },
3559
- get state$() {
3560
- return stateSubject.asObservable();
3561
- },
3562
- get actions$() {
3563
- return actionsSubject.asObservable();
3564
- },
3565
- select(selector) {
3566
- return stateSubject.asObservable().pipe(select(selector));
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;
4262
+ }
4263
+ for (let i = 0; i < chars.length; i++) if (chars[i] === "`") {
4264
+ let backslashCount = 0;
4265
+ for (let j = i - 1; j >= 0 && chars[j] === "\\"; j--) backslashCount++;
4266
+ if (backslashCount % 2 === 0) {
4267
+ for (let j = i + 1; j < chars.length; j++) if (chars[j] === "`") {
4268
+ let closingBackslashCount = 0;
4269
+ for (let k = j - 1; k >= 0 && chars[k] === "\\"; k--) closingBackslashCount++;
4270
+ if (closingBackslashCount % 2 === 0) {
4271
+ inlineCodeRanges.push({
4272
+ start: i,
4273
+ end: j + 1
4274
+ });
4275
+ i = j;
4276
+ break;
4277
+ }
4278
+ }
3581
4279
  }
4280
+ }
4281
+ const isInCode = (pos) => {
4282
+ return codeBlockRanges.some((range) => pos >= range.start && pos < range.end) || inlineCodeRanges.some((range) => pos >= range.start && pos < range.end);
3582
4283
  };
4284
+ for (let i = 0; i < chars.length; i++) {
4285
+ const char = chars[i];
4286
+ const nextChar = chars[i + 1];
4287
+ const prevChar = chars[i - 1];
4288
+ if (isInCode(i)) continue;
4289
+ if (char === "[") {
4290
+ let isCompleteLink = false;
4291
+ let bracketDepth = 1;
4292
+ let j = i + 1;
4293
+ while (j < chars.length && bracketDepth > 0) {
4294
+ if (chars[j] === "[" && !isInCode(j)) bracketDepth++;
4295
+ if (chars[j] === "]" && !isInCode(j)) bracketDepth--;
4296
+ j++;
4297
+ }
4298
+ if (bracketDepth === 0 && chars[j] === "(") {
4299
+ let parenDepth = 1;
4300
+ j++;
4301
+ while (j < chars.length && parenDepth > 0) {
4302
+ if (chars[j] === "(" && !isInCode(j)) parenDepth++;
4303
+ if (chars[j] === ")" && !isInCode(j)) parenDepth--;
4304
+ j++;
4305
+ }
4306
+ if (parenDepth === 0) {
4307
+ isCompleteLink = true;
4308
+ i = j - 1;
4309
+ continue;
4310
+ }
4311
+ }
4312
+ if (!isCompleteLink) {
4313
+ const existingIndex = openElements.findIndex((el) => el.type === "bracket");
4314
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4315
+ else openElements.push({
4316
+ type: "bracket",
4317
+ marker: "[",
4318
+ position: i
4319
+ });
4320
+ }
4321
+ } else if (char === "*" && nextChar === "*") {
4322
+ const existingIndex = openElements.findIndex((el) => el.type === "bold_star");
4323
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4324
+ else openElements.push({
4325
+ type: "bold_star",
4326
+ marker: "**",
4327
+ position: i
4328
+ });
4329
+ i++;
4330
+ } else if (char === "_" && nextChar === "_") {
4331
+ const existingIndex = openElements.findIndex((el) => el.type === "bold_underscore");
4332
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4333
+ else openElements.push({
4334
+ type: "bold_underscore",
4335
+ marker: "__",
4336
+ position: i
4337
+ });
4338
+ i++;
4339
+ } else if (char === "~" && nextChar === "~") {
4340
+ const existingIndex = openElements.findIndex((el) => el.type === "strike");
4341
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4342
+ else openElements.push({
4343
+ type: "strike",
4344
+ marker: "~~",
4345
+ position: i
4346
+ });
4347
+ i++;
4348
+ } else if (char === "*" && prevChar !== "*" && nextChar !== "*") {
4349
+ const existingIndex = openElements.findIndex((el) => el.type === "italic_star");
4350
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4351
+ else openElements.push({
4352
+ type: "italic_star",
4353
+ marker: "*",
4354
+ position: i
4355
+ });
4356
+ } else if (char === "_" && prevChar !== "_" && nextChar !== "_") {
4357
+ const existingIndex = openElements.findIndex((el) => el.type === "italic_underscore");
4358
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4359
+ else openElements.push({
4360
+ type: "italic_underscore",
4361
+ marker: "_",
4362
+ position: i
4363
+ });
4364
+ }
4365
+ }
4366
+ let backtickCount = 0;
4367
+ for (let i = 0; i < chars.length; i++) if (chars[i] === "`" && !isInCode(i)) backtickCount++;
4368
+ if (backtickCount % 2 === 1) s += "`";
4369
+ openElements.sort((a, b) => b.position - a.position);
4370
+ const closers = openElements.map((el) => {
4371
+ switch (el.type) {
4372
+ case "bracket": return "]";
4373
+ case "bold_star": return "**";
4374
+ case "bold_underscore": return "__";
4375
+ case "strike": return "~~";
4376
+ case "italic_star": return "*";
4377
+ case "italic_underscore": return "_";
4378
+ default: return "";
4379
+ }
4380
+ });
4381
+ let result = s + closers.join("");
4382
+ const finalFenceMatches = Array.from(result.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
4383
+ const hasUnclosedBacktick = (result.match(/`/g) || []).length % 2 === 1;
4384
+ const hasUnclosedCodeFence = finalFenceMatches.length % 2 === 1;
4385
+ let shouldCloseParens = !hasUnclosedBacktick && !hasUnclosedCodeFence;
4386
+ if (shouldCloseParens) {
4387
+ const lastOpenParen = result.lastIndexOf("(");
4388
+ if (lastOpenParen !== -1) {
4389
+ if ((result.substring(0, lastOpenParen).match(/`/g) || []).length % 2 === 1) shouldCloseParens = false;
4390
+ }
4391
+ }
4392
+ if (shouldCloseParens) {
4393
+ const openParens = (result.match(/\(/g) || []).length;
4394
+ const closeParens = (result.match(/\)/g) || []).length;
4395
+ if (openParens > closeParens) result += ")".repeat(openParens - closeParens);
4396
+ }
4397
+ return result;
3583
4398
  }
3584
4399
 
3585
4400
  //#endregion
3586
4401
  //#region src/threads.ts
3587
4402
  const THREADS_CHANNEL_EVENT = "thread_metadata";
4403
+ const THREAD_RUN_ACTIVITY_CHANNEL_EVENT = "thread_run_activity";
3588
4404
  const THREAD_SUBSCRIBE_PATH = "/threads/subscribe";
3589
4405
  const MAX_SOCKET_RETRIES = 5;
3590
4406
  const REQUEST_TIMEOUT_MS = 15e3;
@@ -3628,7 +4444,8 @@ const threadSocketEvents = createActionGroup("Thread Socket", {
3628
4444
  errored: props(),
3629
4445
  joinFailed: props(),
3630
4446
  joinTimedOut: props(),
3631
- metadataReceived: props()
4447
+ metadataReceived: props(),
4448
+ runActivityReceived: props()
3632
4449
  });
3633
4450
  const threadDomainEvents = createActionGroup("Thread Domain", {
3634
4451
  threadUpserted: props(),
@@ -3647,6 +4464,28 @@ function upsertThread(threads, thread) {
3647
4464
  next[existingIndex] = thread;
3648
4465
  return sortThreadsByRecency(next);
3649
4466
  }
4467
+ /**
4468
+ * Returns a non-empty string payload field or undefined for absent fields.
4469
+ */
4470
+ function optionalString(value) {
4471
+ return typeof value === "string" && value.length > 0 ? value : void 0;
4472
+ }
4473
+ /**
4474
+ * Converts gateway run-activity payloads into the internal TypeScript shape.
4475
+ */
4476
+ function normalizeThreadRunActivityNotification(payload) {
4477
+ const threadId = optionalString(payload.threadId ?? payload.thread_id);
4478
+ const eventType = optionalString(payload.eventType ?? payload.event_type);
4479
+ if (!threadId || !eventType) return null;
4480
+ return {
4481
+ type: "thread_run_activity",
4482
+ threadId,
4483
+ agentId: optionalString(payload.agentId ?? payload.agent_id),
4484
+ runId: optionalString(payload.runId ?? payload.run_id),
4485
+ eventType,
4486
+ latestEventId: optionalString(payload.latestEventId ?? payload.latest_event_id)
4487
+ };
4488
+ }
3650
4489
  const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
3651
4490
  ...state,
3652
4491
  context,
@@ -3680,12 +4519,14 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3680
4519
  };
3681
4520
  }), on(threadRestEvents.listSucceeded, (state, { sessionId, threads, joinCode, nextCursor }) => {
3682
4521
  if (sessionId !== state.sessionId) return state;
4522
+ const joinCodeChanged = joinCode !== state.metadataJoinCode;
3683
4523
  return {
3684
4524
  ...state,
3685
4525
  threads: sortThreadsByRecency(threads),
3686
4526
  isLoading: false,
3687
4527
  error: null,
3688
4528
  metadataJoinCode: joinCode,
4529
+ metadataCredentialsRequested: joinCodeChanged ? false : state.metadataCredentialsRequested,
3689
4530
  nextCursor
3690
4531
  };
3691
4532
  }), on(threadRestEvents.listFailed, (state, { sessionId, error }) => {
@@ -3714,7 +4555,10 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3714
4555
  };
3715
4556
  }), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId }) => {
3716
4557
  if (sessionId !== state.sessionId) return state;
3717
- return state;
4558
+ return {
4559
+ ...state,
4560
+ metadataCredentialsRequested: false
4561
+ };
3718
4562
  }), on(threadRestEvents.metadataCredentialsRequested, (state, { sessionId }) => {
3719
4563
  if (sessionId !== state.sessionId) return state;
3720
4564
  return {
@@ -3872,7 +4716,27 @@ function createThreadRequestId() {
3872
4716
  return `thread-request-${threadRequestId}`;
3873
4717
  }
3874
4718
  function threadFromFetch(input, init) {
3875
- return (0, rxjs_fetch.fromFetch)(input, init);
4719
+ return new rxjs.Observable((subscriber) => {
4720
+ const { fetch: fetchImpl, selector, signal, ...requestInit } = init;
4721
+ const controller = new AbortController();
4722
+ const abortRequest = () => controller.abort();
4723
+ if (signal?.aborted) abortRequest();
4724
+ else signal?.addEventListener("abort", abortRequest, { once: true });
4725
+ fetchImpl(input, {
4726
+ ...requestInit,
4727
+ signal: controller.signal
4728
+ }).then((response) => selector(response)).then((value) => {
4729
+ if (subscriber.closed) return;
4730
+ subscriber.next(value);
4731
+ subscriber.complete();
4732
+ }).catch((error) => {
4733
+ if (!subscriber.closed) subscriber.error(error);
4734
+ });
4735
+ return () => {
4736
+ signal?.removeEventListener("abort", abortRequest);
4737
+ abortRequest();
4738
+ };
4739
+ });
3876
4740
  }
3877
4741
  function createThreadFetchObservable(environment, context, sessionId) {
3878
4742
  return (0, rxjs.defer)(() => {
@@ -4018,6 +4882,9 @@ function createThreadStore(environment) {
4018
4882
  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
4883
  sessionId: action.sessionId,
4020
4884
  payload
4885
+ }))), 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({
4886
+ sessionId: action.sessionId,
4887
+ notification
4021
4888
  }))), ɵ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
4889
  });
4023
4890
  }))),
@@ -4195,6 +5062,9 @@ function createThreadStore(environment) {
4195
5062
  threadId
4196
5063
  }));
4197
5064
  },
5065
+ subscribeToRunActivity(callback) {
5066
+ 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);
5067
+ },
4198
5068
  getState() {
4199
5069
  return store.getState();
4200
5070
  },
@@ -4274,6 +5144,8 @@ exports.CopilotKitCore = CopilotKitCore;
4274
5144
  exports.CopilotKitCoreErrorCode = CopilotKitCoreErrorCode;
4275
5145
  exports.CopilotKitCoreRuntimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus;
4276
5146
  exports.IntelligenceAgent = IntelligenceAgent;
5147
+ exports.MEMORY_ERROR_REGISTRY = MEMORY_ERROR_REGISTRY;
5148
+ exports.MemoryError = MemoryError;
4277
5149
  exports.ProxiedCopilotRuntimeAgent = ProxiedCopilotRuntimeAgent;
4278
5150
  exports.RunHandler = RunHandler;
4279
5151
  exports.StateManager = StateManager;
@@ -4295,10 +5167,17 @@ exports.props = props;
4295
5167
  exports.select = select;
4296
5168
  exports.ɵCOPILOTKIT_FEATURES = ɵCOPILOTKIT_FEATURES;
4297
5169
  exports.ɵMAX_SOCKET_RETRIES = ɵMAX_SOCKET_RETRIES;
5170
+ exports.ɵcreateMemoryStore = createMemoryStore;
4298
5171
  exports.ɵcreateThreadSelectors = ɵcreateThreadSelectors;
4299
5172
  exports.ɵcreateThreadStore = createThreadStore;
4300
5173
  exports.ɵisCopilotKitFeature = ɵisCopilotKitFeature;
5174
+ exports.ɵisRetryableMemoryStatus = isRetryableStatus;
4301
5175
  exports.ɵjoinPhoenixChannel$ = ɵjoinPhoenixChannel$;
5176
+ exports.ɵmapMemoryMetadataEvent = ɵmapMemoryMetadataEvent;
5177
+ exports.ɵmemoryAdapterEvents = ɵmemoryAdapterEvents;
5178
+ exports.ɵmemoryDomainEvents = ɵmemoryDomainEvents;
5179
+ exports.ɵmemoryReducer = ɵmemoryReducer;
5180
+ exports.ɵmemoryRestEvents = ɵmemoryRestEvents;
4302
5181
  exports.ɵobservePhoenixEvent$ = ɵobservePhoenixEvent$;
4303
5182
  exports.ɵobservePhoenixJoinOutcome$ = ɵobservePhoenixJoinOutcome$;
4304
5183
  exports.ɵobservePhoenixSocketHealth$ = ɵobservePhoenixSocketHealth$;
@@ -4308,6 +5187,12 @@ exports.ɵphoenixSocket$ = ɵphoenixSocket$;
4308
5187
  exports.ɵselectHasNextPage = ɵselectHasNextPage;
4309
5188
  exports.ɵselectIsFetchingNextPage = ɵselectIsFetchingNextPage;
4310
5189
  exports.ɵselectIsMutating = ɵselectIsMutating;
5190
+ exports.ɵselectMemories = ɵselectMemories;
5191
+ exports.ɵselectMemoriesAvailable = ɵselectMemoriesAvailable;
5192
+ exports.ɵselectMemoriesError = ɵselectMemoriesError;
5193
+ exports.ɵselectMemoriesIsLoading = ɵselectMemoriesIsLoading;
5194
+ exports.ɵselectMemoriesIsMutating = ɵselectMemoriesIsMutating;
5195
+ exports.ɵselectMemoriesRealtimeStatus = ɵselectMemoriesRealtimeStatus;
4311
5196
  exports.ɵselectThreads = ɵselectThreads;
4312
5197
  exports.ɵselectThreadsError = ɵselectThreadsError;
4313
5198
  exports.ɵselectThreadsIsLoading = ɵselectThreadsIsLoading;