@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.umd.js CHANGED
@@ -170,6 +170,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
170
170
  const REPLAY_COMPLETE_EVENT = "replay_complete";
171
171
  const STREAM_IDLE_EVENT = "stream_idle";
172
172
  const STOP_RUN_EVENT = "stop_run";
173
+ const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
173
174
  var AgentThreadLockedError = class extends Error {
174
175
  constructor(threadId) {
175
176
  super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
@@ -320,12 +321,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
320
321
  connect(input) {
321
322
  this.threadId = input.threadId;
322
323
  this.canonicalRunId = null;
323
- return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input)).pipe((0, rxjs.switchMap)((credentials) => {
324
+ const replayCursor = this.getReconnectCursor(input);
325
+ return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input, replayCursor)).pipe((0, rxjs.switchMap)((credentials) => {
324
326
  if (credentials === null) return rxjs.EMPTY;
325
327
  const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: false });
326
328
  return this.observeThread$(canonicalInput, credentials, {
327
329
  completeOnRunError: false,
328
- streamMode: "connect"
330
+ streamMode: "connect",
331
+ replayCursor
329
332
  });
330
333
  }));
331
334
  }
@@ -348,7 +351,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
348
351
  cleanup() {
349
352
  this.cleanupOwned(this.activeChannel, this.socket);
350
353
  }
351
- requestJoinCredentials$(mode, input) {
354
+ requestJoinCredentials$(mode, input, replayCursor) {
352
355
  return (0, rxjs.defer)(async () => {
353
356
  try {
354
357
  const response = await fetch(this.buildRuntimeUrl(mode), {
@@ -365,7 +368,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
365
368
  context: input.context,
366
369
  state: input.state,
367
370
  forwardedProps: input.forwardedProps,
368
- ...mode === "connect" ? { lastSeenEventId: this.getReconnectCursor(input) } : {}
371
+ ...mode === "connect" ? { lastSeenEventId: replayCursor === void 0 ? this.getReconnectCursor(input) : replayCursor } : {}
369
372
  }),
370
373
  ...this.config.credentials ? { credentials: this.config.credentials } : {}
371
374
  });
@@ -401,16 +404,17 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
401
404
  observeThread$(input, credentials, options) {
402
405
  return this.observeThreadSession$(input, credentials, options).pipe((0, rxjs_operators.catchError)((error) => {
403
406
  if (!this.isSocketReconnectExhaustedError(error)) return (0, rxjs.throwError)(() => error);
404
- 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, {
407
+ const replayCursor = this.getReconnectCursor(input);
408
+ 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, {
405
409
  ...options,
406
410
  channelMode: "connect",
407
- replayCursor: this.getReconnectCursor(input)
411
+ replayCursor
408
412
  })));
409
413
  }));
410
414
  }
411
415
  observeThreadSession$(input, credentials, options) {
412
416
  return (0, rxjs.defer)(() => {
413
- var _options$channelMode;
417
+ var _options$channelMode, _options$replayCursor;
414
418
  let ownSocket = null;
415
419
  let ownChannel = null;
416
420
  const socket$ = ɵphoenixSocket$({
@@ -442,15 +446,24 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
442
446
  bufferSize: 1,
443
447
  refCount: true
444
448
  }));
445
- const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.share)());
446
- const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.share)());
449
+ const reconnectCursor = this.readDurableEventId((_options$replayCursor = options.replayCursor) !== null && _options$replayCursor !== void 0 ? _options$replayCursor : this.getReconnectCursor(input));
450
+ let latestObservedReplayCursor = null;
451
+ const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.tap)((payload) => {
452
+ var _this$readEventId;
453
+ latestObservedReplayCursor = (_this$readEventId = this.readEventId(payload)) !== null && _this$readEventId !== void 0 ? _this$readEventId : latestObservedReplayCursor;
454
+ }), (0, rxjs_operators.share)());
455
+ const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.shareReplay)({
456
+ bufferSize: 1,
457
+ refCount: true
458
+ }));
447
459
  const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT).pipe((0, rxjs_operators.shareReplay)({
448
460
  bufferSize: 1,
449
461
  refCount: true
450
462
  }));
451
- const streamIdleCompletion$ = options.streamMode === "connect" ? streamIdle$.pipe((0, rxjs_operators.take)(1)) : rxjs.EMPTY;
452
- const terminal$ = (0, rxjs.merge)(threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1)), streamIdleCompletion$);
453
- 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)));
463
+ 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;
464
+ const threadCompleted$ = threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1));
465
+ const terminal$ = (0, rxjs.merge)(threadCompleted$, streamIdleCompletion$);
466
+ 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)));
454
467
  });
455
468
  }
456
469
  joinThreadChannel$(channel$) {
@@ -518,23 +531,37 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
518
531
  updateLastSeenEventId(threadId, payload) {
519
532
  const eventId = this.readEventId(payload);
520
533
  if (!eventId) return;
521
- this.sharedState.lastSeenEventIds.set(threadId, eventId);
534
+ this.advanceLastSeenEventId(threadId, eventId);
522
535
  }
523
536
  updateLastSeenEventIdFromControl(threadId, payload) {
524
537
  const eventId = this.readControlEventId(payload);
525
538
  if (!eventId) return;
539
+ this.advanceLastSeenEventId(threadId, eventId);
540
+ }
541
+ advanceLastSeenEventId(threadId, eventId) {
526
542
  this.sharedState.lastSeenEventIds.set(threadId, eventId);
527
543
  }
528
544
  readEventId(payload) {
529
545
  const metadata = payload.metadata;
530
546
  if (!metadata || typeof metadata !== "object") return null;
531
- const runnerEventId = metadata.cpki_event_id;
532
- return typeof runnerEventId === "string" ? runnerEventId : null;
547
+ const eventMetadata = metadata;
548
+ return this.readDurableEventId(eventMetadata.cpki_event_id);
533
549
  }
534
550
  readControlEventId(payload) {
551
+ var _controlPayload$lates;
535
552
  if (!payload || typeof payload !== "object") return null;
536
- const latestEventId = payload.latestEventId;
537
- return typeof latestEventId === "string" ? latestEventId : null;
553
+ const controlPayload = payload;
554
+ const latestEventId = (_controlPayload$lates = controlPayload.latestEventId) !== null && _controlPayload$lates !== void 0 ? _controlPayload$lates : controlPayload.latest_event_id;
555
+ return this.readDurableEventId(latestEventId);
556
+ }
557
+ readDurableEventId(eventId) {
558
+ if (typeof eventId !== "string" || eventId.trim() === "") return null;
559
+ return eventId.startsWith("cpki_ingested") ? null : eventId;
560
+ }
561
+ canFallbackCompleteConnect(streamIdlePayload, reconnectCursor, latestObservedReplayCursor) {
562
+ const idleCursor = this.readControlEventId(streamIdlePayload);
563
+ if (!idleCursor) return true;
564
+ return idleCursor === reconnectCursor || idleCursor === latestObservedReplayCursor;
538
565
  }
539
566
  applyCanonicalRunIdentity(input, credentials, options) {
540
567
  var _credentials$runId;
@@ -1769,7 +1796,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1769
1796
  _defineProperty(this, "_tools", []);
1770
1797
  _defineProperty(this, "_runAbortController", null);
1771
1798
  _defineProperty(this, "_runDepth", 0);
1772
- _defineProperty(this, "_lastConnectedThreadId", null);
1799
+ _defineProperty(this, "_lastConnectedThreadIdsByAgent", /* @__PURE__ */ new Map());
1800
+ _defineProperty(this, "_anonymousAgentIds", /* @__PURE__ */ new WeakMap());
1801
+ _defineProperty(this, "_nextAnonymousAgentId", 0);
1773
1802
  }
1774
1803
  /**
1775
1804
  * Abort the current run. Called by `CopilotKitCore.stopAgent()` to signal
@@ -1788,6 +1817,20 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1788
1817
  return this.core;
1789
1818
  }
1790
1819
  /**
1820
+ * Return a stable restore-tracking key for the logical agent being
1821
+ * connected. Named agents share their last-thread marker across proxy
1822
+ * instances; anonymous agents fall back to object identity.
1823
+ */
1824
+ getConnectRestoreKey(agent) {
1825
+ if (agent.agentId) return `agent:${agent.agentId}`;
1826
+ const existing = this._anonymousAgentIds.get(agent);
1827
+ if (existing) return existing;
1828
+ const anonymousId = `anonymous:${this._nextAnonymousAgentId}`;
1829
+ this._nextAnonymousAgentId += 1;
1830
+ this._anonymousAgentIds.set(agent, anonymousId);
1831
+ return anonymousId;
1832
+ }
1833
+ /**
1791
1834
  * Get all tools as a readonly array
1792
1835
  */
1793
1836
  get tools() {
@@ -1842,16 +1885,20 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1842
1885
  */
1843
1886
  async connectAgent({ agent }) {
1844
1887
  try {
1845
- var _agent$threadId;
1888
+ var _agent$threadId, _this$_lastConnectedT;
1846
1889
  const incomingThreadId = (_agent$threadId = agent.threadId) !== null && _agent$threadId !== void 0 ? _agent$threadId : null;
1847
- const isFreshRestore = incomingThreadId !== this._lastConnectedThreadId;
1848
- this._lastConnectedThreadId = incomingThreadId;
1890
+ const restoreKey = this.getConnectRestoreKey(agent);
1891
+ const isFreshRestore = incomingThreadId !== ((_this$_lastConnectedT = this._lastConnectedThreadIdsByAgent.get(restoreKey)) !== null && _this$_lastConnectedT !== void 0 ? _this$_lastConnectedT : null);
1892
+ this._lastConnectedThreadIdsByAgent.set(restoreKey, incomingThreadId);
1849
1893
  await agent.detachActiveRun();
1850
1894
  if (isFreshRestore) {
1851
1895
  agent.setMessages([]);
1852
1896
  agent.setState({});
1853
- const proxied = agent;
1854
- if (incomingThreadId && typeof proxied.clearReplayCursor === "function") proxied.clearReplayCursor(incomingThreadId);
1897
+ const cursorAware = agent;
1898
+ if (incomingThreadId) {
1899
+ if (typeof cursorAware.clearReplayCursor === "function") cursorAware.clearReplayCursor(incomingThreadId);
1900
+ if (typeof cursorAware.clearReconnectCursor === "function") cursorAware.clearReconnectCursor(incomingThreadId);
1901
+ }
1855
1902
  }
1856
1903
  this._internal.applyHeadersToAgent(agent);
1857
1904
  await this._internal.notifySubscribers((subscriber) => {
@@ -1868,7 +1915,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1868
1915
  }, this.createAgentErrorSubscriber(agent));
1869
1916
  return this.processAgentResult({
1870
1917
  runAgentResult,
1871
- agent
1918
+ agent,
1919
+ executeFrontendTools: false
1872
1920
  });
1873
1921
  } catch (error) {
1874
1922
  const connectError = error instanceof Error ? error : new Error(String(error));
@@ -1890,7 +1938,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1890
1938
  /**
1891
1939
  * Run an agent
1892
1940
  */
1893
- async runAgent({ agent, forwardedProps, resume }) {
1941
+ async runAgent({ agent, forwardedProps, resume, runId }) {
1894
1942
  if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
1895
1943
  this._internal.applyHeadersToAgent(agent);
1896
1944
  if (agent.detachActiveRun) await agent.detachActiveRun();
@@ -1920,6 +1968,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1920
1968
  ...forwardedProps
1921
1969
  },
1922
1970
  ...resume !== void 0 ? { resume } : {},
1971
+ ...runId !== void 0 ? { runId } : {},
1923
1972
  tools: this.buildFrontendTools(agent.agentId),
1924
1973
  context: this._internal.getContextForAgent(agent.agentId)
1925
1974
  }, this.createAgentErrorSubscriber(agent));
@@ -1948,26 +1997,28 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1948
1997
  /**
1949
1998
  * Process agent result and execute tools
1950
1999
  */
1951
- async processAgentResult({ runAgentResult, agent }) {
2000
+ async processAgentResult({ runAgentResult, agent, executeFrontendTools = true }) {
1952
2001
  var _this$_runAbortContro2;
1953
2002
  const { newMessages } = runAgentResult;
1954
2003
  const agentId = agent.agentId;
1955
2004
  let needsFollowUp = false;
1956
- for (const message of newMessages) if (message.role === "assistant") {
1957
- for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
1958
- const tool = this.getTool({
1959
- toolName: toolCall.function.name,
1960
- agentId: agent.agentId
1961
- });
1962
- if (tool) {
1963
- if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
1964
- } else {
1965
- const wildcardTool = this.getTool({
1966
- toolName: "*",
2005
+ if (executeFrontendTools) {
2006
+ for (const message of newMessages) if (message.role === "assistant") {
2007
+ for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
2008
+ const tool = this.getTool({
2009
+ toolName: toolCall.function.name,
1967
2010
  agentId: agent.agentId
1968
2011
  });
1969
- if (wildcardTool) {
1970
- if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
2012
+ if (tool) {
2013
+ if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
2014
+ } else {
2015
+ const wildcardTool = this.getTool({
2016
+ toolName: "*",
2017
+ agentId: agent.agentId
2018
+ });
2019
+ if (wildcardTool) {
2020
+ if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
2021
+ }
1971
2022
  }
1972
2023
  }
1973
2024
  }
@@ -2665,155 +2716,1133 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2665
2716
  };
2666
2717
 
2667
2718
  //#endregion
2668
- //#region src/core/core.ts
2669
- let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode) {
2670
- CopilotKitCoreErrorCode["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
2671
- CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
2672
- CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
2673
- CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
2674
- CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
2675
- CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
2676
- CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
2677
- CopilotKitCoreErrorCode["TOOL_NOT_FOUND"] = "tool_not_found";
2678
- CopilotKitCoreErrorCode["AGENT_NOT_FOUND"] = "agent_not_found";
2679
- /**
2680
- * Emitted when an agent run fails because the thread is already locked
2681
- * by another active run.
2682
- *
2683
- * @example
2684
- * ```tsx
2685
- * <CopilotKitProvider
2686
- * onError={({ code, error, context }) => {
2687
- * if (code === "agent_thread_locked") {
2688
- * // Show "Agent is busy, retry?" UI
2689
- * }
2690
- * }}
2691
- * />
2692
- * ```
2693
- */
2694
- CopilotKitCoreErrorCode["AGENT_THREAD_LOCKED"] = "agent_thread_locked";
2695
- CopilotKitCoreErrorCode["TRANSCRIPTION_FAILED"] = "transcription_failed";
2696
- CopilotKitCoreErrorCode["TRANSCRIPTION_SERVICE_NOT_CONFIGURED"] = "transcription_service_not_configured";
2697
- CopilotKitCoreErrorCode["TRANSCRIPTION_INVALID_AUDIO"] = "transcription_invalid_audio";
2698
- CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
2699
- CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
2700
- CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
2701
- CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
2702
- return CopilotKitCoreErrorCode;
2703
- }({});
2719
+ //#region src/utils/micro-redux.ts
2720
+ const INTERNAL_ACTION_TYPES = {
2721
+ boot: "@@micro-redux/boot",
2722
+ init: "@@micro-redux/init",
2723
+ stop: "@@micro-redux/stop"
2724
+ };
2725
+ const INTERNAL_BOOT_ACTION = { type: INTERNAL_ACTION_TYPES.boot };
2704
2726
  /**
2705
- * Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
2706
- * to module scope so the Set is allocated once, not per-subscription.
2727
+ * Builds a typed action creator from a type string and payload factory.
2707
2728
  */
2708
- const ALLOWED_KEYS = new Set([
2709
- "onMessagesChanged",
2710
- "onStateChanged",
2711
- "onRunInitialized",
2712
- "onRunFinalized",
2713
- "onRunFailed",
2714
- "onRunErrorEvent"
2715
- ]);
2716
- let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
2717
- CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
2718
- CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
2719
- CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
2720
- CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
2721
- return CopilotKitCoreRuntimeConnectionStatus;
2722
- }({});
2729
+ function createTypedActionCreator(type, factory) {
2730
+ const creator = ((...args) => ({
2731
+ ...factory(...args),
2732
+ type
2733
+ }));
2734
+ creator.type = type;
2735
+ creator.match = (action) => action.type === type;
2736
+ return creator;
2737
+ }
2723
2738
  /**
2724
- * Normalize a header map to the internal invariant: a `Record<string, string>`
2725
- * with no `null`/`undefined` values. Entries whose value is `null`/`undefined`
2726
- * are dropped (this is how a header is cleared). Shared by the constructor and
2727
- * `setHeaders` so both write paths into `_headers` enforce the same invariant.
2739
+ * Declares a payload-based action config for `createActionGroup`.
2740
+ *
2741
+ * @example
2742
+ * ```ts
2743
+ * const actions = createActionGroup("User", {
2744
+ * loaded: props<{ id: string }>(),
2745
+ * });
2746
+ * ```
2728
2747
  */
2729
- function normalizeHeaders(headers) {
2730
- return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
2748
+ function props() {
2749
+ return { kind: "props" };
2731
2750
  }
2732
- var CopilotKitCore = class {
2733
- constructor({ runtimeUrl, runtimeTransport = "auto", headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
2734
- _defineProperty(this, "_headers", void 0);
2735
- _defineProperty(this, "_credentials", void 0);
2736
- _defineProperty(this, "_properties", void 0);
2737
- _defineProperty(this, "_defaultThrottleMs", void 0);
2738
- _defineProperty(this, "_debug", void 0);
2739
- _defineProperty(this, "subscribers", /* @__PURE__ */ new Set());
2740
- _defineProperty(this, "agentRegistry", void 0);
2741
- _defineProperty(this, "contextStore", void 0);
2742
- _defineProperty(this, "suggestionEngine", void 0);
2743
- _defineProperty(this, "runHandler", void 0);
2744
- _defineProperty(this, "stateManager", void 0);
2745
- _defineProperty(this, "threadStoreRegistry", void 0);
2746
- _defineProperty(this, "previousAgentIds", /* @__PURE__ */ new Set());
2747
- this._headers = normalizeHeaders(headers);
2748
- this._credentials = credentials;
2749
- this._properties = properties;
2750
- this._debug = debug;
2751
- this.agentRegistry = new AgentRegistry(this);
2752
- this.contextStore = new ContextStore(this);
2753
- this.suggestionEngine = new SuggestionEngine(this);
2754
- this.runHandler = new RunHandler(this);
2755
- this.stateManager = new StateManager(this);
2756
- this.threadStoreRegistry = new ThreadStoreRegistry(this);
2757
- this.agentRegistry.initialize(agents__unsafe_dev_only);
2758
- this.runHandler.initialize(tools);
2759
- this.suggestionEngine.initialize(suggestionsConfig);
2760
- this.stateManager.initialize();
2761
- this.agentRegistry.setRuntimeTransport(runtimeTransport);
2762
- this.agentRegistry.setRuntimeUrl(runtimeUrl);
2763
- this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
2764
- this.subscribe({ onAgentsChanged: ({ agents }) => {
2765
- Object.values(agents).forEach((agent) => {
2766
- if (agent.agentId) this.stateManager.subscribeToAgent(agent);
2767
- });
2768
- const currentAgentIds = new Set(Object.keys(agents));
2769
- for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) try {
2770
- this.threadStoreRegistry.unregister(agentId);
2771
- } catch (err) {
2772
- console.error(`CopilotKitCore.onAgentsChanged: threadStoreRegistry.unregister failed for "${agentId}":`, err);
2773
- }
2774
- for (const agentId of this.previousAgentIds) if (!currentAgentIds.has(agentId)) try {
2775
- this.stateManager.unsubscribeFromAgent(agentId);
2776
- } catch (err) {
2777
- console.error(`CopilotKitCore.onAgentsChanged: stateManager.unsubscribeFromAgent failed for "${agentId}":`, err);
2778
- }
2779
- this.previousAgentIds = currentAgentIds;
2780
- } });
2751
+ /**
2752
+ * Declares a no-payload action config for `createActionGroup`.
2753
+ *
2754
+ * @example
2755
+ * ```ts
2756
+ * const actions = createActionGroup("User", {
2757
+ * reset: empty(),
2758
+ * });
2759
+ * ```
2760
+ */
2761
+ function empty() {
2762
+ return { kind: "empty" };
2763
+ }
2764
+ /**
2765
+ * Creates a namespaced group of typed action creators.
2766
+ *
2767
+ * Action types are formatted as: `[Source] actionName`.
2768
+ */
2769
+ function createActionGroup(source, config) {
2770
+ const group = {};
2771
+ for (const eventName of Object.keys(config)) {
2772
+ const eventConfig = config[eventName];
2773
+ if (!eventConfig) continue;
2774
+ const actionType = `[${source}] ${eventName}`;
2775
+ if (eventConfig.kind === "props") {
2776
+ group[eventName] = createTypedActionCreator(actionType, (payload) => ({ ...payload }));
2777
+ continue;
2778
+ }
2779
+ group[eventName] = createTypedActionCreator(actionType, () => ({}));
2781
2780
  }
2782
- /**
2783
- * Internal method used by delegate classes and subclasses to notify subscribers
2784
- */
2785
- async notifySubscribers(handler, errorMessage) {
2786
- await Promise.all(Array.from(this.subscribers).map(async (subscriber) => {
2787
- try {
2788
- await handler(subscriber);
2789
- } catch (error) {
2790
- console.error(errorMessage, error);
2791
- }
2792
- }));
2781
+ return group;
2782
+ }
2783
+ /**
2784
+ * Registers one reducer handler for one or more action creators.
2785
+ *
2786
+ * @throws Error when called without at least one action creator and reducer.
2787
+ */
2788
+ function on(...args) {
2789
+ if (args.length < 2) throw new Error("on requires at least one action creator and one reducer");
2790
+ const reducer = args[args.length - 1];
2791
+ return {
2792
+ creators: args.slice(0, -1),
2793
+ reducer
2794
+ };
2795
+ }
2796
+ /**
2797
+ * Creates a reducer from an initial state and `on(...)` handler entries.
2798
+ *
2799
+ * Unknown action types return the current state unchanged.
2800
+ */
2801
+ function createReducer(initialState, ...entries) {
2802
+ const reducerMap = /* @__PURE__ */ new Map();
2803
+ for (const entry of entries) for (const creator of entry.creators) {
2804
+ var _reducerMap$get;
2805
+ const handlers = (_reducerMap$get = reducerMap.get(creator.type)) !== null && _reducerMap$get !== void 0 ? _reducerMap$get : [];
2806
+ handlers.push(entry.reducer);
2807
+ reducerMap.set(creator.type, handlers);
2793
2808
  }
2794
- /**
2795
- * Internal method used by delegate classes to emit errors
2796
- */
2797
- async emitError({ error, code, context = {} }) {
2798
- await this.notifySubscribers((subscriber) => {
2799
- var _subscriber$onError;
2800
- return (_subscriber$onError = subscriber.onError) === null || _subscriber$onError === void 0 ? void 0 : _subscriber$onError.call(subscriber, {
2801
- copilotkit: this,
2802
- error,
2803
- code,
2804
- context
2805
- });
2806
- }, "Subscriber onError error:");
2809
+ return (state, action) => {
2810
+ const currentState = state !== null && state !== void 0 ? state : initialState;
2811
+ const handlers = reducerMap.get(action.type);
2812
+ if (!handlers || handlers.length === 0) return currentState;
2813
+ let nextState = currentState;
2814
+ for (const handler of handlers) nextState = handler(nextState, action);
2815
+ return nextState;
2816
+ };
2817
+ }
2818
+ /**
2819
+ * Creates a selector that caches and reuses the last computed result
2820
+ * when all input references are unchanged.
2821
+ */
2822
+ function createSelector(...args) {
2823
+ if (args.length === 1) {
2824
+ const projector = args[0];
2825
+ let hasCached = false;
2826
+ let lastState;
2827
+ let lastResult;
2828
+ return (state) => {
2829
+ if (hasCached && state === lastState) return lastResult;
2830
+ lastState = state;
2831
+ lastResult = projector(state);
2832
+ hasCached = true;
2833
+ return lastResult;
2834
+ };
2807
2835
  }
2808
- /**
2809
- * Log a message to the console and emit an error to subscribers.
2810
- * Catches failures from `emitError` itself to prevent unhandled rejections.
2811
- */
2812
- logAndEmitError(message, params, logLevel = "error") {
2813
- console[logLevel](message, params.error);
2814
- this.emitError(params).catch((emitErr) => {
2815
- console.error(message + " — emitError itself failed:", emitErr);
2816
- });
2836
+ const projector = args[args.length - 1];
2837
+ const selectors = args.slice(0, -1);
2838
+ let hasCached = false;
2839
+ let lastInputs = [];
2840
+ let lastResult;
2841
+ return (state) => {
2842
+ const inputs = selectors.map((selector) => selector(state));
2843
+ if (hasCached && inputs.length === lastInputs.length && inputs.every((value, index) => value === lastInputs[index])) return lastResult;
2844
+ lastInputs = inputs;
2845
+ lastResult = projector(...inputs);
2846
+ hasCached = true;
2847
+ return lastResult;
2848
+ };
2849
+ }
2850
+ /**
2851
+ * RxJS operator that maps state emissions through a selector and suppresses
2852
+ * unchanged projected values via reference equality.
2853
+ */
2854
+ function select(selector) {
2855
+ return (source$) => source$.pipe((0, rxjs_operators.map)(selector), (0, rxjs_operators.distinctUntilChanged)());
2856
+ }
2857
+ /**
2858
+ * RxJS operator that filters an action stream by action creators and narrows
2859
+ * the output action type to the matched creator union.
2860
+ *
2861
+ * @throws Error when called without at least one action creator.
2862
+ */
2863
+ function ofType(...creators) {
2864
+ if (creators.length === 0) throw new Error("ofType requires at least one action creator");
2865
+ const actionTypes = new Set(creators.map((creator) => creator.type));
2866
+ return (source$) => {
2867
+ return source$.pipe((0, rxjs_operators.filter)((action) => {
2868
+ return actionTypes.has(action.type);
2869
+ }));
2870
+ };
2871
+ }
2872
+ /**
2873
+ * Creates an effect descriptor consumed by `createStore`.
2874
+ */
2875
+ function createEffect(factory, options = {}) {
2876
+ if (options.dispatch === false) return {
2877
+ run: factory,
2878
+ dispatch: false
2879
+ };
2880
+ return {
2881
+ run: factory,
2882
+ dispatch: true
2883
+ };
2884
+ }
2885
+ /**
2886
+ * Creates a small observable store with reducer + effects.
2887
+ *
2888
+ * Behavior:
2889
+ * - `init()` starts effects and dispatches `@@micro-redux/init`.
2890
+ * - `stop()` dispatches `@@micro-redux/stop` and unsubscribes all effects.
2891
+ * - Effect action observation is scheduled on `asapScheduler` to avoid
2892
+ * synchronous re-entrancy in the effect loop.
2893
+ * - Any effect error triggers fail-fast teardown and errors both `actions$`
2894
+ * and `state$`.
2895
+ */
2896
+ function createStore(options) {
2897
+ var _options$effects;
2898
+ const reducer = options.reducer;
2899
+ const effects = (_options$effects = options.effects) !== null && _options$effects !== void 0 ? _options$effects : [];
2900
+ let hasFatalError = false;
2901
+ let isRunning = false;
2902
+ let effectSubscriptions = new rxjs.Subscription();
2903
+ let currentState = reducer(void 0, INTERNAL_BOOT_ACTION);
2904
+ const stateSubject = new rxjs.BehaviorSubject(currentState);
2905
+ const actionsSubject = new rxjs.Subject();
2906
+ const dispatchInternal = (action) => {
2907
+ if (hasFatalError) throw new Error("Store is in a failed state due to an effect error");
2908
+ currentState = reducer(currentState, action);
2909
+ stateSubject.next(currentState);
2910
+ actionsSubject.next(action);
2911
+ };
2912
+ const failFast = (error) => {
2913
+ if (hasFatalError) return;
2914
+ hasFatalError = true;
2915
+ isRunning = false;
2916
+ effectSubscriptions.unsubscribe();
2917
+ effectSubscriptions = new rxjs.Subscription();
2918
+ actionsSubject.error(error);
2919
+ stateSubject.error(error);
2920
+ };
2921
+ const startEffects = () => {
2922
+ for (const effect of effects) {
2923
+ const scheduledActions$ = actionsSubject.asObservable().pipe((0, rxjs_operators.observeOn)(rxjs.asapScheduler));
2924
+ const state$ = stateSubject.asObservable();
2925
+ if (effect.dispatch) {
2926
+ const subscription = effect.run(scheduledActions$, state$).subscribe({
2927
+ next: (effectAction) => {
2928
+ if (hasFatalError) return;
2929
+ dispatchInternal(effectAction);
2930
+ },
2931
+ error: (error) => {
2932
+ failFast(error);
2933
+ }
2934
+ });
2935
+ effectSubscriptions.add(subscription);
2936
+ continue;
2937
+ }
2938
+ const subscription = effect.run(scheduledActions$, state$).subscribe({ error: (error) => {
2939
+ failFast(error);
2940
+ } });
2941
+ effectSubscriptions.add(subscription);
2942
+ }
2943
+ };
2944
+ return {
2945
+ dispatch(action) {
2946
+ dispatchInternal(action);
2947
+ },
2948
+ getState() {
2949
+ return currentState;
2950
+ },
2951
+ get state$() {
2952
+ return stateSubject.asObservable();
2953
+ },
2954
+ get actions$() {
2955
+ return actionsSubject.asObservable();
2956
+ },
2957
+ select(selector) {
2958
+ return stateSubject.asObservable().pipe(select(selector));
2959
+ },
2960
+ init() {
2961
+ if (hasFatalError || isRunning) return;
2962
+ isRunning = true;
2963
+ startEffects();
2964
+ if (hasFatalError) return;
2965
+ dispatchInternal({ type: INTERNAL_ACTION_TYPES.init });
2966
+ },
2967
+ stop() {
2968
+ if (hasFatalError || !isRunning) return;
2969
+ dispatchInternal({ type: INTERNAL_ACTION_TYPES.stop });
2970
+ effectSubscriptions.unsubscribe();
2971
+ effectSubscriptions = new rxjs.Subscription();
2972
+ isRunning = false;
2973
+ }
2974
+ };
2975
+ }
2976
+
2977
+ //#endregion
2978
+ //#region src/memory-errors.ts
2979
+ /**
2980
+ * The memory error registry: the single source of truth for memory error
2981
+ * metadata. Keyed by `code` so a code maps to exactly one category/retryable
2982
+ * default.
2983
+ *
2984
+ * Categories/retryable rationale:
2985
+ * - List/credentials/mutation failures are `dependency` (the runtime/platform
2986
+ * the store calls failed). A 5xx is transient (`retryable: true`); a 4xx is
2987
+ * caller-caused, so the helpers below downgrade those to non-retryable.
2988
+ * - Timeouts are `dependency` and `retryable: true` (the request may simply be
2989
+ * slow).
2990
+ */
2991
+ const MEMORY_ERROR_REGISTRY = Object.freeze({
2992
+ MEMORY_LIST_FAILED: {
2993
+ code: "MEMORY_LIST_FAILED",
2994
+ category: "dependency",
2995
+ retryable: true,
2996
+ message: "Failed to fetch memories",
2997
+ docsPath: "docs/errors/memory.md#memory_list_failed"
2998
+ },
2999
+ MEMORY_CREDENTIALS_FAILED: {
3000
+ code: "MEMORY_CREDENTIALS_FAILED",
3001
+ category: "dependency",
3002
+ retryable: true,
3003
+ message: "Failed to fetch memory subscribe credentials",
3004
+ docsPath: "docs/errors/memory.md#memory_credentials_failed"
3005
+ },
3006
+ MEMORY_MUTATION_FAILED: {
3007
+ code: "MEMORY_MUTATION_FAILED",
3008
+ category: "dependency",
3009
+ retryable: true,
3010
+ message: "Memory mutation request failed",
3011
+ docsPath: "docs/errors/memory.md#memory_mutation_failed"
3012
+ },
3013
+ MEMORY_REQUEST_TIMEOUT: {
3014
+ code: "MEMORY_REQUEST_TIMEOUT",
3015
+ category: "dependency",
3016
+ retryable: true,
3017
+ message: "Request timed out",
3018
+ docsPath: "docs/errors/memory.md#memory_request_timeout"
3019
+ }
3020
+ });
3021
+ /**
3022
+ * An `Error` carrying a stable memory error `code`, `category`, and `retryable`
3023
+ * flag so consumers and observability can branch on it without string-matching
3024
+ * the message.
3025
+ *
3026
+ * It is a real `Error` subclass: `instanceof Error` is true, so the public
3027
+ * `MemoryState.error: Error | null` contract (and the `error: Error | null`
3028
+ * surfaced by `useMemories` / `injectMemories`) holds unchanged. Existing
3029
+ * consumers that only read `.message` keep working; the richer fields are
3030
+ * additive.
3031
+ */
3032
+ var MemoryError = class MemoryError extends Error {
3033
+ /**
3034
+ * @param code - Registry code identifying this error.
3035
+ * @param options - Optional overrides:
3036
+ * - `message`: human-readable message (defaults to the registry message;
3037
+ * callers pass a status-bearing string to preserve prior wording).
3038
+ * - `retryable`: overrides the registry default (e.g. a 4xx list failure is
3039
+ * not retryable even though the code's default is).
3040
+ * - `cause`: the underlying error, preserved for debugging.
3041
+ */
3042
+ constructor(code, options) {
3043
+ var _options$message, _options$retryable;
3044
+ const entry = MEMORY_ERROR_REGISTRY[code];
3045
+ super((_options$message = options === null || options === void 0 ? void 0 : options.message) !== null && _options$message !== void 0 ? _options$message : entry.message, { cause: options === null || options === void 0 ? void 0 : options.cause });
3046
+ _defineProperty(this, "code", void 0);
3047
+ _defineProperty(this, "category", void 0);
3048
+ _defineProperty(this, "retryable", void 0);
3049
+ this.name = "MemoryError";
3050
+ this.code = code;
3051
+ this.category = entry.category;
3052
+ this.retryable = (_options$retryable = options === null || options === void 0 ? void 0 : options.retryable) !== null && _options$retryable !== void 0 ? _options$retryable : entry.retryable;
3053
+ Object.setPrototypeOf(this, MemoryError.prototype);
3054
+ }
3055
+ };
3056
+ /**
3057
+ * Narrows an HTTP status to whether the failure is worth retrying: a 5xx (or a
3058
+ * missing/0 status) is a transient dependency failure and retryable; a 4xx is
3059
+ * caller-caused and not. Used so a `MEMORY_LIST_FAILED`/`MEMORY_MUTATION_FAILED`
3060
+ * carries an accurate `retryable` flag derived from the response status.
3061
+ */
3062
+ function isRetryableStatus(status) {
3063
+ return !(Number.isInteger(status) && status >= 400 && status <= 499);
3064
+ }
3065
+
3066
+ //#endregion
3067
+ //#region src/memory.ts
3068
+ const MEMORIES_PATH = "/memories";
3069
+ const MEMORIES_SUBSCRIBE_PATH = "/memories/subscribe";
3070
+ const REQUEST_TIMEOUT_MS$1 = 15e3;
3071
+ /** Consecutive socket errors tolerated before the realtime stream gives up. */
3072
+ const MAX_SOCKET_RETRIES$1 = 5;
3073
+ /**
3074
+ * HTTP status codes that indicate memory routes are not configured (non-fatal).
3075
+ * 404/501 mean the route is absent/unimplemented; 422 is the runtime's
3076
+ * MISSING_INTELLIGENCE signal (intelligence not configured on the deployment —
3077
+ * see packages/runtime/.../handlers/intelligence/memories.ts). All three map to
3078
+ * the graceful "not available" locked-teaser path, not a hard error.
3079
+ */
3080
+ const ROUTE_UNAVAILABLE_STATUSES = new Set([
3081
+ 404,
3082
+ 422,
3083
+ 501
3084
+ ]);
3085
+ /**
3086
+ * Thrown when a memory route returns a 404/422/501 — treated as "not
3087
+ * configured" (422 is the runtime's MISSING_INTELLIGENCE signal).
3088
+ */
3089
+ var MemoryRouteUnavailableError = class extends Error {};
3090
+ const initialMemoryState = Object.freeze({
3091
+ memories: Object.freeze([]),
3092
+ isLoading: false,
3093
+ inFlightMutationCount: 0,
3094
+ error: null,
3095
+ context: null,
3096
+ sessionId: 0,
3097
+ available: true,
3098
+ realtimeStatus: "connecting"
3099
+ });
3100
+ const memoryAdapterEvents = createActionGroup("Memory Adapter", {
3101
+ started: empty(),
3102
+ stopped: empty(),
3103
+ contextChanged: props(),
3104
+ addRequested: props(),
3105
+ updateRequested: props(),
3106
+ removeRequested: props()
3107
+ });
3108
+ const memoryRestEvents = createActionGroup("Memory REST", {
3109
+ listRequested: props(),
3110
+ listSucceeded: props(),
3111
+ listFailed: props(),
3112
+ listUnavailable: props(),
3113
+ mutationFinished: props(),
3114
+ credentialsRequested: props(),
3115
+ credentialsSucceeded: props(),
3116
+ credentialsFailed: props(),
3117
+ credentialsUnavailable: props()
3118
+ });
3119
+ const memoryDomainEvents = createActionGroup("Memory Domain", {
3120
+ memoryUpserted: props(),
3121
+ memoryInvalidated: props(),
3122
+ realtimeConnecting: props(),
3123
+ realtimeConnected: props(),
3124
+ realtimeUnavailable: props()
3125
+ });
3126
+ /** Projects a wire memory to the public {@link Memory} shape (drops tenant ids). */
3127
+ function toMemory(memory) {
3128
+ return {
3129
+ id: memory.id,
3130
+ kind: memory.kind,
3131
+ scope: memory.scope,
3132
+ content: memory.content,
3133
+ sourceThreadIds: memory.sourceThreadIds,
3134
+ invalidatedAt: memory.invalidatedAt
3135
+ };
3136
+ }
3137
+ /**
3138
+ * Maps a realtime `memory_metadata` event to the domain action that applies it:
3139
+ * `created`/`updated` upsert the projected memory, `invalidated` removes it by
3140
+ * id. Carries the current `sessionId` so the reducer's session guard can drop
3141
+ * deltas left over from a previous context.
3142
+ */
3143
+ function mapMemoryMetadataEvent(event, sessionId) {
3144
+ if (event.operation === "invalidated") return memoryDomainEvents.memoryInvalidated({
3145
+ sessionId,
3146
+ memoryId: event.invalidated.id
3147
+ });
3148
+ return memoryDomainEvents.memoryUpserted({
3149
+ sessionId,
3150
+ memory: toMemory(event.memory)
3151
+ });
3152
+ }
3153
+ /**
3154
+ * Inserts or replaces a memory by id. A new memory is prepended (newest first,
3155
+ * matching the REST list's `created_at DESC` ordering without needing a date
3156
+ * field on the public projection); an existing memory is replaced in place.
3157
+ */
3158
+ function upsertMemory(memories, memory) {
3159
+ const existingIndex = memories.findIndex((item) => item.id === memory.id);
3160
+ if (existingIndex === -1) return [memory, ...memories];
3161
+ const next = [...memories];
3162
+ next[existingIndex] = memory;
3163
+ return next;
3164
+ }
3165
+ const memoryReducer = createReducer(initialMemoryState, on(memoryAdapterEvents.contextChanged, (state, { context }) => ({
3166
+ ...state,
3167
+ context,
3168
+ sessionId: state.sessionId + 1,
3169
+ memories: [],
3170
+ isLoading: Boolean(context),
3171
+ inFlightMutationCount: 0,
3172
+ error: null,
3173
+ available: true,
3174
+ realtimeStatus: "connecting"
3175
+ })), on(memoryAdapterEvents.stopped, (state) => ({
3176
+ ...state,
3177
+ memories: [],
3178
+ isLoading: false,
3179
+ inFlightMutationCount: 0,
3180
+ error: null,
3181
+ available: true,
3182
+ realtimeStatus: "connecting"
3183
+ })), on(memoryRestEvents.listRequested, (state, { sessionId }) => {
3184
+ if (sessionId !== state.sessionId || !state.context) return state;
3185
+ return {
3186
+ ...state,
3187
+ isLoading: true,
3188
+ error: null,
3189
+ available: true
3190
+ };
3191
+ }), on(memoryRestEvents.listFailed, (state, { sessionId, error }) => {
3192
+ if (sessionId !== state.sessionId) return state;
3193
+ return {
3194
+ ...state,
3195
+ isLoading: false,
3196
+ error
3197
+ };
3198
+ }), on(memoryRestEvents.listUnavailable, (state, { sessionId }) => {
3199
+ if (sessionId !== state.sessionId) return state;
3200
+ return {
3201
+ ...state,
3202
+ memories: [],
3203
+ isLoading: false,
3204
+ error: null,
3205
+ available: false
3206
+ };
3207
+ }), on(memoryAdapterEvents.addRequested, memoryAdapterEvents.updateRequested, memoryAdapterEvents.removeRequested, (state) => ({
3208
+ ...state,
3209
+ inFlightMutationCount: state.inFlightMutationCount + 1
3210
+ })), on(memoryRestEvents.mutationFinished, (state, { outcome }) => {
3211
+ if (outcome.sessionId !== state.sessionId) return state;
3212
+ return {
3213
+ ...state,
3214
+ inFlightMutationCount: Math.max(0, state.inFlightMutationCount - 1),
3215
+ error: outcome.ok ? null : outcome.error
3216
+ };
3217
+ }), on(memoryRestEvents.listSucceeded, (state, { sessionId, memories }) => {
3218
+ if (sessionId !== state.sessionId) return state;
3219
+ return {
3220
+ ...state,
3221
+ memories,
3222
+ isLoading: false,
3223
+ error: null,
3224
+ available: true
3225
+ };
3226
+ }), on(memoryDomainEvents.memoryUpserted, (state, { sessionId, memory }) => {
3227
+ if (sessionId !== state.sessionId) return state;
3228
+ return {
3229
+ ...state,
3230
+ memories: upsertMemory(state.memories, memory)
3231
+ };
3232
+ }), on(memoryDomainEvents.memoryInvalidated, (state, { sessionId, memoryId }) => {
3233
+ if (sessionId !== state.sessionId) return state;
3234
+ return {
3235
+ ...state,
3236
+ memories: state.memories.filter((memory) => memory.id !== memoryId)
3237
+ };
3238
+ }), on(memoryDomainEvents.realtimeConnecting, (state, { sessionId }) => {
3239
+ if (sessionId !== state.sessionId) return state;
3240
+ return {
3241
+ ...state,
3242
+ realtimeStatus: "connecting"
3243
+ };
3244
+ }), on(memoryDomainEvents.realtimeConnected, (state, { sessionId }) => {
3245
+ if (sessionId !== state.sessionId) return state;
3246
+ return {
3247
+ ...state,
3248
+ realtimeStatus: "connected"
3249
+ };
3250
+ }), on(memoryDomainEvents.realtimeUnavailable, (state, { sessionId }) => {
3251
+ if (sessionId !== state.sessionId) return state;
3252
+ return {
3253
+ ...state,
3254
+ realtimeStatus: "unavailable"
3255
+ };
3256
+ }));
3257
+ const selectMemories = createSelector((state) => state.memories);
3258
+ const selectMemoriesIsLoading = createSelector((state) => state.isLoading);
3259
+ const selectMemoriesError = createSelector((state) => state.error);
3260
+ /**
3261
+ * Reports whether at least one mutation is in flight. Derived from
3262
+ * `inFlightMutationCount` so concurrent mutations stay correct: the boolean
3263
+ * only clears once every in-flight mutation has settled.
3264
+ */
3265
+ const selectMemoriesIsMutating = createSelector((state) => state.inFlightMutationCount > 0);
3266
+ /**
3267
+ * Reports whether the memory routes are available. Becomes `false` after a
3268
+ * 404, 422 (the runtime's MISSING_INTELLIGENCE signal), or 501 response during
3269
+ * an auto-activation read; defaults to `true`.
3270
+ */
3271
+ const selectMemoriesAvailable = createSelector((state) => state.available);
3272
+ /**
3273
+ * Reports the realtime-connection health (see {@link MemoryRealtimeStatus}).
3274
+ * Distinct from `available`/`error`: it reflects ONLY the live socket/channel,
3275
+ * so the UI can suppress a "live" indicator once realtime permanently dies even
3276
+ * while the REST list route stays healthy. Defaults to `"connecting"`.
3277
+ */
3278
+ const selectMemoriesRealtimeStatus = createSelector((state) => state.realtimeStatus);
3279
+ const MEMORY_METADATA_EVENT = "memory_metadata";
3280
+ function memoryFromFetch(input, init) {
3281
+ return (0, rxjs_fetch.fromFetch)(input, init);
3282
+ }
3283
+ /**
3284
+ * Fetches the memory snapshot and maps it to a success/failure action. Keeps
3285
+ * only user-scoped memories (v1 surfaces user scope only; the realtime stream
3286
+ * is user-scoped too), so project-scoped rows visible to the caller are
3287
+ * dropped from the store.
3288
+ */
3289
+ function createMemoryFetchObservable(environment, context, sessionId) {
3290
+ return (0, rxjs.defer)(() => {
3291
+ const qs = context.includeInvalidated ? "?includeInvalidated=true" : "";
3292
+ return memoryFromFetch(`${context.runtimeUrl}${MEMORIES_PATH}${qs}`, {
3293
+ selector: (response) => {
3294
+ if (!response.ok) {
3295
+ if (ROUTE_UNAVAILABLE_STATUSES.has(response.status)) throw new MemoryRouteUnavailableError(String(response.status));
3296
+ throw new MemoryError("MEMORY_LIST_FAILED", {
3297
+ message: `Failed to fetch memories: ${response.status}`,
3298
+ retryable: isRetryableStatus(response.status)
3299
+ });
3300
+ }
3301
+ return response.json();
3302
+ },
3303
+ fetch: environment.fetch,
3304
+ method: "GET",
3305
+ headers: { ...context.headers }
3306
+ }).pipe((0, rxjs_operators.timeout)({
3307
+ first: REQUEST_TIMEOUT_MS$1,
3308
+ with: () => {
3309
+ throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
3310
+ }
3311
+ }), (0, rxjs_operators.map)((data) => memoryRestEvents.listSucceeded({
3312
+ sessionId,
3313
+ memories: data.memories.filter((memory) => memory.scope === "user")
3314
+ })), (0, rxjs_operators.catchError)((error) => {
3315
+ if (error instanceof MemoryRouteUnavailableError) return (0, rxjs.of)(memoryRestEvents.listUnavailable({ sessionId }));
3316
+ return (0, rxjs.of)(memoryRestEvents.listFailed({
3317
+ sessionId,
3318
+ error: error instanceof Error ? error : new Error(String(error))
3319
+ }));
3320
+ }));
3321
+ });
3322
+ }
3323
+ /**
3324
+ * Fetches join credentials from the `/memories/subscribe` endpoint and maps
3325
+ * the response to a success/failure action. Requires both `joinToken` and
3326
+ * `joinCode` to be non-empty strings; throws otherwise so the `catchError`
3327
+ * path emits `credentialsFailed`.
3328
+ */
3329
+ function createMemoryCredentialsFetchObservable(environment, context, sessionId) {
3330
+ return (0, rxjs.defer)(() => memoryFromFetch(`${context.runtimeUrl}${MEMORIES_SUBSCRIBE_PATH}`, {
3331
+ selector: async (response) => {
3332
+ if (!response.ok) {
3333
+ if (ROUTE_UNAVAILABLE_STATUSES.has(response.status)) throw new MemoryRouteUnavailableError(String(response.status));
3334
+ throw new MemoryError("MEMORY_CREDENTIALS_FAILED", {
3335
+ message: `Failed to fetch memory subscribe credentials: ${response.status}`,
3336
+ retryable: isRetryableStatus(response.status)
3337
+ });
3338
+ }
3339
+ return response.json();
3340
+ },
3341
+ fetch: environment.fetch,
3342
+ method: "POST",
3343
+ headers: {
3344
+ ...context.headers,
3345
+ "Content-Type": "application/json"
3346
+ },
3347
+ body: JSON.stringify({})
3348
+ }).pipe((0, rxjs_operators.timeout)({
3349
+ first: REQUEST_TIMEOUT_MS$1,
3350
+ with: () => {
3351
+ throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
3352
+ }
3353
+ }), (0, rxjs_operators.map)((data) => {
3354
+ if (typeof data.joinToken !== "string" || data.joinToken.length === 0) throw new Error("missing joinToken");
3355
+ if (typeof data.joinCode !== "string" || data.joinCode.length === 0) throw new Error("missing joinCode");
3356
+ return memoryRestEvents.credentialsSucceeded({
3357
+ sessionId,
3358
+ joinToken: data.joinToken,
3359
+ joinCode: data.joinCode
3360
+ });
3361
+ }), (0, rxjs_operators.catchError)((error) => {
3362
+ if (error instanceof MemoryRouteUnavailableError) return (0, rxjs.of)(memoryRestEvents.credentialsUnavailable({ sessionId }));
3363
+ return (0, rxjs.of)(memoryRestEvents.credentialsFailed({
3364
+ sessionId,
3365
+ error: error instanceof Error ? error : new Error(String(error))
3366
+ }));
3367
+ })));
3368
+ }
3369
+ /** Projects a REST mutation response to the public {@link Memory} shape. */
3370
+ function responseToMemory(data) {
3371
+ return {
3372
+ id: data.id,
3373
+ kind: data.kind,
3374
+ scope: data.scope,
3375
+ content: data.content,
3376
+ sourceThreadIds: data.sourceThreadIds,
3377
+ invalidatedAt: data.invalidatedAt
3378
+ };
3379
+ }
3380
+ const MEMORY_KINDS = new Set([
3381
+ "topical",
3382
+ "episodic",
3383
+ "operational"
3384
+ ]);
3385
+ const MEMORY_SCOPES = new Set(["user", "project"]);
3386
+ /**
3387
+ * Validates the required fields of a create/supersede REST response before it is
3388
+ * projected to a {@link Memory}. Returns an `Error` describing the first
3389
+ * missing/invalid field, or `null` when the body is well-formed. Without this a
3390
+ * malformed 200 body yields a Memory with undefined fields that gets upserted.
3391
+ */
3392
+ function validateMutationResponse(data) {
3393
+ if (!data || typeof data !== "object") return /* @__PURE__ */ new Error("memory mutation response missing/invalid body");
3394
+ if (typeof data.id !== "string" || data.id.length === 0) return /* @__PURE__ */ new Error("memory mutation response missing/invalid id");
3395
+ if (typeof data.kind !== "string" || !MEMORY_KINDS.has(data.kind)) return /* @__PURE__ */ new Error("memory mutation response missing/invalid kind");
3396
+ if (typeof data.scope !== "string" || !MEMORY_SCOPES.has(data.scope)) return /* @__PURE__ */ new Error("memory mutation response missing/invalid scope");
3397
+ if (typeof data.content !== "string") return /* @__PURE__ */ new Error("memory mutation response missing/invalid content");
3398
+ if (!Array.isArray(data.sourceThreadIds) || !data.sourceThreadIds.every((id) => typeof id === "string")) return /* @__PURE__ */ new Error("memory mutation response missing/invalid sourceThreadIds");
3399
+ if (data.invalidatedAt !== null && typeof data.invalidatedAt !== "string") return /* @__PURE__ */ new Error("memory mutation response missing/invalid invalidatedAt");
3400
+ return null;
3401
+ }
3402
+ /**
3403
+ * Request body for create/supersede. `scope` is forwarded only when the caller
3404
+ * supplies it: the platform owns the default (`scope` defaults to `"user"` in
3405
+ * the `/api/memories` schema), so the store does not second-guess it here —
3406
+ * one default, at the contract owner. `sourceThreadIds` defaults to `[]`.
3407
+ */
3408
+ function toMutationBody(input) {
3409
+ var _input$sourceThreadId;
3410
+ return {
3411
+ content: input.content,
3412
+ kind: input.kind,
3413
+ ...input.scope !== void 0 ? { scope: input.scope } : {},
3414
+ sourceThreadIds: (_input$sourceThreadId = input.sourceThreadIds) !== null && _input$sourceThreadId !== void 0 ? _input$sourceThreadId : []
3415
+ };
3416
+ }
3417
+ /**
3418
+ * Builds the actions a successful mutation dispatches (server-authoritative):
3419
+ * the REST response is applied to local state immediately, and the realtime
3420
+ * event reconciles idempotently (upsert-by-id). `mutationFinished` resolves the
3421
+ * caller's promise.
3422
+ */
3423
+ function buildMutationSuccessActions(request, data) {
3424
+ const { requestId, sessionId } = request;
3425
+ if (request.kind === "remove") return [memoryDomainEvents.memoryInvalidated({
3426
+ sessionId,
3427
+ memoryId: request.id
3428
+ }), memoryRestEvents.mutationFinished({ outcome: {
3429
+ requestId,
3430
+ sessionId,
3431
+ ok: true,
3432
+ memory: null
3433
+ } })];
3434
+ const validationError = validateMutationResponse(data);
3435
+ if (validationError) return [memoryRestEvents.mutationFinished({ outcome: {
3436
+ requestId,
3437
+ sessionId,
3438
+ ok: false,
3439
+ error: validationError
3440
+ } })];
3441
+ const memory = responseToMemory(data);
3442
+ if (request.kind === "update") {
3443
+ const retiredId = data.retiredId;
3444
+ if (typeof retiredId !== "string" || retiredId.length === 0) return [memoryRestEvents.mutationFinished({ outcome: {
3445
+ requestId,
3446
+ sessionId,
3447
+ ok: false,
3448
+ error: /* @__PURE__ */ new Error("supersede response missing retiredId")
3449
+ } })];
3450
+ return [
3451
+ memoryDomainEvents.memoryInvalidated({
3452
+ sessionId,
3453
+ memoryId: retiredId
3454
+ }),
3455
+ memoryDomainEvents.memoryUpserted({
3456
+ sessionId,
3457
+ memory
3458
+ }),
3459
+ memoryRestEvents.mutationFinished({ outcome: {
3460
+ requestId,
3461
+ sessionId,
3462
+ ok: true,
3463
+ memory
3464
+ } })
3465
+ ];
3466
+ }
3467
+ return [memoryDomainEvents.memoryUpserted({
3468
+ sessionId,
3469
+ memory
3470
+ }), memoryRestEvents.mutationFinished({ outcome: {
3471
+ requestId,
3472
+ sessionId,
3473
+ ok: true,
3474
+ memory
3475
+ } })];
3476
+ }
3477
+ /** Performs a create/supersede/retire HTTP call and emits its resulting actions. */
3478
+ function createMemoryMutationObservable(environment, context, request) {
3479
+ const method = request.kind === "add" ? "POST" : request.kind === "update" ? "PATCH" : "DELETE";
3480
+ const path = request.kind === "add" ? MEMORIES_PATH : `${MEMORIES_PATH}/${encodeURIComponent(request.id)}`;
3481
+ return (0, rxjs.defer)(() => memoryFromFetch(`${context.runtimeUrl}${path}`, {
3482
+ selector: async (response) => {
3483
+ if (!response.ok) throw new MemoryError("MEMORY_MUTATION_FAILED", {
3484
+ message: `Request failed: ${response.status}`,
3485
+ retryable: isRetryableStatus(response.status)
3486
+ });
3487
+ return request.kind === "remove" ? null : await response.json();
3488
+ },
3489
+ fetch: environment.fetch,
3490
+ method,
3491
+ headers: {
3492
+ ...context.headers,
3493
+ "Content-Type": "application/json"
3494
+ },
3495
+ body: request.kind === "remove" ? void 0 : JSON.stringify(request.body)
3496
+ }).pipe((0, rxjs_operators.timeout)({
3497
+ first: REQUEST_TIMEOUT_MS$1,
3498
+ with: () => {
3499
+ throw new MemoryError("MEMORY_REQUEST_TIMEOUT");
3500
+ }
3501
+ }), (0, rxjs_operators.mergeMap)((data) => (0, rxjs.of)(...buildMutationSuccessActions(request, data))), (0, rxjs_operators.catchError)((error) => (0, rxjs.of)(memoryRestEvents.mutationFinished({ outcome: {
3502
+ requestId: request.requestId,
3503
+ sessionId: request.sessionId,
3504
+ ok: false,
3505
+ error: error instanceof Error ? error : new Error(String(error))
3506
+ } })))));
3507
+ }
3508
+ /**
3509
+ * Creates the framework-agnostic memory store: a REST snapshot on `setContext`,
3510
+ * server-authoritative add/update/remove mutations, and realtime
3511
+ * `memory_metadata` deltas off the injected `user_meta` event source — all
3512
+ * reduced into observable state.
3513
+ */
3514
+ function createMemoryStore(environment) {
3515
+ let memoryRequestId = 0;
3516
+ const createMemoryRequestId = () => {
3517
+ memoryRequestId += 1;
3518
+ return `memory-request-${memoryRequestId}`;
3519
+ };
3520
+ 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 }))));
3521
+ 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 }))));
3522
+ 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) => ({
3523
+ action,
3524
+ context
3525
+ })), (0, rxjs_operators.takeUntil)(actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped))), (0, rxjs_operators.switchMap)(({ action: currentAction, context }) => createMemoryCredentialsFetchObservable(environment, context, currentAction.sessionId))))));
3526
+ const store = createStore({
3527
+ reducer: memoryReducer,
3528
+ effects: [
3529
+ bootstrapEffect,
3530
+ credentialsBootstrapEffect,
3531
+ 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) => ({
3532
+ action,
3533
+ context
3534
+ })), (0, rxjs_operators.takeUntil)(actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped))), (0, rxjs_operators.switchMap)(({ action: currentAction, context }) => createMemoryFetchObservable(environment, context, currentAction.sessionId)))))),
3535
+ credentialsFetchEffect,
3536
+ createEffect((actions$, state$) => actions$.pipe(ofType(memoryAdapterEvents.addRequested, memoryAdapterEvents.updateRequested, memoryAdapterEvents.removeRequested), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.mergeMap)(([action, state]) => {
3537
+ const context = state.context;
3538
+ const sessionId = state.sessionId;
3539
+ if (!(context === null || context === void 0 ? void 0 : context.runtimeUrl)) return (0, rxjs.of)(memoryRestEvents.mutationFinished({ outcome: {
3540
+ requestId: action.requestId,
3541
+ sessionId,
3542
+ ok: false,
3543
+ error: /* @__PURE__ */ new Error("Runtime URL is not configured")
3544
+ } }));
3545
+ if (memoryAdapterEvents.addRequested.match(action)) return createMemoryMutationObservable(environment, context, {
3546
+ requestId: action.requestId,
3547
+ sessionId,
3548
+ kind: "add",
3549
+ body: toMutationBody(action.input)
3550
+ });
3551
+ if (memoryAdapterEvents.updateRequested.match(action)) return createMemoryMutationObservable(environment, context, {
3552
+ requestId: action.requestId,
3553
+ sessionId,
3554
+ kind: "update",
3555
+ id: action.id,
3556
+ body: toMutationBody(action.changes)
3557
+ });
3558
+ return createMemoryMutationObservable(environment, context, {
3559
+ requestId: action.requestId,
3560
+ sessionId,
3561
+ kind: "remove",
3562
+ id: action.id
3563
+ });
3564
+ }))),
3565
+ createEffect((actions$, state$) => actions$.pipe(ofType(memoryRestEvents.credentialsSucceeded), (0, rxjs_operators.withLatestFrom)(state$), (0, rxjs_operators.filter)(([action, state]) => {
3566
+ var _state$context;
3567
+ return action.sessionId === state.sessionId && Boolean((_state$context = state.context) === null || _state$context === void 0 ? void 0 : _state$context.wsUrl);
3568
+ }), (0, rxjs_operators.switchMap)(([action, state]) => {
3569
+ const context = state.context;
3570
+ const { joinToken, joinCode } = action;
3571
+ const sessionId = action.sessionId;
3572
+ const shutdown$ = actions$.pipe(ofType(memoryAdapterEvents.contextChanged, memoryAdapterEvents.stopped));
3573
+ return (0, rxjs.defer)(() => {
3574
+ const socket$ = ɵphoenixSocket$({
3575
+ url: context.wsUrl,
3576
+ options: {
3577
+ params: { join_token: joinToken },
3578
+ reconnectAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(100, 1e4),
3579
+ rejoinAfterMs: (0, _copilotkit_shared.phoenixExponentialBackoff)(1e3, 3e4)
3580
+ }
3581
+ }).pipe((0, rxjs_operators.shareReplay)({
3582
+ bufferSize: 1,
3583
+ refCount: true
3584
+ }));
3585
+ const channel$ = ɵphoenixChannel$({
3586
+ socket$,
3587
+ topic: `user_meta:memories:${joinCode}`
3588
+ }).pipe((0, rxjs_operators.shareReplay)({
3589
+ bufferSize: 1,
3590
+ refCount: true
3591
+ }));
3592
+ const fatalSocketShutdown$ = ɵobservePhoenixSocketHealth$(ɵobservePhoenixSocketSignals$(socket$).pipe((0, rxjs_operators.share)()), MAX_SOCKET_RETRIES$1).pipe((0, rxjs_operators.catchError)(() => {
3593
+ console.warn(`[memory] WebSocket failed after ${MAX_SOCKET_RETRIES$1} attempts, giving up`);
3594
+ return (0, rxjs.of)(void 0);
3595
+ }), (0, rxjs_operators.share)());
3596
+ const fatalStatus$ = fatalSocketShutdown$.pipe((0, rxjs_operators.map)(() => memoryDomainEvents.realtimeUnavailable({ sessionId })));
3597
+ const metadata$ = channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => ɵobservePhoenixEvent$(channel, MEMORY_METADATA_EVENT)), (0, rxjs_operators.map)((event) => mapMemoryMetadataEvent(event, action.sessionId)));
3598
+ const join$ = ɵjoinPhoenixChannel$(channel$).pipe((0, rxjs_operators.concatWith)((0, rxjs.of)(memoryDomainEvents.realtimeConnected({ sessionId }))), (0, rxjs_operators.catchError)((error) => {
3599
+ console.warn(`[memory] failed to join user_meta:memories:${joinCode}`, error);
3600
+ return (0, rxjs.of)(memoryDomainEvents.realtimeUnavailable({ sessionId }));
3601
+ }));
3602
+ 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)(() => {}));
3603
+ });
3604
+ })))
3605
+ ]
3606
+ });
3607
+ function trackMutation(dispatchAction, extract) {
3608
+ const { requestId } = dispatchAction;
3609
+ 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)(() => ({
3610
+ requestId,
3611
+ sessionId: store.getState().sessionId,
3612
+ ok: false,
3613
+ error: /* @__PURE__ */ new Error("Memory store stopped before mutation completed")
3614
+ })))).pipe((0, rxjs_operators.take)(1))).then((outcome) => {
3615
+ if (!outcome.ok) throw outcome.error;
3616
+ return extract(outcome);
3617
+ });
3618
+ store.dispatch(dispatchAction);
3619
+ return resultPromise;
3620
+ }
3621
+ return {
3622
+ start() {
3623
+ store.init();
3624
+ store.dispatch(memoryAdapterEvents.started());
3625
+ },
3626
+ stop() {
3627
+ store.dispatch(memoryAdapterEvents.stopped());
3628
+ store.stop();
3629
+ },
3630
+ setContext(context) {
3631
+ store.dispatch(memoryAdapterEvents.contextChanged({ context }));
3632
+ },
3633
+ refresh() {
3634
+ const { sessionId, context } = store.getState();
3635
+ if (!context) return Promise.resolve();
3636
+ 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) => {
3637
+ if (memoryRestEvents.listFailed.match(action)) throw action.error;
3638
+ if (memoryAdapterEvents.stopped.match(action)) throw new Error("Memory store stopped before refresh completed");
3639
+ if (memoryAdapterEvents.contextChanged.match(action)) return;
3640
+ });
3641
+ store.dispatch(memoryRestEvents.listRequested({ sessionId }));
3642
+ return done;
3643
+ },
3644
+ addMemory(input) {
3645
+ return trackMutation(memoryAdapterEvents.addRequested({
3646
+ requestId: createMemoryRequestId(),
3647
+ input
3648
+ }), (outcome) => {
3649
+ if (outcome.memory == null) throw new Error("add resolved without a memory");
3650
+ return outcome.memory;
3651
+ });
3652
+ },
3653
+ updateMemory(id, changes) {
3654
+ return trackMutation(memoryAdapterEvents.updateRequested({
3655
+ requestId: createMemoryRequestId(),
3656
+ id,
3657
+ changes
3658
+ }), (outcome) => {
3659
+ if (outcome.memory == null) throw new Error("update resolved without a memory");
3660
+ return outcome.memory;
3661
+ });
3662
+ },
3663
+ removeMemory(id) {
3664
+ return trackMutation(memoryAdapterEvents.removeRequested({
3665
+ requestId: createMemoryRequestId(),
3666
+ id
3667
+ }), () => void 0);
3668
+ },
3669
+ getState() {
3670
+ return store.getState();
3671
+ },
3672
+ getServerState() {
3673
+ return initialMemoryState;
3674
+ },
3675
+ select: store.select.bind(store)
3676
+ };
3677
+ }
3678
+ const ɵmemoryAdapterEvents = memoryAdapterEvents;
3679
+ const ɵmemoryRestEvents = memoryRestEvents;
3680
+ const ɵmemoryDomainEvents = memoryDomainEvents;
3681
+ const ɵmemoryReducer = memoryReducer;
3682
+ const ɵmapMemoryMetadataEvent = mapMemoryMetadataEvent;
3683
+ const ɵselectMemories = selectMemories;
3684
+ const ɵselectMemoriesIsLoading = selectMemoriesIsLoading;
3685
+ const ɵselectMemoriesError = selectMemoriesError;
3686
+ const ɵselectMemoriesIsMutating = selectMemoriesIsMutating;
3687
+ const ɵselectMemoriesAvailable = selectMemoriesAvailable;
3688
+ const ɵselectMemoriesRealtimeStatus = selectMemoriesRealtimeStatus;
3689
+
3690
+ //#endregion
3691
+ //#region src/core/core.ts
3692
+ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode) {
3693
+ CopilotKitCoreErrorCode["RUNTIME_INFO_FETCH_FAILED"] = "runtime_info_fetch_failed";
3694
+ CopilotKitCoreErrorCode["AGENT_CONNECT_FAILED"] = "agent_connect_failed";
3695
+ CopilotKitCoreErrorCode["AGENT_RUN_FAILED"] = "agent_run_failed";
3696
+ CopilotKitCoreErrorCode["AGENT_RUN_FAILED_EVENT"] = "agent_run_failed_event";
3697
+ CopilotKitCoreErrorCode["AGENT_RUN_ERROR_EVENT"] = "agent_run_error_event";
3698
+ CopilotKitCoreErrorCode["TOOL_ARGUMENT_PARSE_FAILED"] = "tool_argument_parse_failed";
3699
+ CopilotKitCoreErrorCode["TOOL_HANDLER_FAILED"] = "tool_handler_failed";
3700
+ CopilotKitCoreErrorCode["TOOL_NOT_FOUND"] = "tool_not_found";
3701
+ CopilotKitCoreErrorCode["AGENT_NOT_FOUND"] = "agent_not_found";
3702
+ /**
3703
+ * Emitted when an agent run fails because the thread is already locked
3704
+ * by another active run.
3705
+ *
3706
+ * @example
3707
+ * ```tsx
3708
+ * <CopilotKitProvider
3709
+ * onError={({ code, error, context }) => {
3710
+ * if (code === "agent_thread_locked") {
3711
+ * // Show "Agent is busy, retry?" UI
3712
+ * }
3713
+ * }}
3714
+ * />
3715
+ * ```
3716
+ */
3717
+ CopilotKitCoreErrorCode["AGENT_THREAD_LOCKED"] = "agent_thread_locked";
3718
+ CopilotKitCoreErrorCode["TRANSCRIPTION_FAILED"] = "transcription_failed";
3719
+ CopilotKitCoreErrorCode["TRANSCRIPTION_SERVICE_NOT_CONFIGURED"] = "transcription_service_not_configured";
3720
+ CopilotKitCoreErrorCode["TRANSCRIPTION_INVALID_AUDIO"] = "transcription_invalid_audio";
3721
+ CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
3722
+ CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
3723
+ CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
3724
+ CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
3725
+ return CopilotKitCoreErrorCode;
3726
+ }({});
3727
+ /**
3728
+ * Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
3729
+ * to module scope so the Set is allocated once, not per-subscription.
3730
+ */
3731
+ const ALLOWED_KEYS = new Set([
3732
+ "onMessagesChanged",
3733
+ "onStateChanged",
3734
+ "onRunInitialized",
3735
+ "onRunFinalized",
3736
+ "onRunFailed",
3737
+ "onRunErrorEvent"
3738
+ ]);
3739
+ let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
3740
+ CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
3741
+ CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
3742
+ CopilotKitCoreRuntimeConnectionStatus["Connecting"] = "connecting";
3743
+ CopilotKitCoreRuntimeConnectionStatus["Error"] = "error";
3744
+ return CopilotKitCoreRuntimeConnectionStatus;
3745
+ }({});
3746
+ /**
3747
+ * Normalize a header map to the internal invariant: a `Record<string, string>`
3748
+ * with no `null`/`undefined` values. Entries whose value is `null`/`undefined`
3749
+ * are dropped (this is how a header is cleared). Shared by the constructor and
3750
+ * `setHeaders` so both write paths into `_headers` enforce the same invariant.
3751
+ */
3752
+ function normalizeHeaders(headers) {
3753
+ return Object.fromEntries(Object.entries(headers).filter((entry) => entry[1] != null));
3754
+ }
3755
+ var CopilotKitCore = class {
3756
+ constructor({ runtimeUrl, runtimeTransport = "auto", headers = {}, credentials, properties = {}, agents__unsafe_dev_only = {}, tools = [], suggestionsConfig = [], debug }) {
3757
+ _defineProperty(this, "_headers", void 0);
3758
+ _defineProperty(this, "_credentials", void 0);
3759
+ _defineProperty(this, "_properties", void 0);
3760
+ _defineProperty(this, "_defaultThrottleMs", void 0);
3761
+ _defineProperty(this, "_debug", void 0);
3762
+ _defineProperty(this, "subscribers", /* @__PURE__ */ new Set());
3763
+ _defineProperty(this, "agentRegistry", void 0);
3764
+ _defineProperty(this, "contextStore", void 0);
3765
+ _defineProperty(this, "suggestionEngine", void 0);
3766
+ _defineProperty(this, "runHandler", void 0);
3767
+ _defineProperty(this, "stateManager", void 0);
3768
+ _defineProperty(this, "threadStoreRegistry", void 0);
3769
+ _defineProperty(this, "_memoryStore", void 0);
3770
+ _defineProperty(this, "previousAgentIds", /* @__PURE__ */ new Set());
3771
+ this._headers = normalizeHeaders(headers);
3772
+ this._credentials = credentials;
3773
+ this._properties = properties;
3774
+ this._debug = debug;
3775
+ this.agentRegistry = new AgentRegistry(this);
3776
+ this.contextStore = new ContextStore(this);
3777
+ this.suggestionEngine = new SuggestionEngine(this);
3778
+ this.runHandler = new RunHandler(this);
3779
+ this.stateManager = new StateManager(this);
3780
+ this.threadStoreRegistry = new ThreadStoreRegistry(this);
3781
+ this.agentRegistry.initialize(agents__unsafe_dev_only);
3782
+ this.runHandler.initialize(tools);
3783
+ this.suggestionEngine.initialize(suggestionsConfig);
3784
+ this.stateManager.initialize();
3785
+ this.agentRegistry.setRuntimeTransport(runtimeTransport);
3786
+ this.agentRegistry.setRuntimeUrl(runtimeUrl);
3787
+ this.previousAgentIds = new Set(Object.keys(agents__unsafe_dev_only));
3788
+ this.subscribe({
3789
+ onRuntimeConnectionStatusChanged: () => {
3790
+ if (this._memoryStore) this.syncMemoryContext();
3791
+ },
3792
+ onAgentsChanged: ({ agents }) => {
3793
+ Object.values(agents).forEach((agent) => {
3794
+ if (agent.agentId) this.stateManager.subscribeToAgent(agent);
3795
+ });
3796
+ const currentAgentIds = new Set(Object.keys(agents));
3797
+ for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) try {
3798
+ this.threadStoreRegistry.unregister(agentId);
3799
+ } catch (err) {
3800
+ console.error(`CopilotKitCore.onAgentsChanged: threadStoreRegistry.unregister failed for "${agentId}":`, err);
3801
+ }
3802
+ for (const agentId of this.previousAgentIds) if (!currentAgentIds.has(agentId)) try {
3803
+ this.stateManager.unsubscribeFromAgent(agentId);
3804
+ } catch (err) {
3805
+ console.error(`CopilotKitCore.onAgentsChanged: stateManager.unsubscribeFromAgent failed for "${agentId}":`, err);
3806
+ }
3807
+ this.previousAgentIds = currentAgentIds;
3808
+ }
3809
+ });
3810
+ }
3811
+ /**
3812
+ * Internal method used by delegate classes and subclasses to notify subscribers
3813
+ */
3814
+ async notifySubscribers(handler, errorMessage) {
3815
+ await Promise.all(Array.from(this.subscribers).map(async (subscriber) => {
3816
+ try {
3817
+ await handler(subscriber);
3818
+ } catch (error) {
3819
+ console.error(errorMessage, error);
3820
+ }
3821
+ }));
3822
+ }
3823
+ /**
3824
+ * Internal method used by delegate classes to emit errors
3825
+ */
3826
+ async emitError({ error, code, context = {} }) {
3827
+ await this.notifySubscribers((subscriber) => {
3828
+ var _subscriber$onError;
3829
+ return (_subscriber$onError = subscriber.onError) === null || _subscriber$onError === void 0 ? void 0 : _subscriber$onError.call(subscriber, {
3830
+ copilotkit: this,
3831
+ error,
3832
+ code,
3833
+ context
3834
+ });
3835
+ }, "Subscriber onError error:");
3836
+ }
3837
+ /**
3838
+ * Log a message to the console and emit an error to subscribers.
3839
+ * Catches failures from `emitError` itself to prevent unhandled rejections.
3840
+ */
3841
+ logAndEmitError(message, params, logLevel = "error") {
3842
+ console[logLevel](message, params.error);
3843
+ this.emitError(params).catch((emitErr) => {
3844
+ console.error(message + " — emitError itself failed:", emitErr);
3845
+ });
2817
3846
  }
2818
3847
  /**
2819
3848
  * Snapshot accessors
@@ -2954,6 +3983,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2954
3983
  */
2955
3984
  setHeaders(headers) {
2956
3985
  this._headers = normalizeHeaders(headers);
3986
+ if (this._memoryStore) this.syncMemoryContext();
2957
3987
  this.agentRegistry.applyHeadersToAgents(this.agentRegistry.agents);
2958
3988
  this.notifySubscribers((subscriber) => {
2959
3989
  var _subscriber$onHeaders;
@@ -3065,6 +4095,47 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3065
4095
  return this.threadStoreRegistry.getAll();
3066
4096
  }
3067
4097
  /**
4098
+ * Returns the single core-owned, user-scoped memory store, creating and
4099
+ * starting it on first access. Unlike thread stores, memory is not scoped per
4100
+ * agent: there is exactly one store whose runtime context the core wires
4101
+ * itself (see `syncMemoryContext`), so consumers (e.g. a `useMemories`
4102
+ * binding) just read this store rather than registering one.
4103
+ */
4104
+ getMemoryStore() {
4105
+ return this.ensureMemoryStore();
4106
+ }
4107
+ /**
4108
+ * Lazily creates, starts, and context-syncs the core-owned memory store on
4109
+ * first access, then returns it. Subsequent calls return the existing store.
4110
+ * The store is constructed with a bound `globalThis.fetch` and immediately
4111
+ * has its runtime context synced from the current connection state.
4112
+ */
4113
+ ensureMemoryStore() {
4114
+ if (!this._memoryStore) {
4115
+ this._memoryStore = createMemoryStore({ fetch: globalThis.fetch.bind(globalThis) });
4116
+ this._memoryStore.start();
4117
+ this.syncMemoryContext();
4118
+ }
4119
+ return this._memoryStore;
4120
+ }
4121
+ /**
4122
+ * Pushes the current runtime wiring into the memory store. When the runtime
4123
+ * is connected and both the intelligence WebSocket URL and runtime URL are
4124
+ * available, the store receives a context (runtime URL, WebSocket URL, and a
4125
+ * copy of the current headers); otherwise its context is cleared. No-op when
4126
+ * the store has not been created yet.
4127
+ */
4128
+ syncMemoryContext() {
4129
+ var _this$intelligence;
4130
+ if (!this._memoryStore) return;
4131
+ if (this.runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected && ((_this$intelligence = this.intelligence) === null || _this$intelligence === void 0 ? void 0 : _this$intelligence.wsUrl) && this.runtimeUrl) this._memoryStore.setContext({
4132
+ runtimeUrl: this.runtimeUrl,
4133
+ wsUrl: this.intelligence.wsUrl,
4134
+ headers: { ...this.headers }
4135
+ });
4136
+ else this._memoryStore.setContext(null);
4137
+ }
4138
+ /**
3068
4139
  * Suggestions management (delegated to SuggestionEngine)
3069
4140
  */
3070
4141
  addSuggestionsConfig(config) {
@@ -3228,517 +4299,259 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3228
4299
  throttler.maybeExecute();
3229
4300
  };
3230
4301
  if (subscriber.onStateChanged) wrappedSubscriber.onStateChanged = (params) => {
3231
- latestStateParams = params;
3232
- throttler.maybeExecute();
3233
- };
3234
- const subscription = agent.subscribe(wrappedSubscriber);
3235
- return { unsubscribe: () => {
3236
- active = false;
3237
- throttler.cancel();
3238
- subscription.unsubscribe();
3239
- } };
3240
- }
3241
- /**
3242
- * Agent connectivity (delegated to RunHandler)
3243
- */
3244
- async connectAgent(params) {
3245
- return this.runHandler.connectAgent(params);
3246
- }
3247
- stopAgent(params) {
3248
- this.runHandler.abortCurrentRun();
3249
- params.agent.abortRun();
3250
- }
3251
- async runAgent(params) {
3252
- return this.runHandler.runAgent(params);
3253
- }
3254
- /**
3255
- * Programmatically execute a registered frontend tool without going through an LLM turn.
3256
- * The handler runs, render components show up in the UI, and both the tool call and
3257
- * result messages are added to `agent.messages`.
3258
- */
3259
- async runTool(params) {
3260
- return this.runHandler.runTool(params);
3261
- }
3262
- /**
3263
- * State management (delegated to StateManager)
3264
- */
3265
- getStateByRun(agentId, threadId, runId) {
3266
- return this.stateManager.getStateByRun(agentId, threadId, runId);
3267
- }
3268
- getRunIdForMessage(agentId, threadId, messageId) {
3269
- return this.stateManager.getRunIdForMessage(agentId, threadId, messageId);
3270
- }
3271
- getRunIdsForThread(agentId, threadId) {
3272
- return this.stateManager.getRunIdsForThread(agentId, threadId);
3273
- }
3274
- /**
3275
- * Internal method used by RunHandler to build frontend tools
3276
- */
3277
- buildFrontendTools(agentId) {
3278
- return this.runHandler.buildFrontendTools(agentId);
3279
- }
3280
- /**
3281
- * Called before each follow-up agent run (after tool execution).
3282
- *
3283
- * When a frontend tool handler calls framework state setters (e.g. React's
3284
- * setState), those updates are batched and deferred — they do not take effect
3285
- * until the framework's scheduler runs (React uses MessageChannel).
3286
- * useAgentContext registers context via useLayoutEffect, which runs
3287
- * synchronously after React commits that deferred batch.
3288
- *
3289
- * Without yielding here, the follow-up runAgent reads the context store
3290
- * synchronously while the deferred updates are still pending, producing stale
3291
- * context for the next agent turn.
3292
- *
3293
- * Override in framework-specific subclasses to yield to the framework
3294
- * scheduler before the follow-up run. The base implementation is a no-op
3295
- * because non-React environments have no deferred state to flush.
3296
- */
3297
- async waitForPendingFrameworkUpdates() {}
3298
- };
3299
-
3300
- //#endregion
3301
- //#region src/types.ts
3302
- /**
3303
- * Status of a tool call execution
3304
- */
3305
- let ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
3306
- ToolCallStatus["InProgress"] = "inProgress";
3307
- ToolCallStatus["Executing"] = "executing";
3308
- ToolCallStatus["Complete"] = "complete";
3309
- return ToolCallStatus;
3310
- }({});
3311
-
3312
- //#endregion
3313
- //#region src/utils/markdown.ts
3314
- function completePartialMarkdown(input) {
3315
- let s = input;
3316
- const fenceMatches = Array.from(s.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
3317
- if (fenceMatches.length % 2 === 1) {
3318
- const [, indent, fence] = fenceMatches[0];
3319
- s += `\n${indent}${fence}`;
3320
- }
3321
- if (s.match(/\[([^\]]*)\]\(([^)]*)$/)) s += ")";
3322
- const openElements = [];
3323
- const chars = Array.from(s);
3324
- const codeBlockRanges = [];
3325
- const inlineCodeRanges = [];
3326
- let tempCodeFenceCount = 0;
3327
- let currentCodeBlockStart = -1;
3328
- for (let i = 0; i < chars.length; i++) if (i === 0 || chars[i - 1] === "\n") {
3329
- const lineMatch = s.substring(i).match(/^(\s*)(`{3,}|~{3,})/);
3330
- if (lineMatch) {
3331
- tempCodeFenceCount++;
3332
- if (tempCodeFenceCount % 2 === 1) currentCodeBlockStart = i;
3333
- else if (currentCodeBlockStart !== -1) {
3334
- codeBlockRanges.push({
3335
- start: currentCodeBlockStart,
3336
- end: i + lineMatch[0].length
3337
- });
3338
- currentCodeBlockStart = -1;
3339
- }
3340
- i += lineMatch[0].length - 1;
3341
- }
3342
- }
3343
- for (let i = 0; i < chars.length; i++) if (chars[i] === "`") {
3344
- let backslashCount = 0;
3345
- for (let j = i - 1; j >= 0 && chars[j] === "\\"; j--) backslashCount++;
3346
- if (backslashCount % 2 === 0) {
3347
- for (let j = i + 1; j < chars.length; j++) if (chars[j] === "`") {
3348
- let closingBackslashCount = 0;
3349
- for (let k = j - 1; k >= 0 && chars[k] === "\\"; k--) closingBackslashCount++;
3350
- if (closingBackslashCount % 2 === 0) {
3351
- inlineCodeRanges.push({
3352
- start: i,
3353
- end: j + 1
3354
- });
3355
- i = j;
3356
- break;
3357
- }
3358
- }
3359
- }
3360
- }
3361
- const isInCode = (pos) => {
3362
- return codeBlockRanges.some((range) => pos >= range.start && pos < range.end) || inlineCodeRanges.some((range) => pos >= range.start && pos < range.end);
3363
- };
3364
- for (let i = 0; i < chars.length; i++) {
3365
- const char = chars[i];
3366
- const nextChar = chars[i + 1];
3367
- const prevChar = chars[i - 1];
3368
- if (isInCode(i)) continue;
3369
- if (char === "[") {
3370
- let isCompleteLink = false;
3371
- let bracketDepth = 1;
3372
- let j = i + 1;
3373
- while (j < chars.length && bracketDepth > 0) {
3374
- if (chars[j] === "[" && !isInCode(j)) bracketDepth++;
3375
- if (chars[j] === "]" && !isInCode(j)) bracketDepth--;
3376
- j++;
3377
- }
3378
- if (bracketDepth === 0 && chars[j] === "(") {
3379
- let parenDepth = 1;
3380
- j++;
3381
- while (j < chars.length && parenDepth > 0) {
3382
- if (chars[j] === "(" && !isInCode(j)) parenDepth++;
3383
- if (chars[j] === ")" && !isInCode(j)) parenDepth--;
3384
- j++;
3385
- }
3386
- if (parenDepth === 0) {
3387
- isCompleteLink = true;
3388
- i = j - 1;
3389
- continue;
3390
- }
3391
- }
3392
- if (!isCompleteLink) {
3393
- const existingIndex = openElements.findIndex((el) => el.type === "bracket");
3394
- if (existingIndex !== -1) openElements.splice(existingIndex, 1);
3395
- else openElements.push({
3396
- type: "bracket",
3397
- marker: "[",
3398
- position: i
3399
- });
3400
- }
3401
- } else if (char === "*" && nextChar === "*") {
3402
- const existingIndex = openElements.findIndex((el) => el.type === "bold_star");
3403
- if (existingIndex !== -1) openElements.splice(existingIndex, 1);
3404
- else openElements.push({
3405
- type: "bold_star",
3406
- marker: "**",
3407
- position: i
3408
- });
3409
- i++;
3410
- } else if (char === "_" && nextChar === "_") {
3411
- const existingIndex = openElements.findIndex((el) => el.type === "bold_underscore");
3412
- if (existingIndex !== -1) openElements.splice(existingIndex, 1);
3413
- else openElements.push({
3414
- type: "bold_underscore",
3415
- marker: "__",
3416
- position: i
3417
- });
3418
- i++;
3419
- } else if (char === "~" && nextChar === "~") {
3420
- const existingIndex = openElements.findIndex((el) => el.type === "strike");
3421
- if (existingIndex !== -1) openElements.splice(existingIndex, 1);
3422
- else openElements.push({
3423
- type: "strike",
3424
- marker: "~~",
3425
- position: i
3426
- });
3427
- i++;
3428
- } else if (char === "*" && prevChar !== "*" && nextChar !== "*") {
3429
- const existingIndex = openElements.findIndex((el) => el.type === "italic_star");
3430
- if (existingIndex !== -1) openElements.splice(existingIndex, 1);
3431
- else openElements.push({
3432
- type: "italic_star",
3433
- marker: "*",
3434
- position: i
3435
- });
3436
- } else if (char === "_" && prevChar !== "_" && nextChar !== "_") {
3437
- const existingIndex = openElements.findIndex((el) => el.type === "italic_underscore");
3438
- if (existingIndex !== -1) openElements.splice(existingIndex, 1);
3439
- else openElements.push({
3440
- type: "italic_underscore",
3441
- marker: "_",
3442
- position: i
3443
- });
3444
- }
3445
- }
3446
- let backtickCount = 0;
3447
- for (let i = 0; i < chars.length; i++) if (chars[i] === "`" && !isInCode(i)) backtickCount++;
3448
- if (backtickCount % 2 === 1) s += "`";
3449
- openElements.sort((a, b) => b.position - a.position);
3450
- const closers = openElements.map((el) => {
3451
- switch (el.type) {
3452
- case "bracket": return "]";
3453
- case "bold_star": return "**";
3454
- case "bold_underscore": return "__";
3455
- case "strike": return "~~";
3456
- case "italic_star": return "*";
3457
- case "italic_underscore": return "_";
3458
- default: return "";
3459
- }
3460
- });
3461
- let result = s + closers.join("");
3462
- const finalFenceMatches = Array.from(result.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
3463
- const hasUnclosedBacktick = (result.match(/`/g) || []).length % 2 === 1;
3464
- const hasUnclosedCodeFence = finalFenceMatches.length % 2 === 1;
3465
- let shouldCloseParens = !hasUnclosedBacktick && !hasUnclosedCodeFence;
3466
- if (shouldCloseParens) {
3467
- const lastOpenParen = result.lastIndexOf("(");
3468
- if (lastOpenParen !== -1) {
3469
- if ((result.substring(0, lastOpenParen).match(/`/g) || []).length % 2 === 1) shouldCloseParens = false;
3470
- }
4302
+ latestStateParams = params;
4303
+ throttler.maybeExecute();
4304
+ };
4305
+ const subscription = agent.subscribe(wrappedSubscriber);
4306
+ return { unsubscribe: () => {
4307
+ active = false;
4308
+ throttler.cancel();
4309
+ subscription.unsubscribe();
4310
+ } };
3471
4311
  }
3472
- if (shouldCloseParens) {
3473
- const openParens = (result.match(/\(/g) || []).length;
3474
- const closeParens = (result.match(/\)/g) || []).length;
3475
- if (openParens > closeParens) result += ")".repeat(openParens - closeParens);
4312
+ /**
4313
+ * Agent connectivity (delegated to RunHandler)
4314
+ */
4315
+ async connectAgent(params) {
4316
+ return this.runHandler.connectAgent(params);
3476
4317
  }
3477
- return result;
3478
- }
3479
-
3480
- //#endregion
3481
- //#region src/utils/micro-redux.ts
3482
- const INTERNAL_ACTION_TYPES = {
3483
- boot: "@@micro-redux/boot",
3484
- init: "@@micro-redux/init",
3485
- stop: "@@micro-redux/stop"
3486
- };
3487
- const INTERNAL_BOOT_ACTION = { type: INTERNAL_ACTION_TYPES.boot };
3488
- /**
3489
- * Builds a typed action creator from a type string and payload factory.
3490
- */
3491
- function createTypedActionCreator(type, factory) {
3492
- const creator = ((...args) => ({
3493
- ...factory(...args),
3494
- type
3495
- }));
3496
- creator.type = type;
3497
- creator.match = (action) => action.type === type;
3498
- return creator;
3499
- }
3500
- /**
3501
- * Declares a payload-based action config for `createActionGroup`.
3502
- *
3503
- * @example
3504
- * ```ts
3505
- * const actions = createActionGroup("User", {
3506
- * loaded: props<{ id: string }>(),
3507
- * });
3508
- * ```
3509
- */
3510
- function props() {
3511
- return { kind: "props" };
3512
- }
3513
- /**
3514
- * Declares a no-payload action config for `createActionGroup`.
3515
- *
3516
- * @example
3517
- * ```ts
3518
- * const actions = createActionGroup("User", {
3519
- * reset: empty(),
3520
- * });
3521
- * ```
3522
- */
3523
- function empty() {
3524
- return { kind: "empty" };
3525
- }
3526
- /**
3527
- * Creates a namespaced group of typed action creators.
3528
- *
3529
- * Action types are formatted as: `[Source] actionName`.
3530
- */
3531
- function createActionGroup(source, config) {
3532
- const group = {};
3533
- for (const eventName of Object.keys(config)) {
3534
- const eventConfig = config[eventName];
3535
- if (!eventConfig) continue;
3536
- const actionType = `[${source}] ${eventName}`;
3537
- if (eventConfig.kind === "props") {
3538
- group[eventName] = createTypedActionCreator(actionType, (payload) => ({ ...payload }));
3539
- continue;
3540
- }
3541
- group[eventName] = createTypedActionCreator(actionType, () => ({}));
4318
+ stopAgent(params) {
4319
+ this.runHandler.abortCurrentRun();
4320
+ params.agent.abortRun();
3542
4321
  }
3543
- return group;
3544
- }
3545
- /**
3546
- * Registers one reducer handler for one or more action creators.
3547
- *
3548
- * @throws Error when called without at least one action creator and reducer.
3549
- */
3550
- function on(...args) {
3551
- if (args.length < 2) throw new Error("on requires at least one action creator and one reducer");
3552
- const reducer = args[args.length - 1];
3553
- return {
3554
- creators: args.slice(0, -1),
3555
- reducer
3556
- };
3557
- }
3558
- /**
3559
- * Creates a reducer from an initial state and `on(...)` handler entries.
3560
- *
3561
- * Unknown action types return the current state unchanged.
3562
- */
3563
- function createReducer(initialState, ...entries) {
3564
- const reducerMap = /* @__PURE__ */ new Map();
3565
- for (const entry of entries) for (const creator of entry.creators) {
3566
- var _reducerMap$get;
3567
- const handlers = (_reducerMap$get = reducerMap.get(creator.type)) !== null && _reducerMap$get !== void 0 ? _reducerMap$get : [];
3568
- handlers.push(entry.reducer);
3569
- reducerMap.set(creator.type, handlers);
4322
+ async runAgent(params) {
4323
+ return this.runHandler.runAgent(params);
3570
4324
  }
3571
- return (state, action) => {
3572
- const currentState = state !== null && state !== void 0 ? state : initialState;
3573
- const handlers = reducerMap.get(action.type);
3574
- if (!handlers || handlers.length === 0) return currentState;
3575
- let nextState = currentState;
3576
- for (const handler of handlers) nextState = handler(nextState, action);
3577
- return nextState;
3578
- };
3579
- }
3580
- /**
3581
- * Creates a selector that caches and reuses the last computed result
3582
- * when all input references are unchanged.
3583
- */
3584
- function createSelector(...args) {
3585
- if (args.length === 1) {
3586
- const projector = args[0];
3587
- let hasCached = false;
3588
- let lastState;
3589
- let lastResult;
3590
- return (state) => {
3591
- if (hasCached && state === lastState) return lastResult;
3592
- lastState = state;
3593
- lastResult = projector(state);
3594
- hasCached = true;
3595
- return lastResult;
3596
- };
4325
+ /**
4326
+ * Programmatically execute a registered frontend tool without going through an LLM turn.
4327
+ * The handler runs, render components show up in the UI, and both the tool call and
4328
+ * result messages are added to `agent.messages`.
4329
+ */
4330
+ async runTool(params) {
4331
+ return this.runHandler.runTool(params);
3597
4332
  }
3598
- const projector = args[args.length - 1];
3599
- const selectors = args.slice(0, -1);
3600
- let hasCached = false;
3601
- let lastInputs = [];
3602
- let lastResult;
3603
- return (state) => {
3604
- const inputs = selectors.map((selector) => selector(state));
3605
- if (hasCached && inputs.length === lastInputs.length && inputs.every((value, index) => value === lastInputs[index])) return lastResult;
3606
- lastInputs = inputs;
3607
- lastResult = projector(...inputs);
3608
- hasCached = true;
3609
- return lastResult;
3610
- };
3611
- }
3612
- /**
3613
- * RxJS operator that maps state emissions through a selector and suppresses
3614
- * unchanged projected values via reference equality.
3615
- */
3616
- function select(selector) {
3617
- return (source$) => source$.pipe((0, rxjs_operators.map)(selector), (0, rxjs_operators.distinctUntilChanged)());
3618
- }
3619
- /**
3620
- * RxJS operator that filters an action stream by action creators and narrows
3621
- * the output action type to the matched creator union.
3622
- *
3623
- * @throws Error when called without at least one action creator.
3624
- */
3625
- function ofType(...creators) {
3626
- if (creators.length === 0) throw new Error("ofType requires at least one action creator");
3627
- const actionTypes = new Set(creators.map((creator) => creator.type));
3628
- return (source$) => {
3629
- return source$.pipe((0, rxjs_operators.filter)((action) => {
3630
- return actionTypes.has(action.type);
3631
- }));
3632
- };
3633
- }
3634
- /**
3635
- * Creates an effect descriptor consumed by `createStore`.
3636
- */
3637
- function createEffect(factory, options = {}) {
3638
- if (options.dispatch === false) return {
3639
- run: factory,
3640
- dispatch: false
3641
- };
3642
- return {
3643
- run: factory,
3644
- dispatch: true
3645
- };
3646
- }
3647
- /**
3648
- * Creates a small observable store with reducer + effects.
3649
- *
3650
- * Behavior:
3651
- * - `init()` starts effects and dispatches `@@micro-redux/init`.
3652
- * - `stop()` dispatches `@@micro-redux/stop` and unsubscribes all effects.
3653
- * - Effect action observation is scheduled on `asapScheduler` to avoid
3654
- * synchronous re-entrancy in the effect loop.
3655
- * - Any effect error triggers fail-fast teardown and errors both `actions$`
3656
- * and `state$`.
3657
- */
3658
- function createStore(options) {
3659
- var _options$effects;
3660
- const reducer = options.reducer;
3661
- const effects = (_options$effects = options.effects) !== null && _options$effects !== void 0 ? _options$effects : [];
3662
- let hasFatalError = false;
3663
- let isRunning = false;
3664
- let effectSubscriptions = new rxjs.Subscription();
3665
- let currentState = reducer(void 0, INTERNAL_BOOT_ACTION);
3666
- const stateSubject = new rxjs.BehaviorSubject(currentState);
3667
- const actionsSubject = new rxjs.Subject();
3668
- const dispatchInternal = (action) => {
3669
- if (hasFatalError) throw new Error("Store is in a failed state due to an effect error");
3670
- currentState = reducer(currentState, action);
3671
- stateSubject.next(currentState);
3672
- actionsSubject.next(action);
3673
- };
3674
- const failFast = (error) => {
3675
- if (hasFatalError) return;
3676
- hasFatalError = true;
3677
- isRunning = false;
3678
- effectSubscriptions.unsubscribe();
3679
- effectSubscriptions = new rxjs.Subscription();
3680
- actionsSubject.error(error);
3681
- stateSubject.error(error);
3682
- };
3683
- const startEffects = () => {
3684
- for (const effect of effects) {
3685
- const scheduledActions$ = actionsSubject.asObservable().pipe((0, rxjs_operators.observeOn)(rxjs.asapScheduler));
3686
- const state$ = stateSubject.asObservable();
3687
- if (effect.dispatch) {
3688
- const subscription = effect.run(scheduledActions$, state$).subscribe({
3689
- next: (effectAction) => {
3690
- if (hasFatalError) return;
3691
- dispatchInternal(effectAction);
3692
- },
3693
- error: (error) => {
3694
- failFast(error);
3695
- }
4333
+ /**
4334
+ * State management (delegated to StateManager)
4335
+ */
4336
+ getStateByRun(agentId, threadId, runId) {
4337
+ return this.stateManager.getStateByRun(agentId, threadId, runId);
4338
+ }
4339
+ getRunIdForMessage(agentId, threadId, messageId) {
4340
+ return this.stateManager.getRunIdForMessage(agentId, threadId, messageId);
4341
+ }
4342
+ getRunIdsForThread(agentId, threadId) {
4343
+ return this.stateManager.getRunIdsForThread(agentId, threadId);
4344
+ }
4345
+ /**
4346
+ * Internal method used by RunHandler to build frontend tools
4347
+ */
4348
+ buildFrontendTools(agentId) {
4349
+ return this.runHandler.buildFrontendTools(agentId);
4350
+ }
4351
+ /**
4352
+ * Called before each follow-up agent run (after tool execution).
4353
+ *
4354
+ * When a frontend tool handler calls framework state setters (e.g. React's
4355
+ * setState), those updates are batched and deferred — they do not take effect
4356
+ * until the framework's scheduler runs (React uses MessageChannel).
4357
+ * useAgentContext registers context via useLayoutEffect, which runs
4358
+ * synchronously after React commits that deferred batch.
4359
+ *
4360
+ * Without yielding here, the follow-up runAgent reads the context store
4361
+ * synchronously while the deferred updates are still pending, producing stale
4362
+ * context for the next agent turn.
4363
+ *
4364
+ * Override in framework-specific subclasses to yield to the framework
4365
+ * scheduler before the follow-up run. The base implementation is a no-op
4366
+ * because non-React environments have no deferred state to flush.
4367
+ */
4368
+ async waitForPendingFrameworkUpdates() {}
4369
+ };
4370
+
4371
+ //#endregion
4372
+ //#region src/types.ts
4373
+ /**
4374
+ * Status of a tool call execution
4375
+ */
4376
+ let ToolCallStatus = /* @__PURE__ */ function(ToolCallStatus) {
4377
+ ToolCallStatus["InProgress"] = "inProgress";
4378
+ ToolCallStatus["Executing"] = "executing";
4379
+ ToolCallStatus["Complete"] = "complete";
4380
+ return ToolCallStatus;
4381
+ }({});
4382
+
4383
+ //#endregion
4384
+ //#region src/utils/markdown.ts
4385
+ function completePartialMarkdown(input) {
4386
+ let s = input;
4387
+ const fenceMatches = Array.from(s.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
4388
+ if (fenceMatches.length % 2 === 1) {
4389
+ const [, indent, fence] = fenceMatches[0];
4390
+ s += `\n${indent}${fence}`;
4391
+ }
4392
+ if (s.match(/\[([^\]]*)\]\(([^)]*)$/)) s += ")";
4393
+ const openElements = [];
4394
+ const chars = Array.from(s);
4395
+ const codeBlockRanges = [];
4396
+ const inlineCodeRanges = [];
4397
+ let tempCodeFenceCount = 0;
4398
+ let currentCodeBlockStart = -1;
4399
+ for (let i = 0; i < chars.length; i++) if (i === 0 || chars[i - 1] === "\n") {
4400
+ const lineMatch = s.substring(i).match(/^(\s*)(`{3,}|~{3,})/);
4401
+ if (lineMatch) {
4402
+ tempCodeFenceCount++;
4403
+ if (tempCodeFenceCount % 2 === 1) currentCodeBlockStart = i;
4404
+ else if (currentCodeBlockStart !== -1) {
4405
+ codeBlockRanges.push({
4406
+ start: currentCodeBlockStart,
4407
+ end: i + lineMatch[0].length
3696
4408
  });
3697
- effectSubscriptions.add(subscription);
3698
- continue;
4409
+ currentCodeBlockStart = -1;
3699
4410
  }
3700
- const subscription = effect.run(scheduledActions$, state$).subscribe({ error: (error) => {
3701
- failFast(error);
3702
- } });
3703
- effectSubscriptions.add(subscription);
4411
+ i += lineMatch[0].length - 1;
3704
4412
  }
3705
- };
3706
- return {
3707
- dispatch(action) {
3708
- dispatchInternal(action);
3709
- },
3710
- getState() {
3711
- return currentState;
3712
- },
3713
- get state$() {
3714
- return stateSubject.asObservable();
3715
- },
3716
- get actions$() {
3717
- return actionsSubject.asObservable();
3718
- },
3719
- select(selector) {
3720
- return stateSubject.asObservable().pipe(select(selector));
3721
- },
3722
- init() {
3723
- if (hasFatalError || isRunning) return;
3724
- isRunning = true;
3725
- startEffects();
3726
- if (hasFatalError) return;
3727
- dispatchInternal({ type: INTERNAL_ACTION_TYPES.init });
3728
- },
3729
- stop() {
3730
- if (hasFatalError || !isRunning) return;
3731
- dispatchInternal({ type: INTERNAL_ACTION_TYPES.stop });
3732
- effectSubscriptions.unsubscribe();
3733
- effectSubscriptions = new rxjs.Subscription();
3734
- isRunning = false;
4413
+ }
4414
+ for (let i = 0; i < chars.length; i++) if (chars[i] === "`") {
4415
+ let backslashCount = 0;
4416
+ for (let j = i - 1; j >= 0 && chars[j] === "\\"; j--) backslashCount++;
4417
+ if (backslashCount % 2 === 0) {
4418
+ for (let j = i + 1; j < chars.length; j++) if (chars[j] === "`") {
4419
+ let closingBackslashCount = 0;
4420
+ for (let k = j - 1; k >= 0 && chars[k] === "\\"; k--) closingBackslashCount++;
4421
+ if (closingBackslashCount % 2 === 0) {
4422
+ inlineCodeRanges.push({
4423
+ start: i,
4424
+ end: j + 1
4425
+ });
4426
+ i = j;
4427
+ break;
4428
+ }
4429
+ }
3735
4430
  }
4431
+ }
4432
+ const isInCode = (pos) => {
4433
+ return codeBlockRanges.some((range) => pos >= range.start && pos < range.end) || inlineCodeRanges.some((range) => pos >= range.start && pos < range.end);
3736
4434
  };
4435
+ for (let i = 0; i < chars.length; i++) {
4436
+ const char = chars[i];
4437
+ const nextChar = chars[i + 1];
4438
+ const prevChar = chars[i - 1];
4439
+ if (isInCode(i)) continue;
4440
+ if (char === "[") {
4441
+ let isCompleteLink = false;
4442
+ let bracketDepth = 1;
4443
+ let j = i + 1;
4444
+ while (j < chars.length && bracketDepth > 0) {
4445
+ if (chars[j] === "[" && !isInCode(j)) bracketDepth++;
4446
+ if (chars[j] === "]" && !isInCode(j)) bracketDepth--;
4447
+ j++;
4448
+ }
4449
+ if (bracketDepth === 0 && chars[j] === "(") {
4450
+ let parenDepth = 1;
4451
+ j++;
4452
+ while (j < chars.length && parenDepth > 0) {
4453
+ if (chars[j] === "(" && !isInCode(j)) parenDepth++;
4454
+ if (chars[j] === ")" && !isInCode(j)) parenDepth--;
4455
+ j++;
4456
+ }
4457
+ if (parenDepth === 0) {
4458
+ isCompleteLink = true;
4459
+ i = j - 1;
4460
+ continue;
4461
+ }
4462
+ }
4463
+ if (!isCompleteLink) {
4464
+ const existingIndex = openElements.findIndex((el) => el.type === "bracket");
4465
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4466
+ else openElements.push({
4467
+ type: "bracket",
4468
+ marker: "[",
4469
+ position: i
4470
+ });
4471
+ }
4472
+ } else if (char === "*" && nextChar === "*") {
4473
+ const existingIndex = openElements.findIndex((el) => el.type === "bold_star");
4474
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4475
+ else openElements.push({
4476
+ type: "bold_star",
4477
+ marker: "**",
4478
+ position: i
4479
+ });
4480
+ i++;
4481
+ } else if (char === "_" && nextChar === "_") {
4482
+ const existingIndex = openElements.findIndex((el) => el.type === "bold_underscore");
4483
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4484
+ else openElements.push({
4485
+ type: "bold_underscore",
4486
+ marker: "__",
4487
+ position: i
4488
+ });
4489
+ i++;
4490
+ } else if (char === "~" && nextChar === "~") {
4491
+ const existingIndex = openElements.findIndex((el) => el.type === "strike");
4492
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4493
+ else openElements.push({
4494
+ type: "strike",
4495
+ marker: "~~",
4496
+ position: i
4497
+ });
4498
+ i++;
4499
+ } else if (char === "*" && prevChar !== "*" && nextChar !== "*") {
4500
+ const existingIndex = openElements.findIndex((el) => el.type === "italic_star");
4501
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4502
+ else openElements.push({
4503
+ type: "italic_star",
4504
+ marker: "*",
4505
+ position: i
4506
+ });
4507
+ } else if (char === "_" && prevChar !== "_" && nextChar !== "_") {
4508
+ const existingIndex = openElements.findIndex((el) => el.type === "italic_underscore");
4509
+ if (existingIndex !== -1) openElements.splice(existingIndex, 1);
4510
+ else openElements.push({
4511
+ type: "italic_underscore",
4512
+ marker: "_",
4513
+ position: i
4514
+ });
4515
+ }
4516
+ }
4517
+ let backtickCount = 0;
4518
+ for (let i = 0; i < chars.length; i++) if (chars[i] === "`" && !isInCode(i)) backtickCount++;
4519
+ if (backtickCount % 2 === 1) s += "`";
4520
+ openElements.sort((a, b) => b.position - a.position);
4521
+ const closers = openElements.map((el) => {
4522
+ switch (el.type) {
4523
+ case "bracket": return "]";
4524
+ case "bold_star": return "**";
4525
+ case "bold_underscore": return "__";
4526
+ case "strike": return "~~";
4527
+ case "italic_star": return "*";
4528
+ case "italic_underscore": return "_";
4529
+ default: return "";
4530
+ }
4531
+ });
4532
+ let result = s + closers.join("");
4533
+ const finalFenceMatches = Array.from(result.matchAll(/^(\s*)(`{3,}|~{3,})/gm));
4534
+ const hasUnclosedBacktick = (result.match(/`/g) || []).length % 2 === 1;
4535
+ const hasUnclosedCodeFence = finalFenceMatches.length % 2 === 1;
4536
+ let shouldCloseParens = !hasUnclosedBacktick && !hasUnclosedCodeFence;
4537
+ if (shouldCloseParens) {
4538
+ const lastOpenParen = result.lastIndexOf("(");
4539
+ if (lastOpenParen !== -1) {
4540
+ if ((result.substring(0, lastOpenParen).match(/`/g) || []).length % 2 === 1) shouldCloseParens = false;
4541
+ }
4542
+ }
4543
+ if (shouldCloseParens) {
4544
+ const openParens = (result.match(/\(/g) || []).length;
4545
+ const closeParens = (result.match(/\)/g) || []).length;
4546
+ if (openParens > closeParens) result += ")".repeat(openParens - closeParens);
4547
+ }
4548
+ return result;
3737
4549
  }
3738
4550
 
3739
4551
  //#endregion
3740
4552
  //#region src/threads.ts
3741
4553
  const THREADS_CHANNEL_EVENT = "thread_metadata";
4554
+ const THREAD_RUN_ACTIVITY_CHANNEL_EVENT = "thread_run_activity";
3742
4555
  const THREAD_SUBSCRIBE_PATH = "/threads/subscribe";
3743
4556
  const MAX_SOCKET_RETRIES = 5;
3744
4557
  const REQUEST_TIMEOUT_MS = 15e3;
@@ -3782,7 +4595,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3782
4595
  errored: props(),
3783
4596
  joinFailed: props(),
3784
4597
  joinTimedOut: props(),
3785
- metadataReceived: props()
4598
+ metadataReceived: props(),
4599
+ runActivityReceived: props()
3786
4600
  });
3787
4601
  const threadDomainEvents = createActionGroup("Thread Domain", {
3788
4602
  threadUpserted: props(),
@@ -3802,6 +4616,29 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3802
4616
  next[existingIndex] = thread;
3803
4617
  return sortThreadsByRecency(next);
3804
4618
  }
4619
+ /**
4620
+ * Returns a non-empty string payload field or undefined for absent fields.
4621
+ */
4622
+ function optionalString(value) {
4623
+ return typeof value === "string" && value.length > 0 ? value : void 0;
4624
+ }
4625
+ /**
4626
+ * Converts gateway run-activity payloads into the internal TypeScript shape.
4627
+ */
4628
+ function normalizeThreadRunActivityNotification(payload) {
4629
+ var _payload$threadId, _payload$eventType, _payload$agentId, _payload$runId, _payload$latestEventI;
4630
+ const threadId = optionalString((_payload$threadId = payload.threadId) !== null && _payload$threadId !== void 0 ? _payload$threadId : payload.thread_id);
4631
+ const eventType = optionalString((_payload$eventType = payload.eventType) !== null && _payload$eventType !== void 0 ? _payload$eventType : payload.event_type);
4632
+ if (!threadId || !eventType) return null;
4633
+ return {
4634
+ type: "thread_run_activity",
4635
+ threadId,
4636
+ agentId: optionalString((_payload$agentId = payload.agentId) !== null && _payload$agentId !== void 0 ? _payload$agentId : payload.agent_id),
4637
+ runId: optionalString((_payload$runId = payload.runId) !== null && _payload$runId !== void 0 ? _payload$runId : payload.run_id),
4638
+ eventType,
4639
+ latestEventId: optionalString((_payload$latestEventI = payload.latestEventId) !== null && _payload$latestEventI !== void 0 ? _payload$latestEventI : payload.latest_event_id)
4640
+ };
4641
+ }
3805
4642
  const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
3806
4643
  ...state,
3807
4644
  context,
@@ -3835,12 +4672,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3835
4672
  };
3836
4673
  }), on(threadRestEvents.listSucceeded, (state, { sessionId, threads, joinCode, nextCursor }) => {
3837
4674
  if (sessionId !== state.sessionId) return state;
4675
+ const joinCodeChanged = joinCode !== state.metadataJoinCode;
3838
4676
  return {
3839
4677
  ...state,
3840
4678
  threads: sortThreadsByRecency(threads),
3841
4679
  isLoading: false,
3842
4680
  error: null,
3843
4681
  metadataJoinCode: joinCode,
4682
+ metadataCredentialsRequested: joinCodeChanged ? false : state.metadataCredentialsRequested,
3844
4683
  nextCursor
3845
4684
  };
3846
4685
  }), on(threadRestEvents.listFailed, (state, { sessionId, error }) => {
@@ -3869,7 +4708,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3869
4708
  };
3870
4709
  }), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId }) => {
3871
4710
  if (sessionId !== state.sessionId) return state;
3872
- return state;
4711
+ return {
4712
+ ...state,
4713
+ metadataCredentialsRequested: false
4714
+ };
3873
4715
  }), on(threadRestEvents.metadataCredentialsRequested, (state, { sessionId }) => {
3874
4716
  if (sessionId !== state.sessionId) return state;
3875
4717
  return {
@@ -4028,7 +4870,27 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4028
4870
  return `thread-request-${threadRequestId}`;
4029
4871
  }
4030
4872
  function threadFromFetch(input, init) {
4031
- return (0, rxjs_fetch.fromFetch)(input, init);
4873
+ return new rxjs.Observable((subscriber) => {
4874
+ const { fetch: fetchImpl, selector, signal, ...requestInit } = init;
4875
+ const controller = new AbortController();
4876
+ const abortRequest = () => controller.abort();
4877
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) abortRequest();
4878
+ else signal === null || signal === void 0 || signal.addEventListener("abort", abortRequest, { once: true });
4879
+ fetchImpl(input, {
4880
+ ...requestInit,
4881
+ signal: controller.signal
4882
+ }).then((response) => selector(response)).then((value) => {
4883
+ if (subscriber.closed) return;
4884
+ subscriber.next(value);
4885
+ subscriber.complete();
4886
+ }).catch((error) => {
4887
+ if (!subscriber.closed) subscriber.error(error);
4888
+ });
4889
+ return () => {
4890
+ signal === null || signal === void 0 || signal.removeEventListener("abort", abortRequest);
4891
+ abortRequest();
4892
+ };
4893
+ });
4032
4894
  }
4033
4895
  function createThreadFetchObservable(environment, context, sessionId) {
4034
4896
  return (0, rxjs.defer)(() => {
@@ -4179,6 +5041,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4179
5041
  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({
4180
5042
  sessionId: action.sessionId,
4181
5043
  payload
5044
+ }))), 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({
5045
+ sessionId: action.sessionId,
5046
+ notification
4182
5047
  }))), ɵ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$)));
4183
5048
  });
4184
5049
  }))),
@@ -4363,6 +5228,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4363
5228
  threadId
4364
5229
  }));
4365
5230
  },
5231
+ subscribeToRunActivity(callback) {
5232
+ 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);
5233
+ },
4366
5234
  getState() {
4367
5235
  return store.getState();
4368
5236
  },
@@ -4442,6 +5310,8 @@ exports.CopilotKitCore = CopilotKitCore;
4442
5310
  exports.CopilotKitCoreErrorCode = CopilotKitCoreErrorCode;
4443
5311
  exports.CopilotKitCoreRuntimeConnectionStatus = CopilotKitCoreRuntimeConnectionStatus;
4444
5312
  exports.IntelligenceAgent = IntelligenceAgent;
5313
+ exports.MEMORY_ERROR_REGISTRY = MEMORY_ERROR_REGISTRY;
5314
+ exports.MemoryError = MemoryError;
4445
5315
  exports.ProxiedCopilotRuntimeAgent = ProxiedCopilotRuntimeAgent;
4446
5316
  exports.RunHandler = RunHandler;
4447
5317
  exports.StateManager = StateManager;
@@ -4463,10 +5333,17 @@ exports.props = props;
4463
5333
  exports.select = select;
4464
5334
  exports.ɵCOPILOTKIT_FEATURES = ɵCOPILOTKIT_FEATURES;
4465
5335
  exports.ɵMAX_SOCKET_RETRIES = ɵMAX_SOCKET_RETRIES;
5336
+ exports.ɵcreateMemoryStore = createMemoryStore;
4466
5337
  exports.ɵcreateThreadSelectors = ɵcreateThreadSelectors;
4467
5338
  exports.ɵcreateThreadStore = createThreadStore;
4468
5339
  exports.ɵisCopilotKitFeature = ɵisCopilotKitFeature;
5340
+ exports.ɵisRetryableMemoryStatus = isRetryableStatus;
4469
5341
  exports.ɵjoinPhoenixChannel$ = ɵjoinPhoenixChannel$;
5342
+ exports.ɵmapMemoryMetadataEvent = ɵmapMemoryMetadataEvent;
5343
+ exports.ɵmemoryAdapterEvents = ɵmemoryAdapterEvents;
5344
+ exports.ɵmemoryDomainEvents = ɵmemoryDomainEvents;
5345
+ exports.ɵmemoryReducer = ɵmemoryReducer;
5346
+ exports.ɵmemoryRestEvents = ɵmemoryRestEvents;
4470
5347
  exports.ɵobservePhoenixEvent$ = ɵobservePhoenixEvent$;
4471
5348
  exports.ɵobservePhoenixJoinOutcome$ = ɵobservePhoenixJoinOutcome$;
4472
5349
  exports.ɵobservePhoenixSocketHealth$ = ɵobservePhoenixSocketHealth$;
@@ -4476,6 +5353,12 @@ exports.ɵphoenixSocket$ = ɵphoenixSocket$;
4476
5353
  exports.ɵselectHasNextPage = ɵselectHasNextPage;
4477
5354
  exports.ɵselectIsFetchingNextPage = ɵselectIsFetchingNextPage;
4478
5355
  exports.ɵselectIsMutating = ɵselectIsMutating;
5356
+ exports.ɵselectMemories = ɵselectMemories;
5357
+ exports.ɵselectMemoriesAvailable = ɵselectMemoriesAvailable;
5358
+ exports.ɵselectMemoriesError = ɵselectMemoriesError;
5359
+ exports.ɵselectMemoriesIsLoading = ɵselectMemoriesIsLoading;
5360
+ exports.ɵselectMemoriesIsMutating = ɵselectMemoriesIsMutating;
5361
+ exports.ɵselectMemoriesRealtimeStatus = ɵselectMemoriesRealtimeStatus;
4479
5362
  exports.ɵselectThreads = ɵselectThreads;
4480
5363
  exports.ɵselectThreadsError = ɵselectThreadsError;
4481
5364
  exports.ɵselectThreadsIsLoading = ɵselectThreadsIsLoading;