@neuronection/assistant-ui 0.8.1 → 0.10.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 (62) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +5 -2
  3. package/dist/Logo-D8DEBUoL.d.ts +11 -0
  4. package/dist/about.d.ts +154 -0
  5. package/dist/about.js +3 -0
  6. package/dist/about.js.map +1 -0
  7. package/dist/badge.d.ts +1 -1
  8. package/dist/badge.js +1 -1
  9. package/dist/capability-chips.d.ts +19 -0
  10. package/dist/capability-chips.js +3 -0
  11. package/dist/capability-chips.js.map +1 -0
  12. package/dist/card.js +1 -1
  13. package/dist/chip-list.js +1 -1
  14. package/dist/chunk-7EG3AUTS.js +3 -0
  15. package/dist/chunk-7EG3AUTS.js.map +1 -0
  16. package/dist/chunk-7RTSSBBR.js +628 -0
  17. package/dist/chunk-7RTSSBBR.js.map +1 -0
  18. package/dist/chunk-A6RXCBJY.js +3 -0
  19. package/dist/chunk-A6RXCBJY.js.map +1 -0
  20. package/dist/chunk-CE7JZP67.js +3 -0
  21. package/dist/chunk-CE7JZP67.js.map +1 -0
  22. package/dist/{chunk-SKTLC2XY.js → chunk-F4DP4PIM.js} +2 -2
  23. package/dist/{chunk-SKTLC2XY.js.map → chunk-F4DP4PIM.js.map} +1 -1
  24. package/dist/chunk-HGJ5HINX.js +500 -0
  25. package/dist/chunk-HGJ5HINX.js.map +1 -0
  26. package/dist/{chunk-UWHUCQC6.js → chunk-LY2B3UJH.js} +10 -4
  27. package/dist/chunk-LY2B3UJH.js.map +1 -0
  28. package/dist/chunk-MLQAA2QV.js +68 -0
  29. package/dist/chunk-MLQAA2QV.js.map +1 -0
  30. package/dist/chunk-Q2JMEAKN.js +340 -0
  31. package/dist/chunk-Q2JMEAKN.js.map +1 -0
  32. package/dist/{chunk-BN3YHYYL.js → chunk-QUPGIPTT.js} +2 -2
  33. package/dist/{chunk-BN3YHYYL.js.map → chunk-QUPGIPTT.js.map} +1 -1
  34. package/dist/{chunk-OPTH3VUY.js → chunk-RI6CEWWF.js} +2 -2
  35. package/dist/chunk-RI6CEWWF.js.map +1 -0
  36. package/dist/{chunk-HSWSYEFQ.js → chunk-RYE5YCFF.js} +2 -2
  37. package/dist/{chunk-HSWSYEFQ.js.map → chunk-RYE5YCFF.js.map} +1 -1
  38. package/dist/chunk-VPLCX2A5.js +3 -0
  39. package/dist/chunk-VPLCX2A5.js.map +1 -0
  40. package/dist/chunk-XB7QWPHP.js +127 -0
  41. package/dist/chunk-XB7QWPHP.js.map +1 -0
  42. package/dist/connection-test-row.d.ts +4 -0
  43. package/dist/connection-test-row.js +1 -1
  44. package/dist/index.d.ts +7 -2
  45. package/dist/index.js +22 -18
  46. package/dist/index.js.map +1 -1
  47. package/dist/logo.d.ts +18 -0
  48. package/dist/logo.js +3 -0
  49. package/dist/logo.js.map +1 -0
  50. package/dist/model-picker.d.ts +2 -0
  51. package/dist/model-picker.js +1 -1
  52. package/dist/model-registry.d.ts +84 -0
  53. package/dist/model-registry.js +3 -0
  54. package/dist/model-registry.js.map +1 -0
  55. package/dist/styles.css +1 -1
  56. package/dist/task-assignment-picker.d.ts +20 -5
  57. package/dist/task-assignment-picker.js +1 -1
  58. package/package.json +19 -1
  59. package/dist/chunk-OPTH3VUY.js.map +0 -1
  60. package/dist/chunk-TN35RR2R.js +0 -92
  61. package/dist/chunk-TN35RR2R.js.map +0 -1
  62. package/dist/chunk-UWHUCQC6.js.map +0 -1
@@ -0,0 +1,500 @@
1
+ import { SearchInput } from './chunk-H5U4KNXF.js';
2
+ import { CapabilityChips } from './chunk-MLQAA2QV.js';
3
+ import { Button } from './chunk-GTXGTQ6F.js';
4
+ import { Spinner } from './chunk-INTST5VG.js';
5
+ import { cn } from './chunk-BLJWR4ZV.js';
6
+ import * as React from 'react';
7
+ import { ChevronDown, ChevronRight, Plus, Pencil, Trash2, Check } from 'lucide-react';
8
+ import { jsxs, jsx } from 'react/jsx-runtime';
9
+
10
+ var UNCLASSIFIED = "__unclassified__";
11
+ var ModelRegistry = React.forwardRef(
12
+ function ModelRegistry2({
13
+ providers,
14
+ models,
15
+ caps,
16
+ expandedProviderId,
17
+ onExpandedProviderChange,
18
+ remoteModels,
19
+ remoteState = "ready",
20
+ remoteError,
21
+ onRetryRemote,
22
+ onAddModel,
23
+ onAddAll,
24
+ onUpdateModel,
25
+ onDeleteModel,
26
+ rank,
27
+ reasoningEffortOptions,
28
+ addLabel = "Add",
29
+ addedLabel = "Added",
30
+ addAllLabel = "Add all",
31
+ configureLabel = "Configure",
32
+ editLabel = "Edit",
33
+ removeLabel = "Remove",
34
+ enabledLabel = "Enabled",
35
+ missingLabel = "Missing",
36
+ capsLabel = "Capabilities",
37
+ searchPlaceholder = "Search models\u2026",
38
+ searchLabel = "Search models",
39
+ capFilterLabel = "Filter by capability",
40
+ unclassifiedLabel = "Unclassified",
41
+ emptyProviderLabel = "No models yet \u2014 add from the catalog below.",
42
+ remoteEmptyLabel = "No models match.",
43
+ remoteLoadingLabel = "Loading models\u2026",
44
+ retryLabel = "Retry",
45
+ manualAddLabel = "Add manually",
46
+ externalIdLabel = "Model ID",
47
+ labelLabel = "Display label",
48
+ reasoningEffortLabel = "Reasoning effort",
49
+ reasoningEffortPlaceholder,
50
+ saveLabel = "Save",
51
+ cancelLabel = "Cancel",
52
+ addDraftLabel = "Add model",
53
+ providersEmptyLabel = "No providers yet.",
54
+ emptyAction,
55
+ className
56
+ }, ref) {
57
+ const [query, setQuery] = React.useState("");
58
+ const [capFilter, setCapFilter] = React.useState(null);
59
+ const [draft, setDraft] = React.useState(null);
60
+ const [draftError, setDraftError] = React.useState(null);
61
+ const descriptorFor = React.useCallback(
62
+ (value) => caps.find((cap) => cap.value === value) ?? { value, label: value },
63
+ [caps]
64
+ );
65
+ const filteredRemote = React.useMemo(() => {
66
+ const items = remoteModels ?? [];
67
+ const needle = query.trim().toLowerCase();
68
+ const ranked = needle && rank ? rank(items, query) : items;
69
+ const searched = needle && !rank ? ranked.filter((item) => item.id.toLowerCase().includes(needle)) : ranked;
70
+ if (capFilter === UNCLASSIFIED) return searched.filter((item) => item.caps.length === 0);
71
+ if (capFilter) return searched.filter((item) => item.caps.includes(capFilter));
72
+ return searched;
73
+ }, [remoteModels, query, capFilter, rank]);
74
+ const filterDescriptors = React.useMemo(
75
+ () => [...caps, { value: UNCLASSIFIED, label: unclassifiedLabel }],
76
+ [caps, unclassifiedLabel]
77
+ );
78
+ const pendingRemote = React.useMemo(() => {
79
+ const expanded = providers.find((provider) => provider.id === expandedProviderId);
80
+ if (!expanded) return [];
81
+ const existingIds = new Set(
82
+ models.filter((model) => model.providerId === expanded.id).map((model) => model.externalId)
83
+ );
84
+ return filteredRemote.filter((remote) => !existingIds.has(remote.id));
85
+ }, [filteredRemote, providers, expandedProviderId, models]);
86
+ const resetDraft = React.useCallback(() => {
87
+ setDraft(null);
88
+ setDraftError(null);
89
+ }, []);
90
+ const toggleProvider = (providerId) => {
91
+ const next = expandedProviderId === providerId ? null : providerId;
92
+ onExpandedProviderChange(next);
93
+ setQuery("");
94
+ setCapFilter(null);
95
+ resetDraft();
96
+ };
97
+ const openAddDraft = (providerId, remote) => {
98
+ setDraft({
99
+ key: `remote:${remote.id}`,
100
+ mode: "add",
101
+ providerId,
102
+ externalId: remote.id,
103
+ label: "",
104
+ caps: [...remote.caps],
105
+ reasoningEffort: ""
106
+ });
107
+ setDraftError(null);
108
+ };
109
+ const openManualDraft = (providerId) => {
110
+ setDraft({
111
+ key: `manual:${providerId}`,
112
+ mode: "add",
113
+ providerId,
114
+ externalId: "",
115
+ label: "",
116
+ caps: caps[0] ? [caps[0].value] : [],
117
+ reasoningEffort: ""
118
+ });
119
+ setDraftError(null);
120
+ };
121
+ const openEditDraft = (model) => {
122
+ setDraft({
123
+ key: `model:${model.id}`,
124
+ mode: "edit",
125
+ providerId: model.providerId,
126
+ externalId: model.externalId,
127
+ label: model.label ?? "",
128
+ caps: [...model.caps],
129
+ reasoningEffort: model.reasoningEffort ?? "",
130
+ model
131
+ });
132
+ setDraftError(null);
133
+ };
134
+ const toggleDraftCap = (value) => {
135
+ setDraft(
136
+ (current) => current ? {
137
+ ...current,
138
+ caps: current.caps.includes(value) ? current.caps.filter((entry) => entry !== value) : [...current.caps, value]
139
+ } : current
140
+ );
141
+ };
142
+ const submitDraft = () => {
143
+ if (!draft) return;
144
+ const externalId = draft.externalId.trim();
145
+ if (!externalId) {
146
+ setDraftError(externalIdLabel);
147
+ return;
148
+ }
149
+ const payload = {
150
+ externalId,
151
+ label: draft.label.trim() || void 0,
152
+ caps: draft.caps,
153
+ reasoningEffort: draft.reasoningEffort.trim() || void 0
154
+ };
155
+ if (draft.mode === "add") {
156
+ onAddModel(draft.providerId, payload);
157
+ } else if (draft.model) {
158
+ onUpdateModel(draft.model, payload);
159
+ }
160
+ resetDraft();
161
+ };
162
+ const renderDraftPanel = () => {
163
+ if (!draft) return null;
164
+ const confirmDisabled = draft.mode === "add" && !draft.externalId.trim();
165
+ return /* @__PURE__ */ jsxs(
166
+ "div",
167
+ {
168
+ "data-as": "model-registry-draft",
169
+ className: "flex flex-col gap-3 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3",
170
+ children: [
171
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [
172
+ /* @__PURE__ */ jsxs("label", { className: "min-w-0 flex-1 space-y-1 text-xs", children: [
173
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: externalIdLabel }),
174
+ /* @__PURE__ */ jsx(
175
+ "input",
176
+ {
177
+ type: "text",
178
+ value: draft.externalId,
179
+ disabled: draft.mode === "edit",
180
+ onChange: (event) => setDraft(
181
+ (current) => current ? { ...current, externalId: event.target.value } : current
182
+ ),
183
+ className: "w-full rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 font-mono text-xs text-[var(--as-fg)] disabled:opacity-60"
184
+ }
185
+ )
186
+ ] }),
187
+ /* @__PURE__ */ jsxs("label", { className: "min-w-0 flex-1 space-y-1 text-xs", children: [
188
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: labelLabel }),
189
+ /* @__PURE__ */ jsx(
190
+ "input",
191
+ {
192
+ type: "text",
193
+ value: draft.label,
194
+ onChange: (event) => setDraft(
195
+ (current) => current ? { ...current, label: event.target.value } : current
196
+ ),
197
+ className: "w-full rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 text-xs text-[var(--as-fg)]"
198
+ }
199
+ )
200
+ ] })
201
+ ] }),
202
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
203
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: capsLabel }),
204
+ /* @__PURE__ */ jsx(
205
+ CapabilityChips,
206
+ {
207
+ caps,
208
+ selected: draft.caps,
209
+ onToggle: toggleDraftCap,
210
+ ariaLabel: capsLabel
211
+ }
212
+ )
213
+ ] }),
214
+ reasoningEffortOptions ? /* @__PURE__ */ jsxs("label", { className: "space-y-1 text-xs", children: [
215
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: reasoningEffortLabel }),
216
+ /* @__PURE__ */ jsx(
217
+ "input",
218
+ {
219
+ type: "text",
220
+ value: draft.reasoningEffort,
221
+ placeholder: reasoningEffortPlaceholder,
222
+ list: "as-reasoning-effort-options",
223
+ onChange: (event) => setDraft(
224
+ (current) => current ? { ...current, reasoningEffort: event.target.value } : current
225
+ ),
226
+ className: "w-full rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 text-xs text-[var(--as-fg)]"
227
+ }
228
+ ),
229
+ /* @__PURE__ */ jsx("datalist", { id: "as-reasoning-effort-options", children: reasoningEffortOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option }, option)) })
230
+ ] }) : null,
231
+ draftError ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-danger)]", children: draftError }) : null,
232
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
233
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: resetDraft, children: cancelLabel }),
234
+ /* @__PURE__ */ jsxs(
235
+ Button,
236
+ {
237
+ size: "sm",
238
+ disabled: confirmDisabled,
239
+ onClick: submitDraft,
240
+ children: [
241
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
242
+ draft.mode === "add" ? addDraftLabel : saveLabel
243
+ ]
244
+ }
245
+ )
246
+ ] })
247
+ ]
248
+ }
249
+ );
250
+ };
251
+ const renderRemoteRows = (providerId) => {
252
+ const providerModels = models.filter((model) => model.providerId === providerId);
253
+ const existingFor = (externalId) => providerModels.find((model) => model.externalId === externalId);
254
+ if (remoteState === "loading") {
255
+ return /* @__PURE__ */ jsxs("p", { className: "flex items-center justify-center gap-2 py-4 text-xs text-[var(--as-muted-fg)]", children: [
256
+ /* @__PURE__ */ jsx(Spinner, { size: "sm" }),
257
+ remoteLoadingLabel
258
+ ] });
259
+ }
260
+ if (remoteState === "error") {
261
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 py-2", children: [
262
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-[var(--as-danger)]", children: remoteError }),
263
+ onRetryRemote ? /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onRetryRemote, children: retryLabel }) : null
264
+ ] });
265
+ }
266
+ if (filteredRemote.length === 0) {
267
+ return /* @__PURE__ */ jsx("p", { className: "py-3 text-center text-xs text-[var(--as-muted-fg)]", children: remoteEmptyLabel });
268
+ }
269
+ return /* @__PURE__ */ jsx("div", { "data-as": "model-registry-catalog", className: "flex flex-col gap-1", children: filteredRemote.map((remote) => {
270
+ const existing = existingFor(remote.id);
271
+ const expandedRow = draft?.key === `remote:${remote.id}`;
272
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
273
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2 rounded-[var(--as-radius-sm)] border border-[var(--as-border)] px-3 py-2", children: [
274
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-xs text-[var(--as-fg)]", children: remote.id }),
275
+ /* @__PURE__ */ jsx(
276
+ CapabilityChips,
277
+ {
278
+ variant: "badge",
279
+ caps: remote.caps.map(descriptorFor),
280
+ selected: remote.caps
281
+ }
282
+ ),
283
+ /* @__PURE__ */ jsx(
284
+ "button",
285
+ {
286
+ type: "button",
287
+ "aria-expanded": expandedRow,
288
+ "aria-label": `${existing ? editLabel : configureLabel} ${remote.id}`,
289
+ onClick: () => {
290
+ if (expandedRow) {
291
+ resetDraft();
292
+ } else if (existing) {
293
+ openEditDraft(existing);
294
+ } else {
295
+ openAddDraft(providerId, remote);
296
+ }
297
+ },
298
+ className: "cursor-pointer rounded-[var(--as-radius-sm)] p-1.5 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-muted)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
299
+ children: expandedRow ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true })
300
+ }
301
+ ),
302
+ existing?.enabled ? /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[11px] text-[var(--as-muted-fg)]", children: [
303
+ /* @__PURE__ */ jsx(Check, { className: "size-3", "aria-hidden": true }),
304
+ addedLabel
305
+ ] }) : /* @__PURE__ */ jsxs(
306
+ Button,
307
+ {
308
+ variant: "outline",
309
+ size: "sm",
310
+ "aria-label": `${addLabel} ${remote.id}`,
311
+ onClick: () => onAddModel(providerId, { externalId: remote.id, caps: remote.caps }),
312
+ children: [
313
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
314
+ addLabel
315
+ ]
316
+ }
317
+ )
318
+ ] }),
319
+ expandedRow ? renderDraftPanel() : null
320
+ ] }, remote.id);
321
+ }) });
322
+ };
323
+ const renderModelRow = (model) => {
324
+ const expandedRow = draft?.key === `model:${model.id}`;
325
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
326
+ /* @__PURE__ */ jsxs(
327
+ "div",
328
+ {
329
+ className: cn(
330
+ "flex min-w-0 items-center gap-2 rounded-[var(--as-radius-sm)] px-2 py-1.5 text-sm",
331
+ model.missing && "opacity-50"
332
+ ),
333
+ children: [
334
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-xs text-[var(--as-fg)]", children: model.externalId }),
335
+ model.missing ? /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--as-warning)]", children: missingLabel }) : null,
336
+ /* @__PURE__ */ jsx(
337
+ CapabilityChips,
338
+ {
339
+ variant: "badge",
340
+ caps: model.caps.map(descriptorFor),
341
+ selected: model.caps
342
+ }
343
+ ),
344
+ /* @__PURE__ */ jsx("label", { className: "flex shrink-0 cursor-pointer items-center gap-1.5 text-xs text-[var(--as-muted-fg)]", children: /* @__PURE__ */ jsx(
345
+ "input",
346
+ {
347
+ type: "checkbox",
348
+ checked: model.enabled,
349
+ onChange: (event) => onUpdateModel(model, { enabled: event.target.checked }),
350
+ "aria-label": `${enabledLabel} \u2014 ${model.externalId}`
351
+ }
352
+ ) }),
353
+ /* @__PURE__ */ jsx(
354
+ "button",
355
+ {
356
+ type: "button",
357
+ "aria-expanded": expandedRow,
358
+ "aria-label": `${editLabel} ${model.externalId}`,
359
+ onClick: () => expandedRow ? resetDraft() : openEditDraft(model),
360
+ className: "cursor-pointer rounded-[var(--as-radius-sm)] p-1.5 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-muted)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
361
+ children: /* @__PURE__ */ jsx(Pencil, { className: "size-3.5", "aria-hidden": true })
362
+ }
363
+ ),
364
+ /* @__PURE__ */ jsx(
365
+ "button",
366
+ {
367
+ type: "button",
368
+ "aria-label": `${removeLabel} ${model.externalId}`,
369
+ onClick: () => {
370
+ if (expandedRow) resetDraft();
371
+ onDeleteModel(model);
372
+ },
373
+ className: "cursor-pointer rounded-[var(--as-radius-sm)] p-1.5 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-muted)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
374
+ children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5", "aria-hidden": true })
375
+ }
376
+ )
377
+ ]
378
+ }
379
+ ),
380
+ expandedRow ? renderDraftPanel() : null
381
+ ] }, model.id);
382
+ };
383
+ return /* @__PURE__ */ jsxs(
384
+ "div",
385
+ {
386
+ ref,
387
+ "data-as": "model-registry",
388
+ className: cn("flex w-full flex-col gap-4", className),
389
+ children: [
390
+ providers.map((provider) => {
391
+ const expanded = expandedProviderId === provider.id;
392
+ const providerModels = models.filter((model) => model.providerId === provider.id);
393
+ return /* @__PURE__ */ jsxs(
394
+ "div",
395
+ {
396
+ "data-as": "model-registry-provider",
397
+ className: cn(
398
+ "rounded-[var(--as-radius-lg)] border bg-[var(--as-surface)] transition-colors",
399
+ expanded ? "border-[var(--as-primary)]" : "border-[var(--as-border)]"
400
+ ),
401
+ children: [
402
+ /* @__PURE__ */ jsxs(
403
+ "button",
404
+ {
405
+ type: "button",
406
+ "aria-expanded": expanded,
407
+ onClick: () => toggleProvider(provider.id),
408
+ className: "flex w-full cursor-pointer items-center gap-3 p-4 text-left focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
409
+ children: [
410
+ expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-5 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-5 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true }),
411
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
412
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-sm font-semibold text-[var(--as-fg)]", children: [
413
+ provider.name,
414
+ provider.type ? /* @__PURE__ */ jsx("span", { className: "rounded-full border border-[var(--as-border)] px-2 py-0.5 text-[11px] font-normal text-[var(--as-muted-fg)]", children: provider.type }) : null,
415
+ /* @__PURE__ */ jsxs("span", { className: "text-xs font-normal text-[var(--as-muted-fg)]", children: [
416
+ providerModels.filter((model) => model.enabled).length,
417
+ "/",
418
+ providerModels.length
419
+ ] })
420
+ ] }),
421
+ provider.baseUrl ? /* @__PURE__ */ jsx("span", { className: "block truncate font-mono text-xs text-[var(--as-muted-fg)]", children: provider.baseUrl }) : null
422
+ ] })
423
+ ]
424
+ }
425
+ ),
426
+ expanded ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 border-t border-[var(--as-border)] p-4", children: [
427
+ providerModels.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-muted-fg)]", children: emptyProviderLabel }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: providerModels.map(renderModelRow) }),
428
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-[var(--as-border)] pt-3", children: [
429
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
430
+ /* @__PURE__ */ jsx(
431
+ SearchInput,
432
+ {
433
+ value: query,
434
+ onChange: (next) => {
435
+ setQuery(next);
436
+ resetDraft();
437
+ },
438
+ placeholder: searchPlaceholder,
439
+ ariaLabel: searchLabel,
440
+ className: "max-w-xs flex-1"
441
+ }
442
+ ),
443
+ /* @__PURE__ */ jsx(
444
+ CapabilityChips,
445
+ {
446
+ caps: filterDescriptors,
447
+ selected: capFilter ? [capFilter] : [],
448
+ onToggle: (value) => setCapFilter((current) => current === value ? null : value),
449
+ ariaLabel: capFilterLabel
450
+ }
451
+ ),
452
+ /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => openManualDraft(provider.id), children: [
453
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
454
+ manualAddLabel
455
+ ] }),
456
+ onAddAll ? /* @__PURE__ */ jsxs(
457
+ Button,
458
+ {
459
+ variant: "outline",
460
+ size: "sm",
461
+ disabled: remoteState !== "ready" || pendingRemote.length === 0,
462
+ onClick: () => onAddAll(
463
+ provider.id,
464
+ pendingRemote.map((remote) => ({
465
+ externalId: remote.id,
466
+ caps: remote.caps
467
+ }))
468
+ ),
469
+ children: [
470
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
471
+ addAllLabel,
472
+ " (",
473
+ pendingRemote.length,
474
+ ")"
475
+ ]
476
+ }
477
+ ) : null
478
+ ] }),
479
+ draft?.key.startsWith("manual:") ? renderDraftPanel() : null,
480
+ renderRemoteRows(provider.id)
481
+ ] })
482
+ ] }) : null
483
+ ]
484
+ },
485
+ provider.id
486
+ );
487
+ }),
488
+ providers.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8 text-center", children: [
489
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--as-muted-fg)]", children: providersEmptyLabel }),
490
+ emptyAction
491
+ ] }) : null
492
+ ]
493
+ }
494
+ );
495
+ }
496
+ );
497
+
498
+ export { ModelRegistry };
499
+ //# sourceMappingURL=chunk-HGJ5HINX.js.map
500
+ //# sourceMappingURL=chunk-HGJ5HINX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-registry/ModelRegistry.tsx"],"names":["ModelRegistry"],"mappings":"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","file":"chunk-HGJ5HINX.js","sourcesContent":["import * as React from 'react'\nimport { Check, ChevronDown, ChevronRight, Pencil, Plus, Trash2 } from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button'\nimport { CapabilityChips, type CapabilityDescriptor } from '../capability-chips'\nimport { SearchInput } from '../search-input'\nimport { Spinner } from '../spinner'\n\nexport interface ModelRegistryProvider {\n id: string\n name: string\n type?: string\n baseUrl?: string\n}\n\nexport interface ModelRegistryModel {\n id: string\n providerId: string\n externalId: string\n label?: string\n caps: string[]\n enabled: boolean\n reasoningEffort?: string\n missing?: boolean\n}\n\nexport interface ModelRegistryRemoteModel {\n id: string\n caps: string[]\n}\n\nexport interface ModelRegistryDraft {\n externalId: string\n label?: string\n caps: string[]\n reasoningEffort?: string\n}\n\nexport interface ModelRegistryPatch {\n label?: string\n caps?: string[]\n enabled?: boolean\n reasoningEffort?: string\n}\n\nexport type ModelRegistryRemoteState = 'loading' | 'error' | 'ready'\n\nexport interface ModelRegistryProps {\n providers: ModelRegistryProvider[]\n models: ModelRegistryModel[]\n caps: CapabilityDescriptor[]\n expandedProviderId?: string | null\n onExpandedProviderChange: (providerId: string | null) => void\n remoteModels?: ModelRegistryRemoteModel[]\n remoteState?: ModelRegistryRemoteState\n remoteError?: string | null\n onRetryRemote?: () => void\n onAddModel: (providerId: string, draft: ModelRegistryDraft) => void\n onAddAll?: (providerId: string, drafts: ModelRegistryDraft[]) => void\n onUpdateModel: (model: ModelRegistryModel, patch: ModelRegistryPatch) => void\n onDeleteModel: (model: ModelRegistryModel) => void\n rank?: (items: ModelRegistryRemoteModel[], query: string) => ModelRegistryRemoteModel[]\n reasoningEffortOptions?: string[]\n addLabel?: string\n addedLabel?: string\n addAllLabel?: string\n configureLabel?: string\n editLabel?: string\n removeLabel?: string\n enabledLabel?: string\n missingLabel?: string\n capsLabel?: string\n searchPlaceholder?: string\n searchLabel?: string\n capFilterLabel?: string\n unclassifiedLabel?: string\n emptyProviderLabel?: string\n remoteEmptyLabel?: string\n remoteLoadingLabel?: string\n retryLabel?: string\n manualAddLabel?: string\n externalIdLabel?: string\n labelLabel?: string\n reasoningEffortLabel?: string\n reasoningEffortPlaceholder?: string\n saveLabel?: string\n cancelLabel?: string\n addDraftLabel?: string\n providersEmptyLabel?: string\n emptyAction?: React.ReactNode\n className?: string\n}\n\nconst UNCLASSIFIED = '__unclassified__'\n\ninterface DraftState {\n key: string\n mode: 'add' | 'edit'\n providerId: string\n externalId: string\n label: string\n caps: string[]\n reasoningEffort: string\n model?: ModelRegistryModel\n}\n\nexport const ModelRegistry = React.forwardRef<HTMLDivElement, ModelRegistryProps>(\n function ModelRegistry(\n {\n providers,\n models,\n caps,\n expandedProviderId,\n onExpandedProviderChange,\n remoteModels,\n remoteState = 'ready',\n remoteError,\n onRetryRemote,\n onAddModel,\n onAddAll,\n onUpdateModel,\n onDeleteModel,\n rank,\n reasoningEffortOptions,\n addLabel = 'Add',\n addedLabel = 'Added',\n addAllLabel = 'Add all',\n configureLabel = 'Configure',\n editLabel = 'Edit',\n removeLabel = 'Remove',\n enabledLabel = 'Enabled',\n missingLabel = 'Missing',\n capsLabel = 'Capabilities',\n searchPlaceholder = 'Search models…',\n searchLabel = 'Search models',\n capFilterLabel = 'Filter by capability',\n unclassifiedLabel = 'Unclassified',\n emptyProviderLabel = 'No models yet — add from the catalog below.',\n remoteEmptyLabel = 'No models match.',\n remoteLoadingLabel = 'Loading models…',\n retryLabel = 'Retry',\n manualAddLabel = 'Add manually',\n externalIdLabel = 'Model ID',\n labelLabel = 'Display label',\n reasoningEffortLabel = 'Reasoning effort',\n reasoningEffortPlaceholder,\n saveLabel = 'Save',\n cancelLabel = 'Cancel',\n addDraftLabel = 'Add model',\n providersEmptyLabel = 'No providers yet.',\n emptyAction,\n className,\n },\n ref,\n ) {\n const [query, setQuery] = React.useState('')\n const [capFilter, setCapFilter] = React.useState<string | null>(null)\n const [draft, setDraft] = React.useState<DraftState | null>(null)\n const [draftError, setDraftError] = React.useState<string | null>(null)\n\n const descriptorFor = React.useCallback(\n (value: string): CapabilityDescriptor =>\n caps.find((cap) => cap.value === value) ?? { value, label: value },\n [caps],\n )\n\n const filteredRemote = React.useMemo(() => {\n const items = remoteModels ?? []\n const needle = query.trim().toLowerCase()\n const ranked =\n needle && rank ? rank(items, query) : items\n const searched =\n needle && !rank\n ? ranked.filter((item) => item.id.toLowerCase().includes(needle))\n : ranked\n if (capFilter === UNCLASSIFIED) return searched.filter((item) => item.caps.length === 0)\n if (capFilter) return searched.filter((item) => item.caps.includes(capFilter))\n return searched\n }, [remoteModels, query, capFilter, rank])\n\n const filterDescriptors: CapabilityDescriptor[] = React.useMemo(\n () => [...caps, { value: UNCLASSIFIED, label: unclassifiedLabel }],\n [caps, unclassifiedLabel],\n )\n\n const pendingRemote = React.useMemo(() => {\n const expanded = providers.find((provider) => provider.id === expandedProviderId)\n if (!expanded) return []\n const existingIds = new Set(\n models\n .filter((model) => model.providerId === expanded.id)\n .map((model) => model.externalId),\n )\n return filteredRemote.filter((remote) => !existingIds.has(remote.id))\n }, [filteredRemote, providers, expandedProviderId, models])\n\n const resetDraft = React.useCallback(() => {\n setDraft(null)\n setDraftError(null)\n }, [])\n\n const toggleProvider = (providerId: string) => {\n const next = expandedProviderId === providerId ? null : providerId\n onExpandedProviderChange(next)\n setQuery('')\n setCapFilter(null)\n resetDraft()\n }\n\n const openAddDraft = (providerId: string, remote: ModelRegistryRemoteModel) => {\n setDraft({\n key: `remote:${remote.id}`,\n mode: 'add',\n providerId,\n externalId: remote.id,\n label: '',\n caps: [...remote.caps],\n reasoningEffort: '',\n })\n setDraftError(null)\n }\n\n const openManualDraft = (providerId: string) => {\n setDraft({\n key: `manual:${providerId}`,\n mode: 'add',\n providerId,\n externalId: '',\n label: '',\n caps: caps[0] ? [caps[0].value] : [],\n reasoningEffort: '',\n })\n setDraftError(null)\n }\n\n const openEditDraft = (model: ModelRegistryModel) => {\n setDraft({\n key: `model:${model.id}`,\n mode: 'edit',\n providerId: model.providerId,\n externalId: model.externalId,\n label: model.label ?? '',\n caps: [...model.caps],\n reasoningEffort: model.reasoningEffort ?? '',\n model,\n })\n setDraftError(null)\n }\n\n const toggleDraftCap = (value: string) => {\n setDraft((current) =>\n current\n ? {\n ...current,\n caps: current.caps.includes(value)\n ? current.caps.filter((entry) => entry !== value)\n : [...current.caps, value],\n }\n : current,\n )\n }\n\n const submitDraft = () => {\n if (!draft) return\n const externalId = draft.externalId.trim()\n if (!externalId) {\n setDraftError(externalIdLabel)\n return\n }\n const payload: ModelRegistryDraft = {\n externalId,\n label: draft.label.trim() || undefined,\n caps: draft.caps,\n reasoningEffort: draft.reasoningEffort.trim() || undefined,\n }\n if (draft.mode === 'add') {\n onAddModel(draft.providerId, payload)\n } else if (draft.model) {\n onUpdateModel(draft.model, payload)\n }\n resetDraft()\n }\n\n const renderDraftPanel = () => {\n if (!draft) return null\n const confirmDisabled = draft.mode === 'add' && !draft.externalId.trim()\n return (\n <div\n data-as=\"model-registry-draft\"\n className=\"flex flex-col gap-3 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3\"\n >\n <div className=\"flex flex-col gap-2 sm:flex-row\">\n <label className=\"min-w-0 flex-1 space-y-1 text-xs\">\n <span className=\"text-[var(--as-muted-fg)]\">{externalIdLabel}</span>\n <input\n type=\"text\"\n value={draft.externalId}\n disabled={draft.mode === 'edit'}\n onChange={(event) =>\n setDraft((current) =>\n current ? { ...current, externalId: event.target.value } : current,\n )\n }\n className=\"w-full rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 font-mono text-xs text-[var(--as-fg)] disabled:opacity-60\"\n />\n </label>\n <label className=\"min-w-0 flex-1 space-y-1 text-xs\">\n <span className=\"text-[var(--as-muted-fg)]\">{labelLabel}</span>\n <input\n type=\"text\"\n value={draft.label}\n onChange={(event) =>\n setDraft((current) =>\n current ? { ...current, label: event.target.value } : current,\n )\n }\n className=\"w-full rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 text-xs text-[var(--as-fg)]\"\n />\n </label>\n </div>\n <div className=\"space-y-1\">\n <span className=\"text-[var(--as-muted-fg)]\">{capsLabel}</span>\n <CapabilityChips\n caps={caps}\n selected={draft.caps}\n onToggle={toggleDraftCap}\n ariaLabel={capsLabel}\n />\n </div>\n {reasoningEffortOptions ? (\n <label className=\"space-y-1 text-xs\">\n <span className=\"text-[var(--as-muted-fg)]\">{reasoningEffortLabel}</span>\n <input\n type=\"text\"\n value={draft.reasoningEffort}\n placeholder={reasoningEffortPlaceholder}\n list=\"as-reasoning-effort-options\"\n onChange={(event) =>\n setDraft((current) =>\n current ? { ...current, reasoningEffort: event.target.value } : current,\n )\n }\n className=\"w-full rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 text-xs text-[var(--as-fg)]\"\n />\n <datalist id=\"as-reasoning-effort-options\">\n {reasoningEffortOptions.map((option) => (\n <option key={option} value={option} />\n ))}\n </datalist>\n </label>\n ) : null}\n {draftError ? (\n <p className=\"text-xs text-[var(--as-danger)]\">{draftError}</p>\n ) : null}\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={resetDraft}>\n {cancelLabel}\n </Button>\n <Button\n size=\"sm\"\n disabled={confirmDisabled}\n onClick={submitDraft}\n >\n <Plus aria-hidden />\n {draft.mode === 'add' ? addDraftLabel : saveLabel}\n </Button>\n </div>\n </div>\n )\n }\n\n const renderRemoteRows = (providerId: string) => {\n const providerModels = models.filter((model) => model.providerId === providerId)\n const existingFor = (externalId: string) =>\n providerModels.find((model) => model.externalId === externalId)\n if (remoteState === 'loading') {\n return (\n <p className=\"flex items-center justify-center gap-2 py-4 text-xs text-[var(--as-muted-fg)]\">\n <Spinner size=\"sm\" />\n {remoteLoadingLabel}\n </p>\n )\n }\n if (remoteState === 'error') {\n return (\n <div className=\"flex items-center justify-between gap-2 py-2\">\n <p className=\"truncate text-xs text-[var(--as-danger)]\">{remoteError}</p>\n {onRetryRemote ? (\n <Button variant=\"outline\" size=\"sm\" onClick={onRetryRemote}>\n {retryLabel}\n </Button>\n ) : null}\n </div>\n )\n }\n if (filteredRemote.length === 0) {\n return (\n <p className=\"py-3 text-center text-xs text-[var(--as-muted-fg)]\">\n {remoteEmptyLabel}\n </p>\n )\n }\n return (\n <div data-as=\"model-registry-catalog\" className=\"flex flex-col gap-1\">\n {filteredRemote.map((remote) => {\n const existing = existingFor(remote.id)\n const expandedRow = draft?.key === `remote:${remote.id}`\n return (\n <div key={remote.id} className=\"flex flex-col gap-2\">\n <div className=\"flex min-w-0 items-center gap-2 rounded-[var(--as-radius-sm)] border border-[var(--as-border)] px-3 py-2\">\n <span className=\"min-w-0 flex-1 truncate font-mono text-xs text-[var(--as-fg)]\">\n {remote.id}\n </span>\n <CapabilityChips\n variant=\"badge\"\n caps={remote.caps.map(descriptorFor)}\n selected={remote.caps}\n />\n <button\n type=\"button\"\n aria-expanded={expandedRow}\n aria-label={`${existing ? editLabel : configureLabel} ${remote.id}`}\n onClick={() => {\n if (expandedRow) {\n resetDraft()\n } else if (existing) {\n openEditDraft(existing)\n } else {\n openAddDraft(providerId, remote)\n }\n }}\n className=\"cursor-pointer rounded-[var(--as-radius-sm)] p-1.5 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-muted)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n {expandedRow ? (\n <ChevronDown className=\"size-4\" aria-hidden />\n ) : (\n <ChevronRight className=\"size-4\" aria-hidden />\n )}\n </button>\n {existing?.enabled ? (\n <span className=\"flex shrink-0 items-center gap-1 text-[11px] text-[var(--as-muted-fg)]\">\n <Check className=\"size-3\" aria-hidden />\n {addedLabel}\n </span>\n ) : (\n <Button\n variant=\"outline\"\n size=\"sm\"\n aria-label={`${addLabel} ${remote.id}`}\n onClick={() =>\n onAddModel(providerId, { externalId: remote.id, caps: remote.caps })\n }\n >\n <Plus aria-hidden />\n {addLabel}\n </Button>\n )}\n </div>\n {expandedRow ? renderDraftPanel() : null}\n </div>\n )\n })}\n </div>\n )\n }\n\n const renderModelRow = (model: ModelRegistryModel) => {\n const expandedRow = draft?.key === `model:${model.id}`\n return (\n <div key={model.id} className=\"flex flex-col gap-2\">\n <div\n className={cn(\n 'flex min-w-0 items-center gap-2 rounded-[var(--as-radius-sm)] px-2 py-1.5 text-sm',\n model.missing && 'opacity-50',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate font-mono text-xs text-[var(--as-fg)]\">\n {model.externalId}\n </span>\n {model.missing ? (\n <span className=\"text-xs text-[var(--as-warning)]\">{missingLabel}</span>\n ) : null}\n <CapabilityChips\n variant=\"badge\"\n caps={model.caps.map(descriptorFor)}\n selected={model.caps}\n />\n <label className=\"flex shrink-0 cursor-pointer items-center gap-1.5 text-xs text-[var(--as-muted-fg)]\">\n <input\n type=\"checkbox\"\n checked={model.enabled}\n onChange={(event) =>\n onUpdateModel(model, { enabled: event.target.checked })\n }\n aria-label={`${enabledLabel} — ${model.externalId}`}\n />\n </label>\n <button\n type=\"button\"\n aria-expanded={expandedRow}\n aria-label={`${editLabel} ${model.externalId}`}\n onClick={() => (expandedRow ? resetDraft() : openEditDraft(model))}\n className=\"cursor-pointer rounded-[var(--as-radius-sm)] p-1.5 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-muted)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <Pencil className=\"size-3.5\" aria-hidden />\n </button>\n <button\n type=\"button\"\n aria-label={`${removeLabel} ${model.externalId}`}\n onClick={() => {\n if (expandedRow) resetDraft()\n onDeleteModel(model)\n }}\n className=\"cursor-pointer rounded-[var(--as-radius-sm)] p-1.5 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-muted)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <Trash2 className=\"size-3.5\" aria-hidden />\n </button>\n </div>\n {expandedRow ? renderDraftPanel() : null}\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"model-registry\"\n className={cn('flex w-full flex-col gap-4', className)}\n >\n {providers.map((provider) => {\n const expanded = expandedProviderId === provider.id\n const providerModels = models.filter((model) => model.providerId === provider.id)\n return (\n <div\n key={provider.id}\n data-as=\"model-registry-provider\"\n className={cn(\n 'rounded-[var(--as-radius-lg)] border bg-[var(--as-surface)] transition-colors',\n expanded ? 'border-[var(--as-primary)]' : 'border-[var(--as-border)]',\n )}\n >\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => toggleProvider(provider.id)}\n className=\"flex w-full cursor-pointer items-center gap-3 p-4 text-left focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n {expanded ? (\n <ChevronDown className=\"size-5 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden />\n ) : (\n <ChevronRight className=\"size-5 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden />\n )}\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-2 text-sm font-semibold text-[var(--as-fg)]\">\n {provider.name}\n {provider.type ? (\n <span className=\"rounded-full border border-[var(--as-border)] px-2 py-0.5 text-[11px] font-normal text-[var(--as-muted-fg)]\">\n {provider.type}\n </span>\n ) : null}\n <span className=\"text-xs font-normal text-[var(--as-muted-fg)]\">\n {providerModels.filter((model) => model.enabled).length}/\n {providerModels.length}\n </span>\n </span>\n {provider.baseUrl ? (\n <span className=\"block truncate font-mono text-xs text-[var(--as-muted-fg)]\">\n {provider.baseUrl}\n </span>\n ) : null}\n </span>\n </button>\n {expanded ? (\n <div className=\"flex flex-col gap-3 border-t border-[var(--as-border)] p-4\">\n {providerModels.length === 0 ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\">{emptyProviderLabel}</p>\n ) : (\n <div className=\"flex flex-col gap-1\">\n {providerModels.map(renderModelRow)}\n </div>\n )}\n <div className=\"flex flex-col gap-2 border-t border-[var(--as-border)] pt-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <SearchInput\n value={query}\n onChange={(next) => {\n setQuery(next)\n resetDraft()\n }}\n placeholder={searchPlaceholder}\n ariaLabel={searchLabel}\n className=\"max-w-xs flex-1\"\n />\n <CapabilityChips\n caps={filterDescriptors}\n selected={capFilter ? [capFilter] : []}\n onToggle={(value) =>\n setCapFilter((current) => (current === value ? null : value))\n }\n ariaLabel={capFilterLabel}\n />\n <Button variant=\"ghost\" size=\"sm\" onClick={() => openManualDraft(provider.id)}>\n <Plus aria-hidden />\n {manualAddLabel}\n </Button>\n {onAddAll ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={remoteState !== 'ready' || pendingRemote.length === 0}\n onClick={() =>\n onAddAll(\n provider.id,\n pendingRemote.map((remote) => ({\n externalId: remote.id,\n caps: remote.caps,\n })),\n )\n }\n >\n <Plus aria-hidden />\n {addAllLabel} ({pendingRemote.length})\n </Button>\n ) : null}\n </div>\n {draft?.key.startsWith('manual:') ? renderDraftPanel() : null}\n {renderRemoteRows(provider.id)}\n </div>\n </div>\n ) : null}\n </div>\n )\n })}\n {providers.length === 0 ? (\n <div className=\"flex flex-col items-center gap-2 py-8 text-center\">\n <p className=\"text-sm text-[var(--as-muted-fg)]\">{providersEmptyLabel}</p>\n {emptyAction}\n </div>\n ) : null}\n </div>\n )\n },\n)\n"]}
@@ -15,6 +15,8 @@ var ConnectionTestRow = React.forwardRef(function ConnectionTestRow2({
15
15
  errorMessage,
16
16
  onTest,
17
17
  disabled = false,
18
+ variant = "row",
19
+ meta,
18
20
  className
19
21
  }, ref) {
20
22
  const state = status === "ok" ? { text: okLabel, icon: /* @__PURE__ */ jsx(Check, { className: "size-3.5", "aria-hidden": true }), tone: "text-[var(--as-success)]" } : status === "fail" ? {
@@ -28,8 +30,11 @@ var ConnectionTestRow = React.forwardRef(function ConnectionTestRow2({
28
30
  ref,
29
31
  "data-as": "connection-test-row",
30
32
  "data-status": status,
33
+ "data-variant": variant,
31
34
  className: cn(
32
- "flex items-center justify-between gap-3 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2",
35
+ "flex items-center justify-between gap-3 rounded-[var(--as-radius)] px-3 py-2",
36
+ variant === "row" && "border border-[var(--as-border)] bg-[var(--as-surface)]",
37
+ variant === "inline" && "px-0 py-0",
33
38
  className
34
39
  ),
35
40
  children: [
@@ -48,7 +53,8 @@ var ConnectionTestRow = React.forwardRef(function ConnectionTestRow2({
48
53
  latencyLabel
49
54
  ] }) : null
50
55
  ] }) : null,
51
- status === "fail" && errorMessage ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-[var(--as-danger)]", children: errorMessage }) : null
56
+ status === "fail" && errorMessage ? /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-[var(--as-danger)]", children: errorMessage }) : null,
57
+ meta ? /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--as-muted-fg)]", children: meta }) : null
52
58
  ] }),
53
59
  onTest ? /* @__PURE__ */ jsxs(
54
60
  "button",
@@ -69,5 +75,5 @@ var ConnectionTestRow = React.forwardRef(function ConnectionTestRow2({
69
75
  });
70
76
 
71
77
  export { ConnectionTestRow };
72
- //# sourceMappingURL=chunk-UWHUCQC6.js.map
73
- //# sourceMappingURL=chunk-UWHUCQC6.js.map
78
+ //# sourceMappingURL=chunk-LY2B3UJH.js.map
79
+ //# sourceMappingURL=chunk-LY2B3UJH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/connection-test-row/ConnectionTestRow.tsx"],"names":["ConnectionTestRow"],"mappings":"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","file":"chunk-LY2B3UJH.js","sourcesContent":["import * as React from 'react'\nimport { Check, TriangleAlert, X } from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport { Spinner } from '../spinner/Spinner'\n\nexport type ConnectionTestStatus = 'idle' | 'testing' | 'ok' | 'fail'\n\nexport interface ConnectionTestRowProps {\n status: ConnectionTestStatus\n latencyMs?: number | null\n label?: string\n testLabel?: string\n okLabel?: string\n failLabel?: string\n latencyLabel?: string\n errorMessage?: string | null\n onTest?: () => void\n disabled?: boolean\n /** `row` = standalone bordered row; `inline` = bare, for embedding in app cards. */\n variant?: 'row' | 'inline'\n /** Extra app-side context rendered after the status (e.g. model count). */\n meta?: React.ReactNode\n className?: string\n}\n\n/**\n * Presentational connection-test row (idle/testing/ok/fail + latency).\n * The actual ping is app-side: flip `status` from the test handler.\n */\nexport const ConnectionTestRow = React.forwardRef<\n HTMLDivElement,\n ConnectionTestRowProps\n>(function ConnectionTestRow(\n {\n status,\n latencyMs,\n label = 'Connection',\n testLabel = 'Test',\n okLabel = 'Connected',\n failLabel = 'Failed',\n latencyLabel = 'ms',\n errorMessage,\n onTest,\n disabled = false,\n variant = 'row',\n meta,\n className,\n },\n ref,\n) {\n const state =\n status === 'ok'\n ? { text: okLabel, icon: <Check className=\"size-3.5\" aria-hidden />, tone: 'text-[var(--as-success)]' }\n : status === 'fail'\n ? {\n text: failLabel,\n icon: <TriangleAlert className=\"size-3.5\" aria-hidden />,\n tone: 'text-[var(--as-danger)]',\n }\n : null\n\n return (\n <div\n ref={ref}\n data-as=\"connection-test-row\"\n data-status={status}\n data-variant={variant}\n className={cn(\n 'flex items-center justify-between gap-3 rounded-[var(--as-radius)] px-3 py-2',\n variant === 'row' && 'border border-[var(--as-border)] bg-[var(--as-surface)]',\n variant === 'inline' && 'px-0 py-0',\n className,\n )}\n >\n <div className=\"flex min-w-0 items-center gap-2 text-sm\">\n <span className=\"font-medium text-[var(--as-fg)]\">{label}</span>\n {status === 'testing' ? (\n <span className=\"flex items-center gap-1.5 text-[var(--as-muted-fg)]\" role=\"status\">\n <Spinner size=\"sm\" />\n {testLabel}…\n </span>\n ) : state ? (\n <span className={cn('flex items-center gap-1 font-medium', state.tone)}>\n {state.icon}\n {state.text}\n {status === 'ok' && latencyMs != null ? (\n <span className=\"font-normal text-[var(--as-muted-fg)]\">\n · {latencyMs}\n {latencyLabel}\n </span>\n ) : null}\n </span>\n ) : null}\n {status === 'fail' && errorMessage ? (\n <span className=\"truncate text-xs text-[var(--as-danger)]\">\n {errorMessage}\n </span>\n ) : null}\n {meta ? <span className=\"text-xs text-[var(--as-muted-fg)]\">{meta}</span> : null}\n </div>\n {onTest ? (\n <button\n type=\"button\"\n onClick={onTest}\n disabled={disabled || status === 'testing'}\n className=\"shrink-0 cursor-pointer rounded-[var(--as-radius-sm)] border border-[var(--as-border)] px-2.5 py-1 text-xs font-medium text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)] disabled:pointer-events-none disabled:opacity-50\"\n >\n {status === 'fail' ? <X className=\"mr-1 inline size-3\" aria-hidden /> : null}\n {testLabel}\n </button>\n ) : null}\n </div>\n )\n})\n"]}