- New App/Voice/{VoiceOrchestratorAdapter,VoiceTTSAdapter,VoiceBusEmitterAdapter,RejectReasonCopy}.swift
replaces NullOrchestratorAdapter / NullTTSAdapter / NullBusEmitterAdapter (D-09).
- VoiceOrchestratorAdapter forwards submit/cancelAndSubmit to AgentOrchestrator,
appends user-side text to TurnTranscriptStore (BLOCKER-1), enqueues a HUDBanner
on every SubmitOutcome.rejected case via shared RejectReasonCopy (D-10).
- VoiceTTSAdapter wraps an optional TTSEngineActor (engine construction lands
in a follow-on plan; nil-engine path no-ops gracefully).
- VoiceBusEmitterAdapter wraps an OutboundBatcher whose sink is the WebviewBridge
so audio-level RMS reaches the HUD's RingMesh pulse.
- AppDelegate.installVoice now uses the production adapters; install order
in applicationWillFinishLaunching reordered to vision -> agent -> voice
with voiceInstallTask awaiting agentInstallTask?.value (WARNING-5).
- New broadcaster .voice subscriber in installAgent: per-turn assistantText
accumulator + turnSourceWasVoice filter so text-originated turns NEVER drive
emitTurnEnded on the voice adapter (BLOCKER-2).
- SubmitOutcome.superseded extended with newTurnId so cancelAndSubmit callers
can append user text under the new turn id (BLOCKER-1 user-side closure on
the cancel path).
- VoiceSubscriberTextTurnFilterTests proves text turns never trigger
emitTurnEnded; VoiceOrchestratorAdapterTests covers RejectReasonCopy +
banner id mapping + VoiceBusEmitterAdapter forwarding.
- New scripts/check-install-order.sh + scripts/check-no-null-voice-adapters.sh
catch regressions structurally.
17 lines
548 B
Swift
17 lines
548 B
Swift
import Foundation
|
|
import Voice // BusOutboundEmitter
|
|
import Bus // OutboundBatcher
|
|
|
|
/// Production adapter bridging `Voice.BusOutboundEmitter` to `OutboundBatcher`.
|
|
/// Routes the ~30 Hz audio-level RMS values from `AudioLevelEmitter` into the
|
|
/// batcher so the HUD's RingMesh pulses with the mic level.
|
|
///
|
|
/// Phase 9 / Plan 4 / D-09: replaces `NullBusEmitterAdapter`.
|
|
struct VoiceBusEmitterAdapter: BusOutboundEmitter {
|
|
let batcher: OutboundBatcher
|
|
|
|
func postAudio(_ rms: Float) async {
|
|
await batcher.postAudio(rms)
|
|
}
|
|
}
|