@bastani/atomic 0.9.28-alpha.2 → 0.9.28-alpha.4

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 (327) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/builtin/intercom/package.json +2 -2
  3. package/dist/builtin/mcp/native-client-licenses/NOTICE +2 -0
  4. package/dist/builtin/mcp/package.json +1 -1
  5. package/dist/builtin/subagents/CHANGELOG.md +6 -0
  6. package/dist/builtin/subagents/package.json +3 -3
  7. package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
  8. package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +60 -39
  9. package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +119 -36
  10. package/dist/builtin/subagents/skills/cua-driver/LINUX.md +225 -183
  11. package/dist/builtin/subagents/skills/cua-driver/MACOS.md +120 -89
  12. package/dist/builtin/subagents/skills/cua-driver/README.md +16 -7
  13. package/dist/builtin/subagents/skills/cua-driver/RECORDING.md +85 -115
  14. package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +113 -0
  15. package/dist/builtin/subagents/skills/cua-driver/SKILL.md +55 -1071
  16. package/dist/builtin/subagents/skills/cua-driver/VISUAL.md +125 -0
  17. package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +145 -185
  18. package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +173 -0
  19. package/dist/builtin/web-access/package.json +2 -2
  20. package/dist/builtin/workflows/CHANGELOG.md +21 -0
  21. package/dist/builtin/workflows/README.md +1 -1
  22. package/dist/builtin/workflows/package.json +2 -2
  23. package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -2
  24. package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +6 -0
  25. package/dist/builtin/workflows/skills/impeccable/reference/audit.md +2 -1
  26. package/dist/builtin/workflows/skills/impeccable/reference/component-review.md +63 -0
  27. package/dist/builtin/workflows/skills/impeccable/reference/degraded/asset-producer.md +5 -0
  28. package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +1 -1
  29. package/dist/builtin/workflows/skills/impeccable/reference/generate.md +101 -0
  30. package/dist/builtin/workflows/skills/impeccable/reference/harden.md +9 -0
  31. package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +3 -1
  32. package/dist/builtin/workflows/skills/impeccable/reference/mode-operate.md +21 -0
  33. package/dist/builtin/workflows/skills/impeccable/reference/mode-persuade.md +19 -0
  34. package/dist/builtin/workflows/skills/impeccable/reference/mode-read.md +21 -0
  35. package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +19 -12
  36. package/dist/builtin/workflows/skills/impeccable/reference/region-map.md +26 -0
  37. package/dist/builtin/workflows/skills/impeccable/reference/routing.md +1 -1
  38. package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +5 -5
  39. package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
  40. package/dist/builtin/workflows/skills/impeccable/scripts/command-metadata.json +4 -0
  41. package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +2 -2
  42. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +5 -1
  43. package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +524 -4
  44. package/dist/builtin/workflows/skills/prompt-engineer/SKILL.md +1 -0
  45. package/dist/builtin/workflows/skills/prompt-engineer/references/claude_haiku_5_5.md +81 -0
  46. package/dist/builtin/workflows/src/extension/index.bundle.mjs +14733 -14704
  47. package/dist/cli/args.d.ts.map +1 -1
  48. package/dist/cli/args.js +8 -1
  49. package/dist/cli/args.js.map +1 -1
  50. package/dist/codemode-worker.js +2 -2
  51. package/dist/config.d.ts +2 -1
  52. package/dist/config.d.ts.map +1 -1
  53. package/dist/config.js +4 -2
  54. package/dist/config.js.map +1 -1
  55. package/dist/core/agent-session-compaction.d.ts +3 -3
  56. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  57. package/dist/core/agent-session-compaction.js +5 -1
  58. package/dist/core/agent-session-compaction.js.map +1 -1
  59. package/dist/core/agent-session-events.d.ts.map +1 -1
  60. package/dist/core/agent-session-events.js +1 -0
  61. package/dist/core/agent-session-events.js.map +1 -1
  62. package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
  63. package/dist/core/agent-session-extension-bindings.js +7 -2
  64. package/dist/core/agent-session-extension-bindings.js.map +1 -1
  65. package/dist/core/agent-session-methods.d.ts +7 -1
  66. package/dist/core/agent-session-methods.d.ts.map +1 -1
  67. package/dist/core/agent-session-methods.js.map +1 -1
  68. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  69. package/dist/core/agent-session-prompt.js +3 -2
  70. package/dist/core/agent-session-prompt.js.map +1 -1
  71. package/dist/core/agent-session-tool-registry.js.map +1 -1
  72. package/dist/core/agent-session-types.d.ts +2 -0
  73. package/dist/core/agent-session-types.d.ts.map +1 -1
  74. package/dist/core/agent-session-types.js.map +1 -1
  75. package/dist/core/agent-session.d.ts +2 -0
  76. package/dist/core/agent-session.d.ts.map +1 -1
  77. package/dist/core/agent-session.js +6 -1
  78. package/dist/core/agent-session.js.map +1 -1
  79. package/dist/core/bash-executor.d.ts.map +1 -1
  80. package/dist/core/bash-executor.js +22 -4
  81. package/dist/core/bash-executor.js.map +1 -1
  82. package/dist/core/child-session-options.d.ts.map +1 -1
  83. package/dist/core/child-session-options.js +17 -2
  84. package/dist/core/child-session-options.js.map +1 -1
  85. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  86. package/dist/core/export-html/tool-renderer.js +2 -0
  87. package/dist/core/export-html/tool-renderer.js.map +1 -1
  88. package/dist/core/extensions/agent-events.d.ts +2 -0
  89. package/dist/core/extensions/agent-events.d.ts.map +1 -1
  90. package/dist/core/extensions/agent-events.js.map +1 -1
  91. package/dist/core/extensions/context-types.d.ts +2 -0
  92. package/dist/core/extensions/context-types.d.ts.map +1 -1
  93. package/dist/core/extensions/context-types.js.map +1 -1
  94. package/dist/core/extensions/loader-virtual-modules.d.ts +3 -4
  95. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  96. package/dist/core/extensions/loader-virtual-modules.js +14 -9
  97. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  98. package/dist/core/extensions/mcp-server-registry.d.ts +4 -1
  99. package/dist/core/extensions/mcp-server-registry.d.ts.map +1 -1
  100. package/dist/core/extensions/mcp-server-registry.js +7 -4
  101. package/dist/core/extensions/mcp-server-registry.js.map +1 -1
  102. package/dist/core/extensions/runner.d.ts +3 -0
  103. package/dist/core/extensions/runner.d.ts.map +1 -1
  104. package/dist/core/extensions/runner.js +19 -0
  105. package/dist/core/extensions/runner.js.map +1 -1
  106. package/dist/core/extensions/tool-events.d.ts +1 -1
  107. package/dist/core/extensions/tool-events.js.map +1 -1
  108. package/dist/core/extensions/tool-types.d.ts +2 -0
  109. package/dist/core/extensions/tool-types.d.ts.map +1 -1
  110. package/dist/core/extensions/tool-types.js.map +1 -1
  111. package/dist/core/extensions/ts-source-specifiers.d.ts +18 -0
  112. package/dist/core/extensions/ts-source-specifiers.d.ts.map +1 -0
  113. package/dist/core/extensions/ts-source-specifiers.js +142 -0
  114. package/dist/core/extensions/ts-source-specifiers.js.map +1 -0
  115. package/dist/core/fast-model-variants.d.ts.map +1 -1
  116. package/dist/core/fast-model-variants.js +3 -2
  117. package/dist/core/fast-model-variants.js.map +1 -1
  118. package/dist/core/model-resolver-defaults.d.ts.map +1 -1
  119. package/dist/core/model-resolver-defaults.js +2 -0
  120. package/dist/core/model-resolver-defaults.js.map +1 -1
  121. package/dist/core/nested-tool-calls.d.ts +1 -0
  122. package/dist/core/nested-tool-calls.d.ts.map +1 -1
  123. package/dist/core/nested-tool-calls.js +1 -0
  124. package/dist/core/nested-tool-calls.js.map +1 -1
  125. package/dist/core/sdk-exports.d.ts +2 -2
  126. package/dist/core/sdk-exports.js.map +1 -1
  127. package/dist/core/sdk-types.d.ts +3 -0
  128. package/dist/core/sdk-types.d.ts.map +1 -1
  129. package/dist/core/sdk-types.js.map +1 -1
  130. package/dist/core/sdk.d.ts.map +1 -1
  131. package/dist/core/sdk.js +17 -8
  132. package/dist/core/sdk.js.map +1 -1
  133. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  134. package/dist/core/settings-manager-core.js.map +1 -1
  135. package/dist/core/settings-merge.d.ts +3 -0
  136. package/dist/core/settings-merge.d.ts.map +1 -1
  137. package/dist/core/settings-merge.js +18 -4
  138. package/dist/core/settings-merge.js.map +1 -1
  139. package/dist/core/settings-storage.js.map +1 -1
  140. package/dist/core/settings-types.js.map +1 -1
  141. package/dist/core/tools/bash.d.ts.map +1 -1
  142. package/dist/core/tools/bash.js +7 -3
  143. package/dist/core/tools/bash.js.map +1 -1
  144. package/dist/core/tools/edit.js +1 -1
  145. package/dist/core/tools/edit.js.map +1 -1
  146. package/dist/extensions/codemode/execute.d.ts.map +1 -1
  147. package/dist/extensions/codemode/execute.js +69 -8
  148. package/dist/extensions/codemode/execute.js.map +1 -1
  149. package/dist/extensions/codemode/index.d.ts.map +1 -1
  150. package/dist/extensions/codemode/index.js +7 -0
  151. package/dist/extensions/codemode/index.js.map +1 -1
  152. package/dist/extensions/codemode/tool.d.ts +2 -0
  153. package/dist/extensions/codemode/tool.d.ts.map +1 -1
  154. package/dist/extensions/codemode/tool.js +4 -2
  155. package/dist/extensions/codemode/tool.js.map +1 -1
  156. package/dist/extensions/llama/provider.d.ts.map +1 -1
  157. package/dist/extensions/llama/provider.js +19 -8
  158. package/dist/extensions/llama/provider.js.map +1 -1
  159. package/dist/extensions/mcp/cli.js +18 -24
  160. package/dist/extensions/mcp/cli.js.map +1 -1
  161. package/dist/extensions/mcp/client/auth-provider.d.ts +4 -0
  162. package/dist/extensions/mcp/client/auth-provider.d.ts.map +1 -1
  163. package/dist/extensions/mcp/client/auth-provider.js.map +1 -1
  164. package/dist/extensions/mcp/client/oauth/discovery.d.ts +3 -0
  165. package/dist/extensions/mcp/client/oauth/discovery.d.ts.map +1 -1
  166. package/dist/extensions/mcp/client/oauth/discovery.js +8 -5
  167. package/dist/extensions/mcp/client/oauth/discovery.js.map +1 -1
  168. package/dist/extensions/mcp/client/oauth/flow.d.ts +4 -0
  169. package/dist/extensions/mcp/client/oauth/flow.d.ts.map +1 -1
  170. package/dist/extensions/mcp/client/oauth/flow.js +12 -2
  171. package/dist/extensions/mcp/client/oauth/flow.js.map +1 -1
  172. package/dist/extensions/mcp/client/transports/streamable-http.d.ts +3 -0
  173. package/dist/extensions/mcp/client/transports/streamable-http.d.ts.map +1 -1
  174. package/dist/extensions/mcp/client/transports/streamable-http.js +17 -14
  175. package/dist/extensions/mcp/client/transports/streamable-http.js.map +1 -1
  176. package/dist/extensions/mcp/index.d.ts.map +1 -1
  177. package/dist/extensions/mcp/index.js +150 -72
  178. package/dist/extensions/mcp/index.js.map +1 -1
  179. package/dist/extensions/mcp/oauth.d.ts +5 -3
  180. package/dist/extensions/mcp/oauth.d.ts.map +1 -1
  181. package/dist/extensions/mcp/oauth.js +36 -10
  182. package/dist/extensions/mcp/oauth.js.map +1 -1
  183. package/dist/extensions/mcp/ui.d.ts +3 -3
  184. package/dist/extensions/mcp/ui.d.ts.map +1 -1
  185. package/dist/extensions/mcp/ui.js +10 -2
  186. package/dist/extensions/mcp/ui.js.map +1 -1
  187. package/dist/index.d.ts +2 -2
  188. package/dist/index.d.ts.map +1 -1
  189. package/dist/index.js.map +1 -1
  190. package/dist/main-deferred-startup.d.ts +1 -0
  191. package/dist/main-deferred-startup.d.ts.map +1 -1
  192. package/dist/main-deferred-startup.js +9 -21
  193. package/dist/main-deferred-startup.js.map +1 -1
  194. package/dist/main.d.ts.map +1 -1
  195. package/dist/main.js +8 -6
  196. package/dist/main.js.map +1 -1
  197. package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
  198. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  199. package/dist/modes/interactive/components/bash-execution.js +17 -14
  200. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  201. package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
  202. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  203. package/dist/modes/interactive/components/branch-summary-message.js +5 -2
  204. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  205. package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -0
  206. package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/chat-message-renderer.js +19 -8
  208. package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
  209. package/dist/modes/interactive/components/compaction-boundary-message.d.ts +3 -2
  210. package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -1
  211. package/dist/modes/interactive/components/compaction-boundary-message.js +7 -4
  212. package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
  213. package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
  214. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  215. package/dist/modes/interactive/components/custom-entry.js +8 -2
  216. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  217. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  218. package/dist/modes/interactive/components/custom-message.js +1 -0
  219. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  220. package/dist/modes/interactive/components/settings-selector-items.js +1 -1
  221. package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
  222. package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
  223. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  224. package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
  225. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  226. package/dist/modes/interactive/components/tool-execution.d.ts +4 -0
  227. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  228. package/dist/modes/interactive/components/tool-execution.js +10 -0
  229. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  230. package/dist/modes/interactive/interactive-agent-events.js +3 -1
  231. package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
  232. package/dist/modes/interactive/interactive-auth-login.js +6 -0
  233. package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
  234. package/dist/modes/interactive/interactive-bash-compact.js +2 -2
  235. package/dist/modes/interactive/interactive-bash-compact.js.map +1 -1
  236. package/dist/modes/interactive/interactive-extension-dialogs.js +11 -2
  237. package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  238. package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
  239. package/dist/modes/interactive/interactive-input-handling.js +1 -47
  240. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  241. package/dist/modes/interactive/interactive-mode-base.d.ts +3 -1
  242. package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
  243. package/dist/modes/interactive/interactive-mode-base.js +6 -1
  244. package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
  245. package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -2
  246. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  248. package/dist/modes/interactive/interactive-prompt-restore.d.ts.map +1 -1
  249. package/dist/modes/interactive/interactive-prompt-restore.js +0 -5
  250. package/dist/modes/interactive/interactive-prompt-restore.js.map +1 -1
  251. package/dist/modes/interactive/interactive-render-chat.js +7 -10
  252. package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
  253. package/dist/modes/interactive/interactive-selectors.js +8 -1
  254. package/dist/modes/interactive/interactive-selectors.js.map +1 -1
  255. package/dist/modes/interactive/interactive-session-runtime.js +1 -0
  256. package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
  257. package/dist/modes/interactive/interactive-startup.js +1 -0
  258. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  259. package/dist/modes/interactive/program-status-reporter.d.ts +24 -0
  260. package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
  261. package/dist/modes/interactive/program-status-reporter.js +96 -0
  262. package/dist/modes/interactive/program-status-reporter.js.map +1 -0
  263. package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
  264. package/dist/modes/interactive-engine/engine-custom-ui.js +1 -0
  265. package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
  266. package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
  267. package/dist/modes/interactive-engine/engine-render-service.js +3 -1
  268. package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
  269. package/dist/modes/interactive-engine/protocol.d.ts +1 -0
  270. package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
  271. package/dist/modes/interactive-engine/protocol.js +1 -0
  272. package/dist/modes/interactive-engine/protocol.js.map +1 -1
  273. package/dist/modes/interactive-engine/remote-renderer.d.ts +3 -0
  274. package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
  275. package/dist/modes/interactive-engine/remote-renderer.js +7 -0
  276. package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
  277. package/dist/modes/rpc/rpc-client-process.d.ts +7 -0
  278. package/dist/modes/rpc/rpc-client-process.d.ts.map +1 -1
  279. package/dist/modes/rpc/rpc-client-process.js +20 -3
  280. package/dist/modes/rpc/rpc-client-process.js.map +1 -1
  281. package/dist/modes/rpc/rpc-command-timeouts.d.ts.map +1 -1
  282. package/dist/modes/rpc/rpc-command-timeouts.js +1 -0
  283. package/dist/modes/rpc/rpc-command-timeouts.js.map +1 -1
  284. package/dist/utils/ansi.d.ts +8 -0
  285. package/dist/utils/ansi.d.ts.map +1 -1
  286. package/dist/utils/ansi.js +29 -10
  287. package/dist/utils/ansi.js.map +1 -1
  288. package/dist/utils/clipboard.d.ts.map +1 -1
  289. package/dist/utils/clipboard.js +13 -3
  290. package/dist/utils/clipboard.js.map +1 -1
  291. package/dist/utils/image-resize-core.d.ts +8 -0
  292. package/dist/utils/image-resize-core.d.ts.map +1 -1
  293. package/dist/utils/image-resize-core.js +1 -0
  294. package/dist/utils/image-resize-core.js.map +1 -1
  295. package/dist/utils/image-resize-worker.js +3 -2
  296. package/dist/utils/image-resize-worker.js.map +1 -1
  297. package/dist/utils/image-resize.d.ts +2 -2
  298. package/dist/utils/image-resize.d.ts.map +1 -1
  299. package/dist/utils/image-resize.js +7 -10
  300. package/dist/utils/image-resize.js.map +1 -1
  301. package/docs/codemode.md +30 -6
  302. package/docs/compaction.md +1 -1
  303. package/docs/computer-use.md +9 -9
  304. package/docs/custom-provider/streaming.md +4 -0
  305. package/docs/environment-variables.md +2 -0
  306. package/docs/extensions/api-reference.md +1 -1
  307. package/docs/extensions/authoring.md +2 -0
  308. package/docs/extensions/events.md +5 -1
  309. package/docs/getting-started/first-session.md +1 -1
  310. package/docs/json.md +6 -1
  311. package/docs/llama-cpp.md +9 -2
  312. package/docs/mcp-servers.md +3 -3
  313. package/docs/models/evals.md +34 -3
  314. package/docs/models.md +10 -0
  315. package/docs/providers.md +35 -4
  316. package/docs/reference/cli.md +2 -2
  317. package/docs/sdk/reference.md +3 -3
  318. package/docs/sdk.md +7 -1
  319. package/docs/settings.md +3 -3
  320. package/docs/skills.md +1 -1
  321. package/docs/terminal-setup.md +14 -0
  322. package/docs/tools.md +1 -1
  323. package/docs/workflows/authoring.md +3 -3
  324. package/docs/workflows/operations.md +2 -2
  325. package/examples/extensions/sandbox/package-lock.json +3 -3
  326. package/npm-shrinkwrap.json +67 -67
  327. package/package.json +8 -8
@@ -1,12 +1,12 @@
1
1
  import { Worker } from "node:worker_threads";
2
- import { resizeImageInProcess } from "./image-resize-core.js";
2
+ import { IMAGE_RESIZE_WORKER_RESPONSE_TYPE, resizeImageInProcess, } from "./image-resize-core.js";
3
3
  function toTransferableBytes(input) {
4
4
  // Transfer detaches the buffer, so transfer a worker-owned copy and leave the
5
5
  // caller's bytes intact.
6
6
  return new Uint8Array(input);
7
7
  }
8
8
  function isResizeImageWorkerResponse(value) {
9
- return value !== null && typeof value === "object";
9
+ return (value !== null && typeof value === "object" && "type" in value && value.type === IMAGE_RESIZE_WORKER_RESPONSE_TYPE);
10
10
  }
11
11
  function createResizeWorker(workerSpecifier) {
12
12
  return new Worker(workerSpecifier);
@@ -29,16 +29,13 @@ async function resizeImageInWorker(workerSpecifier, inputBytes, mimeType, option
29
29
  settled = true;
30
30
  reject(error);
31
31
  };
32
- worker.once("message", (message) => {
33
- if (!isResizeImageWorkerResponse(message)) {
34
- fail(new Error("Invalid image resize worker response"));
32
+ worker.on("message", (message) => {
33
+ if (!isResizeImageWorkerResponse(message))
35
34
  return;
36
- }
37
- if (message.error) {
35
+ if ("error" in message)
38
36
  fail(new Error(message.error));
39
- return;
40
- }
41
- settle(message.result ?? null);
37
+ else
38
+ settle(message.result);
42
39
  });
43
40
  worker.once("error", fail);
44
41
  worker.once("exit", (code) => {
@@ -1 +1 @@
1
- {"version":3,"file":"image-resize.js","sourceRoot":"","sources":["../../src/utils/image-resize.ts"],"names":[],"mappings":"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","sourcesContent":["import { Worker } from \"node:worker_threads\";\nimport { type ImageResizeOptions, type ResizedImage, resizeImageInProcess } from \"./image-resize-core.ts\";\n\nexport type { ImageResizeOptions, ResizedImage } from \"./image-resize-core.ts\";\n\ninterface ResizeImageWorkerResponse {\n\tresult?: ResizedImage | null;\n\terror?: string;\n}\n\nfunction toTransferableBytes(input: Uint8Array): Uint8Array<ArrayBuffer> {\n\t// Transfer detaches the buffer, so transfer a worker-owned copy and leave the\n\t// caller's bytes intact.\n\treturn new Uint8Array(input);\n}\n\nfunction isResizeImageWorkerResponse(value: unknown): value is ResizeImageWorkerResponse {\n\treturn value !== null && typeof value === \"object\";\n}\n\nfunction createResizeWorker(workerSpecifier: string | URL): Worker {\n\treturn new Worker(workerSpecifier);\n}\n\nasync function resizeImageInWorker(\n\tworkerSpecifier: string | URL,\n\tinputBytes: Uint8Array,\n\tmimeType: string,\n\toptions?: ImageResizeOptions,\n): Promise<ResizedImage | null> {\n\tconst worker = createResizeWorker(workerSpecifier);\n\ttry {\n\t\tconst inputBytesForWorker = toTransferableBytes(inputBytes);\n\t\treturn await new Promise<ResizedImage | null>((resolve, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst settle = (result: ResizedImage | null): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolve(result);\n\t\t\t};\n\t\t\tconst fail = (error: Error): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\treject(error);\n\t\t\t};\n\n\t\t\tworker.once(\"message\", (message: unknown) => {\n\t\t\t\tif (!isResizeImageWorkerResponse(message)) {\n\t\t\t\t\tfail(new Error(\"Invalid image resize worker response\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (message.error) {\n\t\t\t\t\tfail(new Error(message.error));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsettle(message.result ?? null);\n\t\t\t});\n\t\t\tworker.once(\"error\", fail);\n\t\t\tworker.once(\"exit\", (code) => {\n\t\t\t\tif (!settled) {\n\t\t\t\t\tfail(new Error(`Image resize worker exited with code ${code}`));\n\t\t\t\t}\n\t\t\t});\n\t\t\tworker.postMessage(\n\t\t\t\t{\n\t\t\t\t\tinputBytes: inputBytesForWorker,\n\t\t\t\t\tmimeType,\n\t\t\t\t\toptions,\n\t\t\t\t},\n\t\t\t\t[inputBytesForWorker.buffer],\n\t\t\t);\n\t\t});\n\t} finally {\n\t\tvoid worker.terminate().catch(() => undefined);\n\t}\n}\n\n/**\n * Resize an image to fit within the specified max dimensions and encoded file size.\n * Runs Photon in a worker thread so WASM decoding, resizing, and encoding do not\n * block the TUI event loop. If the worker cannot be loaded (for example in some\n * Bun compiled executable layouts), fall back to in-process resizing so image\n * reads still work.\n */\nexport async function resizeImage(\n\tinputBytes: Uint8Array,\n\tmimeType: string,\n\toptions?: ImageResizeOptions,\n): Promise<ResizedImage | null> {\n\tconst isTypeScriptRuntime = import.meta.url.endsWith(\".ts\");\n\tconst workerUrl = new URL(\n\t\tisTypeScriptRuntime ? \"./image-resize-worker.ts\" : \"./image-resize-worker.js\",\n\t\timport.meta.url,\n\t);\n\n\t// Bun compiled executables resolve worker entrypoints by string path, not via\n\t// new URL(..., import.meta.url). Try the string path first under Bun so the\n\t// release binary uses the embedded worker instead of falling back in-process.\n\tif (typeof process.versions.bun === \"string\") {\n\t\ttry {\n\t\t\treturn await resizeImageInWorker(\"./src/utils/image-resize-worker.ts\", inputBytes, mimeType, options);\n\t\t} catch {}\n\t}\n\n\ttry {\n\t\treturn await resizeImageInWorker(workerUrl, inputBytes, mimeType, options);\n\t} catch {\n\t\treturn resizeImageInProcess(inputBytes, mimeType, options);\n\t}\n}\n\n/**\n * Format a dimension note for resized images.\n * This helps the model understand the coordinate mapping.\n */\nexport function formatDimensionNote(result: ResizedImage): string | undefined {\n\tif (!result.wasResized) {\n\t\treturn undefined;\n\t}\n\n\tconst scale = result.originalWidth / result.width;\n\treturn `[Image: original ${result.originalWidth}x${result.originalHeight}, displayed at ${result.width}x${result.height}. Multiply coordinates by ${scale.toFixed(2)} to map to original image.]`;\n}\n"]}
1
+ {"version":3,"file":"image-resize.js","sourceRoot":"","sources":["../../src/utils/image-resize.ts"],"names":[],"mappings":"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","sourcesContent":["import { Worker } from \"node:worker_threads\";\nimport {\n\tIMAGE_RESIZE_WORKER_RESPONSE_TYPE,\n\ttype ImageResizeOptions,\n\ttype ResizedImage,\n\ttype ResizeImageWorkerResponse,\n\tresizeImageInProcess,\n} from \"./image-resize-core.js\";\n\nexport type { ImageResizeOptions, ResizedImage } from \"./image-resize-core.js\";\n\nfunction toTransferableBytes(input: Uint8Array): Uint8Array<ArrayBuffer> {\n\t// Transfer detaches the buffer, so transfer a worker-owned copy and leave the\n\t// caller's bytes intact.\n\treturn new Uint8Array(input);\n}\n\nfunction isResizeImageWorkerResponse(value: unknown): value is ResizeImageWorkerResponse {\n\treturn (\n\t\tvalue !== null && typeof value === \"object\" && \"type\" in value && value.type === IMAGE_RESIZE_WORKER_RESPONSE_TYPE\n\t);\n}\n\nfunction createResizeWorker(workerSpecifier: string | URL): Worker {\n\treturn new Worker(workerSpecifier);\n}\n\nasync function resizeImageInWorker(\n\tworkerSpecifier: string | URL,\n\tinputBytes: Uint8Array,\n\tmimeType: string,\n\toptions?: ImageResizeOptions,\n): Promise<ResizedImage | null> {\n\tconst worker = createResizeWorker(workerSpecifier);\n\ttry {\n\t\tconst inputBytesForWorker = toTransferableBytes(inputBytes);\n\t\treturn await new Promise<ResizedImage | null>((resolve, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst settle = (result: ResizedImage | null): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tresolve(result);\n\t\t\t};\n\t\t\tconst fail = (error: Error): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\treject(error);\n\t\t\t};\n\n\t\t\tworker.on(\"message\", (message: unknown) => {\n\t\t\t\tif (!isResizeImageWorkerResponse(message)) return;\n\t\t\t\tif (\"error\" in message) fail(new Error(message.error));\n\t\t\t\telse settle(message.result);\n\t\t\t});\n\t\t\tworker.once(\"error\", fail);\n\t\t\tworker.once(\"exit\", (code) => {\n\t\t\t\tif (!settled) {\n\t\t\t\t\tfail(new Error(`Image resize worker exited with code ${code}`));\n\t\t\t\t}\n\t\t\t});\n\t\t\tworker.postMessage(\n\t\t\t\t{\n\t\t\t\t\tinputBytes: inputBytesForWorker,\n\t\t\t\t\tmimeType,\n\t\t\t\t\toptions,\n\t\t\t\t},\n\t\t\t\t[inputBytesForWorker.buffer],\n\t\t\t);\n\t\t});\n\t} finally {\n\t\tvoid worker.terminate().catch(() => undefined);\n\t}\n}\n\n/**\n * Resize an image to fit within the specified max dimensions and encoded file size.\n * Runs Photon in a worker thread so WASM decoding, resizing, and encoding do not\n * block the TUI event loop. If the worker cannot be loaded (for example in some\n * Bun compiled executable layouts), fall back to in-process resizing so image\n * reads still work.\n */\nexport async function resizeImage(\n\tinputBytes: Uint8Array,\n\tmimeType: string,\n\toptions?: ImageResizeOptions,\n): Promise<ResizedImage | null> {\n\tconst isTypeScriptRuntime = import.meta.url.endsWith(\".ts\");\n\tconst workerUrl = new URL(\n\t\tisTypeScriptRuntime ? \"./image-resize-worker.ts\" : \"./image-resize-worker.js\",\n\t\timport.meta.url,\n\t);\n\n\t// Bun compiled executables resolve worker entrypoints by string path, not via\n\t// new URL(..., import.meta.url). Try the string path first under Bun so the\n\t// release binary uses the embedded worker instead of falling back in-process.\n\tif (typeof process.versions.bun === \"string\") {\n\t\ttry {\n\t\t\treturn await resizeImageInWorker(\"./src/utils/image-resize-worker.ts\", inputBytes, mimeType, options);\n\t\t} catch {}\n\t}\n\n\ttry {\n\t\treturn await resizeImageInWorker(workerUrl, inputBytes, mimeType, options);\n\t} catch {\n\t\treturn resizeImageInProcess(inputBytes, mimeType, options);\n\t}\n}\n\n/**\n * Format a dimension note for resized images.\n * This helps the model understand the coordinate mapping.\n */\nexport function formatDimensionNote(result: ResizedImage): string | undefined {\n\tif (!result.wasResized) {\n\t\treturn undefined;\n\t}\n\n\tconst scale = result.originalWidth / result.width;\n\treturn `[Image: original ${result.originalWidth}x${result.originalHeight}, displayed at ${result.width}x${result.height}. Multiply coordinates by ${scale.toFixed(2)} to map to original image.]`;\n}\n"]}
package/docs/codemode.md CHANGED
@@ -20,7 +20,7 @@ A script may start with an options line:
20
20
  - `max_output_tokens` (default 10000) limits the output. Longer output keeps its start and end, and the full text is written to a temp file whose path is included in the result.
21
21
  - `timeout_ms` is a hard deadline for the whole script. It is unset by default. Image generation can take minutes, so do not set a short deadline for scripts that generate images.
22
22
 
23
- The result starts with `Script completed` or `Script failed`, the wall time, and the output. A failed script keeps its partial output, followed by `Script error:` and the error. Tool calls are real: calls made before a failure are not undone. Calls still running when the script ends are cancelled, and unawaited promises are discarded.
23
+ The result starts with `Script completed` or `Script failed`, the wall time, and the output. Text and image items appear in order. When output has multiple text items (from `text()` or `return`), each starts with a `==> text N/M <==` line. Console calls follow the other output in one `<console_output>` block, with one line per call. A failed script keeps its partial output, followed by `Script error:` and the error. Tool calls are real: calls made before a failure are not undone. Calls still running when the script ends are cancelled, and unawaited promises are discarded.
24
24
 
25
25
  ## Globals
26
26
 
@@ -29,13 +29,13 @@ The result starts with `Script completed` or `Script failed`, the wall time, and
29
29
  | `tools.<name>(args)` | Call a tool. See [Call tools](#call-tools). |
30
30
  | `text(value)` | Add a text item to the output. Strings are added as is, other values as JSON. |
31
31
  | `image(value)` | Add an image to the output: a base64 `data:` URL, an `{ image_url }` object, or an image block `{ type: "image", data, mimeType }` such as those returned by MCP tools and `models.generateImages()`. Remote URLs are not supported. PNG, JPEG, GIF, and WebP are accepted. Each image is also saved to a temp file, and the result names the path before the image. |
32
- | `console.log(...)` | Like `text()`; `info`, `warn`, `error`, and `debug` do the same. |
32
+ | `console.log(...)` | Add a line to the `<console_output>` block after other output. Arguments are joined with spaces; `info`, `warn`, `error`, and `debug` do the same. |
33
33
  | `return value` | A top-level `return` adds the value like `text()`. |
34
34
  | `exit()` | End the script successfully. |
35
35
  | `store(key, value)` / `load(key)` | Keep small JSON values across `codemode` calls. See [Store values](#store-values). |
36
- | `ALL_TOOLS` | Every callable tool as `{ name, description }`, including tools the description does not list. |
37
- | `searchTools(query, { limit?, namespace? })` | Rank callable tools by relevance (BM25, default limit 8). Resolves to `{ name, description }[]`. |
38
- | `describeTool(name)` | Resolves to a tool's description and TypeScript declaration, or `undefined`. |
36
+ | `ALL_TOOLS` | Every script-callable tool as `{ name, description }`, including tools the description does not list. [Model-only tools](#model-only-tools) are excluded. |
37
+ | `searchTools(query, { limit?, namespace? })` | Rank script-callable tools by relevance (BM25, default limit 8). Resolves to `{ name, description }[]`. A query that names an active model-only tool exactly returns it first with a hint to call it directly. |
38
+ | `describeTool(name)` | Resolves to a script-callable tool's description and TypeScript declaration, a hint for an active model-only tool, or `undefined`. |
39
39
  | `describeNamespace(name)` | Resolves to `{ name, description?, instructions?, tools }` for a namespace such as an MCP server, or `undefined`. |
40
40
  | `models` | List and run non-LLM models. See [Models](#models). |
41
41
 
@@ -56,6 +56,10 @@ The `codemode` description lists tools with their TypeScript declarations, group
56
56
 
57
57
  While `codemode` is active, `codemode.mode` in [settings](/settings#tools) decides how the other tools are presented. With `on` (default) declared tools stay declared, and their descriptions say in one line how scripts call them and what the call resolves to. With `only` they are hidden from the model and listed in the `codemode` description instead, so the model calls them through scripts. Tool declarations in the `codemode` description, `describeTool()`, and `ALL_TOOLS` carry the tools' prompt guidelines, since the system prompt rules only cover declared tools.
58
58
 
59
+ ### Model-only tools
60
+
61
+ Model-only tools, such as `subagent`, `workflow`, `intercom`, and `ask_user_question`, are not in `tools` or `ALL_TOOLS`, and `searchTools()` never ranks them as matches. Scripts cannot call them, but the model can call them directly, so a missing entry does not mean the tool is unavailable. While such a tool is active, `searchTools()` and `describeTool()` answer its exact name, such as `searchTools("subagent")`, with a hint to call it directly. The hint does not make the tool callable from scripts.
62
+
59
63
  ## Store values
60
64
 
61
65
  `store(key, value)` keeps a JSON value under a string key for later `codemode` calls; storing `undefined` deletes the key. `load(key)` returns the value, or `undefined`. Writes are kept only when the script succeeds: each successful script that stores values appends a `codemode-store` custom entry to the session, so resumed sessions keep the values and each branch sees only the values written on its path.
@@ -64,7 +68,7 @@ The store is for small state such as IDs, cursors, or summaries. One value may h
64
68
 
65
69
  ## Models
66
70
 
67
- `models` reaches the model catalog and runs non-LLM models with the session's credentials: classifiers, which answer typed questions about JSON state, and image models, which generate images. Chat models are listed but cannot be run from scripts. Classifier models include [TypeSafe Jev](/providers#typesafe-jev) and [local llama.cpp models](/llama-cpp); image models include OpenRouter's, such as `google/gemini-2.5-flash-image` and `black-forest-labs/flux.2-pro`, which use the same `OPENROUTER_API_KEY` or `/login` credential as its chat models. Neither kind appears in `/model`.
71
+ `models` reaches the model catalog and runs non-LLM models with the session's credentials: classifiers, which answer typed questions about JSON state and, for some models, images, and image models, which generate images. Chat models are listed but cannot be run from scripts. Classifier models include [TypeSafe Jev](/providers#typesafe-jev), [OpenAI GPT-6 Luna](/models#use-classifier-models), and [local llama.cpp models](/llama-cpp); image models include OpenRouter's, such as `google/gemini-2.5-flash-image` and `black-forest-labs/flux.2-pro`, which use the same `OPENROUTER_API_KEY` or `/login` credential as its chat models. Neither kind appears in `/model`.
68
72
 
69
73
  ```ts
70
74
  type ModelType = "chat" | "image" | "classifier";
@@ -105,6 +109,7 @@ Model IDs differ between providers. Use `models.getAvailableOfType(type)` to fin
105
109
  interface ClassifierContext {
106
110
  /** The data to classify. */
107
111
  state: Record<string, unknown>;
112
+ images?: { type: "image"; data: string; mimeType: string }[];
108
113
  /** Questions by ID. One call answers all of them. */
109
114
  questions: Record<string, ClassifierQuestion>;
110
115
  }
@@ -168,6 +173,25 @@ return results.map((result, i) =>
168
173
  );
169
174
  ```
170
175
 
176
+ Classifiers whose `input` includes `"image"` can judge images alongside the state. `tools.read()` returns image blocks that `images` accepts. Text-only classifiers and APIs that cannot send images return an error result for nonempty `images`.
177
+
178
+ ```js
179
+ const luna = await models.getModelOfType("classifier", "openai-decisions", "gpt-6-luna");
180
+ const photo = await tools.read({ path: "screenshot.png" });
181
+ const result = await models.classify(luna, {
182
+ state: { task: "Settings page redesign" },
183
+ images: [photo],
184
+ questions: {
185
+ broken: {
186
+ type: "bool",
187
+ instructions: "Does the screenshot show a broken layout?",
188
+ criteria: { true: "Overlapping, cut-off, or misaligned elements", false: "Clean layout" },
189
+ },
190
+ },
191
+ });
192
+ return result.stopReason === "stop" ? result.answers : result.errorMessage;
193
+ ```
194
+
171
195
  ### Generate images
172
196
 
173
197
  ```ts
@@ -102,7 +102,7 @@ You can also set `compactionModel` in `~/.atomic/agent/settings.json` or a trust
102
102
 
103
103
  The default, `auto`, or an empty value uses the current session model, including Anthropic models. An exact registered chat-model ID selects that model just for compaction. Registered classifiers and Morph compactors are also selectable. Project settings cannot select `morph/*`; choose Morph globally instead.
104
104
 
105
- An explicit compaction model can send the compactable transcript to a different provider, using that provider's credentials. Choose only providers permitted to receive your conversation. Changing `compactionModel` does not affect branch summaries.
105
+ An explicit compaction model can send the compactable transcript to a different provider, using that provider's credentials. Choose only providers permitted to receive your conversation. Changing `compactionModel` does not affect branch summaries. SDK and extension code can pick a model for a single run with `session.compact({ compactionModel })` or `ctx.compact({ compactionModel })`, which leaves the setting unchanged.
106
106
 
107
107
  For classifier compaction, log in with `/login typesafe`, then set `"compactionModel": "typesafe/jev-latest"`. The classifier scores groups of transcript lines; Atomic removes lower-scored groups without rewriting the rest. Protected lines and the recent tail are not sent for scoring. If scoring fails, Atomic tries your fallback models. Group boundaries can make the retained fraction differ from the requested compression ratio.
108
108
 
@@ -212,7 +212,7 @@ Report what the installer did. On macOS it places `CuaDriver.app` in `/Applicati
212
212
 
213
213
  Never loop on the installer. In a workflow stage, a refused or failed install is reported as `blocked`/`needs_human` together with the exact installer command above, not worked around with an alternative tool.
214
214
 
215
- If the installed driver is older than the bundled skill's `version` (`0.28.2`), run `cua-driver update --apply` once and restart the daemon with the platform's startup command below. If it is newer, proceed and note the skew in the report. `cua-driver check-update` only checks; it changes nothing.
215
+ The bundled skill's `version` (`0.34.0`) identifies its source release, not the running daemon. Check the installed driver's advertised schema before using unfamiliar parameters; do not upgrade software or change permissions merely to make a recipe work. If an upgrade is authorized, run `cua-driver update --apply` once and restart the daemon with the platform's startup command below. `cua-driver check-update` only checks; it changes nothing.
216
216
 
217
217
  ### Turn telemetry off
218
218
 
@@ -245,18 +245,18 @@ A missing macOS Accessibility or Screen Recording grant, a non-interactive Windo
245
245
 
246
246
  ### Drive a window from the shell
247
247
 
248
- Load the `cua-driver` skill and follow its loop. The shape, with `CUA_DRIVER_RS_TELEMETRY_ENABLED=false` exported as above, is:
248
+ Load the `cua-driver` skill and follow its loop. For a multi-call CLI run, choose a short, non-default session label and repeat it on every call that accepts `session`; omitting it uses a disposable implicit lease rather than preserving the prior call's state. The shape, with `CUA_DRIVER_RS_TELEMETRY_ENABLED=false` exported as above, is:
249
249
 
250
250
  ```sh
251
251
  cua-driver call list_apps
252
252
  cua-driver call list_windows '{"pid":844}'
253
- cua-driver call get_window_state '{"pid":844,"window_id":10725,"screenshot_out_file":"artifacts/before.png"}' > artifacts/before.json
254
- # Pick one element_token from before.json, then act on it in the background.
255
- cua-driver call click '{"pid":844,"element_token":"s0000002a:14"}'
256
- cua-driver call get_window_state '{"pid":844,"window_id":10725,"screenshot_out_file":"artifacts/after.png"}' > artifacts/after.json
253
+ cua-driver call get_window_state '{"pid":844,"window_id":10725,"session":"run-1","screenshot_out_file":"artifacts/before.png"}' > artifacts/before.json
254
+ # Pick one element_token from before.json, then act on that exact window in the background.
255
+ cua-driver call click '{"target":{"kind":"window","pid":844,"window_id":10725},"element_token":"s0000002a:14","session":"run-1","delivery_mode":"background"}'
256
+ cua-driver call get_window_state '{"pid":844,"window_id":10725,"session":"run-1","screenshot_out_file":"artifacts/after.png"}' > artifacts/after.json
257
257
  ```
258
258
 
259
- Replace the pid, window id, and token with values read from your own output; tokens are bound to the snapshot that produced them and must be re-read after any UI change. Check the postcondition in `after.json` with a bounded poll deadline, never a fixed sleep and never a repeated click. A `degraded` or `truncated` snapshot is a reason to stop and re-observe, and a refused background action is an escalation signal, not something to retry. Foreground delivery is an explicit escalation. Keep the JSON results and the `screenshot_out_file` images as evidence. When the work ends in a PR, attach the before/after PNGs to the PR body (`gh pr create --body-file body.md --attach 'before.png#Before' --attach 'after.png#After'` on supported GitHub) next to the scenario they prove, and cite the JSON by name as a local artifact; see [Verification and evidence](/workflows/verification#native-github-media).
259
+ Replace the pid, window id, token, and session label with values for your own run; tokens are bound to the snapshot that produced them and must be re-read after any UI change. Check the postcondition in `after.json` with a bounded poll deadline, never a fixed sleep and never a repeated click. A `degraded` or `truncated` snapshot is a reason to stop and re-observe. If background delivery is refused, refresh state and ask before foreground or desktop control unless it was already authorized; do not retry automatically. End only your run with `cua-driver call end_session '{"session":"run-1"}'`, not `cua-driver stop` on a shared service. Keep the JSON results and the `screenshot_out_file` images as evidence. When the work ends in a PR, attach the before/after PNGs to the PR body (`gh pr create --body-file body.md --attach 'before.png#Before' --attach 'after.png#After'` on supported GitHub) next to the scenario they prove, and cite the JSON by name as a local artifact; see [Verification and evidence](/workflows/verification#native-github-media).
260
260
 
261
261
  ### Run a scenario from workflow code
262
262
 
@@ -264,7 +264,7 @@ When a custom workflow owns the scenario, use the `@trycua/cua-driver` TypeScrip
264
264
 
265
265
  - **Prerequisite.** `node` (preferred) or `bun` on the host. If neither is present, install one in a bounded attempt (Node via [fnm](https://github.com/Schniz/fnm) with `fnm install --lts` or the host's package manager, Bun via `curl -fsSL https://bun.sh/install | bash`) and report what the installer did; if the install is refused or fails, report that as the limitation rather than retrying.
266
266
  - **Install.** `npm install @trycua/cua-driver@<exact pin matching cua-driver --version>` into a scratch directory outside the user's repository, one bounded attempt. The package ships per-platform native optional dependencies, so it is self-contained. Pin the exact driver version: daemon-backed clients verify contract, tool-schema, capability, and protocol versions before each action and refuse on mismatch.
267
- - **Acquire the driver.** When `cua-driver status` reports a running daemon, use `CuaDriver.connect()` so the scenario reuses the daemon's permission identity (on macOS, `CuaDriver.app`'s grants) and the persisted telemetry-off preference; upstream describes `connect()` as a compatibility and app-hosting path, and that is exactly the role it plays here. Only when no daemon is reachable, fall back to `CuaDriver.create()`, which loads the runtime into the node process. On macOS that in-process fallback attributes Accessibility and Screen Recording to the node host, normally the terminal app, as a **separate grant**; `checkPermissions` is then read-only, and the host must fully quit and relaunch after granting.
267
+ - **Acquire the driver.** When `cua-driver status` reports a running daemon, use `CuaDriver.connect(undefined)` so the scenario reuses the daemon's permission identity (on macOS, `CuaDriver.app`'s grants) and the persisted telemetry-off preference; upstream describes `connect()` as a compatibility and app-hosting path, and that is exactly the role it plays here. Only when no daemon is reachable, fall back to `CuaDriver.create(undefined)`, which loads the runtime into the node process. On macOS that in-process fallback attributes Accessibility and Screen Recording to the node host, normally the terminal app, as a **separate grant**; `checkPermissions` is then read-only, and the host must fully quit and relaunch after granting.
268
268
  - **Telemetry.** Set `CUA_DRIVER_RS_TELEMETRY_ENABLED=false` in the child environment before constructing the driver.
269
269
  - **Loop.** `listApps` → `listWindows` → `getWindowState` (refuse `degraded`/`truncated`) → resolve exactly one element → act by `elementToken` with `InputDeliveryMode.Background` → `getWindowState` again → bounded-poll the postcondition. `shutdown()` in `finally`, then `uniffiDestroy()` when present.
270
270
  - **Result.** Machine-readable `verified` / `refuted` / `blocked` / `unknown`; the wrapper maps anything but `verified` to a nonzero outcome. An action that times out before its response is `unknown`, resolved by the postcondition, never by replaying the mutation.
@@ -485,7 +485,7 @@ See [workflow authoring](/workflows/authoring) for stages and human-input gates.
485
485
  | `cua-driver`, uv, or another command is missing | Install it when permitted with one bounded attempt, refresh PATH, and check its version in the same shell that will launch automation. |
486
486
  | `cua-driver call` fails or `permissions status` reports `unknown` | The daemon is not running. Start it with `open -n -g -a CuaDriver --args serve` on macOS, an interactive-session `cua-driver serve` on Windows, or a foreground `cua-driver serve` inside the graphical session on Linux, then rerun `cua-driver status`. |
487
487
  | Grants look correct but actions or captures are refused | Stale TCC grants. Toggle CuaDriver off and on under Accessibility and Screen & System Audio Recording, or click **+** and re-add `/Applications/CuaDriver.app`, then fully relaunch the daemon. An in-process SDK runtime needs the node host relaunched instead. |
488
- | Contract, schema, or protocol mismatch | Version skew between the bundled skill (`0.28.2`), the `@trycua/cua-driver` pin, and `cua-driver --version`. Run `cua-driver update --apply` once, restart the daemon, and reinstall the SDK at the exact driver version. |
488
+ | Contract, schema, or protocol mismatch | Version skew between the `@trycua/cua-driver` SDK pin and the running driver. Check `cua-driver --version` and reinstall the SDK at that exact version. The bundled skill (`0.34.0`) identifies its source release, not the daemon's protocol. If a driver upgrade is authorized, run `cua-driver update --apply` once and restart the daemon. |
489
489
  | Snapshot reports `degraded` or `truncated` | Do not act on it. Re-observe, narrow the query, or fall back to a pixel action from the same snapshot only where the skill allows it. |
490
490
  | Black screenshot or no desktop | Check screen permissions, display/session ownership, X11 versus Wayland, and remote-session state. |
491
491
  | Input reaches the wrong app | Stop. Confirm focus, window identity, scaling, and that no other controller shares the desktop. |
@@ -24,6 +24,10 @@ Per-vendor provider configurations (base URLs, auth, model catalogs) live under
24
24
 
25
25
  All providers follow the same pattern:
26
26
 
27
+ Return a stream from `createAssistantMessageEventStream()` or construct `AssistantMessageEventStream` directly. A plain `EventStream` subclass does not satisfy the response stream type.
28
+
29
+ The stream sets optional `durationMs` on the final assistant message using a monotonic clock. Set `timestamp` when the request starts. Existing durations are preserved; messages whose timestamps predate the stream, such as fetched deferred results, remain untimed.
30
+
27
31
  ```typescript
28
32
  import {
29
33
  type AssistantMessage,
@@ -21,6 +21,8 @@ Atomic accepts environment variables for configuration, provider credentials, an
21
21
 
22
22
  The renderer also owns `PI_HYPERLINKS`, `PI_IMAGE_PROTOCOL`, and `PI_TRUE_COLOR`. `PI_HYPERLINKS=1|0|auto` and `PI_TRUE_COLOR=1|0|auto` override or preserve detection; `PI_IMAGE_PROTOCOL=kitty|iterm2|none|auto` selects, disables, or preserves image-protocol detection. Explicit JSON values under `terminal.hyperlinks`, `terminal.images`, and `terminal.trueColor` take precedence. These renderer-owned names intentionally have no `ATOMIC_*` aliases.
23
23
 
24
+ `PI_PROGRAM_STATUS=1` forces OSC 7501 program-status reports; `0` disables them. Otherwise Atomic reports only after the terminal confirms support. This renderer-owned variable has no `ATOMIC_*` alias. See [Program status](/terminal-setup#program-status).
25
+
24
26
  ## Prompt-cache retention
25
27
 
26
28
  Atomic defaults to **long** prompt-cache retention in main chat, workflow stages, and subagents wherever the provider/model supports it. `PI_CACHE_RETENTION` intentionally has no `ATOMIC_*` alias. Set it before launching Atomic to choose `short`, `none`, or `long`:
@@ -185,7 +185,7 @@ if (usage && usage.tokens > 100_000) {
185
185
 
186
186
  ### ctx.compact()
187
187
 
188
- Trigger Atomic's verbatim line compactor without awaiting completion. The planner emits numbered deleted-line ranges only; Atomic validates them and reconstructs retained text mechanically. Use `compression_ratio` (fraction of compactable lines to keep), client-side `preserve_recent` (an exact context-visible message count), and `query` to tune the run, and `onComplete`/`onError` for follow-up actions.
188
+ Trigger Atomic's verbatim line compactor without awaiting completion. The planner emits numbered deleted-line ranges only; Atomic validates them and reconstructs retained text mechanically. Use `compression_ratio` (fraction of compactable lines to keep), client-side `preserve_recent` (an exact context-visible message count), and `query` to tune the run, `compactionModel` to pick an exact compaction model for this run without changing settings, and `onComplete`/`onError` for follow-up actions.
189
189
 
190
190
  ```typescript
191
191
  ctx.compact({
@@ -628,6 +628,8 @@ pi.registerTool({
628
628
  - `lastComponent` - the previously returned component for that slot, if any
629
629
  - `invalidate()` - request a rerender of this tool row
630
630
  - `toolCallId`, `cwd`, `executionStarted`, `argsComplete`, `isPartial`, `expanded`, `showImages`, `isError`
631
+ - `durationMs` - recorded execution time of the final result; `undefined` while running, when the tool did not run, or for older saved results
632
+ - `outputPad` - configured horizontal padding; renderers with `renderShell: "self"` apply it themselves
631
633
 
632
634
  Use `context.state` for cross-slot shared state. Keep slot-local caches on the returned component instance when you want to reuse and mutate the same component across renders.
633
635
 
@@ -312,6 +312,8 @@ Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` bo
312
312
 
313
313
  `agent_start` begins a low-level run. `agent_end` fires when that run ends, but Atomic may still retry, compact and retry, or deliver queued follow-ups. `agent_before_settle` is the final actionable boundary: it can append session entries and request one continuation. `agent_settled` is final and notification-only; use it when a status integration needs to know Atomic has no automatic continuation left, including a chain of repeated output-cap continuations. Silence during a provider request or between these runs is not settlement.
314
314
 
315
+ `agent_settled` includes `aborted: true` when the prompt was cancelled, including cancellation during `agent_before_settle`. Otherwise it is `false`. Use this field to distinguish cancellation from normal completion; an aborted prompt still emits the final settlement notification.
316
+
315
317
  ```typescript
316
318
  pi.on("agent_start", async (_event, ctx) => {});
317
319
  pi.on("agent_end", async (event, ctx) => {
@@ -459,10 +461,12 @@ pi.on("tool_execution_update", async (event, ctx) => {
459
461
  });
460
462
 
461
463
  pi.on("tool_execution_end", async (event, ctx) => {
462
- // event.toolCallId, event.toolName, event.result, event.isError
464
+ // event.toolCallId, event.toolName, event.result, event.isError, event.durationMs
463
465
  });
464
466
  ```
465
467
 
468
+ `durationMs` is the time spent in the tool's `execute()`, measured with a monotonic clock. It is absent when the tool did not run.
469
+
466
470
  #### context
467
471
 
468
472
  Fired before each LLM call. Modify messages non-destructively. See [Session Format](/session-format) for message types. When tool output crosses the buffered compaction threshold, the post-tool compaction preflight finishes before this hook runs for the follow-up call, so `event.messages` contains the rebuilt compacted context.
@@ -120,7 +120,7 @@ Skills are reusable expert instructions. Trigger one with `/skill:<name>` follow
120
120
  | `liteparse` | Pull text, tables, or values out of PDF, DOCX, PPTX, XLSX, and image files locally. | `/skill:liteparse` |
121
121
  | `show-me` | Explain a topic visually with concise diagrams, code-shape sketches, or focused HTML artifacts. HumanLayer, MIT licensed. | `/skill:show-me` |
122
122
 
123
- Impeccable 4.3.1 runs its commands (`context`, `live`, `detect`, hooks, and the rest) through a self-contained engine binary instead of Node scripts. The bundled launcher, `scripts/impeccable` (`impeccable.cmd` on Windows), looks for a binary next to itself, then in `~/.impeccable/bin/`, and otherwise downloads the pinned engine release for your platform into `~/.impeccable/bin/<version>/` and verifies it against its published SHA-256 before running it, so the first use needs network access. Point `IMPECCABLE_BIN` at a preinstalled engine or set `IMPECCABLE_HOME` to a writable cache when that is not possible. Atomic's launcher keeps the engine's anonymous concept-roll ping and its `npx impeccable update` check switched off, since the skill ships with each Atomic release. Live sessions resolve to the selected app root and support SvelteKit, Nuxt, TanStack Start, Astro, Next.js, Vite, and static HTML injection. The image fallback runs only with `OPENAI_API_KEY`, sends prompts and optional reference images to OpenAI, and spends that account's API credit. Generated image prompts are embedded in the image or a sidecar, so do not include secrets.
123
+ Impeccable 4.5.0 runs its commands (`context`, `live`, `detect`, hooks, and the rest) through a self-contained engine binary instead of Node scripts. The bundled launcher, `scripts/impeccable` (`impeccable.cmd` on Windows), looks for a binary next to itself, then in `~/.impeccable/bin/`, and otherwise downloads the pinned engine release for your platform into `~/.impeccable/bin/<version>/` and verifies it against its published SHA-256 before running it, so the first use needs network access. Point `IMPECCABLE_BIN` at a preinstalled engine or set `IMPECCABLE_HOME` to a writable cache when that is not possible. Atomic's launcher keeps the engine's anonymous concept-roll ping and its `npx impeccable update` check switched off, since the skill ships with each Atomic release. Live sessions resolve to the selected app root and support SvelteKit, Nuxt, TanStack Start, Astro, Next.js, Vite, and static HTML injection. The image fallback runs only with `OPENAI_API_KEY`, sends prompts and optional reference images to OpenAI, and spends that account's API credit. Generated image prompts are embedded in the image or a sidecar, so do not include secrets.
124
124
 
125
125
  Use `/skill:research-codebase` for a focused subsystem or question. For repository-wide research, use `fan-out-and-synthesize` with distinct repository partitions and an artifact synthesis barrier. Use Goal for ledger-backed bounded orchestration and Ralph for research-first delegated implementation with iterative review; task size alone does not select either workflow.
126
126
 
package/docs/json.md CHANGED
@@ -32,6 +32,7 @@ Events are defined in [`AgentSessionEvent`](https://github.com/bastani-inc/atomi
32
32
  ```typescript
33
33
  type AgentSessionEvent =
34
34
  | AgentEvent
35
+ | { type: "agent_settled"; aborted: boolean }
35
36
  | { type: "queue_update"; steering: readonly string[]; followUp: readonly string[] }
36
37
  | { type: "compaction_start"; reason: "manual" | "threshold" | "overflow" }
37
38
  | { type: "session_info_changed"; name: string | undefined }
@@ -48,6 +49,8 @@ type AgentSessionEvent =
48
49
 
49
50
  `queue_update` emits the full pending steering and follow-up queues whenever they change. `session_info_changed`, `model_changed`, and `thinking_level_changed` report interactive session metadata changes. `compaction_start` and `compaction_end` cover manual and automatic verbatim line compaction: the model emits deleted ranges and Atomic mechanically reconstructs retained text.
50
51
 
52
+ `agent_end` closes one low-level agent run; retries, compaction recovery, or queued work may still continue. `agent_settled` means no automatic work remains for the session-level run. Its `aborted` field is `true` when the run was cancelled.
53
+
51
54
  For automatic compaction, `compaction_end.willRetry === true` means the interrupted turn will retry; `AgentSession.prompt()` waits for that continuation. This includes overflow and retry-worthy threshold recovery, such as output-token truncation or OpenAI Responses output-budget underflow. Generic `invalid_request_body` failures still use `willRetry: false` when threshold compaction is warranted.
52
55
 
53
56
  If same-model compact-and-retry recovery is exhausted, `unresolvedOverflow: true` and `errorMessage` let integrations choose another model rather than treating the prompt as successful.
@@ -73,9 +76,11 @@ type AgentEvent =
73
76
  // Tool execution
74
77
  | { type: "tool_execution_start"; toolCallId: string; toolName: string; args: any }
75
78
  | { type: "tool_execution_update"; toolCallId: string; toolName: string; args: any; partialResult: any }
76
- | { type: "tool_execution_end"; toolCallId: string; toolName: string; result: any; isError: boolean };
79
+ | { type: "tool_execution_end"; toolCallId: string; toolName: string; result: any; isError: boolean; durationMs?: number };
77
80
  ```
78
81
 
82
+ Final assistant and tool-result messages include optional `durationMs` timing. On `tool_execution_end`, it records how long the tool's `execute()` took using a monotonic clock; it is absent when the tool did not run.
83
+
79
84
  On the wire, each `message_update` record carries:
80
85
 
81
86
  - The streaming delta in `assistantMessageEvent`, with its cumulative `partial` field stripped.
package/docs/llama-cpp.md CHANGED
@@ -70,11 +70,18 @@ Each llama model uses the router-reported loaded context (`meta.n_ctx`, then tra
70
70
 
71
71
  ## Classification
72
72
 
73
- Every model listed for chat is also listed as a classifier model with the same ID and the `llama-cpp-classify` API. Classifier models answer typed `choice`, `bool`, and `score` questions about JSON state, like TypeSafe's Jev models, so a local model can make `model: "auto"` routing decisions. Classifier models never appear in `/model`.
73
+ Classifier models answer typed `choice`, `bool`, and `score` questions about JSON state, like TypeSafe's Jev models, so a local model can make `model: "auto"` routing decisions. Extensions can call `ctx.modelRegistry.classify()` and codemode scripts can call `models.classify()`; see [Classifier models](/models#use-classifier-models). Atomic lists llama.cpp models as classifiers in two ways:
74
+
75
+ - **Decision models** such as Julia-1, Laya, Kev, lev, and OpenJev answer natively through llama.cpp's `/v1/systemone` endpoint with the `typesafe-system-one` API. Decision-only models do not appear in `/model`.
76
+ - **Chat models** are also listed as classifiers with the same ID and the `llama-cpp-classify` API, which reads answers from next-token probabilities as described below.
77
+
78
+ llama.cpp 0.6.0 and later report decision models through `architecture.output_modalities` containing `decisions`. Atomic recognizes these models even when sleeping or unloaded, without loading them during discovery. Unloaded presets are selectable only when router autoload is enabled. Older servers omit this metadata, so their models use the chat-model fallback.
79
+
80
+ ### Chat models as classifiers
74
81
 
75
82
  The model does not generate an answer. Each question becomes one chat prompt: the state, every question of the request, the state again, and then the question with its answers under single-token labels. Labels are letters for a choice (up to 62 options), `Yes`/`No` for a bool, and digits for a score (up to 10 levels). Atomic reads the probabilities of the labels as the next token and normalizes them. A choice returns every option's probability and a confidence of `(n * peak - 1) / (n - 1)`; a score returns the expected level.
76
83
 
77
- - An explicit [`routerModel`](/settings#routermodel) resolves a classifier before a chat model, so `routerModel: "llama.cpp/<id>"` routes with the classifier, not the chat model. A routing shortlist with more than 62 models fails on the classifier, and routing switches to the current chat model. The **Router model** picker lists each llama.cpp model twice, once as a classifier and once as a chat model; both rows save the same ID.
84
+ - An explicit [`routerModel`](/settings#routermodel) resolves a classifier before a chat model, so `routerModel: "llama.cpp/<id>"` routes with the classifier, not the chat model. A routing shortlist with more than 62 models fails on the chat-model classifier, and routing switches to the current chat model. The **Router model** picker lists each chat-capable llama.cpp model twice, once as a classifier and once as a chat model; both rows save the same ID. Decision-only models have only a classifier row.
78
85
  - The `structured_output` tool and `generateStructuredOutput()` resolve the chat model first when a chat and a classifier model share an ID, so naming `llama.cpp/<id>` there keeps using the chat model.
79
86
  - Raw label probabilities are usually overconfident. The `temperature` option of SDK `classify()` calls divides the label logits before normalizing; values above 1 soften the distribution. It changes no answer.
80
87
  - Questions run one after another. Everything before the final question is the same for all questions of a request, so the server's prompt cache evaluates it once. The state appears twice, so it needs twice its size in context.
@@ -80,7 +80,7 @@ Installed [packages](/packages/authoring#mcp-servers) and extensions can contrib
80
80
 
81
81
  ## Manage servers
82
82
 
83
- `/mcp` opens a server manager with connection state, tool count, exposure, and source. Select a server to inspect tools and connection details, sign in or out, reconnect, enable or disable it, or change exposure. Servers that need attention appear first.
83
+ `/mcp` opens a server manager with connection state, tool count, exposure, and source, even while startup connections are pending. Select a server to inspect tools and connection details, sign in or out, reconnect, enable or disable it, or change exposure. Servers that need attention appear first. Enable, disable, and reconnect run in the background; the manager updates live and you can keep navigating or close it while they finish.
84
84
 
85
85
  | Command | Action |
86
86
  | --- | --- |
@@ -108,7 +108,7 @@ atomic mcp logout <server>
108
108
 
109
109
  `add` replaces an existing entry of the same name. `add` and `remove` accept `--local` (`-l`) for the project file. For stdio, use repeatable `--env KEY=VALUE` and `--cwd`. For HTTP, use repeatable `--header KEY=VALUE`, `--bearer-token-env-var NAME`, and `--oauth-client-id`, `--oauth-client-secret`, `--oauth-callback-port`, or `--oauth-client-name`. Both transports accept `--exposure` and `--description`. Run `atomic mcp --help` for usage.
110
110
 
111
- `list` connects to enabled servers and reports state, tools, and errors; it exits with status 1 for invalid configuration or an enabled server that is not connected. `--json` produces a machine-readable report. Login waits up to 300 seconds by default; `--timeout` changes that browser-login budget, not the server request timeout. A running session uses new credentials on its next turn.
111
+ `list` connects to enabled servers and reports state, tools, and errors; it exits with status 1 for invalid configuration or an enabled server that is not connected. `--json` produces a machine-readable report. Login gives up after 300 seconds by default; `--timeout` limits the whole sign-in, including requests to the authorization server, but not the MCP server request timeout. A running session uses new credentials on its next turn.
112
112
 
113
113
  ## Find and call tools
114
114
 
@@ -165,7 +165,7 @@ MCP Apps resources (`ui://` URIs or `text/html;profile=mcp-app`) are omitted bec
165
165
 
166
166
  ## Authentication
167
167
 
168
- For a remote OAuth server, configure its URL and run `/mcp login my-server`, or select **Sign in** in `/mcp`. Atomic opens the authorization page and displays a clickable URL. If the browser runs on another machine, paste the complete URL it was redirected to into the sign-in prompt. Treat authorization and redirect URLs as sensitive.
168
+ For a remote OAuth server, configure its URL and run `/mcp login my-server`, or select **Sign in** in `/mcp`. Atomic opens the authorization page and displays a clickable URL. If the browser runs on another machine, paste the complete URL it was redirected to into the sign-in prompt. Press Esc to cancel a sign-in at any step; requests to the authorization server time out after 15 seconds. Treat authorization and redirect URLs as sensitive.
169
169
 
170
170
  Atomic registers OAuth clients as `atomic`, stores credentials in `~/.atomic/agent/mcp-auth.json`, and refreshes tokens when they expire or are rejected. A successful sign-in reconnects the server. If additional scope is required, sign in again. `/mcp logout my-server` or `atomic mcp logout my-server` deletes stored credentials. Old adapter credential files are not imported; sign in through the native client.
171
171
 
@@ -5,7 +5,7 @@ description: "Primary-source benchmark facts used by Atomic automatic model rout
5
5
 
6
6
  # Evals
7
7
 
8
- Last Accessed: 2026-09-25.
8
+ Last Accessed: 2026-10-07 (Claude Haiku 5.5 additions; earlier rows retain their snapshot dates below).
9
9
 
10
10
  Key:
11
11
 
@@ -46,12 +46,19 @@ Key:
46
46
 
47
47
  ## Artificial Analysis Intelligence Index v4.3.2
48
48
 
49
- Table: the 673 models on the Artificial Analysis leaderboard as of 2026-09-25, including models with no published scores, plus 5 Claude Sonnet 5.5 rows accessed 2026-09-28 and 5 GPT-6.1 Sol rows accessed 2026-09-29.
49
+ Table: the 673 models on the Artificial Analysis leaderboard as of 2026-09-25, including models with no published scores, plus 5 Claude Sonnet 5.5 rows accessed 2026-09-28, 5 GPT-6.1 Sol rows accessed 2026-09-29, and 5 Claude Haiku 5.5 rows accessed 2026-10-07.
50
50
 
51
51
  GPT-6.1 Sol's five effort rows were accessed 2026-09-29 from the [leaderboard](https://artificialanalysis.ai/leaderboards/models) and [model page](https://artificialanalysis.ai/models/gpt-6-1-sol). The release date is not an evaluation run date; run dates are unpublished. AA's [methodology](https://artificialanalysis.ai/methodology/intelligence-benchmarking) uses mini-swe-agent for TB4, all 66 tasks, pass@1 averaged over three repeats, a 500-step cap and no context compaction.
52
52
 
53
+ Claude Haiku 5.5 rows were accessed 2026-10-07 from the [leaderboard](https://artificialanalysis.ai/leaderboards/models) and the [max](https://artificialanalysis.ai/models/claude-haiku-5-5), [xhigh](https://artificialanalysis.ai/models/claude-haiku-5-5-xhigh), [high](https://artificialanalysis.ai/models/claude-haiku-5-5-high), [medium](https://artificialanalysis.ai/models/claude-haiku-5-5-medium), and [low](https://artificialanalysis.ai/models/claude-haiku-5-5-low) model pages. AA labels these configurations "with fallback". All five pages publish non-estimated indices and twelve component measurements in their public structured data, although their text rendering says "Not publicly available". Evaluation run dates are unpublished; the release date is not an evaluation run date. These are AA measurements, not Anthropic's launch-table results. Missing `ONH` remains unknown; the published hallucination rate is a different metric.
54
+
53
55
  | slug | Model | Release date | idx | Brief | Gn | Auto | TB4 | Sci | HLE | PDF | Crit | OA | ONH | LCR | Omni | GPQA | TB21 | TBh | IF | MMMU | tau2 | tauB | Analyst | ITB | Apex | AIME | LCB | Harvey | MLCR | Open | Ent |
54
56
  | --- | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
57
+ | claude-haiku-5-5 | Claude Haiku 5.5 (Adaptive Reasoning, Max Effort, With Fallback) | 2026-10-07 | 43.4 | 53.9 | 56.0 | 35.4 | 32.8 | 55.0 | 44.4 | 20.8 | 18.9 | 36.4 | ∅ | 82.7 | 10.7 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | 89.9 | ∅ | ∅ | ∅ |
58
+ | claude-haiku-5-5-xhigh | Claude Haiku 5.5 (Adaptive Reasoning, Xhigh Effort, With Fallback) | 2026-10-07 | 41.2 | 51.6 | 50.5 | 36.0 | 29.3 | 51.7 | 42.7 | 18.2 | 22.6 | 35.0 | ∅ | 78.3 | 6.1 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | 89.9 | ∅ | ∅ | ∅ |
59
+ | claude-haiku-5-5-high | Claude Haiku 5.5 (Adaptive Reasoning, High Effort, With Fallback) | 2026-10-07 | 37.8 | 47.1 | 46.0 | 33.7 | 21.7 | 48.7 | 37.3 | 17.2 | 18.6 | 34.8 | ∅ | 77.3 | 5.8 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | 89.5 | ∅ | ∅ | ∅ |
60
+ | claude-haiku-5-5-medium | Claude Haiku 5.5 (Adaptive Reasoning, Medium Effort, With Fallback) | 2026-10-07 | 34.5 | 43.6 | 38.8 | 28.6 | 15.2 | 49.0 | 33.8 | 15.2 | 12.9 | 34.0 | ∅ | 77.3 | 4.5 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | 89.2 | ∅ | ∅ | ∅ |
61
+ | claude-haiku-5-5-low | Claude Haiku 5.5 (Adaptive Reasoning, Low Effort, With Fallback) | 2026-10-07 | 29.4 | 30.6 | 31.2 | 22.9 | 12.6 | 49.2 | 27.0 | 11.2 | 9.1 | 33.3 | ∅ | 72.0 | 3.3 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | 87.9 | ∅ | ∅ | ∅ |
55
62
  | gpt-6-1-sol | GPT-6.1 Sol (max) | 2026-09-29 | 51.8 | 53.2 | 53.8 | 64.9 | 56.1 | 54.2 | 52.9 | 31 | 31.7 | 62.1 | 45.7 | 83 | 41.5 | ∅ | ∅ | ∅ | ∅ | 86 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | 33.9 | ∅ | ∅ |
56
63
  | gpt-6-1-sol-xhigh | GPT-6.1 Sol (xhigh) | 2026-09-29 | 51 | 50.3 | 50.5 | 66.6 | 54 | 55.7 | 52.6 | 31.8 | 31.7 | 60.8 | 49.1 | 79.7 | 40.9 | ∅ | ∅ | ∅ | ∅ | 85.1 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ |
57
64
  | gpt-6-1-sol-high | GPT-6.1 Sol (high) | 2026-09-29 | 50.2 | 48.6 | 49.3 | 64.5 | 51.5 | 55.8 | 51.4 | 32 | 30 | 60.8 | 50.6 | 82.3 | 41.5 | ∅ | ∅ | ∅ | ∅ | 84.9 | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ | ∅ |
@@ -780,6 +787,8 @@ Source: [FrontierCode leaderboard](https://cognition.com/frontiercode) by Cognit
780
787
 
781
788
  GPT-6.1 Sol was added 2026-09-29 and accessed that day in the [primary JSON](https://cognition.com/data/frontiercode-leaderboard/data.json). Its best score on both sets is medium effort under the `codex` harness. The Codex revision and run date are unpublished. Main averages 11,365 output tokens and 14.42 minutes per rollout.
782
789
 
790
+ Claude Haiku 5.5 was added and accessed 2026-10-07 in the [primary JSON](https://cognition.com/data/frontiercode-leaderboard/data.json). Its best score on both sets is max effort under the Claude Code harness; the run date is unpublished. No unfair-internet-use flag rate is recorded here. Mean cost per Main rollout is $1.33.
791
+
783
792
  Key:
784
793
 
785
794
  - FrontierCode: mergeability of agent-written pull requests on tasks built by open-source maintainers, graded by rubrics, unit tests and other verifiers for correctness, test quality, scope discipline, style and codebase conventions. Runs that consult solution-bearing sources such as the original pull request score zero.
@@ -802,6 +811,7 @@ Key:
802
811
  | grok-4-7 | Grok 4.7 | high | 47.6 | 53.1 | 59.4 | 65.2 | 1.3 | $6.65 |
803
812
  | gpt-5-6-sol | GPT-5.6 Sol | max | 47.5 | 52.9 | 60.6 | 66.6 | 0.0 | $5.19 |
804
813
  | claude-opus-4-8 | Opus 4.8 | max | 46.5 | 51.6 | 59.6 | 65.5 | 0.6 | $9.62 |
814
+ | claude-haiku-5-5 | Haiku 5.5 | max | 46.4 | 51.7 | 58.4 | 64.7 | ∅ | $1.33 |
805
815
  | kimi-k3 | Kimi K3 | ∅ | 44.2 | 48.9 | 58.2 | 63.6 | 0.2 | $3.82 |
806
816
  | gemini-3-7-flash | Gemini 3.7 Flash | medium | 43.6 | 48.9 | 56.3 | 62.3 | 0.0 | $1.82 |
807
817
  | gpt-5-5 | GPT-5.5 | xhigh | 43.0 | 48.2 | 56.7 | 62.8 | 0.4 | $4.03 |
@@ -834,7 +844,7 @@ Key:
834
844
 
835
845
  ## Published benchmark results
836
846
 
837
- Scores published by model vendors and benchmark owners for recent frontier models, accessed 2026-09-25; Claude Sonnet 5.5 rows accessed 2026-09-28. Values are percent. Each row names its source; the same benchmark can appear once per source because vendors run different harnesses, grading and effort levels. Internal vendor evaluations are excluded.
847
+ Scores published by model vendors and benchmark owners for recent frontier models, accessed 2026-09-25; Claude Sonnet 5.5 rows accessed 2026-09-28 and Claude Haiku 5.5 rows accessed 2026-10-07. Values are percent unless the setting names another unit. Each row names its source; the same benchmark can appear once per source because vendors run different harnesses, grading and effort levels. Internal vendor evaluations are excluded.
838
848
 
839
849
  Sources: OpenAI = [GPT-6 Astra announcement](https://openai.com/index/gpt-6-astra/); Anthropic = [Claude Fable 5.1 announcement](https://www.anthropic.com/claude-fable-and-mythos-5-1), [Claude Sonnet 5.5 announcement](https://www.anthropic.com/claude-sonnet-5-5) and [system card](https://www.anthropic.com/claude-sonnet-5-5-system-card); Google = [Gemini 3.8 Flash model card](https://deepmind.google/models/model-cards/gemini-3-8-flash/); ARC Prize = [arcprize.org results](https://arcprize.org/results/google-gemini-3-8-flash); TB-Science leaderboard = [terminal-bench-science.ai](https://www.terminal-bench-science.ai/); Zapier = [AutomationBench leaderboard](https://zapier.com/benchmarks).
840
850
 
@@ -842,10 +852,18 @@ GPT-6.1 Sol rows were accessed 2026-09-29. OpenAI = [Sol 6.1 announcement](https
842
852
 
843
853
  No matching Sol 6.1 row was retrieved from the DeepSWE, TB-Science, Zapier, Surge GDP.pdf, OSWorld or ARC Prize owner leaderboards on that date. These gaps are unknown, not zero. No `minimal` effort is measured here, and no Fast or Ultrafast tier has a separate benchmark or latency measurement for any model. Atomic's derived `-fast` and `-ultrafast` routes use explicit base-model metadata to reuse capability evidence, not a separately measured tier score or latency result.
844
854
 
855
+ Claude Haiku 5.5: Anthropic = [launch announcement](https://www.anthropic.com/claude-haiku-5-5), published and accessed 2026-10-07. These launch-table results are vendor-reported; effort, harness revisions, and evaluation run dates are not stated unless shown in the setting. GDPval-AA and AA-Briefcase are raw Elo, not the normalized AA columns above. No Haiku 5.5 result was published on the checked [DeepSWE leaderboard](https://deepswe.datacurve.ai/) on 2026-10-07; no row is added to that table.
856
+
857
+ Artificial Analysis independently measures Haiku 5.5 Terminal-Bench-Science in its **with-fallback** configuration. Sources accessed 2026-10-07: effort-specific model pages for [max](https://artificialanalysis.ai/models/claude-haiku-5-5), [xhigh](https://artificialanalysis.ai/models/claude-haiku-5-5-xhigh), [high](https://artificialanalysis.ai/models/claude-haiku-5-5-high), [medium](https://artificialanalysis.ai/models/claude-haiku-5-5-medium), and [low](https://artificialanalysis.ai/models/claude-haiku-5-5-low), the [evaluation page](https://artificialanalysis.ai/evaluations/terminal-bench-science), and [AA's general methodology](https://artificialanalysis.ai/methodology/intelligence-benchmarking). That methodology specifies version 0.1.0, 70 tasks, mini-swe-agent, pass@1 averaged over three repeats, and a 1,000-step cap. These are AA's general settings, not a separately documented Haiku-specific harness revision. Evaluation run dates are unpublished; these are not Anthropic launch-table results.
858
+
845
859
  Key:
846
860
 
847
861
  - `DSWE`: DeepSWE v1.1, vendor-reported software-engineering results; distinct from Datacurve's independent table above.
848
862
  - `GDPpdf`: GDP.pdf All-pass, satisfying every criterion on professional-document tasks.
863
+ - `GDPElo`, `BriefElo`: GDPval-AA v2.1 and AA-Briefcase v1.1, raw Elo ratings.
864
+ - `OSW21`: OSWorld 2.1, computer-use workflows; the Haiku result covers the offline subset.
865
+ - `FC11`: FrontierCode 1.1 Main, weighted rubric score; distinct from all-blocking-criteria pass rate.
866
+ - `Chart`: Chartography, chart understanding without tools.
849
867
 
850
868
  - `ALE`: [Agents' Last Exam](https://agents-last-exam.org/), long-horizon professional tasks in real software, from financial modeling to engineering and media production.
851
869
  - `OSW2`, `OSW2s`: [OSWorld 2.0](https://osworld-v2.xlang.ai/), long-horizon computer-use workflows operating desktop applications through the screen; partial credit and strict all-pass scoring.
@@ -864,6 +882,19 @@ Key:
864
882
 
865
883
  | slug | Model | Benchmark | Score | Setting | Source |
866
884
  | --- | --- | --- | ---: | --- | --- |
885
+ | claude-haiku-5-5 | Claude Haiku 5.5 | GDPElo | 1620 | v2.1; raw Elo; effort not stated | Anthropic |
886
+ | claude-haiku-5-5 | Claude Haiku 5.5 | BriefElo | 1578 | v1.1; raw Elo; effort not stated | Anthropic |
887
+ | claude-haiku-5-5 | Claude Haiku 5.5 | OSW21 | 72.4 | v2.1, offline subset; effort not stated | Anthropic |
888
+ | claude-haiku-5-5 | Claude Haiku 5.5 | HLE | 45.9 | no tools; effort not stated | Anthropic |
889
+ | claude-haiku-5-5 | Claude Haiku 5.5 | HLEt | 57.4 | with tools; effort not stated | Anthropic |
890
+ | claude-haiku-5-5 | Claude Haiku 5.5 | TB4 | 39.2 | v4.0; effort not stated | Anthropic |
891
+ | claude-haiku-5-5 | Claude Haiku 5.5 | FC11 | 46.4 | v1.1 Main; effort not stated in launch table | Anthropic |
892
+ | claude-haiku-5-5 | Claude Haiku 5.5 | Chart | 46.4 | no tools; effort not stated | Anthropic |
893
+ | claude-haiku-5-5 | Claude Haiku 5.5 | TBSci | 20.0 | max effort; with-fallback; AA general settings above | Artificial Analysis |
894
+ | claude-haiku-5-5-xhigh | Claude Haiku 5.5 | TBSci | 18.1 | xhigh effort; with-fallback; AA general settings above | Artificial Analysis |
895
+ | claude-haiku-5-5-high | Claude Haiku 5.5 | TBSci | 10.0 | high effort; with-fallback; AA general settings above | Artificial Analysis |
896
+ | claude-haiku-5-5-medium | Claude Haiku 5.5 | TBSci | 7.1 | medium effort; with-fallback; AA general settings above | Artificial Analysis |
897
+ | claude-haiku-5-5-low | Claude Haiku 5.5 | TBSci | 1.9 | low effort; with-fallback; AA general settings above | Artificial Analysis |
867
898
  | gpt-6-1-sol | GPT-6.1 Sol | TBSci | 58.1 | max effort; v0.1.0, 70 tasks, mini-swe-agent, pass@1 over 3 repeats, 1000-step cap | Artificial Analysis |
868
899
  | gpt-6-1-sol-low | GPT-6.1 Sol | DSWE | 64.4 | low effort; v1.1; OpenAI-reported, harness not stated | OpenAI |
869
900
  | gpt-6-1-sol-medium | GPT-6.1 Sol | DSWE | 73 | medium effort; v1.1; OpenAI-reported, harness not stated | OpenAI |
package/docs/models.md CHANGED
@@ -21,6 +21,16 @@ This page shows minimal and full `models.json` examples you can copy. Every fiel
21
21
 
22
22
  For choosing which model to use rather than how to declare one, see [Model selection](/models/model-selection).
23
23
 
24
+ ## Use classifier models
25
+
26
+ Classifier models answer typed questions about JSON state instead of chatting. They do not appear in `/model`. Enable [codemode](/tools#codemode), list them with `models.getAvailableOfType("classifier")`, and call `models.classify(model, { state, questions })`. See [Codemode](/codemode#classify) for question and answer shapes.
27
+
28
+ OpenAI's GPT-6 Luna Decisions classifier is `openai-decisions/gpt-6-luna`. It uses the [Decisions API](https://developers.openai.com/api/docs/guides/decisions) and needs an API key, either from `OPENAI_API_KEY` or saved with `/login openai-decisions`. ChatGPT sign-in does not work with it. The provider has its own credential, so you can sign in with ChatGPT on `openai` and still use the classifier. `openai/gpt-6-luna` always means the chat model.
29
+
30
+ GPT-6 Luna accepts up to 128 image blocks through `images`, alongside the JSON state. Other classifiers reject images unless their catalog input and API support them. Refused answers produce an error result. The endpoint rejects inputs above 922K tokens; very large inputs, currently above roughly 600K tokens, can hit its gateway time limit. These 504 responses are not retried, so reduce the input before trying again.
31
+
32
+ TypeSafe Jev and Cloudflare Clef classifiers are also available through their providers. [Local llama.cpp models](/llama-cpp#classification) support native decision models and a next-token-probability fallback for chat models.
33
+
24
34
  ## Table of Contents
25
35
 
26
36
  - [Minimal Example](/models#minimal-example)