@liveblocks/react-ui 2.25.0-aiprivatebeta9 → 3.0.0
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/_private/package.json +2 -2
- package/dist/_private/index.cjs +4 -0
- package/dist/_private/index.cjs.map +1 -1
- package/dist/_private/index.d.cts +8 -4
- package/dist/_private/index.d.ts +8 -4
- package/dist/_private/index.js +2 -0
- package/dist/_private/index.js.map +1 -1
- package/dist/components/AiChat.cjs +15 -19
- package/dist/components/AiChat.cjs.map +1 -1
- package/dist/components/AiChat.js +16 -20
- package/dist/components/AiChat.js.map +1 -1
- package/dist/components/AiTool.cjs +52 -28
- package/dist/components/AiTool.cjs.map +1 -1
- package/dist/components/AiTool.js +53 -29
- package/dist/components/AiTool.js.map +1 -1
- package/dist/components/Comment.cjs +254 -235
- package/dist/components/Comment.cjs.map +1 -1
- package/dist/components/Comment.js +255 -236
- package/dist/components/Comment.js.map +1 -1
- package/dist/components/Composer.cjs +42 -30
- package/dist/components/Composer.cjs.map +1 -1
- package/dist/components/Composer.js +44 -32
- package/dist/components/Composer.js.map +1 -1
- package/dist/components/Thread.cjs +7 -1
- package/dist/components/Thread.cjs.map +1 -1
- package/dist/components/Thread.js +8 -2
- package/dist/components/Thread.js.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.cjs +38 -6
- package/dist/components/internal/AiChatAssistantMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatAssistantMessage.js +39 -7
- package/dist/components/internal/AiChatAssistantMessage.js.map +1 -1
- package/dist/components/internal/AiChatComposer.cjs.map +1 -1
- package/dist/components/internal/AiChatComposer.js.map +1 -1
- package/dist/components/internal/AiChatUserMessage.cjs.map +1 -1
- package/dist/components/internal/AiChatUserMessage.js.map +1 -1
- package/dist/components/internal/CodeBlock.cjs +6 -3
- package/dist/components/internal/CodeBlock.cjs.map +1 -1
- package/dist/components/internal/CodeBlock.js +6 -3
- package/dist/components/internal/CodeBlock.js.map +1 -1
- package/dist/components/internal/Dropdown.cjs +1 -1
- package/dist/components/internal/Dropdown.cjs.map +1 -1
- package/dist/components/internal/Dropdown.js +2 -2
- package/dist/components/internal/Dropdown.js.map +1 -1
- package/dist/components/internal/EmojiPicker.cjs +1 -1
- package/dist/components/internal/EmojiPicker.cjs.map +1 -1
- package/dist/components/internal/EmojiPicker.js +2 -2
- package/dist/components/internal/EmojiPicker.js.map +1 -1
- package/dist/components/internal/InboxNotificationThread.cjs +5 -2
- package/dist/components/internal/InboxNotificationThread.cjs.map +1 -1
- package/dist/components/internal/InboxNotificationThread.js +6 -3
- package/dist/components/internal/InboxNotificationThread.js.map +1 -1
- package/dist/components/internal/Tooltip.cjs +1 -1
- package/dist/components/internal/Tooltip.cjs.map +1 -1
- package/dist/components/internal/Tooltip.js +2 -2
- package/dist/components/internal/Tooltip.js.map +1 -1
- package/dist/config.cjs +9 -9
- package/dist/config.cjs.map +1 -1
- package/dist/config.js +8 -8
- package/dist/config.js.map +1 -1
- package/dist/icons/CrossCircleFill.cjs +25 -0
- package/dist/icons/CrossCircleFill.cjs.map +1 -0
- package/dist/icons/CrossCircleFill.js +23 -0
- package/dist/icons/CrossCircleFill.js.map +1 -0
- package/dist/icons/MinusCircle.cjs +23 -0
- package/dist/icons/MinusCircle.cjs.map +1 -0
- package/dist/icons/MinusCircle.js +21 -0
- package/dist/icons/MinusCircle.js.map +1 -0
- package/dist/icons/index.cjs +4 -0
- package/dist/icons/index.cjs.map +1 -1
- package/dist/icons/index.js +2 -0
- package/dist/icons/index.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +232 -25
- package/dist/index.d.ts +232 -25
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/overrides.cjs +5 -1
- package/dist/overrides.cjs.map +1 -1
- package/dist/overrides.js +5 -1
- package/dist/overrides.js.map +1 -1
- package/dist/primitives/AiMessage/index.cjs +11 -67
- package/dist/primitives/AiMessage/index.cjs.map +1 -1
- package/dist/primitives/AiMessage/index.js +13 -69
- package/dist/primitives/AiMessage/index.js.map +1 -1
- package/dist/primitives/AiMessage/tool-invocation.cjs +70 -0
- package/dist/primitives/AiMessage/tool-invocation.cjs.map +1 -0
- package/dist/primitives/AiMessage/tool-invocation.js +68 -0
- package/dist/primitives/AiMessage/tool-invocation.js.map +1 -0
- package/dist/primitives/Collapsible/index.cjs +3 -3
- package/dist/primitives/Collapsible/index.cjs.map +1 -1
- package/dist/primitives/Collapsible/index.js +3 -3
- package/dist/primitives/Collapsible/index.js.map +1 -1
- package/dist/primitives/Comment/index.cjs +5 -4
- package/dist/primitives/Comment/index.cjs.map +1 -1
- package/dist/primitives/Comment/index.js +5 -4
- package/dist/primitives/Comment/index.js.map +1 -1
- package/dist/primitives/Composer/index.cjs +49 -41
- package/dist/primitives/Composer/index.cjs.map +1 -1
- package/dist/primitives/Composer/index.js +50 -42
- package/dist/primitives/Composer/index.js.map +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.cjs +4 -4
- package/dist/primitives/Composer/slate/plugins/mentions.cjs.map +1 -1
- package/dist/primitives/Composer/slate/plugins/mentions.js +4 -4
- package/dist/primitives/Composer/slate/plugins/mentions.js.map +1 -1
- package/dist/primitives/Composer/utils.cjs +3 -6
- package/dist/primitives/Composer/utils.cjs.map +1 -1
- package/dist/primitives/Composer/utils.js +3 -6
- package/dist/primitives/Composer/utils.js.map +1 -1
- package/dist/primitives/Markdown.cjs +6 -2
- package/dist/primitives/Markdown.cjs.map +1 -1
- package/dist/primitives/Markdown.js +6 -2
- package/dist/primitives/Markdown.js.map +1 -1
- package/dist/primitives/index.d.cts +18 -18
- package/dist/primitives/index.d.ts +18 -18
- package/dist/utils/use-controllable-state.cjs +25 -2
- package/dist/utils/use-controllable-state.cjs.map +1 -1
- package/dist/utils/use-controllable-state.js +25 -3
- package/dist/utils/use-controllable-state.js.map +1 -1
- package/dist/utils/use-visible.cjs +3 -1
- package/dist/utils/use-visible.cjs.map +1 -1
- package/dist/utils/use-visible.js +3 -1
- package/dist/utils/use-visible.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +16 -5
- package/primitives/package.json +2 -2
- package/src/styles/index.css +22 -4
- package/styles.css +1 -1
- package/styles.css.map +1 -1
|
@@ -5,13 +5,17 @@ var core = require('@liveblocks/core');
|
|
|
5
5
|
var react = require('react');
|
|
6
6
|
require('../_private/index.cjs');
|
|
7
7
|
require('../icons/index.cjs');
|
|
8
|
+
var overrides = require('../overrides.cjs');
|
|
8
9
|
var contexts = require('../primitives/AiMessage/contexts.cjs');
|
|
9
10
|
var index = require('../primitives/Collapsible/index.cjs');
|
|
10
11
|
var classNames = require('../utils/class-names.cjs');
|
|
12
|
+
var useControllableState = require('../utils/use-controllable-state.cjs');
|
|
11
13
|
var CodeBlock = require('./internal/CodeBlock.cjs');
|
|
12
14
|
var Button = require('./internal/Button.cjs');
|
|
13
15
|
var ChevronRight = require('../icons/ChevronRight.cjs');
|
|
14
16
|
var CheckCircleFill = require('../icons/CheckCircleFill.cjs');
|
|
17
|
+
var CrossCircleFill = require('../icons/CrossCircleFill.cjs');
|
|
18
|
+
var MinusCircle = require('../icons/MinusCircle.cjs');
|
|
15
19
|
var Spinner = require('../icons/Spinner.cjs');
|
|
16
20
|
|
|
17
21
|
function AiToolIcon({ className, ...props }) {
|
|
@@ -42,26 +46,31 @@ function AiToolConfirmation({
|
|
|
42
46
|
variant = "default",
|
|
43
47
|
confirm,
|
|
44
48
|
cancel,
|
|
49
|
+
overrides: overrides$1,
|
|
45
50
|
className,
|
|
46
51
|
...props
|
|
47
52
|
}) {
|
|
48
|
-
const {
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
[toolName, toolCallId]
|
|
53
|
-
);
|
|
53
|
+
const { stage, args, respond, name, invocationId } = contexts.useAiToolInvocationContext();
|
|
54
|
+
const $ = overrides.useOverrides(overrides$1);
|
|
55
|
+
const enabled = stage === "executing";
|
|
56
|
+
const context = react.useMemo(() => ({ name, invocationId }), [name, invocationId]);
|
|
54
57
|
const onConfirmClick = react.useCallback(async () => {
|
|
55
58
|
if (enabled) {
|
|
56
|
-
|
|
59
|
+
const result = await confirm(args, context);
|
|
60
|
+
respond(result ?? void 0);
|
|
57
61
|
}
|
|
58
62
|
}, [enabled, args, confirm, respond, context]);
|
|
59
63
|
const onCancelClick = react.useCallback(async () => {
|
|
60
64
|
if (enabled) {
|
|
61
|
-
|
|
65
|
+
if (cancel === void 0) {
|
|
66
|
+
respond({ cancel: true });
|
|
67
|
+
} else {
|
|
68
|
+
const result = await cancel(args, context);
|
|
69
|
+
respond(result ?? void 0);
|
|
70
|
+
}
|
|
62
71
|
}
|
|
63
72
|
}, [enabled, args, cancel, respond, context]);
|
|
64
|
-
if (
|
|
73
|
+
if (stage === "executed" && !children) {
|
|
65
74
|
return null;
|
|
66
75
|
}
|
|
67
76
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
@@ -72,22 +81,22 @@ function AiToolConfirmation({
|
|
|
72
81
|
className: "lb-ai-tool-confirmation-content",
|
|
73
82
|
children
|
|
74
83
|
}) : null,
|
|
75
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
84
|
+
stage !== "executed" && /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
76
85
|
className: "lb-ai-tool-confirmation-footer",
|
|
77
86
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
78
87
|
className: "lb-ai-tool-confirmation-actions",
|
|
79
88
|
children: [
|
|
80
89
|
/* @__PURE__ */ jsxRuntime.jsx(Button.Button, {
|
|
81
90
|
disabled: !enabled,
|
|
82
|
-
onClick:
|
|
83
|
-
variant:
|
|
84
|
-
children:
|
|
91
|
+
onClick: onCancelClick,
|
|
92
|
+
variant: "secondary",
|
|
93
|
+
children: $.AI_TOOL_CONFIRMATION_CANCEL
|
|
85
94
|
}),
|
|
86
95
|
/* @__PURE__ */ jsxRuntime.jsx(Button.Button, {
|
|
87
96
|
disabled: !enabled,
|
|
88
|
-
onClick:
|
|
89
|
-
variant: "
|
|
90
|
-
children:
|
|
97
|
+
onClick: onConfirmClick,
|
|
98
|
+
variant: variant === "destructive" ? "destructive" : "primary",
|
|
99
|
+
children: $.AI_TOOL_CONFIRMATION_CONFIRM
|
|
91
100
|
})
|
|
92
101
|
]
|
|
93
102
|
})
|
|
@@ -98,28 +107,43 @@ function AiToolConfirmation({
|
|
|
98
107
|
function prettifyString(string) {
|
|
99
108
|
return string.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase().replace(/^\w/, (character) => character.toUpperCase());
|
|
100
109
|
}
|
|
101
|
-
const noop = () => {
|
|
102
|
-
};
|
|
103
110
|
const AiTool = Object.assign(
|
|
104
111
|
react.forwardRef(
|
|
105
|
-
({
|
|
112
|
+
({
|
|
113
|
+
children,
|
|
114
|
+
title,
|
|
115
|
+
icon,
|
|
116
|
+
collapsed,
|
|
117
|
+
onCollapsedChange,
|
|
118
|
+
className,
|
|
119
|
+
...props
|
|
120
|
+
}, forwardedRef) => {
|
|
106
121
|
const {
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
stage,
|
|
123
|
+
result,
|
|
124
|
+
name,
|
|
109
125
|
[core.kInternal]: { execute }
|
|
110
126
|
} = contexts.useAiToolInvocationContext();
|
|
111
|
-
const [
|
|
127
|
+
const [semiControlledCollapsed, onSemiControlledCollapsed] = useControllableState.useSemiControllableState(collapsed ?? false, onCollapsedChange);
|
|
112
128
|
const hasContent = react.Children.count(children) > 0;
|
|
113
129
|
const resolvedTitle = react.useMemo(() => {
|
|
114
|
-
return title ?? prettifyString(
|
|
115
|
-
}, [title,
|
|
130
|
+
return title ?? prettifyString(name);
|
|
131
|
+
}, [title, name]);
|
|
132
|
+
const handleCollapsibleOpenChange = react.useCallback(
|
|
133
|
+
(open) => {
|
|
134
|
+
onSemiControlledCollapsed(!open);
|
|
135
|
+
},
|
|
136
|
+
[onSemiControlledCollapsed]
|
|
137
|
+
);
|
|
116
138
|
return /* @__PURE__ */ jsxRuntime.jsxs(index.Root, {
|
|
117
139
|
ref: forwardedRef,
|
|
118
140
|
className: classNames.classNames("lb-collapsible lb-ai-tool", className),
|
|
119
141
|
...props,
|
|
120
|
-
open: hasContent ?
|
|
121
|
-
onOpenChange:
|
|
142
|
+
open: hasContent ? !semiControlledCollapsed : false,
|
|
143
|
+
onOpenChange: handleCollapsibleOpenChange,
|
|
122
144
|
disabled: !hasContent,
|
|
145
|
+
"data-result": result?.type,
|
|
146
|
+
"data-stage": stage,
|
|
123
147
|
children: [
|
|
124
148
|
/* @__PURE__ */ jsxRuntime.jsxs(index.Trigger, {
|
|
125
149
|
className: "lb-collapsible-trigger lb-ai-tool-header",
|
|
@@ -138,11 +162,11 @@ const AiTool = Object.assign(
|
|
|
138
162
|
}) : null,
|
|
139
163
|
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
140
164
|
className: "lb-ai-tool-header-status",
|
|
141
|
-
children:
|
|
165
|
+
children: stage === "executed" ? result.type === "success" ? /* @__PURE__ */ jsxRuntime.jsx(CheckCircleFill.CheckCircleFillIcon, {}) : result.type === "error" ? /* @__PURE__ */ jsxRuntime.jsx(CrossCircleFill.CrossCircleFillIcon, {}) : result.type === "cancelled" ? /* @__PURE__ */ jsxRuntime.jsx(MinusCircle.MinusCircleIcon, {}) : null : execute !== void 0 ? /* @__PURE__ */ jsxRuntime.jsx(Spinner.SpinnerIcon, {}) : null
|
|
142
166
|
})
|
|
143
167
|
]
|
|
144
168
|
}),
|
|
145
|
-
|
|
169
|
+
hasContent ? /* @__PURE__ */ jsxRuntime.jsx(index.Content, {
|
|
146
170
|
className: "lb-collapsible-content lb-ai-tool-content-container",
|
|
147
171
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
148
172
|
className: "lb-ai-tool-content",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiTool.cjs","sources":["../../src/components/AiTool.tsx"],"sourcesContent":["import {\n type AiToolExecuteCallback,\n type AiToolTypePack,\n type JsonObject,\n kInternal,\n type ToolResultData,\n} from \"@liveblocks/core\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Children, forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport { Button } from \"../_private\";\nimport { CheckCircleFillIcon, ChevronRightIcon, SpinnerIcon } from \"../icons\";\nimport { useAiToolInvocationContext } from \"../primitives/AiMessage/contexts\";\nimport * as Collapsible from \"../primitives/Collapsible\";\nimport { classNames } from \"../utils/class-names\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\n\nexport interface AiToolProps\n extends Omit<ComponentProps<\"div\">, \"title\" | \"children\"> {\n /**\n * The tool's title.\n *\n * By default, a human-readable version of the tool's name is used:\n * - `\"showTodo\"` → \"Show todo\"\n * - `\"get_weather\"` → \"Get weather\"\n */\n title?: string;\n\n /**\n * An optional icon displayed next to the title.\n */\n icon?: ReactNode;\n\n /**\n * The content shown in the tool.\n */\n children?: ReactNode;\n}\n\nexport type AiToolIconProps = ComponentProps<\"div\">;\n\nexport type AiToolInspectorProps = ComponentProps<\"div\">;\n\n// TODO: AiToolConfirmationProps might need a generic since we're outside of the\n// tool definition so things like inferred args and result types are not\n// available here for `confirm` and `cancel`\n\n/**\n * @private This API will change, and is not considered stable. DO NOT RELY on it.\n *\n * This component can be used to build human-in-the-loop interfaces.\n */\nexport interface AiToolConfirmationProps<\n A extends JsonObject,\n R extends ToolResultData,\n> extends ComponentProps<\"div\"> {\n args?: A;\n confirm: AiToolExecuteCallback<A, R>;\n cancel: AiToolExecuteCallback<A, R>;\n variant?: \"default\" | \"destructive\";\n\n // TODO: Use existing overrides API to allow customizing the \"Confirm\" and \"Cancel\" labels\n // overrides?: Partial<GlobalOverrides & AiToolConfirmationOverrides>;\n}\n\nfunction AiToolIcon({ className, ...props }: AiToolIconProps) {\n return (\n <div className={classNames(\"lb-ai-tool-icon\", className)} {...props} />\n );\n}\n\nfunction AiToolInspector({ className, ...props }: AiToolInspectorProps) {\n const { args, partialArgs, result } = useAiToolInvocationContext();\n\n return (\n <div className={classNames(\"lb-ai-tool-inspector\", className)} {...props}>\n <CodeBlock\n title=\"Arguments\"\n code={JSON.stringify(args ?? partialArgs, null, 2)}\n />\n {result !== undefined ? (\n <CodeBlock title=\"Result\" code={JSON.stringify(result, null, 2)} />\n ) : null}\n </div>\n );\n}\n\nfunction AiToolConfirmation<\n TPack extends AiToolTypePack,\n A extends JsonObject = TPack[\"A\"],\n R extends ToolResultData = TPack[\"R\"],\n>({\n children,\n variant = \"default\",\n confirm,\n cancel,\n className,\n ...props\n}: AiToolConfirmationProps<A, R>) {\n const { status, args, respond, toolName, toolCallId } =\n useAiToolInvocationContext();\n\n const enabled = status === \"executing\";\n\n const context = useMemo(\n () => ({ toolName, toolCallId }),\n [toolName, toolCallId]\n );\n\n const onConfirmClick = useCallback(async () => {\n if (enabled) {\n respond(await confirm(args as A, context));\n }\n }, [enabled, args, confirm, respond, context]);\n\n const onCancelClick = useCallback(async () => {\n if (enabled) {\n respond(await cancel(args as A, context));\n }\n }, [enabled, args, cancel, respond, context]);\n\n if (status === \"executed\") {\n return null;\n }\n\n return (\n <div\n className={classNames(\"lb-ai-tool-confirmation\", className)}\n {...props}\n >\n {children ? (\n <div className=\"lb-ai-tool-confirmation-content\">{children}</div>\n ) : null}\n <div className=\"lb-ai-tool-confirmation-footer\">\n <div className=\"lb-ai-tool-confirmation-actions\">\n <Button\n disabled={!enabled}\n onClick={onConfirmClick}\n variant={variant === \"destructive\" ? \"destructive\" : \"primary\"}\n >\n Confirm\n </Button>\n <Button\n disabled={!enabled}\n onClick={onCancelClick}\n variant=\"secondary\"\n >\n Cancel\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction prettifyString(string: string) {\n return (\n string\n // Convert camelCase to spaces\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n // Convert snake_case and kebab-case to spaces\n .replace(/[_-]+/g, \" \")\n // Collapse multiple following spaces\n .replace(/\\s+/g, \" \")\n // Trim leading and trailing spaces\n .trim()\n // Capitalize first word\n .toLowerCase()\n .replace(/^\\w/, (character) => character.toUpperCase())\n );\n}\n\nconst noop = () => {};\n\nexport const AiTool = Object.assign(\n forwardRef<HTMLDivElement, AiToolProps>(\n ({ children, title, icon, className, ...props }, forwardedRef) => {\n const {\n status,\n toolName,\n [kInternal]: { execute },\n } = useAiToolInvocationContext();\n const [isOpen, setIsOpen] = useState(true);\n // TODO: This check won't work for cases like:\n // <AiTool>\n // <ComponentThatRendersNull />\n // <ComponentThatAlsoRendersNull />\n // </AiTool>\n // One solution could be to check the DOM on every render with `useLayoutEffect`\n // to see if there's any actual content.\n const hasContent = Children.count(children) > 0;\n const resolvedTitle = useMemo(() => {\n return title ?? prettifyString(toolName);\n }, [title, toolName]);\n\n return (\n <Collapsible.Root\n ref={forwardedRef}\n className={classNames(\"lb-collapsible lb-ai-tool\", className)}\n {...props}\n open={hasContent ? isOpen : false}\n onOpenChange={hasContent ? setIsOpen : noop}\n disabled={!hasContent}\n >\n <Collapsible.Trigger className=\"lb-collapsible-trigger lb-ai-tool-header\">\n {icon ? (\n <div className=\"lb-ai-tool-header-icon-container\">{icon}</div>\n ) : null}\n <span className=\"lb-ai-tool-header-title\">{resolvedTitle}</span>\n {hasContent ? (\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n ) : null}\n <div className=\"lb-ai-tool-header-status\">\n {status === \"executed\" ? (\n <CheckCircleFillIcon />\n ) : execute !== undefined ? (\n // Only show a spinner if the tool has an `execute` method.\n <SpinnerIcon />\n ) : null}\n </div>\n </Collapsible.Trigger>\n\n {children ? (\n <Collapsible.Content className=\"lb-collapsible-content lb-ai-tool-content-container\">\n <div className=\"lb-ai-tool-content\">{children}</div>\n </Collapsible.Content>\n ) : null}\n </Collapsible.Root>\n );\n }\n ),\n {\n Icon: AiToolIcon,\n Inspector: AiToolInspector,\n Confirmation: AiToolConfirmation,\n }\n);\n"],"names":["jsx","classNames","useAiToolInvocationContext","jsxs","CodeBlock","useMemo","useCallback","Button","forwardRef","kInternal","useState","Children","Collapsible.Root","Collapsible.Trigger","ChevronRightIcon","CheckCircleFillIcon","SpinnerIcon","Collapsible.Content"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiTool.cjs","sources":["../../src/components/AiTool.tsx"],"sourcesContent":["import type {\n AiToolExecuteCallback,\n AiToolTypePack,\n JsonObject,\n NoInfr,\n} from \"@liveblocks/core\";\nimport { kInternal } from \"@liveblocks/core\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Children, forwardRef, useCallback, useMemo } from \"react\";\n\nimport { Button } from \"../_private\";\nimport {\n CheckCircleFillIcon,\n ChevronRightIcon,\n CrossCircleFillIcon,\n MinusCircleIcon,\n SpinnerIcon,\n} from \"../icons\";\nimport {\n type AiToolConfirmationOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport { useAiToolInvocationContext } from \"../primitives/AiMessage/contexts\";\nimport * as Collapsible from \"../primitives/Collapsible\";\nimport { classNames } from \"../utils/class-names\";\nimport { useSemiControllableState } from \"../utils/use-controllable-state\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\n\nexport interface AiToolProps\n extends Omit<ComponentProps<\"div\">, \"title\" | \"children\"> {\n /**\n * The tool's title.\n *\n * By default, a human-readable version of the tool's name is used:\n * - `\"showTodo\"` → \"Show todo\"\n * - `\"get_weather\"` → \"Get weather\"\n */\n title?: string;\n\n /**\n * An optional icon displayed next to the title.\n */\n icon?: ReactNode;\n\n /**\n * The content shown in the tool.\n */\n children?: ReactNode;\n\n /**\n * Whether the content is currently collapsed.\n * It is not a traditional controlled value, as in if you set it to `true` it would only stay expanded.\n * Instead, it is \"semi-controlled\", meaning that setting it to `true` will expand it, but it\n * can still be collapsed/expanded by clicking on it.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the content is collapsed or expanded by clicking on it.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n}\n\nexport type AiToolIconProps = ComponentProps<\"div\">;\n\nexport type AiToolInspectorProps = ComponentProps<\"div\">;\n\nexport interface AiToolConfirmationProps<\n A extends JsonObject,\n R extends JsonObject,\n> extends ComponentProps<\"div\"> {\n /**\n * The callback invoked when the user clicks the confirm button.\n */\n confirm: AiToolExecuteCallback<A, R>;\n\n /**\n * The callback invoked when the user clicks the cancel button.\n */\n cancel?: AiToolExecuteCallback<A, R>;\n\n /**\n * The visual appearance.\n */\n variant?: \"default\" | \"destructive\";\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & AiToolConfirmationOverrides>;\n\n /**\n * The tool's result type, to be used with the `types` prop in the `render` method.\n *\n * @example\n * defineAiTool<{ value: number }>()({\n * // ...\n * render: ({ types }) => (\n * <AiTool.Confirmation\n * types={types}\n * confirm={() => {\n * return {\n * // Using `types` makes the result type-safe\n * // based on the tool's definition\n * data: { value: 123 },\n * };\n * }}\n * />\n * ),\n * })\n */\n types?: NoInfr<AiToolTypePack<A, R>>;\n}\n\nfunction AiToolIcon({ className, ...props }: AiToolIconProps) {\n return (\n <div className={classNames(\"lb-ai-tool-icon\", className)} {...props} />\n );\n}\n\nfunction AiToolInspector({ className, ...props }: AiToolInspectorProps) {\n const { args, partialArgs, result } = useAiToolInvocationContext();\n\n return (\n <div className={classNames(\"lb-ai-tool-inspector\", className)} {...props}>\n <CodeBlock\n title=\"Arguments\"\n code={JSON.stringify(args ?? partialArgs, null, 2)}\n />\n {result !== undefined ? (\n <CodeBlock title=\"Result\" code={JSON.stringify(result, null, 2)} />\n ) : null}\n </div>\n );\n}\n\nfunction AiToolConfirmation<\n TPack extends AiToolTypePack,\n A extends JsonObject = TPack[\"A\"],\n R extends JsonObject = TPack[\"R\"],\n>({\n children,\n variant = \"default\",\n confirm,\n cancel,\n overrides,\n className,\n ...props\n}: AiToolConfirmationProps<A, R>) {\n const { stage, args, respond, name, invocationId } =\n useAiToolInvocationContext();\n const $ = useOverrides(overrides);\n\n const enabled = stage === \"executing\";\n\n const context = useMemo(() => ({ name, invocationId }), [name, invocationId]);\n\n const onConfirmClick = useCallback(async () => {\n if (enabled) {\n const result = await confirm(args as A, context);\n respond(result ?? undefined);\n }\n }, [enabled, args, confirm, respond, context]);\n\n const onCancelClick = useCallback(async () => {\n if (enabled) {\n if (cancel === undefined) {\n respond({ cancel: true });\n } else {\n const result = await cancel(args as A, context);\n respond(result ?? undefined);\n }\n }\n }, [enabled, args, cancel, respond, context]);\n\n // If there's no content and the tool has been executed (so there's no\n // confirmation UI displayed either), don't render anything.\n if (stage === \"executed\" && !children) {\n return null;\n }\n\n return (\n <div\n className={classNames(\"lb-ai-tool-confirmation\", className)}\n {...props}\n >\n {children ? (\n <div className=\"lb-ai-tool-confirmation-content\">{children}</div>\n ) : null}\n {stage !== \"executed\" && (\n <div className=\"lb-ai-tool-confirmation-footer\">\n <div className=\"lb-ai-tool-confirmation-actions\">\n <Button\n disabled={!enabled}\n onClick={onCancelClick}\n variant=\"secondary\"\n >\n {$.AI_TOOL_CONFIRMATION_CANCEL}\n </Button>\n <Button\n disabled={!enabled}\n onClick={onConfirmClick}\n variant={variant === \"destructive\" ? \"destructive\" : \"primary\"}\n >\n {$.AI_TOOL_CONFIRMATION_CONFIRM}\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction prettifyString(string: string) {\n return (\n string\n // Convert camelCase to spaces\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n // Convert snake_case and kebab-case to spaces\n .replace(/[_-]+/g, \" \")\n // Collapse multiple following spaces\n .replace(/\\s+/g, \" \")\n // Trim leading and trailing spaces\n .trim()\n // Capitalize first word\n .toLowerCase()\n .replace(/^\\w/, (character) => character.toUpperCase())\n );\n}\n\n/**\n * A pre-built component which displays a tool call.\n *\n * By default, a human-readable version of the tool's name is used as a title:\n * - `\"showTodo\"` → \"Show todo\"\n * - `\"get_weather\"` → \"Get weather\"\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: () => (\n * <AiTool />\n * ),\n * })\n *\n * It can be customized in various ways:\n * - adding an icon\n * - customizing the title (even dynamically)\n * - adding custom content inside it\n * - collapsing it conditionally\n * - etc.\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: ({ stage, result }) => (\n * <AiTool\n * icon=\"🔍\"\n *\n * // Override the default title based on the tool's stage\n * title={stage === \"executing\" ? \"Searching…\" : \"Search results\"}\n *\n * // Start open and automatically collapse after it is executed\n * // The user can still expand/collapse it manually at any time\n * collapsed={stage === \"executed\"}\n * >\n * <SearchResults data={result.data} />\n * </AiTool>\n * ),\n * })\n *\n * It also comes with a few built-in sub-components:\n * - `AiTool.Confirmation` to display a human-in-the-loop confirmation step\n * which can be accepted or cancelled by the user.\n * - `AiTool.Inspector` to display the tool's arguments and result which can\n * be useful during development.\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: () => (\n * <AiTool>\n * <AiTool.Confirmation\n * // Use a destructive visual appearance\n * variant=\"destructive\"\n *\n * // The tool's arguments can be directly accessed like in `execute`\n * confirm={({ pageIds }) => {\n * const deletedPageTitles = pages\n * .filter((p) => pageIds.includes(p.id))\n * .map((page) => page.title);\n *\n * deletePages(pageIds);\n *\n * // This result will be available as `result` in the tool's `render` props\n * return { data: { deletedPageTitles } };\n * }}\n *\n * // If needed, `cancel={() => ...}` would work similarly\n * >\n * Do you want to delete these pages?\n * <PagesPreviews />\n * </AiTool.Confirmation>\n * </AiTool>\n * ),\n * })\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: () => (\n * <AiTool>\n * <AiTool.Inspector />\n * </AiTool>\n * ),\n * })\n */\nexport const AiTool = Object.assign(\n forwardRef<HTMLDivElement, AiToolProps>(\n (\n {\n children,\n title,\n icon,\n collapsed,\n onCollapsedChange,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const {\n stage,\n result,\n name,\n [kInternal]: { execute },\n } = useAiToolInvocationContext();\n const [semiControlledCollapsed, onSemiControlledCollapsed] =\n useSemiControllableState(collapsed ?? false, onCollapsedChange);\n // TODO: This check won't work for cases like:\n // <AiTool>\n // <ComponentThatRendersNull />\n // <ComponentThatAlsoRendersNull />\n // </AiTool>\n // One solution could be to check the DOM on every render with `useLayoutEffect`\n // to see if there's any actual content.\n // For now we're limiting the visual issues caused by the above by using CSS's\n // `:empty` pseudo-class to make the content 0px high if it's actually empty.\n const hasContent = Children.count(children) > 0;\n const resolvedTitle = useMemo(() => {\n return title ?? prettifyString(name);\n }, [title, name]);\n\n // `AiTool` uses \"collapsed\" instead of \"open\" (like the `Composer` component) because \"open\"\n // makes sense next to something called \"Collapsible\" but less so for something called \"AiTool\".\n const handleCollapsibleOpenChange = useCallback(\n (open: boolean) => {\n onSemiControlledCollapsed(!open);\n },\n [onSemiControlledCollapsed]\n );\n\n return (\n <Collapsible.Root\n ref={forwardedRef}\n className={classNames(\"lb-collapsible lb-ai-tool\", className)}\n {...props}\n // Regardless of `semiControlledCollapsed`, the collapsible is closed if there's no content.\n open={hasContent ? !semiControlledCollapsed : false}\n onOpenChange={handleCollapsibleOpenChange}\n disabled={!hasContent}\n data-result={result?.type}\n data-stage={stage}\n >\n <Collapsible.Trigger className=\"lb-collapsible-trigger lb-ai-tool-header\">\n {icon ? (\n <div className=\"lb-ai-tool-header-icon-container\">{icon}</div>\n ) : null}\n <span className=\"lb-ai-tool-header-title\">{resolvedTitle}</span>\n {hasContent ? (\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n ) : null}\n <div className=\"lb-ai-tool-header-status\">\n {stage === \"executed\" ? (\n result.type === \"success\" ? (\n <CheckCircleFillIcon />\n ) : result.type === \"error\" ? (\n <CrossCircleFillIcon />\n ) : result.type === \"cancelled\" ? (\n <MinusCircleIcon />\n ) : null\n ) : execute !== undefined ? (\n // Only show a spinner if the tool has an `execute` method.\n <SpinnerIcon />\n ) : null}\n </div>\n </Collapsible.Trigger>\n\n {hasContent ? (\n <Collapsible.Content className=\"lb-collapsible-content lb-ai-tool-content-container\">\n <div className=\"lb-ai-tool-content\">{children}</div>\n </Collapsible.Content>\n ) : null}\n </Collapsible.Root>\n );\n }\n ),\n {\n /**\n * Display an icon in a container.\n *\n * @example\n * <AiTool\n * icon={\n * <AiTool.Icon>🔍</AiTool.Icon>\n * }\n * />\n */\n Icon: AiToolIcon,\n\n /**\n * Display the tool's arguments and result, which can be useful during\n * development.\n *\n * @example\n * <AiTool>\n * <AiTool.Inspector />\n * </AiTool>\n */\n Inspector: AiToolInspector,\n\n /**\n * Display a human-in-the-loop confirmation step which can be accepted\n * or cancelled by the user.\n *\n * The `confirm` and `cancel` callbacks work like `execute` in tool definitions: they can\n * perform side-effects, be async if needed, and return a result. The tool call will stay\n * pending until either `confirm` or `cancel` is called.\n *\n * @example\n * <AiTool>\n * <AiTool.Confirmation\n * // Use a destructive visual appearance\n * variant=\"destructive\"\n *\n * // The tool's arguments can be directly accessed like in `execute`\n * confirm={({ pageIds }) => {\n * const deletedPageTitles = pages\n * .filter((p) => pageIds.includes(p.id))\n * .map((page) => page.title);\n *\n * deletePages(pageIds);\n *\n * // This result will be available as `result` in the tool's `render` props\n * return { data: { deletedPageTitles } };\n * }}\n *\n * // If needed, `cancel={() => ...}` would work similarly\n * >\n * Do you want to delete these pages?\n * <PagesPreviews />\n * </AiTool.Confirmation>\n * </AiTool>\n */\n Confirmation: AiToolConfirmation,\n }\n);\n"],"names":["jsx","classNames","useAiToolInvocationContext","jsxs","CodeBlock","overrides","useOverrides","useMemo","useCallback","Button","forwardRef","kInternal","useSemiControllableState","Children","Collapsible.Root","Collapsible.Trigger","ChevronRightIcon","CheckCircleFillIcon","CrossCircleFillIcon","MinusCircleIcon","SpinnerIcon","Collapsible.Content"],"mappings":"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"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { kInternal } from '@liveblocks/core';
|
|
3
|
-
import { useMemo, useCallback, forwardRef,
|
|
3
|
+
import { useMemo, useCallback, forwardRef, Children } from 'react';
|
|
4
4
|
import '../_private/index.js';
|
|
5
5
|
import '../icons/index.js';
|
|
6
|
+
import { useOverrides } from '../overrides.js';
|
|
6
7
|
import { useAiToolInvocationContext } from '../primitives/AiMessage/contexts.js';
|
|
7
8
|
import { Root as CollapsibleRoot, Trigger as CollapsibleTrigger, Content as CollapsibleContent } from '../primitives/Collapsible/index.js';
|
|
8
9
|
import { classNames } from '../utils/class-names.js';
|
|
10
|
+
import { useSemiControllableState } from '../utils/use-controllable-state.js';
|
|
9
11
|
import { CodeBlock } from './internal/CodeBlock.js';
|
|
10
12
|
import { Button } from './internal/Button.js';
|
|
11
13
|
import { ChevronRightIcon } from '../icons/ChevronRight.js';
|
|
12
14
|
import { CheckCircleFillIcon } from '../icons/CheckCircleFill.js';
|
|
15
|
+
import { CrossCircleFillIcon } from '../icons/CrossCircleFill.js';
|
|
16
|
+
import { MinusCircleIcon } from '../icons/MinusCircle.js';
|
|
13
17
|
import { SpinnerIcon } from '../icons/Spinner.js';
|
|
14
18
|
|
|
15
19
|
function AiToolIcon({ className, ...props }) {
|
|
@@ -40,26 +44,31 @@ function AiToolConfirmation({
|
|
|
40
44
|
variant = "default",
|
|
41
45
|
confirm,
|
|
42
46
|
cancel,
|
|
47
|
+
overrides,
|
|
43
48
|
className,
|
|
44
49
|
...props
|
|
45
50
|
}) {
|
|
46
|
-
const {
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
[toolName, toolCallId]
|
|
51
|
-
);
|
|
51
|
+
const { stage, args, respond, name, invocationId } = useAiToolInvocationContext();
|
|
52
|
+
const $ = useOverrides(overrides);
|
|
53
|
+
const enabled = stage === "executing";
|
|
54
|
+
const context = useMemo(() => ({ name, invocationId }), [name, invocationId]);
|
|
52
55
|
const onConfirmClick = useCallback(async () => {
|
|
53
56
|
if (enabled) {
|
|
54
|
-
|
|
57
|
+
const result = await confirm(args, context);
|
|
58
|
+
respond(result ?? void 0);
|
|
55
59
|
}
|
|
56
60
|
}, [enabled, args, confirm, respond, context]);
|
|
57
61
|
const onCancelClick = useCallback(async () => {
|
|
58
62
|
if (enabled) {
|
|
59
|
-
|
|
63
|
+
if (cancel === void 0) {
|
|
64
|
+
respond({ cancel: true });
|
|
65
|
+
} else {
|
|
66
|
+
const result = await cancel(args, context);
|
|
67
|
+
respond(result ?? void 0);
|
|
68
|
+
}
|
|
60
69
|
}
|
|
61
70
|
}, [enabled, args, cancel, respond, context]);
|
|
62
|
-
if (
|
|
71
|
+
if (stage === "executed" && !children) {
|
|
63
72
|
return null;
|
|
64
73
|
}
|
|
65
74
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -70,22 +79,22 @@ function AiToolConfirmation({
|
|
|
70
79
|
className: "lb-ai-tool-confirmation-content",
|
|
71
80
|
children
|
|
72
81
|
}) : null,
|
|
73
|
-
/* @__PURE__ */ jsx("div", {
|
|
82
|
+
stage !== "executed" && /* @__PURE__ */ jsx("div", {
|
|
74
83
|
className: "lb-ai-tool-confirmation-footer",
|
|
75
84
|
children: /* @__PURE__ */ jsxs("div", {
|
|
76
85
|
className: "lb-ai-tool-confirmation-actions",
|
|
77
86
|
children: [
|
|
78
87
|
/* @__PURE__ */ jsx(Button, {
|
|
79
88
|
disabled: !enabled,
|
|
80
|
-
onClick:
|
|
81
|
-
variant:
|
|
82
|
-
children:
|
|
89
|
+
onClick: onCancelClick,
|
|
90
|
+
variant: "secondary",
|
|
91
|
+
children: $.AI_TOOL_CONFIRMATION_CANCEL
|
|
83
92
|
}),
|
|
84
93
|
/* @__PURE__ */ jsx(Button, {
|
|
85
94
|
disabled: !enabled,
|
|
86
|
-
onClick:
|
|
87
|
-
variant: "
|
|
88
|
-
children:
|
|
95
|
+
onClick: onConfirmClick,
|
|
96
|
+
variant: variant === "destructive" ? "destructive" : "primary",
|
|
97
|
+
children: $.AI_TOOL_CONFIRMATION_CONFIRM
|
|
89
98
|
})
|
|
90
99
|
]
|
|
91
100
|
})
|
|
@@ -96,28 +105,43 @@ function AiToolConfirmation({
|
|
|
96
105
|
function prettifyString(string) {
|
|
97
106
|
return string.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().toLowerCase().replace(/^\w/, (character) => character.toUpperCase());
|
|
98
107
|
}
|
|
99
|
-
const noop = () => {
|
|
100
|
-
};
|
|
101
108
|
const AiTool = Object.assign(
|
|
102
109
|
forwardRef(
|
|
103
|
-
({
|
|
110
|
+
({
|
|
111
|
+
children,
|
|
112
|
+
title,
|
|
113
|
+
icon,
|
|
114
|
+
collapsed,
|
|
115
|
+
onCollapsedChange,
|
|
116
|
+
className,
|
|
117
|
+
...props
|
|
118
|
+
}, forwardedRef) => {
|
|
104
119
|
const {
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
stage,
|
|
121
|
+
result,
|
|
122
|
+
name,
|
|
107
123
|
[kInternal]: { execute }
|
|
108
124
|
} = useAiToolInvocationContext();
|
|
109
|
-
const [
|
|
125
|
+
const [semiControlledCollapsed, onSemiControlledCollapsed] = useSemiControllableState(collapsed ?? false, onCollapsedChange);
|
|
110
126
|
const hasContent = Children.count(children) > 0;
|
|
111
127
|
const resolvedTitle = useMemo(() => {
|
|
112
|
-
return title ?? prettifyString(
|
|
113
|
-
}, [title,
|
|
128
|
+
return title ?? prettifyString(name);
|
|
129
|
+
}, [title, name]);
|
|
130
|
+
const handleCollapsibleOpenChange = useCallback(
|
|
131
|
+
(open) => {
|
|
132
|
+
onSemiControlledCollapsed(!open);
|
|
133
|
+
},
|
|
134
|
+
[onSemiControlledCollapsed]
|
|
135
|
+
);
|
|
114
136
|
return /* @__PURE__ */ jsxs(CollapsibleRoot, {
|
|
115
137
|
ref: forwardedRef,
|
|
116
138
|
className: classNames("lb-collapsible lb-ai-tool", className),
|
|
117
139
|
...props,
|
|
118
|
-
open: hasContent ?
|
|
119
|
-
onOpenChange:
|
|
140
|
+
open: hasContent ? !semiControlledCollapsed : false,
|
|
141
|
+
onOpenChange: handleCollapsibleOpenChange,
|
|
120
142
|
disabled: !hasContent,
|
|
143
|
+
"data-result": result?.type,
|
|
144
|
+
"data-stage": stage,
|
|
121
145
|
children: [
|
|
122
146
|
/* @__PURE__ */ jsxs(CollapsibleTrigger, {
|
|
123
147
|
className: "lb-collapsible-trigger lb-ai-tool-header",
|
|
@@ -136,11 +160,11 @@ const AiTool = Object.assign(
|
|
|
136
160
|
}) : null,
|
|
137
161
|
/* @__PURE__ */ jsx("div", {
|
|
138
162
|
className: "lb-ai-tool-header-status",
|
|
139
|
-
children:
|
|
163
|
+
children: stage === "executed" ? result.type === "success" ? /* @__PURE__ */ jsx(CheckCircleFillIcon, {}) : result.type === "error" ? /* @__PURE__ */ jsx(CrossCircleFillIcon, {}) : result.type === "cancelled" ? /* @__PURE__ */ jsx(MinusCircleIcon, {}) : null : execute !== void 0 ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : null
|
|
140
164
|
})
|
|
141
165
|
]
|
|
142
166
|
}),
|
|
143
|
-
|
|
167
|
+
hasContent ? /* @__PURE__ */ jsx(CollapsibleContent, {
|
|
144
168
|
className: "lb-collapsible-content lb-ai-tool-content-container",
|
|
145
169
|
children: /* @__PURE__ */ jsx("div", {
|
|
146
170
|
className: "lb-ai-tool-content",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AiTool.js","sources":["../../src/components/AiTool.tsx"],"sourcesContent":["import {\n type AiToolExecuteCallback,\n type AiToolTypePack,\n type JsonObject,\n kInternal,\n type ToolResultData,\n} from \"@liveblocks/core\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Children, forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport { Button } from \"../_private\";\nimport { CheckCircleFillIcon, ChevronRightIcon, SpinnerIcon } from \"../icons\";\nimport { useAiToolInvocationContext } from \"../primitives/AiMessage/contexts\";\nimport * as Collapsible from \"../primitives/Collapsible\";\nimport { classNames } from \"../utils/class-names\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\n\nexport interface AiToolProps\n extends Omit<ComponentProps<\"div\">, \"title\" | \"children\"> {\n /**\n * The tool's title.\n *\n * By default, a human-readable version of the tool's name is used:\n * - `\"showTodo\"` → \"Show todo\"\n * - `\"get_weather\"` → \"Get weather\"\n */\n title?: string;\n\n /**\n * An optional icon displayed next to the title.\n */\n icon?: ReactNode;\n\n /**\n * The content shown in the tool.\n */\n children?: ReactNode;\n}\n\nexport type AiToolIconProps = ComponentProps<\"div\">;\n\nexport type AiToolInspectorProps = ComponentProps<\"div\">;\n\n// TODO: AiToolConfirmationProps might need a generic since we're outside of the\n// tool definition so things like inferred args and result types are not\n// available here for `confirm` and `cancel`\n\n/**\n * @private This API will change, and is not considered stable. DO NOT RELY on it.\n *\n * This component can be used to build human-in-the-loop interfaces.\n */\nexport interface AiToolConfirmationProps<\n A extends JsonObject,\n R extends ToolResultData,\n> extends ComponentProps<\"div\"> {\n args?: A;\n confirm: AiToolExecuteCallback<A, R>;\n cancel: AiToolExecuteCallback<A, R>;\n variant?: \"default\" | \"destructive\";\n\n // TODO: Use existing overrides API to allow customizing the \"Confirm\" and \"Cancel\" labels\n // overrides?: Partial<GlobalOverrides & AiToolConfirmationOverrides>;\n}\n\nfunction AiToolIcon({ className, ...props }: AiToolIconProps) {\n return (\n <div className={classNames(\"lb-ai-tool-icon\", className)} {...props} />\n );\n}\n\nfunction AiToolInspector({ className, ...props }: AiToolInspectorProps) {\n const { args, partialArgs, result } = useAiToolInvocationContext();\n\n return (\n <div className={classNames(\"lb-ai-tool-inspector\", className)} {...props}>\n <CodeBlock\n title=\"Arguments\"\n code={JSON.stringify(args ?? partialArgs, null, 2)}\n />\n {result !== undefined ? (\n <CodeBlock title=\"Result\" code={JSON.stringify(result, null, 2)} />\n ) : null}\n </div>\n );\n}\n\nfunction AiToolConfirmation<\n TPack extends AiToolTypePack,\n A extends JsonObject = TPack[\"A\"],\n R extends ToolResultData = TPack[\"R\"],\n>({\n children,\n variant = \"default\",\n confirm,\n cancel,\n className,\n ...props\n}: AiToolConfirmationProps<A, R>) {\n const { status, args, respond, toolName, toolCallId } =\n useAiToolInvocationContext();\n\n const enabled = status === \"executing\";\n\n const context = useMemo(\n () => ({ toolName, toolCallId }),\n [toolName, toolCallId]\n );\n\n const onConfirmClick = useCallback(async () => {\n if (enabled) {\n respond(await confirm(args as A, context));\n }\n }, [enabled, args, confirm, respond, context]);\n\n const onCancelClick = useCallback(async () => {\n if (enabled) {\n respond(await cancel(args as A, context));\n }\n }, [enabled, args, cancel, respond, context]);\n\n if (status === \"executed\") {\n return null;\n }\n\n return (\n <div\n className={classNames(\"lb-ai-tool-confirmation\", className)}\n {...props}\n >\n {children ? (\n <div className=\"lb-ai-tool-confirmation-content\">{children}</div>\n ) : null}\n <div className=\"lb-ai-tool-confirmation-footer\">\n <div className=\"lb-ai-tool-confirmation-actions\">\n <Button\n disabled={!enabled}\n onClick={onConfirmClick}\n variant={variant === \"destructive\" ? \"destructive\" : \"primary\"}\n >\n Confirm\n </Button>\n <Button\n disabled={!enabled}\n onClick={onCancelClick}\n variant=\"secondary\"\n >\n Cancel\n </Button>\n </div>\n </div>\n </div>\n );\n}\n\nfunction prettifyString(string: string) {\n return (\n string\n // Convert camelCase to spaces\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n // Convert snake_case and kebab-case to spaces\n .replace(/[_-]+/g, \" \")\n // Collapse multiple following spaces\n .replace(/\\s+/g, \" \")\n // Trim leading and trailing spaces\n .trim()\n // Capitalize first word\n .toLowerCase()\n .replace(/^\\w/, (character) => character.toUpperCase())\n );\n}\n\nconst noop = () => {};\n\nexport const AiTool = Object.assign(\n forwardRef<HTMLDivElement, AiToolProps>(\n ({ children, title, icon, className, ...props }, forwardedRef) => {\n const {\n status,\n toolName,\n [kInternal]: { execute },\n } = useAiToolInvocationContext();\n const [isOpen, setIsOpen] = useState(true);\n // TODO: This check won't work for cases like:\n // <AiTool>\n // <ComponentThatRendersNull />\n // <ComponentThatAlsoRendersNull />\n // </AiTool>\n // One solution could be to check the DOM on every render with `useLayoutEffect`\n // to see if there's any actual content.\n const hasContent = Children.count(children) > 0;\n const resolvedTitle = useMemo(() => {\n return title ?? prettifyString(toolName);\n }, [title, toolName]);\n\n return (\n <Collapsible.Root\n ref={forwardedRef}\n className={classNames(\"lb-collapsible lb-ai-tool\", className)}\n {...props}\n open={hasContent ? isOpen : false}\n onOpenChange={hasContent ? setIsOpen : noop}\n disabled={!hasContent}\n >\n <Collapsible.Trigger className=\"lb-collapsible-trigger lb-ai-tool-header\">\n {icon ? (\n <div className=\"lb-ai-tool-header-icon-container\">{icon}</div>\n ) : null}\n <span className=\"lb-ai-tool-header-title\">{resolvedTitle}</span>\n {hasContent ? (\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n ) : null}\n <div className=\"lb-ai-tool-header-status\">\n {status === \"executed\" ? (\n <CheckCircleFillIcon />\n ) : execute !== undefined ? (\n // Only show a spinner if the tool has an `execute` method.\n <SpinnerIcon />\n ) : null}\n </div>\n </Collapsible.Trigger>\n\n {children ? (\n <Collapsible.Content className=\"lb-collapsible-content lb-ai-tool-content-container\">\n <div className=\"lb-ai-tool-content\">{children}</div>\n </Collapsible.Content>\n ) : null}\n </Collapsible.Root>\n );\n }\n ),\n {\n Icon: AiToolIcon,\n Inspector: AiToolInspector,\n Confirmation: AiToolConfirmation,\n }\n);\n"],"names":["Collapsible.Root","Collapsible.Trigger","Collapsible.Content"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AiTool.js","sources":["../../src/components/AiTool.tsx"],"sourcesContent":["import type {\n AiToolExecuteCallback,\n AiToolTypePack,\n JsonObject,\n NoInfr,\n} from \"@liveblocks/core\";\nimport { kInternal } from \"@liveblocks/core\";\nimport type { ComponentProps, ReactNode } from \"react\";\nimport { Children, forwardRef, useCallback, useMemo } from \"react\";\n\nimport { Button } from \"../_private\";\nimport {\n CheckCircleFillIcon,\n ChevronRightIcon,\n CrossCircleFillIcon,\n MinusCircleIcon,\n SpinnerIcon,\n} from \"../icons\";\nimport {\n type AiToolConfirmationOverrides,\n type GlobalOverrides,\n useOverrides,\n} from \"../overrides\";\nimport { useAiToolInvocationContext } from \"../primitives/AiMessage/contexts\";\nimport * as Collapsible from \"../primitives/Collapsible\";\nimport { classNames } from \"../utils/class-names\";\nimport { useSemiControllableState } from \"../utils/use-controllable-state\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\n\nexport interface AiToolProps\n extends Omit<ComponentProps<\"div\">, \"title\" | \"children\"> {\n /**\n * The tool's title.\n *\n * By default, a human-readable version of the tool's name is used:\n * - `\"showTodo\"` → \"Show todo\"\n * - `\"get_weather\"` → \"Get weather\"\n */\n title?: string;\n\n /**\n * An optional icon displayed next to the title.\n */\n icon?: ReactNode;\n\n /**\n * The content shown in the tool.\n */\n children?: ReactNode;\n\n /**\n * Whether the content is currently collapsed.\n * It is not a traditional controlled value, as in if you set it to `true` it would only stay expanded.\n * Instead, it is \"semi-controlled\", meaning that setting it to `true` will expand it, but it\n * can still be collapsed/expanded by clicking on it.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the content is collapsed or expanded by clicking on it.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n}\n\nexport type AiToolIconProps = ComponentProps<\"div\">;\n\nexport type AiToolInspectorProps = ComponentProps<\"div\">;\n\nexport interface AiToolConfirmationProps<\n A extends JsonObject,\n R extends JsonObject,\n> extends ComponentProps<\"div\"> {\n /**\n * The callback invoked when the user clicks the confirm button.\n */\n confirm: AiToolExecuteCallback<A, R>;\n\n /**\n * The callback invoked when the user clicks the cancel button.\n */\n cancel?: AiToolExecuteCallback<A, R>;\n\n /**\n * The visual appearance.\n */\n variant?: \"default\" | \"destructive\";\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & AiToolConfirmationOverrides>;\n\n /**\n * The tool's result type, to be used with the `types` prop in the `render` method.\n *\n * @example\n * defineAiTool<{ value: number }>()({\n * // ...\n * render: ({ types }) => (\n * <AiTool.Confirmation\n * types={types}\n * confirm={() => {\n * return {\n * // Using `types` makes the result type-safe\n * // based on the tool's definition\n * data: { value: 123 },\n * };\n * }}\n * />\n * ),\n * })\n */\n types?: NoInfr<AiToolTypePack<A, R>>;\n}\n\nfunction AiToolIcon({ className, ...props }: AiToolIconProps) {\n return (\n <div className={classNames(\"lb-ai-tool-icon\", className)} {...props} />\n );\n}\n\nfunction AiToolInspector({ className, ...props }: AiToolInspectorProps) {\n const { args, partialArgs, result } = useAiToolInvocationContext();\n\n return (\n <div className={classNames(\"lb-ai-tool-inspector\", className)} {...props}>\n <CodeBlock\n title=\"Arguments\"\n code={JSON.stringify(args ?? partialArgs, null, 2)}\n />\n {result !== undefined ? (\n <CodeBlock title=\"Result\" code={JSON.stringify(result, null, 2)} />\n ) : null}\n </div>\n );\n}\n\nfunction AiToolConfirmation<\n TPack extends AiToolTypePack,\n A extends JsonObject = TPack[\"A\"],\n R extends JsonObject = TPack[\"R\"],\n>({\n children,\n variant = \"default\",\n confirm,\n cancel,\n overrides,\n className,\n ...props\n}: AiToolConfirmationProps<A, R>) {\n const { stage, args, respond, name, invocationId } =\n useAiToolInvocationContext();\n const $ = useOverrides(overrides);\n\n const enabled = stage === \"executing\";\n\n const context = useMemo(() => ({ name, invocationId }), [name, invocationId]);\n\n const onConfirmClick = useCallback(async () => {\n if (enabled) {\n const result = await confirm(args as A, context);\n respond(result ?? undefined);\n }\n }, [enabled, args, confirm, respond, context]);\n\n const onCancelClick = useCallback(async () => {\n if (enabled) {\n if (cancel === undefined) {\n respond({ cancel: true });\n } else {\n const result = await cancel(args as A, context);\n respond(result ?? undefined);\n }\n }\n }, [enabled, args, cancel, respond, context]);\n\n // If there's no content and the tool has been executed (so there's no\n // confirmation UI displayed either), don't render anything.\n if (stage === \"executed\" && !children) {\n return null;\n }\n\n return (\n <div\n className={classNames(\"lb-ai-tool-confirmation\", className)}\n {...props}\n >\n {children ? (\n <div className=\"lb-ai-tool-confirmation-content\">{children}</div>\n ) : null}\n {stage !== \"executed\" && (\n <div className=\"lb-ai-tool-confirmation-footer\">\n <div className=\"lb-ai-tool-confirmation-actions\">\n <Button\n disabled={!enabled}\n onClick={onCancelClick}\n variant=\"secondary\"\n >\n {$.AI_TOOL_CONFIRMATION_CANCEL}\n </Button>\n <Button\n disabled={!enabled}\n onClick={onConfirmClick}\n variant={variant === \"destructive\" ? \"destructive\" : \"primary\"}\n >\n {$.AI_TOOL_CONFIRMATION_CONFIRM}\n </Button>\n </div>\n </div>\n )}\n </div>\n );\n}\n\nfunction prettifyString(string: string) {\n return (\n string\n // Convert camelCase to spaces\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n // Convert snake_case and kebab-case to spaces\n .replace(/[_-]+/g, \" \")\n // Collapse multiple following spaces\n .replace(/\\s+/g, \" \")\n // Trim leading and trailing spaces\n .trim()\n // Capitalize first word\n .toLowerCase()\n .replace(/^\\w/, (character) => character.toUpperCase())\n );\n}\n\n/**\n * A pre-built component which displays a tool call.\n *\n * By default, a human-readable version of the tool's name is used as a title:\n * - `\"showTodo\"` → \"Show todo\"\n * - `\"get_weather\"` → \"Get weather\"\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: () => (\n * <AiTool />\n * ),\n * })\n *\n * It can be customized in various ways:\n * - adding an icon\n * - customizing the title (even dynamically)\n * - adding custom content inside it\n * - collapsing it conditionally\n * - etc.\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: ({ stage, result }) => (\n * <AiTool\n * icon=\"🔍\"\n *\n * // Override the default title based on the tool's stage\n * title={stage === \"executing\" ? \"Searching…\" : \"Search results\"}\n *\n * // Start open and automatically collapse after it is executed\n * // The user can still expand/collapse it manually at any time\n * collapsed={stage === \"executed\"}\n * >\n * <SearchResults data={result.data} />\n * </AiTool>\n * ),\n * })\n *\n * It also comes with a few built-in sub-components:\n * - `AiTool.Confirmation` to display a human-in-the-loop confirmation step\n * which can be accepted or cancelled by the user.\n * - `AiTool.Inspector` to display the tool's arguments and result which can\n * be useful during development.\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: () => (\n * <AiTool>\n * <AiTool.Confirmation\n * // Use a destructive visual appearance\n * variant=\"destructive\"\n *\n * // The tool's arguments can be directly accessed like in `execute`\n * confirm={({ pageIds }) => {\n * const deletedPageTitles = pages\n * .filter((p) => pageIds.includes(p.id))\n * .map((page) => page.title);\n *\n * deletePages(pageIds);\n *\n * // This result will be available as `result` in the tool's `render` props\n * return { data: { deletedPageTitles } };\n * }}\n *\n * // If needed, `cancel={() => ...}` would work similarly\n * >\n * Do you want to delete these pages?\n * <PagesPreviews />\n * </AiTool.Confirmation>\n * </AiTool>\n * ),\n * })\n *\n * @example\n * defineAiTool()({\n * // ...\n * render: () => (\n * <AiTool>\n * <AiTool.Inspector />\n * </AiTool>\n * ),\n * })\n */\nexport const AiTool = Object.assign(\n forwardRef<HTMLDivElement, AiToolProps>(\n (\n {\n children,\n title,\n icon,\n collapsed,\n onCollapsedChange,\n className,\n ...props\n },\n forwardedRef\n ) => {\n const {\n stage,\n result,\n name,\n [kInternal]: { execute },\n } = useAiToolInvocationContext();\n const [semiControlledCollapsed, onSemiControlledCollapsed] =\n useSemiControllableState(collapsed ?? false, onCollapsedChange);\n // TODO: This check won't work for cases like:\n // <AiTool>\n // <ComponentThatRendersNull />\n // <ComponentThatAlsoRendersNull />\n // </AiTool>\n // One solution could be to check the DOM on every render with `useLayoutEffect`\n // to see if there's any actual content.\n // For now we're limiting the visual issues caused by the above by using CSS's\n // `:empty` pseudo-class to make the content 0px high if it's actually empty.\n const hasContent = Children.count(children) > 0;\n const resolvedTitle = useMemo(() => {\n return title ?? prettifyString(name);\n }, [title, name]);\n\n // `AiTool` uses \"collapsed\" instead of \"open\" (like the `Composer` component) because \"open\"\n // makes sense next to something called \"Collapsible\" but less so for something called \"AiTool\".\n const handleCollapsibleOpenChange = useCallback(\n (open: boolean) => {\n onSemiControlledCollapsed(!open);\n },\n [onSemiControlledCollapsed]\n );\n\n return (\n <Collapsible.Root\n ref={forwardedRef}\n className={classNames(\"lb-collapsible lb-ai-tool\", className)}\n {...props}\n // Regardless of `semiControlledCollapsed`, the collapsible is closed if there's no content.\n open={hasContent ? !semiControlledCollapsed : false}\n onOpenChange={handleCollapsibleOpenChange}\n disabled={!hasContent}\n data-result={result?.type}\n data-stage={stage}\n >\n <Collapsible.Trigger className=\"lb-collapsible-trigger lb-ai-tool-header\">\n {icon ? (\n <div className=\"lb-ai-tool-header-icon-container\">{icon}</div>\n ) : null}\n <span className=\"lb-ai-tool-header-title\">{resolvedTitle}</span>\n {hasContent ? (\n <span className=\"lb-collapsible-chevron lb-icon-container\">\n <ChevronRightIcon />\n </span>\n ) : null}\n <div className=\"lb-ai-tool-header-status\">\n {stage === \"executed\" ? (\n result.type === \"success\" ? (\n <CheckCircleFillIcon />\n ) : result.type === \"error\" ? (\n <CrossCircleFillIcon />\n ) : result.type === \"cancelled\" ? (\n <MinusCircleIcon />\n ) : null\n ) : execute !== undefined ? (\n // Only show a spinner if the tool has an `execute` method.\n <SpinnerIcon />\n ) : null}\n </div>\n </Collapsible.Trigger>\n\n {hasContent ? (\n <Collapsible.Content className=\"lb-collapsible-content lb-ai-tool-content-container\">\n <div className=\"lb-ai-tool-content\">{children}</div>\n </Collapsible.Content>\n ) : null}\n </Collapsible.Root>\n );\n }\n ),\n {\n /**\n * Display an icon in a container.\n *\n * @example\n * <AiTool\n * icon={\n * <AiTool.Icon>🔍</AiTool.Icon>\n * }\n * />\n */\n Icon: AiToolIcon,\n\n /**\n * Display the tool's arguments and result, which can be useful during\n * development.\n *\n * @example\n * <AiTool>\n * <AiTool.Inspector />\n * </AiTool>\n */\n Inspector: AiToolInspector,\n\n /**\n * Display a human-in-the-loop confirmation step which can be accepted\n * or cancelled by the user.\n *\n * The `confirm` and `cancel` callbacks work like `execute` in tool definitions: they can\n * perform side-effects, be async if needed, and return a result. The tool call will stay\n * pending until either `confirm` or `cancel` is called.\n *\n * @example\n * <AiTool>\n * <AiTool.Confirmation\n * // Use a destructive visual appearance\n * variant=\"destructive\"\n *\n * // The tool's arguments can be directly accessed like in `execute`\n * confirm={({ pageIds }) => {\n * const deletedPageTitles = pages\n * .filter((p) => pageIds.includes(p.id))\n * .map((page) => page.title);\n *\n * deletePages(pageIds);\n *\n * // This result will be available as `result` in the tool's `render` props\n * return { data: { deletedPageTitles } };\n * }}\n *\n * // If needed, `cancel={() => ...}` would work similarly\n * >\n * Do you want to delete these pages?\n * <PagesPreviews />\n * </AiTool.Confirmation>\n * </AiTool>\n */\n Confirmation: AiToolConfirmation,\n }\n);\n"],"names":["Collapsible.Root","Collapsible.Trigger","Collapsible.Content"],"mappings":"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"}
|