@neuronection/assistant-ui 0.9.0 → 0.11.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 (43) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +3 -2
  3. package/dist/about.d.ts +31 -1
  4. package/dist/about.js +1 -1
  5. package/dist/capability-chips.d.ts +21 -0
  6. package/dist/capability-chips.js +3 -0
  7. package/dist/capability-chips.js.map +1 -0
  8. package/dist/{chunk-3QGVWTBU.js → chunk-7RTSSBBR.js} +157 -4
  9. package/dist/chunk-7RTSSBBR.js.map +1 -0
  10. package/dist/{chunk-RJSN4TVT.js → chunk-A3A4J5M5.js} +4 -3
  11. package/dist/chunk-A3A4J5M5.js.map +1 -0
  12. package/dist/chunk-G3DWN2DJ.js +80 -0
  13. package/dist/chunk-G3DWN2DJ.js.map +1 -0
  14. package/dist/{chunk-UWHUCQC6.js → chunk-LY2B3UJH.js} +10 -4
  15. package/dist/chunk-LY2B3UJH.js.map +1 -0
  16. package/dist/chunk-M67KF4W2.js +130 -0
  17. package/dist/chunk-M67KF4W2.js.map +1 -0
  18. package/dist/chunk-N5V5LVZX.js +517 -0
  19. package/dist/chunk-N5V5LVZX.js.map +1 -0
  20. package/dist/{chunk-OPTH3VUY.js → chunk-RI6CEWWF.js} +2 -2
  21. package/dist/chunk-RI6CEWWF.js.map +1 -0
  22. package/dist/connection-test-row.d.ts +4 -0
  23. package/dist/connection-test-row.js +1 -1
  24. package/dist/index.d.ts +4 -2
  25. package/dist/index.js +9 -7
  26. package/dist/index.js.map +1 -1
  27. package/dist/model-picker.d.ts +2 -0
  28. package/dist/model-picker.js +1 -1
  29. package/dist/model-registry.d.ts +86 -0
  30. package/dist/model-registry.js +3 -0
  31. package/dist/model-registry.js.map +1 -0
  32. package/dist/provider-form.d.ts +2 -0
  33. package/dist/provider-form.js +1 -1
  34. package/dist/styles.css +1 -1
  35. package/dist/task-assignment-picker.d.ts +25 -6
  36. package/dist/task-assignment-picker.js +1 -1
  37. package/package.json +9 -1
  38. package/dist/chunk-3QGVWTBU.js.map +0 -1
  39. package/dist/chunk-OPTH3VUY.js.map +0 -1
  40. package/dist/chunk-RJSN4TVT.js.map +0 -1
  41. package/dist/chunk-TN35RR2R.js +0 -92
  42. package/dist/chunk-TN35RR2R.js.map +0 -1
  43. package/dist/chunk-UWHUCQC6.js.map +0 -1
@@ -0,0 +1,517 @@
1
+ import { SearchInput } from './chunk-H5U4KNXF.js';
2
+ import { CapabilityChips } from './chunk-G3DWN2DJ.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, Fragment } 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
+ missingLabel = "Missing",
35
+ capsLabel = "Capabilities",
36
+ searchPlaceholder = "Search models\u2026",
37
+ searchLabel = "Search models",
38
+ capFilterLabel = "Filter by capability",
39
+ unclassifiedLabel = "Unclassified",
40
+ emptyProviderLabel = "No models yet \u2014 add from the catalog below.",
41
+ remoteEmptyLabel = "No models match.",
42
+ remoteLoadingLabel = "Loading models\u2026",
43
+ retryLabel = "Retry",
44
+ browseLabel = "Browse catalog",
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 [catalogOpen, setCatalogOpen] = React.useState(false);
62
+ const descriptorFor = React.useCallback(
63
+ (value) => caps.find((cap) => cap.value === value) ?? { value, label: value },
64
+ [caps]
65
+ );
66
+ const filteredRemote = React.useMemo(() => {
67
+ const items = remoteModels ?? [];
68
+ const needle = query.trim().toLowerCase();
69
+ const ranked = needle && rank ? rank(items, query) : items;
70
+ const searched = needle && !rank ? ranked.filter((item) => item.id.toLowerCase().includes(needle)) : ranked;
71
+ if (capFilter === UNCLASSIFIED) return searched.filter((item) => item.caps.length === 0);
72
+ if (capFilter) return searched.filter((item) => item.caps.includes(capFilter));
73
+ return searched;
74
+ }, [remoteModels, query, capFilter, rank]);
75
+ const filterDescriptors = React.useMemo(
76
+ () => [...caps, { value: UNCLASSIFIED, label: unclassifiedLabel }],
77
+ [caps, unclassifiedLabel]
78
+ );
79
+ const pendingRemote = React.useMemo(() => {
80
+ const expanded = providers.find((provider) => provider.id === expandedProviderId);
81
+ if (!expanded) return [];
82
+ const existingIds = new Set(
83
+ models.filter((model) => model.providerId === expanded.id).map((model) => model.externalId)
84
+ );
85
+ return filteredRemote.filter((remote) => !existingIds.has(remote.id));
86
+ }, [filteredRemote, providers, expandedProviderId, models]);
87
+ const resetDraft = React.useCallback(() => {
88
+ setDraft(null);
89
+ setDraftError(null);
90
+ }, []);
91
+ const toggleProvider = (providerId) => {
92
+ const next = expandedProviderId === providerId ? null : providerId;
93
+ onExpandedProviderChange(next);
94
+ setQuery("");
95
+ setCapFilter(null);
96
+ setCatalogOpen(false);
97
+ resetDraft();
98
+ };
99
+ const openAddDraft = (providerId, remote) => {
100
+ setDraft({
101
+ key: `remote:${remote.id}`,
102
+ mode: "add",
103
+ providerId,
104
+ externalId: remote.id,
105
+ label: "",
106
+ caps: [...remote.caps],
107
+ reasoningEffort: ""
108
+ });
109
+ setDraftError(null);
110
+ };
111
+ const openManualDraft = (providerId) => {
112
+ setDraft({
113
+ key: `manual:${providerId}`,
114
+ mode: "add",
115
+ providerId,
116
+ externalId: "",
117
+ label: "",
118
+ caps: caps[0] ? [caps[0].value] : [],
119
+ reasoningEffort: ""
120
+ });
121
+ setDraftError(null);
122
+ };
123
+ const openEditDraft = (model) => {
124
+ setDraft({
125
+ key: `model:${model.id}`,
126
+ mode: "edit",
127
+ providerId: model.providerId,
128
+ externalId: model.externalId,
129
+ label: model.label ?? "",
130
+ caps: [...model.caps],
131
+ reasoningEffort: model.reasoningEffort ?? "",
132
+ model
133
+ });
134
+ setDraftError(null);
135
+ };
136
+ const toggleDraftCap = (value) => {
137
+ setDraft(
138
+ (current) => current ? {
139
+ ...current,
140
+ caps: current.caps.includes(value) ? current.caps.filter((entry) => entry !== value) : [...current.caps, value]
141
+ } : current
142
+ );
143
+ };
144
+ const submitDraft = () => {
145
+ if (!draft) return;
146
+ const externalId = draft.externalId.trim();
147
+ if (!externalId) {
148
+ setDraftError(externalIdLabel);
149
+ return;
150
+ }
151
+ const payload = {
152
+ externalId,
153
+ label: draft.label.trim() || void 0,
154
+ caps: draft.caps,
155
+ reasoningEffort: draft.reasoningEffort.trim()
156
+ };
157
+ if (draft.mode === "add") {
158
+ onAddModel(draft.providerId, payload);
159
+ } else if (draft.model) {
160
+ onUpdateModel(draft.model, payload);
161
+ }
162
+ resetDraft();
163
+ };
164
+ const renderDraftPanel = () => {
165
+ if (!draft) return null;
166
+ const confirmDisabled = draft.mode === "add" && !draft.externalId.trim();
167
+ return /* @__PURE__ */ jsxs(
168
+ "div",
169
+ {
170
+ "data-as": "model-registry-draft",
171
+ className: "flex flex-col gap-3 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3",
172
+ children: [
173
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [
174
+ /* @__PURE__ */ jsxs("label", { className: "min-w-0 flex-1 space-y-1 text-xs", children: [
175
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: externalIdLabel }),
176
+ /* @__PURE__ */ jsx(
177
+ "input",
178
+ {
179
+ type: "text",
180
+ value: draft.externalId,
181
+ disabled: draft.mode === "edit",
182
+ onChange: (event) => setDraft(
183
+ (current) => current ? { ...current, externalId: event.target.value } : current
184
+ ),
185
+ 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"
186
+ }
187
+ )
188
+ ] }),
189
+ /* @__PURE__ */ jsxs("label", { className: "min-w-0 flex-1 space-y-1 text-xs", children: [
190
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: labelLabel }),
191
+ /* @__PURE__ */ jsx(
192
+ "input",
193
+ {
194
+ type: "text",
195
+ value: draft.label,
196
+ onChange: (event) => setDraft(
197
+ (current) => current ? { ...current, label: event.target.value } : current
198
+ ),
199
+ 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)]"
200
+ }
201
+ )
202
+ ] })
203
+ ] }),
204
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
205
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: capsLabel }),
206
+ /* @__PURE__ */ jsx(
207
+ CapabilityChips,
208
+ {
209
+ caps,
210
+ selected: draft.caps,
211
+ onToggle: toggleDraftCap,
212
+ ariaLabel: capsLabel
213
+ }
214
+ )
215
+ ] }),
216
+ reasoningEffortOptions ? /* @__PURE__ */ jsxs("label", { className: "space-y-1 text-xs", children: [
217
+ /* @__PURE__ */ jsx("span", { className: "text-[var(--as-muted-fg)]", children: reasoningEffortLabel }),
218
+ /* @__PURE__ */ jsx(
219
+ "input",
220
+ {
221
+ type: "text",
222
+ value: draft.reasoningEffort,
223
+ placeholder: reasoningEffortPlaceholder,
224
+ list: "as-reasoning-effort-options",
225
+ onChange: (event) => setDraft(
226
+ (current) => current ? { ...current, reasoningEffort: event.target.value } : current
227
+ ),
228
+ 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)]"
229
+ }
230
+ ),
231
+ /* @__PURE__ */ jsx("datalist", { id: "as-reasoning-effort-options", children: reasoningEffortOptions.map((option) => /* @__PURE__ */ jsx("option", { value: option }, option)) })
232
+ ] }) : null,
233
+ draftError ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-danger)]", children: draftError }) : null,
234
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2", children: [
235
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: resetDraft, children: cancelLabel }),
236
+ /* @__PURE__ */ jsxs(
237
+ Button,
238
+ {
239
+ size: "sm",
240
+ disabled: confirmDisabled,
241
+ onClick: submitDraft,
242
+ children: [
243
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
244
+ draft.mode === "add" ? addDraftLabel : saveLabel
245
+ ]
246
+ }
247
+ )
248
+ ] })
249
+ ]
250
+ }
251
+ );
252
+ };
253
+ const renderRemoteRows = (providerId) => {
254
+ const providerModels = models.filter((model) => model.providerId === providerId);
255
+ const existingFor = (externalId) => providerModels.find((model) => model.externalId === externalId);
256
+ if (remoteState === "loading") {
257
+ return /* @__PURE__ */ jsxs("p", { className: "flex items-center justify-center gap-2 py-4 text-xs text-[var(--as-muted-fg)]", children: [
258
+ /* @__PURE__ */ jsx(Spinner, { size: "sm" }),
259
+ remoteLoadingLabel
260
+ ] });
261
+ }
262
+ if (remoteState === "error") {
263
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 py-2", children: [
264
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-[var(--as-danger)]", children: remoteError }),
265
+ onRetryRemote ? /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onRetryRemote, children: retryLabel }) : null
266
+ ] });
267
+ }
268
+ if (filteredRemote.length === 0) {
269
+ return /* @__PURE__ */ jsx("p", { className: "py-3 text-center text-xs text-[var(--as-muted-fg)]", children: remoteEmptyLabel });
270
+ }
271
+ return /* @__PURE__ */ jsx("div", { "data-as": "model-registry-catalog", className: "flex flex-col gap-1", children: filteredRemote.map((remote) => {
272
+ const existing = existingFor(remote.id);
273
+ const expandedRow = draft?.key === `remote:${remote.id}`;
274
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
275
+ /* @__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: [
276
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-xs text-[var(--as-fg)]", children: remote.id }),
277
+ /* @__PURE__ */ jsx(
278
+ CapabilityChips,
279
+ {
280
+ variant: "badge",
281
+ caps: remote.caps.map(descriptorFor),
282
+ selected: remote.caps
283
+ }
284
+ ),
285
+ /* @__PURE__ */ jsx(
286
+ "button",
287
+ {
288
+ type: "button",
289
+ "aria-expanded": expandedRow,
290
+ "aria-label": `${existing ? editLabel : configureLabel} ${remote.id}`,
291
+ onClick: () => {
292
+ if (expandedRow) {
293
+ resetDraft();
294
+ } else if (existing) {
295
+ openEditDraft(existing);
296
+ } else {
297
+ openAddDraft(providerId, remote);
298
+ }
299
+ },
300
+ 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)]",
301
+ children: expandedRow ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true })
302
+ }
303
+ ),
304
+ existing?.enabled ? /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1 text-[11px] text-[var(--as-muted-fg)]", children: [
305
+ /* @__PURE__ */ jsx(Check, { className: "size-3", "aria-hidden": true }),
306
+ addedLabel
307
+ ] }) : /* @__PURE__ */ jsxs(
308
+ Button,
309
+ {
310
+ variant: "outline",
311
+ size: "sm",
312
+ "aria-label": `${addLabel} ${remote.id}`,
313
+ onClick: () => onAddModel(providerId, { externalId: remote.id, caps: remote.caps }),
314
+ children: [
315
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
316
+ addLabel
317
+ ]
318
+ }
319
+ )
320
+ ] }),
321
+ expandedRow ? renderDraftPanel() : null
322
+ ] }, remote.id);
323
+ }) });
324
+ };
325
+ const renderModelRow = (model) => {
326
+ const expandedRow = draft?.key === `model:${model.id}`;
327
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
328
+ /* @__PURE__ */ jsxs(
329
+ "div",
330
+ {
331
+ className: cn(
332
+ "flex min-w-0 items-center gap-2 rounded-[var(--as-radius-sm)] px-2 py-1.5 text-sm",
333
+ model.missing && "opacity-50"
334
+ ),
335
+ children: [
336
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-xs text-[var(--as-fg)]", children: model.externalId }),
337
+ model.missing ? /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--as-warning)]", children: missingLabel }) : null,
338
+ /* @__PURE__ */ jsx(
339
+ CapabilityChips,
340
+ {
341
+ variant: "badge",
342
+ caps: model.caps.map(descriptorFor),
343
+ selected: model.caps
344
+ }
345
+ ),
346
+ /* @__PURE__ */ jsx(
347
+ "button",
348
+ {
349
+ type: "button",
350
+ "aria-expanded": expandedRow,
351
+ "aria-label": `${editLabel} ${model.externalId}`,
352
+ onClick: () => expandedRow ? resetDraft() : openEditDraft(model),
353
+ 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)]",
354
+ children: /* @__PURE__ */ jsx(Pencil, { className: "size-3.5", "aria-hidden": true })
355
+ }
356
+ ),
357
+ /* @__PURE__ */ jsx(
358
+ "button",
359
+ {
360
+ type: "button",
361
+ "aria-label": `${removeLabel} ${model.externalId}`,
362
+ onClick: () => {
363
+ if (expandedRow) resetDraft();
364
+ onDeleteModel(model);
365
+ },
366
+ 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)]",
367
+ children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5", "aria-hidden": true })
368
+ }
369
+ )
370
+ ]
371
+ }
372
+ ),
373
+ expandedRow ? renderDraftPanel() : null
374
+ ] }, model.id);
375
+ };
376
+ return /* @__PURE__ */ jsxs(
377
+ "div",
378
+ {
379
+ ref,
380
+ "data-as": "model-registry",
381
+ className: cn("flex w-full flex-col gap-4", className),
382
+ children: [
383
+ providers.map((provider) => {
384
+ const expanded = expandedProviderId === provider.id;
385
+ const providerModels = models.filter((model) => model.providerId === provider.id);
386
+ return /* @__PURE__ */ jsxs(
387
+ "div",
388
+ {
389
+ "data-as": "model-registry-provider",
390
+ className: cn(
391
+ "rounded-[var(--as-radius-lg)] border bg-[var(--as-surface)] transition-all",
392
+ expanded ? "border-[var(--as-primary)] shadow-[var(--as-shadow-1)]" : "border-[var(--as-border)]"
393
+ ),
394
+ children: [
395
+ /* @__PURE__ */ jsxs(
396
+ "button",
397
+ {
398
+ type: "button",
399
+ "aria-expanded": expanded,
400
+ onClick: () => toggleProvider(provider.id),
401
+ className: "group flex w-full cursor-pointer items-center gap-4 p-4 text-left focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
402
+ children: [
403
+ /* @__PURE__ */ jsx(
404
+ "span",
405
+ {
406
+ className: cn(
407
+ "flex size-9 shrink-0 items-center justify-center rounded-[var(--as-radius)] transition-colors",
408
+ expanded ? "bg-[var(--as-primary)] text-[var(--as-primary-fg)]" : "bg-[var(--as-muted)] text-[var(--as-muted-fg)] group-hover:bg-[var(--as-primary)]/10 group-hover:text-[var(--as-primary)]"
409
+ ),
410
+ children: expanded ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-5", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-5", "aria-hidden": true })
411
+ }
412
+ ),
413
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
414
+ /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-center gap-2 text-sm font-semibold text-[var(--as-fg)]", children: [
415
+ provider.name,
416
+ provider.type ? /* @__PURE__ */ jsx("span", { className: "rounded-full border border-[var(--as-border)] px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-[var(--as-muted-fg)]", children: provider.type }) : null,
417
+ providerModels.length ? /* @__PURE__ */ jsxs("span", { className: "rounded-full bg-[var(--as-muted)] px-2.5 py-0.5 text-[10px] font-semibold uppercase tracking-widest text-[var(--as-muted-fg)]", children: [
418
+ providerModels.filter((model) => model.enabled).length,
419
+ "/",
420
+ providerModels.length
421
+ ] }) : null
422
+ ] }),
423
+ provider.baseUrl ? /* @__PURE__ */ jsx("span", { className: "block truncate font-mono text-xs text-[var(--as-muted-fg)]", children: provider.baseUrl }) : null
424
+ ] })
425
+ ]
426
+ }
427
+ ),
428
+ expanded ? /* @__PURE__ */ jsxs("div", { className: "as-anim-fade flex flex-col gap-3 border-t border-[var(--as-border)] p-4", children: [
429
+ 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) }),
430
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-[var(--as-border)] pt-3", children: [
431
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(
432
+ Button,
433
+ {
434
+ variant: "outline",
435
+ size: "sm",
436
+ "aria-expanded": catalogOpen,
437
+ onClick: () => setCatalogOpen((open) => !open),
438
+ children: [
439
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
440
+ browseLabel
441
+ ]
442
+ }
443
+ ) }),
444
+ catalogOpen ? /* @__PURE__ */ jsxs(Fragment, { children: [
445
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
446
+ /* @__PURE__ */ jsx(
447
+ SearchInput,
448
+ {
449
+ value: query,
450
+ onChange: (next) => {
451
+ setQuery(next);
452
+ resetDraft();
453
+ },
454
+ placeholder: searchPlaceholder,
455
+ ariaLabel: searchLabel,
456
+ className: "max-w-xs flex-1"
457
+ }
458
+ ),
459
+ /* @__PURE__ */ jsx(
460
+ CapabilityChips,
461
+ {
462
+ caps: filterDescriptors,
463
+ selected: capFilter ? [capFilter] : [],
464
+ onToggle: (value) => setCapFilter((current) => current === value ? null : value),
465
+ ariaLabel: capFilterLabel
466
+ }
467
+ ),
468
+ /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => openManualDraft(provider.id), children: [
469
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
470
+ manualAddLabel
471
+ ] }),
472
+ onAddAll ? /* @__PURE__ */ jsxs(
473
+ Button,
474
+ {
475
+ variant: "outline",
476
+ size: "sm",
477
+ disabled: remoteState !== "ready" || pendingRemote.length === 0,
478
+ onClick: () => onAddAll(
479
+ provider.id,
480
+ pendingRemote.map((remote) => ({
481
+ externalId: remote.id,
482
+ caps: remote.caps
483
+ }))
484
+ ),
485
+ children: [
486
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true }),
487
+ addAllLabel,
488
+ " (",
489
+ pendingRemote.length,
490
+ ")"
491
+ ]
492
+ }
493
+ ) : null
494
+ ] }),
495
+ draft?.key.startsWith("manual:") ? renderDraftPanel() : null,
496
+ renderRemoteRows(provider.id)
497
+ ] }) : null
498
+ ] })
499
+ ] }) : null
500
+ ]
501
+ },
502
+ provider.id
503
+ );
504
+ }),
505
+ providers.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 py-8 text-center", children: [
506
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--as-muted-fg)]", children: providersEmptyLabel }),
507
+ emptyAction
508
+ ] }) : null
509
+ ]
510
+ }
511
+ );
512
+ }
513
+ );
514
+
515
+ export { ModelRegistry };
516
+ //# sourceMappingURL=chunk-N5V5LVZX.js.map
517
+ //# sourceMappingURL=chunk-N5V5LVZX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-registry/ModelRegistry.tsx"],"names":["ModelRegistry"],"mappings":"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","file":"chunk-N5V5LVZX.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 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 /** Catalog disclosure trigger; the search/filter zone renders only when opened. */\n browseLabel?: 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 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 browseLabel = 'Browse catalog',\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 const [catalogOpen, setCatalogOpen] = React.useState(false)\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 setCatalogOpen(false)\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(),\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 <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-all',\n expanded\n ? 'border-[var(--as-primary)] shadow-[var(--as-shadow-1)]'\n : 'border-[var(--as-border)]',\n )}\n >\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={() => toggleProvider(provider.id)}\n className=\"group flex w-full cursor-pointer items-center gap-4 p-4 text-left focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <span\n className={cn(\n 'flex size-9 shrink-0 items-center justify-center rounded-[var(--as-radius)] transition-colors',\n expanded\n ? 'bg-[var(--as-primary)] text-[var(--as-primary-fg)]'\n : 'bg-[var(--as-muted)] text-[var(--as-muted-fg)] group-hover:bg-[var(--as-primary)]/10 group-hover:text-[var(--as-primary)]',\n )}\n >\n {expanded ? (\n <ChevronDown className=\"size-5\" aria-hidden />\n ) : (\n <ChevronRight className=\"size-5\" aria-hidden />\n )}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex flex-wrap 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-[10px] font-medium uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {provider.type}\n </span>\n ) : null}\n {providerModels.length ? (\n <span className=\"rounded-full bg-[var(--as-muted)] px-2.5 py-0.5 text-[10px] font-semibold uppercase tracking-widest text-[var(--as-muted-fg)]\">\n {providerModels.filter((model) => model.enabled).length}/\n {providerModels.length}\n </span>\n ) : null}\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=\"as-anim-fade 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>\n <Button\n variant=\"outline\"\n size=\"sm\"\n aria-expanded={catalogOpen}\n onClick={() => setCatalogOpen((open) => !open)}\n >\n <Plus aria-hidden />\n {browseLabel}\n </Button>\n </div>\n {catalogOpen ? (\n <>\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 </>\n ) : null}\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"]}
@@ -59,5 +59,5 @@ var ModelPicker = React.forwardRef(
59
59
  );
60
60
 
61
61
  export { ModelPicker };
62
- //# sourceMappingURL=chunk-OPTH3VUY.js.map
63
- //# sourceMappingURL=chunk-OPTH3VUY.js.map
62
+ //# sourceMappingURL=chunk-RI6CEWWF.js.map
63
+ //# sourceMappingURL=chunk-RI6CEWWF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/model-picker/ModelPicker.tsx"],"names":["ModelPicker"],"mappings":";;;;;AA6CO,IAAM,WAAA,GAAoB,KAAA,CAAA,UAAA;AAAA,EAC/B,SAASA,YAAAA,CACP;AAAA,IACE,SAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAA,GAAc,sBAAA;AAAA,IACd,iBAAA,GAAoB,qBAAA;AAAA,IACpB,WAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA,GAAU,KAAA;AAAA,IACV,QAAA,GAAW,KAAA;AAAA,IACX,SAAA,GAAY,KAAA;AAAA,IACZ,UAAA;AAAA,IACA,KAAA;AAAA,IACA,KAAA;AAAA,IACA,EAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,KAEF,GAAA,EACA;AACA,IAAA,MAAM,OAAA,GAAkC,KAAA,CAAA,OAAA;AAAA,MACtC,MACE,SAAA,CAAU,OAAA;AAAA,QAAQ,CAAC,QAAA,KACjB,QAAA,CAAS,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,UAC9B,OAAO,KAAA,CAAM,EAAA;AAAA,UACb,OAAO,KAAA,CAAM,IAAA;AAAA,UACb,OAAO,QAAA,CAAS,IAAA;AAAA,UAChB,OAAO,KAAA,CAAM;AAAA,SACf,CAAE;AAAA,OACJ;AAAA,MACF,CAAC,SAAS;AAAA,KACZ;AAEA,IAAA,uBACE,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAA;AAAA,QACA,QAAA;AAAA,QACA,WAAA;AAAA,QACA,iBAAA;AAAA,QACA,WAAA;AAAA,QACA,UAAA;AAAA,QACA,OAAA;AAAA,QACA,QAAA;AAAA,QACA,SAAA;AAAA,QACA,UAAA;AAAA,QACA,KAAA;AAAA,QACA,KAAA;AAAA,QACA,EAAA;AAAA,QACA,SAAA,EAAW,EAAA,CAAG,QAAA,EAAU,SAAS,CAAA;AAAA,QACjC;AAAA;AAAA,KACF;AAAA,EAEJ;AACF","file":"chunk-RI6CEWWF.js","sourcesContent":["import * as React from 'react'\nimport { cn } from '../../lib/utils'\nimport {\n Combobox,\n type ComboboxOption,\n} from '../combobox'\n\nexport interface ModelPickerModel {\n id: string\n name: string\n /** Short capability chip, e.g. `vision` or `tools`. */\n capability?: string\n /** Full capability set, matched by TaskAssignmentPicker `requires`. */\n capabilities?: string[]\n}\n\nexport interface ModelPickerProvider {\n id: string\n name: string\n models: ModelPickerModel[]\n}\n\nexport interface ModelPickerProps {\n providers: ModelPickerProvider[]\n value?: string\n onChange: (modelId: string) => void\n placeholder?: string\n searchPlaceholder?: string\n searchLabel?: string\n emptyLabel?: string\n loading?: boolean\n disabled?: boolean\n clearable?: boolean\n clearLabel?: string\n label?: string\n error?: string\n id?: string\n className?: string\n panelClassName?: string\n}\n\n/**\n * Grouped, searchable provider → model picker. Presentational: the model\n * list comes in via props, selection goes out via `onChange`.\n */\nexport const ModelPicker = React.forwardRef<HTMLButtonElement, ModelPickerProps>(\n function ModelPicker(\n {\n providers,\n value,\n onChange,\n placeholder = 'Select a model…',\n searchPlaceholder = 'Search models…',\n searchLabel,\n emptyLabel,\n loading = false,\n disabled = false,\n clearable = false,\n clearLabel,\n label,\n error,\n id,\n className,\n panelClassName,\n },\n ref,\n ) {\n const options: ComboboxOption[] = React.useMemo(\n () =>\n providers.flatMap((provider) =>\n provider.models.map((model) => ({\n value: model.id,\n label: model.name,\n group: provider.name,\n badge: model.capability,\n })),\n ),\n [providers],\n )\n\n return (\n <Combobox\n ref={ref}\n options={options}\n value={value}\n onChange={onChange}\n placeholder={placeholder}\n searchPlaceholder={searchPlaceholder}\n searchLabel={searchLabel}\n emptyLabel={emptyLabel}\n loading={loading}\n disabled={disabled}\n clearable={clearable}\n clearLabel={clearLabel}\n label={label}\n error={error}\n id={id}\n className={cn('w-full', className)}\n panelClassName={panelClassName}\n />\n )\n },\n)\n"]}
@@ -12,6 +12,10 @@ interface ConnectionTestRowProps {
12
12
  errorMessage?: string | null;
13
13
  onTest?: () => void;
14
14
  disabled?: boolean;
15
+ /** `row` = standalone bordered row; `inline` = bare, for embedding in app cards. */
16
+ variant?: 'row' | 'inline';
17
+ /** Extra app-side context rendered after the status (e.g. model count). */
18
+ meta?: React.ReactNode;
15
19
  className?: string;
16
20
  }
17
21
  /**