From 81c4bfd7e30b3e370761643fd1983635bb4235c4 Mon Sep 17 00:00:00 2001 From: cynarAI <155274210+cynarAI@users.noreply.github.com> Date: Sat, 10 Oct 2026 09:55:01 +0200 Subject: [PATCH] web: move the 1:1 Oo status into the chat header (#193) The strip under the header of a running 1:1 chat repeated what the header already carried (a "Present" pill plus a persona line). The header's second line now shows what the Oo is doing (Working, Thinking, waiting for input, needs attention, or a delegation), and the bot's role while it rests. The stage only appears in an empty chat and no longer repeats the name. Claude-Session: https://claude.ai/code/session_01H3buE7EyYCfz8nYccLCcct Co-authored-by: Claude --- apps/web/e2e/oo-chat-header.spec.ts | 30 ++ apps/web/src/components/stage/OoStage.tsx | 271 +++++++----------- .../src/components/stage/use-oo-presence.ts | 133 +++++++++ apps/web/src/locales/de/messages.po | 11 +- apps/web/src/locales/en/messages.po | 11 +- apps/web/src/locales/es/messages.po | 11 +- apps/web/src/locales/hi/messages.po | 11 +- apps/web/src/locales/ko/messages.po | 11 +- apps/web/src/locales/pt-BR/messages.po | 11 +- apps/web/src/locales/ru/messages.po | 11 +- apps/web/src/locales/tr/messages.po | 11 +- apps/web/src/locales/zh-CN/messages.po | 11 +- apps/web/src/pages/Shell.tsx | 19 +- 13 files changed, 308 insertions(+), 244 deletions(-) create mode 100644 apps/web/e2e/oo-chat-header.spec.ts create mode 100644 apps/web/src/components/stage/use-oo-presence.ts diff --git a/apps/web/e2e/oo-chat-header.spec.ts b/apps/web/e2e/oo-chat-header.spec.ts new file mode 100644 index 0000000..369fc7d --- /dev/null +++ b/apps/web/e2e/oo-chat-header.spec.ts @@ -0,0 +1,30 @@ +import { expect, test } from "@playwright/test"; +import { captureScreenshot, completeOnboarding, signup } from "./helpers"; + +test("a 1:1 chat keeps name and status in the header instead of a banner", async ({ + page, +}, testInfo) => { + await page.setViewportSize({ width: 390, height: 844 }); + await signup(page, `oo-header-${Date.now()}@rakazo.test`, "password12", "Header QA"); + await completeOnboarding(page); + + const composer = page.getByRole("combobox", { name: /^Message/ }); + await composer.fill("Please review `shared/PROJECT_CHECKPOINT_WRAPUP.md`."); + await composer.press("Enter"); + await expect( + page + .getByTestId("transcript") + .locator("[data-message-id]") + .filter({ hasText: "done. i handled:" }), + ).toBeVisible({ timeout: 30_000 }); + + await expect(page.getByTestId("oo-stage")).toHaveCount(0); + await expect(page.getByTestId("bot-settings-trigger")).toBeVisible(); + + await page.emulateMedia({ colorScheme: "light" }); + await expect(page.locator("html")).toHaveAttribute("data-theme", "light"); + await captureScreenshot(page, testInfo, "oo-chat-header-light"); + await page.emulateMedia({ colorScheme: "dark" }); + await expect(page.locator("html")).toHaveAttribute("data-theme", "dark"); + await captureScreenshot(page, testInfo, "oo-chat-header-dark"); +}); diff --git a/apps/web/src/components/stage/OoStage.tsx b/apps/web/src/components/stage/OoStage.tsx index 9817ee8..3d6c5cf 100644 --- a/apps/web/src/components/stage/OoStage.tsx +++ b/apps/web/src/components/stage/OoStage.tsx @@ -26,7 +26,9 @@ import { personaIdlePrompt, personaThinkingLines } from "../../lib/voice-persona import { VoiceAwarenessStrip } from "../voice/VoiceAwarenessStrip"; import { StageHero } from "./StageHero"; import { TextStageCanvas } from "./TextStageCanvas"; +import { useOoPresence } from "./use-oo-presence"; +/** The empty 1:1 chat: the Oo greets. Name and live status live in the chat header. */ export function OoStage({ botId, botName, @@ -36,7 +38,6 @@ export function OoStage({ botStatus, snapshot, running, - hasMessages, }: { botId: string; botName: string; @@ -46,117 +47,24 @@ export function OoStage({ botStatus?: string; snapshot: ThreadSnapshot | null; running: boolean; - hasMessages: boolean; }) { const { t } = useLingui(); - const [reducedMotion, setReducedMotion] = useState(false); - const [thinkingIndex, setThinkingIndex] = useState(0); - - const persona = useMemo( - () => - resolveBotPersona({ - name: botName, - title: botTitle, - description: botDescription, - }), - [botName, botTitle, botDescription], - ); - - const streaming = useMemo( - () => - (snapshot?.messages ?? []).some( - (message) => - message.id.startsWith("progress:") && - message.blocks.some((block) => block.kind === "progress" || block.kind === "text"), - ), - [snapshot?.messages], - ); - - const awarenessEvent = useMemo( - () => extractVoiceAwareness(snapshot, botName), - [snapshot, botName], - ); - const collaborating = Boolean(awarenessEvent); - - const phase = resolveTextStagePhase({ - running, - botStatus, - streaming, - hasMessages, - awareness: awarenessEvent, - }); - - const pose = - phase === "idle" && !hasMessages - ? "greeting" - : personaTextPose( - persona, - phase, - collaborating && - (awarenessEvent?.kind === "subagent" || - awarenessEvent?.kind === "handoff" || - awarenessEvent?.kind === "delegation"), - ); - - const thinkingLines = useMemo( - () => personaThinkingLines(persona.archetype).map((line) => t(line)), - [persona.archetype, t], - ); - - useEffect(() => { - const media = window.matchMedia("(prefers-reduced-motion: reduce)"); - function sync() { - setReducedMotion(media.matches); - } - sync(); - media.addEventListener("change", sync); - return () => media.removeEventListener("change", sync); - }, []); - - useEffect(() => { - if (phase !== "working" && phase !== "thinking") return; - const interval = setInterval(() => { - setThinkingIndex((index) => (index + 1) % Math.max(thinkingLines.length, 1)); - }, cadencePulseMs(persona.cadence)); - return () => clearInterval(interval); - }, [phase, persona.cadence, thinkingLines.length]); - - const awarenessLabel = awarenessEvent - ? narrateAwarenessForPersona(persona, awarenessEvent) - : null; - - const subtitle = useMemo(() => { - if (awarenessLabel) return awarenessLabel; - if (phase === "error") return t`Something needs your attention.`; - if (phase === "working" || phase === "thinking") { - return thinkingLines[thinkingIndex] ?? t`Working on your request…`; - } - if (phase === "listening") return t`Waiting for your input…`; - if (phase === "speaking") return t`Composing a reply…`; - return t(personaIdlePrompt(persona.archetype)); - }, [awarenessLabel, phase, persona.archetype, t, thinkingIndex, thinkingLines]); - - const energy = - phase === "speaking" ? 0.65 : phase === "working" || phase === "thinking" ? 0.48 : 0.18; - - const phaseLabel = - phase === "working" - ? t`Working` - : phase === "listening" - ? t`Listening` - : phase === "thinking" - ? t`Thinking` - : phase === "speaking" - ? t`Speaking` - : phase === "error" - ? t`Needs attention` - : t`Present`; + const { persona, phase, pose, subtitle, energy, reducedMotion, awarenessEvent, awarenessLabel } = + useOoPresence({ + botName, + botTitle, + botDescription, + botStatus, + snapshot, + running, + hasMessages: false, + }); return (
-
- {(hasMessages || phase !== "idle") && ( -
-
- - {phaseLabel} -
-
- )} - {!hasMessages ? ( -
-

- {botName} -

- {persona.roleLine ? ( -

- {persona.roleLine} -

- ) : null} -
- ) : null} - +
{awarenessLabel && awarenessEvent ? (
) : null} - {!hasMessages ? ( - <> - -

- {subtitle} -

- - ) : ( -

- {subtitle} -

- )} + +

+ {subtitle} +

); } +/** Second header line of a 1:1 chat: what the Oo is doing, or its role while it rests. */ +export function OoHeaderStatus({ + botName, + botTitle, + botDescription, + botStatus, + snapshot, + running, + hasMessages, +}: { + botName: string; + botTitle: string; + botDescription: string; + botStatus?: string; + snapshot: ThreadSnapshot | null; + running: boolean; + hasMessages: boolean; +}) { + const { t } = useLingui(); + const { phase, awarenessLabel, reducedMotion } = useOoPresence({ + botName, + botTitle, + botDescription, + botStatus, + snapshot, + running, + hasMessages, + }); + const text = + phase === "idle" + ? botTitle.trim() + : (awarenessLabel ?? + (phase === "working" + ? t`Working` + : phase === "thinking" + ? t`Thinking` + : phase === "speaking" + ? t`Speaking` + : phase === "listening" + ? t`Waiting for your input…` + : t`Needs attention`)); + if (!text) return null; + return ( + + {phase === "idle" ? null : ( + + ); +} + function StageEnsemble({ members, workingBotIds, diff --git a/apps/web/src/components/stage/use-oo-presence.ts b/apps/web/src/components/stage/use-oo-presence.ts new file mode 100644 index 0000000..566135e --- /dev/null +++ b/apps/web/src/components/stage/use-oo-presence.ts @@ -0,0 +1,133 @@ +import { useLingui } from "@lingui/react/macro"; +import type { ThreadSnapshot } from "@rakazo/contracts"; +import { useEffect, useMemo, useState } from "react"; +import { + cadencePulseMs, + extractVoiceAwareness, + narrateAwarenessForPersona, + personaTextPose, + resolveBotPersona, + resolveTextStagePhase, +} from "../../lib/bot-persona"; +import { personaIdlePrompt, personaThinkingLines } from "../../lib/voice-persona-copy"; + +/** What a 1:1 Oo is doing right now, shared by the chat header and the empty-chat stage. */ +export function useOoPresence({ + botName, + botTitle, + botDescription, + botStatus, + snapshot, + running, + hasMessages, +}: { + botName: string; + botTitle: string; + botDescription: string; + botStatus?: string; + snapshot: ThreadSnapshot | null; + running: boolean; + hasMessages: boolean; +}) { + const { t } = useLingui(); + const [reducedMotion, setReducedMotion] = useState(false); + const [thinkingIndex, setThinkingIndex] = useState(0); + + const persona = useMemo( + () => + resolveBotPersona({ + name: botName, + title: botTitle, + description: botDescription, + }), + [botName, botTitle, botDescription], + ); + + const streaming = useMemo( + () => + (snapshot?.messages ?? []).some( + (message) => + message.id.startsWith("progress:") && + message.blocks.some((block) => block.kind === "progress" || block.kind === "text"), + ), + [snapshot?.messages], + ); + + const awarenessEvent = useMemo( + () => extractVoiceAwareness(snapshot, botName), + [snapshot, botName], + ); + const collaborating = Boolean(awarenessEvent); + + const phase = resolveTextStagePhase({ + running, + botStatus, + streaming, + hasMessages, + awareness: awarenessEvent, + }); + + const pose = + phase === "idle" && !hasMessages + ? "greeting" + : personaTextPose( + persona, + phase, + collaborating && + (awarenessEvent?.kind === "subagent" || + awarenessEvent?.kind === "handoff" || + awarenessEvent?.kind === "delegation"), + ); + + const thinkingLines = useMemo( + () => personaThinkingLines(persona.archetype).map((line) => t(line)), + [persona.archetype, t], + ); + + useEffect(() => { + const media = window.matchMedia("(prefers-reduced-motion: reduce)"); + function sync() { + setReducedMotion(media.matches); + } + sync(); + media.addEventListener("change", sync); + return () => media.removeEventListener("change", sync); + }, []); + + useEffect(() => { + if (phase !== "working" && phase !== "thinking") return; + const interval = setInterval(() => { + setThinkingIndex((index) => (index + 1) % Math.max(thinkingLines.length, 1)); + }, cadencePulseMs(persona.cadence)); + return () => clearInterval(interval); + }, [phase, persona.cadence, thinkingLines.length]); + + const awarenessLabel = awarenessEvent + ? narrateAwarenessForPersona(persona, awarenessEvent) + : null; + + const subtitle = useMemo(() => { + if (awarenessLabel) return awarenessLabel; + if (phase === "error") return t`Something needs your attention.`; + if (phase === "working" || phase === "thinking") { + return thinkingLines[thinkingIndex] ?? t`Working on your request…`; + } + if (phase === "listening") return t`Waiting for your input…`; + if (phase === "speaking") return t`Composing a reply…`; + return t(personaIdlePrompt(persona.archetype)); + }, [awarenessLabel, phase, persona.archetype, t, thinkingIndex, thinkingLines]); + + const energy = + phase === "speaking" ? 0.65 : phase === "working" || phase === "thinking" ? 0.48 : 0.18; + + return { + persona, + phase, + pose, + subtitle, + energy, + reducedMotion, + awarenessEvent, + awarenessLabel, + } as const; +} diff --git a/apps/web/src/locales/de/messages.po b/apps/web/src/locales/de/messages.po index 5680578..3315a97 100644 --- a/apps/web/src/locales/de/messages.po +++ b/apps/web/src/locales/de/messages.po @@ -1040,10 +1040,6 @@ msgstr "Hase" msgid "Bushy" msgstr "Buschig" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "Beschäftigt" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "Ruhige Hinweistöne für erledigte Arbeit, Sprachphasen und Übergaben. Berücksichtigt reduzierte Bewegung." @@ -1409,7 +1405,7 @@ msgstr "Kommunikationsstil" msgid "Complete" msgstr "Abschließen" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "Schreibt eine Antwort…" @@ -4855,7 +4851,7 @@ msgstr "Zart" msgid "Software update" msgstr "Software-Update" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "Etwas braucht deine Aufmerksamkeit." @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "Warte, bis die API wieder da ist…" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "Wartet auf deine Eingabe…" @@ -5706,7 +5703,7 @@ msgstr "Arbeitet" msgid "Working in my lane…" msgstr "Arbeite in meinem Fachgebiet…" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "Arbeitet an deiner Anfrage…" diff --git a/apps/web/src/locales/en/messages.po b/apps/web/src/locales/en/messages.po index 3b434df..891fcbe 100644 --- a/apps/web/src/locales/en/messages.po +++ b/apps/web/src/locales/en/messages.po @@ -1040,10 +1040,6 @@ msgstr "Bunny" msgid "Bushy" msgstr "Bushy" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "Busy" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." @@ -1409,7 +1405,7 @@ msgstr "Communication style" msgid "Complete" msgstr "Complete" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "Composing a reply…" @@ -4855,7 +4851,7 @@ msgstr "Soft" msgid "Software update" msgstr "Software update" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "Something needs your attention." @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "Waiting for the API to come back…" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "Waiting for your input…" @@ -5706,7 +5703,7 @@ msgstr "Working" msgid "Working in my lane…" msgstr "Working in my lane…" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "Working on your request…" diff --git a/apps/web/src/locales/es/messages.po b/apps/web/src/locales/es/messages.po index c09f376..74a0921 100644 --- a/apps/web/src/locales/es/messages.po +++ b/apps/web/src/locales/es/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "Completado" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "Actualización de software" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "Esperando a que vuelva la API…" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/locales/hi/messages.po b/apps/web/src/locales/hi/messages.po index 00ec7b7..ab8f7b7 100644 --- a/apps/web/src/locales/hi/messages.po +++ b/apps/web/src/locales/hi/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "पूर्ण" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/locales/ko/messages.po b/apps/web/src/locales/ko/messages.po index 7d3d41e..299bb31 100644 --- a/apps/web/src/locales/ko/messages.po +++ b/apps/web/src/locales/ko/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "완료" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "소프트웨어 업데이트" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "API가 다시 작동하기를 기다리는 중…" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/locales/pt-BR/messages.po b/apps/web/src/locales/pt-BR/messages.po index dcccea2..2aa0a6d 100644 --- a/apps/web/src/locales/pt-BR/messages.po +++ b/apps/web/src/locales/pt-BR/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "Concluir" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/locales/ru/messages.po b/apps/web/src/locales/ru/messages.po index 12bfba2..7eb2672 100644 --- a/apps/web/src/locales/ru/messages.po +++ b/apps/web/src/locales/ru/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "Завершить" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "Обновление программного обеспечения" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "Ждём возвращения API…" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/locales/tr/messages.po b/apps/web/src/locales/tr/messages.po index 8cd0d65..1bc865a 100644 --- a/apps/web/src/locales/tr/messages.po +++ b/apps/web/src/locales/tr/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "Tamamlandı" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/locales/zh-CN/messages.po b/apps/web/src/locales/zh-CN/messages.po index 7d442f0..4a161ef 100644 --- a/apps/web/src/locales/zh-CN/messages.po +++ b/apps/web/src/locales/zh-CN/messages.po @@ -1040,10 +1040,6 @@ msgstr "" msgid "Bushy" msgstr "" -#: src/pages/Shell.tsx -msgid "Busy" -msgstr "" - #: src/pages/VoiceSettingsOverlay.tsx msgid "Calm audio cues for finished work, voice phases, and handoffs. Respects reduced motion." msgstr "" @@ -1409,7 +1405,7 @@ msgstr "" msgid "Complete" msgstr "完成" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Composing a reply…" msgstr "" @@ -4855,7 +4851,7 @@ msgstr "" msgid "Software update" msgstr "软件更新" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Something needs your attention." msgstr "" @@ -5553,6 +5549,7 @@ msgid "Waiting for the API to come back…" msgstr "正在等待 API 恢复…" #: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Waiting for your input…" msgstr "" @@ -5706,7 +5703,7 @@ msgstr "" msgid "Working in my lane…" msgstr "" -#: src/components/stage/OoStage.tsx +#: src/components/stage/use-oo-presence.ts msgid "Working on your request…" msgstr "" diff --git a/apps/web/src/pages/Shell.tsx b/apps/web/src/pages/Shell.tsx index a4e36fe..6b7bfac 100644 --- a/apps/web/src/pages/Shell.tsx +++ b/apps/web/src/pages/Shell.tsx @@ -91,7 +91,7 @@ import { ArtifactPane } from "../components/ArtifactPane"; import { InAppBrowser } from "../components/browser/InAppBrowser"; import { ComputerUpdateProgress } from "../components/ComputerUpdateProgress"; import { MainInbox } from "../components/MainInbox"; -import { OoGroupStage, OoStage } from "../components/stage/OoStage"; +import { OoGroupStage, OoHeaderStatus, OoStage } from "../components/stage/OoStage"; import { useSidebarResize } from "../hooks/useSidebarResize"; import { useWideLayout } from "../hooks/useWideLayout"; import { readActivityMode, writeActivityMode } from "../lib/activity-mode"; @@ -3357,10 +3357,16 @@ export function ShellPage() { ? (activeGroup?.name ?? activeSnapshot?.groupName ?? t`Group`) : (active?.name ?? t`Choose a conversation`)} - {!inGroup && active && (composerRunning || active.status !== "idle") ? ( - - {composerRunning || active.status === "running" ? t`Busy` : active.status} - + {!inGroup && active ? ( + 0} + /> ) : multiOoInGroup && projectSessionKey ? ( {t`Group conversation`} @@ -3459,7 +3465,7 @@ export function ShellPage() { ) : ( <> - {!callOpen && active && !inGroup ? ( + {!callOpen && active && !inGroup && transcriptMessages.length === 0 ? ( 0} /> ) : null} {!callOpen && inGroup ? (