@tangle-network/sandbox-ui 0.15.3 → 0.15.4

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.
@@ -4,7 +4,7 @@ import {
4
4
 
5
5
  // src/dashboard/model-picker.tsx
6
6
  import * as React from "react";
7
- import { ChevronDown, Search, Sparkles, Zap, Brain, Star, Loader2 } from "lucide-react";
7
+ import { ChevronDown, Search, Sparkles, Loader2 } from "lucide-react";
8
8
  import * as Popover from "@radix-ui/react-dropdown-menu";
9
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10
10
  function canonicalModelId(model) {
@@ -31,45 +31,13 @@ function formatContext(ctx) {
31
31
  if (ctx >= 1e3) return `${Math.round(ctx / 1e3)}k ctx`;
32
32
  return `${ctx} ctx`;
33
33
  }
34
- var DEFAULT_PRESETS = [
35
- {
36
- id: "fast",
37
- label: "Fast",
38
- hint: "Cheapest, lowest latency",
39
- icon: Zap,
40
- match: (models) => {
41
- const ids = models.map(canonicalModelId);
42
- return ids.find((m) => /gpt-5\.\d+-mini$/.test(m)) ?? ids.find((m) => /gpt-5-mini$/.test(m)) ?? ids.find((m) => m.endsWith("/claude-haiku-4.5")) ?? ids.find((m) => /haiku/.test(m));
43
- }
44
- },
45
- {
46
- id: "balanced",
47
- label: "Balanced",
48
- hint: "Best value for most chat",
49
- icon: Sparkles,
50
- match: (models) => {
51
- const ids = models.map(canonicalModelId);
52
- return ids.find((m) => /^openai\/gpt-5\.\d+$/.test(m)) ?? ids.find((m) => /^openai\/gpt-5$/.test(m)) ?? ids.find((m) => m.endsWith("/claude-sonnet-4-6")) ?? ids.find((m) => /sonnet/.test(m));
53
- }
54
- },
55
- {
56
- id: "best",
57
- label: "Best",
58
- hint: "Hardest reasoning, highest quality",
59
- icon: Brain,
60
- match: (models) => {
61
- const ids = models.map(canonicalModelId);
62
- return ids.find((m) => /^openai\/gpt-5\.\d+-pro$/.test(m)) ?? ids.find((m) => /^openai\/o3$/.test(m)) ?? ids.find((m) => m.endsWith("/claude-opus-4-7")) ?? ids.find((m) => /opus/.test(m));
63
- }
64
- }
65
- ];
66
34
  function ModelPicker({
67
35
  value,
68
36
  onChange,
69
37
  models,
70
38
  loading = false,
71
39
  recents,
72
- presets = DEFAULT_PRESETS,
40
+ popular,
73
41
  excludeProviders,
74
42
  modalities,
75
43
  variant = "field",
@@ -115,6 +83,11 @@ function ModelPicker({
115
83
  const lookup = new Map(models.map((m) => [canonicalModelId(m), m]));
116
84
  return recents.map((id) => lookup.get(id)).filter((m) => Boolean(m)).slice(0, 4);
117
85
  }, [recents, models]);
86
+ const popularModels = React.useMemo(() => {
87
+ if (!popular?.length) return [];
88
+ const lookup = new Map(models.map((m) => [canonicalModelId(m), m]));
89
+ return popular.map((id) => lookup.get(id)).filter((m) => Boolean(m));
90
+ }, [popular, models]);
118
91
  const handleSelect = (id) => {
119
92
  onChange(id);
120
93
  setOpen(false);
@@ -201,34 +174,15 @@ function ModelPicker({
201
174
  loading && /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin text-muted-foreground" })
202
175
  ] }),
203
176
  /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
204
- !query && presets.length > 0 && /* @__PURE__ */ jsx(Section, { label: "Presets", children: presets.map((preset) => {
205
- const Icon = preset.icon ?? Star;
206
- const matchedId = preset.match(models);
207
- if (!matchedId) return null;
208
- const matched = models.find((m) => canonicalModelId(m) === matchedId);
209
- const isCurrent = matchedId === value;
210
- return /* @__PURE__ */ jsxs(
211
- PickerItem,
212
- {
213
- onSelect: () => handleSelect(matchedId),
214
- active: isCurrent,
215
- children: [
216
- /* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 text-[var(--accent-text)]" }),
217
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
218
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
219
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: preset.label }),
220
- /* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground truncate", children: [
221
- "\u2192 ",
222
- matched?.name ?? matchedId
223
- ] })
224
- ] }),
225
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: preset.hint })
226
- ] })
227
- ]
228
- },
229
- preset.id
230
- );
231
- }) }),
177
+ !query && popularModels.length > 0 && /* @__PURE__ */ jsx(Section, { label: "Popular", children: popularModels.map((m) => /* @__PURE__ */ jsx(
178
+ ModelRow,
179
+ {
180
+ model: m,
181
+ active: canonicalModelId(m) === value,
182
+ onSelect: handleSelect
183
+ },
184
+ `popular-${canonicalModelId(m)}`
185
+ )) }),
232
186
  !query && recentIds.length > 0 && /* @__PURE__ */ jsx(Section, { label: "Recent", children: recentIds.map((m) => /* @__PURE__ */ jsx(
233
187
  ModelRow,
234
188
  {
@@ -558,7 +512,7 @@ function BillingDashboard({
558
512
  }
559
513
 
560
514
  // src/dashboard/pricing-page.tsx
561
- import { Check, Zap as Zap2 } from "lucide-react";
515
+ import { Check, Zap } from "lucide-react";
562
516
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
563
517
  function formatPrice(cents) {
564
518
  if (!Number.isFinite(cents) || cents < 0) return "$0";
@@ -622,7 +576,7 @@ function PricingPage({
622
576
  ),
623
577
  children: [
624
578
  isRecommended && /* @__PURE__ */ jsx3("div", { className: "absolute -top-4 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsxs3("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-primary px-4 py-1.5 text-xs font-bold text-primary-foreground shadow-sm", children: [
625
- /* @__PURE__ */ jsx3(Zap2, { className: "h-3 w-3" }),
579
+ /* @__PURE__ */ jsx3(Zap, { className: "h-3 w-3" }),
626
580
  "Most Popular"
627
581
  ] }) }),
628
582
  isCurrentTier && !isRecommended && /* @__PURE__ */ jsx3("div", { className: "absolute -top-4 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx3("span", { className: "inline-flex items-center rounded-full bg-muted border border-border px-4 py-1.5 text-xs font-bold text-foreground", children: "Current Plan" }) }),
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, h as ModelPreset, P as PricingPage, i as PricingPageProps, j as PricingTier, T as TemplateCard, k as TemplateCardData, l as TemplateCardProps, U as UsageChart, m as UsageChartProps, n as UsageDataPoint, o as canonicalModelId, p as formatContext, q as formatPrice, r as formatPricing } from './template-card-DStb8boW.js';
3
+ export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, P as PricingPage, h as PricingPageProps, i as PricingTier, T as TemplateCard, j as TemplateCardData, k as TemplateCardProps, U as UsageChart, l as UsageChartProps, m as UsageDataPoint, n as canonicalModelId, o as formatContext, p as formatPrice, q as formatPricing } from './template-card-Dufxl4hV.js';
4
4
 
5
5
  interface SidebarUser {
6
6
  email: string;
package/dist/dashboard.js CHANGED
@@ -55,7 +55,7 @@ import {
55
55
  formatContext,
56
56
  formatPrice,
57
57
  formatPricing
58
- } from "./chunk-EHMKLMMU.js";
58
+ } from "./chunk-27X3DWMO.js";
59
59
  import "./chunk-7ZA5SEK3.js";
60
60
  import "./chunk-EI44GEQ5.js";
61
61
  export {
package/dist/globals.css CHANGED
@@ -1922,6 +1922,9 @@
1922
1922
  .underline {
1923
1923
  text-decoration-line: underline;
1924
1924
  }
1925
+ .underline-offset-2 {
1926
+ text-underline-offset: 2px;
1927
+ }
1925
1928
  .opacity-0 {
1926
1929
  opacity: 0%;
1927
1930
  }
@@ -2397,6 +2400,11 @@
2397
2400
  border-color: transparent;
2398
2401
  }
2399
2402
  }
2403
+ .focus\:underline {
2404
+ &:focus {
2405
+ text-decoration-line: underline;
2406
+ }
2407
+ }
2400
2408
  .focus\:ring-0 {
2401
2409
  &:focus {
2402
2410
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { ExpandedToolDetail, ExpandedToolDetailProps, InlineThinkingItem, Inline
9
9
  export { CommandPreview, DiffPreview, GlobResultsPreview, GrepResultsPreview, QuestionPreview, WebSearchPreview, WriteFilePreview } from '@tangle-network/ui/tool-previews';
10
10
  export { FileArtifactPane, FileArtifactPaneProps, FileNode, FilePreview, FilePreviewProps, FileTabData, FileTabs, FileTabsProps, FileTree, FileTreeProps, FileTreeVisibilityOptions, RichFileTree, RichFileTreeGitEntry, RichFileTreeGitStatus, RichFileTreeProps, RichFileTreeThemeVars, filterFileTree } from '@tangle-network/ui/files';
11
11
  export { Backend, BackendConfig, BackendConfigProps, BackendSelector, BackendSelectorProps, BackendStatusData, ClusterStatusBar, ClusterStatusBarProps, ClusterStatusItem, CreditBalance, CreditBalanceProps, DashboardLayout, DashboardLayoutProps, DashboardProfile, DashboardSnapshotInfo, DashboardUser, ExposedPort, GitCommitData, GitPanel, GitPanelProps, GitStatusData, HARNESS_OPTIONS, HarnessPicker, HarnessPickerProps, HarnessType, InfoPanel, InfoPanelProps, Invoice, InvoiceTable, InvoiceTableProps, McpServer, NavItem, NetworkConfig, NetworkConfigData, NetworkConfigProps, NewSandboxCard, NewSandboxCardProps, PlanCardData, PlanCards, PlanCardsProps, PlanFeature, PortsList, PortsListProps, ProcessInfo, ProcessList, ProcessListProps, ProductVariant, ProfileAvatar, ProfileAvatarProps, ProfileComparison, ProfileComparisonProps, ProfileSelector, ProfileSelectorProps, PromoBanner, PromoBannerProps, RailButton, RailButtonProps, RailModeButton, RailModeButtonProps, RailSeparator, RailSeparatorProps, ResourceMeter, ResourceMeterProps, SIDEBAR_MOBILE_WIDTH, SIDEBAR_PANEL_WIDTH, SIDEBAR_RAIL_WIDTH, SIDEBAR_TOTAL_WIDTH, SandboxCard, SandboxCardData, SandboxCardProps, SandboxStatus, SandboxTable, SandboxTableProps, Sidebar, SidebarContent, SidebarContentProps, SidebarPanel, SidebarPanelContent, SidebarPanelContentProps, SidebarPanelHeader, SidebarPanelHeaderProps, SidebarPanelProps, SidebarProps, SidebarProvider, SidebarProviderProps, SidebarRail, SidebarRailFooter, SidebarRailFooterProps, SidebarRailHeader, SidebarRailHeaderProps, SidebarRailNav, SidebarRailNavProps, SidebarRailProps, SidebarUser, SnapshotList, SnapshotListProps, SystemLogsViewer, SystemLogsViewerProps, TeamRole, UsageSummary, UsageSummaryData, UsageSummaryProps, Variant, VariantList, VariantListProps, VariantOutcome, VariantStatus, canAdminSandbox, useSidebar } from './dashboard.js';
12
- export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, h as ModelPreset, P as PricingPage, i as PricingPageProps, j as PricingTier, T as TemplateCard, k as TemplateCardData, l as TemplateCardProps, U as UsageChart, m as UsageChartProps, n as UsageDataPoint, o as canonicalModelId, p as formatContext, q as formatPrice, r as formatPricing } from './template-card-DStb8boW.js';
12
+ export { B as BillingBalance, a as BillingDashboard, b as BillingDashboardProps, c as BillingSubscription, d as BillingUsage, M as ModelInfo, e as ModelPicker, f as ModelPickerProps, g as ModelPickerVariant, P as PricingPage, h as PricingPageProps, i as PricingTier, T as TemplateCard, j as TemplateCardData, k as TemplateCardProps, U as UsageChart, l as UsageChartProps, m as UsageDataPoint, n as canonicalModelId, o as formatContext, p as formatPrice, q as formatPricing } from './template-card-Dufxl4hV.js';
13
13
  export { AuthHeader, AuthHeaderProps, GitHubLoginButton, GitHubLoginButtonProps, LoginLayout, LoginLayoutProps, SessionUser, UserMenu, UserMenuProps } from '@tangle-network/ui/auth';
14
14
  export { AgentStreamEvent, AppendUserMessageOptions, ApplySdkEventOptions, AuthUser, AutomationStreamEvent, BeginAssistantMessageOptions, BotStreamEvent, CompleteAssistantMessageOptions, RealtimeSessionOptions, RealtimeSessionRegistry, RealtimeSessionRegistryProps, RealtimeSessionState, RealtimeSessionTarget, SSEEvent, SdkSessionAttachment, SdkSessionEvent, SdkSessionSeed, TaskStreamEvent, TerminalStreamEvent, UseAuthOptions, UseAuthResult, UseRunGroupsOptions, UseSSEStreamOptions, UseSSEStreamResult, UseSdkSessionOptions, UseSdkSessionReturn, UseToolCallStreamReturn, createAuthFetcher, useApiKey, useAuth, useAutoScroll, useDropdownMenu, useLiveTime, useRealtimeSession, useRunCollapseState, useRunGroups, useSSEStream, useSdkSession, useToolCallStream } from '@tangle-network/ui/hooks';
15
15
  export { SandboxMetrics, SidecarMetricsPayload, UsePtySessionOptions, UsePtySessionReturn, UseSandboxMetricsOptions, UseSandboxMetricsResult, useCreateSession, useDeleteSession, usePtySession, useRenameSession, useSandboxMetrics, useSessions } from './hooks.js';
package/dist/index.js CHANGED
@@ -200,7 +200,7 @@ import {
200
200
  formatContext,
201
201
  formatPrice,
202
202
  formatPricing
203
- } from "./chunk-EHMKLMMU.js";
203
+ } from "./chunk-27X3DWMO.js";
204
204
  import {
205
205
  Avatar,
206
206
  AvatarFallback,
package/dist/pages.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { c as BillingSubscription, B as BillingBalance, d as BillingUsage, n as UsageDataPoint, j as PricingTier, M as ModelInfo, k as TemplateCardData } from './template-card-DStb8boW.js';
2
+ import { c as BillingSubscription, B as BillingBalance, d as BillingUsage, m as UsageDataPoint, i as PricingTier, M as ModelInfo, j as TemplateCardData } from './template-card-Dufxl4hV.js';
3
3
  import * as React from 'react';
4
4
 
5
5
  type ProductVariant$1 = "sandbox";
@@ -85,6 +85,28 @@ interface ProvisioningWizardProps {
85
85
  * disabled trigger with "no models available" copy.
86
86
  */
87
87
  models?: ModelInfo[];
88
+ /**
89
+ * Canonical model ids to surface in the picker's "Popular" section.
90
+ * Forwarded straight to ModelPicker. Use this to surface a curated set
91
+ * of common models (e.g. one per provider/tier) without imposing a
92
+ * Fast/Balanced/Best taxonomy.
93
+ */
94
+ popular?: ReadonlyArray<string>;
95
+ /**
96
+ * The user's saved preferred model id (canonical, e.g.
97
+ * "openai/gpt-5.4"). Used as the initial `modelTier` when
98
+ * `defaultConfig.modelTier` isn't set, and as the next-best fallback
99
+ * when the current selection drops out of the loaded model list.
100
+ * Persistence is the caller's responsibility.
101
+ */
102
+ defaultModel?: string | null;
103
+ /**
104
+ * Persist the current `modelTier` as the user's default. When provided,
105
+ * the wizard renders a "Save as default" affordance under the model
106
+ * picker. The wizard does not store anything itself — the caller owns
107
+ * persistence (e.g. localStorage, account settings API).
108
+ */
109
+ onSetDefault?: (modelId: string) => void;
88
110
  /** Real pricing rates from the API for accurate cost calculation */
89
111
  pricingRates?: PricingRates;
90
112
  /**
@@ -119,7 +141,7 @@ interface ProvisioningConfig {
119
141
  startupScriptIds?: string[];
120
142
  }
121
143
  declare function resolveEnvironment(env: EnvironmentEntry): EnvironmentOption;
122
- declare function ProvisioningWizard({ environments: environmentsProp, onLoadEnvironments, onSubmit, onBack, className, variant, defaultEnvironment, defaultConfig, skipToReview, onLoadStartupScripts, resourceLimits, models, pricingRates, planTiers, }: ProvisioningWizardProps): react_jsx_runtime.JSX.Element;
144
+ declare function ProvisioningWizard({ environments: environmentsProp, onLoadEnvironments, onSubmit, onBack, className, variant, defaultEnvironment, defaultConfig, skipToReview, onLoadStartupScripts, resourceLimits, models, popular, defaultModel, onSetDefault, pricingRates, planTiers, }: ProvisioningWizardProps): react_jsx_runtime.JSX.Element;
123
145
 
124
146
  type ProductVariant = "sandbox";
125
147
  interface StandalonePricingPageProps {
package/dist/pages.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  TemplateCard,
7
7
  UsageChart,
8
8
  canonicalModelId
9
- } from "./chunk-EHMKLMMU.js";
9
+ } from "./chunk-27X3DWMO.js";
10
10
  import {
11
11
  cn
12
12
  } from "./chunk-EI44GEQ5.js";
@@ -452,6 +452,9 @@ function ProvisioningWizard({
452
452
  onLoadStartupScripts,
453
453
  resourceLimits,
454
454
  models,
455
+ popular,
456
+ defaultModel,
457
+ onSetDefault,
455
458
  pricingRates,
456
459
  planTiers
457
460
  }) {
@@ -537,7 +540,9 @@ function ProvisioningWizard({
537
540
  (prev) => snapSliderValue(prev, STORAGE_MIN, storageMax, storageStep)
538
541
  );
539
542
  }, [cpuMax, ramMax, storageMax, cpuStep, ramStep, storageStep]);
540
- const [modelTier, setModelTier] = React2.useState(dc?.modelTier ?? "");
543
+ const [modelTier, setModelTier] = React2.useState(
544
+ dc?.modelTier ?? defaultModel ?? ""
545
+ );
541
546
  const [systemPrompt, setSystemPrompt] = React2.useState(
542
547
  dc?.systemPrompt ?? ""
543
548
  );
@@ -545,9 +550,9 @@ function ProvisioningWizard({
545
550
  if (!models || models.length === 0) return;
546
551
  const ids = models.map(canonicalModelId);
547
552
  if (ids.includes(modelTier)) return;
548
- const next = ids[0];
553
+ const next = (defaultModel && ids.includes(defaultModel) ? defaultModel : void 0) ?? popular?.find((p) => ids.includes(p)) ?? ids[0];
549
554
  if (next && next !== modelTier) setModelTier(next);
550
- }, [models, modelTier]);
555
+ }, [models, modelTier, defaultModel, popular]);
551
556
  const [name, setName] = React2.useState(dc?.name ?? "");
552
557
  const [gitUrl, setGitUrl] = React2.useState(dc?.gitUrl ?? "");
553
558
  const [envVars, setEnvVars] = React2.useState(dc?.envVars ?? [{ key: "", value: "" }]);
@@ -951,8 +956,17 @@ function ProvisioningWizard({
951
956
  models: models ?? [],
952
957
  loading: !models,
953
958
  disabled: !models || models.length === 0,
959
+ popular,
954
960
  triggerClassName: "rounded-xl h-12 px-4 font-bold"
955
961
  }
962
+ ),
963
+ onSetDefault && /* @__PURE__ */ jsx2(
964
+ SaveAsDefault,
965
+ {
966
+ modelTier,
967
+ defaultModel: defaultModel ?? null,
968
+ onSetDefault
969
+ }
956
970
  )
957
971
  ] }),
958
972
  /* @__PURE__ */ jsxs2("div", { children: [
@@ -1347,6 +1361,36 @@ function ProvisioningWizard({
1347
1361
  ] })
1348
1362
  ] });
1349
1363
  }
1364
+ function SaveAsDefault({
1365
+ modelTier,
1366
+ defaultModel,
1367
+ onSetDefault
1368
+ }) {
1369
+ const isCurrentDefault = Boolean(modelTier) && modelTier === defaultModel;
1370
+ const disabled = !modelTier || isCurrentDefault;
1371
+ return /* @__PURE__ */ jsxs2("div", { className: "mt-2 flex items-center gap-2 text-xs text-muted-foreground", children: [
1372
+ /* @__PURE__ */ jsx2(
1373
+ "button",
1374
+ {
1375
+ type: "button",
1376
+ onClick: () => {
1377
+ if (!disabled) onSetDefault(modelTier);
1378
+ },
1379
+ disabled,
1380
+ className: cn(
1381
+ "underline-offset-2 transition-colors",
1382
+ disabled ? "cursor-default opacity-60" : "hover:text-foreground hover:underline focus:outline-none focus:text-foreground focus:underline"
1383
+ ),
1384
+ children: isCurrentDefault ? "\u2713 Saved as default" : "Save as default"
1385
+ }
1386
+ ),
1387
+ defaultModel && !isCurrentDefault && /* @__PURE__ */ jsxs2("span", { className: "truncate", children: [
1388
+ "(current default: ",
1389
+ /* @__PURE__ */ jsx2("span", { className: "font-mono", children: defaultModel }),
1390
+ ")"
1391
+ ] })
1392
+ ] });
1393
+ }
1350
1394
 
1351
1395
  // src/pages/pricing-page.tsx
1352
1396
  import * as React3 from "react";
package/dist/styles.css CHANGED
@@ -1922,6 +1922,9 @@
1922
1922
  .underline {
1923
1923
  text-decoration-line: underline;
1924
1924
  }
1925
+ .underline-offset-2 {
1926
+ text-underline-offset: 2px;
1927
+ }
1925
1928
  .opacity-0 {
1926
1929
  opacity: 0%;
1927
1930
  }
@@ -2397,6 +2400,11 @@
2397
2400
  border-color: transparent;
2398
2401
  }
2399
2402
  }
2403
+ .focus\:underline {
2404
+ &:focus {
2405
+ text-decoration-line: underline;
2406
+ }
2407
+ }
2400
2408
  .focus\:ring-0 {
2401
2409
  &:focus {
2402
2410
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
@@ -31,24 +31,6 @@ interface ModelInfo {
31
31
  output_modalities?: string[];
32
32
  };
33
33
  }
34
- /**
35
- * Curated preset bucket. Three are surfaced by default — they map to typical
36
- * cost/quality tradeoffs without forcing the consumer to pick a specific
37
- * model. `match` resolves the preset against the loaded model list.
38
- */
39
- interface ModelPreset {
40
- id: "fast" | "balanced" | "best" | string;
41
- label: string;
42
- hint: string;
43
- icon?: React.ComponentType<{
44
- className?: string;
45
- }>;
46
- /**
47
- * Pick the canonical model id for this preset given the loaded list.
48
- * Should return undefined if no acceptable model is loaded yet.
49
- */
50
- match: (models: ModelInfo[]) => string | undefined;
51
- }
52
34
  type ModelPickerVariant = "field" | "pill";
53
35
  interface ModelPickerProps {
54
36
  /** Canonical model id (provider-prefixed, e.g. "openai/gpt-5.4"). */
@@ -61,10 +43,12 @@ interface ModelPickerProps {
61
43
  /** Recently-used canonical ids to surface at the top. */
62
44
  recents?: ReadonlyArray<string>;
63
45
  /**
64
- * Curated presets shown above the full list. Defaults to Fast/Balanced/Best
65
- * resolved against common gpt-5/Claude families.
46
+ * Canonical model ids to surface in a "Popular" section above the full
47
+ * list. Each id is resolved against `models`; ids not present in the
48
+ * loaded catalog are silently skipped, so callers can pass a stable
49
+ * curation list without worrying about provider availability.
66
50
  */
67
- presets?: ReadonlyArray<ModelPreset>;
51
+ popular?: ReadonlyArray<string>;
68
52
  /** Drop providers from the picker entirely (e.g. "audio", "embedding"). */
69
53
  excludeProviders?: ReadonlyArray<string>;
70
54
  /** Restrict to these architectures (e.g. ["text"]). Default: all. */
@@ -94,7 +78,7 @@ declare function canonicalModelId(model: ModelInfo): string;
94
78
  declare function formatPricing(pricing: ModelInfo["pricing"]): string | null;
95
79
  /** Format context length compactly (e.g. 200_000 → "200k"). */
96
80
  declare function formatContext(ctx: number | undefined): string | null;
97
- declare function ModelPicker({ value, onChange, models, loading, recents, presets, excludeProviders, modalities, variant, label, placeholder, className, triggerClassName, disabled, }: ModelPickerProps): react_jsx_runtime.JSX.Element;
81
+ declare function ModelPicker({ value, onChange, models, loading, recents, popular, excludeProviders, modalities, variant, label, placeholder, className, triggerClassName, disabled, }: ModelPickerProps): react_jsx_runtime.JSX.Element;
98
82
 
99
83
  interface BillingSubscription {
100
84
  status: string;
@@ -180,4 +164,4 @@ interface TemplateCardProps {
180
164
  }
181
165
  declare function TemplateCard({ template, onUseTemplate, className }: TemplateCardProps): react_jsx_runtime.JSX.Element;
182
166
 
183
- export { type BillingBalance as B, type ModelInfo as M, PricingPage as P, TemplateCard as T, UsageChart as U, BillingDashboard as a, type BillingDashboardProps as b, type BillingSubscription as c, type BillingUsage as d, ModelPicker as e, type ModelPickerProps as f, type ModelPickerVariant as g, type ModelPreset as h, type PricingPageProps as i, type PricingTier as j, type TemplateCardData as k, type TemplateCardProps as l, type UsageChartProps as m, type UsageDataPoint as n, canonicalModelId as o, formatContext as p, formatPrice as q, formatPricing as r };
167
+ export { type BillingBalance as B, type ModelInfo as M, PricingPage as P, TemplateCard as T, UsageChart as U, BillingDashboard as a, type BillingDashboardProps as b, type BillingSubscription as c, type BillingUsage as d, ModelPicker as e, type ModelPickerProps as f, type ModelPickerVariant as g, type PricingPageProps as h, type PricingTier as i, type TemplateCardData as j, type TemplateCardProps as k, type UsageChartProps as l, type UsageDataPoint as m, canonicalModelId as n, formatContext as o, formatPrice as p, formatPricing as q };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/sandbox-ui",
3
- "version": "0.15.3",
3
+ "version": "0.15.4",
4
4
  "description": "Unified UI component library for Tangle Sandbox — primitives, chat, dashboard, terminal, editor, and workspace components",
5
5
  "repository": {
6
6
  "type": "git",