Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/app/lab/session-ui-showcase.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ test("renders every ported session-ui piece from mock canonical nodes", () => {

// Queued pill: honest FIFO copy, Send now only on the head message.
expect(html).toContain('data-session-ui="queued-message-pill"');
expect(html).toContain("Queued - sends after the current run");
expect(html).toContain("Queued - sends after the current reply");
expect(html).toContain("Send now");
expect(html).toContain("Queued #2 - 1 reply ahead");

Expand Down
4 changes: 2 additions & 2 deletions frontend/components/chat/child-labels.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe("childKindLabel", () => {
expect(childKindLabel("bot_thread")).toBe("bot thread");
expect(childKindLabel("subagent")).toBe("subagent");
expect(childKindLabel("child_thread")).toBe("child thread");
expect(childKindLabel("spawned_session")).toBe("spawned session");
expect(childKindLabel("spawned_session")).toBe("helper agent");
});
});

Expand All @@ -16,7 +16,7 @@ describe("childGroupLabel", () => {
expect(childGroupLabel({ subagent: 2, bot_thread: 1 })).toBe("2 subagents, 1 bot thread");
expect(childGroupLabel({ subagent: 1 })).toBe("1 subagent");
expect(childGroupLabel({ bot_thread: 2, spawned_session: 1, child_thread: 0 })).toBe(
"2 bot threads, 1 spawned session",
"2 bot threads, 1 helper agent",
);
expect(childGroupLabel({})).toBe("");
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/chat/child-labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const SINGULAR: Record<ChildKind, string> = {
subagent: "subagent",
bot_thread: "bot thread",
child_thread: "child thread",
spawned_session: "spawned session",
spawned_session: "helper agent",
};

const ORDER: readonly ChildKind[] = ["subagent", "bot_thread", "child_thread", "spawned_session"];
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/chat/conversation-grammar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ test("a gateway child-session turn folds under its parent, never a second turn b
// Its truth lives in the parent's subagent fold: honest serial Queued state
// plus the open-as-own-session affordance.
expect(html).toContain('data-testid="subagents-fold"');
expect(html).toContain("1 spawned session");
expect(html).toContain("1 helper agent");
expect(html).toContain("Delegated: audit the docs");
expect(html).toContain("Queued");
expect(html).toContain('href="/session/run-child"');
Expand Down
7 changes: 5 additions & 2 deletions frontend/components/chat/session-details-rail.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe("SessionDetailsRail", () => {
expect(html).not.toContain("not reported");
});

test("the runtime line presents the model as the one requested, not as the one that answered", () => {
test("the model line presents the model as the one requested, not as the one that answered", () => {
// runs.model is what the plane asked the runtime for; no runtime reports
// the model that answered, so the rail must not read as a fact.
const html = renderToStaticMarkup(
Expand All @@ -115,7 +115,10 @@ describe("SessionDetailsRail", () => {
expect(html).toContain("Codex");
expect(html).toContain('data-testid="runtime-model-requested"');
expect(html).toContain(">requested<");
expect(html).toContain("does not report which model answered");
expect(html).toContain("We are not told which model actually answered");
// Plain words for people (#339): no run, turn, session or runtime in the row or its tooltip.
expect(html).toContain("<dt class=\"shrink-0 text-text-tertiary\">Model</dt>");
expect(html).not.toContain("Runtime</dt>");
});

test("a thread with unloaded outline turns says its plan and totals are partial", () => {
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/chat/session-details-rail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ export function SessionDetailsRail({
<Section title="Environment">
<dl className="flex flex-col gap-1.5 rounded-2xl bg-background-secondary-default px-3 py-2.5">
<Row label="Project">{project || "No repository"}</Row>
<Row label="Runtime">
<Row label="Model">
<span className="flex min-w-0 items-center justify-end gap-2">
{/* The model is the one the plane asked the runtime for (the run
row); no runtime reports back which model answered, so the
rail says so instead of presenting the request as a fact. */}
<span
className="truncate"
title="The model this run asked for. The runtime does not report which model answered."
title="The model this task asked for. We are not told which model actually answered."
>
{engineDisplayLabel(newest.engine)} · {modelLabel(newest.model, newest.engine)}{" "}
<span data-testid="runtime-model-requested" className="text-text-tertiary">
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/chat/subagent-pane-body.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe("run peek body", () => {

test("loading and error shells are neutral unless the caller knows it is a child", () => {
expect(renderToStaticMarkup(<PaneStub>Loading</PaneStub>)).toContain(">Thread<");
expect(renderToStaticMarkup(<PaneStub label="Run">Loading</PaneStub>)).toContain(">Run<");
expect(renderToStaticMarkup(<PaneStub label="Task">Loading</PaneStub>)).toContain(">Task<");
expect(renderToStaticMarkup(<PaneStub childSession>Loading</PaneStub>)).toContain(
">Subagent<",
);
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/chat/subagent-pane-body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ export default function SubagentPaneBody({
return (
<PaneStub childSession={childSession}>
<p className="text-body-2-regular text-text-secondary text-center">
Couldn&apos;t load this run.
Couldn&apos;t load this task.
</p>
</PaneStub>
);
}
if (!run) {
return (
<PaneStub childSession={childSession}>
<LoadingState label="Loading run" />
<LoadingState label="Loading task" />
</PaneStub>
);
}
Expand Down
8 changes: 4 additions & 4 deletions frontend/components/chat/subagent-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export function PaneStub({
}: {
children: React.ReactNode;
childSession?: boolean;
label?: "Run";
label?: "Task";
}) {
return (
<>
Expand All @@ -122,8 +122,8 @@ export function PaneStub({
const SubagentPaneBody = dynamic(() => import("@/components/chat/subagent-pane-body"), {
ssr: false,
loading: () => (
<PaneStub label="Run">
<LoadingState label="Loading run" />
<PaneStub label="Task">
<LoadingState label="Loading task" />
</PaneStub>
),
});
Expand Down Expand Up @@ -245,7 +245,7 @@ export function SubagentPeekButton({
return (
<button
type="button"
aria-label="Peek run"
aria-label="Preview task"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
Expand Down
11 changes: 9 additions & 2 deletions frontend/components/chat/subagents-fold.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { renderToStaticMarkup } from "react-dom/server";
import { createCanonicalThreadStore, type CanonicalThreadEvent } from "@useagent/agent-client";
import type { ThreadRelationship } from "@useagent/agent-client";
import type { CanonicalChildEventLike } from "./canonical-children";
import { childKindLabel } from "./child-labels";
import { EXECUTION_SUMMARY_ROLLOUT_MODE } from "./execution-summary-rollout";
import { type GatewayChildSession, SubagentsFold } from "./subagents-fold";

Expand Down Expand Up @@ -106,7 +107,7 @@ describe("subagents fold (inline conversation group)", () => {
/>,
);
expect(html).toContain('data-testid="subagents-fold"');
expect(html).toContain("1 subagent, 1 spawned session");
expect(html).toContain("1 subagent, 1 helper agent");
// Native child row: title, agent-type, model, tokens, live state.
expect(html).toContain("Verify checkout");
expect(html).toContain("verifier");
Expand All @@ -117,6 +118,12 @@ describe("subagents fold (inline conversation group)", () => {
expect(html).toContain("Summarize the wiki for onboarding");
expect(html).toContain("Queued");
expect(html).toContain('href="/session/child-run-1"');
// The link's name comes from the shared kind label, so this row and the Agents
// rail never call the same child two different things (#339).
expect(html).toContain(
`aria-label="Open ${childKindLabel("spawned_session")}: Summarize the wiki for onboarding"`,
);
expect(html).not.toContain("spawned");
expect(html).not.toContain("parallel");
});

Expand All @@ -139,7 +146,7 @@ describe("subagents fold (inline conversation group)", () => {
childSessions={[gatewayChild({ status: "completed", summary: "Wiki summarized." })]}
/>,
);
expect(html).toContain("1 subagent, 1 spawned session");
expect(html).toContain("1 subagent, 1 helper agent");
expect(html).toContain('aria-expanded="false"');
expect(html).not.toContain("Suite green.");
});
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/chat/subagents-fold.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function GatewayChildRow({ child }: { child: GatewayChildSession }) {
</div>
<Link
href={`/session/${child.id}`}
aria-label={`Open spawned session: ${firstLine(child.prompt)}`}
aria-label={`Open ${childKindLabel("spawned_session")}: ${firstLine(child.prompt)}`}
title="Open as its own thread"
className={ROW_LINK_CLASS}
>
Expand Down
2 changes: 1 addition & 1 deletion frontend/components/pro/queued-messages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function Row({
<button
type="button"
onClick={onSendNow}
title="Stops the current turn; this message starts immediately"
title="Stops what the agent is doing now and sends this message right away"
className="shrink-0 cursor-pointer text-caption-1-medium text-accent-500 underline-offset-2 outline-none hover:underline focus-visible:underline"
>
Send now
Expand Down
6 changes: 3 additions & 3 deletions frontend/components/session-ui/agent-panel-row.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,14 @@ describe("AgentPanelRow kind caption", () => {
expect(html).not.toContain("text-[.65rem]");
});

test("gateway rows read as spawned sessions", () => {
test("gateway rows read as helper agents, in the shared plain words", () => {
const html = renderToStaticMarkup(
<AgentPanelRow
agent={{ ...base, lane: "gateway", kind: "spawned_session", engine: "claude" }}
href="/session/child-1"
/>,
);
expect(html).toContain("spawned session · Running");
expect(html).toContain('aria-label="Open spawned session: Research checkout"');
expect(html).toContain("helper agent · Running");
expect(html).toContain('aria-label="Open helper agent: Research checkout"');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe("render gating", () => {
// Four ticks, each a titled button.
expect(html.match(/<button/g)?.length).toBe(4);
expect(html).toContain('title="first turn"');
expect(html).toContain('aria-label="Jump to turn 4: fourth turn"');
expect(html).toContain('aria-label="Jump to message 4: fourth turn"');
// First tick is active on first paint (activeIndex defaults to 0).
expect(html).toContain('aria-current="true"');
});
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/session-ui/message-scroller-rail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function MessageScrollerRail({
return (
<nav
data-session-ui="message-scroller-rail"
aria-label="Jump to a turn"
aria-label="Jump to a message"
className="pointer-events-none absolute inset-y-4 right-2 z-20 hidden flex-col items-end justify-center gap-1 overflow-hidden lg:flex"
>
{ticks.map((tick, index) => {
Expand All @@ -126,7 +126,7 @@ export function MessageScrollerRail({
key={tick.id}
type="button"
title={tick.snippet}
aria-label={`Jump to turn ${index + 1}: ${tick.snippet}`}
aria-label={`Jump to message ${index + 1}: ${tick.snippet}`}
aria-current={active ? "true" : undefined}
onClick={() => jumpTo(index)}
className="group pointer-events-auto flex h-3.5 w-3 items-center justify-end rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-border-focus-ring"
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/session-ui/queued-message-pill.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { renderToStaticMarkup } from "react-dom/server";
import { queuedPillLabel, QueuedMessagePill } from "./queued-message-pill";

test("labels state the honest FIFO position, never a countdown", () => {
expect(queuedPillLabel(1)).toBe("Queued - sends after the current run");
expect(queuedPillLabel(1)).toBe("Queued - sends after the current reply");
expect(queuedPillLabel(1, false)).toBe("Queued - waiting to start");
expect(queuedPillLabel(2)).toBe("Queued #2 - 1 reply ahead");
expect(queuedPillLabel(3)).toBe("Queued #3 - 2 replies ahead");
Expand All @@ -14,7 +14,7 @@ test("head queued pill is right-aligned and carries the Send now steering", () =
expect(html).toContain('data-session-ui="queued-message-pill"');
expect(html).toContain("justify-end");
expect(html).toContain('role="status"');
expect(html).toContain("Queued - sends after the current run");
expect(html).toContain("Queued - sends after the current reply");
expect(html).toContain("Send now");
});

Expand Down
4 changes: 2 additions & 2 deletions frontend/components/session-ui/queued-message-pill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { RiTimeLine } from "@remixicon/react";
* positions also wait on the replies ahead of them. */
export function queuedPillLabel(position: number, waitingOnCurrentRun = true): string {
if (!waitingOnCurrentRun) return "Queued - waiting to start";
if (position <= 1) return "Queued - sends after the current run";
if (position <= 1) return "Queued - sends after the current reply";
const ahead = position - 1;
return `Queued #${position} - ${ahead} ${ahead === 1 ? "reply" : "replies"} ahead`;
}
Expand Down Expand Up @@ -47,7 +47,7 @@ export function QueuedMessagePill({
<button
type="button"
onClick={onSendNow}
title="Stops the current turn; this message starts immediately"
title="Stops what the agent is doing now and sends this message right away"
className="shrink-0 cursor-pointer text-accent-500 underline-offset-2 outline-none hover:underline focus-visible:underline"
>
Send now
Expand Down
Loading