@oh-my-pi/pi-coding-agent 17.0.9 → 17.1.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 (285) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +1 -1
  3. package/dist/cli.js +4659 -4261
  4. package/dist/types/async/job-manager.d.ts +37 -1
  5. package/dist/types/cli/args.d.ts +2 -0
  6. package/dist/types/cli/bench-cli.d.ts +41 -0
  7. package/dist/types/commands/bench.d.ts +15 -3
  8. package/dist/types/commands/launch.d.ts +4 -0
  9. package/dist/types/config/model-registry.d.ts +3 -1
  10. package/dist/types/config/models-config-schema.d.ts +18 -6
  11. package/dist/types/config/models-config.d.ts +14 -5
  12. package/dist/types/config/provider-globals.d.ts +2 -2
  13. package/dist/types/config/service-tier.d.ts +5 -1
  14. package/dist/types/config/settings-schema.d.ts +316 -47
  15. package/dist/types/config/settings.d.ts +7 -0
  16. package/dist/types/dap/client.d.ts +20 -0
  17. package/dist/types/exec/bash-executor.d.ts +38 -0
  18. package/dist/types/exec/direnv.d.ts +33 -0
  19. package/dist/types/export/html/args.d.ts +15 -0
  20. package/dist/types/export/html/index.d.ts +11 -26
  21. package/dist/types/export/html/web-palette.d.ts +55 -116
  22. package/dist/types/extensibility/extensions/loader.d.ts +3 -0
  23. package/dist/types/extensibility/extensions/types.d.ts +17 -2
  24. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +13 -0
  25. package/dist/types/live/controller.d.ts +40 -0
  26. package/dist/types/live/protocol.d.ts +85 -0
  27. package/dist/types/live/protocol.test.d.ts +1 -0
  28. package/dist/types/live/transport.d.ts +48 -0
  29. package/dist/types/live/visualizer.d.ts +33 -0
  30. package/dist/types/lsp/client.d.ts +16 -1
  31. package/dist/types/mcp/config-writer.test.d.ts +1 -0
  32. package/dist/types/mcp/oauth-discovery.d.ts +2 -0
  33. package/dist/types/mcp/smithery-auth.d.ts +1 -1
  34. package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
  35. package/dist/types/memory-backend/tool-names.d.ts +2 -0
  36. package/dist/types/modes/components/login-dialog.d.ts +2 -2
  37. package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
  38. package/dist/types/modes/components/settings-defs.d.ts +7 -1
  39. package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
  40. package/dist/types/modes/components/tool-execution.d.ts +9 -1
  41. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  42. package/dist/types/modes/controllers/event-controller.d.ts +6 -1
  43. package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
  44. package/dist/types/modes/interactive-mode.d.ts +5 -0
  45. package/dist/types/modes/theme/theme.d.ts +1 -1
  46. package/dist/types/modes/types.d.ts +3 -1
  47. package/dist/types/modes/utils/context-usage.d.ts +12 -2
  48. package/dist/types/plan-mode/plan-files.d.ts +10 -0
  49. package/dist/types/registry/agent-lifecycle.d.ts +21 -9
  50. package/dist/types/registry/agent-registry.d.ts +11 -4
  51. package/dist/types/sdk.d.ts +15 -1
  52. package/dist/types/secrets/index.d.ts +15 -2
  53. package/dist/types/secrets/obfuscator.d.ts +113 -15
  54. package/dist/types/session/acp-permission-gate.d.ts +19 -0
  55. package/dist/types/session/agent-session-events.d.ts +84 -0
  56. package/dist/types/session/agent-session-types.d.ts +314 -0
  57. package/dist/types/session/agent-session.d.ts +118 -755
  58. package/dist/types/session/async-job-delivery.d.ts +28 -0
  59. package/dist/types/session/bash-runner.d.ts +75 -0
  60. package/dist/types/session/blob-store.d.ts +11 -1
  61. package/dist/types/session/blob-store.test.d.ts +1 -0
  62. package/dist/types/session/checkpoint-entries.d.ts +28 -0
  63. package/dist/types/session/eval-runner.d.ts +49 -0
  64. package/dist/types/session/irc-bridge.d.ts +46 -0
  65. package/dist/types/session/messages.d.ts +22 -0
  66. package/dist/types/session/model-controls.d.ts +180 -0
  67. package/dist/types/session/prewalk.d.ts +46 -0
  68. package/dist/types/session/queued-messages.d.ts +22 -0
  69. package/dist/types/session/redis-session-storage.d.ts +1 -0
  70. package/dist/types/session/retry-fallback-chains.d.ts +74 -0
  71. package/dist/types/session/role-models.d.ts +15 -0
  72. package/dist/types/session/session-advisors.d.ts +228 -0
  73. package/dist/types/session/session-entries.d.ts +8 -0
  74. package/dist/types/session/session-handoff.d.ts +70 -0
  75. package/dist/types/session/session-history-format.d.ts +6 -1
  76. package/dist/types/session/session-maintenance.d.ts +246 -0
  77. package/dist/types/session/session-manager.d.ts +41 -0
  78. package/dist/types/session/session-memory.d.ts +56 -0
  79. package/dist/types/session/session-provider-boundary.d.ts +62 -0
  80. package/dist/types/session/session-stats.d.ts +48 -0
  81. package/dist/types/session/session-tools.d.ts +143 -0
  82. package/dist/types/session/session-workspace.d.ts +32 -0
  83. package/dist/types/session/stream-guards.d.ts +44 -0
  84. package/dist/types/session/todo-tracker.d.ts +56 -0
  85. package/dist/types/session/ttsr-coordinator.d.ts +51 -0
  86. package/dist/types/session/turn-recovery.d.ts +225 -0
  87. package/dist/types/system-prompt.d.ts +2 -0
  88. package/dist/types/task/executor.d.ts +4 -1
  89. package/dist/types/task/output-manager.d.ts +3 -1
  90. package/dist/types/tools/approval.d.ts +1 -0
  91. package/dist/types/tools/browser/launch.d.ts +5 -0
  92. package/dist/types/tools/image-gen.d.ts +4 -4
  93. package/dist/types/tools/image-providers.d.ts +38 -0
  94. package/dist/types/tools/index.d.ts +5 -0
  95. package/dist/types/tools/path-utils.d.ts +8 -0
  96. package/dist/types/tools/todo.d.ts +10 -4
  97. package/dist/types/tools/xdev.d.ts +5 -1
  98. package/dist/types/tts/streaming-player.d.ts +14 -0
  99. package/dist/types/tts/vocalizer.d.ts +5 -0
  100. package/dist/types/utils/jj.d.ts +29 -0
  101. package/dist/types/utils/lang-from-path.d.ts +1 -0
  102. package/dist/types/utils/title-generator.d.ts +30 -0
  103. package/dist/types/vibe/runtime.d.ts +36 -8
  104. package/dist/types/web/search/index.d.ts +1 -1
  105. package/dist/types/web/search/provider.d.ts +15 -5
  106. package/dist/types/web/search/types.d.ts +94 -0
  107. package/package.json +12 -12
  108. package/scripts/generate-share-viewer.ts +4 -6
  109. package/src/advisor/__tests__/advisor.test.ts +643 -0
  110. package/src/advisor/runtime.ts +144 -43
  111. package/src/async/job-manager.ts +90 -2
  112. package/src/cli/args.ts +2 -0
  113. package/src/cli/auth-gateway-cli.ts +18 -3
  114. package/src/cli/bench-cli.ts +395 -29
  115. package/src/cli/flag-tables.ts +3 -0
  116. package/src/cli/gc-cli.ts +2 -2
  117. package/src/cli/usage-cli.ts +10 -1
  118. package/src/collab/host.ts +3 -2
  119. package/src/commands/bench.ts +18 -4
  120. package/src/commands/launch.ts +4 -0
  121. package/src/config/model-registry.ts +10 -2
  122. package/src/config/models-config-schema.ts +15 -4
  123. package/src/config/provider-globals.ts +9 -9
  124. package/src/config/service-tier.ts +26 -1
  125. package/src/config/settings-schema.ts +209 -51
  126. package/src/config/settings.ts +81 -2
  127. package/src/dap/client.ts +37 -4
  128. package/src/edit/index.ts +49 -12
  129. package/src/eval/py/executor.ts +103 -33
  130. package/src/exec/bash-executor.ts +89 -6
  131. package/src/exec/direnv.ts +145 -0
  132. package/src/export/html/args.ts +20 -0
  133. package/src/export/html/index.ts +45 -47
  134. package/src/export/html/template.css +19 -1
  135. package/src/export/html/template.html +6 -0
  136. package/src/export/html/template.js +21 -0
  137. package/src/export/html/tool-views.generated.js +31 -31
  138. package/src/export/html/web-palette.ts +116 -132
  139. package/src/export/share.ts +249 -49
  140. package/src/extensibility/extensions/loader.ts +29 -1
  141. package/src/extensibility/extensions/runner.ts +6 -0
  142. package/src/extensibility/extensions/types.ts +33 -2
  143. package/src/extensibility/plugins/legacy-pi-compat.ts +19 -1
  144. package/src/hindsight/state.ts +64 -6
  145. package/src/internal-urls/local-protocol.ts +2 -1
  146. package/src/internal-urls/memory-protocol.ts +2 -2
  147. package/src/internal-urls/skill-protocol.ts +2 -2
  148. package/src/internal-urls/ssh-protocol.ts +2 -1
  149. package/src/internal-urls/vault-protocol.ts +2 -1
  150. package/src/live/audio-worklet.txt +59 -0
  151. package/src/live/browser-runtime.txt +221 -0
  152. package/src/live/controller.ts +464 -0
  153. package/src/live/prompts/agent-final-message.md +3 -0
  154. package/src/live/prompts/live-instructions.md +23 -0
  155. package/src/live/protocol.test.ts +140 -0
  156. package/src/live/protocol.ts +233 -0
  157. package/src/live/transport.ts +490 -0
  158. package/src/live/visualizer.ts +234 -0
  159. package/src/lsp/client.ts +29 -9
  160. package/src/lsp/index.ts +19 -4
  161. package/src/main.ts +8 -1
  162. package/src/mcp/config-writer.test.ts +43 -0
  163. package/src/mcp/config-writer.ts +109 -82
  164. package/src/mcp/oauth-discovery.ts +10 -2
  165. package/src/mcp/smithery-auth.test.ts +29 -0
  166. package/src/mcp/smithery-auth.ts +3 -2
  167. package/src/memories/index.ts +40 -20
  168. package/src/memory-backend/tool-names.ts +2 -0
  169. package/src/mnemopi/backend.ts +24 -7
  170. package/src/modes/acp/acp-agent.ts +56 -10
  171. package/src/modes/acp/acp-event-mapper.ts +8 -1
  172. package/src/modes/components/agent-hub.ts +1 -1
  173. package/src/modes/components/login-dialog.ts +14 -4
  174. package/src/modes/components/plan-review-overlay.ts +350 -35
  175. package/src/modes/components/settings-defs.ts +23 -1
  176. package/src/modes/components/settings-selector.ts +169 -1
  177. package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
  178. package/src/modes/components/status-line/component.ts +123 -2
  179. package/src/modes/components/tool-execution.ts +11 -2
  180. package/src/modes/controllers/command-controller.ts +56 -15
  181. package/src/modes/controllers/event-controller.ts +111 -16
  182. package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
  183. package/src/modes/controllers/extension-ui-controller.ts +20 -4
  184. package/src/modes/controllers/live-command-controller.ts +178 -0
  185. package/src/modes/controllers/mcp-command-controller.ts +10 -1
  186. package/src/modes/controllers/omfg-controller.ts +44 -40
  187. package/src/modes/controllers/selector-controller.ts +18 -10
  188. package/src/modes/controllers/session-focus-controller.ts +6 -1
  189. package/src/modes/interactive-mode.ts +157 -38
  190. package/src/modes/runtime-init.ts +2 -0
  191. package/src/modes/setup-wizard/scenes/web-search.ts +17 -9
  192. package/src/modes/theme/theme.ts +1 -1
  193. package/src/modes/types.ts +3 -1
  194. package/src/modes/utils/context-usage.ts +23 -7
  195. package/src/modes/utils/ui-helpers.ts +10 -5
  196. package/src/plan-mode/plan-files.ts +40 -0
  197. package/src/prompts/bench/cache-prefix-chunk.md +1 -0
  198. package/src/prompts/bench/cache-prefix.md +3 -0
  199. package/src/prompts/bench/cache-suffix.md +1 -0
  200. package/src/prompts/system/custom-system-prompt.md +1 -1
  201. package/src/prompts/system/project-prompt.md +8 -1
  202. package/src/prompts/system/subagent-async-pending.md +6 -0
  203. package/src/prompts/system/system-prompt.md +1 -1
  204. package/src/prompts/system/workflow-notice.md +48 -40
  205. package/src/prompts/system/xdev-mount-notice.md +4 -0
  206. package/src/prompts/tools/todo.md +3 -1
  207. package/src/registry/agent-lifecycle.ts +116 -46
  208. package/src/registry/agent-registry.ts +35 -8
  209. package/src/registry/persisted-agents.ts +26 -2
  210. package/src/sdk.ts +210 -136
  211. package/src/secrets/index.ts +127 -4
  212. package/src/secrets/obfuscator.ts +2328 -105
  213. package/src/session/acp-permission-gate.ts +165 -0
  214. package/src/session/agent-session-error-log.test.ts +1 -1
  215. package/src/session/agent-session-events.ts +66 -0
  216. package/src/session/agent-session-types.ts +334 -0
  217. package/src/session/agent-session.ts +1892 -12226
  218. package/src/session/artifacts.ts +6 -5
  219. package/src/session/async-job-delivery.ts +74 -0
  220. package/src/session/bash-runner.ts +326 -0
  221. package/src/session/blob-store.test.ts +56 -0
  222. package/src/session/blob-store.ts +18 -2
  223. package/src/session/checkpoint-entries.ts +81 -0
  224. package/src/session/eval-runner.ts +212 -0
  225. package/src/session/indexed-session-storage.ts +9 -2
  226. package/src/session/irc-bridge.ts +203 -0
  227. package/src/session/messages.ts +263 -1
  228. package/src/session/model-controls.ts +714 -0
  229. package/src/session/prewalk.ts +252 -0
  230. package/src/session/queued-messages.ts +93 -0
  231. package/src/session/redis-session-storage.ts +51 -11
  232. package/src/session/retry-fallback-chains.ts +455 -0
  233. package/src/session/role-models.ts +85 -0
  234. package/src/session/session-advisors.ts +1679 -0
  235. package/src/session/session-context.ts +6 -3
  236. package/src/session/session-entries.ts +8 -0
  237. package/src/session/session-handoff.ts +308 -0
  238. package/src/session/session-history-format.ts +20 -9
  239. package/src/session/session-loader.ts +0 -46
  240. package/src/session/session-maintenance.ts +2983 -0
  241. package/src/session/session-manager.ts +390 -30
  242. package/src/session/session-memory.ts +222 -0
  243. package/src/session/session-provider-boundary.ts +307 -0
  244. package/src/session/session-stats.ts +293 -0
  245. package/src/session/session-tools.ts +943 -0
  246. package/src/session/session-workspace.ts +53 -0
  247. package/src/session/stream-guards.ts +417 -0
  248. package/src/session/todo-tracker.ts +380 -0
  249. package/src/session/ttsr-coordinator.ts +496 -0
  250. package/src/session/turn-recovery.ts +1629 -0
  251. package/src/slash-commands/builtin-registry.ts +92 -11
  252. package/src/slash-commands/helpers/usage-report.ts +22 -3
  253. package/src/system-prompt.ts +41 -17
  254. package/src/task/executor.ts +285 -70
  255. package/src/task/index.ts +98 -105
  256. package/src/task/output-manager.ts +25 -3
  257. package/src/task/persisted-revive.ts +4 -3
  258. package/src/task/structured-subagent.ts +1 -0
  259. package/src/tools/approval.ts +55 -10
  260. package/src/tools/bash-interactive.ts +26 -0
  261. package/src/tools/bash-skill-urls.ts +28 -2
  262. package/src/tools/bash.ts +339 -123
  263. package/src/tools/browser/launch.ts +9 -1
  264. package/src/tools/browser/tab-supervisor.ts +8 -5
  265. package/src/tools/browser.ts +94 -47
  266. package/src/tools/image-gen.ts +20 -28
  267. package/src/tools/image-providers.ts +50 -0
  268. package/src/tools/index.ts +9 -0
  269. package/src/tools/path-utils.ts +49 -2
  270. package/src/tools/read.ts +156 -88
  271. package/src/tools/renderers.ts +7 -1
  272. package/src/tools/todo.ts +101 -11
  273. package/src/tools/vibe.ts +1 -2
  274. package/src/tools/write.ts +51 -1
  275. package/src/tools/xdev.ts +67 -3
  276. package/src/tts/streaming-player.ts +62 -4
  277. package/src/tts/vocalizer.ts +18 -1
  278. package/src/utils/jj.ts +125 -4
  279. package/src/utils/lang-from-path.ts +7 -0
  280. package/src/utils/title-generator.ts +137 -1
  281. package/src/vibe/runtime.ts +852 -72
  282. package/src/web/search/index.ts +3 -6
  283. package/src/web/search/provider.ts +31 -16
  284. package/src/web/search/providers/xai.ts +7 -1
  285. package/src/web/search/types.ts +3 -0
@@ -15,15 +15,24 @@ export default class Bench extends Command {
15
15
  };
16
16
 
17
17
  static flags = {
18
- runs: Flags.integer({ description: "Requests per model (results are averaged)", default: 10 }),
19
- "max-tokens": Flags.integer({ description: "Max output tokens per request", default: 512 }),
18
+ runs: Flags.integer({ description: "Requests per model (results are averaged; default: 10)" }),
19
+ "max-tokens": Flags.integer({ description: "Max output tokens per request (default: 512; cache mode: 64)" }),
20
20
  prompt: Flags.string({ description: "Custom prompt text (default: bundled bench prompt)" }),
21
21
  "service-tier": Flags.string({
22
22
  description: "Service tier applied per model family (default: configured `tier.*` settings; `none` omits it)",
23
23
  options: SERVICE_TIER_OPENAI_VALUES,
24
24
  }),
25
25
  json: Flags.boolean({ description: "Output JSON" }),
26
- par: Flags.integer({ description: "Execute runs with N parallel queries/requests", default: 4 }),
26
+ par: Flags.integer({ description: "Execute runs with N parallel queries/requests (default: 4)" }),
27
+ cache: Flags.boolean({
28
+ description: "Run independent cold/warm prompt-cache pairs (not supported for openai-codex-responses)",
29
+ }),
30
+ "cache-prefix-file": Flags.string({ description: "Stable prompt prefix file for --cache" }),
31
+ "cache-prefix-bytes": Flags.integer({ description: "Stable prefix byte budget for --cache (default: 8192)" }),
32
+ "cache-pairs": Flags.integer({ description: "Cold/warm pairs per model for --cache (default: 1)" }),
33
+ "cache-concurrency": Flags.integer({
34
+ description: "Concurrent cache pairs for --cache; each pair remains sequential (default: 1)",
35
+ }),
27
36
  };
28
37
 
29
38
  static examples = [
@@ -31,7 +40,7 @@ export default class Bench extends Command {
31
40
  "# Fuzzy selectors work\n omp bench opus sonnet",
32
41
  "# Average over 3 runs each\n omp bench opus gpt-5.2 --runs 3",
33
42
  "# Force priority serving tier\n omp bench openai-codex/gpt-5.5:low --runs 10 --service-tier priority",
34
- "# Machine-readable output\n omp bench opus --json",
43
+ "# Measure one cold/warm prompt-cache pair\n omp bench openai/gpt-5.6 --cache --json",
35
44
  ];
36
45
 
37
46
  async run(): Promise<void> {
@@ -45,6 +54,11 @@ export default class Bench extends Command {
45
54
  serviceTier: flags["service-tier"],
46
55
  json: flags.json,
47
56
  par: flags.par,
57
+ cache: flags.cache,
58
+ cachePrefixFile: flags["cache-prefix-file"],
59
+ cachePrefixBytes: flags["cache-prefix-bytes"],
60
+ cachePairs: flags["cache-pairs"],
61
+ cacheConcurrency: flags["cache-concurrency"],
48
62
  },
49
63
  });
50
64
  }
@@ -83,6 +83,10 @@ export default class Index extends Command {
83
83
  description: "Load an extra config.yml-style overlay for this run (repeatable)",
84
84
  multiple: true,
85
85
  }),
86
+ "add-dir": Flags.string({
87
+ description: "Add a workspace directory beyond the working directory (repeatable)",
88
+ multiple: true,
89
+ }),
86
90
  print: Flags.boolean({
87
91
  char: "p",
88
92
  description: "Non-interactive mode: process prompt and exit",
@@ -2171,13 +2171,21 @@ export class ModelRegistry {
2171
2171
  /**
2172
2172
  * Get API key for a model.
2173
2173
  */
2174
- async getApiKey(model: Model<Api>, sessionId?: string): Promise<string | undefined> {
2174
+ async getApiKey(
2175
+ model: Model<Api>,
2176
+ sessionId?: string,
2177
+ options?: { signal?: AbortSignal },
2178
+ ): Promise<string | undefined> {
2175
2179
  const commandKey = this.#resolveCommandBackedApiKey(model.provider);
2176
2180
  if (commandKey.configured) return commandKey.value;
2177
2181
  if (this.#keylessProviders.has(model.provider) && !this.authStorage.hasAuth(model.provider)) {
2178
2182
  return kNoAuth;
2179
2183
  }
2180
- return this.authStorage.getApiKey(model.provider, sessionId, { baseUrl: model.baseUrl, modelId: model.id });
2184
+ return this.authStorage.getApiKey(model.provider, sessionId, {
2185
+ baseUrl: model.baseUrl,
2186
+ modelId: model.id,
2187
+ signal: options?.signal,
2188
+ });
2181
2189
  }
2182
2190
 
2183
2191
  /**
@@ -73,8 +73,19 @@ export const OpenAICompatSchema = type({
73
73
  "whenThinking?": OpenAICompatFieldsSchema,
74
74
  });
75
75
 
76
+ const BedrockCompatSchema = type({
77
+ "promptCacheMode?": '"none" | "automatic" | "explicit"',
78
+ "supportsLongPromptCacheRetention?": "boolean",
79
+ "promptCacheMinimumTokens?": "number >= 0",
80
+ "promptCacheMaximumCheckpoints?": "number >= 0",
81
+ });
82
+
83
+ // Provider-level overrides can target bundled models whose API is not repeated
84
+ // in models.yml, so preserve the sparse compat shape for each supported API.
85
+ const ApiCompatSchema = OpenAICompatSchema.and(BedrockCompatSchema);
86
+
76
87
  const ApiSchema = type(
77
- '"openai-completions" | "openai-responses" | "openai-codex-responses" | "azure-openai-responses" | "anthropic-messages" | "google-generative-ai" | "google-gemini-cli" | "google-vertex"',
88
+ '"openai-completions" | "openai-responses" | "openai-codex-responses" | "azure-openai-responses" | "anthropic-messages" | "bedrock-converse-stream" | "google-generative-ai" | "google-gemini-cli" | "google-vertex"',
78
89
  );
79
90
 
80
91
  const EffortSchema = type('"minimal" | "low" | "medium" | "high" | "xhigh" | "max"');
@@ -173,7 +184,7 @@ const ModelDefinitionSchema = type({
173
184
  "maxTokens?": "number",
174
185
  "omitMaxOutputTokens?": "boolean",
175
186
  "headers?": { "[string]": "string" },
176
- "compat?": OpenAICompatSchema,
187
+ "compat?": ApiCompatSchema,
177
188
  "contextPromotionTarget?": "string",
178
189
  "compactionModel?": "string",
179
190
  "remoteCompaction?": RemoteCompactionSchema,
@@ -222,7 +233,7 @@ export const ModelOverrideSchema = type({
222
233
  "maxTokens?": "number",
223
234
  "omitMaxOutputTokens?": "boolean",
224
235
  "headers?": { "[string]": "string" },
225
- "compat?": OpenAICompatSchema,
236
+ "compat?": ApiCompatSchema,
226
237
  "contextPromotionTarget?": "string",
227
238
  "compactionModel?": "string",
228
239
  "remoteCompaction?": RemoteCompactionSchema,
@@ -263,7 +274,7 @@ const ProviderConfigSchema = type({
263
274
  "apiKey?": "string",
264
275
  "api?": ApiSchema,
265
276
  "headers?": { "[string]": "string" },
266
- "compat?": OpenAICompatSchema,
277
+ "compat?": ApiCompatSchema,
267
278
  "remoteCompaction?": RemoteCompactionSchema,
268
279
  "authHeader?": "boolean",
269
280
  "auth?": ProviderAuthSchema,
@@ -1,10 +1,10 @@
1
- import * as imageGen from "../tools/image-gen";
1
+ import { setImageProviderOrder } from "../tools/image-gen";
2
2
  import * as webSearch from "../web/search";
3
3
 
4
4
  interface ProviderGlobalSettings {
5
+ get(path: "providers.webSearchOrder"): unknown;
5
6
  get(path: "providers.webSearchExclude"): unknown;
6
- get(path: "providers.webSearch"): unknown;
7
- get(path: "providers.image"): unknown;
7
+ get(path: "providers.imageOrder"): unknown;
8
8
  }
9
9
 
10
10
  export function applyProviderGlobalsFromSettings(settings: ProviderGlobalSettings): void {
@@ -13,13 +13,13 @@ export function applyProviderGlobalsFromSettings(settings: ProviderGlobalSetting
13
13
  webSearch.setExcludedSearchProviders(excludedWebSearchProviders.filter(webSearch.isSearchProviderId));
14
14
  }
15
15
 
16
- const webSearchProvider = settings.get("providers.webSearch");
17
- if (typeof webSearchProvider === "string" && webSearch.isSearchProviderPreference(webSearchProvider)) {
18
- webSearch.setPreferredSearchProvider(webSearchProvider);
16
+ const orderedWebSearchProviders = settings.get("providers.webSearchOrder");
17
+ if (Array.isArray(orderedWebSearchProviders)) {
18
+ webSearch.setSearchProviderOrder(orderedWebSearchProviders.filter(webSearch.isSearchProviderId));
19
19
  }
20
20
 
21
- const imageProvider = settings.get("providers.image");
22
- if (imageGen.isImageProviderPreference(imageProvider)) {
23
- imageGen.setPreferredImageProvider(imageProvider);
21
+ const orderedImageProviders = settings.get("providers.imageOrder");
22
+ if (Array.isArray(orderedImageProviders)) {
23
+ setImageProviderOrder(orderedImageProviders.filter((entry): entry is string => typeof entry === "string"));
24
24
  }
25
25
  }
@@ -1,4 +1,4 @@
1
- import type { ServiceTier, ServiceTierByFamily } from "@oh-my-pi/pi-ai";
1
+ import type { ServiceTier, ServiceTierByFamily, ServiceTierFamily } from "@oh-my-pi/pi-ai";
2
2
  import type { SubmenuOption } from "./settings-schema";
3
3
 
4
4
  /**
@@ -16,6 +16,31 @@ export type ServiceTierOpenAISettingValue = (typeof SERVICE_TIER_OPENAI_VALUES)[
16
16
  export type ServiceTierAnthropicSettingValue = (typeof SERVICE_TIER_ANTHROPIC_VALUES)[number];
17
17
  export type ServiceTierGoogleSettingValue = (typeof SERVICE_TIER_GOOGLE_VALUES)[number];
18
18
 
19
+ /** Whether a runtime value names a provider family with an independent service-tier knob. */
20
+ export function isServiceTierFamily(value: unknown): value is ServiceTierFamily {
21
+ return value === "openai" || value === "anthropic" || value === "google";
22
+ }
23
+
24
+ /** Whether a runtime value is a supported service tier for one provider family. */
25
+ export function isServiceTierForFamily(family: string, tier: unknown): tier is ServiceTier {
26
+ if (typeof tier !== "string" || tier === "none") return false;
27
+ let values: readonly string[];
28
+ switch (family) {
29
+ case "openai":
30
+ values = SERVICE_TIER_OPENAI_VALUES;
31
+ break;
32
+ case "anthropic":
33
+ values = SERVICE_TIER_ANTHROPIC_VALUES;
34
+ break;
35
+ case "google":
36
+ values = SERVICE_TIER_GOOGLE_VALUES;
37
+ break;
38
+ default:
39
+ return false;
40
+ }
41
+ return values.includes(tier);
42
+ }
43
+
19
44
  /**
20
45
  * Inherit-capable single value for the subagent/advisor tiers. The chosen tier
21
46
  * is broadcast across families and applied to whichever family the spawned
@@ -26,6 +26,7 @@ import {
26
26
  TINY_TITLE_MODEL_OPTIONS,
27
27
  TINY_TITLE_MODEL_VALUES,
28
28
  } from "../tiny/models";
29
+ import { IMAGE_PROVIDER_CHOICES, type ImageProvider } from "../tools/image-providers";
29
30
  import {
30
31
  DEFAULT_TTS_LOCAL_MODEL_KEY,
31
32
  DEFAULT_TTS_VOICE,
@@ -35,7 +36,7 @@ import {
35
36
  TTS_LOCAL_VOICE_VALUES,
36
37
  } from "../tts/models";
37
38
  import { EDIT_MODES } from "../utils/edit-mode";
38
- import { SEARCH_PROVIDER_OPTIONS, SEARCH_PROVIDER_PREFERENCES, type SearchProviderId } from "../web/search/types";
39
+ import { SEARCH_PROVIDER_CHOICES, type SearchProviderId } from "../web/search/types";
39
40
  import {
40
41
  SERVICE_TIER_ANTHROPIC_OPTIONS,
41
42
  SERVICE_TIER_ANTHROPIC_VALUES,
@@ -218,10 +219,18 @@ interface UiString extends UiBase {
218
219
  options?: ReadonlyArray<SubmenuOption> | "runtime";
219
220
  }
220
221
 
222
+ interface UiArray extends UiBase {
223
+ /** Membership choices. Without options, an array setting has no UI representation (config-file only). */
224
+ options?: ReadonlyArray<SubmenuOption>;
225
+ /** Selection order is meaningful; the editor renders positions and supports reordering. */
226
+ ordered?: boolean;
227
+ }
228
+
221
229
  /** Wide ui shape exposed to consumers that walk the schema generically. */
222
230
  export type AnyUiMetadata = UiBase & {
223
231
  options?: ReadonlyArray<SubmenuOption> | "runtime";
224
232
  secret?: boolean;
233
+ ordered?: boolean;
225
234
  };
226
235
 
227
236
  interface BooleanDef {
@@ -252,7 +261,7 @@ interface EnumDef<T extends readonly string[]> {
252
261
  interface ArrayDef<T> {
253
262
  type: "array";
254
263
  default: T[];
255
- ui?: UiBase;
264
+ ui?: UiArray;
256
265
  }
257
266
 
258
267
  interface RecordDef<T> {
@@ -904,6 +913,18 @@ export const SETTINGS_SCHEMA = {
904
913
  },
905
914
  },
906
915
 
916
+ "tui.titleState": {
917
+ type: "boolean",
918
+ default: true,
919
+ ui: {
920
+ tab: "appearance",
921
+ group: "Display",
922
+ label: "Terminal Title Run State",
923
+ description:
924
+ "Show the agent run state in the terminal title's separator — an animated spinner while working, '>' when it's your turn, '!' when the agent is waiting on you",
925
+ },
926
+ },
927
+
907
928
  "tui.hyperlinks": {
908
929
  type: "enum",
909
930
  values: ["off", "auto", "always"] as const,
@@ -1188,6 +1209,18 @@ export const SETTINGS_SCHEMA = {
1188
1209
  },
1189
1210
  },
1190
1211
 
1212
+ "workspace.additionalDirectories": {
1213
+ type: "array",
1214
+ default: [] as string[],
1215
+ ui: {
1216
+ tab: "context",
1217
+ group: "General",
1218
+ label: "Additional Workspace Dirs",
1219
+ description:
1220
+ "Extra workspace directories added to every session as additional roots (multi-root workspace). Managed live via /add-dir and /remove-dir. Paths resolve relative to cwd; absolute paths recommended. The agent is told these roots exist and can read/grep/glob them.",
1221
+ },
1222
+ },
1223
+
1191
1224
  personality: {
1192
1225
  type: "enum",
1193
1226
  values: ["default", "friendly", "pragmatic", "none"] as const,
@@ -1460,6 +1493,65 @@ export const SETTINGS_SCHEMA = {
1460
1493
  description: "Allow retry recovery to switch to configured fallback models",
1461
1494
  },
1462
1495
  },
1496
+ "retry.usageAwareFallback": {
1497
+ type: "boolean",
1498
+ default: false,
1499
+ ui: {
1500
+ tab: "model",
1501
+ group: "Retry & Fallback",
1502
+ label: "Usage-Aware Fallback",
1503
+ description:
1504
+ "Use reliable coding-plan quota reports to prefer same-provider accounts, then configured fallback models, before a hard usage limit. Ordinary configured API keys are excluded.",
1505
+ },
1506
+ },
1507
+ "retry.usageReservePct": {
1508
+ type: "number",
1509
+ default: 10,
1510
+ ui: {
1511
+ tab: "model",
1512
+ group: "Retry & Fallback",
1513
+ label: "Reserve Margin",
1514
+ description:
1515
+ "Treat a coding-plan model as near its limit below this remaining percentage. Unknown or unmapped usage keeps the primary model.",
1516
+ condition: "usageAwareFallbackEnabled",
1517
+ options: [
1518
+ { value: "5", label: "5%", description: "Act only when nearly exhausted" },
1519
+ { value: "10", label: "10%", description: "Balanced safety margin" },
1520
+ { value: "15", label: "15%", description: "Conservative" },
1521
+ { value: "20", label: "20%", description: "Early protection" },
1522
+ { value: "25", label: "25%", description: "Very conservative" },
1523
+ ],
1524
+ },
1525
+ },
1526
+ "retry.usageReservePolicy": {
1527
+ type: "enum",
1528
+ values: ["confirm", "auto", "fail-closed"] as const,
1529
+ default: "confirm",
1530
+ ui: {
1531
+ tab: "model",
1532
+ group: "Retry & Fallback",
1533
+ label: "Reserve Policy",
1534
+ description: "What to do when every same-provider coding-plan account is inside the reserve margin.",
1535
+ condition: "usageAwareFallbackEnabled",
1536
+ options: [
1537
+ {
1538
+ value: "confirm",
1539
+ label: "Confirm interactively",
1540
+ description: "Keep interactive sessions on the primary until confirmed; background agents auto-fallback",
1541
+ },
1542
+ {
1543
+ value: "auto",
1544
+ label: "Auto-fallback",
1545
+ description: "Always select the next eligible configured fallback",
1546
+ },
1547
+ {
1548
+ value: "fail-closed",
1549
+ label: "Fail closed",
1550
+ description: "Do not spend reserve quota or select a fallback",
1551
+ },
1552
+ ],
1553
+ },
1554
+ },
1463
1555
  "retry.fallbackChains": {
1464
1556
  type: "record",
1465
1557
  default: {} as Record<string, string[]>,
@@ -1773,6 +1865,18 @@ export const SETTINGS_SCHEMA = {
1773
1865
  },
1774
1866
  },
1775
1867
 
1868
+ "error.notify": {
1869
+ type: "enum",
1870
+ values: ["on", "off"] as const,
1871
+ default: "off",
1872
+ ui: {
1873
+ tab: "interaction",
1874
+ group: "Notifications",
1875
+ label: "Error Notification",
1876
+ description: "Notify when the agent stops with an error",
1877
+ },
1878
+ },
1879
+
1776
1880
  "ask.timeout": {
1777
1881
  type: "number",
1778
1882
  default: 0,
@@ -2448,9 +2552,8 @@ export const SETTINGS_SCHEMA = {
2448
2552
  "memories.summaryInjectionTokenLimit": { type: "number", default: 5000 },
2449
2553
 
2450
2554
  // Memory backend selector — picks between local memories pipeline,
2451
- // Mnemopi local SQLite, Hindsight remote memory, or off. Legacy
2452
- // `memories.enabled` keeps gating the local backend; see config/settings.ts
2453
- // migration for details.
2555
+ // Mnemopi local SQLite, Hindsight remote memory, or off. The legacy
2556
+ // `memories.enabled` flag is migration input only; see config/settings.ts.
2454
2557
  "memory.backend": {
2455
2558
  type: "enum",
2456
2559
  values: ["off", "local", "hindsight", "mnemopi"] as const,
@@ -3108,6 +3211,17 @@ export const SETTINGS_SCHEMA = {
3108
3211
  },
3109
3212
  },
3110
3213
 
3214
+ "read.renderMarkdown": {
3215
+ type: "boolean",
3216
+ default: false,
3217
+ ui: {
3218
+ tab: "files",
3219
+ group: "Reading",
3220
+ label: "Markdown Previews",
3221
+ description: "Render Markdown read results as formatted terminal Markdown previews instead of raw source",
3222
+ },
3223
+ },
3224
+
3111
3225
  "read.summarize.enabled": {
3112
3226
  type: "boolean",
3113
3227
  default: true,
@@ -3287,6 +3401,17 @@ export const SETTINGS_SCHEMA = {
3287
3401
  description: "Automatically background long-running bash commands and deliver the result later",
3288
3402
  },
3289
3403
  },
3404
+ "bash.patterns": {
3405
+ type: "array",
3406
+ default: [],
3407
+ ui: {
3408
+ tab: "shell",
3409
+ group: "Bash",
3410
+ label: "Bash Approval Patterns",
3411
+ description:
3412
+ "Ordered bash command approval rules. Each item has match and approval fields; only '*' wildcards are supported.",
3413
+ },
3414
+ },
3290
3415
 
3291
3416
  // Bash interceptor
3292
3417
  "bashInterceptor.enabled": {
@@ -3301,6 +3426,29 @@ export const SETTINGS_SCHEMA = {
3301
3426
  },
3302
3427
  "bashInterceptor.patterns": { type: "array", default: DEFAULT_BASH_INTERCEPTOR_RULES },
3303
3428
 
3429
+ "bash.direnv": {
3430
+ type: "enum",
3431
+ values: ["auto", "off"] as const,
3432
+ default: "auto",
3433
+ ui: {
3434
+ tab: "shell",
3435
+ group: "Bash",
3436
+ label: "direnv Auto-Load",
3437
+ description:
3438
+ "Auto-load a repo's direnv/devenv `.envrc` into the bash session so devenv tools and env vars are present without manual `direnv exec`. Honors direnv's allow list: an `.envrc` you haven't `direnv allow`ed is never executed",
3439
+ },
3440
+ },
3441
+ "bash.direnvLoadTimeoutMs": {
3442
+ type: "number",
3443
+ default: 30_000,
3444
+ ui: {
3445
+ tab: "shell",
3446
+ group: "Bash",
3447
+ label: "direnv Load Timeout (ms)",
3448
+ description:
3449
+ "Max wait for the first `direnv export` (a cold devenv shell can be slow); on timeout the session runs without the direnv env",
3450
+ },
3451
+ },
3304
3452
  // Shell output minimizer
3305
3453
  "shellMinimizer.enabled": {
3306
3454
  type: "boolean",
@@ -3947,6 +4095,40 @@ export const SETTINGS_SCHEMA = {
3947
4095
  },
3948
4096
  },
3949
4097
 
4098
+ "tools.xdevDocs": {
4099
+ type: "enum",
4100
+ values: ["inline", "builtins", "catalog"] as const,
4101
+ default: "builtins",
4102
+ ui: {
4103
+ tab: "tools",
4104
+ group: "Discovery & MCP",
4105
+ label: "xd:// Prompt Docs",
4106
+ description:
4107
+ "Choose which mounted-device docs and schemas are inlined in the system prompt. Built-ins keeps core tools inline while MCP and extension tools stay on-demand.",
4108
+ options: [
4109
+ { value: "inline", label: "All Devices", description: "Inline docs and schemas for every mounted device." },
4110
+ {
4111
+ value: "builtins",
4112
+ label: "Built-ins Only",
4113
+ description: "Inline built-in docs; fetch MCP and extension docs on demand.",
4114
+ },
4115
+ { value: "catalog", label: "Catalog Only", description: "List every device; fetch all docs on demand." },
4116
+ ],
4117
+ },
4118
+ },
4119
+
4120
+ "tools.xdevInlineDevices": {
4121
+ type: "array",
4122
+ default: EMPTY_STRING_ARRAY,
4123
+ ui: {
4124
+ tab: "tools",
4125
+ group: "Discovery & MCP",
4126
+ label: "xd:// Inline Devices",
4127
+ description:
4128
+ "When xd:// Prompt Docs is Built-ins Only, inline dynamic devices whose names match these glob patterns (for example mcp__context_mode_*). Catalog Only ignores this setting.",
4129
+ },
4130
+ },
4131
+
3950
4132
  // MCP
3951
4133
  "mcp.enableProjectConfig": {
3952
4134
  type: "boolean",
@@ -4195,7 +4377,7 @@ export const SETTINGS_SCHEMA = {
4195
4377
  group: "Subagents",
4196
4378
  label: "Batch Task Calls",
4197
4379
  description:
4198
- "Switch the task tool to its batch shape: one call carries { agent, context, tasks[] } — one subagent per item (with per-item isolation) and a required shared context prepended to every assignment. With async.enabled=true, each spawn runs as an independent background agent with the normal idle/parked lifecycle; otherwise the call blocks for merged results. Disable to restore the flat single-spawn schema.",
4380
+ "Switch the task tool to its batch shape: one call carries { context, tasks[] } — one subagent per item, with an optional per-item agent (defaulting to the session spawn-policy agent), per-item isolation, and a required shared context prepended to every assignment. With async.enabled=true, each spawn runs as an independent background agent with the normal idle/parked lifecycle; otherwise the call blocks for merged results. Disable to restore the flat single-spawn schema.",
4199
4381
  },
4200
4382
  },
4201
4383
 
@@ -4458,7 +4640,7 @@ export const SETTINGS_SCHEMA = {
4458
4640
  tab: "providers",
4459
4641
  group: "Privacy",
4460
4642
  label: "Hide Secrets",
4461
- description: "Obfuscate secrets before sending to AI providers",
4643
+ description: "Obfuscate configured secrets and redact credential-shaped tokens before sending to AI providers",
4462
4644
  },
4463
4645
  },
4464
4646
 
@@ -4474,16 +4656,17 @@ export const SETTINGS_SCHEMA = {
4474
4656
  "Maximum concurrent Ollama Cloud subagent runs per process; 0 disables the provider-specific limit",
4475
4657
  },
4476
4658
  },
4477
- "providers.webSearch": {
4478
- type: "enum",
4479
- values: SEARCH_PROVIDER_PREFERENCES,
4480
- default: "auto",
4659
+ "providers.webSearchOrder": {
4660
+ type: "array",
4661
+ default: [] as SearchProviderId[],
4481
4662
  ui: {
4482
4663
  tab: "providers",
4483
4664
  group: "Services",
4484
- label: "Web Search Provider",
4485
- description: "Preferred provider for the web_search tool",
4486
- options: SEARCH_PROVIDER_OPTIONS,
4665
+ label: "Web Search Provider Order",
4666
+ description:
4667
+ "Prioritized providers for the web_search tool; unlisted providers retain their default order afterward",
4668
+ options: SEARCH_PROVIDER_CHOICES,
4669
+ ordered: true,
4487
4670
  },
4488
4671
  },
4489
4672
  "providers.webSearchExclude": {
@@ -4494,6 +4677,7 @@ export const SETTINGS_SCHEMA = {
4494
4677
  group: "Services",
4495
4678
  label: "Excluded Web Search Providers",
4496
4679
  description: "Providers that web_search should never use, even as fallbacks",
4680
+ options: SEARCH_PROVIDER_CHOICES,
4497
4681
  },
4498
4682
  },
4499
4683
  "providers.webSearchGeminiModel": {
@@ -4534,46 +4718,17 @@ export const SETTINGS_SCHEMA = {
4534
4718
  ],
4535
4719
  },
4536
4720
  },
4537
- "providers.image": {
4538
- type: "enum",
4539
- values: ["auto", "openai", "openai-codex", "antigravity", "xai", "gemini", "openrouter"] as const,
4540
- default: "auto",
4721
+ "providers.imageOrder": {
4722
+ type: "array",
4723
+ default: [] as ImageProvider[],
4541
4724
  ui: {
4542
4725
  tab: "providers",
4543
4726
  group: "Services",
4544
- label: "Image Provider",
4545
- description: "Preferred provider for image generation",
4546
- options: [
4547
- {
4548
- value: "auto",
4549
- label: "Auto",
4550
- description:
4551
- "Priority: per-request provider > configured provider > active session provider > GPT model image tool > Codex subscription > Antigravity > xAI > OpenRouter > Gemini",
4552
- },
4553
- {
4554
- value: "openai",
4555
- label: "OpenAI",
4556
- description:
4557
- "OPENAI_API_KEY (gpt-image-2) or active GPT model; falls back to a connected Codex subscription",
4558
- },
4559
- {
4560
- value: "openai-codex",
4561
- label: "OpenAI Codex (ChatGPT)",
4562
- description: "Uses a connected Codex / ChatGPT subscription — no OPENAI_API_KEY needed",
4563
- },
4564
- {
4565
- value: "antigravity",
4566
- label: "Antigravity",
4567
- description: "Requires google-antigravity OAuth",
4568
- },
4569
- {
4570
- value: "xai",
4571
- label: "xAI Grok Imagine",
4572
- description: "Requires xAI Grok OAuth or XAI_API_KEY",
4573
- },
4574
- { value: "gemini", label: "Gemini", description: "Requires GEMINI_API_KEY" },
4575
- { value: "openrouter", label: "OpenRouter", description: "Requires OPENROUTER_API_KEY" },
4576
- ],
4727
+ label: "Image Provider Order",
4728
+ description:
4729
+ "Prioritized providers for image generation; unlisted providers follow the active session provider and the built-in order",
4730
+ options: IMAGE_PROVIDER_CHOICES,
4731
+ ordered: true,
4577
4732
  },
4578
4733
  },
4579
4734
  "providers.fireworksTier": {
@@ -5263,6 +5418,9 @@ export interface RetrySettings {
5263
5418
  baseDelayMs: number;
5264
5419
  maxDelayMs: number;
5265
5420
  modelFallback: boolean;
5421
+ usageAwareFallback: boolean;
5422
+ usageReservePct: number;
5423
+ usageReservePolicy: "confirm" | "auto" | "fail-closed";
5266
5424
  }
5267
5425
 
5268
5426
  export interface MemoriesSettings {