diff --git a/packages/session-ui/src/components/session-turn.tsx b/packages/session-ui/src/components/session-turn.tsx index 4ebf6459b1..2c7d7508ff 100644 --- a/packages/session-ui/src/components/session-turn.tsx +++ b/packages/session-ui/src/components/session-turn.tsx @@ -297,6 +297,7 @@ export function SessionTurn( const error = createMemo( () => assistantMessages().find((m) => m.error && m.error.name !== "MessageAbortedError")?.error, ) + const contentFiltered = createMemo(() => assistantMessages().some((m) => m.finish === "content-filter")) const showAssistantCopyPartID = createMemo(() => { const messages = assistantMessages() @@ -315,6 +316,7 @@ export function SessionTurn( return undefined }) const errorText = createMemo(() => { + if (contentFiltered()) return "The response was blocked by the provider's content filter" const msg = error()?.data?.message if (typeof msg === "string") return unwrap(msg) if (msg === undefined || msg === null) return "" @@ -525,7 +527,7 @@ export function SessionTurn( - + {errorText()} diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx index e2ece2fbd5..a4dc56258a 100644 --- a/packages/tui/src/routes/session/index.tsx +++ b/packages/tui/src/routes/session/index.tsx @@ -1197,9 +1197,13 @@ function AssistantFooter(props: { message: SessionMessageAssistant }) { const duration = createMemo(() => props.message.time.completed ? props.message.time.completed - props.message.time.created : 0, ) + const contentFiltered = createMemo(() => props.message.finish === "content-filter") + const errorText = createMemo(() => + contentFiltered() ? "The response was blocked by the provider's content filter" : errorMessage(props.message.error), + ) return ( <> - + - {errorMessage(props.message.error)} + {errorText()} - + - + {Locale.titlecase(props.message.agent)} · {model()} @@ -1386,13 +1394,7 @@ function UserMessage(props: { message: SessionMessageUser }) { > {props.message.text} - + {(file) => { const directory = file.mime === "application/x-directory" @@ -1452,6 +1454,10 @@ function AssistantMessage(props: { message: SessionMessageAssistant; last: boole if (!props.message.time.completed) return 0 return props.message.time.completed - props.message.time.created }) + const contentFiltered = createMemo(() => props.message.finish === "content-filter") + const errorText = createMemo(() => + contentFiltered() ? "The response was blocked by the provider's content filter" : errorMessage(props.message.error), + ) const exploration = createMemo(() => { const grouped = new Map() @@ -1514,7 +1520,7 @@ function AssistantMessage(props: { message: SessionMessageAssistant; last: boole )} - + - {errorMessage(props.message.error)} + {errorText()} - + - + {Locale.titlecase(props.message.agent)} · {model()} @@ -1722,7 +1733,8 @@ function ToolPart(props: { part: SessionMessageAssistantTool }) { return Boolean(shellID && data.shell.get(shellID)) } if (display() === "subagent") { - const sessionID = stringValue(props.part.state.structured.sessionID) ?? stringValue(props.part.state.structured.sessionId) + const sessionID = + stringValue(props.part.state.structured.sessionID) ?? stringValue(props.part.state.structured.sessionId) return Boolean(sessionID && data.session.status(sessionID) === "running") } return false diff --git a/packages/tui/test/cli/tui/session-rows.test.ts b/packages/tui/test/cli/tui/session-rows.test.ts index fec6f5eb87..4ffeef53fe 100644 --- a/packages/tui/test/cli/tui/session-rows.test.ts +++ b/packages/tui/test/cli/tui/session-rows.test.ts @@ -95,9 +95,7 @@ test("completes exploration groups when another row follows", () => { ]) finished.finish = "stop" const messages: SessionMessage[] = [ - assistant("assistant-1", [ - { type: "tool", id: "read-1", name: "read", state: pending(), time: { created: 1 } }, - ]), + assistant("assistant-1", [{ type: "tool", id: "read-1", name: "read", state: pending(), time: { created: 1 } }]), { type: "user", id: "user-1", text: "Continue", time: { created: 2 } }, finished, ] @@ -122,6 +120,13 @@ test("completes exploration groups when another row follows", () => { ]) }) +test("adds a footer for content-filter assistant finishes without parts", () => { + const filtered = assistant("assistant-filtered", []) + filtered.finish = "content-filter" + + expect(reduceSessionRows([filtered])).toEqual([{ type: "assistant-footer", messageID: "assistant-filtered" }]) +}) + test("hides synthetic messages without descriptions", () => { const messages: SessionMessage[] = [ assistant("assistant-1", [{ type: "tool", id: "read-1", name: "read", state: pending(), time: { created: 1 } }]),