@copilotkitnext/react 1.52.0-next.6 → 1.52.0-next.7

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.
Files changed (41) hide show
  1. package/dist/components/chat/CopilotChatMessageView.cjs +18 -5
  2. package/dist/components/chat/CopilotChatMessageView.cjs.map +1 -1
  3. package/dist/components/chat/CopilotChatMessageView.d.cts +1 -0
  4. package/dist/components/chat/CopilotChatMessageView.d.cts.map +1 -1
  5. package/dist/components/chat/CopilotChatMessageView.d.mts +1 -0
  6. package/dist/components/chat/CopilotChatMessageView.d.mts.map +1 -1
  7. package/dist/components/chat/CopilotChatMessageView.mjs +19 -6
  8. package/dist/components/chat/CopilotChatMessageView.mjs.map +1 -1
  9. package/dist/hooks/index.cjs +1 -0
  10. package/dist/hooks/index.d.cts +2 -1
  11. package/dist/hooks/index.d.mts +2 -1
  12. package/dist/hooks/index.mjs +1 -0
  13. package/dist/hooks/use-interrupt.cjs +171 -0
  14. package/dist/hooks/use-interrupt.cjs.map +1 -0
  15. package/dist/hooks/use-interrupt.d.cts +102 -0
  16. package/dist/hooks/use-interrupt.d.cts.map +1 -0
  17. package/dist/hooks/use-interrupt.d.mts +102 -0
  18. package/dist/hooks/use-interrupt.d.mts.map +1 -0
  19. package/dist/hooks/use-interrupt.mjs +170 -0
  20. package/dist/hooks/use-interrupt.mjs.map +1 -0
  21. package/dist/index.cjs +2 -0
  22. package/dist/index.d.cts +3 -1
  23. package/dist/index.d.mts +3 -1
  24. package/dist/index.mjs +2 -1
  25. package/dist/index.umd.js +198 -5
  26. package/dist/index.umd.js.map +1 -1
  27. package/dist/lib/react-core.cjs +13 -0
  28. package/dist/lib/react-core.cjs.map +1 -1
  29. package/dist/lib/react-core.d.cts +8 -0
  30. package/dist/lib/react-core.d.cts.map +1 -1
  31. package/dist/lib/react-core.d.mts +8 -0
  32. package/dist/lib/react-core.d.mts.map +1 -1
  33. package/dist/lib/react-core.mjs +13 -0
  34. package/dist/lib/react-core.mjs.map +1 -1
  35. package/dist/types/index.d.cts +2 -1
  36. package/dist/types/index.d.mts +2 -1
  37. package/dist/types/interrupt.d.cts +17 -0
  38. package/dist/types/interrupt.d.cts.map +1 -0
  39. package/dist/types/interrupt.d.mts +17 -0
  40. package/dist/types/interrupt.d.mts.map +1 -0
  41. package/package.json +6 -6
package/dist/index.umd.js CHANGED
@@ -1798,6 +1798,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1798
1798
  _defineProperty(this, "_renderToolCalls", []);
1799
1799
  _defineProperty(this, "_renderCustomMessages", []);
1800
1800
  _defineProperty(this, "_renderActivityMessages", []);
1801
+ _defineProperty(this, "_interruptElement", null);
1801
1802
  this._renderToolCalls = (_config$renderToolCal = config.renderToolCalls) !== null && _config$renderToolCal !== void 0 ? _config$renderToolCal : [];
1802
1803
  this._renderCustomMessages = (_config$renderCustomM = config.renderCustomMessages) !== null && _config$renderCustomM !== void 0 ? _config$renderCustomM : [];
1803
1804
  this._renderActivityMessages = (_config$renderActivit = config.renderActivityMessages) !== null && _config$renderActivit !== void 0 ? _config$renderActivit : [];
@@ -1821,6 +1822,20 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1821
1822
  });
1822
1823
  }, "Subscriber onRenderToolCallsChanged error:");
1823
1824
  }
1825
+ get interruptElement() {
1826
+ return this._interruptElement;
1827
+ }
1828
+ setInterruptElement(element) {
1829
+ this._interruptElement = element;
1830
+ this.notifySubscribers((subscriber) => {
1831
+ var _reactSubscriber$onIn;
1832
+ const reactSubscriber = subscriber;
1833
+ (_reactSubscriber$onIn = reactSubscriber.onInterruptElementChanged) === null || _reactSubscriber$onIn === void 0 || _reactSubscriber$onIn.call(reactSubscriber, {
1834
+ copilotkit: this,
1835
+ interruptElement: this._interruptElement
1836
+ });
1837
+ }, "Subscriber onInterruptElementChanged error:");
1838
+ }
1824
1839
  subscribe(subscriber) {
1825
1840
  return super.subscribe(subscriber);
1826
1841
  }
@@ -2956,6 +2971,170 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
2956
2971
  });
2957
2972
  }
2958
2973
 
2974
+ //#endregion
2975
+ //#region src/hooks/use-interrupt.tsx
2976
+ const INTERRUPT_EVENT_NAME = "on_interrupt";
2977
+ function isPromiseLike(value) {
2978
+ return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
2979
+ }
2980
+ /**
2981
+ * Handles agent interrupts (`on_interrupt`) with optional filtering, preprocessing, and resume behavior.
2982
+ *
2983
+ * The hook listens to custom events on the active agent, stores interrupt payloads per run,
2984
+ * and surfaces a render callback once the run finalizes. Call `resolve` from your UI to resume
2985
+ * execution with user-provided data.
2986
+ *
2987
+ * - `renderInChat: true` (default): the element is published into `<CopilotChat>` and this hook returns `void`.
2988
+ * - `renderInChat: false`: the hook returns the interrupt element so you can place it anywhere in your component tree.
2989
+ *
2990
+ * `event.value` is typed as `any` since the interrupt payload shape depends on your agent.
2991
+ * Type-narrow it in your callbacks (e.g. `handler`, `enabled`, `render`) as needed.
2992
+ *
2993
+ * @typeParam TResult - Inferred from `handler` return type. Exposed as `result` in `render`.
2994
+ * @param config - Interrupt configuration (renderer, optional handler/filter, and render mode).
2995
+ * @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
2996
+ * Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
2997
+ * either the handler's resolved return value or `null` (including when no handler is provided,
2998
+ * when filtering skips the interrupt, or when handler execution fails).
2999
+ *
3000
+ * @example
3001
+ * ```tsx
3002
+ * import { useInterrupt } from "@copilotkitnext/react";
3003
+ *
3004
+ * function InterruptUI() {
3005
+ * useInterrupt({
3006
+ * render: ({ event, resolve }) => (
3007
+ * <div>
3008
+ * <p>{event.value.question}</p>
3009
+ * <button onClick={() => resolve({ approved: true })}>Approve</button>
3010
+ * <button onClick={() => resolve({ approved: false })}>Reject</button>
3011
+ * </div>
3012
+ * ),
3013
+ * });
3014
+ *
3015
+ * return null;
3016
+ * }
3017
+ * ```
3018
+ *
3019
+ * @example
3020
+ * ```tsx
3021
+ * import { useInterrupt } from "@copilotkitnext/react";
3022
+ *
3023
+ * function CustomPanel() {
3024
+ * const interruptElement = useInterrupt({
3025
+ * renderInChat: false,
3026
+ * enabled: (event) => event.value.startsWith("approval:"),
3027
+ * handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
3028
+ * render: ({ event, result, resolve }) => (
3029
+ * <aside>
3030
+ * <strong>{result?.label ?? ""}</strong>
3031
+ * <button onClick={() => resolve({ value: event.value })}>Continue</button>
3032
+ * </aside>
3033
+ * ),
3034
+ * });
3035
+ *
3036
+ * return <>{interruptElement}</>;
3037
+ * }
3038
+ * ```
3039
+ */
3040
+ function useInterrupt(config) {
3041
+ const { copilotkit } = useCopilotKit();
3042
+ const { agent } = useAgent({ agentId: config.agentId });
3043
+ const [pendingEvent, setPendingEvent] = (0, react.useState)(null);
3044
+ const [handlerResult, setHandlerResult] = (0, react.useState)(null);
3045
+ (0, react.useEffect)(() => {
3046
+ let localInterrupt = null;
3047
+ const subscription = agent.subscribe({
3048
+ onCustomEvent: ({ event }) => {
3049
+ if (event.name === INTERRUPT_EVENT_NAME) localInterrupt = {
3050
+ name: event.name,
3051
+ value: event.value
3052
+ };
3053
+ },
3054
+ onRunStartedEvent: () => {
3055
+ localInterrupt = null;
3056
+ setPendingEvent(null);
3057
+ },
3058
+ onRunFinalized: () => {
3059
+ if (localInterrupt) {
3060
+ setPendingEvent(localInterrupt);
3061
+ localInterrupt = null;
3062
+ }
3063
+ },
3064
+ onRunFailed: () => {
3065
+ localInterrupt = null;
3066
+ }
3067
+ });
3068
+ return () => subscription.unsubscribe();
3069
+ }, [agent]);
3070
+ const resolve = (0, react.useCallback)((response) => {
3071
+ setPendingEvent(null);
3072
+ copilotkit.runAgent({
3073
+ agent,
3074
+ forwardedProps: { command: { resume: response } }
3075
+ });
3076
+ }, [agent, copilotkit]);
3077
+ (0, react.useEffect)(() => {
3078
+ if (!pendingEvent) {
3079
+ setHandlerResult(null);
3080
+ return;
3081
+ }
3082
+ if (config.enabled && !config.enabled(pendingEvent)) {
3083
+ setHandlerResult(null);
3084
+ return;
3085
+ }
3086
+ const handler = config.handler;
3087
+ if (!handler) {
3088
+ setHandlerResult(null);
3089
+ return;
3090
+ }
3091
+ let cancelled = false;
3092
+ const maybePromise = handler({
3093
+ event: pendingEvent,
3094
+ resolve
3095
+ });
3096
+ if (isPromiseLike(maybePromise)) Promise.resolve(maybePromise).then((resolved) => {
3097
+ if (!cancelled) setHandlerResult(resolved);
3098
+ }).catch(() => {
3099
+ if (!cancelled) setHandlerResult(null);
3100
+ });
3101
+ else setHandlerResult(maybePromise);
3102
+ return () => {
3103
+ cancelled = true;
3104
+ };
3105
+ }, [
3106
+ pendingEvent,
3107
+ config.enabled,
3108
+ config.handler,
3109
+ resolve
3110
+ ]);
3111
+ const element = (0, react.useMemo)(() => {
3112
+ if (!pendingEvent) return null;
3113
+ if (config.enabled && !config.enabled(pendingEvent)) return null;
3114
+ return config.render({
3115
+ event: pendingEvent,
3116
+ result: handlerResult,
3117
+ resolve
3118
+ });
3119
+ }, [
3120
+ pendingEvent,
3121
+ handlerResult,
3122
+ config.enabled,
3123
+ config.render,
3124
+ resolve
3125
+ ]);
3126
+ (0, react.useEffect)(() => {
3127
+ if (config.renderInChat === false) return;
3128
+ copilotkit.setInterruptElement(element);
3129
+ return () => copilotkit.setInterruptElement(null);
3130
+ }, [
3131
+ element,
3132
+ config.renderInChat,
3133
+ copilotkit
3134
+ ]);
3135
+ if (config.renderInChat === false) return element;
3136
+ }
3137
+
2959
3138
  //#endregion
2960
3139
  //#region src/components/chat/CopilotChatToolCallsView.tsx
2961
3140
  function CopilotChatToolCallsView({ message, messages = [] }) {
@@ -3645,6 +3824,14 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3645
3824
  copilotkit,
3646
3825
  forceUpdate
3647
3826
  ]);
3827
+ const [interruptElement, setInterruptElement] = (0, react.useState)(null);
3828
+ (0, react.useEffect)(() => {
3829
+ setInterruptElement(copilotkit.interruptElement);
3830
+ const subscription = copilotkit.subscribe({ onInterruptElementChanged: ({ interruptElement }) => {
3831
+ setInterruptElement(interruptElement);
3832
+ } });
3833
+ return () => subscription.unsubscribe();
3834
+ }, [copilotkit]);
3648
3835
  const getStateSnapshotForMessage = (messageId) => {
3649
3836
  var _copilotkit$getRunIdF;
3650
3837
  if (!config) return void 0;
@@ -3719,7 +3906,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3719
3906
  children: children({
3720
3907
  messageElements,
3721
3908
  messages,
3722
- isRunning
3909
+ isRunning,
3910
+ interruptElement
3723
3911
  })
3724
3912
  });
3725
3913
  const lastMessage = messages[messages.length - 1];
@@ -3728,10 +3916,14 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3728
3916
  "data-copilotkit": true,
3729
3917
  className: (0, tailwind_merge.twMerge)("cpk:flex cpk:flex-col", className),
3730
3918
  ...props,
3731
- children: [messageElements, showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3732
- className: "cpk:mt-2",
3733
- children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
3734
- })]
3919
+ children: [
3920
+ messageElements,
3921
+ interruptElement,
3922
+ showCursor && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3923
+ className: "cpk:mt-2",
3924
+ children: renderSlot(cursor, CopilotChatMessageView.Cursor, {})
3925
+ })
3926
+ ]
3735
3927
  });
3736
3928
  }
3737
3929
  CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
@@ -4952,6 +5144,7 @@ exports.useCopilotKit = useCopilotKit;
4952
5144
  exports.useDefaultRenderTool = useDefaultRenderTool;
4953
5145
  exports.useFrontendTool = useFrontendTool;
4954
5146
  exports.useHumanInTheLoop = useHumanInTheLoop;
5147
+ exports.useInterrupt = useInterrupt;
4955
5148
  exports.useRenderActivityMessage = useRenderActivityMessage;
4956
5149
  exports.useRenderCustomMessages = useRenderCustomMessages;
4957
5150
  exports.useRenderTool = useRenderTool;