practice: the agent's data drawer — full transparency on every conclude card (round 17)

Owner ask (2026-10-06): reveal everything the agent filled in when
writing the problem and concluding it, at the very bottom of the
conclude card, collapsible, arriving collapsed.

The fields, both calls:
- problem: mode (recall/discrimination/composition), target
  proposition ids, statement, modelSolution (the last two ARE the
  visible card — the drawer shows the metadata only)
- conclude: outcome, hint rung (R0–R5/null), miss class
  (cue/discrimination/execution/careless/structural/null), retest.

Seams: problemInputForConclude (native-messages) walks the reveal's
walk and folds the WHOLE problem-call input onto the conclude part
(projectView join; same refused-pose law — an unacked pose folds
nothing); ArtifactPartProps grows problemInput. Targets resolve to
proposition NAMES at render (one lazy module-cached /api/graph fetch;
failure degrades to raw ids — observability never breaks the card).
The drawer: divider + chevron 'AGENT'S DATA' toggle (mono-caps
eyebrow register), definition rows with mono values, 'untagged'/
'none' honest empties, absent entirely when the calls filled nothing
(the dismissal line, legacy bare records).
This commit is contained in:
amosblomqvist
2026-10-06 04:18:26 +03:00
parent 0af3514d9b
commit 793638d6ce
6 changed files with 172 additions and 3 deletions
+17 -2
View File
@@ -364,6 +364,20 @@ export function modelSolutionForConclude(
messages: readonly LhMessage[],
concludeCallId: string,
): string | undefined {
const input = problemInputForConclude(messages, concludeCallId);
return typeof input?.modelSolution === "string" ? input.modelSolution : undefined;
}
/** The full pose-side fold (owner round 17, 2026-10-06 — observability):
* EVERYTHING the agent filled into the problem call — mode, target ids,
* statement, the committed solution — joined onto the conclude part so
* the card's collapsible "agent's data" drawer renders pure. Same walk
* and refusal law as the reveal: a pose the record never acked (a
* refused call) folds nothing. */
export function problemInputForConclude(
messages: readonly LhMessage[],
concludeCallId: string,
): { statement?: unknown; mode?: unknown; target?: unknown; modelSolution?: unknown } | undefined {
let mi = messages.findIndex(
(m) =>
(m as { role?: string }).role === "assistant" &&
@@ -381,8 +395,9 @@ export function modelSolutionForConclude(
const block = assistant.content[bi]!;
if (block.type !== "toolCall" || block.name !== PRACTICE_PROBLEM_TOOL) continue;
if (!clean.has(block.id)) continue; // a refused pose revealed nothing
const solution = (block.arguments as { modelSolution?: unknown } | undefined)?.modelSolution;
return typeof solution === "string" ? solution : undefined;
return (block.arguments ?? undefined) as
| { statement?: unknown; mode?: unknown; target?: unknown; modelSolution?: unknown }
| undefined;
}
}
return undefined;