@iloveagents/foundry-web-ui 0.8.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,25 +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
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "../ui/dropdown-menu.js";
6
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from "../ui/dropdown-menu.js";
7
7
  const OPTIONS = [
8
- { value: "default", hint: "Let the app decide" },
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
- { value: "high", hint: "Slower, best for hard problems" },
11
+ { value: "high", hint: "Slower, better on hard problems" },
12
+ { value: "xhigh", hint: "Slowest, for the hardest questions" },
12
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
+ }
13
27
  /**
14
28
  * Lets the user choose how hard the model thinks, per conversation.
15
29
  *
16
30
  * Sits in the composer next to Send. The choice rides on every request as
17
31
  * an AG-UI forwarded prop and is read at send time, so switching it
18
- * mid-conversation applies from the next message on. `Auto` sends nothing
19
- * 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.
20
37
  */
21
38
  export function ReasoningEffortPicker({ className }) {
22
39
  const effort = useStore(reasoningEffortStore, (s) => s.effort);
23
40
  const setEffort = useStore(reasoningEffortStore, (s) => s.setEffort);
24
- 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": `Thinking effort: ${REASONING_EFFORT_LABELS[effort]}`, children: [_jsx("span", { children: REASONING_EFFORT_LABELS[effort] }), _jsx(ChevronDown, { className: "size-3.5" })] }) }), _jsx(DropdownMenuContent, { align: "end", className: "w-56", children: 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", 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)))] })] }));
25
50
  }
@@ -16,7 +16,7 @@
16
16
  * @see https://docs.ag-ui.com/sdk/js/client/http-agent
17
17
  * @see https://www.assistant-ui.com/docs/runtimes/custom/local
18
18
  */
19
- import { AGUIRunner, clientToolRegistry, streamingStatusStore } from "@iloveagents/foundry-agent";
19
+ import { AGUIRunner, agentStateStore, clientToolRegistry, streamingStatusStore, } from "@iloveagents/foundry-agent";
20
20
  import { tokenFetch } from "@iloveagents/foundry-agent/msal";
21
21
  import { useAppStore } from "./app-store.js";
22
22
  import { useDevStore } from "./dev-store.js";
@@ -159,6 +159,20 @@ export class AGUIAdapterSDK {
159
159
  case "reasoning-end":
160
160
  shouldYield = true;
161
161
  break;
162
+ case "agent-state":
163
+ // Publish server state so pages can react to it. Not a chat
164
+ // message, so no yield.
165
+ agentStateStore.getState().setAgentState(event.state, event.patch);
166
+ break;
167
+ case "messages-snapshot":
168
+ case "activity":
169
+ case "raw":
170
+ // Protocol surfaces this adapter deliberately does not render:
171
+ // history reconciliation, generative-UI activities and provider
172
+ // passthrough belong to the host app, which can consume the
173
+ // RunnerEvent stream directly. Handled here so the switch stays
174
+ // exhaustive and they can never silently become "unknown".
175
+ break;
162
176
  case "step-started":
163
177
  case "step-finished":
164
178
  // Progress only — the status store already carries the step name
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iloveagents/foundry-web-ui",
3
- "version": "0.8.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.8.0",
74
- "@iloveagents/foundry-web-primitives": "^0.8.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",