@agimon-ai/doompi-voice 0.0.1-alpha.13 → 0.0.1-alpha.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/adapters/pi/minorModeCatalog.cjs +2 -0
  2. package/dist/adapters/pi/minorModeCatalog.cjs.map +1 -0
  3. package/dist/adapters/pi/minorModeCatalog.mjs +2 -0
  4. package/dist/adapters/pi/minorModeCatalog.mjs.map +1 -0
  5. package/dist/adapters/pi/voice.cjs +1 -1
  6. package/dist/adapters/pi/voice.cjs.map +1 -1
  7. package/dist/adapters/pi/voice.d.cts +1 -11
  8. package/dist/adapters/pi/voice.d.cts.map +1 -1
  9. package/dist/adapters/pi/voice.d.mts +1 -11
  10. package/dist/adapters/pi/voice.d.mts.map +1 -1
  11. package/dist/adapters/pi/voice.mjs +1 -1
  12. package/dist/adapters/pi/voice.mjs.map +1 -1
  13. package/dist/adapters/pi/voiceCommandContext.cjs +2 -0
  14. package/dist/adapters/pi/voiceCommandContext.cjs.map +1 -0
  15. package/dist/adapters/pi/voiceCommandContext.mjs +2 -0
  16. package/dist/adapters/pi/voiceCommandContext.mjs.map +1 -0
  17. package/dist/adapters/process/turnSpool.cjs +1 -1
  18. package/dist/adapters/process/turnSpool.cjs.map +1 -1
  19. package/dist/adapters/process/turnSpool.mjs +1 -1
  20. package/dist/adapters/process/turnSpool.mjs.map +1 -1
  21. package/dist/adapters/process/voiceWorkerAutoCaptureController.cjs +1 -1
  22. package/dist/adapters/process/voiceWorkerAutoCaptureController.cjs.map +1 -1
  23. package/dist/adapters/process/voiceWorkerAutoCaptureController.d.cts +4 -0
  24. package/dist/adapters/process/voiceWorkerAutoCaptureController.d.cts.map +1 -1
  25. package/dist/adapters/process/voiceWorkerAutoCaptureController.d.mts +4 -0
  26. package/dist/adapters/process/voiceWorkerAutoCaptureController.d.mts.map +1 -1
  27. package/dist/adapters/process/voiceWorkerAutoCaptureController.mjs +1 -1
  28. package/dist/adapters/process/voiceWorkerAutoCaptureController.mjs.map +1 -1
  29. package/dist/adapters/process/voiceWorkerPipeline.cjs +1 -1
  30. package/dist/adapters/process/voiceWorkerPipeline.cjs.map +1 -1
  31. package/dist/adapters/process/voiceWorkerPipeline.mjs +1 -1
  32. package/dist/adapters/process/voiceWorkerPipeline.mjs.map +1 -1
  33. package/dist/extensions/doom.cjs +1 -1
  34. package/dist/extensions/doom.cjs.map +1 -1
  35. package/dist/extensions/doom.d.cts.map +1 -1
  36. package/dist/extensions/doom.d.mts.map +1 -1
  37. package/dist/extensions/doom.mjs +1 -1
  38. package/dist/extensions/doom.mjs.map +1 -1
  39. package/dist/index.cjs +1 -1
  40. package/dist/index.d.cts +3 -2
  41. package/dist/index.d.mts +3 -2
  42. package/dist/index.mjs +1 -1
  43. package/dist/services/voice/autoCapture.cjs +1 -0
  44. package/dist/services/voice/autoCapture.cjs.map +1 -1
  45. package/dist/services/voice/autoCapture.d.cts +2 -0
  46. package/dist/services/voice/autoCapture.d.cts.map +1 -1
  47. package/dist/services/voice/autoCapture.d.mts +2 -0
  48. package/dist/services/voice/autoCapture.d.mts.map +1 -1
  49. package/dist/services/voice/autoCapture.mjs +1 -0
  50. package/dist/services/voice/autoCapture.mjs.map +1 -1
  51. package/dist/services/voice/autonomousNarration.cjs +1 -1
  52. package/dist/services/voice/autonomousNarration.cjs.map +1 -1
  53. package/dist/services/voice/autonomousNarration.mjs +1 -1
  54. package/dist/services/voice/autonomousNarration.mjs.map +1 -1
  55. package/dist/services/voice/autonomousVoiceSession.cjs +1 -1
  56. package/dist/services/voice/autonomousVoiceSession.cjs.map +1 -1
  57. package/dist/services/voice/autonomousVoiceSession.mjs +1 -1
  58. package/dist/services/voice/autonomousVoiceSession.mjs.map +1 -1
  59. package/dist/services/voice/commandCorrection.cjs +7 -0
  60. package/dist/services/voice/commandCorrection.cjs.map +1 -0
  61. package/dist/services/voice/commandCorrection.d.cts +34 -0
  62. package/dist/services/voice/commandCorrection.d.cts.map +1 -0
  63. package/dist/services/voice/commandCorrection.d.mts +34 -0
  64. package/dist/services/voice/commandCorrection.d.mts.map +1 -0
  65. package/dist/services/voice/commandCorrection.mjs +7 -0
  66. package/dist/services/voice/commandCorrection.mjs.map +1 -0
  67. package/dist/services/voice/voice.d.cts +2 -2
  68. package/dist/services/voice/voice.d.mts +2 -2
  69. package/package.json +5 -5
@@ -0,0 +1,2 @@
1
+ let e=require("@agimon-ai/doompi-extension-contracts/mode"),t=require("@agimon-ai/doompi-extension-contracts/protocol");function n(n){let r=(0,e.createMinorModeCatalogClient)(),i;return{bind(e){i?.(),i=r.bind((0,t.createProtocolRuntime)({bus:n.events,source:`@agimon-ai/doompi-voice`,sessionId:e}))},records:()=>r.getSnapshot()?.modes,dispose(){i?.(),i=void 0,r.dispose()}}}exports.createVoiceMinorModeCatalog=n;
2
+ //# sourceMappingURL=minorModeCatalog.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minorModeCatalog.cjs","names":["createMinorModeCatalogClient","createProtocolRuntime"],"sources":["../../../src/adapters/pi/minorModeCatalog.ts"],"sourcesContent":["import { createMinorModeCatalogClient, type MinorModeRecord } from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-voice';\n\nexport interface VoiceMinorModeCatalog {\n bind(sessionId: string): void;\n records(): readonly MinorModeRecord[] | undefined;\n dispose(): void;\n}\n\nexport function createVoiceMinorModeCatalog(pi: ExtensionAPI): VoiceMinorModeCatalog {\n const client = createMinorModeCatalogClient();\n let disposeBinding: (() => void) | undefined;\n return {\n bind(sessionId) {\n disposeBinding?.();\n disposeBinding = client.bind(createProtocolRuntime({ bus: pi.events, source: PACKAGE_SOURCE, sessionId }));\n },\n records: () => client.getSnapshot()?.modes,\n dispose() {\n disposeBinding?.();\n disposeBinding = undefined;\n client.dispose();\n },\n };\n}\n"],"mappings":"wHAYA,SAAgB,EAA4B,EAAyC,CACnF,IAAM,GAAA,EAASA,EAAAA,6BAAAA,CAA6B,EACxC,EACJ,MAAO,CACL,KAAK,EAAW,CACd,IAAiB,EACjB,EAAiB,EAAO,MAAA,EAAKC,EAAAA,sBAAAA,CAAsB,CAAE,IAAK,EAAG,OAAQ,OAAQ,0BAAgB,WAAU,CAAC,CAAC,CAC3G,EACA,YAAe,EAAO,YAAY,CAAC,EAAE,MACrC,SAAU,CACR,IAAiB,EACjB,EAAiB,IAAA,GACjB,EAAO,QAAQ,CACjB,CACF,CACF"}
@@ -0,0 +1,2 @@
1
+ import{createMinorModeCatalogClient as e}from"@agimon-ai/doompi-extension-contracts/mode";import{createProtocolRuntime as t}from"@agimon-ai/doompi-extension-contracts/protocol";function n(n){let r=e(),i;return{bind(e){i?.(),i=r.bind(t({bus:n.events,source:`@agimon-ai/doompi-voice`,sessionId:e}))},records:()=>r.getSnapshot()?.modes,dispose(){i?.(),i=void 0,r.dispose()}}}export{n as createVoiceMinorModeCatalog};
2
+ //# sourceMappingURL=minorModeCatalog.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minorModeCatalog.mjs","names":[],"sources":["../../../src/adapters/pi/minorModeCatalog.ts"],"sourcesContent":["import { createMinorModeCatalogClient, type MinorModeRecord } from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createProtocolRuntime } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-voice';\n\nexport interface VoiceMinorModeCatalog {\n bind(sessionId: string): void;\n records(): readonly MinorModeRecord[] | undefined;\n dispose(): void;\n}\n\nexport function createVoiceMinorModeCatalog(pi: ExtensionAPI): VoiceMinorModeCatalog {\n const client = createMinorModeCatalogClient();\n let disposeBinding: (() => void) | undefined;\n return {\n bind(sessionId) {\n disposeBinding?.();\n disposeBinding = client.bind(createProtocolRuntime({ bus: pi.events, source: PACKAGE_SOURCE, sessionId }));\n },\n records: () => client.getSnapshot()?.modes,\n dispose() {\n disposeBinding?.();\n disposeBinding = undefined;\n client.dispose();\n },\n };\n}\n"],"mappings":"iLAYA,SAAgB,EAA4B,EAAyC,CACnF,IAAM,EAAS,EAA6B,EACxC,EACJ,MAAO,CACL,KAAK,EAAW,CACd,IAAiB,EACjB,EAAiB,EAAO,KAAK,EAAsB,CAAE,IAAK,EAAG,OAAQ,OAAQ,0BAAgB,WAAU,CAAC,CAAC,CAC3G,EACA,YAAe,EAAO,YAAY,CAAC,EAAE,MACrC,SAAU,CACR,IAAiB,EACjB,EAAiB,IAAA,GACjB,EAAO,QAAQ,CACjB,CACF,CACF"}
@@ -1,2 +1,2 @@
1
- const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../types/index.cjs"),n=require("../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.cjs"),r=require("../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateMetadata.cjs"),i=require("../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateParam.cjs"),a=require("../audio/infrastructure.cjs"),o=require("../../services/voice/narration.cjs"),s=require("../../services/voice/semanticEcho.cjs"),c=require("../../services/voice/autoCapture.cjs"),l=require("../process/voiceWorkerAutoCaptureController.cjs"),u=require("../process/voiceWorkerSessionController.cjs"),d=require("../transcription/whisper.cjs");let f=require("node:fs");f=e.__toESM(f,1);let p=require("node:os");p=e.__toESM(p,1);let m=require("node:path");m=e.__toESM(m,1);let h=require("inversify");require("reflect-metadata");let g=require("@agimon-ai/doompi-config/config"),_=require("@agimon-ai/doompi-config/types"),v=require("@agimon-ai/doompi-extension-contracts"),y=require("@agimon-ai/doompi-extension-contracts/narration"),b=require("@agimon-ai/doompi-telemetry");const x=`voice`,S=`voice-auto`,C=`doom-voice`,w=[`·`,`•`,`●`,`•`],T=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`],E=`info`,D=`error`,O=`doom_voice.transcription_finished`,k=`idle`,A=`recording`,j=`transcribing`,M=[{id:`voice.toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`v`,label:`toggle`,detail:`record or transcribe`}],command:{name:x}},{id:`voice.auto-toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`a`,label:`auto`,detail:`continuous autonomous conversation`}],command:{name:S}}];function N(e){let t=e.state===A?w:T,n=t[Math.max(0,Math.floor(e.frameIndex))%t.length],r=e.state===A?`warning`:`accent`,i=Math.max(0,Math.floor(e.elapsedSeconds??0));return{statusText:e.state===A?`${n} voice: recording ${Math.floor(i/60)}:${String(i%60).padStart(2,`0`)}`:`${n} voice: transcribing`,footer:{fullText:n,compactText:n,fullSegments:[{text:n,color:r}],compactSegments:[{text:n,color:r}]}}}function P(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:(t,n)=>e.ui.setStatus(t,n),setIndicator:e=>t.update(e?N(e).footer:void 0),getEditorText:()=>e.ui.getEditorText(),setEditorText:t=>e.ui.setEditorText(t)}}function F(e){let t=e===`listening`?{frame:`A`,statusText:`voice auto: listening`,color:`accent`}:e===`speech`?{frame:`!`,statusText:`voice auto: hearing speech`,color:`warning`}:e===`processing`?{frame:`…`,statusText:`voice auto: processing while listening`,color:`accent`}:e===`narrating`?{frame:`A`,statusText:`voice auto: narrating and listening`,color:`accent`}:e===`confirming`?{frame:`?`,statusText:`voice auto: confirmation needed`,color:`warning`}:e===`waiting`?{frame:`…`,statusText:`voice auto: waiting for keyboard input`,color:`warning`}:{frame:`A`,statusText:`voice auto: draining`,color:`warning`};return{statusText:t.statusText,footer:{fullText:t.frame,compactText:t.frame,fullSegments:[{text:t.frame,color:t.color}],compactSegments:[{text:t.frame,color:t.color}]}}}function I(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:t=>e.ui.setStatus(C,t),setIndicator:e=>t.update(e?F(e).footer:void 0)}}function L(e,t,n,r=`immediate`){if(t.isIdle()){e.sendUserMessage(n);return}e.sendUserMessage(n,{deliverAs:r===`queuedFollowUp`?`followUp`:`steer`})}function R(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function z(e){return R(e)&&typeof e.active==`boolean`}function B(e){if(!R(e)||e.role!==`assistant`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(R(n)){if(n.type===`toolCall`)return{text:t.join(``).trim()};n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}}function V(e){if(!R(e)||e.role!==`assistant`||e.stopReason===`toolUse`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(R(n)){if(n.type===`toolCall`)return;n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}return t.join(``).trim()||void 0}function H(e,t,n){return e!==`write_plan`||t||!R(n)?!1:R(n.details)&&n.details.written===!0}function U(e,t,n){return(0,y.subscribeToNarrationRequests)({bus:e,source:`@agimon-ai/doompi-voice`,sessionId:t},({text:e})=>n.narrate(e))}function W(e,t){e.events?.on(v.ASK_USER_BLOCKED_EVENT,e=>{z(e)&&t.askUserBlocked(e.active)}),e.on(`input`,e=>{t.observeInput({text:e.text,source:e.source,...e.streamingBehavior?{streamingBehavior:e.streamingBehavior}:{}})}),e.on(`before_agent_start`,e=>t.beforeAgentStart(e.prompt)),e.on(`agent_start`,()=>t.agentStarted()),e.on(`message_end`,e=>{let n=B(e.message);n&&t.finalizedAssistantIntent(n.text)}),e.on(`tool_execution_end`,e=>{H(e.toolName,e.isError,e.result)&&t.planWritten()}),e.on(`turn_end`,e=>{let n=e.message;t.turnFinished(e.turnIndex,n.role===`assistant`?n.stopReason:`unknown`,e.toolResults.length,V(n))}),e.on(`agent_settled`,async()=>t.agentSettled())}function G(e,t){let n=e.indexOf(`/`);if(n<=0||n===e.length-1)throw Error(`Autonomous voice model must use provider/model-id form`);let r=e.slice(0,n),i=e.slice(n+1),a=t.modelRegistry.find(r,i);if(!a)throw Error(`Autonomous voice model is not registered: ${e}`);if(!t.modelRegistry.hasConfiguredAuth(a))throw Error(`Autonomous voice model has no configured authentication: ${e}`);let l={complete:async e=>{let n=await t.modelRegistry.complete(a,{systemPrompt:e.systemPrompt,messages:[{role:`user`,content:e.input,timestamp:Date.now()}]},{signal:e.signal,...e.maxTokens===void 0?{}:{maxTokens:e.maxTokens},cacheRetention:e.cacheRetention,reasoningEffort:`none`,maxRetries:0});if(n.stopReason===`error`||n.stopReason===`aborted`)throw Error(n.errorMessage??`Autonomous voice model stopped with ${n.stopReason}`);return n.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}};return{adjudicator:new c.VoiceAutoCaptureAdjudicator(l),echo:new s.SemanticEchoAdjudicator,narrator:new o.NarrationGenerator(l)}}let K=class{configs;clock;workspaces;recorder;analyzer;registry;currentState=k;recording;workspace;config;selected;startedAt=0;activityFrame=0;activityTimer;limitTimer;telemetry=(0,b.createDoomTelemetry)({serviceName:`doom-voice`,packageName:`@agimon-ai/doompi-voice`,env:process.env,enableLogs:!0,enableTraces:!0});constructor(e,t,n,r,i,a){this.configs=e,this.clock=t,this.workspaces=n,this.recorder=r,this.analyzer=i,this.registry=a}get state(){return this.currentState}async toggle(e){if(this.currentState===j){e.notify(`Voice transcription is already running`,E);return}if(this.currentState===A){await this.stopAndTranscribe(e);return}await this.startRecording(e)}async startRecording(e){try{let t=process.env.PI_PROJECT_ROOT??process.cwd(),n=this.configs.load(t).voice;if(!n)throw Error(`Voice is not configured in the Pi agent configuration.`);let r=(0,g.resolveVoiceConfig)(n);this.recorder.preflight(r);let i=this.registry.select(r);this.telemetry.recordEvent(`doom_voice.recording_requested`,{engine:i.adapter.engine,mode:r.language});let a=this.workspaces.create();this.recording=this.recorder.start(r,a),this.workspace=a,this.config=r,this.selected=i,this.currentState=A,this.startedAt=this.clock.now(),this.startActivity(e),this.limitTimer=this.clock.setTimeout(()=>{this.stopAndTranscribe(e)},3e5),this.telemetry.recordEvent(`doom_voice.recording_started`,{engine:i.adapter.engine,outcome:`started`})}catch(t){await this.telemetry.recordError(`doom_voice.recording_failed`,t,{outcome:`failed`}),this.reset(e),e.notify(t instanceof Error?t.message:String(t),D)}}startActivity(e){this.activityFrame=0,this.publishActivity(e),this.activityTimer=this.clock.setInterval(()=>{this.activityFrame+=1,this.publishActivity(e)},120)}publishActivity(e){if(this.currentState===k)return;let t={state:this.currentState,frameIndex:this.activityFrame,...this.currentState===A?{elapsedSeconds:Math.max(0,Math.floor((this.clock.now()-this.startedAt)/1e3))}:{}};e.setIndicator(t),e.setStatus(C,N(t).statusText)}async stopAndTranscribe(e){let t=this.recording,n=this.workspace,r=this.config,i=this.selected;if(!t||!n||!r||!i||this.currentState!==A)return;this.clearTimers();let a=this.startedAt;this.currentState=j,this.startActivity(e),this.telemetry.recordEvent(`doom_voice.transcription_started`,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)});try{await t.stop();let o=Math.max(0,this.clock.now()-a);if(this.analyzer.analyze(t.filePath).silent){await this.telemetry.recordEvent(O,{engine:i.adapter.engine,duration_ms:o,silence:!0,outcome:`empty`}),e.notify(`No speech detected`,E);return}let s=(await i.adapter.transcribe({audioPath:t.filePath,workspace:n,config:i.config,language:r.language})).trim();if(!s){await this.telemetry.recordEvent(O,{engine:i.adapter.engine,duration_ms:o,empty:!0,outcome:`empty`}),e.notify(`Voice transcription was empty`,E);return}let c=e.getEditorText();e.setEditorText(`${c}${c&&!/\s$/.test(c)?` `:``}${s}`),await this.telemetry.recordEvent(O,{engine:i.adapter.engine,duration_ms:o,empty:!1,outcome:`completed`})}catch(t){await this.telemetry.recordError(`doom_voice.transcription_failed`,t,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)}),e.notify(t instanceof Error?t.message:String(t),D)}finally{this.reset(e)}}async shutdown(e){this.clearTimers(),this.recording&&this.currentState===A&&(await this.recording.abort(),this.telemetry.recordEvent(`doom_voice.recording_finished`,{outcome:`aborted`})),this.reset(e),this.telemetry.shutdown()}clearTimers(){this.activityTimer&&this.clock.clear(this.activityTimer),this.limitTimer&&this.clock.clear(this.limitTimer),this.activityTimer=void 0,this.limitTimer=void 0}reset(e){this.clearTimers(),this.workspace&&this.workspaces.remove(this.workspace),this.recording=void 0,this.workspace=void 0,this.config=void 0,this.selected=void 0,this.currentState=k,this.activityFrame=0,e?.setIndicator(void 0),e?.setStatus(C,void 0)}};K=n.default([(0,h.injectable)(),i.default(0,(0,h.inject)(_.DOOM_CONFIG_TYPES.ConfigService)),i.default(1,(0,h.inject)(t.DOOM_VOICE_TYPES.Clock)),i.default(2,(0,h.inject)(t.DOOM_VOICE_TYPES.TemporaryWorkspace)),i.default(3,(0,h.inject)(t.DOOM_VOICE_TYPES.AudioRecorder)),i.default(4,(0,h.inject)(t.DOOM_VOICE_TYPES.AudioAnalyzer)),i.default(5,(0,h.inject)(t.DOOM_VOICE_TYPES.TranscriberRegistry)),r.default(`design:paramtypes`,[Object,Object,Object,Object,Object,Object])],K);function q(e){return f.default.existsSync(e)?(0,g.parseDoomConfig)(f.default.readFileSync(e,`utf8`),e):{projectTrust:`ask`}}function J(e){let t=process.env.PI_CODING_AGENT_DIR||m.default.join(e,`.pi`,`agent`);return m.default.join(t,`doom-voice`,`config.yaml`)}function Y(e){let t=q((0,g.globalDoomConfigPath)(e));if(t.voice)return t;let n=q(J(e));return n.voice?(0,g.mergeDoomConfigs)(t,n):t}let X=class{load(e,t=p.default.homedir()){let n=Y(t);if(process.env.PI_PROJECT_TRUST!==`trusted`)return n;let r=q((0,g.repositoryDoomConfigPath)(e));return r.projectTrust===`never`?n:(0,g.mergeDoomConfigs)(n,r)}};X=n.default([(0,h.injectable)()],X);function Z(){return new h.ContainerModule(({bind:e})=>{e(t.DOOM_VOICE_TYPES.Clock).to(a.SystemClock).inSingletonScope(),e(t.DOOM_VOICE_TYPES.ExecutableResolver).to(a.ExecutableResolver).inSingletonScope(),e(t.DOOM_VOICE_TYPES.ProcessSpawner).to(a.NodeProcessSpawner).inSingletonScope(),e(t.DOOM_VOICE_TYPES.BinaryProcessSpawner).to(a.NodeBinaryProcessSpawner).inSingletonScope(),e(t.DOOM_VOICE_TYPES.TemporaryWorkspace).to(a.TemporaryWorkspace).inSingletonScope(),e(t.DOOM_VOICE_TYPES.AudioRecorder).to(a.FfmpegAudioRecorder).inSingletonScope(),e(t.DOOM_VOICE_TYPES.PcmAudioRecorder).to(a.FfmpegPcmAudioRecorder).inSingletonScope(),e(t.DOOM_VOICE_TYPES.TtsAdapter).to(a.MacOsSayTtsAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.AudioAnalyzer).to(a.PcmWavAnalyzer).inSingletonScope(),e(t.DOOM_VOICE_TYPES.WhisperCppAdapter).to(d.WhisperCppAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.OpenAiWhisperAdapter).to(d.OpenAiWhisperAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.MlxWhisperAdapter).to(d.MlxWhisperAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.TranscriberRegistry).to(d.TranscriberRegistry).inSingletonScope(),e(t.DOOM_VOICE_TYPES.SessionController).to(u.VoiceWorkerSessionController).inSingletonScope()})}function Q(){let e=new h.Container;return e.bind(_.DOOM_CONFIG_TYPES.ConfigService).to(X).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.Clock).to(a.SystemClock).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.ExecutableResolver).to(a.ExecutableResolver).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.ProcessSpawner).to(a.NodeProcessSpawner).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.BinaryProcessSpawner).to(a.NodeBinaryProcessSpawner).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.TemporaryWorkspace).to(a.TemporaryWorkspace).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.AudioRecorder).to(a.FfmpegAudioRecorder).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.PcmAudioRecorder).to(a.FfmpegPcmAudioRecorder).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.TtsAdapter).to(a.MacOsSayTtsAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.AudioAnalyzer).to(a.PcmWavAnalyzer).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.WhisperCppAdapter).to(d.WhisperCppAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.OpenAiWhisperAdapter).to(d.OpenAiWhisperAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.MlxWhisperAdapter).to(d.MlxWhisperAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.TranscriberRegistry).to(d.TranscriberRegistry).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.SessionController).to(u.VoiceWorkerSessionController).inSingletonScope(),e}function $(e,n={}){let r=n.container??Q(),i=r.get(t.DOOM_VOICE_TYPES.SessionController),a=r.get(_.DOOM_CONFIG_TYPES.ConfigService),o=n.footer??{update:()=>void 0,dispose:()=>void 0},s=n.mode??{update:()=>void 0,dispose:()=>void 0},c,u,d,f,p=!1,m=e=>{e!==p&&(p=e,s.update(e?{label:`VOICE`,color:`accent`}:void 0))},h=new l.VoiceWorkerAutoCaptureController({loadConfig:()=>{let e=process.env.PI_PROJECT_ROOT??process.cwd(),t=a.load(e).voice;if(!t)throw Error(`Voice is not configured in the Pi agent configuration.`);return(0,g.resolveVoiceConfig)(t)},resolveModel:async e=>{if(!d)throw Error(`No autonomous voice session is active`);return G(e,d)},tts:r.get(t.DOOM_VOICE_TYPES.TtsAdapter),clock:r.get(t.DOOM_VOICE_TYPES.Clock),deliver:t=>{if(!d)throw Error(`No autonomous voice session is active`);L(e,d,t)},manualState:()=>i.state,onActivationStateChange:e=>m(e===`active`),...n.autoClientFactory?{clientFactory:n.autoClientFactory}:{}});e.registerCommand(x,{description:`Toggle local voice recording and transcription`,handler:async(e,t)=>{if(t.hasUI){if(c=P(t,o),h.state!==`disabled`){c.notify(`Disable autonomous voice before using manual voice`,E);return}await i.toggle(c)}}}),e.registerCommand(S,{description:`Toggle continuous autonomous voice conversation`,handler:async(e,t)=>{t.hasUI&&(d=t,u=I(t,o),await h.toggle(u))}}),e.on(`session_start`,async(t,n)=>{d=n,f?.();let r=n.sessionManager?.getSessionId();f=r?U(e.events,r,h):void 0,n.hasUI&&(c=P(n,o),u=I(n,o),c.setIndicator(void 0),c.setStatus(C,void 0),p=!1,s.update(void 0))}),W(e,h),e.on(`session_shutdown`,async()=>{let e=c,t=u;c=void 0,u=void 0,d=void 0,f?.(),f=void 0,await h.shutdown(t),await i.shutdown(e),o.dispose(),s.dispose()})}Object.defineProperty(exports,"MlxWhisperAdapter",{enumerable:!0,get:function(){return d.MlxWhisperAdapter}}),Object.defineProperty(exports,"OpenAiWhisperAdapter",{enumerable:!0,get:function(){return d.OpenAiWhisperAdapter}}),Object.defineProperty(exports,"PiVoiceConfigService",{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,"TranscriberRegistry",{enumerable:!0,get:function(){return d.TranscriberRegistry}}),exports.VOICE_LEADER_BINDINGS=M,Object.defineProperty(exports,"VoiceSessionController",{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,"WhisperCppAdapter",{enumerable:!0,get:function(){return d.WhisperCppAdapter}}),exports.createVoiceContainer=Q,exports.createVoiceModule=Z,exports.deliverAutoCaptureInput=L,exports.extractFinalizedIntentSource=B,exports.extractTerminalAssistantText=V,exports.formatAutoCaptureActivity=F,exports.formatVoiceActivity=N,exports.isAskUserBlockedPayload=z,exports.isSuccessfulPlanWrite=H,exports.registerAutoCapturePiEventHandlers=W,exports.registerNarrationRequestHandler=U,exports.resolveAutoCaptureModelContracts=G,exports.voiceExtension=$;
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../types/index.cjs"),n=require("../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.cjs"),r=require("../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateMetadata.cjs"),i=require("../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateParam.cjs"),a=require("../audio/infrastructure.cjs"),o=require("../../services/voice/narration.cjs"),s=require("../../services/voice/semanticEcho.cjs"),c=require("../../services/voice/autoCapture.cjs"),l=require("../../services/voice/commandCorrection.cjs"),u=require("../process/voiceWorkerAutoCaptureController.cjs"),d=require("../process/voiceWorkerSessionController.cjs"),f=require("../transcription/whisper.cjs"),p=require("./minorModeCatalog.cjs"),m=require("./voiceCommandContext.cjs");let h=require("node:fs");h=e.__toESM(h,1);let g=require("node:os");g=e.__toESM(g,1);let _=require("node:path");_=e.__toESM(_,1);let v=require("inversify");require("reflect-metadata");let y=require("@agimon-ai/doompi-config/config"),b=require("@agimon-ai/doompi-config/types"),x=require("@agimon-ai/doompi-extension-contracts"),S=require("@agimon-ai/doompi-extension-contracts/mode"),C=require("@agimon-ai/doompi-extension-contracts/narration"),ee=require("@agimon-ai/doompi-telemetry");const w=`voice`,T=`voice-auto`,E=`doom-voice`;function D(e,t=!1){let n=e!==`disabled`,r=e===`starting`||e===`draining`||e===`shuttingDown`;return{activation:e===`starting`?`activating`:e===`draining`||e===`shuttingDown`?`deactivating`:n?`active`:`inactive`,condition:r?`queued`:`ready`,...n?{detail:e,color:`accent`}:{},actions:t?r?[{id:`activate`,enabled:!1,disabledReason:`Autonomous voice is transitioning.`},{id:`deactivate`,enabled:!1,disabledReason:`Autonomous voice is transitioning.`}]:[...n?[{id:`activate`,enabled:!1,disabledReason:`Autonomous voice is already enabled.`}]:[{id:`activate`,enabled:!0}],...n?[{id:`deactivate`,enabled:!0}]:[{id:`deactivate`,enabled:!1,disabledReason:`Autonomous voice is disabled.`}]]:[{id:`activate`,enabled:!1,disabledReason:`Autonomous voice requires a TUI session.`},{id:`deactivate`,enabled:!1,disabledReason:`Autonomous voice requires a TUI session.`}]}}const O=[`·`,`•`,`●`,`•`],te=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`],k=`info`,A=`error`,j=`doom_voice.transcription_finished`,M=`idle`,N=`recording`,P=`transcribing`,F=[{id:`voice.toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`v`,label:`toggle`,detail:`record or transcribe`}],command:{name:w}},{id:`voice.auto-toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`a`,label:`auto`,detail:`continuous autonomous conversation`}],command:{name:T}}];function I(e){let t=e.state===N?O:te,n=t[Math.max(0,Math.floor(e.frameIndex))%t.length],r=e.state===N?`warning`:`accent`,i=Math.max(0,Math.floor(e.elapsedSeconds??0));return{statusText:e.state===N?`${n} voice: recording ${Math.floor(i/60)}:${String(i%60).padStart(2,`0`)}`:`${n} voice: transcribing`,footer:{fullText:n,compactText:n,fullSegments:[{text:n,color:r}],compactSegments:[{text:n,color:r}]}}}function L(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:(t,n)=>e.ui.setStatus(t,n),setIndicator:e=>t.update(e?I(e).footer:void 0),getEditorText:()=>e.ui.getEditorText(),setEditorText:t=>e.ui.setEditorText(t)}}function R(e){let t=e===`listening`?{frame:`A`,statusText:`voice auto: listening`,color:`accent`}:e===`speech`?{frame:`!`,statusText:`voice auto: hearing speech`,color:`warning`}:e===`processing`?{frame:`…`,statusText:`voice auto: processing while listening`,color:`accent`}:e===`narrating`?{frame:`A`,statusText:`voice auto: narrating and listening`,color:`accent`}:e===`confirming`?{frame:`?`,statusText:`voice auto: confirmation needed`,color:`warning`}:e===`waiting`?{frame:`…`,statusText:`voice auto: waiting for keyboard input`,color:`warning`}:{frame:`A`,statusText:`voice auto: draining`,color:`warning`};return{statusText:t.statusText,footer:{fullText:t.frame,compactText:t.frame,fullSegments:[{text:t.frame,color:t.color}],compactSegments:[{text:t.frame,color:t.color}]}}}function z(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:t=>e.ui.setStatus(E,t),setIndicator:e=>t.update(e?R(e).footer:void 0)}}function B(e,t,n,r=`immediate`){if(t.isIdle()){e.sendUserMessage(n);return}e.sendUserMessage(n,{deliverAs:r===`queuedFollowUp`?`followUp`:`steer`})}function V(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function H(e){return V(e)&&typeof e.active==`boolean`}function U(e){if(!V(e)||e.role!==`assistant`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(V(n)){if(n.type===`toolCall`)return{text:t.join(``).trim()};n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}}function W(e){if(!V(e)||e.role!==`assistant`||e.stopReason===`toolUse`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(V(n)){if(n.type===`toolCall`)return;n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}return t.join(``).trim()||void 0}function G(e,t,n){return e!==`write_plan`||t||!V(n)?!1:V(n.details)&&n.details.written===!0}function K(e,t,n){return(0,C.subscribeToNarrationRequests)({bus:e,source:`@agimon-ai/doompi-voice`,sessionId:t},({text:e})=>n.narrate(e))}function q(e,t){e.events?.on(x.ASK_USER_BLOCKED_EVENT,e=>{H(e)&&t.askUserBlocked(e.active)}),e.on(`input`,e=>{t.observeInput({text:e.text,source:e.source,...e.streamingBehavior?{streamingBehavior:e.streamingBehavior}:{}})}),e.on(`before_agent_start`,e=>t.beforeAgentStart(e.prompt)),e.on(`agent_start`,()=>t.agentStarted()),e.on(`message_end`,e=>{let n=U(e.message);n&&t.finalizedAssistantIntent(n.text)}),e.on(`tool_execution_end`,e=>{G(e.toolName,e.isError,e.result)&&t.planWritten()}),e.on(`turn_end`,e=>{let n=e.message;t.turnFinished(e.turnIndex,n.role===`assistant`?n.stopReason:`unknown`,e.toolResults.length,W(n))}),e.on(`agent_settled`,async()=>t.agentSettled())}function J(e,t){let n=e.indexOf(`/`);if(n<=0||n===e.length-1)throw Error(`Autonomous voice model must use provider/model-id form`);let r=e.slice(0,n),i=e.slice(n+1),a=t.modelRegistry.find(r,i);if(!a)throw Error(`Autonomous voice model is not registered: ${e}`);if(!t.modelRegistry.hasConfiguredAuth(a))throw Error(`Autonomous voice model has no configured authentication: ${e}`);let u={complete:async e=>{let n=await t.modelRegistry.complete(a,{systemPrompt:e.systemPrompt,messages:[{role:`user`,content:e.input,timestamp:Date.now()}]},{signal:e.signal,...e.maxTokens===void 0?{}:{maxTokens:e.maxTokens},cacheRetention:e.cacheRetention,reasoningEffort:`none`,maxRetries:0});if(n.stopReason===`error`||n.stopReason===`aborted`)throw Error(n.errorMessage??`Autonomous voice model stopped with ${n.stopReason}`);return n.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}};return{adjudicator:new c.VoiceAutoCaptureAdjudicator(u),echo:new s.SemanticEchoAdjudicator,narrator:new o.NarrationGenerator(u),corrector:new l.VoiceCommandCorrector(u)}}let Y=class{configs;clock;workspaces;recorder;analyzer;registry;currentState=M;recording;workspace;config;selected;startedAt=0;activityFrame=0;activityTimer;limitTimer;telemetry=(0,ee.createDoomTelemetry)({serviceName:`doom-voice`,packageName:`@agimon-ai/doompi-voice`,env:process.env,enableLogs:!0,enableTraces:!0});constructor(e,t,n,r,i,a){this.configs=e,this.clock=t,this.workspaces=n,this.recorder=r,this.analyzer=i,this.registry=a}get state(){return this.currentState}async toggle(e){if(this.currentState===P){e.notify(`Voice transcription is already running`,k);return}if(this.currentState===N){await this.stopAndTranscribe(e);return}await this.startRecording(e)}async startRecording(e){try{let t=process.env.PI_PROJECT_ROOT??process.cwd(),n=this.configs.load(t).voice;if(!n)throw Error(`Voice is not configured in the Pi agent configuration.`);let r=(0,y.resolveVoiceConfig)(n);this.recorder.preflight(r);let i=this.registry.select(r);this.telemetry.recordEvent(`doom_voice.recording_requested`,{engine:i.adapter.engine,mode:r.language});let a=this.workspaces.create();this.recording=this.recorder.start(r,a),this.workspace=a,this.config=r,this.selected=i,this.currentState=N,this.startedAt=this.clock.now(),this.startActivity(e),this.limitTimer=this.clock.setTimeout(()=>{this.stopAndTranscribe(e)},3e5),this.telemetry.recordEvent(`doom_voice.recording_started`,{engine:i.adapter.engine,outcome:`started`})}catch(t){await this.telemetry.recordError(`doom_voice.recording_failed`,t,{outcome:`failed`}),this.reset(e),e.notify(t instanceof Error?t.message:String(t),A)}}startActivity(e){this.activityFrame=0,this.publishActivity(e),this.activityTimer=this.clock.setInterval(()=>{this.activityFrame+=1,this.publishActivity(e)},120)}publishActivity(e){if(this.currentState===M)return;let t={state:this.currentState,frameIndex:this.activityFrame,...this.currentState===N?{elapsedSeconds:Math.max(0,Math.floor((this.clock.now()-this.startedAt)/1e3))}:{}};e.setIndicator(t),e.setStatus(E,I(t).statusText)}async stopAndTranscribe(e){let t=this.recording,n=this.workspace,r=this.config,i=this.selected;if(!t||!n||!r||!i||this.currentState!==N)return;this.clearTimers();let a=this.startedAt;this.currentState=P,this.startActivity(e),this.telemetry.recordEvent(`doom_voice.transcription_started`,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)});try{await t.stop();let o=Math.max(0,this.clock.now()-a);if(this.analyzer.analyze(t.filePath).silent){await this.telemetry.recordEvent(j,{engine:i.adapter.engine,duration_ms:o,silence:!0,outcome:`empty`}),e.notify(`No speech detected`,k);return}let s=(await i.adapter.transcribe({audioPath:t.filePath,workspace:n,config:i.config,language:r.language})).trim();if(!s){await this.telemetry.recordEvent(j,{engine:i.adapter.engine,duration_ms:o,empty:!0,outcome:`empty`}),e.notify(`Voice transcription was empty`,k);return}let c=e.getEditorText();e.setEditorText(`${c}${c&&!/\s$/.test(c)?` `:``}${s}`),await this.telemetry.recordEvent(j,{engine:i.adapter.engine,duration_ms:o,empty:!1,outcome:`completed`})}catch(t){await this.telemetry.recordError(`doom_voice.transcription_failed`,t,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)}),e.notify(t instanceof Error?t.message:String(t),A)}finally{this.reset(e)}}async shutdown(e){this.clearTimers(),this.recording&&this.currentState===N&&(await this.recording.abort(),this.telemetry.recordEvent(`doom_voice.recording_finished`,{outcome:`aborted`})),this.reset(e),this.telemetry.shutdown()}clearTimers(){this.activityTimer&&this.clock.clear(this.activityTimer),this.limitTimer&&this.clock.clear(this.limitTimer),this.activityTimer=void 0,this.limitTimer=void 0}reset(e){this.clearTimers(),this.workspace&&this.workspaces.remove(this.workspace),this.recording=void 0,this.workspace=void 0,this.config=void 0,this.selected=void 0,this.currentState=M,this.activityFrame=0,e?.setIndicator(void 0),e?.setStatus(E,void 0)}};Y=n.default([(0,v.injectable)(),i.default(0,(0,v.inject)(b.DOOM_CONFIG_TYPES.ConfigService)),i.default(1,(0,v.inject)(t.DOOM_VOICE_TYPES.Clock)),i.default(2,(0,v.inject)(t.DOOM_VOICE_TYPES.TemporaryWorkspace)),i.default(3,(0,v.inject)(t.DOOM_VOICE_TYPES.AudioRecorder)),i.default(4,(0,v.inject)(t.DOOM_VOICE_TYPES.AudioAnalyzer)),i.default(5,(0,v.inject)(t.DOOM_VOICE_TYPES.TranscriberRegistry)),r.default(`design:paramtypes`,[Object,Object,Object,Object,Object,Object])],Y);function X(e){return h.default.existsSync(e)?(0,y.parseDoomConfig)(h.default.readFileSync(e,`utf8`),e):{projectTrust:`ask`}}function ne(e){let t=process.env.PI_CODING_AGENT_DIR||_.default.join(e,`.pi`,`agent`);return _.default.join(t,`doom-voice`,`config.yaml`)}function re(e){let t=X((0,y.globalDoomConfigPath)(e));if(t.voice)return t;let n=X(ne(e));return n.voice?(0,y.mergeDoomConfigs)(t,n):t}let Z=class{load(e,t=g.default.homedir()){let n=re(t);if(process.env.PI_PROJECT_TRUST!==`trusted`)return n;let r=X((0,y.repositoryDoomConfigPath)(e));return r.projectTrust===`never`?n:(0,y.mergeDoomConfigs)(n,r)}};Z=n.default([(0,v.injectable)()],Z);function ie(){return new v.ContainerModule(({bind:e})=>{e(t.DOOM_VOICE_TYPES.Clock).to(a.SystemClock).inSingletonScope(),e(t.DOOM_VOICE_TYPES.ExecutableResolver).to(a.ExecutableResolver).inSingletonScope(),e(t.DOOM_VOICE_TYPES.ProcessSpawner).to(a.NodeProcessSpawner).inSingletonScope(),e(t.DOOM_VOICE_TYPES.BinaryProcessSpawner).to(a.NodeBinaryProcessSpawner).inSingletonScope(),e(t.DOOM_VOICE_TYPES.TemporaryWorkspace).to(a.TemporaryWorkspace).inSingletonScope(),e(t.DOOM_VOICE_TYPES.AudioRecorder).to(a.FfmpegAudioRecorder).inSingletonScope(),e(t.DOOM_VOICE_TYPES.PcmAudioRecorder).to(a.FfmpegPcmAudioRecorder).inSingletonScope(),e(t.DOOM_VOICE_TYPES.TtsAdapter).to(a.MacOsSayTtsAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.AudioAnalyzer).to(a.PcmWavAnalyzer).inSingletonScope(),e(t.DOOM_VOICE_TYPES.WhisperCppAdapter).to(f.WhisperCppAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.OpenAiWhisperAdapter).to(f.OpenAiWhisperAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.MlxWhisperAdapter).to(f.MlxWhisperAdapter).inSingletonScope(),e(t.DOOM_VOICE_TYPES.TranscriberRegistry).to(f.TranscriberRegistry).inSingletonScope(),e(t.DOOM_VOICE_TYPES.SessionController).to(d.VoiceWorkerSessionController).inSingletonScope()})}function Q(){let e=new v.Container;return e.bind(b.DOOM_CONFIG_TYPES.ConfigService).to(Z).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.Clock).to(a.SystemClock).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.ExecutableResolver).to(a.ExecutableResolver).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.ProcessSpawner).to(a.NodeProcessSpawner).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.BinaryProcessSpawner).to(a.NodeBinaryProcessSpawner).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.TemporaryWorkspace).to(a.TemporaryWorkspace).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.AudioRecorder).to(a.FfmpegAudioRecorder).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.PcmAudioRecorder).to(a.FfmpegPcmAudioRecorder).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.TtsAdapter).to(a.MacOsSayTtsAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.AudioAnalyzer).to(a.PcmWavAnalyzer).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.WhisperCppAdapter).to(f.WhisperCppAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.OpenAiWhisperAdapter).to(f.OpenAiWhisperAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.MlxWhisperAdapter).to(f.MlxWhisperAdapter).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.TranscriberRegistry).to(f.TranscriberRegistry).inSingletonScope(),e.bind(t.DOOM_VOICE_TYPES.SessionController).to(d.VoiceWorkerSessionController).inSingletonScope(),e}function $(e,t){let n=e.getActiveTools(),r=n.includes(S.MINOR_MODE_TOOL_NAME);if(!t&&r){e.setActiveTools(n.filter(e=>e!==S.MINOR_MODE_TOOL_NAME));return}let i=e.getAllTools().some(e=>e.name===S.MINOR_MODE_TOOL_NAME);t&&i&&!r&&e.setActiveTools([...n,S.MINOR_MODE_TOOL_NAME])}function ae(e,n={}){let r=n.container??Q(),i=r.get(t.DOOM_VOICE_TYPES.SessionController),a=r.get(b.DOOM_CONFIG_TYPES.ConfigService),o=n.footer??{update:()=>void 0,dispose:()=>void 0},s,c,l,d,f=p.createVoiceMinorModeCatalog(e),h,g=new u.VoiceWorkerAutoCaptureController({loadConfig:()=>{let e=process.env.PI_PROJECT_ROOT??process.cwd(),t=a.load(e).voice;if(!t)throw Error(`Voice is not configured in the Pi agent configuration.`);return(0,y.resolveVoiceConfig)(t)},resolveModel:async e=>{if(!l)throw Error(`No autonomous voice session is active`);return J(e,l)},tts:r.get(t.DOOM_VOICE_TYPES.TtsAdapter),clock:r.get(t.DOOM_VOICE_TYPES.Clock),deliver:t=>{if(!l)throw Error(`No autonomous voice session is active`);B(e,l,t)},manualState:()=>i.state,commandContext:()=>l?m.collectVoiceCommandContext(l.sessionManager.getBranch(),f.records()):void 0,onActivationStateChange:t=>{$(e,t===`active`),h?.publish(D(t,l?.hasUI===!0))},...n.autoClientFactory?{clientFactory:n.autoClientFactory}:{}});h=(0,S.registerMinorModeOwner)(e,{descriptor:{source:`@agimon-ai/doompi-voice`,id:`voice-auto`,label:`VOICE`,description:`Continuous autonomous voice capture, correction, and narration.`,order:30,actions:[{id:`activate`,label:`Activate`,description:`Start autonomous voice capture.`,contexts:[`tui`],parameters:[]},{id:`deactivate`,label:`Deactivate`,description:`Stop autonomous voice capture.`,contexts:[`tui`],parameters:[]}]},initialState:D(`disabled`),async handleAction(e,t,n){l=n.context;let r=z(n.context,o);if(c=r,e===`activate`)return await g.activate(r),{message:`Autonomous voice activation requested.`};if(e===`deactivate`)return await g.deactivate(r),{message:`Autonomous voice deactivation requested.`};throw Error(`Unknown autonomous voice action: ${e}`)}}),e.registerCommand(w,{description:`Toggle local voice recording and transcription`,handler:async(e,t)=>{if(t.hasUI){if(s=L(t,o),g.state!==`disabled`){s.notify(`Disable autonomous voice before using manual voice`,k);return}await i.toggle(s)}}}),e.registerCommand(T,{description:`Toggle continuous autonomous voice conversation`,handler:async(e,t)=>{t.hasUI&&(l=t,c=z(t,o),g.state===`disabled`?await g.activate(c):await g.deactivate(c))}}),e.on(`session_start`,async(t,n)=>{$(e,!1),l=n,d?.();let r=n.sessionManager?.getSessionId();r&&f.bind(r),d=r?K(e.events,r,g):void 0,n.hasUI&&(s=L(n,o),c=z(n,o),s.setIndicator(void 0),s.setStatus(E,void 0),h?.publish(D(`disabled`,n.hasUI)))}),e.on(`before_agent_start`,()=>{$(e,g.state===`active`)}),q(e,g),e.on(`session_shutdown`,async()=>{let t=s,n=c;s=void 0,c=void 0,l=void 0,$(e,!1),d?.(),d=void 0,f.dispose(),await g.shutdown(n),await i.shutdown(t),o.dispose(),h?.dispose()})}Object.defineProperty(exports,"MlxWhisperAdapter",{enumerable:!0,get:function(){return f.MlxWhisperAdapter}}),Object.defineProperty(exports,"OpenAiWhisperAdapter",{enumerable:!0,get:function(){return f.OpenAiWhisperAdapter}}),Object.defineProperty(exports,"PiVoiceConfigService",{enumerable:!0,get:function(){return Z}}),Object.defineProperty(exports,"TranscriberRegistry",{enumerable:!0,get:function(){return f.TranscriberRegistry}}),exports.VOICE_LEADER_BINDINGS=F,Object.defineProperty(exports,"VoiceSessionController",{enumerable:!0,get:function(){return Y}}),Object.defineProperty(exports,"WhisperCppAdapter",{enumerable:!0,get:function(){return f.WhisperCppAdapter}}),exports.createVoiceContainer=Q,exports.createVoiceModule=ie,exports.deliverAutoCaptureInput=B,exports.extractFinalizedIntentSource=U,exports.extractTerminalAssistantText=W,exports.formatAutoCaptureActivity=R,exports.formatVoiceActivity=I,exports.isAskUserBlockedPayload=H,exports.isSuccessfulPlanWrite=G,exports.registerAutoCapturePiEventHandlers=q,exports.registerNarrationRequestHandler=K,exports.resolveAutoCaptureModelContracts=J,exports.voiceExtension=ae;
2
2
  //# sourceMappingURL=voice.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"voice.cjs","names":["subscribeToNarrationRequests","ASK_USER_BLOCKED_EVENT","VoiceAutoCaptureAdjudicator","SemanticEchoAdjudicator","NarrationGenerator","createDoomTelemetry","resolveVoiceConfig","injectable","inject","DOOM_CONFIG_TYPES","DOOM_VOICE_TYPES","fs","parseDoomConfig","path","globalDoomConfigPath","mergeDoomConfigs","os","repositoryDoomConfigPath","ContainerModule","SystemClock","ExecutableResolver","NodeProcessSpawner","NodeBinaryProcessSpawner","TemporaryWorkspace","FfmpegAudioRecorder","FfmpegPcmAudioRecorder","MacOsSayTtsAdapter","PcmWavAnalyzer","WhisperCppAdapter","OpenAiWhisperAdapter","MlxWhisperAdapter","TranscriberRegistry","VoiceWorkerSessionController","Container","VoiceWorkerAutoCaptureController"],"sources":["../../../src/adapters/pi/voice.ts"],"sourcesContent":["import 'reflect-metadata';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {\n globalDoomConfigPath,\n mergeDoomConfigs,\n parseDoomConfig,\n repositoryDoomConfigPath,\n resolveVoiceConfig,\n} from '@agimon-ai/doompi-config/config';\nimport {\n DOOM_CONFIG_TYPES,\n type DoomConfig,\n type IDoomConfigService,\n type ResolvedVoiceConfig,\n} from '@agimon-ai/doompi-config/types';\nimport { ASK_USER_BLOCKED_EVENT } from '@agimon-ai/doompi-extension-contracts';\nimport type { LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport { subscribeToNarrationRequests } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { Container, ContainerModule, inject, injectable } from 'inversify';\nimport {\n type AutoCaptureModelContracts,\n type AutoCaptureModelRequest,\n type IAutoCaptureModelClient,\n VoiceAutoCaptureAdjudicator,\n} from '../../services/voice/autoCapture.ts';\nimport {\n type INarrationModelClient,\n NarrationGenerator,\n type NarrationModelRequest,\n} from '../../services/voice/narration.ts';\nimport { SemanticEchoAdjudicator } from '../../services/voice/semanticEcho.ts';\nimport {\n type AutoCaptureIndicatorState,\n type AutoCaptureUi,\n DOOM_VOICE_TYPES,\n type IAudioAnalyzer,\n type IAudioRecorder,\n type IBinaryProcessSpawner,\n type IClock,\n type IExecutableResolver,\n type IPcmAudioRecorder,\n type IProcessSpawner,\n type ITemporaryWorkspace,\n type ITranscriberAdapter,\n type ITranscriberRegistry,\n type ITtsAdapter,\n type IVoiceSessionController,\n type RecordingHandle,\n type SelectedTranscriber,\n type TimerHandle,\n type VoiceActivityUpdate,\n type VoiceState,\n type VoiceUi,\n} from '../../types/index.ts';\nimport {\n ExecutableResolver,\n FfmpegAudioRecorder,\n FfmpegPcmAudioRecorder,\n MacOsSayTtsAdapter,\n NodeBinaryProcessSpawner,\n NodeProcessSpawner,\n PcmWavAnalyzer,\n SystemClock,\n TemporaryWorkspace,\n} from '../audio/infrastructure.ts';\nimport { VoiceWorkerAutoCaptureController } from '../process/voiceWorkerAutoCaptureController.ts';\nimport {\n type VoiceWorkerSessionClientFactory,\n VoiceWorkerSessionController,\n} from '../process/voiceWorkerSessionController.ts';\nimport {\n MlxWhisperAdapter,\n OpenAiWhisperAdapter,\n TranscriberRegistry,\n WhisperCppAdapter,\n} from '../transcription/whisper.ts';\n\nexport {\n MlxWhisperAdapter,\n OpenAiWhisperAdapter,\n TranscriberRegistry,\n WhisperCppAdapter,\n} from '../transcription/whisper.ts';\n\ninterface VoiceSessionContextLike {\n sessionManager?: { getSessionId(): string };\n}\n\nconst VOICE_SOURCE = '@agimon-ai/doompi-voice';\nconst COMMAND_NAME = 'voice';\nconst AUTO_COMMAND_NAME = 'voice-auto';\nconst STATUS_KEY = 'doom-voice';\nconst MAX_RECORDING_MS = 300_000;\nconst ACTIVITY_INTERVAL_MS = 120;\nconst LEADER_GROUP_ORDER = 67;\nconst AUTO_LEADER_DETAIL = 'continuous autonomous conversation';\nconst AUTO_MODE_LABEL = 'VOICE';\nconst AUTO_MODE_COLOR = 'accent' as const;\nconst RECORDING_FRAMES = ['·', '•', '●', '•'] as const;\nconst TRANSCRIBING_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] as const;\nconst INFO_NOTIFICATION = 'info';\nconst ERROR_NOTIFICATION = 'error';\nconst RECORDING_REQUESTED_EVENT = 'doom_voice.recording_requested';\nconst RECORDING_STARTED_EVENT = 'doom_voice.recording_started';\nconst RECORDING_FAILED_EVENT = 'doom_voice.recording_failed';\nconst RECORDING_FINISHED_EVENT = 'doom_voice.recording_finished';\nconst TRANSCRIPTION_STARTED_EVENT = 'doom_voice.transcription_started';\nconst TRANSCRIPTION_FINISHED_EVENT = 'doom_voice.transcription_finished';\nconst TRANSCRIPTION_FAILED_EVENT = 'doom_voice.transcription_failed';\nconst IDLE_STATE = 'idle' as const;\nconst RECORDING_STATE = 'recording' as const;\nconst TRANSCRIBING_STATE = 'transcribing' as const;\n\nexport interface VoiceFooterContributionValue {\n fullText: string;\n compactText: string;\n fullSegments: Array<{ text: string; color: 'warning' | 'accent' }>;\n compactSegments: Array<{ text: string; color: 'warning' | 'accent' }>;\n}\n\nexport interface VoiceFooterContributionHandle {\n update(value: VoiceFooterContributionValue | undefined): void;\n dispose(): void;\n}\n\nexport interface VoiceModeContributionValue {\n label: string;\n detail?: string;\n color?: 'accent' | 'warning' | 'mdHeading' | 'muted' | 'dim';\n}\n\nexport interface VoiceModeContributionHandle {\n update(value: VoiceModeContributionValue | undefined): void;\n dispose(): void;\n}\n\nexport const VOICE_LEADER_BINDINGS: readonly LeaderBinding[] = [\n {\n id: 'voice.toggle',\n path: [\n { key: 'v', label: 'voice', order: LEADER_GROUP_ORDER },\n { key: 'v', label: 'toggle', detail: 'record or transcribe' },\n ],\n command: { name: COMMAND_NAME },\n },\n {\n id: 'voice.auto-toggle',\n path: [\n { key: 'v', label: 'voice', order: LEADER_GROUP_ORDER },\n { key: 'a', label: 'auto', detail: AUTO_LEADER_DETAIL },\n ],\n command: { name: AUTO_COMMAND_NAME },\n },\n];\n\nexport interface VoiceActivityPresentation {\n statusText: string;\n footer: VoiceFooterContributionValue;\n}\n\nexport interface AutoCaptureActivityPresentation {\n statusText: string;\n footer: VoiceFooterContributionValue;\n}\n\nexport function formatVoiceActivity(update: VoiceActivityUpdate): VoiceActivityPresentation {\n const frames = update.state === RECORDING_STATE ? RECORDING_FRAMES : TRANSCRIBING_FRAMES;\n const frameIndex = Math.max(0, Math.floor(update.frameIndex)) % frames.length;\n const frame = frames[frameIndex]!;\n const color = update.state === RECORDING_STATE ? ('warning' as const) : ('accent' as const);\n const elapsed = Math.max(0, Math.floor(update.elapsedSeconds ?? 0));\n const statusText =\n update.state === RECORDING_STATE\n ? `${frame} voice: recording ${Math.floor(elapsed / 60)}:${String(elapsed % 60).padStart(2, '0')}`\n : `${frame} voice: transcribing`;\n return {\n statusText,\n footer: {\n fullText: frame,\n compactText: frame,\n fullSegments: [{ text: frame, color }],\n compactSegments: [{ text: frame, color }],\n },\n };\n}\n\nfunction createVoiceUi(context: ExtensionContext, footer: VoiceFooterContributionHandle): VoiceUi {\n return {\n notify: (message, level) => context.ui.notify(message, level),\n setStatus: (key, value) => context.ui.setStatus(key, value),\n setIndicator: (update) => footer.update(update ? formatVoiceActivity(update).footer : undefined),\n getEditorText: () => context.ui.getEditorText(),\n setEditorText: (text) => context.ui.setEditorText(text),\n };\n}\n\nexport function formatAutoCaptureActivity(state: AutoCaptureIndicatorState): AutoCaptureActivityPresentation {\n const presentation =\n state === 'listening'\n ? { frame: 'A', statusText: 'voice auto: listening', color: 'accent' as const }\n : state === 'speech'\n ? { frame: '!', statusText: 'voice auto: hearing speech', color: 'warning' as const }\n : state === 'processing'\n ? { frame: '…', statusText: 'voice auto: processing while listening', color: 'accent' as const }\n : state === 'narrating'\n ? { frame: 'A', statusText: 'voice auto: narrating and listening', color: 'accent' as const }\n : state === 'confirming'\n ? { frame: '?', statusText: 'voice auto: confirmation needed', color: 'warning' as const }\n : state === 'waiting'\n ? { frame: '…', statusText: 'voice auto: waiting for keyboard input', color: 'warning' as const }\n : { frame: 'A', statusText: 'voice auto: draining', color: 'warning' as const };\n return {\n statusText: presentation.statusText,\n footer: {\n fullText: presentation.frame,\n compactText: presentation.frame,\n fullSegments: [{ text: presentation.frame, color: presentation.color }],\n compactSegments: [{ text: presentation.frame, color: presentation.color }],\n },\n };\n}\n\nfunction createAutoCaptureUi(context: ExtensionContext, footer: VoiceFooterContributionHandle): AutoCaptureUi {\n return {\n notify: (message, level) => context.ui.notify(message, level),\n setStatus: (value) => context.ui.setStatus(STATUS_KEY, value),\n setIndicator: (state) => footer.update(state ? formatAutoCaptureActivity(state).footer : undefined),\n };\n}\n\ntype PiVoiceModelRequest = AutoCaptureModelRequest | NarrationModelRequest;\ntype PiVoiceModelClient = IAutoCaptureModelClient & INarrationModelClient;\nexport type AutoCaptureDeliveryIntent = 'immediate' | 'queuedFollowUp';\n\nexport function deliverAutoCaptureInput(\n pi: Pick<ExtensionAPI, 'sendUserMessage'>,\n context: Pick<ExtensionContext, 'isIdle'>,\n text: string,\n intent: AutoCaptureDeliveryIntent = 'immediate',\n): void {\n if (context.isIdle()) {\n pi.sendUserMessage(text);\n return;\n }\n pi.sendUserMessage(text, { deliverAs: intent === 'queuedFollowUp' ? 'followUp' : 'steer' });\n}\n\nexport interface AutoCapturePiEventController {\n observeInput(event: {\n text: string;\n source: 'interactive' | 'rpc' | 'extension';\n streamingBehavior?: 'steer' | 'followUp';\n }): void;\n beforeAgentStart(prompt: string): void;\n agentStarted(): void;\n finalizedAssistantIntent(sourceText: string): void;\n planWritten(): void;\n askUserBlocked(blocked: boolean): void;\n turnFinished(turnIndex: number, reason: string, toolCount: number, latestAssistantText?: string): void;\n agentSettled(): Promise<void>;\n}\n\ninterface FinalizedIntentSource {\n text: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isAskUserBlockedPayload(payload: unknown): payload is { active: boolean } {\n return isRecord(payload) && typeof payload.active === 'boolean';\n}\n\nexport function extractFinalizedIntentSource(message: unknown): FinalizedIntentSource | undefined {\n if (!isRecord(message) || message.role !== 'assistant' || !Array.isArray(message.content)) return undefined;\n const text: string[] = [];\n for (const block of message.content) {\n if (!isRecord(block)) continue;\n if (block.type === 'toolCall') return { text: text.join('').trim() };\n if (block.type === 'text' && typeof block.text === 'string') text.push(block.text);\n }\n return undefined;\n}\n\nexport function extractTerminalAssistantText(message: unknown): string | undefined {\n if (\n !isRecord(message) ||\n message.role !== 'assistant' ||\n message.stopReason === 'toolUse' ||\n !Array.isArray(message.content)\n )\n return undefined;\n const text: string[] = [];\n for (const block of message.content) {\n if (!isRecord(block)) continue;\n if (block.type === 'toolCall') return undefined;\n if (block.type === 'text' && typeof block.text === 'string') text.push(block.text);\n }\n return text.join('').trim() || undefined;\n}\n\nexport function isSuccessfulPlanWrite(toolName: string, isError: boolean, result: unknown): boolean {\n if (toolName !== 'write_plan' || isError || !isRecord(result)) return false;\n return isRecord(result.details) && result.details.written === true;\n}\n\nexport function registerNarrationRequestHandler(\n events: ExtensionAPI['events'],\n sessionId: string,\n controller: Pick<VoiceWorkerAutoCaptureController, 'narrate'>,\n): () => void {\n return subscribeToNarrationRequests({ bus: events, source: VOICE_SOURCE, sessionId }, ({ text }) =>\n controller.narrate(text),\n );\n}\n\nexport function registerAutoCapturePiEventHandlers(\n pi: Pick<ExtensionAPI, 'on'> & { events?: Pick<ExtensionAPI['events'], 'on'> },\n controller: AutoCapturePiEventController,\n): void {\n pi.events?.on(ASK_USER_BLOCKED_EVENT, (payload) => {\n if (isAskUserBlockedPayload(payload)) controller.askUserBlocked(payload.active);\n });\n pi.on('input', (event) => {\n controller.observeInput({\n text: event.text,\n source: event.source,\n ...(event.streamingBehavior ? { streamingBehavior: event.streamingBehavior } : {}),\n });\n });\n pi.on('before_agent_start', (event) => controller.beforeAgentStart(event.prompt));\n pi.on('agent_start', () => controller.agentStarted());\n pi.on('message_end', (event) => {\n const source = extractFinalizedIntentSource(event.message);\n if (source) controller.finalizedAssistantIntent(source.text);\n });\n pi.on('tool_execution_end', (event) => {\n if (isSuccessfulPlanWrite(event.toolName, event.isError, event.result)) controller.planWritten();\n });\n pi.on('turn_end', (event) => {\n const message = event.message;\n controller.turnFinished(\n event.turnIndex,\n message.role === 'assistant' ? message.stopReason : 'unknown',\n event.toolResults.length,\n extractTerminalAssistantText(message),\n );\n });\n pi.on('agent_settled', async () => controller.agentSettled());\n}\n\nexport function resolveAutoCaptureModelContracts(\n reference: string,\n context: ExtensionContext,\n): AutoCaptureModelContracts {\n const separator = reference.indexOf('/');\n if (separator <= 0 || separator === reference.length - 1)\n throw new Error('Autonomous voice model must use provider/model-id form');\n const provider = reference.slice(0, separator);\n const modelId = reference.slice(separator + 1);\n const model = context.modelRegistry.find(provider, modelId);\n if (!model) throw new Error(`Autonomous voice model is not registered: ${reference}`);\n if (!context.modelRegistry.hasConfiguredAuth(model))\n throw new Error(`Autonomous voice model has no configured authentication: ${reference}`);\n\n const modelClient: PiVoiceModelClient = {\n complete: async (request: PiVoiceModelRequest): Promise<string> => {\n const response = await context.modelRegistry.complete(\n model,\n {\n systemPrompt: request.systemPrompt,\n messages: [{ role: 'user', content: request.input, timestamp: Date.now() }],\n },\n {\n signal: request.signal,\n ...(request.maxTokens === undefined ? {} : { maxTokens: request.maxTokens }),\n cacheRetention: request.cacheRetention,\n reasoningEffort: 'none',\n maxRetries: 0,\n },\n );\n if (response.stopReason === 'error' || response.stopReason === 'aborted')\n throw new Error(response.errorMessage ?? `Autonomous voice model stopped with ${response.stopReason}`);\n return response.content\n .filter((content) => content.type === 'text')\n .map((content) => content.text)\n .join('')\n .trim();\n },\n };\n return {\n adjudicator: new VoiceAutoCaptureAdjudicator(modelClient),\n echo: new SemanticEchoAdjudicator(),\n narrator: new NarrationGenerator(modelClient),\n };\n}\n\n@injectable()\nexport class VoiceSessionController implements IVoiceSessionController {\n private currentState: VoiceState = IDLE_STATE;\n private recording?: RecordingHandle;\n private workspace?: string;\n private config?: ResolvedVoiceConfig;\n private selected?: SelectedTranscriber;\n private startedAt = 0;\n private activityFrame = 0;\n private activityTimer?: TimerHandle;\n private limitTimer?: TimerHandle;\n private readonly telemetry = createDoomTelemetry({\n serviceName: 'doom-voice',\n packageName: '@agimon-ai/doompi-voice',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n constructor(\n @inject(DOOM_CONFIG_TYPES.ConfigService) private readonly configs: IDoomConfigService,\n @inject(DOOM_VOICE_TYPES.Clock) private readonly clock: IClock,\n @inject(DOOM_VOICE_TYPES.TemporaryWorkspace) private readonly workspaces: ITemporaryWorkspace,\n @inject(DOOM_VOICE_TYPES.AudioRecorder) private readonly recorder: IAudioRecorder,\n @inject(DOOM_VOICE_TYPES.AudioAnalyzer) private readonly analyzer: IAudioAnalyzer,\n @inject(DOOM_VOICE_TYPES.TranscriberRegistry) private readonly registry: ITranscriberRegistry,\n ) {}\n get state(): VoiceState {\n return this.currentState;\n }\n async toggle(ui: VoiceUi): Promise<void> {\n if (this.currentState === TRANSCRIBING_STATE) {\n ui.notify('Voice transcription is already running', INFO_NOTIFICATION);\n return;\n }\n if (this.currentState === RECORDING_STATE) {\n await this.stopAndTranscribe(ui);\n return;\n }\n await this.startRecording(ui);\n }\n private async startRecording(ui: VoiceUi): Promise<void> {\n try {\n const projectRoot = process.env.PI_PROJECT_ROOT ?? process.cwd();\n const loaded = this.configs.load(projectRoot).voice;\n if (!loaded) throw new Error('Voice is not configured in the Pi agent configuration.');\n const config = resolveVoiceConfig(loaded);\n this.recorder.preflight(config);\n const selected = this.registry.select(config);\n void this.telemetry.recordEvent(RECORDING_REQUESTED_EVENT, {\n engine: selected.adapter.engine,\n mode: config.language,\n });\n const workspace = this.workspaces.create();\n this.recording = this.recorder.start(config, workspace);\n this.workspace = workspace;\n this.config = config;\n this.selected = selected;\n this.currentState = RECORDING_STATE;\n this.startedAt = this.clock.now();\n this.startActivity(ui);\n this.limitTimer = this.clock.setTimeout(() => {\n void this.stopAndTranscribe(ui);\n }, MAX_RECORDING_MS);\n void this.telemetry.recordEvent(RECORDING_STARTED_EVENT, {\n engine: selected.adapter.engine,\n outcome: 'started',\n });\n } catch (error) {\n await this.telemetry.recordError(RECORDING_FAILED_EVENT, error, { outcome: 'failed' });\n this.reset(ui);\n ui.notify(error instanceof Error ? error.message : String(error), ERROR_NOTIFICATION);\n }\n }\n private startActivity(ui: VoiceUi): void {\n this.activityFrame = 0;\n this.publishActivity(ui);\n this.activityTimer = this.clock.setInterval(() => {\n this.activityFrame += 1;\n this.publishActivity(ui);\n }, ACTIVITY_INTERVAL_MS);\n }\n private publishActivity(ui: VoiceUi): void {\n if (this.currentState === IDLE_STATE) return;\n const update: VoiceActivityUpdate = {\n state: this.currentState,\n frameIndex: this.activityFrame,\n ...(this.currentState === RECORDING_STATE\n ? { elapsedSeconds: Math.max(0, Math.floor((this.clock.now() - this.startedAt) / 1_000)) }\n : {}),\n };\n ui.setIndicator(update);\n ui.setStatus(STATUS_KEY, formatVoiceActivity(update).statusText);\n }\n private async stopAndTranscribe(ui: VoiceUi): Promise<void> {\n const recording = this.recording;\n const workspace = this.workspace;\n const config = this.config;\n const selected = this.selected;\n if (!recording || !workspace || !config || !selected || this.currentState !== RECORDING_STATE) return;\n this.clearTimers();\n const recordingStartedAt = this.startedAt;\n this.currentState = TRANSCRIBING_STATE;\n this.startActivity(ui);\n void this.telemetry.recordEvent(TRANSCRIPTION_STARTED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: Math.max(0, this.clock.now() - recordingStartedAt),\n });\n try {\n await recording.stop();\n const recordingDurationMs = Math.max(0, this.clock.now() - recordingStartedAt);\n if (this.analyzer.analyze(recording.filePath).silent) {\n await this.telemetry.recordEvent(TRANSCRIPTION_FINISHED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: recordingDurationMs,\n silence: true,\n outcome: 'empty',\n });\n ui.notify('No speech detected', INFO_NOTIFICATION);\n return;\n }\n const transcript = (\n await selected.adapter.transcribe({\n audioPath: recording.filePath,\n workspace,\n config: selected.config,\n language: config.language,\n })\n ).trim();\n if (!transcript) {\n await this.telemetry.recordEvent(TRANSCRIPTION_FINISHED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: recordingDurationMs,\n empty: true,\n outcome: 'empty',\n });\n ui.notify('Voice transcription was empty', INFO_NOTIFICATION);\n return;\n }\n const draft = ui.getEditorText();\n ui.setEditorText(`${draft}${draft && !/\\s$/.test(draft) ? ' ' : ''}${transcript}`);\n await this.telemetry.recordEvent(TRANSCRIPTION_FINISHED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: recordingDurationMs,\n empty: false,\n outcome: 'completed',\n });\n } catch (error) {\n await this.telemetry.recordError(TRANSCRIPTION_FAILED_EVENT, error, {\n engine: selected.adapter.engine,\n duration_ms: Math.max(0, this.clock.now() - recordingStartedAt),\n });\n ui.notify(error instanceof Error ? error.message : String(error), ERROR_NOTIFICATION);\n } finally {\n this.reset(ui);\n }\n }\n async shutdown(ui?: VoiceUi): Promise<void> {\n this.clearTimers();\n if (this.recording && this.currentState === RECORDING_STATE) {\n await this.recording.abort();\n void this.telemetry.recordEvent(RECORDING_FINISHED_EVENT, { outcome: 'aborted' });\n }\n this.reset(ui);\n void this.telemetry.shutdown();\n }\n private clearTimers(): void {\n if (this.activityTimer) this.clock.clear(this.activityTimer);\n if (this.limitTimer) this.clock.clear(this.limitTimer);\n this.activityTimer = undefined;\n this.limitTimer = undefined;\n }\n private reset(ui?: VoiceUi): void {\n this.clearTimers();\n if (this.workspace) this.workspaces.remove(this.workspace);\n this.recording = undefined;\n this.workspace = undefined;\n this.config = undefined;\n this.selected = undefined;\n this.currentState = IDLE_STATE;\n this.activityFrame = 0;\n ui?.setIndicator(undefined);\n ui?.setStatus(STATUS_KEY, undefined);\n }\n}\n\nfunction readVoiceConfig(filePath: string): DoomConfig {\n if (!fs.existsSync(filePath)) return { projectTrust: 'ask' };\n return parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath);\n}\n\nfunction voiceAgentConfigPath(homeDirectory: string): string {\n const agentDirectory = process.env.PI_CODING_AGENT_DIR || path.join(homeDirectory, '.pi', 'agent');\n return path.join(agentDirectory, 'doom-voice', 'config.yaml');\n}\n\n/**\n * Shared Doom config owns `voice:`; the package-scoped file is the fallback for\n * standalone installs that have no Doom config.\n */\nfunction readGlobalVoiceConfig(homeDirectory: string): DoomConfig {\n const doomConfig = readVoiceConfig(globalDoomConfigPath(homeDirectory));\n if (doomConfig.voice) return doomConfig;\n const packageConfig = readVoiceConfig(voiceAgentConfigPath(homeDirectory));\n return packageConfig.voice ? mergeDoomConfigs(doomConfig, packageConfig) : doomConfig;\n}\n\n@injectable()\nexport class PiVoiceConfigService implements IDoomConfigService {\n load(repoRoot: string, homeDirectory = os.homedir()): DoomConfig {\n const globalConfig = readGlobalVoiceConfig(homeDirectory);\n const trusted = process.env.PI_PROJECT_TRUST === 'trusted';\n if (!trusted) return globalConfig;\n\n const projectPath = repositoryDoomConfigPath(repoRoot);\n const projectConfig = readVoiceConfig(projectPath);\n if (projectConfig.projectTrust === 'never') return globalConfig;\n return mergeDoomConfigs(globalConfig, projectConfig);\n }\n}\n\nexport function createVoiceModule(): ContainerModule {\n return new ContainerModule(({ bind }) => {\n bind<IClock>(DOOM_VOICE_TYPES.Clock).to(SystemClock).inSingletonScope();\n bind<IExecutableResolver>(DOOM_VOICE_TYPES.ExecutableResolver).to(ExecutableResolver).inSingletonScope();\n bind<IProcessSpawner>(DOOM_VOICE_TYPES.ProcessSpawner).to(NodeProcessSpawner).inSingletonScope();\n bind<IBinaryProcessSpawner>(DOOM_VOICE_TYPES.BinaryProcessSpawner).to(NodeBinaryProcessSpawner).inSingletonScope();\n bind<ITemporaryWorkspace>(DOOM_VOICE_TYPES.TemporaryWorkspace).to(TemporaryWorkspace).inSingletonScope();\n bind<IAudioRecorder>(DOOM_VOICE_TYPES.AudioRecorder).to(FfmpegAudioRecorder).inSingletonScope();\n bind<IPcmAudioRecorder>(DOOM_VOICE_TYPES.PcmAudioRecorder).to(FfmpegPcmAudioRecorder).inSingletonScope();\n bind<ITtsAdapter>(DOOM_VOICE_TYPES.TtsAdapter).to(MacOsSayTtsAdapter).inSingletonScope();\n bind<IAudioAnalyzer>(DOOM_VOICE_TYPES.AudioAnalyzer).to(PcmWavAnalyzer).inSingletonScope();\n bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.WhisperCppAdapter).to(WhisperCppAdapter).inSingletonScope();\n bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.OpenAiWhisperAdapter).to(OpenAiWhisperAdapter).inSingletonScope();\n bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.MlxWhisperAdapter).to(MlxWhisperAdapter).inSingletonScope();\n bind<ITranscriberRegistry>(DOOM_VOICE_TYPES.TranscriberRegistry).to(TranscriberRegistry).inSingletonScope();\n bind<IVoiceSessionController>(DOOM_VOICE_TYPES.SessionController)\n .to(VoiceWorkerSessionController)\n .inSingletonScope();\n });\n}\nexport function createVoiceContainer(): Container {\n const container = new Container();\n container.bind<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService).to(PiVoiceConfigService).inSingletonScope();\n container.bind<IClock>(DOOM_VOICE_TYPES.Clock).to(SystemClock).inSingletonScope();\n container.bind<IExecutableResolver>(DOOM_VOICE_TYPES.ExecutableResolver).to(ExecutableResolver).inSingletonScope();\n container.bind<IProcessSpawner>(DOOM_VOICE_TYPES.ProcessSpawner).to(NodeProcessSpawner).inSingletonScope();\n container\n .bind<IBinaryProcessSpawner>(DOOM_VOICE_TYPES.BinaryProcessSpawner)\n .to(NodeBinaryProcessSpawner)\n .inSingletonScope();\n container.bind<ITemporaryWorkspace>(DOOM_VOICE_TYPES.TemporaryWorkspace).to(TemporaryWorkspace).inSingletonScope();\n container.bind<IAudioRecorder>(DOOM_VOICE_TYPES.AudioRecorder).to(FfmpegAudioRecorder).inSingletonScope();\n container.bind<IPcmAudioRecorder>(DOOM_VOICE_TYPES.PcmAudioRecorder).to(FfmpegPcmAudioRecorder).inSingletonScope();\n container.bind<ITtsAdapter>(DOOM_VOICE_TYPES.TtsAdapter).to(MacOsSayTtsAdapter).inSingletonScope();\n container.bind<IAudioAnalyzer>(DOOM_VOICE_TYPES.AudioAnalyzer).to(PcmWavAnalyzer).inSingletonScope();\n container.bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.WhisperCppAdapter).to(WhisperCppAdapter).inSingletonScope();\n container\n .bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.OpenAiWhisperAdapter)\n .to(OpenAiWhisperAdapter)\n .inSingletonScope();\n container.bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.MlxWhisperAdapter).to(MlxWhisperAdapter).inSingletonScope();\n container.bind<ITranscriberRegistry>(DOOM_VOICE_TYPES.TranscriberRegistry).to(TranscriberRegistry).inSingletonScope();\n container\n .bind<IVoiceSessionController>(DOOM_VOICE_TYPES.SessionController)\n .to(VoiceWorkerSessionController)\n .inSingletonScope();\n return container;\n}\n\nexport interface VoiceExtensionOptions {\n footer?: VoiceFooterContributionHandle;\n mode?: VoiceModeContributionHandle;\n container?: Container;\n autoClientFactory?: VoiceWorkerSessionClientFactory;\n}\n\nexport function voiceExtension(pi: ExtensionAPI, options: VoiceExtensionOptions = {}): void {\n const container = options.container ?? createVoiceContainer();\n const controller = container.get<IVoiceSessionController>(DOOM_VOICE_TYPES.SessionController);\n const configs = container.get<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService);\n const footer = options.footer ?? { update: () => undefined, dispose: () => undefined };\n const mode = options.mode ?? { update: () => undefined, dispose: () => undefined };\n let lastUi: VoiceUi | undefined;\n let lastAutoUi: AutoCaptureUi | undefined;\n let activeContext: ExtensionContext | undefined;\n let disposeNarrationRequests: (() => void) | undefined;\n let autoModeVisible = false;\n const updateAutoMode = (visible: boolean): void => {\n if (visible === autoModeVisible) return;\n autoModeVisible = visible;\n mode.update(visible ? { label: AUTO_MODE_LABEL, color: AUTO_MODE_COLOR } : undefined);\n };\n const autoController = new VoiceWorkerAutoCaptureController({\n loadConfig: () => {\n const root = process.env.PI_PROJECT_ROOT ?? process.cwd();\n const loaded = configs.load(root).voice;\n if (!loaded) throw new Error('Voice is not configured in the Pi agent configuration.');\n return resolveVoiceConfig(loaded);\n },\n resolveModel: async (reference) => {\n if (!activeContext) throw new Error('No autonomous voice session is active');\n return resolveAutoCaptureModelContracts(reference, activeContext);\n },\n tts: container.get<ITtsAdapter>(DOOM_VOICE_TYPES.TtsAdapter),\n clock: container.get<IClock>(DOOM_VOICE_TYPES.Clock),\n deliver: (text) => {\n if (!activeContext) throw new Error('No autonomous voice session is active');\n deliverAutoCaptureInput(pi, activeContext, text);\n },\n manualState: () => controller.state,\n onActivationStateChange: (state) => updateAutoMode(state === 'active'),\n ...(options.autoClientFactory ? { clientFactory: options.autoClientFactory } : {}),\n });\n\n pi.registerCommand(COMMAND_NAME, {\n description: 'Toggle local voice recording and transcription',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) return;\n lastUi = createVoiceUi(ctx, footer);\n if (autoController.state !== 'disabled') {\n lastUi.notify('Disable autonomous voice before using manual voice', INFO_NOTIFICATION);\n return;\n }\n await controller.toggle(lastUi);\n },\n });\n pi.registerCommand(AUTO_COMMAND_NAME, {\n description: 'Toggle continuous autonomous voice conversation',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) return;\n activeContext = ctx;\n lastAutoUi = createAutoCaptureUi(ctx, footer);\n await autoController.toggle(lastAutoUi);\n },\n });\n pi.on('session_start', async (_event, ctx) => {\n activeContext = ctx;\n disposeNarrationRequests?.();\n const sessionId = (ctx as unknown as VoiceSessionContextLike).sessionManager?.getSessionId();\n disposeNarrationRequests = sessionId\n ? registerNarrationRequestHandler(pi.events, sessionId, autoController)\n : undefined;\n if (!ctx.hasUI) return;\n lastUi = createVoiceUi(ctx, footer);\n lastAutoUi = createAutoCaptureUi(ctx, footer);\n lastUi.setIndicator(undefined);\n lastUi.setStatus(STATUS_KEY, undefined);\n autoModeVisible = false;\n mode.update(undefined);\n });\n registerAutoCapturePiEventHandlers(pi, autoController);\n pi.on('session_shutdown', async () => {\n const ui = lastUi;\n const autoUi = lastAutoUi;\n lastUi = undefined;\n lastAutoUi = undefined;\n activeContext = undefined;\n disposeNarrationRequests?.();\n disposeNarrationRequests = undefined;\n await autoController.shutdown(autoUi);\n await controller.shutdown(ui);\n footer.dispose();\n mode.dispose();\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"voice.cjs","names":["subscribeToNarrationRequests","ASK_USER_BLOCKED_EVENT","VoiceAutoCaptureAdjudicator","SemanticEchoAdjudicator","NarrationGenerator","VoiceCommandCorrector","createDoomTelemetry","resolveVoiceConfig","injectable","inject","DOOM_CONFIG_TYPES","DOOM_VOICE_TYPES","fs","parseDoomConfig","path","globalDoomConfigPath","mergeDoomConfigs","os","repositoryDoomConfigPath","ContainerModule","SystemClock","ExecutableResolver","NodeProcessSpawner","NodeBinaryProcessSpawner","TemporaryWorkspace","FfmpegAudioRecorder","FfmpegPcmAudioRecorder","MacOsSayTtsAdapter","PcmWavAnalyzer","WhisperCppAdapter","OpenAiWhisperAdapter","MlxWhisperAdapter","TranscriberRegistry","VoiceWorkerSessionController","Container","MINOR_MODE_TOOL_NAME","createVoiceMinorModeCatalog","VoiceWorkerAutoCaptureController","collectVoiceCommandContext","registerMinorModeOwner"],"sources":["../../../src/adapters/pi/voice.ts"],"sourcesContent":["import 'reflect-metadata';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {\n globalDoomConfigPath,\n mergeDoomConfigs,\n parseDoomConfig,\n repositoryDoomConfigPath,\n resolveVoiceConfig,\n} from '@agimon-ai/doompi-config/config';\nimport {\n DOOM_CONFIG_TYPES,\n type DoomConfig,\n type IDoomConfigService,\n type ResolvedVoiceConfig,\n} from '@agimon-ai/doompi-config/types';\nimport { ASK_USER_BLOCKED_EVENT } from '@agimon-ai/doompi-extension-contracts';\nimport type { LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport {\n MINOR_MODE_TOOL_NAME,\n type MinorModeOwnerHandle,\n type MinorModeState,\n registerMinorModeOwner,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { subscribeToNarrationRequests } from '@agimon-ai/doompi-extension-contracts/narration';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { Container, ContainerModule, inject, injectable } from 'inversify';\nimport {\n type AutoCaptureModelContracts,\n type AutoCaptureModelRequest,\n type IAutoCaptureModelClient,\n VoiceAutoCaptureAdjudicator,\n} from '../../services/voice/autoCapture.ts';\nimport {\n type IVoiceCommandCorrectionModelClient,\n type VoiceCommandCorrectionModelRequest,\n VoiceCommandCorrector,\n} from '../../services/voice/commandCorrection.ts';\nimport {\n type INarrationModelClient,\n NarrationGenerator,\n type NarrationModelRequest,\n} from '../../services/voice/narration.ts';\nimport { SemanticEchoAdjudicator } from '../../services/voice/semanticEcho.ts';\nimport {\n type AutoCaptureActivationState,\n type AutoCaptureIndicatorState,\n type AutoCaptureUi,\n DOOM_VOICE_TYPES,\n type IAudioAnalyzer,\n type IAudioRecorder,\n type IBinaryProcessSpawner,\n type IClock,\n type IExecutableResolver,\n type IPcmAudioRecorder,\n type IProcessSpawner,\n type ITemporaryWorkspace,\n type ITranscriberAdapter,\n type ITranscriberRegistry,\n type ITtsAdapter,\n type IVoiceSessionController,\n type RecordingHandle,\n type SelectedTranscriber,\n type TimerHandle,\n type VoiceActivityUpdate,\n type VoiceState,\n type VoiceUi,\n} from '../../types/index.ts';\nimport {\n ExecutableResolver,\n FfmpegAudioRecorder,\n FfmpegPcmAudioRecorder,\n MacOsSayTtsAdapter,\n NodeBinaryProcessSpawner,\n NodeProcessSpawner,\n PcmWavAnalyzer,\n SystemClock,\n TemporaryWorkspace,\n} from '../audio/infrastructure.ts';\nimport { VoiceWorkerAutoCaptureController } from '../process/voiceWorkerAutoCaptureController.ts';\nimport {\n type VoiceWorkerSessionClientFactory,\n VoiceWorkerSessionController,\n} from '../process/voiceWorkerSessionController.ts';\nimport {\n MlxWhisperAdapter,\n OpenAiWhisperAdapter,\n TranscriberRegistry,\n WhisperCppAdapter,\n} from '../transcription/whisper.ts';\nimport { createVoiceMinorModeCatalog } from './minorModeCatalog.ts';\nimport { collectVoiceCommandContext } from './voiceCommandContext.ts';\n\nexport {\n MlxWhisperAdapter,\n OpenAiWhisperAdapter,\n TranscriberRegistry,\n WhisperCppAdapter,\n} from '../transcription/whisper.ts';\n\ninterface VoiceSessionContextLike {\n sessionManager?: { getSessionId(): string };\n}\n\nconst VOICE_SOURCE = '@agimon-ai/doompi-voice';\nconst COMMAND_NAME = 'voice';\nconst AUTO_COMMAND_NAME = 'voice-auto';\nconst STATUS_KEY = 'doom-voice';\nconst MAX_RECORDING_MS = 300_000;\nconst ACTIVITY_INTERVAL_MS = 120;\nconst LEADER_GROUP_ORDER = 67;\nconst AUTO_LEADER_DETAIL = 'continuous autonomous conversation';\nconst AUTO_MODE_LABEL = 'VOICE';\nconst AUTO_MODE_COLOR = 'accent' as const;\n\nfunction voiceModeState(state: AutoCaptureActivationState, hasUi = false): MinorModeState {\n const active = state !== 'disabled';\n const transitioning = state === 'starting' || state === 'draining' || state === 'shuttingDown';\n return {\n activation:\n state === 'starting'\n ? 'activating'\n : state === 'draining' || state === 'shuttingDown'\n ? 'deactivating'\n : active\n ? 'active'\n : 'inactive',\n condition: transitioning ? 'queued' : 'ready',\n ...(active ? { detail: state, color: AUTO_MODE_COLOR } : {}),\n actions: !hasUi\n ? [\n { id: 'activate', enabled: false, disabledReason: 'Autonomous voice requires a TUI session.' },\n { id: 'deactivate', enabled: false, disabledReason: 'Autonomous voice requires a TUI session.' },\n ]\n : transitioning\n ? [\n { id: 'activate', enabled: false, disabledReason: 'Autonomous voice is transitioning.' },\n { id: 'deactivate', enabled: false, disabledReason: 'Autonomous voice is transitioning.' },\n ]\n : [\n ...(active\n ? [{ id: 'activate', enabled: false, disabledReason: 'Autonomous voice is already enabled.' } as const]\n : [{ id: 'activate', enabled: true } as const]),\n ...(active\n ? [{ id: 'deactivate', enabled: true } as const]\n : [{ id: 'deactivate', enabled: false, disabledReason: 'Autonomous voice is disabled.' } as const]),\n ],\n };\n}\n\nconst RECORDING_FRAMES = ['·', '•', '●', '•'] as const;\nconst TRANSCRIBING_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] as const;\nconst INFO_NOTIFICATION = 'info';\nconst ERROR_NOTIFICATION = 'error';\nconst RECORDING_REQUESTED_EVENT = 'doom_voice.recording_requested';\nconst RECORDING_STARTED_EVENT = 'doom_voice.recording_started';\nconst RECORDING_FAILED_EVENT = 'doom_voice.recording_failed';\nconst RECORDING_FINISHED_EVENT = 'doom_voice.recording_finished';\nconst TRANSCRIPTION_STARTED_EVENT = 'doom_voice.transcription_started';\nconst TRANSCRIPTION_FINISHED_EVENT = 'doom_voice.transcription_finished';\nconst TRANSCRIPTION_FAILED_EVENT = 'doom_voice.transcription_failed';\nconst IDLE_STATE = 'idle' as const;\nconst RECORDING_STATE = 'recording' as const;\nconst TRANSCRIBING_STATE = 'transcribing' as const;\n\nexport interface VoiceFooterContributionValue {\n fullText: string;\n compactText: string;\n fullSegments: Array<{ text: string; color: 'warning' | 'accent' }>;\n compactSegments: Array<{ text: string; color: 'warning' | 'accent' }>;\n}\n\nexport interface VoiceFooterContributionHandle {\n update(value: VoiceFooterContributionValue | undefined): void;\n dispose(): void;\n}\n\nexport const VOICE_LEADER_BINDINGS: readonly LeaderBinding[] = [\n {\n id: 'voice.toggle',\n path: [\n { key: 'v', label: 'voice', order: LEADER_GROUP_ORDER },\n { key: 'v', label: 'toggle', detail: 'record or transcribe' },\n ],\n command: { name: COMMAND_NAME },\n },\n {\n id: 'voice.auto-toggle',\n path: [\n { key: 'v', label: 'voice', order: LEADER_GROUP_ORDER },\n { key: 'a', label: 'auto', detail: AUTO_LEADER_DETAIL },\n ],\n command: { name: AUTO_COMMAND_NAME },\n },\n];\n\nexport interface VoiceActivityPresentation {\n statusText: string;\n footer: VoiceFooterContributionValue;\n}\n\nexport interface AutoCaptureActivityPresentation {\n statusText: string;\n footer: VoiceFooterContributionValue;\n}\n\nexport function formatVoiceActivity(update: VoiceActivityUpdate): VoiceActivityPresentation {\n const frames = update.state === RECORDING_STATE ? RECORDING_FRAMES : TRANSCRIBING_FRAMES;\n const frameIndex = Math.max(0, Math.floor(update.frameIndex)) % frames.length;\n const frame = frames[frameIndex]!;\n const color = update.state === RECORDING_STATE ? ('warning' as const) : ('accent' as const);\n const elapsed = Math.max(0, Math.floor(update.elapsedSeconds ?? 0));\n const statusText =\n update.state === RECORDING_STATE\n ? `${frame} voice: recording ${Math.floor(elapsed / 60)}:${String(elapsed % 60).padStart(2, '0')}`\n : `${frame} voice: transcribing`;\n return {\n statusText,\n footer: {\n fullText: frame,\n compactText: frame,\n fullSegments: [{ text: frame, color }],\n compactSegments: [{ text: frame, color }],\n },\n };\n}\n\nfunction createVoiceUi(context: ExtensionContext, footer: VoiceFooterContributionHandle): VoiceUi {\n return {\n notify: (message, level) => context.ui.notify(message, level),\n setStatus: (key, value) => context.ui.setStatus(key, value),\n setIndicator: (update) => footer.update(update ? formatVoiceActivity(update).footer : undefined),\n getEditorText: () => context.ui.getEditorText(),\n setEditorText: (text) => context.ui.setEditorText(text),\n };\n}\n\nexport function formatAutoCaptureActivity(state: AutoCaptureIndicatorState): AutoCaptureActivityPresentation {\n const presentation =\n state === 'listening'\n ? { frame: 'A', statusText: 'voice auto: listening', color: 'accent' as const }\n : state === 'speech'\n ? { frame: '!', statusText: 'voice auto: hearing speech', color: 'warning' as const }\n : state === 'processing'\n ? { frame: '…', statusText: 'voice auto: processing while listening', color: 'accent' as const }\n : state === 'narrating'\n ? { frame: 'A', statusText: 'voice auto: narrating and listening', color: 'accent' as const }\n : state === 'confirming'\n ? { frame: '?', statusText: 'voice auto: confirmation needed', color: 'warning' as const }\n : state === 'waiting'\n ? { frame: '…', statusText: 'voice auto: waiting for keyboard input', color: 'warning' as const }\n : { frame: 'A', statusText: 'voice auto: draining', color: 'warning' as const };\n return {\n statusText: presentation.statusText,\n footer: {\n fullText: presentation.frame,\n compactText: presentation.frame,\n fullSegments: [{ text: presentation.frame, color: presentation.color }],\n compactSegments: [{ text: presentation.frame, color: presentation.color }],\n },\n };\n}\n\nfunction createAutoCaptureUi(context: ExtensionContext, footer: VoiceFooterContributionHandle): AutoCaptureUi {\n return {\n notify: (message, level) => context.ui.notify(message, level),\n setStatus: (value) => context.ui.setStatus(STATUS_KEY, value),\n setIndicator: (state) => footer.update(state ? formatAutoCaptureActivity(state).footer : undefined),\n };\n}\n\ntype PiVoiceModelRequest = AutoCaptureModelRequest | NarrationModelRequest | VoiceCommandCorrectionModelRequest;\ntype PiVoiceModelClient = IAutoCaptureModelClient & INarrationModelClient & IVoiceCommandCorrectionModelClient;\nexport type AutoCaptureDeliveryIntent = 'immediate' | 'queuedFollowUp';\n\nexport function deliverAutoCaptureInput(\n pi: Pick<ExtensionAPI, 'sendUserMessage'>,\n context: Pick<ExtensionContext, 'isIdle'>,\n text: string,\n intent: AutoCaptureDeliveryIntent = 'immediate',\n): void {\n if (context.isIdle()) {\n pi.sendUserMessage(text);\n return;\n }\n pi.sendUserMessage(text, { deliverAs: intent === 'queuedFollowUp' ? 'followUp' : 'steer' });\n}\n\nexport interface AutoCapturePiEventController {\n observeInput(event: {\n text: string;\n source: 'interactive' | 'rpc' | 'extension';\n streamingBehavior?: 'steer' | 'followUp';\n }): void;\n beforeAgentStart(prompt: string): void;\n agentStarted(): void;\n finalizedAssistantIntent(sourceText: string): void;\n planWritten(): void;\n askUserBlocked(blocked: boolean): void;\n turnFinished(turnIndex: number, reason: string, toolCount: number, latestAssistantText?: string): void;\n agentSettled(): Promise<void>;\n}\n\ninterface FinalizedIntentSource {\n text: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isAskUserBlockedPayload(payload: unknown): payload is { active: boolean } {\n return isRecord(payload) && typeof payload.active === 'boolean';\n}\n\nexport function extractFinalizedIntentSource(message: unknown): FinalizedIntentSource | undefined {\n if (!isRecord(message) || message.role !== 'assistant' || !Array.isArray(message.content)) return undefined;\n const text: string[] = [];\n for (const block of message.content) {\n if (!isRecord(block)) continue;\n if (block.type === 'toolCall') return { text: text.join('').trim() };\n if (block.type === 'text' && typeof block.text === 'string') text.push(block.text);\n }\n return undefined;\n}\n\nexport function extractTerminalAssistantText(message: unknown): string | undefined {\n if (\n !isRecord(message) ||\n message.role !== 'assistant' ||\n message.stopReason === 'toolUse' ||\n !Array.isArray(message.content)\n )\n return undefined;\n const text: string[] = [];\n for (const block of message.content) {\n if (!isRecord(block)) continue;\n if (block.type === 'toolCall') return undefined;\n if (block.type === 'text' && typeof block.text === 'string') text.push(block.text);\n }\n return text.join('').trim() || undefined;\n}\n\nexport function isSuccessfulPlanWrite(toolName: string, isError: boolean, result: unknown): boolean {\n if (toolName !== 'write_plan' || isError || !isRecord(result)) return false;\n return isRecord(result.details) && result.details.written === true;\n}\n\nexport function registerNarrationRequestHandler(\n events: ExtensionAPI['events'],\n sessionId: string,\n controller: Pick<VoiceWorkerAutoCaptureController, 'narrate'>,\n): () => void {\n return subscribeToNarrationRequests({ bus: events, source: VOICE_SOURCE, sessionId }, ({ text }) =>\n controller.narrate(text),\n );\n}\n\nexport function registerAutoCapturePiEventHandlers(\n pi: Pick<ExtensionAPI, 'on'> & { events?: Pick<ExtensionAPI['events'], 'on'> },\n controller: AutoCapturePiEventController,\n): void {\n pi.events?.on(ASK_USER_BLOCKED_EVENT, (payload) => {\n if (isAskUserBlockedPayload(payload)) controller.askUserBlocked(payload.active);\n });\n pi.on('input', (event) => {\n controller.observeInput({\n text: event.text,\n source: event.source,\n ...(event.streamingBehavior ? { streamingBehavior: event.streamingBehavior } : {}),\n });\n });\n pi.on('before_agent_start', (event) => controller.beforeAgentStart(event.prompt));\n pi.on('agent_start', () => controller.agentStarted());\n pi.on('message_end', (event) => {\n const source = extractFinalizedIntentSource(event.message);\n if (source) controller.finalizedAssistantIntent(source.text);\n });\n pi.on('tool_execution_end', (event) => {\n if (isSuccessfulPlanWrite(event.toolName, event.isError, event.result)) controller.planWritten();\n });\n pi.on('turn_end', (event) => {\n const message = event.message;\n controller.turnFinished(\n event.turnIndex,\n message.role === 'assistant' ? message.stopReason : 'unknown',\n event.toolResults.length,\n extractTerminalAssistantText(message),\n );\n });\n pi.on('agent_settled', async () => controller.agentSettled());\n}\n\nexport function resolveAutoCaptureModelContracts(\n reference: string,\n context: ExtensionContext,\n): AutoCaptureModelContracts {\n const separator = reference.indexOf('/');\n if (separator <= 0 || separator === reference.length - 1)\n throw new Error('Autonomous voice model must use provider/model-id form');\n const provider = reference.slice(0, separator);\n const modelId = reference.slice(separator + 1);\n const model = context.modelRegistry.find(provider, modelId);\n if (!model) throw new Error(`Autonomous voice model is not registered: ${reference}`);\n if (!context.modelRegistry.hasConfiguredAuth(model))\n throw new Error(`Autonomous voice model has no configured authentication: ${reference}`);\n\n const modelClient: PiVoiceModelClient = {\n complete: async (request: PiVoiceModelRequest): Promise<string> => {\n const response = await context.modelRegistry.complete(\n model,\n {\n systemPrompt: request.systemPrompt,\n messages: [{ role: 'user', content: request.input, timestamp: Date.now() }],\n },\n {\n signal: request.signal,\n ...(request.maxTokens === undefined ? {} : { maxTokens: request.maxTokens }),\n cacheRetention: request.cacheRetention,\n reasoningEffort: 'none',\n maxRetries: 0,\n },\n );\n if (response.stopReason === 'error' || response.stopReason === 'aborted')\n throw new Error(response.errorMessage ?? `Autonomous voice model stopped with ${response.stopReason}`);\n return response.content\n .filter((content) => content.type === 'text')\n .map((content) => content.text)\n .join('')\n .trim();\n },\n };\n return {\n adjudicator: new VoiceAutoCaptureAdjudicator(modelClient),\n echo: new SemanticEchoAdjudicator(),\n narrator: new NarrationGenerator(modelClient),\n corrector: new VoiceCommandCorrector(modelClient),\n };\n}\n\n@injectable()\nexport class VoiceSessionController implements IVoiceSessionController {\n private currentState: VoiceState = IDLE_STATE;\n private recording?: RecordingHandle;\n private workspace?: string;\n private config?: ResolvedVoiceConfig;\n private selected?: SelectedTranscriber;\n private startedAt = 0;\n private activityFrame = 0;\n private activityTimer?: TimerHandle;\n private limitTimer?: TimerHandle;\n private readonly telemetry = createDoomTelemetry({\n serviceName: 'doom-voice',\n packageName: '@agimon-ai/doompi-voice',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n constructor(\n @inject(DOOM_CONFIG_TYPES.ConfigService) private readonly configs: IDoomConfigService,\n @inject(DOOM_VOICE_TYPES.Clock) private readonly clock: IClock,\n @inject(DOOM_VOICE_TYPES.TemporaryWorkspace) private readonly workspaces: ITemporaryWorkspace,\n @inject(DOOM_VOICE_TYPES.AudioRecorder) private readonly recorder: IAudioRecorder,\n @inject(DOOM_VOICE_TYPES.AudioAnalyzer) private readonly analyzer: IAudioAnalyzer,\n @inject(DOOM_VOICE_TYPES.TranscriberRegistry) private readonly registry: ITranscriberRegistry,\n ) {}\n get state(): VoiceState {\n return this.currentState;\n }\n async toggle(ui: VoiceUi): Promise<void> {\n if (this.currentState === TRANSCRIBING_STATE) {\n ui.notify('Voice transcription is already running', INFO_NOTIFICATION);\n return;\n }\n if (this.currentState === RECORDING_STATE) {\n await this.stopAndTranscribe(ui);\n return;\n }\n await this.startRecording(ui);\n }\n private async startRecording(ui: VoiceUi): Promise<void> {\n try {\n const projectRoot = process.env.PI_PROJECT_ROOT ?? process.cwd();\n const loaded = this.configs.load(projectRoot).voice;\n if (!loaded) throw new Error('Voice is not configured in the Pi agent configuration.');\n const config = resolveVoiceConfig(loaded);\n this.recorder.preflight(config);\n const selected = this.registry.select(config);\n void this.telemetry.recordEvent(RECORDING_REQUESTED_EVENT, {\n engine: selected.adapter.engine,\n mode: config.language,\n });\n const workspace = this.workspaces.create();\n this.recording = this.recorder.start(config, workspace);\n this.workspace = workspace;\n this.config = config;\n this.selected = selected;\n this.currentState = RECORDING_STATE;\n this.startedAt = this.clock.now();\n this.startActivity(ui);\n this.limitTimer = this.clock.setTimeout(() => {\n void this.stopAndTranscribe(ui);\n }, MAX_RECORDING_MS);\n void this.telemetry.recordEvent(RECORDING_STARTED_EVENT, {\n engine: selected.adapter.engine,\n outcome: 'started',\n });\n } catch (error) {\n await this.telemetry.recordError(RECORDING_FAILED_EVENT, error, { outcome: 'failed' });\n this.reset(ui);\n ui.notify(error instanceof Error ? error.message : String(error), ERROR_NOTIFICATION);\n }\n }\n private startActivity(ui: VoiceUi): void {\n this.activityFrame = 0;\n this.publishActivity(ui);\n this.activityTimer = this.clock.setInterval(() => {\n this.activityFrame += 1;\n this.publishActivity(ui);\n }, ACTIVITY_INTERVAL_MS);\n }\n private publishActivity(ui: VoiceUi): void {\n if (this.currentState === IDLE_STATE) return;\n const update: VoiceActivityUpdate = {\n state: this.currentState,\n frameIndex: this.activityFrame,\n ...(this.currentState === RECORDING_STATE\n ? { elapsedSeconds: Math.max(0, Math.floor((this.clock.now() - this.startedAt) / 1_000)) }\n : {}),\n };\n ui.setIndicator(update);\n ui.setStatus(STATUS_KEY, formatVoiceActivity(update).statusText);\n }\n private async stopAndTranscribe(ui: VoiceUi): Promise<void> {\n const recording = this.recording;\n const workspace = this.workspace;\n const config = this.config;\n const selected = this.selected;\n if (!recording || !workspace || !config || !selected || this.currentState !== RECORDING_STATE) return;\n this.clearTimers();\n const recordingStartedAt = this.startedAt;\n this.currentState = TRANSCRIBING_STATE;\n this.startActivity(ui);\n void this.telemetry.recordEvent(TRANSCRIPTION_STARTED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: Math.max(0, this.clock.now() - recordingStartedAt),\n });\n try {\n await recording.stop();\n const recordingDurationMs = Math.max(0, this.clock.now() - recordingStartedAt);\n if (this.analyzer.analyze(recording.filePath).silent) {\n await this.telemetry.recordEvent(TRANSCRIPTION_FINISHED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: recordingDurationMs,\n silence: true,\n outcome: 'empty',\n });\n ui.notify('No speech detected', INFO_NOTIFICATION);\n return;\n }\n const transcript = (\n await selected.adapter.transcribe({\n audioPath: recording.filePath,\n workspace,\n config: selected.config,\n language: config.language,\n })\n ).trim();\n if (!transcript) {\n await this.telemetry.recordEvent(TRANSCRIPTION_FINISHED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: recordingDurationMs,\n empty: true,\n outcome: 'empty',\n });\n ui.notify('Voice transcription was empty', INFO_NOTIFICATION);\n return;\n }\n const draft = ui.getEditorText();\n ui.setEditorText(`${draft}${draft && !/\\s$/.test(draft) ? ' ' : ''}${transcript}`);\n await this.telemetry.recordEvent(TRANSCRIPTION_FINISHED_EVENT, {\n engine: selected.adapter.engine,\n duration_ms: recordingDurationMs,\n empty: false,\n outcome: 'completed',\n });\n } catch (error) {\n await this.telemetry.recordError(TRANSCRIPTION_FAILED_EVENT, error, {\n engine: selected.adapter.engine,\n duration_ms: Math.max(0, this.clock.now() - recordingStartedAt),\n });\n ui.notify(error instanceof Error ? error.message : String(error), ERROR_NOTIFICATION);\n } finally {\n this.reset(ui);\n }\n }\n async shutdown(ui?: VoiceUi): Promise<void> {\n this.clearTimers();\n if (this.recording && this.currentState === RECORDING_STATE) {\n await this.recording.abort();\n void this.telemetry.recordEvent(RECORDING_FINISHED_EVENT, { outcome: 'aborted' });\n }\n this.reset(ui);\n void this.telemetry.shutdown();\n }\n private clearTimers(): void {\n if (this.activityTimer) this.clock.clear(this.activityTimer);\n if (this.limitTimer) this.clock.clear(this.limitTimer);\n this.activityTimer = undefined;\n this.limitTimer = undefined;\n }\n private reset(ui?: VoiceUi): void {\n this.clearTimers();\n if (this.workspace) this.workspaces.remove(this.workspace);\n this.recording = undefined;\n this.workspace = undefined;\n this.config = undefined;\n this.selected = undefined;\n this.currentState = IDLE_STATE;\n this.activityFrame = 0;\n ui?.setIndicator(undefined);\n ui?.setStatus(STATUS_KEY, undefined);\n }\n}\n\nfunction readVoiceConfig(filePath: string): DoomConfig {\n if (!fs.existsSync(filePath)) return { projectTrust: 'ask' };\n return parseDoomConfig(fs.readFileSync(filePath, 'utf8'), filePath);\n}\n\nfunction voiceAgentConfigPath(homeDirectory: string): string {\n const agentDirectory = process.env.PI_CODING_AGENT_DIR || path.join(homeDirectory, '.pi', 'agent');\n return path.join(agentDirectory, 'doom-voice', 'config.yaml');\n}\n\n/**\n * Shared Doom config owns `voice:`; the package-scoped file is the fallback for\n * standalone installs that have no Doom config.\n */\nfunction readGlobalVoiceConfig(homeDirectory: string): DoomConfig {\n const doomConfig = readVoiceConfig(globalDoomConfigPath(homeDirectory));\n if (doomConfig.voice) return doomConfig;\n const packageConfig = readVoiceConfig(voiceAgentConfigPath(homeDirectory));\n return packageConfig.voice ? mergeDoomConfigs(doomConfig, packageConfig) : doomConfig;\n}\n\n@injectable()\nexport class PiVoiceConfigService implements IDoomConfigService {\n load(repoRoot: string, homeDirectory = os.homedir()): DoomConfig {\n const globalConfig = readGlobalVoiceConfig(homeDirectory);\n const trusted = process.env.PI_PROJECT_TRUST === 'trusted';\n if (!trusted) return globalConfig;\n\n const projectPath = repositoryDoomConfigPath(repoRoot);\n const projectConfig = readVoiceConfig(projectPath);\n if (projectConfig.projectTrust === 'never') return globalConfig;\n return mergeDoomConfigs(globalConfig, projectConfig);\n }\n}\n\nexport function createVoiceModule(): ContainerModule {\n return new ContainerModule(({ bind }) => {\n bind<IClock>(DOOM_VOICE_TYPES.Clock).to(SystemClock).inSingletonScope();\n bind<IExecutableResolver>(DOOM_VOICE_TYPES.ExecutableResolver).to(ExecutableResolver).inSingletonScope();\n bind<IProcessSpawner>(DOOM_VOICE_TYPES.ProcessSpawner).to(NodeProcessSpawner).inSingletonScope();\n bind<IBinaryProcessSpawner>(DOOM_VOICE_TYPES.BinaryProcessSpawner).to(NodeBinaryProcessSpawner).inSingletonScope();\n bind<ITemporaryWorkspace>(DOOM_VOICE_TYPES.TemporaryWorkspace).to(TemporaryWorkspace).inSingletonScope();\n bind<IAudioRecorder>(DOOM_VOICE_TYPES.AudioRecorder).to(FfmpegAudioRecorder).inSingletonScope();\n bind<IPcmAudioRecorder>(DOOM_VOICE_TYPES.PcmAudioRecorder).to(FfmpegPcmAudioRecorder).inSingletonScope();\n bind<ITtsAdapter>(DOOM_VOICE_TYPES.TtsAdapter).to(MacOsSayTtsAdapter).inSingletonScope();\n bind<IAudioAnalyzer>(DOOM_VOICE_TYPES.AudioAnalyzer).to(PcmWavAnalyzer).inSingletonScope();\n bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.WhisperCppAdapter).to(WhisperCppAdapter).inSingletonScope();\n bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.OpenAiWhisperAdapter).to(OpenAiWhisperAdapter).inSingletonScope();\n bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.MlxWhisperAdapter).to(MlxWhisperAdapter).inSingletonScope();\n bind<ITranscriberRegistry>(DOOM_VOICE_TYPES.TranscriberRegistry).to(TranscriberRegistry).inSingletonScope();\n bind<IVoiceSessionController>(DOOM_VOICE_TYPES.SessionController)\n .to(VoiceWorkerSessionController)\n .inSingletonScope();\n });\n}\nexport function createVoiceContainer(): Container {\n const container = new Container();\n container.bind<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService).to(PiVoiceConfigService).inSingletonScope();\n container.bind<IClock>(DOOM_VOICE_TYPES.Clock).to(SystemClock).inSingletonScope();\n container.bind<IExecutableResolver>(DOOM_VOICE_TYPES.ExecutableResolver).to(ExecutableResolver).inSingletonScope();\n container.bind<IProcessSpawner>(DOOM_VOICE_TYPES.ProcessSpawner).to(NodeProcessSpawner).inSingletonScope();\n container\n .bind<IBinaryProcessSpawner>(DOOM_VOICE_TYPES.BinaryProcessSpawner)\n .to(NodeBinaryProcessSpawner)\n .inSingletonScope();\n container.bind<ITemporaryWorkspace>(DOOM_VOICE_TYPES.TemporaryWorkspace).to(TemporaryWorkspace).inSingletonScope();\n container.bind<IAudioRecorder>(DOOM_VOICE_TYPES.AudioRecorder).to(FfmpegAudioRecorder).inSingletonScope();\n container.bind<IPcmAudioRecorder>(DOOM_VOICE_TYPES.PcmAudioRecorder).to(FfmpegPcmAudioRecorder).inSingletonScope();\n container.bind<ITtsAdapter>(DOOM_VOICE_TYPES.TtsAdapter).to(MacOsSayTtsAdapter).inSingletonScope();\n container.bind<IAudioAnalyzer>(DOOM_VOICE_TYPES.AudioAnalyzer).to(PcmWavAnalyzer).inSingletonScope();\n container.bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.WhisperCppAdapter).to(WhisperCppAdapter).inSingletonScope();\n container\n .bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.OpenAiWhisperAdapter)\n .to(OpenAiWhisperAdapter)\n .inSingletonScope();\n container.bind<ITranscriberAdapter>(DOOM_VOICE_TYPES.MlxWhisperAdapter).to(MlxWhisperAdapter).inSingletonScope();\n container.bind<ITranscriberRegistry>(DOOM_VOICE_TYPES.TranscriberRegistry).to(TranscriberRegistry).inSingletonScope();\n container\n .bind<IVoiceSessionController>(DOOM_VOICE_TYPES.SessionController)\n .to(VoiceWorkerSessionController)\n .inSingletonScope();\n return container;\n}\n\nfunction reconcileMinorModeTool(pi: ExtensionAPI, enabled: boolean): void {\n const activeTools = pi.getActiveTools();\n const active = activeTools.includes(MINOR_MODE_TOOL_NAME);\n if (!enabled && active) {\n pi.setActiveTools(activeTools.filter((name) => name !== MINOR_MODE_TOOL_NAME));\n return;\n }\n const registered = pi.getAllTools().some((tool) => tool.name === MINOR_MODE_TOOL_NAME);\n if (enabled && registered && !active) pi.setActiveTools([...activeTools, MINOR_MODE_TOOL_NAME]);\n}\n\nexport interface VoiceExtensionOptions {\n footer?: VoiceFooterContributionHandle;\n container?: Container;\n autoClientFactory?: VoiceWorkerSessionClientFactory;\n}\n\nexport function voiceExtension(pi: ExtensionAPI, options: VoiceExtensionOptions = {}): void {\n const container = options.container ?? createVoiceContainer();\n const controller = container.get<IVoiceSessionController>(DOOM_VOICE_TYPES.SessionController);\n const configs = container.get<IDoomConfigService>(DOOM_CONFIG_TYPES.ConfigService);\n const footer = options.footer ?? { update: () => undefined, dispose: () => undefined };\n let lastUi: VoiceUi | undefined;\n let lastAutoUi: AutoCaptureUi | undefined;\n let activeContext: ExtensionContext | undefined;\n let disposeNarrationRequests: (() => void) | undefined;\n const modeCatalog = createVoiceMinorModeCatalog(pi);\n let mode: Pick<MinorModeOwnerHandle, 'publish' | 'dispose'> | undefined;\n const autoController = new VoiceWorkerAutoCaptureController({\n loadConfig: () => {\n const root = process.env.PI_PROJECT_ROOT ?? process.cwd();\n const loaded = configs.load(root).voice;\n if (!loaded) throw new Error('Voice is not configured in the Pi agent configuration.');\n return resolveVoiceConfig(loaded);\n },\n resolveModel: async (reference) => {\n if (!activeContext) throw new Error('No autonomous voice session is active');\n return resolveAutoCaptureModelContracts(reference, activeContext);\n },\n tts: container.get<ITtsAdapter>(DOOM_VOICE_TYPES.TtsAdapter),\n clock: container.get<IClock>(DOOM_VOICE_TYPES.Clock),\n deliver: (text) => {\n if (!activeContext) throw new Error('No autonomous voice session is active');\n deliverAutoCaptureInput(pi, activeContext, text);\n },\n manualState: () => controller.state,\n commandContext: () =>\n activeContext\n ? collectVoiceCommandContext(activeContext.sessionManager.getBranch(), modeCatalog.records())\n : undefined,\n onActivationStateChange: (state) => {\n reconcileMinorModeTool(pi, state === 'active');\n mode?.publish(voiceModeState(state, activeContext?.hasUI === true));\n },\n ...(options.autoClientFactory ? { clientFactory: options.autoClientFactory } : {}),\n });\n mode = registerMinorModeOwner(pi, {\n descriptor: {\n source: '@agimon-ai/doompi-voice',\n id: 'voice-auto',\n label: AUTO_MODE_LABEL,\n description: 'Continuous autonomous voice capture, correction, and narration.',\n order: 30,\n actions: [\n {\n id: 'activate',\n label: 'Activate',\n description: 'Start autonomous voice capture.',\n contexts: ['tui'],\n parameters: [],\n },\n {\n id: 'deactivate',\n label: 'Deactivate',\n description: 'Stop autonomous voice capture.',\n contexts: ['tui'],\n parameters: [],\n },\n ],\n },\n initialState: voiceModeState('disabled'),\n async handleAction(actionId, _argumentsValue, execution) {\n activeContext = execution.context;\n const ui = createAutoCaptureUi(execution.context, footer);\n lastAutoUi = ui;\n if (actionId === 'activate') {\n await autoController.activate(ui);\n return { message: 'Autonomous voice activation requested.' };\n }\n if (actionId === 'deactivate') {\n await autoController.deactivate(ui);\n return { message: 'Autonomous voice deactivation requested.' };\n }\n throw new Error(`Unknown autonomous voice action: ${actionId}`);\n },\n });\n\n pi.registerCommand(COMMAND_NAME, {\n description: 'Toggle local voice recording and transcription',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) return;\n lastUi = createVoiceUi(ctx, footer);\n if (autoController.state !== 'disabled') {\n lastUi.notify('Disable autonomous voice before using manual voice', INFO_NOTIFICATION);\n return;\n }\n await controller.toggle(lastUi);\n },\n });\n pi.registerCommand(AUTO_COMMAND_NAME, {\n description: 'Toggle continuous autonomous voice conversation',\n handler: async (_args, ctx) => {\n if (!ctx.hasUI) return;\n activeContext = ctx;\n lastAutoUi = createAutoCaptureUi(ctx, footer);\n if (autoController.state === 'disabled') await autoController.activate(lastAutoUi);\n else await autoController.deactivate(lastAutoUi);\n },\n });\n pi.on('session_start', async (_event, ctx) => {\n reconcileMinorModeTool(pi, false);\n activeContext = ctx;\n disposeNarrationRequests?.();\n const sessionId = (ctx as unknown as VoiceSessionContextLike).sessionManager?.getSessionId();\n if (sessionId) modeCatalog.bind(sessionId);\n disposeNarrationRequests = sessionId\n ? registerNarrationRequestHandler(pi.events, sessionId, autoController)\n : undefined;\n if (!ctx.hasUI) return;\n lastUi = createVoiceUi(ctx, footer);\n lastAutoUi = createAutoCaptureUi(ctx, footer);\n lastUi.setIndicator(undefined);\n lastUi.setStatus(STATUS_KEY, undefined);\n mode?.publish(voiceModeState('disabled', ctx.hasUI));\n });\n pi.on('before_agent_start', () => {\n reconcileMinorModeTool(pi, autoController.state === 'active');\n });\n registerAutoCapturePiEventHandlers(pi, autoController);\n pi.on('session_shutdown', async () => {\n const ui = lastUi;\n const autoUi = lastAutoUi;\n lastUi = undefined;\n lastAutoUi = undefined;\n activeContext = undefined;\n reconcileMinorModeTool(pi, false);\n disposeNarrationRequests?.();\n disposeNarrationRequests = undefined;\n modeCatalog.dispose();\n await autoController.shutdown(autoUi);\n await controller.shutdown(ui);\n footer.dispose();\n mode?.dispose();\n });\n}\n"],"mappings":"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"}
@@ -25,15 +25,6 @@ interface VoiceFooterContributionHandle {
25
25
  update(value: VoiceFooterContributionValue | undefined): void;
26
26
  dispose(): void;
27
27
  }
28
- interface VoiceModeContributionValue {
29
- label: string;
30
- detail?: string;
31
- color?: 'accent' | 'warning' | 'mdHeading' | 'muted' | 'dim';
32
- }
33
- interface VoiceModeContributionHandle {
34
- update(value: VoiceModeContributionValue | undefined): void;
35
- dispose(): void;
36
- }
37
28
  declare const VOICE_LEADER_BINDINGS: readonly LeaderBinding[];
38
29
  interface VoiceActivityPresentation {
39
30
  statusText: string;
@@ -110,11 +101,10 @@ declare function createVoiceModule(): ContainerModule;
110
101
  declare function createVoiceContainer(): Container;
111
102
  interface VoiceExtensionOptions {
112
103
  footer?: VoiceFooterContributionHandle;
113
- mode?: VoiceModeContributionHandle;
114
104
  container?: Container;
115
105
  autoClientFactory?: VoiceWorkerSessionClientFactory;
116
106
  }
117
107
  declare function voiceExtension(pi: ExtensionAPI, options?: VoiceExtensionOptions): void;
118
108
  //#endregion
119
- export { AutoCaptureActivityPresentation, AutoCaptureDeliveryIntent, AutoCapturePiEventController, MlxWhisperAdapter, OpenAiWhisperAdapter, PiVoiceConfigService, TranscriberRegistry, VOICE_LEADER_BINDINGS, VoiceActivityPresentation, VoiceExtensionOptions, VoiceFooterContributionHandle, VoiceFooterContributionValue, VoiceModeContributionHandle, VoiceModeContributionValue, VoiceSessionController, WhisperCppAdapter, createVoiceContainer, createVoiceModule, deliverAutoCaptureInput, extractFinalizedIntentSource, extractTerminalAssistantText, formatAutoCaptureActivity, formatVoiceActivity, isAskUserBlockedPayload, isSuccessfulPlanWrite, registerAutoCapturePiEventHandlers, registerNarrationRequestHandler, resolveAutoCaptureModelContracts, voiceExtension };
109
+ export { AutoCaptureActivityPresentation, AutoCaptureDeliveryIntent, AutoCapturePiEventController, MlxWhisperAdapter, OpenAiWhisperAdapter, PiVoiceConfigService, TranscriberRegistry, VOICE_LEADER_BINDINGS, VoiceActivityPresentation, VoiceExtensionOptions, VoiceFooterContributionHandle, VoiceFooterContributionValue, VoiceSessionController, WhisperCppAdapter, createVoiceContainer, createVoiceModule, deliverAutoCaptureInput, extractFinalizedIntentSource, extractTerminalAssistantText, formatAutoCaptureActivity, formatVoiceActivity, isAskUserBlockedPayload, isSuccessfulPlanWrite, registerAutoCapturePiEventHandlers, registerNarrationRequestHandler, resolveAutoCaptureModelContracts, voiceExtension };
120
110
  //# sourceMappingURL=voice.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"voice.d.cts","names":[],"sources":["../../../src/adapters/pi/voice.ts"],"mappings":";;;;;;;;;;;UAqHiB;EACf;EACA;EACA,cAAc;IAAQ;IAAc;;EACpC,iBAAiB;IAAQ;IAAc;;;UAGxB;EACf,OAAO,OAAO;EACd;;UAGe;EACf;EACA;EACA;;UAGe;EACf,OAAO,OAAO;EACd;;cAGW,gCAAgC;UAmB5B;EACf;EACA,QAAQ;;UAGO;EACf;EACA,QAAQ;;iBAGM,oBAAoB,QAAQ,sBAAsB;iBA+BlD,0BAA0B,OAAO,4BAA4B;KAoCjE;iBAEI,wBACd,IAAI,KAAK,kCACT,SAAS,KAAK,6BACd,cACA,SAAQ;UASO;EACf,aAAa;IACX;IACA;IACA;;EAEF,iBAAiB;EACjB;EACA,yBAAyB;EACzB;EACA,eAAe;EACf,aAAa,mBAAmB,gBAAgB,mBAAmB;EACnE,gBAAgB;;UAGR;EACR;;iBAOc,wBAAwB,mBAAmB;EAAa;;iBAIxD,6BAA6B,mBAAmB;iBAWhD,6BAA6B;iBAiB7B,sBAAsB,kBAAkB,kBAAkB;iBAK1D,gCACd,QAAQ,wBACR,mBACA,YAAY,KAAK;iBAOH,mCACd,IAAI,KAAK;EAAwB,SAAS,KAAK;GAC/C,YAAY;iBAiCE,iCACd,mBACA,SAAS,mBACR;cA4CU,kCAAkC;mBAkBe;mBACT;mBACa;mBACL;mBACA;mBACM;UAtBzD;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;EAQ2C,YAAA,SAAS,oBAClB,OAAO,QACM,YAAY,qBACjB,UAAU,gBACV,UAAU,gBACJ,UAAU;MAEvE,SAAS;EAGP,OAAO,IAAI,UAAU;UAWb;UAiCN;UAQA;UAYM;EA+DR,SAAS,KAAK,UAAU;UAStB;UAMA;;cAoCG,gCAAgC;EAC3C,KAAK,kBAAkB,yBAA+B;;iBAYxC,qBAAqB;iBAoBrB,wBAAwB;UA6BvB;EACf,SAAS;EACT,OAAO;EACP,YAAY;EACZ,oBAAoB;;iBAGN,eAAe,IAAI,cAAc,UAAS"}
1
+ {"version":3,"file":"voice.d.cts","names":[],"sources":["../../../src/adapters/pi/voice.ts"],"mappings":";;;;;;;;;;;UAuKiB;EACf;EACA;EACA,cAAc;IAAQ;IAAc;;EACpC,iBAAiB;IAAQ;IAAc;;;UAGxB;EACf,OAAO,OAAO;EACd;;cAGW,gCAAgC;UAmB5B;EACf;EACA,QAAQ;;UAGO;EACf;EACA,QAAQ;;iBAGM,oBAAoB,QAAQ,sBAAsB;iBA+BlD,0BAA0B,OAAO,4BAA4B;KAoCjE;iBAEI,wBACd,IAAI,KAAK,kCACT,SAAS,KAAK,6BACd,cACA,SAAQ;UASO;EACf,aAAa;IACX;IACA;IACA;;EAEF,iBAAiB;EACjB;EACA,yBAAyB;EACzB;EACA,eAAe;EACf,aAAa,mBAAmB,gBAAgB,mBAAmB;EACnE,gBAAgB;;UAGR;EACR;;iBAOc,wBAAwB,mBAAmB;EAAa;;iBAIxD,6BAA6B,mBAAmB;iBAWhD,6BAA6B;iBAiB7B,sBAAsB,kBAAkB,kBAAkB;iBAK1D,gCACd,QAAQ,wBACR,mBACA,YAAY,KAAK;iBAOH,mCACd,IAAI,KAAK;EAAwB,SAAS,KAAK;GAC/C,YAAY;iBAiCE,iCACd,mBACA,SAAS,mBACR;cA6CU,kCAAkC;mBAkBe;mBACT;mBACa;mBACL;mBACA;mBACM;UAtBzD;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;EAQ2C,YAAA,SAAS,oBAClB,OAAO,QACM,YAAY,qBACjB,UAAU,gBACV,UAAU,gBACJ,UAAU;MAEvE,SAAS;EAGP,OAAO,IAAI,UAAU;UAWb;UAiCN;UAQA;UAYM;EA+DR,SAAS,KAAK,UAAU;UAStB;UAMA;;cAoCG,gCAAgC;EAC3C,KAAK,kBAAkB,yBAA+B;;iBAYxC,qBAAqB;iBAoBrB,wBAAwB;UAwCvB;EACf,SAAS;EACT,YAAY;EACZ,oBAAoB;;iBAGN,eAAe,IAAI,cAAc,UAAS"}
@@ -25,15 +25,6 @@ interface VoiceFooterContributionHandle {
25
25
  update(value: VoiceFooterContributionValue | undefined): void;
26
26
  dispose(): void;
27
27
  }
28
- interface VoiceModeContributionValue {
29
- label: string;
30
- detail?: string;
31
- color?: 'accent' | 'warning' | 'mdHeading' | 'muted' | 'dim';
32
- }
33
- interface VoiceModeContributionHandle {
34
- update(value: VoiceModeContributionValue | undefined): void;
35
- dispose(): void;
36
- }
37
28
  declare const VOICE_LEADER_BINDINGS: readonly LeaderBinding[];
38
29
  interface VoiceActivityPresentation {
39
30
  statusText: string;
@@ -110,11 +101,10 @@ declare function createVoiceModule(): ContainerModule;
110
101
  declare function createVoiceContainer(): Container;
111
102
  interface VoiceExtensionOptions {
112
103
  footer?: VoiceFooterContributionHandle;
113
- mode?: VoiceModeContributionHandle;
114
104
  container?: Container;
115
105
  autoClientFactory?: VoiceWorkerSessionClientFactory;
116
106
  }
117
107
  declare function voiceExtension(pi: ExtensionAPI, options?: VoiceExtensionOptions): void;
118
108
  //#endregion
119
- export { AutoCaptureActivityPresentation, AutoCaptureDeliveryIntent, AutoCapturePiEventController, MlxWhisperAdapter, OpenAiWhisperAdapter, PiVoiceConfigService, TranscriberRegistry, VOICE_LEADER_BINDINGS, VoiceActivityPresentation, VoiceExtensionOptions, VoiceFooterContributionHandle, VoiceFooterContributionValue, VoiceModeContributionHandle, VoiceModeContributionValue, VoiceSessionController, WhisperCppAdapter, createVoiceContainer, createVoiceModule, deliverAutoCaptureInput, extractFinalizedIntentSource, extractTerminalAssistantText, formatAutoCaptureActivity, formatVoiceActivity, isAskUserBlockedPayload, isSuccessfulPlanWrite, registerAutoCapturePiEventHandlers, registerNarrationRequestHandler, resolveAutoCaptureModelContracts, voiceExtension };
109
+ export { AutoCaptureActivityPresentation, AutoCaptureDeliveryIntent, AutoCapturePiEventController, MlxWhisperAdapter, OpenAiWhisperAdapter, PiVoiceConfigService, TranscriberRegistry, VOICE_LEADER_BINDINGS, VoiceActivityPresentation, VoiceExtensionOptions, VoiceFooterContributionHandle, VoiceFooterContributionValue, VoiceSessionController, WhisperCppAdapter, createVoiceContainer, createVoiceModule, deliverAutoCaptureInput, extractFinalizedIntentSource, extractTerminalAssistantText, formatAutoCaptureActivity, formatVoiceActivity, isAskUserBlockedPayload, isSuccessfulPlanWrite, registerAutoCapturePiEventHandlers, registerNarrationRequestHandler, resolveAutoCaptureModelContracts, voiceExtension };
120
110
  //# sourceMappingURL=voice.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"voice.d.mts","names":[],"sources":["../../../src/adapters/pi/voice.ts"],"mappings":";;;;;;;;;;;UAqHiB;EACf;EACA;EACA,cAAc;IAAQ;IAAc;;EACpC,iBAAiB;IAAQ;IAAc;;;UAGxB;EACf,OAAO,OAAO;EACd;;UAGe;EACf;EACA;EACA;;UAGe;EACf,OAAO,OAAO;EACd;;cAGW,gCAAgC;UAmB5B;EACf;EACA,QAAQ;;UAGO;EACf;EACA,QAAQ;;iBAGM,oBAAoB,QAAQ,sBAAsB;iBA+BlD,0BAA0B,OAAO,4BAA4B;KAoCjE;iBAEI,wBACd,IAAI,KAAK,kCACT,SAAS,KAAK,6BACd,cACA,SAAQ;UASO;EACf,aAAa;IACX;IACA;IACA;;EAEF,iBAAiB;EACjB;EACA,yBAAyB;EACzB;EACA,eAAe;EACf,aAAa,mBAAmB,gBAAgB,mBAAmB;EACnE,gBAAgB;;UAGR;EACR;;iBAOc,wBAAwB,mBAAmB;EAAa;;iBAIxD,6BAA6B,mBAAmB;iBAWhD,6BAA6B;iBAiB7B,sBAAsB,kBAAkB,kBAAkB;iBAK1D,gCACd,QAAQ,wBACR,mBACA,YAAY,KAAK;iBAOH,mCACd,IAAI,KAAK;EAAwB,SAAS,KAAK;GAC/C,YAAY;iBAiCE,iCACd,mBACA,SAAS,mBACR;cA4CU,kCAAkC;mBAkBe;mBACT;mBACa;mBACL;mBACA;mBACM;UAtBzD;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;EAQ2C,YAAA,SAAS,oBAClB,OAAO,QACM,YAAY,qBACjB,UAAU,gBACV,UAAU,gBACJ,UAAU;MAEvE,SAAS;EAGP,OAAO,IAAI,UAAU;UAWb;UAiCN;UAQA;UAYM;EA+DR,SAAS,KAAK,UAAU;UAStB;UAMA;;cAoCG,gCAAgC;EAC3C,KAAK,kBAAkB,yBAA+B;;iBAYxC,qBAAqB;iBAoBrB,wBAAwB;UA6BvB;EACf,SAAS;EACT,OAAO;EACP,YAAY;EACZ,oBAAoB;;iBAGN,eAAe,IAAI,cAAc,UAAS"}
1
+ {"version":3,"file":"voice.d.mts","names":[],"sources":["../../../src/adapters/pi/voice.ts"],"mappings":";;;;;;;;;;;UAuKiB;EACf;EACA;EACA,cAAc;IAAQ;IAAc;;EACpC,iBAAiB;IAAQ;IAAc;;;UAGxB;EACf,OAAO,OAAO;EACd;;cAGW,gCAAgC;UAmB5B;EACf;EACA,QAAQ;;UAGO;EACf;EACA,QAAQ;;iBAGM,oBAAoB,QAAQ,sBAAsB;iBA+BlD,0BAA0B,OAAO,4BAA4B;KAoCjE;iBAEI,wBACd,IAAI,KAAK,kCACT,SAAS,KAAK,6BACd,cACA,SAAQ;UASO;EACf,aAAa;IACX;IACA;IACA;;EAEF,iBAAiB;EACjB;EACA,yBAAyB;EACzB;EACA,eAAe;EACf,aAAa,mBAAmB,gBAAgB,mBAAmB;EACnE,gBAAgB;;UAGR;EACR;;iBAOc,wBAAwB,mBAAmB;EAAa;;iBAIxD,6BAA6B,mBAAmB;iBAWhD,6BAA6B;iBAiB7B,sBAAsB,kBAAkB,kBAAkB;iBAK1D,gCACd,QAAQ,wBACR,mBACA,YAAY,KAAK;iBAOH,mCACd,IAAI,KAAK;EAAwB,SAAS,KAAK;GAC/C,YAAY;iBAiCE,iCACd,mBACA,SAAS,mBACR;cA6CU,kCAAkC;mBAkBe;mBACT;mBACa;mBACL;mBACA;mBACM;UAtBzD;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;EAQ2C,YAAA,SAAS,oBAClB,OAAO,QACM,YAAY,qBACjB,UAAU,gBACV,UAAU,gBACJ,UAAU;MAEvE,SAAS;EAGP,OAAO,IAAI,UAAU;UAWb;UAiCN;UAQA;UAYM;EA+DR,SAAS,KAAK,UAAU;UAStB;UAMA;;cAoCG,gCAAgC;EAC3C,KAAK,kBAAkB,yBAA+B;;iBAYxC,qBAAqB;iBAoBrB,wBAAwB;UAwCvB;EACf,SAAS;EACT,YAAY;EACZ,oBAAoB;;iBAGN,eAAe,IAAI,cAAc,UAAS"}
@@ -1,2 +1,2 @@
1
- import{DOOM_VOICE_TYPES as e}from"../../types/index.mjs";import t from"../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.mjs";import n from"../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateMetadata.mjs";import r from"../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateParam.mjs";import{ExecutableResolver as i,FfmpegAudioRecorder as a,FfmpegPcmAudioRecorder as o,MacOsSayTtsAdapter as s,NodeBinaryProcessSpawner as c,NodeProcessSpawner as l,PcmWavAnalyzer as u,SystemClock as d,TemporaryWorkspace as f}from"../audio/infrastructure.mjs";import{NarrationGenerator as p}from"../../services/voice/narration.mjs";import{SemanticEchoAdjudicator as m}from"../../services/voice/semanticEcho.mjs";import{VoiceAutoCaptureAdjudicator as ee}from"../../services/voice/autoCapture.mjs";import{VoiceWorkerAutoCaptureController as te}from"../process/voiceWorkerAutoCaptureController.mjs";import{VoiceWorkerSessionController as h}from"../process/voiceWorkerSessionController.mjs";import{MlxWhisperAdapter as g,OpenAiWhisperAdapter as _,TranscriberRegistry as v,WhisperCppAdapter as y}from"../transcription/whisper.mjs";import b from"node:fs";import ne from"node:os";import x from"node:path";import{Container as re,ContainerModule as ie,inject as S,injectable as C}from"inversify";import"reflect-metadata";import{globalDoomConfigPath as ae,mergeDoomConfigs as w,parseDoomConfig as oe,repositoryDoomConfigPath as se,resolveVoiceConfig as T}from"@agimon-ai/doompi-config/config";import{DOOM_CONFIG_TYPES as E}from"@agimon-ai/doompi-config/types";import{ASK_USER_BLOCKED_EVENT as ce}from"@agimon-ai/doompi-extension-contracts";import{subscribeToNarrationRequests as le}from"@agimon-ai/doompi-extension-contracts/narration";import{createDoomTelemetry as ue}from"@agimon-ai/doompi-telemetry";const D=`voice`,O=`voice-auto`,k=`doom-voice`,de=[`·`,`•`,`●`,`•`],fe=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`],A=`info`,j=`error`,M=`doom_voice.transcription_finished`,N=`idle`,P=`recording`,F=`transcribing`,pe=[{id:`voice.toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`v`,label:`toggle`,detail:`record or transcribe`}],command:{name:D}},{id:`voice.auto-toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`a`,label:`auto`,detail:`continuous autonomous conversation`}],command:{name:O}}];function I(e){let t=e.state===P?de:fe,n=t[Math.max(0,Math.floor(e.frameIndex))%t.length],r=e.state===P?`warning`:`accent`,i=Math.max(0,Math.floor(e.elapsedSeconds??0));return{statusText:e.state===P?`${n} voice: recording ${Math.floor(i/60)}:${String(i%60).padStart(2,`0`)}`:`${n} voice: transcribing`,footer:{fullText:n,compactText:n,fullSegments:[{text:n,color:r}],compactSegments:[{text:n,color:r}]}}}function L(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:(t,n)=>e.ui.setStatus(t,n),setIndicator:e=>t.update(e?I(e).footer:void 0),getEditorText:()=>e.ui.getEditorText(),setEditorText:t=>e.ui.setEditorText(t)}}function R(e){let t=e===`listening`?{frame:`A`,statusText:`voice auto: listening`,color:`accent`}:e===`speech`?{frame:`!`,statusText:`voice auto: hearing speech`,color:`warning`}:e===`processing`?{frame:`…`,statusText:`voice auto: processing while listening`,color:`accent`}:e===`narrating`?{frame:`A`,statusText:`voice auto: narrating and listening`,color:`accent`}:e===`confirming`?{frame:`?`,statusText:`voice auto: confirmation needed`,color:`warning`}:e===`waiting`?{frame:`…`,statusText:`voice auto: waiting for keyboard input`,color:`warning`}:{frame:`A`,statusText:`voice auto: draining`,color:`warning`};return{statusText:t.statusText,footer:{fullText:t.frame,compactText:t.frame,fullSegments:[{text:t.frame,color:t.color}],compactSegments:[{text:t.frame,color:t.color}]}}}function z(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:t=>e.ui.setStatus(k,t),setIndicator:e=>t.update(e?R(e).footer:void 0)}}function B(e,t,n,r=`immediate`){if(t.isIdle()){e.sendUserMessage(n);return}e.sendUserMessage(n,{deliverAs:r===`queuedFollowUp`?`followUp`:`steer`})}function V(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function H(e){return V(e)&&typeof e.active==`boolean`}function U(e){if(!V(e)||e.role!==`assistant`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(V(n)){if(n.type===`toolCall`)return{text:t.join(``).trim()};n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}}function W(e){if(!V(e)||e.role!==`assistant`||e.stopReason===`toolUse`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(V(n)){if(n.type===`toolCall`)return;n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}return t.join(``).trim()||void 0}function G(e,t,n){return e!==`write_plan`||t||!V(n)?!1:V(n.details)&&n.details.written===!0}function K(e,t,n){return le({bus:e,source:`@agimon-ai/doompi-voice`,sessionId:t},({text:e})=>n.narrate(e))}function q(e,t){e.events?.on(ce,e=>{H(e)&&t.askUserBlocked(e.active)}),e.on(`input`,e=>{t.observeInput({text:e.text,source:e.source,...e.streamingBehavior?{streamingBehavior:e.streamingBehavior}:{}})}),e.on(`before_agent_start`,e=>t.beforeAgentStart(e.prompt)),e.on(`agent_start`,()=>t.agentStarted()),e.on(`message_end`,e=>{let n=U(e.message);n&&t.finalizedAssistantIntent(n.text)}),e.on(`tool_execution_end`,e=>{G(e.toolName,e.isError,e.result)&&t.planWritten()}),e.on(`turn_end`,e=>{let n=e.message;t.turnFinished(e.turnIndex,n.role===`assistant`?n.stopReason:`unknown`,e.toolResults.length,W(n))}),e.on(`agent_settled`,async()=>t.agentSettled())}function J(e,t){let n=e.indexOf(`/`);if(n<=0||n===e.length-1)throw Error(`Autonomous voice model must use provider/model-id form`);let r=e.slice(0,n),i=e.slice(n+1),a=t.modelRegistry.find(r,i);if(!a)throw Error(`Autonomous voice model is not registered: ${e}`);if(!t.modelRegistry.hasConfiguredAuth(a))throw Error(`Autonomous voice model has no configured authentication: ${e}`);let o={complete:async e=>{let n=await t.modelRegistry.complete(a,{systemPrompt:e.systemPrompt,messages:[{role:`user`,content:e.input,timestamp:Date.now()}]},{signal:e.signal,...e.maxTokens===void 0?{}:{maxTokens:e.maxTokens},cacheRetention:e.cacheRetention,reasoningEffort:`none`,maxRetries:0});if(n.stopReason===`error`||n.stopReason===`aborted`)throw Error(n.errorMessage??`Autonomous voice model stopped with ${n.stopReason}`);return n.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}};return{adjudicator:new ee(o),echo:new m,narrator:new p(o)}}let Y=class{configs;clock;workspaces;recorder;analyzer;registry;currentState=N;recording;workspace;config;selected;startedAt=0;activityFrame=0;activityTimer;limitTimer;telemetry=ue({serviceName:`doom-voice`,packageName:`@agimon-ai/doompi-voice`,env:process.env,enableLogs:!0,enableTraces:!0});constructor(e,t,n,r,i,a){this.configs=e,this.clock=t,this.workspaces=n,this.recorder=r,this.analyzer=i,this.registry=a}get state(){return this.currentState}async toggle(e){if(this.currentState===F){e.notify(`Voice transcription is already running`,A);return}if(this.currentState===P){await this.stopAndTranscribe(e);return}await this.startRecording(e)}async startRecording(e){try{let t=process.env.PI_PROJECT_ROOT??process.cwd(),n=this.configs.load(t).voice;if(!n)throw Error(`Voice is not configured in the Pi agent configuration.`);let r=T(n);this.recorder.preflight(r);let i=this.registry.select(r);this.telemetry.recordEvent(`doom_voice.recording_requested`,{engine:i.adapter.engine,mode:r.language});let a=this.workspaces.create();this.recording=this.recorder.start(r,a),this.workspace=a,this.config=r,this.selected=i,this.currentState=P,this.startedAt=this.clock.now(),this.startActivity(e),this.limitTimer=this.clock.setTimeout(()=>{this.stopAndTranscribe(e)},3e5),this.telemetry.recordEvent(`doom_voice.recording_started`,{engine:i.adapter.engine,outcome:`started`})}catch(t){await this.telemetry.recordError(`doom_voice.recording_failed`,t,{outcome:`failed`}),this.reset(e),e.notify(t instanceof Error?t.message:String(t),j)}}startActivity(e){this.activityFrame=0,this.publishActivity(e),this.activityTimer=this.clock.setInterval(()=>{this.activityFrame+=1,this.publishActivity(e)},120)}publishActivity(e){if(this.currentState===N)return;let t={state:this.currentState,frameIndex:this.activityFrame,...this.currentState===P?{elapsedSeconds:Math.max(0,Math.floor((this.clock.now()-this.startedAt)/1e3))}:{}};e.setIndicator(t),e.setStatus(k,I(t).statusText)}async stopAndTranscribe(e){let t=this.recording,n=this.workspace,r=this.config,i=this.selected;if(!t||!n||!r||!i||this.currentState!==P)return;this.clearTimers();let a=this.startedAt;this.currentState=F,this.startActivity(e),this.telemetry.recordEvent(`doom_voice.transcription_started`,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)});try{await t.stop();let o=Math.max(0,this.clock.now()-a);if(this.analyzer.analyze(t.filePath).silent){await this.telemetry.recordEvent(M,{engine:i.adapter.engine,duration_ms:o,silence:!0,outcome:`empty`}),e.notify(`No speech detected`,A);return}let s=(await i.adapter.transcribe({audioPath:t.filePath,workspace:n,config:i.config,language:r.language})).trim();if(!s){await this.telemetry.recordEvent(M,{engine:i.adapter.engine,duration_ms:o,empty:!0,outcome:`empty`}),e.notify(`Voice transcription was empty`,A);return}let c=e.getEditorText();e.setEditorText(`${c}${c&&!/\s$/.test(c)?` `:``}${s}`),await this.telemetry.recordEvent(M,{engine:i.adapter.engine,duration_ms:o,empty:!1,outcome:`completed`})}catch(t){await this.telemetry.recordError(`doom_voice.transcription_failed`,t,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)}),e.notify(t instanceof Error?t.message:String(t),j)}finally{this.reset(e)}}async shutdown(e){this.clearTimers(),this.recording&&this.currentState===P&&(await this.recording.abort(),this.telemetry.recordEvent(`doom_voice.recording_finished`,{outcome:`aborted`})),this.reset(e),this.telemetry.shutdown()}clearTimers(){this.activityTimer&&this.clock.clear(this.activityTimer),this.limitTimer&&this.clock.clear(this.limitTimer),this.activityTimer=void 0,this.limitTimer=void 0}reset(e){this.clearTimers(),this.workspace&&this.workspaces.remove(this.workspace),this.recording=void 0,this.workspace=void 0,this.config=void 0,this.selected=void 0,this.currentState=N,this.activityFrame=0,e?.setIndicator(void 0),e?.setStatus(k,void 0)}};Y=t([C(),r(0,S(E.ConfigService)),r(1,S(e.Clock)),r(2,S(e.TemporaryWorkspace)),r(3,S(e.AudioRecorder)),r(4,S(e.AudioAnalyzer)),r(5,S(e.TranscriberRegistry)),n(`design:paramtypes`,[Object,Object,Object,Object,Object,Object])],Y);function X(e){return b.existsSync(e)?oe(b.readFileSync(e,`utf8`),e):{projectTrust:`ask`}}function me(e){let t=process.env.PI_CODING_AGENT_DIR||x.join(e,`.pi`,`agent`);return x.join(t,`doom-voice`,`config.yaml`)}function Z(e){let t=X(ae(e));if(t.voice)return t;let n=X(me(e));return n.voice?w(t,n):t}let Q=class{load(e,t=ne.homedir()){let n=Z(t);if(process.env.PI_PROJECT_TRUST!==`trusted`)return n;let r=X(se(e));return r.projectTrust===`never`?n:w(n,r)}};Q=t([C()],Q);function he(){return new ie(({bind:t})=>{t(e.Clock).to(d).inSingletonScope(),t(e.ExecutableResolver).to(i).inSingletonScope(),t(e.ProcessSpawner).to(l).inSingletonScope(),t(e.BinaryProcessSpawner).to(c).inSingletonScope(),t(e.TemporaryWorkspace).to(f).inSingletonScope(),t(e.AudioRecorder).to(a).inSingletonScope(),t(e.PcmAudioRecorder).to(o).inSingletonScope(),t(e.TtsAdapter).to(s).inSingletonScope(),t(e.AudioAnalyzer).to(u).inSingletonScope(),t(e.WhisperCppAdapter).to(y).inSingletonScope(),t(e.OpenAiWhisperAdapter).to(_).inSingletonScope(),t(e.MlxWhisperAdapter).to(g).inSingletonScope(),t(e.TranscriberRegistry).to(v).inSingletonScope(),t(e.SessionController).to(h).inSingletonScope()})}function $(){let t=new re;return t.bind(E.ConfigService).to(Q).inSingletonScope(),t.bind(e.Clock).to(d).inSingletonScope(),t.bind(e.ExecutableResolver).to(i).inSingletonScope(),t.bind(e.ProcessSpawner).to(l).inSingletonScope(),t.bind(e.BinaryProcessSpawner).to(c).inSingletonScope(),t.bind(e.TemporaryWorkspace).to(f).inSingletonScope(),t.bind(e.AudioRecorder).to(a).inSingletonScope(),t.bind(e.PcmAudioRecorder).to(o).inSingletonScope(),t.bind(e.TtsAdapter).to(s).inSingletonScope(),t.bind(e.AudioAnalyzer).to(u).inSingletonScope(),t.bind(e.WhisperCppAdapter).to(y).inSingletonScope(),t.bind(e.OpenAiWhisperAdapter).to(_).inSingletonScope(),t.bind(e.MlxWhisperAdapter).to(g).inSingletonScope(),t.bind(e.TranscriberRegistry).to(v).inSingletonScope(),t.bind(e.SessionController).to(h).inSingletonScope(),t}function ge(t,n={}){let r=n.container??$(),i=r.get(e.SessionController),a=r.get(E.ConfigService),o=n.footer??{update:()=>void 0,dispose:()=>void 0},s=n.mode??{update:()=>void 0,dispose:()=>void 0},c,l,u,d,f=!1,p=e=>{e!==f&&(f=e,s.update(e?{label:`VOICE`,color:`accent`}:void 0))},m=new te({loadConfig:()=>{let e=process.env.PI_PROJECT_ROOT??process.cwd(),t=a.load(e).voice;if(!t)throw Error(`Voice is not configured in the Pi agent configuration.`);return T(t)},resolveModel:async e=>{if(!u)throw Error(`No autonomous voice session is active`);return J(e,u)},tts:r.get(e.TtsAdapter),clock:r.get(e.Clock),deliver:e=>{if(!u)throw Error(`No autonomous voice session is active`);B(t,u,e)},manualState:()=>i.state,onActivationStateChange:e=>p(e===`active`),...n.autoClientFactory?{clientFactory:n.autoClientFactory}:{}});t.registerCommand(D,{description:`Toggle local voice recording and transcription`,handler:async(e,t)=>{if(t.hasUI){if(c=L(t,o),m.state!==`disabled`){c.notify(`Disable autonomous voice before using manual voice`,A);return}await i.toggle(c)}}}),t.registerCommand(O,{description:`Toggle continuous autonomous voice conversation`,handler:async(e,t)=>{t.hasUI&&(u=t,l=z(t,o),await m.toggle(l))}}),t.on(`session_start`,async(e,n)=>{u=n,d?.();let r=n.sessionManager?.getSessionId();d=r?K(t.events,r,m):void 0,n.hasUI&&(c=L(n,o),l=z(n,o),c.setIndicator(void 0),c.setStatus(k,void 0),f=!1,s.update(void 0))}),q(t,m),t.on(`session_shutdown`,async()=>{let e=c,t=l;c=void 0,l=void 0,u=void 0,d?.(),d=void 0,await m.shutdown(t),await i.shutdown(e),o.dispose(),s.dispose()})}export{g as MlxWhisperAdapter,_ as OpenAiWhisperAdapter,Q as PiVoiceConfigService,v as TranscriberRegistry,pe as VOICE_LEADER_BINDINGS,Y as VoiceSessionController,y as WhisperCppAdapter,$ as createVoiceContainer,he as createVoiceModule,B as deliverAutoCaptureInput,U as extractFinalizedIntentSource,W as extractTerminalAssistantText,R as formatAutoCaptureActivity,I as formatVoiceActivity,H as isAskUserBlockedPayload,G as isSuccessfulPlanWrite,q as registerAutoCapturePiEventHandlers,K as registerNarrationRequestHandler,J as resolveAutoCaptureModelContracts,ge as voiceExtension};
1
+ import{DOOM_VOICE_TYPES as e}from"../../types/index.mjs";import t from"../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorate.mjs";import n from"../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateMetadata.mjs";import r from"../../_virtual/_@oxc-project_runtime@0.143.0/helpers/esm/decorateParam.mjs";import{ExecutableResolver as i,FfmpegAudioRecorder as a,FfmpegPcmAudioRecorder as o,MacOsSayTtsAdapter as s,NodeBinaryProcessSpawner as c,NodeProcessSpawner as l,PcmWavAnalyzer as u,SystemClock as d,TemporaryWorkspace as f}from"../audio/infrastructure.mjs";import{NarrationGenerator as p}from"../../services/voice/narration.mjs";import{SemanticEchoAdjudicator as ee}from"../../services/voice/semanticEcho.mjs";import{VoiceAutoCaptureAdjudicator as te}from"../../services/voice/autoCapture.mjs";import{VoiceCommandCorrector as ne}from"../../services/voice/commandCorrection.mjs";import{VoiceWorkerAutoCaptureController as re}from"../process/voiceWorkerAutoCaptureController.mjs";import{VoiceWorkerSessionController as m}from"../process/voiceWorkerSessionController.mjs";import{MlxWhisperAdapter as h,OpenAiWhisperAdapter as g,TranscriberRegistry as _,WhisperCppAdapter as v}from"../transcription/whisper.mjs";import{createVoiceMinorModeCatalog as ie}from"./minorModeCatalog.mjs";import{collectVoiceCommandContext as ae}from"./voiceCommandContext.mjs";import y from"node:fs";import oe from"node:os";import b from"node:path";import{Container as se,ContainerModule as ce,inject as x,injectable as S}from"inversify";import"reflect-metadata";import{globalDoomConfigPath as le,mergeDoomConfigs as C,parseDoomConfig as ue,repositoryDoomConfigPath as de,resolveVoiceConfig as w}from"@agimon-ai/doompi-config/config";import{DOOM_CONFIG_TYPES as T}from"@agimon-ai/doompi-config/types";import{ASK_USER_BLOCKED_EVENT as fe}from"@agimon-ai/doompi-extension-contracts";import{MINOR_MODE_TOOL_NAME as E,registerMinorModeOwner as pe}from"@agimon-ai/doompi-extension-contracts/mode";import{subscribeToNarrationRequests as me}from"@agimon-ai/doompi-extension-contracts/narration";import{createDoomTelemetry as he}from"@agimon-ai/doompi-telemetry";const D=`voice`,O=`voice-auto`,k=`doom-voice`;function A(e,t=!1){let n=e!==`disabled`,r=e===`starting`||e===`draining`||e===`shuttingDown`;return{activation:e===`starting`?`activating`:e===`draining`||e===`shuttingDown`?`deactivating`:n?`active`:`inactive`,condition:r?`queued`:`ready`,...n?{detail:e,color:`accent`}:{},actions:t?r?[{id:`activate`,enabled:!1,disabledReason:`Autonomous voice is transitioning.`},{id:`deactivate`,enabled:!1,disabledReason:`Autonomous voice is transitioning.`}]:[...n?[{id:`activate`,enabled:!1,disabledReason:`Autonomous voice is already enabled.`}]:[{id:`activate`,enabled:!0}],...n?[{id:`deactivate`,enabled:!0}]:[{id:`deactivate`,enabled:!1,disabledReason:`Autonomous voice is disabled.`}]]:[{id:`activate`,enabled:!1,disabledReason:`Autonomous voice requires a TUI session.`},{id:`deactivate`,enabled:!1,disabledReason:`Autonomous voice requires a TUI session.`}]}}const ge=[`·`,`•`,`●`,`•`],_e=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`],j=`info`,M=`error`,N=`doom_voice.transcription_finished`,P=`idle`,F=`recording`,I=`transcribing`,ve=[{id:`voice.toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`v`,label:`toggle`,detail:`record or transcribe`}],command:{name:D}},{id:`voice.auto-toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`a`,label:`auto`,detail:`continuous autonomous conversation`}],command:{name:O}}];function L(e){let t=e.state===F?ge:_e,n=t[Math.max(0,Math.floor(e.frameIndex))%t.length],r=e.state===F?`warning`:`accent`,i=Math.max(0,Math.floor(e.elapsedSeconds??0));return{statusText:e.state===F?`${n} voice: recording ${Math.floor(i/60)}:${String(i%60).padStart(2,`0`)}`:`${n} voice: transcribing`,footer:{fullText:n,compactText:n,fullSegments:[{text:n,color:r}],compactSegments:[{text:n,color:r}]}}}function R(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:(t,n)=>e.ui.setStatus(t,n),setIndicator:e=>t.update(e?L(e).footer:void 0),getEditorText:()=>e.ui.getEditorText(),setEditorText:t=>e.ui.setEditorText(t)}}function z(e){let t=e===`listening`?{frame:`A`,statusText:`voice auto: listening`,color:`accent`}:e===`speech`?{frame:`!`,statusText:`voice auto: hearing speech`,color:`warning`}:e===`processing`?{frame:`…`,statusText:`voice auto: processing while listening`,color:`accent`}:e===`narrating`?{frame:`A`,statusText:`voice auto: narrating and listening`,color:`accent`}:e===`confirming`?{frame:`?`,statusText:`voice auto: confirmation needed`,color:`warning`}:e===`waiting`?{frame:`…`,statusText:`voice auto: waiting for keyboard input`,color:`warning`}:{frame:`A`,statusText:`voice auto: draining`,color:`warning`};return{statusText:t.statusText,footer:{fullText:t.frame,compactText:t.frame,fullSegments:[{text:t.frame,color:t.color}],compactSegments:[{text:t.frame,color:t.color}]}}}function B(e,t){return{notify:(t,n)=>e.ui.notify(t,n),setStatus:t=>e.ui.setStatus(k,t),setIndicator:e=>t.update(e?z(e).footer:void 0)}}function V(e,t,n,r=`immediate`){if(t.isIdle()){e.sendUserMessage(n);return}e.sendUserMessage(n,{deliverAs:r===`queuedFollowUp`?`followUp`:`steer`})}function H(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function U(e){return H(e)&&typeof e.active==`boolean`}function W(e){if(!H(e)||e.role!==`assistant`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(H(n)){if(n.type===`toolCall`)return{text:t.join(``).trim()};n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}}function G(e){if(!H(e)||e.role!==`assistant`||e.stopReason===`toolUse`||!Array.isArray(e.content))return;let t=[];for(let n of e.content)if(H(n)){if(n.type===`toolCall`)return;n.type===`text`&&typeof n.text==`string`&&t.push(n.text)}return t.join(``).trim()||void 0}function K(e,t,n){return e!==`write_plan`||t||!H(n)?!1:H(n.details)&&n.details.written===!0}function q(e,t,n){return me({bus:e,source:`@agimon-ai/doompi-voice`,sessionId:t},({text:e})=>n.narrate(e))}function J(e,t){e.events?.on(fe,e=>{U(e)&&t.askUserBlocked(e.active)}),e.on(`input`,e=>{t.observeInput({text:e.text,source:e.source,...e.streamingBehavior?{streamingBehavior:e.streamingBehavior}:{}})}),e.on(`before_agent_start`,e=>t.beforeAgentStart(e.prompt)),e.on(`agent_start`,()=>t.agentStarted()),e.on(`message_end`,e=>{let n=W(e.message);n&&t.finalizedAssistantIntent(n.text)}),e.on(`tool_execution_end`,e=>{K(e.toolName,e.isError,e.result)&&t.planWritten()}),e.on(`turn_end`,e=>{let n=e.message;t.turnFinished(e.turnIndex,n.role===`assistant`?n.stopReason:`unknown`,e.toolResults.length,G(n))}),e.on(`agent_settled`,async()=>t.agentSettled())}function Y(e,t){let n=e.indexOf(`/`);if(n<=0||n===e.length-1)throw Error(`Autonomous voice model must use provider/model-id form`);let r=e.slice(0,n),i=e.slice(n+1),a=t.modelRegistry.find(r,i);if(!a)throw Error(`Autonomous voice model is not registered: ${e}`);if(!t.modelRegistry.hasConfiguredAuth(a))throw Error(`Autonomous voice model has no configured authentication: ${e}`);let o={complete:async e=>{let n=await t.modelRegistry.complete(a,{systemPrompt:e.systemPrompt,messages:[{role:`user`,content:e.input,timestamp:Date.now()}]},{signal:e.signal,...e.maxTokens===void 0?{}:{maxTokens:e.maxTokens},cacheRetention:e.cacheRetention,reasoningEffort:`none`,maxRetries:0});if(n.stopReason===`error`||n.stopReason===`aborted`)throw Error(n.errorMessage??`Autonomous voice model stopped with ${n.stopReason}`);return n.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}};return{adjudicator:new te(o),echo:new ee,narrator:new p(o),corrector:new ne(o)}}let X=class{configs;clock;workspaces;recorder;analyzer;registry;currentState=P;recording;workspace;config;selected;startedAt=0;activityFrame=0;activityTimer;limitTimer;telemetry=he({serviceName:`doom-voice`,packageName:`@agimon-ai/doompi-voice`,env:process.env,enableLogs:!0,enableTraces:!0});constructor(e,t,n,r,i,a){this.configs=e,this.clock=t,this.workspaces=n,this.recorder=r,this.analyzer=i,this.registry=a}get state(){return this.currentState}async toggle(e){if(this.currentState===I){e.notify(`Voice transcription is already running`,j);return}if(this.currentState===F){await this.stopAndTranscribe(e);return}await this.startRecording(e)}async startRecording(e){try{let t=process.env.PI_PROJECT_ROOT??process.cwd(),n=this.configs.load(t).voice;if(!n)throw Error(`Voice is not configured in the Pi agent configuration.`);let r=w(n);this.recorder.preflight(r);let i=this.registry.select(r);this.telemetry.recordEvent(`doom_voice.recording_requested`,{engine:i.adapter.engine,mode:r.language});let a=this.workspaces.create();this.recording=this.recorder.start(r,a),this.workspace=a,this.config=r,this.selected=i,this.currentState=F,this.startedAt=this.clock.now(),this.startActivity(e),this.limitTimer=this.clock.setTimeout(()=>{this.stopAndTranscribe(e)},3e5),this.telemetry.recordEvent(`doom_voice.recording_started`,{engine:i.adapter.engine,outcome:`started`})}catch(t){await this.telemetry.recordError(`doom_voice.recording_failed`,t,{outcome:`failed`}),this.reset(e),e.notify(t instanceof Error?t.message:String(t),M)}}startActivity(e){this.activityFrame=0,this.publishActivity(e),this.activityTimer=this.clock.setInterval(()=>{this.activityFrame+=1,this.publishActivity(e)},120)}publishActivity(e){if(this.currentState===P)return;let t={state:this.currentState,frameIndex:this.activityFrame,...this.currentState===F?{elapsedSeconds:Math.max(0,Math.floor((this.clock.now()-this.startedAt)/1e3))}:{}};e.setIndicator(t),e.setStatus(k,L(t).statusText)}async stopAndTranscribe(e){let t=this.recording,n=this.workspace,r=this.config,i=this.selected;if(!t||!n||!r||!i||this.currentState!==F)return;this.clearTimers();let a=this.startedAt;this.currentState=I,this.startActivity(e),this.telemetry.recordEvent(`doom_voice.transcription_started`,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)});try{await t.stop();let o=Math.max(0,this.clock.now()-a);if(this.analyzer.analyze(t.filePath).silent){await this.telemetry.recordEvent(N,{engine:i.adapter.engine,duration_ms:o,silence:!0,outcome:`empty`}),e.notify(`No speech detected`,j);return}let s=(await i.adapter.transcribe({audioPath:t.filePath,workspace:n,config:i.config,language:r.language})).trim();if(!s){await this.telemetry.recordEvent(N,{engine:i.adapter.engine,duration_ms:o,empty:!0,outcome:`empty`}),e.notify(`Voice transcription was empty`,j);return}let c=e.getEditorText();e.setEditorText(`${c}${c&&!/\s$/.test(c)?` `:``}${s}`),await this.telemetry.recordEvent(N,{engine:i.adapter.engine,duration_ms:o,empty:!1,outcome:`completed`})}catch(t){await this.telemetry.recordError(`doom_voice.transcription_failed`,t,{engine:i.adapter.engine,duration_ms:Math.max(0,this.clock.now()-a)}),e.notify(t instanceof Error?t.message:String(t),M)}finally{this.reset(e)}}async shutdown(e){this.clearTimers(),this.recording&&this.currentState===F&&(await this.recording.abort(),this.telemetry.recordEvent(`doom_voice.recording_finished`,{outcome:`aborted`})),this.reset(e),this.telemetry.shutdown()}clearTimers(){this.activityTimer&&this.clock.clear(this.activityTimer),this.limitTimer&&this.clock.clear(this.limitTimer),this.activityTimer=void 0,this.limitTimer=void 0}reset(e){this.clearTimers(),this.workspace&&this.workspaces.remove(this.workspace),this.recording=void 0,this.workspace=void 0,this.config=void 0,this.selected=void 0,this.currentState=P,this.activityFrame=0,e?.setIndicator(void 0),e?.setStatus(k,void 0)}};X=t([S(),r(0,x(T.ConfigService)),r(1,x(e.Clock)),r(2,x(e.TemporaryWorkspace)),r(3,x(e.AudioRecorder)),r(4,x(e.AudioAnalyzer)),r(5,x(e.TranscriberRegistry)),n(`design:paramtypes`,[Object,Object,Object,Object,Object,Object])],X);function Z(e){return y.existsSync(e)?ue(y.readFileSync(e,`utf8`),e):{projectTrust:`ask`}}function ye(e){let t=process.env.PI_CODING_AGENT_DIR||b.join(e,`.pi`,`agent`);return b.join(t,`doom-voice`,`config.yaml`)}function be(e){let t=Z(le(e));if(t.voice)return t;let n=Z(ye(e));return n.voice?C(t,n):t}let Q=class{load(e,t=oe.homedir()){let n=be(t);if(process.env.PI_PROJECT_TRUST!==`trusted`)return n;let r=Z(de(e));return r.projectTrust===`never`?n:C(n,r)}};Q=t([S()],Q);function xe(){return new ce(({bind:t})=>{t(e.Clock).to(d).inSingletonScope(),t(e.ExecutableResolver).to(i).inSingletonScope(),t(e.ProcessSpawner).to(l).inSingletonScope(),t(e.BinaryProcessSpawner).to(c).inSingletonScope(),t(e.TemporaryWorkspace).to(f).inSingletonScope(),t(e.AudioRecorder).to(a).inSingletonScope(),t(e.PcmAudioRecorder).to(o).inSingletonScope(),t(e.TtsAdapter).to(s).inSingletonScope(),t(e.AudioAnalyzer).to(u).inSingletonScope(),t(e.WhisperCppAdapter).to(v).inSingletonScope(),t(e.OpenAiWhisperAdapter).to(g).inSingletonScope(),t(e.MlxWhisperAdapter).to(h).inSingletonScope(),t(e.TranscriberRegistry).to(_).inSingletonScope(),t(e.SessionController).to(m).inSingletonScope()})}function Se(){let t=new se;return t.bind(T.ConfigService).to(Q).inSingletonScope(),t.bind(e.Clock).to(d).inSingletonScope(),t.bind(e.ExecutableResolver).to(i).inSingletonScope(),t.bind(e.ProcessSpawner).to(l).inSingletonScope(),t.bind(e.BinaryProcessSpawner).to(c).inSingletonScope(),t.bind(e.TemporaryWorkspace).to(f).inSingletonScope(),t.bind(e.AudioRecorder).to(a).inSingletonScope(),t.bind(e.PcmAudioRecorder).to(o).inSingletonScope(),t.bind(e.TtsAdapter).to(s).inSingletonScope(),t.bind(e.AudioAnalyzer).to(u).inSingletonScope(),t.bind(e.WhisperCppAdapter).to(v).inSingletonScope(),t.bind(e.OpenAiWhisperAdapter).to(g).inSingletonScope(),t.bind(e.MlxWhisperAdapter).to(h).inSingletonScope(),t.bind(e.TranscriberRegistry).to(_).inSingletonScope(),t.bind(e.SessionController).to(m).inSingletonScope(),t}function $(e,t){let n=e.getActiveTools(),r=n.includes(E);if(!t&&r){e.setActiveTools(n.filter(e=>e!==E));return}let i=e.getAllTools().some(e=>e.name===E);t&&i&&!r&&e.setActiveTools([...n,E])}function Ce(t,n={}){let r=n.container??Se(),i=r.get(e.SessionController),a=r.get(T.ConfigService),o=n.footer??{update:()=>void 0,dispose:()=>void 0},s,c,l,u,d=ie(t),f,p=new re({loadConfig:()=>{let e=process.env.PI_PROJECT_ROOT??process.cwd(),t=a.load(e).voice;if(!t)throw Error(`Voice is not configured in the Pi agent configuration.`);return w(t)},resolveModel:async e=>{if(!l)throw Error(`No autonomous voice session is active`);return Y(e,l)},tts:r.get(e.TtsAdapter),clock:r.get(e.Clock),deliver:e=>{if(!l)throw Error(`No autonomous voice session is active`);V(t,l,e)},manualState:()=>i.state,commandContext:()=>l?ae(l.sessionManager.getBranch(),d.records()):void 0,onActivationStateChange:e=>{$(t,e===`active`),f?.publish(A(e,l?.hasUI===!0))},...n.autoClientFactory?{clientFactory:n.autoClientFactory}:{}});f=pe(t,{descriptor:{source:`@agimon-ai/doompi-voice`,id:`voice-auto`,label:`VOICE`,description:`Continuous autonomous voice capture, correction, and narration.`,order:30,actions:[{id:`activate`,label:`Activate`,description:`Start autonomous voice capture.`,contexts:[`tui`],parameters:[]},{id:`deactivate`,label:`Deactivate`,description:`Stop autonomous voice capture.`,contexts:[`tui`],parameters:[]}]},initialState:A(`disabled`),async handleAction(e,t,n){l=n.context;let r=B(n.context,o);if(c=r,e===`activate`)return await p.activate(r),{message:`Autonomous voice activation requested.`};if(e===`deactivate`)return await p.deactivate(r),{message:`Autonomous voice deactivation requested.`};throw Error(`Unknown autonomous voice action: ${e}`)}}),t.registerCommand(D,{description:`Toggle local voice recording and transcription`,handler:async(e,t)=>{if(t.hasUI){if(s=R(t,o),p.state!==`disabled`){s.notify(`Disable autonomous voice before using manual voice`,j);return}await i.toggle(s)}}}),t.registerCommand(O,{description:`Toggle continuous autonomous voice conversation`,handler:async(e,t)=>{t.hasUI&&(l=t,c=B(t,o),p.state===`disabled`?await p.activate(c):await p.deactivate(c))}}),t.on(`session_start`,async(e,n)=>{$(t,!1),l=n,u?.();let r=n.sessionManager?.getSessionId();r&&d.bind(r),u=r?q(t.events,r,p):void 0,n.hasUI&&(s=R(n,o),c=B(n,o),s.setIndicator(void 0),s.setStatus(k,void 0),f?.publish(A(`disabled`,n.hasUI)))}),t.on(`before_agent_start`,()=>{$(t,p.state===`active`)}),J(t,p),t.on(`session_shutdown`,async()=>{let e=s,n=c;s=void 0,c=void 0,l=void 0,$(t,!1),u?.(),u=void 0,d.dispose(),await p.shutdown(n),await i.shutdown(e),o.dispose(),f?.dispose()})}export{h as MlxWhisperAdapter,g as OpenAiWhisperAdapter,Q as PiVoiceConfigService,_ as TranscriberRegistry,ve as VOICE_LEADER_BINDINGS,X as VoiceSessionController,v as WhisperCppAdapter,Se as createVoiceContainer,xe as createVoiceModule,V as deliverAutoCaptureInput,W as extractFinalizedIntentSource,G as extractTerminalAssistantText,z as formatAutoCaptureActivity,L as formatVoiceActivity,U as isAskUserBlockedPayload,K as isSuccessfulPlanWrite,J as registerAutoCapturePiEventHandlers,q as registerNarrationRequestHandler,Y as resolveAutoCaptureModelContracts,Ce as voiceExtension};
2
2
  //# sourceMappingURL=voice.mjs.map