@agimon-ai/doompi-voice 0.0.1-alpha.13 → 0.0.1-alpha.15
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.
- package/README.md +53 -36
- package/dist/adapters/pi/minorModeCatalog.cjs +2 -0
- package/dist/adapters/pi/minorModeCatalog.cjs.map +1 -0
- package/dist/adapters/pi/minorModeCatalog.mjs +2 -0
- package/dist/adapters/pi/minorModeCatalog.mjs.map +1 -0
- package/dist/adapters/pi/voice.cjs +1 -1
- package/dist/adapters/pi/voice.cjs.map +1 -1
- package/dist/adapters/pi/voice.d.cts +3 -11
- package/dist/adapters/pi/voice.d.cts.map +1 -1
- package/dist/adapters/pi/voice.d.mts +3 -11
- package/dist/adapters/pi/voice.d.mts.map +1 -1
- package/dist/adapters/pi/voice.mjs +1 -1
- package/dist/adapters/pi/voice.mjs.map +1 -1
- package/dist/adapters/pi/voiceCommandContext.cjs +2 -0
- package/dist/adapters/pi/voiceCommandContext.cjs.map +1 -0
- package/dist/adapters/pi/voiceCommandContext.mjs +2 -0
- package/dist/adapters/pi/voiceCommandContext.mjs.map +1 -0
- package/dist/adapters/pi/voiceToolRender.cjs +2 -0
- package/dist/adapters/pi/voiceToolRender.cjs.map +1 -0
- package/dist/adapters/pi/voiceToolRender.mjs +2 -0
- package/dist/adapters/pi/voiceToolRender.mjs.map +1 -0
- package/dist/adapters/pi/voiceTools.cjs +2 -0
- package/dist/adapters/pi/voiceTools.cjs.map +1 -0
- package/dist/adapters/pi/voiceTools.mjs +2 -0
- package/dist/adapters/pi/voiceTools.mjs.map +1 -0
- package/dist/adapters/process/turnSpool.cjs +1 -1
- package/dist/adapters/process/turnSpool.cjs.map +1 -1
- package/dist/adapters/process/turnSpool.mjs +1 -1
- package/dist/adapters/process/turnSpool.mjs.map +1 -1
- package/dist/adapters/process/voiceWorkerAutoCaptureController.cjs +1 -1
- package/dist/adapters/process/voiceWorkerAutoCaptureController.cjs.map +1 -1
- package/dist/adapters/process/voiceWorkerAutoCaptureController.d.cts +6 -0
- package/dist/adapters/process/voiceWorkerAutoCaptureController.d.cts.map +1 -1
- package/dist/adapters/process/voiceWorkerAutoCaptureController.d.mts +6 -0
- package/dist/adapters/process/voiceWorkerAutoCaptureController.d.mts.map +1 -1
- package/dist/adapters/process/voiceWorkerAutoCaptureController.mjs +1 -1
- package/dist/adapters/process/voiceWorkerAutoCaptureController.mjs.map +1 -1
- package/dist/adapters/process/voiceWorkerPipeline.cjs +1 -1
- package/dist/adapters/process/voiceWorkerPipeline.cjs.map +1 -1
- package/dist/adapters/process/voiceWorkerPipeline.mjs +1 -1
- package/dist/adapters/process/voiceWorkerPipeline.mjs.map +1 -1
- package/dist/extensions/doom.cjs +1 -1
- package/dist/extensions/doom.cjs.map +1 -1
- package/dist/extensions/doom.d.cts.map +1 -1
- package/dist/extensions/doom.d.mts.map +1 -1
- package/dist/extensions/doom.mjs +1 -1
- package/dist/extensions/doom.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +1 -1
- package/dist/services/voice/autoCapture.cjs +1 -0
- package/dist/services/voice/autoCapture.cjs.map +1 -1
- package/dist/services/voice/autoCapture.d.cts +2 -0
- package/dist/services/voice/autoCapture.d.cts.map +1 -1
- package/dist/services/voice/autoCapture.d.mts +2 -0
- package/dist/services/voice/autoCapture.d.mts.map +1 -1
- package/dist/services/voice/autoCapture.mjs +1 -0
- package/dist/services/voice/autoCapture.mjs.map +1 -1
- package/dist/services/voice/autonomousNarration.cjs +1 -1
- package/dist/services/voice/autonomousNarration.cjs.map +1 -1
- package/dist/services/voice/autonomousNarration.mjs +1 -1
- package/dist/services/voice/autonomousNarration.mjs.map +1 -1
- package/dist/services/voice/autonomousTurn.cjs +1 -1
- package/dist/services/voice/autonomousTurn.cjs.map +1 -1
- package/dist/services/voice/autonomousTurn.d.cts +7 -0
- package/dist/services/voice/autonomousTurn.d.cts.map +1 -0
- package/dist/services/voice/autonomousTurn.d.mts +7 -0
- package/dist/services/voice/autonomousTurn.d.mts.map +1 -0
- package/dist/services/voice/autonomousTurn.mjs +1 -1
- package/dist/services/voice/autonomousTurn.mjs.map +1 -1
- package/dist/services/voice/autonomousVoiceSession.cjs +1 -1
- package/dist/services/voice/autonomousVoiceSession.cjs.map +1 -1
- package/dist/services/voice/autonomousVoiceSession.mjs +1 -1
- package/dist/services/voice/autonomousVoiceSession.mjs.map +1 -1
- package/dist/services/voice/commandCorrection.cjs +7 -0
- package/dist/services/voice/commandCorrection.cjs.map +1 -0
- package/dist/services/voice/commandCorrection.d.cts +34 -0
- package/dist/services/voice/commandCorrection.d.cts.map +1 -0
- package/dist/services/voice/commandCorrection.d.mts +34 -0
- package/dist/services/voice/commandCorrection.d.mts.map +1 -0
- package/dist/services/voice/commandCorrection.mjs +7 -0
- package/dist/services/voice/commandCorrection.mjs.map +1 -0
- package/dist/services/voice/voice.d.cts +2 -2
- package/dist/services/voice/voice.d.mts +2 -2
- package/dist/voiceTools.cjs +1 -0
- package/dist/voiceTools.d.cts +1 -0
- package/dist/voiceTools.d.mts +1 -0
- package/dist/voiceTools.mjs +1 -0
- package/package.json +12 -7
package/README.md
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
# @agimon-ai/doompi-voice
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Speech in. Audio stays home.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This package adds local speech-to-text to Pi. Use it for one recording or leave autonomous
|
|
6
|
+
capture on and keep talking to the same session. Audio stays on the machine; only bounded
|
|
7
|
+
state metadata and transcript candidates return from the private worker.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
Voice is a minor mode. Autonomous capture reports itself beside `INSERT`, microphone
|
|
10
|
+
activity appears briefly in the Doom modeline, and other extensions can contribute spoken
|
|
11
|
+
actions without registering more direct tools with the model.
|
|
12
|
+
|
|
13
|
+
This is part of [Doompi](https://www.npmjs.com/package/@agimon-ai/doompi). Most users get
|
|
14
|
+
it with the distribution.
|
|
10
15
|
|
|
11
16
|
## Install
|
|
12
17
|
|
|
@@ -16,21 +21,18 @@ npm install @agimon-ai/doompi-voice
|
|
|
16
21
|
|
|
17
22
|
## How it loads
|
|
18
23
|
|
|
19
|
-
Doompi loads
|
|
20
|
-
`.doom/modes.yaml
|
|
21
|
-
|
|
22
|
-
Extension entry: `@agimon-ai/doompi-voice/extensions/doom`
|
|
24
|
+
Doompi loads Voice as core. It is not a major-mode layer and does not appear in
|
|
25
|
+
`.doom/modes.yaml`. The bare package name follows its Pi manifest and selects the Doom
|
|
26
|
+
adapter. Explicit `/extensions/pi` and `/extensions/doom` subpaths remain available.
|
|
23
27
|
|
|
24
28
|
## Leader
|
|
25
29
|
|
|
26
30
|
- `SPC v v` records or transcribes once.
|
|
27
|
-
- `SPC v a` toggles autonomous
|
|
31
|
+
- `SPC v a` toggles autonomous capture.
|
|
28
32
|
|
|
29
|
-
## Autonomous
|
|
33
|
+
## Autonomous capture
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
`utteranceIdleMs` setting controls how long the assistant waits after the last
|
|
33
|
-
voiced frame before treating thoughtful dictation as complete:
|
|
35
|
+
Configure autonomous capture in `~/.pi/.doom/config.yaml`:
|
|
34
36
|
|
|
35
37
|
```yaml
|
|
36
38
|
voice:
|
|
@@ -41,35 +43,50 @@ voice:
|
|
|
41
43
|
engine: macos-say
|
|
42
44
|
```
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
complete
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
`utteranceIdleMs` is the pause after the last voiced frame before Doompi treats the turn as
|
|
47
|
+
complete. It accepts 1500 through 10000 milliseconds and defaults to 3000. The worker uses
|
|
48
|
+
acoustic activity only as an endpoint hint: it keeps the full turn PCM, including pauses
|
|
49
|
+
and quiet speech, and transcribes a new immutable full-turn revision for each decision.
|
|
50
|
+
|
|
51
|
+
## Voice tools without a tool pile
|
|
52
|
+
|
|
53
|
+
While autonomous Voice is active, Pi sees exactly two façade tools:
|
|
54
|
+
|
|
55
|
+
- `describe_voice_tools` returns the session's spoken capabilities and an opaque catalog
|
|
56
|
+
token.
|
|
57
|
+
- `use_voice_tools` executes a bounded batch against that token, in order.
|
|
58
|
+
|
|
59
|
+
Extensions register callbacks through
|
|
60
|
+
`@agimon-ai/doompi-extension-contracts/voice-tools`; those callbacks never become direct Pi
|
|
61
|
+
tools. `@agimon-ai/doompi-voice/voice-tools` remains as a compatibility import for the same
|
|
62
|
+
contract.
|
|
63
|
+
|
|
64
|
+
A committed Voice-originated domain switch is the only reload that resumes capture. It
|
|
65
|
+
starts fresh session, capture, and turn identities. A manual reload does not silently turn
|
|
66
|
+
the microphone back on.
|
|
49
67
|
|
|
50
68
|
## Local worker and privacy
|
|
51
69
|
|
|
52
|
-
Capture, PCM validation,
|
|
53
|
-
Whisper run in a private supervised worker thread. Audio and filesystem paths do
|
|
54
|
-
not cross its control protocol;
|
|
55
|
-
|
|
56
|
-
minutes. Autonomous capture uses the same
|
|
57
|
-
|
|
58
|
-
with confirmed speech is finalized for transcription.
|
|
70
|
+
Capture, PCM validation, voice activity detection, spooling, WAV creation, normalization,
|
|
71
|
+
and Whisper all run in a private supervised worker thread. Audio and filesystem paths do
|
|
72
|
+
not cross its control protocol; bounded state metadata and transcript candidates do.
|
|
73
|
+
|
|
74
|
+
Manual capture stops explicitly or after five minutes. Autonomous capture uses the same
|
|
75
|
+
five-minute bound for each spool. An idle window is replaced without disabling Voice; a
|
|
76
|
+
window with confirmed speech is finalized for transcription.
|
|
59
77
|
|
|
60
|
-
Unacknowledged turns remain in private `0700`/`0600` storage and are rediscovered
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
loaded unless verified pure-WASM runtime and model assets are available; this
|
|
64
|
-
build advertises and uses the worker-side adaptive VAD fallback.
|
|
78
|
+
Unacknowledged turns remain in private `0700`/`0600` storage and are rediscovered after a
|
|
79
|
+
worker restart. Neural VAD is advertised only when verified pure-WASM runtime and model
|
|
80
|
+
assets exist; otherwise Voice uses its worker-side adaptive fallback.
|
|
65
81
|
|
|
66
82
|
## Entry points
|
|
67
83
|
|
|
68
|
-
| Import |
|
|
69
|
-
| ----------------------------------------- |
|
|
70
|
-
| `@agimon-ai/doompi-voice` |
|
|
71
|
-
| `@agimon-ai/doompi-voice/extensions/pi` |
|
|
72
|
-
| `@agimon-ai/doompi-voice/extensions/doom` |
|
|
84
|
+
| Import | Purpose |
|
|
85
|
+
| ----------------------------------------- | ----------------------------- |
|
|
86
|
+
| `@agimon-ai/doompi-voice` | Library API |
|
|
87
|
+
| `@agimon-ai/doompi-voice/extensions/pi` | Standalone Pi adapter |
|
|
88
|
+
| `@agimon-ai/doompi-voice/extensions/doom` | Doompi adapter |
|
|
89
|
+
| `@agimon-ai/doompi-voice/voice-tools` | Compatibility contract export |
|
|
73
90
|
|
|
74
91
|
## License
|
|
75
92
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("@agimon-ai/doompi-extension-contracts/mode"),t=require("@agimon-ai/doompi-extension-contracts/protocol");const n=`@agimon-ai/doompi-voice`;function r(n,r){if(n)return n;throw new t.DoomProtocolError({code:e.MINOR_MODE_ERROR_CODE.invalidArguments,message:`${r} is required when action is invoke.`})}function i(e){return{source:r(e.source,`source`),id:r(e.id,`id`),ownerGeneration:r(e.ownerGeneration,`ownerGeneration`),registrationId:r(e.registrationId,`registrationId`)}}function a(a){return{descriptor:{source:n,id:e.MINOR_MODE_TOOL_NAME,name:e.MINOR_MODE_TOOL_NAME,label:`Minor Mode`,description:`List independently registered Doompi minor modes, or invoke one advertised action using the exact registration reference returned by list.`,order:0,inputSchema:e.MinorModeToolInputSchema,resultSchema:e.MinorModeToolResultSchema},async execute(n,o){let s=n;if(s.action===`list`){let n=a.snapshot();if(n)return n;throw new t.DoomProtocolError({code:e.MINOR_MODE_ERROR_CODE.sessionReplaced,message:`The minor-mode catalog is not active for this session.`,retryable:!0})}return a.invoke(i(s),r(s.modeAction,`modeAction`),s.arguments??{},o.signal)}}}function o(r){let i=(0,e.createMinorModeCatalogClient)(),a;return{bind(e){a?.(),a=i.bind((0,t.createProtocolRuntime)({bus:r.events,source:n,sessionId:e}))},snapshot:()=>i.getSnapshot(),records:()=>i.getSnapshot()?.modes,invoke:(e,t,n,r)=>i.invoke(e,t,n,{signal:r}),dispose(){a?.(),a=void 0,i.dispose()}}}exports.createMinorModeVoiceTool=a,exports.createVoiceMinorModeCatalog=o;
|
|
2
|
+
//# sourceMappingURL=minorModeCatalog.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"minorModeCatalog.cjs","names":["DoomProtocolError","MINOR_MODE_ERROR_CODE","MINOR_MODE_TOOL_NAME","MinorModeToolInputSchema","MinorModeToolResultSchema","createMinorModeCatalogClient","createProtocolRuntime"],"sources":["../../../src/adapters/pi/minorModeCatalog.ts"],"sourcesContent":["import {\n MINOR_MODE_ERROR_CODE,\n MINOR_MODE_TOOL_NAME,\n type MinorModeActionResponse,\n type MinorModeArguments,\n createMinorModeCatalogClient,\n type MinorModeCatalogSnapshot,\n type MinorModeRecord,\n type MinorModeRegistrationRef,\n type MinorModeToolInput,\n MinorModeToolInputSchema,\n MinorModeToolResultSchema,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createProtocolRuntime, DoomProtocolError } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { VoiceToolDefinition } from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-voice';\n\nexport interface VoiceMinorModeCatalog {\n bind(sessionId: string): void;\n snapshot(): MinorModeCatalogSnapshot | undefined;\n records(): readonly MinorModeRecord[] | undefined;\n invoke(\n mode: MinorModeRegistrationRef,\n actionId: string,\n argumentsValue: MinorModeArguments,\n signal: AbortSignal,\n ): Promise<MinorModeActionResponse>;\n dispose(): void;\n}\n\nfunction required(value: string | undefined, name: string): string {\n if (value) return value;\n throw new DoomProtocolError({\n code: MINOR_MODE_ERROR_CODE.invalidArguments,\n message: `${name} is required when action is invoke.`,\n });\n}\n\nfunction registration(input: MinorModeToolInput): MinorModeRegistrationRef {\n return {\n source: required(input.source, 'source'),\n id: required(input.id, 'id'),\n ownerGeneration: required(input.ownerGeneration, 'ownerGeneration'),\n registrationId: required(input.registrationId, 'registrationId'),\n };\n}\n\nexport function createMinorModeVoiceTool(catalog: VoiceMinorModeCatalog): VoiceToolDefinition<ExtensionContext> {\n return {\n descriptor: {\n source: PACKAGE_SOURCE,\n id: MINOR_MODE_TOOL_NAME,\n name: MINOR_MODE_TOOL_NAME,\n label: 'Minor Mode',\n description:\n 'List independently registered Doompi minor modes, or invoke one advertised action using the exact registration reference returned by list.',\n order: 0,\n inputSchema: MinorModeToolInputSchema,\n resultSchema: MinorModeToolResultSchema,\n },\n async execute(input, execution) {\n const params = input as MinorModeToolInput;\n if (params.action === 'list') {\n const snapshot = catalog.snapshot();\n if (snapshot) return snapshot;\n throw new DoomProtocolError({\n code: MINOR_MODE_ERROR_CODE.sessionReplaced,\n message: 'The minor-mode catalog is not active for this session.',\n retryable: true,\n });\n }\n return catalog.invoke(\n registration(params),\n required(params.modeAction, 'modeAction'),\n params.arguments ?? {},\n execution.signal,\n );\n },\n };\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 snapshot: () => client.getSnapshot(),\n records: () => client.getSnapshot()?.modes,\n invoke: (mode, actionId, argumentsValue, signal) => client.invoke(mode, actionId, argumentsValue, { signal }),\n dispose() {\n disposeBinding?.();\n disposeBinding = undefined;\n client.dispose();\n },\n };\n}\n"],"mappings":"wHAiBA,MAAM,EAAiB,0BAevB,SAAS,EAAS,EAA2B,EAAsB,CACjE,GAAI,EAAO,OAAO,EAClB,MAAM,IAAIA,EAAAA,kBAAkB,CAC1B,KAAMC,EAAAA,sBAAsB,iBAC5B,QAAS,GAAG,EAAK,oCACnB,CAAC,CACH,CAEA,SAAS,EAAa,EAAqD,CACzE,MAAO,CACL,OAAQ,EAAS,EAAM,OAAQ,QAAQ,EACvC,GAAI,EAAS,EAAM,GAAI,IAAI,EAC3B,gBAAiB,EAAS,EAAM,gBAAiB,iBAAiB,EAClE,eAAgB,EAAS,EAAM,eAAgB,gBAAgB,CACjE,CACF,CAEA,SAAgB,EAAyB,EAAuE,CAC9G,MAAO,CACL,WAAY,CACV,OAAQ,EACR,GAAIC,EAAAA,qBACJ,KAAMA,EAAAA,qBACN,MAAO,aACP,YACE,6IACF,MAAO,EACP,YAAaC,EAAAA,yBACb,aAAcC,EAAAA,yBAChB,EACA,MAAM,QAAQ,EAAO,EAAW,CAC9B,IAAM,EAAS,EACf,GAAI,EAAO,SAAW,OAAQ,CAC5B,IAAM,EAAW,EAAQ,SAAS,EAClC,GAAI,EAAU,OAAO,EACrB,MAAM,IAAIJ,EAAAA,kBAAkB,CAC1B,KAAMC,EAAAA,sBAAsB,gBAC5B,QAAS,yDACT,UAAW,EACb,CAAC,CACH,CACA,OAAO,EAAQ,OACb,EAAa,CAAM,EACnB,EAAS,EAAO,WAAY,YAAY,EACxC,EAAO,WAAa,CAAC,EACrB,EAAU,MACZ,CACF,CACF,CACF,CAEA,SAAgB,EAA4B,EAAyC,CACnF,IAAM,GAAA,EAASI,EAAAA,6BAAAA,CAA6B,EACxC,EACJ,MAAO,CACL,KAAK,EAAW,CACd,IAAiB,EACjB,EAAiB,EAAO,MAAA,EAAKC,EAAAA,sBAAAA,CAAsB,CAAE,IAAK,EAAG,OAAQ,OAAQ,EAAgB,WAAU,CAAC,CAAC,CAC3G,EACA,aAAgB,EAAO,YAAY,EACnC,YAAe,EAAO,YAAY,CAAC,EAAE,MACrC,QAAS,EAAM,EAAU,EAAgB,IAAW,EAAO,OAAO,EAAM,EAAU,EAAgB,CAAE,QAAO,CAAC,EAC5G,SAAU,CACR,IAAiB,EACjB,EAAiB,IAAA,GACjB,EAAO,QAAQ,CACjB,CACF,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{MINOR_MODE_ERROR_CODE as e,MINOR_MODE_TOOL_NAME as t,MinorModeToolInputSchema as n,MinorModeToolResultSchema as r,createMinorModeCatalogClient as i}from"@agimon-ai/doompi-extension-contracts/mode";import{DoomProtocolError as a,createProtocolRuntime as o}from"@agimon-ai/doompi-extension-contracts/protocol";const s=`@agimon-ai/doompi-voice`;function c(t,n){if(t)return t;throw new a({code:e.invalidArguments,message:`${n} is required when action is invoke.`})}function l(e){return{source:c(e.source,`source`),id:c(e.id,`id`),ownerGeneration:c(e.ownerGeneration,`ownerGeneration`),registrationId:c(e.registrationId,`registrationId`)}}function u(i){return{descriptor:{source:s,id:t,name:t,label:`Minor Mode`,description:`List independently registered Doompi minor modes, or invoke one advertised action using the exact registration reference returned by list.`,order:0,inputSchema:n,resultSchema:r},async execute(t,n){let r=t;if(r.action===`list`){let t=i.snapshot();if(t)return t;throw new a({code:e.sessionReplaced,message:`The minor-mode catalog is not active for this session.`,retryable:!0})}return i.invoke(l(r),c(r.modeAction,`modeAction`),r.arguments??{},n.signal)}}}function d(e){let t=i(),n;return{bind(r){n?.(),n=t.bind(o({bus:e.events,source:s,sessionId:r}))},snapshot:()=>t.getSnapshot(),records:()=>t.getSnapshot()?.modes,invoke:(e,n,r,i)=>t.invoke(e,n,r,{signal:i}),dispose(){n?.(),n=void 0,t.dispose()}}}export{u as createMinorModeVoiceTool,d 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 {\n MINOR_MODE_ERROR_CODE,\n MINOR_MODE_TOOL_NAME,\n type MinorModeActionResponse,\n type MinorModeArguments,\n createMinorModeCatalogClient,\n type MinorModeCatalogSnapshot,\n type MinorModeRecord,\n type MinorModeRegistrationRef,\n type MinorModeToolInput,\n MinorModeToolInputSchema,\n MinorModeToolResultSchema,\n} from '@agimon-ai/doompi-extension-contracts/mode';\nimport { createProtocolRuntime, DoomProtocolError } from '@agimon-ai/doompi-extension-contracts/protocol';\nimport type { VoiceToolDefinition } from '@agimon-ai/doompi-extension-contracts/voice-tools';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-voice';\n\nexport interface VoiceMinorModeCatalog {\n bind(sessionId: string): void;\n snapshot(): MinorModeCatalogSnapshot | undefined;\n records(): readonly MinorModeRecord[] | undefined;\n invoke(\n mode: MinorModeRegistrationRef,\n actionId: string,\n argumentsValue: MinorModeArguments,\n signal: AbortSignal,\n ): Promise<MinorModeActionResponse>;\n dispose(): void;\n}\n\nfunction required(value: string | undefined, name: string): string {\n if (value) return value;\n throw new DoomProtocolError({\n code: MINOR_MODE_ERROR_CODE.invalidArguments,\n message: `${name} is required when action is invoke.`,\n });\n}\n\nfunction registration(input: MinorModeToolInput): MinorModeRegistrationRef {\n return {\n source: required(input.source, 'source'),\n id: required(input.id, 'id'),\n ownerGeneration: required(input.ownerGeneration, 'ownerGeneration'),\n registrationId: required(input.registrationId, 'registrationId'),\n };\n}\n\nexport function createMinorModeVoiceTool(catalog: VoiceMinorModeCatalog): VoiceToolDefinition<ExtensionContext> {\n return {\n descriptor: {\n source: PACKAGE_SOURCE,\n id: MINOR_MODE_TOOL_NAME,\n name: MINOR_MODE_TOOL_NAME,\n label: 'Minor Mode',\n description:\n 'List independently registered Doompi minor modes, or invoke one advertised action using the exact registration reference returned by list.',\n order: 0,\n inputSchema: MinorModeToolInputSchema,\n resultSchema: MinorModeToolResultSchema,\n },\n async execute(input, execution) {\n const params = input as MinorModeToolInput;\n if (params.action === 'list') {\n const snapshot = catalog.snapshot();\n if (snapshot) return snapshot;\n throw new DoomProtocolError({\n code: MINOR_MODE_ERROR_CODE.sessionReplaced,\n message: 'The minor-mode catalog is not active for this session.',\n retryable: true,\n });\n }\n return catalog.invoke(\n registration(params),\n required(params.modeAction, 'modeAction'),\n params.arguments ?? {},\n execution.signal,\n );\n },\n };\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 snapshot: () => client.getSnapshot(),\n records: () => client.getSnapshot()?.modes,\n invoke: (mode, actionId, argumentsValue, signal) => client.invoke(mode, actionId, argumentsValue, { signal }),\n dispose() {\n disposeBinding?.();\n disposeBinding = undefined;\n client.dispose();\n },\n };\n}\n"],"mappings":"0TAiBA,MAAM,EAAiB,0BAevB,SAAS,EAAS,EAA2B,EAAsB,CACjE,GAAI,EAAO,OAAO,EAClB,MAAM,IAAI,EAAkB,CAC1B,KAAM,EAAsB,iBAC5B,QAAS,GAAG,EAAK,oCACnB,CAAC,CACH,CAEA,SAAS,EAAa,EAAqD,CACzE,MAAO,CACL,OAAQ,EAAS,EAAM,OAAQ,QAAQ,EACvC,GAAI,EAAS,EAAM,GAAI,IAAI,EAC3B,gBAAiB,EAAS,EAAM,gBAAiB,iBAAiB,EAClE,eAAgB,EAAS,EAAM,eAAgB,gBAAgB,CACjE,CACF,CAEA,SAAgB,EAAyB,EAAuE,CAC9G,MAAO,CACL,WAAY,CACV,OAAQ,EACR,GAAI,EACJ,KAAM,EACN,MAAO,aACP,YACE,6IACF,MAAO,EACP,YAAa,EACb,aAAc,CAChB,EACA,MAAM,QAAQ,EAAO,EAAW,CAC9B,IAAM,EAAS,EACf,GAAI,EAAO,SAAW,OAAQ,CAC5B,IAAM,EAAW,EAAQ,SAAS,EAClC,GAAI,EAAU,OAAO,EACrB,MAAM,IAAI,EAAkB,CAC1B,KAAM,EAAsB,gBAC5B,QAAS,yDACT,UAAW,EACb,CAAC,CACH,CACA,OAAO,EAAQ,OACb,EAAa,CAAM,EACnB,EAAS,EAAO,WAAY,YAAY,EACxC,EAAO,WAAa,CAAC,EACrB,EAAU,MACZ,CACF,CACF,CACF,CAEA,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,EAAgB,WAAU,CAAC,CAAC,CAC3G,EACA,aAAgB,EAAO,YAAY,EACnC,YAAe,EAAO,YAAY,CAAC,EAAE,MACrC,QAAS,EAAM,EAAU,EAAgB,IAAW,EAAO,OAAO,EAAM,EAAU,EAAgB,CAAE,QAAO,CAAC,EAC5G,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"),ee=require("./voiceTools.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"),w=require("@agimon-ai/doompi-telemetry"),T=require("@agimon-ai/doompi-extension-contracts/voice-tools");const E=`voice`,D=`voice-auto`,O=`doom-voice`;function k(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 te=[`·`,`•`,`●`,`•`],ne=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`],A=`info`,j=`error`,M=`doom_voice.transcription_finished`,N=`idle`,P=`recording`,F=`transcribing`,I=[{id:`voice.toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`v`,label:`toggle`,detail:`record or transcribe`}],command:{name:E}},{id:`voice.auto-toggle`,path:[{key:`v`,label:`voice`,order:67},{key:`a`,label:`auto`,detail:`continuous autonomous conversation`}],command:{name:D}}];function L(e){let t=e.state===P?te:ne,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 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(O,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(0,C.subscribeToNarrationRequests)({bus:e,source:`@agimon-ai/doompi-voice`,sessionId:t},({text:e})=>n.narrate(e))}function J(e,t){e.events?.on(x.ASK_USER_BLOCKED_EVENT,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 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 X=class{configs;clock;workspaces;recorder;analyzer;registry;currentState=N;recording;workspace;config;selected;startedAt=0;activityFrame=0;activityTimer;limitTimer;telemetry=(0,w.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===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=(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=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(O,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!==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(O,void 0)}};X=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])],X);function Z(e){return h.default.existsSync(e)?(0,y.parseDoomConfig)(h.default.readFileSync(e,`utf8`),e):{projectTrust:`ask`}}function re(e){let t=process.env.PI_CODING_AGENT_DIR||_.default.join(e,`.pi`,`agent`);return _.default.join(t,`doom-voice`,`config.yaml`)}function ie(e){let t=Z((0,y.globalDoomConfigPath)(e));if(t.voice)return t;let n=Z(re(e));return n.voice?(0,y.mergeDoomConfigs)(t,n):t}let Q=class{load(e,t=g.default.homedir()){let n=ie(t);if(process.env.PI_PROJECT_TRUST!==`trusted`)return n;let r=Z((0,y.repositoryDoomConfigPath)(e));return r.projectTrust===`never`?n:(0,y.mergeDoomConfigs)(n,r)}};Q=n.default([(0,v.injectable)()],Q);function ae(){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 $(){let e=new v.Container;return e.bind(b.DOOM_CONFIG_TYPES.ConfigService).to(Q).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 oe(e,t){let n=e.getActiveTools(),r=new Set(T.VOICE_FACADE_TOOL_NAMES),i=new Set(e.getAllTools().map(e=>e.name)),a=n.filter(e=>!r.has(e));t&&T.VOICE_FACADE_TOOL_NAMES.every(e=>i.has(e))&&a.push(...T.VOICE_FACADE_TOOL_NAMES),(a.length!==n.length||a.some((e,t)=>e!==n[t]))&&e.setActiveTools(a)}function se(e,n={}){let r=n.container??$(),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,h,g=typeof e.registerTool==`function`?ee.registerVoiceToolFacades(e,()=>h):void 0,_=p.createVoiceMinorModeCatalog(e),v=(0,T.registerVoiceToolContribution)(e,p.createMinorModeVoiceTool(_)),x,C=t=>{let n=l?.sessionManager?.getSessionId(),r=t===`active`&&l?.hasUI===!0&&h!==void 0&&n===h.sessionId;h?.setActive(r),oe(e,r)},w=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 Y(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`);V(e,l,t)},manualState:()=>i.state,commandContext:()=>l?m.collectVoiceCommandContext(l.sessionManager.getBranch(),_.records()):void 0,onActivationStateChange:e=>{C(e),g?.refresh(),x?.publish(k(e,l?.hasUI===!0))},...n.autoClientFactory?{clientFactory:n.autoClientFactory}:{},...n.identityNonceFactory?{identityNonceFactory:n.identityNonceFactory}:{}});x=(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:k(`disabled`),async handleAction(e,t,n){l=n.context;let r=B(n.context,o);if(c=r,e===`activate`)return await w.activate(r),{message:`Autonomous voice activation requested.`};if(e===`deactivate`)return await w.deactivate(r),{message:`Autonomous voice deactivation requested.`};throw Error(`Unknown autonomous voice action: ${e}`)}}),e.registerCommand(E,{description:`Toggle local voice recording and transcription`,handler:async(e,t)=>{if(t.hasUI){if(s=R(t,o),w.state!==`disabled`){s.notify(`Disable autonomous voice before using manual voice`,A);return}await i.toggle(s)}}}),e.registerCommand(D,{description:`Toggle continuous autonomous voice conversation`,handler:async(e,t)=>{t.hasUI&&(l=t,c=B(t,o),w.state===`disabled`?await w.activate(c):await w.deactivate(c))}}),e.on(`session_start`,async(t,n)=>{let r=t.reason;w.state!==`disabled`&&await w.deactivate(c??B(n,o)),l=n,s=void 0,c=void 0,d?.(),d=void 0,h?.setActive(!1),h?.dispose(),h=void 0,g?.bind(void 0),f?.dispose(),f=(0,T.createVoiceToolHost)();let i=n.sessionManager?.getSessionId(),a=!1;if(i){try{h=f.bindSession(i,n),g?.bind(h),a=r===`reload`&&(0,T.consumeVoiceReloadHandoff)(i)!==void 0}catch(e){f.dispose(),f=void 0;let t=e instanceof Error?e.message:String(e);n.hasUI&&n.ui.notify(`Voice capability host unavailable: ${t}`,j)}_.bind(i),d=q(e.events,i,w)}C(`disabled`),g?.refresh(),n.hasUI&&(s=R(n,o),c=B(n,o),s.setIndicator(void 0),s.setStatus(O,void 0),x?.publish(k(`disabled`,n.hasUI)),a&&c&&await w.activate(c))}),e.on(`before_agent_start`,(e,t)=>{l=t,C(w.state),g?.refresh()}),J(e,w),e.on(`session_shutdown`,async()=>{let e=s,t=c;C(`disabled`),h?.setActive(!1),h?.dispose(),h=void 0,g?.bind(void 0),g?.dispose(),f?.dispose(),f=void 0,s=void 0,c=void 0,l=void 0,d?.(),d=void 0,v.dispose(),_.dispose(),await w.shutdown(t),await i.shutdown(e),o.dispose(),x?.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 Q}}),Object.defineProperty(exports,"TranscriberRegistry",{enumerable:!0,get:function(){return f.TranscriberRegistry}}),exports.VOICE_LEADER_BINDINGS=I,Object.defineProperty(exports,"VoiceSessionController",{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,"WhisperCppAdapter",{enumerable:!0,get:function(){return f.WhisperCppAdapter}}),exports.createVoiceContainer=$,exports.createVoiceModule=ae,exports.deliverAutoCaptureInput=V,exports.extractFinalizedIntentSource=W,exports.extractTerminalAssistantText=G,exports.formatAutoCaptureActivity=z,exports.formatVoiceActivity=L,exports.isAskUserBlockedPayload=U,exports.isSuccessfulPlanWrite=K,exports.registerAutoCapturePiEventHandlers=J,exports.registerNarrationRequestHandler=q,exports.resolveAutoCaptureModelContracts=Y,exports.voiceExtension=se;
|
|
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":"4mCA4FA,MACM,EAAe,QACf,EAAoB,aACpB,EAAa,aAOb,EAAmB,CAAC,KAAM,KAAM,KAAM,IAAI,EAC1C,EAAsB,CAAC,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,KAAM,IAAI,EACjF,EAAoB,OACpB,EAAqB,QAMrB,EAA+B,oCAE/B,EAAa,OACb,EAAkB,YAClB,EAAqB,eAyBd,EAAkD,CAC7D,CACE,GAAI,eACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,QAAS,MAAO,EAAmB,EACtD,CAAE,IAAK,IAAK,MAAO,SAAU,OAAQ,sBAAuB,CAC9D,EACA,QAAS,CAAE,KAAM,CAAa,CAChC,EACA,CACE,GAAI,oBACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,QAAS,MAAO,EAAmB,EACtD,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,oCAAmB,CACxD,EACA,QAAS,CAAE,KAAM,CAAkB,CACrC,CACF,EAYA,SAAgB,EAAoB,EAAwD,CAC1F,IAAM,EAAS,EAAO,QAAU,EAAkB,EAAmB,EAE/D,EAAQ,EADK,KAAK,IAAI,EAAG,KAAK,MAAM,EAAO,UAAU,CAAC,EAAI,EAAO,QAEjE,EAAQ,EAAO,QAAU,EAAmB,UAAuB,SACnE,EAAU,KAAK,IAAI,EAAG,KAAK,MAAM,EAAO,gBAAkB,CAAC,CAAC,EAKlE,MAAO,CACL,WAJA,EAAO,QAAU,EACb,GAAG,EAAM,oBAAoB,KAAK,MAAM,EAAU,EAAE,EAAE,GAAG,OAAO,EAAU,EAAE,CAAC,CAAC,SAAS,EAAG,GAAG,IAC7F,GAAG,EAAM,sBAGb,OAAQ,CACN,SAAU,EACV,YAAa,EACb,aAAc,CAAC,CAAE,KAAM,EAAO,OAAM,CAAC,EACrC,gBAAiB,CAAC,CAAE,KAAM,EAAO,OAAM,CAAC,CAC1C,CACF,CACF,CAEA,SAAS,EAAc,EAA2B,EAAgD,CAChG,MAAO,CACL,QAAS,EAAS,IAAU,EAAQ,GAAG,OAAO,EAAS,CAAK,EAC5D,WAAY,EAAK,IAAU,EAAQ,GAAG,UAAU,EAAK,CAAK,EAC1D,aAAe,GAAW,EAAO,OAAO,EAAS,EAAoB,CAAM,CAAC,CAAC,OAAS,IAAA,EAAS,EAC/F,kBAAqB,EAAQ,GAAG,cAAc,EAC9C,cAAgB,GAAS,EAAQ,GAAG,cAAc,CAAI,CACxD,CACF,CAEA,SAAgB,EAA0B,EAAmE,CAC3G,IAAM,EACJ,IAAU,YACN,CAAE,MAAO,KAAM,WAAY,wBAAyB,MAAO,QAAkB,EAC7E,IAAU,SACR,CAAE,MAAO,KAAM,WAAY,6BAA8B,MAAO,SAAmB,EACnF,IAAU,aACR,CAAE,MAAO,KAAM,WAAY,yCAA0C,MAAO,QAAkB,EAC9F,IAAU,YACR,CAAE,MAAO,KAAM,WAAY,sCAAuC,MAAO,QAAkB,EAC3F,IAAU,aACR,CAAE,MAAO,KAAM,WAAY,kCAAmC,MAAO,SAAmB,EACxF,IAAU,UACR,CAAE,MAAO,KAAM,WAAY,yCAA0C,MAAO,SAAmB,EAC/F,CAAE,MAAO,KAAM,WAAY,uBAAwB,MAAO,SAAmB,EAC7F,MAAO,CACL,WAAY,EAAa,WACzB,OAAQ,CACN,SAAU,EAAa,MACvB,YAAa,EAAa,MAC1B,aAAc,CAAC,CAAE,KAAM,EAAa,MAAO,MAAO,EAAa,KAAM,CAAC,EACtE,gBAAiB,CAAC,CAAE,KAAM,EAAa,MAAO,MAAO,EAAa,KAAM,CAAC,CAC3E,CACF,CACF,CAEA,SAAS,EAAoB,EAA2B,EAAsD,CAC5G,MAAO,CACL,QAAS,EAAS,IAAU,EAAQ,GAAG,OAAO,EAAS,CAAK,EAC5D,UAAY,GAAU,EAAQ,GAAG,UAAU,EAAY,CAAK,EAC5D,aAAe,GAAU,EAAO,OAAO,EAAQ,EAA0B,CAAK,CAAC,CAAC,OAAS,IAAA,EAAS,CACpG,CACF,CAMA,SAAgB,EACd,EACA,EACA,EACA,EAAoC,YAC9B,CACN,GAAI,EAAQ,OAAO,EAAG,CACpB,EAAG,gBAAgB,CAAI,EACvB,MACF,CACA,EAAG,gBAAgB,EAAM,CAAE,UAAW,IAAW,iBAAmB,WAAa,OAAQ,CAAC,CAC5F,CAqBA,SAAS,EAAS,EAAkD,CAClE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,SAAgB,EAAwB,EAAkD,CACxF,OAAO,EAAS,CAAO,GAAK,OAAO,EAAQ,QAAW,SACxD,CAEA,SAAgB,EAA6B,EAAqD,CAChG,GAAI,CAAC,EAAS,CAAO,GAAK,EAAQ,OAAS,aAAe,CAAC,MAAM,QAAQ,EAAQ,OAAO,EAAG,OAC3F,IAAM,EAAiB,CAAC,EACxB,IAAK,IAAM,KAAS,EAAQ,QACrB,KAAS,CAAK,EACnB,IAAI,EAAM,OAAS,WAAY,MAAO,CAAE,KAAM,EAAK,KAAK,EAAE,CAAC,CAAC,KAAK,CAAE,EAC/D,EAAM,OAAS,QAAU,OAAO,EAAM,MAAS,UAAU,EAAK,KAAK,EAAM,IAAI,CADd,CAIvE,CAEA,SAAgB,EAA6B,EAAsC,CACjF,GACE,CAAC,EAAS,CAAO,GACjB,EAAQ,OAAS,aACjB,EAAQ,aAAe,WACvB,CAAC,MAAM,QAAQ,EAAQ,OAAO,EAE9B,OACF,IAAM,EAAiB,CAAC,EACxB,IAAK,IAAM,KAAS,EAAQ,QACrB,KAAS,CAAK,EACnB,IAAI,EAAM,OAAS,WAAY,OAC3B,EAAM,OAAS,QAAU,OAAO,EAAM,MAAS,UAAU,EAAK,KAAK,EAAM,IAAI,CAD3C,CAGxC,OAAO,EAAK,KAAK,EAAE,CAAC,CAAC,KAAK,GAAK,IAAA,EACjC,CAEA,SAAgB,EAAsB,EAAkB,EAAkB,EAA0B,CAElG,OADI,IAAa,cAAgB,GAAW,CAAC,EAAS,CAAM,EAAU,GAC/D,EAAS,EAAO,OAAO,GAAK,EAAO,QAAQ,UAAY,EAChE,CAEA,SAAgB,EACd,EACA,EACA,EACY,CACZ,OAAA,EAAOA,EAAAA,6BAAAA,CAA6B,CAAE,IAAK,EAAQ,OAAQ,0BAAc,WAAU,GAAI,CAAE,UACvF,EAAW,QAAQ,CAAI,CACzB,CACF,CAEA,SAAgB,EACd,EACA,EACM,CACN,EAAG,QAAQ,GAAGC,EAAAA,uBAAyB,GAAY,CAC7C,EAAwB,CAAO,GAAG,EAAW,eAAe,EAAQ,MAAM,CAChF,CAAC,EACD,EAAG,GAAG,QAAU,GAAU,CACxB,EAAW,aAAa,CACtB,KAAM,EAAM,KACZ,OAAQ,EAAM,OACd,GAAI,EAAM,kBAAoB,CAAE,kBAAmB,EAAM,iBAAkB,EAAI,CAAC,CAClF,CAAC,CACH,CAAC,EACD,EAAG,GAAG,qBAAuB,GAAU,EAAW,iBAAiB,EAAM,MAAM,CAAC,EAChF,EAAG,GAAG,kBAAqB,EAAW,aAAa,CAAC,EACpD,EAAG,GAAG,cAAgB,GAAU,CAC9B,IAAM,EAAS,EAA6B,EAAM,OAAO,EACrD,GAAQ,EAAW,yBAAyB,EAAO,IAAI,CAC7D,CAAC,EACD,EAAG,GAAG,qBAAuB,GAAU,CACjC,EAAsB,EAAM,SAAU,EAAM,QAAS,EAAM,MAAM,GAAG,EAAW,YAAY,CACjG,CAAC,EACD,EAAG,GAAG,WAAa,GAAU,CAC3B,IAAM,EAAU,EAAM,QACtB,EAAW,aACT,EAAM,UACN,EAAQ,OAAS,YAAc,EAAQ,WAAa,UACpD,EAAM,YAAY,OAClB,EAA6B,CAAO,CACtC,CACF,CAAC,EACD,EAAG,GAAG,gBAAiB,SAAY,EAAW,aAAa,CAAC,CAC9D,CAEA,SAAgB,EACd,EACA,EAC2B,CAC3B,IAAM,EAAY,EAAU,QAAQ,GAAG,EACvC,GAAI,GAAa,GAAK,IAAc,EAAU,OAAS,EACrD,MAAU,MAAM,wDAAwD,EAC1E,IAAM,EAAW,EAAU,MAAM,EAAG,CAAS,EACvC,EAAU,EAAU,MAAM,EAAY,CAAC,EACvC,EAAQ,EAAQ,cAAc,KAAK,EAAU,CAAO,EAC1D,GAAI,CAAC,EAAO,MAAU,MAAM,6CAA6C,GAAW,EACpF,GAAI,CAAC,EAAQ,cAAc,kBAAkB,CAAK,EAChD,MAAU,MAAM,4DAA4D,GAAW,EAEzF,IAAM,EAAkC,CACtC,SAAU,KAAO,IAAkD,CACjE,IAAM,EAAW,MAAM,EAAQ,cAAc,SAC3C,EACA,CACE,aAAc,EAAQ,aACtB,SAAU,CAAC,CAAE,KAAM,OAAQ,QAAS,EAAQ,MAAO,UAAW,KAAK,IAAI,CAAE,CAAC,CAC5E,EACA,CACE,OAAQ,EAAQ,OAChB,GAAI,EAAQ,YAAc,IAAA,GAAY,CAAC,EAAI,CAAE,UAAW,EAAQ,SAAU,EAC1E,eAAgB,EAAQ,eACxB,gBAAiB,OACjB,WAAY,CACd,CACF,EACA,GAAI,EAAS,aAAe,SAAW,EAAS,aAAe,UAC7D,MAAU,MAAM,EAAS,cAAgB,uCAAuC,EAAS,YAAY,EACvG,OAAO,EAAS,QACb,OAAQ,GAAY,EAAQ,OAAS,MAAM,CAAC,CAC5C,IAAK,GAAY,EAAQ,IAAI,CAAC,CAC9B,KAAK,EAAE,CAAC,CACR,KAAK,CACV,CACF,EACA,MAAO,CACL,YAAa,IAAIC,EAAAA,4BAA4B,CAAW,EACxD,KAAM,IAAIC,EAAAA,wBACV,SAAU,IAAIC,EAAAA,mBAAmB,CAAW,CAC9C,CACF,CAGO,IAAM,EAAN,KAAgE,CAkBT,QACT,MACa,WACL,SACA,SACM,SAtBjE,aAAmC,EACnC,UACA,UACA,OACA,SACA,UAAoB,EACpB,cAAwB,EACxB,cACA,WACA,WAAiB,EAAYC,EAAAA,oBAAAA,CAAoB,CAC/C,YAAa,aACb,YAAa,0BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,YACE,EACA,EACA,EACA,EACA,EACA,EACA,CAN0D,KAAA,QAAA,EACT,KAAA,MAAA,EACa,KAAA,WAAA,EACL,KAAA,SAAA,EACA,KAAA,SAAA,EACM,KAAA,SAAA,CAC9D,CACH,IAAI,OAAoB,CACtB,OAAO,KAAK,YACd,CACA,MAAM,OAAO,EAA4B,CACvC,GAAI,KAAK,eAAiB,EAAoB,CAC5C,EAAG,OAAO,yCAA0C,CAAiB,EACrE,MACF,CACA,GAAI,KAAK,eAAiB,EAAiB,CACzC,MAAM,KAAK,kBAAkB,CAAE,EAC/B,MACF,CACA,MAAM,KAAK,eAAe,CAAE,CAC9B,CACA,MAAc,eAAe,EAA4B,CACvD,GAAI,CACF,IAAM,EAAc,QAAQ,IAAI,iBAAmB,QAAQ,IAAI,EACzD,EAAS,KAAK,QAAQ,KAAK,CAAW,CAAC,CAAC,MAC9C,GAAI,CAAC,EAAQ,MAAU,MAAM,wDAAwD,EACrF,IAAM,GAAA,EAASC,EAAAA,mBAAAA,CAAmB,CAAM,EACxC,KAAK,SAAS,UAAU,CAAM,EAC9B,IAAM,EAAW,KAAK,SAAS,OAAO,CAAM,EAC5C,KAAU,UAAU,YAAY,iCAA2B,CACzD,OAAQ,EAAS,QAAQ,OACzB,KAAM,EAAO,QACf,CAAC,EACD,IAAM,EAAY,KAAK,WAAW,OAAO,EACzC,KAAK,UAAY,KAAK,SAAS,MAAM,EAAQ,CAAS,EACtD,KAAK,UAAY,EACjB,KAAK,OAAS,EACd,KAAK,SAAW,EAChB,KAAK,aAAe,EACpB,KAAK,UAAY,KAAK,MAAM,IAAI,EAChC,KAAK,cAAc,CAAE,EACrB,KAAK,WAAa,KAAK,MAAM,eAAiB,CAC5C,KAAU,kBAAkB,CAAE,CAChC,EAAG,GAAgB,EACnB,KAAU,UAAU,YAAY,+BAAyB,CACvD,OAAQ,EAAS,QAAQ,OACzB,QAAS,SACX,CAAC,CACH,OAAS,EAAO,CACd,MAAM,KAAK,UAAU,YAAY,8BAAwB,EAAO,CAAE,QAAS,QAAS,CAAC,EACrF,KAAK,MAAM,CAAE,EACb,EAAG,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAG,CAAkB,CACtF,CACF,CACA,cAAsB,EAAmB,CACvC,KAAK,cAAgB,EACrB,KAAK,gBAAgB,CAAE,EACvB,KAAK,cAAgB,KAAK,MAAM,gBAAkB,CAChD,KAAK,eAAiB,EACtB,KAAK,gBAAgB,CAAE,CACzB,EAAG,GAAoB,CACzB,CACA,gBAAwB,EAAmB,CACzC,GAAI,KAAK,eAAiB,EAAY,OACtC,IAAM,EAA8B,CAClC,MAAO,KAAK,aACZ,WAAY,KAAK,cACjB,GAAI,KAAK,eAAiB,EACtB,CAAE,eAAgB,KAAK,IAAI,EAAG,KAAK,OAAO,KAAK,MAAM,IAAI,EAAI,KAAK,WAAa,GAAK,CAAC,CAAE,EACvF,CAAC,CACP,EACA,EAAG,aAAa,CAAM,EACtB,EAAG,UAAU,EAAY,EAAoB,CAAM,CAAC,CAAC,UAAU,CACjE,CACA,MAAc,kBAAkB,EAA4B,CAC1D,IAAM,EAAY,KAAK,UACjB,EAAY,KAAK,UACjB,EAAS,KAAK,OACd,EAAW,KAAK,SACtB,GAAI,CAAC,GAAa,CAAC,GAAa,CAAC,GAAU,CAAC,GAAY,KAAK,eAAiB,EAAiB,OAC/F,KAAK,YAAY,EACjB,IAAM,EAAqB,KAAK,UAChC,KAAK,aAAe,EACpB,KAAK,cAAc,CAAE,EACrB,KAAU,UAAU,YAAY,mCAA6B,CAC3D,OAAQ,EAAS,QAAQ,OACzB,YAAa,KAAK,IAAI,EAAG,KAAK,MAAM,IAAI,EAAI,CAAkB,CAChE,CAAC,EACD,GAAI,CACF,MAAM,EAAU,KAAK,EACrB,IAAM,EAAsB,KAAK,IAAI,EAAG,KAAK,MAAM,IAAI,EAAI,CAAkB,EAC7E,GAAI,KAAK,SAAS,QAAQ,EAAU,QAAQ,CAAC,CAAC,OAAQ,CACpD,MAAM,KAAK,UAAU,YAAY,EAA8B,CAC7D,OAAQ,EAAS,QAAQ,OACzB,YAAa,EACb,QAAS,GACT,QAAS,OACX,CAAC,EACD,EAAG,OAAO,qBAAsB,CAAiB,EACjD,MACF,CACA,IAAM,GACJ,MAAM,EAAS,QAAQ,WAAW,CAChC,UAAW,EAAU,SACrB,YACA,OAAQ,EAAS,OACjB,SAAU,EAAO,QACnB,CAAC,EAAA,CACD,KAAK,EACP,GAAI,CAAC,EAAY,CACf,MAAM,KAAK,UAAU,YAAY,EAA8B,CAC7D,OAAQ,EAAS,QAAQ,OACzB,YAAa,EACb,MAAO,GACP,QAAS,OACX,CAAC,EACD,EAAG,OAAO,gCAAiC,CAAiB,EAC5D,MACF,CACA,IAAM,EAAQ,EAAG,cAAc,EAC/B,EAAG,cAAc,GAAG,IAAQ,GAAS,CAAC,MAAM,KAAK,CAAK,EAAI,IAAM,KAAK,GAAY,EACjF,MAAM,KAAK,UAAU,YAAY,EAA8B,CAC7D,OAAQ,EAAS,QAAQ,OACzB,YAAa,EACb,MAAO,GACP,QAAS,WACX,CAAC,CACH,OAAS,EAAO,CACd,MAAM,KAAK,UAAU,YAAY,kCAA4B,EAAO,CAClE,OAAQ,EAAS,QAAQ,OACzB,YAAa,KAAK,IAAI,EAAG,KAAK,MAAM,IAAI,EAAI,CAAkB,CAChE,CAAC,EACD,EAAG,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAG,CAAkB,CACtF,QAAU,CACR,KAAK,MAAM,CAAE,CACf,CACF,CACA,MAAM,SAAS,EAA6B,CAC1C,KAAK,YAAY,EACb,KAAK,WAAa,KAAK,eAAiB,IAC1C,MAAM,KAAK,UAAU,MAAM,EAC3B,KAAU,UAAU,YAAY,gCAA0B,CAAE,QAAS,SAAU,CAAC,GAElF,KAAK,MAAM,CAAE,EACb,KAAU,UAAU,SAAS,CAC/B,CACA,aAA4B,CACtB,KAAK,eAAe,KAAK,MAAM,MAAM,KAAK,aAAa,EACvD,KAAK,YAAY,KAAK,MAAM,MAAM,KAAK,UAAU,EACrD,KAAK,cAAgB,IAAA,GACrB,KAAK,WAAa,IAAA,EACpB,CACA,MAAc,EAAoB,CAChC,KAAK,YAAY,EACb,KAAK,WAAW,KAAK,WAAW,OAAO,KAAK,SAAS,EACzD,KAAK,UAAY,IAAA,GACjB,KAAK,UAAY,IAAA,GACjB,KAAK,OAAS,IAAA,GACd,KAAK,SAAW,IAAA,GAChB,KAAK,aAAe,EACpB,KAAK,cAAgB,EACrB,GAAI,aAAa,IAAA,EAAS,EAC1B,GAAI,UAAU,EAAY,IAAA,EAAS,CACrC,CACF,gBAvLCC,EAAAA,EAAAA,WAAAA,CAAW,EAmBPC,EAAAA,QAAAA,GAAAA,EAAAA,EAAAA,OAAAA,CAAOC,EAAAA,kBAAkB,aAAa,CAAA,EACtCD,EAAAA,QAAAA,GAAAA,EAAAA,EAAAA,OAAAA,CAAOE,EAAAA,iBAAiB,KAAK,CAAA,EAC7BF,EAAAA,QAAAA,GAAAA,EAAAA,EAAAA,OAAAA,CAAOE,EAAAA,iBAAiB,kBAAkB,CAAA,EAC1CF,EAAAA,QAAAA,GAAAA,EAAAA,EAAAA,OAAAA,CAAOE,EAAAA,iBAAiB,aAAa,CAAA,EACrCF,EAAAA,QAAAA,GAAAA,EAAAA,EAAAA,OAAAA,CAAOE,EAAAA,iBAAiB,aAAa,CAAA,EACrCF,EAAAA,QAAAA,GAAAA,EAAAA,EAAAA,OAAAA,CAAOE,EAAAA,iBAAiB,mBAAmB,CAAA,iFAiKhD,SAAS,EAAgB,EAA8B,CAErD,OADKC,EAAAA,QAAG,WAAW,CAAQ,GAC3B,EAAOC,EAAAA,gBAAAA,CAAgBD,EAAAA,QAAG,aAAa,EAAU,MAAM,EAAG,CAAQ,EAD7B,CAAE,aAAc,KAAM,CAE7D,CAEA,SAAS,EAAqB,EAA+B,CAC3D,IAAM,EAAiB,QAAQ,IAAI,qBAAuBE,EAAAA,QAAK,KAAK,EAAe,MAAO,OAAO,EACjG,OAAOA,EAAAA,QAAK,KAAK,EAAgB,aAAc,aAAa,CAC9D,CAMA,SAAS,EAAsB,EAAmC,CAChE,IAAM,EAAa,GAAA,EAAgBC,EAAAA,qBAAAA,CAAqB,CAAa,CAAC,EACtE,GAAI,EAAW,MAAO,OAAO,EAC7B,IAAM,EAAgB,EAAgB,EAAqB,CAAa,CAAC,EACzE,OAAO,EAAc,OAAA,EAAQC,EAAAA,iBAAAA,CAAiB,EAAY,CAAa,EAAI,CAC7E,CAGO,IAAM,EAAN,KAAyD,CAC9D,KAAK,EAAkB,EAAgBC,EAAAA,QAAG,QAAQ,EAAe,CAC/D,IAAM,EAAe,EAAsB,CAAa,EAExD,GADgB,QAAQ,IAAI,mBAAqB,UACnC,OAAO,EAGrB,IAAM,EAAgB,GAAA,EADFC,EAAAA,yBAAAA,CAAyB,CACG,CAAC,EAEjD,OADI,EAAc,eAAiB,QAAgB,GACnD,EAAOF,EAAAA,iBAAAA,CAAiB,EAAc,CAAa,CACrD,CACF,EAZCR,EAAAA,EAAAA,QAAAA,EAAAA,EAAAA,EAAAA,WAAAA,CAAW,CAAA,EAAA,CAAA,EAcZ,SAAgB,GAAqC,CACnD,OAAO,IAAIW,EAAAA,iBAAiB,CAAE,UAAW,CACvC,EAAaR,EAAAA,iBAAiB,KAAK,CAAC,CAAC,GAAGS,EAAAA,WAAW,CAAC,CAAC,iBAAiB,EACtE,EAA0BT,EAAAA,iBAAiB,kBAAkB,CAAC,CAAC,GAAGU,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACvG,EAAsBV,EAAAA,iBAAiB,cAAc,CAAC,CAAC,GAAGW,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EAC/F,EAA4BX,EAAAA,iBAAiB,oBAAoB,CAAC,CAAC,GAAGY,EAAAA,wBAAwB,CAAC,CAAC,iBAAiB,EACjH,EAA0BZ,EAAAA,iBAAiB,kBAAkB,CAAC,CAAC,GAAGa,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACvG,EAAqBb,EAAAA,iBAAiB,aAAa,CAAC,CAAC,GAAGc,EAAAA,mBAAmB,CAAC,CAAC,iBAAiB,EAC9F,EAAwBd,EAAAA,iBAAiB,gBAAgB,CAAC,CAAC,GAAGe,EAAAA,sBAAsB,CAAC,CAAC,iBAAiB,EACvG,EAAkBf,EAAAA,iBAAiB,UAAU,CAAC,CAAC,GAAGgB,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACvF,EAAqBhB,EAAAA,iBAAiB,aAAa,CAAC,CAAC,GAAGiB,EAAAA,cAAc,CAAC,CAAC,iBAAiB,EACzF,EAA0BjB,EAAAA,iBAAiB,iBAAiB,CAAC,CAAC,GAAGkB,EAAAA,iBAAiB,CAAC,CAAC,iBAAiB,EACrG,EAA0BlB,EAAAA,iBAAiB,oBAAoB,CAAC,CAAC,GAAGmB,EAAAA,oBAAoB,CAAC,CAAC,iBAAiB,EAC3G,EAA0BnB,EAAAA,iBAAiB,iBAAiB,CAAC,CAAC,GAAGoB,EAAAA,iBAAiB,CAAC,CAAC,iBAAiB,EACrG,EAA2BpB,EAAAA,iBAAiB,mBAAmB,CAAC,CAAC,GAAGqB,EAAAA,mBAAmB,CAAC,CAAC,iBAAiB,EAC1G,EAA8BrB,EAAAA,iBAAiB,iBAAiB,CAAC,CAC9D,GAAGsB,EAAAA,4BAA4B,CAAC,CAChC,iBAAiB,CACtB,CAAC,CACH,CACA,SAAgB,GAAkC,CAChD,IAAM,EAAY,IAAIC,EAAAA,UAyBtB,OAxBA,EAAU,KAAyBxB,EAAAA,kBAAkB,aAAa,CAAC,CAAC,GAAG,CAAoB,CAAC,CAAC,iBAAiB,EAC9G,EAAU,KAAaC,EAAAA,iBAAiB,KAAK,CAAC,CAAC,GAAGS,EAAAA,WAAW,CAAC,CAAC,iBAAiB,EAChF,EAAU,KAA0BT,EAAAA,iBAAiB,kBAAkB,CAAC,CAAC,GAAGU,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACjH,EAAU,KAAsBV,EAAAA,iBAAiB,cAAc,CAAC,CAAC,GAAGW,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACzG,EACG,KAA4BX,EAAAA,iBAAiB,oBAAoB,CAAC,CAClE,GAAGY,EAAAA,wBAAwB,CAAC,CAC5B,iBAAiB,EACpB,EAAU,KAA0BZ,EAAAA,iBAAiB,kBAAkB,CAAC,CAAC,GAAGa,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACjH,EAAU,KAAqBb,EAAAA,iBAAiB,aAAa,CAAC,CAAC,GAAGc,EAAAA,mBAAmB,CAAC,CAAC,iBAAiB,EACxG,EAAU,KAAwBd,EAAAA,iBAAiB,gBAAgB,CAAC,CAAC,GAAGe,EAAAA,sBAAsB,CAAC,CAAC,iBAAiB,EACjH,EAAU,KAAkBf,EAAAA,iBAAiB,UAAU,CAAC,CAAC,GAAGgB,EAAAA,kBAAkB,CAAC,CAAC,iBAAiB,EACjG,EAAU,KAAqBhB,EAAAA,iBAAiB,aAAa,CAAC,CAAC,GAAGiB,EAAAA,cAAc,CAAC,CAAC,iBAAiB,EACnG,EAAU,KAA0BjB,EAAAA,iBAAiB,iBAAiB,CAAC,CAAC,GAAGkB,EAAAA,iBAAiB,CAAC,CAAC,iBAAiB,EAC/G,EACG,KAA0BlB,EAAAA,iBAAiB,oBAAoB,CAAC,CAChE,GAAGmB,EAAAA,oBAAoB,CAAC,CACxB,iBAAiB,EACpB,EAAU,KAA0BnB,EAAAA,iBAAiB,iBAAiB,CAAC,CAAC,GAAGoB,EAAAA,iBAAiB,CAAC,CAAC,iBAAiB,EAC/G,EAAU,KAA2BpB,EAAAA,iBAAiB,mBAAmB,CAAC,CAAC,GAAGqB,EAAAA,mBAAmB,CAAC,CAAC,iBAAiB,EACpH,EACG,KAA8BrB,EAAAA,iBAAiB,iBAAiB,CAAC,CACjE,GAAGsB,EAAAA,4BAA4B,CAAC,CAChC,iBAAiB,EACb,CACT,CASA,SAAgB,EAAe,EAAkB,EAAiC,CAAC,EAAS,CAC1F,IAAM,EAAY,EAAQ,WAAa,EAAqB,EACtD,EAAa,EAAU,IAA6BtB,EAAAA,iBAAiB,iBAAiB,EACtF,EAAU,EAAU,IAAwBD,EAAAA,kBAAkB,aAAa,EAC3E,EAAS,EAAQ,QAAU,CAAE,WAAc,IAAA,GAAW,YAAe,IAAA,EAAU,EAC/E,EAAO,EAAQ,MAAQ,CAAE,WAAc,IAAA,GAAW,YAAe,IAAA,EAAU,EAC7E,EACA,EACA,EACA,EACA,EAAkB,GAChB,EAAkB,GAA2B,CAC7C,IAAY,IAChB,EAAkB,EAClB,EAAK,OAAO,EAAU,CAAE,MAAO,QAAiB,MAAO,QAAgB,EAAI,IAAA,EAAS,EACtF,EACM,EAAiB,IAAIyB,EAAAA,iCAAiC,CAC1D,eAAkB,CAChB,IAAM,EAAO,QAAQ,IAAI,iBAAmB,QAAQ,IAAI,EAClD,EAAS,EAAQ,KAAK,CAAI,CAAC,CAAC,MAClC,GAAI,CAAC,EAAQ,MAAU,MAAM,wDAAwD,EACrF,OAAA,EAAO5B,EAAAA,mBAAAA,CAAmB,CAAM,CAClC,EACA,aAAc,KAAO,IAAc,CACjC,GAAI,CAAC,EAAe,MAAU,MAAM,uCAAuC,EAC3E,OAAO,EAAiC,EAAW,CAAa,CAClE,EACA,IAAK,EAAU,IAAiBI,EAAAA,iBAAiB,UAAU,EAC3D,MAAO,EAAU,IAAYA,EAAAA,iBAAiB,KAAK,EACnD,QAAU,GAAS,CACjB,GAAI,CAAC,EAAe,MAAU,MAAM,uCAAuC,EAC3E,EAAwB,EAAI,EAAe,CAAI,CACjD,EACA,gBAAmB,EAAW,MAC9B,wBAA0B,GAAU,EAAe,IAAU,QAAQ,EACrE,GAAI,EAAQ,kBAAoB,CAAE,cAAe,EAAQ,iBAAkB,EAAI,CAAC,CAClF,CAAC,EAED,EAAG,gBAAgB,EAAc,CAC/B,YAAa,iDACb,QAAS,MAAO,EAAO,IAAQ,CACxB,KAAI,MAET,IADA,EAAS,EAAc,EAAK,CAAM,EAC9B,EAAe,QAAU,WAAY,CACvC,EAAO,OAAO,qDAAsD,CAAiB,EACrF,MACF,CACA,MAAM,EAAW,OAAO,CAAM,CAD9B,CAEF,CACF,CAAC,EACD,EAAG,gBAAgB,EAAmB,CACpC,YAAa,kDACb,QAAS,MAAO,EAAO,IAAQ,CACxB,EAAI,QACT,EAAgB,EAChB,EAAa,EAAoB,EAAK,CAAM,EAC5C,MAAM,EAAe,OAAO,CAAU,EACxC,CACF,CAAC,EACD,EAAG,GAAG,gBAAiB,MAAO,EAAQ,IAAQ,CAC5C,EAAgB,EAChB,IAA2B,EAC3B,IAAM,EAAa,EAA2C,gBAAgB,aAAa,EAC3F,EAA2B,EACvB,EAAgC,EAAG,OAAQ,EAAW,CAAc,EACpE,IAAA,GACC,EAAI,QACT,EAAS,EAAc,EAAK,CAAM,EAClC,EAAa,EAAoB,EAAK,CAAM,EAC5C,EAAO,aAAa,IAAA,EAAS,EAC7B,EAAO,UAAU,EAAY,IAAA,EAAS,EACtC,EAAkB,GAClB,EAAK,OAAO,IAAA,EAAS,EACvB,CAAC,EACD,EAAmC,EAAI,CAAc,EACrD,EAAG,GAAG,mBAAoB,SAAY,CACpC,IAAM,EAAK,EACL,EAAS,EACf,EAAS,IAAA,GACT,EAAa,IAAA,GACb,EAAgB,IAAA,GAChB,IAA2B,EAC3B,EAA2B,IAAA,GAC3B,MAAM,EAAe,SAAS,CAAM,EACpC,MAAM,EAAW,SAAS,CAAE,EAC5B,EAAO,QAAQ,EACf,EAAK,QAAQ,CACf,CAAC,CACH"}
|
|
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","VOICE_FACADE_TOOL_NAMES","registerVoiceToolFacades","createVoiceMinorModeCatalog","registerVoiceToolContribution","createMinorModeVoiceTool","VoiceWorkerAutoCaptureController","collectVoiceCommandContext","registerMinorModeOwner","createVoiceToolHost","consumeVoiceReloadHandoff"],"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 { DoomExtensionHost } from '@agimon-ai/doompi-extension-contracts/config';\nimport type { LeaderBinding } from '@agimon-ai/doompi-extension-contracts/leader';\nimport {\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 {\n consumeVoiceReloadHandoff,\n createVoiceToolHost,\n registerVoiceToolContribution,\n VOICE_FACADE_TOOL_NAMES,\n type VoiceToolHostHandle,\n type VoiceToolSessionHandle,\n} from '@agimon-ai/doompi-extension-contracts/voice-tools';\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 type { AutonomousTurnNonceFactory } from '../../services/voice/autonomousTurn.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 { createMinorModeVoiceTool, createVoiceMinorModeCatalog } from './minorModeCatalog.ts';\nimport { collectVoiceCommandContext } from './voiceCommandContext.ts';\nimport { registerVoiceToolFacades } from './voiceTools.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 reconcileVoiceFacadeTools(pi: ExtensionAPI, enabled: boolean): void {\n const activeTools = pi.getActiveTools();\n const facadeNames = new Set<string>(VOICE_FACADE_TOOL_NAMES);\n const registeredNames = new Set(pi.getAllTools().map((tool) => tool.name));\n const nextTools = activeTools.filter((name) => !facadeNames.has(name));\n if (enabled && VOICE_FACADE_TOOL_NAMES.every((name) => registeredNames.has(name))) {\n nextTools.push(...VOICE_FACADE_TOOL_NAMES);\n }\n if (nextTools.length !== activeTools.length || nextTools.some((name, index) => name !== activeTools[index])) {\n pi.setActiveTools(nextTools);\n }\n}\n\nexport interface VoiceExtensionOptions {\n footer?: VoiceFooterContributionHandle;\n container?: Container;\n autoClientFactory?: VoiceWorkerSessionClientFactory;\n identityNonceFactory?: AutonomousTurnNonceFactory;\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 let voiceToolHost: VoiceToolHostHandle<ExtensionContext> | undefined;\n let voiceToolSession: VoiceToolSessionHandle<ExtensionContext> | undefined;\n const voiceToolFacades =\n typeof pi.registerTool === 'function' ? registerVoiceToolFacades(pi, () => voiceToolSession) : undefined;\n const modeCatalog = createVoiceMinorModeCatalog(pi);\n const modeToolContribution = registerVoiceToolContribution<ExtensionContext>(\n pi as unknown as DoomExtensionHost<ExtensionContext>,\n createMinorModeVoiceTool(modeCatalog),\n );\n let mode: Pick<MinorModeOwnerHandle, 'publish' | 'dispose'> | undefined;\n const reconcileVoiceTools = (state: AutoCaptureActivationState): void => {\n const contextSessionId = (\n activeContext as unknown as VoiceSessionContextLike | undefined\n )?.sessionManager?.getSessionId();\n const enabled =\n state === 'active' &&\n activeContext?.hasUI === true &&\n voiceToolSession !== undefined &&\n contextSessionId === voiceToolSession.sessionId;\n voiceToolSession?.setActive(enabled);\n reconcileVoiceFacadeTools(pi, enabled);\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 commandContext: () =>\n activeContext\n ? collectVoiceCommandContext(activeContext.sessionManager.getBranch(), modeCatalog.records())\n : undefined,\n onActivationStateChange: (state) => {\n reconcileVoiceTools(state);\n voiceToolFacades?.refresh();\n mode?.publish(voiceModeState(state, activeContext?.hasUI === true));\n },\n ...(options.autoClientFactory ? { clientFactory: options.autoClientFactory } : {}),\n ...(options.identityNonceFactory ? { identityNonceFactory: options.identityNonceFactory } : {}),\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 const reason = (event as { reason?: string }).reason;\n if (autoController.state !== 'disabled') {\n await autoController.deactivate(lastAutoUi ?? createAutoCaptureUi(ctx, footer));\n }\n activeContext = ctx;\n lastUi = undefined;\n lastAutoUi = undefined;\n disposeNarrationRequests?.();\n disposeNarrationRequests = undefined;\n\n voiceToolSession?.setActive(false);\n voiceToolSession?.dispose();\n voiceToolSession = undefined;\n voiceToolFacades?.bind(undefined);\n voiceToolHost?.dispose();\n voiceToolHost = createVoiceToolHost<ExtensionContext>();\n\n const sessionId = (ctx as unknown as VoiceSessionContextLike).sessionManager?.getSessionId();\n let reloadHandoff = false;\n if (sessionId) {\n try {\n voiceToolSession = voiceToolHost.bindSession(sessionId, ctx);\n voiceToolFacades?.bind(voiceToolSession);\n reloadHandoff = reason === 'reload' && consumeVoiceReloadHandoff(sessionId) !== undefined;\n } catch (error) {\n voiceToolHost.dispose();\n voiceToolHost = undefined;\n const message = error instanceof Error ? error.message : String(error);\n if (ctx.hasUI) ctx.ui.notify(`Voice capability host unavailable: ${message}`, ERROR_NOTIFICATION);\n }\n modeCatalog.bind(sessionId);\n disposeNarrationRequests = registerNarrationRequestHandler(pi.events, sessionId, autoController);\n }\n reconcileVoiceTools('disabled');\n voiceToolFacades?.refresh();\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 if (reloadHandoff && lastAutoUi) await autoController.activate(lastAutoUi);\n });\n pi.on('before_agent_start', (_event, ctx) => {\n activeContext = ctx;\n reconcileVoiceTools(autoController.state);\n voiceToolFacades?.refresh();\n });\n registerAutoCapturePiEventHandlers(pi, autoController);\n pi.on('session_shutdown', async () => {\n const ui = lastUi;\n const autoUi = lastAutoUi;\n reconcileVoiceTools('disabled');\n voiceToolSession?.setActive(false);\n voiceToolSession?.dispose();\n voiceToolSession = undefined;\n voiceToolFacades?.bind(undefined);\n voiceToolFacades?.dispose();\n voiceToolHost?.dispose();\n voiceToolHost = undefined;\n lastUi = undefined;\n lastAutoUi = undefined;\n activeContext = undefined;\n disposeNarrationRequests?.();\n disposeNarrationRequests = undefined;\n modeToolContribution.dispose();\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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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AutoCaptureIndicatorState, IAudioAnalyzer, IAudioRecorder, IClock, ITemporaryWorkspace, ITranscriberRegistry, IVoiceSessionController, VoiceActivityUpdate, VoiceState, VoiceUi } from "../../types/index.cjs";
|
|
2
2
|
import { AutoCaptureModelContracts } from "../../services/voice/autoCapture.cjs";
|
|
3
|
+
import { AutonomousTurnNonceFactory } from "../../services/voice/autonomousTurn.cjs";
|
|
3
4
|
import { VoiceWorkerSessionClientFactory } from "../process/voiceWorkerSessionController.cjs";
|
|
4
5
|
import { VoiceWorkerAutoCaptureController } from "../process/voiceWorkerAutoCaptureController.cjs";
|
|
5
6
|
import { MlxWhisperAdapter, OpenAiWhisperAdapter, TranscriberRegistry, WhisperCppAdapter } from "../transcription/whisper.cjs";
|
|
@@ -25,15 +26,6 @@ interface VoiceFooterContributionHandle {
|
|
|
25
26
|
update(value: VoiceFooterContributionValue | undefined): void;
|
|
26
27
|
dispose(): void;
|
|
27
28
|
}
|
|
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
29
|
declare const VOICE_LEADER_BINDINGS: readonly LeaderBinding[];
|
|
38
30
|
interface VoiceActivityPresentation {
|
|
39
31
|
statusText: string;
|
|
@@ -110,11 +102,11 @@ declare function createVoiceModule(): ContainerModule;
|
|
|
110
102
|
declare function createVoiceContainer(): Container;
|
|
111
103
|
interface VoiceExtensionOptions {
|
|
112
104
|
footer?: VoiceFooterContributionHandle;
|
|
113
|
-
mode?: VoiceModeContributionHandle;
|
|
114
105
|
container?: Container;
|
|
115
106
|
autoClientFactory?: VoiceWorkerSessionClientFactory;
|
|
107
|
+
identityNonceFactory?: AutonomousTurnNonceFactory;
|
|
116
108
|
}
|
|
117
109
|
declare function voiceExtension(pi: ExtensionAPI, options?: VoiceExtensionOptions): void;
|
|
118
110
|
//#endregion
|
|
119
|
-
export { AutoCaptureActivityPresentation, AutoCaptureDeliveryIntent, AutoCapturePiEventController, MlxWhisperAdapter, OpenAiWhisperAdapter, PiVoiceConfigService, TranscriberRegistry, VOICE_LEADER_BINDINGS, VoiceActivityPresentation, VoiceExtensionOptions, VoiceFooterContributionHandle, VoiceFooterContributionValue,
|
|
111
|
+
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
112
|
//# sourceMappingURL=voice.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice.d.cts","names":[],"sources":["../../../src/adapters/pi/voice.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"voice.d.cts","names":[],"sources":["../../../src/adapters/pi/voice.ts"],"mappings":";;;;;;;;;;;;UAiLiB;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;UA0CvB;EACf,SAAS;EACT,YAAY;EACZ,oBAAoB;EACpB,uBAAuB;;iBAGT,eAAe,IAAI,cAAc,UAAS"}
|