@parallelworks/ui 0.41.0 → 0.43.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.
Files changed (283) hide show
  1. package/README.md +25 -0
  2. package/dist/ai/components/AllocationSelector.d.ts +3 -4
  3. package/dist/ai/components/AllocationSelector.js +37 -33
  4. package/dist/ai/components/AttachmentManager.js +7 -7
  5. package/dist/ai/components/AttachmentUpload.js +5 -5
  6. package/dist/ai/components/BranchNavigator.js +1 -1
  7. package/dist/ai/components/ChatEmptyState.js +2 -2
  8. package/dist/ai/components/ChatInput.js +10 -8
  9. package/dist/ai/components/ChatLayout.js +4 -5
  10. package/dist/ai/components/ChatMessage.js +12 -12
  11. package/dist/ai/components/ChatMessageList.js +9 -9
  12. package/dist/ai/components/ChatSidebar.js +8 -9
  13. package/dist/ai/components/ChatThread.js +4 -4
  14. package/dist/ai/components/ComposerChrome.d.ts +2 -2
  15. package/dist/ai/components/ComposerChrome.js +3 -6
  16. package/dist/ai/components/DragOverlay.js +2 -2
  17. package/dist/ai/components/ModelSelector.d.ts +5 -3
  18. package/dist/ai/components/ModelSelector.js +102 -339
  19. package/dist/ai/components/PastedText.js +11 -11
  20. package/dist/ai/components/ProviderIssueBanner.d.ts +2 -0
  21. package/dist/ai/components/ProviderIssueBanner.js +34 -16
  22. package/dist/ai/components/Reasoning.js +4 -4
  23. package/dist/ai/components/ShareDialog.js +43 -35
  24. package/dist/ai/components/SlashMenu.d.ts +12 -2
  25. package/dist/ai/components/SlashMenu.js +29 -13
  26. package/dist/ai/components/agent/ActivityLine.js +3 -3
  27. package/dist/ai/components/agent/AgentMessageParts.js +20 -20
  28. package/dist/ai/components/agent/PermissionPicker.js +13 -11
  29. package/dist/ai/components/conversationActions.d.ts +4 -6
  30. package/dist/ai/components/conversationActions.js +9 -13
  31. package/dist/ai/core/ChatProvider.js +1 -1
  32. package/dist/ai/core/config.js +1 -1
  33. package/dist/ai/core/providerIssues.d.ts +7 -0
  34. package/dist/ai/core/providerIssues.js +9 -1
  35. package/dist/ai/core/useKeyboardShortcuts.d.ts +4 -0
  36. package/dist/ai/core/useKeyboardShortcuts.js +8 -2
  37. package/dist/ai/index.d.ts +0 -1
  38. package/dist/ai/index.js +1 -2
  39. package/dist/ai/strings.d.ts +19 -0
  40. package/dist/ai/strings.js +18 -1
  41. package/dist/ai/ui/Avatar.js +5 -5
  42. package/dist/ai/ui/ConversationSidebar.d.ts +0 -1
  43. package/dist/ai/ui/ConversationSidebar.js +6 -7
  44. package/dist/ai/ui/Markdown.js +3 -3
  45. package/dist/ai/ui/Notice.js +6 -6
  46. package/dist/ai/ui/chip.d.ts +4 -0
  47. package/dist/ai/ui/chip.js +8 -0
  48. package/dist/ai/ui/sidebar.d.ts +6 -5
  49. package/dist/ai/ui/sidebar.js +39 -43
  50. package/dist/components/ActionMenu.d.ts +13 -0
  51. package/dist/components/ActionMenu.js +30 -0
  52. package/dist/components/Avatar.js +6 -6
  53. package/dist/components/Breadcrumbs.js +1 -1
  54. package/dist/components/Button.js +10 -10
  55. package/dist/components/Callout.js +2 -2
  56. package/dist/components/Card.js +3 -3
  57. package/dist/components/Combobox.d.ts +49 -0
  58. package/dist/components/Combobox.js +405 -0
  59. package/dist/components/ConfirmModal.js +11 -11
  60. package/dist/components/ContextMenu.d.ts +23 -0
  61. package/dist/components/ContextMenu.js +89 -0
  62. package/dist/components/CopyToClipboard.js +2 -2
  63. package/dist/components/CreateModal.d.ts +19 -38
  64. package/dist/components/CreateModal.js +116 -267
  65. package/dist/components/DescriptionList.js +8 -8
  66. package/dist/components/Filter.js +2 -2
  67. package/dist/components/FilterPill.js +2 -2
  68. package/dist/components/HoverCard.d.ts +14 -0
  69. package/dist/components/HoverCard.js +33 -0
  70. package/dist/components/IconButton.d.ts +5 -5
  71. package/dist/components/IconButton.js +18 -22
  72. package/dist/components/InfoTip.d.ts +15 -0
  73. package/dist/components/InfoTip.js +60 -0
  74. package/dist/components/Input.js +5 -5
  75. package/dist/components/LetterBadge.js +2 -2
  76. package/dist/components/Loader.js +3 -3
  77. package/dist/components/Markdown.js +1 -1
  78. package/dist/components/MarkdownImpl.js +2 -2
  79. package/dist/components/Menu.d.ts +33 -0
  80. package/dist/components/Menu.js +86 -0
  81. package/dist/components/MenuEntries.d.ts +56 -0
  82. package/dist/components/MenuEntries.js +123 -0
  83. package/dist/components/Modal.d.ts +29 -0
  84. package/dist/components/Modal.js +47 -0
  85. package/dist/components/Overview.js +11 -10
  86. package/dist/components/PageHeader.d.ts +10 -16
  87. package/dist/components/PageHeader.js +69 -95
  88. package/dist/components/Pagination.js +5 -5
  89. package/dist/components/Provider.d.ts +5 -11
  90. package/dist/components/Provider.js +11 -14
  91. package/dist/components/Radio.d.ts +8 -0
  92. package/dist/components/Radio.js +16 -0
  93. package/dist/components/SectionHeader.js +2 -2
  94. package/dist/components/SegmentedControl.d.ts +6 -5
  95. package/dist/components/SegmentedControl.js +34 -30
  96. package/dist/components/Select.d.ts +27 -0
  97. package/dist/components/Select.js +78 -0
  98. package/dist/components/SettingModeOption.d.ts +5 -8
  99. package/dist/components/SettingModeOption.js +10 -12
  100. package/dist/components/SettingRow.js +4 -4
  101. package/dist/components/SettingsCard.js +4 -4
  102. package/dist/components/SettingsGroup.js +2 -2
  103. package/dist/components/Sort.js +1 -1
  104. package/dist/components/StatusBadge.js +7 -7
  105. package/dist/components/StatusIcons.js +4 -4
  106. package/dist/components/Switch.d.ts +22 -0
  107. package/dist/components/Switch.js +28 -0
  108. package/dist/components/Table.js +11 -11
  109. package/dist/components/Tooltip.d.ts +24 -20
  110. package/dist/components/Tooltip.js +58 -76
  111. package/dist/components/comboboxItems.d.ts +24 -0
  112. package/dist/components/comboboxItems.js +10 -0
  113. package/dist/components/floating.d.ts +14 -0
  114. package/dist/components/floating.js +21 -0
  115. package/dist/components/search.d.ts +2 -0
  116. package/dist/components/search.js +14 -0
  117. package/dist/editor/Editor.js +1 -1
  118. package/dist/editor/EditorField.js +16 -21
  119. package/dist/editor/FormCodePanel.js +19 -19
  120. package/dist/editor/Monaco.js +3 -3
  121. package/dist/file-explorer/FileExplorer.js +77 -81
  122. package/dist/file-explorer/FileExplorerContext.js +2 -2
  123. package/dist/file-explorer/FilePreview/CodePreviewEditor.js +1 -1
  124. package/dist/file-explorer/FilePreview/Inline.js +1 -1
  125. package/dist/file-explorer/FilePreview/StreamedBadge.js +5 -6
  126. package/dist/file-explorer/FilePreview/Viewer.js +8 -8
  127. package/dist/file-explorer/FilePreview/index.d.ts +1 -1
  128. package/dist/file-explorer/FilePreview/index.js +49 -83
  129. package/dist/file-explorer/FileRow.d.ts +4 -3
  130. package/dist/file-explorer/FileRow.js +32 -38
  131. package/dist/file-explorer/FileRowsWindow.d.ts +3 -2
  132. package/dist/file-explorer/FileRowsWindow.js +4 -4
  133. package/dist/file-explorer/FileTable.d.ts +3 -2
  134. package/dist/file-explorer/FileTable.js +3 -3
  135. package/dist/file-explorer/LoadMoreRow.js +1 -1
  136. package/dist/file-explorer/TreeView.js +11 -16
  137. package/dist/file-explorer/helpers.js +11 -12
  138. package/dist/file-explorer/toasts.js +11 -11
  139. package/dist/form/FieldGroup.d.ts +11 -0
  140. package/dist/form/FieldGroup.js +36 -0
  141. package/dist/form/FieldWrapper.js +4 -4
  142. package/dist/form/Fields/BooleanField.js +23 -33
  143. package/dist/form/Fields/CheckboxGroupField.d.ts +1 -1
  144. package/dist/form/Fields/CheckboxGroupField.js +9 -13
  145. package/dist/form/Fields/ColorField.d.ts +1 -2
  146. package/dist/form/Fields/ColorField.js +6 -11
  147. package/dist/form/Fields/DropdownField.d.ts +3 -13
  148. package/dist/form/Fields/DropdownField.js +40 -27
  149. package/dist/form/Fields/DurationField.d.ts +1 -2
  150. package/dist/form/Fields/DurationField.js +25 -32
  151. package/dist/form/Fields/LabelField.js +2 -2
  152. package/dist/form/Fields/MultiDropdownField.d.ts +6 -12
  153. package/dist/form/Fields/MultiDropdownField.js +31 -22
  154. package/dist/form/Fields/NumberField.d.ts +1 -1
  155. package/dist/form/Fields/NumberField.js +65 -35
  156. package/dist/form/Fields/ObjectField.d.ts +1 -1
  157. package/dist/form/Fields/ObjectField.js +12 -43
  158. package/dist/form/Fields/RadioField.d.ts +1 -1
  159. package/dist/form/Fields/RadioField.js +30 -41
  160. package/dist/form/Fields/RangeField.d.ts +1 -2
  161. package/dist/form/Fields/RangeField.js +23 -16
  162. package/dist/form/Fields/StringField.d.ts +1 -2
  163. package/dist/form/Fields/StringField.js +58 -26
  164. package/dist/form/Fields/TextAreaField.js +12 -10
  165. package/dist/form/Form.d.ts +30 -48
  166. package/dist/form/Form.js +306 -412
  167. package/dist/form/FormLayout.js +9 -9
  168. package/dist/form/Wizard/WizardContainer.d.ts +1 -4
  169. package/dist/form/Wizard/WizardContainer.js +40 -56
  170. package/dist/form/Wizard/WizardNavigation.js +1 -1
  171. package/dist/form/Wizard/WizardStepContent.d.ts +1 -5
  172. package/dist/form/Wizard/WizardStepContent.js +11 -16
  173. package/dist/form/Wizard/WizardStepIndicator.js +6 -6
  174. package/dist/form/Wizard/types.d.ts +0 -14
  175. package/dist/form/fieldRegistry.d.ts +1 -1
  176. package/dist/form/fieldRegistry.js +6 -6
  177. package/dist/form/formEditing.js +1 -1
  178. package/dist/form/index.d.ts +5 -4
  179. package/dist/form/index.js +6 -7
  180. package/dist/form/lib.js +3 -2
  181. package/dist/form/types/fieldComponentTypes.d.ts +8 -10
  182. package/dist/form/useChoiceField.d.ts +18 -0
  183. package/dist/form/useChoiceField.js +46 -0
  184. package/dist/form/useFieldValue.d.ts +7 -0
  185. package/dist/form/useFieldValue.js +20 -0
  186. package/dist/form/useParsedOpts.d.ts +3 -1
  187. package/dist/form/useParsedOpts.js +12 -17
  188. package/dist/form/utils/dependentOptions.d.ts +8 -4
  189. package/dist/form/utils/dependentOptions.js +25 -17
  190. package/dist/form/utils/fieldItems.d.ts +32 -0
  191. package/dist/form/utils/fieldItems.js +32 -0
  192. package/dist/form/utils/fieldPath.d.ts +10 -0
  193. package/dist/form/utils/fieldPath.js +20 -0
  194. package/dist/form/utils/shareEqual.d.ts +6 -0
  195. package/dist/form/utils/shareEqual.js +38 -0
  196. package/dist/graph/AnnotationBanner.js +8 -8
  197. package/dist/graph/Collapse.d.ts +1 -0
  198. package/dist/graph/Collapse.js +6 -27
  199. package/dist/graph/Connectors.js +5 -5
  200. package/dist/graph/DependencyGraph.js +20 -19
  201. package/dist/graph/GraphEditor.js +30 -41
  202. package/dist/graph/GraphEditorDialogs.js +17 -17
  203. package/dist/graph/GraphNode.js +1 -1
  204. package/dist/graph/InputDialog.js +19 -22
  205. package/dist/graph/InputsEditor.js +58 -66
  206. package/dist/graph/JobSummary.js +42 -39
  207. package/dist/graph/MatrixGroup.js +1 -1
  208. package/dist/graph/ProblemsButton.js +18 -19
  209. package/dist/graph/Reveal.js +1 -1
  210. package/dist/graph/ShortcutsButton.js +15 -18
  211. package/dist/graph/SuggestionInput.d.ts +5 -10
  212. package/dist/graph/SuggestionInput.js +14 -18
  213. package/dist/graph/ToolbarPopover.d.ts +11 -6
  214. package/dist/graph/ToolbarPopover.js +35 -67
  215. package/dist/graph/TreeView.js +24 -37
  216. package/dist/graph/WorkflowSettingsDialog.js +4 -4
  217. package/dist/graph/editorChrome.js +13 -12
  218. package/dist/graph/editorFields.js +29 -29
  219. package/dist/graph/editorPrimitives.d.ts +1 -1
  220. package/dist/graph/editorPrimitives.js +10 -7
  221. package/dist/graph/editorRows.js +103 -97
  222. package/dist/graph/fieldProblems.js +2 -2
  223. package/dist/graph/graphEditorState.d.ts +4 -3
  224. package/dist/graph/inputRefs.js +9 -9
  225. package/dist/graph/settingsViews.js +6 -7
  226. package/dist/graph/stepWith.js +6 -6
  227. package/dist/index.d.ts +14 -15
  228. package/dist/index.js +15 -14
  229. package/dist/list/ActionToolbar.d.ts +6 -14
  230. package/dist/list/ActionToolbar.js +48 -96
  231. package/dist/list/ListPage.d.ts +6 -12
  232. package/dist/list/ListPage.js +46 -29
  233. package/dist/list/ListPager.js +4 -4
  234. package/dist/list/ListTable.js +5 -5
  235. package/dist/list/ListViewControls.d.ts +5 -4
  236. package/dist/list/ListViewControls.js +177 -267
  237. package/dist/list/UserHoverCard.d.ts +3 -17
  238. package/dist/list/UserHoverCard.js +21 -45
  239. package/dist/list/index.d.ts +3 -4
  240. package/dist/list/index.js +3 -4
  241. package/dist/list/listSearch.js +12 -11
  242. package/dist/list/rowMenu.d.ts +68 -0
  243. package/dist/list/rowMenu.js +136 -0
  244. package/dist/logviewer/LogViewer.js +26 -26
  245. package/dist/styles.css +1 -1
  246. package/package.json +7 -13
  247. package/dist/ai/ui/Dropdown.d.ts +0 -31
  248. package/dist/ai/ui/Dropdown.js +0 -110
  249. package/dist/components/AddMenu.d.ts +0 -18
  250. package/dist/components/AddMenu.js +0 -46
  251. package/dist/components/BareModal.d.ts +0 -17
  252. package/dist/components/BareModal.js +0 -77
  253. package/dist/components/CollapsiblePanel.d.ts +0 -27
  254. package/dist/components/CollapsiblePanel.js +0 -77
  255. package/dist/components/Dropdown.d.ts +0 -28
  256. package/dist/components/Dropdown.js +0 -355
  257. package/dist/components/Listbox.d.ts +0 -21
  258. package/dist/components/Listbox.js +0 -119
  259. package/dist/components/MultiSelect.d.ts +0 -22
  260. package/dist/components/MultiSelect.js +0 -168
  261. package/dist/components/SwitchToggle.d.ts +0 -15
  262. package/dist/components/SwitchToggle.js +0 -57
  263. package/dist/components/SwitchToggleSmall.d.ts +0 -6
  264. package/dist/components/SwitchToggleSmall.js +0 -14
  265. package/dist/components/Toggle.d.ts +0 -6
  266. package/dist/components/Toggle.js +0 -20
  267. package/dist/components/dropdownUtils.d.ts +0 -37
  268. package/dist/components/dropdownUtils.js +0 -99
  269. package/dist/form/SpecialTypes/DropdownWrapper.d.ts +0 -25
  270. package/dist/form/SpecialTypes/DropdownWrapper.js +0 -28
  271. package/dist/form/SpecialTypes/FormikCustomDropdown.d.ts +0 -51
  272. package/dist/form/SpecialTypes/FormikCustomDropdown.js +0 -119
  273. package/dist/form/SpecialTypes/FormikCustomInput.d.ts +0 -19
  274. package/dist/form/SpecialTypes/FormikCustomInput.js +0 -121
  275. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.d.ts +0 -13
  276. package/dist/form/SpecialTypes/FormikMultiSelectDropdown.js +0 -31
  277. package/dist/form/SpecialTypes/FormikNumericInput.d.ts +0 -9
  278. package/dist/form/SpecialTypes/FormikNumericInput.js +0 -60
  279. package/dist/form/SpecialTypes/index.d.ts +0 -3
  280. package/dist/list/HoverCard.d.ts +0 -24
  281. package/dist/list/HoverCard.js +0 -73
  282. package/dist/list/RowContextMenu.d.ts +0 -127
  283. package/dist/list/RowContextMenu.js +0 -515
@@ -38,13 +38,10 @@ function ComposerUsage({ children }) {
38
38
  children
39
39
  });
40
40
  }
41
- /** The two selectors every surface carries, bare so they read as text beside
42
- * whatever the surface puts next to them. */
41
+ /** The two selectors every surface carries, reading as text beside whatever
42
+ * the surface puts next to them. */
43
43
  function ComposerControls({ targetSession }) {
44
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ModelSelector, {
45
- variant: "bare",
46
- targetSession
47
- }), /* @__PURE__ */ jsx(AllocationSelector, { variant: "bare" })] });
44
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ModelSelector, { targetSession }), /* @__PURE__ */ jsx(AllocationSelector, {})] });
48
45
  }
49
46
  /** Where the reader manages the providers behind the model picker, at the
50
47
  * foot of a conversation list. */
@@ -1,9 +1,9 @@
1
- import cx from "classnames";
1
+ import { clsx } from "clsx";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  //#region src/ai/components/DragOverlay.tsx
4
4
  function DragOverlay({ className }) {
5
5
  return /* @__PURE__ */ jsx("div", {
6
- className: cx("absolute inset-0 z-50 flex items-center justify-center bg-blue-500/10 border-2 border-dashed border-blue-500 backdrop-blur-sm pointer-events-none", className),
6
+ className: clsx("absolute inset-0 z-50 flex items-center justify-center bg-blue-500/10 border-2 border-dashed border-blue-500 backdrop-blur-sm pointer-events-none", className),
7
7
  children: /* @__PURE__ */ jsxs("div", {
8
8
  className: "text-center",
9
9
  children: [/* @__PURE__ */ jsx("p", {
@@ -1,6 +1,8 @@
1
1
  export declare function getProviderKeyFromModelId(modelId: string): string;
2
- export default function ModelSelector({ targetSession, variant, }: {
2
+ /** Picks the model a conversation runs on, grouped by provider. Sessions that
3
+ * are still connecting or not responding show as headings with their status,
4
+ * so the reader sees why their models are missing. */
5
+ export default function ModelSelector({ targetSession, }: {
6
+ /** A session, as "owner:name", whose models the reader is waiting for. */
3
7
  targetSession?: string | null | undefined;
4
- /** 'bare' drops the border and the icon, for a toolbar that reads as text. */
5
- variant?: 'default' | 'bare';
6
8
  }): import("react").JSX.Element;
@@ -1,17 +1,15 @@
1
- import { FaCheck } from "../../icons/fa/FaCheck.js";
2
1
  import { FaChevronDown } from "../../icons/fa/FaChevronDown.js";
3
2
  import { FaCloud } from "../../icons/fa/FaCloud.js";
4
- import { FaCog } from "../../icons/fa/FaCog.js";
5
3
  import { FaExclamationTriangle } from "../../icons/fa/FaExclamationTriangle.js";
6
- import { FaRobot } from "../../icons/fa/FaRobot.js";
7
4
  import { FaUndoAlt } from "../../icons/fa/FaUndoAlt.js";
5
+ import { Combobox } from "../../components/Combobox.js";
8
6
  import { useChatConfig } from "../core/config.js";
9
- import { providerIssueFor } from "../core/providerIssues.js";
7
+ import { issueDetail, issueLabel, providerIssueFor } from "../core/providerIssues.js";
10
8
  import { useChat } from "../core/ChatProvider.js";
11
- import cx from "classnames";
12
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
13
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
14
- import { createPortal } from "react-dom";
9
+ import { chipClassName } from "../ui/chip.js";
10
+ import { clsx } from "clsx";
11
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ import { useMemo } from "react";
15
13
  //#region src/ai/components/ModelSelector.tsx
16
14
  var ORG_OWNER = "org";
17
15
  /** Who registered a provider: the provider list's owner when the adapter
@@ -21,14 +19,11 @@ function providerOwner(info, model) {
21
19
  if (info) return info.user === ORG_OWNER ? "" : info.user;
22
20
  return model?.provider_owner ?? "";
23
21
  }
24
- /** The search field plus the list's max-h-80, so the flip decision matches
25
- * what renders. */
26
- var MAX_PANEL_HEIGHT_PX = 380;
27
22
  function CspIcon({ cspKind, className }) {
28
23
  const { slots } = useChatConfig();
29
24
  const custom = slots.providerIcon?.(cspKind, className);
30
- if (custom) return /* @__PURE__ */ jsx(Fragment$1, { children: custom });
31
- return /* @__PURE__ */ jsx(FaCloud, { className: cx("text-purple-500", className) });
25
+ if (custom) return /* @__PURE__ */ jsx(Fragment, { children: custom });
26
+ return /* @__PURE__ */ jsx(FaCloud, { className: clsx("text-purple-500", className) });
32
27
  }
33
28
  function getProviderKeyFromModelId(modelId) {
34
29
  const idx = modelId.indexOf("/");
@@ -54,339 +49,107 @@ function groupModelsByProvider(models) {
54
49
  }
55
50
  return groups;
56
51
  }
57
- function ModelSelector({ targetSession, variant = "default" }) {
58
- const bare = variant === "bare";
52
+ /** Picks the model a conversation runs on, grouped by provider. Sessions that
53
+ * are still connecting or not responding show as headings with their status,
54
+ * so the reader sees why their models are missing. */
55
+ function ModelSelector({ targetSession }) {
59
56
  const { providers, models, unreachableSessions, providerIssues, selectedProvider, setSelectedProvider, isLoadingModels, hasLoadedModels, modelsError, refreshModels, currentUser } = useChat();
60
- const { extraLinks, LinkComponent, strings } = useChatConfig();
61
- const [isOpen, setIsOpen] = useState(false);
62
- const [searchQuery, setSearchQuery] = useState("");
63
- const [dropdownPosition, setDropdownPosition] = useState({
64
- top: 0,
65
- bottom: 0,
66
- left: 0,
67
- width: 0,
68
- flipped: false
69
- });
70
- const containerRef = useRef(null);
71
- const dropdownRef = useRef(null);
72
- const buttonRef = useRef(null);
73
- const inputRef = useRef(null);
74
- const [mounted, setMounted] = useState(false);
75
- useEffect(() => {
76
- setMounted(true);
77
- }, []);
78
- const updateDropdownPosition = useCallback(() => {
79
- if (!buttonRef.current) return;
80
- const rect = buttonRef.current.getBoundingClientRect();
81
- const below = window.innerHeight - rect.bottom;
82
- setDropdownPosition({
83
- top: rect.bottom + 4,
84
- bottom: window.innerHeight - rect.top + 4,
85
- left: rect.left,
86
- width: Math.max(rect.width, 320),
87
- flipped: below < MAX_PANEL_HEIGHT_PX && rect.top > below
57
+ const { strings } = useChatConfig();
58
+ const t = strings.modelPicker;
59
+ const targetSessionFound = !!targetSession && models.some((m) => m.id.startsWith(`session:${targetSession}/`));
60
+ const targetSessionStatus = !targetSession ? null : isLoadingModels ? "connecting" : hasLoadedModels && !targetSessionFound ? "offline" : null;
61
+ const groups = useMemo(() => {
62
+ const status = (label, description) => ({
63
+ label,
64
+ icon: /* @__PURE__ */ jsx(FaCloud, { className: "h-3 w-3 text-amber-500" }),
65
+ description,
66
+ items: []
88
67
  });
89
- }, []);
90
- useEffect(() => {
91
- if (!isOpen) return;
92
- function handleClickOutside(event) {
93
- const target = event.target;
94
- const clickedInsideButton = containerRef.current?.contains(target);
95
- const clickedInsideDropdown = dropdownRef.current?.contains(target);
96
- if (!clickedInsideButton && !clickedInsideDropdown) setIsOpen(false);
97
- }
98
- const timeoutId = setTimeout(() => {
99
- document.addEventListener("mousedown", handleClickOutside);
100
- }, 0);
101
- return () => {
102
- clearTimeout(timeoutId);
103
- document.removeEventListener("mousedown", handleClickOutside);
104
- };
105
- }, [isOpen]);
106
- useEffect(() => {
107
- if (!isOpen) return;
108
- updateDropdownPosition();
109
- window.addEventListener("scroll", updateDropdownPosition, true);
110
- window.addEventListener("resize", updateDropdownPosition);
111
- return () => {
112
- window.removeEventListener("scroll", updateDropdownPosition, true);
113
- window.removeEventListener("resize", updateDropdownPosition);
114
- };
115
- }, [isOpen, updateDropdownPosition]);
116
- useEffect(() => {
117
- if (isOpen && inputRef.current) inputRef.current.focus();
118
- }, [isOpen]);
119
- const filteredModels = useMemo(() => {
120
- if (!searchQuery.trim()) return models;
121
- const query = searchQuery.toLowerCase();
122
- return models.filter((model) => getModelNameFromId(model.id).toLowerCase().includes(query) || (model.provider || "").toLowerCase().includes(query) || (model.name || "").toLowerCase().includes(query));
123
- }, [models, searchQuery]);
124
- const groupedModels = useMemo(() => groupModelsByProvider(filteredModels), [filteredModels]);
125
- const selectedModelInfo = models.find((m) => m.id === selectedProvider);
126
- const selectedModelName = selectedModelInfo ? getModelLabel(selectedModelInfo) : null;
127
- const selectedProviderName = selectedModelInfo?.provider || null;
128
- const issueLabel = (issue) => issue.status === "unauthorized" ? strings.providerIssue.keyRejected : strings.providerIssue.unreachable;
129
- const issueDetail = (issue) => issue.message || (issue.status === "unauthorized" ? strings.providerIssue.keyRejectedHint : strings.providerIssue.unreachableHint);
130
- const issueSummary = (issue) => `${issueLabel(issue)} \u2014 ${issueDetail(issue)}`;
131
- const selectedModelIssue = providerIssueFor(providerIssues, selectedModelInfo);
132
- const handleSelect = (modelId) => {
133
- setSelectedProvider(modelId);
134
- setIsOpen(false);
135
- setSearchQuery("");
136
- };
137
- const targetSessionDisplayName = targetSession?.split(":").pop();
138
- const targetSessionFound = targetSession && models.length > 0 ? models.some((m) => m.id.startsWith(`session:${targetSession}/`)) : false;
139
- const targetSessionStatus = targetSession ? isLoadingModels ? "connecting" : hasLoadedModels && !targetSessionFound ? "offline" : null : null;
140
- const boxClass = bare ? "flex items-center gap-1.5 rounded-full h-8 px-2.5 min-w-0 max-w-[280px]" : "flex items-center gap-2 px-3 h-8 rounded-lg min-w-[180px] max-w-[280px]";
141
- const textClass = bare ? "text-[13px]" : "text-sm";
142
- if (isLoadingModels && models.length === 0 && !targetSession) return /* @__PURE__ */ jsx("div", {
143
- ref: containerRef,
144
- className: "relative min-w-0",
145
- children: /* @__PURE__ */ jsxs("div", {
146
- className: boxClass,
147
- children: [!bare && /* @__PURE__ */ jsx(FaRobot, { className: "h-4 w-4 text-purple-500 flex-shrink-0 animate-pulse" }), /* @__PURE__ */ jsx("span", {
148
- className: cx(textClass, "theme-muted-text"),
149
- children: "Loading models..."
150
- })]
151
- })
152
- });
153
- if (modelsError && models.length === 0) return /* @__PURE__ */ jsx("div", {
154
- ref: containerRef,
155
- className: "relative min-w-0",
156
- children: /* @__PURE__ */ jsxs("div", {
157
- className: boxClass,
158
- children: [
159
- !bare && /* @__PURE__ */ jsx(FaRobot, { className: "h-4 w-4 text-red-500 flex-shrink-0" }),
160
- /* @__PURE__ */ jsx("span", {
161
- className: cx(textClass, "text-red-600"),
162
- children: "Failed to load models"
68
+ const sessions = unreachableSessions.filter((s) => `${s.owner}:${s.name}` !== targetSession).map((s) => status(s.name, t.notResponding));
69
+ if (targetSession && targetSessionStatus) sessions.unshift(status(targetSession.split(":").pop() ?? targetSession, targetSessionStatus === "connecting" ? t.connecting : t.notResponding));
70
+ const byProvider = [...groupModelsByProvider(models)].map(([providerKey, providerModels]) => {
71
+ const info = providers.find((p) => `${p.user}:${p.name}` === providerKey);
72
+ const first = providerModels[0];
73
+ const name = first?.provider || info?.name || providerKey;
74
+ const platform = info?.platformLabel;
75
+ const owner = providerOwner(info, first);
76
+ const issue = providerIssueFor(providerIssues, first);
77
+ const description = [
78
+ platform && platform.toLowerCase() !== name.toLowerCase() ? platform : null,
79
+ owner && owner !== currentUser.username ? t.sharedBy(owner) : null,
80
+ issue ? issueLabel(strings.providerIssue, issue) : null
81
+ ].filter(Boolean).join(" · ");
82
+ return {
83
+ label: name,
84
+ icon: /* @__PURE__ */ jsx(CspIcon, {
85
+ cspKind: info?.cspKind ?? "other",
86
+ className: "h-3 w-3"
163
87
  }),
164
- /* @__PURE__ */ jsxs("button", {
165
- type: "button",
166
- onClick: () => refreshModels(),
167
- className: "flex items-center gap-1 text-xs text-blue-600 hover:underline ml-1",
168
- children: [/* @__PURE__ */ jsx(FaUndoAlt, { className: "h-2.5 w-2.5" }), "Retry"]
169
- })
170
- ]
171
- })
88
+ description: description || void 0,
89
+ items: providerModels.map((model) => ({
90
+ label: getModelLabel(model),
91
+ value: model.id,
92
+ disabled: !!issue
93
+ }))
94
+ };
95
+ });
96
+ return [...sessions, ...byProvider];
97
+ }, [
98
+ models,
99
+ providers,
100
+ providerIssues,
101
+ unreachableSessions,
102
+ targetSession,
103
+ targetSessionStatus,
104
+ currentUser.username,
105
+ strings.providerIssue,
106
+ t
107
+ ]);
108
+ if (isLoadingModels && models.length === 0 && !targetSession) return /* @__PURE__ */ jsx("span", {
109
+ className: clsx(chipClassName, "cursor-default animate-pulse"),
110
+ children: t.loading
172
111
  });
173
- if (hasLoadedModels && models.length === 0 && !targetSessionStatus && unreachableSessions.length === 0) return /* @__PURE__ */ jsx("div", {
174
- ref: containerRef,
175
- className: "relative min-w-0",
176
- children: /* @__PURE__ */ jsxs("div", {
177
- className: boxClass,
178
- children: [!bare && /* @__PURE__ */ jsx(FaRobot, { className: "h-4 w-4 theme-muted-text flex-shrink-0" }), /* @__PURE__ */ jsx("span", {
179
- className: cx(textClass, "theme-muted-text"),
180
- children: "No models available"
181
- })]
182
- })
112
+ if (modelsError && models.length === 0) return /* @__PURE__ */ jsxs("span", {
113
+ className: clsx(chipClassName, "cursor-default text-(--theme-error)"),
114
+ children: [t.failed, /* @__PURE__ */ jsxs("button", {
115
+ type: "button",
116
+ onClick: () => refreshModels(),
117
+ className: "flex items-center gap-1 text-xs text-(--theme-element) hover:underline",
118
+ children: [/* @__PURE__ */ jsx(FaUndoAlt, { className: "h-2.5 w-2.5" }), t.retry]
119
+ })]
120
+ });
121
+ if (groups.length === 0 && hasLoadedModels) return /* @__PURE__ */ jsx("span", {
122
+ className: clsx(chipClassName, "cursor-default"),
123
+ children: t.none
183
124
  });
184
- const triggerText = selectedModelName ? null : targetSessionStatus === "connecting" ? "Connecting..." : models.length === 0 && isLoadingModels ? "Loading models..." : "Select a model";
185
- return /* @__PURE__ */ jsxs("div", {
186
- ref: containerRef,
187
- className: "relative min-w-0",
188
- children: [/* @__PURE__ */ jsxs("button", {
189
- ref: buttonRef,
125
+ const selected = models.find((m) => m.id === selectedProvider);
126
+ const issue = providerIssueFor(providerIssues, selected);
127
+ return /* @__PURE__ */ jsx(Combobox, {
128
+ "aria-label": t.choose,
129
+ placeholder: t.search,
130
+ items: groups,
131
+ value: selectedProvider,
132
+ onValueChange: (id) => id && setSelectedProvider(id),
133
+ disabled: groups.length === 0,
134
+ triggerTooltip: issue ? `${issueLabel(strings.providerIssue, issue)} \u2014 ${issueDetail(strings.providerIssue, issue)}` : void 0,
135
+ trigger: /* @__PURE__ */ jsxs("button", {
190
136
  type: "button",
191
- onClick: () => setIsOpen(!isOpen),
192
- "aria-haspopup": "dialog",
193
- "aria-expanded": isOpen,
194
- disabled: models.length === 0 && !targetSessionStatus && unreachableSessions.length === 0,
195
- className: cx(boxClass, "transition-all cursor-pointer bg-transparent", "focus:outline-none", "disabled:opacity-50 disabled:cursor-not-allowed", bare ? "hover:chat-tint" : "border theme-border hover:theme-hover"),
196
- children: [
197
- !bare && /* @__PURE__ */ jsx(FaRobot, { className: cx("h-4 w-4 flex-shrink-0", targetSessionStatus === "connecting" ? "text-amber-500 animate-pulse" : "text-purple-500") }),
198
- /* @__PURE__ */ jsx("div", {
199
- className: "flex-1 min-w-0 text-left",
200
- children: selectedModelName ? /* @__PURE__ */ jsxs("div", {
201
- className: "flex items-baseline gap-1.5 min-w-0",
202
- children: [
203
- /* @__PURE__ */ jsx("span", {
204
- title: selectedModelName,
205
- className: cx("truncate", bare ? "text-[13px] font-medium theme-text" : "text-sm font-medium text-(--theme-panel)"),
206
- children: selectedModelName
207
- }),
208
- selectedProviderName && /* @__PURE__ */ jsx("span", {
209
- title: selectedProviderName,
210
- className: "theme-muted-text truncate flex-shrink-0 max-w-[45%] text-xs",
211
- children: selectedProviderName
212
- }),
213
- selectedModelIssue && /* @__PURE__ */ jsx(FaExclamationTriangle, {
214
- title: issueSummary(selectedModelIssue),
215
- className: "h-3.5 w-3.5 text-amber-500 flex-shrink-0 self-center"
216
- })
217
- ]
218
- }) : /* @__PURE__ */ jsx("span", {
219
- className: cx(textClass, targetSessionStatus === "connecting" ? "text-amber-600" : "theme-muted-text"),
220
- children: triggerText
221
- })
137
+ className: chipClassName,
138
+ children: [selected ? /* @__PURE__ */ jsxs(Fragment, { children: [
139
+ /* @__PURE__ */ jsx("span", {
140
+ className: "truncate font-medium theme-text",
141
+ children: getModelLabel(selected)
142
+ }),
143
+ selected.provider && /* @__PURE__ */ jsx("span", {
144
+ className: "max-w-[45%] shrink-0 truncate text-xs",
145
+ children: selected.provider
222
146
  }),
223
- /* @__PURE__ */ jsx(FaChevronDown, { className: cx("h-3 w-3 theme-muted-text transition-transform flex-shrink-0", !bare && "ml-auto", isOpen && "rotate-180") })
224
- ]
225
- }), isOpen && mounted && createPortal(/* @__PURE__ */ jsxs("div", {
226
- ref: dropdownRef,
227
- role: "none",
228
- onClick: (e) => e.stopPropagation(),
229
- onKeyDown: (e) => {
230
- if (e.key === "Escape") {
231
- e.preventDefault();
232
- setIsOpen(false);
233
- buttonRef.current?.focus();
234
- }
235
- },
236
- style: {
237
- position: "fixed",
238
- ...dropdownPosition.flipped ? { bottom: dropdownPosition.bottom } : { top: dropdownPosition.top },
239
- left: dropdownPosition.left,
240
- width: dropdownPosition.width,
241
- zIndex: 9999
242
- },
243
- className: cx("theme-panel rounded-lg shadow-lg", "border theme-border", "overflow-hidden"),
244
- children: [/* @__PURE__ */ jsx("div", {
245
- className: "p-2 border-b theme-border",
246
- children: /* @__PURE__ */ jsx("input", {
247
- ref: inputRef,
248
- type: "text",
249
- value: searchQuery,
250
- onChange: (e) => setSearchQuery(e.target.value),
251
- placeholder: "Search models...",
252
- className: cx("w-full px-3 py-2 text-sm rounded-md", "theme-muted-panel", "border theme-border", "focus:outline-none focus:ring-2 focus:ring-blue-500", "placeholder:theme-muted-text")
253
- })
254
- }), /* @__PURE__ */ jsxs("div", {
255
- className: "max-h-80 overflow-y-auto",
256
- children: [
257
- targetSessionStatus && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
258
- className: "px-3 py-1.5 bg-amber-500/5 sticky top-0",
259
- children: /* @__PURE__ */ jsxs("div", {
260
- className: "flex items-center gap-2",
261
- children: [
262
- /* @__PURE__ */ jsx(FaCloud, { className: "h-3 w-3 text-amber-500" }),
263
- /* @__PURE__ */ jsx("span", {
264
- className: "text-xs font-semibold text-amber-600 uppercase tracking-wide flex-1",
265
- children: targetSessionDisplayName
266
- }),
267
- /* @__PURE__ */ jsx("span", {
268
- className: cx("text-[10px] px-1.5 py-0.5 rounded-full", targetSessionStatus === "connecting" ? "text-amber-600 bg-amber-500/10 animate-pulse" : "text-amber-500 bg-amber-500/10"),
269
- children: targetSessionStatus === "connecting" ? "Connecting..." : "Not responding"
270
- })
271
- ]
272
- })
273
- }), /* @__PURE__ */ jsx("div", {
274
- className: "px-4 py-2 flex items-center gap-2",
275
- children: /* @__PURE__ */ jsx("span", {
276
- className: "text-sm theme-muted-text italic",
277
- children: targetSessionStatus === "connecting" ? "Loading session models..." : "Service not responding — ensure it is running on the remote host"
278
- })
279
- })] }),
280
- unreachableSessions.filter((s) => !targetSession || `${s.owner}:${s.name}` !== targetSession).map((s) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
281
- className: "px-3 py-1.5 bg-amber-500/5 sticky top-0",
282
- children: /* @__PURE__ */ jsxs("div", {
283
- className: "flex items-center gap-2",
284
- children: [
285
- /* @__PURE__ */ jsx(FaCloud, { className: "h-3 w-3 text-amber-500" }),
286
- /* @__PURE__ */ jsx("span", {
287
- className: "text-xs font-semibold text-amber-600 uppercase tracking-wide flex-1",
288
- children: s.name
289
- }),
290
- /* @__PURE__ */ jsx("span", {
291
- className: "text-[10px] text-amber-500 bg-amber-500/10 px-1.5 py-0.5 rounded-full",
292
- children: "Not responding"
293
- })
294
- ]
295
- })
296
- }), /* @__PURE__ */ jsx("div", {
297
- className: "px-4 py-2 flex items-center gap-2",
298
- children: /* @__PURE__ */ jsx("span", {
299
- className: "text-sm theme-muted-text italic",
300
- children: "Service not responding — ensure it is running on the remote host"
301
- })
302
- })] }, `${s.owner}:${s.name}`)),
303
- groupedModels.size === 0 && !targetSessionStatus && unreachableSessions.length === 0 ? /* @__PURE__ */ jsx("div", {
304
- className: "p-4 text-center theme-muted-text text-sm",
305
- children: "No models found"
306
- }) : Array.from(groupedModels.entries()).map(([providerKey, providerModels]) => {
307
- const providerInfo = providers.find((p) => `${p.user}:${p.name}` === providerKey);
308
- const providerName = providerModels[0]?.provider || providerInfo?.name || "Unknown Provider";
309
- const platform = providerInfo?.platformLabel;
310
- const platformSuffix = providerInfo && platform && platform.toLowerCase() !== providerName.toLowerCase() ? platform : null;
311
- const isOwner = providerInfo?.user === currentUser.username;
312
- const owner = providerOwner(providerInfo, providerModels[0]);
313
- const headerSuffix = [platformSuffix, owner && owner !== currentUser.username ? strings.modelPicker.sharedBy(owner) : null].filter(Boolean).join(" · ");
314
- const settingsHref = providerInfo && extraLinks.providerSettings ? extraLinks.providerSettings(providerInfo.user, providerInfo.name) : null;
315
- const issue = providerIssueFor(providerIssues, providerModels[0]);
316
- return /* @__PURE__ */ jsxs("div", { children: [
317
- /* @__PURE__ */ jsx("div", {
318
- className: "px-3 py-1.5 theme-muted-panel sticky top-0",
319
- children: /* @__PURE__ */ jsxs("div", {
320
- className: "flex items-center gap-2",
321
- children: [
322
- /* @__PURE__ */ jsx(CspIcon, {
323
- cspKind: providerInfo?.cspKind ?? "other",
324
- className: "h-3 w-3"
325
- }),
326
- /* @__PURE__ */ jsx("span", {
327
- className: "text-xs font-semibold theme-muted-text uppercase tracking-wide",
328
- children: providerName
329
- }),
330
- /* @__PURE__ */ jsx("span", {
331
- className: "min-w-0 flex-1 truncate text-xs theme-muted-text",
332
- children: headerSuffix ? `· ${headerSuffix}` : ""
333
- }),
334
- /* @__PURE__ */ jsxs("span", {
335
- className: "text-xs theme-muted-text",
336
- children: [
337
- "(",
338
- providerModels.length,
339
- ")"
340
- ]
341
- }),
342
- issue && /* @__PURE__ */ jsx("span", {
343
- className: "text-[10px] text-amber-600 bg-amber-500/10 px-1.5 py-0.5 rounded-full flex-shrink-0",
344
- children: issueLabel(issue)
345
- }),
346
- isOwner && settingsHref && /* @__PURE__ */ jsx(LinkComponent, {
347
- target: {
348
- kind: "external",
349
- href: settingsHref
350
- },
351
- onClick: (e) => e.stopPropagation(),
352
- className: "p-0.5 rounded hover:theme-hover theme-muted-text hover:text-blue-600 transition-colors",
353
- title: "Manage provider",
354
- children: /* @__PURE__ */ jsx(FaCog, { className: "h-3 w-3" })
355
- })
356
- ]
357
- })
358
- }),
359
- issue && /* @__PURE__ */ jsxs("div", {
360
- className: "flex items-start gap-2 px-4 py-1.5 bg-amber-500/5",
361
- children: [/* @__PURE__ */ jsx(FaExclamationTriangle, { className: "h-3 w-3 text-amber-500 flex-shrink-0 mt-0.5" }), /* @__PURE__ */ jsx("span", {
362
- className: "text-xs text-amber-600 line-clamp-2",
363
- children: issueDetail(issue)
364
- })]
365
- }),
366
- providerModels.map((model) => {
367
- const modelName = getModelLabel(model);
368
- const isSelected = model.id === selectedProvider;
369
- return /* @__PURE__ */ jsxs("button", {
370
- type: "button",
371
- "aria-disabled": !!issue,
372
- title: issue ? issueSummary(issue) : void 0,
373
- onClick: () => {
374
- if (!issue) handleSelect(model.id);
375
- },
376
- className: cx("w-full flex items-center gap-3 px-4 py-2 text-left", issue ? "opacity-40 cursor-not-allowed" : "cursor-pointer hover:bg-blue-500/5 transition-colors", isSelected && "bg-blue-500/10"),
377
- children: [/* @__PURE__ */ jsx("span", {
378
- title: modelName,
379
- className: cx("flex-1 min-w-0 text-sm truncate", isSelected ? "text-blue-600 font-medium" : ""),
380
- style: !isSelected ? { color: "var(--theme-panel, #1f2937)" } : void 0,
381
- children: modelName
382
- }), isSelected && /* @__PURE__ */ jsx(FaCheck, { className: "h-3.5 w-3.5 text-blue-600 flex-shrink-0" })]
383
- }, model.id);
384
- })
385
- ] }, providerKey);
386
- })
387
- ]
388
- })]
389
- }), document.body)]
147
+ issue && /* @__PURE__ */ jsx(FaExclamationTriangle, { className: "h-3.5 w-3.5 shrink-0 text-amber-500" })
148
+ ] }) : /* @__PURE__ */ jsx("span", {
149
+ className: clsx("truncate", targetSessionStatus === "connecting" && "animate-pulse"),
150
+ children: targetSessionStatus === "connecting" ? t.connecting : t.select
151
+ }), /* @__PURE__ */ jsx(FaChevronDown, { className: "h-3 w-3 shrink-0" })]
152
+ })
390
153
  });
391
154
  }
392
155
  //#endregion
@@ -6,9 +6,9 @@ import { formatFileSize } from "../utils.js";
6
6
  import Markdown from "../ui/Markdown.js";
7
7
  import { fencePaste } from "../core/pasteLanguage.js";
8
8
  import { splitPastes } from "../core/pastes.js";
9
- import cx from "classnames";
10
- import { Fragment } from "react";
11
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ import { clsx } from "clsx";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ import { Fragment as Fragment$1 } from "react";
12
12
  //#region src/ai/components/PastedText.tsx
13
13
  /** A paste sent, or about to be sent, as its saved file. */
14
14
  function PasteFileCard({ id, lines, bytes, saving = false, error, onRemove }) {
@@ -16,7 +16,7 @@ function PasteFileCard({ id, lines, bytes, saving = false, error, onRemove }) {
16
16
  const detail = error ?? (saving ? t.saving : `${t.lines(lines)} · ${formatFileSize(bytes)}`);
17
17
  return /* @__PURE__ */ jsxs("div", {
18
18
  "data-testid": "paste-file-card",
19
- className: cx("inline-flex max-w-full items-center gap-2.5 rounded-xl px-3 py-2 align-top whitespace-normal", "bg-(--theme-panel-bg)", error ? "border border-red-500" : "chat-hairline"),
19
+ className: clsx("inline-flex max-w-full items-center gap-2.5 rounded-xl px-3 py-2 align-top whitespace-normal", "bg-(--theme-panel-bg)", error ? "border border-red-500" : "chat-hairline"),
20
20
  children: [
21
21
  /* @__PURE__ */ jsx(FiFile, { className: "h-5 w-5 flex-shrink-0 theme-muted-text" }),
22
22
  /* @__PURE__ */ jsxs("div", {
@@ -25,7 +25,7 @@ function PasteFileCard({ id, lines, bytes, saving = false, error, onRemove }) {
25
25
  className: "truncate text-sm font-medium theme-text",
26
26
  children: id ? `paste-${id}.txt` : t.title
27
27
  }), /* @__PURE__ */ jsx("div", {
28
- className: cx("truncate text-xs", error ? "text-red-500" : "theme-muted-text"),
28
+ className: clsx("truncate text-xs", error ? "text-red-500" : "theme-muted-text"),
29
29
  children: detail
30
30
  })]
31
31
  }),
@@ -45,23 +45,23 @@ function PasteFileCard({ id, lines, bytes, saving = false, error, onRemove }) {
45
45
  * it reads as, one sent as its file as a card. The blank lines the composer puts around a
46
46
  * paste would stack on the block's own spacing, so they are dropped. */
47
47
  function UserMessageText({ content, pastes }) {
48
- if (!pastes?.length) return /* @__PURE__ */ jsx(Fragment$1, { children: content });
48
+ if (!pastes?.length) return /* @__PURE__ */ jsx(Fragment, { children: content });
49
49
  const segments = splitPastes(content, pastes);
50
50
  const shows = (seg) => typeof seg !== "string" || seg.trim() !== "";
51
- const blockSpacing = (i) => cx(segments.slice(0, i).some(shows) ? "mt-2.5" : "mt-0", segments.slice(i + 1).some(shows) ? "mb-2.5" : "mb-0");
52
- return /* @__PURE__ */ jsx(Fragment$1, { children: segments.map((segment, i) => {
51
+ const blockSpacing = (i) => clsx(segments.slice(0, i).some(shows) ? "mt-2.5" : "mt-0", segments.slice(i + 1).some(shows) ? "mb-2.5" : "mb-0");
52
+ return /* @__PURE__ */ jsx(Fragment, { children: segments.map((segment, i) => {
53
53
  if (typeof segment === "string") {
54
54
  let text = segment;
55
55
  if (i > 0) text = text.replace(/^\n+/, "");
56
56
  if (i < segments.length - 1) text = text.replace(/\n+$/, "");
57
- return text ? /* @__PURE__ */ jsx(Fragment, { children: text }, i) : null;
57
+ return text ? /* @__PURE__ */ jsx(Fragment$1, { children: text }, i) : null;
58
58
  }
59
59
  if (segment.inline && segment.text !== void 0) return /* @__PURE__ */ jsx("span", {
60
- className: cx("chat-paste-code block", blockSpacing(i)),
60
+ className: clsx("chat-paste-code block", blockSpacing(i)),
61
61
  children: /* @__PURE__ */ jsx(Markdown, { children: fencePaste(segment.text) })
62
62
  }, i);
63
63
  return /* @__PURE__ */ jsx("span", {
64
- className: cx("flex [&>*]:flex-1", blockSpacing(i)),
64
+ className: clsx("flex [&>*]:flex-1", blockSpacing(i)),
65
65
  children: /* @__PURE__ */ jsx(PasteFileCard, {
66
66
  id: segment.id,
67
67
  lines: segment.lines,
@@ -1 +1,3 @@
1
+ /** Why the selected model can't answer, with a way to fix it for the
2
+ * provider's owner, who alone can change its key or endpoint. */
1
3
  export default function ProviderIssueBanner(): import("react").JSX.Element | null;