@neuronection/assistant-ui 0.12.1 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +47 -30
- package/dist/{chunk-LC7CYUY4.js → chunk-AATZUVW4.js} +5 -136
- package/dist/chunk-AATZUVW4.js.map +1 -0
- package/dist/chunk-B2G66OSQ.js +143 -0
- package/dist/chunk-B2G66OSQ.js.map +1 -0
- package/dist/{chunk-QIXRJMCL.js → chunk-JSPXF5YG.js} +8 -12
- package/dist/chunk-JSPXF5YG.js.map +1 -0
- package/dist/{chunk-WHOJXXGI.js → chunk-SVQK7TXU.js} +5 -3
- package/dist/chunk-SVQK7TXU.js.map +1 -0
- package/dist/chunk-YGYKYELC.js +182 -0
- package/dist/chunk-YGYKYELC.js.map +1 -0
- package/dist/combobox.d.ts +2 -0
- package/dist/combobox.js +1 -1
- package/dist/fuzzy.d.ts +6 -0
- package/dist/fuzzy.js +3 -0
- package/dist/fuzzy.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/model-picker.d.ts +2 -0
- package/dist/model-picker.js +1 -1
- package/dist/model-registry.d.ts +2 -0
- package/dist/model-registry.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/task-assignment-picker.d.ts +6 -2
- package/dist/task-assignment-picker.js +1 -1
- package/package.json +6 -2
- package/dist/chunk-LC7CYUY4.js.map +0 -1
- package/dist/chunk-QIXRJMCL.js.map +0 -1
- package/dist/chunk-WHOJXXGI.js.map +0 -1
- package/dist/chunk-YU6YF4YH.js +0 -133
- package/dist/chunk-YU6YF4YH.js.map +0 -1
package/dist/chunk-YU6YF4YH.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { ModelPicker } from './chunk-WHOJXXGI.js';
|
|
2
|
-
import { cn } from './chunk-BLJWR4ZV.js';
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { X } from 'lucide-react';
|
|
5
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
|
-
function filterProviders(providers, requires) {
|
|
8
|
-
if (!requires) return providers;
|
|
9
|
-
const matches = (model) => model.capability === requires || (model.capabilities?.includes(requires) ?? false);
|
|
10
|
-
return providers.map((provider) => ({
|
|
11
|
-
...provider,
|
|
12
|
-
models: provider.models.filter(matches)
|
|
13
|
-
})).filter((provider) => provider.models.length > 0);
|
|
14
|
-
}
|
|
15
|
-
var TaskAssignmentPicker = React.forwardRef(function TaskAssignmentPicker2({
|
|
16
|
-
tasks = [],
|
|
17
|
-
sections,
|
|
18
|
-
providers,
|
|
19
|
-
value,
|
|
20
|
-
onAssign,
|
|
21
|
-
secondaryValue,
|
|
22
|
-
onAssignSecondary,
|
|
23
|
-
secondaryLabel = "Fallback model",
|
|
24
|
-
renderMeta,
|
|
25
|
-
unassignedLabel = "Not assigned",
|
|
26
|
-
clearLabel = "Clear assignment",
|
|
27
|
-
modelLabel = "Model",
|
|
28
|
-
disabled = false,
|
|
29
|
-
className
|
|
30
|
-
}, ref) {
|
|
31
|
-
const modelName = React.useCallback(
|
|
32
|
-
(modelId) => {
|
|
33
|
-
if (!modelId) return null;
|
|
34
|
-
for (const provider of providers) {
|
|
35
|
-
const model = provider.models.find((m) => m.id === modelId);
|
|
36
|
-
if (model) return { name: model.name, provider: provider.name };
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
},
|
|
40
|
-
[providers]
|
|
41
|
-
);
|
|
42
|
-
const renderRow = (task, showSecondary) => {
|
|
43
|
-
const assigned = modelName(value[task.id]);
|
|
44
|
-
const catalog = filterProviders(providers, task.requires);
|
|
45
|
-
return /* @__PURE__ */ jsxs(
|
|
46
|
-
"div",
|
|
47
|
-
{
|
|
48
|
-
className: "flex flex-col gap-2 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3 sm:flex-row sm:items-center sm:justify-between",
|
|
49
|
-
children: [
|
|
50
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
|
|
51
|
-
task.icon ? /* @__PURE__ */ jsx("span", { className: "flex size-9 shrink-0 items-center justify-center rounded-[var(--as-radius)] bg-[var(--as-muted)] text-[var(--as-muted-fg)]", children: /* @__PURE__ */ jsx(task.icon, { className: "size-4", "aria-hidden": true }) }) : null,
|
|
52
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
53
|
-
/* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-[var(--as-fg)]", children: task.label }),
|
|
54
|
-
task.description ? /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-[var(--as-muted-fg)]", children: task.description }) : null,
|
|
55
|
-
renderMeta ? renderMeta(task) : null,
|
|
56
|
-
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-[var(--as-muted-fg)]", children: assigned ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
57
|
-
modelLabel,
|
|
58
|
-
":",
|
|
59
|
-
" ",
|
|
60
|
-
/* @__PURE__ */ jsxs("span", { className: "font-medium text-[var(--as-fg)]", children: [
|
|
61
|
-
assigned.provider,
|
|
62
|
-
" / ",
|
|
63
|
-
assigned.name
|
|
64
|
-
] })
|
|
65
|
-
] }) : unassignedLabel })
|
|
66
|
-
] })
|
|
67
|
-
] }),
|
|
68
|
-
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
69
|
-
showSecondary && onAssignSecondary ? /* @__PURE__ */ jsx(
|
|
70
|
-
ModelPicker,
|
|
71
|
-
{
|
|
72
|
-
providers: catalog,
|
|
73
|
-
value: secondaryValue?.[task.id] ?? "",
|
|
74
|
-
onChange: (modelId) => onAssignSecondary(task.id, modelId),
|
|
75
|
-
disabled,
|
|
76
|
-
clearable: Boolean(secondaryValue?.[task.id]),
|
|
77
|
-
clearLabel,
|
|
78
|
-
label: `${secondaryLabel} \u2014 ${task.label}`,
|
|
79
|
-
className: "w-48"
|
|
80
|
-
}
|
|
81
|
-
) : null,
|
|
82
|
-
/* @__PURE__ */ jsx(
|
|
83
|
-
ModelPicker,
|
|
84
|
-
{
|
|
85
|
-
providers: catalog,
|
|
86
|
-
value: value[task.id] ?? "",
|
|
87
|
-
onChange: (modelId) => onAssign(task.id, modelId),
|
|
88
|
-
disabled,
|
|
89
|
-
clearable: Boolean(value[task.id]),
|
|
90
|
-
clearLabel,
|
|
91
|
-
label: `${modelLabel} \u2014 ${task.label}`,
|
|
92
|
-
className: "w-56"
|
|
93
|
-
}
|
|
94
|
-
),
|
|
95
|
-
value[task.id] ? /* @__PURE__ */ jsx(
|
|
96
|
-
"button",
|
|
97
|
-
{
|
|
98
|
-
type: "button",
|
|
99
|
-
"aria-label": `${clearLabel} \u2014 ${task.label}`,
|
|
100
|
-
disabled,
|
|
101
|
-
onClick: () => onAssign(task.id, null),
|
|
102
|
-
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)] disabled:pointer-events-none disabled:opacity-50",
|
|
103
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-4", "aria-hidden": true })
|
|
104
|
-
}
|
|
105
|
-
) : null
|
|
106
|
-
] })
|
|
107
|
-
]
|
|
108
|
-
},
|
|
109
|
-
task.id
|
|
110
|
-
);
|
|
111
|
-
};
|
|
112
|
-
return /* @__PURE__ */ jsx(
|
|
113
|
-
"div",
|
|
114
|
-
{
|
|
115
|
-
ref,
|
|
116
|
-
"data-as": "task-assignment-picker",
|
|
117
|
-
className: cn("flex w-full flex-col gap-3", className),
|
|
118
|
-
children: sections ? sections.map((section) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
119
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
120
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]", children: section.label }),
|
|
121
|
-
section.description ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-[var(--as-muted-fg)]", children: section.description }) : null
|
|
122
|
-
] }),
|
|
123
|
-
section.tasks.map(
|
|
124
|
-
(task) => renderRow(task, section.secondary || Boolean(task.secondary))
|
|
125
|
-
)
|
|
126
|
-
] }, section.id)) : tasks.map((task) => renderRow(task, Boolean(task.secondary)))
|
|
127
|
-
}
|
|
128
|
-
);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
export { TaskAssignmentPicker };
|
|
132
|
-
//# sourceMappingURL=chunk-YU6YF4YH.js.map
|
|
133
|
-
//# sourceMappingURL=chunk-YU6YF4YH.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/task-assignment-picker/TaskAssignmentPicker.tsx"],"names":["TaskAssignmentPicker"],"mappings":"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","file":"chunk-YU6YF4YH.js","sourcesContent":["import * as React from 'react'\nimport { X } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '../../lib/utils'\nimport {\n ModelPicker,\n type ModelPickerModel,\n type ModelPickerProvider,\n} from '../model-picker/ModelPicker'\n\nexport interface TaskAssignmentTask {\n id: string\n label: string\n description?: string\n /** Rendered in an icon tile at the row's leading edge. */\n icon?: LucideIcon\n /** When set, the row's picker offers only models matching this capability. */\n requires?: string\n /** Render the fallback-model picker for this row (needs `onAssignSecondary`). */\n secondary?: boolean\n}\n\nexport interface TaskAssignmentSection {\n id: string\n label: string\n /** Muted context line under the section label (e.g. what the rows mean). */\n description?: string\n /** Show the fallback picker on every task in the section (task-level wins). */\n secondary?: boolean\n tasks: TaskAssignmentTask[]\n}\n\nexport interface TaskAssignmentPickerProps {\n /** Flat rendering; ignored when `sections` is set. */\n tasks?: TaskAssignmentTask[]\n /** Grouped rendering; when set, `tasks` is ignored. */\n sections?: TaskAssignmentSection[]\n providers: ModelPickerProvider[]\n /** Current mapping: taskId → modelId (null/undefined = unassigned). */\n value: Record<string, string | null>\n onAssign: (taskId: string, modelId: string | null) => void\n /** Enables fallback-model rows for tasks flagged (directly or via section). */\n secondaryValue?: Record<string, string | null>\n onAssignSecondary?: (taskId: string, modelId: string | null) => void\n secondaryLabel?: string\n /** App-rendered per-row context (inherit notes, spend, badges). */\n renderMeta?: (task: TaskAssignmentTask) => React.ReactNode\n unassignedLabel?: string\n clearLabel?: string\n modelLabel?: string\n disabled?: boolean\n className?: string\n}\n\nfunction filterProviders(\n providers: ModelPickerProvider[],\n requires: string | undefined,\n): ModelPickerProvider[] {\n if (!requires) return providers\n const matches = (model: ModelPickerModel) =>\n model.capability === requires || (model.capabilities?.includes(requires) ?? false)\n return providers\n .map((provider) => ({\n ...provider,\n models: provider.models.filter(matches),\n }))\n .filter((provider) => provider.models.length > 0)\n}\n\nexport const TaskAssignmentPicker = React.forwardRef<\n HTMLDivElement,\n TaskAssignmentPickerProps\n>(function TaskAssignmentPicker(\n {\n tasks = [],\n sections,\n providers,\n value,\n onAssign,\n secondaryValue,\n onAssignSecondary,\n secondaryLabel = 'Fallback model',\n renderMeta,\n unassignedLabel = 'Not assigned',\n clearLabel = 'Clear assignment',\n modelLabel = 'Model',\n disabled = false,\n className,\n },\n ref,\n) {\n const modelName = React.useCallback(\n (modelId: string | null | undefined) => {\n if (!modelId) return null\n for (const provider of providers) {\n const model = provider.models.find((m) => m.id === modelId)\n if (model) return { name: model.name, provider: provider.name }\n }\n return null\n },\n [providers],\n )\n\n const renderRow = (task: TaskAssignmentTask, showSecondary: boolean) => {\n const assigned = modelName(value[task.id])\n const catalog = filterProviders(providers, task.requires)\n return (\n <div\n key={task.id}\n className=\"flex flex-col gap-2 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-3 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"flex min-w-0 items-center gap-3\">\n {task.icon ? (\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-[var(--as-radius)] bg-[var(--as-muted)] text-[var(--as-muted-fg)]\">\n <task.icon className=\"size-4\" aria-hidden />\n </span>\n ) : null}\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-[var(--as-fg)]\">\n {task.label}\n </p>\n {task.description ? (\n <p className=\"truncate text-xs text-[var(--as-muted-fg)]\">\n {task.description}\n </p>\n ) : null}\n {renderMeta ? renderMeta(task) : null}\n <p className=\"mt-0.5 text-xs text-[var(--as-muted-fg)]\">\n {assigned ? (\n <>\n {modelLabel}:{' '}\n <span className=\"font-medium text-[var(--as-fg)]\">\n {assigned.provider} / {assigned.name}\n </span>\n </>\n ) : (\n unassignedLabel\n )}\n </p>\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-1.5\">\n {showSecondary && onAssignSecondary ? (\n <ModelPicker\n providers={catalog}\n value={secondaryValue?.[task.id] ?? ''}\n onChange={(modelId) => onAssignSecondary(task.id, modelId)}\n disabled={disabled}\n clearable={Boolean(secondaryValue?.[task.id])}\n clearLabel={clearLabel}\n label={`${secondaryLabel} — ${task.label}`}\n className=\"w-48\"\n />\n ) : null}\n <ModelPicker\n providers={catalog}\n value={value[task.id] ?? ''}\n onChange={(modelId) => onAssign(task.id, modelId)}\n disabled={disabled}\n clearable={Boolean(value[task.id])}\n clearLabel={clearLabel}\n label={`${modelLabel} — ${task.label}`}\n className=\"w-56\"\n />\n {value[task.id] ? (\n <button\n type=\"button\"\n aria-label={`${clearLabel} — ${task.label}`}\n disabled={disabled}\n onClick={() => onAssign(task.id, null)}\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)] disabled:pointer-events-none disabled:opacity-50\"\n >\n <X className=\"size-4\" aria-hidden />\n </button>\n ) : null}\n </div>\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"task-assignment-picker\"\n className={cn('flex w-full flex-col gap-3', className)}\n >\n {sections\n ? sections.map((section) => (\n <div key={section.id} className=\"flex flex-col gap-2\">\n <div>\n <p className=\"text-xs font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {section.label}\n </p>\n {section.description ? (\n <p className=\"mt-0.5 text-xs text-[var(--as-muted-fg)]\">\n {section.description}\n </p>\n ) : null}\n </div>\n {section.tasks.map((task) =>\n renderRow(task, section.secondary || Boolean(task.secondary)),\n )}\n </div>\n ))\n : tasks.map((task) => renderRow(task, Boolean(task.secondary)))}\n </div>\n )\n})\n"]}
|