@copilotkit/react-core 1.59.2 → 1.59.4

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.
@@ -220,9 +220,9 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
220
220
 
221
221
  //#endregion
222
222
  //#region src/v2/lib/utils.ts
223
- const twMerge$7 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
223
+ const twMerge$8 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
224
224
  function cn(...inputs) {
225
- return twMerge$7((0, clsx.clsx)(inputs));
225
+ return twMerge$8((0, clsx.clsx)(inputs));
226
226
  }
227
227
 
228
228
  //#endregion
@@ -780,7 +780,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
780
780
  }
781
781
  if (e.key === "Enter" && !e.shiftKey) {
782
782
  e.preventDefault();
783
- if (isProcessing) onStop?.();
783
+ if (isProcessing && !canSend) onStop?.();
784
784
  else send();
785
785
  }
786
786
  };
@@ -4797,6 +4797,175 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4797
4797
  };
4798
4798
  }
4799
4799
 
4800
+ //#endregion
4801
+ //#region src/v2/lib/record-annotation.ts
4802
+ /**
4803
+ * Low-level function that posts an arbitrary annotation to the CopilotKit
4804
+ * runtime's general annotation endpoint (`POST /annotate`).
4805
+ *
4806
+ * This is the single transport entry point for all annotation types. Higher-
4807
+ * level hooks (e.g. `useLearnFromUserAction`) build the `type`/`payload` pair
4808
+ * for their specific annotation shape and delegate the HTTP call here.
4809
+ *
4810
+ * The function uses the same transport as `useLearnFromUserAction`:
4811
+ * - `runtimeUrl` from `copilotkit.runtimeUrl` (BFF proxies to the platform)
4812
+ * - `headers` from `copilotkit.headers` (customer auth forwarded to BFF)
4813
+ * - `clientEventId` auto-generated via `randomUUID()` when omitted
4814
+ * - `userId` is resolved server-side by the runtime; the client never sends it
4815
+ * - Errors propagate to the caller (fire-and-propagate, not fire-and-forget)
4816
+ *
4817
+ * @param args - Transport dependencies plus annotation fields.
4818
+ * @returns The platform result containing the annotation row `id` and a
4819
+ * `duplicate` flag.
4820
+ * @throws When the network request fails or the runtime returns a non-2xx
4821
+ * status. Callers that want fire-and-forget behavior should `.catch`
4822
+ * at the call site.
4823
+ */
4824
+ async function recordAnnotation(args) {
4825
+ const { runtimeUrl, headers, type, payload, threadId, occurredAt } = args;
4826
+ const body = {
4827
+ type,
4828
+ threadId,
4829
+ clientEventId: args.clientEventId ?? (0, _copilotkit_shared.randomUUID)(),
4830
+ ...payload !== void 0 ? { payload } : {},
4831
+ ...occurredAt !== void 0 ? { occurredAt } : {}
4832
+ };
4833
+ const response = await fetch(`${runtimeUrl}/annotate`, {
4834
+ method: "POST",
4835
+ headers: {
4836
+ "Content-Type": "application/json",
4837
+ ...headers
4838
+ },
4839
+ body: JSON.stringify(body)
4840
+ });
4841
+ if (!response.ok) {
4842
+ const text = await response.text().catch(() => "");
4843
+ throw new Error(`recordAnnotation: request failed (${response.status})${text ? `: ${text}` : ""}`);
4844
+ }
4845
+ const text = await response.text();
4846
+ if (!text) throw new Error(`recordAnnotation: runtime ${runtimeUrl}/annotate returned ${response.status} with an empty body`);
4847
+ try {
4848
+ return JSON.parse(text);
4849
+ } catch {
4850
+ throw new Error(`recordAnnotation: runtime ${runtimeUrl}/annotate returned a non-JSON body (status ${response.status})`);
4851
+ }
4852
+ }
4853
+
4854
+ //#endregion
4855
+ //#region src/v2/hooks/use-learn-from-user-action.tsx
4856
+ /**
4857
+ * Record a user UI interaction in the Intelligence platform's user-actions
4858
+ * stream. The platform's auto-curated knowledge base agent reads these
4859
+ * (alongside finished agent runs) and writes free-form Obsidian-flavored
4860
+ * markdown to `/project`, where any agent in the same project can later
4861
+ * read it via the `copilotkit_knowledge_base_shell` MCP tool.
4862
+ *
4863
+ * The hook returns a stable function. Calling it issues a request to the
4864
+ * customer's CopilotKit runtime (`POST ${runtimeUrl}/annotate`), which
4865
+ * resolves the Intel user from the BFF's auth and forwards to the
4866
+ * platform — the Intel API key never reaches the browser.
4867
+ *
4868
+ * If `clientEventId` is omitted `recordAnnotation` generates a UUID per call,
4869
+ * so a naive double-call (e.g. React 18 strict-mode double-mount, or a retry
4870
+ * after a network blip on a fresh Promise) is naturally safe. Supply your
4871
+ * own key when a single semantic event must remain idempotent across
4872
+ * multiple `learnFromUserAction(...)` calls.
4873
+ *
4874
+ * @example
4875
+ * ```tsx
4876
+ * import { useLearnFromUserAction } from "@copilotkit/react-core";
4877
+ *
4878
+ * function SettingsPage({ threadId }) {
4879
+ * const learnFromUserAction = useLearnFromUserAction();
4880
+ *
4881
+ * const onRename = (oldName: string, newName: string) => {
4882
+ * void learnFromUserAction({
4883
+ * threadId,
4884
+ * title: "Renamed project",
4885
+ * data: { previous: { name: oldName }, next: { name: newName } },
4886
+ * });
4887
+ * };
4888
+ * }
4889
+ * ```
4890
+ */
4891
+ function useLearnFromUserAction() {
4892
+ const { copilotkit } = useCopilotKit();
4893
+ return (0, react.useCallback)(async (input) => {
4894
+ const runtimeUrl = copilotkit.runtimeUrl;
4895
+ if (!runtimeUrl) throw new Error("useLearnFromUserAction: runtimeUrl is not configured. Set it on <CopilotKitProvider runtimeUrl=...>.");
4896
+ const payload = {
4897
+ ...input.title !== void 0 ? { title: input.title } : {},
4898
+ ...input.description !== void 0 ? { description: input.description } : {},
4899
+ ...input.data !== void 0 ? { data: input.data } : {}
4900
+ };
4901
+ return recordAnnotation({
4902
+ runtimeUrl,
4903
+ headers: copilotkit.headers ?? {},
4904
+ type: "user_action",
4905
+ payload: Object.keys(payload).length > 0 ? payload : void 0,
4906
+ threadId: input.threadId,
4907
+ clientEventId: input.clientEventId,
4908
+ occurredAt: input.occurredAt
4909
+ });
4910
+ }, [copilotkit]);
4911
+ }
4912
+
4913
+ //#endregion
4914
+ //#region src/v2/hooks/use-learn-from-user-action-in-current-thread.tsx
4915
+ /**
4916
+ * Record a user UI interaction against the **current chat's** thread. The
4917
+ * `threadId` is sourced from the surrounding
4918
+ * `<CopilotChatConfigurationProvider>` (the same provider `<CopilotChat>`,
4919
+ * `<CopilotSidebar>`, and friends set up), so callers in a chat-aware
4920
+ * subtree don't need to thread an id through manually.
4921
+ *
4922
+ * Throws on **call** (not on mount) when there is no chat-config provider
4923
+ * in scope — matches the "throw on call when runtimeUrl is missing"
4924
+ * behavior of {@link useLearnFromUserAction}. Mounting the hook in a branch
4925
+ * that never fires is harmless.
4926
+ *
4927
+ * The recorder does NOT accept a `threadId` override. If you need to
4928
+ * record against an explicit thread, use {@link useLearnFromUserAction}
4929
+ * directly — two hooks, two crisp contracts, no mode confusion.
4930
+ *
4931
+ * This hook always uses `config.threadId`, regardless of whether the
4932
+ * surrounding chat config minted it internally or received one from
4933
+ * the caller. Auto-minted threads simply mean the action lands under
4934
+ * a thread the platform never saw — the writer agent still distills
4935
+ * user-action-only threads (it does not require the thread to exist
4936
+ * in `cpki.threads`), so the loop keeps learning.
4937
+ *
4938
+ * @example
4939
+ * ```tsx
4940
+ * import { useLearnFromUserActionInCurrentThread } from "@copilotkit/react-core";
4941
+ *
4942
+ * function SettingsPanel() {
4943
+ * const learnFromUserAction = useLearnFromUserActionInCurrentThread();
4944
+ *
4945
+ * const onRename = (oldName: string, newName: string) => {
4946
+ * void learnFromUserAction({
4947
+ * title: "Renamed project",
4948
+ * data: { previous: { name: oldName }, next: { name: newName } },
4949
+ * });
4950
+ * };
4951
+ *
4952
+ * // ...
4953
+ * }
4954
+ * ```
4955
+ */
4956
+ function useLearnFromUserActionInCurrentThread() {
4957
+ const config = useCopilotChatConfiguration();
4958
+ const learnFromUserAction = useLearnFromUserAction();
4959
+ return (0, react.useCallback)(async (input) => {
4960
+ const threadId = config?.threadId;
4961
+ if (!threadId) throw new Error("useLearnFromUserActionInCurrentThread: no CopilotChatConfigurationProvider in scope. Wrap the call site in <CopilotChat>, <CopilotSidebar>, or <CopilotChatConfigurationProvider>, or use `useLearnFromUserAction()` and pass `threadId` explicitly.");
4962
+ return learnFromUserAction({
4963
+ ...input,
4964
+ threadId
4965
+ });
4966
+ }, [config?.threadId, learnFromUserAction]);
4967
+ }
4968
+
4800
4969
  //#endregion
4801
4970
  //#region src/v2/hooks/use-attachments.tsx
4802
4971
  /**
@@ -4955,6 +5124,153 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4955
5124
  };
4956
5125
  }
4957
5126
 
5127
+ //#endregion
5128
+ //#region src/v2/hooks/use-learning-containers.tsx
5129
+ /** The default learning containers value. Matches the backend default. */
5130
+ const DEFAULT_CONTAINERS = ["project"];
5131
+ /**
5132
+ * Declaratively keeps a thread's learning containers in sync by emitting
5133
+ * `set_learning_containers` annotations via the CopilotKit runtime annotate
5134
+ * endpoint (`POST ${runtimeUrl}/annotate`).
5135
+ *
5136
+ * **Emit rules:**
5137
+ * - On mount with `["project"]` (the backend default) → does NOT emit.
5138
+ * Absence of an annotation equals the default, so the round-trip is skipped.
5139
+ * - On mount with any other value → emits immediately.
5140
+ * - On any subsequent content change (including a switch back to
5141
+ * `["project"]`) → emits (a deliberate switch is always recorded).
5142
+ * - On unmount or threadId change → emits a reset to `["project"]`
5143
+ * so the backend is left in a clean state for the next consumer.
5144
+ * Changing `learningContainers` within the same thread does NOT reset the
5145
+ * thread; only the new value is emitted.
5146
+ *
5147
+ * Content-equality is evaluated via `JSON.stringify` so a fresh array literal
5148
+ * with the same items does NOT trigger a redundant emit.
5149
+ *
5150
+ * If `runtimeUrl` is absent, all emits are silently skipped.
5151
+ *
5152
+ * @example
5153
+ * ```tsx
5154
+ * function ThreadPane({ threadId, userScope }: Props) {
5155
+ * useLearningContainers({
5156
+ * threadId,
5157
+ * learningContainers: [userScope],
5158
+ * });
5159
+ * // ...
5160
+ * }
5161
+ * ```
5162
+ */
5163
+ function useLearningContainers({ threadId, learningContainers }) {
5164
+ const { copilotkit } = useCopilotKit();
5165
+ /**
5166
+ * Tracks the last-synced container list so content-identical rerenders
5167
+ * (fresh array, same values) do not fire a redundant emit.
5168
+ * `null` = nothing synced yet (initial state or after a threadId reset).
5169
+ */
5170
+ const lastSyncedRef = (0, react.useRef)(null);
5171
+ /** Guards the missing-runtimeUrl warning so it fires at most once per hook instance. */
5172
+ const warnedMissingUrlRef = (0, react.useRef)(false);
5173
+ const runtimeUrlRef = (0, react.useRef)(copilotkit.runtimeUrl);
5174
+ const headersRef = (0, react.useRef)(copilotkit.headers ?? {});
5175
+ runtimeUrlRef.current = copilotkit.runtimeUrl;
5176
+ headersRef.current = copilotkit.headers ?? {};
5177
+ const key = JSON.stringify(learningContainers);
5178
+ const defaultKey = JSON.stringify(DEFAULT_CONTAINERS);
5179
+ (0, react.useEffect)(() => {
5180
+ const runtimeUrl = copilotkit.runtimeUrl;
5181
+ const headers = copilotkit.headers ?? {};
5182
+ /**
5183
+ * Fire-and-forget emit; errors must not surface in render.
5184
+ * Failures are logged as warnings so they are diagnosable without
5185
+ * propagating into the React render cycle.
5186
+ */
5187
+ const emit = (containers) => {
5188
+ if (!runtimeUrl) {
5189
+ if (!warnedMissingUrlRef.current) {
5190
+ warnedMissingUrlRef.current = true;
5191
+ console.warn("useLearningContainers: runtimeUrl not configured; learning-container sync disabled");
5192
+ }
5193
+ return;
5194
+ }
5195
+ recordAnnotation({
5196
+ runtimeUrl,
5197
+ headers,
5198
+ type: "set_learning_containers",
5199
+ payload: { containers },
5200
+ threadId
5201
+ }).catch((err) => {
5202
+ console.warn("useLearningContainers: failed to record set_learning_containers", err);
5203
+ });
5204
+ };
5205
+ if (lastSyncedRef.current === null) {
5206
+ if (key === defaultKey) {
5207
+ lastSyncedRef.current = learningContainers;
5208
+ return;
5209
+ }
5210
+ emit(learningContainers);
5211
+ lastSyncedRef.current = learningContainers;
5212
+ } else if (key !== JSON.stringify(lastSyncedRef.current)) {
5213
+ emit(learningContainers);
5214
+ lastSyncedRef.current = learningContainers;
5215
+ }
5216
+ }, [threadId, key]);
5217
+ (0, react.useEffect)(() => {
5218
+ const capturedThreadId = threadId;
5219
+ return () => {
5220
+ const capturedRuntimeUrl = runtimeUrlRef.current;
5221
+ const capturedHeaders = headersRef.current;
5222
+ if (capturedRuntimeUrl) recordAnnotation({
5223
+ runtimeUrl: capturedRuntimeUrl,
5224
+ headers: capturedHeaders,
5225
+ type: "set_learning_containers",
5226
+ payload: { containers: DEFAULT_CONTAINERS },
5227
+ threadId: capturedThreadId
5228
+ }).catch((err) => {
5229
+ console.warn("useLearningContainers: failed to record set_learning_containers", err);
5230
+ });
5231
+ lastSyncedRef.current = null;
5232
+ };
5233
+ }, [threadId]);
5234
+ }
5235
+
5236
+ //#endregion
5237
+ //#region src/v2/hooks/use-learning-containers-in-current-thread.tsx
5238
+ /**
5239
+ * Declaratively keeps the **current chat thread's** learning containers in
5240
+ * sync. The `threadId` is sourced from the surrounding
5241
+ * `<CopilotChatConfigurationProvider>` (the same provider `<CopilotChat>`,
5242
+ * `<CopilotSidebar>`, and friends set up), so callers in a chat-aware
5243
+ * subtree don't need to thread an id through manually.
5244
+ *
5245
+ * **Throws on render** when there is no chat-config provider in scope or
5246
+ * when the provider does not yet have an active `threadId`. Mount the hook
5247
+ * inside a subtree that is guaranteed to have a thread context.
5248
+ *
5249
+ * If you need to manage an explicit thread, use {@link useLearningContainers}
5250
+ * directly — two hooks, two crisp contracts, no mode confusion.
5251
+ *
5252
+ * @throws When no `CopilotChatConfigurationProvider` is in scope or when the
5253
+ * active `threadId` is absent/empty.
5254
+ *
5255
+ * @example
5256
+ * ```tsx
5257
+ * function ThreadPanel({ scope }: Props) {
5258
+ * useLearningContainersInCurrentThread({
5259
+ * learningContainers: [scope],
5260
+ * });
5261
+ * // ...
5262
+ * }
5263
+ * ```
5264
+ */
5265
+ function useLearningContainersInCurrentThread({ learningContainers }) {
5266
+ const threadId = useCopilotChatConfiguration()?.threadId;
5267
+ if (!threadId) throw new Error("useLearningContainersInCurrentThread must be used within a thread context (no active threadId). Wrap the component in <CopilotChat>, <CopilotSidebar>, or <CopilotChatConfigurationProvider>, or use `useLearningContainers()` and pass `threadId` explicitly.");
5268
+ useLearningContainers({
5269
+ threadId,
5270
+ learningContainers
5271
+ });
5272
+ }
5273
+
4958
5274
  //#endregion
4959
5275
  //#region src/v2/components/chat/CopilotChatToolCallsView.tsx
4960
5276
  function CopilotChatToolCallsView({ message, messages = [] }) {
@@ -5727,33 +6043,174 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5727
6043
  */
5728
6044
  const ScrollElementContext = react.default.createContext(null);
5729
6045
 
6046
+ //#endregion
6047
+ //#region src/v2/components/intelligence-indicator/IntelligenceIndicatorView.tsx
6048
+ /**
6049
+ * The presentational "CopilotKit Intelligence" face — the default
6050
+ * rendered by the {@link IntelligenceIndicator} brain and the default
6051
+ * value for the `intelligenceIndicator` slot.
6052
+ *
6053
+ * Single-element three-stage design:
6054
+ * 1. **In-progress.** Glassmorphism pill chrome around a 270° arc icon
6055
+ * and the label. The arc has a single continuous visible stroke
6056
+ * (one `stroke-dasharray` dash + one gap, summing to the path
6057
+ * length) and the whole SVG rotates — so the viewer sees one
6058
+ * C-shaped arc spinning around the visual center.
6059
+ * 2. **Icon morph (~250 ms).** On status flip the single icon path
6060
+ * interpolates from the arc to a checkmark via CSS `d:` while the
6061
+ * dashed stroke transitions to solid (filling in the gap that was
6062
+ * the spinner's open portion). The SVG rotation animation is
6063
+ * removed; the snap back to identity is masked by the simultaneous
6064
+ * shape change. Chrome and text stay at full opacity throughout.
6065
+ * 3. **Settle (~400 ms, starts at +250 ms).** Chrome (background,
6066
+ * border, shadow, backdrop-blur) fades to zero opacity. The label
6067
+ * and icon stroke color transitions from saturated purple to a
6068
+ * true-neutral gray at 0.8 alpha — no hue cast, reads as "settled
6069
+ * history metadata." The label simultaneously skews to ~10° (a
6070
+ * transform-based italic feel that interpolates smoothly with the
6071
+ * color, rather than the discrete `font-style: italic` snap that
6072
+ * would cause a layout pop). The label text stays put — only its
6073
+ * color and slant change — so there is no "bump" where the brand
6074
+ * text disappears and reappears.
6075
+ *
6076
+ * Hard sequence: stage 3 has a 250 ms transition-delay so it waits
6077
+ * for stage 2 to finish. Total settle time ~650 ms in production.
6078
+ *
6079
+ * Both shapes are 3-segment cubic Bézier paths with matched command
6080
+ * structure (one `M` plus three `C`s), which is what makes the d
6081
+ * morph interpolate as a continuous shape change rather than snapping.
6082
+ *
6083
+ * The label is identical in both states (default "CopilotKit
6084
+ * Intelligence"). The static check icon carries the "done" semantic;
6085
+ * the color + slant transition does the "settle" work without needing
6086
+ * any wording change.
6087
+ *
6088
+ * Customize via the `intelligenceIndicator` slot on `CopilotChat`:
6089
+ * a className string restyles the wrapper, a props object tweaks
6090
+ * the default (`{ label }`), and a component replaces it entirely
6091
+ * with full control over visuals and timing.
6092
+ */
6093
+ function IntelligenceIndicatorView({ message, status, label, className, ...rest }) {
6094
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6095
+ className: (0, tailwind_merge.twMerge)("cpk-intelligence-indicator", className),
6096
+ role: "status",
6097
+ "aria-live": "polite",
6098
+ "data-testid": `cpk-intelligence-indicator-${message.id}`,
6099
+ "data-status": status,
6100
+ title: label,
6101
+ ...rest,
6102
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6103
+ className: "cpk-intelligence-indicator__chrome",
6104
+ "aria-hidden": "true"
6105
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
6106
+ className: "cpk-intelligence-indicator__content",
6107
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
6108
+ className: "cpk-intelligence-indicator__icon",
6109
+ viewBox: "0 0 24 24",
6110
+ width: "14",
6111
+ height: "14",
6112
+ "aria-hidden": "true",
6113
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { className: "cpk-intelligence-indicator__icon-path" })
6114
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6115
+ className: "cpk-intelligence-indicator__label",
6116
+ children: label
6117
+ })]
6118
+ })]
6119
+ });
6120
+ }
6121
+
5730
6122
  //#endregion
5731
6123
  //#region src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx
5732
6124
  /**
5733
6125
  * Grace window before showing the spinner. A matching tool call must
5734
6126
  * remain unresolved (no `tool`-role result message in `agent.messages`)
5735
- * for at least this long before the pill appears. This filters out
5736
- * history-replay flashes — during `connectAgent` replay, tool calls and
5737
- * their results arrive back-to-back in sub-millisecond bursts, so the
5738
- * timer is cancelled before it fires. Live runs cross the threshold
5739
- * easily because the tool actually has to execute.
6127
+ * for at least this long before the indicator transitions out of
6128
+ * `hidden`. This filters out history-replay flashes — during
6129
+ * `connectAgent` replay, tool calls and their results arrive
6130
+ * back-to-back in sub-millisecond bursts, so the timer is cancelled
6131
+ * before it fires. Live runs cross the threshold easily because the
6132
+ * tool actually has to execute.
5740
6133
  */
5741
6134
  const PENDING_THRESHOLD_MS = 100;
5742
- /** Hold the checkmark briefly before fading out. */
5743
- const CHECK_HOLD_MS = 800;
5744
6135
  /**
5745
- * Duration of the fade-out animation. Must match
5746
- * `cpk-intelligence-pill-fade-out` keyframes in `v2/styles/globals.css`.
6136
+ * Tool-name regex patterns that trigger the indicator. Matches any tool
6137
+ * name *containing* the Intelligence MCP server's canonical tool name, so
6138
+ * both the bare `copilotkit_knowledge_base_shell` and the namespaced
6139
+ * `mcp__<server>__copilotkit_knowledge_base_shell` form (emitted by
6140
+ * `@ag-ui/mcp-middleware`) light up the pill. If we add per-instance
6141
+ * customization later (e.g. a `CopilotKitProvider` prop or a runtime-info
6142
+ * field), this constant becomes the fallback.
5747
6143
  */
5748
- const FADE_OUT_ANIMATION_MS = 480;
6144
+ const DEFAULT_TOOL_PATTERNS = [/copilotkit_knowledge_base_shell/];
6145
+ /**
6146
+ * Phase to start in when an indicator first mounts. A turn that is already
6147
+ * complete at mount jumps straight to `finished` — no `hidden` flash, no
6148
+ * spinner blip — which is what makes scrolled-back / replayed history render
6149
+ * its indicators directly in the finished state.
6150
+ *
6151
+ * Pure and timing-free on purpose: the grace window ({@link
6152
+ * PENDING_THRESHOLD_MS}) only controls *when* the live transition is applied;
6153
+ * these functions decide *what* it resolves to, so the decision can be unit
6154
+ * tested deterministically without any timers.
6155
+ */
6156
+ function initialIndicatorPhase(turnComplete) {
6157
+ return turnComplete ? "finished" : "hidden";
6158
+ }
5749
6159
  /**
5750
- * Tool-name regex patterns that trigger the indicator. Currently
5751
- * hardcoded to the Intelligence MCP server's canonical tool name. If
5752
- * we add per-instance customization later (e.g. a `CopilotKitProvider`
5753
- * prop or a runtime-info field), this constant becomes the fallback.
6160
+ * Phase the grace window resolves to once it elapses:
6161
+ * - completed turn `finished` (replay-flash suppression: a tool whose
6162
+ * result lands within the window skips the spinner entirely),
6163
+ * - a still-pending matching tool call `spinner`,
6164
+ * - otherwise stay `hidden` (the matching tool call hasn't landed yet).
5754
6165
  */
5755
- const DEFAULT_TOOL_PATTERNS = [/^copilotkit_knowledge_base_shell$/];
6166
+ function resolveGracePhase(turnComplete, hasPending) {
6167
+ if (turnComplete) return "finished";
6168
+ if (hasPending) return "spinner";
6169
+ return "hidden";
6170
+ }
5756
6171
  const isMatchingToolCallName = (name) => typeof name === "string" && DEFAULT_TOOL_PATTERNS.some((p) => p.test(name));
6172
+ const messageHasMatchingToolCall = (m) => {
6173
+ if (m.role !== "assistant") return false;
6174
+ return (Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name));
6175
+ };
6176
+ /**
6177
+ * Stable turn id for the messages that precede the first user message (a turn
6178
+ * with no opening user message of its own). Used as the React key so the
6179
+ * indicator for that turn never collides with a real user-message id.
6180
+ */
6181
+ const INTELLIGENCE_TURN_HEAD = "__cpk_turn_head__";
6182
+ /**
6183
+ * Map each Intelligence-using turn to its anchor message — the FIRST bash-using
6184
+ * assistant message of the turn — and a stable turn id (the id of the user
6185
+ * message that opened the turn, or {@link INTELLIGENCE_TURN_HEAD} for the
6186
+ * pre-first-user turn). Returns `Map<anchorMessageId, turnId>`.
6187
+ *
6188
+ * Anchoring to the FIRST (not last) bash-using message keeps the indicator
6189
+ * fixed in place for the whole turn: later bash steps don't reposition it, so
6190
+ * the spinner never abruptly jumps mid-turn (bug 1). `CopilotChatMessageView`
6191
+ * emits exactly one `IntelligenceIndicator` per entry, keyed by the turn id and
6192
+ * positioned at the anchor; the per-turn key also lets every past turn keep its
6193
+ * own indicator in scroll-back.
6194
+ */
6195
+ function getIntelligenceTurnAnchors(messages) {
6196
+ const anchors = /* @__PURE__ */ new Map();
6197
+ let turnId = INTELLIGENCE_TURN_HEAD;
6198
+ let anchorId = null;
6199
+ const commit = () => {
6200
+ if (anchorId !== null) anchors.set(anchorId, turnId);
6201
+ anchorId = null;
6202
+ };
6203
+ for (const m of messages) {
6204
+ if (m.role === "user") {
6205
+ commit();
6206
+ turnId = m.id;
6207
+ continue;
6208
+ }
6209
+ if (anchorId === null && messageHasMatchingToolCall(m)) anchorId = m.id;
6210
+ }
6211
+ commit();
6212
+ return anchors;
6213
+ }
5757
6214
  /**
5758
6215
  * "Tool-call-like" messages do NOT count as a real follow-up: tool
5759
6216
  * result messages, assistant messages that carry tool calls, and
@@ -5772,45 +6229,51 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5772
6229
  return false;
5773
6230
  };
5774
6231
  /**
5775
- * The "Using CopilotKit Intelligence" pill. Auto-mounted by
5776
- * `CopilotChatMessageView` for every message slot when
5777
- * `copilotkit.intelligence` is configured callers do not register
5778
- * this themselves. Self-gates so only the canonical message renders a
5779
- * pill.
6232
+ * The "Using CopilotKit Intelligence" indicator brain. Auto-mounted by
6233
+ * `CopilotChatMessageView` once per Intelligence-using turn, at that
6234
+ * turn's anchor message and keyed by the turn id (see
6235
+ * {@link getIntelligenceTurnAnchors}). Callers do not register this
6236
+ * themselves. It owns the run subscription and the phase machine and
6237
+ * renders its swappable face via the `intelligenceIndicator` slot.
6238
+ *
6239
+ * Placement (which message anchors the turn) is decided by the view, so
6240
+ * this component does not self-gate its own placement; it only derives
6241
+ * in-progress/finished for the turn it was mounted on.
5780
6242
  *
5781
6243
  * Render gates (all must hold):
5782
6244
  * 1. `copilotkit.intelligence !== undefined`
5783
- * 2. The message is an assistant message with at least one tool call
5784
- * whose name matches {@link DEFAULT_TOOL_PATTERNS}
5785
- * 3. The message is the *latest* such matching-assistant message in
5786
- * `agent.messages` — tool-result messages and prose-only assistant
5787
- * messages don't invalidate the slot, so the pill stays
5788
- * continuously through a multi-step tool chain.
5789
- * 4. The phase machine is past `idle` (the pending-grace timer fired)
5790
- * and not yet `hidden`.
6245
+ * 2. The (anchor) message is an assistant message with at least one
6246
+ * tool call whose name matches {@link DEFAULT_TOOL_PATTERNS}.
6247
+ * 3. The phase machine is past `hidden`.
6248
+ *
6249
+ * Because the view keys each indicator by its turn id, the instance moves
6250
+ * with the anchor across a hand-off (no remount, no spinner restart), and
6251
+ * every prior Intelligence-using turn keeps its own persistent indicator
6252
+ * in chat history.
5791
6253
  *
5792
6254
  * Phase machine (per-instance, all timers local):
5793
- * - Starts in `idle` nothing rendered.
5794
- * - `idle spinner` once a matching tool call has been pending
6255
+ * - Starts in `hidden`, unless the message mounts onto an
6256
+ * already-completed turn (no pending work, agent stopped or a
6257
+ * real follow-up already present), in which case the lazy
6258
+ * `useState` initializer starts directly in `finished`. This is
6259
+ * what avoids a "hidden flash" on history replay.
6260
+ * - `hidden → spinner` once a matching tool call has been pending
5795
6261
  * (no `tool`-role result with a matching `toolCallId`) for
5796
6262
  * {@link PENDING_THRESHOLD_MS}. Replay flashes (tool call + result
5797
6263
  * in the same tick) never cross this threshold.
5798
- * - `spinnercheck` as soon as EITHER `agent.isRunning` flips
6264
+ * - `hiddenfinished` if after the grace window the turn is
6265
+ * already complete (no pending work AND
6266
+ * `sawRealFollowup || !agent.isRunning`). Handles very fast tools
6267
+ * whose result lands within the grace window.
6268
+ * - `spinner → finished` as soon as EITHER `agent.isRunning` flips
5799
6269
  * false OR a non-tool-call-like message appears later in
5800
- * `agent.messages` (i.e. the agent has produced a "real"
5801
- * follow-up — prose answer or a new user turn).
5802
- * - `check fading` after {@link CHECK_HOLD_MS}.
5803
- * - `fading hidden` after {@link FADE_OUT_ANIMATION_MS}.
5804
- *
5805
- * Once `hidden`, the phase is sticky — a finished pill never re-spawns
5806
- * on the same message. New runs mount fresh indicator instances on
5807
- * their own assistant messages.
5808
- *
5809
- * The "exactly one pill at a time" guarantee is structural: only one
5810
- * message satisfies the latest-matching-assistant gate at any moment.
6270
+ * `agent.messages` (i.e. the agent produced a "real" follow-up —
6271
+ * prose answer or a new user turn).
6272
+ * - `finished` is terminal: the indicator settles into its
6273
+ * persistent tag form and stays mounted.
5811
6274
  */
5812
6275
  function IntelligenceIndicator(props) {
5813
- const { message, agentId, label = "Using CopilotKit Intelligence" } = props;
6276
+ const { message, agentId, label = "CopilotKit Intelligence", intelligenceIndicator } = props;
5814
6277
  const { copilotkit } = useCopilotKit();
5815
6278
  const config = useCopilotChatConfiguration();
5816
6279
  const { agent } = useAgent({
@@ -5830,84 +6293,37 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
5830
6293
  for (const m of agent.messages) if (m.role === "tool" && m.toolCallId) resolved.add(m.toolCallId);
5831
6294
  return matchingToolCallIds.some((id) => !resolved.has(id));
5832
6295
  }, [matchingToolCallIds, agent.messages]);
5833
- const sawRealFollowup = (0, react.useMemo)(() => {
6296
+ const turnComplete = (0, react.useMemo)(() => {
5834
6297
  const idx = agent.messages.findIndex((m) => m.id === message.id);
5835
6298
  if (idx < 0) return false;
5836
6299
  for (let i = idx + 1; i < agent.messages.length; i += 1) if (!isToolCallLikeMessage(agent.messages[i])) return true;
5837
6300
  return false;
5838
- }, [agent.messages, message.id]);
5839
- const [phase, setPhase] = (0, react.useState)("idle");
6301
+ }, [agent.messages, message.id]) || !agent.isRunning;
6302
+ const [phase, setPhase] = (0, react.useState)(() => initialIndicatorPhase(turnComplete));
5840
6303
  (0, react.useEffect)(() => {
5841
- if (phase !== "idle") return void 0;
5842
- if (!hasPending) return void 0;
5843
- const t = setTimeout(() => setPhase("spinner"), PENDING_THRESHOLD_MS);
6304
+ if (phase !== "hidden") return void 0;
6305
+ const t = setTimeout(() => {
6306
+ setPhase(resolveGracePhase(turnComplete, hasPending));
6307
+ }, PENDING_THRESHOLD_MS);
5844
6308
  return () => clearTimeout(t);
5845
- }, [phase, hasPending]);
5846
- (0, react.useEffect)(() => {
5847
- if (phase !== "spinner") return void 0;
5848
- if (!agent.isRunning || sawRealFollowup) setPhase("check");
5849
6309
  }, [
5850
6310
  phase,
5851
- agent.isRunning,
5852
- sawRealFollowup
6311
+ hasPending,
6312
+ turnComplete
5853
6313
  ]);
5854
6314
  (0, react.useEffect)(() => {
5855
- if (phase !== "check") return void 0;
5856
- const t = setTimeout(() => setPhase("fading"), CHECK_HOLD_MS);
5857
- return () => clearTimeout(t);
5858
- }, [phase]);
5859
- (0, react.useEffect)(() => {
5860
- if (phase !== "fading") return void 0;
5861
- const t = setTimeout(() => setPhase("hidden"), FADE_OUT_ANIMATION_MS);
5862
- return () => clearTimeout(t);
5863
- }, [phase]);
6315
+ if (phase !== "spinner") return void 0;
6316
+ if (turnComplete) setPhase("finished");
6317
+ }, [phase, turnComplete]);
5864
6318
  if (copilotkit.intelligence === void 0) return null;
5865
6319
  if (!config) return null;
5866
- if (phase === "idle" || phase === "hidden") return null;
6320
+ if (phase === "hidden") return null;
5867
6321
  if (message.role !== "assistant") return null;
5868
- if (!(Array.isArray(message.toolCalls) ? message.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) return null;
5869
- let latestMatchingAssistantId;
5870
- for (let i = agent.messages.length - 1; i >= 0; i -= 1) {
5871
- const m = agent.messages[i];
5872
- if (m.role !== "assistant") continue;
5873
- if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) {
5874
- latestMatchingAssistantId = m.id;
5875
- break;
5876
- }
5877
- }
5878
- if (latestMatchingAssistantId !== message.id) return null;
5879
- const showSpinner = phase === "spinner";
5880
- const isFading = phase === "fading";
5881
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5882
- className: "cpk-intelligence-pill" + (isFading ? " cpk-intelligence-pill--fading" : ""),
5883
- role: "status",
5884
- "aria-live": "polite",
5885
- "aria-hidden": isFading || void 0,
5886
- "data-testid": `cpk-intelligence-pill-${message.id}`,
5887
- title: label,
5888
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
5889
- className: "cpk-intelligence-pill__icon",
5890
- viewBox: "0 0 24 24",
5891
- width: "14",
5892
- height: "14",
5893
- "aria-hidden": "true",
5894
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
5895
- cx: "12",
5896
- cy: "12",
5897
- r: "9",
5898
- fill: "none",
5899
- strokeWidth: "2.5",
5900
- strokeLinecap: "round",
5901
- className: "cpk-intelligence-pill__ring" + (showSpinner ? "" : " cpk-intelligence-pill__ring--done")
5902
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
5903
- d: "M8 12.5l3 3 5-6",
5904
- fill: "none",
5905
- strokeWidth: "2.5",
5906
- strokeLinecap: "round",
5907
- strokeLinejoin: "round",
5908
- className: "cpk-intelligence-pill__check" + (showSpinner ? "" : " cpk-intelligence-pill__check--shown")
5909
- })]
5910
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
6322
+ if (!messageHasMatchingToolCall(message)) return null;
6323
+ return renderSlot(intelligenceIndicator, IntelligenceIndicatorView, {
6324
+ message,
6325
+ status: phase === "finished" ? "finished" : "in-progress",
6326
+ label
5911
6327
  });
5912
6328
  }
5913
6329
 
@@ -6060,7 +6476,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6060
6476
  return [...acc.values()];
6061
6477
  }
6062
6478
  const VIRTUALIZE_THRESHOLD = 50;
6063
- function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
6479
+ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, isRunning = false, children, className, ...props }) {
6064
6480
  const renderCustomMessage = useRenderCustomMessages();
6065
6481
  const { renderActivityMessage } = useRenderActivityMessage();
6066
6482
  const { copilotkit } = useCopilotKit();
@@ -6118,6 +6534,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6118
6534
  if (!shouldVirtualize || !deduplicatedMessages.length) return;
6119
6535
  virtualizer.scrollToIndex(deduplicatedMessages.length - 1, { align: "end" });
6120
6536
  }, [shouldVirtualize, firstMessageId]);
6537
+ const intelligenceTurnAnchors = (0, react.useMemo)(() => getIntelligenceTurnAnchors(deduplicatedMessages), [deduplicatedMessages]);
6121
6538
  const renderMessageBlock = (message) => {
6122
6539
  const elements = [];
6123
6540
  const stateSnapshot = getStateSnapshotForMessage(message.id);
@@ -6156,10 +6573,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6156
6573
  renderCustomMessage,
6157
6574
  stateSnapshot
6158
6575
  }, `${message.id}-custom-after`));
6159
- if (copilotkit.intelligence !== void 0 && message.role === "assistant") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntelligenceIndicator, {
6576
+ const intelligenceTurnId = intelligenceTurnAnchors.get(message.id);
6577
+ if (intelligenceTurnId !== void 0) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntelligenceIndicator, {
6160
6578
  message,
6161
- agentId: config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID
6162
- }, `${message.id}-intelligence`));
6579
+ agentId: config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID,
6580
+ intelligenceIndicator
6581
+ }, `intelligence-${intelligenceTurnId}`));
6163
6582
  return elements.filter(Boolean);
6164
6583
  };
6165
6584
  const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
@@ -6596,7 +7015,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6596
7015
  })
6597
7016
  });
6598
7017
  }
6599
- function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, children, className, ...props }) {
7018
+ function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, intelligenceIndicator, children, className, ...props }) {
6600
7019
  const [inputContainerEl, setInputContainerEl] = (0, react.useState)(null);
6601
7020
  const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
6602
7021
  const [isResizing, setIsResizing] = (0, react.useState)(false);
@@ -6633,7 +7052,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6633
7052
  }, [inputContainerEl]);
6634
7053
  const BoundMessageView = renderSlot(messageView, CopilotChatMessageView, {
6635
7054
  messages,
6636
- isRunning
7055
+ isRunning,
7056
+ intelligenceIndicator
6637
7057
  });
6638
7058
  const BoundInput = renderSlot(input, CopilotChatInput_default, {
6639
7059
  onSubmitMessage,
@@ -7139,6 +7559,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7139
7559
  const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
7140
7560
  const [isTranscribing, setIsTranscribing] = (0, react.useState)(false);
7141
7561
  const { attachments: selectedAttachments, enabled: attachmentsEnabled, dragOver, fileInputRef, containerRef: chatContainerRef, handleFileUpload, handleDragOver, handleDragLeave, handleDrop, removeAttachment, consumeAttachments } = useAttachments({ config: attachmentsConfig });
7562
+ const selectedAttachmentsRef = (0, react.useRef)(selectedAttachments);
7563
+ (0, react.useEffect)(() => {
7564
+ selectedAttachmentsRef.current = selectedAttachments;
7565
+ }, [selectedAttachments]);
7142
7566
  const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
7143
7567
  const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
7144
7568
  const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
@@ -7174,9 +7598,25 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7174
7598
  resolvedAgentId,
7175
7599
  hasExplicitThreadId
7176
7600
  ]);
7601
+ const waitForActiveRunToSettle = (0, react.useCallback)(async () => {
7602
+ if (agent.isRunning && (0, _copilotkit_core.isRunCompletionAware)(agent) && agent.activeRunCompletionPromise) try {
7603
+ await agent.activeRunCompletionPromise;
7604
+ } catch (error) {
7605
+ console.error("CopilotChat: in-flight run rejected while queuing send", error);
7606
+ }
7607
+ }, [agent]);
7177
7608
  const onSubmitInput = (0, react.useCallback)(async (value) => {
7178
- if (selectedAttachments.some((a) => a.status === "uploading")) {
7179
- console.error("[CopilotKit] Cannot send while attachments are uploading");
7609
+ if (selectedAttachmentsRef.current.some((a) => a.status === "uploading")) {
7610
+ console.error("[CopilotKit] Cannot send while attachments are uploading (pre-await guard)");
7611
+ setTranscriptionError("Cannot send while attachments are uploading.");
7612
+ return;
7613
+ }
7614
+ setInputValue("");
7615
+ await waitForActiveRunToSettle();
7616
+ if (selectedAttachmentsRef.current.some((a) => a.status === "uploading")) {
7617
+ console.error("[CopilotKit] Cannot send while attachments are uploading (post-await re-check)");
7618
+ setTranscriptionError("Cannot send while attachments are uploading.");
7619
+ setInputValue(value);
7180
7620
  return;
7181
7621
  }
7182
7622
  const readyAttachments = consumeAttachments();
@@ -7204,7 +7644,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7204
7644
  role: "user",
7205
7645
  content: value
7206
7646
  });
7207
- setInputValue("");
7208
7647
  try {
7209
7648
  await copilotkit.runAgent({ agent });
7210
7649
  } catch (error) {
@@ -7212,10 +7651,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7212
7651
  }
7213
7652
  }, [
7214
7653
  agent,
7215
- selectedAttachments,
7216
- consumeAttachments
7654
+ consumeAttachments,
7655
+ waitForActiveRunToSettle
7217
7656
  ]);
7218
7657
  const handleSelectSuggestion = (0, react.useCallback)(async (suggestion) => {
7658
+ await waitForActiveRunToSettle();
7219
7659
  agent.addMessage({
7220
7660
  id: (0, _copilotkit_shared.randomUUID)(),
7221
7661
  role: "user",
@@ -7226,7 +7666,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7226
7666
  } catch (error) {
7227
7667
  console.error("CopilotChat: runAgent failed after selecting suggestion", error);
7228
7668
  }
7229
- }, [agent]);
7669
+ }, [agent, waitForActiveRunToSettle]);
7230
7670
  const stopCurrentRun = (0, react.useCallback)(() => {
7231
7671
  try {
7232
7672
  copilotkit.stopAgent({ agent });
@@ -10035,7 +10475,9 @@ Object.defineProperty(exports, 'CopilotSidebarView', {
10035
10475
  return CopilotSidebarView;
10036
10476
  }
10037
10477
  });
10478
+ exports.INTELLIGENCE_TURN_HEAD = INTELLIGENCE_TURN_HEAD;
10038
10479
  exports.IntelligenceIndicator = IntelligenceIndicator;
10480
+ exports.IntelligenceIndicatorView = IntelligenceIndicatorView;
10039
10481
  exports.MCPAppsActivityContentSchema = MCPAppsActivityContentSchema;
10040
10482
  exports.MCPAppsActivityRenderer = MCPAppsActivityRenderer;
10041
10483
  exports.MCPAppsActivityType = MCPAppsActivityType;
@@ -10050,6 +10492,7 @@ Object.defineProperty(exports, 'a2uiDefaultTheme', {
10050
10492
  });
10051
10493
  exports.createA2UIMessageRenderer = createA2UIMessageRenderer;
10052
10494
  exports.defineToolCallRenderer = defineToolCallRenderer;
10495
+ exports.getIntelligenceTurnAnchors = getIntelligenceTurnAnchors;
10053
10496
  exports.useAgent = useAgent;
10054
10497
  exports.useAgentContext = useAgentContext;
10055
10498
  exports.useAttachments = useAttachments;
@@ -10062,6 +10505,10 @@ exports.useDefaultRenderTool = useDefaultRenderTool;
10062
10505
  exports.useFrontendTool = useFrontendTool;
10063
10506
  exports.useHumanInTheLoop = useHumanInTheLoop;
10064
10507
  exports.useInterrupt = useInterrupt;
10508
+ exports.useLearnFromUserAction = useLearnFromUserAction;
10509
+ exports.useLearnFromUserActionInCurrentThread = useLearnFromUserActionInCurrentThread;
10510
+ exports.useLearningContainers = useLearningContainers;
10511
+ exports.useLearningContainersInCurrentThread = useLearningContainersInCurrentThread;
10065
10512
  exports.useRenderActivityMessage = useRenderActivityMessage;
10066
10513
  exports.useRenderCustomMessages = useRenderCustomMessages;
10067
10514
  exports.useRenderTool = useRenderTool;