@code-yeongyu/senpi 2026.7.17-5 → 2026.7.20-2

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 (605) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +5 -2
  3. package/dist/cli/neo/build-argv.d.ts.map +1 -1
  4. package/dist/cli/neo/build-argv.js +2 -0
  5. package/dist/cli/neo/build-argv.js.map +1 -1
  6. package/dist/core/agent-session-services.d.ts.map +1 -1
  7. package/dist/core/agent-session-services.js +11 -4
  8. package/dist/core/agent-session-services.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +37 -0
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +395 -73
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/compaction/compaction.d.ts +2 -2
  14. package/dist/core/compaction/compaction.d.ts.map +1 -1
  15. package/dist/core/compaction/compaction.js +59 -15
  16. package/dist/core/compaction/compaction.js.map +1 -1
  17. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  18. package/dist/core/extensions/builtin/compaction/index.js +68 -10
  19. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  20. package/dist/core/extensions/builtin/compaction/speculative.d.ts +7 -1
  21. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  22. package/dist/core/extensions/builtin/compaction/speculative.js +29 -11
  23. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  24. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts +9 -7
  25. package/dist/core/extensions/builtin/compaction/todo-bridge.d.ts.map +1 -1
  26. package/dist/core/extensions/builtin/compaction/todo-bridge.js +34 -9
  27. package/dist/core/extensions/builtin/compaction/todo-bridge.js.map +1 -1
  28. package/dist/core/extensions/builtin/goal/command-registration.d.ts +2 -2
  29. package/dist/core/extensions/builtin/goal/command-registration.d.ts.map +1 -1
  30. package/dist/core/extensions/builtin/goal/command-registration.js +3 -4
  31. package/dist/core/extensions/builtin/goal/command-registration.js.map +1 -1
  32. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  33. package/dist/core/extensions/builtin/goal/index.js +11 -27
  34. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  35. package/dist/core/extensions/builtin/goal/tool-registration.d.ts +2 -2
  36. package/dist/core/extensions/builtin/goal/tool-registration.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/goal/tool-registration.js +2 -3
  38. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  39. package/dist/core/extensions/builtin/goal/turn-usage.d.ts +20 -0
  40. package/dist/core/extensions/builtin/goal/turn-usage.d.ts.map +1 -0
  41. package/dist/core/extensions/builtin/goal/turn-usage.js +61 -0
  42. package/dist/core/extensions/builtin/goal/turn-usage.js.map +1 -0
  43. package/dist/core/extensions/builtin/gpt-apply-patch/constants.d.ts +1 -0
  44. package/dist/core/extensions/builtin/gpt-apply-patch/constants.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/gpt-apply-patch/constants.js +5 -1
  46. package/dist/core/extensions/builtin/gpt-apply-patch/constants.js.map +1 -1
  47. package/dist/core/extensions/builtin/gpt-apply-patch/extension.d.ts +2 -1
  48. package/dist/core/extensions/builtin/gpt-apply-patch/extension.d.ts.map +1 -1
  49. package/dist/core/extensions/builtin/gpt-apply-patch/extension.js +48 -29
  50. package/dist/core/extensions/builtin/gpt-apply-patch/extension.js.map +1 -1
  51. package/dist/core/extensions/builtin/gpt-apply-patch/index.d.ts +2 -2
  52. package/dist/core/extensions/builtin/gpt-apply-patch/index.d.ts.map +1 -1
  53. package/dist/core/extensions/builtin/gpt-apply-patch/index.js +2 -2
  54. package/dist/core/extensions/builtin/gpt-apply-patch/index.js.map +1 -1
  55. package/dist/core/extensions/builtin/gpt-apply-patch/tool.d.ts +1 -1
  56. package/dist/core/extensions/builtin/gpt-apply-patch/tool.d.ts.map +1 -1
  57. package/dist/core/extensions/builtin/gpt-apply-patch/tool.js +5 -3
  58. package/dist/core/extensions/builtin/gpt-apply-patch/tool.js.map +1 -1
  59. package/dist/core/extensions/builtin/gpt-apply-patch/types.d.ts +7 -6
  60. package/dist/core/extensions/builtin/gpt-apply-patch/types.d.ts.map +1 -1
  61. package/dist/core/extensions/builtin/gpt-apply-patch/types.js.map +1 -1
  62. package/dist/core/extensions/builtin/hooks/matcher.d.ts.map +1 -1
  63. package/dist/core/extensions/builtin/hooks/matcher.js +1 -0
  64. package/dist/core/extensions/builtin/hooks/matcher.js.map +1 -1
  65. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  66. package/dist/core/extensions/builtin/index.js +4 -0
  67. package/dist/core/extensions/builtin/index.js.map +1 -1
  68. package/dist/core/extensions/builtin/model-fallback/index.d.ts +4 -0
  69. package/dist/core/extensions/builtin/model-fallback/index.d.ts.map +1 -0
  70. package/dist/core/extensions/builtin/model-fallback/index.js +55 -0
  71. package/dist/core/extensions/builtin/model-fallback/index.js.map +1 -0
  72. package/dist/core/extensions/builtin/model-fallback/settings.d.ts +6 -0
  73. package/dist/core/extensions/builtin/model-fallback/settings.d.ts.map +1 -0
  74. package/dist/core/extensions/builtin/model-fallback/settings.js +11 -0
  75. package/dist/core/extensions/builtin/model-fallback/settings.js.map +1 -0
  76. package/dist/core/extensions/builtin/model-fallback/ui.d.ts +12 -0
  77. package/dist/core/extensions/builtin/model-fallback/ui.d.ts.map +1 -0
  78. package/dist/core/extensions/builtin/model-fallback/ui.js +72 -0
  79. package/dist/core/extensions/builtin/model-fallback/ui.js.map +1 -0
  80. package/dist/core/extensions/builtin/nested-agents-md/index.d.ts.map +1 -1
  81. package/dist/core/extensions/builtin/nested-agents-md/index.js +4 -1
  82. package/dist/core/extensions/builtin/nested-agents-md/index.js.map +1 -1
  83. package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js +1 -1
  84. package/dist/core/extensions/builtin/prompt-preset/glm-5-2.js.map +1 -1
  85. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js +2 -2
  86. package/dist/core/extensions/builtin/prompt-preset/gpt-5.5.js.map +1 -1
  87. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +2 -2
  88. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  89. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.d.ts +3 -0
  90. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.d.ts.map +1 -0
  91. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js +80 -0
  92. package/dist/core/extensions/builtin/prompt-preset/grok-4.5.js.map +1 -0
  93. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/presets.js +14 -0
  95. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  96. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  97. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  98. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  99. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  100. package/dist/core/extensions/builtin/rules/index.d.ts.map +1 -1
  101. package/dist/core/extensions/builtin/rules/index.js +4 -1
  102. package/dist/core/extensions/builtin/rules/index.js.map +1 -1
  103. package/dist/core/extensions/builtin/terminal/shared.d.ts +7 -0
  104. package/dist/core/extensions/builtin/terminal/shared.d.ts.map +1 -1
  105. package/dist/core/extensions/builtin/terminal/shared.js +7 -0
  106. package/dist/core/extensions/builtin/terminal/shared.js.map +1 -1
  107. package/dist/core/extensions/builtin/terminal/tools/bash.d.ts.map +1 -1
  108. package/dist/core/extensions/builtin/terminal/tools/bash.js +68 -6
  109. package/dist/core/extensions/builtin/terminal/tools/bash.js.map +1 -1
  110. package/dist/core/extensions/builtin/todotools/commands.d.ts +18 -0
  111. package/dist/core/extensions/builtin/todotools/commands.d.ts.map +1 -0
  112. package/dist/core/extensions/builtin/todotools/commands.js +395 -0
  113. package/dist/core/extensions/builtin/todotools/commands.js.map +1 -0
  114. package/dist/core/extensions/builtin/todotools/index.d.ts +4 -1
  115. package/dist/core/extensions/builtin/todotools/index.d.ts.map +1 -1
  116. package/dist/core/extensions/builtin/todotools/index.js +17 -14
  117. package/dist/core/extensions/builtin/todotools/index.js.map +1 -1
  118. package/dist/core/extensions/builtin/todotools/markdown.d.ts +13 -0
  119. package/dist/core/extensions/builtin/todotools/markdown.d.ts.map +1 -0
  120. package/dist/core/extensions/builtin/todotools/markdown.js +82 -0
  121. package/dist/core/extensions/builtin/todotools/markdown.js.map +1 -0
  122. package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -1
  123. package/dist/core/extensions/builtin/todotools/prompt.d.ts.map +1 -1
  124. package/dist/core/extensions/builtin/todotools/prompt.js +50 -153
  125. package/dist/core/extensions/builtin/todotools/prompt.js.map +1 -1
  126. package/dist/core/extensions/builtin/todotools/state.d.ts +67 -14
  127. package/dist/core/extensions/builtin/todotools/state.d.ts.map +1 -1
  128. package/dist/core/extensions/builtin/todotools/state.js +400 -35
  129. package/dist/core/extensions/builtin/todotools/state.js.map +1 -1
  130. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts +22 -0
  131. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -0
  132. package/dist/core/extensions/builtin/todotools/tools/todo.js +229 -0
  133. package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -0
  134. package/dist/core/extensions/builtin/video-in/index.d.ts +3 -0
  135. package/dist/core/extensions/builtin/video-in/index.d.ts.map +1 -0
  136. package/dist/core/extensions/builtin/video-in/index.js +111 -0
  137. package/dist/core/extensions/builtin/video-in/index.js.map +1 -0
  138. package/dist/core/extensions/builtin/websearch/websearch/renderers.d.ts.map +1 -1
  139. package/dist/core/extensions/builtin/websearch/websearch/renderers.js +13 -4
  140. package/dist/core/extensions/builtin/websearch/websearch/renderers.js.map +1 -1
  141. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts +3 -2
  142. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts.map +1 -1
  143. package/dist/core/extensions/builtin/websearch/websearch/search.js +2 -1
  144. package/dist/core/extensions/builtin/websearch/websearch/search.js.map +1 -1
  145. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts.map +1 -1
  146. package/dist/core/extensions/builtin/websearch/websearch/tool.js +17 -1
  147. package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
  148. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +2 -0
  149. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
  150. package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
  151. package/dist/core/extensions/loader.d.ts +10 -1
  152. package/dist/core/extensions/loader.d.ts.map +1 -1
  153. package/dist/core/extensions/loader.js +44 -3
  154. package/dist/core/extensions/loader.js.map +1 -1
  155. package/dist/core/extensions/runner.d.ts +3 -1
  156. package/dist/core/extensions/runner.d.ts.map +1 -1
  157. package/dist/core/extensions/runner.js +60 -8
  158. package/dist/core/extensions/runner.js.map +1 -1
  159. package/dist/core/extensions/types.d.ts +103 -18
  160. package/dist/core/extensions/types.d.ts.map +1 -1
  161. package/dist/core/extensions/types.js.map +1 -1
  162. package/dist/core/model-registry.d.ts +5 -1
  163. package/dist/core/model-registry.d.ts.map +1 -1
  164. package/dist/core/model-registry.js +17 -2
  165. package/dist/core/model-registry.js.map +1 -1
  166. package/dist/core/model-runtime.d.ts +12 -1
  167. package/dist/core/model-runtime.d.ts.map +1 -1
  168. package/dist/core/model-runtime.js +51 -9
  169. package/dist/core/model-runtime.js.map +1 -1
  170. package/dist/core/prompt-templates.d.ts +1 -0
  171. package/dist/core/prompt-templates.d.ts.map +1 -1
  172. package/dist/core/prompt-templates.js +4 -4
  173. package/dist/core/prompt-templates.js.map +1 -1
  174. package/dist/core/provider-composer.d.ts +1 -1
  175. package/dist/core/provider-composer.d.ts.map +1 -1
  176. package/dist/core/provider-composer.js.map +1 -1
  177. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  178. package/dist/core/remote-catalog-provider.js +16 -3
  179. package/dist/core/remote-catalog-provider.js.map +1 -1
  180. package/dist/core/resource-loader.d.ts +6 -0
  181. package/dist/core/resource-loader.d.ts.map +1 -1
  182. package/dist/core/resource-loader.js +27 -2
  183. package/dist/core/resource-loader.js.map +1 -1
  184. package/dist/core/retry-fallback/chains.d.ts +29 -0
  185. package/dist/core/retry-fallback/chains.d.ts.map +1 -0
  186. package/dist/core/retry-fallback/chains.js +109 -0
  187. package/dist/core/retry-fallback/chains.js.map +1 -0
  188. package/dist/core/retry-fallback/controller.d.ts +77 -0
  189. package/dist/core/retry-fallback/controller.d.ts.map +1 -0
  190. package/dist/core/retry-fallback/controller.js +157 -0
  191. package/dist/core/retry-fallback/controller.js.map +1 -0
  192. package/dist/core/retry-fallback/cooldown.d.ts +21 -0
  193. package/dist/core/retry-fallback/cooldown.d.ts.map +1 -0
  194. package/dist/core/retry-fallback/cooldown.js +49 -0
  195. package/dist/core/retry-fallback/cooldown.js.map +1 -0
  196. package/dist/core/retry-fallback/log.d.ts +10 -0
  197. package/dist/core/retry-fallback/log.d.ts.map +1 -0
  198. package/dist/core/retry-fallback/log.js +128 -0
  199. package/dist/core/retry-fallback/log.js.map +1 -0
  200. package/dist/core/retry-fallback/validate.d.ts +8 -0
  201. package/dist/core/retry-fallback/validate.d.ts.map +1 -0
  202. package/dist/core/retry-fallback/validate.js +63 -0
  203. package/dist/core/retry-fallback/validate.js.map +1 -0
  204. package/dist/core/sdk.d.ts.map +1 -1
  205. package/dist/core/sdk.js +1 -0
  206. package/dist/core/sdk.js.map +1 -1
  207. package/dist/core/session-manager.d.ts +6 -1
  208. package/dist/core/session-manager.d.ts.map +1 -1
  209. package/dist/core/session-manager.js +19 -3
  210. package/dist/core/session-manager.js.map +1 -1
  211. package/dist/core/settings-manager.d.ts +21 -0
  212. package/dist/core/settings-manager.d.ts.map +1 -1
  213. package/dist/core/settings-manager.js +100 -1
  214. package/dist/core/settings-manager.js.map +1 -1
  215. package/dist/core/tools/bash.d.ts.map +1 -1
  216. package/dist/core/tools/bash.js +20 -5
  217. package/dist/core/tools/bash.js.map +1 -1
  218. package/dist/core/tools/read.js +1 -1
  219. package/dist/core/tools/read.js.map +1 -1
  220. package/dist/extensions/index.d.ts +3 -0
  221. package/dist/extensions/index.d.ts.map +1 -0
  222. package/dist/extensions/index.js +3 -0
  223. package/dist/extensions/index.js.map +1 -0
  224. package/dist/extensions/llama/client.d.ts +61 -0
  225. package/dist/extensions/llama/client.d.ts.map +1 -0
  226. package/dist/extensions/llama/client.js +298 -0
  227. package/dist/extensions/llama/client.js.map +1 -0
  228. package/dist/extensions/llama/huggingface.d.ts +23 -0
  229. package/dist/extensions/llama/huggingface.d.ts.map +1 -0
  230. package/dist/extensions/llama/huggingface.js +139 -0
  231. package/dist/extensions/llama/huggingface.js.map +1 -0
  232. package/dist/extensions/llama/index.d.ts +3 -0
  233. package/dist/extensions/llama/index.d.ts.map +1 -0
  234. package/dist/extensions/llama/index.js +208 -0
  235. package/dist/extensions/llama/index.js.map +1 -0
  236. package/dist/extensions/llama/provider.d.ts +10 -0
  237. package/dist/extensions/llama/provider.d.ts.map +1 -0
  238. package/dist/extensions/llama/provider.js +106 -0
  239. package/dist/extensions/llama/provider.js.map +1 -0
  240. package/dist/extensions/llama/ui.d.ts +42 -0
  241. package/dist/extensions/llama/ui.d.ts.map +1 -0
  242. package/dist/extensions/llama/ui.js +400 -0
  243. package/dist/extensions/llama/ui.js.map +1 -0
  244. package/dist/index.d.ts +1 -1
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js.map +1 -1
  247. package/dist/main.d.ts.map +1 -1
  248. package/dist/main.js +6 -4
  249. package/dist/main.js.map +1 -1
  250. package/dist/modes/interactive/components/assistant-message.d.ts +6 -7
  251. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  252. package/dist/modes/interactive/components/assistant-message.js +154 -114
  253. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  254. package/dist/modes/interactive/components/footer.d.ts +2 -1
  255. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  256. package/dist/modes/interactive/components/footer.js +25 -4
  257. package/dist/modes/interactive/components/footer.js.map +1 -1
  258. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  259. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  260. package/dist/modes/interactive/components/settings-selector.js +20 -0
  261. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  262. package/dist/modes/interactive/interactive-mode.d.ts +7 -0
  263. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  264. package/dist/modes/interactive/interactive-mode.js +165 -13
  265. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  266. package/dist/modes/interactive/streaming-reveal.d.ts +35 -0
  267. package/dist/modes/interactive/streaming-reveal.d.ts.map +1 -0
  268. package/dist/modes/interactive/streaming-reveal.js +268 -0
  269. package/dist/modes/interactive/streaming-reveal.js.map +1 -0
  270. package/dist/modes/interactive/tool-args-reveal.d.ts +20 -0
  271. package/dist/modes/interactive/tool-args-reveal.d.ts.map +1 -0
  272. package/dist/modes/interactive/tool-args-reveal.js +153 -0
  273. package/dist/modes/interactive/tool-args-reveal.js.map +1 -0
  274. package/dist/utils/child-process.d.ts +17 -1
  275. package/dist/utils/child-process.d.ts.map +1 -1
  276. package/dist/utils/child-process.js +41 -1
  277. package/dist/utils/child-process.js.map +1 -1
  278. package/docs/custom-provider.md +28 -0
  279. package/docs/extensions.md +65 -5
  280. package/docs/index.md +1 -0
  281. package/docs/llama-cpp.md +99 -0
  282. package/docs/neo.md +2 -1
  283. package/docs/prompt-templates.md +1 -0
  284. package/docs/providers.md +7 -0
  285. package/docs/settings.md +35 -0
  286. package/docs/tui.md +41 -26
  287. package/docs/usage.md +1 -0
  288. package/examples/extensions/README.md +1 -1
  289. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +26 -0
  290. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  291. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +0 -1
  292. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  293. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +76 -8
  294. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  295. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  296. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +26 -1
  297. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  299. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +24 -2
  300. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  301. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +5 -0
  302. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  303. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  304. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  305. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  307. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +92 -29
  308. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  309. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +105 -61
  311. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +15 -0
  313. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +15 -0
  315. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  316. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  317. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  318. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  319. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  320. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +4263 -22324
  321. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  322. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts +436 -1988
  323. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  324. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js +2 -1892
  325. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.models.d.ts +10 -80
  327. package/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.models.d.ts.map +1 -1
  328. package/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.models.js +2 -57
  329. package/node_modules/@earendil-works/pi-ai/dist/providers/ant-ling.models.js.map +1 -1
  330. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.d.ts +43 -267
  331. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.d.ts.map +1 -1
  332. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js +2 -252
  333. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts +184 -883
  335. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
  336. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js +2 -811
  337. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js.map +1 -1
  338. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.d.ts +10 -60
  339. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.d.ts.map +1 -1
  340. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js +2 -56
  341. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js.map +1 -1
  342. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.d.ts +168 -884
  343. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
  344. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js +2 -755
  345. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  346. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.models.d.ts +40 -286
  347. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
  348. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.models.js +2 -236
  349. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
  350. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -0
  351. package/node_modules/@earendil-works/pi-ai/dist/providers/data/ant-ling.json +1 -0
  352. package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -0
  353. package/node_modules/@earendil-works/pi-ai/dist/providers/data/azure-openai-responses.json +1 -0
  354. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cerebras.json +1 -0
  355. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -0
  356. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -0
  357. package/node_modules/@earendil-works/pi-ai/dist/providers/data/deepseek.json +1 -0
  358. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -0
  359. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -0
  360. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google-vertex.json +1 -0
  361. package/node_modules/@earendil-works/pi-ai/dist/providers/data/google.json +1 -0
  362. package/node_modules/@earendil-works/pi-ai/dist/providers/data/groq.json +1 -0
  363. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -0
  364. package/node_modules/@earendil-works/pi-ai/dist/providers/data/kimi-coding.json +1 -0
  365. package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax-cn.json +1 -0
  366. package/node_modules/@earendil-works/pi-ai/dist/providers/data/minimax.json +1 -0
  367. package/node_modules/@earendil-works/pi-ai/dist/providers/data/mistral.json +1 -0
  368. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai-cn.json +1 -0
  369. package/node_modules/@earendil-works/pi-ai/dist/providers/data/moonshotai.json +1 -0
  370. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -0
  371. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json +1 -0
  372. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -0
  373. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -0
  374. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -0
  375. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -0
  376. package/node_modules/@earendil-works/pi-ai/dist/providers/data/together.json +1 -0
  377. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -0
  378. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xai.json +1 -0
  379. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -0
  380. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -0
  381. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -0
  382. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi.json +1 -0
  383. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -0
  384. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -0
  385. package/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.models.d.ts +7 -58
  386. package/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.models.d.ts.map +1 -1
  387. package/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.models.js +2 -40
  388. package/node_modules/@earendil-works/pi-ai/dist/providers/deepseek.models.js.map +1 -1
  389. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts +1 -0
  390. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts.map +1 -1
  391. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +1 -0
  392. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js.map +1 -1
  393. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.d.ts +49 -362
  394. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.d.ts.map +1 -1
  395. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.js +2 -292
  396. package/node_modules/@earendil-works/pi-ai/dist/providers/fireworks.models.js.map +1 -1
  397. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.d.ts +85 -760
  398. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.d.ts.map +1 -1
  399. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js +2 -538
  400. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js.map +1 -1
  401. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.models.d.ts +31 -189
  402. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.models.d.ts.map +1 -1
  403. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.models.js +2 -179
  404. package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.models.js.map +1 -1
  405. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.d.ts +49 -309
  406. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.d.ts.map +1 -1
  407. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.js +2 -285
  408. package/node_modules/@earendil-works/pi-ai/dist/providers/google.models.js.map +1 -1
  409. package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.d.ts +22 -118
  410. package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.d.ts.map +1 -1
  411. package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js +2 -122
  412. package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js.map +1 -1
  413. package/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.models.d.ts +196 -979
  414. package/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.models.d.ts.map +1 -1
  415. package/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.models.js +2 -884
  416. package/node_modules/@earendil-works/pi-ai/dist/providers/huggingface.models.js.map +1 -1
  417. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts +13 -122
  418. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.d.ts.map +1 -1
  419. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js +2 -98
  420. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.models.js.map +1 -1
  421. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.models.d.ts +10 -48
  422. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.models.d.ts.map +1 -1
  423. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.models.js +2 -53
  424. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax-cn.models.js.map +1 -1
  425. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax.models.d.ts +10 -48
  426. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax.models.d.ts.map +1 -1
  427. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax.models.js +2 -53
  428. package/node_modules/@earendil-works/pi-ai/dist/providers/minimax.models.js.map +1 -1
  429. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.models.d.ts +91 -480
  430. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.models.d.ts.map +1 -1
  431. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.models.js +2 -512
  432. package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.models.js.map +1 -1
  433. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.d.ts +31 -257
  434. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
  435. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js +2 -185
  436. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai-cn.models.js.map +1 -1
  437. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.d.ts +31 -257
  438. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.d.ts.map +1 -1
  439. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js +2 -185
  440. package/node_modules/@earendil-works/pi-ai/dist/providers/moonshotai.models.js.map +1 -1
  441. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.d.ts +58 -541
  442. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.d.ts.map +1 -1
  443. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.js +2 -382
  444. package/node_modules/@earendil-works/pi-ai/dist/providers/nvidia.models.js.map +1 -1
  445. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts +22 -196
  446. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts.map +1 -1
  447. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js +2 -139
  448. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js.map +1 -1
  449. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts +184 -954
  450. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts.map +1 -1
  451. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js +2 -825
  452. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js.map +1 -1
  453. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.d.ts +1 -1
  454. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.d.ts.map +1 -1
  455. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.js +2 -0
  456. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.js.map +1 -1
  457. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts +46 -335
  458. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.d.ts.map +1 -1
  459. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +2 -273
  460. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js.map +1 -1
  461. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts +163 -1185
  462. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.d.ts.map +1 -1
  463. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js +2 -996
  464. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode.models.js.map +1 -1
  465. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +1076 -5729
  466. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  467. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +2 -4892
  468. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  469. package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.d.ts +49 -610
  470. package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.d.ts.map +1 -1
  471. package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.js +2 -396
  472. package/node_modules/@earendil-works/pi-ai/dist/providers/together.models.js.map +1 -1
  473. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +752 -3336
  474. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  475. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +2 -3263
  476. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  477. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts +10 -65
  478. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.d.ts.map +1 -1
  479. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js +2 -57
  480. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.models.js.map +1 -1
  481. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts +10 -63
  482. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
  483. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js +2 -56
  484. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  485. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts +10 -63
  486. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
  487. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js +2 -56
  488. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  489. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts +10 -63
  490. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
  491. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js +2 -56
  492. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  493. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.d.ts +19 -126
  494. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.d.ts.map +1 -1
  495. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js +2 -110
  496. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js.map +1 -1
  497. package/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.models.d.ts +19 -144
  498. package/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
  499. package/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.models.js +2 -111
  500. package/node_modules/@earendil-works/pi-ai/dist/providers/zai-coding-cn.models.js.map +1 -1
  501. package/node_modules/@earendil-works/pi-ai/dist/providers/zai.models.d.ts +19 -144
  502. package/node_modules/@earendil-works/pi-ai/dist/providers/zai.models.d.ts.map +1 -1
  503. package/node_modules/@earendil-works/pi-ai/dist/providers/zai.models.js +2 -111
  504. package/node_modules/@earendil-works/pi-ai/dist/providers/zai.models.js.map +1 -1
  505. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.d.ts.map +1 -1
  506. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.js +9 -0
  507. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.js.map +1 -1
  508. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts.map +1 -1
  509. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js +2 -1
  510. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js.map +1 -1
  511. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.d.ts +1 -0
  512. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.d.ts.map +1 -1
  513. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.js +1 -1
  514. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.js.map +1 -1
  515. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.d.ts +1 -0
  516. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.d.ts.map +1 -1
  517. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.js +1 -1
  518. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.js.map +1 -1
  519. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-protocol.d.ts +19 -0
  520. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-protocol.d.ts.map +1 -0
  521. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-protocol.js +8 -0
  522. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-protocol.js.map +1 -0
  523. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.d.ts +2 -0
  524. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.d.ts.map +1 -1
  525. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.js +7 -4
  526. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.js.map +1 -1
  527. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts +2 -0
  528. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts.map +1 -1
  529. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js +22 -18
  530. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js.map +1 -1
  531. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/coerce-parameters.d.ts +15 -0
  532. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/coerce-parameters.d.ts.map +1 -0
  533. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/coerce-parameters.js +198 -0
  534. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/coerce-parameters.js.map +1 -0
  535. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/config.d.ts +3 -0
  536. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/config.d.ts.map +1 -0
  537. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/config.js +8 -0
  538. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/config.js.map +1 -0
  539. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/format.d.ts +6 -0
  540. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/format.d.ts.map +1 -0
  541. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/format.js +33 -0
  542. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/format.js.map +1 -0
  543. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.d.ts +6 -0
  544. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.d.ts.map +1 -0
  545. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.js +6 -0
  546. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/index.js.map +1 -0
  547. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/parse.d.ts +4 -0
  548. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/parse.d.ts.map +1 -0
  549. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/parse.js +6 -0
  550. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/parse.js.map +1 -0
  551. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/repair.d.ts +12 -0
  552. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/repair.d.ts.map +1 -0
  553. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/repair.js +46 -0
  554. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/repair.js.map +1 -0
  555. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/stream.d.ts +4 -0
  556. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/stream.d.ts.map +1 -0
  557. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/stream.js +6 -0
  558. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/antml/stream.js.map +1 -0
  559. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.d.ts +2 -1
  560. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.d.ts.map +1 -1
  561. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.js.map +1 -1
  562. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +19 -2
  563. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  564. package/node_modules/@earendil-works/pi-ai/dist/types.js +4 -1
  565. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  566. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  567. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +6 -1
  568. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  569. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts +4 -0
  570. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.d.ts.map +1 -0
  571. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js +6 -0
  572. package/node_modules/@earendil-works/pi-ai/dist/utils/stop-details.js.map +1 -0
  573. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  574. package/node_modules/@earendil-works/pi-pty/dist/registry-session.d.ts +1 -1
  575. package/node_modules/@earendil-works/pi-pty/dist/registry-session.d.ts.map +1 -1
  576. package/node_modules/@earendil-works/pi-pty/dist/registry-session.js +25 -6
  577. package/node_modules/@earendil-works/pi-pty/dist/registry-session.js.map +1 -1
  578. package/node_modules/@earendil-works/pi-pty/dist/registry-types.d.ts +6 -0
  579. package/node_modules/@earendil-works/pi-pty/dist/registry-types.d.ts.map +1 -1
  580. package/node_modules/@earendil-works/pi-pty/dist/registry-types.js.map +1 -1
  581. package/node_modules/@earendil-works/pi-pty/dist/registry.d.ts +1 -0
  582. package/node_modules/@earendil-works/pi-pty/dist/registry.d.ts.map +1 -1
  583. package/node_modules/@earendil-works/pi-pty/dist/registry.js +9 -1
  584. package/node_modules/@earendil-works/pi-pty/dist/registry.js.map +1 -1
  585. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  586. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -1
  587. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  588. package/node_modules/@earendil-works/pi-tui/dist/index.js +1 -1
  589. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  590. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +6 -1
  591. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
  592. package/node_modules/@earendil-works/pi-tui/dist/tui.js +14 -2
  593. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  594. package/node_modules/@earendil-works/pi-tui/dist/utils.js +1 -1
  595. package/node_modules/@earendil-works/pi-tui/dist/utils.js.map +1 -1
  596. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  597. package/package.json +6 -6
  598. package/dist/core/extensions/builtin/todotools/tools/todoread.d.ts +0 -4
  599. package/dist/core/extensions/builtin/todotools/tools/todoread.d.ts.map +0 -1
  600. package/dist/core/extensions/builtin/todotools/tools/todoread.js +0 -37
  601. package/dist/core/extensions/builtin/todotools/tools/todoread.js.map +0 -1
  602. package/dist/core/extensions/builtin/todotools/tools/todowrite.d.ts +0 -10
  603. package/dist/core/extensions/builtin/todotools/tools/todowrite.d.ts.map +0 -1
  604. package/dist/core/extensions/builtin/todotools/tools/todowrite.js +0 -95
  605. package/dist/core/extensions/builtin/todotools/tools/todowrite.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import { spawn as nodeSpawn, spawnSync as nodeSpawnSync, } from "node:child_process";
2
2
  import crossSpawn from "cross-spawn";
3
3
  const EXIT_STDIO_GRACE_MS = 250;
4
+ const ABORT_EXIT_GRACE_MS = 5000;
4
5
  export function spawnProcess(command, args, options) {
5
6
  return process.platform === "win32" ? crossSpawn(command, args, options) : nodeSpawn(command, args, options);
6
7
  }
@@ -19,13 +20,20 @@ export function spawnProcessSync(command, args, options) {
19
20
  * the grace timer is re-armed on every chunk, so an actively writing descendant keeps
20
21
  * us reading, while a quiet inherited handle (e.g. a Windows daemonized descendant
21
22
  * that never lets `close` fire) still releases us after the grace elapses.
23
+ *
24
+ * When `options.signal` aborts, the caller has killed the process and
25
+ * abandoned its output: tail preservation ends, the pipes are destroyed, and
26
+ * the wait resolves on `exit` — or after `abortExitGraceMs` when the kill
27
+ * never lands (uninterruptible IO, failed taskkill).
22
28
  */
23
- export function waitForChildProcess(child) {
29
+ export function waitForChildProcess(child, options) {
24
30
  return new Promise((resolve, reject) => {
25
31
  let settled = false;
26
32
  let exited = false;
27
33
  let exitCode = null;
28
34
  let postExitTimer;
35
+ let abortGraceTimer;
36
+ let detachAbortListener;
29
37
  let stdoutEnded = child.stdout === null;
30
38
  let stderrEnded = child.stderr === null;
31
39
  const cleanup = () => {
@@ -33,6 +41,14 @@ export function waitForChildProcess(child) {
33
41
  clearTimeout(postExitTimer);
34
42
  postExitTimer = undefined;
35
43
  }
44
+ if (abortGraceTimer) {
45
+ clearTimeout(abortGraceTimer);
46
+ abortGraceTimer = undefined;
47
+ }
48
+ if (detachAbortListener) {
49
+ detachAbortListener();
50
+ detachAbortListener = undefined;
51
+ }
36
52
  child.removeListener("error", onError);
37
53
  child.removeListener("exit", onExit);
38
54
  child.removeListener("close", onClose);
@@ -94,6 +110,20 @@ export function waitForChildProcess(child) {
94
110
  const onClose = (code) => {
95
111
  finalize(code);
96
112
  };
113
+ const onAbortRelease = () => {
114
+ // The caller killed the process and abandoned its output: destroy our
115
+ // read ends so surviving descendants cannot re-arm the idle grace
116
+ // forever, then wait only for `exit`, bounded by the abort grace.
117
+ child.stdout?.destroy();
118
+ child.stderr?.destroy();
119
+ stdoutEnded = true;
120
+ stderrEnded = true;
121
+ if (exited) {
122
+ maybeFinalizeAfterExit();
123
+ return;
124
+ }
125
+ abortGraceTimer = setTimeout(() => finalize(exitCode), options?.abortExitGraceMs ?? ABORT_EXIT_GRACE_MS);
126
+ };
97
127
  child.stdout?.once("end", onStdoutEnd);
98
128
  child.stderr?.once("end", onStderrEnd);
99
129
  child.stdout?.on("data", onData);
@@ -101,6 +131,16 @@ export function waitForChildProcess(child) {
101
131
  child.once("error", onError);
102
132
  child.once("exit", onExit);
103
133
  child.once("close", onClose);
134
+ const abortSignal = options?.signal;
135
+ if (abortSignal) {
136
+ if (abortSignal.aborted) {
137
+ onAbortRelease();
138
+ }
139
+ else {
140
+ abortSignal.addEventListener("abort", onAbortRelease, { once: true });
141
+ detachAbortListener = () => abortSignal.removeEventListener("abort", onAbortRelease);
142
+ }
143
+ }
104
144
  });
105
145
  }
106
146
  //# sourceMappingURL=child-process.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"child-process.js","sourceRoot":"","sources":["../../src/utils/child-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,KAAK,IAAI,SAAS,EAClB,SAAS,IAAI,aAAa,GAO1B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,UAAU,MAAM,aAAa,CAAC;AAErC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAQhC,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,IAAc,EAAE,OAAqB;IAClF,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAC9G,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,OAAe,EACf,IAAc,EACd,OAA2C;IAE3C,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO;QAClC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC;QACzC,CAAC,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACtD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,aAAyC,CAAC;QAC9C,IAAI,WAAW,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC;QACxC,IAAI,WAAW,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC;QAExC,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,IAAI,aAAa,EAAE,CAAC;gBACnB,YAAY,CAAC,aAAa,CAAC,CAAC;gBAC5B,aAAa,GAAG,SAAS,CAAC;YAC3B,CAAC;YACD,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACvC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACrC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACvC,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YACjD,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;YACjD,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7C,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9C,CAAC,CAAC;QAEF,MAAM,QAAQ,GAAG,CAAC,IAAmB,EAAE,EAAE;YACxC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YACxB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC;QAEF,MAAM,sBAAsB,GAAG,GAAG,EAAE;YACnC,IAAI,CAAC,MAAM,IAAI,OAAO;gBAAE,OAAO;YAC/B,IAAI,WAAW,IAAI,WAAW,EAAE,CAAC;gBAChC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;QACF,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,GAAG,EAAE;YACzB,IAAI,aAAa;gBAAE,YAAY,CAAC,aAAa,CAAC,CAAC;YAC/C,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC,CAAC;QAC3E,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,GAAG,EAAE;YACnB,oEAAoE;YACpE,sDAAsD;YACtD,IAAI,MAAM,IAAI,CAAC,OAAO;gBAAE,YAAY,EAAE,CAAC;QACxC,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,GAAG,EAAE;YACxB,WAAW,GAAG,IAAI,CAAC;YACnB,sBAAsB,EAAE,CAAC;QAC1B,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,GAAG,EAAE;YACxB,WAAW,GAAG,IAAI,CAAC;YACnB,sBAAsB,EAAE,CAAC;QAC1B,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,CAAC,GAAU,EAAE,EAAE;YAC9B,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,CAAC,CAAC;QACb,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAE,EAAE;YACtC,MAAM,GAAG,IAAI,CAAC;YACd,QAAQ,GAAG,IAAI,CAAC;YAChB,sBAAsB,EAAE,CAAC;YACzB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;YAChB,CAAC;QACF,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,CAAC,IAAmB,EAAE,EAAE;YACvC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC;QAEF,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACvC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACvC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import {\n\ttype ChildProcess,\n\ttype ChildProcessByStdio,\n\tspawn as nodeSpawn,\n\tspawnSync as nodeSpawnSync,\n\ttype SpawnOptions,\n\ttype SpawnOptionsWithStdioTuple,\n\ttype SpawnSyncOptionsWithStringEncoding,\n\ttype SpawnSyncReturns,\n\ttype StdioNull,\n\ttype StdioPipe,\n} from \"node:child_process\";\nimport type { Readable } from \"node:stream\";\nimport crossSpawn from \"cross-spawn\";\n\nconst EXIT_STDIO_GRACE_MS = 250;\n\nexport function spawnProcess(\n\tcommand: string,\n\targs: string[],\n\toptions: SpawnOptionsWithStdioTuple<StdioNull, StdioPipe, StdioPipe>,\n): ChildProcessByStdio<null, Readable, Readable>;\nexport function spawnProcess(command: string, args: string[], options: SpawnOptions): ChildProcess;\nexport function spawnProcess(command: string, args: string[], options: SpawnOptions): ChildProcess {\n\treturn process.platform === \"win32\" ? crossSpawn(command, args, options) : nodeSpawn(command, args, options);\n}\n\nexport function spawnProcessSync(\n\tcommand: string,\n\targs: string[],\n\toptions: SpawnSyncOptionsWithStringEncoding,\n): SpawnSyncReturns<string> {\n\treturn process.platform === \"win32\"\n\t\t? crossSpawn.sync(command, args, options)\n\t\t: nodeSpawnSync(command, args, options);\n}\n\n/**\n * Wait for a child process to terminate without hanging on inherited stdio handles.\n *\n * A short-lived child can `exit` while a detached descendant keeps its stdout/stderr\n * pipe open. We must not resolve and destroy the streams on a fixed deadline measured\n * from `exit`, or output still being written past that deadline is silently lost\n * (earendil-works/pi#5303). Instead, after `exit` we wait for the pipes to fall idle:\n * the grace timer is re-armed on every chunk, so an actively writing descendant keeps\n * us reading, while a quiet inherited handle (e.g. a Windows daemonized descendant\n * that never lets `close` fire) still releases us after the grace elapses.\n */\nexport function waitForChildProcess(child: ChildProcess): Promise<number | null> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet exited = false;\n\t\tlet exitCode: number | null = null;\n\t\tlet postExitTimer: NodeJS.Timeout | undefined;\n\t\tlet stdoutEnded = child.stdout === null;\n\t\tlet stderrEnded = child.stderr === null;\n\n\t\tconst cleanup = () => {\n\t\t\tif (postExitTimer) {\n\t\t\t\tclearTimeout(postExitTimer);\n\t\t\t\tpostExitTimer = undefined;\n\t\t\t}\n\t\t\tchild.removeListener(\"error\", onError);\n\t\t\tchild.removeListener(\"exit\", onExit);\n\t\t\tchild.removeListener(\"close\", onClose);\n\t\t\tchild.stdout?.removeListener(\"end\", onStdoutEnd);\n\t\t\tchild.stderr?.removeListener(\"end\", onStderrEnd);\n\t\t\tchild.stdout?.removeListener(\"data\", onData);\n\t\t\tchild.stderr?.removeListener(\"data\", onData);\n\t\t};\n\n\t\tconst finalize = (code: number | null) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tchild.stdout?.destroy();\n\t\t\tchild.stderr?.destroy();\n\t\t\tresolve(code);\n\t\t};\n\n\t\tconst maybeFinalizeAfterExit = () => {\n\t\t\tif (!exited || settled) return;\n\t\t\tif (stdoutEnded && stderrEnded) {\n\t\t\t\tfinalize(exitCode);\n\t\t\t}\n\t\t};\n\n\t\tconst armIdleTimer = () => {\n\t\t\tif (postExitTimer) clearTimeout(postExitTimer);\n\t\t\tpostExitTimer = setTimeout(() => finalize(exitCode), EXIT_STDIO_GRACE_MS);\n\t\t};\n\n\t\tconst onData = () => {\n\t\t\t// Output is still arriving after exit; defer finalizing so we don't\n\t\t\t// destroy the stream mid-write and truncate the tail.\n\t\t\tif (exited && !settled) armIdleTimer();\n\t\t};\n\n\t\tconst onStdoutEnd = () => {\n\t\t\tstdoutEnded = true;\n\t\t\tmaybeFinalizeAfterExit();\n\t\t};\n\n\t\tconst onStderrEnd = () => {\n\t\t\tstderrEnded = true;\n\t\t\tmaybeFinalizeAfterExit();\n\t\t};\n\n\t\tconst onError = (err: Error) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(err);\n\t\t};\n\n\t\tconst onExit = (code: number | null) => {\n\t\t\texited = true;\n\t\t\texitCode = code;\n\t\t\tmaybeFinalizeAfterExit();\n\t\t\tif (!settled) {\n\t\t\t\tarmIdleTimer();\n\t\t\t}\n\t\t};\n\n\t\tconst onClose = (code: number | null) => {\n\t\t\tfinalize(code);\n\t\t};\n\n\t\tchild.stdout?.once(\"end\", onStdoutEnd);\n\t\tchild.stderr?.once(\"end\", onStderrEnd);\n\t\tchild.stdout?.on(\"data\", onData);\n\t\tchild.stderr?.on(\"data\", onData);\n\t\tchild.once(\"error\", onError);\n\t\tchild.once(\"exit\", onExit);\n\t\tchild.once(\"close\", onClose);\n\t});\n}\n"]}
1
+ {"version":3,"file":"child-process.js","sourceRoot":"","sources":["../../src/utils/child-process.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype ChildProcess,\n\ttype ChildProcessByStdio,\n\tspawn as nodeSpawn,\n\tspawnSync as nodeSpawnSync,\n\ttype SpawnOptions,\n\ttype SpawnOptionsWithStdioTuple,\n\ttype SpawnSyncOptionsWithStringEncoding,\n\ttype SpawnSyncReturns,\n\ttype StdioNull,\n\ttype StdioPipe,\n} from \"node:child_process\";\nimport type { Readable } from \"node:stream\";\nimport crossSpawn from \"cross-spawn\";\n\nconst EXIT_STDIO_GRACE_MS = 250;\nconst ABORT_EXIT_GRACE_MS = 5000;\n\nexport interface WaitForChildProcessOptions {\n\t/**\n\t * Abort when the caller has killed the process and no longer needs its\n\t * output. The wait then stops preserving stdio tails (descendants that\n\t * survived the kill can no longer hold it open) and resolves as soon as\n\t * the process exits, or after `abortExitGraceMs` if it never does.\n\t */\n\tsignal?: AbortSignal;\n\t/** Post-abort deadline for `exit` before resolving anyway. Default 5s. */\n\tabortExitGraceMs?: number;\n}\n\nexport function spawnProcess(\n\tcommand: string,\n\targs: string[],\n\toptions: SpawnOptionsWithStdioTuple<StdioNull, StdioPipe, StdioPipe>,\n): ChildProcessByStdio<null, Readable, Readable>;\nexport function spawnProcess(command: string, args: string[], options: SpawnOptions): ChildProcess;\nexport function spawnProcess(command: string, args: string[], options: SpawnOptions): ChildProcess {\n\treturn process.platform === \"win32\" ? crossSpawn(command, args, options) : nodeSpawn(command, args, options);\n}\n\nexport function spawnProcessSync(\n\tcommand: string,\n\targs: string[],\n\toptions: SpawnSyncOptionsWithStringEncoding,\n): SpawnSyncReturns<string> {\n\treturn process.platform === \"win32\"\n\t\t? crossSpawn.sync(command, args, options)\n\t\t: nodeSpawnSync(command, args, options);\n}\n\n/**\n * Wait for a child process to terminate without hanging on inherited stdio handles.\n *\n * A short-lived child can `exit` while a detached descendant keeps its stdout/stderr\n * pipe open. We must not resolve and destroy the streams on a fixed deadline measured\n * from `exit`, or output still being written past that deadline is silently lost\n * (earendil-works/pi#5303). Instead, after `exit` we wait for the pipes to fall idle:\n * the grace timer is re-armed on every chunk, so an actively writing descendant keeps\n * us reading, while a quiet inherited handle (e.g. a Windows daemonized descendant\n * that never lets `close` fire) still releases us after the grace elapses.\n *\n * When `options.signal` aborts, the caller has killed the process and\n * abandoned its output: tail preservation ends, the pipes are destroyed, and\n * the wait resolves on `exit` — or after `abortExitGraceMs` when the kill\n * never lands (uninterruptible IO, failed taskkill).\n */\nexport function waitForChildProcess(child: ChildProcess, options?: WaitForChildProcessOptions): Promise<number | null> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet exited = false;\n\t\tlet exitCode: number | null = null;\n\t\tlet postExitTimer: NodeJS.Timeout | undefined;\n\t\tlet abortGraceTimer: NodeJS.Timeout | undefined;\n\t\tlet detachAbortListener: (() => void) | undefined;\n\t\tlet stdoutEnded = child.stdout === null;\n\t\tlet stderrEnded = child.stderr === null;\n\n\t\tconst cleanup = () => {\n\t\t\tif (postExitTimer) {\n\t\t\t\tclearTimeout(postExitTimer);\n\t\t\t\tpostExitTimer = undefined;\n\t\t\t}\n\t\t\tif (abortGraceTimer) {\n\t\t\t\tclearTimeout(abortGraceTimer);\n\t\t\t\tabortGraceTimer = undefined;\n\t\t\t}\n\t\t\tif (detachAbortListener) {\n\t\t\t\tdetachAbortListener();\n\t\t\t\tdetachAbortListener = undefined;\n\t\t\t}\n\t\t\tchild.removeListener(\"error\", onError);\n\t\t\tchild.removeListener(\"exit\", onExit);\n\t\t\tchild.removeListener(\"close\", onClose);\n\t\t\tchild.stdout?.removeListener(\"end\", onStdoutEnd);\n\t\t\tchild.stderr?.removeListener(\"end\", onStderrEnd);\n\t\t\tchild.stdout?.removeListener(\"data\", onData);\n\t\t\tchild.stderr?.removeListener(\"data\", onData);\n\t\t};\n\n\t\tconst finalize = (code: number | null) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tchild.stdout?.destroy();\n\t\t\tchild.stderr?.destroy();\n\t\t\tresolve(code);\n\t\t};\n\n\t\tconst maybeFinalizeAfterExit = () => {\n\t\t\tif (!exited || settled) return;\n\t\t\tif (stdoutEnded && stderrEnded) {\n\t\t\t\tfinalize(exitCode);\n\t\t\t}\n\t\t};\n\n\t\tconst armIdleTimer = () => {\n\t\t\tif (postExitTimer) clearTimeout(postExitTimer);\n\t\t\tpostExitTimer = setTimeout(() => finalize(exitCode), EXIT_STDIO_GRACE_MS);\n\t\t};\n\n\t\tconst onData = () => {\n\t\t\t// Output is still arriving after exit; defer finalizing so we don't\n\t\t\t// destroy the stream mid-write and truncate the tail.\n\t\t\tif (exited && !settled) armIdleTimer();\n\t\t};\n\n\t\tconst onStdoutEnd = () => {\n\t\t\tstdoutEnded = true;\n\t\t\tmaybeFinalizeAfterExit();\n\t\t};\n\n\t\tconst onStderrEnd = () => {\n\t\t\tstderrEnded = true;\n\t\t\tmaybeFinalizeAfterExit();\n\t\t};\n\n\t\tconst onError = (err: Error) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(err);\n\t\t};\n\n\t\tconst onExit = (code: number | null) => {\n\t\t\texited = true;\n\t\t\texitCode = code;\n\t\t\tmaybeFinalizeAfterExit();\n\t\t\tif (!settled) {\n\t\t\t\tarmIdleTimer();\n\t\t\t}\n\t\t};\n\n\t\tconst onClose = (code: number | null) => {\n\t\t\tfinalize(code);\n\t\t};\n\n\t\tconst onAbortRelease = () => {\n\t\t\t// The caller killed the process and abandoned its output: destroy our\n\t\t\t// read ends so surviving descendants cannot re-arm the idle grace\n\t\t\t// forever, then wait only for `exit`, bounded by the abort grace.\n\t\t\tchild.stdout?.destroy();\n\t\t\tchild.stderr?.destroy();\n\t\t\tstdoutEnded = true;\n\t\t\tstderrEnded = true;\n\t\t\tif (exited) {\n\t\t\t\tmaybeFinalizeAfterExit();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tabortGraceTimer = setTimeout(() => finalize(exitCode), options?.abortExitGraceMs ?? ABORT_EXIT_GRACE_MS);\n\t\t};\n\n\t\tchild.stdout?.once(\"end\", onStdoutEnd);\n\t\tchild.stderr?.once(\"end\", onStderrEnd);\n\t\tchild.stdout?.on(\"data\", onData);\n\t\tchild.stderr?.on(\"data\", onData);\n\t\tchild.once(\"error\", onError);\n\t\tchild.once(\"exit\", onExit);\n\t\tchild.once(\"close\", onClose);\n\n\t\tconst abortSignal = options?.signal;\n\t\tif (abortSignal) {\n\t\t\tif (abortSignal.aborted) {\n\t\t\t\tonAbortRelease();\n\t\t\t} else {\n\t\t\t\tabortSignal.addEventListener(\"abort\", onAbortRelease, { once: true });\n\t\t\t\tdetachAbortListener = () => abortSignal.removeEventListener(\"abort\", onAbortRelease);\n\t\t\t}\n\t\t}\n\t});\n}\n"]}
@@ -30,10 +30,38 @@ See these complete provider examples:
30
30
 
31
31
  ## Quick Reference
32
32
 
33
+ Extensions can register either a complete pi-ai `Provider` or use the legacy provider-config form. Prefer a complete provider when custom authentication, filtering, refresh, or streaming behavior is required. Pi composes `models.json` overrides above registered native providers.
34
+
33
35
  ```typescript
36
+ import { createProvider, openAICompletionsApi } from "@earendil-works/pi-ai";
34
37
  import type { ExtensionAPI } from "@code-yeongyu/senpi";
35
38
 
36
39
  export default function (pi: ExtensionAPI) {
40
+ pi.registerProvider(createProvider({
41
+ id: "native-local",
42
+ name: "Native Local",
43
+ baseUrl: "http://localhost:8080/v1",
44
+ auth: {
45
+ apiKey: {
46
+ name: "Local server API key",
47
+ async login(interaction) {
48
+ return {
49
+ type: "api_key",
50
+ key: await interaction.prompt({ type: "secret", message: "API key" })
51
+ };
52
+ },
53
+ async resolve({ credential }) {
54
+ return credential?.key
55
+ ? { auth: { apiKey: credential.key }, source: "stored API key" }
56
+ : undefined;
57
+ }
58
+ }
59
+ },
60
+ models: [],
61
+ api: openAICompletionsApi()
62
+ }));
63
+
64
+ // Legacy provider-config form:
37
65
  // Override baseUrl for existing provider
38
66
  pi.registerProvider("anthropic", {
39
67
  baseUrl: "https://proxy.example.com"
@@ -12,6 +12,7 @@ Extensions are TypeScript modules that extend pi's behavior. They can subscribe
12
12
  - **User interaction** - Prompt users via `ctx.ui` (select, confirm, input, notify)
13
13
  - **Custom UI components** - Full TUI components with keyboard input via `ctx.ui.custom()` for complex interactions
14
14
  - **Custom commands** - Register commands like `/mycommand` via `pi.registerCommand()`
15
+ - **Model fallback** - The bundled [`/fallback`](#bundled-fallback-command) command manages global per-model retry chains. Use `/fallback <target> <fallback1> [fallback2 ...]` for scripts, or `/fallback` in the TUI to view and edit chains. `--no-model-fallback` and `SENPI_NO_FALLBACK=1` disable it for one run.
15
16
  - **Session persistence** - Store state that survives restarts via `pi.appendEntry()`
16
17
  - **Custom rendering** - Control how tool calls/results and messages appear in TUI
17
18
 
@@ -31,6 +32,7 @@ See [examples/extensions/](../examples/extensions/) for working implementations.
31
32
  ## Table of Contents
32
33
 
33
34
  - [Quick Start](#quick-start)
35
+ - [Bundled /fallback Command](#bundled-fallback-command)
34
36
  - [Extension Locations](#extension-locations)
35
37
  - [Available Imports](#available-imports)
36
38
  - [Writing an Extension](#writing-an-extension)
@@ -106,6 +108,32 @@ Test with `--extension` (or `-e`) flag:
106
108
  pi -e ./my-extension.ts
107
109
  ```
108
110
 
111
+ ## Bundled /fallback Command
112
+
113
+ The bundled `model-fallback` extension registers `/fallback` to manage global per-model retry fallback chains. The command writes through the active session settings manager, so a saved chain is available to the current session's next retry without restarting Senpi. See [Settings](settings.md#model-fallback-chains) for selector syntax and runtime behavior.
114
+
115
+ Use the quick-set form in scripts or any non-TUI mode:
116
+
117
+ ```text
118
+ /fallback anthropic/claude-fable-5 ccapi/kimi-k3:max
119
+ ```
120
+
121
+ The first argument is the exact primary model selector; each later argument is an ordered fallback selector. Quick-set validates selectors before saving. At least one fallback is required:
122
+
123
+ ```text
124
+ /fallback <target> <fallback1> [fallback2 ...]
125
+ ```
126
+
127
+ Run `/fallback` without arguments in the TUI for a menu that can:
128
+
129
+ - show configured chains and live fallback state;
130
+ - add or edit a chain by choosing the target, each fallback, and either an explicit or inherited thinking level;
131
+ - remove a chain;
132
+ - toggle `retry.modelFallback`; and
133
+ - choose `retry.fallbackRevertPolicy` (`cooldown-expiry` or `never`).
134
+
135
+ Use quick-set in non-TUI modes; the no-argument menu requires interactive UI. Pass `--no-model-fallback` or set `SENPI_NO_FALLBACK=1` to disable fallback for that process without modifying saved settings.
136
+
109
137
  ## Extension Locations
110
138
 
111
139
  > **Security:** Extensions run with your full system permissions and can execute arbitrary code. Only install from sources you trust.
@@ -977,7 +1005,7 @@ ctx.sessionManager.getLeafId() // Current leaf entry ID
977
1005
 
978
1006
  ### ctx.modelRegistry / ctx.model
979
1007
 
980
- Access to models and API keys.
1008
+ Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model.
981
1009
 
982
1010
  ### ctx.signal
983
1011
 
@@ -1725,7 +1753,37 @@ Calls made during the extension factory function are queued and applied once the
1725
1753
 
1726
1754
  Dynamic providers can implement `refreshModels`. Pi calls it during model refresh, publishes the returned list synchronously through the provider, and passes the canonical credential/store/network/signal context. The extension decides whether to persist the catalog through `context.store`; live servers such as llama.cpp can ignore it.
1727
1755
 
1756
+ Extensions that need native provider auth, filtering, refresh, or stream behavior can register a complete `Provider` from `@earendil-works/pi-ai`. The provider becomes the composition base and `models.json` overrides still apply above it.
1757
+
1728
1758
  ```typescript
1759
+ import { createProvider, openAICompletionsApi } from "@earendil-works/pi-ai";
1760
+
1761
+ const provider = createProvider({
1762
+ id: "local-server",
1763
+ name: "Local Server",
1764
+ baseUrl: "http://localhost:8080/v1",
1765
+ auth: {
1766
+ apiKey: {
1767
+ name: "Local server setup",
1768
+ async login(interaction) {
1769
+ return {
1770
+ type: "api_key",
1771
+ key: await interaction.prompt({ type: "secret", message: "API key" }),
1772
+ };
1773
+ },
1774
+ async resolve({ credential }) {
1775
+ return credential?.key
1776
+ ? { auth: { apiKey: credential.key }, source: "stored API key" }
1777
+ : undefined;
1778
+ },
1779
+ },
1780
+ },
1781
+ models: [],
1782
+ api: openAICompletionsApi(),
1783
+ });
1784
+
1785
+ pi.registerProvider(provider);
1786
+
1729
1787
  // Register a new provider with custom models
1730
1788
  pi.registerProvider("my-proxy", {
1731
1789
  name: "My Proxy",
@@ -1794,7 +1852,9 @@ pi.registerProvider("corporate-ai", {
1794
1852
  });
1795
1853
  ```
1796
1854
 
1797
- **Config options:**
1855
+ The object form accepts a complete pi-ai `Provider`, including native `auth`, `getModels`, `refreshModels`, `filterModels`, `stream`, and `streamSimple` behavior.
1856
+
1857
+ **Legacy config options:**
1798
1858
  - `name` - Display name for the provider in UI such as `/login`.
1799
1859
  - `baseUrl` - API endpoint URL. Required when defining models.
1800
1860
  - `apiKey` - API key literal, environment interpolation (`$ENV_VAR` or `${ENV_VAR}`), or leading `!command`. Required when defining models (unless `oauth` provided). `$$` escapes `$`, and `$!` escapes a literal `!` without triggering command execution.
@@ -2754,8 +2814,8 @@ class VimEditor extends CustomEditor {
2754
2814
 
2755
2815
  export default function (pi: ExtensionAPI) {
2756
2816
  pi.on("session_start", (_event, ctx) => {
2757
- ctx.ui.setEditorComponent((_tui, theme, keybindings) =>
2758
- new VimEditor(theme, keybindings)
2817
+ ctx.ui.setEditorComponent((tui, theme, keybindings) =>
2818
+ new VimEditor(tui, theme, keybindings)
2759
2819
  );
2760
2820
  });
2761
2821
  }
@@ -2764,7 +2824,7 @@ export default function (pi: ExtensionAPI) {
2764
2824
  **Key points:**
2765
2825
  - Extend `CustomEditor` (not base `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching)
2766
2826
  - Call `super.handleInput(data)` for keys you don't handle
2767
- - Factory receives `theme` and `keybindings` from the app
2827
+ - Factory receives `tui`, `theme`, and `keybindings` from the app
2768
2828
  - Use `ctx.ui.getEditorComponent()` before `setEditorComponent()` to wrap the previously configured custom editor
2769
2829
  - Pass `undefined` to restore default: `ctx.ui.setEditorComponent(undefined)`
2770
2830
 
package/docs/index.md CHANGED
@@ -33,6 +33,7 @@ For the full first-run flow, see [Quickstart](quickstart.md).
33
33
  - [Quickstart](quickstart.md) - install, authenticate, and run a first session.
34
34
  - [Using Senpi](usage.md) - interactive mode, slash commands, context files, and CLI reference.
35
35
  - [Providers](providers.md) - subscription and API-key setup for built-in providers.
36
+ - [llama.cpp](llama-cpp.md) - run a local router and manage models with `/llama`.
36
37
  - [Security](security.md) - project trust, sandbox boundaries, and vulnerability reporting.
37
38
  - [Containerization](containerization.md) - sandbox senpi with Gondolin, Docker, or OpenShell.
38
39
  - [Settings](settings.md) - global and project settings.
@@ -0,0 +1,99 @@
1
+ # llama.cpp
2
+
3
+ Pi supports the [llama.cpp](https://github.com/ggml-org/llama.cpp) router server. The router discovers multiple GGUF models and loads or unloads them on demand.
4
+
5
+ Use a current llama.cpp build with router support. Follow the [build instructions](https://github.com/ggml-org/llama.cpp/blob/master/docs/build.md) or install a [prebuilt release](https://github.com/ggml-org/llama.cpp/releases) for your platform.
6
+
7
+ ## Start the router
8
+
9
+ Start `llama-server` without `--model` or `-m`. Passing a model starts single-model mode instead of router mode.
10
+
11
+ ```bash
12
+ llama-server \
13
+ --models-dir ~/models \
14
+ --no-models-autoload \
15
+ --jinja \
16
+ --host 127.0.0.1 \
17
+ --port 8080 \
18
+ -ngl 999 \
19
+ -c 32768
20
+ ```
21
+
22
+ Important options:
23
+
24
+ - `--models-dir ~/models` discovers local GGUF files.
25
+ - `--no-models-autoload` keeps loading explicit through `/llama`.
26
+ - `--jinja` enables compatible chat templates and tool calling.
27
+ - `-ngl 999` offloads as many layers as possible to the GPU.
28
+ - `-c 32768` sets the context window for each loaded model. Omit it to use the model's native context, which may require substantially more memory.
29
+
30
+ A single-file model can sit directly in the model directory. Put multimodal and multi-shard models in separate subdirectories:
31
+
32
+ ```text
33
+ ~/models/
34
+ ├── llama-3.2-1b-Q4_K_M.gguf
35
+ ├── gemma-3-4b-it-Q4_K_M/
36
+ │ ├── gemma-3-4b-it-Q4_K_M.gguf
37
+ │ └── mmproj-F16.gguf
38
+ └── large-model-Q4_K_M/
39
+ ├── large-model-Q4_K_M-00001-of-00003.gguf
40
+ ├── large-model-Q4_K_M-00002-of-00003.gguf
41
+ └── large-model-Q4_K_M-00003-of-00003.gguf
42
+ ```
43
+
44
+ Restart the router after manually adding files. For per-model context sizes and other options, use [llama.cpp model presets](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md#model-presets).
45
+
46
+ ## Configure Pi
47
+
48
+ Start Pi and configure the provider:
49
+
50
+ ```text
51
+ /login llama.cpp
52
+ ```
53
+
54
+ Enter the router URL and optional API key. The default URL is `http://127.0.0.1:8080`.
55
+
56
+ Environment variables can configure the same values without `/login`:
57
+
58
+ ```bash
59
+ export LLAMA_BASE_URL=http://127.0.0.1:8080
60
+ export LLAMA_API_KEY=optional-secret
61
+ pi
62
+ ```
63
+
64
+ If the server uses an API key, start `llama-server` with the matching `--api-key` value. Keep `--host 127.0.0.1` for local-only access.
65
+
66
+ ## Manage models
67
+
68
+ Run:
69
+
70
+ ```text
71
+ /llama
72
+ ```
73
+
74
+ - Select an unloaded model to load it.
75
+ - Select a loaded model to unload it.
76
+ - Select **Download model…**, search Hugging Face, then choose a repository and quantization. Exact `owner/repository[:quant]` values also work.
77
+ - Press Escape during a load or download to confirm cancellation.
78
+
79
+ Hugging Face search uses `HF_TOKEN` when set, then checks `$HF_TOKEN_PATH`, `$HF_HOME/token`, `$XDG_CACHE_HOME/huggingface/token`, and `~/.cache/huggingface/token`. Search also works without authentication, subject to lower rate limits. Pi warns before downloading gated repositories and links to their access page. The llama.cpp server performs the download, so its process must also have `HF_TOKEN` when the selected repository requires access.
80
+
81
+ If other models are loaded, Pi asks whether to unload them first or keep them loaded. Pi does not silently unload models and never deletes model files. The router may be shared with other clients, so `/llama` always displays the router's current state.
82
+
83
+ Only loaded models appear in `/model`. After loading a model, run `/model` to select it for the current Pi session.
84
+
85
+ If the router disconnects, `/llama` shows **Retry** and **Close**. Retry reconnects and refreshes model state without replaying the interrupted operation.
86
+
87
+ ## Troubleshooting
88
+
89
+ Check that the router is reachable:
90
+
91
+ ```bash
92
+ curl http://127.0.0.1:8080/health
93
+ curl http://127.0.0.1:8080/models
94
+ ```
95
+
96
+ - **No models in `/llama`:** Check `--models-dir`, the directory layout, and restart the router.
97
+ - **Model missing from `/model`:** Load it with `/llama` first.
98
+ - **Load fails or uses too much memory:** Lower `-c` or unload another model.
99
+ - **Server is not in router mode:** Start it without `--model`, `-m`, or `-hf`.
package/docs/neo.md CHANGED
@@ -46,7 +46,8 @@ The daemon replies `{"type":"welcome","version":1}` or
46
46
  `{"type":"refuse","code":"bad_token|version_mismatch|unsupported_options|malformed_hello","reason":"..."}`.
47
47
  `runtimeOptions` is the typed `NeoRuntimeOptions` payload (every classic runtime
48
48
  flag: provider/model/models/thinking/api-key, session selection, approval, tool
49
- scoping, resource loading, extension flags, and raw initial inputs). Its field
49
+ scoping, resource loading, system prompt overrides, extension flags, and raw
50
+ initial inputs). Its field
50
51
  set is generated from the classic runtime-construction path by an extraction
51
52
  test — a new consumer of a `parsed.*` field fails the test until it is threaded
52
53
  through the payload or documented as a carve-out.
@@ -69,6 +69,7 @@ Templates support positional arguments, defaults, and simple slicing:
69
69
  - `$1`, `$2`, ... positional args
70
70
  - `$@` or `$ARGUMENTS` for all args joined
71
71
  - `${1:-default}` uses arg 1 when present/non-empty, otherwise `default`
72
+ - `${@:-default}` or `${ARGUMENTS:-default}` uses all arguments when present/non-empty, otherwise `default`
72
73
  - `${@:N}` for args from the Nth position (1-indexed)
73
74
  - `${@:N:L}` for `L` args starting at N
74
75
 
package/docs/providers.md CHANGED
@@ -8,6 +8,7 @@ Pi supports subscription-based providers via OAuth and API key providers via env
8
8
  - [API Keys](#api-keys)
9
9
  - [Auth File](#auth-file)
10
10
  - [Cloud Providers](#cloud-providers)
11
+ - [llama.cpp](#llamacpp)
11
12
  - [Custom Providers](#custom-providers)
12
13
  - [Resolution Order](#resolution-order)
13
14
 
@@ -274,6 +275,12 @@ export GOOGLE_CLOUD_LOCATION=us-central1
274
275
 
275
276
  Or set `GOOGLE_APPLICATION_CREDENTIALS` to a service account key file.
276
277
 
278
+ ## llama.cpp
279
+
280
+ Pi supports the llama.cpp router server. Configure it with `/login llama.cpp`, manage loaded models with `/llama`, and select a loaded model with `/model`.
281
+
282
+ See [llama.cpp](llama-cpp.md) for server setup, model directory layout, environment variables, and command usage.
283
+
277
284
  ## Custom Providers
278
285
 
279
286
  **Via models.json:** Add Ollama, LM Studio, vLLM, or any provider that speaks a supported API (OpenAI Completions, OpenAI Responses, Anthropic Messages, Google Generative AI). See [models.md](models.md).
package/docs/settings.md CHANGED
@@ -206,6 +206,9 @@ Set `PI_SKIP_VERSION_CHECK=1` to disable the senpi version update check. Use `--
206
206
  | `retry.enabled` | boolean | `true` | Enable automatic agent-level retry on transient errors |
207
207
  | `retry.maxRetries` | number | `3` | Maximum agent-level retry attempts |
208
208
  | `retry.baseDelayMs` | number | `2000` | Base delay for agent-level exponential backoff (2s, 4s, 8s) |
209
+ | `retry.modelFallback` | boolean | `true` | Let eligible retry failures advance through configured per-model fallback chains |
210
+ | `retry.fallbackChains` | `Record<string, string[]>` | `{}` | Ordered exact model-selector to fallback-selector chains |
211
+ | `retry.fallbackRevertPolicy` | `"cooldown-expiry"` \| `"never"` | `"cooldown-expiry"` | Automatic primary-model restoration policy |
209
212
  | `retry.provider.timeoutMs` | number | `300000` | Provider/SDK request timeout and stream idle timeout in milliseconds |
210
213
  | `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts |
211
214
  | `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s) |
@@ -229,6 +232,38 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
229
232
  }
230
233
  ```
231
234
 
235
+ #### Model fallback chains
236
+
237
+ `retry.fallbackChains` maps one exact primary-model selector to an ordered list of fallback selectors. A selector is `provider/model` with an optional `:thinking-level` suffix. For example, this switches Fable 5 to Kimi K3 at `max` thinking when an eligible failure occurs:
238
+
239
+ ```json
240
+ {
241
+ "retry": {
242
+ "modelFallback": true,
243
+ "fallbackChains": {
244
+ "anthropic/claude-fable-5": ["ccapi/kimi-k3:max"]
245
+ },
246
+ "fallbackRevertPolicy": "cooldown-expiry"
247
+ }
248
+ }
249
+ ```
250
+
251
+ A chain is only for the exact primary model it names: selector lookup first considers an exact thinking-level selector, then the same `provider/model` without its thinking suffix. Wildcard selectors, role keys such as `default`, and other catch-all chains are not supported.
252
+
253
+ A fallback entry with `:thinking-level` requests that level on the target model; a bare entry inherits the current thinking level. Either value is clamped to the target model's supported levels. When an unpinned fallback later returns to the primary, it restores the original thinking level unless you changed it while using the fallback.
254
+
255
+ `/fallback` writes these settings to the global settings file. Project settings are still merged when read; because `fallbackChains` is a nested map, a project `retry.fallbackChains` replaces the global map rather than merging individual chain keys.
256
+
257
+ #### Fallback behavior and diagnostics
258
+
259
+ With `retry.enabled` and `retry.modelFallback` enabled, Senpi can switch from a transient or eligible hard provider failure to the next configured candidate. The switch continues the current turn without changing the existing conversation prefix, preserving prompt-cache inputs; fallback lifecycle events are never added to model context. Returning to a primary model happens only at a turn boundary, never while a response is streaming.
260
+
261
+ Anthropic streaming refusals are identified from typed `stopDetails`. A configured candidate receives an immediate **pinned** fallback switch with a user-visible fallback notice: Senpi does not retry the refusing model and a pinned fallback never auto-reverts. Set `retry.fallbackRevertPolicy` to `"cooldown-expiry"` (the default) to return an unpinned fallback to its primary after the primary's cooldown expires, or `"never"` to keep the fallback until you change models.
262
+
263
+ Fallback decisions are process-local. A `senpi-task` or subagent child process reads its own settings and maintains its own in-memory suppression state; it does not affect its parent process. Disable fallback for one run without changing settings with `--no-model-fallback` or `SENPI_NO_FALLBACK=1`.
264
+
265
+ For diagnostics, Senpi writes sanitized NDJSON records for candidate skips, cooldowns, switches, reverts, manual clears, and validation warnings to `<agentDir>/logs/fallback.log`. The file is mode `0600` and rotates at 5 MB (`fallback.log.1`).
266
+
232
267
  ### Message Delivery
233
268
 
234
269
  | Setting | Type | Default | Description |
package/docs/tui.md CHANGED
@@ -90,19 +90,32 @@ Without this propagation, typing with an IME (Chinese, Japanese, Korean, etc.) w
90
90
 
91
91
  ```typescript
92
92
  pi.on("session_start", async (_event, ctx) => {
93
- const handle = ctx.ui.custom(myComponent);
94
- // handle.requestRender() - trigger re-render
95
- // handle.close() - restore normal UI
93
+ const result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) =>
94
+ new MyComponent({
95
+ theme,
96
+ keybindings,
97
+ onChange: () => tui.requestRender(),
98
+ onSelect: (value) => done(value),
99
+ onCancel: () => done(null),
100
+ })
101
+ );
96
102
  });
97
103
  ```
98
104
 
99
- **In custom tools** via `pi.ui.custom()`:
105
+ **In custom tools** via `ctx.ui.custom()`:
100
106
 
101
107
  ```typescript
102
- async execute(toolCallId, params, onUpdate, ctx, signal) {
103
- const handle = pi.ui.custom(myComponent);
104
- // ...
105
- handle.close();
108
+ async execute(toolCallId, params, signal, onUpdate, ctx) {
109
+ const result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) =>
110
+ new MyComponent({
111
+ theme,
112
+ keybindings,
113
+ onChange: () => tui.requestRender(),
114
+ onSelect: (value) => done(value),
115
+ onCancel: () => done(null),
116
+ })
117
+ );
118
+ // Use result...
106
119
  }
107
120
  ```
108
121
 
@@ -374,24 +387,26 @@ Usage in an extension:
374
387
  ```typescript
375
388
  pi.registerCommand("pick", {
376
389
  description: "Pick an item",
377
- handler: async (args, ctx) => {
390
+ handler: async (_args, ctx) => {
378
391
  const items = ["Option A", "Option B", "Option C"];
379
- const selector = new MySelector(items);
380
-
381
- let handle: { close: () => void; requestRender: () => void };
382
-
383
- await new Promise<void>((resolve) => {
384
- selector.onSelect = (item) => {
385
- ctx.ui.notify(`Selected: ${item}`, "info");
386
- handle.close();
387
- resolve();
388
- };
389
- selector.onCancel = () => {
390
- handle.close();
391
- resolve();
392
+ const selected = await ctx.ui.custom<string | null>((tui, _theme, _keybindings, done) => {
393
+ const selector = new MySelector(items);
394
+ selector.onSelect = done;
395
+ selector.onCancel = () => done(null);
396
+
397
+ return {
398
+ render: (width) => selector.render(width),
399
+ handleInput: (data) => {
400
+ selector.handleInput(data);
401
+ tui.requestRender();
402
+ },
403
+ invalidate: () => selector.invalidate(),
392
404
  };
393
- handle = ctx.ui.custom(selector);
394
405
  });
406
+
407
+ if (selected !== null) {
408
+ ctx.ui.notify(`Selected: ${selected}`, "info");
409
+ }
395
410
  }
396
411
  });
397
412
  ```
@@ -486,7 +501,7 @@ class CachedComponent {
486
501
  }
487
502
  ```
488
503
 
489
- Call `invalidate()` when state changes, then `handle.requestRender()` to trigger re-render.
504
+ Call `invalidate()` when state changes, then use the injected `tui.requestRender()` to trigger re-render.
490
505
 
491
506
  ## Invalidation and Theme Changes
492
507
 
@@ -885,9 +900,9 @@ class VimEditor extends CustomEditor {
885
900
 
886
901
  export default function (pi: ExtensionAPI) {
887
902
  pi.on("session_start", (_event, ctx) => {
888
- // Factory receives theme and keybindings from the app
903
+ // Factory receives the TUI, theme, and keybindings from the app
889
904
  ctx.ui.setEditorComponent((tui, theme, keybindings) =>
890
- new VimEditor(theme, keybindings)
905
+ new VimEditor(tui, theme, keybindings)
891
906
  );
892
907
  });
893
908
  }
package/docs/usage.md CHANGED
@@ -37,6 +37,7 @@ Type `/` in the editor to open command completion. Extensions can register custo
37
37
  | Command | Description |
38
38
  |---------|-------------|
39
39
  | `/login`, `/logout` | Manage OAuth or API-key credentials |
40
+ | [`/llama`](llama-cpp.md) | Download, load, and unload llama.cpp router models |
40
41
  | `/model` | Switch models |
41
42
  | `/scoped-models` | Enable/disable models for Ctrl+P cycling |
42
43
  | `/settings` | Thinking level, theme, message delivery, transport |
@@ -162,7 +162,7 @@ export default function (pi: ExtensionAPI) {
162
162
  parameters: Type.Object({
163
163
  name: Type.String({ description: "Name to greet" }),
164
164
  }),
165
- async execute(toolCallId, params, onUpdate, ctx, signal) {
165
+ async execute(toolCallId, params, signal, onUpdate, ctx) {
166
166
  return {
167
167
  content: [{ type: "text", text: `Hello, ${params.name}!` }],
168
168
  details: {},
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [2026.7.20-2] - 2026-07-20
4
+
5
+ ### Breaking Changes
6
+
7
+ ### Added
8
+
9
+ ### Changed
10
+
11
+ ### Fixed
12
+
13
+ ### Removed
14
+
15
+ ## [2026.7.20] - 2026-07-20
16
+
17
+ ### Breaking Changes
18
+
19
+ ### Added
20
+
21
+ ### Changed
22
+
23
+ ### Fixed
24
+
25
+ - Fixed the Python kernel's `tool.<name>()` proxy injecting an omp-only `i` ("py prelude") intent field into every bridged tool call. Senpi tool schemas never declare `i`, so strict tools (`additionalProperties: false`, e.g. `web_search`) rejected every eval-bridged call with `Validation failed for tool …: must not have additional properties`. Args now pass through verbatim, matching the JS/Ruby/Julia preludes.
26
+
27
+ ### Removed
28
+
3
29
  ## [2026.7.17-5] - 2026-07-17
4
30
 
5
31
  ### Breaking Changes