evOo-local/VOICE.md
cynarAI 2c6b5c3d7b
chore: remove legacy orchestrator, trading and one-off leftovers (#109)
* chore: remove legacy orchestrator, trading and one-off script leftovers

The repository still carried the pre-evOo prototype: a Python orchestrator,
the old HTML "evoo-platform" cockpit (whose test ran in the root unit
suite), an apex-trading package, the hot-reload deploy.sh for it, a
permissions manifest, an architecture note with local file links, agent
handoff notes, a Steve Jobs persona template and about ninety one-off
scripts that probe a developer database with hard-coded local URLs. None
of it is used by the product, CI or the real deploy in ops/evo-deploy.

Delete those files, drop the evoo-platform test glob from the root vitest
config, the Cockpit section from .env.example and the dead biome and
gitignore entries, and update the docs that listed the removed tools.
scripts/start-tmux.sh no longer starts the removed sentinel and resolves
the checkout from its own location instead of a machine-specific path;
scripts/seed-ollama.ts requires DATABASE_URL instead of falling back to a
local URL with a username.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* fix(web): drop trading and persona prompts from the conversation shell

The web shell still showed leftovers from the trading prototype: composer
chips with German trading and "Steve Jobs" prompts, trading suggestion
chips under the empty conversation line, a German trading hero for the
empty transcript, and a German "data protection" status panel in the
sidebar. They suggested actions the product does not have and added
persistent chrome.

Remove the composer chips and their helper, the empty-state chips and the
hero (the empty conversation keeps its existing one-line start hint), the
sidebar trading indicator and the data trust panel. The new-bot E2E now
asserts the plain empty state; the sidebar spec no longer expects the
trading status, and the placeholder Steve Jobs spec with no assertions is
gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>

* refactor: remove the trading bot status integration

With the sidebar trading indicator gone, the only remaining consumer of
the trading bot status was a banner in General settings that reused the
same component. evOo is a personal assistant; a status proxy and poller
for one external trading service, configured through service-specific
TRADING_BOT_URL and VITE_TRADING_BOT_URL variables, does not belong in
the core product.

Remove the settings banner and its prop plumbing, the web poller, the
indicator component, the /api/trading-bot/status proxy, the shared core
contract, the env loading and both variables from .env.example, together
with their tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* chore: remove one-off database scripts and a stale review note

packages/db carried four hand-run scripts outside the package build that
query or seed a developer database with a hard-coded connection string,
one of them for a specific account. docs/VOICE-FIRST-REVIEW.md was a
one-time verification note for a workflow that no longer exists and
named private machines and local paths. Nothing references them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* chore: replace machine-specific paths and addresses with placeholders

ORIGIN.md pinned the intended checkout to an absolute path under a
personal home directory, docs/LOCAL-SETUP.md listed folders on one
developer's machine, and two tests used what looks like a real tailnet
address. Use a home-relative path, drop the machine-specific folder list,
and use 100.100.100.100 in the tests; it is still inside 100.64.0.0/10,
so both tests check the same thing as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

* test(web): drop the trading status from the shell contrast test

main's contrast test now waits for the sidebar trading status before
measuring; this branch removes that status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: cynarAI <cynarAI@users.noreply.github.com>
2026-10-04 01:13:52 +02:00

9.4 KiB
Raw Permalink Blame History

EvOo Voice — Interaction Model

Gesamterfahrung (encounter)

A conversation with an Oo is a shared encounter, not a thread with a tiny avatar:

Layer Role
Oo Stage Primary — large BotAvatar / persona presence, runtime pose, awareness strip
Transcript Secondary protocol — compact caption trail, scrollable record
Sound Calm procedural cues wired to real events (work finished, voice phases, handoffs)

Text mode (OoStage in Shell) and Voice mode (VoiceStage overlay) share the same metaphor: eyes/presence + space + sound. Brand lock (asymmetric Kulleraugen) is unchanged.

Product model — conversation-centric (Grok-like)

Oos (agents) exist, but the product is organized around conversations (Unterhaltungen), not “pick an agent row = the whole app”:

Layer What it is
Team Roster of your Oos — who you can talk to
1:1 Unterhaltung One Oo, one shared encounter (OoStage)
Gruppenunterhaltung Multiple Oos (+ humans later) in one encounter (OoGroupStage)
Projekte Group conversations organized in Ordner (BotSection folders in sidebar)
Mode Shell route Stage
Unterhaltung (1:1) /app/:botId OoStage — one Oo hero
Gruppenunterhaltung /app/g/:groupId?s=live OoGroupStage — active-speaker hero + ensemble row; Riffing when peers spark (docs/GROUP-CONVERSATIONS.md)
Project sessions /app/g/:groupId (timeline) No stage — session list (ProjectSessionTimeline)

Clicking an Oo in Team opens a 1:1 conversation, not “the agent product”. Clicking a project opens a group conversation or its session timeline. Gesamterfahrung (stage + sound + transcript record) applies to both conversation types.

Emergent ensemble: Das Ganze ist mehr als die Summe seiner Teile — power from distinct specialists + chemistry in groups, not one mega-agent (docs/PRODUCT.md).

Voice is the immersive primary mode for 1:1 bot conversations. Text chat uses the same stage-first layout; the transcript stays readable but no longer carries identity chrome.

Entry

Surface Action
Composer Voice pill Opens Voice Stage when a provider is connected; otherwise opens Voice settings
Transcript “Speak this reply” Reads one message aloud (text-first affordance, unchanged)

The composer and stage Voice controls use h-control-lg in neutral tokens; when voice is ready an iridescent aurora rim (VoiceAuroraRim) runs along the bottom edge.

Voice Stage

Full-screen dark layer with one glass panel (VoiceStage): the Oo, the live caption, and a control row. An iridescent aurora (VoiceAurora) rises from the panel's bottom edge. Its spectrum is the bot palette (botColors from @rakazo/ui-tokens) rotated so the active Oo's own color sits in the center.

Persona & consciousness layer

Persona is derived at runtime from existing bot fields (name, title, description) — aligned with templates/* archetypes, not a separate marketing field.

System Path
Archetype detection apps/web/src/lib/bot-persona.ts
i18n status copy apps/web/src/lib/voice-persona-copy.ts
Awareness strip VoiceAwarenessStrip — subagent, handoff, delegation, peer reply
Visual identity BotAvatar — persona shape + unified EvooMascot soul (eyes/mouth/hands) driven by voice phase
Voice delivery speaker.speak(..., { botId }) → server resolves per-bot voiceId

Archetypes include: CTO executive, chief operator (Fixer), builder (Dr. Eggbot), curator (Webby), work/life inboxes, home steward, quant, engineer, specialist (narrow fallback — no Wunderwuzzi). See docs/PRODUCT.md and docs/PERSONA-SELECTION.md.

Companion tone: geek-peer (fachsimpeln when wanted) or quiet-doer (execute without condescension) — inferred per user, not one voice for everyone.

Accessibility of ambition: grandma-simple entry (Thermomix to hard math — no power-user gate); expert-grade ceiling per specialty. Same product, different crews; never a mediocre everything-bot.

Phase labels, idle prompts, and thinking lines are character-specific (DE/EN via Lingui). Collaboration narration uses persona-aware phrasing (“casting”, “routing”, “handing off”) instead of generic tool labels.

States

Phase Visual Audio
Listening Aurora rises and brightens with mic energy, breathing Dictation active; silence endpoint sends
Thinking Aurora settles low and drifts side to side TTS idle; awaiting bot reply
Speaking Full aurora bloom, conductor mascot pose TTS playback; caption shown live

Aurora height and opacity follow dictation.energy (0–1) while listening (voiceAuroraBlobs in apps/web/src/lib/voice-aurora.ts). The caption (VoiceLiveText) fades each new word in; words already on screen stay put while an utterance grows and the caption restarts for a new one. Mascot uses EvooMascot poses: idle / thinking / wave.

Controls

The control row holds the persona phase label (live region), Transcript, Interrupt (mic), and Hang up (×).

Input Action
Space Interrupt (stop TTS or cancel dictation, resume listening)
Esc Hang up — exit Voice Stage
T Toggle transcript drawer (secondary record)

Transcript

Collapsible panel shows the last messages from the thread plus the live utterance. Chat scroll behind the stage is dimmed but unchanged; voice does not replace thread history in the database.

Accessibility

  • prefers-reduced-motion: reduce disables aurora breathing/drift, the panel entrance, and word fade-in; the static aurora remains.
  • Dialog semantics: role="dialog", aria-modal, labelled bot name.
  • Hang up exposes aria-label="Hang up".
  • Shortcuts are exposed through aria-keyshortcuts on the matching controls instead of on-screen hint text.

Architecture

Shell (composer Voice)
  └─ CallView (orchestration: dictation + speaker + thread send)
       └─ VoiceStage (panel, controls, transcript drawer)
            ├─ VoiceAurora (bottom-edge glow, phase + energy)
            └─ VoiceLiveText (word-by-word caption)

Shared singletons: dictation (apps/web/src/lib/dictation.ts), speaker (apps/web/src/lib/tts.ts).

Design tokens

Voice chrome uses text-ui-*, size-icon-*, and h-control-* / size-control-lg — no sub-13px labels on primary controls. See DESIGN.md for the full scale.

Sound language

Procedural Web Audio (oo-sound.ts, oo-vocals.ts, oo-audio-bus.ts) — no sample packs. Full motion/SFX spec: packages/ui-web/MOTION-EVOO-CHARACTER.md.

Cue Trigger
app-start Cold open — mint→violet shimmer
interact Primary nav / roster taps
success-resolve Run finished — mint→gold
need-you waiting_input / takeover — with ouh vocal
work-complete Alias of success-resolve
listening-start / listening-stop Voice phase
speaking-start / speaking-done TTS lifecycle
attention Run error in composer
message-sent Composer send
handoff / group-spark Thread collaboration

Reaction vocals (mh / Mhh nod, ouh, hm on success): state-change only, 8–12 s cooldown, −18…−12 LUFS via shared bus, duck under TTS/PTT.

Toggle: Settings → Voice → Sound feedback. prefers-reduced-motion: reduce → no vocals/SFX loops; character visual state only.

Current slice (this PR)

Stage + sound + onboarding reassurance — shared encounter without requiring the user to sit in front of the screen. Voice Stage is opt-in per session; text mode uses the same Oo Stage metaphor.

Ingo capability vision — document only until explicit opt-in flows exist. Not part of the current Gesamterfahrung slice.

Idea Product rule
Video calls optional Only when the user wants; a simpler audio-only path stays first-class for users who prefer it
"It's just an Oo" User does not need to sit in front constantly — practical help can be ambient (notifications, background runs, crew handoffs)
Ambient presence An Oo can carry a lot of practical presence without demanding attention — aligned with quiet-doer mode
Long-term metaphors (opt-in only) Could eventually stand in for an alarm system or a home camera — strictly user-opt-in, never default, never surveillance-as-a-feature

Hard gates (aligned with docs/OO-RELATIONSHIP.md)

  • No always-on camera or mic without a dedicated, revocable consent UX — not buried in ToS
  • Never creepy — warm competence, not uncanny stalking; earned context only
  • Not yes-men — push back on unsafe or over-broad monitoring requests
  • No Wunderwuzzi — home/security lanes are specialist Oos with narrow scope, not one omniscient watcher

When video or ambient sensing ships: same encounter grammar (Stage + sound + transcript), plus a visible presence mode indicator the user controls.

Out of scope (later)

  • Dedicated /voice route
  • Hold-to-talk in composer
  • WebGL / real audio analyser on TTS output
  • Always-on video / ambient camera without explicit consent UX (see roadmap above)