fix: filter web timeline assistant marks
This commit is contained in:
parent
ad93047a25
commit
c7c838b4e5
|
|
@ -2,7 +2,7 @@
|
||||||
title: 'Backend runtime経由の操作をprotocol transportへ統一しTUI同等にする'
|
title: 'Backend runtime経由の操作をprotocol transportへ統一しTUI同等にする'
|
||||||
state: 'planning'
|
state: 'planning'
|
||||||
created_at: '2026-07-21T09:20:07Z'
|
created_at: '2026-07-21T09:20:07Z'
|
||||||
updated_at: '2026-07-22T06:36:51Z'
|
updated_at: '2026-07-22T07:08:39Z'
|
||||||
assignee: null
|
assignee: null
|
||||||
readiness: 'draft'
|
readiness: 'draft'
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -376,3 +376,41 @@ Verification:
|
||||||
- `git diff --check`
|
- `git diff --check`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<!-- event: comment author: assistant at: 2026-07-22T07:04:51Z -->
|
||||||
|
|
||||||
|
## Comment
|
||||||
|
|
||||||
|
Requested Web Console timeline-bar display change before implementation:
|
||||||
|
|
||||||
|
- Keep user-message markers/items as they are today.
|
||||||
|
- For assistant display in the timeline bar, show only the last assistant item within each turn.
|
||||||
|
|
||||||
|
Implementation plan:
|
||||||
|
- Locate the Web timeline-bar projection/rendering path.
|
||||||
|
- Change only the timeline-bar item derivation/filtering, not the underlying transcript/event model.
|
||||||
|
- Add/update focused Web tests if there is a projection helper; otherwise verify through existing Web check and keep the diff scoped.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- event: implementation_report author: assistant at: 2026-07-22T07:08:39Z -->
|
||||||
|
|
||||||
|
## Implementation report
|
||||||
|
|
||||||
|
Implementation report for Web Console timeline-bar assistant filtering:
|
||||||
|
|
||||||
|
- Added `selectConsoleTimelineLines()` in `web/workspace/src/lib/workspace/console/model.ts`.
|
||||||
|
- The selector keeps every `user` line in the timeline selection.
|
||||||
|
- Assistant lines are grouped by user-delimited turns, and only the last assistant line in each turn is selected.
|
||||||
|
- Non-user/non-assistant lines remain excluded from the timeline bar selection.
|
||||||
|
- Updated `+page.svelte` timeline layout construction to use the selector before converting selected lines to timeline marks. Positioning still uses the full transcript line count, so marks remain aligned to scroll position.
|
||||||
|
- Added a focused model test for `user, assistant, tool, assistant, user, assistant, assistant` to assert the selected timeline items are `u1`, `a2`, `u2`, and `a4`.
|
||||||
|
|
||||||
|
Verification:
|
||||||
|
- `cd web/workspace && deno test --allow-read=src --allow-env=VSCODE_TEXTMATE_DEBUG src/lib/workspace/console/model.test.ts`
|
||||||
|
- `cd web/workspace && deno task check` passed with 0 errors; it still reports the existing 2 a11y warnings in `+page.svelte`.
|
||||||
|
- `git diff --check`
|
||||||
|
|
||||||
|
Note: `deno fmt --check` on the touched files still reports existing formatting changes outside this patch scope, so it was not used as the gating check for this small change.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ import {
|
||||||
createConsoleProjector,
|
createConsoleProjector,
|
||||||
projectConsole,
|
projectConsole,
|
||||||
segmentsToText,
|
segmentsToText,
|
||||||
|
selectConsoleTimelineLines,
|
||||||
workerConsoleHref,
|
workerConsoleHref,
|
||||||
|
type ConsoleLine,
|
||||||
} from "./model.ts";
|
} from "./model.ts";
|
||||||
|
|
||||||
declare const Deno: {
|
declare const Deno: {
|
||||||
|
|
@ -24,6 +26,16 @@ function assertEquals<T>(actual: T, expected: T): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function consoleLine(id: string, kind: ConsoleLine["kind"]): ConsoleLine {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
kind,
|
||||||
|
title: kind,
|
||||||
|
body: id,
|
||||||
|
source: "event",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Deno.test("workerConsoleHref encodes runtime and worker target authority", () => {
|
Deno.test("workerConsoleHref encodes runtime and worker target authority", () => {
|
||||||
assert(
|
assert(
|
||||||
workerConsoleHref({
|
workerConsoleHref({
|
||||||
|
|
@ -857,3 +869,20 @@ Deno.test("projectConsole reseeds visible rows from segment rotation", () => {
|
||||||
["user:after rotation seed"],
|
["user:after rotation seed"],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Deno.test("selectConsoleTimelineLines keeps all users and only last assistant per turn", () => {
|
||||||
|
const items = [
|
||||||
|
consoleLine("u1", "user"),
|
||||||
|
consoleLine("a1", "assistant"),
|
||||||
|
consoleLine("tool1", "tool"),
|
||||||
|
consoleLine("a2", "assistant"),
|
||||||
|
consoleLine("u2", "user"),
|
||||||
|
consoleLine("a3", "assistant"),
|
||||||
|
consoleLine("a4", "assistant"),
|
||||||
|
];
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
selectConsoleTimelineLines(items).map(({ item, index }) => `${index}:${item.id}`),
|
||||||
|
["0:u1", "3:a2", "4:u2", "6:a4"],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,39 @@ export type ConsoleProjection = {
|
||||||
lastEventId: string | null;
|
lastEventId: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ConsoleTimelineLineSelection = {
|
||||||
|
item: ConsoleLine;
|
||||||
|
index: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function selectConsoleTimelineLines(
|
||||||
|
items: ConsoleLine[],
|
||||||
|
): ConsoleTimelineLineSelection[] {
|
||||||
|
const selected: ConsoleTimelineLineSelection[] = [];
|
||||||
|
let lastAssistant: ConsoleTimelineLineSelection | null = null;
|
||||||
|
|
||||||
|
const flushAssistant = () => {
|
||||||
|
if (lastAssistant) {
|
||||||
|
selected.push(lastAssistant);
|
||||||
|
lastAssistant = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
items.forEach((item, index) => {
|
||||||
|
if (item.kind === "user") {
|
||||||
|
flushAssistant();
|
||||||
|
selected.push({ item, index });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (item.kind === "assistant") {
|
||||||
|
lastAssistant = { item, index };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
flushAssistant();
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
export type WorkerTarget = {
|
export type WorkerTarget = {
|
||||||
runtime_id: string;
|
runtime_id: string;
|
||||||
worker_id: string;
|
worker_id: string;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
import { fitTextarea } from "$lib/workspace/console/textarea-fit";
|
import { fitTextarea } from "$lib/workspace/console/textarea-fit";
|
||||||
import {
|
import {
|
||||||
createConsoleProjector,
|
createConsoleProjector,
|
||||||
|
selectConsoleTimelineLines,
|
||||||
type ConsoleEventInput,
|
type ConsoleEventInput,
|
||||||
type ConsoleLine,
|
type ConsoleLine,
|
||||||
type ConsoleProjection,
|
type ConsoleProjection,
|
||||||
|
|
@ -643,8 +644,10 @@
|
||||||
metrics: ScrollMetrics,
|
metrics: ScrollMetrics,
|
||||||
): TimelineLayout {
|
): TimelineLayout {
|
||||||
const denominator = Math.max(items.length - 1, 1);
|
const denominator = Math.max(items.length - 1, 1);
|
||||||
const rawMarks = items
|
const rawMarks = selectConsoleTimelineLines(items)
|
||||||
.map((item, index) => timelineMarkForLine(item, index, denominator))
|
.map(({ item, index }) =>
|
||||||
|
timelineMarkForLine(item, index, denominator)
|
||||||
|
)
|
||||||
.filter((mark): mark is TimelineMark => mark !== null);
|
.filter((mark): mark is TimelineMark => mark !== null);
|
||||||
const trackHeight = timelineTrackHeight(metrics);
|
const trackHeight = timelineTrackHeight(metrics);
|
||||||
const positioned = positionTimelineMarks(rawMarks, trackHeight);
|
const positioned = positionTimelineMarks(rawMarks, trackHeight);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user