@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,660 @@
1
+ /**
2
+ * @module claude-stream
3
+ *
4
+ * Ported verbatim from OD's `apps/daemon/src/runtimes/stream/claude-stream.ts`
5
+ * (only the `role-marker-guard` import path changed — it now resolves
6
+ * within this package instead of two directories up). See `source-map.md`.
7
+ *
8
+ * Parses Claude Code's `--output-format stream-json --verbose` JSONL stream
9
+ * (with or without `--include-partial-messages`) into a small set of
10
+ * UI-friendly events. With partial messages on, text arrives as
11
+ * `stream_event` deltas; without it (older builds <1.0.86, or any build
12
+ * where the flag isn't passed) text arrives only in the final `assistant`
13
+ * wrapper. We handle both. The UI only needs to know five things:
14
+ *
15
+ * - status : high-level lifecycle ("initializing", "requesting",
16
+ * "thinking")
17
+ * - text_delta : assistant text chunk (gets fed to the artifact parser)
18
+ * - thinking_delta: extended-thinking chunk (shown in a collapsed block)
19
+ * - tool_use : { id, name, input } (fires when input is complete)
20
+ * - tool_result : { tool_use_id, content, is_error }
21
+ * - usage : aggregated input/output/cache tokens + cost
22
+ *
23
+ * Callers give us `onEvent({ type, ...payload })`. We track per-content-block
24
+ * state to accumulate partial tool_use input JSON and emit a single
25
+ * `tool_use` event when that block stops.
26
+ */
27
+ import { createRoleMarkerGuard } from './role-marker-guard.js';
28
+ function isRecord(value) {
29
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
30
+ }
31
+ export function createClaudeStreamHandler(onEvent, options = {}) {
32
+ let buffer = '';
33
+ // Per-content-block scratch, keyed by `${messageId}:${blockIndex}`.
34
+ const blocks = new Map();
35
+ // Tool uses already emitted from streamed `input_json_delta` data.
36
+ // Claude Code still repeats them in the final assistant wrapper, often with
37
+ // empty `{}` inputs, so we suppress that duplicate emission.
38
+ const streamedToolUseIds = new Set();
39
+ // Most recent assistant message id so content_block_* events without an id
40
+ // can be attributed correctly.
41
+ let currentMessageId = null;
42
+ // Message ids that already streamed assistant text/thinking via
43
+ // `stream_event` deltas.
44
+ // When `--include-partial-messages` is OFF (older Claude Code, e.g. 1.0.84
45
+ // pre-flag), no deltas arrive — only the final `assistant` wrapper carries
46
+ // content. The fallback below emits that content once, but we must skip it for
47
+ // newer builds that already streamed deltas, otherwise the message would
48
+ // duplicate.
49
+ const textStreamed = new Set();
50
+ const thinkingStreamed = new Set();
51
+ let currentMessageStreamedText = false;
52
+ let currentMessageStreamedThinking = false;
53
+ // Newer Claude Code builds put the terminal stop reason in the partial
54
+ // stream's `message_delta`, while the accompanying top-level `assistant`
55
+ // wrapper carries `stop_reason: null`. Older builds put it on the wrapper.
56
+ // Remember the message id that already emitted `turn_end` so accepting
57
+ // both wire shapes cannot double-trigger stdin continuation/closure.
58
+ let turnEndSignature = null;
59
+ // Per-message role-marker guards for cross-chunk detection (#3247).
60
+ const roleGuards = new Map();
61
+ const runtimeTasks = new Map();
62
+ const canonicalTaskToolUseIds = new Set();
63
+ let nextRuntimeTaskId = 1;
64
+ let suppressNextArtifactText = false;
65
+ let suppressDuplicateArtifactText = false;
66
+ let artifactOpenCandidate = '';
67
+ let pendingArtifactText = '';
68
+ let duplicateArtifactCandidate = '';
69
+ const recentWriteContents = [];
70
+ let wroteHtmlFileThisTurn = false;
71
+ function emitTurnEnd(stopReason) {
72
+ const signature = currentMessageId === null ? null : `${currentMessageId}\u0000${stopReason}`;
73
+ if (signature !== null && turnEndSignature === signature)
74
+ return;
75
+ onEvent({ type: 'turn_end', stopReason });
76
+ turnEndSignature = signature;
77
+ if (stopReason !== 'tool_use') {
78
+ recentWriteContents.length = 0;
79
+ wroteHtmlFileThisTurn = false;
80
+ }
81
+ }
82
+ function normalizeTaskStatus(value) {
83
+ if (value === 'completed' || value === 'in_progress' || value === 'stopped') {
84
+ return value;
85
+ }
86
+ if (value === 'complete' || value === 'done')
87
+ return 'completed';
88
+ if (value === 'doing' || value === 'active')
89
+ return 'in_progress';
90
+ if (value === 'failed' || value === 'canceled' || value === 'cancelled')
91
+ return 'stopped';
92
+ return 'pending';
93
+ }
94
+ function nextGeneratedRuntimeTaskId() {
95
+ // Coverage-driven refactor (2026-07-18, no behavior change): the
96
+ // original OD source guarded the returned id with
97
+ // `while (runtimeTasks.has(String(nextRuntimeTaskId))) nextRuntimeTaskId += 1;`.
98
+ // Tracing every path that can insert a numeric id into `runtimeTasks`
99
+ // shows the guard can never trigger: the only two insertion paths are
100
+ // (a) this function itself, which always hands out the current
101
+ // `nextRuntimeTaskId` and then increments it, so that exact value is
102
+ // never in the map yet; and (b) `runtimeTaskIdFromCreate`'s
103
+ // explicit-id branch, which bumps `nextRuntimeTaskId` to
104
+ // `numericId + 1` (strictly past itself) BEFORE this function could
105
+ // ever be asked to reuse that id. Since `nextRuntimeTaskId` only ever
106
+ // increases, it can never equal an id already present in the map at
107
+ // this point. Removed per the coverage skill's Phase 6.5 "dead
108
+ // branch" classification rather than fake a test for an unreachable
109
+ // loop; see source-map.md.
110
+ const id = String(nextRuntimeTaskId);
111
+ nextRuntimeTaskId += 1;
112
+ return id;
113
+ }
114
+ function runtimeTaskIdFromCreate(input) {
115
+ if (typeof input.taskId === 'string' && input.taskId) {
116
+ const numericId = Number(input.taskId);
117
+ if (Number.isSafeInteger(numericId) && numericId >= nextRuntimeTaskId) {
118
+ nextRuntimeTaskId = numericId + 1;
119
+ }
120
+ return input.taskId;
121
+ }
122
+ return nextGeneratedRuntimeTaskId();
123
+ }
124
+ function emitCanonicalTaskSnapshot(toolUseId, name, input) {
125
+ if (typeof toolUseId !== 'string' || typeof name !== 'string' || !isRecord(input))
126
+ return false;
127
+ if (canonicalTaskToolUseIds.has(toolUseId))
128
+ return true;
129
+ if (name === 'TaskCreate') {
130
+ const content = typeof input.subject === 'string'
131
+ ? input.subject
132
+ : typeof input.description === 'string'
133
+ ? input.description
134
+ : '';
135
+ if (!content)
136
+ return false;
137
+ const id = runtimeTaskIdFromCreate(input);
138
+ const activeForm = typeof input.activeForm === 'string' ? input.activeForm : undefined;
139
+ runtimeTasks.set(id, {
140
+ id,
141
+ content,
142
+ status: normalizeTaskStatus(input.status),
143
+ ...(activeForm ? { activeForm } : {}),
144
+ });
145
+ }
146
+ else if (name === 'TaskUpdate') {
147
+ if (typeof input.taskId !== 'string')
148
+ return false;
149
+ const existing = runtimeTasks.get(input.taskId);
150
+ if (!existing)
151
+ return false;
152
+ const content = typeof input.subject === 'string'
153
+ ? input.subject
154
+ : typeof input.description === 'string'
155
+ ? input.description
156
+ : existing.content;
157
+ const activeForm = typeof input.activeForm === 'string' ? input.activeForm : existing.activeForm;
158
+ runtimeTasks.set(input.taskId, {
159
+ ...existing,
160
+ content,
161
+ status: normalizeTaskStatus(input.status),
162
+ ...(activeForm ? { activeForm } : {}),
163
+ });
164
+ }
165
+ else {
166
+ return false;
167
+ }
168
+ // Coverage-driven refactor (2026-07-18, no behavior change): the
169
+ // original OD source guarded this emission with
170
+ // `if (!changed || runtimeTasks.size === 0) return false;`. Tracing
171
+ // every path into this point shows both conditions are unreachable —
172
+ // the `TaskCreate` and `TaskUpdate` branches above only fall through
173
+ // to here after an unconditional `runtimeTasks.set(...)` (so `size`
174
+ // can never be 0), and every early-return path above returns before
175
+ // reaching here (so the "changed" flag those returns guarded was
176
+ // always true here). Removed the dead double-guard per the coverage
177
+ // skill's Phase 6.5 "dead branch" classification rather than fake a
178
+ // test for an unreachable condition; see source-map.md.
179
+ canonicalTaskToolUseIds.add(toolUseId);
180
+ onEvent({
181
+ type: 'tool_use',
182
+ id: `${toolUseId}:todo-task`,
183
+ name: 'TodoWrite',
184
+ input: {
185
+ todos: Array.from(runtimeTasks.values()).map(({ content, status, activeForm }) => ({
186
+ content,
187
+ status,
188
+ ...(activeForm ? { activeForm } : {}),
189
+ })),
190
+ },
191
+ });
192
+ return true;
193
+ }
194
+ function emitToolUse(id, name, input) {
195
+ if (emitCanonicalTaskSnapshot(id, name, input))
196
+ return;
197
+ if (isFileWriteToolUse(name, input)) {
198
+ suppressNextArtifactText = true;
199
+ const content = fileWriteContent(input);
200
+ if (content) {
201
+ wroteHtmlFileThisTurn = wroteHtmlFileThisTurn || isHtmlWriteToolInput(input);
202
+ recentWriteContents.push(normalizeArtifactEchoContent(content));
203
+ if (recentWriteContents.length > 5)
204
+ recentWriteContents.shift();
205
+ }
206
+ }
207
+ onEvent({
208
+ type: 'tool_use',
209
+ id,
210
+ name,
211
+ input,
212
+ });
213
+ }
214
+ function blockKey(index) {
215
+ return `${currentMessageId ?? 'anon'}:${index}`;
216
+ }
217
+ // Per-message role-marker guard (#3247). Covers text_delta ONLY.
218
+ //
219
+ // Why not thinking_delta: extended thinking is rendered to a
220
+ // separate `kind: 'thinking'` payload and is never folded into
221
+ // `m.content` by `buildDaemonTranscript` (apps/web/src/providers/daemon.ts),
222
+ // so it cannot be re-serialized as a turn boundary on the next
223
+ // round-trip — it is not a #3247 re-injection vector. Models
224
+ // routinely emit literal `## user` / `## assistant` lines in
225
+ // chain-of-thought when reasoning about conversation structure,
226
+ // and with kill-on-detection wired in server.ts a guard on the
227
+ // thinking channel would abort otherwise-legitimate runs without
228
+ // any compensating security benefit. See PR #3303 review
229
+ // r3324xxxxxx. Thinking is passed through unguarded; only the
230
+ // user-visible text channel is policed.
231
+ function emitSafeText(msgId, text, eventType = 'text_delta') {
232
+ if (eventType === 'text_delta') {
233
+ text = stripDuplicateArtifactText(text);
234
+ if (!text)
235
+ return;
236
+ }
237
+ if (eventType !== 'text_delta' || !msgId) {
238
+ onEvent({ type: eventType, delta: text });
239
+ return;
240
+ }
241
+ let guard = roleGuards.get(msgId);
242
+ if (!guard) {
243
+ guard = createRoleMarkerGuard(msgId);
244
+ roleGuards.set(msgId, guard);
245
+ }
246
+ if (guard.contaminated)
247
+ return;
248
+ const safe = guard.feedText(text);
249
+ if (safe.length > 0) {
250
+ onEvent({ type: eventType, delta: safe });
251
+ }
252
+ if (guard.contaminated) {
253
+ const warn = guard.warningEvent();
254
+ if (warn)
255
+ onEvent(warn);
256
+ }
257
+ }
258
+ function stripDuplicateArtifactText(text) {
259
+ if (!suppressNextArtifactText &&
260
+ !suppressDuplicateArtifactText &&
261
+ artifactOpenCandidate.length === 0 &&
262
+ recentWriteContents.length === 0) {
263
+ return text;
264
+ }
265
+ const openTag = '<artifact';
266
+ const current = `${artifactOpenCandidate}${text}`;
267
+ artifactOpenCandidate = '';
268
+ if (suppressDuplicateArtifactText) {
269
+ duplicateArtifactCandidate += current;
270
+ const closeIndex = duplicateArtifactCandidate.indexOf('</artifact>');
271
+ if (closeIndex === -1)
272
+ return '';
273
+ const closeEnd = closeIndex + '</artifact>'.length;
274
+ const candidate = duplicateArtifactCandidate.slice(0, closeEnd);
275
+ const rest = duplicateArtifactCandidate.slice(closeEnd);
276
+ duplicateArtifactCandidate = '';
277
+ suppressDuplicateArtifactText = false;
278
+ suppressNextArtifactText = false;
279
+ const duplicate = isRedundantWrittenArtifact(candidate);
280
+ if (options.suppressHtmlArtifactsAfterFileWrite !== true) {
281
+ recentWriteContents.length = 0;
282
+ }
283
+ return `${duplicate ? '' : candidate}${stripDuplicateArtifactText(rest)}`;
284
+ }
285
+ const openIndex = current.indexOf(openTag);
286
+ if (openIndex === -1) {
287
+ const candidateLength = artifactOpenCandidateLength(current, openTag);
288
+ if ((suppressNextArtifactText || recentWriteContents.length > 0) && candidateLength > 0) {
289
+ artifactOpenCandidate = current.slice(-candidateLength);
290
+ return current.slice(0, -candidateLength);
291
+ }
292
+ return current;
293
+ }
294
+ suppressDuplicateArtifactText = true;
295
+ suppressNextArtifactText = false;
296
+ duplicateArtifactCandidate = current.slice(openIndex);
297
+ const prefix = `${pendingArtifactText}${current.slice(0, openIndex)}`;
298
+ pendingArtifactText = '';
299
+ return `${prefix}${stripDuplicateArtifactText('')}`;
300
+ }
301
+ function isRedundantWrittenArtifact(candidate) {
302
+ const gt = candidate.indexOf('>');
303
+ const close = candidate.lastIndexOf('</artifact>');
304
+ if (gt === -1 || close === -1 || close <= gt)
305
+ return false;
306
+ if (options.suppressHtmlArtifactsAfterFileWrite === true &&
307
+ isHtmlArtifact(candidate) &&
308
+ wroteHtmlFileThisTurn)
309
+ return true;
310
+ const body = normalizeArtifactEchoContent(candidate.slice(gt + 1, close));
311
+ return recentWriteContents.some((content) => content === body);
312
+ }
313
+ function isHtmlArtifact(candidate) {
314
+ const openTag = candidate.slice(0, Math.max(0, candidate.indexOf('>') + 1));
315
+ return /\btype\s*=\s*["']text\/html["']/i.test(openTag);
316
+ }
317
+ function normalizeArtifactEchoContent(value) {
318
+ return value
319
+ .replace(/^\uFEFF/, '')
320
+ .replace(/\r\n?/g, '\n')
321
+ .replace(/^(?:\s|\\r|\\n)+|(?:\s|\\r|\\n)+$/g, '');
322
+ }
323
+ function artifactOpenCandidateLength(text, openTag) {
324
+ const max = Math.min(openTag.length - 1, text.length);
325
+ for (let len = max; len > 0; len -= 1) {
326
+ if (openTag.startsWith(text.slice(-len)))
327
+ return len;
328
+ }
329
+ return 0;
330
+ }
331
+ function isFileWriteToolUse(name, input) {
332
+ if (typeof name !== 'string' || !isRecord(input))
333
+ return false;
334
+ const path = typeof input.file_path === 'string'
335
+ ? input.file_path
336
+ : typeof input.path === 'string'
337
+ ? input.path
338
+ : '';
339
+ const writesFile = name === 'Write' ||
340
+ name === 'Edit' ||
341
+ name === 'write_file' ||
342
+ name === 'replace';
343
+ if (!writesFile)
344
+ return false;
345
+ if (/\.(html|htm|css|js|jsx|ts|tsx|md)$/iu.test(path))
346
+ return true;
347
+ return typeof input.content === 'string' || typeof input.new_string === 'string';
348
+ }
349
+ // Coverage-driven refactor (2026-07-18, no behavior change): both
350
+ // `fileWriteContent` and `isHtmlWriteToolInput` originally opened with
351
+ // their own `if (!isRecord(input)) return ...;` guard. Each function
352
+ // has exactly one call site (`emitToolUse`, for both), and both call
353
+ // sites already sit inside an `if (isFileWriteToolUse(name, input))`
354
+ // block, which itself already asserted `isRecord(input)` before
355
+ // returning true. So `input` is always a record by the time either
356
+ // function runs — the guards duplicated a check the shared caller
357
+ // already made. Removed the runtime early-return per the coverage
358
+ // skill's Phase 6.5 "dead branch" classification rather than fake a
359
+ // test with a non-record `input` neither function can ever actually
360
+ // receive (see source-map.md), replaced by a one-line type assertion
361
+ // (classification 4: TS-required, no real runtime path) so the
362
+ // parameter can stay `unknown` without disturbing the call sites.
363
+ function fileWriteContent(input) {
364
+ const record = input;
365
+ if (typeof record.content === 'string')
366
+ return record.content;
367
+ if (typeof record.new_string === 'string')
368
+ return record.new_string;
369
+ return null;
370
+ }
371
+ function isHtmlWriteToolInput(input) {
372
+ const record = input;
373
+ const rawPath = record.file_path ?? record.filePath;
374
+ if (typeof rawPath === 'string' && /\.(?:html?|xhtml)$/i.test(rawPath))
375
+ return true;
376
+ const content = fileWriteContent(input);
377
+ return typeof content === 'string' && /<!doctype\s+html\b|<html\b/i.test(content);
378
+ }
379
+ function feed(chunk) {
380
+ buffer += chunk;
381
+ let nl;
382
+ while ((nl = buffer.indexOf('\n')) !== -1) {
383
+ const line = buffer.slice(0, nl).trim();
384
+ buffer = buffer.slice(nl + 1);
385
+ if (!line)
386
+ continue;
387
+ let obj;
388
+ try {
389
+ obj = JSON.parse(line);
390
+ }
391
+ catch {
392
+ onEvent({ type: 'raw', line });
393
+ continue;
394
+ }
395
+ handleObject(obj);
396
+ }
397
+ }
398
+ function flush() {
399
+ const rem = buffer.trim();
400
+ buffer = '';
401
+ if (rem) {
402
+ try {
403
+ handleObject(JSON.parse(rem));
404
+ }
405
+ catch {
406
+ onEvent({ type: 'raw', line: rem });
407
+ }
408
+ }
409
+ flushPendingArtifactText();
410
+ }
411
+ function handleObject(obj) {
412
+ if (!isRecord(obj))
413
+ return;
414
+ if (obj.type === 'system' && obj.subtype === 'init') {
415
+ onEvent({
416
+ type: 'status',
417
+ label: 'initializing',
418
+ model: obj.model ?? null,
419
+ sessionId: obj.session_id ?? null,
420
+ });
421
+ return;
422
+ }
423
+ if (obj.type === 'system' && obj.subtype === 'status') {
424
+ onEvent({ type: 'status', label: obj.status ?? 'working' });
425
+ return;
426
+ }
427
+ if (obj.type === 'stream_event' && isRecord(obj.event)) {
428
+ handleStreamEvent(obj.event);
429
+ return;
430
+ }
431
+ // `assistant` messages are the "block finished" signal for the current
432
+ // content block. For tool_use blocks whose input finished assembling,
433
+ // emit tool_use now with the final parsed input. For text blocks, emit
434
+ // the text as a single delta — but only if no streaming deltas already
435
+ // covered it (older Claude Code without --include-partial-messages
436
+ // delivers text only here; newer builds stream it and would duplicate).
437
+ if (obj.type === 'assistant' && isRecord(obj.message) && Array.isArray(obj.message.content)) {
438
+ const explicitMsgId = typeof obj.message.id === 'string' ? obj.message.id : null;
439
+ const textMsgId = explicitMsgId ?? (currentMessageStreamedText ? currentMessageId : null);
440
+ const thinkingMsgId = explicitMsgId ?? (currentMessageStreamedThinking ? currentMessageId : null);
441
+ if (explicitMsgId)
442
+ currentMessageId = explicitMsgId;
443
+ const textAlreadyStreamed = textMsgId ? textStreamed.has(textMsgId) : false;
444
+ const thinkingAlreadyStreamed = thinkingMsgId ? thinkingStreamed.has(thinkingMsgId) : false;
445
+ // Per-turn `stop_reason` is emitted as `turn_end` AFTER the content
446
+ // blocks have been processed (see below). When `--include-partial-
447
+ // messages` is unsupported, tool_use events surface only from the
448
+ // assistant wrapper here — emitting `turn_end` before that loop would
449
+ // let the daemon's stdin-close handler act on the turn before its
450
+ // tool_use blocks were seen, closing stdin mid-tool. Read the
451
+ // stop_reason now, emit after.
452
+ const stopReason = typeof obj.message.stop_reason === 'string'
453
+ ? obj.message.stop_reason
454
+ : null;
455
+ for (const block of obj.message.content) {
456
+ if (!isRecord(block))
457
+ continue;
458
+ if (block.type === 'tool_use') {
459
+ if (typeof block.id === 'string' && streamedToolUseIds.has(block.id)) {
460
+ continue;
461
+ }
462
+ emitToolUse(block.id, block.name, block.input ?? null);
463
+ }
464
+ else if (!textAlreadyStreamed &&
465
+ block.type === 'text' &&
466
+ typeof block.text === 'string' &&
467
+ block.text.length > 0) {
468
+ emitSafeText(textMsgId, block.text);
469
+ }
470
+ else if (!thinkingAlreadyStreamed &&
471
+ block.type === 'thinking' &&
472
+ typeof block.thinking === 'string' &&
473
+ block.thinking.length > 0) {
474
+ emitSafeText(thinkingMsgId, block.thinking, 'thinking_delta');
475
+ }
476
+ }
477
+ // Surface the turn_end signal now that every tool_use in this
478
+ // assistant message has been emitted, so the daemon's stdin-close
479
+ // handler sees the final `stop_reason` before deciding whether to
480
+ // close stream-json input stdin.
481
+ if (stopReason) {
482
+ emitTurnEnd(stopReason);
483
+ }
484
+ if (typeof obj.error === 'string' && obj.error.trim()) {
485
+ onEvent({
486
+ type: 'error',
487
+ message: assistantText(obj.message.content) || obj.error,
488
+ code: obj.error,
489
+ });
490
+ }
491
+ currentMessageStreamedText = false;
492
+ currentMessageStreamedThinking = false;
493
+ return;
494
+ }
495
+ // `user` messages in a stream-json transcript are usually tool_result
496
+ // wrappers from prior turns.
497
+ if (obj.type === 'user' && isRecord(obj.message) && Array.isArray(obj.message.content)) {
498
+ for (const block of obj.message.content) {
499
+ if (!isRecord(block))
500
+ continue;
501
+ if (block.type === 'tool_result') {
502
+ onEvent({
503
+ type: 'tool_result',
504
+ toolUseId: block.tool_use_id,
505
+ content: stringifyToolResult(block.content),
506
+ isError: Boolean(block.is_error),
507
+ });
508
+ }
509
+ }
510
+ return;
511
+ }
512
+ if (obj.type === 'result') {
513
+ const stopReason = (typeof obj.stop_reason === 'string' && obj.stop_reason) ||
514
+ (typeof obj.terminal_reason === 'string' && obj.terminal_reason) ||
515
+ null;
516
+ // Claude Code 2.1.201 does not always emit a terminal
517
+ // stream_event/message_delta. In that wire shape, the top-level result
518
+ // is the only frame carrying `end_turn`. Surface it as a turn boundary
519
+ // so AgentExecutor can close stream-json stdin and reap the process.
520
+ if (stopReason) {
521
+ emitTurnEnd(stopReason);
522
+ }
523
+ onEvent({
524
+ type: 'usage',
525
+ usage: obj.usage ?? null,
526
+ costUsd: obj.total_cost_usd ?? null,
527
+ durationMs: obj.duration_ms ?? null,
528
+ stopReason,
529
+ });
530
+ return;
531
+ }
532
+ }
533
+ function assistantText(content) {
534
+ const parts = [];
535
+ for (const block of content) {
536
+ if (isRecord(block) && block.type === 'text' && typeof block.text === 'string') {
537
+ parts.push(block.text);
538
+ }
539
+ }
540
+ return parts.join('\n').trim();
541
+ }
542
+ function handleStreamEvent(ev) {
543
+ if (ev.type === 'message_start') {
544
+ flushPendingArtifactText();
545
+ // Clean up per-message role-marker guard from the previous message.
546
+ if (currentMessageId)
547
+ roleGuards.delete(currentMessageId);
548
+ currentMessageId = isRecord(ev.message) && typeof ev.message.id === 'string' ? ev.message.id : null;
549
+ currentMessageStreamedText = false;
550
+ currentMessageStreamedThinking = false;
551
+ if (typeof ev.ttft_ms === 'number') {
552
+ onEvent({ type: 'status', label: 'streaming', ttftMs: ev.ttft_ms });
553
+ }
554
+ return;
555
+ }
556
+ if (ev.type === 'content_block_start' && isRecord(ev.content_block)) {
557
+ const key = blockKey(ev.index);
558
+ const block = ev.content_block;
559
+ blocks.set(key, {
560
+ type: block.type,
561
+ name: block.name,
562
+ id: block.id,
563
+ input: '',
564
+ inputValue: 'input' in block ? block.input : undefined,
565
+ });
566
+ if (block.type === 'thinking') {
567
+ onEvent({ type: 'thinking_start' });
568
+ }
569
+ return;
570
+ }
571
+ if (ev.type === 'content_block_delta' && isRecord(ev.delta)) {
572
+ const state = blocks.get(blockKey(ev.index));
573
+ const delta = ev.delta;
574
+ if (delta.type === 'text_delta' && typeof delta.text === 'string') {
575
+ if (currentMessageId)
576
+ textStreamed.add(currentMessageId);
577
+ currentMessageStreamedText = true;
578
+ emitSafeText(currentMessageId, delta.text);
579
+ return;
580
+ }
581
+ if (delta.type === 'thinking_delta' && typeof delta.thinking === 'string') {
582
+ if (currentMessageId)
583
+ thinkingStreamed.add(currentMessageId);
584
+ currentMessageStreamedThinking = true;
585
+ emitSafeText(currentMessageId, delta.thinking, 'thinking_delta');
586
+ return;
587
+ }
588
+ if (delta.type === 'input_json_delta' && typeof delta.partial_json === 'string') {
589
+ if (state && state.type === 'tool_use') {
590
+ state.input += delta.partial_json;
591
+ if (typeof state.id === 'string' && typeof state.name === 'string') {
592
+ onEvent({
593
+ type: 'tool_input_delta',
594
+ id: state.id,
595
+ name: state.name,
596
+ delta: delta.partial_json,
597
+ });
598
+ }
599
+ }
600
+ return;
601
+ }
602
+ }
603
+ if (ev.type === 'content_block_stop') {
604
+ const key = blockKey(ev.index);
605
+ const state = blocks.get(key);
606
+ if (state && state.type === 'tool_use' && typeof state.id === 'string' && state.input.trim()) {
607
+ try {
608
+ emitToolUse(state.id, state.name, JSON.parse(state.input));
609
+ streamedToolUseIds.add(state.id);
610
+ }
611
+ catch {
612
+ // Fall through to the final assistant wrapper's input if the
613
+ // streamed JSON is malformed or incomplete.
614
+ }
615
+ }
616
+ else if (state &&
617
+ state.type === 'tool_use' &&
618
+ typeof state.id === 'string' &&
619
+ state.inputValue !== undefined) {
620
+ emitToolUse(state.id, state.name, state.inputValue);
621
+ streamedToolUseIds.add(state.id);
622
+ }
623
+ blocks.delete(key);
624
+ return;
625
+ }
626
+ if (ev.type === 'message_delta' && isRecord(ev.delta)) {
627
+ const stopReason = typeof ev.delta.stop_reason === 'string'
628
+ ? ev.delta.stop_reason
629
+ : null;
630
+ if (stopReason)
631
+ emitTurnEnd(stopReason);
632
+ return;
633
+ }
634
+ }
635
+ function flushPendingArtifactText() {
636
+ const text = `${pendingArtifactText}${artifactOpenCandidate}${duplicateArtifactCandidate}`;
637
+ if (!text)
638
+ return;
639
+ pendingArtifactText = '';
640
+ artifactOpenCandidate = '';
641
+ duplicateArtifactCandidate = '';
642
+ suppressNextArtifactText = false;
643
+ suppressDuplicateArtifactText = false;
644
+ recentWriteContents.length = 0;
645
+ wroteHtmlFileThisTurn = false;
646
+ emitSafeText(currentMessageId, text);
647
+ }
648
+ return { feed, flush };
649
+ }
650
+ function stringifyToolResult(content) {
651
+ if (typeof content === 'string')
652
+ return content;
653
+ if (Array.isArray(content)) {
654
+ return content
655
+ .map((c) => (isRecord(c) && c.type === 'text' ? String(c.text) : JSON.stringify(c)))
656
+ .join('\n');
657
+ }
658
+ return JSON.stringify(content);
659
+ }
660
+ //# sourceMappingURL=claude-stream.js.map