@oh-my-pi/pi-coding-agent 17.2.3 → 17.2.5

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 (375) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/dist/{CHANGELOG-c5hpqt9r.md → CHANGELOG-q2w43aw3.md} +92 -0
  3. package/dist/cli.js +3979 -3548
  4. package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
  5. package/dist/types/advisor/advise-tool.d.ts +6 -0
  6. package/dist/types/advisor/runtime.d.ts +4 -4
  7. package/dist/types/capability/mcp.d.ts +9 -0
  8. package/dist/types/cli/args.d.ts +4 -1
  9. package/dist/types/cli/browser-relay-cli.d.ts +15 -0
  10. package/dist/types/cli/command-help.d.ts +99 -0
  11. package/dist/types/cli/help-extra.d.ts +2 -0
  12. package/dist/types/cli/models-cli.d.ts +1 -1
  13. package/dist/types/cli/thinking-levels.d.ts +5 -0
  14. package/dist/types/cli/update-cli.d.ts +13 -0
  15. package/dist/types/commands/browser-relay.d.ts +38 -0
  16. package/dist/types/commands/commit.d.ts +3 -0
  17. package/dist/types/commands/complete.d.ts +1 -1
  18. package/dist/types/commands/completions.d.ts +6 -0
  19. package/dist/types/commands/grep.d.ts +3 -0
  20. package/dist/types/commands/join.d.ts +4 -0
  21. package/dist/types/commands/launch-help.d.ts +171 -0
  22. package/dist/types/commands/launch.d.ts +5 -1
  23. package/dist/types/commands/models.d.ts +3 -0
  24. package/dist/types/commands/say.d.ts +10 -0
  25. package/dist/types/commands/worktree.d.ts +3 -0
  26. package/dist/types/config/keybindings.d.ts +6 -1
  27. package/dist/types/config/model-discovery.d.ts +2 -2
  28. package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
  29. package/dist/types/config/models-config-schema.d.ts +2 -0
  30. package/dist/types/config/models-config.d.ts +1 -0
  31. package/dist/types/config/service-tier.d.ts +2 -0
  32. package/dist/types/config/settings-schema.d.ts +70 -22
  33. package/dist/types/cursor-bridge-tools.d.ts +1 -1
  34. package/dist/types/cursor.d.ts +7 -4
  35. package/dist/types/discovery/helpers.d.ts +6 -0
  36. package/dist/types/discovery/omp-extension-roots.d.ts +21 -2
  37. package/dist/types/edit/index.d.ts +3 -3
  38. package/dist/types/edit/modes/replace.d.ts +22 -15
  39. package/dist/types/edit/renderer.d.ts +1 -1
  40. package/dist/types/eval/py/kernel.d.ts +3 -1
  41. package/dist/types/eval/py/spawn-options.d.ts +12 -16
  42. package/dist/types/extensibility/extensions/loader.d.ts +6 -2
  43. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
  44. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
  45. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  46. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +2 -2
  47. package/dist/types/launch/broker.d.ts +1 -1
  48. package/dist/types/launch/client.d.ts +6 -3
  49. package/dist/types/launch/ensure.d.ts +8 -0
  50. package/dist/types/launch/paths.d.ts +3 -2
  51. package/dist/types/launch/protocol.d.ts +2 -2
  52. package/dist/types/lsp/client.d.ts +2 -0
  53. package/dist/types/lsp/mux/daemon.d.ts +15 -0
  54. package/dist/types/lsp/mux/protocol.d.ts +57 -0
  55. package/dist/types/lsp/mux/server.d.ts +18 -0
  56. package/dist/types/lsp/types.d.ts +22 -2
  57. package/dist/types/main.d.ts +2 -0
  58. package/dist/types/mcp/request-id.d.ts +19 -0
  59. package/dist/types/mcp/types.d.ts +14 -0
  60. package/dist/types/memory-backend/index.d.ts +1 -0
  61. package/dist/types/memory-backend/messages.d.ts +15 -0
  62. package/dist/types/mnemopi/embed-client.d.ts +1 -1
  63. package/dist/types/mnemopi/state.d.ts +0 -23
  64. package/dist/types/modes/components/assistant-message.d.ts +2 -0
  65. package/dist/types/modes/components/custom-editor.d.ts +2 -1
  66. package/dist/types/modes/components/model-browser.d.ts +7 -5
  67. package/dist/types/modes/components/model-picker.d.ts +9 -3
  68. package/dist/types/modes/components/read-tool-group.d.ts +11 -0
  69. package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
  70. package/dist/types/modes/components/tool-execution.d.ts +2 -0
  71. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  72. package/dist/types/modes/interactive-mode.d.ts +1 -0
  73. package/dist/types/modes/types.d.ts +2 -1
  74. package/dist/types/modes/workflow.d.ts +2 -1
  75. package/dist/types/registry/agent-lifecycle.d.ts +14 -5
  76. package/dist/types/registry/agent-registry.d.ts +4 -3
  77. package/dist/types/sdk.d.ts +4 -2
  78. package/dist/types/secrets/index.d.ts +7 -9
  79. package/dist/types/session/agent-session-types.d.ts +3 -1
  80. package/dist/types/session/agent-session.d.ts +6 -1
  81. package/dist/types/session/indexed-session-storage.d.ts +1 -0
  82. package/dist/types/session/model-controls.d.ts +0 -1
  83. package/dist/types/session/session-advisors.d.ts +8 -1
  84. package/dist/types/session/session-context.d.ts +2 -1
  85. package/dist/types/session/session-maintenance.d.ts +2 -0
  86. package/dist/types/session/session-manager.d.ts +16 -5
  87. package/dist/types/session/session-stats.d.ts +10 -0
  88. package/dist/types/session/session-storage.d.ts +15 -3
  89. package/dist/types/system-prompt.d.ts +6 -1
  90. package/dist/types/task/index.d.ts +2 -1
  91. package/dist/types/task/spawn-policy.d.ts +5 -0
  92. package/dist/types/thinking.d.ts +1 -7
  93. package/dist/types/tools/ast-grep.d.ts +1 -1
  94. package/dist/types/tools/browser/registry.d.ts +2 -1
  95. package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
  96. package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
  97. package/dist/types/tools/browser/relay/kind.d.ts +19 -0
  98. package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
  99. package/dist/types/tools/browser/relay/server.d.ts +35 -0
  100. package/dist/types/tools/browser/render.d.ts +1 -0
  101. package/dist/types/tools/browser.d.ts +3 -0
  102. package/dist/types/tools/computer/exposure.d.ts +9 -7
  103. package/dist/types/tools/computer/protocol.d.ts +70 -17
  104. package/dist/types/tools/computer/supervisor.d.ts +23 -10
  105. package/dist/types/tools/computer/worker-entry.d.ts +1 -0
  106. package/dist/types/tools/computer/worker.d.ts +42 -7
  107. package/dist/types/tools/computer-renderer.d.ts +7 -5
  108. package/dist/types/tools/computer.d.ts +25 -44
  109. package/dist/types/tools/context.d.ts +3 -0
  110. package/dist/types/tools/default-renderer.d.ts +3 -0
  111. package/dist/types/tools/glob.d.ts +1 -1
  112. package/dist/types/tools/grep.d.ts +1 -1
  113. package/dist/types/tools/render-utils.d.ts +2 -0
  114. package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
  115. package/dist/types/tools/tool-timeouts.d.ts +5 -0
  116. package/dist/types/tools/xdev.d.ts +8 -0
  117. package/dist/types/utils/clipboard.d.ts +2 -2
  118. package/dist/types/web/kagi.d.ts +1 -0
  119. package/dist/types/web/search/index.d.ts +1 -1
  120. package/dist/types/web/search/providers/anthropic.d.ts +1 -0
  121. package/dist/types/web/search/providers/base.d.ts +2 -0
  122. package/dist/types/web/search/providers/brave.d.ts +1 -0
  123. package/dist/types/web/search/providers/browser-page.d.ts +1 -0
  124. package/dist/types/web/search/providers/codex.d.ts +1 -0
  125. package/dist/types/web/search/providers/exa.d.ts +1 -0
  126. package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
  127. package/dist/types/web/search/providers/gemini.d.ts +1 -0
  128. package/dist/types/web/search/providers/jina.d.ts +1 -0
  129. package/dist/types/web/search/providers/kagi.d.ts +1 -0
  130. package/dist/types/web/search/providers/kimi.d.ts +1 -0
  131. package/dist/types/web/search/providers/parallel.d.ts +1 -0
  132. package/dist/types/web/search/providers/perplexity.d.ts +1 -0
  133. package/dist/types/web/search/providers/searxng.d.ts +1 -0
  134. package/dist/types/web/search/providers/tavily.d.ts +1 -0
  135. package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
  136. package/dist/types/web/search/providers/utils.d.ts +6 -9
  137. package/dist/types/web/search/providers/zai.d.ts +1 -0
  138. package/dist/types/web/search/types.d.ts +4 -0
  139. package/package.json +12 -12
  140. package/scripts/legacy-pi-virtual-module.ts +12 -2
  141. package/src/advisor/advise-tool.ts +18 -0
  142. package/src/advisor/runtime.ts +6 -6
  143. package/src/capability/mcp.ts +7 -0
  144. package/src/cli/args.ts +7 -87
  145. package/src/cli/browser-relay-cli.ts +119 -0
  146. package/src/cli/command-help.ts +103 -0
  147. package/src/cli/completion-gen.ts +5 -5
  148. package/src/cli/flag-tables.ts +9 -0
  149. package/src/cli/help-extra.ts +89 -0
  150. package/src/cli/models-cli.ts +13 -16
  151. package/src/cli/setup-cli.ts +13 -21
  152. package/src/cli/thinking-levels.ts +7 -0
  153. package/src/cli/update-cli.ts +26 -7
  154. package/src/cli-commands.ts +170 -33
  155. package/src/cli.ts +17 -5
  156. package/src/collab/host.ts +1 -1
  157. package/src/commands/acp.ts +3 -1
  158. package/src/commands/agents.ts +3 -2
  159. package/src/commands/auth-broker.ts +3 -2
  160. package/src/commands/auth-gateway.ts +3 -2
  161. package/src/commands/bench.ts +2 -3
  162. package/src/commands/browser-relay.ts +53 -0
  163. package/src/commands/cleanse.ts +2 -2
  164. package/src/commands/commit.ts +3 -2
  165. package/src/commands/complete.ts +2 -1
  166. package/src/commands/completions.ts +3 -2
  167. package/src/commands/config.ts +3 -2
  168. package/src/commands/dry-balance.ts +2 -2
  169. package/src/commands/gallery.ts +3 -2
  170. package/src/commands/gc.ts +3 -2
  171. package/src/commands/grep.ts +3 -2
  172. package/src/commands/grievances.ts +3 -2
  173. package/src/commands/install.ts +2 -2
  174. package/src/commands/join.ts +3 -2
  175. package/src/commands/launch-help.ts +116 -0
  176. package/src/commands/launch.ts +7 -191
  177. package/src/commands/models.ts +3 -2
  178. package/src/commands/plugin.ts +3 -2
  179. package/src/commands/read.ts +3 -2
  180. package/src/commands/say.ts +3 -2
  181. package/src/commands/setup.ts +3 -2
  182. package/src/commands/shell.ts +3 -2
  183. package/src/commands/ssh.ts +3 -2
  184. package/src/commands/stats.ts +3 -2
  185. package/src/commands/tiny-models.ts +2 -2
  186. package/src/commands/token.ts +2 -2
  187. package/src/commands/ttsr.ts +2 -2
  188. package/src/commands/update.ts +3 -2
  189. package/src/commands/usage.ts +3 -2
  190. package/src/commands/web-search.ts +3 -2
  191. package/src/commands/worktree.ts +3 -2
  192. package/src/config/keybindings.ts +19 -9
  193. package/src/config/mcp-schema.json +5 -0
  194. package/src/config/model-discovery.ts +30 -13
  195. package/src/config/model-registry.ts +16 -6
  196. package/src/config/models-config-schema-bundle.ts +9 -0
  197. package/src/config/resolve-config-value.ts +2 -1
  198. package/src/config/service-tier.ts +5 -0
  199. package/src/config/settings-schema.ts +73 -21
  200. package/src/cursor-bridge-tools.ts +1 -1
  201. package/src/cursor.ts +10 -14
  202. package/src/discovery/builtin.ts +10 -0
  203. package/src/discovery/helpers.ts +10 -0
  204. package/src/discovery/mcp-json.ts +11 -1
  205. package/src/discovery/omp-extension-roots.ts +79 -20
  206. package/src/discovery/omp-plugins.ts +10 -1
  207. package/src/edit/diff.ts +17 -8
  208. package/src/edit/index.ts +20 -7
  209. package/src/edit/modes/replace.ts +93 -40
  210. package/src/edit/renderer.ts +1 -1
  211. package/src/edit/streaming.ts +14 -17
  212. package/src/eval/py/kernel.ts +2 -1
  213. package/src/eval/py/spawn-options.ts +24 -29
  214. package/src/export/html/template.js +8 -26
  215. package/src/extensibility/extensions/loader.ts +66 -28
  216. package/src/extensibility/extensions/wrapper.ts +1 -0
  217. package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
  218. package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
  219. package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
  220. package/src/extensibility/plugins/marketplace/registry.ts +4 -8
  221. package/src/extensibility/skills.ts +11 -0
  222. package/src/extensibility/utils.ts +10 -2
  223. package/src/launch/broker.ts +1 -1
  224. package/src/launch/client.ts +32 -13
  225. package/src/launch/ensure.ts +73 -0
  226. package/src/launch/paths.ts +3 -6
  227. package/src/launch/protocol.ts +2 -2
  228. package/src/lsp/client.ts +23 -2
  229. package/src/lsp/index.ts +8 -0
  230. package/src/lsp/mux/daemon.ts +348 -0
  231. package/src/lsp/mux/protocol.ts +96 -0
  232. package/src/lsp/mux/server.ts +797 -0
  233. package/src/lsp/types.ts +28 -2
  234. package/src/main.ts +31 -24
  235. package/src/mcp/config.ts +1 -0
  236. package/src/mcp/oauth-flow.ts +11 -1
  237. package/src/mcp/request-id.ts +24 -0
  238. package/src/mcp/transports/http.ts +4 -2
  239. package/src/mcp/transports/sse.ts +4 -2
  240. package/src/mcp/transports/stdio.ts +4 -2
  241. package/src/mcp/types.ts +15 -0
  242. package/src/memory-backend/index.ts +1 -0
  243. package/src/memory-backend/messages.ts +19 -0
  244. package/src/mnemopi/embed-client.ts +49 -2
  245. package/src/mnemopi/state.ts +57 -23
  246. package/src/modes/components/agent-hub.ts +1 -1
  247. package/src/modes/components/assistant-message.ts +11 -0
  248. package/src/modes/components/chat-transcript-builder.ts +4 -0
  249. package/src/modes/components/custom-editor.ts +10 -1
  250. package/src/modes/components/model-browser.ts +25 -17
  251. package/src/modes/components/model-picker.ts +10 -6
  252. package/src/modes/components/read-tool-group.ts +36 -0
  253. package/src/modes/components/status-line/component.ts +1 -1
  254. package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
  255. package/src/modes/components/tool-execution.ts +85 -20
  256. package/src/modes/components/tree-selector.ts +46 -48
  257. package/src/modes/controllers/command-controller.ts +2 -2
  258. package/src/modes/controllers/event-controller.ts +199 -10
  259. package/src/modes/controllers/input-controller.ts +39 -1
  260. package/src/modes/controllers/mcp-command-controller.ts +11 -5
  261. package/src/modes/controllers/selector-controller.ts +47 -6
  262. package/src/modes/interactive-mode.ts +2 -0
  263. package/src/modes/types.ts +6 -1
  264. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  265. package/src/modes/utils/interactive-context-helpers.ts +1 -0
  266. package/src/modes/utils/ui-helpers.ts +6 -10
  267. package/src/modes/workflow.ts +8 -2
  268. package/src/prompts/agents/init.md +1 -1
  269. package/src/prompts/system/plan-mode-active.md +2 -2
  270. package/src/prompts/system/system-prompt.md +26 -52
  271. package/src/prompts/system/workflow-notice.md +3 -3
  272. package/src/prompts/tools/ast-grep.md +1 -1
  273. package/src/prompts/tools/bash.md +1 -1
  274. package/src/prompts/tools/browser.md +1 -0
  275. package/src/prompts/tools/computer.md +21 -21
  276. package/src/prompts/tools/glob.md +1 -1
  277. package/src/prompts/tools/grep.md +1 -1
  278. package/src/prompts/tools/replace.md +5 -4
  279. package/src/prompts/tools/task.md +4 -4
  280. package/src/registry/agent-lifecycle.ts +36 -11
  281. package/src/registry/agent-registry.ts +12 -5
  282. package/src/sdk.ts +102 -35
  283. package/src/secrets/index.ts +16 -18
  284. package/src/session/agent-session-types.ts +3 -1
  285. package/src/session/agent-session.ts +23 -2
  286. package/src/session/agent-storage.ts +6 -4
  287. package/src/session/history-storage.ts +4 -2
  288. package/src/session/indexed-session-storage.ts +9 -0
  289. package/src/session/messages.ts +31 -7
  290. package/src/session/model-controls.ts +0 -1
  291. package/src/session/prewalk.ts +24 -2
  292. package/src/session/session-advisors.ts +21 -3
  293. package/src/session/session-context.ts +16 -12
  294. package/src/session/session-dump-format.ts +1 -1
  295. package/src/session/session-maintenance.ts +41 -4
  296. package/src/session/session-manager.ts +181 -94
  297. package/src/session/session-paths.ts +118 -55
  298. package/src/session/session-stats.ts +48 -3
  299. package/src/session/session-storage.ts +30 -22
  300. package/src/session/session-tools.ts +25 -23
  301. package/src/session/stream-guards.ts +1 -1
  302. package/src/slash-commands/builtin-registry.ts +29 -26
  303. package/src/system-prompt.ts +14 -4
  304. package/src/task/executor.ts +8 -1
  305. package/src/task/index.ts +23 -8
  306. package/src/task/spawn-policy.ts +14 -0
  307. package/src/thinking.ts +2 -8
  308. package/src/tiny/text.ts +12 -0
  309. package/src/tools/ast-grep.ts +10 -4
  310. package/src/tools/browser/cmux/cmux-tab.ts +5 -10
  311. package/src/tools/browser/cmux/rpc.ts +2 -8
  312. package/src/tools/browser/registry.ts +53 -2
  313. package/src/tools/browser/relay/bridge.ts +945 -0
  314. package/src/tools/browser/relay/daemon.ts +117 -0
  315. package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
  316. package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
  317. package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
  318. package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
  319. package/src/tools/browser/relay/kind.ts +41 -0
  320. package/src/tools/browser/relay/protocol.ts +54 -0
  321. package/src/tools/browser/relay/server.ts +141 -0
  322. package/src/tools/browser/render.ts +4 -1
  323. package/src/tools/browser/shared-daemon.ts +7 -58
  324. package/src/tools/browser/tab-supervisor.ts +5 -4
  325. package/src/tools/browser/tab-worker.ts +33 -12
  326. package/src/tools/browser.ts +26 -1
  327. package/src/tools/computer/exposure.ts +11 -35
  328. package/src/tools/computer/protocol.ts +51 -10
  329. package/src/tools/computer/supervisor.ts +227 -124
  330. package/src/tools/computer/worker-entry.ts +11 -6
  331. package/src/tools/computer/worker.ts +695 -81
  332. package/src/tools/computer-renderer.ts +104 -65
  333. package/src/tools/computer.ts +134 -428
  334. package/src/tools/context.ts +3 -0
  335. package/src/tools/default-renderer.ts +19 -4
  336. package/src/tools/glob.ts +9 -2
  337. package/src/tools/grep.ts +12 -6
  338. package/src/tools/index.ts +10 -6
  339. package/src/tools/inspect-image.ts +32 -6
  340. package/src/tools/render-utils.ts +2 -0
  341. package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
  342. package/src/tools/tool-timeouts.ts +1 -0
  343. package/src/tools/xdev.ts +29 -2
  344. package/src/utils/clipboard.ts +40 -14
  345. package/src/utils/command-args.ts +26 -28
  346. package/src/utils/tool-choice.ts +0 -13
  347. package/src/web/kagi.ts +2 -1
  348. package/src/web/search/index.ts +18 -2
  349. package/src/web/search/providers/anthropic.ts +7 -2
  350. package/src/web/search/providers/base.ts +2 -0
  351. package/src/web/search/providers/brave.ts +3 -1
  352. package/src/web/search/providers/browser-page.ts +6 -4
  353. package/src/web/search/providers/codex.ts +4 -1
  354. package/src/web/search/providers/duckduckgo.ts +2 -1
  355. package/src/web/search/providers/ecosia.ts +2 -1
  356. package/src/web/search/providers/exa.ts +4 -2
  357. package/src/web/search/providers/firecrawl.ts +3 -1
  358. package/src/web/search/providers/gemini.ts +8 -2
  359. package/src/web/search/providers/google.ts +2 -1
  360. package/src/web/search/providers/jina.ts +12 -2
  361. package/src/web/search/providers/kagi.ts +3 -0
  362. package/src/web/search/providers/kimi.ts +5 -1
  363. package/src/web/search/providers/mojeek.ts +2 -1
  364. package/src/web/search/providers/parallel.ts +5 -1
  365. package/src/web/search/providers/perplexity.ts +6 -3
  366. package/src/web/search/providers/public.ts +1 -1
  367. package/src/web/search/providers/searxng.ts +11 -5
  368. package/src/web/search/providers/startpage.ts +10 -4
  369. package/src/web/search/providers/synthetic.ts +11 -5
  370. package/src/web/search/providers/tavily.ts +3 -1
  371. package/src/web/search/providers/tinyfish.ts +3 -1
  372. package/src/web/search/providers/utils.ts +12 -10
  373. package/src/web/search/providers/xai.ts +2 -2
  374. package/src/web/search/providers/zai.ts +18 -3
  375. package/src/web/search/types.ts +6 -0
@@ -24,6 +24,7 @@ import type {
24
24
  } from "@oh-my-pi/pi-ai";
25
25
  import * as AIError from "@oh-my-pi/pi-ai/error";
26
26
  import { isRecord, logger, prompt } from "@oh-my-pi/pi-utils";
27
+ import { COLLAB_PROMPT_MESSAGE_TYPE } from "@oh-my-pi/pi-wire";
27
28
  import userInterjectionTemplate from "../prompts/steering/user-interjection.md" with { type: "text" };
28
29
  import { formatTitleConversationContext, type TitleConversationTurn } from "../tiny/message-preproc";
29
30
 
@@ -614,8 +615,18 @@ export function normalizeCustomMessagePayload<T = unknown>(
614
615
  };
615
616
  }
616
617
 
617
- function isSteeringUserMessage(message: AgentMessage | undefined): message is UserMessage & { steering: true } {
618
- return message?.role === "user" && message.steering === true;
618
+ type SteeringUserMessage =
619
+ | (UserMessage & { steering: true })
620
+ | (CustomMessage & {
621
+ customType: typeof COLLAB_PROMPT_MESSAGE_TYPE;
622
+ attribution: "user";
623
+ });
624
+
625
+ function isSteeringUserMessage(message: AgentMessage | undefined): message is SteeringUserMessage {
626
+ if (message?.role === "user") return message.steering === true;
627
+ return (
628
+ message?.role === "custom" && message.customType === COLLAB_PROMPT_MESSAGE_TYPE && message.attribution === "user"
629
+ );
619
630
  }
620
631
 
621
632
  function userMessageWithoutSteering(message: UserMessage): UserMessage {
@@ -655,17 +666,26 @@ function getArrayContentImages(content: (TextContent | ImageContent)[]): ImageCo
655
666
  return images ?? [];
656
667
  }
657
668
 
658
- function wrapSteeringUserMessage(message: UserMessage): UserMessage {
669
+ function wrapSteeringUserMessage(message: SteeringUserMessage): UserMessage {
670
+ const userMessage: UserMessage =
671
+ message.role === "user"
672
+ ? userMessageWithoutSteering(message)
673
+ : {
674
+ role: "user",
675
+ content: message.content,
676
+ attribution: "user",
677
+ timestamp: message.timestamp,
678
+ };
659
679
  if (typeof message.content === "string") {
660
- if (message.content.length === 0) return message;
661
- return { ...userMessageWithoutSteering(message), content: renderSteeringEnvelope(message.content) };
680
+ if (message.content.length === 0) return message.role === "user" ? message : userMessage;
681
+ return { ...userMessage, content: renderSteeringEnvelope(message.content) };
662
682
  }
663
683
 
664
684
  const text = getArrayContentText(message.content);
665
- if (text.length === 0) return message;
685
+ if (text.length === 0) return message.role === "user" ? message : userMessage;
666
686
  const content: (TextContent | ImageContent)[] = [{ type: "text", text: renderSteeringEnvelope(text) }];
667
687
  content.push(...getArrayContentImages(message.content));
668
- return { ...userMessageWithoutSteering(message), content };
688
+ return { ...userMessage, content };
669
689
  }
670
690
 
671
691
  export function wrapSteeringForModel(messages: AgentMessage[]): AgentMessage[] {
@@ -1146,6 +1166,10 @@ function convertOne(m: AgentMessage, interruptedNext: boolean): Message[] {
1146
1166
  }
1147
1167
  case "custom": {
1148
1168
  if (!isCustomMessageContent(m.content)) return [];
1169
+ if (isSteeringUserMessage(m)) {
1170
+ const converted = convertMessageToLlm(wrapSteeringUserMessage(m));
1171
+ return converted ? [converted] : [];
1172
+ }
1149
1173
  if (isUserInvokedSkillPrompt(m)) {
1150
1174
  return [
1151
1175
  {
@@ -209,7 +209,6 @@ export class ModelControls {
209
209
  selector?: string;
210
210
  thinkingLevel?: ThinkingLevel;
211
211
  persist?: boolean;
212
- currentContextTokens?: number;
213
212
  },
214
213
  ): Promise<{ switched: boolean }> {
215
214
  const previousEditMode = this.#host.resolveActiveEditMode();
@@ -1,6 +1,6 @@
1
1
  import type { Agent, AgentMessage, AgentToolResult, AgentTurnEndContext } from "@oh-my-pi/pi-agent-core";
2
2
  import { invalidateMessageCache } from "@oh-my-pi/pi-agent-core/compaction";
3
- import type { Model } from "@oh-my-pi/pi-ai";
3
+ import type { Model, ToolResultMessage } from "@oh-my-pi/pi-ai";
4
4
  import { prompt } from "@oh-my-pi/pi-utils";
5
5
  import type { LocalProtocolOptions } from "../internal-urls";
6
6
  import { resolveApprovedPlan } from "../plan-mode/approved-plan";
@@ -25,6 +25,28 @@ const PREWALK_ACTION_TOOLS: Record<string, true> = {
25
25
  };
26
26
  const PLAN_YOLO_HANDOFF_MESSAGE_TYPE = "plan-yolo-handoff";
27
27
 
28
+ /**
29
+ * Whether a completed tool result is the first workspace-mutating action that
30
+ * arms the prewalk hand-off. A direct `edit`/`write` call always counts; a
31
+ * `write` that dispatched an `xd://` device (e.g. `lsp`, `ast_edit`, `debug`)
32
+ * counts only when the wrapped tool resolved to a `write`/`exec` approval tier.
33
+ * Read-only device calls — LSP navigation, `debug` inspection, `ast_edit` on
34
+ * internal URLs, help lookups — leave the tier `read` (or absent) and must not
35
+ * switch the model mid-investigation (issue #7312).
36
+ */
37
+ function isPrewalkImplementationAction(result: ToolResultMessage): boolean {
38
+ if (!PREWALK_ACTION_TOOLS[result.toolName]) return false;
39
+ const details = result.details;
40
+ // A direct filesystem edit/write carries no `xd://` dispatch metadata.
41
+ if (!details || typeof details !== "object" || !("xdev" in details) || !details.xdev) return true;
42
+ const xdev = details.xdev;
43
+ // Device dispatch: switch only on a genuine mutation tier. An absent tier
44
+ // (help lookup, unresolved approval) declines the switch, matching the
45
+ // reporter's "stay on the large model a couple turns longer" preference.
46
+ if (typeof xdev !== "object" || !("tier" in xdev)) return false;
47
+ return xdev.tier === "write" || xdev.tier === "exec";
48
+ }
49
+
28
50
  /** Capabilities the prewalk coordinator borrows from its owning session. */
29
51
  export interface PrewalkCoordinatorHost {
30
52
  agent: Agent;
@@ -100,7 +122,7 @@ export class PrewalkCoordinator {
100
122
 
101
123
  const todoGateOpen = this.#todoSeen || !this.#host.getActiveToolNames().includes("todo");
102
124
  const action = todoGateOpen
103
- ? context.toolResults.find(result => PREWALK_ACTION_TOOLS[result.toolName])
125
+ ? context.toolResults.find(result => isPrewalkImplementationAction(result))
104
126
  : undefined;
105
127
  if (!action) {
106
128
  if (!this.#planInjected) {
@@ -191,7 +191,7 @@ export interface SessionAdvisorsOptions {
191
191
  /**
192
192
  * Build the `replace`-mode `edit` a Cursor `pi_edit` frame needs. The
193
193
  * advisor's own instance follows the configured `edit.mode` (`hashline` by
194
- * default), whose schema the frame's `old_text`/`new_text` pairs do not
194
+ * default), whose schema the frame's `old_string`/`new_string` args do not
195
195
  * match, so without this every native advisor edit fails validation.
196
196
  */
197
197
  createEditTool?(): AgentTool | undefined;
@@ -760,7 +760,7 @@ export class SessionAdvisors {
760
760
  // to delete workspace files it was never granted (issue #5680 review).
761
761
  const advisorCanMutateFiles = advisorToolMap.has("write") || advisorToolMap.has("edit");
762
762
  if (advisorCanMutateFiles) availableAdvisorToolNames.add("delete");
763
- // `pi_edit` speaks `replace`'s `old_text`/`new_text` schema, which the
763
+ // `pi_edit` speaks `replace`'s `old_string`/`new_string` schema, which the
764
764
  // advisor's ordinary `EditTool` (built at the session's configured
765
765
  // `edit.mode`, `hashline` by default) does not accept. The bridge map
766
766
  // swaps in a `replace` instance for the exec channel only — the
@@ -877,7 +877,10 @@ export class SessionAdvisors {
877
877
  this.#maintainAdvisorContext(advisorRef, incomingTokens, signal),
878
878
  obfuscator: this.#host.obfuscator,
879
879
  getModelIdentity: () => formatModelString(advisorRef.agent.state.model),
880
- beginAdvisorUpdate: () => advisorRef.emissionGuard.beginUpdate(),
880
+ beginAdvisorUpdate: inProgress => {
881
+ advisorRef.adviseTool.beginUpdate(inProgress);
882
+ advisorRef.emissionGuard.beginUpdate();
883
+ },
881
884
  onTurnError: (error, failedMessages, signal) =>
882
885
  this.#recoverAdvisorTurn(advisorRef, error, failedMessages, signal),
883
886
  onTurnSuccess: async () => {
@@ -1449,6 +1452,7 @@ export class SessionAdvisors {
1449
1452
  promptCacheKey: advisorProviderSessionId,
1450
1453
  metadata: advisorMetadata,
1451
1454
  providerSessionState: this.#host.providerSessionState,
1455
+ preferWebsockets: this.#host.preferWebsockets,
1452
1456
  codexCompaction,
1453
1457
  },
1454
1458
  );
@@ -1579,6 +1583,20 @@ export class SessionAdvisors {
1579
1583
  return this.#advisors.length;
1580
1584
  }
1581
1585
 
1586
+ /**
1587
+ * Swap the project context prompt handed to advisor sessions after context
1588
+ * files change (`/reload-plugins` edit/disable). Rebuilds live runtimes in
1589
+ * place so the next advisor turn evaluates against the current instructions;
1590
+ * a no-op when the rendered prompt is unchanged.
1591
+ */
1592
+ setContextPrompt(contextPrompt: string | undefined): void {
1593
+ if (contextPrompt === this.#advisorContextPrompt) return;
1594
+ this.#advisorContextPrompt = contextPrompt;
1595
+ if (!this.#advisorEnabled || this.#advisors.length === 0) return;
1596
+ this.#stopAdvisorRuntime();
1597
+ this.#buildAdvisorRuntime(true);
1598
+ }
1599
+
1582
1600
  /**
1583
1601
  * Whether the advisor setting is enabled for this session.
1584
1602
  */
@@ -154,6 +154,21 @@ function snapcompactHistoryBlocksForContext(
154
154
  return snapcompact.historyBlocks(archive, snapcompactHistoryBlockOptions(archive, options));
155
155
  }
156
156
 
157
+ export function getOpenAiRemoteCompactionPayload(
158
+ compaction: CompactionEntry | null | undefined,
159
+ ): ProviderPayload | undefined {
160
+ const candidate = compaction?.preserveData?.openaiRemoteCompaction;
161
+ if (!candidate || typeof candidate !== "object") return undefined;
162
+ const remote = candidate as { provider?: unknown; replacementHistory?: unknown };
163
+ if (typeof remote.provider !== "string" || remote.provider.length === 0) return undefined;
164
+ if (!Array.isArray(remote.replacementHistory)) return undefined;
165
+ return {
166
+ type: "openaiResponsesHistory",
167
+ provider: remote.provider,
168
+ items: remote.replacementHistory as Array<Record<string, unknown>>,
169
+ };
170
+ }
171
+
157
172
  export function buildSessionContext(
158
173
  entries: SessionEntry[],
159
174
  leafId?: string | null,
@@ -365,18 +380,7 @@ export function buildSessionContext(
365
380
  }
366
381
  }
367
382
  } else if (compaction) {
368
- const providerPayload: ProviderPayload | undefined = (() => {
369
- const candidate = compaction.preserveData?.openaiRemoteCompaction;
370
- if (!candidate || typeof candidate !== "object") return undefined;
371
- const remote = candidate as { provider?: unknown; replacementHistory?: unknown };
372
- if (typeof remote.provider !== "string" || remote.provider.length === 0) return undefined;
373
- if (!Array.isArray(remote.replacementHistory)) return undefined;
374
- return {
375
- type: "openaiResponsesHistory",
376
- provider: remote.provider,
377
- items: remote.replacementHistory as Array<Record<string, unknown>>,
378
- };
379
- })();
383
+ const providerPayload = getOpenAiRemoteCompactionPayload(compaction);
380
384
  const remoteReplacementHistory = providerPayload?.items;
381
385
 
382
386
  // Re-attach any archived snapcompact frames so the model can keep
@@ -82,7 +82,7 @@ function renderDumpHeader(options: FormatSessionDumpTextOptions, inventoryTools:
82
82
  const hasSystemPromptToolInventory = options.inlineToolDescriptors === true;
83
83
  if (inventoryTools.length > 0 && !hasSystemPromptToolInventory) {
84
84
  lines.push("## Available Tools\n");
85
- lines.push(renderToolInventory(inventoryTools, model?.id ?? ""));
85
+ lines.push(renderToolInventory(inventoryTools));
86
86
  lines.push("\n");
87
87
  }
88
88
 
@@ -26,8 +26,10 @@ import {
26
26
  DEFAULT_SHAKE_CONFIG,
27
27
  effectiveReserveTokens,
28
28
  estimateTokens,
29
+ hasContextTokenUsage,
29
30
  NativeCompactionError,
30
31
  prepareCompaction,
32
+ RESCUE_SHAKE_CONFIG,
31
33
  resolveBudgetReserveTokens,
32
34
  resolveThresholdTokens,
33
35
  type ShakeConfig,
@@ -74,7 +76,7 @@ import {
74
76
  resolveRoleModelFull,
75
77
  } from "./role-models";
76
78
  import type { SessionContext } from "./session-context";
77
- import { getLatestCompactionEntry } from "./session-context";
79
+ import { getLatestCompactionEntry, getOpenAiRemoteCompactionPayload } from "./session-context";
78
80
  import type { CompactionEntry, SessionEntry } from "./session-entries";
79
81
  import type { SessionManager } from "./session-manager";
80
82
  import type { ShakeMode, ShakeResult } from "./shake-types";
@@ -180,6 +182,7 @@ export interface SessionMaintenanceHost {
180
182
  extensionRunner: ExtensionRunner | undefined;
181
183
  sideStreamFn: StreamFn;
182
184
  providerSessionState: Map<string, ProviderSessionState>;
185
+ preferWebsockets: boolean | undefined;
183
186
  model(): Model | undefined;
184
187
  thinkingLevel(): ThinkingLevel | undefined;
185
188
  isDisposed(): boolean;
@@ -234,6 +237,7 @@ export interface SessionMaintenanceHost {
234
237
  syncTodoPhasesFromBranch(): void;
235
238
  resetAdvisorRuntimes(): void;
236
239
  rebaseAfterCompaction(): void;
240
+ recordAnchoredHistoryRewrite(tokensRemoved: number): void;
237
241
  getContextBreakdown(options?: {
238
242
  contextWindow?: number;
239
243
  pendingMessages?: AgentMessage[];
@@ -460,11 +464,12 @@ export class SessionMaintenance {
460
464
  }
461
465
 
462
466
  const branchEntries = this.#host.sessionManager.getBranch();
467
+ const latestCompaction = getLatestCompactionEntry(branchEntries);
463
468
  const config = this.#withPlanProtection({
464
469
  ...(opts.config ?? AGGRESSIVE_SHAKE_CONFIG),
465
470
  // Skip entries summarized away by the latest compaction — shaking them
466
471
  // only churns persisted history with no prompt/cache effect.
467
- keepBoundaryId: getLatestCompactionEntry(branchEntries)?.firstKeptEntryId,
472
+ keepBoundaryId: latestCompaction?.firstKeptEntryId,
468
473
  });
469
474
  const regions = collectShakeRegions(branchEntries, config);
470
475
  if (regions.length === 0) {
@@ -474,20 +479,50 @@ export class SessionMaintenance {
474
479
  const artifactId = await this.#saveShakeArtifact(regions);
475
480
  const replacements = regions.map((region, index) => this.#shakeElidePlaceholder(region, index, artifactId));
476
481
 
482
+ const hasRemoteReplacementHistory = getOpenAiRemoteCompactionPayload(latestCompaction) !== undefined;
483
+ const compactionIndex = latestCompaction ? branchEntries.lastIndexOf(latestCompaction) : -1;
484
+ let anchorIndex = -1;
485
+ for (let index = branchEntries.length - 1; index > compactionIndex; index--) {
486
+ const entry = branchEntries[index];
487
+ if (entry.type !== "message" || entry.message.role !== "assistant") continue;
488
+ const assistant = entry.message;
489
+ if (
490
+ assistant.stopReason !== "aborted" &&
491
+ assistant.stopReason !== "error" &&
492
+ assistant.usage &&
493
+ hasContextTokenUsage(assistant.usage)
494
+ ) {
495
+ anchorIndex = index;
496
+ break;
497
+ }
498
+ }
499
+ const entryIndexes = new Map(branchEntries.map((entry, index) => [entry, index]));
500
+
477
501
  let toolResultsDropped = 0;
478
502
  let blocksDropped = 0;
479
503
  let originalTokens = 0;
480
504
  let replacementTokens = 0;
505
+ let anchoredTokensRemoved = 0;
481
506
  const items = regions.map((region, index) => {
482
507
  if (region.kind === "toolResult") toolResultsDropped++;
483
508
  else blocksDropped++;
484
509
  originalTokens += region.tokens;
485
510
  const replacement = replacements[index];
486
- if (replacement.length > 0) replacementTokens += countTokens(replacement);
511
+ const replacementTokenCount = replacement.length > 0 ? countTokens(replacement) : 0;
512
+ replacementTokens += replacementTokenCount;
513
+ const entryIndex = entryIndexes.get(region.entry) ?? -1;
514
+ if (
515
+ entryIndex >= 0 &&
516
+ entryIndex < anchorIndex &&
517
+ (!hasRemoteReplacementHistory || entryIndex > compactionIndex)
518
+ ) {
519
+ anchoredTokensRemoved += Math.max(0, region.tokens - replacementTokenCount);
520
+ }
487
521
  return { region, replacement };
488
522
  });
489
523
 
490
524
  applyShakeRegions(items);
525
+ this.#host.recordAnchoredHistoryRewrite(anchoredTokensRemoved);
491
526
 
492
527
  await this.#host.sessionManager.rewriteEntries();
493
528
  const sessionContext = this.#host.buildDisplaySessionContext();
@@ -1541,6 +1576,7 @@ export class SessionMaintenance {
1541
1576
  sessionId: this.#host.sessionId(),
1542
1577
  promptCacheKey: this.#host.agent.promptCacheKey ?? this.#host.agent.sessionId,
1543
1578
  providerSessionState: this.#host.providerSessionState,
1579
+ preferWebsockets: this.#host.preferWebsockets,
1544
1580
  // Route every summarization HTTP request through the
1545
1581
  // session's side-stream transport so the provider
1546
1582
  // concurrency cap (e.g. providers.ollama-cloud.maxConcurrency)
@@ -1857,7 +1893,7 @@ export class SessionMaintenance {
1857
1893
  let elideSink = "placeholders";
1858
1894
  if (!options.skipElide) {
1859
1895
  try {
1860
- const result = await this.#host.shake("elide", { signal });
1896
+ const result = await this.#host.shake("elide", { config: RESCUE_SHAKE_CONFIG, signal });
1861
1897
  elided = result.toolResultsDropped + result.blocksDropped;
1862
1898
  elidedTokens = result.tokensFreed;
1863
1899
  if (result.artifactId) elideSink = "an artifact";
@@ -2587,6 +2623,7 @@ export class SessionMaintenance {
2587
2623
  sessionId: this.#host.sessionId(),
2588
2624
  promptCacheKey: this.#host.agent.promptCacheKey ?? this.#host.agent.sessionId,
2589
2625
  providerSessionState: this.#host.providerSessionState,
2626
+ preferWebsockets: this.#host.preferWebsockets,
2590
2627
  codexCompaction,
2591
2628
  },
2592
2629
  );