Files
learnharness/components/thinking-default.ts
T
amosblomqvist 9f7dd1a7e9 Refinement round: ring popover down, menu order, tok unit, list indent, lowercase levels
Five small fixes (owner refinement round, 2026-09-24):

1. RING POPOVER OPENS DOWN: the ring lives in the chat top bar —
   the window's top edge is right above it, so the upward popover was
   clipped. top-full mt-1.5 now: it drops below the ring.

2. SESSION MENU ORDER FLIPPED: Rename/Delete first, hairline, then
   the extraction coverage block + Extract at the bottom — the info
   reads after the actions (was the reverse, the block on top).

3. UNIT TYPED OUT: the sidebar block reads "2k tok uncovered" now —
   the tokens unit is explicit (owner: "tok").

4. MARKDOWN LIST INDENT: streamdown ships list-inside with no
   container padding — top-level markers sat ON the text edge (only
   nested lists got their pl-6 via [li_&]). .lh-prose :where(ul, ol)
   { padding-left: 1.5rem } indents both list kinds as blocks, 24px —
   the same measure as the nested-case pl-6. Unlayered CSS beats the
   utility layer; :where keeps specificity zero.

5. THINKING LEVELS LOWERCASE EVERYWHERE: the composer pill and setup
   dialog rendered THINKING_LABEL (Off/Minimal/…/Max) while every
   menu body renders the raw lowercase level — the map is now
   lowercase, the level string IS the display form, everywhere.

Live-verified on :3001: list content inset 24px vs paragraphs
(padding-left computed 24px, nested fine); the composer pill reads
"low" with options low/high/max; menu order Rename → Delete… →
hairline → block. 901/901.
2026-09-24 15:51:40 +03:00

55 lines
2.3 KiB
TypeScript

"use client";
/**
* The default-order resolution, CLIENT-SIDE (chunk 2, Platform interlude
* bd68486): the UI mirrors defaultThinkingLevel from src/agent/models.ts
* EXACTLY — first DEFAULT_THINKING_ORDER entry the model supports, else
* the first supported level, else "off". One source of truth for the
* ordering (the core barrel); this helper is its only client
* interpretation, so a fresh model pick can auto-populate the SAME
* level the engine would run for an unset record (owner ruling: the
* ordering's ONLY purpose is first assignment — an explicit pick always
* wins, and after a swap the WRITE clamps server-side, the signal
* re-reads, and the clamped truth displays).
*/
import { DEFAULT_THINKING_ORDER } from "@/src/core";
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
/** Display labels for the levels (shared by every trigger that shows
* one). Lowercase, always (owner refinement round, 2026-09-24): the
* level strings ARE the display form — the settings menus render them
* raw, so the composer pill and setup dialog must match, never Title
* Case. */
export const THINKING_LABEL: Record<string, string> = {
off: "off",
minimal: "minimal",
low: "low",
medium: "medium",
high: "high",
xhigh: "xhigh",
max: "max",
};
/** The level a fresh pick of `supported` populates with. Empty support
* (shouldn't happen — the catalog always reports at least ["off"])
* resolves "off", matching the server's fallback. */
export function defaultOrderLevel(supported: readonly ThinkingLevel[]): ThinkingLevel {
for (const level of DEFAULT_THINKING_ORDER) {
if (supported.includes(level)) return level;
}
return supported[0] ?? "off";
}
/** An EXPLICIT level always rides — even when the fresh pick's model
* doesn't support it: the WRITE clamps it to the nearest supported level
* server-side (Platform's interlude bd68486 — the owner's swap-400 case
* now just works), and the cross-surface signal re-reads so the clamped
* truth displays. The ordering only assigns FIRST: when no explicit
* level exists, a fresh model pick populates the ordering's level for
* that model (chunk 2: the unset state can never re-enter). */
export function populateLevel(
explicit: ThinkingLevel | undefined,
supported: readonly ThinkingLevel[],
): ThinkingLevel {
return explicit ?? defaultOrderLevel(supported);
}