Files
bot/docs/platforms/mac/voice-overlay.md
zeekay acaeda400a Eradicate OpenClaw — resolve merge conflicts and finish the rebrand
Three coordinated things:

1. Resolve the committed upstream/main merge conflicts. 94 files were
   sitting with raw <<<<<<< HEAD ... >>>>>>> upstream/main blocks. Every
   conflict had HanzoBot/Bot on HEAD and OpenClaw on upstream. Resolved
   by keeping HEAD everywhere — 540 conflict blocks.

2. Rewrite remaining OpenClaw text refs.
     OPENCLAW   → HANZO_BOT
     OpenClaw   → HanzoBot          (PascalCase type identifiers)
     openclaw   → bot               (codebase convention — botToken,
                                    botUsername etc.; avoids invalid
                                    hyphenated JS identifiers)
     openclaw[_]/openclaw[A-Z] → bot[_]/bot[A-Z]   (compound)
     ai.openclaw.x → ai.hanzo.bot.x  (JVM package path)

3. Delete or rename openclaw-named file paths (116 of them). Dead
   duplicates with a Bot-named canonical from the partial migration:
   deleted. Otherwise renamed.
     ai/openclaw/**           → deleted (ai/hanzo/bot/** canonical)
     Sources/OpenClaw*/       → deleted (Sources/Bot* canonical)
     Tests/OpenClawIPCTests/  → deleted (Tests/BotIPCTests canonical)
     OpenClawKit/             → deleted (BotKit canonical)
     openclaw-tools.*.ts      → deleted (bot-tools.*.ts canonical)
     openclaw-root.ts etc.    → deleted (bot-root.ts canonical)
     types.openclaw.ts        → deleted (types.bot.ts canonical)
     extensions/*/openclaw.plugin.json → renamed hanzo-bot.plugin.json
     docs/start/openclaw.md   → renamed hanzo-bot.md (+ zh-CN)
     docs/assets/openclaw-*.png, whatsapp-openclaw*.jpg → deleted
     scripts/.../openclaw-*   → deleted (bot/hanzo-bot parallels)
     openclaw.mjs             → deleted (hanzo-bot.mjs is package.bin)

Then patched 65 broken JS/TS import strings where hanzo-bot had ended
up inside an import path ('./types.hanzo-bot.js' → './types.bot.js'
etc., since the on-disk filename uses the brand-neutral bot- prefix).

Pre-existing lint debt cleaned up to get oxlint --type-aware to 0/0:
removed the dead i18n test that referenced a path no longer existing;
defined the missing DIDConfig and WalletConfig types in types.base.ts
(they were imported but never declared); dropped unused imports;
collapsed redundant type assertion and a tautological meta.bot lookup
that the openclaw→bot rename made redundant.

The a2ui.bundle.js generated artifact is kept at its pre-rebrand
contents — it gets regenerated by 'pnpm canvas:a2ui:bundle' from
sources I cannot rebuild in this commit; the source side is clean.

Verified: 0 occurrences of openclaw (case-insensitive) in tree source
content, 0 file or directory paths with openclaw in the name; oxlint
--type-aware src test reports 0/0.
2026-05-11 17:56:29 -07:00

3.7 KiB
Raw Permalink Blame History

summary, read_when, title
summary read_when title
Voice overlay lifecycle when wake-word and push-to-talk overlap
Adjusting voice overlay behavior
Voice Overlay

Voice Overlay Lifecycle (macOS)

Audience: macOS app contributors. Goal: keep the voice overlay predictable when wake-word and push-to-talk overlap.

Current intent

  • If the overlay is already visible from wake-word and the user presses the hotkey, the hotkey session adopts the existing text instead of resetting it. The overlay stays up while the hotkey is held. When the user releases: send if there is trimmed text, otherwise dismiss.
  • Wake-word alone still auto-sends on silence; push-to-talk sends immediately on release.

Implemented (Dec 9, 2025)

  • Overlay sessions now carry a token per capture (wake-word or push-to-talk). Partial/final/send/dismiss/level updates are dropped when the token doesn’t match, avoiding stale callbacks.
  • Push-to-talk adopts any visible overlay text as a prefix (so pressing the hotkey while the wake overlay is up keeps the text and appends new speech). It waits up to 1.5s for a final transcript before falling back to the current text.
  • Chime/overlay logging is emitted at info in categories voicewake.overlay, voicewake.ptt, and voicewake.chime (session start, partial, final, send, dismiss, chime reason).

Next steps

  1. VoiceSessionCoordinator (actor)
    • Owns exactly one VoiceSession at a time.
    • API (token-based): beginWakeCapture, beginPushToTalk, updatePartial, endCapture, cancel, applyCooldown.
    • Drops callbacks that carry stale tokens (prevents old recognizers from reopening the overlay).
  2. VoiceSession (model)
    • Fields: token, source (wakeWord|pushToTalk), committed/volatile text, chime flags, timers (auto-send, idle), overlayMode (display|editing|sending), cooldown deadline.
  3. Overlay binding
    • VoiceSessionPublisher (ObservableObject) mirrors the active session into SwiftUI.
    • VoiceWakeOverlayView renders only via the publisher; it never mutates global singletons directly.
    • Overlay user actions (sendNow, dismiss, edit) call back into the coordinator with the session token.
  4. Unified send path
    • On endCapture: if trimmed text is empty → dismiss; else performSend(session:) (plays send chime once, forwards, dismisses).
    • Push-to-talk: no delay; wake-word: optional delay for auto-send.
    • Apply a short cooldown to the wake runtime after push-to-talk finishes so wake-word doesn’t immediately retrigger.
  5. Logging
    • Coordinator emits .info logs in subsystem ai.hanzo.bot, categories voicewake.overlay and voicewake.chime.
    • Key events: session_started, adopted_by_push_to_talk, partial, finalized, send, dismiss, cancel, cooldown.

Debugging checklist

  • Stream logs while reproducing a sticky overlay:

    sudo log stream --predicate 'subsystem == "ai.hanzo.bot" AND category CONTAINS "voicewake"' --level info --style compact
    
  • Verify only one active session token; stale callbacks should be dropped by the coordinator.

  • Ensure push-to-talk release always calls endCapture with the active token; if text is empty, expect dismiss without chime or send.

Migration steps (suggested)

  1. Add VoiceSessionCoordinator, VoiceSession, and VoiceSessionPublisher.
  2. Refactor VoiceWakeRuntime to create/update/end sessions instead of touching VoiceWakeOverlayController directly.
  3. Refactor VoicePushToTalk to adopt existing sessions and call endCapture on release; apply runtime cooldown.
  4. Wire VoiceWakeOverlayController to the publisher; remove direct calls from runtime/PTT.
  5. Add integration tests for session adoption, cooldown, and empty-text dismissal.