Hold lead signal turns until they draw something visible

This commit is contained in:
Ian Gulliver
2026-10-15 13:56:37 -07:00
parent 9f08ef401b
commit 0f41dab390
4 changed files with 53 additions and 35 deletions
+25 -16
View File
@@ -166,7 +166,7 @@ export function mountChat(root, src, makeHead) {
subagents: new Map(),
run: undefined,
lastMessage: undefined,
turnStart: undefined,
held: undefined,
quiet: false,
handoff: undefined,
root: src.root,
@@ -199,15 +199,28 @@ export function mountChat(root, src, makeHead) {
transcript.append(el);
}
};
const put = (el) => {
const syncRunning = () => setRunning(src.session()?.state === "running" && !ctx.held);
const release = () => {
const el = ctx.held;
if (!el) {
return;
}
ctx.held = undefined;
putBefore(el, stream?.el ?? pending[0]?.el);
syncRunning();
};
const put = (el, keepHeld = false) => {
if (ctx.handoff) {
ctx.handoff.body.append(el);
return;
}
if (!keepHeld) {
release();
}
putBefore(el, pending[0]?.el);
};
const renderHead = () => {
setRunning(src.session()?.state === "running");
syncRunning();
if (!src.key()) {
replace(head);
return;
@@ -300,7 +313,7 @@ export function mountChat(root, src, makeHead) {
if (!stream) {
stream = { el: h("div", { class: "msg agent" }), text: "", timer: 0 };
ctx.run = undefined;
put(stream.el);
put(stream.el, true);
}
stream.text += String(ev.payload["text"] ?? "");
if (stream.timer) {
@@ -311,7 +324,7 @@ export function mountChat(root, src, makeHead) {
return;
}
stream.timer = 0;
stream.el.hidden = quietReply.startsWith(stream.text.trim());
stream.el.hidden = ctx.held !== undefined || quietReply.startsWith(stream.text.trim());
replace(stream.el, markdown(stream.text, "text md", { taskId: ctx.taskId }));
pin();
}, 100);
@@ -392,21 +405,17 @@ export function mountChat(root, src, makeHead) {
if (ev.kind === "user.message" && p["handoff"] === true) {
openHandoff();
}
if (ev.kind === "turn.ended" && ctx.quiet && ctx.turnStart?.parentNode === transcript) {
let node = ctx.turnStart;
while (node && node !== spinner) {
const next = node.nextSibling;
node.remove();
node = next;
}
ctx.turnStart = undefined;
if (ev.kind === "turn.ended" && ctx.quiet && ctx.held) {
ctx.held = undefined;
ctx.quiet = false;
continue;
}
put(el);
if (ev.kind === "user.message" && p["mid_turn"] !== true) {
ctx.turnStart = el;
if (ev.kind === "user.message" && ev.actor === "byre" && ev.owner && p["mid_turn"] !== true && p["handoff"] !== true) {
ctx.held = el;
syncRunning();
continue;
}
put(el);
}
if (contextChanged) {
renderHead();
+1 -1
View File
File diff suppressed because one or more lines are too long
+26 -17
View File
@@ -56,7 +56,7 @@ type Ctx = {
root: () => string;
taskId: string | undefined;
lastMessage: HTMLElement | undefined;
turnStart: HTMLElement | undefined;
held: HTMLElement | undefined;
quiet: boolean;
handoff: { summary: HTMLElement; body: HTMLElement } | undefined;
watchReport: (el: HTMLElement, itemId: string) => void;
@@ -234,7 +234,7 @@ export function mountChat(root: HTMLElement, src: ChatSource, makeHead: (rerende
subagents: new Map(),
run: undefined,
lastMessage: undefined,
turnStart: undefined,
held: undefined,
quiet: false,
handoff: undefined,
root: src.root,
@@ -266,16 +266,29 @@ export function mountChat(root: HTMLElement, src: ChatSource, makeHead: (rerende
transcript.append(el);
}
};
const put = (el: HTMLElement) => {
const syncRunning = () => setRunning(src.session()?.state === "running" && !ctx.held);
const release = () => {
const el = ctx.held;
if (!el) {
return;
}
ctx.held = undefined;
putBefore(el, stream?.el ?? pending[0]?.el);
syncRunning();
};
const put = (el: HTMLElement, keepHeld = false) => {
if (ctx.handoff) {
ctx.handoff.body.append(el);
return;
}
if (!keepHeld) {
release();
}
putBefore(el, pending[0]?.el);
};
const renderHead = () => {
setRunning(src.session()?.state === "running");
syncRunning();
if (!src.key()) {
replace(head);
return;
@@ -378,7 +391,7 @@ export function mountChat(root: HTMLElement, src: ChatSource, makeHead: (rerende
if (!stream) {
stream = { el: h("div", { class: "msg agent" }), text: "", timer: 0 };
ctx.run = undefined;
put(stream.el);
put(stream.el, true);
}
stream.text += String(ev.payload["text"] ?? "");
if (stream.timer) {
@@ -389,7 +402,7 @@ export function mountChat(root: HTMLElement, src: ChatSource, makeHead: (rerende
return;
}
stream.timer = 0;
stream.el.hidden = quietReply.startsWith(stream.text.trim());
stream.el.hidden = ctx.held !== undefined || quietReply.startsWith(stream.text.trim());
replace(stream.el, markdown(stream.text, "text md", { taskId: ctx.taskId }));
pin();
}, 100);
@@ -471,21 +484,17 @@ export function mountChat(root: HTMLElement, src: ChatSource, makeHead: (rerende
if (ev.kind === "user.message" && p["handoff"] === true) {
openHandoff();
}
if (ev.kind === "turn.ended" && ctx.quiet && ctx.turnStart?.parentNode === transcript) {
let node: ChildNode | null = ctx.turnStart;
while (node && node !== spinner) {
const next: ChildNode | null = node.nextSibling;
node.remove();
node = next;
}
ctx.turnStart = undefined;
if (ev.kind === "turn.ended" && ctx.quiet && ctx.held) {
ctx.held = undefined;
ctx.quiet = false;
continue;
}
put(el);
if (ev.kind === "user.message" && p["mid_turn"] !== true) {
ctx.turnStart = el;
if (ev.kind === "user.message" && ev.actor === "byre" && ev.owner && p["mid_turn"] !== true && p["handoff"] !== true) {
ctx.held = el;
syncRunning();
continue;
}
put(el);
}
if (contextChanged) {
renderHead();