@agimon-ai/po-voice 0.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +13 -0
  3. package/README.md +249 -0
  4. package/dist/apiContracts.cjs +809 -0
  5. package/dist/apiContracts.cjs.map +1 -0
  6. package/dist/apiContracts.d.mts +53 -0
  7. package/dist/apiContracts.d.mts.map +1 -0
  8. package/dist/apiContracts.mjs +805 -0
  9. package/dist/apiContracts.mjs.map +1 -0
  10. package/dist/assets/browserCaptureWorklet-Droj0fW0.js +13 -0
  11. package/dist/assets/silero_vad_v6.2.1-SjbCxFXk.onnx +0 -0
  12. package/dist/clientCaptureActivity-DN4xQtmw.d.mts +234 -0
  13. package/dist/clientCaptureActivity-DN4xQtmw.d.mts.map +1 -0
  14. package/dist/clientMedia-CfTfc9_4.mjs +49 -0
  15. package/dist/clientMedia-CfTfc9_4.mjs.map +1 -0
  16. package/dist/clientMedia-DuA4aYhD.cjs +156 -0
  17. package/dist/clientMedia-DuA4aYhD.cjs.map +1 -0
  18. package/dist/clientMedia.cjs +134 -0
  19. package/dist/clientMedia.cjs.map +1 -0
  20. package/dist/clientMedia.d.mts +2 -0
  21. package/dist/clientMedia.mjs +114 -0
  22. package/dist/clientMedia.mjs.map +1 -0
  23. package/dist/extensions/server.cjs +8975 -0
  24. package/dist/extensions/server.cjs.map +1 -0
  25. package/dist/extensions/server.d.mts +5 -0
  26. package/dist/extensions/server.d.mts.map +1 -0
  27. package/dist/extensions/server.mjs +8968 -0
  28. package/dist/extensions/server.mjs.map +1 -0
  29. package/dist/extensions/web.mjs +4530 -0
  30. package/dist/extensions/web.mjs.map +1 -0
  31. package/dist/index-C95HCjmT.d.mts +212 -0
  32. package/dist/index-C95HCjmT.d.mts.map +1 -0
  33. package/dist/index.cjs +637 -0
  34. package/dist/index.cjs.map +1 -0
  35. package/dist/index.d.mts +603 -0
  36. package/dist/index.d.mts.map +1 -0
  37. package/dist/index.mjs +557 -0
  38. package/dist/index.mjs.map +1 -0
  39. package/dist/narrationBargeIn-C_Po8fgw.mjs +62 -0
  40. package/dist/narrationBargeIn-C_Po8fgw.mjs.map +1 -0
  41. package/dist/narrationBargeIn-Dje82XOm.cjs +73 -0
  42. package/dist/narrationBargeIn-Dje82XOm.cjs.map +1 -0
  43. package/dist/sileroVadWorker-D894njUe.mjs +110 -0
  44. package/dist/sileroVadWorker-D894njUe.mjs.map +1 -0
  45. package/dist/vad-DDe4RIdW.mjs +315 -0
  46. package/dist/vad-DDe4RIdW.mjs.map +1 -0
  47. package/dist/vad-n2RlruzB.cjs +332 -0
  48. package/dist/vad-n2RlruzB.cjs.map +1 -0
  49. package/dist/voiceReloadHandoff.cjs +9 -0
  50. package/dist/voiceReloadHandoff.d.mts +1 -0
  51. package/dist/voiceReloadHandoff.mjs +2 -0
  52. package/dist/voiceTools-CRQHK_Uc.cjs +616 -0
  53. package/dist/voiceTools-CRQHK_Uc.cjs.map +1 -0
  54. package/dist/voiceTools-aCCREMjS.mjs +611 -0
  55. package/dist/voiceTools-aCCREMjS.mjs.map +1 -0
  56. package/dist/voiceTools.cjs +12 -0
  57. package/dist/voiceTools.d.mts +7 -0
  58. package/dist/voiceTools.d.mts.map +1 -0
  59. package/dist/voiceTools.mjs +3 -0
  60. package/dist/voiceWorker.cjs +1929 -0
  61. package/dist/voiceWorker.cjs.map +1 -0
  62. package/dist/voiceWorker.d.mts +200 -0
  63. package/dist/voiceWorker.d.mts.map +1 -0
  64. package/dist/voiceWorker.mjs +1925 -0
  65. package/dist/voiceWorker.mjs.map +1 -0
  66. package/dist/voiceWorkerProtocol-0H3czPjt.cjs +2385 -0
  67. package/dist/voiceWorkerProtocol-0H3czPjt.cjs.map +1 -0
  68. package/dist/voiceWorkerProtocol-B_4B2_fR.mjs +2085 -0
  69. package/dist/voiceWorkerProtocol-B_4B2_fR.mjs.map +1 -0
  70. package/dist/voiceWorkerSessionController-DaYemiL3.cjs +1800 -0
  71. package/dist/voiceWorkerSessionController-DaYemiL3.cjs.map +1 -0
  72. package/dist/voiceWorkerSessionController-GB3SJ6YE.mjs +1734 -0
  73. package/dist/voiceWorkerSessionController-GB3SJ6YE.mjs.map +1 -0
  74. package/licenses/Codex-Apache-2.0.txt +201 -0
  75. package/llms.txt +9 -0
  76. package/package.json +153 -0
  77. package/src/extensions/workspaces/sessions/(frontend)/lifecycle/_lib/models/README.md +11 -0
  78. package/src/extensions/workspaces/sessions/(frontend)/lifecycle/_lib/models/SILERO-LICENSE +21 -0
  79. package/src/prompts/po-use-voice/SKILL.md +35 -0
  80. package/src/types/clientCaptureActivity.ts +155 -0
  81. package/src/types/clientMedia.ts +226 -0
  82. package/src/types/manualTranscription.ts +53 -0
  83. package/src/types/realtime.ts +107 -0
  84. package/src/types/voiceOwnership.ts +315 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vuong Ngo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,13 @@
1
+ This package includes portions adapted from OpenAI Codex.
2
+ Copyright 2025 OpenAI
3
+ https://github.com/openai/codex
4
+ Source revision: 5ecb3afd1b
5
+
6
+ Adapted files:
7
+ - src/services/codexAuth/index.ts, src/services/codexLogin/index.ts, and src/services/codexAuthStorage/index.ts: subscription login, credential storage, and refresh
8
+ - src/services/codexRealtime/index.ts: realtime call creation
9
+ - src/services/realtimeProtocol.ts: Frameless realtime events and context messages
10
+
11
+ These portions were modified for Po and are licensed under Apache-2.0.
12
+ A copy is included in licenses/Codex-Apache-2.0.txt.
13
+ The package's MIT license continues to apply to its original code.
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ # @agimon-ai/po-voice
2
+
3
+ ## Server and browser configuration
4
+
5
+ The web Settings page includes Voice under global and workspace settings. It uses the shared
6
+ config API, including file hashes, atomic saves, numeric values, and scope validation. `voice.mode` and `voice.autoCapture`
7
+ remain global settings. Browser input selection is separate from the host ffmpeg
8
+ `voice.recorder.device` option.
9
+
10
+ The composer Voice button records on whatever input the browser is already using; there is no
11
+ device picker. Autonomous voice asks which input to open only when the browser reports more than
12
+ one, and remembers the answer in that browser's local storage until the set of inputs changes.
13
+ Dismissing that dialog uses the browser's own default input. Each tab keeps its own media
14
+ connection lease. Manual dictation appends to the draft until Send.
15
+
16
+ Voice owns these authenticated server endpoints:
17
+
18
+ | Mount | Endpoint | Purpose |
19
+ | --------------------------------------- | ---------------- | -------------------------------------------------------- |
20
+ | `/api/plugins/voice` | `GET /readiness` | Check configuration and local transcription dependencies |
21
+ | `/api/sessions/:sessionId/plugin/voice` | `GET /status` | Read lifecycle and media readiness |
22
+ | same | `POST /control` | Send `{action, target?}` |
23
+
24
+ Control actions are `status`, `manual`, `activate`, `deactivate`, `mute`, `unmute`, `interrupt`,
25
+ and `transfer` (with a target catalog order and its catalog revision). The typed session method `voice.control` uses the
26
+ same operations as commands and minor-mode actions. Browser recording uploads continue to use
27
+ `/api/sessions/:sessionId/plugin/voice-media/manual/transcribe`.
28
+
29
+ The native server composes Voice controllers with one session media broker. Workers receive PCM
30
+ on a dedicated media port. No terminal editor or Pi ExtensionContext is emulated. Live voice
31
+ still requires its separate subscription credentials; a successful local readiness check does
32
+ not verify a live provider connection.
33
+
34
+ Capture speech on the client, transcribe it on the host, and play responses through Po Voice mode.
35
+
36
+ Part of the [Po distribution](https://www.npmjs.com/package/@agimon-ai/po).
37
+
38
+ Voice can transcribe one recording or keep the currently active session listening. It also gives
39
+ the primary agent a bounded `narrate` tool and accepts narration requests from other extensions.
40
+
41
+ > **Alpha:** Voice state, tool, and platform support may change between releases.
42
+
43
+ ## Realtime companion
44
+
45
+ Realtime is an optional conversational interface, not a replacement for the primary Pi
46
+ agent or for half-duplex Voice. Pi keeps its selected model, reasoning, tools, approvals,
47
+ Team and Workflow. The companion handles speech and forwards fresh action requests to Pi;
48
+ it does not execute tools or launch a second coding agent.
49
+
50
+ The experimental live path connects browser WebRTC, Po-owned subscription login,
51
+ the exclusive media lease, bounded session context, and main-agent requests/results.
52
+ Subscription connectivity and a synthetic echo roundtrip have been exercised. Physical
53
+ playback, echo safety, interruption recovery and microphone usability remain **unqualified**.
54
+
55
+ For a separately approved trial:
56
+
57
+ 1. Select `voice.mode: live` in global configuration. Repository configuration cannot enable it.
58
+ 2. Run `/voice-auto login` and open the displayed URL on the Po host. Credentials stay
59
+ in Po's private `voice/subscription-auth` directory beside its global configuration,
60
+ separate from Codex and Pi OAuth. `/voice-auto login-cancel` cancels the attempt.
61
+ 3. With separate provider and microphone consent, explicitly activate Voice with a connected
62
+ WebRTC-capable browser. Selecting live or signing in does not activate capture.
63
+ 4. Use browser controls or `/voice-auto mute`, `unmute`, `interrupt`, and `end`.
64
+
65
+ Pi's settled final text is returned as a correlated companion result, separately from the
66
+ initial submission acknowledgement. Later Pi turns, including turns responding to Team or
67
+ Workflow completion, can supply speakable session updates without another voice request.
68
+ Responses exceeding the bounded result limit stay in the Pi session; Voice reports that it
69
+ cannot summarize contents it did not transmit. Thinking and raw tool output are not forwarded.
70
+
71
+ Interruption suppresses output for the remainder of that activation; explicitly end and
72
+ reactivate Voice to hear replies again. It does not cancel main-agent work. Exact primary-agent
73
+ `narrate` and its TTS fallback are not enabled in live mode. Voice-only approval answers remain
74
+ unavailable. Reconnect and reload do not resume microphone transmission.
75
+
76
+ Omit `voice.mode` or select the compatibility value `legacy` for the existing half-duplex
77
+ Voice path. It remains a supported interaction choice. Live capture does not require local
78
+ ASR; the local transcription requirements below apply to half-duplex and manual Voice.
79
+ No API-key fallback is provided if subscription access fails.
80
+
81
+ See [ARCHITECTURE.md](docs/ARCHITECTURE.md#realtime-port-foundations) for the current boundary.
82
+ Upstream port attribution is in `NOTICE` and `licenses/Codex-Apache-2.0.txt`.
83
+
84
+ ## Requirements
85
+
86
+ - Node.js 24 or newer
87
+ - A browser with microphone capture and speech synthesis when using `po-web`
88
+ - One supported local transcription engine: `whisper-cli`, `whisper`, or `mlx_whisper` (Apple
89
+ silicon only)
90
+ - Microphone permission on the client device
91
+
92
+ ## Install
93
+
94
+ The seeded `modes.yaml` selects Voice in `default.packages`. Keep it there or select it through a
95
+ layer; Voice is not fixed host infrastructure.
96
+
97
+ ## Configure
98
+
99
+ A complete `~/.po/config.yaml` example using Python Whisper is:
100
+
101
+ ```yaml
102
+ voice:
103
+ engine: openai-whisper
104
+ language: auto
105
+ recorder:
106
+ device: default
107
+ adapters:
108
+ openai-whisper:
109
+ binary: whisper
110
+ model:
111
+ id: base
112
+ autoCapture:
113
+ model: provider/model-id
114
+ startPhrases: []
115
+ stopPhrases: []
116
+ composeOpenPhrases: [hey doom]
117
+ composeSendPhrases: ["that's it"]
118
+ composeCancelPhrases: [scratch that]
119
+ utteranceIdleMs: 3000
120
+ composeUtteranceIdleMs: 1200
121
+ composeNudgeMs: 10000
122
+ transcriptionTimeoutMs: 120000
123
+ tts:
124
+ engine: macos-say
125
+ voice: Samantha
126
+ rate: 190
127
+ ```
128
+
129
+ Replace `provider/model-id` with a model configured in Pi, or omit `autoCapture` when only manual
130
+ transcription is required. Use the `whisper-cpp` engine for `whisper-cli`, `openai-whisper` for
131
+ `whisper`, or `mlx-whisper` for `mlx_whisper`. `utteranceIdleMs` accepts 1,500 to 10,000 ms and
132
+ defaults to 3,000.
133
+
134
+ A profile can give its persona its own voice. Front-matter in the persona's `profile.md` shadows
135
+ `autoCapture.tts` per field, so a persona setting only `rate` keeps the voice configured here:
136
+
137
+ ```markdown
138
+ ---
139
+ name: Rhea
140
+ voice:
141
+ voice: Karen
142
+ rate: 175
143
+ ---
144
+ ```
145
+
146
+ The `engine` is never overridable, because it selects the synthesiser rather than the persona. The
147
+ spoken voice is read when autonomous voice activates, so a profile switch applies it through the
148
+ reload that switch already performs.
149
+
150
+ Autonomous voice can also change profile. The `profile` capability on the voice tool facade lists
151
+ the configured personas and queues a switch, which reloads the session with the new persona, its
152
+ voice, and its avatar. See
153
+ [@agimon-ai/po-profile](../../foundations/po-profile/README.md) for authoring personas.
154
+
155
+ When the agent is launched by `po-server`, capture and narration use the connected media client.
156
+ The protocol is capability-driven rather than browser-specific. A client can own microphone capture,
157
+ adaptive activity detection, endpoint decisions, autonomous capture phases, and playback while streaming
158
+ mono 16 kHz PCM16 through the authenticated session media API. The host supplies capabilities the client
159
+ does not advertise and remains responsible for durable spooling, configured transcription, and Pi or
160
+ model actions. This boundary supports terminal, web, React Native, and future watch adapters without
161
+ putting platform APIs in the shared client runtime.
162
+
163
+ A browser using the sealed remote-control channel takes the session media lease from a local client, so
164
+ narration and capture follow the user to the remote device. Local clients cannot take that lease back
165
+ while the remote client remains connected. In the browser, `tts.voice` selects an exact
166
+ SpeechSynthesis voice name or URI. If it does not match, the browser uses its default voice. Portable
167
+ clients implement the declared ports through `@agimon-ai/po-voice/client-media`. Browser media ownership is page-global rather than tied to the focused cockpit route, so switching sessions does not disconnect an autonomous capture owned by another session.
168
+
169
+ For server-streamed narration, the browser uses the exact 16 kHz PCM as a local echo reference while uploading microphone PCM unchanged. A bounded discriminator filters only the local Silero input and reports cumulative trusted speech duration, never reference audio, residual audio, transcript, correlation, or gain. Natural address-free interruption requires 300 ms of trusted residual speech plus semantic novelty. Missing or uncertain alignment, failed local Silero, unsupported clients, and browser SpeechSynthesis all fail closed to the existing intentional-address or exact-stop behavior. The 800 ms echo tail remains active. Acoustic thresholds are provisional until physical speaker-to-microphone qualification passes.
170
+
171
+ ## Commands and tools
172
+
173
+ - `/voice-auto mute` pauses microphone capture without disabling narration; `/voice-auto unmute` resumes capture.
174
+ - While autonomous capture is active, say `hey doom` at the beginning of a segment to open a long composed prompt. Later finalized segments are buffered until `that's it` submits the combined text or `scratch that` discards it in the example configuration.
175
+ - `describe_voice_tools` returns the active session's spoken capability catalog.
176
+ - `use_voice_tools` executes a bounded ordered batch against that catalog.
177
+ - `narrate` speaks one primary-agent-authored utterance and waits for physical playback.
178
+
179
+ Composition is for long spoken prompts, so a multi-part prompt is not submitted half-written. A short utterance needs no phrase and is delivered as soon as it finalizes.
180
+
181
+ Each configured phrase array replaces its defaults rather than extending them. The example above keeps only one phrase per set, so it does not recognize `doom prompt`, `doom send`, or `doom cancel` as composition commands. Omit the arrays to use all defaults:
182
+
183
+ `composeOpenPhrases` is `hey doom, doom prompt`, `composeSendPhrases` is `that's it, doom send`, and `composeCancelPhrases` is `doom cancel, scratch that`. Matching ignores case, punctuation and apostrophes, and tolerates small transcription differences, so `thats it` and `doom sent` are recognised. Send and cancel act as commands only while a draft is open, and only when the phrase is the whole segment or ends a sentence, so ordinary dictation containing those words stays content. While a draft collects, the endpoint window shortens to `composeUtteranceIdleMs` (default 1,200 ms) so a short command finalizes as its own turn. A composed prompt is queued as a Pi follow-up while Pi is busy.
184
+
185
+ Drafts are held in memory for the active autonomous session and are limited to 32,768 characters. Worker restarts and five-minute idle capture rotation preserve the draft, but deactivation, extension reload, and process restart discard it. Wait until the status returns to `composing, listening` before speaking the next segment because capture pauses during transcription.
186
+
187
+ Before a final response, narration contains the complete answer, including every user-relevant
188
+ conclusion, question, warning, result, and next action in the written response. It does not use
189
+ a shorter spoken summary that leaves essential information only in text. Each narration is
190
+ limited to 4,096 characters and returns `completed`, `interrupted`, `superseded`, or `failed`.
191
+ Once confirmed user speech begins, new narration waits in memory until that turn is synchronously delivered to Pi. Multiple waiting requests use the configured `autoCapture.model` to become one bounded spoken update, with one bounded deterministic utterance if compaction fails. Narration that was already playing is not stopped by this queue gate; the existing ranked barge-in policy remains responsible for interruption.
192
+ Narration fails closed while Voice is starting or draining, during shutdown, reload, or
193
+ deactivation, and when the request belongs to a stale session.
194
+ Paired-host targets are discovered through authenticated Voice grants and appear in the same revision-bound transfer catalog. A handoff prepares the target, releases the source, activates the target, and waits for usable media readiness. It does not transfer agent context, transcripts, pending work, or buffered source audio.
195
+
196
+ If no `narrate` attempt is made before a final response, the active Voice session can produce one
197
+ bounded fallback utterance. Short final responses use deterministic text; longer ones may use
198
+ `autoCapture.model` for one bounded summary and fall back to a deterministic excerpt on failure.
199
+ These optional model calls consume provider quota.
200
+
201
+ ## Data flow and recovery
202
+
203
+ The selected client captures audio. When it advertises client orchestration, its portable PCM state
204
+ machine performs activity detection and endpointing, then sends phase metadata with the streamed audio.
205
+ Clients without those capabilities use host adaptive and neural VAD as a fallback. PCM validation,
206
+ spooling, WAV creation, normalization, and configured local Whisper execution run on the host in a
207
+ private supervised worker. Private spool directories use mode `0700` and files use `0600`.
208
+ Unacknowledged turns can be rediscovered after a worker restart.
209
+
210
+ This is not a blanket “nothing leaves the machine” guarantee:
211
+
212
+ - Client PCM crosses the authenticated cockpit transport, is queued transiently in memory, and is
213
+ persisted only in the host worker's private spool.
214
+ - Transcript candidates and bounded state strings cross the worker/process boundary.
215
+ - Command correction and long-final fallback text can be sent to the configured model provider.
216
+ - Telemetry may contain bounded operational metadata; review its sink configuration.
217
+
218
+ Manual recordings and autonomous spool windows are bounded to five minutes. Deactivation or
219
+ cancellation interrupts pending capture and playback. A manual reload does not silently reactivate
220
+ the microphone.
221
+
222
+ ## Architecture
223
+
224
+ See [Architecture](./docs/ARCHITECTURE.md) for the thread and process topology, the path a single spoken turn takes, the XState lifecycle and how it relates to Pi, the module and cordis service graph, and narration gating and barge-in. [SPEC.md](./docs/SPEC.md) is the normative contract.
225
+
226
+ ## Public API
227
+
228
+ The root exports audio infrastructure, PCM, VAD, and utterance services, narration and playback
229
+ contracts, command correction, fallback narration, and Voice types. Host adapters should import only declared package exports:
230
+
231
+ | Export | Purpose |
232
+ | ---------------------------------- | --------------------------------------------------------------------- |
233
+ | `@agimon-ai/po-voice` | Host audio adapters, narration, PCM, VAD, correction, and Voice types |
234
+ | `@agimon-ai/po-voice/client-media` | Client capture activity and media contracts |
235
+
236
+ ## Development
237
+
238
+ ```bash
239
+ pnpm build
240
+ pnpm typecheck
241
+ pnpm test
242
+ pnpm lint
243
+ ```
244
+
245
+ Maintained by [Agimon](https://agimon.ai/about).
246
+
247
+ ## License
248
+
249
+ MIT