@copilotkit/core 1.62.1 → 1.62.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6,7 +6,6 @@ let rxjs = require("rxjs");
6
6
  let rxjs_operators = require("rxjs/operators");
7
7
  let phoenix = require("phoenix");
8
8
  let zod_to_json_schema = require("zod-to-json-schema");
9
- let rxjs_fetch = require("rxjs/fetch");
10
9
 
11
10
  //#region src/utils/phoenix-observable.ts
12
11
  /**
@@ -131,6 +130,7 @@ const CLIENT_AG_UI_EVENT = "ag_ui_event";
131
130
  const REPLAY_COMPLETE_EVENT = "replay_complete";
132
131
  const STREAM_IDLE_EVENT = "stream_idle";
133
132
  const STOP_RUN_EVENT = "stop_run";
133
+ const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
134
134
  var AgentThreadLockedError = class extends Error {
135
135
  constructor(threadId) {
136
136
  super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
@@ -280,12 +280,14 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
280
280
  connect(input) {
281
281
  this.threadId = input.threadId;
282
282
  this.canonicalRunId = null;
283
- return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input)).pipe((0, rxjs.switchMap)((credentials) => {
283
+ const replayCursor = this.getReconnectCursor(input);
284
+ return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input, replayCursor)).pipe((0, rxjs.switchMap)((credentials) => {
284
285
  if (credentials === null) return rxjs.EMPTY;
285
286
  const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: false });
286
287
  return this.observeThread$(canonicalInput, credentials, {
287
288
  completeOnRunError: false,
288
- streamMode: "connect"
289
+ streamMode: "connect",
290
+ replayCursor
289
291
  });
290
292
  }));
291
293
  }
@@ -308,7 +310,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
308
310
  cleanup() {
309
311
  this.cleanupOwned(this.activeChannel, this.socket);
310
312
  }
311
- requestJoinCredentials$(mode, input) {
313
+ requestJoinCredentials$(mode, input, replayCursor) {
312
314
  return (0, rxjs.defer)(async () => {
313
315
  try {
314
316
  const response = await fetch(this.buildRuntimeUrl(mode), {
@@ -325,7 +327,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
325
327
  context: input.context,
326
328
  state: input.state,
327
329
  forwardedProps: input.forwardedProps,
328
- ...mode === "connect" ? { lastSeenEventId: this.getReconnectCursor(input) } : {}
330
+ ...mode === "connect" ? { lastSeenEventId: replayCursor === void 0 ? this.getReconnectCursor(input) : replayCursor } : {}
329
331
  }),
330
332
  ...this.config.credentials ? { credentials: this.config.credentials } : {}
331
333
  });
@@ -361,10 +363,11 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
361
363
  observeThread$(input, credentials, options) {
362
364
  return this.observeThreadSession$(input, credentials, options).pipe((0, rxjs_operators.catchError)((error) => {
363
365
  if (!this.isSocketReconnectExhaustedError(error)) return (0, rxjs.throwError)(() => error);
364
- return this.requestJoinCredentials$("connect", input).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
366
+ const replayCursor = this.getReconnectCursor(input);
367
+ return this.requestJoinCredentials$("connect", input, replayCursor).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
365
368
  ...options,
366
369
  channelMode: "connect",
367
- replayCursor: this.getReconnectCursor(input)
370
+ replayCursor
368
371
  })));
369
372
  }));
370
373
  }
@@ -401,15 +404,23 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
401
404
  bufferSize: 1,
402
405
  refCount: true
403
406
  }));
404
- const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.share)());
405
- const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.share)());
407
+ const reconnectCursor = this.readDurableEventId(options.replayCursor ?? this.getReconnectCursor(input));
408
+ let latestObservedReplayCursor = null;
409
+ const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.tap)((payload) => {
410
+ latestObservedReplayCursor = this.readEventId(payload) ?? latestObservedReplayCursor;
411
+ }), (0, rxjs_operators.share)());
412
+ const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.shareReplay)({
413
+ bufferSize: 1,
414
+ refCount: true
415
+ }));
406
416
  const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT).pipe((0, rxjs_operators.shareReplay)({
407
417
  bufferSize: 1,
408
418
  refCount: true
409
419
  }));
410
- const streamIdleCompletion$ = options.streamMode === "connect" ? streamIdle$.pipe((0, rxjs_operators.take)(1)) : rxjs.EMPTY;
411
- const terminal$ = (0, rxjs.merge)(threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1)), streamIdleCompletion$);
412
- return (0, rxjs.merge)(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$).pipe((0, rxjs_operators.takeUntil)(terminal$)), threadEvents$.pipe((0, rxjs_operators.takeUntil)(streamIdleCompletion$)), replayComplete$.pipe((0, rxjs_operators.takeUntil)(terminal$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)())).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
420
+ 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;
421
+ const threadCompleted$ = threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1));
422
+ const terminal$ = (0, rxjs.merge)(threadCompleted$, streamIdleCompletion$);
423
+ return (0, rxjs.merge)(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$).pipe((0, rxjs_operators.takeUntil)(terminal$)), threadEvents$.pipe((0, rxjs_operators.takeUntil)(streamIdleCompletion$)), replayComplete$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(terminal$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(threadCompleted$))).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
413
424
  });
414
425
  }
415
426
  joinThreadChannel$(channel$) {
@@ -475,23 +486,36 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
475
486
  updateLastSeenEventId(threadId, payload) {
476
487
  const eventId = this.readEventId(payload);
477
488
  if (!eventId) return;
478
- this.sharedState.lastSeenEventIds.set(threadId, eventId);
489
+ this.advanceLastSeenEventId(threadId, eventId);
479
490
  }
480
491
  updateLastSeenEventIdFromControl(threadId, payload) {
481
492
  const eventId = this.readControlEventId(payload);
482
493
  if (!eventId) return;
494
+ this.advanceLastSeenEventId(threadId, eventId);
495
+ }
496
+ advanceLastSeenEventId(threadId, eventId) {
483
497
  this.sharedState.lastSeenEventIds.set(threadId, eventId);
484
498
  }
485
499
  readEventId(payload) {
486
500
  const metadata = payload.metadata;
487
501
  if (!metadata || typeof metadata !== "object") return null;
488
- const runnerEventId = metadata.cpki_event_id;
489
- return typeof runnerEventId === "string" ? runnerEventId : null;
502
+ const eventMetadata = metadata;
503
+ return this.readDurableEventId(eventMetadata.cpki_event_id);
490
504
  }
491
505
  readControlEventId(payload) {
492
506
  if (!payload || typeof payload !== "object") return null;
493
- const latestEventId = payload.latestEventId;
494
- return typeof latestEventId === "string" ? latestEventId : null;
507
+ const controlPayload = payload;
508
+ const latestEventId = controlPayload.latestEventId ?? controlPayload.latest_event_id;
509
+ return this.readDurableEventId(latestEventId);
510
+ }
511
+ readDurableEventId(eventId) {
512
+ if (typeof eventId !== "string" || eventId.trim() === "") return null;
513
+ return eventId.startsWith("cpki_ingested") ? null : eventId;
514
+ }
515
+ canFallbackCompleteConnect(streamIdlePayload, reconnectCursor, latestObservedReplayCursor) {
516
+ const idleCursor = this.readControlEventId(streamIdlePayload);
517
+ if (!idleCursor) return true;
518
+ return idleCursor === reconnectCursor || idleCursor === latestObservedReplayCursor;
495
519
  }
496
520
  applyCanonicalRunIdentity(input, credentials, options) {
497
521
  this.threadId = credentials.threadId;
@@ -1660,7 +1684,9 @@ var RunHandler = class {
1660
1684
  * downstream churn into duplicate `cpki_event_id` rows in the
1661
1685
  * inspector and intermittent "Message not found" toasts.
1662
1686
  */
1663
- _lastConnectedThreadId = null;
1687
+ _lastConnectedThreadIdsByAgent = /* @__PURE__ */ new Map();
1688
+ _anonymousAgentIds = /* @__PURE__ */ new WeakMap();
1689
+ _nextAnonymousAgentId = 0;
1664
1690
  constructor(core) {
1665
1691
  this.core = core;
1666
1692
  }
@@ -1680,6 +1706,20 @@ var RunHandler = class {
1680
1706
  return this.core;
1681
1707
  }
1682
1708
  /**
1709
+ * Return a stable restore-tracking key for the logical agent being
1710
+ * connected. Named agents share their last-thread marker across proxy
1711
+ * instances; anonymous agents fall back to object identity.
1712
+ */
1713
+ getConnectRestoreKey(agent) {
1714
+ if (agent.agentId) return `agent:${agent.agentId}`;
1715
+ const existing = this._anonymousAgentIds.get(agent);
1716
+ if (existing) return existing;
1717
+ const anonymousId = `anonymous:${this._nextAnonymousAgentId}`;
1718
+ this._nextAnonymousAgentId += 1;
1719
+ this._anonymousAgentIds.set(agent, anonymousId);
1720
+ return anonymousId;
1721
+ }
1722
+ /**
1683
1723
  * Get all tools as a readonly array
1684
1724
  */
1685
1725
  get tools() {
@@ -1735,14 +1775,18 @@ var RunHandler = class {
1735
1775
  async connectAgent({ agent }) {
1736
1776
  try {
1737
1777
  const incomingThreadId = agent.threadId ?? null;
1738
- const isFreshRestore = incomingThreadId !== this._lastConnectedThreadId;
1739
- this._lastConnectedThreadId = incomingThreadId;
1778
+ const restoreKey = this.getConnectRestoreKey(agent);
1779
+ const isFreshRestore = incomingThreadId !== (this._lastConnectedThreadIdsByAgent.get(restoreKey) ?? null);
1780
+ this._lastConnectedThreadIdsByAgent.set(restoreKey, incomingThreadId);
1740
1781
  await agent.detachActiveRun();
1741
1782
  if (isFreshRestore) {
1742
1783
  agent.setMessages([]);
1743
1784
  agent.setState({});
1744
- const proxied = agent;
1745
- if (incomingThreadId && typeof proxied.clearReplayCursor === "function") proxied.clearReplayCursor(incomingThreadId);
1785
+ const cursorAware = agent;
1786
+ if (incomingThreadId) {
1787
+ if (typeof cursorAware.clearReplayCursor === "function") cursorAware.clearReplayCursor(incomingThreadId);
1788
+ if (typeof cursorAware.clearReconnectCursor === "function") cursorAware.clearReconnectCursor(incomingThreadId);
1789
+ }
1746
1790
  }
1747
1791
  this._internal.applyHeadersToAgent(agent);
1748
1792
  await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
@@ -1756,7 +1800,8 @@ var RunHandler = class {
1756
1800
  }, this.createAgentErrorSubscriber(agent));
1757
1801
  return this.processAgentResult({
1758
1802
  runAgentResult,
1759
- agent
1803
+ agent,
1804
+ executeFrontendTools: false
1760
1805
  });
1761
1806
  } catch (error) {
1762
1807
  const connectError = error instanceof Error ? error : new Error(String(error));
@@ -1778,7 +1823,7 @@ var RunHandler = class {
1778
1823
  /**
1779
1824
  * Run an agent
1780
1825
  */
1781
- async runAgent({ agent, forwardedProps, resume }) {
1826
+ async runAgent({ agent, forwardedProps, resume, runId }) {
1782
1827
  if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
1783
1828
  this._internal.applyHeadersToAgent(agent);
1784
1829
  if (agent.detachActiveRun) await agent.detachActiveRun();
@@ -1805,6 +1850,7 @@ var RunHandler = class {
1805
1850
  ...forwardedProps
1806
1851
  },
1807
1852
  ...resume !== void 0 ? { resume } : {},
1853
+ ...runId !== void 0 ? { runId } : {},
1808
1854
  tools: this.buildFrontendTools(agent.agentId),
1809
1855
  context: this._internal.getContextForAgent(agent.agentId)
1810
1856
  }, this.createAgentErrorSubscriber(agent));
@@ -1833,25 +1879,27 @@ var RunHandler = class {
1833
1879
  /**
1834
1880
  * Process agent result and execute tools
1835
1881
  */
1836
- async processAgentResult({ runAgentResult, agent }) {
1882
+ async processAgentResult({ runAgentResult, agent, executeFrontendTools = true }) {
1837
1883
  const { newMessages } = runAgentResult;
1838
1884
  const agentId = agent.agentId;
1839
1885
  let needsFollowUp = false;
1840
- for (const message of newMessages) if (message.role === "assistant") {
1841
- for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
1842
- const tool = this.getTool({
1843
- toolName: toolCall.function.name,
1844
- agentId: agent.agentId
1845
- });
1846
- if (tool) {
1847
- if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
1848
- } else {
1849
- const wildcardTool = this.getTool({
1850
- toolName: "*",
1886
+ if (executeFrontendTools) {
1887
+ for (const message of newMessages) if (message.role === "assistant") {
1888
+ for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
1889
+ const tool = this.getTool({
1890
+ toolName: toolCall.function.name,
1851
1891
  agentId: agent.agentId
1852
1892
  });
1853
- if (wildcardTool) {
1854
- if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
1893
+ if (tool) {
1894
+ if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
1895
+ } else {
1896
+ const wildcardTool = this.getTool({
1897
+ toolName: "*",
1898
+ agentId: agent.agentId
1899
+ });
1900
+ if (wildcardTool) {
1901
+ if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
1902
+ }
1855
1903
  }
1856
1904
  }
1857
1905
  }
@@ -3585,6 +3633,7 @@ function createStore(options) {
3585
3633
  //#endregion
3586
3634
  //#region src/threads.ts
3587
3635
  const THREADS_CHANNEL_EVENT = "thread_metadata";
3636
+ const THREAD_RUN_ACTIVITY_CHANNEL_EVENT = "thread_run_activity";
3588
3637
  const THREAD_SUBSCRIBE_PATH = "/threads/subscribe";
3589
3638
  const MAX_SOCKET_RETRIES = 5;
3590
3639
  const REQUEST_TIMEOUT_MS = 15e3;
@@ -3628,7 +3677,8 @@ const threadSocketEvents = createActionGroup("Thread Socket", {
3628
3677
  errored: props(),
3629
3678
  joinFailed: props(),
3630
3679
  joinTimedOut: props(),
3631
- metadataReceived: props()
3680
+ metadataReceived: props(),
3681
+ runActivityReceived: props()
3632
3682
  });
3633
3683
  const threadDomainEvents = createActionGroup("Thread Domain", {
3634
3684
  threadUpserted: props(),
@@ -3647,6 +3697,28 @@ function upsertThread(threads, thread) {
3647
3697
  next[existingIndex] = thread;
3648
3698
  return sortThreadsByRecency(next);
3649
3699
  }
3700
+ /**
3701
+ * Returns a non-empty string payload field or undefined for absent fields.
3702
+ */
3703
+ function optionalString(value) {
3704
+ return typeof value === "string" && value.length > 0 ? value : void 0;
3705
+ }
3706
+ /**
3707
+ * Converts gateway run-activity payloads into the internal TypeScript shape.
3708
+ */
3709
+ function normalizeThreadRunActivityNotification(payload) {
3710
+ const threadId = optionalString(payload.threadId ?? payload.thread_id);
3711
+ const eventType = optionalString(payload.eventType ?? payload.event_type);
3712
+ if (!threadId || !eventType) return null;
3713
+ return {
3714
+ type: "thread_run_activity",
3715
+ threadId,
3716
+ agentId: optionalString(payload.agentId ?? payload.agent_id),
3717
+ runId: optionalString(payload.runId ?? payload.run_id),
3718
+ eventType,
3719
+ latestEventId: optionalString(payload.latestEventId ?? payload.latest_event_id)
3720
+ };
3721
+ }
3650
3722
  const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
3651
3723
  ...state,
3652
3724
  context,
@@ -3680,12 +3752,14 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3680
3752
  };
3681
3753
  }), on(threadRestEvents.listSucceeded, (state, { sessionId, threads, joinCode, nextCursor }) => {
3682
3754
  if (sessionId !== state.sessionId) return state;
3755
+ const joinCodeChanged = joinCode !== state.metadataJoinCode;
3683
3756
  return {
3684
3757
  ...state,
3685
3758
  threads: sortThreadsByRecency(threads),
3686
3759
  isLoading: false,
3687
3760
  error: null,
3688
3761
  metadataJoinCode: joinCode,
3762
+ metadataCredentialsRequested: joinCodeChanged ? false : state.metadataCredentialsRequested,
3689
3763
  nextCursor
3690
3764
  };
3691
3765
  }), on(threadRestEvents.listFailed, (state, { sessionId, error }) => {
@@ -3714,7 +3788,10 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3714
3788
  };
3715
3789
  }), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId }) => {
3716
3790
  if (sessionId !== state.sessionId) return state;
3717
- return state;
3791
+ return {
3792
+ ...state,
3793
+ metadataCredentialsRequested: false
3794
+ };
3718
3795
  }), on(threadRestEvents.metadataCredentialsRequested, (state, { sessionId }) => {
3719
3796
  if (sessionId !== state.sessionId) return state;
3720
3797
  return {
@@ -3872,7 +3949,27 @@ function createThreadRequestId() {
3872
3949
  return `thread-request-${threadRequestId}`;
3873
3950
  }
3874
3951
  function threadFromFetch(input, init) {
3875
- return (0, rxjs_fetch.fromFetch)(input, init);
3952
+ return new rxjs.Observable((subscriber) => {
3953
+ const { fetch: fetchImpl, selector, signal, ...requestInit } = init;
3954
+ const controller = new AbortController();
3955
+ const abortRequest = () => controller.abort();
3956
+ if (signal?.aborted) abortRequest();
3957
+ else signal?.addEventListener("abort", abortRequest, { once: true });
3958
+ fetchImpl(input, {
3959
+ ...requestInit,
3960
+ signal: controller.signal
3961
+ }).then((response) => selector(response)).then((value) => {
3962
+ if (subscriber.closed) return;
3963
+ subscriber.next(value);
3964
+ subscriber.complete();
3965
+ }).catch((error) => {
3966
+ if (!subscriber.closed) subscriber.error(error);
3967
+ });
3968
+ return () => {
3969
+ signal?.removeEventListener("abort", abortRequest);
3970
+ abortRequest();
3971
+ };
3972
+ });
3876
3973
  }
3877
3974
  function createThreadFetchObservable(environment, context, sessionId) {
3878
3975
  return (0, rxjs.defer)(() => {
@@ -4018,6 +4115,9 @@ function createThreadStore(environment) {
4018
4115
  return (0, rxjs.merge)(socketSignals$.pipe((0, rxjs_operators.map)((signal) => signal.type === "open" ? threadSocketEvents.opened({ sessionId: action.sessionId }) : threadSocketEvents.errored({ sessionId: action.sessionId }))), channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => ɵobservePhoenixEvent$(channel, THREADS_CHANNEL_EVENT)), (0, rxjs_operators.map)((payload) => threadSocketEvents.metadataReceived({
4019
4116
  sessionId: action.sessionId,
4020
4117
  payload
4118
+ }))), 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({
4119
+ sessionId: action.sessionId,
4120
+ notification
4021
4121
  }))), ɵobservePhoenixJoinOutcome$(channel$).pipe((0, rxjs_operators.filter)((outcome) => outcome.type !== "joined"), (0, rxjs_operators.map)((outcome) => outcome.type === "timeout" ? threadSocketEvents.joinTimedOut({ sessionId: action.sessionId }) : threadSocketEvents.joinFailed({ sessionId: action.sessionId })))).pipe((0, rxjs_operators.takeUntil)((0, rxjs.merge)(shutdown$, fatalSocketShutdown$)));
4022
4122
  });
4023
4123
  }))),
@@ -4195,6 +4295,9 @@ function createThreadStore(environment) {
4195
4295
  threadId
4196
4296
  }));
4197
4297
  },
4298
+ subscribeToRunActivity(callback) {
4299
+ 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);
4300
+ },
4198
4301
  getState() {
4199
4302
  return store.getState();
4200
4303
  },