@tangle-network/agent-app 0.45.37 → 0.45.39

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.
@@ -231,6 +231,39 @@ interface EffortLevel {
231
231
  label: string;
232
232
  }
233
233
  declare const DEFAULT_EFFORT_LEVELS: readonly EffortLevel[];
234
+ /**
235
+ * The user-facing label for an engine level id: the canonical vocabulary when
236
+ * the id is one this package names, otherwise the id itself made readable
237
+ * (`auto` -> "Auto", `ultra-code` -> "Ultra code"). Never invents a depth word,
238
+ * so an id nobody declared a label for still reads as ITSELF and never as some
239
+ * other level.
240
+ */
241
+ declare function effortLevelLabel(id: string): string;
242
+ /**
243
+ * Build a levels list from the engine ids a backend applies — the shape the
244
+ * removed `ComposerAgentControls` took as `reasoning.available`, so a product
245
+ * migrating that list has one call to make instead of a hand-written label map
246
+ * per product (which is how "Quick" and "Low" drift apart across surfaces).
247
+ */
248
+ declare function effortLevelsFromIds(ids: readonly string[]): readonly EffortLevel[];
249
+ /**
250
+ * The list {@link EffortPicker} RENDERS for `value` — the declared levels, plus
251
+ * `value` itself when the declaration omits it.
252
+ *
253
+ * A picker cannot honestly resolve a selected value it was not given, and the
254
+ * failure it used to take instead — fall back to the middle entry — renders the
255
+ * session's real depth as a DIFFERENT level's name. That is exactly the defect
256
+ * `levels` was added to prevent: the legacy adapter's `available` list excluded
257
+ * the `auto` sentinel because the old picker injected it, so a product mapping
258
+ * that list straight across ships a session running on `auto` labelled
259
+ * "Extended". Admitting the value is not offering a new choice — it is
260
+ * reporting the state the session is already in, and it disappears from the
261
+ * list as soon as the user picks a declared level.
262
+ *
263
+ * A blank value is not admitted (there is no honest label for it); the picker
264
+ * renders no selection instead.
265
+ */
266
+ declare function reconcileEffortLevels(value: string, levels?: readonly EffortLevel[]): readonly EffortLevel[];
234
267
  /** Segments the meter draws — fixed geometry so the ladder stays tabular
235
268
  * across levels (and across the trigger and its menu rows). */
236
269
  declare const EFFORT_METER_SEGMENTS = 4;
@@ -256,7 +289,12 @@ interface EffortPickerProps {
256
289
  onChange: (id: string) => void;
257
290
  /** Selectable levels (engine id + user-facing label). Defaults to the plain
258
291
  * "Thinking" vocabulary; override to relabel without changing the ids the
259
- * runtime receives. */
292
+ * runtime receives.
293
+ *
294
+ * A list that omits the current `value` is not a rendering error the picker
295
+ * papers over: `value` is reconciled INTO the rendered list under its own
296
+ * name (see {@link reconcileEffortLevels}), because a control must report
297
+ * the depth the session is running at and never some other list entry. */
260
298
  levels?: readonly EffortLevel[];
261
299
  /** Prefix shown before the active level on the pill — the "what is this"
262
300
  * context the bare value lacked. Default "Thinking". Pass '' to hide it. */
@@ -294,6 +332,15 @@ interface AgentSessionControlsProps {
294
332
  * selected harness/model passes that subset here. Without it the strip
295
333
  * offers every level and the backend silently ignores the ones it does not
296
334
  * apply — a control that reports a choice the system never made.
335
+ *
336
+ * This is the COMPLETE renderable set, not an allow-list layered over a
337
+ * default one — the removed `ComposerAgentControls`' `available` list was the
338
+ * latter, and its picker injected the `auto` sentinel itself. A list that
339
+ * omits the current {@link effort} is still safe: `EffortPicker` reconciles
340
+ * the selected value into the rendered list under its own name rather than
341
+ * resolving it to a different entry (`reconcileEffortLevels`). Build the list
342
+ * from engine ids with `effortLevelsFromIds`; the migration is in
343
+ * `docs/ui-picker-canon.md`.
297
344
  */
298
345
  effortLevels?: readonly EffortLevel[];
299
346
  /**
@@ -308,4 +355,4 @@ interface AgentSessionControlsProps {
308
355
  }
309
356
  declare function AgentSessionControls(props: AgentSessionControlsProps): react.JSX.Element;
310
357
 
311
- export { type AgentSessionControlsProps as A, type ComposerMentionProp as C, DEFAULT_EFFORT_LEVELS as D, EFFORT_METER_SEGMENTS as E, INDEX_REFRESH_AFTER_MS as I, type MentionItem as M, OVERLAY_SHADOW as O, POPOVER_SURFACE_ATTR as P, type UseFileMentionsResult as U, AgentSessionControls as a, DEFAULT_MENTION_EMPTY_TEXT as b, DEFAULT_MENTION_LIMIT as c, type EffortLevel as d, EffortMeter as e, EffortPicker as f, type EffortPickerProps as g, ModelPicker as h, type ModelPickerProps as i, PopoverSurface as j, type PopoverSurfaceProps as k, type UseFileMentionsOptions as l, effortMeterFill as m, usePending as n, usePopover as o, rankFileMentions as r, useFileMentions as u };
358
+ export { type AgentSessionControlsProps as A, type ComposerMentionProp as C, DEFAULT_EFFORT_LEVELS as D, EFFORT_METER_SEGMENTS as E, INDEX_REFRESH_AFTER_MS as I, type MentionItem as M, OVERLAY_SHADOW as O, POPOVER_SURFACE_ATTR as P, type UseFileMentionsResult as U, AgentSessionControls as a, DEFAULT_MENTION_EMPTY_TEXT as b, DEFAULT_MENTION_LIMIT as c, type EffortLevel as d, EffortMeter as e, EffortPicker as f, type EffortPickerProps as g, ModelPicker as h, type ModelPickerProps as i, PopoverSurface as j, type PopoverSurfaceProps as k, type UseFileMentionsOptions as l, effortLevelLabel as m, effortLevelsFromIds as n, effortMeterFill as o, reconcileEffortLevels as p, usePending as q, rankFileMentions as r, usePopover as s, useFileMentions as u };
@@ -8,7 +8,7 @@ import '../plans/index.js';
8
8
  import '../parts-BqIHMdyu.js';
9
9
  import '../types-CCeYywdS.js';
10
10
  import '../wire-DOZ-O6hD.js';
11
- import '../agent-session-controls-CCeu5QLS.js';
11
+ import '../agent-session-controls-BGNNTeJ5.js';
12
12
  import '../harness/index.js';
13
13
  import '../catalog/index.js';
14
14
  import '../agent-activity-C8ZG0F0M.js';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ChatComposer,
3
3
  ChatMessages
4
- } from "../chunk-TB7T7C3X.js";
4
+ } from "../chunk-4TZZXCLF.js";
5
5
  import "../chunk-FBVLEGEG.js";
6
6
  import "../chunk-5MZXWPFN.js";
7
7
  import "../chunk-GEYACSFW.js";
@@ -9,7 +9,7 @@ import {
9
9
  ModelPicker,
10
10
  OVERLAY_SHADOW,
11
11
  ProviderLogo
12
- } from "../chunk-3AXSERRK.js";
12
+ } from "../chunk-JRPXENLF.js";
13
13
  import "../chunk-BATKJP3P.js";
14
14
  import {
15
15
  AsyncView
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { AgentComposer } from '@tangle-network/sandbox-ui/chat';
4
- import { A as AgentSessionControlsProps, U as UseFileMentionsResult } from '../agent-session-controls-CCeu5QLS.js';
4
+ import { A as AgentSessionControlsProps, U as UseFileMentionsResult } from '../agent-session-controls-BGNNTeJ5.js';
5
5
  import { b as ChatAttachmentInput, F as FileMention } from '../wire-DOZ-O6hD.js';
6
6
  import '../harness/index.js';
7
7
  import '@tangle-network/agent-interface';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AgentSessionControls,
3
3
  useComposerAttachments
4
- } from "../chunk-3AXSERRK.js";
4
+ } from "../chunk-JRPXENLF.js";
5
5
  import {
6
6
  ATTACHMENT_ACCEPT
7
7
  } from "../chunk-CCVG2TL6.js";
@@ -9,8 +9,10 @@ import {
9
9
  ChevronDown,
10
10
  OVERLAY_SHADOW,
11
11
  POPOVER_OPTION_FOCUS,
12
- usePending
13
- } from "./chunk-3AXSERRK.js";
12
+ PopoverSurface,
13
+ usePending,
14
+ usePopover
15
+ } from "./chunk-JRPXENLF.js";
14
16
  import {
15
17
  UNTITLED_SESSION_LABEL,
16
18
  mergeSessionPages,
@@ -3120,6 +3122,7 @@ function SeatPaywall({
3120
3122
  import {
3121
3123
  useCallback as useCallback8,
3122
3124
  useEffect as useEffect9,
3125
+ useId as useId2,
3123
3126
  useMemo as useMemo5,
3124
3127
  useRef as useRef8,
3125
3128
  useState as useState12
@@ -3802,6 +3805,8 @@ function SessionRow({
3802
3805
  onSelectedChange
3803
3806
  }) {
3804
3807
  const [menuOpen, setMenuOpen] = useState12(false);
3808
+ const panelId = useId2();
3809
+ const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(menuOpen, setMenuOpen);
3805
3810
  const extras = extraActions?.(session) ?? [];
3806
3811
  const hasMenu = Boolean(onRename) || Boolean(onDelete) || extras.length > 0;
3807
3812
  const showUnread = Boolean(session.unread) && !responding;
@@ -3829,60 +3834,72 @@ function SessionRow({
3829
3834
  )
3830
3835
  ] }),
3831
3836
  /* @__PURE__ */ jsx11("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: timestamp }),
3832
- hasMenu && /* @__PURE__ */ jsxs9("div", { className: "relative shrink-0", children: [
3837
+ hasMenu && /* @__PURE__ */ jsxs9("div", { ref: containerRef, className: "relative shrink-0", children: [
3833
3838
  /* @__PURE__ */ jsx11(
3834
3839
  "button",
3835
3840
  {
3836
3841
  type: "button",
3842
+ ...triggerProps,
3837
3843
  "aria-label": "Session actions",
3838
- "aria-expanded": menuOpen,
3844
+ "aria-controls": menuOpen ? panelId : void 0,
3839
3845
  onClick: () => setMenuOpen((open) => !open),
3840
3846
  className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:bg-muted hover:text-foreground focus-visible:opacity-100 sm:opacity-0 sm:group-hover:opacity-100 aria-expanded:opacity-100",
3841
3847
  children: /* @__PURE__ */ jsx11("span", { "aria-hidden": true, className: "text-base leading-none", children: "\u22EF" })
3842
3848
  }
3843
3849
  ),
3844
- menuOpen && /* @__PURE__ */ jsxs9(Fragment5, { children: [
3845
- /* @__PURE__ */ jsx11("div", { className: "fixed inset-0 z-20", onClick: () => setMenuOpen(false), "aria-hidden": true }),
3846
- /* @__PURE__ */ jsxs9("div", { className: `absolute right-0 z-30 mt-1 w-36 overflow-hidden rounded-md border border-border bg-popover py-1 ${OVERLAY_SHADOW}`, children: [
3847
- onRename && /* @__PURE__ */ jsx11(
3848
- "button",
3849
- {
3850
- type: "button",
3851
- onClick: () => {
3852
- setMenuOpen(false);
3853
- onRename(session);
3854
- },
3855
- className: "block w-full px-3 py-1.5 text-left text-xs text-foreground transition hover:bg-accent",
3856
- children: renameLabel
3857
- }
3858
- ),
3859
- extras.map((action) => /* @__PURE__ */ jsx11(
3860
- "button",
3861
- {
3862
- type: "button",
3863
- onClick: () => {
3864
- setMenuOpen(false);
3865
- action.onSelect();
3866
- },
3867
- className: `block w-full px-3 py-1.5 text-left text-xs transition ${action.destructive ? "text-destructive hover:bg-destructive/10" : "text-foreground hover:bg-accent"}`,
3868
- children: action.label
3869
- },
3870
- action.id
3871
- )),
3872
- onDelete && /* @__PURE__ */ jsx11(
3873
- "button",
3874
- {
3875
- type: "button",
3876
- onClick: () => {
3877
- setMenuOpen(false);
3878
- onDelete(session);
3850
+ /* @__PURE__ */ jsxs9(
3851
+ PopoverSurface,
3852
+ {
3853
+ open: menuOpen,
3854
+ id: panelId,
3855
+ role: "menu",
3856
+ triggerRef,
3857
+ panelRef,
3858
+ className: `w-36 overflow-hidden rounded-md border border-border bg-popover py-1 ${OVERLAY_SHADOW}`,
3859
+ children: [
3860
+ onRename && /* @__PURE__ */ jsx11(
3861
+ "button",
3862
+ {
3863
+ type: "button",
3864
+ role: "menuitem",
3865
+ onClick: () => {
3866
+ setMenuOpen(false);
3867
+ onRename(session);
3868
+ },
3869
+ className: "block w-full px-3 py-1.5 text-left text-xs text-foreground transition hover:bg-accent",
3870
+ children: renameLabel
3871
+ }
3872
+ ),
3873
+ extras.map((action) => /* @__PURE__ */ jsx11(
3874
+ "button",
3875
+ {
3876
+ type: "button",
3877
+ role: "menuitem",
3878
+ onClick: () => {
3879
+ setMenuOpen(false);
3880
+ action.onSelect();
3881
+ },
3882
+ className: `block w-full px-3 py-1.5 text-left text-xs transition ${action.destructive ? "text-destructive hover:bg-destructive/10" : "text-foreground hover:bg-accent"}`,
3883
+ children: action.label
3879
3884
  },
3880
- className: "block w-full px-3 py-1.5 text-left text-xs text-destructive transition hover:bg-destructive/10",
3881
- children: deleteLabel
3882
- }
3883
- )
3884
- ] })
3885
- ] })
3885
+ action.id
3886
+ )),
3887
+ onDelete && /* @__PURE__ */ jsx11(
3888
+ "button",
3889
+ {
3890
+ type: "button",
3891
+ role: "menuitem",
3892
+ onClick: () => {
3893
+ setMenuOpen(false);
3894
+ onDelete(session);
3895
+ },
3896
+ className: "block w-full px-3 py-1.5 text-left text-xs text-destructive transition hover:bg-destructive/10",
3897
+ children: deleteLabel
3898
+ }
3899
+ )
3900
+ ]
3901
+ }
3902
+ )
3886
3903
  ] })
3887
3904
  ] });
3888
3905
  }
@@ -3893,7 +3910,7 @@ import {
3893
3910
  isValidElement,
3894
3911
  useCallback as useCallback9,
3895
3912
  useEffect as useEffect10,
3896
- useId as useId2,
3913
+ useId as useId3,
3897
3914
  useMemo as useMemo6,
3898
3915
  useRef as useRef9,
3899
3916
  useState as useState13
@@ -4280,7 +4297,7 @@ function RecordGrid({
4280
4297
  loadingRowCount = 3,
4281
4298
  className
4282
4299
  }) {
4283
- const fieldPrefix = useId2();
4300
+ const fieldPrefix = useId3();
4284
4301
  const [overlay, setOverlay] = useState13(EMPTY_RECORD_GRID_OVERLAY);
4285
4302
  const [editing, setEditingState] = useState13(null);
4286
4303
  const [cellErrors, setCellErrors] = useState13({});
@@ -4883,13 +4900,20 @@ function CellEditor({ column, rowLabel, text, invalid, describedBy, onText, onCo
4883
4900
  }
4884
4901
  function SourceMarker({ panelId, columnHeader, rowLabel, source, open, onToggle }) {
4885
4902
  const basis = source.basis ?? "asserted";
4886
- return /* @__PURE__ */ jsxs10("span", { className: "relative inline-flex", children: [
4903
+ const setOpen = useCallback9(
4904
+ (next) => {
4905
+ if (!next) onToggle();
4906
+ },
4907
+ [onToggle]
4908
+ );
4909
+ const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(open, setOpen);
4910
+ return /* @__PURE__ */ jsxs10("span", { ref: containerRef, className: "relative inline-flex", children: [
4887
4911
  /* @__PURE__ */ jsx12(
4888
4912
  "button",
4889
4913
  {
4890
4914
  type: "button",
4915
+ ...triggerProps,
4891
4916
  "aria-label": `Source for ${columnHeader}, ${rowLabel}`,
4892
- "aria-expanded": open,
4893
4917
  "aria-controls": open ? panelId : void 0,
4894
4918
  title: BASIS_TITLES[basis],
4895
4919
  onClick: (event) => {
@@ -4912,12 +4936,15 @@ function SourceMarker({ panelId, columnHeader, rowLabel, source, open, onToggle
4912
4936
  )
4913
4937
  }
4914
4938
  ),
4915
- open && /* @__PURE__ */ jsxs10(
4916
- "span",
4939
+ /* @__PURE__ */ jsxs10(
4940
+ PopoverSurface,
4917
4941
  {
4942
+ open,
4918
4943
  id: panelId,
4919
4944
  role: "note",
4920
- className: `absolute left-0 top-5 z-10 w-64 rounded-lg border border-border bg-popover p-3 text-left ${OVERLAY_SHADOW}`,
4945
+ triggerRef,
4946
+ panelRef,
4947
+ className: `w-64 rounded-lg border border-border bg-popover p-3 text-left ${OVERLAY_SHADOW}`,
4921
4948
  children: [
4922
4949
  source.quote && /* @__PURE__ */ jsxs10("span", { className: "block border-l-2 border-primary/50 pl-2 text-xs italic leading-snug text-foreground", children: [
4923
4950
  "\u201C",
@@ -5963,4 +5990,4 @@ export {
5963
5990
  useThinkingSeconds,
5964
5991
  ChatMessages
5965
5992
  };
5966
- //# sourceMappingURL=chunk-TB7T7C3X.js.map
5993
+ //# sourceMappingURL=chunk-4TZZXCLF.js.map