@clawpump/claw-agent 0.1.5 → 0.1.6

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 (1212) hide show
  1. package/agent/.dockerignore +67 -0
  2. package/agent/.envrc +1 -1
  3. package/agent/.gitattributes +8 -0
  4. package/agent/AGENTS.md +216 -4
  5. package/agent/CONTRIBUTING.md +46 -8
  6. package/agent/Dockerfile +78 -35
  7. package/agent/MANIFEST.in +2 -0
  8. package/agent/README.md +12 -5
  9. package/agent/README.ur-pk.md +261 -0
  10. package/agent/README.zh-CN.md +11 -8
  11. package/agent/SECURITY.md +5 -4
  12. package/agent/acp_adapter/provenance.py +127 -0
  13. package/agent/acp_adapter/server.py +112 -5
  14. package/agent/acp_adapter/session.py +1 -6
  15. package/agent/acp_registry/agent.json +2 -2
  16. package/agent/agent/account_usage.py +313 -1
  17. package/agent/agent/agent_init.py +140 -37
  18. package/agent/agent/agent_runtime_helpers.py +342 -83
  19. package/agent/agent/anthropic_adapter.py +320 -33
  20. package/agent/agent/auxiliary_client.py +525 -105
  21. package/agent/agent/background_review.py +157 -19
  22. package/agent/agent/bedrock_adapter.py +71 -6
  23. package/agent/agent/billing_view.py +295 -0
  24. package/agent/agent/chat_completion_helpers.py +229 -4
  25. package/agent/agent/codex_responses_adapter.py +86 -10
  26. package/agent/agent/codex_runtime.py +153 -1
  27. package/agent/agent/coding_context.py +738 -0
  28. package/agent/agent/context_compressor.py +392 -44
  29. package/agent/agent/context_references.py +34 -1
  30. package/agent/agent/conversation_compression.py +159 -22
  31. package/agent/agent/conversation_loop.py +643 -908
  32. package/agent/agent/copilot_acp_client.py +4 -11
  33. package/agent/agent/credential_pool.py +5 -3
  34. package/agent/agent/credits_tracker.py +794 -0
  35. package/agent/agent/curator.py +91 -18
  36. package/agent/agent/curator_backup.py +26 -10
  37. package/agent/agent/display.py +42 -1
  38. package/agent/agent/error_classifier.py +52 -3
  39. package/agent/agent/errors.py +3 -0
  40. package/agent/agent/file_safety.py +0 -17
  41. package/agent/agent/gemini_native_adapter.py +31 -1
  42. package/agent/agent/i18n.py +48 -4
  43. package/agent/agent/image_gen_provider.py +74 -5
  44. package/agent/agent/image_routing.py +29 -0
  45. package/agent/agent/insights.py +8 -17
  46. package/agent/agent/lsp/install.py +3 -0
  47. package/agent/agent/memory_manager.py +326 -31
  48. package/agent/agent/message_content.py +50 -0
  49. package/agent/agent/model_metadata.py +214 -3
  50. package/agent/agent/moonshot_schema.py +8 -1
  51. package/agent/agent/onboarding.py +60 -0
  52. package/agent/agent/prompt_builder.py +327 -37
  53. package/agent/agent/redact.py +1 -0
  54. package/agent/agent/runtime_cwd.py +34 -5
  55. package/agent/agent/secret_scope.py +205 -0
  56. package/agent/agent/secret_sources/bitwarden.py +34 -2
  57. package/agent/agent/skill_commands.py +90 -1
  58. package/agent/agent/skill_preprocessing.py +1 -0
  59. package/agent/agent/skill_utils.py +209 -36
  60. package/agent/agent/ssl_guard.py +94 -0
  61. package/agent/agent/system_prompt.py +133 -5
  62. package/agent/agent/tool_executor.py +496 -70
  63. package/agent/agent/transports/anthropic.py +83 -21
  64. package/agent/agent/transports/chat_completions.py +94 -5
  65. package/agent/agent/transports/codex.py +67 -2
  66. package/agent/agent/transports/codex_app_server.py +1 -0
  67. package/agent/agent/transports/codex_app_server_session.py +30 -0
  68. package/agent/agent/transports/types.py +12 -0
  69. package/agent/agent/turn_context.py +408 -0
  70. package/agent/agent/turn_finalizer.py +428 -0
  71. package/agent/agent/turn_retry_state.py +68 -0
  72. package/agent/agent/usage_pricing.py +3 -0
  73. package/agent/apps/bootstrap-installer/package.json +6 -5
  74. package/agent/apps/bootstrap-installer/src/routes/failure.tsx +12 -5
  75. package/agent/apps/bootstrap-installer/src/routes/progress.tsx +1 -3
  76. package/agent/apps/bootstrap-installer/src/store.ts +3 -2
  77. package/agent/apps/bootstrap-installer/src-tauri/src/bootstrap.rs +172 -7
  78. package/agent/apps/bootstrap-installer/src-tauri/src/events.rs +14 -1
  79. package/agent/apps/bootstrap-installer/src-tauri/src/paths.rs +29 -0
  80. package/agent/apps/bootstrap-installer/src-tauri/src/powershell.rs +93 -3
  81. package/agent/apps/bootstrap-installer/src-tauri/src/update.rs +695 -39
  82. package/agent/apps/bootstrap-installer/tsconfig.json +3 -4
  83. package/agent/apps/desktop/DESIGN.md +167 -0
  84. package/agent/apps/desktop/README.md +20 -16
  85. package/agent/apps/desktop/assets/icon.icns +0 -0
  86. package/agent/apps/desktop/assets/icon.ico +0 -0
  87. package/agent/apps/desktop/assets/icon.png +0 -0
  88. package/agent/apps/desktop/electron/backend-env.cjs +112 -0
  89. package/agent/apps/desktop/electron/backend-env.test.cjs +111 -0
  90. package/agent/apps/desktop/electron/backend-probes.test.cjs +3 -1
  91. package/agent/apps/desktop/electron/backend-ready.cjs +66 -0
  92. package/agent/apps/desktop/electron/bootstrap-platform.cjs +52 -0
  93. package/agent/apps/desktop/electron/bootstrap-platform.test.cjs +59 -1
  94. package/agent/apps/desktop/electron/bootstrap-runner.cjs +176 -38
  95. package/agent/apps/desktop/electron/bootstrap-runner.test.cjs +112 -1
  96. package/agent/apps/desktop/electron/connection-config.cjs +288 -0
  97. package/agent/apps/desktop/electron/connection-config.test.cjs +396 -0
  98. package/agent/apps/desktop/electron/dashboard-token.cjs +99 -0
  99. package/agent/apps/desktop/electron/dashboard-token.test.cjs +142 -0
  100. package/agent/apps/desktop/electron/desktop-uninstall.cjs +232 -0
  101. package/agent/apps/desktop/electron/desktop-uninstall.test.cjs +246 -0
  102. package/agent/apps/desktop/electron/entitlements.mac.inherit.plist +2 -0
  103. package/agent/apps/desktop/electron/fs-read-dir.cjs +109 -0
  104. package/agent/apps/desktop/electron/fs-read-dir.test.cjs +364 -0
  105. package/agent/apps/desktop/electron/gateway-ws-probe.cjs +188 -0
  106. package/agent/apps/desktop/electron/gateway-ws-probe.test.cjs +122 -0
  107. package/agent/apps/desktop/electron/git-root.cjs +54 -0
  108. package/agent/apps/desktop/electron/git-root.test.cjs +40 -0
  109. package/agent/apps/desktop/electron/git-worktrees.cjs +174 -0
  110. package/agent/apps/desktop/electron/hardening.cjs +123 -28
  111. package/agent/apps/desktop/electron/hardening.test.cjs +163 -0
  112. package/agent/apps/desktop/electron/main.cjs +3121 -331
  113. package/agent/apps/desktop/electron/oauth-net-request.cjs +20 -0
  114. package/agent/apps/desktop/electron/oauth-net-request.test.cjs +34 -0
  115. package/agent/apps/desktop/electron/preload.cjs +52 -2
  116. package/agent/apps/desktop/electron/session-windows.cjs +124 -0
  117. package/agent/apps/desktop/electron/session-windows.test.cjs +199 -0
  118. package/agent/apps/desktop/electron/update-rebuild.cjs +29 -0
  119. package/agent/apps/desktop/electron/update-rebuild.test.cjs +55 -0
  120. package/agent/apps/desktop/electron/update-remote.cjs +56 -0
  121. package/agent/apps/desktop/electron/update-remote.test.cjs +78 -0
  122. package/agent/apps/desktop/electron/vscode-marketplace.cjs +331 -0
  123. package/agent/apps/desktop/electron/vscode-marketplace.test.cjs +113 -0
  124. package/agent/apps/desktop/electron/windows-child-process.test.cjs +57 -0
  125. package/agent/apps/desktop/electron/windows-user-env.cjs +76 -0
  126. package/agent/apps/desktop/electron/windows-user-env.test.cjs +90 -0
  127. package/agent/apps/desktop/electron/workspace-cwd.cjs +38 -0
  128. package/agent/apps/desktop/electron/workspace-cwd.test.cjs +45 -0
  129. package/agent/apps/desktop/eslint.config.mjs +0 -3
  130. package/agent/apps/desktop/index.html +27 -2
  131. package/agent/apps/desktop/package.json +31 -11
  132. package/agent/apps/desktop/pr-assets/session-source-folders.png +0 -0
  133. package/agent/apps/desktop/public/apple-touch-icon.png +0 -0
  134. package/agent/apps/desktop/public/nous-girl.jpg +0 -0
  135. package/agent/apps/desktop/scripts/assert-dist-built.cjs +70 -0
  136. package/agent/apps/desktop/scripts/assert-dist-built.test.cjs +84 -0
  137. package/agent/apps/desktop/scripts/before-pack.cjs +78 -0
  138. package/agent/apps/desktop/scripts/before-pack.test.cjs +53 -0
  139. package/agent/apps/desktop/scripts/diag-scroll-reset.mjs +229 -0
  140. package/agent/apps/desktop/scripts/patch-electron-builder-mac-binary.cjs +64 -0
  141. package/agent/apps/desktop/scripts/run-electron-builder.cjs +57 -0
  142. package/agent/apps/desktop/src/app/agents/index.tsx +53 -45
  143. package/agent/apps/desktop/src/app/artifacts/index.tsx +102 -83
  144. package/agent/apps/desktop/src/app/chat/chat-drop-overlay.tsx +29 -8
  145. package/agent/apps/desktop/src/app/chat/chat-swap-overlay.tsx +47 -0
  146. package/agent/apps/desktop/src/app/chat/composer/attachments.tsx +81 -45
  147. package/agent/apps/desktop/src/app/chat/composer/completion-drawer.tsx +13 -24
  148. package/agent/apps/desktop/src/app/chat/composer/context-menu.tsx +138 -88
  149. package/agent/apps/desktop/src/app/chat/composer/controls.tsx +138 -90
  150. package/agent/apps/desktop/src/app/chat/composer/enter-submit-dom-race.test.tsx +218 -0
  151. package/agent/apps/desktop/src/app/chat/composer/focus.ts +32 -0
  152. package/agent/apps/desktop/src/app/chat/composer/help-hint.tsx +38 -25
  153. package/agent/apps/desktop/src/app/chat/composer/hooks/use-live-completion-adapter.ts +7 -0
  154. package/agent/apps/desktop/src/app/chat/composer/hooks/use-mic-recorder.ts +22 -12
  155. package/agent/apps/desktop/src/app/chat/composer/hooks/use-slash-completions.ts +142 -14
  156. package/agent/apps/desktop/src/app/chat/composer/hooks/use-voice-conversation.ts +14 -11
  157. package/agent/apps/desktop/src/app/chat/composer/hooks/use-voice-recorder.ts +9 -6
  158. package/agent/apps/desktop/src/app/chat/composer/ime-composition-dom-repro.test.tsx +108 -0
  159. package/agent/apps/desktop/src/app/chat/composer/index.tsx +930 -180
  160. package/agent/apps/desktop/src/app/chat/composer/inline-refs.ts +136 -32
  161. package/agent/apps/desktop/src/app/chat/composer/model-pill.tsx +86 -0
  162. package/agent/apps/desktop/src/app/chat/composer/queue-panel.tsx +54 -75
  163. package/agent/apps/desktop/src/app/chat/composer/rich-editor.test.ts +117 -1
  164. package/agent/apps/desktop/src/app/chat/composer/rich-editor.ts +117 -6
  165. package/agent/apps/desktop/src/app/chat/composer/slash-nav-dom-repro.test.tsx +186 -0
  166. package/agent/apps/desktop/src/app/chat/composer/status-stack/index.tsx +202 -0
  167. package/agent/apps/desktop/src/app/chat/composer/status-stack/status-row.tsx +155 -0
  168. package/agent/apps/desktop/src/app/chat/composer/text-utils.test.ts +104 -0
  169. package/agent/apps/desktop/src/app/chat/composer/text-utils.ts +37 -9
  170. package/agent/apps/desktop/src/app/chat/composer/trigger-popover.test.tsx +50 -0
  171. package/agent/apps/desktop/src/app/chat/composer/trigger-popover.tsx +105 -40
  172. package/agent/apps/desktop/src/app/chat/composer/types.ts +5 -0
  173. package/agent/apps/desktop/src/app/chat/composer/url-dialog.tsx +11 -15
  174. package/agent/apps/desktop/src/app/chat/composer/voice-activity.tsx +8 -4
  175. package/agent/apps/desktop/src/app/chat/hooks/use-composer-actions.test.ts +57 -0
  176. package/agent/apps/desktop/src/app/chat/hooks/use-composer-actions.ts +70 -16
  177. package/agent/apps/desktop/src/app/chat/hooks/use-file-drop-zone.ts +52 -16
  178. package/agent/apps/desktop/src/app/chat/index.tsx +234 -81
  179. package/agent/apps/desktop/src/app/chat/perf-probe.tsx +69 -21
  180. package/agent/apps/desktop/src/app/chat/right-rail/preview-console.tsx +44 -40
  181. package/agent/apps/desktop/src/app/chat/right-rail/preview-file.tsx +71 -25
  182. package/agent/apps/desktop/src/app/chat/right-rail/preview-pane.test.tsx +40 -1
  183. package/agent/apps/desktop/src/app/chat/right-rail/preview-pane.tsx +55 -53
  184. package/agent/apps/desktop/src/app/chat/right-rail/preview.tsx +35 -17
  185. package/agent/apps/desktop/src/app/chat/scroll-to-bottom-button.test.tsx +67 -0
  186. package/agent/apps/desktop/src/app/chat/scroll-to-bottom-button.tsx +74 -0
  187. package/agent/apps/desktop/src/app/chat/sidebar/cron-jobs-section.tsx +356 -0
  188. package/agent/apps/desktop/src/app/chat/sidebar/index.tsx +1189 -364
  189. package/agent/apps/desktop/src/app/chat/sidebar/load-more-row.tsx +30 -0
  190. package/agent/apps/desktop/src/app/chat/sidebar/order.test.ts +21 -0
  191. package/agent/apps/desktop/src/app/chat/sidebar/order.ts +17 -0
  192. package/agent/apps/desktop/src/app/chat/sidebar/profile-switcher.tsx +524 -0
  193. package/agent/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx +80 -45
  194. package/agent/apps/desktop/src/app/chat/sidebar/session-row.tsx +120 -25
  195. package/agent/apps/desktop/src/app/chat/sidebar/virtual-session-list.tsx +7 -13
  196. package/agent/apps/desktop/src/app/chat/sidebar/workspace-groups.test.ts +149 -0
  197. package/agent/apps/desktop/src/app/chat/sidebar/workspace-groups.ts +326 -0
  198. package/agent/apps/desktop/src/app/chat/thread-loading.ts +7 -2
  199. package/agent/apps/desktop/src/app/command-center/index.tsx +320 -581
  200. package/agent/apps/desktop/src/app/command-palette/index.tsx +681 -0
  201. package/agent/apps/desktop/src/app/command-palette/marketplace-theme-page.tsx +157 -0
  202. package/agent/apps/desktop/src/app/cron/index.tsx +392 -324
  203. package/agent/apps/desktop/src/app/cron/job-state.ts +29 -0
  204. package/agent/apps/desktop/src/app/desktop-controller.tsx +618 -123
  205. package/agent/apps/desktop/src/app/floating-hud.ts +22 -0
  206. package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-boot.test.tsx +265 -0
  207. package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-boot.ts +260 -14
  208. package/agent/apps/desktop/src/app/gateway/hooks/use-gateway-request.ts +48 -4
  209. package/agent/apps/desktop/src/app/hooks/use-keybinds.ts +270 -0
  210. package/agent/apps/desktop/src/app/hooks/use-refresh-hotkey.ts +45 -0
  211. package/agent/apps/desktop/src/app/layout-constants.ts +19 -0
  212. package/agent/apps/desktop/src/app/messaging/index.tsx +136 -241
  213. package/agent/apps/desktop/src/app/messaging/platform-icon.tsx +95 -0
  214. package/agent/apps/desktop/src/app/model-visibility-overlay.tsx +31 -0
  215. package/agent/apps/desktop/src/app/overlays/overlay-search-input.tsx +18 -62
  216. package/agent/apps/desktop/src/app/overlays/overlay-split-layout.tsx +59 -7
  217. package/agent/apps/desktop/src/app/overlays/overlay-view.tsx +9 -5
  218. package/agent/apps/desktop/src/app/page-search-shell.tsx +42 -20
  219. package/agent/apps/desktop/src/app/profiles/create-profile-dialog.tsx +165 -0
  220. package/agent/apps/desktop/src/app/profiles/delete-profile-dialog.tsx +65 -0
  221. package/agent/apps/desktop/src/app/profiles/index.tsx +174 -199
  222. package/agent/apps/desktop/src/app/profiles/rename-profile-dialog.tsx +125 -0
  223. package/agent/apps/desktop/src/app/right-sidebar/files/dnd-manager.ts +27 -0
  224. package/agent/apps/desktop/src/app/right-sidebar/files/ipc.test.ts +100 -0
  225. package/agent/apps/desktop/src/app/right-sidebar/files/ipc.ts +12 -18
  226. package/agent/apps/desktop/src/app/right-sidebar/files/remote-picker.tsx +177 -0
  227. package/agent/apps/desktop/src/app/right-sidebar/files/tree.tsx +35 -21
  228. package/agent/apps/desktop/src/app/right-sidebar/files/use-project-tree.test.ts +75 -3
  229. package/agent/apps/desktop/src/app/right-sidebar/files/use-project-tree.ts +152 -5
  230. package/agent/apps/desktop/src/app/right-sidebar/index.test.tsx +75 -0
  231. package/agent/apps/desktop/src/app/right-sidebar/index.tsx +166 -129
  232. package/agent/apps/desktop/src/app/right-sidebar/store.ts +19 -4
  233. package/agent/apps/desktop/src/app/right-sidebar/terminal/buffer.ts +65 -0
  234. package/agent/apps/desktop/src/app/right-sidebar/terminal/index.tsx +29 -34
  235. package/agent/apps/desktop/src/app/right-sidebar/terminal/persistent.tsx +18 -6
  236. package/agent/apps/desktop/src/app/right-sidebar/terminal/selection.ts +93 -32
  237. package/agent/apps/desktop/src/app/right-sidebar/terminal/use-terminal-session.ts +381 -119
  238. package/agent/apps/desktop/src/app/routes.ts +9 -0
  239. package/agent/apps/desktop/src/app/session/hooks/use-cwd-actions.ts +17 -7
  240. package/agent/apps/desktop/src/app/session/hooks/use-message-stream.ts +365 -47
  241. package/agent/apps/desktop/src/app/session/hooks/use-model-controls.test.tsx +198 -0
  242. package/agent/apps/desktop/src/app/session/hooks/use-model-controls.ts +70 -34
  243. package/agent/apps/desktop/src/app/session/hooks/use-prompt-actions.test.tsx +1061 -0
  244. package/agent/apps/desktop/src/app/session/hooks/use-prompt-actions.ts +1143 -165
  245. package/agent/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx +341 -2
  246. package/agent/apps/desktop/src/app/session/hooks/use-route-resume.ts +176 -5
  247. package/agent/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx +259 -0
  248. package/agent/apps/desktop/src/app/session/hooks/use-session-actions.ts +452 -149
  249. package/agent/apps/desktop/src/app/session/hooks/use-session-state-cache.test.tsx +327 -0
  250. package/agent/apps/desktop/src/app/session/hooks/use-session-state-cache.ts +133 -4
  251. package/agent/apps/desktop/src/app/session-picker-overlay.tsx +32 -0
  252. package/agent/apps/desktop/src/app/session-switcher.tsx +107 -0
  253. package/agent/apps/desktop/src/app/settings/about-settings.tsx +45 -36
  254. package/agent/apps/desktop/src/app/settings/appearance-settings.tsx +243 -162
  255. package/agent/apps/desktop/src/app/settings/config-settings.tsx +86 -66
  256. package/agent/apps/desktop/src/app/settings/constants.ts +459 -122
  257. package/agent/apps/desktop/src/app/settings/credential-key-ui.tsx +373 -0
  258. package/agent/apps/desktop/src/app/settings/env-credentials.tsx +198 -0
  259. package/agent/apps/desktop/src/app/settings/env-var-actions-menu.tsx +136 -0
  260. package/agent/apps/desktop/src/app/settings/field-copy.ts +56 -0
  261. package/agent/apps/desktop/src/app/settings/gateway-settings.tsx +385 -72
  262. package/agent/apps/desktop/src/app/settings/helpers.test.ts +156 -1
  263. package/agent/apps/desktop/src/app/settings/helpers.ts +30 -2
  264. package/agent/apps/desktop/src/app/settings/index.tsx +118 -84
  265. package/agent/apps/desktop/src/app/settings/keys-settings.tsx +62 -419
  266. package/agent/apps/desktop/src/app/settings/mcp-settings.tsx +65 -60
  267. package/agent/apps/desktop/src/app/settings/model-settings.test.tsx +129 -5
  268. package/agent/apps/desktop/src/app/settings/model-settings.tsx +370 -65
  269. package/agent/apps/desktop/src/app/settings/notifications-settings.tsx +150 -0
  270. package/agent/apps/desktop/src/app/settings/primitives.tsx +5 -11
  271. package/agent/apps/desktop/src/app/settings/provider-config-panel.test.tsx +142 -0
  272. package/agent/apps/desktop/src/app/settings/provider-config-panel.tsx +182 -0
  273. package/agent/apps/desktop/src/app/settings/providers-settings.test.tsx +171 -0
  274. package/agent/apps/desktop/src/app/settings/providers-settings.tsx +471 -0
  275. package/agent/apps/desktop/src/app/settings/sessions-settings.tsx +183 -71
  276. package/agent/apps/desktop/src/app/settings/toolset-config-panel.test.tsx +135 -1
  277. package/agent/apps/desktop/src/app/settings/toolset-config-panel.tsx +180 -57
  278. package/agent/apps/desktop/src/app/settings/types.ts +9 -6
  279. package/agent/apps/desktop/src/app/settings/uninstall-section.tsx +185 -0
  280. package/agent/apps/desktop/src/app/settings/use-deep-link-highlight.ts +60 -0
  281. package/agent/apps/desktop/src/app/shell/app-shell.tsx +59 -13
  282. package/agent/apps/desktop/src/app/shell/gateway-menu-panel.tsx +37 -32
  283. package/agent/apps/desktop/src/app/shell/hooks/use-overlay-routing.ts +6 -3
  284. package/agent/apps/desktop/src/app/shell/hooks/use-statusbar-items.tsx +212 -53
  285. package/agent/apps/desktop/src/app/shell/keybind-panel.tsx +215 -0
  286. package/agent/apps/desktop/src/app/shell/model-edit-submenu.test.tsx +84 -0
  287. package/agent/apps/desktop/src/app/shell/model-edit-submenu.tsx +244 -0
  288. package/agent/apps/desktop/src/app/shell/model-menu-panel.tsx +392 -0
  289. package/agent/apps/desktop/src/app/shell/statusbar-controls.tsx +23 -33
  290. package/agent/apps/desktop/src/app/shell/titlebar-controls.tsx +79 -95
  291. package/agent/apps/desktop/src/app/shell/titlebar.ts +8 -2
  292. package/agent/apps/desktop/src/app/skills/index.test.tsx +11 -0
  293. package/agent/apps/desktop/src/app/skills/index.tsx +79 -64
  294. package/agent/apps/desktop/src/app/types.ts +85 -0
  295. package/agent/apps/desktop/src/app/updates-overlay.tsx +110 -105
  296. package/agent/apps/desktop/src/components/assistant-ui/ansi-text.tsx +34 -0
  297. package/agent/apps/desktop/src/components/assistant-ui/block-direction.test.tsx +129 -0
  298. package/agent/apps/desktop/src/components/assistant-ui/clarify-tool.tsx +102 -81
  299. package/agent/apps/desktop/src/components/assistant-ui/directive-text.tsx +92 -15
  300. package/agent/apps/desktop/src/components/assistant-ui/markdown-text.test.ts +38 -0
  301. package/agent/apps/desktop/src/components/assistant-ui/markdown-text.tsx +304 -45
  302. package/agent/apps/desktop/src/components/assistant-ui/message-render-boundary.test.tsx +80 -0
  303. package/agent/apps/desktop/src/components/assistant-ui/message-render-boundary.tsx +48 -0
  304. package/agent/apps/desktop/src/components/assistant-ui/streaming.test.tsx +142 -90
  305. package/agent/apps/desktop/src/components/assistant-ui/thread-list.tsx +337 -0
  306. package/agent/apps/desktop/src/components/assistant-ui/thread.tsx +667 -190
  307. package/agent/apps/desktop/src/components/assistant-ui/tool-approval-group.test.tsx +299 -0
  308. package/agent/apps/desktop/src/components/assistant-ui/tool-approval.test.tsx +133 -0
  309. package/agent/apps/desktop/src/components/assistant-ui/tool-approval.tsx +239 -0
  310. package/agent/apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts +31 -0
  311. package/agent/apps/desktop/src/components/assistant-ui/tool-fallback-model.ts +152 -134
  312. package/agent/apps/desktop/src/components/assistant-ui/tool-fallback.tsx +142 -150
  313. package/agent/apps/desktop/src/components/assistant-ui/tooltip-icon-button.tsx +14 -12
  314. package/agent/apps/desktop/src/components/assistant-ui/user-message-edit.test.tsx +141 -0
  315. package/agent/apps/desktop/src/components/assistant-ui/user-message-text.tsx +152 -0
  316. package/agent/apps/desktop/src/components/boot-failure-overlay.tsx +150 -33
  317. package/agent/apps/desktop/src/components/boot-failure-reauth.test.ts +100 -0
  318. package/agent/apps/desktop/src/components/boot-failure-reauth.ts +81 -0
  319. package/agent/apps/desktop/src/components/brand-mark.tsx +19 -0
  320. package/agent/apps/desktop/src/components/chat/code-card.tsx +1 -1
  321. package/agent/apps/desktop/src/components/chat/composer-dock.ts +31 -0
  322. package/agent/apps/desktop/src/components/chat/diff-lines.tsx +1 -1
  323. package/agent/apps/desktop/src/components/chat/disclosure-row.tsx +13 -3
  324. package/agent/apps/desktop/src/components/chat/expandable-block.tsx +52 -0
  325. package/agent/apps/desktop/src/components/chat/generated-image-result.tsx +174 -0
  326. package/agent/apps/desktop/src/components/chat/image-generation-placeholder.tsx +70 -37
  327. package/agent/apps/desktop/src/components/chat/intro.tsx +8 -7
  328. package/agent/apps/desktop/src/components/chat/preview-attachment.tsx +4 -2
  329. package/agent/apps/desktop/src/components/chat/shiki-highlighter.test.ts +37 -0
  330. package/agent/apps/desktop/src/components/chat/shiki-highlighter.tsx +96 -22
  331. package/agent/apps/desktop/src/components/chat/status-row.tsx +70 -0
  332. package/agent/apps/desktop/src/components/chat/status-section.tsx +42 -0
  333. package/agent/apps/desktop/src/components/chat/terminal-output.tsx +54 -0
  334. package/agent/apps/desktop/src/components/chat/zoomable-image.tsx +70 -109
  335. package/agent/apps/desktop/src/components/desktop-install-overlay.tsx +154 -84
  336. package/agent/apps/desktop/src/components/desktop-onboarding-overlay.test.tsx +38 -8
  337. package/agent/apps/desktop/src/components/desktop-onboarding-overlay.tsx +789 -233
  338. package/agent/apps/desktop/src/components/error-boundary.tsx +77 -0
  339. package/agent/apps/desktop/src/components/gateway-connecting-overlay.test.tsx +144 -0
  340. package/agent/apps/desktop/src/components/gateway-connecting-overlay.tsx +7 -1
  341. package/agent/apps/desktop/src/components/haptics-provider.tsx +24 -0
  342. package/agent/apps/desktop/src/components/language-switcher.test.tsx +53 -0
  343. package/agent/apps/desktop/src/components/language-switcher.tsx +175 -0
  344. package/agent/apps/desktop/src/components/model-picker.tsx +42 -40
  345. package/agent/apps/desktop/src/components/model-visibility-dialog.tsx +166 -0
  346. package/agent/apps/desktop/src/components/notifications.tsx +48 -27
  347. package/agent/apps/desktop/src/components/pane-shell/index.ts +1 -1
  348. package/agent/apps/desktop/src/components/pane-shell/pane-shell.tsx +146 -9
  349. package/agent/apps/desktop/src/components/prompt-overlays.tsx +234 -0
  350. package/agent/apps/desktop/src/components/session-picker.tsx +108 -0
  351. package/agent/apps/desktop/src/components/ui/action-status.tsx +25 -0
  352. package/agent/apps/desktop/src/components/ui/badge.tsx +35 -0
  353. package/agent/apps/desktop/src/components/ui/button.tsx +37 -13
  354. package/agent/apps/desktop/src/components/ui/confirm-dialog.tsx +109 -0
  355. package/agent/apps/desktop/src/components/ui/control.ts +25 -0
  356. package/agent/apps/desktop/src/components/ui/copy-button.test.tsx +36 -0
  357. package/agent/apps/desktop/src/components/ui/copy-button.tsx +38 -27
  358. package/agent/apps/desktop/src/components/ui/dialog.tsx +39 -11
  359. package/agent/apps/desktop/src/components/ui/dropdown-menu.tsx +98 -24
  360. package/agent/apps/desktop/src/components/ui/error-state.tsx +50 -0
  361. package/agent/apps/desktop/src/components/ui/fade-text.tsx +9 -2
  362. package/agent/apps/desktop/src/components/ui/{braille-spinner.tsx → glyph-spinner.tsx} +15 -13
  363. package/agent/apps/desktop/src/components/ui/input.tsx +5 -2
  364. package/agent/apps/desktop/src/components/ui/kbd.tsx +83 -12
  365. package/agent/apps/desktop/src/components/ui/log-view.tsx +19 -0
  366. package/agent/apps/desktop/src/components/ui/pagination.tsx +12 -5
  367. package/agent/apps/desktop/src/components/ui/popover.tsx +44 -0
  368. package/agent/apps/desktop/src/components/ui/search-field.tsx +80 -0
  369. package/agent/apps/desktop/src/components/ui/segmented-control.tsx +51 -0
  370. package/agent/apps/desktop/src/components/ui/select.tsx +10 -3
  371. package/agent/apps/desktop/src/components/ui/sheet.tsx +8 -2
  372. package/agent/apps/desktop/src/components/ui/sidebar.tsx +18 -25
  373. package/agent/apps/desktop/src/components/ui/switch.tsx +38 -15
  374. package/agent/apps/desktop/src/components/ui/textarea.tsx +4 -11
  375. package/agent/apps/desktop/src/components/ui/tool-icon.tsx +65 -0
  376. package/agent/apps/desktop/src/components/ui/tooltip.tsx +31 -4
  377. package/agent/apps/desktop/src/fonts/JetBrainsMono-Bold.woff2 +0 -0
  378. package/agent/apps/desktop/src/fonts/JetBrainsMono-Italic.woff2 +0 -0
  379. package/agent/apps/desktop/src/fonts/JetBrainsMono-Regular.woff2 +0 -0
  380. package/agent/apps/desktop/src/global.d.ts +181 -4
  381. package/agent/apps/desktop/src/hermes.test.ts +60 -0
  382. package/agent/apps/desktop/src/hermes.ts +190 -13
  383. package/agent/apps/desktop/src/hooks/use-image-download.ts +85 -0
  384. package/agent/apps/desktop/src/hooks/use-resize-observer.ts +13 -4
  385. package/agent/apps/desktop/src/hooks/use-worktree-info.ts +68 -0
  386. package/agent/apps/desktop/src/i18n/catalog.ts +12 -0
  387. package/agent/apps/desktop/src/i18n/context.test.tsx +232 -0
  388. package/agent/apps/desktop/src/i18n/context.tsx +183 -0
  389. package/agent/apps/desktop/src/i18n/define-locale.ts +41 -0
  390. package/agent/apps/desktop/src/i18n/en.ts +1921 -0
  391. package/agent/apps/desktop/src/i18n/index.ts +20 -0
  392. package/agent/apps/desktop/src/i18n/ja.ts +2053 -0
  393. package/agent/apps/desktop/src/i18n/languages.test.ts +43 -0
  394. package/agent/apps/desktop/src/i18n/languages.ts +86 -0
  395. package/agent/apps/desktop/src/i18n/runtime.test.ts +75 -0
  396. package/agent/apps/desktop/src/i18n/runtime.ts +53 -0
  397. package/agent/apps/desktop/src/i18n/types.ts +1559 -0
  398. package/agent/apps/desktop/src/i18n/zh-hant.ts +1992 -0
  399. package/agent/apps/desktop/src/i18n/zh.ts +2099 -0
  400. package/agent/apps/desktop/src/lib/ansi.test.ts +123 -0
  401. package/agent/apps/desktop/src/lib/ansi.ts +186 -0
  402. package/agent/apps/desktop/src/lib/chat-messages.test.ts +79 -0
  403. package/agent/apps/desktop/src/lib/chat-messages.ts +68 -29
  404. package/agent/apps/desktop/src/lib/chat-runtime.test.ts +65 -1
  405. package/agent/apps/desktop/src/lib/chat-runtime.ts +39 -3
  406. package/agent/apps/desktop/src/lib/completion-sound.ts +519 -0
  407. package/agent/apps/desktop/src/lib/desktop-fs.test.ts +116 -0
  408. package/agent/apps/desktop/src/lib/desktop-fs.ts +113 -0
  409. package/agent/apps/desktop/src/lib/desktop-slash-commands.test.ts +89 -6
  410. package/agent/apps/desktop/src/lib/desktop-slash-commands.ts +270 -131
  411. package/agent/apps/desktop/src/lib/external-link.test.tsx +27 -0
  412. package/agent/apps/desktop/src/lib/external-link.tsx +9 -2
  413. package/agent/apps/desktop/src/lib/gateway-events.test.ts +27 -0
  414. package/agent/apps/desktop/src/lib/gateway-events.ts +16 -0
  415. package/agent/apps/desktop/src/lib/gateway-ws-url.test.ts +78 -0
  416. package/agent/apps/desktop/src/lib/gateway-ws-url.ts +91 -0
  417. package/agent/apps/desktop/src/lib/generated-images.test.ts +97 -0
  418. package/agent/apps/desktop/src/lib/generated-images.ts +116 -0
  419. package/agent/apps/desktop/src/lib/haptics.ts +17 -0
  420. package/agent/apps/desktop/src/lib/icons.ts +10 -2
  421. package/agent/apps/desktop/src/lib/keybinds/actions.ts +137 -0
  422. package/agent/apps/desktop/src/lib/keybinds/combo.test.ts +86 -0
  423. package/agent/apps/desktop/src/lib/keybinds/combo.ts +195 -0
  424. package/agent/apps/desktop/src/lib/local-preview.ts +23 -2
  425. package/agent/apps/desktop/src/lib/markdown-preprocess.ts +20 -7
  426. package/agent/apps/desktop/src/lib/media.remote.test.ts +90 -0
  427. package/agent/apps/desktop/src/lib/media.ts +40 -1
  428. package/agent/apps/desktop/src/lib/model-status-label.test.ts +59 -0
  429. package/agent/apps/desktop/src/lib/model-status-label.ts +122 -0
  430. package/agent/apps/desktop/src/lib/mutable-ref.ts +6 -0
  431. package/agent/apps/desktop/src/lib/profile-color.ts +58 -0
  432. package/agent/apps/desktop/src/lib/query-client.ts +13 -0
  433. package/agent/apps/desktop/src/lib/remend-tail.test.ts +105 -0
  434. package/agent/apps/desktop/src/lib/remend-tail.ts +108 -0
  435. package/agent/apps/desktop/src/lib/session-export.ts +6 -3
  436. package/agent/apps/desktop/src/lib/session-ids.test.ts +44 -0
  437. package/agent/apps/desktop/src/lib/session-ids.ts +26 -0
  438. package/agent/apps/desktop/src/lib/session-search.test.ts +66 -0
  439. package/agent/apps/desktop/src/lib/session-search.ts +21 -0
  440. package/agent/apps/desktop/src/lib/session-source.ts +126 -0
  441. package/agent/apps/desktop/src/lib/storage.test.ts +25 -0
  442. package/agent/apps/desktop/src/lib/storage.ts +35 -1
  443. package/agent/apps/desktop/src/lib/todos.test.ts +46 -1
  444. package/agent/apps/desktop/src/lib/todos.ts +37 -0
  445. package/agent/apps/desktop/src/lib/tool-result-summary.ts +5 -1
  446. package/agent/apps/desktop/src/lib/update-copy.test.ts +38 -0
  447. package/agent/apps/desktop/src/lib/update-copy.ts +44 -0
  448. package/agent/apps/desktop/src/lib/use-enter-animation.ts +2 -2
  449. package/agent/apps/desktop/src/lib/yolo-session.ts +50 -0
  450. package/agent/apps/desktop/src/main.tsx +19 -19
  451. package/agent/apps/desktop/src/store/boot.ts +4 -3
  452. package/agent/apps/desktop/src/store/clarify.test.ts +81 -0
  453. package/agent/apps/desktop/src/store/clarify.ts +50 -13
  454. package/agent/apps/desktop/src/store/command-palette.ts +20 -0
  455. package/agent/apps/desktop/src/store/compaction.test.ts +53 -0
  456. package/agent/apps/desktop/src/store/compaction.ts +38 -0
  457. package/agent/apps/desktop/src/store/completion-sound.ts +32 -0
  458. package/agent/apps/desktop/src/store/composer-input-history.test.ts +147 -0
  459. package/agent/apps/desktop/src/store/composer-input-history.ts +158 -0
  460. package/agent/apps/desktop/src/store/composer-queue.test.ts +68 -0
  461. package/agent/apps/desktop/src/store/composer-queue.ts +76 -0
  462. package/agent/apps/desktop/src/store/composer-status.test.ts +99 -0
  463. package/agent/apps/desktop/src/store/composer-status.ts +277 -0
  464. package/agent/apps/desktop/src/store/composer.test.ts +106 -0
  465. package/agent/apps/desktop/src/store/composer.ts +116 -0
  466. package/agent/apps/desktop/src/store/cron.ts +19 -0
  467. package/agent/apps/desktop/src/store/gateway.ts +280 -6
  468. package/agent/apps/desktop/src/store/keybinds.ts +143 -0
  469. package/agent/apps/desktop/src/store/layout.ts +107 -9
  470. package/agent/apps/desktop/src/store/model-presets.test.ts +51 -0
  471. package/agent/apps/desktop/src/store/model-presets.ts +86 -0
  472. package/agent/apps/desktop/src/store/model-visibility.test.ts +99 -0
  473. package/agent/apps/desktop/src/store/model-visibility.ts +161 -0
  474. package/agent/apps/desktop/src/store/native-notifications.test.ts +192 -0
  475. package/agent/apps/desktop/src/store/native-notifications.ts +203 -0
  476. package/agent/apps/desktop/src/store/notifications.ts +10 -7
  477. package/agent/apps/desktop/src/store/onboarding.test.ts +271 -1
  478. package/agent/apps/desktop/src/store/onboarding.ts +268 -38
  479. package/agent/apps/desktop/src/store/preview.ts +10 -1
  480. package/agent/apps/desktop/src/store/profile.test.ts +89 -0
  481. package/agent/apps/desktop/src/store/profile.ts +395 -0
  482. package/agent/apps/desktop/src/store/prompts.test.ts +127 -0
  483. package/agent/apps/desktop/src/store/prompts.ts +117 -0
  484. package/agent/apps/desktop/src/store/session-switcher.test.ts +115 -0
  485. package/agent/apps/desktop/src/store/session-switcher.ts +128 -0
  486. package/agent/apps/desktop/src/store/session-sync.ts +25 -0
  487. package/agent/apps/desktop/src/store/session.test.ts +268 -2
  488. package/agent/apps/desktop/src/store/session.ts +392 -18
  489. package/agent/apps/desktop/src/store/subagents.ts +3 -0
  490. package/agent/apps/desktop/src/store/system-actions.ts +48 -0
  491. package/agent/apps/desktop/src/store/thread-scroll.ts +58 -5
  492. package/agent/apps/desktop/src/store/todos.test.ts +47 -0
  493. package/agent/apps/desktop/src/store/todos.ts +64 -0
  494. package/agent/apps/desktop/src/store/tool-dismiss.ts +45 -0
  495. package/agent/apps/desktop/src/store/translucency.ts +38 -0
  496. package/agent/apps/desktop/src/store/updates.test.ts +187 -2
  497. package/agent/apps/desktop/src/store/updates.ts +268 -18
  498. package/agent/apps/desktop/src/store/windows.test.ts +143 -0
  499. package/agent/apps/desktop/src/store/windows.ts +115 -0
  500. package/agent/apps/desktop/src/styles.css +510 -119
  501. package/agent/apps/desktop/src/themes/color.ts +142 -0
  502. package/agent/apps/desktop/src/themes/context.tsx +128 -75
  503. package/agent/apps/desktop/src/themes/install.test.ts +119 -0
  504. package/agent/apps/desktop/src/themes/install.ts +95 -0
  505. package/agent/apps/desktop/src/themes/presets.test.ts +33 -0
  506. package/agent/apps/desktop/src/themes/presets.ts +13 -4
  507. package/agent/apps/desktop/src/themes/profile-theme.test.ts +41 -0
  508. package/agent/apps/desktop/src/themes/types.ts +35 -0
  509. package/agent/apps/desktop/src/themes/user-themes.test.ts +63 -0
  510. package/agent/apps/desktop/src/themes/user-themes.ts +122 -0
  511. package/agent/apps/desktop/src/themes/vscode.test.ts +171 -0
  512. package/agent/apps/desktop/src/themes/vscode.ts +343 -0
  513. package/agent/apps/desktop/src/types/hermes.ts +138 -1
  514. package/agent/apps/desktop/tsconfig.json +2 -2
  515. package/agent/apps/desktop/vite.config.ts +18 -0
  516. package/agent/apps/shared/package.json +1 -1
  517. package/agent/apps/shared/src/json-rpc-gateway.ts +63 -2
  518. package/agent/apps/shared/tsconfig.json +2 -2
  519. package/agent/cli-config.yaml.example +78 -1
  520. package/agent/cli.py +2177 -3162
  521. package/agent/cron/blueprint_catalog.py +713 -0
  522. package/agent/cron/jobs.py +226 -110
  523. package/agent/cron/scheduler.py +468 -193
  524. package/agent/cron/scheduler_provider.py +177 -0
  525. package/agent/cron/scripts/__init__.py +1 -0
  526. package/agent/cron/scripts/classify_items.py +226 -0
  527. package/agent/cron/suggestion_catalog.py +154 -0
  528. package/agent/cron/suggestions.py +257 -0
  529. package/agent/docs/chronos-managed-cron-contract.md +196 -0
  530. package/agent/docs/design/profile-builder.md +146 -0
  531. package/agent/docs/middleware/README.md +260 -0
  532. package/agent/docs/observability/README.md +316 -0
  533. package/agent/docs/plans/2026-06-09-003-fix-telegram-stream-overflow-continuations-plan.md +240 -0
  534. package/agent/docs/rca-ssl-cacert-post-git-pull.md +54 -0
  535. package/agent/docs/relay-connector-contract.md +285 -0
  536. package/agent/gateway/authz_mixin.py +536 -0
  537. package/agent/gateway/channel_directory.py +65 -3
  538. package/agent/gateway/config.py +222 -12
  539. package/agent/gateway/display_config.py +10 -0
  540. package/agent/gateway/hooks.py +17 -0
  541. package/agent/gateway/kanban_watchers.py +1146 -0
  542. package/agent/gateway/message_timestamps.py +166 -0
  543. package/agent/gateway/platforms/ADDING_A_PLATFORM.md +29 -0
  544. package/agent/gateway/platforms/api_server.py +216 -38
  545. package/agent/gateway/platforms/base.py +210 -58
  546. package/agent/gateway/platforms/email.py +122 -12
  547. package/agent/gateway/platforms/feishu.py +80 -11
  548. package/agent/gateway/platforms/feishu_meeting_invite.py +212 -0
  549. package/agent/gateway/platforms/matrix.py +1498 -297
  550. package/agent/gateway/platforms/qqbot/adapter.py +6 -0
  551. package/agent/gateway/platforms/signal.py +8 -0
  552. package/agent/gateway/platforms/slack.py +308 -12
  553. package/agent/gateway/platforms/telegram.py +831 -24
  554. package/agent/gateway/platforms/webhook.py +109 -21
  555. package/agent/gateway/platforms/weixin.py +113 -2
  556. package/agent/gateway/platforms/whatsapp.py +94 -288
  557. package/agent/gateway/platforms/whatsapp_cloud.py +1956 -0
  558. package/agent/gateway/platforms/whatsapp_common.py +367 -0
  559. package/agent/gateway/platforms/yuanbao.py +608 -191
  560. package/agent/gateway/platforms/yuanbao_proto.py +232 -23
  561. package/agent/gateway/relay/__init__.py +375 -0
  562. package/agent/gateway/relay/adapter.py +222 -0
  563. package/agent/gateway/relay/auth.py +168 -0
  564. package/agent/gateway/relay/descriptor.py +118 -0
  565. package/agent/gateway/relay/transport.py +101 -0
  566. package/agent/gateway/relay/ws_transport.py +327 -0
  567. package/agent/gateway/response_filters.py +53 -0
  568. package/agent/gateway/rich_sent_store.py +80 -0
  569. package/agent/gateway/run.py +2940 -5001
  570. package/agent/gateway/session.py +109 -8
  571. package/agent/gateway/session_context.py +22 -4
  572. package/agent/gateway/slash_commands.py +3854 -0
  573. package/agent/gateway/status.py +141 -21
  574. package/agent/gateway/stream_consumer.py +288 -31
  575. package/agent/hermes-already-has-routines.md +1 -1
  576. package/agent/hermes_cli/__init__.py +62 -17
  577. package/agent/hermes_cli/_parser.py +30 -0
  578. package/agent/hermes_cli/_subprocess_compat.py +61 -0
  579. package/agent/hermes_cli/active_sessions.py +320 -0
  580. package/agent/hermes_cli/auth.py +707 -59
  581. package/agent/hermes_cli/auth_commands.py +39 -22
  582. package/agent/hermes_cli/backup.py +109 -7
  583. package/agent/hermes_cli/banner.py +88 -0
  584. package/agent/hermes_cli/blueprint_cmd.py +318 -0
  585. package/agent/hermes_cli/cli_agent_setup_mixin.py +684 -0
  586. package/agent/hermes_cli/cli_commands_mixin.py +2293 -0
  587. package/agent/hermes_cli/commands.py +215 -91
  588. package/agent/hermes_cli/config.py +967 -130
  589. package/agent/hermes_cli/container_boot.py +76 -11
  590. package/agent/hermes_cli/cron.py +5 -11
  591. package/agent/hermes_cli/curator.py +21 -0
  592. package/agent/hermes_cli/dashboard_auth/__init__.py +2 -0
  593. package/agent/hermes_cli/dashboard_auth/base.py +62 -0
  594. package/agent/hermes_cli/dashboard_auth/cookies.py +32 -19
  595. package/agent/hermes_cli/dashboard_auth/login_page.py +156 -6
  596. package/agent/hermes_cli/dashboard_auth/middleware.py +28 -4
  597. package/agent/hermes_cli/dashboard_auth/prefix.py +46 -2
  598. package/agent/hermes_cli/dashboard_auth/public_paths.py +6 -0
  599. package/agent/hermes_cli/dashboard_auth/routes.py +158 -2
  600. package/agent/hermes_cli/dashboard_auth/ws_tickets.py +85 -11
  601. package/agent/hermes_cli/dashboard_register.py +427 -0
  602. package/agent/hermes_cli/debug.py +155 -50
  603. package/agent/hermes_cli/doctor.py +255 -14
  604. package/agent/hermes_cli/dump.py +60 -6
  605. package/agent/hermes_cli/env_loader.py +33 -0
  606. package/agent/hermes_cli/gateway.py +755 -103
  607. package/agent/hermes_cli/gateway_enroll.py +250 -0
  608. package/agent/hermes_cli/gateway_windows.py +254 -11
  609. package/agent/hermes_cli/gui_uninstall.py +285 -0
  610. package/agent/hermes_cli/inventory.py +105 -4
  611. package/agent/hermes_cli/kanban.py +58 -71
  612. package/agent/hermes_cli/kanban_db.py +391 -14
  613. package/agent/hermes_cli/kanban_decompose.py +2 -2
  614. package/agent/hermes_cli/kanban_specify.py +3 -1
  615. package/agent/hermes_cli/logs.py +2 -0
  616. package/agent/hermes_cli/main.py +2889 -5287
  617. package/agent/hermes_cli/managed_scope.py +214 -0
  618. package/agent/hermes_cli/managed_uv.py +254 -0
  619. package/agent/hermes_cli/mcp_catalog.py +6 -3
  620. package/agent/hermes_cli/mcp_config.py +145 -21
  621. package/agent/hermes_cli/mcp_security.py +96 -0
  622. package/agent/hermes_cli/mcp_startup.py +32 -3
  623. package/agent/hermes_cli/memory_providers.py +149 -0
  624. package/agent/hermes_cli/memory_setup.py +97 -42
  625. package/agent/hermes_cli/middleware.py +313 -0
  626. package/agent/hermes_cli/model_catalog.py +31 -0
  627. package/agent/hermes_cli/model_cost_guard.py +134 -0
  628. package/agent/hermes_cli/model_normalize.py +2 -1
  629. package/agent/hermes_cli/model_setup_flows.py +2759 -0
  630. package/agent/hermes_cli/model_switch.py +242 -27
  631. package/agent/hermes_cli/models.py +284 -44
  632. package/agent/hermes_cli/nous_account.py +33 -6
  633. package/agent/hermes_cli/nous_billing.py +406 -0
  634. package/agent/hermes_cli/nous_subscription.py +202 -5
  635. package/agent/hermes_cli/platforms.py +1 -0
  636. package/agent/hermes_cli/plugins.py +218 -18
  637. package/agent/hermes_cli/plugins_cmd.py +249 -105
  638. package/agent/hermes_cli/portal_cli.py +56 -16
  639. package/agent/hermes_cli/profile_distribution.py +6 -1
  640. package/agent/hermes_cli/profiles.py +283 -32
  641. package/agent/hermes_cli/provider_catalog.py +170 -0
  642. package/agent/hermes_cli/providers.py +4 -1
  643. package/agent/hermes_cli/pty_bridge.py +53 -4
  644. package/agent/hermes_cli/runtime_provider.py +216 -34
  645. package/agent/hermes_cli/secret_prompt.py +4 -4
  646. package/agent/hermes_cli/secrets_cli.py +24 -0
  647. package/agent/hermes_cli/send_cmd.py +28 -2
  648. package/agent/hermes_cli/service_manager.py +166 -19
  649. package/agent/hermes_cli/session_listing.py +97 -0
  650. package/agent/hermes_cli/setup.py +158 -94
  651. package/agent/hermes_cli/setup_whatsapp_cloud.py +541 -0
  652. package/agent/hermes_cli/skills_config.py +8 -2
  653. package/agent/hermes_cli/skills_hub.py +149 -7
  654. package/agent/hermes_cli/status.py +2 -2
  655. package/agent/hermes_cli/subcommands/__init__.py +18 -0
  656. package/agent/hermes_cli/subcommands/_shared.py +29 -0
  657. package/agent/hermes_cli/subcommands/acp.py +52 -0
  658. package/agent/hermes_cli/subcommands/auth.py +109 -0
  659. package/agent/hermes_cli/subcommands/backup.py +38 -0
  660. package/agent/hermes_cli/subcommands/claw.py +92 -0
  661. package/agent/hermes_cli/subcommands/config.py +49 -0
  662. package/agent/hermes_cli/subcommands/cron.py +163 -0
  663. package/agent/hermes_cli/subcommands/dashboard.py +143 -0
  664. package/agent/hermes_cli/subcommands/debug.py +77 -0
  665. package/agent/hermes_cli/subcommands/doctor.py +35 -0
  666. package/agent/hermes_cli/subcommands/dump.py +28 -0
  667. package/agent/hermes_cli/subcommands/gateway.py +332 -0
  668. package/agent/hermes_cli/subcommands/gui.py +63 -0
  669. package/agent/hermes_cli/subcommands/hooks.py +77 -0
  670. package/agent/hermes_cli/subcommands/import_cmd.py +31 -0
  671. package/agent/hermes_cli/subcommands/insights.py +25 -0
  672. package/agent/hermes_cli/subcommands/login.py +78 -0
  673. package/agent/hermes_cli/subcommands/logout.py +28 -0
  674. package/agent/hermes_cli/subcommands/logs.py +78 -0
  675. package/agent/hermes_cli/subcommands/mcp.py +108 -0
  676. package/agent/hermes_cli/subcommands/memory.py +53 -0
  677. package/agent/hermes_cli/subcommands/model.py +72 -0
  678. package/agent/hermes_cli/subcommands/pairing.py +36 -0
  679. package/agent/hermes_cli/subcommands/plugins.py +94 -0
  680. package/agent/hermes_cli/subcommands/postinstall.py +23 -0
  681. package/agent/hermes_cli/subcommands/profile.py +203 -0
  682. package/agent/hermes_cli/subcommands/prompt_size.py +36 -0
  683. package/agent/hermes_cli/subcommands/security.py +62 -0
  684. package/agent/hermes_cli/subcommands/setup.py +58 -0
  685. package/agent/hermes_cli/subcommands/skills.py +298 -0
  686. package/agent/hermes_cli/subcommands/slack.py +60 -0
  687. package/agent/hermes_cli/subcommands/status.py +28 -0
  688. package/agent/hermes_cli/subcommands/tools.py +95 -0
  689. package/agent/hermes_cli/subcommands/uninstall.py +41 -0
  690. package/agent/hermes_cli/subcommands/update.py +70 -0
  691. package/agent/hermes_cli/subcommands/version.py +18 -0
  692. package/agent/hermes_cli/subcommands/webhook.py +76 -0
  693. package/agent/hermes_cli/subcommands/whatsapp.py +22 -0
  694. package/agent/hermes_cli/suggestions_cmd.py +153 -0
  695. package/agent/hermes_cli/telegram_managed_bot.py +358 -0
  696. package/agent/hermes_cli/tips.py +3 -4
  697. package/agent/hermes_cli/tools_config.py +155 -28
  698. package/agent/hermes_cli/uninstall.py +231 -35
  699. package/agent/hermes_cli/web_server.py +6188 -975
  700. package/agent/hermes_cli/win_pty_bridge.py +179 -0
  701. package/agent/hermes_cli/write_approval_commands.py +209 -0
  702. package/agent/hermes_constants.py +164 -33
  703. package/agent/hermes_logging.py +74 -2
  704. package/agent/hermes_state.py +919 -106
  705. package/agent/hermes_time.py +20 -0
  706. package/agent/locales/af.yaml +23 -0
  707. package/agent/locales/de.yaml +23 -0
  708. package/agent/locales/en.yaml +20 -0
  709. package/agent/locales/es.yaml +23 -0
  710. package/agent/locales/fr.yaml +23 -0
  711. package/agent/locales/ga.yaml +23 -0
  712. package/agent/locales/hu.yaml +23 -0
  713. package/agent/locales/it.yaml +23 -0
  714. package/agent/locales/ja.yaml +23 -0
  715. package/agent/locales/ko.yaml +23 -0
  716. package/agent/locales/pt.yaml +23 -0
  717. package/agent/locales/ru.yaml +23 -0
  718. package/agent/locales/tr.yaml +23 -0
  719. package/agent/locales/uk.yaml +23 -0
  720. package/agent/locales/zh-hant.yaml +23 -0
  721. package/agent/locales/zh.yaml +23 -0
  722. package/agent/model_tools.py +204 -40
  723. package/agent/optional-mcps/clawpump/manifest.yaml +4 -2
  724. package/agent/optional-mcps/clawpump-stdio/manifest.yaml +2 -0
  725. package/agent/optional-mcps/unreal-engine/manifest.yaml +54 -0
  726. package/agent/optional-skills/blockchain/hyperliquid/SKILL.md +2 -2
  727. package/agent/optional-skills/blockchain/hyperliquid/scripts/hyperliquid_client.py +1 -1
  728. package/agent/optional-skills/creative/kanban-video-orchestrator/SKILL.md +1 -1
  729. package/agent/optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl +4 -3
  730. package/agent/optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md +6 -4
  731. package/agent/optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md +2 -2
  732. package/agent/{skills/software-development → optional-skills/devops}/hermes-s6-container-supervision/SKILL.md +2 -0
  733. package/agent/optional-skills/devops/watchers/SKILL.md +1 -1
  734. package/agent/optional-skills/devops/watchers/scripts/watch_github.py +2 -1
  735. package/agent/optional-skills/payments/mpp-agent/SKILL.md +124 -0
  736. package/agent/optional-skills/payments/stripe-link-cli/SKILL.md +184 -0
  737. package/agent/optional-skills/payments/stripe-projects/SKILL.md +120 -0
  738. package/agent/optional-skills/productivity/canvas/SKILL.md +1 -1
  739. package/agent/optional-skills/productivity/canvas/scripts/canvas_api.py +4 -1
  740. package/agent/optional-skills/productivity/shop/SKILL.md +224 -0
  741. package/agent/optional-skills/productivity/shop/references/catalog-mcp.md +236 -0
  742. package/agent/optional-skills/productivity/shop/references/direct-api.md +278 -0
  743. package/agent/optional-skills/productivity/shop/references/legal.md +3 -0
  744. package/agent/optional-skills/productivity/shop/references/safety.md +36 -0
  745. package/agent/optional-skills/productivity/shopify/SKILL.md +1 -1
  746. package/agent/optional-skills/productivity/siyuan/SKILL.md +1 -1
  747. package/agent/optional-skills/productivity/telephony/SKILL.md +4 -4
  748. package/agent/optional-skills/productivity/telephony/scripts/telephony.py +15 -15
  749. package/agent/optional-skills/security/1password/SKILL.md +1 -1
  750. package/agent/{skills/red-teaming → optional-skills/security}/godmode/SKILL.md +3 -4
  751. package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/auto_jailbreak.py +3 -1
  752. package/agent/optional-skills/software-development/rest-graphql-debug/SKILL.md +1 -1
  753. package/agent/{skills → optional-skills}/software-development/subagent-driven-development/SKILL.md +5 -5
  754. package/agent/package-lock.json +4082 -7907
  755. package/agent/package.json +18 -3
  756. package/agent/plugins/browser/firecrawl/provider.py +4 -1
  757. package/agent/plugins/cron/__init__.py +344 -0
  758. package/agent/plugins/cron/chronos/__init__.py +241 -0
  759. package/agent/plugins/cron/chronos/_nas_client.py +123 -0
  760. package/agent/plugins/cron/chronos/plugin.yaml +9 -0
  761. package/agent/plugins/cron/chronos/verify.py +103 -0
  762. package/agent/plugins/dashboard_auth/basic/__init__.py +491 -0
  763. package/agent/plugins/dashboard_auth/basic/plugin.yaml +7 -0
  764. package/agent/plugins/dashboard_auth/nous/__init__.py +12 -14
  765. package/agent/plugins/dashboard_auth/self_hosted/__init__.py +736 -0
  766. package/agent/plugins/dashboard_auth/self_hosted/plugin.yaml +8 -0
  767. package/agent/plugins/disk-cleanup/disk_cleanup.py +100 -20
  768. package/agent/plugins/google_meet/audio_bridge.py +4 -0
  769. package/agent/plugins/google_meet/meet_bot.py +7 -1
  770. package/agent/plugins/hermes-achievements/dashboard/dist/index.js +9 -15
  771. package/agent/plugins/image_gen/fal/__init__.py +35 -6
  772. package/agent/plugins/image_gen/krea/__init__.py +56 -13
  773. package/agent/plugins/image_gen/openai/__init__.py +122 -24
  774. package/agent/plugins/image_gen/openai-codex/__init__.py +28 -2
  775. package/agent/plugins/image_gen/xai/__init__.py +92 -12
  776. package/agent/plugins/kanban/dashboard/dist/index.js +63 -48
  777. package/agent/plugins/kanban/dashboard/plugin_api.py +39 -35
  778. package/agent/plugins/memory/__init__.py +48 -5
  779. package/agent/plugins/memory/byterover/__init__.py +1 -0
  780. package/agent/plugins/memory/hindsight/README.md +1 -1
  781. package/agent/plugins/memory/hindsight/__init__.py +138 -24
  782. package/agent/plugins/memory/hindsight/plugin.yaml +1 -1
  783. package/agent/plugins/memory/honcho/README.md +13 -10
  784. package/agent/plugins/memory/honcho/cli.py +247 -122
  785. package/agent/plugins/memory/honcho/client.py +112 -102
  786. package/agent/plugins/memory/openviking/README.md +12 -1
  787. package/agent/plugins/memory/openviking/__init__.py +2281 -107
  788. package/agent/plugins/memory/openviking/plugin.yaml +1 -2
  789. package/agent/plugins/memory/supermemory/README.md +22 -10
  790. package/agent/plugins/memory/supermemory/__init__.py +142 -37
  791. package/agent/plugins/memory/supermemory/plugin.yaml +1 -1
  792. package/agent/plugins/model-providers/anthropic/__init__.py +1 -0
  793. package/agent/plugins/model-providers/bedrock/__init__.py +1 -0
  794. package/agent/plugins/model-providers/copilot-acp/__init__.py +1 -0
  795. package/agent/plugins/model-providers/custom/__init__.py +8 -2
  796. package/agent/plugins/model-providers/kimi-coding/__init__.py +16 -7
  797. package/agent/plugins/model-providers/minimax/__init__.py +60 -8
  798. package/agent/plugins/model-providers/opencode-zen/__init__.py +12 -3
  799. package/agent/plugins/model-providers/openrouter/__init__.py +75 -4
  800. package/agent/plugins/model-providers/xiaomi/__init__.py +2 -0
  801. package/agent/plugins/model-providers/zai/__init__.py +1 -0
  802. package/agent/plugins/observability/langfuse/__init__.py +147 -14
  803. package/agent/plugins/observability/nemo_relay/README.md +559 -0
  804. package/agent/plugins/observability/nemo_relay/__init__.py +962 -0
  805. package/agent/plugins/observability/nemo_relay/plugin.yaml +20 -0
  806. package/agent/plugins/platforms/discord/adapter.py +932 -61
  807. package/agent/plugins/platforms/discord/voice_mixer.py +379 -0
  808. package/agent/plugins/platforms/google_chat/adapter.py +9 -3
  809. package/agent/plugins/platforms/google_chat/oauth.py +1 -1
  810. package/agent/plugins/platforms/homeassistant/__init__.py +3 -0
  811. package/agent/{gateway/platforms/homeassistant.py → plugins/platforms/homeassistant/adapter.py} +128 -0
  812. package/agent/plugins/platforms/homeassistant/plugin.yaml +22 -0
  813. package/agent/plugins/platforms/irc/adapter.py +4 -1
  814. package/agent/plugins/platforms/line/adapter.py +16 -1
  815. package/agent/plugins/platforms/mattermost/adapter.py +100 -24
  816. package/agent/plugins/platforms/photon/README.md +179 -0
  817. package/agent/plugins/platforms/photon/__init__.py +4 -0
  818. package/agent/plugins/platforms/photon/adapter.py +1586 -0
  819. package/agent/plugins/platforms/photon/auth.py +1046 -0
  820. package/agent/plugins/platforms/photon/cli.py +439 -0
  821. package/agent/plugins/platforms/photon/plugin.yaml +88 -0
  822. package/agent/plugins/platforms/photon/sidecar/README.md +52 -0
  823. package/agent/plugins/platforms/photon/sidecar/index.mjs +720 -0
  824. package/agent/plugins/platforms/photon/sidecar/package-lock.json +1730 -0
  825. package/agent/plugins/platforms/photon/sidecar/package.json +25 -0
  826. package/agent/plugins/platforms/photon/sidecar/patch-spectrum-mixed-attachments.mjs +155 -0
  827. package/agent/plugins/platforms/raft/__init__.py +3 -0
  828. package/agent/plugins/platforms/raft/adapter.py +774 -0
  829. package/agent/plugins/platforms/raft/plugin.yaml +19 -0
  830. package/agent/plugins/platforms/simplex/adapter.py +777 -220
  831. package/agent/plugins/platforms/simplex/plugin.yaml +21 -2
  832. package/agent/plugins/platforms/teams/adapter.py +175 -5
  833. package/agent/plugins/plugin_utils.py +135 -0
  834. package/agent/plugins/video_gen/fal/__init__.py +10 -3
  835. package/agent/plugins/web/searxng/provider.py +15 -2
  836. package/agent/plugins/web/xai/provider.py +2 -2
  837. package/agent/providers/base.py +22 -3
  838. package/agent/pyproject.toml +115 -21
  839. package/agent/run_agent.py +733 -39
  840. package/agent/scripts/build_skills_index.py +51 -19
  841. package/agent/scripts/check_subprocess_stdin.py +177 -0
  842. package/agent/scripts/contributor_audit.py +2 -0
  843. package/agent/scripts/docker_config_migrate.py +67 -0
  844. package/agent/scripts/install.cmd +3 -3
  845. package/agent/scripts/install.ps1 +580 -154
  846. package/agent/scripts/install.sh +402 -185
  847. package/agent/scripts/lib/node-bootstrap.sh +39 -4
  848. package/agent/scripts/release.py +183 -0
  849. package/agent/scripts/run_tests.sh +1 -0
  850. package/agent/scripts/run_tests_parallel.py +18 -23
  851. package/agent/scripts/whatsapp-bridge/bridge.js +25 -4
  852. package/agent/setup.py +59 -0
  853. package/agent/skills/autonomous-ai-agents/codex/SKILL.md +19 -0
  854. package/agent/skills/autonomous-ai-agents/hermes-agent/SKILL.md +10 -3
  855. package/agent/skills/{mcp/native-mcp/SKILL.md → autonomous-ai-agents/hermes-agent/references/native-mcp.md} +0 -13
  856. package/agent/skills/{devops/webhook-subscriptions/SKILL.md → autonomous-ai-agents/hermes-agent/references/webhooks.md} +1 -11
  857. package/agent/skills/clawpump/SKILL.md +3 -1
  858. package/agent/skills/devops/kanban-orchestrator/SKILL.md +1 -0
  859. package/agent/skills/devops/kanban-worker/SKILL.md +1 -0
  860. package/agent/skills/github/github-auth/SKILL.md +2 -2
  861. package/agent/skills/github/github-auth/scripts/gh-env.sh +2 -2
  862. package/agent/skills/github/github-code-review/SKILL.md +2 -2
  863. package/agent/skills/github/github-issues/SKILL.md +2 -2
  864. package/agent/skills/github/github-pr-workflow/SKILL.md +2 -2
  865. package/agent/skills/github/github-repo-management/SKILL.md +2 -2
  866. package/agent/skills/media/gif-search/SKILL.md +1 -1
  867. package/agent/skills/media/youtube-content/SKILL.md +10 -7
  868. package/agent/skills/media/youtube-content/scripts/fetch_transcript.py +3 -3
  869. package/agent/skills/note-taking/obsidian/SKILL.md +1 -1
  870. package/agent/skills/productivity/airtable/SKILL.md +2 -2
  871. package/agent/skills/productivity/google-workspace/scripts/setup.py +33 -7
  872. package/agent/skills/productivity/notion/SKILL.md +2 -2
  873. package/agent/skills/productivity/teams-meeting-pipeline/SKILL.md +1 -1
  874. package/agent/skills/research/llm-wiki/SKILL.md +1 -1
  875. package/agent/skills/social-media/xurl/SKILL.md +9 -0
  876. package/agent/skills/software-development/hermes-agent-skill-authoring/SKILL.md +1 -1
  877. package/agent/skills/software-development/plan/SKILL.md +285 -5
  878. package/agent/skills/software-development/requesting-code-review/SKILL.md +2 -2
  879. package/agent/skills/software-development/simplify-code/SKILL.md +212 -0
  880. package/agent/skills/software-development/spike/SKILL.md +2 -2
  881. package/agent/skills/software-development/systematic-debugging/SKILL.md +1 -1
  882. package/agent/skills/software-development/test-driven-development/SKILL.md +1 -1
  883. package/agent/tools/approval.py +302 -4
  884. package/agent/tools/async_delegation.py +386 -0
  885. package/agent/tools/blueprints.py +325 -0
  886. package/agent/tools/browser_cdp_tool.py +3 -3
  887. package/agent/tools/browser_tool.py +34 -6
  888. package/agent/tools/checkpoint_manager.py +31 -1
  889. package/agent/tools/clarify_tool.py +55 -5
  890. package/agent/tools/code_execution_tool.py +31 -14
  891. package/agent/tools/computer_use/cua_backend.py +81 -3
  892. package/agent/tools/computer_use/tool.py +79 -5
  893. package/agent/tools/computer_use/vision_routing.py +55 -3
  894. package/agent/tools/credential_files.py +31 -12
  895. package/agent/tools/cronjob_tools.py +30 -20
  896. package/agent/tools/delegate_tool.py +356 -31
  897. package/agent/tools/env_probe.py +1 -0
  898. package/agent/tools/environments/docker.py +163 -8
  899. package/agent/tools/environments/file_sync.py +2 -1
  900. package/agent/tools/environments/local.py +74 -23
  901. package/agent/tools/environments/singularity.py +4 -1
  902. package/agent/tools/environments/ssh.py +78 -11
  903. package/agent/tools/file_operations.py +277 -41
  904. package/agent/tools/file_tools.py +166 -28
  905. package/agent/tools/image_generation_tool.py +515 -29
  906. package/agent/tools/kanban_tools.py +99 -0
  907. package/agent/tools/lazy_deps.py +33 -2
  908. package/agent/tools/mcp_oauth.py +5 -5
  909. package/agent/tools/mcp_oauth_manager.py +7 -5
  910. package/agent/tools/mcp_tool.py +840 -33
  911. package/agent/tools/memory_tool.py +335 -38
  912. package/agent/tools/osv_check.py +15 -1
  913. package/agent/tools/process_registry.py +155 -11
  914. package/agent/tools/read_extract.py +248 -0
  915. package/agent/tools/read_terminal_tool.py +93 -0
  916. package/agent/tools/schema_sanitizer.py +38 -0
  917. package/agent/tools/send_message_tool.py +163 -49
  918. package/agent/tools/session_search_tool.py +189 -7
  919. package/agent/tools/skill_manager_tool.py +202 -3
  920. package/agent/tools/skill_usage.py +52 -4
  921. package/agent/tools/skills_hub.py +184 -44
  922. package/agent/tools/skills_sync.py +232 -5
  923. package/agent/tools/skills_tool.py +125 -11
  924. package/agent/tools/terminal_tool.py +148 -26
  925. package/agent/tools/tirith_security.py +2 -0
  926. package/agent/tools/todo_tool.py +32 -1
  927. package/agent/tools/transcription_tools.py +13 -5
  928. package/agent/tools/tts_tool.py +332 -38
  929. package/agent/tools/url_safety.py +52 -1
  930. package/agent/tools/vision_tools.py +124 -39
  931. package/agent/tools/voice_mode.py +4 -3
  932. package/agent/tools/web_tools.py +45 -15
  933. package/agent/tools/write_approval.py +493 -0
  934. package/agent/toolsets.py +34 -10
  935. package/agent/trajectory_compressor.py +81 -10
  936. package/agent/tui_gateway/entry.py +43 -6
  937. package/agent/tui_gateway/server.py +3335 -330
  938. package/agent/tui_gateway/slash_worker.py +61 -0
  939. package/agent/tui_gateway/ws.py +67 -9
  940. package/agent/ui-tui/eslint.config.mjs +0 -4
  941. package/agent/ui-tui/package.json +6 -6
  942. package/agent/ui-tui/packages/hermes-ink/package.json +1 -1
  943. package/agent/ui-tui/packages/hermes-ink/src/ink/app-mouse.test.ts +34 -1
  944. package/agent/ui-tui/packages/hermes-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
  945. package/agent/ui-tui/packages/hermes-ink/src/ink/components/App.tsx +35 -2
  946. package/agent/ui-tui/packages/hermes-ink/src/ink/events/input-event.ts +4 -11
  947. package/agent/ui-tui/packages/hermes-ink/src/ink/parse-keypress.test.ts +23 -57
  948. package/agent/ui-tui/packages/hermes-ink/src/ink/parse-keypress.ts +11 -135
  949. package/agent/ui-tui/packages/hermes-ink/src/ink/termio/tokenize.test.ts +185 -0
  950. package/agent/ui-tui/packages/hermes-ink/src/ink/termio/tokenize.ts +37 -3
  951. package/agent/ui-tui/packages/hermes-ink/src/utils/execFileNoThrow.ts +5 -5
  952. package/agent/ui-tui/src/__tests__/appChromeStatusRule.test.tsx +217 -0
  953. package/agent/ui-tui/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
  954. package/agent/ui-tui/src/__tests__/approvalAction.test.ts +11 -0
  955. package/agent/ui-tui/src/__tests__/billingCommand.test.ts +301 -0
  956. package/agent/ui-tui/src/__tests__/blockLayout.test.ts +122 -0
  957. package/agent/ui-tui/src/__tests__/brandingMcpCount.test.ts +111 -0
  958. package/agent/ui-tui/src/__tests__/completionApply.test.ts +51 -0
  959. package/agent/ui-tui/src/__tests__/createGatewayEventHandler.test.ts +487 -2
  960. package/agent/ui-tui/src/__tests__/createSlashHandler.test.ts +54 -0
  961. package/agent/ui-tui/src/__tests__/creditsCommand.test.ts +144 -0
  962. package/agent/ui-tui/src/__tests__/gatewayClient.test.ts +120 -99
  963. package/agent/ui-tui/src/__tests__/gracefulExit.test.ts +11 -0
  964. package/agent/ui-tui/src/__tests__/memoryMonitor.test.ts +102 -0
  965. package/agent/ui-tui/src/__tests__/paths.test.ts +41 -1
  966. package/agent/ui-tui/src/__tests__/terminalModes.test.ts +22 -0
  967. package/agent/ui-tui/src/__tests__/text.test.ts +23 -0
  968. package/agent/ui-tui/src/__tests__/textInputFastEcho.test.ts +37 -0
  969. package/agent/ui-tui/src/__tests__/turnControllerNotice.test.ts +43 -0
  970. package/agent/ui-tui/src/__tests__/useInputHandlers.test.ts +38 -1
  971. package/agent/ui-tui/src/__tests__/virtualHeights.test.ts +8 -0
  972. package/agent/ui-tui/src/app/createGatewayEventHandler.ts +102 -7
  973. package/agent/ui-tui/src/app/interfaces.ts +64 -1
  974. package/agent/ui-tui/src/app/overlayStore.ts +18 -2
  975. package/agent/ui-tui/src/app/slash/commands/billing.ts +332 -0
  976. package/agent/ui-tui/src/app/slash/commands/core.ts +31 -2
  977. package/agent/ui-tui/src/app/slash/commands/credits.ts +57 -0
  978. package/agent/ui-tui/src/app/slash/commands/ops.ts +28 -0
  979. package/agent/ui-tui/src/app/slash/commands/session.ts +32 -4
  980. package/agent/ui-tui/src/app/slash/registry.ts +4 -0
  981. package/agent/ui-tui/src/app/turnController.ts +145 -2
  982. package/agent/ui-tui/src/app/uiStore.ts +2 -0
  983. package/agent/ui-tui/src/app/useInputHandlers.ts +42 -4
  984. package/agent/ui-tui/src/app/useMainApp.ts +54 -8
  985. package/agent/ui-tui/src/app/useSessionLifecycle.ts +40 -31
  986. package/agent/ui-tui/src/app/useSubmission.ts +23 -31
  987. package/agent/ui-tui/src/components/appChrome.tsx +112 -5
  988. package/agent/ui-tui/src/components/appLayout.tsx +9 -0
  989. package/agent/ui-tui/src/components/appOverlays.tsx +25 -1
  990. package/agent/ui-tui/src/components/billingOverlay.tsx +684 -0
  991. package/agent/ui-tui/src/components/branding.tsx +15 -3
  992. package/agent/ui-tui/src/components/messageLine.tsx +25 -3
  993. package/agent/ui-tui/src/components/pluginsHub.tsx +238 -0
  994. package/agent/ui-tui/src/components/prompts.tsx +31 -17
  995. package/agent/ui-tui/src/components/streamingAssistant.tsx +63 -55
  996. package/agent/ui-tui/src/components/textInput.tsx +16 -0
  997. package/agent/ui-tui/src/config/env.ts +12 -0
  998. package/agent/ui-tui/src/config/limits.ts +13 -0
  999. package/agent/ui-tui/src/domain/blockLayout.ts +146 -0
  1000. package/agent/ui-tui/src/domain/paths.ts +24 -0
  1001. package/agent/ui-tui/src/domain/slash.ts +40 -0
  1002. package/agent/ui-tui/src/entry.tsx +35 -4
  1003. package/agent/ui-tui/src/gatewayClient.ts +22 -10
  1004. package/agent/ui-tui/src/gatewayTypes.ts +130 -1
  1005. package/agent/ui-tui/src/lib/gracefulExit.ts +24 -4
  1006. package/agent/ui-tui/src/lib/memory.test.ts +162 -0
  1007. package/agent/ui-tui/src/lib/memory.ts +60 -1
  1008. package/agent/ui-tui/src/lib/memoryMonitor.ts +79 -4
  1009. package/agent/ui-tui/src/lib/osc52.ts +1 -1
  1010. package/agent/ui-tui/src/lib/text.test.ts +32 -1
  1011. package/agent/ui-tui/src/lib/text.ts +29 -2
  1012. package/agent/ui-tui/src/lib/virtualHeights.ts +13 -0
  1013. package/agent/ui-tui/src/types.ts +5 -0
  1014. package/agent/ui-tui/tsconfig.build.json +0 -1
  1015. package/agent/ui-tui/tsconfig.json +2 -1
  1016. package/agent/utils.py +66 -2
  1017. package/agent/uv.lock +300 -684
  1018. package/agent/web/index.html +2 -2
  1019. package/agent/web/package.json +11 -6
  1020. package/agent/web/public/claw-bg.webp +0 -0
  1021. package/agent/web/public/claw-logo.webp +0 -0
  1022. package/agent/web/src/App.tsx +138 -48
  1023. package/agent/web/src/components/AutomationBlueprints.tsx +225 -0
  1024. package/agent/web/src/components/Backdrop.tsx +15 -0
  1025. package/agent/web/src/components/ChatSessionList.tsx +260 -0
  1026. package/agent/web/src/components/ChatSidebar.tsx +262 -78
  1027. package/agent/web/src/components/ConfirmDialog.tsx +122 -0
  1028. package/agent/web/src/components/ModelPickerDialog.tsx +111 -16
  1029. package/agent/web/src/components/ModelReloadConfirm.tsx +40 -0
  1030. package/agent/web/src/components/ProfileScopeBanner.tsx +30 -0
  1031. package/agent/web/src/components/ProfileSwitcher.tsx +67 -0
  1032. package/agent/web/src/components/ReasoningPicker.tsx +167 -0
  1033. package/agent/web/src/components/SkillEditorDialog.tsx +215 -0
  1034. package/agent/web/src/components/ThemeSwitcher.tsx +119 -4
  1035. package/agent/web/src/components/ToolsetConfigDrawer.tsx +457 -0
  1036. package/agent/web/src/contexts/PageHeaderProvider.tsx +7 -4
  1037. package/agent/web/src/contexts/ProfileProvider.tsx +137 -0
  1038. package/agent/web/src/contexts/SystemActions.tsx +6 -8
  1039. package/agent/web/src/contexts/profile-context.ts +19 -0
  1040. package/agent/web/src/contexts/useProfileScope.ts +6 -0
  1041. package/agent/web/src/i18n/af.ts +5 -4
  1042. package/agent/web/src/i18n/de.ts +5 -4
  1043. package/agent/web/src/i18n/en.ts +58 -4
  1044. package/agent/web/src/i18n/es.ts +5 -3
  1045. package/agent/web/src/i18n/fr.ts +5 -3
  1046. package/agent/web/src/i18n/ga.ts +5 -4
  1047. package/agent/web/src/i18n/hu.ts +5 -4
  1048. package/agent/web/src/i18n/it.ts +5 -4
  1049. package/agent/web/src/i18n/ja.ts +5 -4
  1050. package/agent/web/src/i18n/ko.ts +5 -4
  1051. package/agent/web/src/i18n/pt.ts +5 -3
  1052. package/agent/web/src/i18n/ru.ts +5 -4
  1053. package/agent/web/src/i18n/tr.ts +5 -4
  1054. package/agent/web/src/i18n/types.ts +59 -1
  1055. package/agent/web/src/i18n/uk.ts +5 -3
  1056. package/agent/web/src/i18n/zh-hant.ts +5 -4
  1057. package/agent/web/src/i18n/zh.ts +5 -4
  1058. package/agent/web/src/index.css +2 -2
  1059. package/agent/web/src/lib/api.ts +819 -52
  1060. package/agent/web/src/lib/dashboard-flags.ts +16 -7
  1061. package/agent/web/src/lib/reasoning-effort.test.ts +48 -0
  1062. package/agent/web/src/lib/reasoning-effort.ts +36 -0
  1063. package/agent/web/src/lib/session-refresh.test.ts +21 -0
  1064. package/agent/web/src/lib/session-refresh.ts +26 -0
  1065. package/agent/web/src/pages/ChannelsPage.tsx +529 -68
  1066. package/agent/web/src/pages/ChatPage.tsx +249 -56
  1067. package/agent/web/src/pages/ConfigPage.tsx +11 -1
  1068. package/agent/web/src/pages/CronPage.tsx +219 -31
  1069. package/agent/web/src/pages/EnvPage.tsx +25 -6
  1070. package/agent/web/src/pages/FilesPage.tsx +525 -0
  1071. package/agent/web/src/pages/McpPage.tsx +80 -3
  1072. package/agent/web/src/pages/ModelsPage.tsx +97 -12
  1073. package/agent/web/src/pages/PluginsPage.tsx +1 -1
  1074. package/agent/web/src/pages/ProfileBuilderPage.tsx +611 -0
  1075. package/agent/web/src/pages/ProfilesPage.tsx +1038 -172
  1076. package/agent/web/src/pages/SessionsPage.tsx +144 -13
  1077. package/agent/web/src/pages/SkillsPage.tsx +851 -70
  1078. package/agent/web/src/pages/SystemPage.tsx +340 -4
  1079. package/agent/web/src/pages/WalletPage.tsx +401 -0
  1080. package/agent/web/src/pages/WebhooksPage.tsx +145 -15
  1081. package/agent/web/src/pages/X402Page.tsx +207 -0
  1082. package/agent/web/src/plugins/registry.ts +28 -11
  1083. package/agent/web/src/plugins/sdk.d.ts +160 -0
  1084. package/agent/web/src/themes/context.tsx +112 -5
  1085. package/agent/web/src/themes/fonts.ts +167 -0
  1086. package/agent/web/src/themes/index.ts +7 -0
  1087. package/agent/web/tsconfig.app.json +0 -1
  1088. package/agent/web/vite.config.ts +1 -8
  1089. package/agent/web/vitest.config.ts +16 -0
  1090. package/package.json +1 -1
  1091. package/agent/apps/desktop/package-lock.json +0 -18363
  1092. package/agent/apps/desktop/src/app/chat/composer/skin-slash-popover.tsx +0 -56
  1093. package/agent/apps/desktop/src/components/assistant-ui/thread-virtualizer.tsx +0 -382
  1094. package/agent/apps/desktop/src/components/assistant-ui/todo-tool.tsx +0 -109
  1095. package/agent/apps/desktop/src/components/chat/generated-image-context.tsx +0 -19
  1096. package/agent/optional-skills/productivity/shop-app/SKILL.md +0 -340
  1097. package/agent/skills/autonomous-ai-agents/kanban-codex-lane/SKILL.md +0 -277
  1098. package/agent/skills/autonomous-ai-agents/kanban-codex-lane/templates/pmb-codex-lane-prompt.md +0 -57
  1099. package/agent/skills/diagramming/DESCRIPTION.md +0 -3
  1100. package/agent/skills/domain/DESCRIPTION.md +0 -24
  1101. package/agent/skills/gifs/DESCRIPTION.md +0 -3
  1102. package/agent/skills/inference-sh/DESCRIPTION.md +0 -19
  1103. package/agent/skills/mcp/DESCRIPTION.md +0 -3
  1104. package/agent/skills/media/spotify/SKILL.md +0 -135
  1105. package/agent/skills/mlops/training/DESCRIPTION.md +0 -3
  1106. package/agent/skills/mlops/vector-databases/DESCRIPTION.md +0 -3
  1107. package/agent/skills/productivity/linear/SKILL.md +0 -380
  1108. package/agent/skills/productivity/linear/scripts/linear_api.py +0 -445
  1109. package/agent/skills/software-development/debugging-hermes-tui-commands/SKILL.md +0 -152
  1110. package/agent/skills/software-development/writing-plans/SKILL.md +0 -297
  1111. package/agent/ui-tui/package-lock.json +0 -7449
  1112. package/agent/ui-tui/packages/hermes-ink/package-lock.json +0 -1289
  1113. package/agent/web/package-lock.json +0 -8887
  1114. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/PORT_NOTES.md +0 -0
  1115. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/SKILL.md +0 -0
  1116. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/prompts/system.md +0 -0
  1117. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/macaron.md +0 -0
  1118. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/mono-ink.md +0 -0
  1119. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/neon.md +0 -0
  1120. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/palettes/warm.md +0 -0
  1121. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/prompt-construction.md +0 -0
  1122. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/style-presets.md +0 -0
  1123. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/blueprint.md +0 -0
  1124. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/chalkboard.md +0 -0
  1125. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/editorial.md +0 -0
  1126. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/elegant.md +0 -0
  1127. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/fantasy-animation.md +0 -0
  1128. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/flat-doodle.md +0 -0
  1129. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/flat.md +0 -0
  1130. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/ink-notes.md +0 -0
  1131. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/intuition-machine.md +0 -0
  1132. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/minimal.md +0 -0
  1133. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/nature.md +0 -0
  1134. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/notion.md +0 -0
  1135. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/pixel-art.md +0 -0
  1136. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/playful.md +0 -0
  1137. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/retro.md +0 -0
  1138. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/scientific.md +0 -0
  1139. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/screen-print.md +0 -0
  1140. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/sketch-notes.md +0 -0
  1141. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/sketch.md +0 -0
  1142. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/vector-illustration.md +0 -0
  1143. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/vintage.md +0 -0
  1144. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/warm.md +0 -0
  1145. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles/watercolor.md +0 -0
  1146. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/styles.md +0 -0
  1147. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/usage.md +0 -0
  1148. /package/agent/{skills → optional-skills}/creative/baoyu-article-illustrator/references/workflow.md +0 -0
  1149. /package/agent/{skills → optional-skills}/creative/baoyu-comic/PORT_NOTES.md +0 -0
  1150. /package/agent/{skills → optional-skills}/creative/baoyu-comic/SKILL.md +0 -0
  1151. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/analysis-framework.md +0 -0
  1152. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/chalk.md +0 -0
  1153. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/ink-brush.md +0 -0
  1154. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/ligne-claire.md +0 -0
  1155. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/manga.md +0 -0
  1156. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/minimalist.md +0 -0
  1157. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/art-styles/realistic.md +0 -0
  1158. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/auto-selection.md +0 -0
  1159. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/base-prompt.md +0 -0
  1160. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/character-template.md +0 -0
  1161. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/cinematic.md +0 -0
  1162. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/dense.md +0 -0
  1163. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/four-panel.md +0 -0
  1164. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/mixed.md +0 -0
  1165. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/splash.md +0 -0
  1166. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/standard.md +0 -0
  1167. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/layouts/webtoon.md +0 -0
  1168. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/ohmsha-guide.md +0 -0
  1169. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/partial-workflows.md +0 -0
  1170. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/concept-story.md +0 -0
  1171. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/four-panel.md +0 -0
  1172. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/ohmsha.md +0 -0
  1173. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/shoujo.md +0 -0
  1174. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/presets/wuxia.md +0 -0
  1175. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/storyboard-template.md +0 -0
  1176. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/action.md +0 -0
  1177. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/dramatic.md +0 -0
  1178. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/energetic.md +0 -0
  1179. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/neutral.md +0 -0
  1180. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/romantic.md +0 -0
  1181. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/vintage.md +0 -0
  1182. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/tones/warm.md +0 -0
  1183. /package/agent/{skills → optional-skills}/creative/baoyu-comic/references/workflow.md +0 -0
  1184. /package/agent/{skills → optional-skills}/creative/creative-ideation/SKILL.md +0 -0
  1185. /package/agent/{skills → optional-skills}/creative/creative-ideation/references/full-prompt-library.md +0 -0
  1186. /package/agent/{skills → optional-skills}/creative/pixel-art/ATTRIBUTION.md +0 -0
  1187. /package/agent/{skills → optional-skills}/creative/pixel-art/SKILL.md +0 -0
  1188. /package/agent/{skills → optional-skills}/creative/pixel-art/references/palettes.md +0 -0
  1189. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/__init__.py +0 -0
  1190. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/palettes.py +0 -0
  1191. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/pixel_art.py +0 -0
  1192. /package/agent/{skills → optional-skills}/creative/pixel-art/scripts/pixel_art_video.py +0 -0
  1193. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/SKILL.md +0 -0
  1194. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/references/analysis-modules.md +0 -0
  1195. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/references/methods-guide.md +0 -0
  1196. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/abliteration-config.yaml +0 -0
  1197. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/analysis-study.yaml +0 -0
  1198. /package/agent/{skills/mlops/inference → optional-skills/mlops}/obliteratus/templates/batch-abliteration.yaml +0 -0
  1199. /package/agent/{skills → optional-skills}/mlops/research/DESCRIPTION.md +0 -0
  1200. /package/agent/{skills → optional-skills}/mlops/research/dspy/SKILL.md +0 -0
  1201. /package/agent/{skills → optional-skills}/mlops/research/dspy/references/examples.md +0 -0
  1202. /package/agent/{skills → optional-skills}/mlops/research/dspy/references/modules.md +0 -0
  1203. /package/agent/{skills → optional-skills}/mlops/research/dspy/references/optimizers.md +0 -0
  1204. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/references/jailbreak-templates.md +0 -0
  1205. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/references/refusal-detection.md +0 -0
  1206. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/godmode_race.py +0 -0
  1207. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/load_godmode.py +0 -0
  1208. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/scripts/parseltongue.py +0 -0
  1209. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/templates/prefill-subtle.json +0 -0
  1210. /package/agent/{skills/red-teaming → optional-skills/security}/godmode/templates/prefill.json +0 -0
  1211. /package/agent/{skills → optional-skills}/software-development/subagent-driven-development/references/context-budget-discipline.md +0 -0
  1212. /package/agent/{skills → optional-skills}/software-development/subagent-driven-development/references/gates-taxonomy.md +0 -0
@@ -45,7 +45,7 @@ import tempfile
45
45
  import time
46
46
  import threading
47
47
  import uuid
48
- from typing import List, Dict, Any, Optional
48
+ from typing import List, Dict, Any, Optional, Callable
49
49
  # NOTE: `from openai import OpenAI` is deliberately NOT at module top — the
50
50
  # SDK pulls ~240 ms of imports. We expose `OpenAI` as a thin proxy object
51
51
  # that imports the SDK on first call/isinstance check. This preserves:
@@ -60,9 +60,35 @@ from typing import List, Dict, Any, Optional
60
60
  # ModuleNotFoundError on broken/partial installs where `fire` isn't present.
61
61
  from datetime import datetime
62
62
  from pathlib import Path
63
+ from types import SimpleNamespace
63
64
 
64
65
  from hermes_constants import get_hermes_home
65
66
 
67
+
68
+ def _launch_cwd_for_session(source: str) -> Optional[str]:
69
+ """Working directory to stamp on a new session row, or None.
70
+
71
+ Only local CLI sessions get a recorded cwd: the directory the process was
72
+ launched from is meaningful for ``hermes -c`` / ``--resume`` (relaunch
73
+ where you left off). Gateway/cron/remote-backend sessions have no stable
74
+ host cwd to restore, so they record nothing.
75
+
76
+ ``TERMINAL_ENV`` is set by the CLI's config bridge (``load_cli_config``);
77
+ a non-"local" backend (docker/ssh/modal/...) means the host cwd is
78
+ irrelevant to the agent's tools, so we skip it there too.
79
+ """
80
+ if source != "cli":
81
+ return None
82
+ backend = (os.environ.get("TERMINAL_ENV") or "local").strip().lower()
83
+ if backend and backend != "local":
84
+ return None
85
+ try:
86
+ return os.getcwd()
87
+ except OSError:
88
+ # cwd was unlinked out from under us — nothing meaningful to record.
89
+ return None
90
+
91
+
66
92
  # OpenAI lazy proxy + safe stdio + proxy URL helpers — see agent/process_bootstrap.py.
67
93
  # `OpenAI` is re-exported here so `patch("run_agent.OpenAI", ...)` in tests works.
68
94
  # The other `# noqa: F401` re-exports below cover names accessed via
@@ -143,7 +169,7 @@ from agent.codex_responses_adapter import (
143
169
  _derive_responses_function_call_id as _codex_derive_responses_function_call_id,
144
170
  _deterministic_call_id as _codex_deterministic_call_id,
145
171
  _split_responses_tool_id as _codex_split_responses_tool_id,
146
- _summarize_user_message_for_log, # noqa: F401 # re-exported for tests
172
+ _summarize_user_message_for_log, # also used by _sync_external_memory_for_turn (memory boundary)
147
173
  )
148
174
  from agent.tool_guardrails import (
149
175
  ToolGuardrailDecision,
@@ -170,7 +196,7 @@ from agent.tool_dispatch_helpers import (
170
196
  _extract_error_preview,
171
197
  _trajectory_normalize_msg, # noqa: F401 # re-exported for tests that `from run_agent import _trajectory_normalize_msg`
172
198
  )
173
- from utils import atomic_json_write, base_url_host_matches, base_url_hostname
199
+ from utils import atomic_json_write, base_url_host_matches, base_url_hostname, is_truthy_value, model_forces_max_completion_tokens
174
200
 
175
201
 
176
202
 
@@ -332,6 +358,7 @@ class AIAgent:
332
358
  save_trajectories: bool = False,
333
359
  verbose_logging: bool = False,
334
360
  quiet_mode: bool = False,
361
+ tool_progress_mode: str = "all",
335
362
  ephemeral_system_prompt: str = None,
336
363
  log_prefix_chars: int = 100,
337
364
  log_prefix: str = "",
@@ -349,11 +376,15 @@ class AIAgent:
349
376
  thinking_callback: callable = None,
350
377
  reasoning_callback: callable = None,
351
378
  clarify_callback: callable = None,
379
+ read_terminal_callback: callable = None,
352
380
  step_callback: callable = None,
353
381
  stream_delta_callback: callable = None,
354
382
  interim_assistant_callback: callable = None,
355
383
  tool_gen_callback: callable = None,
356
384
  status_callback: callable = None,
385
+ notice_callback: callable = None,
386
+ notice_clear_callback: callable = None,
387
+ event_callback: Optional[Callable[[str, dict], None]] = None,
357
388
  max_tokens: int = None,
358
389
  reasoning_config: Dict[str, Any] = None,
359
390
  service_tier: str = None,
@@ -402,6 +433,7 @@ class AIAgent:
402
433
  save_trajectories=save_trajectories,
403
434
  verbose_logging=verbose_logging,
404
435
  quiet_mode=quiet_mode,
436
+ tool_progress_mode=tool_progress_mode,
405
437
  ephemeral_system_prompt=ephemeral_system_prompt,
406
438
  log_prefix_chars=log_prefix_chars,
407
439
  log_prefix=log_prefix,
@@ -419,11 +451,15 @@ class AIAgent:
419
451
  thinking_callback=thinking_callback,
420
452
  reasoning_callback=reasoning_callback,
421
453
  clarify_callback=clarify_callback,
454
+ read_terminal_callback=read_terminal_callback,
422
455
  step_callback=step_callback,
423
456
  stream_delta_callback=stream_delta_callback,
424
457
  interim_assistant_callback=interim_assistant_callback,
425
458
  tool_gen_callback=tool_gen_callback,
426
459
  status_callback=status_callback,
460
+ notice_callback=notice_callback,
461
+ notice_clear_callback=notice_clear_callback,
462
+ event_callback=event_callback,
427
463
  max_tokens=max_tokens,
428
464
  reasoning_config=reasoning_config,
429
465
  service_tier=service_tier,
@@ -476,15 +512,17 @@ class AIAgent:
476
512
  """Create session DB row on first use. Disables _session_db on failure."""
477
513
  if self._session_db_created or not self._session_db:
478
514
  return
515
+ source = self.platform or os.environ.get("HERMES_SESSION_SOURCE", "cli")
479
516
  try:
480
517
  self._session_db.create_session(
481
518
  session_id=self.session_id,
482
- source=self.platform or os.environ.get("HERMES_SESSION_SOURCE", "cli"),
519
+ source=source,
483
520
  model=self.model,
484
521
  model_config=self._session_init_model_config,
485
522
  system_prompt=self._cached_system_prompt,
486
523
  user_id=None,
487
524
  parent_session_id=self._parent_session_id,
525
+ cwd=_launch_cwd_for_session(source),
488
526
  )
489
527
  self._session_db_created = True
490
528
  except Exception as e:
@@ -768,6 +806,27 @@ class AIAgent:
768
806
  except Exception:
769
807
  logger.debug("status_callback error in _emit_warning", exc_info=True)
770
808
 
809
+ def _emit_notice(self, notice) -> None:
810
+ """Fire a structured ``AgentNotice`` to the active driver (TUI / CLI).
811
+
812
+ Driver-agnostic: the bound ``notice_callback`` renders it however that
813
+ driver does (TUI status-bar override, CLI console line). Swallows all
814
+ callback errors — a notice must NEVER break the agent loop (D-D fail-open).
815
+ """
816
+ if self.notice_callback:
817
+ try:
818
+ self.notice_callback(notice)
819
+ except Exception:
820
+ logger.debug("notice_callback error in _emit_notice", exc_info=True)
821
+
822
+ def _emit_notice_clear(self, key: str) -> None:
823
+ """Clear a previously-fired sticky notice by ``key`` (e.g. on recovery)."""
824
+ if self.notice_clear_callback:
825
+ try:
826
+ self.notice_clear_callback(key)
827
+ except Exception:
828
+ logger.debug("notice_clear_callback error in _emit_notice_clear", exc_info=True)
829
+
771
830
  # ── Buffered retry/fallback status ────────────────────────────────────
772
831
  # Retry and fallback chains were flooding the CLI/gateway with status
773
832
  # noise that users found confusing: a single transient 429 could produce
@@ -1196,13 +1255,24 @@ class AIAgent:
1196
1255
  def _max_tokens_param(self, value: int) -> dict:
1197
1256
  """Return the correct max tokens kwarg for the current provider.
1198
1257
 
1199
- OpenAI's newer models (gpt-4o, o-series, gpt-5+) require
1200
- 'max_completion_tokens'. Azure OpenAI also requires
1201
- 'max_completion_tokens' for gpt-5.x models served via the
1202
- OpenAI-compatible endpoint. OpenRouter, local models, and older
1258
+ OpenAI's newer models (gpt-4o, gpt-4.1, gpt-5+, o-series) require
1259
+ 'max_completion_tokens'. Azure OpenAI and GitHub Copilot also require
1260
+ 'max_completion_tokens' for those families served via their
1261
+ OpenAI-compatible endpoints. OpenRouter, local models, and older
1203
1262
  OpenAI models use 'max_tokens'.
1263
+
1264
+ The check is URL-first (api.openai.com / Azure / Copilot all use the
1265
+ new kwarg), then falls back to a model-name check so third-party
1266
+ OpenAI-compatible endpoints fronting those models are recognised —
1267
+ URL-only detection misses that case and silently sends the wrong
1268
+ kwarg, which the upstream model rejects with a 400.
1204
1269
  """
1205
- if self._is_direct_openai_url() or self._is_azure_openai_url() or self._is_github_copilot_url():
1270
+ if (
1271
+ self._is_direct_openai_url()
1272
+ or self._is_azure_openai_url()
1273
+ or self._is_github_copilot_url()
1274
+ or model_forces_max_completion_tokens(self.model)
1275
+ ):
1206
1276
  return {"max_completion_tokens": value}
1207
1277
  return {"max_tokens": value}
1208
1278
 
@@ -1343,10 +1413,15 @@ class AIAgent:
1343
1413
  def _summarize_background_review_actions(
1344
1414
  review_messages: List[Dict],
1345
1415
  prior_snapshot: List[Dict],
1416
+ notification_mode: str = "on",
1346
1417
  ) -> List[str]:
1347
1418
  """Forwarder — see ``agent.background_review.summarize_background_review_actions``."""
1348
1419
  from agent.background_review import summarize_background_review_actions
1349
- return summarize_background_review_actions(review_messages, prior_snapshot)
1420
+ return summarize_background_review_actions(
1421
+ review_messages,
1422
+ prior_snapshot,
1423
+ notification_mode=notification_mode,
1424
+ )
1350
1425
 
1351
1426
  def _spawn_background_review(
1352
1427
  self,
@@ -1397,16 +1472,29 @@ class AIAgent:
1397
1472
  that synthetic text leak into persisted transcripts or resumed session
1398
1473
  history. When an override is configured for the active turn, mutate the
1399
1474
  in-memory messages list in place so both persistence and returned
1400
- history stay clean.
1475
+ history stay clean. A paired timestamp override preserves the platform
1476
+ event time as message metadata, rather than embedding it in content.
1401
1477
  """
1402
1478
  idx = getattr(self, "_persist_user_message_idx", None)
1403
1479
  override = getattr(self, "_persist_user_message_override", None)
1404
- if override is None or idx is None:
1480
+ timestamp = getattr(self, "_persist_user_message_timestamp", None)
1481
+ if idx is None or (override is None and timestamp is None):
1405
1482
  return
1406
1483
  if 0 <= idx < len(messages):
1407
1484
  msg = messages[idx]
1408
1485
  if isinstance(msg, dict) and msg.get("role") == "user":
1409
- msg["content"] = override
1486
+ # Text-only call paths may pass a synthetic API-facing prompt
1487
+ # and a cleaner transcript string separately. Multimodal
1488
+ # turns, however, keep image/audio blocks in the live
1489
+ # messages list that is still used for the API request after
1490
+ # early crash-resilience persistence. Do not replace those
1491
+ # blocks with the text-only persistence override before the
1492
+ # model call is built. The paired timestamp override still
1493
+ # applies — it is metadata, not content.
1494
+ if override is not None and not isinstance(msg.get("content"), list):
1495
+ msg["content"] = override
1496
+ if timestamp is not None:
1497
+ msg["timestamp"] = timestamp
1410
1498
 
1411
1499
  def _persist_session(self, messages: List[Dict], conversation_history: List[Dict] = None):
1412
1500
  """Save session state to both JSON log and SQLite on any exit path.
@@ -1480,9 +1568,10 @@ class AIAgent:
1480
1568
  def _flush_messages_to_session_db(self, messages: List[Dict], conversation_history: List[Dict] = None):
1481
1569
  """Persist any un-flushed messages to the SQLite session store.
1482
1570
 
1483
- Uses _last_flushed_db_idx to track which messages have already been
1484
- written, so repeated calls (from multiple exit paths) only write
1485
- truly new messages — preventing the duplicate-write bug (#860).
1571
+ Uses per-session message identity tracking so repeated calls (from
1572
+ multiple exit paths) only write truly new messages — preventing the
1573
+ duplicate-write bug (#860) without relying on positional slices that
1574
+ can drift after message-sequence repair.
1486
1575
  """
1487
1576
  if not self._session_db:
1488
1577
  return
@@ -1491,9 +1580,41 @@ class AIAgent:
1491
1580
  # Retry row creation if the earlier attempt failed transiently.
1492
1581
  if not self._session_db_created:
1493
1582
  self._ensure_db_session()
1494
- start_idx = len(conversation_history) if conversation_history else 0
1495
- flush_from = max(start_idx, self._last_flushed_db_idx)
1496
- for msg in messages[flush_from:]:
1583
+ # Positional flushing used to slice at
1584
+ # max(len(conversation_history), _last_flushed_db_idx). That
1585
+ # assumes the live `messages` list is the original history plus a
1586
+ # new tail. repair_message_sequence can shrink/merge the history
1587
+ # copy before the final flush, making len(conversation_history)
1588
+ # larger than len(messages); the slice is then empty and delivered
1589
+ # assistant responses never reach state.db (#46053).
1590
+ #
1591
+ # Track object identities instead. `messages` is a shallow copy of
1592
+ # `conversation_history`, so history dicts are skipped by identity,
1593
+ # and new dicts appended during this turn are written once even if
1594
+ # repair compacts the list around them.
1595
+ current_session_id = getattr(self, "session_id", None)
1596
+ flushed_session_id = getattr(self, "_flushed_db_message_session_id", None)
1597
+ if flushed_session_id != current_session_id or self._last_flushed_db_idx == 0:
1598
+ self._flushed_db_message_ids = set()
1599
+ self._flushed_db_message_session_id = current_session_id
1600
+ flushed_ids = getattr(self, "_flushed_db_message_ids", None)
1601
+ if not isinstance(flushed_ids, set):
1602
+ flushed_ids = set()
1603
+ self._flushed_db_message_ids = flushed_ids
1604
+ history_ids = {
1605
+ id(item) for item in (conversation_history or [])
1606
+ if isinstance(item, dict)
1607
+ }
1608
+
1609
+ for msg in messages:
1610
+ if not isinstance(msg, dict):
1611
+ continue
1612
+ msg_id = id(msg)
1613
+ if msg_id in flushed_ids:
1614
+ continue
1615
+ if msg_id in history_ids:
1616
+ flushed_ids.add(msg_id)
1617
+ continue
1497
1618
  role = msg.get("role", "unknown")
1498
1619
  content = msg.get("content")
1499
1620
  # Persist multimodal tool results as their text summary only —
@@ -1531,7 +1652,9 @@ class AIAgent:
1531
1652
  reasoning_details=msg.get("reasoning_details") if role == "assistant" else None,
1532
1653
  codex_reasoning_items=msg.get("codex_reasoning_items") if role == "assistant" else None,
1533
1654
  codex_message_items=msg.get("codex_message_items") if role == "assistant" else None,
1655
+ timestamp=msg.get("timestamp"),
1534
1656
  )
1657
+ flushed_ids.add(msg_id)
1535
1658
  self._last_flushed_db_idx = len(messages)
1536
1659
  except Exception as e:
1537
1660
  logger.warning("Session DB append_message failed: %s", e)
@@ -1717,6 +1840,35 @@ class AIAgent:
1717
1840
  return detail
1718
1841
  return f"{detail}{hint}"
1719
1842
 
1843
+ @staticmethod
1844
+ def _coerce_api_error_detail(value: Any) -> str:
1845
+ """Return a display-safe string for structured provider error fields."""
1846
+ if isinstance(value, str):
1847
+ return value
1848
+ if isinstance(value, dict):
1849
+ for key in ("message", "detail", "error", "code", "type"):
1850
+ nested = value.get(key)
1851
+ if isinstance(nested, str) and nested.strip():
1852
+ return nested
1853
+ for key in ("message", "detail", "error", "code", "type"):
1854
+ if key in value:
1855
+ nested_detail = AIAgent._coerce_api_error_detail(value[key])
1856
+ if nested_detail:
1857
+ return nested_detail
1858
+ try:
1859
+ return json.dumps(value, ensure_ascii=False, sort_keys=True)
1860
+ except TypeError:
1861
+ return str(value)
1862
+ if isinstance(value, (list, tuple)):
1863
+ parts = [
1864
+ AIAgent._coerce_api_error_detail(item)
1865
+ for item in value
1866
+ ]
1867
+ return "; ".join(part for part in parts if part)
1868
+ if value is None:
1869
+ return ""
1870
+ return str(value)
1871
+
1720
1872
  @staticmethod
1721
1873
  def _summarize_api_error(error: Exception) -> str:
1722
1874
  """Extract a human-readable one-liner from an API error.
@@ -1756,6 +1908,7 @@ class AIAgent:
1756
1908
  if msg:
1757
1909
  status_code = getattr(error, "status_code", None)
1758
1910
  prefix = f"HTTP {status_code}: " if status_code else ""
1911
+ msg = AIAgent._coerce_api_error_detail(msg)
1759
1912
  return AIAgent._decorate_xai_entitlement_error(f"{prefix}{msg[:300]}")
1760
1913
 
1761
1914
  # Fallback: truncate the raw string but give more room than 200 chars
@@ -1822,6 +1975,254 @@ class AIAgent:
1822
1975
  summary["total_tokens"] = cu.total_tokens
1823
1976
  return summary
1824
1977
 
1978
+ @staticmethod
1979
+ def _hook_payload_max_chars() -> int:
1980
+ raw = os.getenv("HERMES_PLUGIN_PAYLOAD_MAX_CHARS", "50000")
1981
+ try:
1982
+ return max(1000, int(raw))
1983
+ except (TypeError, ValueError):
1984
+ return 50000
1985
+
1986
+ @staticmethod
1987
+ def _is_sensitive_hook_key(key: Any) -> bool:
1988
+ if not isinstance(key, str):
1989
+ return False
1990
+ lowered = key.lower().replace("-", "_")
1991
+ exact = {
1992
+ "api_key",
1993
+ "authorization",
1994
+ "proxy_authorization",
1995
+ "cookie",
1996
+ "set_cookie",
1997
+ }
1998
+ return lowered in exact or lowered.endswith("_api_key")
1999
+
2000
+ @classmethod
2001
+ def _hook_jsonable(
2002
+ cls,
2003
+ value: Any,
2004
+ *,
2005
+ depth: int = 0,
2006
+ max_depth: int = 8,
2007
+ max_string: int = 8000,
2008
+ max_sequence: int = 200,
2009
+ ) -> Any:
2010
+ if depth > max_depth:
2011
+ return f"<{type(value).__name__} depth limit>"
2012
+ if value is None or isinstance(value, (bool, int, float)):
2013
+ return value
2014
+ if isinstance(value, str):
2015
+ if len(value) > max_string:
2016
+ return value[:max_string] + f"...[truncated {len(value) - max_string} chars]"
2017
+ return value
2018
+ if isinstance(value, (bytes, bytearray)):
2019
+ return f"<{len(value)} bytes>"
2020
+ if isinstance(value, dict):
2021
+ out: Dict[str, Any] = {}
2022
+ for idx, (key, item) in enumerate(value.items()):
2023
+ if idx >= max_sequence:
2024
+ out["_truncated_items"] = len(value) - max_sequence
2025
+ break
2026
+ str_key = str(key)
2027
+ if cls._is_sensitive_hook_key(str_key):
2028
+ out[str_key] = "<redacted>"
2029
+ else:
2030
+ out[str_key] = cls._hook_jsonable(
2031
+ item,
2032
+ depth=depth + 1,
2033
+ max_depth=max_depth,
2034
+ max_string=max_string,
2035
+ max_sequence=max_sequence,
2036
+ )
2037
+ return out
2038
+ if isinstance(value, (list, tuple, set)):
2039
+ seq = list(value)
2040
+ out = [
2041
+ cls._hook_jsonable(
2042
+ item,
2043
+ depth=depth + 1,
2044
+ max_depth=max_depth,
2045
+ max_string=max_string,
2046
+ max_sequence=max_sequence,
2047
+ )
2048
+ for item in seq[:max_sequence]
2049
+ ]
2050
+ if len(seq) > max_sequence:
2051
+ out.append({"_truncated_items": len(seq) - max_sequence})
2052
+ return out
2053
+ try:
2054
+ if hasattr(value, "model_dump"):
2055
+ try:
2056
+ dumped = value.model_dump(mode="json")
2057
+ except TypeError:
2058
+ dumped = value.model_dump()
2059
+ return cls._hook_jsonable(
2060
+ dumped,
2061
+ depth=depth + 1,
2062
+ max_depth=max_depth,
2063
+ max_string=max_string,
2064
+ max_sequence=max_sequence,
2065
+ )
2066
+ except Exception:
2067
+ pass
2068
+ try:
2069
+ from dataclasses import asdict, is_dataclass
2070
+ if is_dataclass(value):
2071
+ return cls._hook_jsonable(
2072
+ asdict(value),
2073
+ depth=depth + 1,
2074
+ max_depth=max_depth,
2075
+ max_string=max_string,
2076
+ max_sequence=max_sequence,
2077
+ )
2078
+ except Exception:
2079
+ pass
2080
+ if isinstance(value, SimpleNamespace):
2081
+ return cls._hook_jsonable(
2082
+ vars(value),
2083
+ depth=depth + 1,
2084
+ max_depth=max_depth,
2085
+ max_string=max_string,
2086
+ max_sequence=max_sequence,
2087
+ )
2088
+ if hasattr(value, "__dict__"):
2089
+ try:
2090
+ public_attrs = {
2091
+ k: v
2092
+ for k, v in vars(value).items()
2093
+ if not str(k).startswith("_")
2094
+ }
2095
+ return cls._hook_jsonable(
2096
+ public_attrs,
2097
+ depth=depth + 1,
2098
+ max_depth=max_depth,
2099
+ max_string=max_string,
2100
+ max_sequence=max_sequence,
2101
+ )
2102
+ except Exception:
2103
+ pass
2104
+ return str(value)[:max_string]
2105
+
2106
+ @classmethod
2107
+ def _sanitize_hook_payload(cls, value: Any) -> Any:
2108
+ payload = cls._hook_jsonable(value)
2109
+ limit = cls._hook_payload_max_chars()
2110
+ try:
2111
+ encoded = json.dumps(payload, ensure_ascii=False, default=str)
2112
+ except Exception:
2113
+ return str(payload)[:limit]
2114
+ if len(encoded) <= limit:
2115
+ return payload
2116
+ payload = cls._hook_jsonable(value, max_string=1000, max_sequence=50)
2117
+ try:
2118
+ encoded = json.dumps(payload, ensure_ascii=False, default=str)
2119
+ except Exception:
2120
+ return str(payload)[:limit]
2121
+ if len(encoded) <= limit:
2122
+ return payload
2123
+ return {
2124
+ "_truncated": True,
2125
+ "original_type": type(value).__name__,
2126
+ "preview": encoded[:limit],
2127
+ }
2128
+
2129
+ def _api_request_payload_for_hook(self, api_kwargs: Optional[Dict[str, Any]]) -> Dict[str, Any]:
2130
+ body = {
2131
+ key: value
2132
+ for key, value in (api_kwargs or {}).items()
2133
+ if key not in {"timeout", "http_client"}
2134
+ }
2135
+ return self._sanitize_hook_payload(
2136
+ {
2137
+ "method": "POST",
2138
+ "body": body,
2139
+ }
2140
+ )
2141
+
2142
+ def _api_response_payload_for_hook(
2143
+ self,
2144
+ response: Any,
2145
+ assistant_message: Any,
2146
+ *,
2147
+ finish_reason: Optional[str],
2148
+ ) -> Dict[str, Any]:
2149
+ # ``tool_calls`` is the raw list of provider SDK objects (e.g.
2150
+ # OpenAI ``ChatCompletionMessageToolCall``). We deliberately hand
2151
+ # the raw objects to ``_sanitize_hook_payload`` and rely on
2152
+ # ``_hook_jsonable`` to normalise them via ``model_dump`` /
2153
+ # ``__dict__`` / dataclass introspection — a future refactor of
2154
+ # the sanitiser MUST preserve that capability or hook subscribers
2155
+ # will receive opaque ``str(obj)`` blobs here.
2156
+ tool_calls = getattr(assistant_message, "tool_calls", None) or []
2157
+ return self._sanitize_hook_payload(
2158
+ {
2159
+ "model": getattr(response, "model", None),
2160
+ "finish_reason": finish_reason,
2161
+ "assistant_message": {
2162
+ "role": getattr(assistant_message, "role", "assistant"),
2163
+ "content": getattr(assistant_message, "content", None),
2164
+ "tool_calls": tool_calls,
2165
+ },
2166
+ "usage": self._usage_summary_for_api_request_hook(response),
2167
+ }
2168
+ )
2169
+
2170
+ def _invoke_api_request_error_hook(
2171
+ self,
2172
+ *,
2173
+ task_id: str,
2174
+ turn_id: str,
2175
+ api_request_id: str,
2176
+ api_call_count: int,
2177
+ api_start_time: float,
2178
+ api_kwargs: Optional[Dict[str, Any]],
2179
+ error_type: str,
2180
+ error_message: str,
2181
+ status_code: Optional[int] = None,
2182
+ retry_count: Optional[int] = None,
2183
+ max_retries: Optional[int] = None,
2184
+ retryable: Optional[bool] = None,
2185
+ reason: Optional[str] = None,
2186
+ ) -> None:
2187
+ # Lazy module import (not from-import) so tests that
2188
+ # ``monkeypatch.setattr("hermes_cli.plugins.has_hook", ...)`` still
2189
+ # take effect on this call site. After first call the import is a
2190
+ # ``sys.modules`` dict lookup, so retries don't repay any real cost.
2191
+ try:
2192
+ from hermes_cli import plugins as _plugins
2193
+
2194
+ if not _plugins.has_hook("api_request_error"):
2195
+ return
2196
+ ended_at = time.time()
2197
+ _plugins.invoke_hook(
2198
+ "api_request_error",
2199
+ task_id=task_id,
2200
+ turn_id=turn_id,
2201
+ api_request_id=api_request_id,
2202
+ session_id=self.session_id or "",
2203
+ platform=self.platform or "",
2204
+ model=self.model,
2205
+ provider=self.provider,
2206
+ base_url=self.base_url,
2207
+ api_mode=self.api_mode,
2208
+ api_call_count=api_call_count,
2209
+ api_duration=ended_at - api_start_time,
2210
+ started_at=api_start_time,
2211
+ ended_at=ended_at,
2212
+ status_code=status_code,
2213
+ retry_count=retry_count,
2214
+ max_retries=max_retries,
2215
+ retryable=retryable,
2216
+ reason=reason,
2217
+ error={
2218
+ "type": error_type,
2219
+ "message": error_message,
2220
+ },
2221
+ request=self._api_request_payload_for_hook(api_kwargs),
2222
+ )
2223
+ except Exception:
2224
+ pass
2225
+
1825
2226
  def _dump_api_request_debug(
1826
2227
  self,
1827
2228
  api_kwargs: Dict[str, Any],
@@ -2418,6 +2819,157 @@ class AIAgent:
2418
2819
  """Return the last captured RateLimitState, or None."""
2419
2820
  return self._rate_limit_state
2420
2821
 
2822
+ def _capture_credits(self, http_response: Any) -> None:
2823
+ """Parse x-nous-credits-* headers, cache CreditsState, fire threshold notices.
2824
+
2825
+ Fail-open throughout — header issues never break the agent loop. The PARSE is
2826
+ swallowed (any error → treated as a miss → keep last-known). The notice
2827
+ EVALUATION/EMIT is a SEPARATE block that WARNS on failure (R1-M2): a bug in the
2828
+ depletion-notice path must not vanish silently under the parse swallow.
2829
+ """
2830
+ # Dev test fixture (HERMES_DEV_CREDITS_FIXTURE): inject a chosen notice state
2831
+ # each turn for repeatable testing, bypassing real headers. Throwaway scaffolding.
2832
+ try:
2833
+ from agent.credits_tracker import dev_fixture_credits_state
2834
+ _fixture = dev_fixture_credits_state()
2835
+ except Exception:
2836
+ _fixture = None
2837
+ if _fixture is not None:
2838
+ self._credits_state = _fixture
2839
+ if self._credits_session_start_micros is None:
2840
+ self._credits_session_start_micros = _fixture.remaining_micros
2841
+ _latch = getattr(self, "_credits_latch", None)
2842
+ if isinstance(_latch, dict):
2843
+ _latch["seen_below_90"] = True # let warn90 fire without a real crossing
2844
+ _used = _fixture.used_fraction
2845
+ logger.info(
2846
+ "credits ▸ [FIXTURE] remaining=%d (%s) · paid=%s · denom=%s · used=%s "
2847
+ "(real headers bypassed — `echo clear` / unset HERMES_DEV_CREDITS_FIXTURE to restore)",
2848
+ _fixture.remaining_micros,
2849
+ _fixture.remaining_usd or "?",
2850
+ _fixture.paid_access,
2851
+ _fixture.denominator_kind,
2852
+ ("%.0f%%" % (_used * 100)) if _used is not None else "n/a",
2853
+ )
2854
+ self._emit_credits_notices()
2855
+ return
2856
+ if http_response is None:
2857
+ return
2858
+ headers = getattr(http_response, "headers", None)
2859
+ if not headers:
2860
+ return
2861
+ _dev = is_truthy_value(os.environ.get("HERMES_DEV_CREDITS"))
2862
+
2863
+ # ── Parse (fail-open → miss; never overwrite good state with None) ──
2864
+ try:
2865
+ from agent.credits_tracker import parse_credits_headers
2866
+ state = parse_credits_headers(headers, provider=self.provider)
2867
+ except Exception:
2868
+ return # parse error → treat as a miss, keep last-known
2869
+ if state is None:
2870
+ if _dev:
2871
+ logger.info(
2872
+ "credits ▸ response had no valid x-nous-credits-* headers "
2873
+ "(miss — producer off / non-Nous path / >TTL stale)"
2874
+ )
2875
+ return
2876
+
2877
+ # retain-last-known: only overwrite on a fresh valid parse
2878
+ self._credits_state = state
2879
+ # Latch session-start remaining the first time we ever see a header
2880
+ if self._credits_session_start_micros is None:
2881
+ self._credits_session_start_micros = state.remaining_micros
2882
+ if _dev:
2883
+ # HERMES_DEV_CREDITS: stream each capture to agent.log — watch live with
2884
+ # `hermes logs -f` (grep 'credits ▸'). Dev-only; silent for normal users.
2885
+ spent = self.get_credits_spent_micros()
2886
+ used = state.used_fraction
2887
+ logger.info(
2888
+ "credits ▸ remaining=%d (%s) · paid=%s · denom=%s · used=%s "
2889
+ "· Δspent=%s · age=%s%s",
2890
+ state.remaining_micros,
2891
+ state.remaining_usd or "?",
2892
+ state.paid_access,
2893
+ state.denominator_kind,
2894
+ ("%.0f%%" % (used * 100)) if used is not None else "n/a",
2895
+ ("%.1f¢" % (spent / 10000)) if spent is not None else "n/a",
2896
+ ("%.0fs" % state.age_seconds) if state.age_seconds != float("inf") else "n/a",
2897
+ (" · disabled=%s" % state.disabled_reason) if state.disabled_reason else "",
2898
+ )
2899
+
2900
+ # Threshold notices — shared with the cold-start seed (see _emit_credits_notices).
2901
+ self._emit_credits_notices()
2902
+
2903
+ def _emit_credits_notices(self) -> None:
2904
+ """Run the threshold policy on the current credits state and emit notices.
2905
+
2906
+ Shared by the warm path (_capture_credits) and the L3 cold-start seed, so a
2907
+ session that opens already depleted warns immediately — not only after the first
2908
+ inference header. Runs only when a notice consumer is bound (messaging binds none
2909
+ → state still cached for /usage, no policy). WARNS on failure rather than
2910
+ swallowing (R1-M2): a depletion-path bug must not vanish silently. Emits clears
2911
+ FIRST, then shows (so depleted lands last in a latest-wins slot).
2912
+ """
2913
+ if getattr(self, "notice_callback", None) is None and getattr(self, "notice_clear_callback", None) is None:
2914
+ return
2915
+ if not self._credits_notices_enabled():
2916
+ return
2917
+ state = getattr(self, "_credits_state", None)
2918
+ if state is None:
2919
+ return
2920
+ try:
2921
+ from agent.credits_tracker import evaluate_credits_notices, is_free_tier_model
2922
+ latch = getattr(self, "_credits_latch", None)
2923
+ if latch is None:
2924
+ latch = self._credits_latch = {"active": set(), "seen_below_90": False, "usage_band": None}
2925
+ # Free-model gate: a depleted account on a free model can still
2926
+ # inference, so the depleted error banner is suppressed. Local-data
2927
+ # only (":free" suffix + pricing-cache peek) — never a network call.
2928
+ model_is_free = is_free_tier_model(
2929
+ getattr(self, "model", "") or "",
2930
+ getattr(self, "base_url", "") or "",
2931
+ )
2932
+ to_show, to_clear = evaluate_credits_notices(state, latch, model_is_free=model_is_free)
2933
+ for key in to_clear: # clears FIRST …
2934
+ self._emit_notice_clear(key)
2935
+ for notice in to_show: # … then shows (depleted lands last in a latest-wins slot)
2936
+ self._emit_notice(notice)
2937
+ except Exception:
2938
+ logger.warning("credits notice evaluation/emit failed", exc_info=True)
2939
+
2940
+ def _credits_notices_enabled(self) -> bool:
2941
+ """Whether credits notices are enabled (config display.credits_notices).
2942
+
2943
+ Read once per agent and cached — the policy runs after every API
2944
+ response, and the setting governs UI noise, not correctness, so a
2945
+ config flip applying on the next session is fine. Fail-open True
2946
+ (preserve current behaviour) on any config error.
2947
+ """
2948
+ cached = getattr(self, "_credits_notices_enabled_cache", None)
2949
+ if cached is not None:
2950
+ return cached
2951
+ enabled = True
2952
+ try:
2953
+ from hermes_cli.config import load_config as _load_config
2954
+ _cfg = _load_config() or {}
2955
+ _display = _cfg.get("display") if isinstance(_cfg, dict) else None
2956
+ if isinstance(_display, dict) and "credits_notices" in _display:
2957
+ enabled = bool(_display.get("credits_notices"))
2958
+ except Exception:
2959
+ enabled = True
2960
+ self._credits_notices_enabled_cache = enabled
2961
+ return enabled
2962
+
2963
+ def get_credits_state(self):
2964
+ """Return the last captured CreditsState, or None."""
2965
+ return self._credits_state
2966
+
2967
+ def get_credits_spent_micros(self):
2968
+ """Session-cumulative micros spent = first_seen_remaining - current_remaining. None if no data."""
2969
+ if self._credits_session_start_micros is None or self._credits_state is None:
2970
+ return None
2971
+ return self._credits_session_start_micros - self._credits_state.remaining_micros
2972
+
2421
2973
  def _check_openrouter_cache_status(self, http_response: Any) -> None:
2422
2974
  """Read X-OpenRouter-Cache-Status from response headers and log it.
2423
2975
 
@@ -2548,17 +3100,24 @@ class AIAgent:
2548
3100
  return
2549
3101
  if not (self._memory_manager and final_response and original_user_message):
2550
3102
  return
3103
+ # Multimodal turns carry content as a list of typed parts; providers
3104
+ # expect plain strings, so flatten to text first (newline-joined for
3105
+ # memory, vs the default space-join used for log/trajectory previews).
3106
+ user_text = _summarize_user_message_for_log(original_user_message, sep="\n")
3107
+ response_text = _summarize_user_message_for_log(final_response, sep="\n")
3108
+ if not (user_text and response_text):
3109
+ return
2551
3110
  try:
2552
3111
  sync_kwargs = {"session_id": self.session_id or ""}
2553
3112
  if messages is not None:
2554
3113
  sync_kwargs["messages"] = messages
2555
3114
  self._memory_manager.sync_all(
2556
- original_user_message,
2557
- final_response,
3115
+ user_text,
3116
+ response_text,
2558
3117
  **sync_kwargs,
2559
3118
  )
2560
3119
  self._memory_manager.queue_prefetch_all(
2561
- original_user_message,
3120
+ user_text,
2562
3121
  session_id=self.session_id or "",
2563
3122
  )
2564
3123
  except Exception:
@@ -2667,6 +3226,17 @@ class AIAgent:
2667
3226
  except Exception:
2668
3227
  pass
2669
3228
 
3229
+ # 6. Free conversation history. Mirrors _release_evicted_agent_soft's
3230
+ # soft-eviction clear — close() is the hard teardown for true session
3231
+ # boundaries (/new, /reset, session expiry), so the message list won't
3232
+ # be reused. Drops the reference proactively rather than waiting for
3233
+ # the agent object itself to be collected, which matters when a caller
3234
+ # still holds the closed agent (e.g. a draining background task).
3235
+ try:
3236
+ self._session_messages = []
3237
+ except Exception:
3238
+ pass
3239
+
2670
3240
  def _hydrate_todo_store(self, history: List[Dict[str, Any]]) -> None:
2671
3241
  """
2672
3242
  Recover todo state from conversation history.
@@ -2756,7 +3326,11 @@ class AIAgent:
2756
3326
  return sanitize_api_messages(messages)
2757
3327
 
2758
3328
  @staticmethod
2759
- def _is_thinking_only_assistant(msg: Dict[str, Any]) -> bool:
3329
+ def _is_thinking_only_assistant(
3330
+ msg: Dict[str, Any],
3331
+ *,
3332
+ drop_codex_reasoning_items: bool = True,
3333
+ ) -> bool:
2760
3334
  """Return True if ``msg`` is an assistant turn whose only payload is reasoning.
2761
3335
 
2762
3336
  "Thinking-only" means the model emitted reasoning (``reasoning`` or
@@ -2807,15 +3381,30 @@ class AIAgent:
2807
3381
  rd = msg.get("reasoning_details")
2808
3382
  if isinstance(rd, list) and rd:
2809
3383
  return True
3384
+ # Codex Responses stores encrypted reasoning state under a separate
3385
+ # assistant-message key. Treat only real reasoning items as
3386
+ # thinking-only; empty/junk lists should fall through to the generic
3387
+ # empty-turn handling instead of being dropped here.
3388
+ codex_items = msg.get("codex_reasoning_items")
3389
+ if drop_codex_reasoning_items and isinstance(codex_items, list):
3390
+ return any(
3391
+ isinstance(item, dict) and item.get("type") == "reasoning"
3392
+ for item in codex_items
3393
+ )
2810
3394
  return False
2811
3395
 
2812
3396
  @staticmethod
2813
3397
  def _drop_thinking_only_and_merge_users(
2814
3398
  messages: List[Dict[str, Any]],
3399
+ *,
3400
+ drop_codex_reasoning_items: bool = True,
2815
3401
  ) -> List[Dict[str, Any]]:
2816
3402
  """Forwarder — see ``agent.agent_runtime_helpers.drop_thinking_only_and_merge_users``."""
2817
3403
  from agent.agent_runtime_helpers import drop_thinking_only_and_merge_users
2818
- return drop_thinking_only_and_merge_users(messages)
3404
+ return drop_thinking_only_and_merge_users(
3405
+ messages,
3406
+ drop_codex_reasoning_items=drop_codex_reasoning_items,
3407
+ )
2819
3408
 
2820
3409
  @staticmethod
2821
3410
  def _cap_delegate_task_calls(tool_calls: list) -> list:
@@ -3389,6 +3978,41 @@ class AIAgent:
3389
3978
  else:
3390
3979
  self._client_kwargs.pop("default_headers", None)
3391
3980
 
3981
+ # User-configured overrides win over URL/profile defaults — keep them
3982
+ # applied across credential swaps and client rebuilds, not just at
3983
+ # first construction.
3984
+ self._apply_user_default_headers()
3985
+
3986
+ def _apply_user_default_headers(self) -> None:
3987
+ """Merge user-configured request headers onto the OpenAI client.
3988
+
3989
+ Reads ``model.default_headers`` from config.yaml and merges it onto
3990
+ ``self._client_kwargs["default_headers"]``, with user values taking
3991
+ precedence over provider- and SDK-supplied defaults.
3992
+
3993
+ This exists for ``custom`` OpenAI-compatible endpoints sitting behind
3994
+ a gateway/WAF that rejects the OpenAI Python SDK's identifying headers
3995
+ (``User-Agent: OpenAI/Python ...``, ``X-Stainless-*``). Setting e.g.
3996
+ ``model.default_headers: {User-Agent: curl/8.7.1}`` lets the request
3997
+ reach such an upstream instead of failing with an opaque 4xx/502 even
3998
+ though the same body works under ``curl``. (#40033)
3999
+
4000
+ Delegates the config read + merge to
4001
+ ``agent.auxiliary_client._apply_user_default_headers`` so the main and
4002
+ auxiliary clients can never drift on precedence or value handling.
4003
+
4004
+ No-op for Anthropic/Bedrock modes, which don't use the OpenAI client,
4005
+ and when no overrides are configured.
4006
+ """
4007
+ if self.api_mode in ("anthropic_messages", "bedrock_converse"):
4008
+ return
4009
+ from agent.auxiliary_client import (
4010
+ _apply_user_default_headers as _merge_user_headers,
4011
+ )
4012
+ merged = _merge_user_headers(self._client_kwargs.get("default_headers"))
4013
+ if merged:
4014
+ self._client_kwargs["default_headers"] = merged
4015
+
3392
4016
  def _swap_credential(self, entry) -> None:
3393
4017
  runtime_key = getattr(entry, "runtime_api_key", None) or getattr(entry, "access_token", "")
3394
4018
  runtime_base = getattr(entry, "runtime_base_url", None) or getattr(entry, "base_url", None) or self.base_url
@@ -3449,7 +4073,16 @@ class AIAgent:
3449
4073
  def _anthropic_messages_create(self, api_kwargs: dict):
3450
4074
  if self.api_mode == "anthropic_messages":
3451
4075
  self._try_refresh_anthropic_client_credentials()
3452
- return self._anthropic_client.messages.create(**api_kwargs)
4076
+ # Defensive: strip Responses-only kwargs that can leak in under an
4077
+ # api_mode-flip race (the Anthropic SDK raises a non-retryable
4078
+ # TypeError on them). See #31673.
4079
+ from agent.anthropic_adapter import create_anthropic_message
4080
+ return create_anthropic_message(
4081
+ self._anthropic_client,
4082
+ api_kwargs,
4083
+ log_prefix=getattr(self, "log_prefix", ""),
4084
+ prefer_stream=not bool(getattr(self, "_disable_streaming", False)),
4085
+ )
3453
4086
 
3454
4087
  def _rebuild_anthropic_client(self) -> None:
3455
4088
  """Rebuild the Anthropic client after an interrupt or stale call.
@@ -3800,6 +4433,23 @@ class AIAgent:
3800
4433
  except Exception:
3801
4434
  return False
3802
4435
 
4436
+ def _provider_supports_vision_tool_messages(self) -> bool:
4437
+ """Return True if the active provider accepts list-type tool content.
4438
+
4439
+ Some providers (e.g. Xiaomi MiMo) support multimodal user messages
4440
+ but reject list-type tool message content with 400 errors. This
4441
+ checks the provider profile's ``supports_vision_tool_messages`` field.
4442
+ """
4443
+ try:
4444
+ from providers import get_provider_profile
4445
+ provider = (getattr(self, "provider", "") or "").strip()
4446
+ profile = get_provider_profile(provider)
4447
+ if profile is not None:
4448
+ return getattr(profile, "supports_vision_tool_messages", True)
4449
+ except Exception:
4450
+ pass
4451
+ return True # default: assume compatible
4452
+
3803
4453
  def _preprocess_anthropic_content(self, content: Any, role: str) -> Any:
3804
4454
  if not self._content_has_image_parts(content):
3805
4455
  return content
@@ -3939,13 +4589,17 @@ class AIAgent:
3939
4589
  return content
3940
4590
 
3941
4591
  if self._model_supports_vision():
3942
- # Vision-capable on paper — but if we've already learned in this
3943
- # session that the active (provider, model) rejects list-type
3944
- # tool content (e.g. Xiaomi MiMo's 400 "text is not set"),
3945
- # short-circuit to a text summary so we don't burn another
3946
- # round-trip relearning the same lesson. Cache populated by
3947
- # the 400 recovery path in agent.conversation_loop. Transient
3948
- # per-session; next session retries.
4592
+ # Vision-capable on paper — but if the provider rejects list-type
4593
+ # tool content (e.g. Xiaomi MiMo's 400 "text is not set"), or if
4594
+ # we've already learned this lesson in-session, short-circuit to
4595
+ # a text summary so we don't burn a round-trip relearning it.
4596
+ if not self._provider_supports_vision_tool_messages():
4597
+ logger.debug(
4598
+ "Tool %s: provider %s does not accept list-type tool "
4599
+ "content — sending text summary",
4600
+ tool_name, getattr(self, "provider", ""),
4601
+ )
4602
+ return _multimodal_text_summary(result)
3949
4603
  key = (
3950
4604
  (getattr(self, "provider", "") or "").strip().lower(),
3951
4605
  (getattr(self, "model", "") or "").strip(),
@@ -3981,10 +4635,18 @@ class AIAgent:
3981
4635
  )
3982
4636
  return summary
3983
4637
 
3984
- def _try_shrink_image_parts_in_messages(self, api_messages: list) -> bool:
4638
+ def _try_shrink_image_parts_in_messages(
4639
+ self,
4640
+ api_messages: list,
4641
+ *,
4642
+ max_dimension: int = 8000,
4643
+ ) -> bool:
3985
4644
  """Forwarder — see ``agent.conversation_compression.try_shrink_image_parts_in_messages``."""
3986
4645
  from agent.conversation_compression import try_shrink_image_parts_in_messages
3987
- return try_shrink_image_parts_in_messages(api_messages)
4646
+ return try_shrink_image_parts_in_messages(
4647
+ api_messages,
4648
+ max_dimension=max_dimension,
4649
+ )
3988
4650
 
3989
4651
  def _try_strip_image_parts_from_tool_messages(self, api_messages: list) -> bool:
3990
4652
  """Downgrade list-type tool messages to text summaries in-place.
@@ -4379,7 +5041,7 @@ class AIAgent:
4379
5041
  return reapply_reasoning_echo_for_provider(self, api_messages)
4380
5042
 
4381
5043
  @staticmethod
4382
- def _sanitize_tool_calls_for_strict_api(api_msg: dict) -> dict:
5044
+ def _sanitize_tool_calls_for_strict_api(api_msg: dict, model: "str | None" = None) -> dict:
4383
5045
  """Strip Codex Responses API fields from tool_calls for strict providers.
4384
5046
 
4385
5047
  Providers like Mistral, Fireworks, and other strict OpenAI-compatible APIs
@@ -4388,17 +5050,26 @@ class AIAgent:
4388
5050
  the internal message history — this method only modifies the outgoing
4389
5051
  API copy.
4390
5052
 
5053
+ ``extra_content`` (Gemini thought_signature) is also stripped — strict
5054
+ providers reject it with "Extra inputs are not permitted" — UNLESS the
5055
+ outgoing ``model`` is itself Gemini-family, in which case it must be
5056
+ replayed (Gemini 3 thinking models 400 without it). Defaults to
5057
+ stripping when no model is supplied.
5058
+
4391
5059
  Creates new tool_call dicts rather than mutating in-place, so the
4392
5060
  original messages list retains call_id/response_item_id for Codex
4393
5061
  Responses API compatibility (e.g. if the session falls back to a
4394
5062
  Codex provider later).
4395
5063
 
4396
- Fields stripped: call_id, response_item_id
5064
+ Fields stripped: call_id, response_item_id, extra_content (model-gated)
4397
5065
  """
4398
5066
  tool_calls = api_msg.get("tool_calls")
4399
5067
  if not isinstance(tool_calls, list):
4400
5068
  return api_msg
5069
+ from agent.transports.chat_completions import _model_consumes_thought_signature
4401
5070
  _STRIP_KEYS = {"call_id", "response_item_id"}
5071
+ if not _model_consumes_thought_signature(model):
5072
+ _STRIP_KEYS = _STRIP_KEYS | {"extra_content"}
4402
5073
  api_msg["tool_calls"] = [
4403
5074
  {k: v for k, v in tc.items() if k not in _STRIP_KEYS}
4404
5075
  if isinstance(tc, dict) else tc
@@ -4522,15 +5193,28 @@ class AIAgent:
4522
5193
  acp_command=function_args.get("acp_command"),
4523
5194
  acp_args=function_args.get("acp_args"),
4524
5195
  role=function_args.get("role"),
5196
+ background=function_args.get("background"),
4525
5197
  parent_agent=self,
4526
5198
  )
4527
5199
 
4528
5200
  def _invoke_tool(self, function_name: str, function_args: dict, effective_task_id: str,
4529
5201
  tool_call_id: Optional[str] = None, messages: list = None,
4530
- pre_tool_block_checked: bool = False) -> str:
5202
+ pre_tool_block_checked: bool = False,
5203
+ skip_tool_request_middleware: bool = False,
5204
+ tool_request_middleware_trace: Optional[list[dict[str, Any]]] = None) -> str:
4531
5205
  """Forwarder — see ``agent.agent_runtime_helpers.invoke_tool``."""
4532
5206
  from agent.agent_runtime_helpers import invoke_tool
4533
- return invoke_tool(self, function_name, function_args, effective_task_id, tool_call_id, messages, pre_tool_block_checked)
5207
+ return invoke_tool(
5208
+ self,
5209
+ function_name,
5210
+ function_args,
5211
+ effective_task_id,
5212
+ tool_call_id,
5213
+ messages,
5214
+ pre_tool_block_checked,
5215
+ skip_tool_request_middleware,
5216
+ tool_request_middleware_trace,
5217
+ )
4534
5218
 
4535
5219
  @staticmethod
4536
5220
  def _wrap_verbose(label: str, text: str, indent: str = " ") -> str:
@@ -4580,10 +5264,20 @@ class AIAgent:
4580
5264
  task_id: str = None,
4581
5265
  stream_callback: Optional[callable] = None,
4582
5266
  persist_user_message: Optional[str] = None,
5267
+ persist_user_timestamp: Optional[float] = None,
4583
5268
  ) -> Dict[str, Any]:
4584
5269
  """Forwarder — see ``agent.conversation_loop.run_conversation``."""
4585
5270
  from agent.conversation_loop import run_conversation
4586
- return run_conversation(self, user_message, system_message, conversation_history, task_id, stream_callback, persist_user_message)
5271
+ return run_conversation(
5272
+ self,
5273
+ user_message,
5274
+ system_message,
5275
+ conversation_history,
5276
+ task_id,
5277
+ stream_callback,
5278
+ persist_user_message,
5279
+ persist_user_timestamp,
5280
+ )
4587
5281
 
4588
5282
  def chat(self, message: str, stream_callback: Optional[callable] = None) -> str:
4589
5283
  """