Fix wave chunk 2: thinking levels auto-populate everywhere; legacy records show the resolved level

- thinking-default.ts: defaultOrderLevel (the ordering's first supported,
  the client twin of the server's defaultThinkingLevel) + populateLevel
  (an explicit level always rides; the WRITE clamps server-side, bd68486,
  and the cross-surface signal re-reads the clamped truth; only absence
  populates from the ordering) + THINKING_LABEL shared.
- Setup dialog (item 5): per-slot thinking selectors pre-populated with
  the default-order level per picked model, editable; disabled until the
  model pick; prefillLevelFromPin keeps a stored level as-is and populates
  legacy pins from the ordering.
- Composer + agent section (item 6): fresh model picks always write a
  level: the stored one rides, absence populates; the unset state can
  never re-enter. Item 4: records with a model but no stored level display
  the RESOLVED level (ordering's first supported) instead of a dash, in
  the composer pill and the settings slot triggers/menus.
- Item 7 verified live end-to-end: an explicit level rides into the PUT,
  the server clamps, the signal re-reads, the pill shows the clamped truth.
This commit is contained in:
amosblomqvist
2026-09-22 22:05:27 +03:00
parent e766a13eb1
commit 5e92d0e73e
6 changed files with 292 additions and 62 deletions
+51
View File
@@ -0,0 +1,51 @@
"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). */
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);
}