@copilotkit/react-core 1.79.1-canary.1792091124 → 1.79.2-canary.1792172552

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.
@@ -51,7 +51,7 @@ function shallowEqual(obj1, obj2) {
51
51
  * Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
52
52
  * class instances, and other exotic objects that happen to have typeof "object".
53
53
  */
54
- function isPlainObject(obj) {
54
+ function isPlainObject$1(obj) {
55
55
  return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
56
56
  }
57
57
  /**
@@ -70,7 +70,7 @@ function isPlainObject(obj) {
70
70
  function useShallowStableRef(value) {
71
71
  const ref = (0, react.useRef)(value);
72
72
  if (ref.current === value) return ref.current;
73
- if (isPlainObject(ref.current) && isPlainObject(value)) {
73
+ if (isPlainObject$1(ref.current) && isPlainObject$1(value)) {
74
74
  if (shallowEqual(ref.current, value)) return ref.current;
75
75
  }
76
76
  ref.current = value;
@@ -562,12 +562,86 @@ function useAgent({ agentId, threadId, runtimeAgentId, updates, throttleMs } = {
562
562
  };
563
563
  }
564
564
 
565
+ //#endregion
566
+ //#region src/v2/hooks/tool-registration.ts
567
+ /**
568
+ * Deps comparison shared by `useFrontendTool` (and through it
569
+ * `useHumanInTheLoop` and `useComponent`) and `useRenderTool`. Not part of the
570
+ * public API.
571
+ */
572
+ const EMPTY_DEPS$1 = [];
573
+ function isPlainObject(value) {
574
+ const proto = Object.getPrototypeOf(value);
575
+ return proto === Object.prototype || proto === null;
576
+ }
577
+ /**
578
+ * Plain data (primitives, plain objects, arrays, dates) compares by value.
579
+ * Functions always compare equal: these hooks used to compare
580
+ * `JSON.stringify(deps)`, which turns every function into `null`, and a
581
+ * function that counted as changed would re-register on every render when it
582
+ * is written inline (and loop in a component that also reads
583
+ * `useRenderToolCall`). Everything else (class instances, maps, sets) compares
584
+ * by identity. A cycle inside plain data is safe: a pair already being
585
+ * compared counts as equal for that branch.
586
+ */
587
+ function depEqual(a, b, seen) {
588
+ if (Object.is(a, b)) return true;
589
+ if (typeof a === "function" && typeof b === "function") return true;
590
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
591
+ if (a instanceof Date && b instanceof Date) return Object.is(a.getTime(), b.getTime());
592
+ const aIsArray = Array.isArray(a);
593
+ if (aIsArray !== Array.isArray(b)) return false;
594
+ if (!aIsArray && !(isPlainObject(a) && isPlainObject(b))) return false;
595
+ if (seen.get(a) === b) return true;
596
+ seen.set(a, b);
597
+ if (aIsArray) {
598
+ const left = a;
599
+ const right = b;
600
+ if (left.length !== right.length) return false;
601
+ for (let i = 0; i < left.length; i++) if (!depEqual(left[i], right[i], seen)) return false;
602
+ return true;
603
+ }
604
+ const left = a;
605
+ const right = b;
606
+ const leftKeys = Object.keys(left);
607
+ if (leftKeys.length !== Object.keys(right).length) return false;
608
+ for (const key of leftKeys) {
609
+ if (!Object.prototype.hasOwnProperty.call(right, key)) return false;
610
+ if (!depEqual(left[key], right[key], seen)) return false;
611
+ }
612
+ return true;
613
+ }
614
+ /** Whether two deps arrays are equal. A change in length is always a change. */
615
+ function depsEqual(prev, next) {
616
+ if (prev.length !== next.length) return false;
617
+ const seen = /* @__PURE__ */ new Map();
618
+ for (let i = 0; i < prev.length; i++) if (!depEqual(prev[i], next[i], seen)) return false;
619
+ return true;
620
+ }
621
+ /**
622
+ * Turns a caller's `deps` array into a number that changes exactly when the
623
+ * deps change, by the rules of {@link depsEqual}. Put the number, not the
624
+ * array, in the registration effect's dependency list: that keeps the list a
625
+ * constant length and never serializes a value.
626
+ */
627
+ function useDepsVersion(deps) {
628
+ const next = deps ?? EMPTY_DEPS$1;
629
+ const ref = (0, react.useRef)({
630
+ deps: next,
631
+ version: 0
632
+ });
633
+ if (ref.current.deps !== next && !depsEqual(ref.current.deps, next)) ref.current = {
634
+ deps: next,
635
+ version: ref.current.version + 1
636
+ };
637
+ return ref.current.version;
638
+ }
639
+
565
640
  //#endregion
566
641
  //#region src/v2/hooks/use-frontend-tool.tsx
567
- const EMPTY_DEPS$2 = [];
568
642
  function useFrontendTool(tool, deps) {
569
643
  const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
570
- const extraDeps = deps ?? EMPTY_DEPS$2;
644
+ const depsVersion = useDepsVersion(deps);
571
645
  (0, react.useLayoutEffect)(() => {
572
646
  const name = tool.name;
573
647
  if (copilotkit.getTool({
@@ -591,14 +665,14 @@ function useFrontendTool(tool, deps) {
591
665
  tool.name,
592
666
  tool.available,
593
667
  copilotkit,
594
- JSON.stringify(extraDeps),
668
+ depsVersion,
595
669
  JSON.stringify(tool.webmcp ?? null)
596
670
  ]);
597
671
  }
598
672
 
599
673
  //#endregion
600
674
  //#region src/v2/hooks/use-frontend-tools.tsx
601
- const EMPTY_DEPS$1 = [];
675
+ const EMPTY_DEPS = [];
602
676
  const EMPTY_TOOLS = [];
603
677
  /**
604
678
  * Register a list of frontend tools whose length can change between renders.
@@ -652,7 +726,7 @@ const EMPTY_TOOLS = [];
652
726
  function useFrontendTools(tools, deps) {
653
727
  const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
654
728
  const toolList = tools ?? EMPTY_TOOLS;
655
- const extraDeps = deps ?? EMPTY_DEPS$1;
729
+ const extraDeps = deps ?? EMPTY_DEPS;
656
730
  (0, react.useLayoutEffect)(() => {
657
731
  const deduped = /* @__PURE__ */ new Map();
658
732
  for (const tool of toolList) {
@@ -1570,7 +1644,6 @@ function defineToolCallRenderer(def) {
1570
1644
 
1571
1645
  //#endregion
1572
1646
  //#region src/v2/hooks/use-render-tool.tsx
1573
- const EMPTY_DEPS = [];
1574
1647
  /**
1575
1648
  * Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
1576
1649
  *
@@ -1614,7 +1687,7 @@ const EMPTY_DEPS = [];
1614
1687
  */
1615
1688
  function useRenderTool(config, deps) {
1616
1689
  const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
1617
- const extraDeps = deps ?? EMPTY_DEPS;
1690
+ const depsVersion = useDepsVersion(deps);
1618
1691
  (0, react.useEffect)(() => {
1619
1692
  const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
1620
1693
  name: "*",
@@ -1646,7 +1719,7 @@ function useRenderTool(config, deps) {
1646
1719
  }, [
1647
1720
  config.name,
1648
1721
  copilotkit,
1649
- JSON.stringify(extraDeps)
1722
+ depsVersion
1650
1723
  ]);
1651
1724
  }
1652
1725