fix: keep scene 8 transcript visible

This commit is contained in:
lda
2026-07-12 05:28:44 +07:00 Verified
parent d1128c0b49
commit 7165c74d83
6 changed files with 92 additions and 3 deletions
@@ -179,6 +179,53 @@ describe("AssistantOperatorThread", () => {
}
});
it("can keep a first-stage group anchored at the start of the transcript", async () => {
const setScrollTop = vi.fn();
const originalDescriptor = Object.getOwnPropertyDescriptor(HTMLDivElement.prototype, "scrollTop");
const messages: ReadonlyArray<AgentMessage> = [
{
id: "assistant-start-scroll-text",
role: "assistant",
parts: [
{ type: "text", text: "The first authoring turn is visible." },
],
},
{
id: "authoring-discover-tools",
role: "assistant",
parts: [
{ type: "tool-call", call: { id: "authoring-discover-command-0", name: "workflow.sources.list", input: { phase: "discover" } } },
{ type: "tool-result", result: { callId: "authoring-discover-command-0", name: "workflow.sources.list", status: "success", output: {} } },
],
},
];
try {
Object.defineProperty(HTMLDivElement.prototype, "scrollTop", {
configurable: true,
get: () => 0,
set: setScrollTop,
});
render(
<AssistantOperatorThread
mode="full"
surface="stage"
messages={messages}
activeToolGroupId="authoring-discover"
scrollMode="start"
/>,
);
await waitFor(() => expect(setScrollTop).toHaveBeenCalledWith(0));
} finally {
if (originalDescriptor) {
Object.defineProperty(HTMLDivElement.prototype, "scrollTop", originalDescriptor);
} else {
delete (HTMLDivElement.prototype as { scrollTop?: number }).scrollTop;
}
}
});
it("pairs a lone tool call with its result", () => {
const messages: ReadonlyArray<AgentMessage> = [
{
@@ -24,6 +24,7 @@ type AssistantOperatorThreadProps = {
readonly mode: "hidden" | "full" | "rail" | "dock";
readonly messages: ReadonlyArray<AgentMessage>;
readonly runAction?: { readonly label: string; readonly disabled: boolean; readonly run: () => void } | undefined;
readonly scrollMode?: "active" | "start" | undefined;
readonly submitApproval?: (() => void) | undefined;
readonly requestRevision?: (() => void) | undefined;
readonly ariaLabel?: string | undefined;
@@ -250,6 +251,7 @@ export const AssistantOperatorThread = ({
mode,
messages,
runAction,
scrollMode = "active",
submitApproval,
requestRevision,
ariaLabel = "operator conversation",
@@ -282,13 +284,17 @@ export const AssistantOperatorThread = ({
if (!viewport || !activeGroup) return;
const bottomAlignedTop = activeGroup.offsetTop + activeGroup.offsetHeight - viewport.clientHeight;
const dockCenteredTop = activeGroup.offsetTop - (viewport.clientHeight - activeGroup.offsetHeight) / 2;
const requestedTop = surface === "dock" ? dockCenteredTop : bottomAlignedTop;
const requestedTop = scrollMode === "start"
? 0
: surface === "dock"
? dockCenteredTop
: bottomAlignedTop;
const top = Math.min(
Math.max(0, requestedTop),
Math.max(0, viewport.scrollHeight - viewport.clientHeight),
);
viewport.scrollTop = top;
}, [activeToolGroupId, projected, surface]);
}, [activeToolGroupId, projected, scrollMode, surface]);
const setToolGroupOpen = useCallback((groupId: string, open: boolean) => {
setToolGroupOverrides((current) => {