diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx index 87248a6a8ba..ca559f6cdc4 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-timeline.tsx @@ -1,8 +1,8 @@ import { createMemo, onMount } from "solid-js" import { useSync } from "@tui/context/sync" import { DialogSelect, type DialogSelectOption } from "@tui/ui/dialog-select" -import type { TextPart } from "@opencode-ai/sdk/v2" import { Locale } from "@/util/locale" +import { getVisibleTextPart } from "@tui/util/message-filter" import { DialogMessage } from "./dialog-message" import { useDialog } from "../../ui/dialog" import type { PromptInfo } from "../../component/prompt/history" @@ -24,9 +24,7 @@ export function DialogTimeline(props: { const result = [] as DialogSelectOption[] for (const message of messages) { if (message.role !== "user") continue - const part = (sync.data.part[message.id] ?? []).find( - (x) => x.type === "text" && !x.synthetic && !x.ignored, - ) as TextPart + const part = getVisibleTextPart(sync.data.part[message.id] ?? []) if (!part) continue result.push({ title: part.text.replace(/\n/g, " "), diff --git a/packages/opencode/src/cli/cmd/tui/util/message-filter.ts b/packages/opencode/src/cli/cmd/tui/util/message-filter.ts new file mode 100644 index 00000000000..3b248606a1c --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/util/message-filter.ts @@ -0,0 +1,16 @@ +import type { Part, TextPart } from "@opencode-ai/sdk/v2" + +/** + * Returns true if a part is a visible text part (not synthetic and not ignored). + */ +export function isVisibleTextPart(part: Part): part is TextPart { + return part.type === "text" && !part.synthetic && !part.ignored +} + +/** + * Returns the first visible text part from an array of parts. + * A visible text part is one that is not synthetic and not ignored. + */ +export function getVisibleTextPart(parts: Part[]): TextPart | undefined { + return parts.find(isVisibleTextPart) +}