@copilotkit/react-core 1.73.0 → 1.73.2-canary.1790068297

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.
@@ -3391,7 +3391,7 @@ function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
3391
3391
  }, [value, warningMessage]);
3392
3392
  return value;
3393
3393
  }
3394
- const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY_HEADERS, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = EMPTY_PROPERTIES, agents__unsafe_dev_only: agents = EMPTY_AGENTS, selfManagedAgents = EMPTY_AGENTS, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, enableInspector, agentId, useSingleEndpoint, onError, a2ui, defaultThrottleMs, debug }) => {
3394
+ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY_HEADERS, credentials, messageFilter, publicApiKey, publicLicenseKey, licenseToken, properties = EMPTY_PROPERTIES, agents__unsafe_dev_only: agents = EMPTY_AGENTS, selfManagedAgents = EMPTY_AGENTS, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, enableInspector, agentId, useSingleEndpoint, onError, a2ui, defaultThrottleMs, debug }) => {
3395
3395
  const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
3396
3396
  const [inspectorVisible, setInspectorVisible] = (0, react.useState)(false);
3397
3397
  (0, react.useEffect)(() => {
@@ -3512,6 +3512,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3512
3512
  const processedRenderToolCalls = [];
3513
3513
  humanInTheLoopList.forEach((tool) => {
3514
3514
  const frontendTool = {
3515
+ type: "human-in-the-loop",
3515
3516
  name: tool.name,
3516
3517
  description: tool.description,
3517
3518
  parameters: tool.parameters,
@@ -3618,6 +3619,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3618
3619
  runtimeTransport: useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto",
3619
3620
  headers: mergedHeaders,
3620
3621
  credentials,
3622
+ messageFilter,
3621
3623
  properties,
3622
3624
  agents__unsafe_dev_only: mergedAgents,
3623
3625
  tools: allTools,
@@ -3703,6 +3705,9 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3703
3705
  subscription.unsubscribe();
3704
3706
  };
3705
3707
  }, [copilotkit]);
3708
+ (0, react.useEffect)(() => {
3709
+ copilotkit.setMessageFilter(messageFilter);
3710
+ }, [copilotkit, messageFilter]);
3706
3711
  (0, react.useEffect)(() => {
3707
3712
  copilotkit.setRuntimeUrl(chatApiEndpoint);
3708
3713
  copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
@@ -3932,10 +3937,10 @@ function useRenderActivityMessage() {
3932
3937
 
3933
3938
  //#endregion
3934
3939
  //#region src/v2/hooks/use-frontend-tool.tsx
3935
- const EMPTY_DEPS$1 = [];
3940
+ const EMPTY_DEPS$2 = [];
3936
3941
  function useFrontendTool(tool, deps) {
3937
3942
  const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
3938
- const extraDeps = deps ?? EMPTY_DEPS$1;
3943
+ const extraDeps = deps ?? EMPTY_DEPS$2;
3939
3944
  (0, react.useLayoutEffect)(() => {
3940
3945
  const name = tool.name;
3941
3946
  if (copilotkit.getTool({
@@ -3964,6 +3969,103 @@ function useFrontendTool(tool, deps) {
3964
3969
  ]);
3965
3970
  }
3966
3971
 
3972
+ //#endregion
3973
+ //#region src/v2/hooks/use-frontend-tools.tsx
3974
+ const EMPTY_DEPS$1 = [];
3975
+ const EMPTY_TOOLS = [];
3976
+ /**
3977
+ * Register a list of frontend tools whose length can change between renders.
3978
+ *
3979
+ * `useFrontendTool` registers exactly one tool per call, so it cannot be called
3980
+ * in a loop over a runtime-length list without breaking the rules of hooks.
3981
+ * This hook runs a single effect over the whole array instead, which makes it
3982
+ * safe to build the list from state, props, or a server response.
3983
+ *
3984
+ * Tools are keyed by `name` plus `agentId`, the same as `useFrontendTool`. A
3985
+ * tool that disappears from the array is unregistered on the next render, and
3986
+ * every tool is unregistered on unmount. Renderers stay registered after
3987
+ * unmount so past tool calls still render in the chat history.
3988
+ *
3989
+ * @param tools - The tools to register. May be empty and may change length.
3990
+ * @param deps - Extra dependencies that force re-registration, compared by
3991
+ * identity like the second argument of `useEffect`. Use this when a handler
3992
+ * closes over a value that is not part of the tool definition. Keep the array
3993
+ * a constant length across renders.
3994
+ *
3995
+ * @example
3996
+ * Register one tool per item in application state:
3997
+ * ```tsx
3998
+ * const [reports, setReports] = useState<Report[]>([]);
3999
+ *
4000
+ * useFrontendTools(
4001
+ * reports.map((report) => ({
4002
+ * name: `open_${report.id}`,
4003
+ * description: `Open the ${report.title} report`,
4004
+ * handler: async () => navigate(`/reports/${report.id}`),
4005
+ * })),
4006
+ * [navigate],
4007
+ * );
4008
+ * ```
4009
+ *
4010
+ * @example
4011
+ * Register tools described by the backend:
4012
+ * ```tsx
4013
+ * const { data } = useQuery(fetchToolDescriptors);
4014
+ *
4015
+ * useFrontendTools(
4016
+ * (data ?? []).map((descriptor) => ({
4017
+ * name: descriptor.name,
4018
+ * description: descriptor.description,
4019
+ * parameters: z.object({ query: z.string() }),
4020
+ * handler: async ({ query }) => runDescriptor(descriptor.id, query),
4021
+ * })),
4022
+ * );
4023
+ * ```
4024
+ */
4025
+ function useFrontendTools(tools, deps) {
4026
+ const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
4027
+ const toolList = tools ?? EMPTY_TOOLS;
4028
+ const extraDeps = deps ?? EMPTY_DEPS$1;
4029
+ (0, react.useLayoutEffect)(() => {
4030
+ const deduped = /* @__PURE__ */ new Map();
4031
+ for (const tool of toolList) {
4032
+ const key = `${tool.agentId ?? ""}:${tool.name}`;
4033
+ if (deduped.has(key)) console.warn(`Tool '${tool.name}' is listed more than once for agent '${tool.agentId || "global"}' in the same useFrontendTools call. Using the last entry.`);
4034
+ deduped.set(key, tool);
4035
+ }
4036
+ const registered = [...deduped.values()];
4037
+ for (const tool of registered) {
4038
+ if (copilotkit.getTool({
4039
+ toolName: tool.name,
4040
+ agentId: tool.agentId
4041
+ })) {
4042
+ console.warn(`Tool '${tool.name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
4043
+ copilotkit.removeTool(tool.name, tool.agentId);
4044
+ }
4045
+ copilotkit.addTool(tool);
4046
+ if (tool.render) copilotkit.addHookRenderToolCall({
4047
+ name: tool.name,
4048
+ args: tool.parameters,
4049
+ agentId: tool.agentId,
4050
+ render: tool.render
4051
+ });
4052
+ }
4053
+ return () => {
4054
+ for (const tool of registered) copilotkit.removeTool(tool.name, tool.agentId);
4055
+ };
4056
+ }, [
4057
+ JSON.stringify(toolList.map((tool) => [
4058
+ tool.name,
4059
+ tool.description ?? null,
4060
+ tool.agentId ?? null,
4061
+ tool.available ?? null,
4062
+ tool.webmcp ?? null
4063
+ ])),
4064
+ copilotkit,
4065
+ ...extraDeps
4066
+ ]);
4067
+ }
4068
+
3967
4069
  //#endregion
3968
4070
  //#region src/v2/hooks/use-component.tsx
3969
4071
  /**
@@ -4380,6 +4482,7 @@ function useHumanInTheLoop(tool, deps) {
4380
4482
  ]);
4381
4483
  useFrontendTool({
4382
4484
  ...tool,
4485
+ type: "human-in-the-loop",
4383
4486
  handler,
4384
4487
  render: RenderComponent
4385
4488
  }, deps);
@@ -7525,6 +7628,13 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7525
7628
  return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
7526
7629
  };
7527
7630
  const deduplicatedMessages = (0, react.useMemo)(() => deduplicateMessages(messages), [messages]);
7631
+ const rowKeyStoreRef = (0, react.useRef)(null);
7632
+ rowKeyStoreRef.current ??= (0, _copilotkit_shared.createRowKeyStore)();
7633
+ const rowKeyStore = rowKeyStoreRef.current;
7634
+ const rowRenderKeys = (0, react.useMemo)(() => (0, _copilotkit_shared.resolveRowRenderKeysById)(rowKeyStore, deduplicatedMessages), [rowKeyStore, deduplicatedMessages]);
7635
+ (0, react.useLayoutEffect)(() => {
7636
+ (0, _copilotkit_shared.commitRowKeyStore)(rowKeyStore, deduplicatedMessages);
7637
+ }, [rowKeyStore, deduplicatedMessages]);
7528
7638
  if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Merged ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
7529
7639
  const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
7530
7640
  const agentId = config?.agentId;
@@ -7579,41 +7689,42 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7579
7689
  const renderMessageBlock = (message) => {
7580
7690
  const elements = [];
7581
7691
  const stateSnapshot = getStateSnapshotForMessage(message.id);
7692
+ const rowKey = rowRenderKeys.get(message.id) ?? message.id;
7582
7693
  if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
7583
7694
  message,
7584
7695
  position: "before",
7585
7696
  renderCustomMessage,
7586
7697
  stateSnapshot
7587
- }, `${message.id}-custom-before`));
7698
+ }, `${rowKey}-custom-before`));
7588
7699
  if (message.role === "assistant") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedAssistantMessage, {
7589
7700
  message,
7590
7701
  messages,
7591
7702
  isRunning,
7592
7703
  AssistantMessageComponent: AssistantComponent,
7593
7704
  slotProps: assistantSlotPropsWithFeedback
7594
- }, message.id));
7705
+ }, rowKey));
7595
7706
  else if (message.role === "user") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedUserMessage, {
7596
7707
  message,
7597
7708
  UserMessageComponent: UserComponent,
7598
7709
  slotProps: userSlotProps
7599
- }, message.id));
7710
+ }, rowKey));
7600
7711
  else if (message.role === "activity") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedActivityMessage, {
7601
7712
  message,
7602
7713
  renderActivityMessage
7603
- }, message.id));
7714
+ }, rowKey));
7604
7715
  else if (message.role === "reasoning") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedReasoningMessage, {
7605
7716
  message,
7606
7717
  messages,
7607
7718
  isRunning,
7608
7719
  ReasoningMessageComponent: ReasoningComponent,
7609
7720
  slotProps: reasoningSlotProps
7610
- }, message.id));
7721
+ }, rowKey));
7611
7722
  if (renderCustomMessage) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoizedCustomMessage, {
7612
7723
  message,
7613
7724
  position: "after",
7614
7725
  renderCustomMessage,
7615
7726
  stateSnapshot
7616
- }, `${message.id}-custom-after`));
7727
+ }, `${rowKey}-custom-after`));
7617
7728
  const intelligenceTurnId = intelligenceTurnAnchors.get(message.id);
7618
7729
  if (intelligenceTurnId !== void 0) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntelligenceIndicator, {
7619
7730
  message,
@@ -7659,7 +7770,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7659
7770
  transform: `translateY(${virtualItem.start}px)`
7660
7771
  },
7661
7772
  children: renderMessageBlock(message)
7662
- }, message.id);
7773
+ }, rowRenderKeys.get(message.id) ?? message.id);
7663
7774
  })
7664
7775
  }) : messageElements,
7665
7776
  interruptElement,
@@ -8972,14 +9083,7 @@ function CopilotChat({ agentId, threadId, labels, inspectorTools, chatView, isMo
8972
9083
  type: "text",
8973
9084
  text: value
8974
9085
  });
8975
- for (const att of readyAttachments) contentParts.push({
8976
- type: att.type,
8977
- source: att.source,
8978
- metadata: {
8979
- ...att.filename ? { filename: att.filename } : {},
8980
- ...att.metadata
8981
- }
8982
- });
9086
+ for (const att of readyAttachments) contentParts.push((0, _copilotkit_shared.createAttachmentContent)(att));
8983
9087
  agent.addMessage({
8984
9088
  id: (0, _copilotkit_shared.randomUUID)(),
8985
9089
  role: "user",
@@ -12803,6 +12907,12 @@ Object.defineProperty(exports, 'useFrontendTool', {
12803
12907
  return useFrontendTool;
12804
12908
  }
12805
12909
  });
12910
+ Object.defineProperty(exports, 'useFrontendTools', {
12911
+ enumerable: true,
12912
+ get: function () {
12913
+ return useFrontendTools;
12914
+ }
12915
+ });
12806
12916
  Object.defineProperty(exports, 'useHumanInTheLoop', {
12807
12917
  enumerable: true,
12808
12918
  get: function () {
@@ -12899,4 +13009,4 @@ Object.defineProperty(exports, 'useToast', {
12899
13009
  return useToast;
12900
13010
  }
12901
13011
  });
12902
- //# sourceMappingURL=copilotkit-tkBlMrXl.cjs.map
13012
+ //# sourceMappingURL=copilotkit-D_c2dJ9t.cjs.map