@tangle-network/sandbox-ui 0.31.0 → 0.33.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/chat.d.ts CHANGED
@@ -1,20 +1,19 @@
1
1
  import { MessageRole } from '@tangle-network/ui/chat';
2
2
  export { AgentTimeline, AgentTimelineArtifactItem, AgentTimelineCustomItem, AgentTimelineItem, AgentTimelineMessageItem, AgentTimelineProps, AgentTimelineStatusItem, AgentTimelineTone, AgentTimelineToolGroupItem, AgentTimelineToolItem, ChatContainer, ChatContainerProps, ChatInput, ChatInputProps, ChatMessage, ChatMessageProps, MessageList, MessageListProps, MessageRole, PendingFile, ThinkingIndicator, ThinkingIndicatorProps, UserMessage, UserMessageProps } from '@tangle-network/ui/chat';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ReasoningEffort, HarnessType } from '@tangle-network/agent-interface';
4
5
  import * as React from 'react';
5
6
  import { M as ModelInfo } from './model-picker-Cmisf9Y8.js';
6
- import { e as HarnessType } from './harness-picker-lyeEncN4.js';
7
7
 
8
8
  /**
9
- * Thinking-effort ladder — the superset of the per-harness reasoning scales so
10
- * one control covers every backend. Consumers map each level onto what the
11
- * chosen harness/model supports (and degrade unsupported ones):
12
- * - OpenAI / Codex reasoning_effort: minimal · low · medium · high · xhigh
13
- * - Anthropic (Claude) extended thinking: … · high · max
14
- * - Claude Code: … · high · max · ultracode
15
- * - generic: low · medium · high
9
+ * A reasoning selection: `auto` is a UI-only sentinel ("let the harness/model default decide",
10
+ * sends no explicit override); every other value is the canonical `ReasoningEffort` from
11
+ * `@tangle-network/agent-interface` (the single source of truth — `none` … `ultracode`). The picker
12
+ * shows only the levels the chosen harness/model supports — see `reasoningEffortsFor` + the
13
+ * `available` prop — so unsupported levels (codex's `xhigh`/`ultracode`, kimi's mid-range) never
14
+ * appear rather than being silently degraded.
16
15
  */
17
- type ReasoningLevel = "auto" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | "ultracode";
16
+ type ReasoningLevel = "auto" | ReasoningEffort;
18
17
  interface ReasoningLevelOption {
19
18
  value: ReasoningLevel;
20
19
  label: string;
@@ -27,9 +26,16 @@ interface ReasoningLevelPickerProps {
27
26
  className?: string;
28
27
  triggerClassName?: string;
29
28
  options?: ReadonlyArray<ReasoningLevelOption>;
29
+ /**
30
+ * Capability filter — the reasoning efforts the currently-selected harness/model supports, from
31
+ * `reasoningEffortsFor(harness, model)`. When provided, the picker shows ONLY these (plus the
32
+ * `auto` sentinel), so a harness that can't do `ultracode`/`xhigh` (e.g. codex) never offers it.
33
+ * Omit to show every option.
34
+ */
35
+ available?: ReadonlyArray<ReasoningEffort>;
30
36
  }
31
37
  declare const DEFAULT_REASONING_LEVEL_OPTIONS: ReadonlyArray<ReasoningLevelOption>;
32
- declare function ReasoningLevelPicker({ value, onChange, disabled, className, triggerClassName, options, }: ReasoningLevelPickerProps): react_jsx_runtime.JSX.Element;
38
+ declare function ReasoningLevelPicker({ value, onChange, disabled, className, triggerClassName, options, available, }: ReasoningLevelPickerProps): react_jsx_runtime.JSX.Element;
33
39
 
34
40
  interface AgentSessionHarnessControl {
35
41
  value: HarnessType;
@@ -63,6 +69,11 @@ interface AgentSessionReasoningControl {
63
69
  onChange: (value: ReasoningLevel) => void;
64
70
  options?: ReadonlyArray<ReasoningLevelOption>;
65
71
  disabled?: boolean;
72
+ /**
73
+ * Reasoning efforts to offer when no harness is selected (e.g. a model-derived capability set).
74
+ * When a harness IS present the strip derives this from `reasoningEffortsFor(harness)` instead.
75
+ */
76
+ available?: ReadonlyArray<ReasoningEffort>;
66
77
  }
67
78
  interface AgentSessionControlsProps {
68
79
  /**
@@ -130,7 +141,7 @@ interface HarnessModelPolicy {
130
141
  */
131
142
  preferred: ReadonlyArray<RegExp>;
132
143
  }
133
- declare const HARNESS_MODEL_POLICIES: Record<HarnessType, HarnessModelPolicy>;
144
+ declare const HARNESS_MODEL_POLICIES: Partial<Record<HarnessType, HarnessModelPolicy>>;
134
145
  /** Provider prefix of a canonical id ("anthropic/claude-…" → "anthropic"). */
135
146
  declare function modelProvider(modelId: string): string | null;
136
147
  /**
package/dist/chat.js CHANGED
@@ -16,9 +16,9 @@ import {
16
16
  modelProvider,
17
17
  snapHarnessToModel,
18
18
  snapModelToHarness
19
- } from "./chunk-BJFWPP5T.js";
20
- import "./chunk-ELGN7DPS.js";
21
- import "./chunk-6NQBODYV.js";
19
+ } from "./chunk-AWYBQTP6.js";
20
+ import "./chunk-I64YISXS.js";
21
+ import "./chunk-NMR2CTGP.js";
22
22
  import "./chunk-EI44GEQ5.js";
23
23
  export {
24
24
  AgentSessionControls,
@@ -414,7 +414,7 @@ function UsageChart({ data, title, unit, className }) {
414
414
  onMouseEnter: () => setHoveredIndex(index),
415
415
  onMouseLeave: () => setHoveredIndex(null),
416
416
  children: [
417
- isHovered && /* @__PURE__ */ jsxs3("div", { className: "absolute -top-12 z-10 rounded-lg bg-popover px-3 py-1.5 text-sm shadow-lg", children: [
417
+ isHovered && /* @__PURE__ */ jsxs3("div", { className: "absolute -top-12 z-10 rounded-lg border border-border bg-popover px-3 py-1.5 text-sm shadow-[var(--shadow-dropdown)]", children: [
418
418
  /* @__PURE__ */ jsxs3("p", { className: "font-medium", children: [
419
419
  formatValue(point.value),
420
420
  " ",
@@ -490,7 +490,7 @@ function TemplateCard({ template, onUseTemplate, className }) {
490
490
  "div",
491
491
  {
492
492
  className: cn(
493
- "group relative flex flex-col justify-between rounded-2xl border border-border bg-card p-6 transition-all hover:border-primary/30 hover:shadow-md",
493
+ "group relative flex flex-col justify-between rounded-xl border border-border bg-card p-6 transition-colors hover:border-[var(--border-accent)]",
494
494
  className
495
495
  ),
496
496
  children: [
@@ -1048,7 +1048,7 @@ function SessionSidebar({
1048
1048
  className: cn("relative flex shrink-0 flex-col border-r border-border bg-card", className),
1049
1049
  style: { width: resizable ? resize.width : defaultWidth },
1050
1050
  children: [
1051
- /* @__PURE__ */ jsx7("div", { className: "flex h-14 shrink-0 items-center border-b border-border px-3", children: /* @__PURE__ */ jsxs7("div", { className: "flex w-full items-center justify-between gap-2", children: [
1051
+ /* @__PURE__ */ jsx7("div", { className: "flex shrink-0 items-center border-b border-border bg-muted/20 px-3 py-1.5", children: /* @__PURE__ */ jsxs7("div", { className: "flex w-full items-center justify-between gap-2", children: [
1052
1052
  /* @__PURE__ */ jsxs7("div", { className: "flex min-w-0 items-center gap-2", children: [
1053
1053
  /* @__PURE__ */ jsx7("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-[var(--border-accent)] bg-[var(--accent-surface-soft)] text-primary", children: /* @__PURE__ */ jsx7(MessageSquareText, { className: "h-3.5 w-3.5" }) }),
1054
1054
  /* @__PURE__ */ jsxs7("div", { className: "min-w-0", children: [
@@ -1080,7 +1080,7 @@ function SessionSidebar({
1080
1080
  onChange: (event) => setQuery(event.target.value),
1081
1081
  placeholder: searchPlaceholder,
1082
1082
  "aria-label": searchPlaceholder,
1083
- className: "h-8 w-full rounded-[var(--radius-sm)] border border-border bg-muted pl-7 pr-2 text-sm text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-accent)]"
1083
+ className: "h-8 w-full rounded-[var(--radius-sm)] border border-transparent bg-muted/40 pl-7 pr-2 text-sm text-foreground placeholder:text-muted-foreground transition-colors focus-visible:border-[var(--border-accent)] focus-visible:bg-transparent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[var(--border-accent)]"
1084
1084
  }
1085
1085
  )
1086
1086
  ] }),
@@ -1104,20 +1104,23 @@ function SessionSidebar({
1104
1104
  );
1105
1105
  }) })
1106
1106
  ] }),
1107
- /* @__PURE__ */ jsx7("nav", { "aria-label": "Sessions", className: "flex-1 overflow-y-auto px-1.5 py-1.5", children: visibleItems.length === 0 ? /* @__PURE__ */ jsx7("div", { className: "rounded-[var(--radius-lg)] border border-dashed border-border px-3 py-3 text-sm text-muted-foreground", children: query.trim() ? `No sessions match "${query.trim()}".` : emptyMessage }) : /* @__PURE__ */ jsx7("ul", { className: "space-y-px", children: visibleItems.map((item) => {
1107
+ /* @__PURE__ */ jsx7("nav", { "aria-label": "Sessions", className: "flex-1 overflow-y-auto px-1.5 py-1.5", children: visibleItems.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center gap-2 px-4 py-10 text-center text-sm text-muted-foreground", children: [
1108
+ /* @__PURE__ */ jsx7(MessageSquareText, { className: "h-5 w-5 opacity-50", "aria-hidden": "true" }),
1109
+ /* @__PURE__ */ jsx7("p", { children: query.trim() ? `No sessions match "${query.trim()}".` : emptyMessage })
1110
+ ] }) : /* @__PURE__ */ jsx7("ul", { className: "space-y-px", children: visibleItems.map((item) => {
1108
1111
  const session = sessionsById.get(item.id) ?? null;
1109
1112
  const isActive = currentItemId === item.id;
1110
1113
  const status = session?.status ?? item.status;
1111
1114
  const visibleBadges = [
1112
- ...item.isPinned ? [{ id: `${item.id}-pinned`, label: "Pinned", tone: "accent" }] : [],
1115
+ ...item.isPinned ? [{ id: `${item.id}-pinned`, label: "Pinned", tone: "neutral" }] : [],
1113
1116
  ...item.badges ?? []
1114
1117
  ];
1115
- return /* @__PURE__ */ jsx7("li", { children: /* @__PURE__ */ jsxs7(
1118
+ return /* @__PURE__ */ jsx7("li", { className: "animate-row-in", children: /* @__PURE__ */ jsxs7(
1116
1119
  "div",
1117
1120
  {
1118
1121
  className: cn(
1119
- "group relative flex items-center gap-2 rounded-[var(--radius-sm)] px-3 py-2 transition-colors",
1120
- isActive ? "bg-primary/10 font-medium text-foreground" : "text-muted-foreground hover:bg-accent/30"
1122
+ "group relative flex items-center gap-2 rounded-[var(--radius-sm)] px-2.5 py-1.5 transition-colors",
1123
+ isActive ? "bg-accent font-medium text-foreground" : "text-muted-foreground hover:bg-accent/30"
1121
1124
  ),
1122
1125
  children: [
1123
1126
  /* @__PURE__ */ jsxs7(
@@ -1157,7 +1160,7 @@ function SessionSidebar({
1157
1160
  },
1158
1161
  badge.id
1159
1162
  )),
1160
- session?.isForeground && /* @__PURE__ */ jsx7("span", { className: "h-1.5 w-1.5 rounded-full bg-primary animate-pulse", title: "Live" }),
1163
+ session?.isForeground && /* @__PURE__ */ jsx7("span", { className: "h-1.5 w-1.5 rounded-full bg-[var(--status-running)]", title: "Live" }),
1161
1164
  renderItemActions ? /* @__PURE__ */ jsx7(
1162
1165
  "div",
1163
1166
  {
@@ -2,11 +2,11 @@ import {
2
2
  HARNESS_OPTIONS,
3
3
  HarnessLogo,
4
4
  chatCapableHarnesses
5
- } from "./chunk-ELGN7DPS.js";
5
+ } from "./chunk-I64YISXS.js";
6
6
  import {
7
7
  ModelPicker,
8
8
  canonicalModelId
9
- } from "./chunk-6NQBODYV.js";
9
+ } from "./chunk-NMR2CTGP.js";
10
10
  import {
11
11
  cn
12
12
  } from "./chunk-EI44GEQ5.js";
@@ -23,18 +23,11 @@ import {
23
23
  } from "@tangle-network/ui/chat";
24
24
 
25
25
  // src/chat/reasoning-level-picker.tsx
26
+ import { reasoningLadder } from "@tangle-network/agent-interface";
26
27
  import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
27
28
  import { Brain, ChevronDown, Sparkles } from "lucide-react";
28
29
  import { jsx, jsxs } from "react/jsx-runtime";
29
- var REASONING_LADDER = [
30
- "minimal",
31
- "low",
32
- "medium",
33
- "high",
34
- "xhigh",
35
- "max",
36
- "ultracode"
37
- ];
30
+ var REASONING_LADDER = reasoningLadder;
38
31
  function ReasoningGlyph({ level }) {
39
32
  if (level === "auto") {
40
33
  return /* @__PURE__ */ jsx(Sparkles, { className: "h-3.5 w-3.5 text-muted-foreground" });
@@ -64,13 +57,13 @@ function ReasoningGlyph({ level }) {
64
57
  }
65
58
  var DEFAULT_REASONING_LEVEL_OPTIONS = [
66
59
  { value: "auto", label: "Auto", description: "Let the agent pick the right depth." },
67
- { value: "minimal", label: "Minimal", description: "Almost no deliberation \u2014 fastest, cheapest." },
60
+ { value: "none", label: "None", description: "No extended thinking \u2014 fastest, cheapest." },
61
+ { value: "minimal", label: "Minimal", description: "Thinking on, lowest budget." },
68
62
  { value: "low", label: "Low", description: "Fast, direct answers." },
69
63
  { value: "medium", label: "Medium", description: "Inspect context before acting." },
70
64
  { value: "high", label: "High", description: "Deeper planning and edge-case checks." },
71
65
  { value: "xhigh", label: "Extra High", description: "Extended reasoning for hard problems (Codex/OpenAI)." },
72
- { value: "max", label: "Max", description: "Maximum extended thinking budget (Claude)." },
73
- { value: "ultracode", label: "Ultracode", description: "Exhaustive multi-pass reasoning (Claude Code)." }
66
+ { value: "ultracode", label: "Ultracode", description: "Maximum extended thinking (Claude Code's ultracode)." }
74
67
  ];
75
68
  function ReasoningLevelPicker({
76
69
  value,
@@ -78,9 +71,11 @@ function ReasoningLevelPicker({
78
71
  disabled,
79
72
  className,
80
73
  triggerClassName,
81
- options = DEFAULT_REASONING_LEVEL_OPTIONS
74
+ options = DEFAULT_REASONING_LEVEL_OPTIONS,
75
+ available
82
76
  }) {
83
- const selected = options.find((option) => option.value === value);
77
+ const shown = available ? options.filter((o) => o.value === "auto" || available.includes(o.value)) : options;
78
+ const selected = shown.find((option) => option.value === value);
84
79
  const label = selected?.label ?? "Auto";
85
80
  return /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
86
81
  /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
@@ -91,8 +86,8 @@ function ReasoningLevelPicker({
91
86
  className: cn(
92
87
  "inline-flex h-8 items-center gap-1.5 rounded-lg border border-border bg-card px-2.5",
93
88
  "text-xs font-medium text-foreground shadow-sm transition-colors",
94
- "hover:border-primary/30 hover:bg-accent/30 focus:outline-none focus:border-primary/40",
95
- "data-[state=open]:border-primary/40 data-[state=open]:bg-accent/30",
89
+ "hover:border-border hover:bg-muted/40 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
90
+ "data-[state=open]:border-border data-[state=open]:bg-muted/40",
96
91
  "disabled:cursor-not-allowed disabled:opacity-50",
97
92
  className,
98
93
  triggerClassName
@@ -117,7 +112,7 @@ function ReasoningLevelPicker({
117
112
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
118
113
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95"
119
114
  ),
120
- children: options.map((option) => /* @__PURE__ */ jsxs(
115
+ children: shown.map((option) => /* @__PURE__ */ jsxs(
121
116
  DropdownMenu.Item,
122
117
  {
123
118
  onSelect: (event) => {
@@ -145,6 +140,7 @@ function ReasoningLevelPicker({
145
140
  }
146
141
 
147
142
  // src/chat/agent-session-controls.tsx
143
+ import { reasoningEffortsFor } from "@tangle-network/agent-interface";
148
144
  import * as DropdownMenu2 from "@radix-ui/react-dropdown-menu";
149
145
  import { ChevronDown as ChevronDown2, Lock, SlidersHorizontal } from "lucide-react";
150
146
 
@@ -200,6 +196,7 @@ function snapModelToHarness(harness, modelId, models) {
200
196
  if (isModelCompatibleWithHarness(harness, modelId)) return modelId;
201
197
  const ids = models.map(canonicalModelId);
202
198
  const policy = HARNESS_MODEL_POLICIES[harness];
199
+ if (!policy) return modelId;
203
200
  for (const pattern of policy.preferred) {
204
201
  const matches = ids.filter((id) => pattern.test(id)).sort((a, b) => numericDesc.compare(b, a));
205
202
  if (matches.length > 0) return matches[0];
@@ -242,8 +239,8 @@ function HarnessDropdown({
242
239
  className: cn(
243
240
  "inline-flex h-8 items-center gap-1.5 rounded-lg border border-border bg-card px-2.5",
244
241
  "text-xs font-medium text-foreground shadow-sm transition-colors",
245
- "hover:border-primary/30 hover:bg-accent/40 focus:outline-none focus:border-primary/40",
246
- "data-[state=open]:border-primary/40 data-[state=open]:bg-accent/40",
242
+ "hover:border-border hover:bg-muted/40 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
243
+ "data-[state=open]:border-border data-[state=open]:bg-muted/40",
247
244
  "disabled:cursor-not-allowed disabled:opacity-60"
248
245
  ),
249
246
  "aria-label": "Agent harness",
@@ -356,7 +353,8 @@ function AgentSessionControls({
356
353
  value: reasoning.value,
357
354
  onChange: reasoning.onChange,
358
355
  options: reasoning.options,
359
- disabled: reasoning.disabled
356
+ disabled: reasoning.disabled,
357
+ available: harness ? reasoningEffortsFor(harness.value) : reasoning.available
360
358
  }
361
359
  );
362
360
  if (layout === "gear") {
@@ -408,8 +406,8 @@ function GearControls({
408
406
  className: cn(
409
407
  "inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border bg-card",
410
408
  "text-foreground shadow-sm transition-colors",
411
- "hover:border-primary/30 hover:bg-accent/40 focus:outline-none focus:border-primary/40",
412
- "data-[state=open]:border-primary/40 data-[state=open]:bg-accent/40"
409
+ "hover:border-border hover:bg-muted/40 focus:outline-none focus-visible:ring-1 focus-visible:ring-ring",
410
+ "data-[state=open]:border-border data-[state=open]:bg-muted/40"
413
411
  ),
414
412
  children: /* @__PURE__ */ jsx2(SlidersHorizontal, { className: "h-4 w-4 text-muted-foreground" })
415
413
  }
@@ -631,14 +629,14 @@ function ArtifactAgentDock({
631
629
  "aside",
632
630
  {
633
631
  className: cn(
634
- "flex h-full w-[420px] min-w-[360px] max-w-[480px] flex-col border-l border-border bg-card/95 shadow-xl",
632
+ "flex h-full w-[420px] min-w-[360px] max-w-[480px] flex-col border-l border-border bg-card/95 shadow-[var(--shadow-dropdown)]",
635
633
  className
636
634
  ),
637
635
  "aria-label": `Agent chat about ${heading}`,
638
636
  children: [
639
637
  /* @__PURE__ */ jsxs3("header", { className: "flex items-center justify-between border-b border-border bg-background/60 px-4 py-3", children: [
640
638
  /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2", children: [
641
- /* @__PURE__ */ jsx3(Sparkles2, { className: "h-4 w-4 shrink-0 text-primary" }),
639
+ /* @__PURE__ */ jsx3(Sparkles2, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
642
640
  /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
643
641
  /* @__PURE__ */ jsx3("div", { className: "text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: "Discussing" }),
644
642
  /* @__PURE__ */ jsx3("div", { className: "truncate text-sm font-semibold text-foreground", children: heading })
@@ -690,7 +688,7 @@ function ArtifactAgentDock({
690
688
  placeholder: `Ask about ${heading}\u2026`,
691
689
  rows: 2,
692
690
  disabled: !threadId,
693
- className: "min-h-[44px] flex-1 resize-none rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary/40 disabled:opacity-50"
691
+ className: "min-h-[44px] flex-1 resize-none rounded-[20px] border border-border bg-background px-3.5 py-2 text-sm text-foreground placeholder:text-muted-foreground transition-colors focus:outline-none focus:border-[var(--border-accent)] disabled:opacity-50"
694
692
  }
695
693
  ),
696
694
  sending ? /* @__PURE__ */ jsx3(
@@ -708,7 +706,7 @@ function ArtifactAgentDock({
708
706
  type: "submit",
709
707
  disabled: !composer.trim() || !threadId,
710
708
  "aria-label": "Send",
711
- className: "inline-flex h-9 w-9 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50",
709
+ className: "inline-flex h-9 w-9 items-center justify-center rounded-full bg-primary text-primary-foreground transition-colors hover:bg-primary/90 disabled:opacity-50",
712
710
  children: /* @__PURE__ */ jsx3(Send, { className: "h-4 w-4" })
713
711
  }
714
712
  )