Collapse byre-sent prompts in the transcript like tool calls
This commit is contained in:
+1
-1
@@ -96,7 +96,7 @@ The Admin view (a pane tab, also opened in the right pane by the navbar's **Admi
|
||||
|
||||
Agent activity becomes events with `agent_session_id` set: `user.message`, `agent.message`, `agent.thinking`, `agent.tool_call`, `agent.tool_result`, `turn.ended`, `session.state`, `session.model`, and `session.context`. Anything else Claude Code emits (rate-limit status, task progress, state changes) is recorded unchanged as `agent.vendor`. The one exception is partial output: each top-level `text_delta` is broadcast to SSE clients as an `agent.delta` event (`payload.text`, `seq` 0) that is never stored, and the transcript grows a live message from them until the finished `agent.message` replaces it. A `turn.ended` event carries `inbox_item_id` when its final message was filed as a `report` item. `session.context` records the context size whenever it changes: `used` is the last assistant message's input, cache-read, cache-creation and output tokens, and `window` is the model's context window from the turn's `result` (`modelUsage[model].contextWindow`), so it is 0 until the session's first turn after a server start ends. The task header's **Compact** button shows the latest one as a background fill across the button, proportional to the window, tinted amber from 70% and red from 90%; the exact count is in its tooltip.
|
||||
|
||||
Messages byre itself sends an agent (actor `byre`, such as the restart notice) show as a muted note, not a user bubble. The transcript view has an accent border while the session is `running`, and a braille spinner on its last line, cycling ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ every 0.8s. It is one element with one CSS animation: the ten frames are drawn side by side in an inline SVG used as the `.spinner` mask over an accent background, and the `braille` keyframes in `web/style.css` step the mask position through them. Orion freezes animated GIFs and per-dot `step-end` opacity animations partway through a turn, so it stays a single element with a single animation. Consecutive tool calls (with any thinking between them) collapse into one group whose summary counts calls per tool and file, and file paths show relative to the worktree. A turn's final message that is at least half visible in the transcript while the page is visible dismisses its `report` inbox item, as the viewing user. Selecting a task that has never had a session focuses the composer. In the composer, Enter sends and Shift-Enter adds a newline; unsent text is kept per task in memory, so it survives switching tabs or tasks but not a page reload. The composer is the same whether or not the task has a live session: Send posts to the session's messages, or starts a session with the text when there is none or the last one completed. A sent message shows at once as a "sending…" bubble, replaced by the server's `user.message` event with the same text when it arrives, and removed (text and images back in the composer) if the request fails.
|
||||
Messages byre itself sends an agent (actor `byre`: the restart notice, Sync and Merge prompts, Compact's handoff request and the continuation's handoff) show collapsed like a tool call, labelled `byre` with the first line as the brief; expanding it shows the full text. The transcript view has an accent border while the session is `running`, and a braille spinner on its last line, cycling ⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏ every 0.8s. It is one element with one CSS animation: the ten frames are drawn side by side in an inline SVG used as the `.spinner` mask over an accent background, and the `braille` keyframes in `web/style.css` step the mask position through them. Orion freezes animated GIFs and per-dot `step-end` opacity animations partway through a turn, so it stays a single element with a single animation. Consecutive tool calls (with any thinking between them) collapse into one group whose summary counts calls per tool and file, and file paths show relative to the worktree. A turn's final message that is at least half visible in the transcript while the page is visible dismisses its `report` inbox item, as the viewing user. Selecting a task that has never had a session focuses the composer. In the composer, Enter sends and Shift-Enter adds a newline; unsent text is kept per task in memory, so it survives switching tabs or tasks but not a page reload. The composer is the same whether or not the task has a live session: Send posts to the session's messages, or starts a session with the text when there is none or the last one completed. A sent message shows at once as a "sending…" bubble, replaced by the server's `user.message` event with the same text when it arrives, and removed (text and images back in the composer) if the request fails.
|
||||
|
||||
The task switcher (⌘K, or the navbar crumb) lists active tasks with their session state and open inbox item count, live while it is open. Tasks with inbox items come first; within each group, the task least recently visited in this browser comes first (never-visited tasks before all others, ties in the server's order: projects by name, tasks newest first). Visit times are kept in the browser's localStorage under `byre.visits`, stamped when a task is selected and again when it is left. Typing filters them and adds a last row that creates a task with the typed text as its title, in the current task's project (the first project when no task is selected); Enter picks the highlighted row. Picking a task here or in the Tasks view selects it and, if neither pane shows the Transcript tab, switches a pane that isn't showing Tasks to it.
|
||||
|
||||
|
||||
Vendored
+3
-5
@@ -608,11 +608,9 @@ function renderEvent(ev, ctx) {
|
||||
ctx.lastMessage = undefined;
|
||||
if (ev.actor === "byre") {
|
||||
const text = String(p["text"]);
|
||||
const [first, ...rest] = text.split("\n");
|
||||
if (rest.join("").trim() === "") {
|
||||
return h("div", { class: "note" }, text, " ", when);
|
||||
}
|
||||
return h("details", { class: "note" }, h("summary", {}, first, " ", when), markdown(rest.join("\n"), "text md"));
|
||||
const first = text.split("\n")[0] ?? "";
|
||||
const brief = first.length > 120 ? `${first.slice(0, 120)}…` : first;
|
||||
return h("details", { class: "tool byre-prompt" }, h("summary", {}, h("span", { class: "tool-name" }, "byre"), " ", h("span", { class: "tool-brief" }, brief), " ", when), markdown(text, "text md"));
|
||||
}
|
||||
return h("div", { class: "msg user" }, h("div", { class: "who" }, ev.actor, " ", when), messageImages(p["images"]), String(p["text"] ?? "").trim() ? markdown(String(p["text"]), "text md") : null);
|
||||
case "agent.message":
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+8
-5
@@ -693,11 +693,14 @@ function renderEvent(ev: ByreEvent, ctx: Ctx): HTMLElement | null {
|
||||
ctx.lastMessage = undefined;
|
||||
if (ev.actor === "byre") {
|
||||
const text = String(p["text"]);
|
||||
const [first, ...rest] = text.split("\n");
|
||||
if (rest.join("").trim() === "") {
|
||||
return h("div", { class: "note" }, text, " ", when);
|
||||
}
|
||||
return h("details", { class: "note" }, h("summary", {}, first, " ", when), markdown(rest.join("\n"), "text md"));
|
||||
const first = text.split("\n")[0] ?? "";
|
||||
const brief = first.length > 120 ? `${first.slice(0, 120)}…` : first;
|
||||
return h(
|
||||
"details",
|
||||
{ class: "tool byre-prompt" },
|
||||
h("summary", {}, h("span", { class: "tool-name" }, "byre"), " ", h("span", { class: "tool-brief" }, brief), " ", when),
|
||||
markdown(text, "text md"),
|
||||
);
|
||||
}
|
||||
return h(
|
||||
"div",
|
||||
|
||||
+10
-1
@@ -713,11 +713,20 @@ button.compact.danger {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.note time {
|
||||
.note time,
|
||||
.byre-prompt time {
|
||||
float: right;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.byre-prompt time {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.byre-prompt .md {
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
details.note summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user