@flanksource/clicky-ui 0.2.15 → 0.2.17

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 (205) hide show
  1. package/dist/chat.cjs +16 -0
  2. package/dist/chat.cjs.map +1 -1
  3. package/dist/chat.js +17 -1
  4. package/dist/chat.js.map +1 -1
  5. package/dist/components/Combobox.cjs +34 -11
  6. package/dist/components/Combobox.cjs.map +1 -1
  7. package/dist/components/Combobox.d.ts +8 -0
  8. package/dist/components/Combobox.d.ts.map +1 -1
  9. package/dist/components/Combobox.js +34 -11
  10. package/dist/components/Combobox.js.map +1 -1
  11. package/dist/components/DateTimePicker.cjs +3 -0
  12. package/dist/components/DateTimePicker.cjs.map +1 -1
  13. package/dist/components/DateTimePicker.d.ts +6 -2
  14. package/dist/components/DateTimePicker.d.ts.map +1 -1
  15. package/dist/components/DateTimePicker.js +3 -0
  16. package/dist/components/DateTimePicker.js.map +1 -1
  17. package/dist/components/Field.cjs +33 -0
  18. package/dist/components/Field.cjs.map +1 -0
  19. package/dist/components/Field.d.ts +27 -0
  20. package/dist/components/Field.d.ts.map +1 -0
  21. package/dist/components/Field.js +33 -0
  22. package/dist/components/Field.js.map +1 -0
  23. package/dist/components/FilterBar.cjs +81 -20
  24. package/dist/components/FilterBar.cjs.map +1 -1
  25. package/dist/components/FilterBar.d.ts +30 -0
  26. package/dist/components/FilterBar.d.ts.map +1 -1
  27. package/dist/components/FilterBar.js +83 -22
  28. package/dist/components/FilterBar.js.map +1 -1
  29. package/dist/components/JsonSchemaForm.cjs +26 -3
  30. package/dist/components/JsonSchemaForm.cjs.map +1 -1
  31. package/dist/components/JsonSchemaForm.d.ts.map +1 -1
  32. package/dist/components/JsonSchemaForm.js +26 -3
  33. package/dist/components/JsonSchemaForm.js.map +1 -1
  34. package/dist/components/MultiSelect.cjs +2 -1
  35. package/dist/components/MultiSelect.cjs.map +1 -1
  36. package/dist/components/MultiSelect.d.ts +5 -1
  37. package/dist/components/MultiSelect.d.ts.map +1 -1
  38. package/dist/components/MultiSelect.js +2 -1
  39. package/dist/components/MultiSelect.js.map +1 -1
  40. package/dist/components/json-schema-form-fields.cjs +15 -8
  41. package/dist/components/json-schema-form-fields.cjs.map +1 -1
  42. package/dist/components/json-schema-form-fields.d.ts.map +1 -1
  43. package/dist/components/json-schema-form-fields.js +15 -8
  44. package/dist/components/json-schema-form-fields.js.map +1 -1
  45. package/dist/components/json-schema-form-preferences.cjs +4 -0
  46. package/dist/components/json-schema-form-preferences.cjs.map +1 -1
  47. package/dist/components/json-schema-form-preferences.d.ts +2 -0
  48. package/dist/components/json-schema-form-preferences.d.ts.map +1 -1
  49. package/dist/components/json-schema-form-preferences.js +4 -0
  50. package/dist/components/json-schema-form-preferences.js.map +1 -1
  51. package/dist/components/json-schema-form-render.cjs +1 -1
  52. package/dist/components/json-schema-form-render.cjs.map +1 -1
  53. package/dist/components/json-schema-form-render.d.ts.map +1 -1
  54. package/dist/components/json-schema-form-render.js +2 -2
  55. package/dist/components/json-schema-form-render.js.map +1 -1
  56. package/dist/components/json-schema-form-types.d.ts +4 -2
  57. package/dist/components/json-schema-form-types.d.ts.map +1 -1
  58. package/dist/components/json-schema-form-utils.cjs +13 -0
  59. package/dist/components/json-schema-form-utils.cjs.map +1 -1
  60. package/dist/components/json-schema-form-utils.d.ts +2 -0
  61. package/dist/components/json-schema-form-utils.d.ts.map +1 -1
  62. package/dist/components/json-schema-form-utils.js +13 -0
  63. package/dist/components/json-schema-form-utils.js.map +1 -1
  64. package/dist/components/loading.cjs +21 -8
  65. package/dist/components/loading.cjs.map +1 -1
  66. package/dist/components/loading.d.ts +6 -4
  67. package/dist/components/loading.d.ts.map +1 -1
  68. package/dist/components/loading.js +21 -8
  69. package/dist/components/loading.js.map +1 -1
  70. package/dist/components/use-form.cjs +27 -0
  71. package/dist/components/use-form.cjs.map +1 -0
  72. package/dist/components/use-form.d.ts +30 -0
  73. package/dist/components/use-form.d.ts.map +1 -0
  74. package/dist/components/use-form.js +27 -0
  75. package/dist/components/use-form.js.map +1 -0
  76. package/dist/components.cjs +7 -0
  77. package/dist/components.cjs.map +1 -1
  78. package/dist/components.d.ts +4 -1
  79. package/dist/components.d.ts.map +1 -1
  80. package/dist/components.js +8 -1
  81. package/dist/components.js.map +1 -1
  82. package/dist/data/Markdown.cjs +14 -40
  83. package/dist/data/Markdown.cjs.map +1 -1
  84. package/dist/data/Markdown.d.ts +3 -0
  85. package/dist/data/Markdown.d.ts.map +1 -1
  86. package/dist/data/Markdown.js +14 -40
  87. package/dist/data/Markdown.js.map +1 -1
  88. package/dist/data/TaskProgress.cjs +22 -0
  89. package/dist/data/TaskProgress.cjs.map +1 -1
  90. package/dist/data/TaskProgress.js +22 -0
  91. package/dist/data/TaskProgress.js.map +1 -1
  92. package/dist/data/TaskSnapshot.cjs.map +1 -1
  93. package/dist/data/TaskSnapshot.d.ts +5 -0
  94. package/dist/data/TaskSnapshot.d.ts.map +1 -1
  95. package/dist/data/TaskSnapshot.js.map +1 -1
  96. package/dist/data/Tree.cjs +32 -1
  97. package/dist/data/Tree.cjs.map +1 -1
  98. package/dist/data/Tree.d.ts +9 -1
  99. package/dist/data/Tree.d.ts.map +1 -1
  100. package/dist/data/Tree.js +32 -1
  101. package/dist/data/Tree.js.map +1 -1
  102. package/dist/data/chat/Attachment.cjs +79 -0
  103. package/dist/data/chat/Attachment.cjs.map +1 -0
  104. package/dist/data/chat/Attachment.d.ts +18 -0
  105. package/dist/data/chat/Attachment.d.ts.map +1 -0
  106. package/dist/data/chat/Attachment.js +79 -0
  107. package/dist/data/chat/Attachment.js.map +1 -0
  108. package/dist/data/chat/Chat.cjs +71 -14
  109. package/dist/data/chat/Chat.cjs.map +1 -1
  110. package/dist/data/chat/Chat.d.ts +30 -12
  111. package/dist/data/chat/Chat.d.ts.map +1 -1
  112. package/dist/data/chat/Chat.fixtures.d.ts +9 -0
  113. package/dist/data/chat/Chat.fixtures.d.ts.map +1 -1
  114. package/dist/data/chat/Chat.js +73 -16
  115. package/dist/data/chat/Chat.js.map +1 -1
  116. package/dist/data/chat/Conversation.cjs +32 -14
  117. package/dist/data/chat/Conversation.cjs.map +1 -1
  118. package/dist/data/chat/Conversation.d.ts +5 -3
  119. package/dist/data/chat/Conversation.d.ts.map +1 -1
  120. package/dist/data/chat/Conversation.js +34 -16
  121. package/dist/data/chat/Conversation.js.map +1 -1
  122. package/dist/data/chat/Message.cjs +73 -14
  123. package/dist/data/chat/Message.cjs.map +1 -1
  124. package/dist/data/chat/Message.d.ts +11 -4
  125. package/dist/data/chat/Message.d.ts.map +1 -1
  126. package/dist/data/chat/Message.js +75 -16
  127. package/dist/data/chat/Message.js.map +1 -1
  128. package/dist/data/chat/MessageActions.cjs +54 -0
  129. package/dist/data/chat/MessageActions.cjs.map +1 -0
  130. package/dist/data/chat/MessageActions.d.ts +11 -0
  131. package/dist/data/chat/MessageActions.d.ts.map +1 -0
  132. package/dist/data/chat/MessageActions.js +54 -0
  133. package/dist/data/chat/MessageActions.js.map +1 -0
  134. package/dist/data/chat/ModelSelector.cjs +43 -0
  135. package/dist/data/chat/ModelSelector.cjs.map +1 -0
  136. package/dist/data/chat/ModelSelector.d.ts +22 -0
  137. package/dist/data/chat/ModelSelector.d.ts.map +1 -0
  138. package/dist/data/chat/ModelSelector.js +43 -0
  139. package/dist/data/chat/ModelSelector.js.map +1 -0
  140. package/dist/data/chat/PromptInput.cjs +28 -15
  141. package/dist/data/chat/PromptInput.cjs.map +1 -1
  142. package/dist/data/chat/PromptInput.d.ts +14 -8
  143. package/dist/data/chat/PromptInput.d.ts.map +1 -1
  144. package/dist/data/chat/PromptInput.js +28 -15
  145. package/dist/data/chat/PromptInput.js.map +1 -1
  146. package/dist/data/chat/Reasoning.cjs +37 -0
  147. package/dist/data/chat/Reasoning.cjs.map +1 -0
  148. package/dist/data/chat/Reasoning.d.ts +11 -0
  149. package/dist/data/chat/Reasoning.d.ts.map +1 -0
  150. package/dist/data/chat/Reasoning.js +37 -0
  151. package/dist/data/chat/Reasoning.js.map +1 -0
  152. package/dist/data/chat/Suggestion.cjs +20 -0
  153. package/dist/data/chat/Suggestion.cjs.map +1 -0
  154. package/dist/data/chat/Suggestion.d.ts +10 -0
  155. package/dist/data/chat/Suggestion.d.ts.map +1 -0
  156. package/dist/data/chat/Suggestion.js +20 -0
  157. package/dist/data/chat/Suggestion.js.map +1 -0
  158. package/dist/data/chat/ToolCall.cjs +26 -3
  159. package/dist/data/chat/ToolCall.cjs.map +1 -1
  160. package/dist/data/chat/ToolCall.d.ts +5 -1
  161. package/dist/data/chat/ToolCall.d.ts.map +1 -1
  162. package/dist/data/chat/ToolCall.js +26 -3
  163. package/dist/data/chat/ToolCall.js.map +1 -1
  164. package/dist/data/chat/index.d.ts +7 -2
  165. package/dist/data/chat/index.d.ts.map +1 -1
  166. package/dist/data/chat/types.cjs +16 -0
  167. package/dist/data/chat/types.cjs.map +1 -1
  168. package/dist/data/chat/types.d.ts +29 -2
  169. package/dist/data/chat/types.d.ts.map +1 -1
  170. package/dist/data/chat/types.js +16 -0
  171. package/dist/data/chat/types.js.map +1 -1
  172. package/dist/data/version-info.cjs +3 -3
  173. package/dist/data/version-info.js +3 -3
  174. package/dist/hooks/use-task-run.cjs +33 -20
  175. package/dist/hooks/use-task-run.cjs.map +1 -1
  176. package/dist/hooks/use-task-run.d.ts.map +1 -1
  177. package/dist/hooks/use-task-run.js +33 -20
  178. package/dist/hooks/use-task-run.js.map +1 -1
  179. package/dist/index.cjs +7 -0
  180. package/dist/index.cjs.map +1 -1
  181. package/dist/index.js +8 -1
  182. package/dist/index.js.map +1 -1
  183. package/dist/overlay/Modal.cjs +27 -23
  184. package/dist/overlay/Modal.cjs.map +1 -1
  185. package/dist/overlay/Modal.d.ts +7 -1
  186. package/dist/overlay/Modal.d.ts.map +1 -1
  187. package/dist/overlay/Modal.js +27 -23
  188. package/dist/overlay/Modal.js.map +1 -1
  189. package/dist/rpc/FilterForm.cjs +4 -4
  190. package/dist/rpc/FilterForm.cjs.map +1 -1
  191. package/dist/rpc/FilterForm.js +4 -4
  192. package/dist/rpc/FilterForm.js.map +1 -1
  193. package/dist/rpc/OperationCatalog.cjs +17 -21
  194. package/dist/rpc/OperationCatalog.cjs.map +1 -1
  195. package/dist/rpc/OperationCatalog.d.ts +3 -3
  196. package/dist/rpc/OperationCatalog.d.ts.map +1 -1
  197. package/dist/rpc/OperationCatalog.js +18 -22
  198. package/dist/rpc/OperationCatalog.js.map +1 -1
  199. package/dist/rpc/formMetadata.cjs +5 -3
  200. package/dist/rpc/formMetadata.cjs.map +1 -1
  201. package/dist/rpc/formMetadata.d.ts.map +1 -1
  202. package/dist/rpc/formMetadata.js +5 -3
  203. package/dist/rpc/formMetadata.js.map +1 -1
  204. package/dist/styles.css +1 -1
  205. package/package.json +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/data/chat/PromptInput.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,qEAAqE;IACrE,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF;;8BAE8B;AAC9B,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,MAAM,EACN,MAAM,EACN,WAA4C,EAC5C,SAAS,GACV,EAAE,gBAAgB,2CAkDlB"}
1
+ {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/data/chat/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMrF,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEtD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IACtD,0DAA0D;IAC1D,MAAM,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAClC,qEAAqE;IACrE,MAAM,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,+CAA+C;IAC/C,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF;;;eAGe;AACf,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,MAAM,EACN,MAAM,EACN,WAA4C,EAC5C,iBAAyB,EACzB,OAAO,EACP,SAAS,GACV,EAAE,gBAAgB,2CAqElB"}
@@ -3,6 +3,7 @@ import { useState } from "react";
3
3
  import { cn } from "../../lib/utils.js";
4
4
  import { Button } from "../../components/button.js";
5
5
  import { Icon } from "../Icon.js";
6
+ import { AttachmentList, AttachmentButton } from "./Attachment.js";
6
7
  import { UiStop } from "../../icons/components/UiStop.js";
7
8
  import { UiArrowUp } from "../../icons/components/UiArrowUp.js";
8
9
  function PromptInput({
@@ -10,15 +11,19 @@ function PromptInput({
10
11
  onStop,
11
12
  status,
12
13
  placeholder = "What would you like to know?",
14
+ enableAttachments = false,
15
+ toolbar,
13
16
  className
14
17
  }) {
15
18
  const [value, setValue] = useState("");
19
+ const [files, setFiles] = useState([]);
16
20
  const isGenerating = status === "submitted" || status === "streaming";
17
21
  const submit = () => {
18
22
  const text = value.trim();
19
- if (!text || isGenerating) return;
20
- onSubmit(text);
23
+ if (!text && files.length === 0 || isGenerating) return;
24
+ onSubmit(text, files);
21
25
  setValue("");
26
+ setFiles([]);
22
27
  };
23
28
  const handleSubmit = (e) => {
24
29
  e.preventDefault();
@@ -30,27 +35,35 @@ function PromptInput({
30
35
  submit();
31
36
  }
32
37
  };
38
+ const canSubmit = value.trim().length > 0 || files.length > 0;
33
39
  return /* @__PURE__ */ jsxs(
34
40
  "form",
35
41
  {
36
42
  onSubmit: handleSubmit,
37
43
  className: cn(
38
- "flex items-end gap-2 rounded-lg border border-input bg-background p-2",
44
+ "flex flex-col gap-2 rounded-lg border border-input bg-background p-2",
39
45
  className
40
46
  ),
41
47
  children: [
42
- /* @__PURE__ */ jsx(
43
- "textarea",
44
- {
45
- value,
46
- onChange: (e) => setValue(e.target.value),
47
- onKeyDown: handleKeyDown,
48
- placeholder,
49
- rows: 1,
50
- className: "max-h-48 min-h-9 flex-1 resize-none bg-transparent px-1 py-1.5 text-sm outline-none placeholder:text-muted-foreground"
51
- }
52
- ),
53
- isGenerating && onStop ? /* @__PURE__ */ jsx(Button, { type: "button", size: "icon", variant: "secondary", "aria-label": "Stop", onClick: onStop, children: /* @__PURE__ */ jsx(Icon, { icon: UiStop, className: "size-4" }) }) : /* @__PURE__ */ jsx(Button, { type: "submit", size: "icon", "aria-label": "Send", disabled: !value.trim(), children: /* @__PURE__ */ jsx(Icon, { icon: UiArrowUp, className: "size-4" }) })
48
+ enableAttachments && /* @__PURE__ */ jsx(AttachmentList, { files, onRemove: (i) => setFiles((f) => f.filter((_, j) => j !== i)) }),
49
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-2", children: [
50
+ /* @__PURE__ */ jsx(
51
+ "textarea",
52
+ {
53
+ value,
54
+ onChange: (e) => setValue(e.target.value),
55
+ onKeyDown: handleKeyDown,
56
+ placeholder,
57
+ rows: 1,
58
+ className: "max-h-48 min-h-9 flex-1 resize-none bg-transparent px-1 py-1.5 text-sm outline-none placeholder:text-muted-foreground"
59
+ }
60
+ ),
61
+ isGenerating && onStop ? /* @__PURE__ */ jsx(Button, { type: "button", size: "icon", variant: "secondary", "aria-label": "Stop", onClick: onStop, children: /* @__PURE__ */ jsx(Icon, { icon: UiStop, className: "size-4" }) }) : /* @__PURE__ */ jsx(Button, { type: "submit", size: "icon", "aria-label": "Send", disabled: !canSubmit, children: /* @__PURE__ */ jsx(Icon, { icon: UiArrowUp, className: "size-4" }) })
62
+ ] }),
63
+ (toolbar || enableAttachments) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
64
+ enableAttachments && /* @__PURE__ */ jsx(AttachmentButton, { onAdd: (p) => setFiles((f) => [...f, ...p]), disabled: isGenerating }),
65
+ toolbar
66
+ ] })
54
67
  ]
55
68
  }
56
69
  );
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInput.js","sources":["../../../src/data/chat/PromptInput.tsx"],"sourcesContent":["import { useState, type FormEvent, type KeyboardEvent } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon } from \"../Icon\";\nimport { UiArrowUp, UiStop } from \"../../icons\";\nimport type { ChatStatus } from \"./types\";\n\nexport type PromptInputProps = {\n /** Called with the trimmed text when the user submits a non-empty message. */\n onSubmit: (text: string) => void;\n /** Called when the user stops an in-flight generation. */\n onStop?: () => void;\n /** Current chat status; drives the submit/stop button affordance. */\n status?: ChatStatus | undefined;\n placeholder?: string | undefined;\n className?: string | undefined;\n};\n\n/** Auto-growing prompt textarea with a submit/stop button. Enter (or Cmd/Ctrl+\n * Enter) submits; Shift+Enter inserts a newline. While streaming, the button\n * becomes a stop control. */\nexport function PromptInput({\n onSubmit,\n onStop,\n status,\n placeholder = \"What would you like to know?\",\n className,\n}: PromptInputProps) {\n const [value, setValue] = useState(\"\");\n const isGenerating = status === \"submitted\" || status === \"streaming\";\n\n const submit = () => {\n const text = value.trim();\n if (!text || isGenerating) return;\n onSubmit(text);\n setValue(\"\");\n };\n\n const handleSubmit = (e: FormEvent) => {\n e.preventDefault();\n submit();\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n submit();\n }\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className={cn(\n \"flex items-end gap-2 rounded-lg border border-input bg-background p-2\",\n className,\n )}\n >\n <textarea\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n rows={1}\n className=\"max-h-48 min-h-9 flex-1 resize-none bg-transparent px-1 py-1.5 text-sm outline-none placeholder:text-muted-foreground\"\n />\n {isGenerating && onStop ? (\n <Button type=\"button\" size=\"icon\" variant=\"secondary\" aria-label=\"Stop\" onClick={onStop}>\n <Icon icon={UiStop} className=\"size-4\" />\n </Button>\n ) : (\n <Button type=\"submit\" size=\"icon\" aria-label=\"Send\" disabled={!value.trim()}>\n <Icon icon={UiArrowUp} className=\"size-4\" />\n </Button>\n )}\n </form>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAqBO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AACF,GAAqB;AACnB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,eAAe,WAAW,eAAe,WAAW;AAE1D,QAAM,SAAS,MAAM;AACnB,UAAM,OAAO,MAAM,KAAA;AACnB,QAAI,CAAC,QAAQ,aAAc;AAC3B,aAAS,IAAI;AACb,aAAS,EAAE;AAAA,EACb;AAEA,QAAM,eAAe,CAAC,MAAiB;AACrC,MAAE,eAAA;AACF,WAAA;AAAA,EACF;AAEA,QAAM,gBAAgB,CAAC,MAA0C;AAC/D,QAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,YAAY,CAAC,EAAE,YAAY,aAAa;AAClE,QAAE,eAAA;AACF,aAAA;AAAA,IACF;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,UAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAGF,UAAA;AAAA,QAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,WAAW;AAAA,YACX;AAAA,YACA,MAAM;AAAA,YACN,WAAU;AAAA,UAAA;AAAA,QAAA;AAAA,QAEX,gBAAgB,SACf,oBAAC,UAAO,MAAK,UAAS,MAAK,QAAO,SAAQ,aAAY,cAAW,QAAO,SAAS,QAC/E,8BAAC,MAAA,EAAK,MAAM,QAAQ,WAAU,SAAA,CAAS,EAAA,CACzC,wBAEC,QAAA,EAAO,MAAK,UAAS,MAAK,QAAO,cAAW,QAAO,UAAU,CAAC,MAAM,KAAA,GACnE,UAAA,oBAAC,MAAA,EAAK,MAAM,WAAW,WAAU,UAAS,EAAA,CAC5C;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;"}
1
+ {"version":3,"file":"PromptInput.js","sources":["../../../src/data/chat/PromptInput.tsx"],"sourcesContent":["import { useState, type FormEvent, type KeyboardEvent, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon } from \"../Icon\";\nimport { UiArrowUp, UiStop } from \"../../icons\";\nimport { AttachmentButton, AttachmentList } from \"./Attachment\";\nimport type { ChatStatus, FileUIPart } from \"./types\";\n\nexport type PromptInputProps = {\n /** Called with the trimmed text and any attachments when the user submits. */\n onSubmit: (text: string, files: FileUIPart[]) => void;\n /** Called when the user stops an in-flight generation. */\n onStop?: (() => void) | undefined;\n /** Current chat status; drives the submit/stop button affordance. */\n status?: ChatStatus | undefined;\n placeholder?: string | undefined;\n /** Enables the attachment button and chips. */\n enableAttachments?: boolean | undefined;\n /** Toolbar content (e.g. model/effort selectors) rendered in the footer. */\n toolbar?: ReactNode;\n className?: string | undefined;\n};\n\n/** Auto-growing prompt textarea with a submit/stop button, optional attachment\n * controls, and a toolbar slot (model/effort selectors). Enter submits;\n * Shift+Enter inserts a newline; while streaming the button becomes a stop\n * control. */\nexport function PromptInput({\n onSubmit,\n onStop,\n status,\n placeholder = \"What would you like to know?\",\n enableAttachments = false,\n toolbar,\n className,\n}: PromptInputProps) {\n const [value, setValue] = useState(\"\");\n const [files, setFiles] = useState<FileUIPart[]>([]);\n const isGenerating = status === \"submitted\" || status === \"streaming\";\n\n const submit = () => {\n const text = value.trim();\n if ((!text && files.length === 0) || isGenerating) return;\n onSubmit(text, files);\n setValue(\"\");\n setFiles([]);\n };\n\n const handleSubmit = (e: FormEvent) => {\n e.preventDefault();\n submit();\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n submit();\n }\n };\n\n const canSubmit = value.trim().length > 0 || files.length > 0;\n\n return (\n <form\n onSubmit={handleSubmit}\n className={cn(\n \"flex flex-col gap-2 rounded-lg border border-input bg-background p-2\",\n className,\n )}\n >\n {enableAttachments && (\n <AttachmentList files={files} onRemove={(i) => setFiles((f) => f.filter((_, j) => j !== i))} />\n )}\n\n <div className=\"flex items-end gap-2\">\n <textarea\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n rows={1}\n className=\"max-h-48 min-h-9 flex-1 resize-none bg-transparent px-1 py-1.5 text-sm outline-none placeholder:text-muted-foreground\"\n />\n {isGenerating && onStop ? (\n <Button type=\"button\" size=\"icon\" variant=\"secondary\" aria-label=\"Stop\" onClick={onStop}>\n <Icon icon={UiStop} className=\"size-4\" />\n </Button>\n ) : (\n <Button type=\"submit\" size=\"icon\" aria-label=\"Send\" disabled={!canSubmit}>\n <Icon icon={UiArrowUp} className=\"size-4\" />\n </Button>\n )}\n </div>\n\n {(toolbar || enableAttachments) && (\n <div className=\"flex items-center gap-2\">\n {enableAttachments && (\n <AttachmentButton onAdd={(p) => setFiles((f) => [...f, ...p])} disabled={isGenerating} />\n )}\n {toolbar}\n </div>\n )}\n </form>\n );\n}\n"],"names":[],"mappings":";;;;;;;;AA2BO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,CAAA,CAAE;AACnD,QAAM,eAAe,WAAW,eAAe,WAAW;AAE1D,QAAM,SAAS,MAAM;AACnB,UAAM,OAAO,MAAM,KAAA;AACnB,QAAK,CAAC,QAAQ,MAAM,WAAW,KAAM,aAAc;AACnD,aAAS,MAAM,KAAK;AACpB,aAAS,EAAE;AACX,aAAS,CAAA,CAAE;AAAA,EACb;AAEA,QAAM,eAAe,CAAC,MAAiB;AACrC,MAAE,eAAA;AACF,WAAA;AAAA,EACF;AAEA,QAAM,gBAAgB,CAAC,MAA0C;AAC/D,QAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,YAAY,CAAC,EAAE,YAAY,aAAa;AAClE,QAAE,eAAA;AACF,aAAA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,KAAA,EAAO,SAAS,KAAK,MAAM,SAAS;AAE5D,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,UAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAGD,UAAA;AAAA,QAAA,yCACE,gBAAA,EAAe,OAAc,UAAU,CAAC,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,GAAG;AAAA,QAG/F,qBAAC,OAAA,EAAI,WAAU,wBACb,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,WAAW;AAAA,cACX;AAAA,cACA,MAAM;AAAA,cACN,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEX,gBAAgB,SACf,oBAAC,QAAA,EAAO,MAAK,UAAS,MAAK,QAAO,SAAQ,aAAY,cAAW,QAAO,SAAS,QAC/E,UAAA,oBAAC,MAAA,EAAK,MAAM,QAAQ,WAAU,SAAA,CAAS,GACzC,IAEA,oBAAC,QAAA,EAAO,MAAK,UAAS,MAAK,QAAO,cAAW,QAAO,UAAU,CAAC,WAC7D,UAAA,oBAAC,MAAA,EAAK,MAAM,WAAW,WAAU,UAAS,EAAA,CAC5C;AAAA,QAAA,GAEJ;AAAA,SAEE,WAAW,sBACX,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,UAAA,yCACE,kBAAA,EAAiB,OAAO,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,GAAG,UAAU,cAAc;AAAA,UAExF;AAAA,QAAA,EAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const utils = require("../../lib/utils.cjs");
6
+ const Icon = require("../Icon.cjs");
7
+ const UiBrain = require("../../icons/components/UiBrain.cjs");
8
+ const UiChevronDown = require("../../icons/components/UiChevronDown.cjs");
9
+ function Reasoning({ text, defaultOpen = false, className }) {
10
+ const [open, setOpen] = react.useState(defaultOpen);
11
+ if (!text) return null;
12
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("not-prose w-full", className), children: [
13
+ /* @__PURE__ */ jsxRuntime.jsxs(
14
+ "button",
15
+ {
16
+ type: "button",
17
+ "aria-expanded": open,
18
+ onClick: () => setOpen((v) => !v),
19
+ className: "flex items-center gap-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground",
20
+ children: [
21
+ /* @__PURE__ */ jsxRuntime.jsx(Icon.Icon, { icon: UiBrain.UiBrain, className: "size-3 shrink-0" }),
22
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reasoning" }),
23
+ /* @__PURE__ */ jsxRuntime.jsx(
24
+ Icon.Icon,
25
+ {
26
+ icon: UiChevronDown.UiChevronDown,
27
+ className: utils.cn("size-3 shrink-0 transition-transform", open && "rotate-180")
28
+ }
29
+ )
30
+ ]
31
+ }
32
+ ),
33
+ open && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 border-l-2 border-border pl-3 text-xs italic text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap break-words", children: text }) })
34
+ ] });
35
+ }
36
+ exports.Reasoning = Reasoning;
37
+ //# sourceMappingURL=Reasoning.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reasoning.cjs","sources":["../../../src/data/chat/Reasoning.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiBrain, UiChevronDown } from \"../../icons\";\n\nexport type ReasoningProps = {\n /** The model's reasoning / \"thinking\" text. */\n text: string;\n /** Whether the block starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n className?: string;\n};\n\n/** A collapsible block that shows the model's reasoning (\"thinking\") trace,\n * kept out of the way of the answer by default. */\nexport function Reasoning({ text, defaultOpen = false, className }: ReasoningProps) {\n const [open, setOpen] = useState(defaultOpen);\n if (!text) return null;\n\n return (\n <div className={cn(\"not-prose w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground\"\n >\n <Icon icon={UiBrain} className=\"size-3 shrink-0\" />\n <span>Reasoning</span>\n <Icon\n icon={UiChevronDown}\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n {open && (\n <div className=\"mt-1 border-l-2 border-border pl-3 text-xs italic text-muted-foreground\">\n <p className=\"whitespace-pre-wrap break-words\">{text}</p>\n </div>\n )}\n </div>\n );\n}\n"],"names":["useState","cn","jsxs","jsx","Icon","UiBrain","UiChevronDown"],"mappings":";;;;;;;;AAeO,SAAS,UAAU,EAAE,MAAM,cAAc,OAAO,aAA6B;AAClF,QAAM,CAAC,MAAM,OAAO,IAAIA,MAAAA,SAAS,WAAW;AAC5C,MAAI,CAAC,KAAM,QAAO;AAElB,yCACG,OAAA,EAAI,WAAWC,MAAAA,GAAG,oBAAoB,SAAS,GAC9C,UAAA;AAAA,IAAAC,2BAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,WAAU;AAAA,QAEV,UAAA;AAAA,UAAAC,2BAAAA,IAACC,KAAAA,MAAA,EAAK,MAAMC,QAAAA,SAAS,WAAU,mBAAkB;AAAA,UACjDF,2BAAAA,IAAC,UAAK,UAAA,YAAA,CAAS;AAAA,UACfA,2BAAAA;AAAAA,YAACC,KAAAA;AAAAA,YAAA;AAAA,cACC,MAAME,cAAAA;AAAAA,cACN,WAAWL,MAAAA,GAAG,wCAAwC,QAAQ,YAAY;AAAA,YAAA;AAAA,UAAA;AAAA,QAC5E;AAAA,MAAA;AAAA,IAAA;AAAA,IAED,QACCE,2BAAAA,IAAC,OAAA,EAAI,WAAU,2EACb,yCAAC,KAAA,EAAE,WAAU,mCAAmC,UAAA,KAAA,CAAK,EAAA,CACvD;AAAA,EAAA,GAEJ;AAEJ;;"}
@@ -0,0 +1,11 @@
1
+ export type ReasoningProps = {
2
+ /** The model's reasoning / "thinking" text. */
3
+ text: string;
4
+ /** Whether the block starts expanded. Defaults to false. */
5
+ defaultOpen?: boolean;
6
+ className?: string;
7
+ };
8
+ /** A collapsible block that shows the model's reasoning ("thinking") trace,
9
+ * kept out of the way of the answer by default. */
10
+ export declare function Reasoning({ text, defaultOpen, className }: ReasoningProps): import("react/jsx-runtime").JSX.Element | null;
11
+ //# sourceMappingURL=Reasoning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reasoning.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Reasoning.tsx"],"names":[],"mappings":"AAKA,MAAM,MAAM,cAAc,GAAG;IAC3B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;oDACoD;AACpD,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,WAAmB,EAAE,SAAS,EAAE,EAAE,cAAc,kDA0BjF"}
@@ -0,0 +1,37 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { cn } from "../../lib/utils.js";
4
+ import { Icon } from "../Icon.js";
5
+ import { UiBrain } from "../../icons/components/UiBrain.js";
6
+ import { UiChevronDown } from "../../icons/components/UiChevronDown.js";
7
+ function Reasoning({ text, defaultOpen = false, className }) {
8
+ const [open, setOpen] = useState(defaultOpen);
9
+ if (!text) return null;
10
+ return /* @__PURE__ */ jsxs("div", { className: cn("not-prose w-full", className), children: [
11
+ /* @__PURE__ */ jsxs(
12
+ "button",
13
+ {
14
+ type: "button",
15
+ "aria-expanded": open,
16
+ onClick: () => setOpen((v) => !v),
17
+ className: "flex items-center gap-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground",
18
+ children: [
19
+ /* @__PURE__ */ jsx(Icon, { icon: UiBrain, className: "size-3 shrink-0" }),
20
+ /* @__PURE__ */ jsx("span", { children: "Reasoning" }),
21
+ /* @__PURE__ */ jsx(
22
+ Icon,
23
+ {
24
+ icon: UiChevronDown,
25
+ className: cn("size-3 shrink-0 transition-transform", open && "rotate-180")
26
+ }
27
+ )
28
+ ]
29
+ }
30
+ ),
31
+ open && /* @__PURE__ */ jsx("div", { className: "mt-1 border-l-2 border-border pl-3 text-xs italic text-muted-foreground", children: /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap break-words", children: text }) })
32
+ ] });
33
+ }
34
+ export {
35
+ Reasoning
36
+ };
37
+ //# sourceMappingURL=Reasoning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reasoning.js","sources":["../../../src/data/chat/Reasoning.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon } from \"../Icon\";\nimport { UiBrain, UiChevronDown } from \"../../icons\";\n\nexport type ReasoningProps = {\n /** The model's reasoning / \"thinking\" text. */\n text: string;\n /** Whether the block starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n className?: string;\n};\n\n/** A collapsible block that shows the model's reasoning (\"thinking\") trace,\n * kept out of the way of the answer by default. */\nexport function Reasoning({ text, defaultOpen = false, className }: ReasoningProps) {\n const [open, setOpen] = useState(defaultOpen);\n if (!text) return null;\n\n return (\n <div className={cn(\"not-prose w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center gap-1.5 py-0.5 text-xs text-muted-foreground hover:text-foreground\"\n >\n <Icon icon={UiBrain} className=\"size-3 shrink-0\" />\n <span>Reasoning</span>\n <Icon\n icon={UiChevronDown}\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n {open && (\n <div className=\"mt-1 border-l-2 border-border pl-3 text-xs italic text-muted-foreground\">\n <p className=\"whitespace-pre-wrap break-words\">{text}</p>\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;AAeO,SAAS,UAAU,EAAE,MAAM,cAAc,OAAO,aAA6B;AAClF,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,WAAW;AAC5C,MAAI,CAAC,KAAM,QAAO;AAElB,8BACG,OAAA,EAAI,WAAW,GAAG,oBAAoB,SAAS,GAC9C,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,WAAU;AAAA,QAEV,UAAA;AAAA,UAAA,oBAAC,MAAA,EAAK,MAAM,SAAS,WAAU,mBAAkB;AAAA,UACjD,oBAAC,UAAK,UAAA,YAAA,CAAS;AAAA,UACf;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAM;AAAA,cACN,WAAW,GAAG,wCAAwC,QAAQ,YAAY;AAAA,YAAA;AAAA,UAAA;AAAA,QAC5E;AAAA,MAAA;AAAA,IAAA;AAAA,IAED,QACC,oBAAC,OAAA,EAAI,WAAU,2EACb,8BAAC,KAAA,EAAE,WAAU,mCAAmC,UAAA,KAAA,CAAK,EAAA,CACvD;AAAA,EAAA,GAEJ;AAEJ;"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const utils = require("../../lib/utils.cjs");
5
+ const types = require("./types.cjs");
6
+ function Suggestions({ suggestions, onSelect, className }) {
7
+ if (suggestions.length === 0) return null;
8
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: utils.cn("flex flex-wrap justify-center gap-2", className), children: suggestions.map((s, i) => /* @__PURE__ */ jsxRuntime.jsx(
9
+ "button",
10
+ {
11
+ type: "button",
12
+ onClick: () => onSelect(types.suggestionPrompt(s)),
13
+ className: "rounded-full border border-border bg-background px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
14
+ children: types.suggestionLabel(s)
15
+ },
16
+ `${types.suggestionLabel(s)}-${i}`
17
+ )) });
18
+ }
19
+ exports.Suggestions = Suggestions;
20
+ //# sourceMappingURL=Suggestion.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Suggestion.cjs","sources":["../../../src/data/chat/Suggestion.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { type Suggestion, suggestionLabel, suggestionPrompt } from \"./types\";\n\nexport type SuggestionsProps = {\n suggestions: Suggestion[];\n /** Called with the suggestion's prompt text when a pill is clicked. */\n onSelect: (prompt: string) => void;\n className?: string;\n};\n\n/** A wrap of suggested-prompt pills, shown on the empty state. */\nexport function Suggestions({ suggestions, onSelect, className }: SuggestionsProps) {\n if (suggestions.length === 0) return null;\n return (\n <div className={cn(\"flex flex-wrap justify-center gap-2\", className)}>\n {suggestions.map((s, i) => (\n <button\n key={`${suggestionLabel(s)}-${i}`}\n type=\"button\"\n onClick={() => onSelect(suggestionPrompt(s))}\n className=\"rounded-full border border-border bg-background px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground\"\n >\n {suggestionLabel(s)}\n </button>\n ))}\n </div>\n );\n}\n"],"names":["jsx","cn","suggestionPrompt","suggestionLabel"],"mappings":";;;;;AAWO,SAAS,YAAY,EAAE,aAAa,UAAU,aAA+B;AAClF,MAAI,YAAY,WAAW,EAAG,QAAO;AACrC,SACEA,2BAAAA,IAAC,OAAA,EAAI,WAAWC,MAAAA,GAAG,uCAAuC,SAAS,GAChE,UAAA,YAAY,IAAI,CAAC,GAAG,MACnBD,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,SAASE,MAAAA,iBAAiB,CAAC,CAAC;AAAA,MAC3C,WAAU;AAAA,MAET,gCAAgB,CAAC;AAAA,IAAA;AAAA,IALb,GAAGC,MAAAA,gBAAgB,CAAC,CAAC,IAAI,CAAC;AAAA,EAAA,CAOlC,GACH;AAEJ;;"}
@@ -0,0 +1,10 @@
1
+ import { Suggestion } from './types';
2
+ export type SuggestionsProps = {
3
+ suggestions: Suggestion[];
4
+ /** Called with the suggestion's prompt text when a pill is clicked. */
5
+ onSelect: (prompt: string) => void;
6
+ className?: string;
7
+ };
8
+ /** A wrap of suggested-prompt pills, shown on the empty state. */
9
+ export declare function Suggestions({ suggestions, onSelect, className }: SuggestionsProps): import("react/jsx-runtime").JSX.Element | null;
10
+ //# sourceMappingURL=Suggestion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Suggestion.d.ts","sourceRoot":"","sources":["../../../src/data/chat/Suggestion.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAqC,MAAM,SAAS,CAAC;AAE7E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,kDAgBjF"}
@@ -0,0 +1,20 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ import { suggestionLabel, suggestionPrompt } from "./types.js";
4
+ function Suggestions({ suggestions, onSelect, className }) {
5
+ if (suggestions.length === 0) return null;
6
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-wrap justify-center gap-2", className), children: suggestions.map((s, i) => /* @__PURE__ */ jsx(
7
+ "button",
8
+ {
9
+ type: "button",
10
+ onClick: () => onSelect(suggestionPrompt(s)),
11
+ className: "rounded-full border border-border bg-background px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground",
12
+ children: suggestionLabel(s)
13
+ },
14
+ `${suggestionLabel(s)}-${i}`
15
+ )) });
16
+ }
17
+ export {
18
+ Suggestions
19
+ };
20
+ //# sourceMappingURL=Suggestion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Suggestion.js","sources":["../../../src/data/chat/Suggestion.tsx"],"sourcesContent":["import { cn } from \"../../lib/utils\";\nimport { type Suggestion, suggestionLabel, suggestionPrompt } from \"./types\";\n\nexport type SuggestionsProps = {\n suggestions: Suggestion[];\n /** Called with the suggestion's prompt text when a pill is clicked. */\n onSelect: (prompt: string) => void;\n className?: string;\n};\n\n/** A wrap of suggested-prompt pills, shown on the empty state. */\nexport function Suggestions({ suggestions, onSelect, className }: SuggestionsProps) {\n if (suggestions.length === 0) return null;\n return (\n <div className={cn(\"flex flex-wrap justify-center gap-2\", className)}>\n {suggestions.map((s, i) => (\n <button\n key={`${suggestionLabel(s)}-${i}`}\n type=\"button\"\n onClick={() => onSelect(suggestionPrompt(s))}\n className=\"rounded-full border border-border bg-background px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground\"\n >\n {suggestionLabel(s)}\n </button>\n ))}\n </div>\n );\n}\n"],"names":[],"mappings":";;;AAWO,SAAS,YAAY,EAAE,aAAa,UAAU,aAA+B;AAClF,MAAI,YAAY,WAAW,EAAG,QAAO;AACrC,SACE,oBAAC,OAAA,EAAI,WAAW,GAAG,uCAAuC,SAAS,GAChE,UAAA,YAAY,IAAI,CAAC,GAAG,MACnB;AAAA,IAAC;AAAA,IAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,SAAS,iBAAiB,CAAC,CAAC;AAAA,MAC3C,WAAU;AAAA,MAET,0BAAgB,CAAC;AAAA,IAAA;AAAA,IALb,GAAG,gBAAgB,CAAC,CAAC,IAAI,CAAC;AAAA,EAAA,CAOlC,GACH;AAEJ;"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const react = require("react");
5
5
  const utils = require("../../lib/utils.cjs");
6
+ const button = require("../../components/button.cjs");
6
7
  const Icon = require("../Icon.cjs");
7
8
  const CodeBlock = require("../CodeBlock.cjs");
8
9
  const types = require("./types.cjs");
@@ -30,8 +31,9 @@ const STATUS_ICON = {
30
31
  "output-denied": { icon: UiCircleX.UiCircleX, className: "text-orange-600" },
31
32
  "output-error": { icon: UiCircleX.UiCircleX, className: "text-destructive" }
32
33
  };
33
- function ToolCall({ part, defaultOpen = false, className }) {
34
- const [open, setOpen] = react.useState(defaultOpen);
34
+ function ToolCall({ part, defaultOpen = false, onApprove, className }) {
35
+ const needsApproval = part.state === "approval-requested";
36
+ const [open, setOpen] = react.useState(defaultOpen || needsApproval);
35
37
  const status = STATUS_ICON[part.state];
36
38
  const name = types.toolPartName(part);
37
39
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("not-prose mb-1 w-full", className), children: [
@@ -68,7 +70,28 @@ function ToolCall({ part, defaultOpen = false, className }) {
68
70
  open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 pl-4 pt-0.5", children: [
69
71
  /* @__PURE__ */ jsxRuntime.jsx(ToolInput, { input: part.input }),
70
72
  /* @__PURE__ */ jsxRuntime.jsx(ToolOutput, { part })
71
- ] })
73
+ ] }),
74
+ needsApproval && /* @__PURE__ */ jsxRuntime.jsx(ApprovalControls, { part, onApprove })
75
+ ] });
76
+ }
77
+ function ApprovalControls({
78
+ part,
79
+ onApprove
80
+ }) {
81
+ const approval = "approval" in part ? part.approval : void 0;
82
+ if (!approval || !onApprove) return null;
83
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex items-center gap-2 pl-4", children: [
84
+ /* @__PURE__ */ jsxRuntime.jsx(button.Button, { type: "button", size: "sm", onClick: () => onApprove(approval.id, true), children: "Approve" }),
85
+ /* @__PURE__ */ jsxRuntime.jsx(
86
+ button.Button,
87
+ {
88
+ type: "button",
89
+ size: "sm",
90
+ variant: "outline",
91
+ onClick: () => onApprove(approval.id, false),
92
+ children: "Deny"
93
+ }
94
+ )
72
95
  ] });
73
96
  }
74
97
  function ToolInput({ input }) {
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.cjs","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport { CodeBlock } from \"../CodeBlock\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart } from \"./types\";\nimport { toolPartName } from \"./types\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<ToolState, { icon: StaticIconComponent; className: string }> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": { icon: UiCircleOutline, className: \"text-muted-foreground\" },\n \"input-available\": { icon: UiClock, className: \"text-muted-foreground animate-pulse\" },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name + status, expanding to its JSON input and (once available) output\n * or error. Renders both clicky `dynamic-tool` parts and typed `tool-<name>`\n * parts, keyed off `part.state`. */\nexport function ToolCall({ part, defaultOpen = false, className }: ToolCallProps) {\n const [open, setOpen] = useState(defaultOpen);\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div className=\"space-y-1 pl-4 pt-0.5\">\n <ToolInput input={part.input} />\n <ToolOutput part={part} />\n </div>\n )}\n </div>\n );\n}\n\nfunction ToolInput({ input }: { input: AnyToolPart[\"input\"] }) {\n if (input === undefined || input === null) {\n return null;\n }\n return (\n <div className=\"overflow-hidden text-xs\">\n <CodeBlock language=\"json\" source={JSON.stringify(input, null, 2)} />\n </div>\n );\n}\n\nfunction ToolOutput({ part }: { part: AnyToolPart }) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const output = part.state === \"output-available\" ? part.output : undefined;\n if (output === undefined && errorText === undefined) {\n return null;\n }\n return (\n <div className={cn(\"overflow-x-auto text-xs\", errorText ? \"text-destructive\" : \"text-muted-foreground\")}>\n {errorText !== undefined && <div>{errorText}</div>}\n {output !== undefined && (\n <CodeBlock language=\"json\" source={typeof output === \"string\" ? output : JSON.stringify(output, null, 2)} />\n )}\n </div>\n );\n}\n"],"names":["UiClock","UiCheck","UiCircleOutline","UiCircleX","useState","toolPartName","cn","jsxs","jsx","Icon","UiWrench","UiChevronDown","CodeBlock"],"mappings":"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"}
1
+ {"version":3,"file":"ToolCall.cjs","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport { CodeBlock } from \"../CodeBlock\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart } from \"./types\";\nimport { toolPartName } from \"./types\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n /** Respond to an approval request (only used when state is\n * `approval-requested`). Receives the approval id, the decision, and an\n * optional reason. */\n onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void) | undefined;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<ToolState, { icon: StaticIconComponent; className: string }> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": { icon: UiCircleOutline, className: \"text-muted-foreground\" },\n \"input-available\": { icon: UiClock, className: \"text-muted-foreground animate-pulse\" },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name + status, expanding to its JSON input and (once available) output\n * or error. Renders both clicky `dynamic-tool` parts and typed `tool-<name>`\n * parts, keyed off `part.state`. */\nexport function ToolCall({ part, defaultOpen = false, onApprove, className }: ToolCallProps) {\n const needsApproval = part.state === \"approval-requested\";\n const [open, setOpen] = useState(defaultOpen || needsApproval);\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div className=\"space-y-1 pl-4 pt-0.5\">\n <ToolInput input={part.input} />\n <ToolOutput part={part} />\n </div>\n )}\n\n {needsApproval && <ApprovalControls part={part} onApprove={onApprove} />}\n </div>\n );\n}\n\n/** Approve/Deny controls shown while a tool call awaits human approval. The\n * approval id comes from the part's `approval` envelope (AI SDK v6). */\nfunction ApprovalControls({\n part,\n onApprove,\n}: {\n part: AnyToolPart;\n onApprove: ToolCallProps[\"onApprove\"];\n}) {\n const approval = \"approval\" in part ? part.approval : undefined;\n if (!approval || !onApprove) return null;\n return (\n <div className=\"mt-1.5 flex items-center gap-2 pl-4\">\n <Button type=\"button\" size=\"sm\" onClick={() => onApprove(approval.id, true)}>\n Approve\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => onApprove(approval.id, false)}\n >\n Deny\n </Button>\n </div>\n );\n}\n\nfunction ToolInput({ input }: { input: AnyToolPart[\"input\"] }) {\n if (input === undefined || input === null) {\n return null;\n }\n return (\n <div className=\"overflow-hidden text-xs\">\n <CodeBlock language=\"json\" source={JSON.stringify(input, null, 2)} />\n </div>\n );\n}\n\nfunction ToolOutput({ part }: { part: AnyToolPart }) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const output = part.state === \"output-available\" ? part.output : undefined;\n if (output === undefined && errorText === undefined) {\n return null;\n }\n return (\n <div className={cn(\"overflow-x-auto text-xs\", errorText ? \"text-destructive\" : \"text-muted-foreground\")}>\n {errorText !== undefined && <div>{errorText}</div>}\n {output !== undefined && (\n <CodeBlock language=\"json\" source={typeof output === \"string\" ? output : JSON.stringify(output, null, 2)} />\n )}\n </div>\n );\n}\n"],"names":["UiClock","UiCheck","UiCircleOutline","UiCircleX","useState","toolPartName","cn","jsxs","jsx","Icon","UiWrench","UiChevronDown","Button","CodeBlock"],"mappings":"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"}
@@ -4,11 +4,15 @@ export type ToolCallProps = {
4
4
  part: AnyToolPart;
5
5
  /** Whether the call body starts expanded. Defaults to false. */
6
6
  defaultOpen?: boolean;
7
+ /** Respond to an approval request (only used when state is
8
+ * `approval-requested`). Receives the approval id, the decision, and an
9
+ * optional reason. */
10
+ onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void) | undefined;
7
11
  className?: string;
8
12
  };
9
13
  /** Generic display of a single AI tool call: a collapsible header showing the
10
14
  * tool name + status, expanding to its JSON input and (once available) output
11
15
  * or error. Renders both clicky `dynamic-tool` parts and typed `tool-<name>`
12
16
  * parts, keyed off `part.state`. */
13
- export declare function ToolCall({ part, defaultOpen, className }: ToolCallProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function ToolCall({ part, defaultOpen, onApprove, className }: ToolCallProps): import("react/jsx-runtime").JSX.Element;
14
18
  //# sourceMappingURL=ToolCall.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.d.ts","sourceRoot":"","sources":["../../../src/data/chat/ToolCall.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,MAAM,MAAM,aAAa,GAAG;IAC1B,kEAAkE;IAClE,IAAI,EAAE,WAAW,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAwBF;;;qCAGqC;AACrC,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAmB,EAAE,SAAS,EAAE,EAAE,aAAa,2CAoC/E"}
1
+ {"version":3,"file":"ToolCall.d.ts","sourceRoot":"","sources":["../../../src/data/chat/ToolCall.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,MAAM,MAAM,aAAa,GAAG;IAC1B,kEAAkE;IAClE,IAAI,EAAE,WAAW,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;2BAEuB;IACvB,SAAS,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAwBF;;;qCAGqC;AACrC,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAmB,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,aAAa,2CAuC1F"}
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { cn } from "../../lib/utils.js";
4
+ import { Button } from "../../components/button.js";
4
5
  import { Icon } from "../Icon.js";
5
6
  import { CodeBlock } from "../CodeBlock.js";
6
7
  import { toolPartName } from "./types.js";
@@ -28,8 +29,9 @@ const STATUS_ICON = {
28
29
  "output-denied": { icon: UiCircleX, className: "text-orange-600" },
29
30
  "output-error": { icon: UiCircleX, className: "text-destructive" }
30
31
  };
31
- function ToolCall({ part, defaultOpen = false, className }) {
32
- const [open, setOpen] = useState(defaultOpen);
32
+ function ToolCall({ part, defaultOpen = false, onApprove, className }) {
33
+ const needsApproval = part.state === "approval-requested";
34
+ const [open, setOpen] = useState(defaultOpen || needsApproval);
33
35
  const status = STATUS_ICON[part.state];
34
36
  const name = toolPartName(part);
35
37
  return /* @__PURE__ */ jsxs("div", { className: cn("not-prose mb-1 w-full", className), children: [
@@ -66,7 +68,28 @@ function ToolCall({ part, defaultOpen = false, className }) {
66
68
  open && /* @__PURE__ */ jsxs("div", { className: "space-y-1 pl-4 pt-0.5", children: [
67
69
  /* @__PURE__ */ jsx(ToolInput, { input: part.input }),
68
70
  /* @__PURE__ */ jsx(ToolOutput, { part })
69
- ] })
71
+ ] }),
72
+ needsApproval && /* @__PURE__ */ jsx(ApprovalControls, { part, onApprove })
73
+ ] });
74
+ }
75
+ function ApprovalControls({
76
+ part,
77
+ onApprove
78
+ }) {
79
+ const approval = "approval" in part ? part.approval : void 0;
80
+ if (!approval || !onApprove) return null;
81
+ return /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-2 pl-4", children: [
82
+ /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: () => onApprove(approval.id, true), children: "Approve" }),
83
+ /* @__PURE__ */ jsx(
84
+ Button,
85
+ {
86
+ type: "button",
87
+ size: "sm",
88
+ variant: "outline",
89
+ onClick: () => onApprove(approval.id, false),
90
+ children: "Deny"
91
+ }
92
+ )
70
93
  ] });
71
94
  }
72
95
  function ToolInput({ input }) {
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCall.js","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport { CodeBlock } from \"../CodeBlock\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart } from \"./types\";\nimport { toolPartName } from \"./types\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<ToolState, { icon: StaticIconComponent; className: string }> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": { icon: UiCircleOutline, className: \"text-muted-foreground\" },\n \"input-available\": { icon: UiClock, className: \"text-muted-foreground animate-pulse\" },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name + status, expanding to its JSON input and (once available) output\n * or error. Renders both clicky `dynamic-tool` parts and typed `tool-<name>`\n * parts, keyed off `part.state`. */\nexport function ToolCall({ part, defaultOpen = false, className }: ToolCallProps) {\n const [open, setOpen] = useState(defaultOpen);\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div className=\"space-y-1 pl-4 pt-0.5\">\n <ToolInput input={part.input} />\n <ToolOutput part={part} />\n </div>\n )}\n </div>\n );\n}\n\nfunction ToolInput({ input }: { input: AnyToolPart[\"input\"] }) {\n if (input === undefined || input === null) {\n return null;\n }\n return (\n <div className=\"overflow-hidden text-xs\">\n <CodeBlock language=\"json\" source={JSON.stringify(input, null, 2)} />\n </div>\n );\n}\n\nfunction ToolOutput({ part }: { part: AnyToolPart }) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const output = part.state === \"output-available\" ? part.output : undefined;\n if (output === undefined && errorText === undefined) {\n return null;\n }\n return (\n <div className={cn(\"overflow-x-auto text-xs\", errorText ? \"text-destructive\" : \"text-muted-foreground\")}>\n {errorText !== undefined && <div>{errorText}</div>}\n {output !== undefined && (\n <CodeBlock language=\"json\" source={typeof output === \"string\" ? output : JSON.stringify(output, null, 2)} />\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolCall.js","sources":["../../../src/data/chat/ToolCall.tsx"],"sourcesContent":["import { useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button } from \"../../components/button\";\nimport { Icon, type StaticIconComponent } from \"../Icon\";\nimport { CodeBlock } from \"../CodeBlock\";\nimport {\n UiCheck,\n UiChevronDown,\n UiCircleOutline,\n UiCircleX,\n UiClock,\n UiWrench,\n} from \"../../icons\";\nimport type { AnyToolPart } from \"./types\";\nimport { toolPartName } from \"./types\";\n\nexport type ToolCallProps = {\n /** The tool part from an assistant message (typed or dynamic). */\n part: AnyToolPart;\n /** Whether the call body starts expanded. Defaults to false. */\n defaultOpen?: boolean;\n /** Respond to an approval request (only used when state is\n * `approval-requested`). Receives the approval id, the decision, and an\n * optional reason. */\n onApprove?: ((approvalId: string, approved: boolean, reason?: string) => void) | undefined;\n className?: string;\n};\n\ntype ToolState = AnyToolPart[\"state\"];\n\nconst STATUS_LABEL: Record<ToolState, string> = {\n \"approval-requested\": \"Awaiting approval\",\n \"approval-responded\": \"Responded\",\n \"input-streaming\": \"Pending\",\n \"input-available\": \"Running\",\n \"output-available\": \"Completed\",\n \"output-denied\": \"Denied\",\n \"output-error\": \"Error\",\n};\n\nconst STATUS_ICON: Record<ToolState, { icon: StaticIconComponent; className: string }> = {\n \"approval-requested\": { icon: UiClock, className: \"text-amber-600\" },\n \"approval-responded\": { icon: UiCheck, className: \"text-sky-600\" },\n \"input-streaming\": { icon: UiCircleOutline, className: \"text-muted-foreground\" },\n \"input-available\": { icon: UiClock, className: \"text-muted-foreground animate-pulse\" },\n \"output-available\": { icon: UiCheck, className: \"text-emerald-600\" },\n \"output-denied\": { icon: UiCircleX, className: \"text-orange-600\" },\n \"output-error\": { icon: UiCircleX, className: \"text-destructive\" },\n};\n\n/** Generic display of a single AI tool call: a collapsible header showing the\n * tool name + status, expanding to its JSON input and (once available) output\n * or error. Renders both clicky `dynamic-tool` parts and typed `tool-<name>`\n * parts, keyed off `part.state`. */\nexport function ToolCall({ part, defaultOpen = false, onApprove, className }: ToolCallProps) {\n const needsApproval = part.state === \"approval-requested\";\n const [open, setOpen] = useState(defaultOpen || needsApproval);\n const status = STATUS_ICON[part.state];\n const name = toolPartName(part);\n\n return (\n <div className={cn(\"not-prose mb-1 w-full\", className)}>\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-full items-center justify-between gap-2 py-0.5 text-muted-foreground hover:text-foreground\"\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n <Icon icon={UiWrench} className=\"size-3 shrink-0\" />\n <span className=\"truncate font-mono text-xs\">{name}</span>\n <Icon\n icon={status.icon}\n title={STATUS_LABEL[part.state]}\n className={cn(\"size-3 shrink-0\", status.className)}\n />\n </span>\n <Icon\n icon={UiChevronDown}\n className={cn(\"size-3 shrink-0 transition-transform\", open && \"rotate-180\")}\n />\n </button>\n\n {open && (\n <div className=\"space-y-1 pl-4 pt-0.5\">\n <ToolInput input={part.input} />\n <ToolOutput part={part} />\n </div>\n )}\n\n {needsApproval && <ApprovalControls part={part} onApprove={onApprove} />}\n </div>\n );\n}\n\n/** Approve/Deny controls shown while a tool call awaits human approval. The\n * approval id comes from the part's `approval` envelope (AI SDK v6). */\nfunction ApprovalControls({\n part,\n onApprove,\n}: {\n part: AnyToolPart;\n onApprove: ToolCallProps[\"onApprove\"];\n}) {\n const approval = \"approval\" in part ? part.approval : undefined;\n if (!approval || !onApprove) return null;\n return (\n <div className=\"mt-1.5 flex items-center gap-2 pl-4\">\n <Button type=\"button\" size=\"sm\" onClick={() => onApprove(approval.id, true)}>\n Approve\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={() => onApprove(approval.id, false)}\n >\n Deny\n </Button>\n </div>\n );\n}\n\nfunction ToolInput({ input }: { input: AnyToolPart[\"input\"] }) {\n if (input === undefined || input === null) {\n return null;\n }\n return (\n <div className=\"overflow-hidden text-xs\">\n <CodeBlock language=\"json\" source={JSON.stringify(input, null, 2)} />\n </div>\n );\n}\n\nfunction ToolOutput({ part }: { part: AnyToolPart }) {\n const errorText = part.state === \"output-error\" ? part.errorText : undefined;\n const output = part.state === \"output-available\" ? part.output : undefined;\n if (output === undefined && errorText === undefined) {\n return null;\n }\n return (\n <div className={cn(\"overflow-x-auto text-xs\", errorText ? \"text-destructive\" : \"text-muted-foreground\")}>\n {errorText !== undefined && <div>{errorText}</div>}\n {output !== undefined && (\n <CodeBlock language=\"json\" source={typeof output === \"string\" ? output : JSON.stringify(output, null, 2)} />\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,13 @@
1
1
  export { Chat, type ChatProps } from './Chat';
2
2
  export { Conversation, type ConversationProps } from './Conversation';
3
- export { Message, type MessageProps } from './Message';
3
+ export { Message, type MessageProps, type MessageActionHandlers } from './Message';
4
+ export { MessageActions, type MessageActionsProps } from './MessageActions';
5
+ export { Reasoning, type ReasoningProps } from './Reasoning';
4
6
  export { PromptInput, type PromptInputProps } from './PromptInput';
5
7
  export { ToolCall, type ToolCallProps } from './ToolCall';
8
+ export { Suggestions, type SuggestionsProps } from './Suggestion';
9
+ export { ModelSelector, type ModelSelectorProps, EffortSelector, type EffortSelectorProps, } from './ModelSelector';
10
+ export { AttachmentButton, type AttachmentButtonProps, AttachmentList, type AttachmentListProps, } from './Attachment';
6
11
  export { clickyOperationsToTools, operationToTool, } from './clickyOperationsToTools';
7
- export { isDynamicToolPart, isTypedToolPart, toolPartName, type AnyToolPart, type ChatStatus, type ChatToolInputSchema, type ChatToolMeta, type DynamicToolUIPart, type JSONSchemaProperty, type ToolUIPart, type UIMessage, } from './types';
12
+ export { isDynamicToolPart, isTypedToolPart, isReasoningPart, isFilePart, toolPartName, suggestionLabel, suggestionPrompt, type AnyToolPart, type ChatModel, type ChatStatus, type ChatToolInputSchema, type ChatToolMeta, type DynamicToolUIPart, type FileUIPart, type JSONSchemaProperty, type ReasoningUIPart, type Suggestion, type ToolUIPart, type UIMessage, } from './types';
8
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/chat/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,EACL,uBAAuB,EACvB,eAAe,GAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/data/chat/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EACL,aAAa,EACb,KAAK,kBAAkB,EACvB,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,cAAc,EACd,KAAK,mBAAmB,GACzB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,uBAAuB,EACvB,eAAe,GAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,SAAS,CAAC"}
@@ -1,5 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ function suggestionLabel(s) {
4
+ return typeof s === "string" ? s : s.label;
5
+ }
6
+ function suggestionPrompt(s) {
7
+ return typeof s === "string" ? s : s.prompt;
8
+ }
9
+ function isReasoningPart(part) {
10
+ return part.type === "reasoning";
11
+ }
12
+ function isFilePart(part) {
13
+ return part.type === "file";
14
+ }
3
15
  function isDynamicToolPart(part) {
4
16
  return part.type === "dynamic-tool";
5
17
  }
@@ -13,6 +25,10 @@ function toolPartName(part) {
13
25
  return part.type.slice("tool-".length);
14
26
  }
15
27
  exports.isDynamicToolPart = isDynamicToolPart;
28
+ exports.isFilePart = isFilePart;
29
+ exports.isReasoningPart = isReasoningPart;
16
30
  exports.isTypedToolPart = isTypedToolPart;
31
+ exports.suggestionLabel = suggestionLabel;
32
+ exports.suggestionPrompt = suggestionPrompt;
17
33
  exports.toolPartName = toolPartName;
18
34
  //# sourceMappingURL=types.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.cjs","sources":["../../../src/data/chat/types.ts"],"sourcesContent":["import type { UIMessage, ToolUIPart, DynamicToolUIPart, ChatStatus } from \"ai\";\n\nexport type { UIMessage, ToolUIPart, DynamicToolUIPart, ChatStatus };\n\n/** A tool part as it appears in an assistant UIMessage — either a typed\n * `tool-<name>` part or the generic `dynamic-tool` part. clicky operations\n * surface as dynamic tools, so the chat UI renders both shapes. */\nexport type AnyToolPart = ToolUIPart | DynamicToolUIPart;\n\n/** AI-tool metadata derived from a clicky RPC operation. The Go backend owns\n * execution; the client uses this only for display and to scope which tools a\n * request may call (passed in the transport `body`). */\nexport interface ChatToolMeta {\n /** Stable tool name sent to the model (the operation id). */\n name: string;\n /** Human-readable description shown in tool pickers / tool-call headers. */\n description?: string | undefined;\n /** JSON-Schema for the tool's input, assembled from the operation's\n * parameters + request body. */\n inputSchema: ChatToolInputSchema;\n}\n\nexport interface ChatToolInputSchema {\n type: \"object\";\n properties: Record<string, JSONSchemaProperty>;\n required: string[];\n}\n\nexport interface JSONSchemaProperty {\n type?: string;\n description?: string;\n enum?: unknown[];\n default?: unknown;\n}\n\n/** Returns true for a `dynamic-tool` part (clicky operations surface this way). */\nexport function isDynamicToolPart(part: { type: string }): part is DynamicToolUIPart {\n return part.type === \"dynamic-tool\";\n}\n\n/** Returns true for a typed `tool-<name>` part. */\nexport function isTypedToolPart(part: { type: string }): part is ToolUIPart {\n return part.type.startsWith(\"tool-\");\n}\n\n/** The display name of a tool part: the explicit `toolName` for dynamic tools,\n * otherwise the suffix after `tool-`. */\nexport function toolPartName(part: AnyToolPart): string {\n if (isDynamicToolPart(part)) {\n return part.toolName;\n }\n return part.type.slice(\"tool-\".length);\n}\n"],"names":[],"mappings":";;AAoCO,SAAS,kBAAkB,MAAmD;AACnF,SAAO,KAAK,SAAS;AACvB;AAGO,SAAS,gBAAgB,MAA4C;AAC1E,SAAO,KAAK,KAAK,WAAW,OAAO;AACrC;AAIO,SAAS,aAAa,MAA2B;AACtD,MAAI,kBAAkB,IAAI,GAAG;AAC3B,WAAO,KAAK;AAAA,EACd;AACA,SAAO,KAAK,KAAK,MAAM,QAAQ,MAAM;AACvC;;;;"}
1
+ {"version":3,"file":"types.cjs","sources":["../../../src/data/chat/types.ts"],"sourcesContent":["import type {\n UIMessage,\n ToolUIPart,\n DynamicToolUIPart,\n ChatStatus,\n ReasoningUIPart,\n FileUIPart,\n} from \"ai\";\n\nexport type { UIMessage, ToolUIPart, DynamicToolUIPart, ChatStatus, ReasoningUIPart, FileUIPart };\n\n/** A selectable chat model, as served by the backend's GET /api/chat/models.\n * `configured` is false for catalogued models whose provider has no API key. */\nexport interface ChatModel {\n id: string;\n provider: string;\n label: string;\n reasoning: boolean;\n configured?: boolean;\n}\n\n/** A suggested prompt shown on the empty state. A bare string is both the label\n * and the submitted text; the object form separates them. */\nexport type Suggestion = string | { label: string; prompt: string };\n\n/** The label shown for a suggestion. */\nexport function suggestionLabel(s: Suggestion): string {\n return typeof s === \"string\" ? s : s.label;\n}\n\n/** The text submitted when a suggestion is clicked. */\nexport function suggestionPrompt(s: Suggestion): string {\n return typeof s === \"string\" ? s : s.prompt;\n}\n\n/** Returns true for an assistant reasoning (\"thinking\") part. */\nexport function isReasoningPart(part: { type: string }): part is ReasoningUIPart {\n return part.type === \"reasoning\";\n}\n\n/** Returns true for a file/attachment part. */\nexport function isFilePart(part: { type: string }): part is FileUIPart {\n return part.type === \"file\";\n}\n\n/** A tool part as it appears in an assistant UIMessage — either a typed\n * `tool-<name>` part or the generic `dynamic-tool` part. clicky operations\n * surface as dynamic tools, so the chat UI renders both shapes. */\nexport type AnyToolPart = ToolUIPart | DynamicToolUIPart;\n\n/** AI-tool metadata derived from a clicky RPC operation. The Go backend owns\n * execution; the client uses this only for display and to scope which tools a\n * request may call (passed in the transport `body`). */\nexport interface ChatToolMeta {\n /** Stable tool name sent to the model (the operation id). */\n name: string;\n /** Human-readable description shown in tool pickers / tool-call headers. */\n description?: string | undefined;\n /** JSON-Schema for the tool's input, assembled from the operation's\n * parameters + request body. */\n inputSchema: ChatToolInputSchema;\n}\n\nexport interface ChatToolInputSchema {\n type: \"object\";\n properties: Record<string, JSONSchemaProperty>;\n required: string[];\n}\n\nexport interface JSONSchemaProperty {\n type?: string;\n description?: string;\n enum?: unknown[];\n default?: unknown;\n}\n\n/** Returns true for a `dynamic-tool` part (clicky operations surface this way). */\nexport function isDynamicToolPart(part: { type: string }): part is DynamicToolUIPart {\n return part.type === \"dynamic-tool\";\n}\n\n/** Returns true for a typed `tool-<name>` part. */\nexport function isTypedToolPart(part: { type: string }): part is ToolUIPart {\n return part.type.startsWith(\"tool-\");\n}\n\n/** The display name of a tool part: the explicit `toolName` for dynamic tools,\n * otherwise the suffix after `tool-`. */\nexport function toolPartName(part: AnyToolPart): string {\n if (isDynamicToolPart(part)) {\n return part.toolName;\n }\n return part.type.slice(\"tool-\".length);\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,gBAAgB,GAAuB;AACrD,SAAO,OAAO,MAAM,WAAW,IAAI,EAAE;AACvC;AAGO,SAAS,iBAAiB,GAAuB;AACtD,SAAO,OAAO,MAAM,WAAW,IAAI,EAAE;AACvC;AAGO,SAAS,gBAAgB,MAAiD;AAC/E,SAAO,KAAK,SAAS;AACvB;AAGO,SAAS,WAAW,MAA4C;AACrE,SAAO,KAAK,SAAS;AACvB;AAkCO,SAAS,kBAAkB,MAAmD;AACnF,SAAO,KAAK,SAAS;AACvB;AAGO,SAAS,gBAAgB,MAA4C;AAC1E,SAAO,KAAK,KAAK,WAAW,OAAO;AACrC;AAIO,SAAS,aAAa,MAA2B;AACtD,MAAI,kBAAkB,IAAI,GAAG;AAC3B,WAAO,KAAK;AAAA,EACd;AACA,SAAO,KAAK,KAAK,MAAM,QAAQ,MAAM;AACvC;;;;;;;;"}