pi-ui-extend 1.0.42 → 1.0.46

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 (233) hide show
  1. package/README.md +41 -12
  2. package/dist/app/app.d.ts +10 -0
  3. package/dist/app/app.js +132 -8
  4. package/dist/app/cli/install.js +2 -2
  5. package/dist/app/commands/command-controller.d.ts +4 -0
  6. package/dist/app/commands/command-controller.js +11 -0
  7. package/dist/app/commands/command-git-actions.d.ts +25 -0
  8. package/dist/app/commands/command-git-actions.js +381 -0
  9. package/dist/app/commands/command-host.d.ts +3 -0
  10. package/dist/app/commands/command-host.js +5 -2
  11. package/dist/app/commands/command-model-actions.d.ts +1 -0
  12. package/dist/app/commands/command-model-actions.js +51 -34
  13. package/dist/app/commands/command-navigation-actions.d.ts +1 -0
  14. package/dist/app/commands/command-navigation-actions.js +16 -3
  15. package/dist/app/commands/command-registry.d.ts +2 -0
  16. package/dist/app/commands/command-registry.js +14 -0
  17. package/dist/app/commands/reload-context-inventory.js +12 -1
  18. package/dist/app/input/autocomplete-controller.js +61 -34
  19. package/dist/app/input/input-action-controller.d.ts +2 -0
  20. package/dist/app/input/input-action-controller.js +8 -1
  21. package/dist/app/input/input-controller.d.ts +2 -1
  22. package/dist/app/input/input-controller.js +7 -2
  23. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  24. package/dist/app/input/voice-controller.d.ts +41 -45
  25. package/dist/app/input/voice-controller.js +351 -419
  26. package/dist/app/model/model-usage-controller.js +17 -7
  27. package/dist/app/model/model-usage-status.d.ts +4 -1
  28. package/dist/app/model/model-usage-status.js +270 -46
  29. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  30. package/dist/app/popup/menu-items-controller.js +37 -21
  31. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  32. package/dist/app/popup/popup-action-controller.js +77 -24
  33. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  34. package/dist/app/popup/popup-menu-controller.js +239 -69
  35. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  36. package/dist/app/rendering/dcp-stats.js +40 -425
  37. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  38. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  39. package/dist/app/rendering/render-controller.js +23 -2
  40. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  41. package/dist/app/rendering/status-line-renderer.js +41 -5
  42. package/dist/app/rendering/tab-line-renderer.js +26 -20
  43. package/dist/app/runtime.d.ts +12 -1
  44. package/dist/app/runtime.js +120 -12
  45. package/dist/app/screen/mouse-controller.d.ts +2 -0
  46. package/dist/app/screen/mouse-controller.js +17 -7
  47. package/dist/app/screen/status-controller.d.ts +4 -0
  48. package/dist/app/screen/status-controller.js +5 -0
  49. package/dist/app/session/lazy-session-manager.js +34 -0
  50. package/dist/app/session/session-event-controller.d.ts +1 -0
  51. package/dist/app/session/session-event-controller.js +10 -1
  52. package/dist/app/session/session-history.d.ts +1 -0
  53. package/dist/app/session/session-history.js +12 -1
  54. package/dist/app/session/session-lifecycle-controller.d.ts +6 -1
  55. package/dist/app/session/session-lifecycle-controller.js +10 -1
  56. package/dist/app/session/tabs-controller.d.ts +25 -1
  57. package/dist/app/session/tabs-controller.js +442 -153
  58. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  59. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  60. package/dist/app/types.d.ts +11 -1
  61. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  62. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  63. package/dist/app/workspace/workspace-undo.js +1 -0
  64. package/dist/bundled-extensions/question/index.js +9 -1
  65. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  66. package/dist/bundled-extensions/question/remote.js +33 -0
  67. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  68. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  69. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  70. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  71. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  72. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  73. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  74. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  75. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  76. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  77. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  78. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  79. package/dist/config.d.ts +21 -2
  80. package/dist/config.js +159 -32
  81. package/dist/default-pix-config.js +20 -10
  82. package/dist/schemas/pi-tools-suite-schema.d.ts +8 -4
  83. package/dist/schemas/pi-tools-suite-schema.js +11 -5
  84. package/dist/schemas/pix-schema.d.ts +12 -2
  85. package/dist/schemas/pix-schema.js +37 -9
  86. package/dist/schemas/tasks-schema.js +1 -1
  87. package/docs/concurrency.md +3 -1
  88. package/docs/desktop-mvp.md +10 -5
  89. package/docs/desktop-task-manager.md +81 -28
  90. package/docs/release.md +30 -6
  91. package/external/pi-tools-suite/README.md +165 -39
  92. package/external/pi-tools-suite/docs/session-recovery.md +7 -0
  93. package/external/pi-tools-suite/docs/subagent-model-pools.md +12 -5
  94. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  95. package/external/pi-tools-suite/package.json +6 -1
  96. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  97. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  98. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  99. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  100. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  101. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  102. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  103. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  104. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  105. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  106. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  107. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  108. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  109. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  110. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  111. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  112. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  113. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  114. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  115. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  116. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  117. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  119. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  127. package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
  128. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  129. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +0 -2
  130. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  131. package/external/pi-tools-suite/src/async-subagents/core/config.ts +40 -17
  132. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  133. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  134. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +7 -4
  135. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +34 -24
  136. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  137. package/external/pi-tools-suite/src/async-subagents/lib.ts +9 -1
  138. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +0 -1
  139. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
  140. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  141. package/external/pi-tools-suite/src/config.ts +14 -0
  142. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  143. package/external/pi-tools-suite/src/context-gateway/config.ts +66 -1
  144. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  145. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +123 -3
  146. package/external/pi-tools-suite/src/context-gateway/index.ts +137 -4
  147. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +5 -5
  148. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +2 -2
  149. package/external/pi-tools-suite/src/context-gateway/types.ts +8 -1
  150. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  151. package/external/pi-tools-suite/src/dcp/auto-compress.ts +41 -14
  152. package/external/pi-tools-suite/src/dcp/commands.ts +14 -156
  153. package/external/pi-tools-suite/src/dcp/compress-tool.ts +8 -2
  154. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  155. package/external/pi-tools-suite/src/dcp/config.ts +58 -4
  156. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  157. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  158. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  159. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  160. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  161. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  162. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +92 -2
  163. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  164. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  165. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  166. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  167. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  168. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  169. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +68 -16
  170. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  171. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  172. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  173. package/external/pi-tools-suite/src/resource-registry/index.ts +282 -21
  174. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  175. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  176. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  177. package/external/pi-tools-suite/src/tool-descriptions.ts +44 -15
  178. package/package.json +9 -10
  179. package/schemas/pi-tools-suite.json +44 -12
  180. package/schemas/pix.json +109 -15
  181. package/schemas/tasks.json +1 -2
  182. package/skills/simplify/SKILL.md +33 -5
  183. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -196
  184. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  185. package/skills/playwright-cli/SKILL.md +0 -420
  186. package/skills/playwright-cli/references/element-attributes.md +0 -23
  187. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  188. package/skills/playwright-cli/references/request-mocking.md +0 -87
  189. package/skills/playwright-cli/references/running-code.md +0 -241
  190. package/skills/playwright-cli/references/session-management.md +0 -273
  191. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  192. package/skills/playwright-cli/references/storage-state.md +0 -290
  193. package/skills/playwright-cli/references/test-generation.md +0 -142
  194. package/skills/playwright-cli/references/tracing.md +0 -154
  195. package/skills/playwright-cli/references/video-recording.md +0 -147
  196. package/skills/spec-wiki/SKILL.md +0 -55
  197. package/skills/spec-wiki/evals/evals.json +0 -132
  198. package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +0 -14
  199. package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +0 -4
  200. package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +0 -9
  201. package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +0 -17
  202. package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +0 -12
  203. package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +0 -11
  204. package/skills/spec-wiki/evals/files/focused/src/session.ts +0 -5
  205. package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +0 -17
  206. package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +0 -2
  207. package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +0 -3
  208. package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +0 -18
  209. package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +0 -5
  210. package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +0 -24
  211. package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +0 -7
  212. package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +0 -7
  213. package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +0 -17
  214. package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +0 -3
  215. package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +0 -3
  216. package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +0 -4
  217. package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +0 -9
  218. package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +0 -15
  219. package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +0 -6
  220. package/skills/spec-wiki/evals/maintenance_regression.py +0 -311
  221. package/skills/spec-wiki/evals/retrieval-eval.md +0 -37
  222. package/skills/spec-wiki/evals/retrieval-evals.json +0 -37
  223. package/skills/spec-wiki/evals/trigger-evals.json +0 -94
  224. package/skills/spec-wiki/references/bootstrap.md +0 -100
  225. package/skills/spec-wiki/references/focused-spec.md +0 -117
  226. package/skills/spec-wiki/references/index-schema.md +0 -330
  227. package/skills/spec-wiki/references/maintenance.md +0 -134
  228. package/skills/spec-wiki/references/query.md +0 -74
  229. package/skills/spec-wiki/scripts/spec_wiki.py +0 -2076
  230. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  231. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  232. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
@@ -138,57 +138,84 @@ export class AppAutocompleteController {
138
138
  }
139
139
  }
140
140
  export async function completeInputWithPi(runtime, draft, config, signal) {
141
- const parsedModel = parseModelRef(config.modelRef);
142
141
  const modelRuntime = runtime.services.modelRuntime;
143
- let model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
144
- if (!model) {
145
- await modelRuntime.refresh();
146
- model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
147
- }
148
- if (!model)
149
- throw new Error(`Model not found: ${parsedModel.provider}/${parsedModel.modelId}`);
150
142
  const timeoutMs = numberInRange(config.timeoutMs, AUTOCOMPLETE_TIMEOUT_MS, 250, 10_000);
151
143
  const maxTokens = numberInRange(config.maxTokens, AUTOCOMPLETE_MAX_TOKENS, 8, 256);
152
144
  const maxPromptTokens = numberInRange(config.maxPromptTokens, AUTOCOMPLETE_MAX_PROMPT_TOKENS, 256, 16_000);
153
145
  const requestSignal = createTimeoutSignal(signal, timeoutMs);
154
- const requestMaxTokens = model.maxTokens > 0 ? Math.min(model.maxTokens, maxTokens) : maxTokens;
155
- const requestModel = { ...model, maxTokens: requestMaxTokens };
156
146
  const includeRecentMessages = numberInRange(config.includeRecentMessages, AUTOCOMPLETE_INCLUDE_RECENT_MESSAGES, 0, 20);
157
147
  const history = includeRecentMessages > 0 ? autocompleteHistoryFromMessages(runtime.session.messages, includeRecentMessages) : [];
158
148
  const prompt = buildAutocompletePrompt({ cwd: runtime.cwd, draft, history, maxPromptTokens });
159
149
  if (!prompt)
160
150
  return "";
161
- let output = "";
162
- let streamError;
163
151
  try {
164
- const stream = modelRuntime.streamSimple(requestModel, {
165
- systemPrompt: AUTOCOMPLETE_SYSTEM_PROMPT,
166
- messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
167
- }, {
168
- cacheRetention: "none",
169
- maxRetryDelayMs: 0,
170
- maxRetries: 0,
171
- maxTokens: requestModel.maxTokens,
172
- ...(parsedModel.thinkingLevel && parsedModel.thinkingLevel !== "off" ? { reasoning: parsedModel.thinkingLevel } : {}),
173
- signal: requestSignal.signal,
174
- timeoutMs,
175
- });
176
- for await (const event of stream) {
177
- if (event.type === "text_delta")
178
- output += event.delta;
179
- else if (event.type === "done" && !output)
180
- output = assistantMessageText(event.message);
181
- else if (event.type === "error")
182
- streamError = event.error.errorMessage ?? event.reason;
152
+ let refreshed = false;
153
+ let lastError;
154
+ for (const modelRef of modelRefChain(config.modelRef, config.fallbackModels)) {
155
+ if (requestSignal.signal.aborted)
156
+ throw requestSignal.signal.reason ?? new Error("Autocomplete request aborted");
157
+ let parsedModel;
158
+ try {
159
+ parsedModel = parseModelRef(modelRef);
160
+ }
161
+ catch (error) {
162
+ lastError = error;
163
+ continue;
164
+ }
165
+ let model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
166
+ if (!model && !refreshed) {
167
+ await modelRuntime.refresh();
168
+ refreshed = true;
169
+ model = modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
170
+ }
171
+ if (!model) {
172
+ lastError = new Error(`Model not found: ${parsedModel.provider}/${parsedModel.modelId}`);
173
+ continue;
174
+ }
175
+ try {
176
+ const requestMaxTokens = model.maxTokens > 0 ? Math.min(model.maxTokens, maxTokens) : maxTokens;
177
+ const requestModel = { ...model, maxTokens: requestMaxTokens };
178
+ let output = "";
179
+ let streamError;
180
+ const stream = modelRuntime.streamSimple(requestModel, {
181
+ systemPrompt: AUTOCOMPLETE_SYSTEM_PROMPT,
182
+ messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
183
+ }, {
184
+ cacheRetention: "none",
185
+ maxRetryDelayMs: 0,
186
+ maxRetries: 0,
187
+ maxTokens: requestModel.maxTokens,
188
+ ...(parsedModel.thinkingLevel && parsedModel.thinkingLevel !== "off" ? { reasoning: parsedModel.thinkingLevel } : {}),
189
+ signal: requestSignal.signal,
190
+ timeoutMs,
191
+ });
192
+ for await (const event of stream) {
193
+ if (event.type === "text_delta")
194
+ output += event.delta;
195
+ else if (event.type === "done" && !output)
196
+ output = assistantMessageText(event.message);
197
+ else if (event.type === "error")
198
+ streamError = event.error.errorMessage ?? event.reason;
199
+ }
200
+ if (streamError)
201
+ throw new Error(streamError);
202
+ return output;
203
+ }
204
+ catch (error) {
205
+ if (requestSignal.signal.aborted)
206
+ throw requestSignal.signal.reason ?? error;
207
+ lastError = error;
208
+ }
183
209
  }
184
- if (streamError)
185
- throw new Error(streamError);
186
- return output;
210
+ throw lastError ?? new Error("No autocomplete models are configured");
187
211
  }
188
212
  finally {
189
213
  requestSignal.dispose();
190
214
  }
191
215
  }
216
+ function modelRefChain(primary, fallbacks) {
217
+ return [...new Set([primary, ...(fallbacks ?? [])].map((ref) => ref.trim()).filter(Boolean))];
218
+ }
192
219
  export function autocompleteHistoryFromMessages(messages, includeRecentMessages) {
193
220
  const limit = numberInRange(includeRecentMessages, AUTOCOMPLETE_INCLUDE_RECENT_MESSAGES, 0, 20);
194
221
  if (limit <= 0)
@@ -9,6 +9,8 @@ import type { Entry, SessionActivity } from "../types.js";
9
9
  export type AppInputActionControllerHost = {
10
10
  runtime(): AgentSessionRuntime | undefined;
11
11
  inputScopeKey?(): string | undefined;
12
+ isDraftTabActive?(): boolean;
13
+ materializeDraftSession?(): Promise<AgentSessionRuntime | undefined>;
12
14
  isRunning(): boolean;
13
15
  isSessionSwitching(): boolean;
14
16
  inputEditor(): InputEditor;
@@ -149,7 +149,6 @@ export class AppInputActionController {
149
149
  await this.host.stopVoiceInput();
150
150
  if (this.host.inputScopeKey && this.host.inputScopeKey() !== inputScopeKey)
151
151
  return;
152
- const runtime = this.host.runtime();
153
152
  const inputEditor = this.host.inputEditor();
154
153
  const rawPromptText = inputEditor.promptText;
155
154
  const rawDisplayText = inputEditor.expandedText;
@@ -176,6 +175,14 @@ export class AppInputActionController {
176
175
  await this.popupActions.submitSlashCommand(promptText);
177
176
  return;
178
177
  }
178
+ let runtime = this.host.runtime();
179
+ if (!runtime && this.host.isDraftTabActive?.()) {
180
+ runtime = await this.host.materializeDraftSession?.();
181
+ if (this.host.inputScopeKey && this.host.inputScopeKey() !== inputScopeKey)
182
+ return;
183
+ if (!runtime)
184
+ return;
185
+ }
179
186
  const message = this.queuedMessages.createSubmittedUserMessage(promptText, displayText, images);
180
187
  this.host.requestHistory().add(message.displayText);
181
188
  inputEditor.clear();
@@ -16,6 +16,7 @@ export type InputControllerHost = {
16
16
  resetInputMenuDismissals(): void;
17
17
  render(): void;
18
18
  moveActivePopupMenuSelection(delta: number): boolean;
19
+ moveActiveModelThinkingLevel(delta: number): boolean;
19
20
  navigateRequestHistory(delta: number): boolean;
20
21
  scrollByLines(delta: number): void;
21
22
  scrollByPage(delta: number): void;
@@ -24,8 +25,8 @@ export type InputControllerHost = {
24
25
  handleInterrupt(): Promise<void>;
25
26
  handleEscape(): Promise<void>;
26
27
  handleDirectPopupInput(char: string): boolean;
28
+ toggleModelVisibilityMode(): boolean;
27
29
  autocompleteModel(): boolean;
28
- autocompleteThinking(): boolean;
29
30
  acceptAutocompleteSuggestion(): boolean;
30
31
  autocompleteSlashCommand(): void;
31
32
  toggleVoiceRecording(): void;
@@ -229,6 +229,9 @@ export class AppInputController {
229
229
  getEscapeSequences() {
230
230
  return [
231
231
  ...SHIFT_ENTER_ESCAPE_SEQUENCES.map((sequence) => [sequence, () => this.insertInputNewline()]),
232
+ ["\x1b[Z", () => { this.host.toggleModelVisibilityMode(); }],
233
+ ["\x1b[9;2u", () => { this.host.toggleModelVisibilityMode(); }],
234
+ ["\x1b[27;2;9~", () => { this.host.toggleModelVisibilityMode(); }],
232
235
  ["\x1b[13u", () => this.host.handleEnter()],
233
236
  ["\x1b[13;1u", () => this.host.handleEnter()],
234
237
  ["\x1b[5~", () => this.host.scrollByPage(-1)],
@@ -460,6 +463,8 @@ export class AppInputController {
460
463
  this.host.scrollByLines(1);
461
464
  }
462
465
  handleArrowLeft() {
466
+ if (this.host.moveActiveModelThinkingLevel(-1))
467
+ return;
463
468
  if (this.host.inputEditor.hasSelection) {
464
469
  const [start] = this.orderedEditorSelection();
465
470
  this.host.inputEditor.clearSelection();
@@ -473,6 +478,8 @@ export class AppInputController {
473
478
  }
474
479
  }
475
480
  handleArrowRight() {
481
+ if (this.host.moveActiveModelThinkingLevel(1))
482
+ return;
476
483
  if (this.host.inputEditor.hasSelection) {
477
484
  const [, end] = this.orderedEditorSelection();
478
485
  this.host.inputEditor.clearSelection();
@@ -554,8 +561,6 @@ export class AppInputController {
554
561
  return;
555
562
  if (this.host.autocompleteModel())
556
563
  return;
557
- if (this.host.autocompleteThinking())
558
- return;
559
564
  this.host.autocompleteSlashCommand();
560
565
  return;
561
566
  }
@@ -129,7 +129,6 @@ export function promptEnhancerTextIsSufficient(text) {
129
129
  return text.trim().length >= PROMPT_ENHANCER_MIN_TEXT_LENGTH;
130
130
  }
131
131
  async function enhancePromptWithPi(runtime, draft, config) {
132
- const parsedModel = parseModelRef(config.modelRef);
133
132
  const services = await promptEnhancerPiDeps.createAgentSessionServices({
134
133
  cwd: runtime.cwd,
135
134
  agentDir: runtime.services.agentDir,
@@ -145,41 +144,60 @@ async function enhancePromptWithPi(runtime, draft, config) {
145
144
  },
146
145
  });
147
146
  await services.modelRuntime.refresh();
148
- const model = services.modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
149
- if (!model) {
150
- throw new Error(modelNotFoundMessage(parsedModel.provider, parsedModel.modelId, services.modelRuntime.getModels()));
151
- }
152
- const { session } = await promptEnhancerPiDeps.createAgentSessionFromServices({
153
- services,
154
- sessionManager: promptEnhancerPiDeps.sessionManagerInMemory(runtime.cwd),
155
- model,
156
- thinkingLevel: parsedModel.thinkingLevel ?? "minimal",
157
- noTools: "all",
158
- });
159
- let output = "";
160
- let streamError;
161
- const unsubscribe = session.subscribe((event) => {
162
- if (event.type !== "message_update")
163
- return;
164
- const assistantEvent = event.assistantMessageEvent;
165
- if (assistantEvent.type === "text_delta")
166
- output += assistantEvent.delta;
167
- else if (assistantEvent.type === "error")
168
- streamError = assistantEvent.error.errorMessage ?? assistantEvent.reason;
169
- });
170
- try {
171
- await session.prompt(buildEnhancerPrompt(draft), { expandPromptTemplates: false });
172
- if (streamError)
173
- throw new Error(streamError);
174
- const cleaned = cleanupEnhancedPrompt(output);
175
- if (cleaned.length === 0)
176
- throw new Error("model returned an empty prompt");
177
- return cleaned;
178
- }
179
- finally {
180
- unsubscribe();
181
- session.dispose();
147
+ let lastError;
148
+ for (const modelRef of modelRefChain(config.modelRef, config.fallbackModels)) {
149
+ let parsedModel;
150
+ try {
151
+ parsedModel = parseModelRef(modelRef);
152
+ }
153
+ catch (error) {
154
+ lastError = error;
155
+ continue;
156
+ }
157
+ const model = services.modelRuntime.getModel(parsedModel.provider, parsedModel.modelId);
158
+ if (!model) {
159
+ lastError = new Error(modelNotFoundMessage(parsedModel.provider, parsedModel.modelId, services.modelRuntime.getModels()));
160
+ continue;
161
+ }
162
+ const { session } = await promptEnhancerPiDeps.createAgentSessionFromServices({
163
+ services,
164
+ sessionManager: promptEnhancerPiDeps.sessionManagerInMemory(runtime.cwd),
165
+ model,
166
+ thinkingLevel: parsedModel.thinkingLevel ?? "minimal",
167
+ noTools: "all",
168
+ });
169
+ let output = "";
170
+ let streamError;
171
+ const unsubscribe = session.subscribe((event) => {
172
+ if (event.type !== "message_update")
173
+ return;
174
+ const assistantEvent = event.assistantMessageEvent;
175
+ if (assistantEvent.type === "text_delta")
176
+ output += assistantEvent.delta;
177
+ else if (assistantEvent.type === "error")
178
+ streamError = assistantEvent.error.errorMessage ?? assistantEvent.reason;
179
+ });
180
+ try {
181
+ await session.prompt(buildEnhancerPrompt(draft), { expandPromptTemplates: false });
182
+ if (streamError)
183
+ throw new Error(streamError);
184
+ const cleaned = cleanupEnhancedPrompt(output);
185
+ if (cleaned.length === 0)
186
+ throw new Error("model returned an empty prompt");
187
+ return cleaned;
188
+ }
189
+ catch (error) {
190
+ lastError = error;
191
+ }
192
+ finally {
193
+ unsubscribe();
194
+ session.dispose();
195
+ }
182
196
  }
197
+ throw lastError ?? new Error("No prompt enhancer models are configured");
198
+ }
199
+ function modelRefChain(primary, fallbacks) {
200
+ return [...new Set([primary, ...(fallbacks ?? [])].map((ref) => ref.trim()).filter(Boolean))];
183
201
  }
184
202
  function buildEnhancerPrompt(draft) {
185
203
  return [
@@ -1,7 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
- import { savePixDictationLanguage, type DictationConfig, type DictationLanguageModelConfig } from "../../config.js";
2
+ import { savePixDictationLanguage, type DictationConfig } from "../../config.js";
3
3
  export type VoiceLanguage = string;
4
- export type VoiceInputState = "idle" | "installing" | "downloading" | "loading" | "listening";
4
+ export type VoiceInputState = "idle" | "connecting" | "listening";
5
5
  export type AppVoiceControllerHost = {
6
6
  activeInputScope(): string | undefined;
7
7
  insertTranscript(text: string): void;
@@ -10,58 +10,48 @@ export type AppVoiceControllerHost = {
10
10
  showToast(message: string, kind: "success" | "error" | "warning" | "info"): void;
11
11
  render(): void;
12
12
  };
13
- type VoskRecognitionResult = string | {
14
- text?: unknown;
15
- partial?: unknown;
16
- };
17
- type VoskModel = {
18
- free?: () => void;
19
- };
20
- type VoskRecognizer = {
21
- acceptWaveform(buffer: Buffer): boolean;
22
- partialResult?: () => VoskRecognitionResult;
23
- result(): VoskRecognitionResult;
24
- finalResult(): VoskRecognitionResult;
25
- free?: () => void;
26
- };
27
- type VoskModule = {
28
- Model: new (modelPath: string) => VoskModel;
29
- Recognizer: new (options: {
30
- model: VoskModel;
31
- sampleRate: number;
32
- }) => VoskRecognizer;
33
- setLogLevel?: (level: number) => void;
34
- };
35
- type VoskLoadAttempt = {
36
- ok: true;
37
- module: VoskModule;
38
- } | {
39
- ok: false;
40
- error: unknown;
41
- };
42
- type VoiceModelDefinition = DictationLanguageModelConfig;
43
13
  type RecorderCommand = {
44
14
  command: string;
45
15
  args: string[];
46
16
  description: string;
47
17
  };
18
+ type DeepgramSocketEvent = {
19
+ data?: unknown;
20
+ code?: number;
21
+ reason?: string;
22
+ };
23
+ type DeepgramSocketListener = (event: DeepgramSocketEvent) => void;
24
+ type DeepgramSocket = {
25
+ readyState: number;
26
+ send(data: unknown): void;
27
+ close(code?: number, reason?: string): void;
28
+ addEventListener(type: string, listener: DeepgramSocketListener): void;
29
+ removeEventListener(type: string, listener: DeepgramSocketListener): void;
30
+ };
31
+ export type DeepgramTranscript = {
32
+ text: string;
33
+ isFinal: boolean;
34
+ };
48
35
  type VoiceControllerTestDeps = {
49
- tryLoadVosk: typeof tryLoadVosk;
50
- ensureModel: typeof ensureModel;
36
+ deepgramApiKey: () => string | undefined;
37
+ createDeepgramSocket: typeof createDeepgramSocket;
38
+ waitForSocketOpen: typeof waitForSocketOpen;
51
39
  selectRecorderCommand: typeof selectRecorderCommand;
52
40
  spawn: typeof spawn;
53
41
  savePixDictationLanguage: typeof savePixDictationLanguage;
42
+ delay: typeof delay;
54
43
  };
55
44
  export declare function setVoiceControllerTestDeps(overrides?: Partial<VoiceControllerTestDeps>): void;
56
45
  export declare class AppVoiceController {
57
46
  private readonly host;
58
- private modelDefinitions;
47
+ private languageDefinitions;
59
48
  private languages;
60
49
  private language;
50
+ private deepgramModel;
51
+ private deepgramApiKey;
61
52
  private state;
62
- private readonly modelCache;
63
53
  private audioProcess;
64
- private recognizer;
54
+ private socket;
65
55
  private progressMessage;
66
56
  private progressFrame;
67
57
  private progressTimer;
@@ -70,6 +60,8 @@ export declare class AppVoiceController {
70
60
  private partialTranscriptTimer;
71
61
  private startGeneration;
72
62
  private recordingScope;
63
+ private stopPromise;
64
+ private disposed;
73
65
  constructor(host: AppVoiceControllerHost, dictationConfig: DictationConfig);
74
66
  updateDictationConfig(dictationConfig: DictationConfig): void;
75
67
  statusWidgetText(): string;
@@ -81,27 +73,31 @@ export declare class AppVoiceController {
81
73
  stopRecording(): Promise<void>;
82
74
  dispose(): Promise<void>;
83
75
  private startRecording;
84
- private cachedModel;
76
+ private stopRecordingNow;
77
+ private bindSocket;
78
+ private bindAudioProcess;
85
79
  private nextLanguage;
86
80
  private initialLanguage;
87
81
  private saveLanguageSelection;
88
- private modelDefinition;
89
- private installAndLoadVosk;
90
- private bindAudioProcess;
91
- private cleanupRecognizer;
82
+ private languageDefinition;
83
+ private deepgramLanguage;
92
84
  private setProgressMessage;
93
85
  private clearProgressMessage;
94
86
  private addProgressSystemMessage;
95
- private emitTranscript;
96
87
  private emitPartialTranscript;
97
88
  private clearPartialTranscript;
89
+ private commitPartialTranscript;
98
90
  private schedulePartialTranscriptEmit;
99
91
  private isCurrentStart;
100
92
  private continueStart;
93
+ private isCurrentSocket;
101
94
  private isCurrentAudioProcess;
102
95
  private isScopeActive;
103
96
  }
104
- declare function ensureModel(language: VoiceLanguage, definition: VoiceModelDefinition): Promise<string>;
105
- declare function tryLoadVosk(): VoskLoadAttempt;
97
+ export declare function buildDeepgramUrl(model: string, language: string, rawLinear16: boolean): string;
98
+ export declare function parseDeepgramTranscript(data: unknown): DeepgramTranscript | undefined;
106
99
  declare function selectRecorderCommand(): Promise<RecorderCommand>;
100
+ declare function createDeepgramSocket(url: string, protocols: string[]): DeepgramSocket;
101
+ declare function waitForSocketOpen(socket: DeepgramSocket): Promise<void>;
102
+ declare function delay(ms: number): Promise<void>;
107
103
  export {};