@copilotkit/core 1.61.2 → 1.62.1

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
@@ -1744,6 +1744,10 @@ var RunHandler = class {
1744
1744
  if (incomingThreadId && typeof proxied.clearReplayCursor === "function") proxied.clearReplayCursor(incomingThreadId);
1745
1745
  }
1746
1746
  this._internal.applyHeadersToAgent(agent);
1747
+ await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
1748
+ copilotkit: this.core,
1749
+ agent
1750
+ }), "Subscriber onAgentRunStarted error:");
1747
1751
  const runAgentResult = await agent.connectAgent({
1748
1752
  forwardedProps: this._internal.properties,
1749
1753
  tools: this.buildFrontendTools(agent.agentId),
@@ -1787,6 +1791,10 @@ var RunHandler = class {
1787
1791
  controller.abort();
1788
1792
  originalAbortRun();
1789
1793
  };
1794
+ await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
1795
+ copilotkit: this.core,
1796
+ agent
1797
+ }), "Subscriber onAgentRunStarted error:");
1790
1798
  }
1791
1799
  this._runDepth++;
1792
1800
  try {
@@ -3588,7 +3596,9 @@ const initialThreadState = {
3588
3596
  sessionId: 0,
3589
3597
  metadataCredentialsRequested: false,
3590
3598
  metadataJoinCode: null,
3591
- nextCursor: null
3599
+ nextCursor: null,
3600
+ inFlightMutationCount: 0,
3601
+ pendingDeletes: {}
3592
3602
  };
3593
3603
  const threadAdapterEvents = createActionGroup("Thread Adapter", {
3594
3604
  started: empty(),
@@ -3598,7 +3608,8 @@ const threadAdapterEvents = createActionGroup("Thread Adapter", {
3598
3608
  renameRequested: props(),
3599
3609
  archiveRequested: props(),
3600
3610
  unarchiveRequested: props(),
3601
- deleteRequested: props()
3611
+ deleteRequested: props(),
3612
+ newThreadStarted: empty()
3602
3613
  });
3603
3614
  const threadRestEvents = createActionGroup("Thread REST", {
3604
3615
  listRequested: props(),
@@ -3645,7 +3656,9 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3645
3656
  error: null,
3646
3657
  metadataCredentialsRequested: false,
3647
3658
  metadataJoinCode: null,
3648
- nextCursor: null
3659
+ nextCursor: null,
3660
+ inFlightMutationCount: 0,
3661
+ pendingDeletes: {}
3649
3662
  })), on(threadAdapterEvents.stopped, (state) => ({
3650
3663
  ...state,
3651
3664
  threads: [],
@@ -3654,7 +3667,9 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3654
3667
  error: null,
3655
3668
  metadataCredentialsRequested: false,
3656
3669
  metadataJoinCode: null,
3657
- nextCursor: null
3670
+ nextCursor: null,
3671
+ inFlightMutationCount: 0,
3672
+ pendingDeletes: {}
3658
3673
  })), on(threadRestEvents.listRequested, (state, { sessionId }) => {
3659
3674
  if (sessionId !== state.sessionId || !state.context) return state;
3660
3675
  return {
@@ -3696,12 +3711,9 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3696
3711
  isFetchingNextPage: false,
3697
3712
  error
3698
3713
  };
3699
- }), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId, error }) => {
3714
+ }), on(threadRestEvents.metadataCredentialsFailed, (state, { sessionId }) => {
3700
3715
  if (sessionId !== state.sessionId) return state;
3701
- return {
3702
- ...state,
3703
- error
3704
- };
3716
+ return state;
3705
3717
  }), on(threadRestEvents.metadataCredentialsRequested, (state, { sessionId }) => {
3706
3718
  if (sessionId !== state.sessionId) return state;
3707
3719
  return {
@@ -3714,10 +3726,105 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3714
3726
  ...state,
3715
3727
  isFetchingNextPage: true
3716
3728
  };
3717
- }), on(threadRestEvents.mutationFinished, (state, { outcome }) => ({
3729
+ }), on(threadAdapterEvents.renameRequested, (state, { threadId, name }) => {
3730
+ const existing = state.threads.find((thread) => thread.id === threadId);
3731
+ const inFlightMutationCount = state.inFlightMutationCount + 1;
3732
+ if (!existing) return {
3733
+ ...state,
3734
+ inFlightMutationCount
3735
+ };
3736
+ return {
3737
+ ...state,
3738
+ threads: upsertThread(state.threads, {
3739
+ ...existing,
3740
+ name
3741
+ }),
3742
+ inFlightMutationCount
3743
+ };
3744
+ }), on(threadAdapterEvents.archiveRequested, (state, { threadId }) => {
3745
+ const existing = state.threads.find((thread) => thread.id === threadId);
3746
+ const inFlightMutationCount = state.inFlightMutationCount + 1;
3747
+ if (!existing) return {
3748
+ ...state,
3749
+ inFlightMutationCount
3750
+ };
3751
+ if (!state.context?.includeArchived) return {
3752
+ ...state,
3753
+ threads: state.threads.filter((thread) => thread.id !== threadId),
3754
+ inFlightMutationCount
3755
+ };
3756
+ return {
3757
+ ...state,
3758
+ threads: upsertThread(state.threads, {
3759
+ ...existing,
3760
+ archived: true
3761
+ }),
3762
+ inFlightMutationCount
3763
+ };
3764
+ }), on(threadAdapterEvents.unarchiveRequested, (state, { threadId }) => {
3765
+ const existing = state.threads.find((thread) => thread.id === threadId);
3766
+ const inFlightMutationCount = state.inFlightMutationCount + 1;
3767
+ if (!existing) return {
3768
+ ...state,
3769
+ inFlightMutationCount
3770
+ };
3771
+ return {
3772
+ ...state,
3773
+ threads: upsertThread(state.threads, {
3774
+ ...existing,
3775
+ archived: false
3776
+ }),
3777
+ inFlightMutationCount
3778
+ };
3779
+ }), on(threadAdapterEvents.deleteRequested, (state, { requestId, threadId }) => {
3780
+ const existing = state.threads.find((thread) => thread.id === threadId);
3781
+ const inFlightMutationCount = state.inFlightMutationCount + 1;
3782
+ if (!existing) return {
3783
+ ...state,
3784
+ inFlightMutationCount
3785
+ };
3786
+ return {
3787
+ ...state,
3788
+ threads: state.threads.filter((thread) => thread.id !== threadId),
3789
+ pendingDeletes: {
3790
+ ...state.pendingDeletes,
3791
+ [requestId]: existing
3792
+ },
3793
+ inFlightMutationCount
3794
+ };
3795
+ }), on(threadAdapterEvents.newThreadStarted, (state) => ({
3718
3796
  ...state,
3719
- error: outcome.ok ? state.error : outcome.error
3720
- })), on(threadDomainEvents.threadUpserted, (state, { sessionId, thread }) => {
3797
+ error: null
3798
+ })), on(threadRestEvents.mutationFinished, (state, { outcome }) => {
3799
+ if (outcome.sessionId !== state.sessionId) return state;
3800
+ const inFlightMutationCount = Math.max(0, state.inFlightMutationCount - 1);
3801
+ if (outcome.ok) {
3802
+ if (state.pendingDeletes[outcome.requestId] === void 0) return {
3803
+ ...state,
3804
+ inFlightMutationCount
3805
+ };
3806
+ const { [outcome.requestId]: _settled, ...rest } = state.pendingDeletes;
3807
+ return {
3808
+ ...state,
3809
+ inFlightMutationCount,
3810
+ pendingDeletes: rest
3811
+ };
3812
+ }
3813
+ const rolledBack = state.pendingDeletes[outcome.requestId];
3814
+ if (rolledBack === void 0) return {
3815
+ ...state,
3816
+ inFlightMutationCount,
3817
+ error: outcome.error
3818
+ };
3819
+ const { [outcome.requestId]: _restored, ...rest } = state.pendingDeletes;
3820
+ return {
3821
+ ...state,
3822
+ threads: upsertThread(state.threads, rolledBack),
3823
+ pendingDeletes: rest,
3824
+ inFlightMutationCount,
3825
+ error: outcome.error
3826
+ };
3827
+ }), on(threadDomainEvents.threadUpserted, (state, { sessionId, thread }) => {
3721
3828
  if (sessionId !== state.sessionId) return state;
3722
3829
  return {
3723
3830
  ...state,
@@ -3730,11 +3837,34 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3730
3837
  threads: state.threads.filter((thread) => thread.id !== threadId)
3731
3838
  };
3732
3839
  }));
3733
- const selectThreads = createSelector((state) => state.threads);
3734
- const selectThreadsIsLoading = createSelector((state) => state.isLoading);
3735
- const selectThreadsError = createSelector((state) => state.error);
3736
- const selectHasNextPage = createSelector((state) => state.nextCursor != null);
3737
- const selectIsFetchingNextPage = createSelector((state) => state.isFetchingNextPage);
3840
+ /**
3841
+ * Builds a fresh set of memoized thread selectors.
3842
+ *
3843
+ * Each `createSelector` closure owns a private one-entry cache. Sharing a
3844
+ * single module-level selector instance across multiple concurrent stores
3845
+ * (e.g. a `<CopilotThreadsDrawer>` plus an independent `useThreads`) makes every
3846
+ * cross-store emission a cache miss, defeating memoization and risking
3847
+ * emission instability for any future selector that allocates a new
3848
+ * object/array. Creating a per-store instance keeps each store's cache
3849
+ * isolated so concurrent stores never thrash one another.
3850
+ */
3851
+ function createThreadSelectors() {
3852
+ return {
3853
+ threads: createSelector((state) => state.threads),
3854
+ isLoading: createSelector((state) => state.isLoading),
3855
+ error: createSelector((state) => state.error),
3856
+ hasNextPage: createSelector((state) => state.nextCursor != null),
3857
+ isFetchingNextPage: createSelector((state) => state.isFetchingNextPage),
3858
+ isMutating: createSelector((state) => state.inFlightMutationCount > 0)
3859
+ };
3860
+ }
3861
+ const standaloneSelectors = createThreadSelectors();
3862
+ const selectThreads = standaloneSelectors.threads;
3863
+ const selectThreadsIsLoading = standaloneSelectors.isLoading;
3864
+ const selectThreadsError = standaloneSelectors.error;
3865
+ const selectHasNextPage = standaloneSelectors.hasNextPage;
3866
+ const selectIsFetchingNextPage = standaloneSelectors.isFetchingNextPage;
3867
+ const selectIsMutating = standaloneSelectors.isMutating;
3738
3868
  let threadRequestId = 0;
3739
3869
  function createThreadRequestId() {
3740
3870
  threadRequestId += 1;
@@ -3824,10 +3954,12 @@ function createThreadMutationObservable(environment, context, request) {
3824
3954
  body: JSON.stringify(request.body)
3825
3955
  }).pipe(map(() => threadRestEvents.mutationFinished({ outcome: {
3826
3956
  requestId: request.requestId,
3957
+ sessionId: request.sessionId,
3827
3958
  ok: true
3828
3959
  } })), catchError((error) => {
3829
3960
  return of(threadRestEvents.mutationFinished({ outcome: {
3830
3961
  requestId: request.requestId,
3962
+ sessionId: request.sessionId,
3831
3963
  ok: false,
3832
3964
  error: error instanceof Error ? error : new Error(String(error))
3833
3965
  } }));
@@ -3835,6 +3967,7 @@ function createThreadMutationObservable(environment, context, request) {
3835
3967
  });
3836
3968
  }
3837
3969
  function createThreadStore(environment) {
3970
+ const selectors = createThreadSelectors();
3838
3971
  const store = createStore({
3839
3972
  reducer: threadReducer,
3840
3973
  effects: [
@@ -3901,6 +4034,10 @@ function createThreadStore(environment) {
3901
4034
  thread: action.payload.thread
3902
4035
  });
3903
4036
  }))),
4037
+ createEffect((actions$, state$) => actions$.pipe(ofType(threadSocketEvents.joinFailed, threadSocketEvents.joinTimedOut, threadSocketEvents.errored, threadRestEvents.metadataCredentialsFailed), withLatestFrom(state$), filter(([action, state]) => action.sessionId === state.sessionId), tap(([action]) => {
4038
+ const reason = threadSocketEvents.joinTimedOut.match(action) ? "channel join timed out" : threadSocketEvents.joinFailed.match(action) ? "channel join was rejected" : threadRestEvents.metadataCredentialsFailed.match(action) ? "metadata credentials fetch failed" : "socket errored";
4039
+ console.warn(`[threads] realtime ${reason}; the thread list may be stale until reconnect`);
4040
+ })), { dispatch: false }),
3904
4041
  createEffect((actions$, state$) => actions$.pipe(ofType(threadAdapterEvents.fetchNextPageRequested), withLatestFrom(state$), filter(([, state]) => Boolean(state.context) && Boolean(state.nextCursor)), switchMap$1(([, state]) => {
3905
4042
  const context = state.context;
3906
4043
  const params = {
@@ -3932,11 +4069,13 @@ function createThreadStore(environment) {
3932
4069
  }))), takeUntil(actions$.pipe(ofType(threadAdapterEvents.contextChanged, threadAdapterEvents.stopped))));
3933
4070
  }))),
3934
4071
  createEffect((actions$, state$) => actions$.pipe(ofType(threadAdapterEvents.renameRequested, threadAdapterEvents.archiveRequested, threadAdapterEvents.unarchiveRequested, threadAdapterEvents.deleteRequested), withLatestFrom(state$), mergeMap(([action, state]) => {
4072
+ const sessionId = state.sessionId;
3935
4073
  const context = state.context;
3936
4074
  if (!context?.runtimeUrl) {
3937
4075
  const requestId = action.requestId;
3938
4076
  return of(threadRestEvents.mutationFinished({ outcome: {
3939
4077
  requestId,
4078
+ sessionId,
3940
4079
  ok: false,
3941
4080
  error: /* @__PURE__ */ new Error("Runtime URL is not configured")
3942
4081
  } }));
@@ -3944,6 +4083,7 @@ function createThreadStore(environment) {
3944
4083
  const commonBody = { agentId: context.agentId };
3945
4084
  if (threadAdapterEvents.renameRequested.match(action)) return createThreadMutationObservable(environment, context, {
3946
4085
  requestId: action.requestId,
4086
+ sessionId,
3947
4087
  method: "PATCH",
3948
4088
  path: `/threads/${encodeURIComponent(action.threadId)}`,
3949
4089
  body: {
@@ -3953,12 +4093,14 @@ function createThreadStore(environment) {
3953
4093
  });
3954
4094
  if (threadAdapterEvents.archiveRequested.match(action)) return createThreadMutationObservable(environment, context, {
3955
4095
  requestId: action.requestId,
4096
+ sessionId,
3956
4097
  method: "POST",
3957
4098
  path: `/threads/${encodeURIComponent(action.threadId)}/archive`,
3958
4099
  body: commonBody
3959
4100
  });
3960
4101
  if (threadAdapterEvents.unarchiveRequested.match(action)) return createThreadMutationObservable(environment, context, {
3961
4102
  requestId: action.requestId,
4103
+ sessionId,
3962
4104
  method: "PATCH",
3963
4105
  path: `/threads/${encodeURIComponent(action.threadId)}`,
3964
4106
  body: {
@@ -3968,6 +4110,7 @@ function createThreadStore(environment) {
3968
4110
  });
3969
4111
  return createThreadMutationObservable(environment, context, {
3970
4112
  requestId: action.requestId,
4113
+ sessionId,
3971
4114
  method: "DELETE",
3972
4115
  path: `/threads/${encodeURIComponent(action.threadId)}`,
3973
4116
  body: commonBody
@@ -3978,6 +4121,7 @@ function createThreadStore(environment) {
3978
4121
  function trackMutation(dispatchAction) {
3979
4122
  const resultPromise = firstValueFrom(merge(store.actions$.pipe(ofType(threadRestEvents.mutationFinished), filter((action) => action.outcome.requestId === dispatchAction.requestId), map((action) => action.outcome)), store.actions$.pipe(ofType(threadAdapterEvents.stopped), map(() => ({
3980
4123
  requestId: dispatchAction.requestId,
4124
+ sessionId: store.getState().sessionId,
3981
4125
  ok: false,
3982
4126
  error: /* @__PURE__ */ new Error("Thread store stopped before mutation completed")
3983
4127
  })))).pipe(take(1))).then((outcome) => {
@@ -3987,13 +4131,23 @@ function createThreadStore(environment) {
3987
4131
  store.dispatch(dispatchAction);
3988
4132
  return resultPromise;
3989
4133
  }
4134
+ let errorSubscription = null;
4135
+ const subscribeErrors = () => {
4136
+ if (!environment.onError || errorSubscription) return;
4137
+ errorSubscription = store.actions$.pipe(ofType(threadRestEvents.mutationFinished), filter((action) => !action.outcome.ok && action.outcome.sessionId === store.getState().sessionId)).subscribe((action) => {
4138
+ if (!action.outcome.ok) environment.onError?.(action.outcome.error);
4139
+ });
4140
+ };
3990
4141
  return {
3991
4142
  start() {
3992
4143
  store.init();
4144
+ subscribeErrors();
3993
4145
  store.dispatch(threadAdapterEvents.started());
3994
4146
  },
3995
4147
  stop() {
3996
4148
  store.dispatch(threadAdapterEvents.stopped());
4149
+ errorSubscription?.unsubscribe();
4150
+ errorSubscription = null;
3997
4151
  store.stop();
3998
4152
  },
3999
4153
  setContext(context) {
@@ -4004,6 +4158,14 @@ function createThreadStore(environment) {
4004
4158
  if (!context) return;
4005
4159
  store.dispatch(threadRestEvents.listRequested({ sessionId }));
4006
4160
  },
4161
+ refetchThreads() {
4162
+ const { sessionId, context } = store.getState();
4163
+ if (!context) return;
4164
+ store.dispatch(threadRestEvents.listRequested({ sessionId }));
4165
+ },
4166
+ startNewThread() {
4167
+ store.dispatch(threadAdapterEvents.newThreadStarted());
4168
+ },
4007
4169
  fetchNextPage() {
4008
4170
  store.dispatch(threadAdapterEvents.fetchNextPageRequested());
4009
4171
  },
@@ -4035,15 +4197,21 @@ function createThreadStore(environment) {
4035
4197
  getState() {
4036
4198
  return store.getState();
4037
4199
  },
4038
- select: store.select.bind(store)
4200
+ getServerState() {
4201
+ return initialThreadState;
4202
+ },
4203
+ select: store.select.bind(store),
4204
+ selectors
4039
4205
  };
4040
4206
  }
4041
4207
  const ɵthreadAdapterEvents = threadAdapterEvents;
4208
+ const ɵcreateThreadSelectors = createThreadSelectors;
4042
4209
  const ɵselectThreads = selectThreads;
4043
4210
  const ɵselectThreadsIsLoading = selectThreadsIsLoading;
4044
4211
  const ɵselectThreadsError = selectThreadsError;
4045
4212
  const ɵselectHasNextPage = selectHasNextPage;
4046
4213
  const ɵselectIsFetchingNextPage = selectIsFetchingNextPage;
4214
+ const ɵselectIsMutating = selectIsMutating;
4047
4215
  /**
4048
4216
  * Number of consecutive WebSocket connection failures after which the
4049
4217
  * threads channel tears itself down rather than retrying indefinitely.
@@ -4053,5 +4221,50 @@ const ɵselectIsFetchingNextPage = selectIsFetchingNextPage;
4053
4221
  const ɵMAX_SOCKET_RETRIES = MAX_SOCKET_RETRIES;
4054
4222
 
4055
4223
  //#endregion
4056
- export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, IntelligenceAgent, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, completePartialMarkdown, createActionGroup, createEffect, createReducer, createSelector, createStore, empty, ensureObjectArgs, isRunCompletionAware, ofType, on, parseToolArguments, props, select, ɵMAX_SOCKET_RETRIES, createThreadStore as ɵcreateThreadStore, ɵjoinPhoenixChannel$, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
4224
+ //#region src/features.ts
4225
+ /**
4226
+ * Central registry of CopilotKit feature names.
4227
+ *
4228
+ * Feature names are the strings passed to a license context's `checkFeature`
4229
+ * (see `@copilotkit/shared`'s `LicenseContextValue`). Historically the only
4230
+ * features referenced by literal were the chat surfaces (`chat`, `sidebar`,
4231
+ * `popup`); this module makes the set explicit and typed so new surfaces —
4232
+ * such as the threads drawer — register a real, discoverable feature name
4233
+ * rather than an ad-hoc string scattered across components.
4234
+ *
4235
+ * `checkFeature` itself still accepts any `string` for backward compatibility;
4236
+ * this registry simply documents and types the names CopilotKit recognises.
4237
+ */
4238
+ /**
4239
+ * The set of feature names CopilotKit recognises.
4240
+ *
4241
+ * Frozen so the array cannot be mutated at runtime. Add new surfaces here when
4242
+ * they begin gating behaviour on `checkFeature`.
4243
+ */
4244
+ const ɵCOPILOTKIT_FEATURES = Object.freeze([
4245
+ "chat",
4246
+ "sidebar",
4247
+ "popup",
4248
+ "threads"
4249
+ ]);
4250
+ const FEATURE_SET = new Set(ɵCOPILOTKIT_FEATURES);
4251
+ /**
4252
+ * Type guard: returns `true` when `name` is a recognised CopilotKit feature.
4253
+ *
4254
+ * @param name - Candidate feature name.
4255
+ * @returns Whether `name` is a registered feature.
4256
+ *
4257
+ * @example
4258
+ * ```ts
4259
+ * if (ɵisCopilotKitFeature("threads")) {
4260
+ * // narrowed to ɵCopilotKitFeature
4261
+ * }
4262
+ * ```
4263
+ */
4264
+ function ɵisCopilotKitFeature(name) {
4265
+ return FEATURE_SET.has(name);
4266
+ }
4267
+
4268
+ //#endregion
4269
+ export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, IntelligenceAgent, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, completePartialMarkdown, createActionGroup, createEffect, createReducer, createSelector, createStore, empty, ensureObjectArgs, isRunCompletionAware, ofType, on, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵMAX_SOCKET_RETRIES, ɵcreateThreadSelectors, createThreadStore as ɵcreateThreadStore, ɵisCopilotKitFeature, ɵjoinPhoenixChannel$, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectIsMutating, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
4057
4270
  //# sourceMappingURL=index.mjs.map