@jini-ai/agent-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +43 -0
  3. package/dist/acp-model-probe.d.ts +48 -0
  4. package/dist/acp-model-probe.d.ts.map +1 -0
  5. package/dist/acp-model-probe.js +15 -0
  6. package/dist/acp-model-probe.js.map +1 -0
  7. package/dist/agent-protocol/acp/account-failure.d.ts +54 -0
  8. package/dist/agent-protocol/acp/account-failure.d.ts.map +1 -0
  9. package/dist/agent-protocol/acp/account-failure.js +37 -0
  10. package/dist/agent-protocol/acp/account-failure.js.map +1 -0
  11. package/dist/agent-protocol/acp/constants.d.ts +26 -0
  12. package/dist/agent-protocol/acp/constants.d.ts.map +1 -0
  13. package/dist/agent-protocol/acp/constants.js +39 -0
  14. package/dist/agent-protocol/acp/constants.js.map +1 -0
  15. package/dist/agent-protocol/acp/index.d.ts +14 -0
  16. package/dist/agent-protocol/acp/index.d.ts.map +1 -0
  17. package/dist/agent-protocol/acp/index.js +14 -0
  18. package/dist/agent-protocol/acp/index.js.map +1 -0
  19. package/dist/agent-protocol/acp/json.d.ts +82 -0
  20. package/dist/agent-protocol/acp/json.d.ts.map +1 -0
  21. package/dist/agent-protocol/acp/json.js +144 -0
  22. package/dist/agent-protocol/acp/json.js.map +1 -0
  23. package/dist/agent-protocol/acp/models.d.ts +112 -0
  24. package/dist/agent-protocol/acp/models.d.ts.map +1 -0
  25. package/dist/agent-protocol/acp/models.js +293 -0
  26. package/dist/agent-protocol/acp/models.js.map +1 -0
  27. package/dist/agent-protocol/acp/rpc.d.ts +107 -0
  28. package/dist/agent-protocol/acp/rpc.d.ts.map +1 -0
  29. package/dist/agent-protocol/acp/rpc.js +162 -0
  30. package/dist/agent-protocol/acp/rpc.js.map +1 -0
  31. package/dist/agent-protocol/acp/session-params.d.ts +55 -0
  32. package/dist/agent-protocol/acp/session-params.d.ts.map +1 -0
  33. package/dist/agent-protocol/acp/session-params.js +81 -0
  34. package/dist/agent-protocol/acp/session-params.js.map +1 -0
  35. package/dist/agent-protocol/acp/session.d.ts +101 -0
  36. package/dist/agent-protocol/acp/session.d.ts.map +1 -0
  37. package/dist/agent-protocol/acp/session.js +832 -0
  38. package/dist/agent-protocol/acp/session.js.map +1 -0
  39. package/dist/agent-protocol/acp/text-suppression.d.ts +73 -0
  40. package/dist/agent-protocol/acp/text-suppression.d.ts.map +1 -0
  41. package/dist/agent-protocol/acp/text-suppression.js +229 -0
  42. package/dist/agent-protocol/acp/text-suppression.js.map +1 -0
  43. package/dist/agent-protocol/acp/types.d.ts +27 -0
  44. package/dist/agent-protocol/acp/types.d.ts.map +1 -0
  45. package/dist/agent-protocol/acp/types.js +2 -0
  46. package/dist/agent-protocol/acp/types.js.map +1 -0
  47. package/dist/agent-protocol/acp/updates.d.ts +166 -0
  48. package/dist/agent-protocol/acp/updates.d.ts.map +1 -0
  49. package/dist/agent-protocol/acp/updates.js +268 -0
  50. package/dist/agent-protocol/acp/updates.js.map +1 -0
  51. package/dist/agent-protocol/core/index.d.ts +6 -0
  52. package/dist/agent-protocol/core/index.d.ts.map +1 -0
  53. package/dist/agent-protocol/core/index.js +6 -0
  54. package/dist/agent-protocol/core/index.js.map +1 -0
  55. package/dist/agent-protocol/core/json-line-stream.d.ts +42 -0
  56. package/dist/agent-protocol/core/json-line-stream.d.ts.map +1 -0
  57. package/dist/agent-protocol/core/json-line-stream.js +333 -0
  58. package/dist/agent-protocol/core/json-line-stream.js.map +1 -0
  59. package/dist/agent-protocol/index.d.ts +8 -0
  60. package/dist/agent-protocol/index.d.ts.map +1 -0
  61. package/dist/agent-protocol/index.js +8 -0
  62. package/dist/agent-protocol/index.js.map +1 -0
  63. package/dist/agent-protocol/pi-rpc/events.d.ts +26 -0
  64. package/dist/agent-protocol/pi-rpc/events.d.ts.map +1 -0
  65. package/dist/agent-protocol/pi-rpc/events.js +167 -0
  66. package/dist/agent-protocol/pi-rpc/events.js.map +1 -0
  67. package/dist/agent-protocol/pi-rpc/index.d.ts +11 -0
  68. package/dist/agent-protocol/pi-rpc/index.d.ts.map +1 -0
  69. package/dist/agent-protocol/pi-rpc/index.js +11 -0
  70. package/dist/agent-protocol/pi-rpc/index.js.map +1 -0
  71. package/dist/agent-protocol/pi-rpc/internal.d.ts +45 -0
  72. package/dist/agent-protocol/pi-rpc/internal.d.ts.map +1 -0
  73. package/dist/agent-protocol/pi-rpc/internal.js +41 -0
  74. package/dist/agent-protocol/pi-rpc/internal.js.map +1 -0
  75. package/dist/agent-protocol/pi-rpc/models.d.ts +21 -0
  76. package/dist/agent-protocol/pi-rpc/models.d.ts.map +1 -0
  77. package/dist/agent-protocol/pi-rpc/models.js +48 -0
  78. package/dist/agent-protocol/pi-rpc/models.js.map +1 -0
  79. package/dist/agent-protocol/pi-rpc/session.d.ts +106 -0
  80. package/dist/agent-protocol/pi-rpc/session.d.ts.map +1 -0
  81. package/dist/agent-protocol/pi-rpc/session.js +371 -0
  82. package/dist/agent-protocol/pi-rpc/session.js.map +1 -0
  83. package/dist/amr-model-cache.d.ts +40 -0
  84. package/dist/amr-model-cache.d.ts.map +1 -0
  85. package/dist/amr-model-cache.js +79 -0
  86. package/dist/amr-model-cache.js.map +1 -0
  87. package/dist/amr-profile-resolver.d.ts +21 -0
  88. package/dist/amr-profile-resolver.d.ts.map +1 -0
  89. package/dist/amr-profile-resolver.js +4 -0
  90. package/dist/amr-profile-resolver.js.map +1 -0
  91. package/dist/artifact-taxonomy.d.ts +27 -0
  92. package/dist/artifact-taxonomy.d.ts.map +1 -0
  93. package/dist/artifact-taxonomy.js +5 -0
  94. package/dist/artifact-taxonomy.js.map +1 -0
  95. package/dist/auth.d.ts +25 -0
  96. package/dist/auth.d.ts.map +1 -0
  97. package/dist/auth.js +332 -0
  98. package/dist/auth.js.map +1 -0
  99. package/dist/capabilities.d.ts +9 -0
  100. package/dist/capabilities.d.ts.map +1 -0
  101. package/dist/capabilities.js +2 -0
  102. package/dist/capabilities.js.map +1 -0
  103. package/dist/claude-stream.d.ts +37 -0
  104. package/dist/claude-stream.d.ts.map +1 -0
  105. package/dist/claude-stream.js +660 -0
  106. package/dist/claude-stream.js.map +1 -0
  107. package/dist/copilot-stream.d.ts +37 -0
  108. package/dist/copilot-stream.d.ts.map +1 -0
  109. package/dist/copilot-stream.js +136 -0
  110. package/dist/copilot-stream.js.map +1 -0
  111. package/dist/defs/aider.d.ts +13 -0
  112. package/dist/defs/aider.d.ts.map +1 -0
  113. package/dist/defs/aider.js +63 -0
  114. package/dist/defs/aider.js.map +1 -0
  115. package/dist/defs/amp.d.ts +12 -0
  116. package/dist/defs/amp.d.ts.map +1 -0
  117. package/dist/defs/amp.js +56 -0
  118. package/dist/defs/amp.js.map +1 -0
  119. package/dist/defs/amr.d.ts +37 -0
  120. package/dist/defs/amr.d.ts.map +1 -0
  121. package/dist/defs/amr.js +303 -0
  122. package/dist/defs/amr.js.map +1 -0
  123. package/dist/defs/antigravity.d.ts +25 -0
  124. package/dist/defs/antigravity.d.ts.map +1 -0
  125. package/dist/defs/antigravity.js +213 -0
  126. package/dist/defs/antigravity.js.map +1 -0
  127. package/dist/defs/claude.d.ts +30 -0
  128. package/dist/defs/claude.d.ts.map +1 -0
  129. package/dist/defs/claude.js +130 -0
  130. package/dist/defs/claude.js.map +1 -0
  131. package/dist/defs/codebuddy.d.ts +26 -0
  132. package/dist/defs/codebuddy.d.ts.map +1 -0
  133. package/dist/defs/codebuddy.js +124 -0
  134. package/dist/defs/codebuddy.js.map +1 -0
  135. package/dist/defs/codex.d.ts +30 -0
  136. package/dist/defs/codex.d.ts.map +1 -0
  137. package/dist/defs/codex.js +196 -0
  138. package/dist/defs/codex.js.map +1 -0
  139. package/dist/defs/copilot.d.ts +12 -0
  140. package/dist/defs/copilot.d.ts.map +1 -0
  141. package/dist/defs/copilot.js +88 -0
  142. package/dist/defs/copilot.js.map +1 -0
  143. package/dist/defs/cursor-agent.d.ts +27 -0
  144. package/dist/defs/cursor-agent.d.ts.map +1 -0
  145. package/dist/defs/cursor-agent.js +93 -0
  146. package/dist/defs/cursor-agent.js.map +1 -0
  147. package/dist/defs/deepseek.d.ts +12 -0
  148. package/dist/defs/deepseek.d.ts.map +1 -0
  149. package/dist/defs/deepseek.js +53 -0
  150. package/dist/defs/deepseek.js.map +1 -0
  151. package/dist/defs/devin.d.ts +12 -0
  152. package/dist/defs/devin.d.ts.map +1 -0
  153. package/dist/defs/devin.js +45 -0
  154. package/dist/defs/devin.js.map +1 -0
  155. package/dist/defs/grok-build.d.ts +26 -0
  156. package/dist/defs/grok-build.d.ts.map +1 -0
  157. package/dist/defs/grok-build.js +105 -0
  158. package/dist/defs/grok-build.js.map +1 -0
  159. package/dist/defs/hermes.d.ts +13 -0
  160. package/dist/defs/hermes.d.ts.map +1 -0
  161. package/dist/defs/hermes.js +51 -0
  162. package/dist/defs/hermes.js.map +1 -0
  163. package/dist/defs/index.d.ts +33 -0
  164. package/dist/defs/index.d.ts.map +1 -0
  165. package/dist/defs/index.js +33 -0
  166. package/dist/defs/index.js.map +1 -0
  167. package/dist/defs/kilo.d.ts +12 -0
  168. package/dist/defs/kilo.d.ts.map +1 -0
  169. package/dist/defs/kilo.js +20 -0
  170. package/dist/defs/kilo.js.map +1 -0
  171. package/dist/defs/kimi.d.ts +13 -0
  172. package/dist/defs/kimi.d.ts.map +1 -0
  173. package/dist/defs/kimi.js +26 -0
  174. package/dist/defs/kimi.js.map +1 -0
  175. package/dist/defs/kiro.d.ts +12 -0
  176. package/dist/defs/kiro.d.ts.map +1 -0
  177. package/dist/defs/kiro.js +20 -0
  178. package/dist/defs/kiro.js.map +1 -0
  179. package/dist/defs/mimo.d.ts +13 -0
  180. package/dist/defs/mimo.d.ts.map +1 -0
  181. package/dist/defs/mimo.js +26 -0
  182. package/dist/defs/mimo.js.map +1 -0
  183. package/dist/defs/opencode.d.ts +27 -0
  184. package/dist/defs/opencode.d.ts.map +1 -0
  185. package/dist/defs/opencode.js +89 -0
  186. package/dist/defs/opencode.js.map +1 -0
  187. package/dist/defs/pi.d.ts +18 -0
  188. package/dist/defs/pi.d.ts.map +1 -0
  189. package/dist/defs/pi.js +94 -0
  190. package/dist/defs/pi.js.map +1 -0
  191. package/dist/defs/qoder.d.ts +11 -0
  192. package/dist/defs/qoder.d.ts.map +1 -0
  193. package/dist/defs/qoder.js +50 -0
  194. package/dist/defs/qoder.js.map +1 -0
  195. package/dist/defs/qwen.d.ts +11 -0
  196. package/dist/defs/qwen.d.ts.map +1 -0
  197. package/dist/defs/qwen.js +28 -0
  198. package/dist/defs/qwen.js.map +1 -0
  199. package/dist/defs/reasonix.d.ts +20 -0
  200. package/dist/defs/reasonix.d.ts.map +1 -0
  201. package/dist/defs/reasonix.js +60 -0
  202. package/dist/defs/reasonix.js.map +1 -0
  203. package/dist/defs/shared.d.ts +23 -0
  204. package/dist/defs/shared.d.ts.map +1 -0
  205. package/dist/defs/shared.js +58 -0
  206. package/dist/defs/shared.js.map +1 -0
  207. package/dist/defs/trae-cli.d.ts +14 -0
  208. package/dist/defs/trae-cli.d.ts.map +1 -0
  209. package/dist/defs/trae-cli.js +22 -0
  210. package/dist/defs/trae-cli.js.map +1 -0
  211. package/dist/defs/vibe.d.ts +12 -0
  212. package/dist/defs/vibe.d.ts.map +1 -0
  213. package/dist/defs/vibe.js +20 -0
  214. package/dist/defs/vibe.js.map +1 -0
  215. package/dist/detection.d.ts +14 -0
  216. package/dist/detection.d.ts.map +1 -0
  217. package/dist/detection.js +266 -0
  218. package/dist/detection.js.map +1 -0
  219. package/dist/diagnostics.d.ts +8 -0
  220. package/dist/diagnostics.d.ts.map +1 -0
  221. package/dist/diagnostics.js +95 -0
  222. package/dist/diagnostics.js.map +1 -0
  223. package/dist/env.d.ts +19 -0
  224. package/dist/env.d.ts.map +1 -0
  225. package/dist/env.js +95 -0
  226. package/dist/env.js.map +1 -0
  227. package/dist/executables.d.ts +24 -0
  228. package/dist/executables.d.ts.map +1 -0
  229. package/dist/executables.js +349 -0
  230. package/dist/executables.js.map +1 -0
  231. package/dist/index.d.ts +74 -0
  232. package/dist/index.d.ts.map +1 -0
  233. package/dist/index.js +102 -0
  234. package/dist/index.js.map +1 -0
  235. package/dist/invocation.d.ts +6 -0
  236. package/dist/invocation.d.ts.map +1 -0
  237. package/dist/invocation.js +47 -0
  238. package/dist/invocation.js.map +1 -0
  239. package/dist/json-event-stream.d.ts +9 -0
  240. package/dist/json-event-stream.d.ts.map +1 -0
  241. package/dist/json-event-stream.js +856 -0
  242. package/dist/json-event-stream.js.map +1 -0
  243. package/dist/launch.d.ts +12 -0
  244. package/dist/launch.d.ts.map +1 -0
  245. package/dist/launch.js +221 -0
  246. package/dist/launch.js.map +1 -0
  247. package/dist/mcp.d.ts +44 -0
  248. package/dist/mcp.d.ts.map +1 -0
  249. package/dist/mcp.js +12 -0
  250. package/dist/mcp.js.map +1 -0
  251. package/dist/metadata.d.ts +24 -0
  252. package/dist/metadata.d.ts.map +1 -0
  253. package/dist/metadata.js +100 -0
  254. package/dist/metadata.js.map +1 -0
  255. package/dist/mmd-routes.d.ts +12 -0
  256. package/dist/mmd-routes.d.ts.map +1 -0
  257. package/dist/mmd-routes.js +146 -0
  258. package/dist/mmd-routes.js.map +1 -0
  259. package/dist/model-registry.d.ts +120 -0
  260. package/dist/model-registry.d.ts.map +1 -0
  261. package/dist/model-registry.js +77 -0
  262. package/dist/model-registry.js.map +1 -0
  263. package/dist/models.d.ts +16 -0
  264. package/dist/models.d.ts.map +1 -0
  265. package/dist/models.js +93 -0
  266. package/dist/models.js.map +1 -0
  267. package/dist/opencode-log.d.ts +16 -0
  268. package/dist/opencode-log.d.ts.map +1 -0
  269. package/dist/opencode-log.js +163 -0
  270. package/dist/opencode-log.js.map +1 -0
  271. package/dist/paths.d.ts +3 -0
  272. package/dist/paths.d.ts.map +1 -0
  273. package/dist/paths.js +29 -0
  274. package/dist/paths.js.map +1 -0
  275. package/dist/pi-models.d.ts +13 -0
  276. package/dist/pi-models.d.ts.map +1 -0
  277. package/dist/pi-models.js +36 -0
  278. package/dist/pi-models.js.map +1 -0
  279. package/dist/prompt-augmenter.d.ts +60 -0
  280. package/dist/prompt-augmenter.d.ts.map +1 -0
  281. package/dist/prompt-augmenter.js +26 -0
  282. package/dist/prompt-augmenter.js.map +1 -0
  283. package/dist/prompt-budget.d.ts +20 -0
  284. package/dist/prompt-budget.d.ts.map +1 -0
  285. package/dist/prompt-budget.js +226 -0
  286. package/dist/prompt-budget.js.map +1 -0
  287. package/dist/prompt-file.d.ts +7 -0
  288. package/dist/prompt-file.d.ts.map +1 -0
  289. package/dist/prompt-file.js +27 -0
  290. package/dist/prompt-file.js.map +1 -0
  291. package/dist/providers/aihubmix.d.ts +99 -0
  292. package/dist/providers/aihubmix.d.ts.map +1 -0
  293. package/dist/providers/aihubmix.js +239 -0
  294. package/dist/providers/aihubmix.js.map +1 -0
  295. package/dist/providers/anthropic-messages.d.ts +116 -0
  296. package/dist/providers/anthropic-messages.d.ts.map +1 -0
  297. package/dist/providers/anthropic-messages.js +313 -0
  298. package/dist/providers/anthropic-messages.js.map +1 -0
  299. package/dist/providers/azure-chat.d.ts +99 -0
  300. package/dist/providers/azure-chat.d.ts.map +1 -0
  301. package/dist/providers/azure-chat.js +164 -0
  302. package/dist/providers/azure-chat.js.map +1 -0
  303. package/dist/providers/connection-guard.d.ts +67 -0
  304. package/dist/providers/connection-guard.d.ts.map +1 -0
  305. package/dist/providers/connection-guard.js +211 -0
  306. package/dist/providers/connection-guard.js.map +1 -0
  307. package/dist/providers/elevenlabs.d.ts +28 -0
  308. package/dist/providers/elevenlabs.d.ts.map +1 -0
  309. package/dist/providers/elevenlabs.js +138 -0
  310. package/dist/providers/elevenlabs.js.map +1 -0
  311. package/dist/providers/google-messages.d.ts +108 -0
  312. package/dist/providers/google-messages.d.ts.map +1 -0
  313. package/dist/providers/google-messages.js +284 -0
  314. package/dist/providers/google-messages.js.map +1 -0
  315. package/dist/providers/google.d.ts +20 -0
  316. package/dist/providers/google.d.ts.map +1 -0
  317. package/dist/providers/google.js +42 -0
  318. package/dist/providers/google.js.map +1 -0
  319. package/dist/providers/index.d.ts +39 -0
  320. package/dist/providers/index.d.ts.map +1 -0
  321. package/dist/providers/index.js +39 -0
  322. package/dist/providers/index.js.map +1 -0
  323. package/dist/providers/model-catalog.d.ts +32 -0
  324. package/dist/providers/model-catalog.d.ts.map +1 -0
  325. package/dist/providers/model-catalog.js +394 -0
  326. package/dist/providers/model-catalog.js.map +1 -0
  327. package/dist/providers/oauth-callback-server.d.ts +35 -0
  328. package/dist/providers/oauth-callback-server.d.ts.map +1 -0
  329. package/dist/providers/oauth-callback-server.js +217 -0
  330. package/dist/providers/oauth-callback-server.js.map +1 -0
  331. package/dist/providers/oauth-credentials.d.ts +29 -0
  332. package/dist/providers/oauth-credentials.d.ts.map +1 -0
  333. package/dist/providers/oauth-credentials.js +70 -0
  334. package/dist/providers/oauth-credentials.js.map +1 -0
  335. package/dist/providers/oauth-provider.d.ts +95 -0
  336. package/dist/providers/oauth-provider.d.ts.map +1 -0
  337. package/dist/providers/oauth-provider.js +130 -0
  338. package/dist/providers/oauth-provider.js.map +1 -0
  339. package/dist/providers/oauth-tokens.d.ts +35 -0
  340. package/dist/providers/oauth-tokens.d.ts.map +1 -0
  341. package/dist/providers/oauth-tokens.js +136 -0
  342. package/dist/providers/oauth-tokens.js.map +1 -0
  343. package/dist/providers/ollama-chat.d.ts +106 -0
  344. package/dist/providers/ollama-chat.d.ts.map +1 -0
  345. package/dist/providers/ollama-chat.js +292 -0
  346. package/dist/providers/ollama-chat.js.map +1 -0
  347. package/dist/providers/openai-chat.d.ts +147 -0
  348. package/dist/providers/openai-chat.d.ts.map +1 -0
  349. package/dist/providers/openai-chat.js +302 -0
  350. package/dist/providers/openai-chat.js.map +1 -0
  351. package/dist/providers/pkce.d.ts +81 -0
  352. package/dist/providers/pkce.d.ts.map +1 -0
  353. package/dist/providers/pkce.js +176 -0
  354. package/dist/providers/pkce.js.map +1 -0
  355. package/dist/providers/sse-decode.d.ts +47 -0
  356. package/dist/providers/sse-decode.d.ts.map +1 -0
  357. package/dist/providers/sse-decode.js +109 -0
  358. package/dist/providers/sse-decode.js.map +1 -0
  359. package/dist/providers/token-params.d.ts +29 -0
  360. package/dist/providers/token-params.d.ts.map +1 -0
  361. package/dist/providers/token-params.js +41 -0
  362. package/dist/providers/token-params.js.map +1 -0
  363. package/dist/providers/turn-end-guard.d.ts +37 -0
  364. package/dist/providers/turn-end-guard.d.ts.map +1 -0
  365. package/dist/providers/turn-end-guard.js +42 -0
  366. package/dist/providers/turn-end-guard.js.map +1 -0
  367. package/dist/providers/types.d.ts +36 -0
  368. package/dist/providers/types.d.ts.map +1 -0
  369. package/dist/providers/types.js +13 -0
  370. package/dist/providers/types.js.map +1 -0
  371. package/dist/qoder-stream.d.ts +19 -0
  372. package/dist/qoder-stream.d.ts.map +1 -0
  373. package/dist/qoder-stream.js +167 -0
  374. package/dist/qoder-stream.js.map +1 -0
  375. package/dist/registry.d.ts +5 -0
  376. package/dist/registry.d.ts.map +1 -0
  377. package/dist/registry.js +58 -0
  378. package/dist/registry.js.map +1 -0
  379. package/dist/resolution.d.ts +2 -0
  380. package/dist/resolution.d.ts.map +1 -0
  381. package/dist/resolution.js +19 -0
  382. package/dist/resolution.js.map +1 -0
  383. package/dist/role-marker-guard.d.ts +53 -0
  384. package/dist/role-marker-guard.d.ts.map +1 -0
  385. package/dist/role-marker-guard.js +280 -0
  386. package/dist/role-marker-guard.js.map +1 -0
  387. package/dist/telemetry-sink.d.ts +35 -0
  388. package/dist/telemetry-sink.d.ts.map +1 -0
  389. package/dist/telemetry-sink.js +5 -0
  390. package/dist/telemetry-sink.js.map +1 -0
  391. package/dist/terminal-launch.d.ts +11 -0
  392. package/dist/terminal-launch.d.ts.map +1 -0
  393. package/dist/terminal-launch.js +123 -0
  394. package/dist/terminal-launch.js.map +1 -0
  395. package/dist/types.d.ts +185 -0
  396. package/dist/types.d.ts.map +1 -0
  397. package/dist/types.js +2 -0
  398. package/dist/types.js.map +1 -0
  399. package/package.json +47 -0
@@ -0,0 +1,832 @@
1
+ /** @module agent-protocol/acp/session
2
+ * ACP session orchestrator: performs the full initialize → session/new (or
3
+ * session/load) → session/prompt handshake with an already-spawned ACP
4
+ * subprocess, streams updates to the daemon event bus, handles permission
5
+ * replies, artifact-write mirroring, DSML text suppression, and clean abort.
6
+ * Depends on every other acp/ file and the core JSON-line stream. Consumed by
7
+ * connection-test and server entry points (via the acp/ barrel).
8
+ */
9
+ import path from 'node:path';
10
+ import { createDsmlArtifactTextSuppressor, createToolCallTextSuppressor, } from './text-suppression.js';
11
+ import { createJsonLineStream } from '../core/index.js';
12
+ import { ACP_PROTOCOL_VERSION, DEFAULT_STAGE_TIMEOUT_MS, ACP_ARTIFACT_ECHO_START_RE, ACP_RAW_EVENT_SHAPE_DIAGNOSTIC_LIMIT, AMR_STDERR_RETRY_TAIL_LIMIT, } from './constants.js';
13
+ import { errorMessage, asObject, extractAcpUpdateText } from './json.js';
14
+ import { sendRpc, sendRpcResult, isJsonRpcId, rpcErrorMessage, rpcErrorData, rpcErrorRetryable, promotedOpenCodeSessionErrorPayload, formatUsage, } from './rpc.js';
15
+ import { acpRawEventShape, isAcpCompletedStatus, isAcpTerminalFailureStatus, acpToolCallId, isAcpArtifactWriteLabel, isAcpArtifactWriteUpdate, acpArtifactWritePath, promotedAmrRetryStatusPayload, promotedAmrStderrPayload, } from './updates.js';
16
+ import { findModelConfigOption, currentModelFromSessionResult, modelSelectionErrorIsRecoverable, } from './models.js';
17
+ import { buildAcpSessionNewParams, buildPromptBlocks } from './session-params.js';
18
+ import { noopAccountFailureClassifier } from './account-failure.js';
19
+ /**
20
+ * Attaches an ACP protocol session to an already-spawned child process and
21
+ * drives the full JSON-RPC conversation from handshake to prompt completion.
22
+ *
23
+ * Sequence:
24
+ * 1. Sends `initialize` to confirm the protocol version.
25
+ * 2. Sends `session/new` (or `session/load` when `resumeSessionId` is set).
26
+ * 3. Optionally sends `session/set_model` when a non-default model is requested.
27
+ * 4. Sends `session/prompt` with the user's prompt and any image attachments.
28
+ * 5. Streams `session/update` events to the `send` callback, translating:
29
+ * - `agent_thought_chunk` → `thinking_start` / `thinking_delta`
30
+ * - `agent_message_chunk` → `text_delta` (with DSML and tool-call text suppression)
31
+ * - `tool_call` / `tool_call_update` → deferred `tool_use` / `tool_result` pairs
32
+ * - status updates → `agent.status` events
33
+ * 6. Handles `session/request_permission` calls through an injected policy,
34
+ * failing closed when no policy is supplied.
35
+ * 7. On prompt completion, flushes suppression buffers, emits usage, and closes stdin.
36
+ *
37
+ * Returns a controller object that the caller may use to query session state
38
+ * and to abort the in-progress turn.
39
+ *
40
+ * @param options - See `AttachAcpSessionOptions` for all fields.
41
+ * @returns A controller with `hasFatalError`, `getDurableSessionId`,
42
+ * `completedSuccessfully`, and `abort` methods.
43
+ */
44
+ export function attachAcpSession({ child, prompt, cwd, model, imagePaths = [], mcpServers, envFormat = 'array', send, clientName = 'agent-runtime', clientVersion = 'runtime-adapter', stageTimeoutMs = DEFAULT_STAGE_TIMEOUT_MS, executionProfile = 'filesystem', modelUnavailableErrorCode, accountFailureClassifier = noopAccountFailureClassifier, resumeSessionId, onPermissionRequest, onCliReady, onSessionInit, }) {
45
+ const runStartedAt = Date.now();
46
+ const effectiveCwd = path.resolve(cwd || process.cwd());
47
+ if (!child.stdin || !child.stdout) {
48
+ throw new Error('ACP child process must expose stdin and stdout streams');
49
+ }
50
+ const stdin = child.stdin;
51
+ const stdout = child.stdout;
52
+ let expectedId = 1;
53
+ let nextId = 2;
54
+ let promptRequestId = null;
55
+ let setModelRequestId = null;
56
+ let sessionId = null;
57
+ // The durable upstream session handle reported by the agent on session/new or
58
+ // session/load (e.g. a vendor bridge's own session id). The caller stores it
59
+ // per conversation to resume next turn. Distinct from `sessionId`, which is
60
+ // the ACP wrapper id.
61
+ let durableSessionId = null;
62
+ let activeModel = null;
63
+ let modelConfigId = null;
64
+ let emittedThinkingStart = false;
65
+ let emittedFirstTokenStatus = false;
66
+ let emittedTextChunk = false;
67
+ let emittedVisibleTextChunk = false;
68
+ let emittedToolCall = false;
69
+ let emittedConcreteToolEvent = false;
70
+ let emittedTextBuffer = '';
71
+ let rawAcpShapeDiagnosticCount = 0;
72
+ let artifactSuppressionDiagnosticCount = 0;
73
+ let amrStderrRetryTail = '';
74
+ let finished = false;
75
+ let fatal = false;
76
+ let aborted = false;
77
+ let stageTimer = null;
78
+ let dsmlArtifactSuppressor = null;
79
+ let dsmlArtifactSuppressorLastSuppressedChars = 0;
80
+ let dsmlArtifactSuppressorToolCallId = null;
81
+ let dsmlArtifactSuppressorArmedAfterText = false;
82
+ let dsmlArtifactSuppressorSawIncrementalProse = false;
83
+ const pendingPermissionRequestIds = new Set();
84
+ const toolCallTextSuppressor = createToolCallTextSuppressor();
85
+ let toolCallTextSuppressorLastSuppressedChars = 0;
86
+ const artifactTextSuppressionSummary = {
87
+ suppressedChars: 0,
88
+ suppressedChunks: 0,
89
+ openedBlocks: 0,
90
+ closedBlocks: 0,
91
+ };
92
+ const toolCallTextSuppressionSummary = {
93
+ suppressedChars: 0,
94
+ suppressedChunks: 0,
95
+ openedBlocks: 0,
96
+ closedBlocks: 0,
97
+ };
98
+ const acpArtifactWriteToolCallIds = new Set();
99
+ // Per artifact-write tool call, accumulate the best concrete file path seen
100
+ // across its frames and whether we have already mirrored it into canonical
101
+ // tool_use/tool_result events. Emission is deferred to the terminal frame so
102
+ // a `locations`/`rawInput` path that ACP only sends on a later update is used
103
+ // for classification, instead of locking in a first-frame guess.
104
+ const acpArtifactRunEventState = new Map();
105
+ const stageWatchdogDisabled = stageTimeoutMs <= 0;
106
+ const resetStageTimer = (label) => {
107
+ if (stageTimer)
108
+ clearTimeout(stageTimer);
109
+ // `stageTimeoutMs <= 0` disables the watchdog. Mirrors a typical outer
110
+ // run-level inactivity watchdog's escape hatch. Without this, a caller
111
+ // passing a zero stage timeout would schedule a 0ms timeout that fires on
112
+ // the next tick and kills the session immediately.
113
+ if (stageWatchdogDisabled)
114
+ return;
115
+ stageTimer = setTimeout(() => {
116
+ fail(`ACP ${label} timed out after ${stageTimeoutMs}ms`);
117
+ }, stageTimeoutMs);
118
+ };
119
+ const clearStageTimer = () => {
120
+ if (stageTimer)
121
+ clearTimeout(stageTimer);
122
+ stageTimer = null;
123
+ };
124
+ const amrModelUnavailablePayload = (message) => ({
125
+ message,
126
+ error: {
127
+ code: 'AMR_MODEL_UNAVAILABLE',
128
+ message,
129
+ retryable: false,
130
+ details: { kind: 'amr_model', action: 'choose_model' },
131
+ },
132
+ });
133
+ const isModelUnavailableError = (message) => {
134
+ const value = message.toLowerCase();
135
+ return (value.includes('model not found') ||
136
+ value.includes('providermodelnotfounderror') ||
137
+ value.includes('unknown model') ||
138
+ value.includes('invalid model'));
139
+ };
140
+ // Both call sites below (the session/update retry-status promotion and the
141
+ // stderr promotion) are already nested inside a scope gated by `finished`
142
+ // at their own entry point (the parser callback's own `if (aborted ||
143
+ // finished) return;`, and the stderr handler's `if (!modelUnavailableErrorCode
144
+ // || finished) return;`), and neither is re-entrant within a single
145
+ // synchronous call — so `failWithPayload` can never actually be invoked a
146
+ // second time once `finished` is true. The origin file carried its own
147
+ // `if (finished) return;` re-entry guard here anyway; removed per this
148
+ // package's coverage-driven dead-branch discipline (verified unreachable
149
+ // by tracing every call site — see source-map.md), not suppressed.
150
+ const failWithPayload = (payload) => {
151
+ finished = true;
152
+ fatal = true;
153
+ clearStageTimer();
154
+ send('error', payload);
155
+ if (!child.killed)
156
+ child.kill('SIGTERM');
157
+ };
158
+ const fail = (message, options = {}) => {
159
+ if (finished)
160
+ return;
161
+ finished = true;
162
+ fatal = true;
163
+ clearStageTimer();
164
+ const useModelUnavailable = modelUnavailableErrorCode &&
165
+ (options.forceModelUnavailable || isModelUnavailableError(message));
166
+ send('error', useModelUnavailable
167
+ ? amrModelUnavailablePayload(message)
168
+ : options.details === undefined && options.retryable === undefined
169
+ ? { message }
170
+ : {
171
+ message,
172
+ error: {
173
+ code: 'AGENT_EXECUTION_FAILED',
174
+ message,
175
+ retryable: options.retryable ?? false,
176
+ // Every real call site that reaches this branch (the
177
+ // RPC-error path and the no-visible-output path) always
178
+ // supplies `details` whenever it supplies `retryable`, and
179
+ // `retryable` is itself derived from the same `details`
180
+ // source at the RPC-error call site — so `options.details`
181
+ // is never actually undefined here. Spreading it
182
+ // unconditionally (rather than conditionally omitting the
183
+ // key) is behaviorally identical for every real caller;
184
+ // simplified per this package's coverage-driven
185
+ // dead-branch discipline. See source-map.md.
186
+ details: options.details,
187
+ },
188
+ });
189
+ if (!child.killed)
190
+ child.kill('SIGTERM');
191
+ };
192
+ const writeRpc = (id, method, params, timeoutLabel) => {
193
+ resetStageTimer(timeoutLabel);
194
+ try {
195
+ sendRpc(stdin, id, method, params);
196
+ }
197
+ catch (err) {
198
+ fail(`stdin write failed: ${errorMessage(err)}`);
199
+ }
200
+ };
201
+ const emitAcpRawShapeDiagnostic = (update) => {
202
+ if (!modelUnavailableErrorCode)
203
+ return;
204
+ if (rawAcpShapeDiagnosticCount >= ACP_RAW_EVENT_SHAPE_DIAGNOSTIC_LIMIT)
205
+ return;
206
+ rawAcpShapeDiagnosticCount += 1;
207
+ send('agent', {
208
+ type: 'diagnostic',
209
+ name: 'acp_raw_event_shape',
210
+ source: 'acp-json-rpc',
211
+ elapsedMs: Date.now() - runStartedAt,
212
+ shape: acpRawEventShape(update),
213
+ });
214
+ };
215
+ // All three call sites guard against an empty `delta` before calling this
216
+ // (the finishCleanPrompt flush, the `if (outputDelta)` branch, and the
217
+ // plain-else branch which is only reached after an earlier `if
218
+ // (!toolCallStrippedDelta) return;` already ruled out emptiness) — so the
219
+ // origin file's own `if (!delta) return;` guard here can never actually
220
+ // fire. Removed per this package's coverage-driven dead-branch
221
+ // discipline (verified unreachable by tracing every call site — see
222
+ // source-map.md), not suppressed.
223
+ const emitVisibleTextDelta = (delta) => {
224
+ emittedVisibleTextChunk = true;
225
+ if (!emittedFirstTokenStatus) {
226
+ emittedFirstTokenStatus = true;
227
+ send('agent', {
228
+ type: 'status',
229
+ label: 'streaming',
230
+ ttftMs: Date.now() - runStartedAt,
231
+ });
232
+ }
233
+ send('agent', { type: 'text_delta', delta });
234
+ };
235
+ const noteArtifactTextSuppression = (reason) => {
236
+ if (!dsmlArtifactSuppressor)
237
+ return;
238
+ const stats = dsmlArtifactSuppressor.stats();
239
+ const suppressedDelta = stats.suppressedChars - dsmlArtifactSuppressorLastSuppressedChars;
240
+ if (suppressedDelta <= 0)
241
+ return;
242
+ dsmlArtifactSuppressorLastSuppressedChars = stats.suppressedChars;
243
+ artifactTextSuppressionSummary.suppressedChars += suppressedDelta;
244
+ artifactTextSuppressionSummary.suppressedChunks = stats.suppressedChunks;
245
+ artifactTextSuppressionSummary.openedBlocks = stats.openedBlocks;
246
+ artifactTextSuppressionSummary.closedBlocks = stats.closedBlocks;
247
+ if (artifactSuppressionDiagnosticCount >= ACP_RAW_EVENT_SHAPE_DIAGNOSTIC_LIMIT)
248
+ return;
249
+ artifactSuppressionDiagnosticCount += 1;
250
+ send('agent', {
251
+ type: 'diagnostic',
252
+ name: 'acp_artifact_text_suppression',
253
+ source: 'acp-json-rpc',
254
+ elapsedMs: Date.now() - runStartedAt,
255
+ reason,
256
+ suppressedChars: artifactTextSuppressionSummary.suppressedChars,
257
+ suppressedChunks: artifactTextSuppressionSummary.suppressedChunks,
258
+ openedBlocks: artifactTextSuppressionSummary.openedBlocks,
259
+ closedBlocks: artifactTextSuppressionSummary.closedBlocks,
260
+ pendingCandidateChars: stats.pendingCandidateChars,
261
+ suppressing: stats.suppressing,
262
+ });
263
+ };
264
+ const emitArtifactTextSuppressionSummary = () => {
265
+ if (artifactTextSuppressionSummary.suppressedChars <= 0)
266
+ return;
267
+ if (executionProfile === 'filesystem') {
268
+ send('agent', {
269
+ type: 'diagnostic',
270
+ name: 'unexpected_text_artifact_in_filesystem_run',
271
+ source: 'acp-json-rpc',
272
+ elapsedMs: Date.now() - runStartedAt,
273
+ suppressedChars: artifactTextSuppressionSummary.suppressedChars,
274
+ suppressedChunks: artifactTextSuppressionSummary.suppressedChunks,
275
+ openedBlocks: artifactTextSuppressionSummary.openedBlocks,
276
+ closedBlocks: artifactTextSuppressionSummary.closedBlocks,
277
+ });
278
+ }
279
+ send('agent', {
280
+ type: 'diagnostic',
281
+ name: 'acp_artifact_text_suppression_summary',
282
+ source: 'acp-json-rpc',
283
+ elapsedMs: Date.now() - runStartedAt,
284
+ ...artifactTextSuppressionSummary,
285
+ });
286
+ };
287
+ const noteToolCallTextSuppression = (reason) => {
288
+ const stats = toolCallTextSuppressor.stats();
289
+ const suppressedDelta = stats.suppressedChars - toolCallTextSuppressorLastSuppressedChars;
290
+ if (suppressedDelta <= 0)
291
+ return;
292
+ toolCallTextSuppressorLastSuppressedChars = stats.suppressedChars;
293
+ toolCallTextSuppressionSummary.suppressedChars += suppressedDelta;
294
+ toolCallTextSuppressionSummary.suppressedChunks = stats.suppressedChunks;
295
+ toolCallTextSuppressionSummary.openedBlocks = stats.openedBlocks;
296
+ toolCallTextSuppressionSummary.closedBlocks = stats.closedBlocks;
297
+ if (artifactSuppressionDiagnosticCount >= ACP_RAW_EVENT_SHAPE_DIAGNOSTIC_LIMIT)
298
+ return;
299
+ artifactSuppressionDiagnosticCount += 1;
300
+ send('agent', {
301
+ type: 'diagnostic',
302
+ name: 'acp_tool_call_text_suppression',
303
+ source: 'acp-json-rpc',
304
+ elapsedMs: Date.now() - runStartedAt,
305
+ reason,
306
+ suppressedChars: toolCallTextSuppressionSummary.suppressedChars,
307
+ suppressedChunks: toolCallTextSuppressionSummary.suppressedChunks,
308
+ openedBlocks: toolCallTextSuppressionSummary.openedBlocks,
309
+ closedBlocks: toolCallTextSuppressionSummary.closedBlocks,
310
+ pendingCandidateChars: stats.pendingCandidateChars,
311
+ suppressing: stats.suppressing,
312
+ });
313
+ };
314
+ const emitToolCallTextSuppressionSummary = () => {
315
+ if (toolCallTextSuppressionSummary.suppressedChars <= 0)
316
+ return;
317
+ send('agent', {
318
+ type: 'diagnostic',
319
+ name: 'acp_tool_call_text_suppression_summary',
320
+ source: 'acp-json-rpc',
321
+ elapsedMs: Date.now() - runStartedAt,
322
+ ...toolCallTextSuppressionSummary,
323
+ });
324
+ };
325
+ const sendPrompt = () => {
326
+ promptRequestId = nextId;
327
+ expectedId = promptRequestId;
328
+ writeRpc(promptRequestId, 'session/prompt', {
329
+ sessionId,
330
+ prompt: buildPromptBlocks(prompt, imagePaths),
331
+ }, 'session/prompt');
332
+ send('agent', {
333
+ type: 'status',
334
+ label: 'waiting_for_first_output',
335
+ elapsedMs: Date.now() - runStartedAt,
336
+ });
337
+ nextId += 1;
338
+ };
339
+ // `finishCleanPrompt` has exactly one call site, inside the parser
340
+ // callback's promptRequestId-match branch, which is itself already gated
341
+ // by that same callback's own `if (aborted || finished) return;` at entry
342
+ // — so this function can never actually be invoked once `finished` is
343
+ // true. The origin file carried its own re-entry guard here anyway;
344
+ // removed per this package's coverage-driven dead-branch discipline. See
345
+ // source-map.md.
346
+ const finishCleanPrompt = (usageSource) => {
347
+ const flushedToolText = toolCallTextSuppressor.flush();
348
+ noteToolCallTextSuppression('tool_call_xml_flush');
349
+ const flushedText = flushedToolText ? (dsmlArtifactSuppressor?.strip(flushedToolText) ?? flushedToolText) : '';
350
+ if (flushedText) {
351
+ emitVisibleTextDelta(flushedText);
352
+ }
353
+ noteArtifactTextSuppression('artifact_flush');
354
+ emitToolCallTextSuppressionSummary();
355
+ emitArtifactTextSuppressionSummary();
356
+ const usage = formatUsage(usageSource);
357
+ if (usage) {
358
+ send('agent', {
359
+ type: 'usage',
360
+ usage,
361
+ durationMs: Date.now() - runStartedAt,
362
+ });
363
+ }
364
+ finished = true;
365
+ clearStageTimer();
366
+ stdin.end();
367
+ // Some ACP agents keep the child process alive after stdin closes,
368
+ // waiting for another prompt. Each run owns one process per turn, so
369
+ // close it once this prompt is cleanly complete.
370
+ const cleanExitTimer = setTimeout(() => {
371
+ if (!child.killed)
372
+ child.kill('SIGTERM');
373
+ }, 500);
374
+ child.once('close', () => clearTimeout(cleanExitTimer));
375
+ };
376
+ const replyPermission = (raw) => {
377
+ const params = asObject(raw.params);
378
+ if (!params || !isJsonRpcId(raw.id)) {
379
+ fail(`unhandled ACP permission request: ${JSON.stringify(raw)}`);
380
+ return;
381
+ }
382
+ const requestId = raw.id;
383
+ const optionRecords = Array.isArray(params.options)
384
+ ? params.options.filter((option) => Boolean(asObject(option)) && typeof asObject(option)?.optionId === 'string')
385
+ : [];
386
+ const request = {
387
+ requestId,
388
+ sessionId: typeof params.sessionId === 'string' ? params.sessionId : null,
389
+ toolCall: asObject(params.toolCall) ?? null,
390
+ options: optionRecords,
391
+ rawParams: params,
392
+ };
393
+ const respond = (decision) => {
394
+ pendingPermissionRequestIds.delete(requestId);
395
+ if (aborted || finished)
396
+ return;
397
+ if (decision.outcome === 'selected' &&
398
+ !optionRecords.some((option) => option.optionId === decision.optionId)) {
399
+ fail(`ACP permission handler selected an unavailable option: ${decision.optionId}`);
400
+ return;
401
+ }
402
+ resetStageTimer('session/request_permission');
403
+ try {
404
+ sendRpcResult(stdin, requestId, {
405
+ outcome: decision.outcome === 'selected'
406
+ ? { outcome: 'selected', optionId: decision.optionId }
407
+ : { outcome: 'cancelled' },
408
+ });
409
+ }
410
+ catch (err) {
411
+ fail(`stdin write failed: ${errorMessage(err)}`);
412
+ }
413
+ };
414
+ const rejectHandlerFailure = (err) => {
415
+ pendingPermissionRequestIds.delete(requestId);
416
+ fail(`ACP permission handler failed: ${errorMessage(err)}`);
417
+ };
418
+ pendingPermissionRequestIds.add(requestId);
419
+ if (!onPermissionRequest) {
420
+ pendingPermissionRequestIds.delete(requestId);
421
+ fail('ACP permission request received without an injected permission handler');
422
+ return;
423
+ }
424
+ try {
425
+ Promise.resolve(onPermissionRequest(request)).then(respond, rejectHandlerFailure);
426
+ }
427
+ catch (err) {
428
+ rejectHandlerFailure(err);
429
+ }
430
+ };
431
+ const recoverFromModelSelectionError = () => {
432
+ setModelRequestId = null;
433
+ activeModel = activeModel || 'default';
434
+ send('agent', { type: 'status', label: 'model', model: activeModel });
435
+ sendPrompt();
436
+ };
437
+ const parser = createJsonLineStream((raw, rawLine) => {
438
+ if (aborted || finished)
439
+ return;
440
+ resetStageTimer('response');
441
+ const obj = asObject(raw);
442
+ if (!obj)
443
+ return;
444
+ // First well-formed ACP JSON-RPC message = CLI ready. Caller dedupes, so
445
+ // re-notifying on later messages is harmless.
446
+ onCliReady?.();
447
+ const error = asObject(obj.error);
448
+ const params = asObject(obj.params);
449
+ const result = asObject(obj.result);
450
+ const rpcErr = rpcErrorMessage(obj);
451
+ if (rpcErr) {
452
+ // A late-arriving error from the agent after the session has already
453
+ // finished (pipe-broken, cleanup race conditions, etc.) would be safe
454
+ // to ignore here — but this whole callback is already gated by `if
455
+ // (aborted || finished) return;` at its own top (line 499), and
456
+ // nothing between there and here can flip `finished` to true
457
+ // mid-invocation, so a second, inner check of the same condition can
458
+ // never actually fire. Removed per this package's coverage-driven
459
+ // dead-branch discipline (verified unreachable by tracing the
460
+ // callback's own control flow — see source-map.md), not suppressed.
461
+ // JSON-RPC error handling:
462
+ // -32603 unexpected-id errors are cleanup noise. Expected-id model
463
+ // selection failures are recoverable; all other RPC errors are real
464
+ // protocol failures for initialize/session/new/session/prompt.
465
+ if (obj.id === setModelRequestId &&
466
+ modelSelectionErrorIsRecoverable(error?.code) &&
467
+ promptRequestId === null) {
468
+ recoverFromModelSelectionError();
469
+ return;
470
+ }
471
+ if (error?.code === -32603 && obj.id !== expectedId) {
472
+ return;
473
+ }
474
+ const details = rpcErrorData(obj);
475
+ const promotedPayload = promotedOpenCodeSessionErrorPayload(details, rpcErr);
476
+ if (promotedPayload) {
477
+ failWithPayload(promotedPayload);
478
+ return;
479
+ }
480
+ const retryable = rpcErrorRetryable(details);
481
+ fail(rpcErr, {
482
+ details,
483
+ ...(retryable === undefined ? {} : { retryable }),
484
+ });
485
+ return;
486
+ }
487
+ if (obj.method === 'session/request_permission') {
488
+ replyPermission(obj);
489
+ return;
490
+ }
491
+ const update = asObject(params?.update);
492
+ if (obj.method === 'session/update' && update) {
493
+ if (modelUnavailableErrorCode) {
494
+ const promotedPayload = promotedAmrRetryStatusPayload(update, accountFailureClassifier);
495
+ if (promotedPayload) {
496
+ failWithPayload(promotedPayload);
497
+ return;
498
+ }
499
+ }
500
+ if (update.sessionUpdate !== 'agent_message_chunk' && update.sessionUpdate !== 'agent_thought_chunk') {
501
+ send('agent', {
502
+ type: 'status',
503
+ label: String(update.sessionUpdate || 'session_update'),
504
+ elapsedMs: Date.now() - runStartedAt,
505
+ });
506
+ emitAcpRawShapeDiagnostic(update);
507
+ }
508
+ if (update.sessionUpdate === 'agent_thought_chunk') {
509
+ emitAcpRawShapeDiagnostic(update);
510
+ const text = extractAcpUpdateText(update);
511
+ if (text) {
512
+ if (!emittedThinkingStart) {
513
+ emittedThinkingStart = true;
514
+ send('agent', { type: 'thinking_start' });
515
+ }
516
+ send('agent', { type: 'thinking_delta', delta: text });
517
+ }
518
+ return;
519
+ }
520
+ if (update.sessionUpdate === 'agent_message_chunk') {
521
+ emitAcpRawShapeDiagnostic(update);
522
+ const text = extractAcpUpdateText(update);
523
+ if (text) {
524
+ const isCumulativeSnapshot = text.startsWith(emittedTextBuffer);
525
+ const delta = isCumulativeSnapshot
526
+ ? text.slice(emittedTextBuffer.length)
527
+ : text;
528
+ if (delta.length > 0) {
529
+ emittedTextChunk = true;
530
+ emittedTextBuffer += delta;
531
+ const wasSuppressingToolCall = toolCallTextSuppressor.isSuppressing();
532
+ const toolCallStrippedDelta = toolCallTextSuppressor.strip(delta);
533
+ noteToolCallTextSuppression(wasSuppressingToolCall || toolCallStrippedDelta !== delta
534
+ ? 'tool_call_xml'
535
+ : 'tool_call_candidate');
536
+ if (!toolCallStrippedDelta) {
537
+ return;
538
+ }
539
+ if (dsmlArtifactSuppressor) {
540
+ const wasSuppressingArtifact = dsmlArtifactSuppressor.isSuppressing();
541
+ const hadPendingArtifactCandidate = dsmlArtifactSuppressor.hasPendingCandidate();
542
+ const strippedDelta = dsmlArtifactSuppressor.strip(toolCallStrippedDelta);
543
+ noteArtifactTextSuppression(wasSuppressingArtifact || strippedDelta !== toolCallStrippedDelta
544
+ ? 'artifact_echo'
545
+ : 'artifact_candidate');
546
+ const hasOpenArtifactCandidate = dsmlArtifactSuppressor.isSuppressing() || dsmlArtifactSuppressor.hasPendingCandidate();
547
+ const consumedArtifactText = wasSuppressingArtifact || strippedDelta !== delta;
548
+ const shouldPreserveIncrementalProse = !isCumulativeSnapshot &&
549
+ !wasSuppressingArtifact &&
550
+ !hadPendingArtifactCandidate &&
551
+ !hasOpenArtifactCandidate &&
552
+ (strippedDelta === toolCallStrippedDelta ||
553
+ (!dsmlArtifactSuppressorArmedAfterText &&
554
+ dsmlArtifactSuppressorSawIncrementalProse &&
555
+ !ACP_ARTIFACT_ECHO_START_RE.test(toolCallStrippedDelta)));
556
+ const outputDelta = shouldPreserveIncrementalProse ? toolCallStrippedDelta : strippedDelta;
557
+ if (outputDelta) {
558
+ emitVisibleTextDelta(outputDelta);
559
+ }
560
+ if (strippedDelta === toolCallStrippedDelta &&
561
+ !wasSuppressingArtifact &&
562
+ !hadPendingArtifactCandidate &&
563
+ !hasOpenArtifactCandidate) {
564
+ dsmlArtifactSuppressorSawIncrementalProse = true;
565
+ }
566
+ if (consumedArtifactText && !hasOpenArtifactCandidate) {
567
+ dsmlArtifactSuppressor = null;
568
+ dsmlArtifactSuppressorToolCallId = null;
569
+ dsmlArtifactSuppressorArmedAfterText = false;
570
+ dsmlArtifactSuppressorSawIncrementalProse = false;
571
+ }
572
+ }
573
+ else {
574
+ emitVisibleTextDelta(toolCallStrippedDelta);
575
+ }
576
+ }
577
+ }
578
+ return;
579
+ }
580
+ if (update.sessionUpdate === 'tool_call' ||
581
+ update.sessionUpdate === 'tool_call_update') {
582
+ // The turn did real work (a tool call / file edit), which is valid output even
583
+ // when the model emits no closing assistant text. Track it so the prompt-complete
584
+ // handler does not misreport such a turn as "no output / model unavailable".
585
+ emittedToolCall = true;
586
+ const toolCallId = acpToolCallId(update);
587
+ if (toolCallId && isAcpArtifactWriteLabel(update)) {
588
+ acpArtifactWriteToolCallIds.add(toolCallId);
589
+ }
590
+ // Mirror artifact-write tool calls into the daemon's canonical
591
+ // tool_use/tool_result event shape so a run-artifacts scanner can see
592
+ // ACP file writes. Without this, an ACP agent that emits only
593
+ // text/status/thinking events (never a tool_use/tool_result pair)
594
+ // would report zero artifacts even when the run wrote artifacts.
595
+ //
596
+ // This path only feeds the NO-PROJECT fallback (project runs use the
597
+ // filesystem snapshot). Two correctness rules, both learned the hard
598
+ // way in review:
599
+ // 1. Defer emission to the TERMINAL frame and accumulate the best
600
+ // concrete path across frames — ACP often sends `locations` only
601
+ // on the completing update, and emitting on the first frame would
602
+ // lock in a wrong/empty guess that a later path can't correct.
603
+ // 2. Never fabricate an artifact extension. `isArtifactPath` is what
604
+ // decides whether a write counts; feeding it a real path lets it
605
+ // correctly EXCLUDE non-artifact edits (`config.json`, `README.md`)
606
+ // and INCLUDE real artifacts. A write that never carries a concrete
607
+ // path stays keyed on its (extension-less) toolCallId, so it is
608
+ // simply not counted rather than inflating the metric with a
609
+ // synthetic `.html` — under-counting a truly opaque write is
610
+ // acceptable; a false-positive artifact is not.
611
+ if (toolCallId) {
612
+ const isWriteCall = isAcpArtifactWriteLabel(update) || acpArtifactWriteToolCallIds.has(toolCallId);
613
+ if (isWriteCall) {
614
+ let st = acpArtifactRunEventState.get(toolCallId);
615
+ if (!st) {
616
+ st = { path: null, emitted: false };
617
+ acpArtifactRunEventState.set(toolCallId, st);
618
+ }
619
+ if (!st.path)
620
+ st.path = acpArtifactWritePath(update);
621
+ const failed = isAcpTerminalFailureStatus(update);
622
+ if (!st.emitted && (failed || isAcpCompletedStatus(update))) {
623
+ st.emitted = true;
624
+ send('agent', {
625
+ type: 'tool_use',
626
+ id: toolCallId,
627
+ name: 'Write',
628
+ input: { file_path: st.path ?? toolCallId },
629
+ });
630
+ send('agent', { type: 'tool_result', toolUseId: toolCallId, isError: failed });
631
+ emittedConcreteToolEvent = true;
632
+ }
633
+ }
634
+ }
635
+ if (isAcpArtifactWriteUpdate(update, acpArtifactWriteToolCallIds)) {
636
+ dsmlArtifactSuppressor = createDsmlArtifactTextSuppressor();
637
+ dsmlArtifactSuppressorLastSuppressedChars = 0;
638
+ dsmlArtifactSuppressorToolCallId = toolCallId;
639
+ dsmlArtifactSuppressorArmedAfterText = emittedTextBuffer.length > 0;
640
+ dsmlArtifactSuppressorSawIncrementalProse = false;
641
+ if (toolCallId)
642
+ acpArtifactWriteToolCallIds.delete(toolCallId);
643
+ }
644
+ else if (toolCallId && isAcpTerminalFailureStatus(update)) {
645
+ const ownsPendingWriteSuppression = toolCallId === dsmlArtifactSuppressorToolCallId;
646
+ const ownsPendingWriteCall = acpArtifactWriteToolCallIds.has(toolCallId);
647
+ acpArtifactWriteToolCallIds.delete(toolCallId);
648
+ if (ownsPendingWriteSuppression || ownsPendingWriteCall) {
649
+ dsmlArtifactSuppressor = null;
650
+ dsmlArtifactSuppressorToolCallId = null;
651
+ dsmlArtifactSuppressorArmedAfterText = false;
652
+ dsmlArtifactSuppressorSawIncrementalProse = false;
653
+ }
654
+ }
655
+ return;
656
+ }
657
+ return;
658
+ }
659
+ if (obj.id !== expectedId || !result) {
660
+ return;
661
+ }
662
+ if (expectedId === 1) {
663
+ expectedId = nextId;
664
+ if (resumeSessionId) {
665
+ // Resume the prior upstream session instead of creating a fresh one.
666
+ writeRpc(nextId, 'session/load', { sessionId: resumeSessionId, cwd: effectiveCwd }, 'session/load');
667
+ }
668
+ else {
669
+ writeRpc(nextId, 'session/new', buildAcpSessionNewParams(effectiveCwd, mcpServers ? { mcpServers, envFormat } : { envFormat }), 'session/new');
670
+ }
671
+ nextId += 1;
672
+ return;
673
+ }
674
+ if (expectedId === 2) {
675
+ sessionId = typeof result.sessionId === 'string' ? result.sessionId : null;
676
+ // The durable handle for resuming this session on the next turn.
677
+ durableSessionId =
678
+ typeof result.openCodeSessionId === 'string' ? result.openCodeSessionId : null;
679
+ // session/new acknowledged with a session id = handshake done.
680
+ if (sessionId)
681
+ onSessionInit?.();
682
+ const modelConfig = findModelConfigOption(result.configOptions);
683
+ modelConfigId = modelConfig?.configId ?? null;
684
+ activeModel = currentModelFromSessionResult(result);
685
+ if (sessionId && activeModel) {
686
+ send('agent', { type: 'status', label: 'model', model: activeModel });
687
+ }
688
+ if (sessionId && model && model !== 'default') {
689
+ setModelRequestId = nextId;
690
+ expectedId = nextId;
691
+ const setModelMethod = modelConfigId ? 'session/set_config_option' : 'session/set_model';
692
+ const setModelParams = modelConfigId
693
+ ? { sessionId, configId: modelConfigId, value: model }
694
+ : { sessionId, modelId: model };
695
+ writeRpc(nextId, setModelMethod, setModelParams, setModelMethod);
696
+ nextId += 1;
697
+ return;
698
+ }
699
+ if (!sessionId) {
700
+ fail(`invalid session/new response: ${rawLine}`);
701
+ return;
702
+ }
703
+ sendPrompt();
704
+ return;
705
+ }
706
+ if (promptRequestId !== null && obj.id === promptRequestId) {
707
+ const usage = formatUsage(result.usage);
708
+ if (!emittedVisibleTextChunk && !emittedConcreteToolEvent && modelUnavailableErrorCode) {
709
+ const outputTokens = usage?.output_tokens;
710
+ const hadCompletionTokens = typeof outputTokens === 'number' && outputTokens > 0;
711
+ if (hadCompletionTokens || emittedToolCall || emittedTextChunk) {
712
+ fail('ACP session completed after reporting model activity, but did not produce visible assistant text, concrete tool results, or artifacts.', {
713
+ retryable: true,
714
+ details: {
715
+ kind: 'acp_no_visible_output',
716
+ output_tokens: outputTokens,
717
+ raw_tool_update_seen: emittedToolCall,
718
+ text_chunk_seen: emittedTextChunk,
719
+ },
720
+ });
721
+ }
722
+ else {
723
+ fail('ACP session completed without producing any assistant text. Refresh the AMR model list, choose a supported model, and retry this run.', { forceModelUnavailable: true });
724
+ }
725
+ return;
726
+ }
727
+ finishCleanPrompt(result.usage);
728
+ return;
729
+ }
730
+ if (sessionId && model && model !== 'default' && obj.id === expectedId) {
731
+ activeModel = currentModelFromSessionResult(result) ?? model;
732
+ send('agent', { type: 'status', label: 'model', model: activeModel });
733
+ sendPrompt();
734
+ }
735
+ });
736
+ stdout.on('data', (chunk) => parser.feed(chunk));
737
+ child.stderr?.setEncoding('utf8');
738
+ child.stderr?.on('data', (chunk) => {
739
+ if (!modelUnavailableErrorCode || finished)
740
+ return;
741
+ amrStderrRetryTail = `${amrStderrRetryTail}${String(chunk)}`.slice(-AMR_STDERR_RETRY_TAIL_LIMIT);
742
+ const promotedPayload = promotedAmrStderrPayload(amrStderrRetryTail, accountFailureClassifier);
743
+ if (promotedPayload)
744
+ failWithPayload(promotedPayload);
745
+ });
746
+ child.on('close', (code, signal) => {
747
+ clearStageTimer();
748
+ parser.flush();
749
+ if (!finished && !aborted && !fatal) {
750
+ fail(`ACP session exited before completion (code=${code ?? 'null'}, signal=${signal ?? 'none'})`);
751
+ }
752
+ });
753
+ child.on('error', (err) => fail(err.message));
754
+ stdin.on('error', (err) => fail(`stdin error: ${err.message}`));
755
+ writeRpc(1, 'initialize', {
756
+ protocolVersion: ACP_PROTOCOL_VERSION,
757
+ clientCapabilities: { terminal: false },
758
+ clientInfo: { name: clientName, version: clientVersion },
759
+ }, 'initialize');
760
+ return {
761
+ /** Returns `true` when the session ended with a fatal protocol or transport error, allowing the caller to surface the failure. */
762
+ hasFatalError() {
763
+ return fatal;
764
+ },
765
+ // The durable upstream session handle to persist for resume, or null when
766
+ // none was reported (older agents, or a handshake that never established a
767
+ // session). Mirrors pi-rpc's getLastSessionPath().
768
+ /** Returns the durable upstream session id (e.g. a vendor bridge's own session id) to persist for next-turn resume, or `null` when the agent did not report one. */
769
+ getDurableSessionId() {
770
+ return durableSessionId;
771
+ },
772
+ /** Returns `true` when the prompt request resolved cleanly without a fatal error and without an abort, even if the child process later exited via SIGTERM. */
773
+ completedSuccessfully() {
774
+ // Returns true when the prompt request resolved without a fatal error
775
+ // and was not aborted. The chat consumer treats this as a successful
776
+ // run even if the child process subsequently exited via SIGTERM
777
+ // (which is expected for agents that don't shut down on stdin.end()).
778
+ return finished && !fatal && !aborted;
779
+ },
780
+ /**
781
+ * Aborts an in-progress ACP session. Sends `session/cancel` when a session
782
+ * id has already been established, then always closes stdin so the agent
783
+ * receives EOF and can tear down its own runtime (e.g. a vendor bridge's
784
+ * private backing server). Idempotent — subsequent calls are no-ops.
785
+ */
786
+ abort() {
787
+ if (aborted || finished)
788
+ return;
789
+ aborted = true;
790
+ finished = true;
791
+ clearStageTimer();
792
+ // ACP requires pending permission requests to receive a terminal
793
+ // `cancelled` response when the prompt turn is cancelled. Do this
794
+ // before closing stdin, which may otherwise make the response
795
+ // impossible to deliver.
796
+ for (const requestId of pendingPermissionRequestIds) {
797
+ try {
798
+ sendRpcResult(stdin, requestId, { outcome: { outcome: 'cancelled' } });
799
+ }
800
+ catch {
801
+ // Closing stdin/process signalling below remains the fallback.
802
+ }
803
+ }
804
+ pendingPermissionRequestIds.clear();
805
+ if (!child.stdin || child.stdin.destroyed || child.stdin.writableEnded)
806
+ return;
807
+ // Only cancel an established session; before session/new resolves there
808
+ // is no sessionId to cancel, but we must still close stdin below.
809
+ if (sessionId) {
810
+ try {
811
+ sendRpc(child.stdin, nextId, 'session/cancel', { sessionId });
812
+ nextId += 1;
813
+ }
814
+ catch {
815
+ // The caller owns process-signal fallback if the ACP transport is gone.
816
+ }
817
+ }
818
+ // Always close stdin so the agent receives EOF and shuts down its own
819
+ // runtime — some ACP bridges tear down a private backing server on EOF —
820
+ // instead of lingering (and leaking that server) until the caller's
821
+ // SIGTERM fallback fires. This also covers aborts during ACP startup,
822
+ // before session/new returns. Mirrors the clean-completion path above.
823
+ try {
824
+ child.stdin.end();
825
+ }
826
+ catch {
827
+ // Best effort; the caller still owns the SIGTERM/SIGKILL fallback.
828
+ }
829
+ },
830
+ };
831
+ }
832
+ //# sourceMappingURL=session.js.map