@iloveagents/foundry-web-ui 0.9.0 → 0.10.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.
@@ -3,8 +3,11 @@
3
3
  *
4
4
  * Sits in the composer next to Send. The choice rides on every request as
5
5
  * an AG-UI forwarded prop and is read at send time, so switching it
6
- * mid-conversation applies from the next message on. `Auto` sends nothing
7
- * and leaves the backend's configured level in place.
6
+ * mid-conversation applies from the next message on.
7
+ *
8
+ * `Auto` follows the backend's configured level and names it, so the user
9
+ * can always tell what they are actually running. An explicit level is a
10
+ * pin — nothing moves it, including a change of context.
8
11
  */
9
12
  export declare function ReasoningEffortPicker({ className }: {
10
13
  className?: string;
@@ -1,26 +1,50 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useStore } from "zustand";
3
3
  import { Check, ChevronDown } from "lucide-react";
4
- import { reasoningEffortStore, REASONING_EFFORT_LABELS, } from "@iloveagents/foundry-agent";
4
+ import { reasoningDefaultStore, reasoningEffortStore, REASONING_EFFORT_LABELS, } from "@iloveagents/foundry-agent";
5
5
  import { cn } from "@iloveagents/foundry-web-primitives";
6
6
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from "../ui/dropdown-menu.js";
7
7
  const OPTIONS = [
8
- { value: "default", hint: "Use the app's configured level" },
8
+ { value: "default", hint: "" }, // hint is resolved at render — see autoHint
9
9
  { value: "low", hint: "Answers sooner, thinks less" },
10
10
  { value: "medium", hint: "Good default for most questions" },
11
11
  { value: "high", hint: "Slower, better on hard problems" },
12
12
  { value: "xhigh", hint: "Slowest, for the hardest questions" },
13
13
  ];
14
+ /**
15
+ * What `Auto` is currently doing, in words.
16
+ *
17
+ * Never guesses. If the app has not told us what the backend resolves to,
18
+ * the hint says so rather than naming a level — an `Auto` that claims the
19
+ * wrong level is the exact failure this option is meant to avoid.
20
+ */
21
+ function autoHint(resolved, scope) {
22
+ if (!resolved)
23
+ return "Uses the app's configured level";
24
+ const where = scope ? ` for ${scope}` : "";
25
+ return `Currently ${REASONING_EFFORT_LABELS[resolved]}${where}`;
26
+ }
14
27
  /**
15
28
  * Lets the user choose how hard the model thinks, per conversation.
16
29
  *
17
30
  * Sits in the composer next to Send. The choice rides on every request as
18
31
  * an AG-UI forwarded prop and is read at send time, so switching it
19
- * mid-conversation applies from the next message on. `Auto` sends nothing
20
- * and leaves the backend's configured level in place.
32
+ * mid-conversation applies from the next message on.
33
+ *
34
+ * `Auto` follows the backend's configured level and names it, so the user
35
+ * can always tell what they are actually running. An explicit level is a
36
+ * pin — nothing moves it, including a change of context.
21
37
  */
22
38
  export function ReasoningEffortPicker({ className }) {
23
39
  const effort = useStore(reasoningEffortStore, (s) => s.effort);
24
40
  const setEffort = useStore(reasoningEffortStore, (s) => s.setEffort);
25
- return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("flex items-center gap-1 rounded-md px-2 py-1", "text-xs text-muted-foreground hover:text-foreground hover:bg-muted", "transition-colors", className), "aria-label": `Intelligence: ${REASONING_EFFORT_LABELS[effort]}`, children: [_jsx("span", { children: REASONING_EFFORT_LABELS[effort] }), _jsx(ChevronDown, { className: "size-3.5" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsx(DropdownMenuLabel, { className: "text-xs font-normal text-muted-foreground", children: "Intelligence" }), OPTIONS.map((opt) => (_jsxs(DropdownMenuItem, { onSelect: () => setEffort(opt.value), className: "flex items-start gap-2", children: [_jsx(Check, { className: cn("size-4 mt-0.5 shrink-0", effort === opt.value ? "opacity-100" : "opacity-0") }), _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm", children: REASONING_EFFORT_LABELS[opt.value] }), _jsx("span", { className: "text-xs text-muted-foreground", children: opt.hint })] })] }, opt.value)))] })] }));
41
+ const resolved = useStore(reasoningDefaultStore, (s) => s.resolved);
42
+ const scope = useStore(reasoningDefaultStore, (s) => s.scope);
43
+ // The trigger is the only thing visible without opening the menu, so it
44
+ // carries the resolved level too — "Auto · Medium" rather than a bare
45
+ // "Auto" that leaves the active level a mystery.
46
+ const triggerLabel = effort === "default" && resolved
47
+ ? `${REASONING_EFFORT_LABELS.default} · ${REASONING_EFFORT_LABELS[resolved]}`
48
+ : REASONING_EFFORT_LABELS[effort];
49
+ return (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn("flex items-center gap-1 rounded-md px-2 py-1", "text-xs text-muted-foreground hover:text-foreground hover:bg-muted", "transition-colors", className), "aria-label": `Intelligence: ${triggerLabel}`, children: [_jsx("span", { children: triggerLabel }), _jsx(ChevronDown, { className: "size-3.5" })] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [_jsx(DropdownMenuLabel, { className: "text-xs font-normal text-muted-foreground", children: "Intelligence" }), OPTIONS.map((opt) => (_jsxs(DropdownMenuItem, { onSelect: () => setEffort(opt.value), className: "flex items-start gap-2", children: [_jsx(Check, { className: cn("size-4 mt-0.5 shrink-0", effort === opt.value ? "opacity-100" : "opacity-0") }), _jsxs("span", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm", children: REASONING_EFFORT_LABELS[opt.value] }), _jsx("span", { className: "text-xs text-muted-foreground", children: opt.value === "default" ? autoHint(resolved, scope) : opt.hint })] })] }, opt.value)))] })] }));
26
50
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-web-ui",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "license": "MIT",
5
5
  "description": "React agent UI core for Foundry UI — chat, composer, AG-UI adapter for assistant-ui, tool cards, panels, sidebar, theme runtime, and UI stores.",
6
6
  "keywords": [
@@ -70,8 +70,8 @@
70
70
  "tailwind-merge": "^3.5.0",
71
71
  "react-markdown": "^10.0.0",
72
72
  "remark-gfm": "^4.0.0",
73
- "@iloveagents/foundry-agent": "^0.9.0",
74
- "@iloveagents/foundry-web-primitives": "^0.9.0"
73
+ "@iloveagents/foundry-agent": "^0.10.0",
74
+ "@iloveagents/foundry-web-primitives": "^0.10.0"
75
75
  },
76
76
  "devDependencies": {
77
77
  "@ag-ui/client": "^0.0.52",