Research steers: the wave-1 'view full research' affordance — collapsed <details> carries the full brief
The Research-complete one-liner is now a native <details> disclosure: collapsed it reads exactly as before (Research · complete · N sources); one click expands the full persisted brief + source links via ResearchBriefCard. No fetch, no state, no protocol change — the data-subagent-artifact part in the record is the single source of truth, which is what made this affordance 'feasible later' back in wave 1. The brief still never clutters the transcript by default; the teacher's wake turn remains the primary channel for weaving it into the lesson. Test updated: the brief + sources now assert PRESENT inside the details (and collapsed — no open attribute) instead of absent from the DOM. Gates: typecheck, 279/279 tests, lint, build — all green.
This commit is contained in:
@@ -15,11 +15,11 @@ import { VisualOutputCard } from "@/components/artifacts/visual-card";
|
||||
* ("data-subagent-artifact") carries the result. It renders as an artifact —
|
||||
* NEVER a learner bubble, never wrapped in a message container:
|
||||
*
|
||||
* research — a quiet "Research complete" badge. The full brief is TOO LONG
|
||||
* to inline and the teacher's wake turn weaves it into the lesson anyway;
|
||||
* it stays persisted in the transcript (the artifact part), so a
|
||||
* "view full research" affordance can be added later. Failures keep the
|
||||
* failure card (the brief explains what went wrong).
|
||||
* research — a quiet "Research complete" one-liner that expands on demand
|
||||
* (native <details>) to the full persisted brief + sources: the brief is
|
||||
* too long to inline by default and the teacher's wake turn weaves it
|
||||
* into the lesson anyway. Failures keep the failure card (the brief
|
||||
* explains what went wrong).
|
||||
* demo / visual — the artifact itself (sandboxed iframe / sanitized SVG).
|
||||
* The sub-agent's verification notes are model-facing glue and do NOT
|
||||
* render; only a failure note does.
|
||||
@@ -48,15 +48,25 @@ export function SubagentSteerCard({ message }: { message: TeacherUIMessage }) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Quiet one-liner, the dispatch-settled idiom: the brief lives in the record,
|
||||
* the lesson lives in the teacher's wake turn — the badge just marks delivery. */
|
||||
/** Quiet one-liner, the dispatch-settled idiom — the lesson lives in the
|
||||
* teacher's wake turn; the badge just marks delivery. The persisted brief
|
||||
* rides along in a collapsed <details> (the wave-1 "view full research"
|
||||
* affordance): full markdown + sources, one click away, no extra fetch —
|
||||
* the artifact part in the record is the single source of truth. */
|
||||
function ResearchCompleteBadge({ result }: { result: ResearchResult }) {
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground" data-testid="research-complete-badge">
|
||||
<CheckIcon className="size-3.5" />
|
||||
<span className="font-medium uppercase tracking-wide">Research</span>
|
||||
<span>complete</span>
|
||||
{result.sources.length > 0 && <span>· {result.sources.length} sources</span>}
|
||||
</div>
|
||||
<details data-testid="research-complete-badge" className="group w-full text-xs text-muted-foreground">
|
||||
<summary className="flex cursor-pointer select-none list-none items-center gap-2 [&::-webkit-details-marker]:hidden">
|
||||
<CheckIcon className="size-3.5" />
|
||||
<span className="font-medium uppercase tracking-wide">Research</span>
|
||||
<span>complete</span>
|
||||
{result.sources.length > 0 && <span>· {result.sources.length} sources</span>}
|
||||
<span className="ml-1 text-[11px] text-muted-foreground/70 group-open:hidden">view brief</span>
|
||||
<span className="ml-1 hidden text-[11px] text-muted-foreground/70 group-open:inline">hide brief</span>
|
||||
</summary>
|
||||
<div className="mt-2">
|
||||
<ResearchBriefCard output={result} />
|
||||
</div>
|
||||
</details>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ describe("steer card rendering (the delivered artifact)", () => {
|
||||
assert.ok(!html.includes("Looking at the render"), "model-facing notes never render");
|
||||
});
|
||||
|
||||
it("renders a quiet Research-complete badge — the full brief stays out of the transcript (but persisted)", () => {
|
||||
it("renders a quiet Research-complete one-liner whose collapsed <details> carries the full brief", () => {
|
||||
const steer = buildSubagentSteer(
|
||||
{ id: "jr", kind: "research", toolCallId: "cr" },
|
||||
{
|
||||
@@ -357,8 +357,14 @@ describe("steer card rendering (the delivered artifact)", () => {
|
||||
assert.match(html, /Research/);
|
||||
assert.match(html, /complete/);
|
||||
assert.match(html, /2 sources/);
|
||||
assert.ok(!html.includes("founded the Academy"), "the long brief never renders inline");
|
||||
assert.ok(!html.includes("britannica"), "source links stay out too — the wake turn cites them");
|
||||
assert.match(html, /view brief/, "the expansion affordance is offered");
|
||||
// the one-liner is a native <details> — collapsed by default, so the
|
||||
// brief + sources ride in the DOM but never clutter the transcript
|
||||
// until the learner opens them (the wave-1 "view full research" ask)
|
||||
assert.match(html, /<details[^>]*data-testid="research-complete-badge"/, "a real disclosure");
|
||||
assert.ok(!/<details[^>]*open/.test(html), "collapsed by default — no `open` attribute");
|
||||
assert.ok(html.includes("founded the Academy"), "the persisted brief rides inside the details");
|
||||
assert.ok(html.includes("britannica.com/plato"), "source links ride inside the details");
|
||||
});
|
||||
|
||||
it("renders the visual failure note with no svg when the build FAILED", () => {
|
||||
|
||||
Reference in New Issue
Block a user