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