@tangle-network/sandbox-ui 0.80.0 → 0.82.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.
- package/dist/{WorkflowGraph-SJ2SG5TP.js → WorkflowGraph-472MC3ML.js} +32 -4
- package/dist/chat.d.ts +1 -1
- package/dist/chat.js +4 -3
- package/dist/{chunk-UEMWLVVY.js → chunk-2NS724P4.js} +3 -1
- package/dist/{chunk-IWIZ7RZE.js → chunk-2T6KBMLN.js} +1 -1
- package/dist/{chunk-L62ZT6RS.js → chunk-I3G23XHN.js} +14 -412
- package/dist/chunk-R4AR3TKR.js +424 -0
- package/dist/{chunk-UFVXAJSA.js → chunk-YBFGWPUF.js} +7 -5
- package/dist/dashboard.d.ts +80 -3
- package/dist/dashboard.js +9 -3
- package/dist/globals.css +3 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -4
- package/dist/model-brand-CsFykzMA.d.ts +101 -0
- package/dist/pages.d.ts +1 -2
- package/dist/pages.js +2 -1
- package/dist/styles.css +3 -0
- package/dist/workbench.js +3 -2
- package/dist/workflows.d.ts +2 -0
- package/dist/workflows.js +10 -3
- package/package.json +2 -2
- package/dist/model-picker-COjPVMzg.d.ts +0 -145
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
fmtTokens,
|
|
12
12
|
providerLabel,
|
|
13
13
|
shortModel
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2NS724P4.js";
|
|
15
|
+
import {
|
|
16
|
+
ModelBrandStack,
|
|
17
|
+
modelBrandFor
|
|
18
|
+
} from "./chunk-I3G23XHN.js";
|
|
19
|
+
import "./chunk-EI44GEQ5.js";
|
|
15
20
|
import "./chunk-U67V476Y.js";
|
|
16
21
|
|
|
17
22
|
// src/workflows/WorkflowGraph.tsx
|
|
@@ -341,16 +346,18 @@ var KIND_ICON = {
|
|
|
341
346
|
function NodeMark({
|
|
342
347
|
kind,
|
|
343
348
|
provider,
|
|
349
|
+
model,
|
|
344
350
|
accent,
|
|
345
351
|
tile
|
|
346
352
|
}) {
|
|
347
353
|
const Icon = kind && KIND_ICON[kind] || Circle;
|
|
354
|
+
const brand = !provider && model ? modelBrandFor(model) : null;
|
|
348
355
|
const mark = Math.round(tile * (provider ? 0.58 : 0.5));
|
|
349
356
|
return /* @__PURE__ */ jsx2(
|
|
350
357
|
"span",
|
|
351
358
|
{
|
|
352
359
|
"aria-hidden": "true",
|
|
353
|
-
className: "flex shrink-0 items-center justify-center rounded-lg border border-border",
|
|
360
|
+
className: "flex shrink-0 items-center justify-center overflow-hidden rounded-lg border border-border",
|
|
354
361
|
style: {
|
|
355
362
|
width: tile,
|
|
356
363
|
height: tile,
|
|
@@ -364,6 +371,19 @@ function NodeMark({
|
|
|
364
371
|
size: mark,
|
|
365
372
|
className: "rounded-[3px]"
|
|
366
373
|
}
|
|
374
|
+
) : brand ? (
|
|
375
|
+
// One lab's own model draws ONE mark (28px at `md`) and fills the tile. A
|
|
376
|
+
// HOSTED model draws two — host behind, lab in front — and that stack is
|
|
377
|
+
// 36px wide, which would push the lab chip past the border of an expanded
|
|
378
|
+
// card's 34px tile. So the stacked pair steps down unless the tile can hold
|
|
379
|
+
// it; the single mark never has to.
|
|
380
|
+
/* @__PURE__ */ jsx2(
|
|
381
|
+
ModelBrandStack,
|
|
382
|
+
{
|
|
383
|
+
identity: brand,
|
|
384
|
+
size: brand.combined || tile >= 38 ? "md" : "sm"
|
|
385
|
+
}
|
|
386
|
+
)
|
|
367
387
|
) : /* @__PURE__ */ jsx2(Icon, { size: mark, strokeWidth: 1.75, style: { color: accent } })
|
|
368
388
|
}
|
|
369
389
|
);
|
|
@@ -373,6 +393,10 @@ function NodeMark({
|
|
|
373
393
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
374
394
|
var MUTED_TRACK = "color-mix(in srgb, hsl(var(--muted-foreground)) 22%, transparent)";
|
|
375
395
|
var FIT_VIEW = { padding: 0.16, minZoom: 0.55, maxZoom: 1 };
|
|
396
|
+
function fitViewOnLayoutChange() {
|
|
397
|
+
const moves = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === false;
|
|
398
|
+
return moves ? { ...FIT_VIEW, duration: 220 } : FIT_VIEW;
|
|
399
|
+
}
|
|
376
400
|
function useColorMode() {
|
|
377
401
|
const [mode, setMode] = useState(
|
|
378
402
|
() => typeof document !== "undefined" && document.documentElement.classList.contains("dark") ? "dark" : "light"
|
|
@@ -475,6 +499,7 @@ function WorkflowNode({ data }) {
|
|
|
475
499
|
const accent = TONE_ACCENT[d.tone];
|
|
476
500
|
const isAgent = d.kind === "agent.run";
|
|
477
501
|
const subtitle = isAgent && state?.model ? shortModel(state.model) : d.subtitle;
|
|
502
|
+
const markModel = isAgent && state?.model ? state.model : d.model;
|
|
478
503
|
const runBands = state !== void 0 && d.tone !== "trigger";
|
|
479
504
|
const duration = fmtDuration(state?.durationMs);
|
|
480
505
|
const cost = fmtCost(state?.costUsd);
|
|
@@ -538,6 +563,7 @@ function WorkflowNode({ data }) {
|
|
|
538
563
|
{
|
|
539
564
|
kind: d.kind,
|
|
540
565
|
provider: d.provider,
|
|
566
|
+
model: markModel,
|
|
541
567
|
accent,
|
|
542
568
|
tile: Math.round(COMPACT_TILE * 0.62)
|
|
543
569
|
}
|
|
@@ -602,6 +628,7 @@ function WorkflowNode({ data }) {
|
|
|
602
628
|
{
|
|
603
629
|
kind: d.kind,
|
|
604
630
|
provider: d.provider,
|
|
631
|
+
model: markModel,
|
|
605
632
|
accent,
|
|
606
633
|
tile: 34
|
|
607
634
|
}
|
|
@@ -726,7 +753,7 @@ function WorkflowGraph({
|
|
|
726
753
|
}
|
|
727
754
|
const inst = rfRef.current;
|
|
728
755
|
if (!inst || typeof requestAnimationFrame === "undefined") return;
|
|
729
|
-
const raf = requestAnimationFrame(() => inst.fitView(
|
|
756
|
+
const raf = requestAnimationFrame(() => inst.fitView(fitViewOnLayoutChange()));
|
|
730
757
|
return () => cancelAnimationFrame(raf);
|
|
731
758
|
}, [structural]);
|
|
732
759
|
const handleNodeClick = useCallback(
|
|
@@ -801,5 +828,6 @@ export {
|
|
|
801
828
|
DirectionContext,
|
|
802
829
|
WorkflowGraph,
|
|
803
830
|
WorkflowNode,
|
|
804
|
-
buildStyledEdges
|
|
831
|
+
buildStyledEdges,
|
|
832
|
+
fitViewOnLayoutChange
|
|
805
833
|
};
|
package/dist/chat.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { ReasoningEffort, HarnessType } from '@tangle-network/agent-interface';
|
|
|
5
5
|
export { modelProvider, snapHarnessToModel } from '@tangle-network/agent-interface';
|
|
6
6
|
import * as Popover from '@radix-ui/react-dropdown-menu';
|
|
7
7
|
import * as React from 'react';
|
|
8
|
-
import {
|
|
8
|
+
import { b as ModelInfo } from './model-brand-CsFykzMA.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* A reasoning selection: `auto` is a UI-only sentinel ("let the harness/model default decide",
|
package/dist/chat.js
CHANGED
|
@@ -19,10 +19,11 @@ import {
|
|
|
19
19
|
snapHarnessToModel,
|
|
20
20
|
snapModelToHarness,
|
|
21
21
|
validateComposerFiles
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-YBFGWPUF.js";
|
|
23
23
|
import "./chunk-TK46XFLM.js";
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
import "./chunk-2T6KBMLN.js";
|
|
25
|
+
import "./chunk-R4AR3TKR.js";
|
|
26
|
+
import "./chunk-I3G23XHN.js";
|
|
26
27
|
import "./chunk-EI44GEQ5.js";
|
|
27
28
|
import "./chunk-U67V476Y.js";
|
|
28
29
|
export {
|
|
@@ -279,9 +279,11 @@ var CONTROL_FLOW = new Set(CONTROL_FLOW_KEYS);
|
|
|
279
279
|
function actionKind(rec) {
|
|
280
280
|
return Object.keys(rec).find((k) => !CONTROL_FLOW.has(k));
|
|
281
281
|
}
|
|
282
|
+
var MINTED_PROFILE_ID = /^ap_[A-Za-z0-9_-]{16}$/;
|
|
282
283
|
function agentTitle(profile) {
|
|
283
284
|
const named = str(profile);
|
|
284
|
-
|
|
285
|
+
if (!named || MINTED_PROFILE_ID.test(named)) return "AI Agent";
|
|
286
|
+
return humanizeIdentifier(named);
|
|
285
287
|
}
|
|
286
288
|
function describeActionBase(action) {
|
|
287
289
|
const rec = asRecord(action);
|
|
@@ -2,11 +2,10 @@ import {
|
|
|
2
2
|
cn
|
|
3
3
|
} from "./chunk-EI44GEQ5.js";
|
|
4
4
|
|
|
5
|
-
// src/
|
|
6
|
-
import * as React from "react";
|
|
5
|
+
// src/lib/model-brand.tsx
|
|
7
6
|
import { TangleKnot } from "@tangle-network/brand";
|
|
8
7
|
|
|
9
|
-
// src/
|
|
8
|
+
// src/lib/provider-logo.tsx
|
|
10
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
var LOGOS = {
|
|
12
11
|
anthropic: { viewBox: "0 0 24 24", fill: "#D97757", paths: ["M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z"] },
|
|
@@ -46,10 +45,6 @@ function ProviderLogo({ provider, size = 16 }) {
|
|
|
46
45
|
] });
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
// src/dashboard/model-picker.tsx
|
|
50
|
-
import { ChevronDown, Search, Sparkles, Loader2 } from "lucide-react";
|
|
51
|
-
import * as Popover from "@radix-ui/react-dropdown-menu";
|
|
52
|
-
|
|
53
48
|
// node_modules/.pnpm/@lobehub+icons-static-svg@1.90.0/node_modules/@lobehub/icons-static-svg/icons/ai21.svg
|
|
54
49
|
var ai21_default = 'data:image/svg+xml,<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>AI21</title><path d="M6.47 17l-.367-1.189H2.718L2.35 17H0l3.398-9.789h2.026L8.864 17H6.47zm-2.052-6.993l-1.17 4.028H5.56l-1.142-4.028zm4.707-2.796h2.23V17h-2.23V7.211zM11.955 15c.1-.483.277-.946.524-1.37.214-.359.482-.68.795-.951.32-.273.658-.52 1.013-.741.28-.168.54-.33.781-.483.222-.14.433-.296.632-.468.172-.148.317-.325.428-.525.107-.199.16-.423.157-.65 0-.392-.104-.674-.313-.846a1.176 1.176 0 00-.775-.259 1.207 1.207 0 00-.863.329c-.231.219-.347.585-.347 1.098H11.8a3.387 3.387 0 01.224-1.245c.146-.377.371-.716.66-.993.306-.29.667-.514 1.06-.657A4.04 4.04 0 0115.183 7c.42-.002.84.057 1.244.175.376.107.73.287 1.04.531.305.246.55.562.714.923.185.419.275.875.265 1.335.005.39-.084.774-.259 1.12-.167.328-.38.63-.632.894-.246.259-.517.49-.808.693-.29.2-.554.37-.789.51-.326.224-.596.417-.809.58a3.872 3.872 0 00-.51.455 1.229 1.229 0 00-.265.434 1.633 1.633 0 00-.074.517h4.078V17h-6.606a9.24 9.24 0 01.183-2zM18.8 8.93a5.05 5.05 0 001.135-.105c.25-.049.484-.156.686-.314.163-.139.28-.324.34-.532.068-.25.1-.51.095-.77H23V17h-2.243v-6.475H18.8V8.93z"></path></svg>';
|
|
55
50
|
|
|
@@ -137,7 +132,7 @@ var xai_default = 'data:image/svg+xml,<svg fill="currentColor" fill-rule="evenod
|
|
|
137
132
|
// node_modules/.pnpm/@lobehub+icons-static-svg@1.90.0/node_modules/@lobehub/icons-static-svg/icons/zai.svg
|
|
138
133
|
var zai_default = 'data:image/svg+xml,<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Z.ai</title><path d="M12.105 2L9.927 4.953H.653L2.83 2h9.276zM23.254 19.048L21.078 22h-9.242l2.174-2.952h9.244zM24 2L9.264 22H0L14.736 2H24z"></path></svg>';
|
|
139
134
|
|
|
140
|
-
// src/
|
|
135
|
+
// src/lib/model-brand.tsx
|
|
141
136
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
142
137
|
function canonicalModelId(model) {
|
|
143
138
|
const id = model.id;
|
|
@@ -145,56 +140,6 @@ function canonicalModelId(model) {
|
|
|
145
140
|
const provider = model._provider ?? model.provider;
|
|
146
141
|
return provider ? `${provider}/${id}` : id;
|
|
147
142
|
}
|
|
148
|
-
function modelDedupKey(model) {
|
|
149
|
-
const canonical = canonicalModelId(model).toLowerCase();
|
|
150
|
-
const segments = canonical.split("/").filter(Boolean);
|
|
151
|
-
const modelId = segments[segments.length - 1] ?? canonical;
|
|
152
|
-
const lab = resolveModelBrandIdentity(model).lab.key;
|
|
153
|
-
return lab === "unknown" ? canonical : `${lab}/${modelId}`;
|
|
154
|
-
}
|
|
155
|
-
function dedupeModels(models) {
|
|
156
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
157
|
-
const result = [];
|
|
158
|
-
for (const model of models) {
|
|
159
|
-
const key = modelDedupKey(model);
|
|
160
|
-
const existingIndex = byKey.get(key);
|
|
161
|
-
if (existingIndex === void 0) {
|
|
162
|
-
byKey.set(key, result.length);
|
|
163
|
-
result.push(model);
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
const existing = result[existingIndex];
|
|
167
|
-
if (!existing.featured && model.featured) {
|
|
168
|
-
result[existingIndex] = model;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
var DEFAULT_FEATURED_MODEL_IDS = [
|
|
174
|
-
"anthropic/claude-opus-4-8",
|
|
175
|
-
"anthropic/claude-sonnet-4-6",
|
|
176
|
-
"openai/gpt-5.4",
|
|
177
|
-
"google/gemini-2.5-pro",
|
|
178
|
-
"deepseek/deepseek-v3"
|
|
179
|
-
];
|
|
180
|
-
function formatPricing(pricing) {
|
|
181
|
-
const prompt = Number(pricing?.prompt ?? 0);
|
|
182
|
-
const completion = Number(pricing?.completion ?? 0);
|
|
183
|
-
if (!prompt && !completion) return null;
|
|
184
|
-
const fmt = (n) => {
|
|
185
|
-
const perM = n * 1e6;
|
|
186
|
-
if (perM === 0) return "0";
|
|
187
|
-
if (perM >= 1) return `$${perM.toFixed(2)}`;
|
|
188
|
-
return `$${perM.toFixed(2)}`;
|
|
189
|
-
};
|
|
190
|
-
return `${fmt(prompt)} / ${fmt(completion)} per 1M`;
|
|
191
|
-
}
|
|
192
|
-
function formatContext(ctx) {
|
|
193
|
-
if (!ctx) return null;
|
|
194
|
-
if (ctx >= 1e6) return `${(ctx / 1e6).toFixed(1)}M ctx`;
|
|
195
|
-
if (ctx >= 1e3) return `${Math.round(ctx / 1e3)}k ctx`;
|
|
196
|
-
return `${ctx} ctx`;
|
|
197
|
-
}
|
|
198
143
|
function resolveModelBrandIdentity(model) {
|
|
199
144
|
const canonical = canonicalModelId(model);
|
|
200
145
|
const hostKey = normalizeBrandKey(model.logos?.host ?? model.hostProvider ?? model._provider ?? model.provider ?? firstIdSegment(canonical));
|
|
@@ -209,352 +154,12 @@ function resolveModelBrandIdentity(model) {
|
|
|
209
154
|
combined: host.key === lab.key
|
|
210
155
|
};
|
|
211
156
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return
|
|
218
|
-
}
|
|
219
|
-
function modelGroupLabel(key) {
|
|
220
|
-
if (key === "moonshot") return "Kimi";
|
|
221
|
-
const brand = brandInfo(normalizeBrandKey(key));
|
|
222
|
-
return brand.key === "unknown" ? key : brand.label;
|
|
223
|
-
}
|
|
224
|
-
function modelGroupRank(key) {
|
|
225
|
-
const priorityIndex = PRIORITY_MODEL_GROUPS.indexOf(normalizeBrandKey(key));
|
|
226
|
-
return priorityIndex === -1 ? Number.POSITIVE_INFINITY : priorityIndex;
|
|
227
|
-
}
|
|
228
|
-
function compareModelGroups(a, b) {
|
|
229
|
-
const aRank = modelGroupRank(a);
|
|
230
|
-
const bRank = modelGroupRank(b);
|
|
231
|
-
if (aRank !== bRank) return aRank - bRank;
|
|
232
|
-
return modelGroupLabel(a).localeCompare(modelGroupLabel(b));
|
|
233
|
-
}
|
|
234
|
-
function compareModelsByDisplayName(a, b) {
|
|
235
|
-
return (a.name ?? a.id).localeCompare(b.name ?? b.id);
|
|
236
|
-
}
|
|
237
|
-
function stripBrandPrefix(name, identity) {
|
|
238
|
-
if (!identity) return name;
|
|
239
|
-
for (const label of [identity.lab.label, identity.host.label]) {
|
|
240
|
-
if (!label) continue;
|
|
241
|
-
if (name.toLowerCase().startsWith(label.toLowerCase())) {
|
|
242
|
-
const after = name.slice(label.length);
|
|
243
|
-
if (/^[\s:]/.test(after)) {
|
|
244
|
-
const rest = after.replace(/^[\s:]+/, "").trim();
|
|
245
|
-
if (rest) return rest;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return name;
|
|
250
|
-
}
|
|
251
|
-
function ModelPicker({
|
|
252
|
-
value,
|
|
253
|
-
onChange,
|
|
254
|
-
models,
|
|
255
|
-
loading = false,
|
|
256
|
-
recents,
|
|
257
|
-
popular,
|
|
258
|
-
excludeProviders,
|
|
259
|
-
modalities,
|
|
260
|
-
variant = "field",
|
|
261
|
-
label = "Model",
|
|
262
|
-
placeholder = "Choose a model",
|
|
263
|
-
className,
|
|
264
|
-
triggerClassName,
|
|
265
|
-
disabled,
|
|
266
|
-
side,
|
|
267
|
-
avoidCollisions
|
|
268
|
-
}) {
|
|
269
|
-
const [query, setQuery] = React.useState("");
|
|
270
|
-
const [open, setOpen] = React.useState(false);
|
|
271
|
-
const searchInputRef = React.useRef(null);
|
|
272
|
-
React.useLayoutEffect(() => {
|
|
273
|
-
if (!open) return;
|
|
274
|
-
const frame = requestAnimationFrame(() => {
|
|
275
|
-
searchInputRef.current?.focus();
|
|
276
|
-
searchInputRef.current?.select();
|
|
277
|
-
});
|
|
278
|
-
return () => cancelAnimationFrame(frame);
|
|
279
|
-
}, [open]);
|
|
280
|
-
const deduped = React.useMemo(() => dedupeModels(models), [models]);
|
|
281
|
-
const filtered = React.useMemo(() => {
|
|
282
|
-
const excluded = new Set((excludeProviders ?? []).map((p) => p.toLowerCase()));
|
|
283
|
-
const allowedModalities = modalities ? new Set(modalities) : null;
|
|
284
|
-
const q = query.trim().toLowerCase();
|
|
285
|
-
return deduped.filter((m) => {
|
|
286
|
-
const provider = (m._provider ?? m.provider ?? "").toLowerCase();
|
|
287
|
-
if (excluded.has(provider)) return false;
|
|
288
|
-
if (allowedModalities && m.architecture?.modality && !allowedModalities.has(m.architecture.modality)) return false;
|
|
289
|
-
if (!q) return true;
|
|
290
|
-
const id = canonicalModelId(m).toLowerCase();
|
|
291
|
-
const name = (m.name ?? "").toLowerCase();
|
|
292
|
-
const identity = resolveModelBrandIdentity(m);
|
|
293
|
-
return id.includes(q) || name.includes(q) || provider.includes(q) || identity.host.label.toLowerCase().includes(q) || identity.lab.label.toLowerCase().includes(q);
|
|
294
|
-
});
|
|
295
|
-
}, [deduped, query, modalities, excludeProviders]);
|
|
296
|
-
const grouped = React.useMemo(() => {
|
|
297
|
-
const groups = /* @__PURE__ */ new Map();
|
|
298
|
-
for (const m of filtered) {
|
|
299
|
-
const key = modelGroupKey(m);
|
|
300
|
-
const list = groups.get(key);
|
|
301
|
-
if (list) list.push(m);
|
|
302
|
-
else groups.set(key, [m]);
|
|
303
|
-
}
|
|
304
|
-
return Array.from(groups.entries()).map(([key, list]) => [key, [...list].sort(compareModelsByDisplayName)]).sort(([a], [b]) => compareModelGroups(a, b));
|
|
305
|
-
}, [filtered]);
|
|
306
|
-
const current = React.useMemo(
|
|
307
|
-
() => models.find((m) => canonicalModelId(m) === value),
|
|
308
|
-
[models, value]
|
|
309
|
-
);
|
|
310
|
-
const currentIdentity = current ? resolveModelBrandIdentity(current) : null;
|
|
311
|
-
const currentLabel = stripBrandPrefix(
|
|
312
|
-
current?.name ?? current?.id ?? value,
|
|
313
|
-
currentIdentity
|
|
314
|
-
);
|
|
315
|
-
const recentIds = React.useMemo(() => {
|
|
316
|
-
if (!recents?.length) return [];
|
|
317
|
-
const lookup = new Map(models.map((m) => [canonicalModelId(m), m]));
|
|
318
|
-
return recents.map((id) => lookup.get(id)).filter((m) => Boolean(m)).slice(0, 4);
|
|
319
|
-
}, [recents, models]);
|
|
320
|
-
const popularModels = React.useMemo(() => {
|
|
321
|
-
if (!popular?.length) return [];
|
|
322
|
-
const lookup = new Map(models.map((m) => [canonicalModelId(m), m]));
|
|
323
|
-
return popular.map((id) => lookup.get(id)).filter((m) => Boolean(m));
|
|
324
|
-
}, [popular, models]);
|
|
325
|
-
const featuredModels = React.useMemo(() => {
|
|
326
|
-
const flagged = deduped.filter((m) => m.featured);
|
|
327
|
-
if (flagged.length > 0) return flagged;
|
|
328
|
-
const seedKeys = new Set(
|
|
329
|
-
DEFAULT_FEATURED_MODEL_IDS.map((id) => modelDedupKey({ id }))
|
|
330
|
-
);
|
|
331
|
-
const seeded = deduped.filter((m) => seedKeys.has(modelDedupKey(m)));
|
|
332
|
-
const order = DEFAULT_FEATURED_MODEL_IDS.map((id) => modelDedupKey({ id }));
|
|
333
|
-
return seeded.sort(
|
|
334
|
-
(a, b) => order.indexOf(modelDedupKey(a)) - order.indexOf(modelDedupKey(b))
|
|
335
|
-
);
|
|
336
|
-
}, [deduped]);
|
|
337
|
-
const handleSelect = (id) => {
|
|
338
|
-
onChange(id);
|
|
339
|
-
setOpen(false);
|
|
340
|
-
setQuery("");
|
|
341
|
-
};
|
|
342
|
-
const triggerLabel = label ? `${label}: ${currentLabel || placeholder}` : currentLabel || placeholder;
|
|
343
|
-
const trigger = variant === "pill" ? /* @__PURE__ */ jsxs2(
|
|
344
|
-
"button",
|
|
345
|
-
{
|
|
346
|
-
type: "button",
|
|
347
|
-
"aria-label": triggerLabel,
|
|
348
|
-
disabled,
|
|
349
|
-
className: cn(
|
|
350
|
-
"inline-flex h-8 items-center gap-1.5 rounded-lg border border-[var(--md3-outline-variant)] bg-surface-container",
|
|
351
|
-
"px-2.5 text-xs font-medium text-foreground shadow-sm",
|
|
352
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
353
|
-
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
|
|
354
|
-
"focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
355
|
-
"data-[state=open]:border-[var(--md3-outline)] data-[state=open]:bg-surface-container-high",
|
|
356
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
357
|
-
className,
|
|
358
|
-
triggerClassName
|
|
359
|
-
),
|
|
360
|
-
children: [
|
|
361
|
-
currentIdentity ? /* @__PURE__ */ jsx2(ModelBrandStack, { identity: currentIdentity, size: "sm" }) : /* @__PURE__ */ jsx2(Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
|
|
362
|
-
/* @__PURE__ */ jsx2("span", { className: "truncate max-w-[160px]", children: currentLabel || placeholder }),
|
|
363
|
-
/* @__PURE__ */ jsx2(ChevronDown, { className: "ml-auto h-3 w-3 shrink-0 text-muted-foreground transition-transform data-[state=open]:rotate-180" })
|
|
364
|
-
]
|
|
365
|
-
}
|
|
366
|
-
) : /* @__PURE__ */ jsxs2(
|
|
367
|
-
"button",
|
|
368
|
-
{
|
|
369
|
-
type: "button",
|
|
370
|
-
"aria-label": triggerLabel,
|
|
371
|
-
disabled,
|
|
372
|
-
className: cn(
|
|
373
|
-
"flex w-full items-center justify-between gap-2 rounded-[var(--radius-md)]",
|
|
374
|
-
"border border-[var(--md3-outline-variant)] bg-surface-container px-3 py-2.5 text-sm text-left",
|
|
375
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
376
|
-
"hover:border-[var(--md3-outline-variant)] hover:bg-surface-container-high",
|
|
377
|
-
"focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
|
378
|
-
"data-[state=open]:border-[var(--md3-outline)] data-[state=open]:bg-surface-container-high",
|
|
379
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
380
|
-
className,
|
|
381
|
-
triggerClassName
|
|
382
|
-
),
|
|
383
|
-
children: [
|
|
384
|
-
/* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
385
|
-
currentIdentity && /* @__PURE__ */ jsx2(ModelBrandStack, { identity: currentIdentity, size: "sm" }),
|
|
386
|
-
/* @__PURE__ */ jsx2("span", { className: cn("truncate", current ? "text-foreground font-medium" : "text-muted-foreground"), children: currentLabel || placeholder })
|
|
387
|
-
] }),
|
|
388
|
-
/* @__PURE__ */ jsx2(ChevronDown, { className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform data-[state=open]:rotate-180" })
|
|
389
|
-
]
|
|
390
|
-
}
|
|
391
|
-
);
|
|
392
|
-
return /* @__PURE__ */ jsxs2("div", { className: cn(variant === "field" ? "space-y-1.5" : "inline-flex", variant === "field" ? className : void 0), children: [
|
|
393
|
-
variant === "field" && label && /* @__PURE__ */ jsx2("label", { className: "block text-xs font-medium text-muted-foreground uppercase tracking-[0.06em]", children: label }),
|
|
394
|
-
/* @__PURE__ */ jsxs2(Popover.Root, { open, onOpenChange: setOpen, modal: false, children: [
|
|
395
|
-
/* @__PURE__ */ jsx2(Popover.Trigger, { asChild: true, children: trigger }),
|
|
396
|
-
/* @__PURE__ */ jsx2(Popover.Portal, { children: /* @__PURE__ */ jsxs2(
|
|
397
|
-
Popover.Content,
|
|
398
|
-
{
|
|
399
|
-
side,
|
|
400
|
-
sideOffset: 4,
|
|
401
|
-
align: variant === "pill" ? "start" : "start",
|
|
402
|
-
avoidCollisions,
|
|
403
|
-
collisionPadding: 24,
|
|
404
|
-
className: cn(
|
|
405
|
-
"z-50 w-[var(--radix-dropdown-menu-trigger-width)] min-w-[320px] max-w-[460px]",
|
|
406
|
-
// Cap to the smaller of the fixed height and the viewport space on
|
|
407
|
-
// the open side, so a list pinned downward never runs off-screen.
|
|
408
|
-
"max-h-[min(440px,var(--radix-dropdown-menu-content-available-height))] overflow-hidden flex flex-col",
|
|
409
|
-
"rounded-[var(--radius-md)] border border-[var(--md3-outline-variant)] bg-surface-container-highest shadow-[0_8px_30px_rgba(0,0,0,0.45)] ring-1 ring-[#ffffff14]",
|
|
410
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
411
|
-
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
412
|
-
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95"
|
|
413
|
-
),
|
|
414
|
-
children: [
|
|
415
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-[var(--md3-outline-variant)] bg-surface-container-high px-3 py-2", children: [
|
|
416
|
-
/* @__PURE__ */ jsx2(Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
417
|
-
/* @__PURE__ */ jsx2(
|
|
418
|
-
"input",
|
|
419
|
-
{
|
|
420
|
-
ref: searchInputRef,
|
|
421
|
-
type: "text",
|
|
422
|
-
value: query,
|
|
423
|
-
onChange: (e) => setQuery(e.target.value),
|
|
424
|
-
onKeyDown: (e) => {
|
|
425
|
-
if (e.key.length === 1) e.stopPropagation();
|
|
426
|
-
},
|
|
427
|
-
placeholder: "Search models...",
|
|
428
|
-
autoFocus: true,
|
|
429
|
-
className: "flex-1 bg-transparent text-sm font-medium outline-none placeholder:font-normal placeholder:text-muted-foreground"
|
|
430
|
-
}
|
|
431
|
-
),
|
|
432
|
-
loading && /* @__PURE__ */ jsx2(Loader2, { className: "h-3.5 w-3.5 animate-spin text-muted-foreground" })
|
|
433
|
-
] }),
|
|
434
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex-1 overflow-y-auto", children: [
|
|
435
|
-
!query && featuredModels.length > 0 && /* @__PURE__ */ jsx2(Section, { label: "Recommended", tone: "featured", children: featuredModels.map((m) => /* @__PURE__ */ jsx2(
|
|
436
|
-
ModelRow,
|
|
437
|
-
{
|
|
438
|
-
model: m,
|
|
439
|
-
active: canonicalModelId(m) === value,
|
|
440
|
-
onSelect: handleSelect,
|
|
441
|
-
featured: true
|
|
442
|
-
},
|
|
443
|
-
`featured-${canonicalModelId(m)}`
|
|
444
|
-
)) }),
|
|
445
|
-
!query && popularModels.length > 0 && /* @__PURE__ */ jsx2(Section, { label: "Top models", tone: "featured", children: popularModels.map((m) => /* @__PURE__ */ jsx2(
|
|
446
|
-
ModelRow,
|
|
447
|
-
{
|
|
448
|
-
model: m,
|
|
449
|
-
active: canonicalModelId(m) === value,
|
|
450
|
-
onSelect: handleSelect,
|
|
451
|
-
featured: true
|
|
452
|
-
},
|
|
453
|
-
`popular-${canonicalModelId(m)}`
|
|
454
|
-
)) }),
|
|
455
|
-
!query && recentIds.length > 0 && /* @__PURE__ */ jsx2(Section, { label: "Recent", children: recentIds.map((m) => /* @__PURE__ */ jsx2(
|
|
456
|
-
ModelRow,
|
|
457
|
-
{
|
|
458
|
-
model: m,
|
|
459
|
-
active: canonicalModelId(m) === value,
|
|
460
|
-
onSelect: handleSelect
|
|
461
|
-
},
|
|
462
|
-
`recent-${canonicalModelId(m)}`
|
|
463
|
-
)) }),
|
|
464
|
-
grouped.length === 0 ? /* @__PURE__ */ jsx2("div", { className: "px-3 py-8 text-center text-xs text-muted-foreground", children: loading ? "Loading models..." : query ? "No models match." : "No models available." }) : grouped.map(([groupKey, list]) => /* @__PURE__ */ jsx2(Section, { label: modelGroupLabel(groupKey), children: list.map((m) => /* @__PURE__ */ jsx2(
|
|
465
|
-
ModelRow,
|
|
466
|
-
{
|
|
467
|
-
model: m,
|
|
468
|
-
active: canonicalModelId(m) === value,
|
|
469
|
-
onSelect: handleSelect
|
|
470
|
-
},
|
|
471
|
-
canonicalModelId(m)
|
|
472
|
-
)) }, groupKey))
|
|
473
|
-
] }),
|
|
474
|
-
/* @__PURE__ */ jsxs2("div", { className: "border-t border-[var(--md3-outline-variant)] px-3 py-1.5 text-[10px] text-muted-foreground", children: [
|
|
475
|
-
filtered.length,
|
|
476
|
-
" of ",
|
|
477
|
-
deduped.length,
|
|
478
|
-
" model",
|
|
479
|
-
deduped.length === 1 ? "" : "s"
|
|
480
|
-
] })
|
|
481
|
-
]
|
|
482
|
-
}
|
|
483
|
-
) })
|
|
484
|
-
] })
|
|
485
|
-
] });
|
|
486
|
-
}
|
|
487
|
-
function Section({ label, children, tone }) {
|
|
488
|
-
const identity = brandInfo(normalizeBrandKey(label));
|
|
489
|
-
return /* @__PURE__ */ jsxs2("div", { className: "py-1", children: [
|
|
490
|
-
/* @__PURE__ */ jsxs2(
|
|
491
|
-
"div",
|
|
492
|
-
{
|
|
493
|
-
className: cn(
|
|
494
|
-
"flex items-center gap-1.5 px-3 pt-1.5 pb-0.5 text-[10px] font-mono uppercase tracking-widest",
|
|
495
|
-
tone === "featured" ? "text-primary" : "text-muted-foreground"
|
|
496
|
-
),
|
|
497
|
-
children: [
|
|
498
|
-
identity.key !== "unknown" && /* @__PURE__ */ jsx2(BrandLogo, { brand: identity, size: "xs" }),
|
|
499
|
-
/* @__PURE__ */ jsx2("span", { children: label })
|
|
500
|
-
]
|
|
501
|
-
}
|
|
502
|
-
),
|
|
503
|
-
/* @__PURE__ */ jsx2("div", { children })
|
|
504
|
-
] });
|
|
505
|
-
}
|
|
506
|
-
function PickerItem({
|
|
507
|
-
onSelect,
|
|
508
|
-
active,
|
|
509
|
-
featured,
|
|
510
|
-
children
|
|
511
|
-
}) {
|
|
512
|
-
return /* @__PURE__ */ jsx2(
|
|
513
|
-
Popover.Item,
|
|
514
|
-
{
|
|
515
|
-
onSelect: (e) => {
|
|
516
|
-
e.preventDefault();
|
|
517
|
-
onSelect();
|
|
518
|
-
},
|
|
519
|
-
className: cn(
|
|
520
|
-
"flex cursor-pointer items-start gap-2 rounded-md px-3 py-2 outline-none",
|
|
521
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
522
|
-
"hover:bg-accent/50 focus:bg-accent/50",
|
|
523
|
-
featured && "mx-1 border border-primary/10 bg-primary/[0.04] px-2.5",
|
|
524
|
-
active && "bg-primary/10 font-medium text-foreground ring-1 ring-inset ring-primary/25 hover:bg-primary/15 focus:bg-primary/15"
|
|
525
|
-
),
|
|
526
|
-
children
|
|
527
|
-
}
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
function ModelRow({
|
|
531
|
-
model,
|
|
532
|
-
active,
|
|
533
|
-
onSelect,
|
|
534
|
-
featured
|
|
535
|
-
}) {
|
|
536
|
-
const id = canonicalModelId(model);
|
|
537
|
-
const pricing = formatPricing(model.pricing);
|
|
538
|
-
const ctx = formatContext(model.context_length);
|
|
539
|
-
const identity = resolveModelBrandIdentity(model);
|
|
540
|
-
const via = !identity.combined ? identity.host.label : null;
|
|
541
|
-
return /* @__PURE__ */ jsxs2(PickerItem, { onSelect: () => onSelect(id), active, featured, children: [
|
|
542
|
-
/* @__PURE__ */ jsx2(ModelBrandStack, { identity, size: "md" }),
|
|
543
|
-
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
|
|
544
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5", children: [
|
|
545
|
-
/* @__PURE__ */ jsx2("span", { className: "min-w-0 truncate text-sm font-medium", children: model.name ?? model.id }),
|
|
546
|
-
via && /* @__PURE__ */ jsxs2("span", { className: "shrink-0 rounded-full border border-[var(--md3-outline-variant)] bg-surface-container px-1.5 py-px text-[9px] font-medium text-muted-foreground", children: [
|
|
547
|
-
"via ",
|
|
548
|
-
via
|
|
549
|
-
] })
|
|
550
|
-
] }),
|
|
551
|
-
(ctx || pricing) && /* @__PURE__ */ jsxs2("div", { className: "mt-0.5 flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
552
|
-
ctx && /* @__PURE__ */ jsx2("span", { className: "shrink-0", children: ctx }),
|
|
553
|
-
ctx && pricing && /* @__PURE__ */ jsx2("span", { className: "shrink-0 opacity-40", children: "\xB7" }),
|
|
554
|
-
pricing && /* @__PURE__ */ jsx2("span", { className: "shrink-0 font-mono", children: pricing })
|
|
555
|
-
] })
|
|
556
|
-
] })
|
|
557
|
-
] });
|
|
157
|
+
function modelBrandFor(model) {
|
|
158
|
+
const trimmed = model.trim();
|
|
159
|
+
if (!trimmed) return null;
|
|
160
|
+
const identity = resolveModelBrandIdentity({ id: trimmed });
|
|
161
|
+
const real = hasRealLogo(identity.host) || hasRealLogo(identity.lab);
|
|
162
|
+
return real ? identity : null;
|
|
558
163
|
}
|
|
559
164
|
function ModelBrandStack({ identity, size }) {
|
|
560
165
|
if (identity.combined) return /* @__PURE__ */ jsx2(BrandLogo, { brand: identity.lab, size });
|
|
@@ -788,13 +393,10 @@ var BRAND_INFO = {
|
|
|
788
393
|
export {
|
|
789
394
|
moonshot_default,
|
|
790
395
|
canonicalModelId,
|
|
791
|
-
modelDedupKey,
|
|
792
|
-
dedupeModels,
|
|
793
|
-
DEFAULT_FEATURED_MODEL_IDS,
|
|
794
|
-
formatPricing,
|
|
795
|
-
formatContext,
|
|
796
396
|
resolveModelBrandIdentity,
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
397
|
+
modelBrandFor,
|
|
398
|
+
ModelBrandStack,
|
|
399
|
+
BrandLogo,
|
|
400
|
+
normalizeBrandKey,
|
|
401
|
+
brandInfo
|
|
800
402
|
};
|