calvyn-code 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1718) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +217 -0
  3. package/README.zh-CN.md +180 -0
  4. package/acp_adapter/__init__.py +1 -0
  5. package/acp_adapter/__main__.py +5 -0
  6. package/acp_adapter/auth.py +68 -0
  7. package/acp_adapter/bootstrap/__init__.py +0 -0
  8. package/acp_adapter/bootstrap/bootstrap_browser_tools.ps1 +288 -0
  9. package/acp_adapter/bootstrap/bootstrap_browser_tools.sh +399 -0
  10. package/acp_adapter/entry.py +292 -0
  11. package/acp_adapter/events.py +265 -0
  12. package/acp_adapter/permissions.py +148 -0
  13. package/acp_adapter/server.py +1713 -0
  14. package/acp_adapter/session.py +629 -0
  15. package/acp_adapter/tools.py +1180 -0
  16. package/agent/__init__.py +6 -0
  17. package/agent/__pycache__/__init__.cpython-312.pyc +0 -0
  18. package/agent/__pycache__/account_usage.cpython-312.pyc +0 -0
  19. package/agent/__pycache__/anthropic_adapter.cpython-312.pyc +0 -0
  20. package/agent/__pycache__/async_utils.cpython-312.pyc +0 -0
  21. package/agent/__pycache__/auxiliary_client.cpython-312.pyc +0 -0
  22. package/agent/__pycache__/codex_responses_adapter.cpython-312.pyc +0 -0
  23. package/agent/__pycache__/context_compressor.cpython-312.pyc +0 -0
  24. package/agent/__pycache__/context_engine.cpython-312.pyc +0 -0
  25. package/agent/__pycache__/context_references.cpython-312.pyc +0 -0
  26. package/agent/__pycache__/credential_pool.cpython-312.pyc +0 -0
  27. package/agent/__pycache__/curator.cpython-312.pyc +0 -0
  28. package/agent/__pycache__/display.cpython-312.pyc +0 -0
  29. package/agent/__pycache__/error_classifier.cpython-312.pyc +0 -0
  30. package/agent/__pycache__/file_safety.cpython-312.pyc +0 -0
  31. package/agent/__pycache__/google_code_assist.cpython-312.pyc +0 -0
  32. package/agent/__pycache__/google_oauth.cpython-312.pyc +0 -0
  33. package/agent/__pycache__/i18n.cpython-312.pyc +0 -0
  34. package/agent/__pycache__/image_gen_provider.cpython-312.pyc +0 -0
  35. package/agent/__pycache__/image_gen_registry.cpython-312.pyc +0 -0
  36. package/agent/__pycache__/insights.cpython-312.pyc +0 -0
  37. package/agent/__pycache__/lmstudio_reasoning.cpython-312.pyc +0 -0
  38. package/agent/__pycache__/manual_compression_feedback.cpython-312.pyc +0 -0
  39. package/agent/__pycache__/markdown_tables.cpython-312.pyc +0 -0
  40. package/agent/__pycache__/memory_manager.cpython-312.pyc +0 -0
  41. package/agent/__pycache__/memory_provider.cpython-312.pyc +0 -0
  42. package/agent/__pycache__/model_metadata.cpython-312.pyc +0 -0
  43. package/agent/__pycache__/models_dev.cpython-312.pyc +0 -0
  44. package/agent/__pycache__/moonshot_schema.cpython-312.pyc +0 -0
  45. package/agent/__pycache__/onboarding.cpython-312.pyc +0 -0
  46. package/agent/__pycache__/portal_tags.cpython-312.pyc +0 -0
  47. package/agent/__pycache__/prompt_builder.cpython-312.pyc +0 -0
  48. package/agent/__pycache__/prompt_caching.cpython-312.pyc +0 -0
  49. package/agent/__pycache__/redact.cpython-312.pyc +0 -0
  50. package/agent/__pycache__/retry_utils.cpython-312.pyc +0 -0
  51. package/agent/__pycache__/shell_hooks.cpython-312.pyc +0 -0
  52. package/agent/__pycache__/skill_commands.cpython-312.pyc +0 -0
  53. package/agent/__pycache__/skill_preprocessing.cpython-312.pyc +0 -0
  54. package/agent/__pycache__/skill_utils.cpython-312.pyc +0 -0
  55. package/agent/__pycache__/subdirectory_hints.cpython-312.pyc +0 -0
  56. package/agent/__pycache__/think_scrubber.cpython-312.pyc +0 -0
  57. package/agent/__pycache__/title_generator.cpython-312.pyc +0 -0
  58. package/agent/__pycache__/tool_guardrails.cpython-312.pyc +0 -0
  59. package/agent/__pycache__/tool_result_classification.cpython-312.pyc +0 -0
  60. package/agent/__pycache__/trajectory.cpython-312.pyc +0 -0
  61. package/agent/__pycache__/usage_pricing.cpython-312.pyc +0 -0
  62. package/agent/__pycache__/video_gen_provider.cpython-312.pyc +0 -0
  63. package/agent/__pycache__/video_gen_registry.cpython-312.pyc +0 -0
  64. package/agent/__pycache__/web_search_provider.cpython-312.pyc +0 -0
  65. package/agent/__pycache__/web_search_registry.cpython-312.pyc +0 -0
  66. package/agent/account_usage.py +326 -0
  67. package/agent/anthropic_adapter.py +2087 -0
  68. package/agent/async_utils.py +68 -0
  69. package/agent/auxiliary_client.py +4893 -0
  70. package/agent/bedrock_adapter.py +1276 -0
  71. package/agent/codex_responses_adapter.py +1084 -0
  72. package/agent/context_compressor.py +1583 -0
  73. package/agent/context_engine.py +211 -0
  74. package/agent/context_references.py +519 -0
  75. package/agent/copilot_acp_client.py +684 -0
  76. package/agent/credential_pool.py +1780 -0
  77. package/agent/credential_sources.py +449 -0
  78. package/agent/curator.py +1782 -0
  79. package/agent/curator_backup.py +694 -0
  80. package/agent/display.py +987 -0
  81. package/agent/error_classifier.py +1058 -0
  82. package/agent/file_safety.py +112 -0
  83. package/agent/gemini_cloudcode_adapter.py +909 -0
  84. package/agent/gemini_native_adapter.py +971 -0
  85. package/agent/gemini_schema.py +99 -0
  86. package/agent/google_code_assist.py +452 -0
  87. package/agent/google_oauth.py +1062 -0
  88. package/agent/i18n.py +258 -0
  89. package/agent/image_gen_provider.py +243 -0
  90. package/agent/image_gen_registry.py +145 -0
  91. package/agent/image_routing.py +301 -0
  92. package/agent/insights.py +931 -0
  93. package/agent/lmstudio_reasoning.py +48 -0
  94. package/agent/lsp/__init__.py +106 -0
  95. package/agent/lsp/__pycache__/__init__.cpython-312.pyc +0 -0
  96. package/agent/lsp/__pycache__/cli.cpython-312.pyc +0 -0
  97. package/agent/lsp/__pycache__/client.cpython-312.pyc +0 -0
  98. package/agent/lsp/__pycache__/eventlog.cpython-312.pyc +0 -0
  99. package/agent/lsp/__pycache__/manager.cpython-312.pyc +0 -0
  100. package/agent/lsp/__pycache__/protocol.cpython-312.pyc +0 -0
  101. package/agent/lsp/__pycache__/servers.cpython-312.pyc +0 -0
  102. package/agent/lsp/__pycache__/workspace.cpython-312.pyc +0 -0
  103. package/agent/lsp/cli.py +308 -0
  104. package/agent/lsp/client.py +930 -0
  105. package/agent/lsp/eventlog.py +213 -0
  106. package/agent/lsp/install.py +376 -0
  107. package/agent/lsp/manager.py +644 -0
  108. package/agent/lsp/protocol.py +196 -0
  109. package/agent/lsp/range_shift.py +149 -0
  110. package/agent/lsp/reporter.py +78 -0
  111. package/agent/lsp/servers.py +1040 -0
  112. package/agent/lsp/workspace.py +223 -0
  113. package/agent/manual_compression_feedback.py +49 -0
  114. package/agent/markdown_tables.py +309 -0
  115. package/agent/memory_manager.py +556 -0
  116. package/agent/memory_provider.py +279 -0
  117. package/agent/model_metadata.py +1827 -0
  118. package/agent/models_dev.py +724 -0
  119. package/agent/moonshot_schema.py +231 -0
  120. package/agent/nous_rate_guard.py +326 -0
  121. package/agent/onboarding.py +193 -0
  122. package/agent/plugin_llm.py +1046 -0
  123. package/agent/portal_tags.py +64 -0
  124. package/agent/prompt_builder.py +1457 -0
  125. package/agent/prompt_caching.py +79 -0
  126. package/agent/rate_limit_tracker.py +246 -0
  127. package/agent/redact.py +403 -0
  128. package/agent/retry_utils.py +57 -0
  129. package/agent/shell_hooks.py +837 -0
  130. package/agent/skill_commands.py +502 -0
  131. package/agent/skill_preprocessing.py +131 -0
  132. package/agent/skill_utils.py +512 -0
  133. package/agent/subdirectory_hints.py +224 -0
  134. package/agent/think_scrubber.py +386 -0
  135. package/agent/title_generator.py +171 -0
  136. package/agent/tool_guardrails.py +458 -0
  137. package/agent/tool_result_classification.py +26 -0
  138. package/agent/trajectory.py +56 -0
  139. package/agent/transports/__init__.py +68 -0
  140. package/agent/transports/__pycache__/__init__.cpython-312.pyc +0 -0
  141. package/agent/transports/__pycache__/anthropic.cpython-312.pyc +0 -0
  142. package/agent/transports/__pycache__/base.cpython-312.pyc +0 -0
  143. package/agent/transports/__pycache__/bedrock.cpython-312.pyc +0 -0
  144. package/agent/transports/__pycache__/chat_completions.cpython-312.pyc +0 -0
  145. package/agent/transports/__pycache__/codex.cpython-312.pyc +0 -0
  146. package/agent/transports/__pycache__/types.cpython-312.pyc +0 -0
  147. package/agent/transports/anthropic.py +179 -0
  148. package/agent/transports/base.py +89 -0
  149. package/agent/transports/bedrock.py +154 -0
  150. package/agent/transports/chat_completions.py +614 -0
  151. package/agent/transports/codex.py +283 -0
  152. package/agent/transports/codex_app_server.py +368 -0
  153. package/agent/transports/codex_app_server_session.py +810 -0
  154. package/agent/transports/codex_event_projector.py +312 -0
  155. package/agent/transports/hermes_tools_mcp_server.py +233 -0
  156. package/agent/transports/types.py +162 -0
  157. package/agent/usage_pricing.py +877 -0
  158. package/agent/video_gen_provider.py +300 -0
  159. package/agent/video_gen_registry.py +117 -0
  160. package/agent/web_search_provider.py +221 -0
  161. package/agent/web_search_registry.py +262 -0
  162. package/assets/banner.png +0 -0
  163. package/batch_runner.py +1303 -0
  164. package/bin/calvyn.js +67 -0
  165. package/calvyn_bootstrap.py +130 -0
  166. package/calvyn_constants.py +346 -0
  167. package/calvyn_logging.py +390 -0
  168. package/calvyn_state.py +2967 -0
  169. package/calvyn_time.py +105 -0
  170. package/cli.py +14160 -0
  171. package/cron/__init__.py +42 -0
  172. package/cron/__pycache__/__init__.cpython-312.pyc +0 -0
  173. package/cron/__pycache__/jobs.cpython-312.pyc +0 -0
  174. package/cron/__pycache__/scheduler.cpython-312.pyc +0 -0
  175. package/cron/jobs.py +1160 -0
  176. package/cron/scheduler.py +1832 -0
  177. package/gateway/__init__.py +35 -0
  178. package/gateway/__pycache__/__init__.cpython-312.pyc +0 -0
  179. package/gateway/__pycache__/channel_directory.cpython-312.pyc +0 -0
  180. package/gateway/__pycache__/config.cpython-312.pyc +0 -0
  181. package/gateway/__pycache__/delivery.cpython-312.pyc +0 -0
  182. package/gateway/__pycache__/display_config.cpython-312.pyc +0 -0
  183. package/gateway/__pycache__/hooks.cpython-312.pyc +0 -0
  184. package/gateway/__pycache__/pairing.cpython-312.pyc +0 -0
  185. package/gateway/__pycache__/platform_registry.cpython-312.pyc +0 -0
  186. package/gateway/__pycache__/restart.cpython-312.pyc +0 -0
  187. package/gateway/__pycache__/run.cpython-312.pyc +0 -0
  188. package/gateway/__pycache__/runtime_footer.cpython-312.pyc +0 -0
  189. package/gateway/__pycache__/session.cpython-312.pyc +0 -0
  190. package/gateway/__pycache__/session_context.cpython-312.pyc +0 -0
  191. package/gateway/__pycache__/shutdown_forensics.cpython-312.pyc +0 -0
  192. package/gateway/__pycache__/slash_access.cpython-312.pyc +0 -0
  193. package/gateway/__pycache__/status.cpython-312.pyc +0 -0
  194. package/gateway/__pycache__/stream_consumer.cpython-312.pyc +0 -0
  195. package/gateway/__pycache__/whatsapp_identity.cpython-312.pyc +0 -0
  196. package/gateway/assets/telegram-botfather-threads-settings.jpg +0 -0
  197. package/gateway/builtin_hooks/__init__.py +1 -0
  198. package/gateway/channel_directory.py +357 -0
  199. package/gateway/config.py +1873 -0
  200. package/gateway/delivery.py +258 -0
  201. package/gateway/display_config.py +206 -0
  202. package/gateway/hooks.py +210 -0
  203. package/gateway/mirror.py +179 -0
  204. package/gateway/pairing.py +322 -0
  205. package/gateway/platform_registry.py +260 -0
  206. package/gateway/platforms/ADDING_A_PLATFORM.md +374 -0
  207. package/gateway/platforms/__init__.py +45 -0
  208. package/gateway/platforms/__pycache__/__init__.cpython-312.pyc +0 -0
  209. package/gateway/platforms/__pycache__/base.cpython-312.pyc +0 -0
  210. package/gateway/platforms/__pycache__/helpers.cpython-312.pyc +0 -0
  211. package/gateway/platforms/__pycache__/telegram.cpython-312.pyc +0 -0
  212. package/gateway/platforms/__pycache__/telegram_network.cpython-312.pyc +0 -0
  213. package/gateway/platforms/__pycache__/yuanbao.cpython-312.pyc +0 -0
  214. package/gateway/platforms/__pycache__/yuanbao_media.cpython-312.pyc +0 -0
  215. package/gateway/platforms/__pycache__/yuanbao_proto.cpython-312.pyc +0 -0
  216. package/gateway/platforms/_http_client_limits.py +84 -0
  217. package/gateway/platforms/api_server.py +3488 -0
  218. package/gateway/platforms/base.py +3747 -0
  219. package/gateway/platforms/bluebubbles.py +937 -0
  220. package/gateway/platforms/dingtalk.py +1473 -0
  221. package/gateway/platforms/discord.py +5584 -0
  222. package/gateway/platforms/email.py +773 -0
  223. package/gateway/platforms/feishu.py +5059 -0
  224. package/gateway/platforms/feishu_comment.py +1382 -0
  225. package/gateway/platforms/feishu_comment_rules.py +430 -0
  226. package/gateway/platforms/helpers.py +279 -0
  227. package/gateway/platforms/homeassistant.py +449 -0
  228. package/gateway/platforms/matrix.py +2777 -0
  229. package/gateway/platforms/mattermost.py +852 -0
  230. package/gateway/platforms/msgraph_webhook.py +397 -0
  231. package/gateway/platforms/qqbot/__init__.py +91 -0
  232. package/gateway/platforms/qqbot/adapter.py +3072 -0
  233. package/gateway/platforms/qqbot/chunked_upload.py +602 -0
  234. package/gateway/platforms/qqbot/constants.py +74 -0
  235. package/gateway/platforms/qqbot/crypto.py +45 -0
  236. package/gateway/platforms/qqbot/keyboards.py +473 -0
  237. package/gateway/platforms/qqbot/onboard.py +220 -0
  238. package/gateway/platforms/qqbot/utils.py +71 -0
  239. package/gateway/platforms/signal.py +1518 -0
  240. package/gateway/platforms/signal_rate_limit.py +369 -0
  241. package/gateway/platforms/slack.py +3028 -0
  242. package/gateway/platforms/sms.py +377 -0
  243. package/gateway/platforms/telegram.py +4836 -0
  244. package/gateway/platforms/telegram_network.py +249 -0
  245. package/gateway/platforms/webhook.py +806 -0
  246. package/gateway/platforms/wecom.py +1610 -0
  247. package/gateway/platforms/wecom_callback.py +403 -0
  248. package/gateway/platforms/wecom_crypto.py +142 -0
  249. package/gateway/platforms/weixin.py +2170 -0
  250. package/gateway/platforms/whatsapp.py +1283 -0
  251. package/gateway/platforms/yuanbao.py +4873 -0
  252. package/gateway/platforms/yuanbao_media.py +645 -0
  253. package/gateway/platforms/yuanbao_proto.py +1209 -0
  254. package/gateway/platforms/yuanbao_sticker.py +558 -0
  255. package/gateway/restart.py +20 -0
  256. package/gateway/run.py +17074 -0
  257. package/gateway/runtime_footer.py +150 -0
  258. package/gateway/session.py +1399 -0
  259. package/gateway/session_context.py +156 -0
  260. package/gateway/shutdown_forensics.py +462 -0
  261. package/gateway/slash_access.py +229 -0
  262. package/gateway/status.py +972 -0
  263. package/gateway/sticker_cache.py +111 -0
  264. package/gateway/stream_consumer.py +1286 -0
  265. package/gateway/whatsapp_identity.py +156 -0
  266. package/hermes_cli/__init__.py +47 -0
  267. package/hermes_cli/__pycache__/__init__.cpython-312.pyc +0 -0
  268. package/hermes_cli/__pycache__/_parser.cpython-312.pyc +0 -0
  269. package/hermes_cli/__pycache__/auth.cpython-312.pyc +0 -0
  270. package/hermes_cli/__pycache__/banner.cpython-312.pyc +0 -0
  271. package/hermes_cli/__pycache__/browser_connect.cpython-312.pyc +0 -0
  272. package/hermes_cli/__pycache__/callbacks.cpython-312.pyc +0 -0
  273. package/hermes_cli/__pycache__/checkpoints.cpython-312.pyc +0 -0
  274. package/hermes_cli/__pycache__/cli_output.cpython-312.pyc +0 -0
  275. package/hermes_cli/__pycache__/codex_models.cpython-312.pyc +0 -0
  276. package/hermes_cli/__pycache__/codex_runtime_switch.cpython-312.pyc +0 -0
  277. package/hermes_cli/__pycache__/colors.cpython-312.pyc +0 -0
  278. package/hermes_cli/__pycache__/commands.cpython-312.pyc +0 -0
  279. package/hermes_cli/__pycache__/config.cpython-312.pyc +0 -0
  280. package/hermes_cli/__pycache__/copilot_auth.cpython-312.pyc +0 -0
  281. package/hermes_cli/__pycache__/curator.cpython-312.pyc +0 -0
  282. package/hermes_cli/__pycache__/curses_ui.cpython-312.pyc +0 -0
  283. package/hermes_cli/__pycache__/debug.cpython-312.pyc +0 -0
  284. package/hermes_cli/__pycache__/default_soul.cpython-312.pyc +0 -0
  285. package/hermes_cli/__pycache__/env_loader.cpython-312.pyc +0 -0
  286. package/hermes_cli/__pycache__/fallback_cmd.cpython-312.pyc +0 -0
  287. package/hermes_cli/__pycache__/gateway.cpython-312.pyc +0 -0
  288. package/hermes_cli/__pycache__/gateway_windows.cpython-312.pyc +0 -0
  289. package/hermes_cli/__pycache__/goals.cpython-312.pyc +0 -0
  290. package/hermes_cli/__pycache__/inventory.cpython-312.pyc +0 -0
  291. package/hermes_cli/__pycache__/kanban.cpython-312.pyc +0 -0
  292. package/hermes_cli/__pycache__/kanban_db.cpython-312.pyc +0 -0
  293. package/hermes_cli/__pycache__/main.cpython-312.pyc +0 -0
  294. package/hermes_cli/__pycache__/model_catalog.cpython-312.pyc +0 -0
  295. package/hermes_cli/__pycache__/model_normalize.cpython-312.pyc +0 -0
  296. package/hermes_cli/__pycache__/model_switch.cpython-312.pyc +0 -0
  297. package/hermes_cli/__pycache__/models.cpython-312.pyc +0 -0
  298. package/hermes_cli/__pycache__/nous_subscription.cpython-312.pyc +0 -0
  299. package/hermes_cli/__pycache__/pairing.cpython-312.pyc +0 -0
  300. package/hermes_cli/__pycache__/platforms.cpython-312.pyc +0 -0
  301. package/hermes_cli/__pycache__/plugins.cpython-312.pyc +0 -0
  302. package/hermes_cli/__pycache__/profiles.cpython-312.pyc +0 -0
  303. package/hermes_cli/__pycache__/providers.cpython-312.pyc +0 -0
  304. package/hermes_cli/__pycache__/pt_input_extras.cpython-312.pyc +0 -0
  305. package/hermes_cli/__pycache__/runtime_provider.cpython-312.pyc +0 -0
  306. package/hermes_cli/__pycache__/security_advisories.cpython-312.pyc +0 -0
  307. package/hermes_cli/__pycache__/setup.cpython-312.pyc +0 -0
  308. package/hermes_cli/__pycache__/skills_hub.cpython-312.pyc +0 -0
  309. package/hermes_cli/__pycache__/skin_engine.cpython-312.pyc +0 -0
  310. package/hermes_cli/__pycache__/stdio.cpython-312.pyc +0 -0
  311. package/hermes_cli/__pycache__/timeouts.cpython-312.pyc +0 -0
  312. package/hermes_cli/__pycache__/tips.cpython-312.pyc +0 -0
  313. package/hermes_cli/__pycache__/tools_config.cpython-312.pyc +0 -0
  314. package/hermes_cli/__pycache__/voice.cpython-312.pyc +0 -0
  315. package/hermes_cli/_parser.py +365 -0
  316. package/hermes_cli/_subprocess_compat.py +175 -0
  317. package/hermes_cli/auth.py +6299 -0
  318. package/hermes_cli/auth_commands.py +749 -0
  319. package/hermes_cli/azure_detect.py +300 -0
  320. package/hermes_cli/backup.py +938 -0
  321. package/hermes_cli/banner.py +703 -0
  322. package/hermes_cli/browser_connect.py +139 -0
  323. package/hermes_cli/callbacks.py +243 -0
  324. package/hermes_cli/checkpoints.py +244 -0
  325. package/hermes_cli/claw.py +810 -0
  326. package/hermes_cli/cli_output.py +78 -0
  327. package/hermes_cli/clipboard.py +495 -0
  328. package/hermes_cli/codex_models.py +198 -0
  329. package/hermes_cli/codex_runtime_plugin_migration.py +757 -0
  330. package/hermes_cli/codex_runtime_switch.py +266 -0
  331. package/hermes_cli/colors.py +38 -0
  332. package/hermes_cli/commands.py +1728 -0
  333. package/hermes_cli/completion.py +315 -0
  334. package/hermes_cli/config.py +5382 -0
  335. package/hermes_cli/copilot_auth.py +392 -0
  336. package/hermes_cli/cron.py +313 -0
  337. package/hermes_cli/curator.py +598 -0
  338. package/hermes_cli/curses_ui.py +472 -0
  339. package/hermes_cli/debug.py +747 -0
  340. package/hermes_cli/default_soul.py +11 -0
  341. package/hermes_cli/dep_ensure.py +107 -0
  342. package/hermes_cli/dingtalk_auth.py +293 -0
  343. package/hermes_cli/doctor.py +1863 -0
  344. package/hermes_cli/dump.py +326 -0
  345. package/hermes_cli/env_loader.py +175 -0
  346. package/hermes_cli/fallback_cmd.py +361 -0
  347. package/hermes_cli/gateway.py +5422 -0
  348. package/hermes_cli/gateway_windows.py +692 -0
  349. package/hermes_cli/goals.py +757 -0
  350. package/hermes_cli/hooks.py +385 -0
  351. package/hermes_cli/inventory.py +240 -0
  352. package/hermes_cli/kanban.py +2252 -0
  353. package/hermes_cli/kanban_db.py +4840 -0
  354. package/hermes_cli/kanban_diagnostics.py +776 -0
  355. package/hermes_cli/kanban_specify.py +266 -0
  356. package/hermes_cli/logs.py +391 -0
  357. package/hermes_cli/main.py +12396 -0
  358. package/hermes_cli/mcp_config.py +781 -0
  359. package/hermes_cli/memory_setup.py +465 -0
  360. package/hermes_cli/model_catalog.py +330 -0
  361. package/hermes_cli/model_normalize.py +473 -0
  362. package/hermes_cli/model_switch.py +1777 -0
  363. package/hermes_cli/models.py +3789 -0
  364. package/hermes_cli/nous_subscription.py +799 -0
  365. package/hermes_cli/oneshot.py +351 -0
  366. package/hermes_cli/pairing.py +115 -0
  367. package/hermes_cli/platforms.py +83 -0
  368. package/hermes_cli/plugins.py +1562 -0
  369. package/hermes_cli/plugins_cmd.py +1587 -0
  370. package/hermes_cli/profile_distribution.py +703 -0
  371. package/hermes_cli/profiles.py +1319 -0
  372. package/hermes_cli/providers.py +720 -0
  373. package/hermes_cli/proxy/__init__.py +20 -0
  374. package/hermes_cli/proxy/adapters/__init__.py +35 -0
  375. package/hermes_cli/proxy/adapters/base.py +94 -0
  376. package/hermes_cli/proxy/adapters/nous_portal.py +137 -0
  377. package/hermes_cli/proxy/cli.py +141 -0
  378. package/hermes_cli/proxy/server.py +265 -0
  379. package/hermes_cli/pt_input_extras.py +83 -0
  380. package/hermes_cli/pty_bridge.py +237 -0
  381. package/hermes_cli/relaunch.py +205 -0
  382. package/hermes_cli/runtime_provider.py +1428 -0
  383. package/hermes_cli/security_advisories.py +452 -0
  384. package/hermes_cli/setup.py +3559 -0
  385. package/hermes_cli/skills_config.py +177 -0
  386. package/hermes_cli/skills_hub.py +1595 -0
  387. package/hermes_cli/skin_engine.py +929 -0
  388. package/hermes_cli/slack_cli.py +160 -0
  389. package/hermes_cli/status.py +550 -0
  390. package/hermes_cli/stdio.py +252 -0
  391. package/hermes_cli/timeouts.py +82 -0
  392. package/hermes_cli/tips.py +487 -0
  393. package/hermes_cli/tools_config.py +3151 -0
  394. package/hermes_cli/uninstall.py +681 -0
  395. package/hermes_cli/vercel_auth.py +70 -0
  396. package/hermes_cli/voice.py +846 -0
  397. package/hermes_cli/web_server.py +4438 -0
  398. package/hermes_cli/webhook.py +275 -0
  399. package/locales/af.yaml +350 -0
  400. package/locales/de.yaml +350 -0
  401. package/locales/en.yaml +365 -0
  402. package/locales/es.yaml +350 -0
  403. package/locales/fr.yaml +350 -0
  404. package/locales/ga.yaml +354 -0
  405. package/locales/hu.yaml +350 -0
  406. package/locales/it.yaml +350 -0
  407. package/locales/ja.yaml +350 -0
  408. package/locales/ko.yaml +350 -0
  409. package/locales/pt.yaml +350 -0
  410. package/locales/ru.yaml +350 -0
  411. package/locales/tr.yaml +350 -0
  412. package/locales/uk.yaml +350 -0
  413. package/locales/zh-hant.yaml +350 -0
  414. package/locales/zh.yaml +350 -0
  415. package/mcp_serve.py +898 -0
  416. package/model_tools.py +899 -0
  417. package/optional-skills/DESCRIPTION.md +24 -0
  418. package/optional-skills/autonomous-ai-agents/DESCRIPTION.md +2 -0
  419. package/optional-skills/autonomous-ai-agents/blackbox/SKILL.md +144 -0
  420. package/optional-skills/autonomous-ai-agents/honcho/SKILL.md +431 -0
  421. package/optional-skills/blockchain/evm/SKILL.md +211 -0
  422. package/optional-skills/blockchain/evm/scripts/evm_client.py +1508 -0
  423. package/optional-skills/blockchain/hyperliquid/SKILL.md +211 -0
  424. package/optional-skills/blockchain/hyperliquid/scripts/hyperliquid_client.py +1660 -0
  425. package/optional-skills/blockchain/solana/SKILL.md +208 -0
  426. package/optional-skills/blockchain/solana/scripts/solana_client.py +698 -0
  427. package/optional-skills/communication/DESCRIPTION.md +1 -0
  428. package/optional-skills/communication/one-three-one-rule/SKILL.md +104 -0
  429. package/optional-skills/creative/blender-mcp/SKILL.md +117 -0
  430. package/optional-skills/creative/concept-diagrams/SKILL.md +362 -0
  431. package/optional-skills/creative/concept-diagrams/examples/apartment-floor-plan-conversion.md +244 -0
  432. package/optional-skills/creative/concept-diagrams/examples/automated-password-reset-flow.md +276 -0
  433. package/optional-skills/creative/concept-diagrams/examples/autonomous-llm-research-agent-flow.md +240 -0
  434. package/optional-skills/creative/concept-diagrams/examples/banana-journey-tree-to-smoothie.md +161 -0
  435. package/optional-skills/creative/concept-diagrams/examples/commercial-aircraft-structure.md +209 -0
  436. package/optional-skills/creative/concept-diagrams/examples/cpu-ooo-microarchitecture.md +236 -0
  437. package/optional-skills/creative/concept-diagrams/examples/electricity-grid-flow.md +182 -0
  438. package/optional-skills/creative/concept-diagrams/examples/feature-film-production-pipeline.md +172 -0
  439. package/optional-skills/creative/concept-diagrams/examples/hospital-emergency-department-flow.md +165 -0
  440. package/optional-skills/creative/concept-diagrams/examples/ml-benchmark-grouped-bar-chart.md +114 -0
  441. package/optional-skills/creative/concept-diagrams/examples/place-order-uml-sequence.md +325 -0
  442. package/optional-skills/creative/concept-diagrams/examples/smart-city-infrastructure.md +173 -0
  443. package/optional-skills/creative/concept-diagrams/examples/smartphone-layer-anatomy.md +154 -0
  444. package/optional-skills/creative/concept-diagrams/examples/sn2-reaction-mechanism.md +247 -0
  445. package/optional-skills/creative/concept-diagrams/examples/wind-turbine-structure.md +338 -0
  446. package/optional-skills/creative/concept-diagrams/references/dashboard-patterns.md +43 -0
  447. package/optional-skills/creative/concept-diagrams/references/infrastructure-patterns.md +144 -0
  448. package/optional-skills/creative/concept-diagrams/references/physical-shape-cookbook.md +42 -0
  449. package/optional-skills/creative/concept-diagrams/templates/template.html +174 -0
  450. package/optional-skills/creative/hyperframes/SKILL.md +191 -0
  451. package/optional-skills/creative/hyperframes/references/cli.md +185 -0
  452. package/optional-skills/creative/hyperframes/references/composition.md +129 -0
  453. package/optional-skills/creative/hyperframes/references/features.md +289 -0
  454. package/optional-skills/creative/hyperframes/references/gsap.md +136 -0
  455. package/optional-skills/creative/hyperframes/references/troubleshooting.md +137 -0
  456. package/optional-skills/creative/hyperframes/references/website-to-video.md +145 -0
  457. package/optional-skills/creative/hyperframes/scripts/setup.sh +135 -0
  458. package/optional-skills/creative/kanban-video-orchestrator/SKILL.md +207 -0
  459. package/optional-skills/creative/kanban-video-orchestrator/assets/brief.md.tmpl +79 -0
  460. package/optional-skills/creative/kanban-video-orchestrator/assets/setup.sh.tmpl +185 -0
  461. package/optional-skills/creative/kanban-video-orchestrator/assets/soul.md.tmpl +38 -0
  462. package/optional-skills/creative/kanban-video-orchestrator/references/examples.md +227 -0
  463. package/optional-skills/creative/kanban-video-orchestrator/references/intake.md +166 -0
  464. package/optional-skills/creative/kanban-video-orchestrator/references/kanban-setup.md +276 -0
  465. package/optional-skills/creative/kanban-video-orchestrator/references/monitoring.md +180 -0
  466. package/optional-skills/creative/kanban-video-orchestrator/references/role-archetypes.md +298 -0
  467. package/optional-skills/creative/kanban-video-orchestrator/references/tool-matrix.md +317 -0
  468. package/optional-skills/creative/kanban-video-orchestrator/scripts/bootstrap_pipeline.py +501 -0
  469. package/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py +195 -0
  470. package/optional-skills/creative/meme-generation/EXAMPLES.md +46 -0
  471. package/optional-skills/creative/meme-generation/SKILL.md +130 -0
  472. package/optional-skills/creative/meme-generation/scripts/generate_meme.py +471 -0
  473. package/optional-skills/creative/meme-generation/scripts/templates.json +97 -0
  474. package/optional-skills/devops/cli/SKILL.md +156 -0
  475. package/optional-skills/devops/cli/references/app-discovery.md +112 -0
  476. package/optional-skills/devops/cli/references/authentication.md +59 -0
  477. package/optional-skills/devops/cli/references/cli-reference.md +104 -0
  478. package/optional-skills/devops/cli/references/running-apps.md +171 -0
  479. package/optional-skills/devops/docker-management/SKILL.md +281 -0
  480. package/optional-skills/devops/pinggy-tunnel/SKILL.md +309 -0
  481. package/optional-skills/devops/watchers/SKILL.md +112 -0
  482. package/optional-skills/devops/watchers/scripts/_watermark.py +148 -0
  483. package/optional-skills/devops/watchers/scripts/watch_github.py +168 -0
  484. package/optional-skills/devops/watchers/scripts/watch_http_json.py +131 -0
  485. package/optional-skills/devops/watchers/scripts/watch_rss.py +121 -0
  486. package/optional-skills/dogfood/DESCRIPTION.md +3 -0
  487. package/optional-skills/dogfood/adversarial-ux-test/SKILL.md +191 -0
  488. package/optional-skills/email/agentmail/SKILL.md +126 -0
  489. package/optional-skills/finance/3-statement-model/SKILL.md +433 -0
  490. package/optional-skills/finance/3-statement-model/references/formatting.md +118 -0
  491. package/optional-skills/finance/3-statement-model/references/formulas.md +292 -0
  492. package/optional-skills/finance/3-statement-model/references/sec-filings.md +125 -0
  493. package/optional-skills/finance/comps-analysis/SKILL.md +662 -0
  494. package/optional-skills/finance/dcf-model/SKILL.md +1270 -0
  495. package/optional-skills/finance/dcf-model/TROUBLESHOOTING.md +40 -0
  496. package/optional-skills/finance/dcf-model/requirements.txt +7 -0
  497. package/optional-skills/finance/dcf-model/scripts/validate_dcf.py +292 -0
  498. package/optional-skills/finance/excel-author/SKILL.md +244 -0
  499. package/optional-skills/finance/excel-author/scripts/recalc.py +88 -0
  500. package/optional-skills/finance/lbo-model/SKILL.md +291 -0
  501. package/optional-skills/finance/merger-model/SKILL.md +144 -0
  502. package/optional-skills/finance/pptx-author/SKILL.md +173 -0
  503. package/optional-skills/finance/stocks/SKILL.md +95 -0
  504. package/optional-skills/finance/stocks/scripts/stocks_client.py +755 -0
  505. package/optional-skills/health/DESCRIPTION.md +1 -0
  506. package/optional-skills/health/fitness-nutrition/SKILL.md +256 -0
  507. package/optional-skills/health/fitness-nutrition/references/FORMULAS.md +100 -0
  508. package/optional-skills/health/fitness-nutrition/scripts/body_calc.py +210 -0
  509. package/optional-skills/health/fitness-nutrition/scripts/nutrition_search.py +86 -0
  510. package/optional-skills/health/neuroskill-bci/SKILL.md +459 -0
  511. package/optional-skills/health/neuroskill-bci/references/api.md +286 -0
  512. package/optional-skills/health/neuroskill-bci/references/metrics.md +220 -0
  513. package/optional-skills/health/neuroskill-bci/references/protocols.md +452 -0
  514. package/optional-skills/mcp/DESCRIPTION.md +3 -0
  515. package/optional-skills/mcp/fastmcp/SKILL.md +300 -0
  516. package/optional-skills/mcp/fastmcp/references/fastmcp-cli.md +110 -0
  517. package/optional-skills/mcp/fastmcp/scripts/scaffold_fastmcp.py +56 -0
  518. package/optional-skills/mcp/fastmcp/templates/api_wrapper.py +54 -0
  519. package/optional-skills/mcp/fastmcp/templates/database_server.py +77 -0
  520. package/optional-skills/mcp/fastmcp/templates/file_processor.py +55 -0
  521. package/optional-skills/mcp/mcporter/SKILL.md +123 -0
  522. package/optional-skills/migration/DESCRIPTION.md +2 -0
  523. package/optional-skills/migration/openclaw-migration/SKILL.md +298 -0
  524. package/optional-skills/migration/openclaw-migration/scripts/openclaw_to_hermes.py +3136 -0
  525. package/optional-skills/mlops/accelerate/SKILL.md +336 -0
  526. package/optional-skills/mlops/accelerate/references/custom-plugins.md +453 -0
  527. package/optional-skills/mlops/accelerate/references/megatron-integration.md +489 -0
  528. package/optional-skills/mlops/accelerate/references/performance.md +525 -0
  529. package/optional-skills/mlops/chroma/SKILL.md +410 -0
  530. package/optional-skills/mlops/chroma/references/integration.md +38 -0
  531. package/optional-skills/mlops/clip/SKILL.md +257 -0
  532. package/optional-skills/mlops/clip/references/applications.md +207 -0
  533. package/optional-skills/mlops/faiss/SKILL.md +225 -0
  534. package/optional-skills/mlops/faiss/references/index_types.md +280 -0
  535. package/optional-skills/mlops/flash-attention/SKILL.md +367 -0
  536. package/optional-skills/mlops/flash-attention/references/benchmarks.md +215 -0
  537. package/optional-skills/mlops/flash-attention/references/transformers-integration.md +293 -0
  538. package/optional-skills/mlops/guidance/SKILL.md +576 -0
  539. package/optional-skills/mlops/guidance/references/backends.md +554 -0
  540. package/optional-skills/mlops/guidance/references/constraints.md +674 -0
  541. package/optional-skills/mlops/guidance/references/examples.md +767 -0
  542. package/optional-skills/mlops/huggingface-tokenizers/SKILL.md +520 -0
  543. package/optional-skills/mlops/huggingface-tokenizers/references/algorithms.md +653 -0
  544. package/optional-skills/mlops/huggingface-tokenizers/references/integration.md +637 -0
  545. package/optional-skills/mlops/huggingface-tokenizers/references/pipeline.md +723 -0
  546. package/optional-skills/mlops/huggingface-tokenizers/references/training.md +565 -0
  547. package/optional-skills/mlops/inference/outlines/SKILL.md +656 -0
  548. package/optional-skills/mlops/inference/outlines/references/backends.md +615 -0
  549. package/optional-skills/mlops/inference/outlines/references/examples.md +773 -0
  550. package/optional-skills/mlops/inference/outlines/references/json_generation.md +652 -0
  551. package/optional-skills/mlops/instructor/SKILL.md +744 -0
  552. package/optional-skills/mlops/instructor/references/examples.md +107 -0
  553. package/optional-skills/mlops/instructor/references/providers.md +70 -0
  554. package/optional-skills/mlops/instructor/references/validation.md +606 -0
  555. package/optional-skills/mlops/lambda-labs/SKILL.md +549 -0
  556. package/optional-skills/mlops/lambda-labs/references/advanced-usage.md +611 -0
  557. package/optional-skills/mlops/lambda-labs/references/troubleshooting.md +530 -0
  558. package/optional-skills/mlops/llava/SKILL.md +308 -0
  559. package/optional-skills/mlops/llava/references/training.md +197 -0
  560. package/optional-skills/mlops/modal/SKILL.md +345 -0
  561. package/optional-skills/mlops/modal/references/advanced-usage.md +503 -0
  562. package/optional-skills/mlops/modal/references/troubleshooting.md +494 -0
  563. package/optional-skills/mlops/nemo-curator/SKILL.md +387 -0
  564. package/optional-skills/mlops/nemo-curator/references/deduplication.md +87 -0
  565. package/optional-skills/mlops/nemo-curator/references/filtering.md +102 -0
  566. package/optional-skills/mlops/peft/SKILL.md +435 -0
  567. package/optional-skills/mlops/peft/references/advanced-usage.md +514 -0
  568. package/optional-skills/mlops/peft/references/troubleshooting.md +480 -0
  569. package/optional-skills/mlops/pinecone/SKILL.md +362 -0
  570. package/optional-skills/mlops/pinecone/references/deployment.md +181 -0
  571. package/optional-skills/mlops/pytorch-fsdp/SKILL.md +130 -0
  572. package/optional-skills/mlops/pytorch-fsdp/references/index.md +7 -0
  573. package/optional-skills/mlops/pytorch-fsdp/references/other.md +4261 -0
  574. package/optional-skills/mlops/pytorch-lightning/SKILL.md +350 -0
  575. package/optional-skills/mlops/pytorch-lightning/references/callbacks.md +436 -0
  576. package/optional-skills/mlops/pytorch-lightning/references/distributed.md +490 -0
  577. package/optional-skills/mlops/pytorch-lightning/references/hyperparameter-tuning.md +556 -0
  578. package/optional-skills/mlops/qdrant/SKILL.md +497 -0
  579. package/optional-skills/mlops/qdrant/references/advanced-usage.md +648 -0
  580. package/optional-skills/mlops/qdrant/references/troubleshooting.md +631 -0
  581. package/optional-skills/mlops/saelens/SKILL.md +390 -0
  582. package/optional-skills/mlops/saelens/references/README.md +69 -0
  583. package/optional-skills/mlops/saelens/references/api.md +333 -0
  584. package/optional-skills/mlops/saelens/references/tutorials.md +318 -0
  585. package/optional-skills/mlops/simpo/SKILL.md +223 -0
  586. package/optional-skills/mlops/simpo/references/datasets.md +478 -0
  587. package/optional-skills/mlops/simpo/references/hyperparameters.md +452 -0
  588. package/optional-skills/mlops/simpo/references/loss-functions.md +350 -0
  589. package/optional-skills/mlops/slime/SKILL.md +468 -0
  590. package/optional-skills/mlops/slime/references/api-reference.md +392 -0
  591. package/optional-skills/mlops/slime/references/troubleshooting.md +386 -0
  592. package/optional-skills/mlops/stable-diffusion/SKILL.md +523 -0
  593. package/optional-skills/mlops/stable-diffusion/references/advanced-usage.md +716 -0
  594. package/optional-skills/mlops/stable-diffusion/references/troubleshooting.md +555 -0
  595. package/optional-skills/mlops/tensorrt-llm/SKILL.md +191 -0
  596. package/optional-skills/mlops/tensorrt-llm/references/multi-gpu.md +298 -0
  597. package/optional-skills/mlops/tensorrt-llm/references/optimization.md +242 -0
  598. package/optional-skills/mlops/tensorrt-llm/references/serving.md +470 -0
  599. package/optional-skills/mlops/torchtitan/SKILL.md +362 -0
  600. package/optional-skills/mlops/torchtitan/references/checkpoint.md +181 -0
  601. package/optional-skills/mlops/torchtitan/references/custom-models.md +258 -0
  602. package/optional-skills/mlops/torchtitan/references/float8.md +133 -0
  603. package/optional-skills/mlops/torchtitan/references/fsdp.md +126 -0
  604. package/optional-skills/mlops/training/axolotl/SKILL.md +166 -0
  605. package/optional-skills/mlops/training/axolotl/references/api.md +5548 -0
  606. package/optional-skills/mlops/training/axolotl/references/dataset-formats.md +1029 -0
  607. package/optional-skills/mlops/training/axolotl/references/index.md +15 -0
  608. package/optional-skills/mlops/training/axolotl/references/other.md +3563 -0
  609. package/optional-skills/mlops/training/trl-fine-tuning/SKILL.md +463 -0
  610. package/optional-skills/mlops/training/trl-fine-tuning/references/dpo-variants.md +227 -0
  611. package/optional-skills/mlops/training/trl-fine-tuning/references/grpo-training.md +504 -0
  612. package/optional-skills/mlops/training/trl-fine-tuning/references/online-rl.md +82 -0
  613. package/optional-skills/mlops/training/trl-fine-tuning/references/reward-modeling.md +122 -0
  614. package/optional-skills/mlops/training/trl-fine-tuning/references/sft-training.md +168 -0
  615. package/optional-skills/mlops/training/trl-fine-tuning/templates/basic_grpo_training.py +228 -0
  616. package/optional-skills/mlops/training/unsloth/SKILL.md +84 -0
  617. package/optional-skills/mlops/training/unsloth/references/index.md +7 -0
  618. package/optional-skills/mlops/training/unsloth/references/llms-full.md +16799 -0
  619. package/optional-skills/mlops/training/unsloth/references/llms-txt.md +12044 -0
  620. package/optional-skills/mlops/training/unsloth/references/llms.md +82 -0
  621. package/optional-skills/mlops/whisper/SKILL.md +321 -0
  622. package/optional-skills/mlops/whisper/references/languages.md +189 -0
  623. package/optional-skills/productivity/canvas/SKILL.md +98 -0
  624. package/optional-skills/productivity/canvas/scripts/canvas_api.py +157 -0
  625. package/optional-skills/productivity/here-now/SKILL.md +217 -0
  626. package/optional-skills/productivity/here-now/scripts/drive.sh +406 -0
  627. package/optional-skills/productivity/here-now/scripts/publish.sh +445 -0
  628. package/optional-skills/productivity/memento-flashcards/SKILL.md +324 -0
  629. package/optional-skills/productivity/memento-flashcards/scripts/memento_cards.py +353 -0
  630. package/optional-skills/productivity/memento-flashcards/scripts/youtube_quiz.py +88 -0
  631. package/optional-skills/productivity/shop-app/SKILL.md +340 -0
  632. package/optional-skills/productivity/shopify/SKILL.md +373 -0
  633. package/optional-skills/productivity/siyuan/SKILL.md +298 -0
  634. package/optional-skills/productivity/telephony/SKILL.md +418 -0
  635. package/optional-skills/productivity/telephony/scripts/telephony.py +1343 -0
  636. package/optional-skills/research/bioinformatics/SKILL.md +235 -0
  637. package/optional-skills/research/darwinian-evolver/SKILL.md +199 -0
  638. package/optional-skills/research/darwinian-evolver/scripts/parrot_openrouter.py +218 -0
  639. package/optional-skills/research/darwinian-evolver/scripts/show_snapshot.py +69 -0
  640. package/optional-skills/research/darwinian-evolver/templates/custom_problem_template.py +240 -0
  641. package/optional-skills/research/domain-intel/SKILL.md +97 -0
  642. package/optional-skills/research/domain-intel/scripts/domain_intel.py +397 -0
  643. package/optional-skills/research/drug-discovery/SKILL.md +227 -0
  644. package/optional-skills/research/drug-discovery/references/ADMET_REFERENCE.md +66 -0
  645. package/optional-skills/research/drug-discovery/scripts/chembl_target.py +53 -0
  646. package/optional-skills/research/drug-discovery/scripts/ro5_screen.py +44 -0
  647. package/optional-skills/research/duckduckgo-search/SKILL.md +238 -0
  648. package/optional-skills/research/duckduckgo-search/scripts/duckduckgo.sh +28 -0
  649. package/optional-skills/research/gitnexus-explorer/SKILL.md +214 -0
  650. package/optional-skills/research/gitnexus-explorer/scripts/proxy.mjs +92 -0
  651. package/optional-skills/research/osint-investigation/SKILL.md +277 -0
  652. package/optional-skills/research/osint-investigation/references/sources/courtlistener.md +98 -0
  653. package/optional-skills/research/osint-investigation/references/sources/gdelt.md +104 -0
  654. package/optional-skills/research/osint-investigation/references/sources/icij-offshore.md +104 -0
  655. package/optional-skills/research/osint-investigation/references/sources/nyc-acris.md +90 -0
  656. package/optional-skills/research/osint-investigation/references/sources/ofac-sdn.md +92 -0
  657. package/optional-skills/research/osint-investigation/references/sources/opencorporates.md +103 -0
  658. package/optional-skills/research/osint-investigation/references/sources/sec-edgar.md +83 -0
  659. package/optional-skills/research/osint-investigation/references/sources/senate-ld.md +89 -0
  660. package/optional-skills/research/osint-investigation/references/sources/usaspending.md +97 -0
  661. package/optional-skills/research/osint-investigation/references/sources/wayback.md +93 -0
  662. package/optional-skills/research/osint-investigation/references/sources/wikipedia.md +107 -0
  663. package/optional-skills/research/osint-investigation/scripts/_http.py +82 -0
  664. package/optional-skills/research/osint-investigation/scripts/_normalize.py +67 -0
  665. package/optional-skills/research/osint-investigation/scripts/build_findings.py +221 -0
  666. package/optional-skills/research/osint-investigation/scripts/entity_resolution.py +228 -0
  667. package/optional-skills/research/osint-investigation/scripts/fetch_courtlistener.py +149 -0
  668. package/optional-skills/research/osint-investigation/scripts/fetch_gdelt.py +162 -0
  669. package/optional-skills/research/osint-investigation/scripts/fetch_icij_offshore.py +234 -0
  670. package/optional-skills/research/osint-investigation/scripts/fetch_nyc_acris.py +203 -0
  671. package/optional-skills/research/osint-investigation/scripts/fetch_ofac_sdn.py +175 -0
  672. package/optional-skills/research/osint-investigation/scripts/fetch_opencorporates.py +192 -0
  673. package/optional-skills/research/osint-investigation/scripts/fetch_sec_edgar.py +184 -0
  674. package/optional-skills/research/osint-investigation/scripts/fetch_senate_ld.py +146 -0
  675. package/optional-skills/research/osint-investigation/scripts/fetch_usaspending.py +170 -0
  676. package/optional-skills/research/osint-investigation/scripts/fetch_wayback.py +142 -0
  677. package/optional-skills/research/osint-investigation/scripts/fetch_wikipedia.py +267 -0
  678. package/optional-skills/research/osint-investigation/scripts/timing_analysis.py +253 -0
  679. package/optional-skills/research/osint-investigation/templates/source-template.md +59 -0
  680. package/optional-skills/research/parallel-cli/SKILL.md +391 -0
  681. package/optional-skills/research/qmd/SKILL.md +441 -0
  682. package/optional-skills/research/scrapling/SKILL.md +336 -0
  683. package/optional-skills/research/searxng-search/SKILL.md +212 -0
  684. package/optional-skills/research/searxng-search/scripts/searxng.sh +22 -0
  685. package/optional-skills/security/1password/SKILL.md +163 -0
  686. package/optional-skills/security/1password/references/cli-examples.md +31 -0
  687. package/optional-skills/security/1password/references/get-started.md +21 -0
  688. package/optional-skills/security/DESCRIPTION.md +3 -0
  689. package/optional-skills/security/oss-forensics/SKILL.md +423 -0
  690. package/optional-skills/security/oss-forensics/references/evidence-types.md +89 -0
  691. package/optional-skills/security/oss-forensics/references/github-archive-guide.md +184 -0
  692. package/optional-skills/security/oss-forensics/references/investigation-templates.md +131 -0
  693. package/optional-skills/security/oss-forensics/references/recovery-techniques.md +164 -0
  694. package/optional-skills/security/oss-forensics/scripts/evidence-store.py +313 -0
  695. package/optional-skills/security/oss-forensics/templates/forensic-report.md +151 -0
  696. package/optional-skills/security/oss-forensics/templates/malicious-package-report.md +43 -0
  697. package/optional-skills/security/sherlock/SKILL.md +193 -0
  698. package/optional-skills/software-development/rest-graphql-debug/SKILL.md +514 -0
  699. package/optional-skills/web-development/DESCRIPTION.md +5 -0
  700. package/optional-skills/web-development/page-agent/SKILL.md +190 -0
  701. package/package.json +78 -0
  702. package/plugins/__init__.py +1 -0
  703. package/plugins/__pycache__/__init__.cpython-312.pyc +0 -0
  704. package/plugins/context_engine/__init__.py +219 -0
  705. package/plugins/disk-cleanup/README.md +51 -0
  706. package/plugins/disk-cleanup/__init__.py +316 -0
  707. package/plugins/disk-cleanup/disk_cleanup.py +497 -0
  708. package/plugins/disk-cleanup/plugin.yaml +7 -0
  709. package/plugins/example-dashboard/dashboard/manifest.json +14 -0
  710. package/plugins/example-dashboard/dashboard/plugin_api.py +17 -0
  711. package/plugins/google_meet/README.md +131 -0
  712. package/plugins/google_meet/SKILL.md +148 -0
  713. package/plugins/google_meet/__init__.py +103 -0
  714. package/plugins/google_meet/audio_bridge.py +244 -0
  715. package/plugins/google_meet/cli.py +479 -0
  716. package/plugins/google_meet/meet_bot.py +852 -0
  717. package/plugins/google_meet/node/__init__.py +54 -0
  718. package/plugins/google_meet/node/cli.py +125 -0
  719. package/plugins/google_meet/node/client.py +107 -0
  720. package/plugins/google_meet/node/protocol.py +124 -0
  721. package/plugins/google_meet/node/registry.py +113 -0
  722. package/plugins/google_meet/node/server.py +201 -0
  723. package/plugins/google_meet/plugin.yaml +16 -0
  724. package/plugins/google_meet/process_manager.py +324 -0
  725. package/plugins/google_meet/realtime/__init__.py +10 -0
  726. package/plugins/google_meet/realtime/openai_client.py +332 -0
  727. package/plugins/google_meet/tools.py +348 -0
  728. package/plugins/hermes-achievements/LICENSE +21 -0
  729. package/plugins/hermes-achievements/README.md +150 -0
  730. package/plugins/hermes-achievements/dashboard/dist/index.js +732 -0
  731. package/plugins/hermes-achievements/dashboard/dist/style.css +146 -0
  732. package/plugins/hermes-achievements/dashboard/manifest.json +11 -0
  733. package/plugins/hermes-achievements/dashboard/plugin_api.py +1062 -0
  734. package/plugins/hermes-achievements/docs/achievements-performance-implementation-plan.md +157 -0
  735. package/plugins/hermes-achievements/docs/achievements-performance-implementation-spec.md +219 -0
  736. package/plugins/hermes-achievements/docs/achievements-performance-spec.md +174 -0
  737. package/plugins/hermes-achievements/docs/assets/achievements-dashboard-hd.png +0 -0
  738. package/plugins/hermes-achievements/docs/assets/achievements-tier-showcase-hd.png +0 -0
  739. package/plugins/hermes-achievements/tests/test_achievement_engine.py +156 -0
  740. package/plugins/image_gen/openai/__init__.py +303 -0
  741. package/plugins/image_gen/openai/__pycache__/__init__.cpython-312.pyc +0 -0
  742. package/plugins/image_gen/openai/plugin.yaml +7 -0
  743. package/plugins/image_gen/openai-codex/__init__.py +378 -0
  744. package/plugins/image_gen/openai-codex/__pycache__/__init__.cpython-312.pyc +0 -0
  745. package/plugins/image_gen/openai-codex/plugin.yaml +5 -0
  746. package/plugins/image_gen/xai/__init__.py +316 -0
  747. package/plugins/image_gen/xai/__pycache__/__init__.cpython-312.pyc +0 -0
  748. package/plugins/image_gen/xai/plugin.yaml +7 -0
  749. package/plugins/kanban/dashboard/dist/index.js +3143 -0
  750. package/plugins/kanban/dashboard/dist/style.css +1500 -0
  751. package/plugins/kanban/dashboard/manifest.json +14 -0
  752. package/plugins/kanban/dashboard/plugin_api.py +1612 -0
  753. package/plugins/kanban/systemd/hermes-kanban-dispatcher.service +32 -0
  754. package/plugins/memory/__init__.py +408 -0
  755. package/plugins/memory/byterover/README.md +41 -0
  756. package/plugins/memory/byterover/__init__.py +384 -0
  757. package/plugins/memory/byterover/plugin.yaml +9 -0
  758. package/plugins/memory/hindsight/README.md +138 -0
  759. package/plugins/memory/hindsight/__init__.py +1758 -0
  760. package/plugins/memory/hindsight/plugin.yaml +8 -0
  761. package/plugins/memory/holographic/README.md +36 -0
  762. package/plugins/memory/holographic/__init__.py +409 -0
  763. package/plugins/memory/holographic/holographic.py +203 -0
  764. package/plugins/memory/holographic/plugin.yaml +5 -0
  765. package/plugins/memory/holographic/retrieval.py +593 -0
  766. package/plugins/memory/holographic/store.py +579 -0
  767. package/plugins/memory/honcho/README.md +328 -0
  768. package/plugins/memory/honcho/__init__.py +1329 -0
  769. package/plugins/memory/honcho/cli.py +1452 -0
  770. package/plugins/memory/honcho/client.py +784 -0
  771. package/plugins/memory/honcho/plugin.yaml +7 -0
  772. package/plugins/memory/honcho/session.py +1255 -0
  773. package/plugins/memory/mem0/README.md +38 -0
  774. package/plugins/memory/mem0/__init__.py +374 -0
  775. package/plugins/memory/mem0/plugin.yaml +5 -0
  776. package/plugins/memory/openviking/README.md +40 -0
  777. package/plugins/memory/openviking/__init__.py +945 -0
  778. package/plugins/memory/openviking/plugin.yaml +9 -0
  779. package/plugins/memory/retaindb/README.md +40 -0
  780. package/plugins/memory/retaindb/__init__.py +767 -0
  781. package/plugins/memory/retaindb/plugin.yaml +7 -0
  782. package/plugins/memory/supermemory/README.md +99 -0
  783. package/plugins/memory/supermemory/__init__.py +792 -0
  784. package/plugins/memory/supermemory/plugin.yaml +5 -0
  785. package/plugins/model-providers/README.md +70 -0
  786. package/plugins/model-providers/ai-gateway/__init__.py +43 -0
  787. package/plugins/model-providers/ai-gateway/__pycache__/__init__.cpython-312.pyc +0 -0
  788. package/plugins/model-providers/ai-gateway/plugin.yaml +5 -0
  789. package/plugins/model-providers/alibaba/__init__.py +13 -0
  790. package/plugins/model-providers/alibaba/__pycache__/__init__.cpython-312.pyc +0 -0
  791. package/plugins/model-providers/alibaba/plugin.yaml +5 -0
  792. package/plugins/model-providers/alibaba-coding-plan/__init__.py +21 -0
  793. package/plugins/model-providers/alibaba-coding-plan/__pycache__/__init__.cpython-312.pyc +0 -0
  794. package/plugins/model-providers/alibaba-coding-plan/plugin.yaml +5 -0
  795. package/plugins/model-providers/anthropic/__init__.py +52 -0
  796. package/plugins/model-providers/anthropic/__pycache__/__init__.cpython-312.pyc +0 -0
  797. package/plugins/model-providers/anthropic/plugin.yaml +5 -0
  798. package/plugins/model-providers/arcee/__init__.py +13 -0
  799. package/plugins/model-providers/arcee/__pycache__/__init__.cpython-312.pyc +0 -0
  800. package/plugins/model-providers/arcee/plugin.yaml +5 -0
  801. package/plugins/model-providers/azure-foundry/__init__.py +21 -0
  802. package/plugins/model-providers/azure-foundry/__pycache__/__init__.cpython-312.pyc +0 -0
  803. package/plugins/model-providers/azure-foundry/plugin.yaml +5 -0
  804. package/plugins/model-providers/bedrock/__init__.py +29 -0
  805. package/plugins/model-providers/bedrock/__pycache__/__init__.cpython-312.pyc +0 -0
  806. package/plugins/model-providers/bedrock/plugin.yaml +5 -0
  807. package/plugins/model-providers/copilot/__init__.py +58 -0
  808. package/plugins/model-providers/copilot/__pycache__/__init__.cpython-312.pyc +0 -0
  809. package/plugins/model-providers/copilot/plugin.yaml +5 -0
  810. package/plugins/model-providers/copilot-acp/__init__.py +34 -0
  811. package/plugins/model-providers/copilot-acp/__pycache__/__init__.cpython-312.pyc +0 -0
  812. package/plugins/model-providers/copilot-acp/plugin.yaml +5 -0
  813. package/plugins/model-providers/custom/__init__.py +68 -0
  814. package/plugins/model-providers/custom/__pycache__/__init__.cpython-312.pyc +0 -0
  815. package/plugins/model-providers/custom/plugin.yaml +5 -0
  816. package/plugins/model-providers/deepseek/__init__.py +99 -0
  817. package/plugins/model-providers/deepseek/__pycache__/__init__.cpython-312.pyc +0 -0
  818. package/plugins/model-providers/deepseek/plugin.yaml +5 -0
  819. package/plugins/model-providers/gemini/__init__.py +72 -0
  820. package/plugins/model-providers/gemini/__pycache__/__init__.cpython-312.pyc +0 -0
  821. package/plugins/model-providers/gemini/plugin.yaml +5 -0
  822. package/plugins/model-providers/gmi/__init__.py +31 -0
  823. package/plugins/model-providers/gmi/__pycache__/__init__.cpython-312.pyc +0 -0
  824. package/plugins/model-providers/gmi/plugin.yaml +5 -0
  825. package/plugins/model-providers/huggingface/__init__.py +20 -0
  826. package/plugins/model-providers/huggingface/__pycache__/__init__.cpython-312.pyc +0 -0
  827. package/plugins/model-providers/huggingface/plugin.yaml +5 -0
  828. package/plugins/model-providers/kilocode/__init__.py +14 -0
  829. package/plugins/model-providers/kilocode/__pycache__/__init__.cpython-312.pyc +0 -0
  830. package/plugins/model-providers/kilocode/plugin.yaml +5 -0
  831. package/plugins/model-providers/kimi-coding/__init__.py +71 -0
  832. package/plugins/model-providers/kimi-coding/__pycache__/__init__.cpython-312.pyc +0 -0
  833. package/plugins/model-providers/kimi-coding/plugin.yaml +5 -0
  834. package/plugins/model-providers/minimax/__init__.py +45 -0
  835. package/plugins/model-providers/minimax/__pycache__/__init__.cpython-312.pyc +0 -0
  836. package/plugins/model-providers/minimax/plugin.yaml +5 -0
  837. package/plugins/model-providers/nous/__init__.py +54 -0
  838. package/plugins/model-providers/nous/__pycache__/__init__.cpython-312.pyc +0 -0
  839. package/plugins/model-providers/nous/plugin.yaml +5 -0
  840. package/plugins/model-providers/novita/__init__.py +27 -0
  841. package/plugins/model-providers/novita/__pycache__/__init__.cpython-312.pyc +0 -0
  842. package/plugins/model-providers/novita/plugin.yaml +5 -0
  843. package/plugins/model-providers/nvidia/__init__.py +21 -0
  844. package/plugins/model-providers/nvidia/__pycache__/__init__.cpython-312.pyc +0 -0
  845. package/plugins/model-providers/nvidia/plugin.yaml +5 -0
  846. package/plugins/model-providers/ollama-cloud/__init__.py +14 -0
  847. package/plugins/model-providers/ollama-cloud/__pycache__/__init__.cpython-312.pyc +0 -0
  848. package/plugins/model-providers/ollama-cloud/plugin.yaml +5 -0
  849. package/plugins/model-providers/openai-codex/__init__.py +15 -0
  850. package/plugins/model-providers/openai-codex/__pycache__/__init__.cpython-312.pyc +0 -0
  851. package/plugins/model-providers/openai-codex/plugin.yaml +5 -0
  852. package/plugins/model-providers/opencode-zen/__init__.py +30 -0
  853. package/plugins/model-providers/opencode-zen/__pycache__/__init__.cpython-312.pyc +0 -0
  854. package/plugins/model-providers/opencode-zen/plugin.yaml +5 -0
  855. package/plugins/model-providers/openrouter/__init__.py +115 -0
  856. package/plugins/model-providers/openrouter/__pycache__/__init__.cpython-312.pyc +0 -0
  857. package/plugins/model-providers/openrouter/plugin.yaml +5 -0
  858. package/plugins/model-providers/qwen-oauth/__init__.py +82 -0
  859. package/plugins/model-providers/qwen-oauth/__pycache__/__init__.cpython-312.pyc +0 -0
  860. package/plugins/model-providers/qwen-oauth/plugin.yaml +5 -0
  861. package/plugins/model-providers/stepfun/__init__.py +14 -0
  862. package/plugins/model-providers/stepfun/__pycache__/__init__.cpython-312.pyc +0 -0
  863. package/plugins/model-providers/stepfun/plugin.yaml +5 -0
  864. package/plugins/model-providers/xai/__init__.py +15 -0
  865. package/plugins/model-providers/xai/__pycache__/__init__.cpython-312.pyc +0 -0
  866. package/plugins/model-providers/xai/plugin.yaml +5 -0
  867. package/plugins/model-providers/xiaomi/__init__.py +14 -0
  868. package/plugins/model-providers/xiaomi/__pycache__/__init__.cpython-312.pyc +0 -0
  869. package/plugins/model-providers/xiaomi/plugin.yaml +5 -0
  870. package/plugins/model-providers/zai/__init__.py +21 -0
  871. package/plugins/model-providers/zai/__pycache__/__init__.cpython-312.pyc +0 -0
  872. package/plugins/model-providers/zai/plugin.yaml +5 -0
  873. package/plugins/observability/langfuse/README.md +53 -0
  874. package/plugins/observability/langfuse/__init__.py +1004 -0
  875. package/plugins/observability/langfuse/plugin.yaml +14 -0
  876. package/plugins/platforms/google_chat/__init__.py +3 -0
  877. package/plugins/platforms/google_chat/__pycache__/__init__.cpython-312.pyc +0 -0
  878. package/plugins/platforms/google_chat/__pycache__/adapter.cpython-312.pyc +0 -0
  879. package/plugins/platforms/google_chat/adapter.py +3343 -0
  880. package/plugins/platforms/google_chat/oauth.py +639 -0
  881. package/plugins/platforms/google_chat/plugin.yaml +39 -0
  882. package/plugins/platforms/irc/__init__.py +3 -0
  883. package/plugins/platforms/irc/__pycache__/__init__.cpython-312.pyc +0 -0
  884. package/plugins/platforms/irc/__pycache__/adapter.cpython-312.pyc +0 -0
  885. package/plugins/platforms/irc/adapter.py +969 -0
  886. package/plugins/platforms/irc/plugin.yaml +54 -0
  887. package/plugins/platforms/line/__init__.py +3 -0
  888. package/plugins/platforms/line/__pycache__/__init__.cpython-312.pyc +0 -0
  889. package/plugins/platforms/line/__pycache__/adapter.cpython-312.pyc +0 -0
  890. package/plugins/platforms/line/adapter.py +1639 -0
  891. package/plugins/platforms/line/plugin.yaml +65 -0
  892. package/plugins/platforms/simplex/__init__.py +3 -0
  893. package/plugins/platforms/simplex/__pycache__/__init__.cpython-312.pyc +0 -0
  894. package/plugins/platforms/simplex/__pycache__/adapter.cpython-312.pyc +0 -0
  895. package/plugins/platforms/simplex/adapter.py +746 -0
  896. package/plugins/platforms/simplex/plugin.yaml +37 -0
  897. package/plugins/platforms/teams/__init__.py +3 -0
  898. package/plugins/platforms/teams/__pycache__/__init__.cpython-312.pyc +0 -0
  899. package/plugins/platforms/teams/__pycache__/adapter.cpython-312.pyc +0 -0
  900. package/plugins/platforms/teams/adapter.py +1188 -0
  901. package/plugins/platforms/teams/plugin.yaml +48 -0
  902. package/plugins/spotify/__init__.py +66 -0
  903. package/plugins/spotify/__pycache__/__init__.cpython-312.pyc +0 -0
  904. package/plugins/spotify/__pycache__/client.cpython-312.pyc +0 -0
  905. package/plugins/spotify/__pycache__/tools.cpython-312.pyc +0 -0
  906. package/plugins/spotify/client.py +435 -0
  907. package/plugins/spotify/plugin.yaml +13 -0
  908. package/plugins/spotify/tools.py +454 -0
  909. package/plugins/teams_pipeline/__init__.py +23 -0
  910. package/plugins/teams_pipeline/cli.py +463 -0
  911. package/plugins/teams_pipeline/meetings.py +333 -0
  912. package/plugins/teams_pipeline/models.py +350 -0
  913. package/plugins/teams_pipeline/pipeline.py +692 -0
  914. package/plugins/teams_pipeline/plugin.yaml +9 -0
  915. package/plugins/teams_pipeline/runtime.py +135 -0
  916. package/plugins/teams_pipeline/store.py +194 -0
  917. package/plugins/teams_pipeline/subscriptions.py +249 -0
  918. package/plugins/video_gen/fal/__init__.py +523 -0
  919. package/plugins/video_gen/fal/__pycache__/__init__.cpython-312.pyc +0 -0
  920. package/plugins/video_gen/fal/plugin.yaml +7 -0
  921. package/plugins/video_gen/xai/__init__.py +441 -0
  922. package/plugins/video_gen/xai/__pycache__/__init__.cpython-312.pyc +0 -0
  923. package/plugins/video_gen/xai/plugin.yaml +7 -0
  924. package/plugins/web/__init__.py +7 -0
  925. package/plugins/web/__pycache__/__init__.cpython-312.pyc +0 -0
  926. package/plugins/web/brave_free/__init__.py +14 -0
  927. package/plugins/web/brave_free/__pycache__/__init__.cpython-312.pyc +0 -0
  928. package/plugins/web/brave_free/__pycache__/provider.cpython-312.pyc +0 -0
  929. package/plugins/web/brave_free/plugin.yaml +7 -0
  930. package/plugins/web/brave_free/provider.py +137 -0
  931. package/plugins/web/ddgs/__init__.py +15 -0
  932. package/plugins/web/ddgs/__pycache__/__init__.cpython-312.pyc +0 -0
  933. package/plugins/web/ddgs/__pycache__/provider.cpython-312.pyc +0 -0
  934. package/plugins/web/ddgs/plugin.yaml +7 -0
  935. package/plugins/web/ddgs/provider.py +104 -0
  936. package/plugins/web/exa/__init__.py +15 -0
  937. package/plugins/web/exa/__pycache__/__init__.cpython-312.pyc +0 -0
  938. package/plugins/web/exa/__pycache__/provider.cpython-312.pyc +0 -0
  939. package/plugins/web/exa/plugin.yaml +7 -0
  940. package/plugins/web/exa/provider.py +212 -0
  941. package/plugins/web/firecrawl/__init__.py +28 -0
  942. package/plugins/web/firecrawl/__pycache__/__init__.cpython-312.pyc +0 -0
  943. package/plugins/web/firecrawl/__pycache__/provider.cpython-312.pyc +0 -0
  944. package/plugins/web/firecrawl/plugin.yaml +7 -0
  945. package/plugins/web/firecrawl/provider.py +773 -0
  946. package/plugins/web/parallel/__init__.py +16 -0
  947. package/plugins/web/parallel/__pycache__/__init__.cpython-312.pyc +0 -0
  948. package/plugins/web/parallel/__pycache__/provider.cpython-312.pyc +0 -0
  949. package/plugins/web/parallel/plugin.yaml +7 -0
  950. package/plugins/web/parallel/provider.py +291 -0
  951. package/plugins/web/searxng/__init__.py +15 -0
  952. package/plugins/web/searxng/__pycache__/__init__.cpython-312.pyc +0 -0
  953. package/plugins/web/searxng/__pycache__/provider.cpython-312.pyc +0 -0
  954. package/plugins/web/searxng/plugin.yaml +7 -0
  955. package/plugins/web/searxng/provider.py +140 -0
  956. package/plugins/web/tavily/__init__.py +15 -0
  957. package/plugins/web/tavily/__pycache__/__init__.cpython-312.pyc +0 -0
  958. package/plugins/web/tavily/__pycache__/provider.cpython-312.pyc +0 -0
  959. package/plugins/web/tavily/plugin.yaml +7 -0
  960. package/plugins/web/tavily/provider.py +285 -0
  961. package/providers/README.md +78 -0
  962. package/providers/__init__.py +192 -0
  963. package/providers/__pycache__/__init__.cpython-312.pyc +0 -0
  964. package/providers/__pycache__/base.cpython-312.pyc +0 -0
  965. package/providers/base.py +184 -0
  966. package/pyproject.toml +255 -0
  967. package/run_agent.py +16409 -0
  968. package/scripts/benchmark_browser_eval.py +138 -0
  969. package/scripts/build_model_catalog.py +95 -0
  970. package/scripts/build_skills_index.py +325 -0
  971. package/scripts/check-windows-footguns.py +624 -0
  972. package/scripts/contributor_audit.py +473 -0
  973. package/scripts/discord-voice-doctor.py +396 -0
  974. package/scripts/hermes-gateway +416 -0
  975. package/scripts/install.cmd +28 -0
  976. package/scripts/install.ps1 +1611 -0
  977. package/scripts/install.sh +2007 -0
  978. package/scripts/install_psutil_android.py +117 -0
  979. package/scripts/keystroke_diagnostic.py +81 -0
  980. package/scripts/kill_modal.sh +34 -0
  981. package/scripts/lib/node-bootstrap.sh +238 -0
  982. package/scripts/lint_diff.py +207 -0
  983. package/scripts/postinstall.js +150 -0
  984. package/scripts/profile-tui.py +626 -0
  985. package/scripts/release.py +1680 -0
  986. package/scripts/run_tests.sh +129 -0
  987. package/scripts/sample_and_compress.py +409 -0
  988. package/scripts/setup_open_webui.sh +349 -0
  989. package/scripts/whatsapp-bridge/allowlist.js +88 -0
  990. package/scripts/whatsapp-bridge/allowlist.test.mjs +80 -0
  991. package/scripts/whatsapp-bridge/bridge.js +729 -0
  992. package/scripts/whatsapp-bridge/package-lock.json +2141 -0
  993. package/scripts/whatsapp-bridge/package.json +19 -0
  994. package/skills/apple/DESCRIPTION.md +2 -0
  995. package/skills/apple/apple-notes/SKILL.md +90 -0
  996. package/skills/apple/apple-reminders/SKILL.md +98 -0
  997. package/skills/apple/findmy/SKILL.md +131 -0
  998. package/skills/apple/imessage/SKILL.md +102 -0
  999. package/skills/apple/macos-computer-use/SKILL.md +201 -0
  1000. package/skills/autonomous-ai-agents/DESCRIPTION.md +3 -0
  1001. package/skills/autonomous-ai-agents/claude-code/SKILL.md +745 -0
  1002. package/skills/autonomous-ai-agents/codex/SKILL.md +130 -0
  1003. package/skills/autonomous-ai-agents/hermes-agent/SKILL.md +1014 -0
  1004. package/skills/autonomous-ai-agents/opencode/SKILL.md +219 -0
  1005. package/skills/creative/DESCRIPTION.md +3 -0
  1006. package/skills/creative/architecture-diagram/SKILL.md +148 -0
  1007. package/skills/creative/architecture-diagram/templates/template.html +319 -0
  1008. package/skills/creative/ascii-art/SKILL.md +322 -0
  1009. package/skills/creative/ascii-video/README.md +290 -0
  1010. package/skills/creative/ascii-video/SKILL.md +241 -0
  1011. package/skills/creative/ascii-video/references/architecture.md +802 -0
  1012. package/skills/creative/ascii-video/references/composition.md +892 -0
  1013. package/skills/creative/ascii-video/references/effects.md +1865 -0
  1014. package/skills/creative/ascii-video/references/inputs.md +685 -0
  1015. package/skills/creative/ascii-video/references/optimization.md +688 -0
  1016. package/skills/creative/ascii-video/references/scenes.md +1011 -0
  1017. package/skills/creative/ascii-video/references/shaders.md +1385 -0
  1018. package/skills/creative/ascii-video/references/troubleshooting.md +367 -0
  1019. package/skills/creative/baoyu-comic/PORT_NOTES.md +77 -0
  1020. package/skills/creative/baoyu-comic/SKILL.md +247 -0
  1021. package/skills/creative/baoyu-comic/references/analysis-framework.md +176 -0
  1022. package/skills/creative/baoyu-comic/references/art-styles/chalk.md +101 -0
  1023. package/skills/creative/baoyu-comic/references/art-styles/ink-brush.md +97 -0
  1024. package/skills/creative/baoyu-comic/references/art-styles/ligne-claire.md +75 -0
  1025. package/skills/creative/baoyu-comic/references/art-styles/manga.md +93 -0
  1026. package/skills/creative/baoyu-comic/references/art-styles/minimalist.md +84 -0
  1027. package/skills/creative/baoyu-comic/references/art-styles/realistic.md +89 -0
  1028. package/skills/creative/baoyu-comic/references/auto-selection.md +71 -0
  1029. package/skills/creative/baoyu-comic/references/base-prompt.md +98 -0
  1030. package/skills/creative/baoyu-comic/references/character-template.md +180 -0
  1031. package/skills/creative/baoyu-comic/references/layouts/cinematic.md +23 -0
  1032. package/skills/creative/baoyu-comic/references/layouts/dense.md +23 -0
  1033. package/skills/creative/baoyu-comic/references/layouts/four-panel.md +40 -0
  1034. package/skills/creative/baoyu-comic/references/layouts/mixed.md +23 -0
  1035. package/skills/creative/baoyu-comic/references/layouts/splash.md +23 -0
  1036. package/skills/creative/baoyu-comic/references/layouts/standard.md +23 -0
  1037. package/skills/creative/baoyu-comic/references/layouts/webtoon.md +30 -0
  1038. package/skills/creative/baoyu-comic/references/ohmsha-guide.md +85 -0
  1039. package/skills/creative/baoyu-comic/references/partial-workflows.md +106 -0
  1040. package/skills/creative/baoyu-comic/references/presets/concept-story.md +121 -0
  1041. package/skills/creative/baoyu-comic/references/presets/four-panel.md +107 -0
  1042. package/skills/creative/baoyu-comic/references/presets/ohmsha.md +114 -0
  1043. package/skills/creative/baoyu-comic/references/presets/shoujo.md +116 -0
  1044. package/skills/creative/baoyu-comic/references/presets/wuxia.md +110 -0
  1045. package/skills/creative/baoyu-comic/references/storyboard-template.md +143 -0
  1046. package/skills/creative/baoyu-comic/references/tones/action.md +110 -0
  1047. package/skills/creative/baoyu-comic/references/tones/dramatic.md +95 -0
  1048. package/skills/creative/baoyu-comic/references/tones/energetic.md +105 -0
  1049. package/skills/creative/baoyu-comic/references/tones/neutral.md +63 -0
  1050. package/skills/creative/baoyu-comic/references/tones/romantic.md +100 -0
  1051. package/skills/creative/baoyu-comic/references/tones/vintage.md +104 -0
  1052. package/skills/creative/baoyu-comic/references/tones/warm.md +94 -0
  1053. package/skills/creative/baoyu-comic/references/workflow.md +401 -0
  1054. package/skills/creative/baoyu-infographic/PORT_NOTES.md +43 -0
  1055. package/skills/creative/baoyu-infographic/SKILL.md +237 -0
  1056. package/skills/creative/baoyu-infographic/references/analysis-framework.md +182 -0
  1057. package/skills/creative/baoyu-infographic/references/base-prompt.md +43 -0
  1058. package/skills/creative/baoyu-infographic/references/layouts/bento-grid.md +41 -0
  1059. package/skills/creative/baoyu-infographic/references/layouts/binary-comparison.md +48 -0
  1060. package/skills/creative/baoyu-infographic/references/layouts/bridge.md +41 -0
  1061. package/skills/creative/baoyu-infographic/references/layouts/circular-flow.md +41 -0
  1062. package/skills/creative/baoyu-infographic/references/layouts/comic-strip.md +41 -0
  1063. package/skills/creative/baoyu-infographic/references/layouts/comparison-matrix.md +41 -0
  1064. package/skills/creative/baoyu-infographic/references/layouts/dashboard.md +41 -0
  1065. package/skills/creative/baoyu-infographic/references/layouts/dense-modules.md +72 -0
  1066. package/skills/creative/baoyu-infographic/references/layouts/funnel.md +41 -0
  1067. package/skills/creative/baoyu-infographic/references/layouts/hierarchical-layers.md +48 -0
  1068. package/skills/creative/baoyu-infographic/references/layouts/hub-spoke.md +41 -0
  1069. package/skills/creative/baoyu-infographic/references/layouts/iceberg.md +41 -0
  1070. package/skills/creative/baoyu-infographic/references/layouts/isometric-map.md +41 -0
  1071. package/skills/creative/baoyu-infographic/references/layouts/jigsaw.md +41 -0
  1072. package/skills/creative/baoyu-infographic/references/layouts/linear-progression.md +48 -0
  1073. package/skills/creative/baoyu-infographic/references/layouts/periodic-table.md +41 -0
  1074. package/skills/creative/baoyu-infographic/references/layouts/story-mountain.md +41 -0
  1075. package/skills/creative/baoyu-infographic/references/layouts/structural-breakdown.md +48 -0
  1076. package/skills/creative/baoyu-infographic/references/layouts/tree-branching.md +41 -0
  1077. package/skills/creative/baoyu-infographic/references/layouts/venn-diagram.md +41 -0
  1078. package/skills/creative/baoyu-infographic/references/layouts/winding-roadmap.md +41 -0
  1079. package/skills/creative/baoyu-infographic/references/structured-content-template.md +244 -0
  1080. package/skills/creative/baoyu-infographic/references/styles/aged-academia.md +36 -0
  1081. package/skills/creative/baoyu-infographic/references/styles/bold-graphic.md +36 -0
  1082. package/skills/creative/baoyu-infographic/references/styles/chalkboard.md +61 -0
  1083. package/skills/creative/baoyu-infographic/references/styles/claymation.md +29 -0
  1084. package/skills/creative/baoyu-infographic/references/styles/corporate-memphis.md +29 -0
  1085. package/skills/creative/baoyu-infographic/references/styles/craft-handmade.md +44 -0
  1086. package/skills/creative/baoyu-infographic/references/styles/cyberpunk-neon.md +29 -0
  1087. package/skills/creative/baoyu-infographic/references/styles/hand-drawn-edu.md +63 -0
  1088. package/skills/creative/baoyu-infographic/references/styles/ikea-manual.md +29 -0
  1089. package/skills/creative/baoyu-infographic/references/styles/kawaii.md +29 -0
  1090. package/skills/creative/baoyu-infographic/references/styles/knolling.md +29 -0
  1091. package/skills/creative/baoyu-infographic/references/styles/lego-brick.md +29 -0
  1092. package/skills/creative/baoyu-infographic/references/styles/morandi-journal.md +60 -0
  1093. package/skills/creative/baoyu-infographic/references/styles/origami.md +29 -0
  1094. package/skills/creative/baoyu-infographic/references/styles/pixel-art.md +29 -0
  1095. package/skills/creative/baoyu-infographic/references/styles/pop-laboratory.md +48 -0
  1096. package/skills/creative/baoyu-infographic/references/styles/retro-pop-grid.md +47 -0
  1097. package/skills/creative/baoyu-infographic/references/styles/storybook-watercolor.md +29 -0
  1098. package/skills/creative/baoyu-infographic/references/styles/subway-map.md +29 -0
  1099. package/skills/creative/baoyu-infographic/references/styles/technical-schematic.md +36 -0
  1100. package/skills/creative/baoyu-infographic/references/styles/ui-wireframe.md +29 -0
  1101. package/skills/creative/claude-design/SKILL.md +591 -0
  1102. package/skills/creative/comfyui/SKILL.md +612 -0
  1103. package/skills/creative/comfyui/references/official-cli.md +255 -0
  1104. package/skills/creative/comfyui/references/rest-api.md +312 -0
  1105. package/skills/creative/comfyui/references/template-integrity.md +243 -0
  1106. package/skills/creative/comfyui/references/workflow-format.md +226 -0
  1107. package/skills/creative/comfyui/scripts/_common.py +835 -0
  1108. package/skills/creative/comfyui/scripts/auto_fix_deps.py +225 -0
  1109. package/skills/creative/comfyui/scripts/check_deps.py +437 -0
  1110. package/skills/creative/comfyui/scripts/comfyui_setup.sh +286 -0
  1111. package/skills/creative/comfyui/scripts/extract_schema.py +315 -0
  1112. package/skills/creative/comfyui/scripts/fetch_logs.py +158 -0
  1113. package/skills/creative/comfyui/scripts/hardware_check.py +497 -0
  1114. package/skills/creative/comfyui/scripts/health_check.py +223 -0
  1115. package/skills/creative/comfyui/scripts/run_batch.py +243 -0
  1116. package/skills/creative/comfyui/scripts/run_workflow.py +796 -0
  1117. package/skills/creative/comfyui/scripts/ws_monitor.py +267 -0
  1118. package/skills/creative/comfyui/tests/README.md +50 -0
  1119. package/skills/creative/comfyui/tests/conftest.py +64 -0
  1120. package/skills/creative/comfyui/tests/pytest.ini +5 -0
  1121. package/skills/creative/comfyui/tests/test_check_deps.py +68 -0
  1122. package/skills/creative/comfyui/tests/test_cloud_integration.py +95 -0
  1123. package/skills/creative/comfyui/tests/test_common.py +447 -0
  1124. package/skills/creative/comfyui/tests/test_extract_schema.py +185 -0
  1125. package/skills/creative/comfyui/tests/test_run_workflow.py +213 -0
  1126. package/skills/creative/comfyui/workflows/README.md +86 -0
  1127. package/skills/creative/comfyui/workflows/animatediff_video.json +64 -0
  1128. package/skills/creative/comfyui/workflows/flux_dev_txt2img.json +78 -0
  1129. package/skills/creative/comfyui/workflows/sd15_txt2img.json +49 -0
  1130. package/skills/creative/comfyui/workflows/sdxl_img2img.json +54 -0
  1131. package/skills/creative/comfyui/workflows/sdxl_inpaint.json +59 -0
  1132. package/skills/creative/comfyui/workflows/sdxl_txt2img.json +49 -0
  1133. package/skills/creative/comfyui/workflows/upscale_4x.json +27 -0
  1134. package/skills/creative/comfyui/workflows/wan_video_t2v.json +69 -0
  1135. package/skills/creative/creative-ideation/SKILL.md +152 -0
  1136. package/skills/creative/creative-ideation/references/full-prompt-library.md +110 -0
  1137. package/skills/creative/design-md/SKILL.md +199 -0
  1138. package/skills/creative/design-md/templates/starter.md +99 -0
  1139. package/skills/creative/excalidraw/SKILL.md +199 -0
  1140. package/skills/creative/excalidraw/references/colors.md +44 -0
  1141. package/skills/creative/excalidraw/references/dark-mode.md +68 -0
  1142. package/skills/creative/excalidraw/references/examples.md +141 -0
  1143. package/skills/creative/excalidraw/scripts/upload.py +133 -0
  1144. package/skills/creative/humanizer/LICENSE +21 -0
  1145. package/skills/creative/humanizer/SKILL.md +578 -0
  1146. package/skills/creative/manim-video/README.md +23 -0
  1147. package/skills/creative/manim-video/SKILL.md +269 -0
  1148. package/skills/creative/manim-video/references/animation-design-thinking.md +161 -0
  1149. package/skills/creative/manim-video/references/animations.md +282 -0
  1150. package/skills/creative/manim-video/references/camera-and-3d.md +135 -0
  1151. package/skills/creative/manim-video/references/decorations.md +202 -0
  1152. package/skills/creative/manim-video/references/equations.md +216 -0
  1153. package/skills/creative/manim-video/references/graphs-and-data.md +163 -0
  1154. package/skills/creative/manim-video/references/mobjects.md +333 -0
  1155. package/skills/creative/manim-video/references/paper-explainer.md +255 -0
  1156. package/skills/creative/manim-video/references/production-quality.md +190 -0
  1157. package/skills/creative/manim-video/references/rendering.md +185 -0
  1158. package/skills/creative/manim-video/references/scene-planning.md +118 -0
  1159. package/skills/creative/manim-video/references/troubleshooting.md +135 -0
  1160. package/skills/creative/manim-video/references/updaters-and-trackers.md +260 -0
  1161. package/skills/creative/manim-video/references/visual-design.md +124 -0
  1162. package/skills/creative/manim-video/scripts/setup.sh +14 -0
  1163. package/skills/creative/p5js/README.md +64 -0
  1164. package/skills/creative/p5js/SKILL.md +556 -0
  1165. package/skills/creative/p5js/references/animation.md +439 -0
  1166. package/skills/creative/p5js/references/color-systems.md +352 -0
  1167. package/skills/creative/p5js/references/core-api.md +410 -0
  1168. package/skills/creative/p5js/references/export-pipeline.md +566 -0
  1169. package/skills/creative/p5js/references/interaction.md +398 -0
  1170. package/skills/creative/p5js/references/shapes-and-geometry.md +300 -0
  1171. package/skills/creative/p5js/references/troubleshooting.md +532 -0
  1172. package/skills/creative/p5js/references/typography.md +302 -0
  1173. package/skills/creative/p5js/references/visual-effects.md +895 -0
  1174. package/skills/creative/p5js/references/webgl-and-3d.md +423 -0
  1175. package/skills/creative/p5js/scripts/export-frames.js +179 -0
  1176. package/skills/creative/p5js/scripts/render.sh +108 -0
  1177. package/skills/creative/p5js/scripts/serve.sh +28 -0
  1178. package/skills/creative/p5js/scripts/setup.sh +87 -0
  1179. package/skills/creative/p5js/templates/viewer.html +395 -0
  1180. package/skills/creative/pixel-art/ATTRIBUTION.md +54 -0
  1181. package/skills/creative/pixel-art/SKILL.md +218 -0
  1182. package/skills/creative/pixel-art/references/palettes.md +49 -0
  1183. package/skills/creative/pixel-art/scripts/__init__.py +0 -0
  1184. package/skills/creative/pixel-art/scripts/palettes.py +167 -0
  1185. package/skills/creative/pixel-art/scripts/pixel_art.py +162 -0
  1186. package/skills/creative/pixel-art/scripts/pixel_art_video.py +345 -0
  1187. package/skills/creative/popular-web-designs/SKILL.md +214 -0
  1188. package/skills/creative/popular-web-designs/templates/airbnb.md +259 -0
  1189. package/skills/creative/popular-web-designs/templates/airtable.md +102 -0
  1190. package/skills/creative/popular-web-designs/templates/apple.md +326 -0
  1191. package/skills/creative/popular-web-designs/templates/bmw.md +193 -0
  1192. package/skills/creative/popular-web-designs/templates/cal.md +272 -0
  1193. package/skills/creative/popular-web-designs/templates/claude.md +325 -0
  1194. package/skills/creative/popular-web-designs/templates/clay.md +317 -0
  1195. package/skills/creative/popular-web-designs/templates/clickhouse.md +294 -0
  1196. package/skills/creative/popular-web-designs/templates/cohere.md +279 -0
  1197. package/skills/creative/popular-web-designs/templates/coinbase.md +142 -0
  1198. package/skills/creative/popular-web-designs/templates/composio.md +320 -0
  1199. package/skills/creative/popular-web-designs/templates/cursor.md +322 -0
  1200. package/skills/creative/popular-web-designs/templates/elevenlabs.md +278 -0
  1201. package/skills/creative/popular-web-designs/templates/expo.md +294 -0
  1202. package/skills/creative/popular-web-designs/templates/figma.md +233 -0
  1203. package/skills/creative/popular-web-designs/templates/framer.md +259 -0
  1204. package/skills/creative/popular-web-designs/templates/hashicorp.md +291 -0
  1205. package/skills/creative/popular-web-designs/templates/ibm.md +345 -0
  1206. package/skills/creative/popular-web-designs/templates/intercom.md +159 -0
  1207. package/skills/creative/popular-web-designs/templates/kraken.md +138 -0
  1208. package/skills/creative/popular-web-designs/templates/linear.app.md +380 -0
  1209. package/skills/creative/popular-web-designs/templates/lovable.md +311 -0
  1210. package/skills/creative/popular-web-designs/templates/minimax.md +270 -0
  1211. package/skills/creative/popular-web-designs/templates/mintlify.md +339 -0
  1212. package/skills/creative/popular-web-designs/templates/miro.md +121 -0
  1213. package/skills/creative/popular-web-designs/templates/mistral.ai.md +274 -0
  1214. package/skills/creative/popular-web-designs/templates/mongodb.md +279 -0
  1215. package/skills/creative/popular-web-designs/templates/notion.md +322 -0
  1216. package/skills/creative/popular-web-designs/templates/nvidia.md +306 -0
  1217. package/skills/creative/popular-web-designs/templates/ollama.md +280 -0
  1218. package/skills/creative/popular-web-designs/templates/opencode.ai.md +294 -0
  1219. package/skills/creative/popular-web-designs/templates/pinterest.md +243 -0
  1220. package/skills/creative/popular-web-designs/templates/posthog.md +269 -0
  1221. package/skills/creative/popular-web-designs/templates/raycast.md +281 -0
  1222. package/skills/creative/popular-web-designs/templates/replicate.md +274 -0
  1223. package/skills/creative/popular-web-designs/templates/resend.md +316 -0
  1224. package/skills/creative/popular-web-designs/templates/revolut.md +198 -0
  1225. package/skills/creative/popular-web-designs/templates/runwayml.md +257 -0
  1226. package/skills/creative/popular-web-designs/templates/sanity.md +370 -0
  1227. package/skills/creative/popular-web-designs/templates/sentry.md +275 -0
  1228. package/skills/creative/popular-web-designs/templates/spacex.md +207 -0
  1229. package/skills/creative/popular-web-designs/templates/spotify.md +259 -0
  1230. package/skills/creative/popular-web-designs/templates/stripe.md +335 -0
  1231. package/skills/creative/popular-web-designs/templates/supabase.md +268 -0
  1232. package/skills/creative/popular-web-designs/templates/superhuman.md +265 -0
  1233. package/skills/creative/popular-web-designs/templates/together.ai.md +276 -0
  1234. package/skills/creative/popular-web-designs/templates/uber.md +308 -0
  1235. package/skills/creative/popular-web-designs/templates/vercel.md +323 -0
  1236. package/skills/creative/popular-web-designs/templates/voltagent.md +336 -0
  1237. package/skills/creative/popular-web-designs/templates/warp.md +266 -0
  1238. package/skills/creative/popular-web-designs/templates/webflow.md +105 -0
  1239. package/skills/creative/popular-web-designs/templates/wise.md +186 -0
  1240. package/skills/creative/popular-web-designs/templates/x.ai.md +270 -0
  1241. package/skills/creative/popular-web-designs/templates/zapier.md +341 -0
  1242. package/skills/creative/pretext/SKILL.md +220 -0
  1243. package/skills/creative/pretext/references/patterns.md +258 -0
  1244. package/skills/creative/pretext/templates/donut-orbit.html +1468 -0
  1245. package/skills/creative/pretext/templates/hello-orb-flow.html +95 -0
  1246. package/skills/creative/sketch/SKILL.md +218 -0
  1247. package/skills/creative/songwriting-and-ai-music/SKILL.md +287 -0
  1248. package/skills/creative/touchdesigner-mcp/SKILL.md +356 -0
  1249. package/skills/creative/touchdesigner-mcp/references/3d-scene.md +275 -0
  1250. package/skills/creative/touchdesigner-mcp/references/animation.md +221 -0
  1251. package/skills/creative/touchdesigner-mcp/references/audio-reactive.md +175 -0
  1252. package/skills/creative/touchdesigner-mcp/references/dat-scripting.md +352 -0
  1253. package/skills/creative/touchdesigner-mcp/references/external-data.md +322 -0
  1254. package/skills/creative/touchdesigner-mcp/references/geometry-comp.md +121 -0
  1255. package/skills/creative/touchdesigner-mcp/references/glsl.md +151 -0
  1256. package/skills/creative/touchdesigner-mcp/references/layout-compositor.md +131 -0
  1257. package/skills/creative/touchdesigner-mcp/references/mcp-tools.md +382 -0
  1258. package/skills/creative/touchdesigner-mcp/references/midi-osc.md +211 -0
  1259. package/skills/creative/touchdesigner-mcp/references/network-patterns.md +966 -0
  1260. package/skills/creative/touchdesigner-mcp/references/operator-tips.md +106 -0
  1261. package/skills/creative/touchdesigner-mcp/references/operators.md +239 -0
  1262. package/skills/creative/touchdesigner-mcp/references/panel-ui.md +281 -0
  1263. package/skills/creative/touchdesigner-mcp/references/particles.md +245 -0
  1264. package/skills/creative/touchdesigner-mcp/references/pitfalls.md +704 -0
  1265. package/skills/creative/touchdesigner-mcp/references/postfx.md +183 -0
  1266. package/skills/creative/touchdesigner-mcp/references/projection-mapping.md +211 -0
  1267. package/skills/creative/touchdesigner-mcp/references/python-api.md +463 -0
  1268. package/skills/creative/touchdesigner-mcp/references/replicator.md +198 -0
  1269. package/skills/creative/touchdesigner-mcp/references/troubleshooting.md +244 -0
  1270. package/skills/creative/touchdesigner-mcp/scripts/setup.sh +115 -0
  1271. package/skills/data-science/DESCRIPTION.md +3 -0
  1272. package/skills/data-science/jupyter-live-kernel/SKILL.md +167 -0
  1273. package/skills/devops/kanban-orchestrator/SKILL.md +189 -0
  1274. package/skills/devops/kanban-worker/SKILL.md +184 -0
  1275. package/skills/devops/webhook-subscriptions/SKILL.md +204 -0
  1276. package/skills/diagramming/DESCRIPTION.md +3 -0
  1277. package/skills/dogfood/SKILL.md +162 -0
  1278. package/skills/dogfood/references/issue-taxonomy.md +109 -0
  1279. package/skills/dogfood/templates/dogfood-report-template.md +86 -0
  1280. package/skills/domain/DESCRIPTION.md +24 -0
  1281. package/skills/email/DESCRIPTION.md +3 -0
  1282. package/skills/email/himalaya/SKILL.md +299 -0
  1283. package/skills/email/himalaya/references/configuration.md +227 -0
  1284. package/skills/email/himalaya/references/message-composition.md +199 -0
  1285. package/skills/gaming/DESCRIPTION.md +3 -0
  1286. package/skills/gaming/minecraft-modpack-server/SKILL.md +187 -0
  1287. package/skills/gaming/pokemon-player/SKILL.md +216 -0
  1288. package/skills/gifs/DESCRIPTION.md +3 -0
  1289. package/skills/github/DESCRIPTION.md +3 -0
  1290. package/skills/github/codebase-inspection/SKILL.md +116 -0
  1291. package/skills/github/github-auth/SKILL.md +247 -0
  1292. package/skills/github/github-auth/scripts/gh-env.sh +66 -0
  1293. package/skills/github/github-code-review/SKILL.md +481 -0
  1294. package/skills/github/github-code-review/references/review-output-template.md +74 -0
  1295. package/skills/github/github-issues/SKILL.md +370 -0
  1296. package/skills/github/github-issues/templates/bug-report.md +35 -0
  1297. package/skills/github/github-issues/templates/feature-request.md +31 -0
  1298. package/skills/github/github-pr-workflow/SKILL.md +367 -0
  1299. package/skills/github/github-pr-workflow/references/ci-troubleshooting.md +183 -0
  1300. package/skills/github/github-pr-workflow/references/conventional-commits.md +71 -0
  1301. package/skills/github/github-pr-workflow/templates/pr-body-bugfix.md +35 -0
  1302. package/skills/github/github-pr-workflow/templates/pr-body-feature.md +33 -0
  1303. package/skills/github/github-repo-management/SKILL.md +516 -0
  1304. package/skills/github/github-repo-management/references/github-api-cheatsheet.md +161 -0
  1305. package/skills/index-cache/anthropics_skills_skills_.json +1 -0
  1306. package/skills/index-cache/claude_marketplace_anthropics_skills.json +1 -0
  1307. package/skills/index-cache/lobehub_index.json +1 -0
  1308. package/skills/index-cache/openai_skills_skills_.json +1 -0
  1309. package/skills/inference-sh/DESCRIPTION.md +19 -0
  1310. package/skills/mcp/DESCRIPTION.md +3 -0
  1311. package/skills/mcp/native-mcp/SKILL.md +357 -0
  1312. package/skills/media/DESCRIPTION.md +3 -0
  1313. package/skills/media/gif-search/SKILL.md +91 -0
  1314. package/skills/media/heartmula/SKILL.md +171 -0
  1315. package/skills/media/songsee/SKILL.md +83 -0
  1316. package/skills/media/spotify/SKILL.md +135 -0
  1317. package/skills/media/youtube-content/SKILL.md +73 -0
  1318. package/skills/media/youtube-content/references/output-formats.md +56 -0
  1319. package/skills/media/youtube-content/scripts/fetch_transcript.py +124 -0
  1320. package/skills/mlops/DESCRIPTION.md +3 -0
  1321. package/skills/mlops/evaluation/DESCRIPTION.md +3 -0
  1322. package/skills/mlops/evaluation/lm-evaluation-harness/SKILL.md +498 -0
  1323. package/skills/mlops/evaluation/lm-evaluation-harness/references/api-evaluation.md +490 -0
  1324. package/skills/mlops/evaluation/lm-evaluation-harness/references/benchmark-guide.md +488 -0
  1325. package/skills/mlops/evaluation/lm-evaluation-harness/references/custom-tasks.md +602 -0
  1326. package/skills/mlops/evaluation/lm-evaluation-harness/references/distributed-eval.md +519 -0
  1327. package/skills/mlops/evaluation/weights-and-biases/SKILL.md +594 -0
  1328. package/skills/mlops/evaluation/weights-and-biases/references/artifacts.md +584 -0
  1329. package/skills/mlops/evaluation/weights-and-biases/references/integrations.md +700 -0
  1330. package/skills/mlops/evaluation/weights-and-biases/references/sweeps.md +847 -0
  1331. package/skills/mlops/huggingface-hub/SKILL.md +81 -0
  1332. package/skills/mlops/inference/DESCRIPTION.md +3 -0
  1333. package/skills/mlops/inference/llama-cpp/SKILL.md +249 -0
  1334. package/skills/mlops/inference/llama-cpp/references/advanced-usage.md +504 -0
  1335. package/skills/mlops/inference/llama-cpp/references/hub-discovery.md +168 -0
  1336. package/skills/mlops/inference/llama-cpp/references/optimization.md +89 -0
  1337. package/skills/mlops/inference/llama-cpp/references/quantization.md +243 -0
  1338. package/skills/mlops/inference/llama-cpp/references/server.md +150 -0
  1339. package/skills/mlops/inference/llama-cpp/references/troubleshooting.md +442 -0
  1340. package/skills/mlops/inference/obliteratus/SKILL.md +342 -0
  1341. package/skills/mlops/inference/obliteratus/references/analysis-modules.md +166 -0
  1342. package/skills/mlops/inference/obliteratus/references/methods-guide.md +141 -0
  1343. package/skills/mlops/inference/obliteratus/templates/abliteration-config.yaml +33 -0
  1344. package/skills/mlops/inference/obliteratus/templates/analysis-study.yaml +40 -0
  1345. package/skills/mlops/inference/obliteratus/templates/batch-abliteration.yaml +41 -0
  1346. package/skills/mlops/inference/vllm/SKILL.md +372 -0
  1347. package/skills/mlops/inference/vllm/references/optimization.md +226 -0
  1348. package/skills/mlops/inference/vllm/references/quantization.md +284 -0
  1349. package/skills/mlops/inference/vllm/references/server-deployment.md +255 -0
  1350. package/skills/mlops/inference/vllm/references/troubleshooting.md +447 -0
  1351. package/skills/mlops/models/DESCRIPTION.md +3 -0
  1352. package/skills/mlops/models/audiocraft/SKILL.md +568 -0
  1353. package/skills/mlops/models/audiocraft/references/advanced-usage.md +666 -0
  1354. package/skills/mlops/models/audiocraft/references/troubleshooting.md +504 -0
  1355. package/skills/mlops/models/segment-anything/SKILL.md +506 -0
  1356. package/skills/mlops/models/segment-anything/references/advanced-usage.md +589 -0
  1357. package/skills/mlops/models/segment-anything/references/troubleshooting.md +484 -0
  1358. package/skills/mlops/research/DESCRIPTION.md +3 -0
  1359. package/skills/mlops/research/dspy/SKILL.md +594 -0
  1360. package/skills/mlops/research/dspy/references/examples.md +663 -0
  1361. package/skills/mlops/research/dspy/references/modules.md +475 -0
  1362. package/skills/mlops/research/dspy/references/optimizers.md +566 -0
  1363. package/skills/mlops/training/DESCRIPTION.md +3 -0
  1364. package/skills/mlops/vector-databases/DESCRIPTION.md +3 -0
  1365. package/skills/note-taking/DESCRIPTION.md +3 -0
  1366. package/skills/note-taking/obsidian/SKILL.md +61 -0
  1367. package/skills/productivity/DESCRIPTION.md +3 -0
  1368. package/skills/productivity/airtable/SKILL.md +229 -0
  1369. package/skills/productivity/google-workspace/SKILL.md +335 -0
  1370. package/skills/productivity/google-workspace/references/gmail-search-syntax.md +63 -0
  1371. package/skills/productivity/google-workspace/scripts/_hermes_home.py +43 -0
  1372. package/skills/productivity/google-workspace/scripts/google_api.py +1221 -0
  1373. package/skills/productivity/google-workspace/scripts/gws_bridge.py +108 -0
  1374. package/skills/productivity/google-workspace/scripts/setup.py +454 -0
  1375. package/skills/productivity/linear/SKILL.md +380 -0
  1376. package/skills/productivity/linear/scripts/linear_api.py +445 -0
  1377. package/skills/productivity/maps/SKILL.md +195 -0
  1378. package/skills/productivity/maps/scripts/maps_client.py +1298 -0
  1379. package/skills/productivity/nano-pdf/SKILL.md +52 -0
  1380. package/skills/productivity/notion/SKILL.md +448 -0
  1381. package/skills/productivity/notion/references/block-types.md +112 -0
  1382. package/skills/productivity/ocr-and-documents/DESCRIPTION.md +3 -0
  1383. package/skills/productivity/ocr-and-documents/SKILL.md +172 -0
  1384. package/skills/productivity/ocr-and-documents/scripts/extract_marker.py +87 -0
  1385. package/skills/productivity/ocr-and-documents/scripts/extract_pymupdf.py +98 -0
  1386. package/skills/productivity/powerpoint/LICENSE.txt +30 -0
  1387. package/skills/productivity/powerpoint/SKILL.md +237 -0
  1388. package/skills/productivity/powerpoint/editing.md +205 -0
  1389. package/skills/productivity/powerpoint/pptxgenjs.md +420 -0
  1390. package/skills/productivity/powerpoint/scripts/__init__.py +0 -0
  1391. package/skills/productivity/powerpoint/scripts/add_slide.py +195 -0
  1392. package/skills/productivity/powerpoint/scripts/clean.py +286 -0
  1393. package/skills/productivity/powerpoint/scripts/office/helpers/__init__.py +0 -0
  1394. package/skills/productivity/powerpoint/scripts/office/helpers/merge_runs.py +199 -0
  1395. package/skills/productivity/powerpoint/scripts/office/helpers/simplify_redlines.py +197 -0
  1396. package/skills/productivity/powerpoint/scripts/office/pack.py +159 -0
  1397. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  1398. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  1399. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  1400. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  1401. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  1402. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  1403. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  1404. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  1405. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  1406. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  1407. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  1408. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  1409. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  1410. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  1411. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  1412. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  1413. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  1414. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  1415. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  1416. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  1417. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  1418. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  1419. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  1420. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  1421. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  1422. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  1423. package/skills/productivity/powerpoint/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  1424. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-contentTypes.xsd +42 -0
  1425. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-coreProperties.xsd +50 -0
  1426. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-digSig.xsd +49 -0
  1427. package/skills/productivity/powerpoint/scripts/office/schemas/ecma/fourth-edition/opc-relationships.xsd +33 -0
  1428. package/skills/productivity/powerpoint/scripts/office/schemas/mce/mc.xsd +75 -0
  1429. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  1430. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  1431. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  1432. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  1433. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  1434. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  1435. package/skills/productivity/powerpoint/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  1436. package/skills/productivity/teams-meeting-pipeline/SKILL.md +116 -0
  1437. package/skills/red-teaming/godmode/SKILL.md +404 -0
  1438. package/skills/red-teaming/godmode/references/jailbreak-templates.md +128 -0
  1439. package/skills/red-teaming/godmode/references/refusal-detection.md +142 -0
  1440. package/skills/red-teaming/godmode/scripts/auto_jailbreak.py +769 -0
  1441. package/skills/red-teaming/godmode/scripts/godmode_race.py +530 -0
  1442. package/skills/red-teaming/godmode/scripts/load_godmode.py +45 -0
  1443. package/skills/red-teaming/godmode/scripts/parseltongue.py +550 -0
  1444. package/skills/red-teaming/godmode/templates/prefill-subtle.json +10 -0
  1445. package/skills/red-teaming/godmode/templates/prefill.json +18 -0
  1446. package/skills/research/DESCRIPTION.md +3 -0
  1447. package/skills/research/arxiv/SKILL.md +282 -0
  1448. package/skills/research/arxiv/scripts/search_arxiv.py +114 -0
  1449. package/skills/research/blogwatcher/SKILL.md +137 -0
  1450. package/skills/research/llm-wiki/SKILL.md +507 -0
  1451. package/skills/research/polymarket/SKILL.md +77 -0
  1452. package/skills/research/polymarket/references/api-endpoints.md +220 -0
  1453. package/skills/research/polymarket/scripts/polymarket.py +284 -0
  1454. package/skills/research/research-paper-writing/SKILL.md +2377 -0
  1455. package/skills/research/research-paper-writing/references/autoreason-methodology.md +394 -0
  1456. package/skills/research/research-paper-writing/references/checklists.md +434 -0
  1457. package/skills/research/research-paper-writing/references/citation-workflow.md +564 -0
  1458. package/skills/research/research-paper-writing/references/experiment-patterns.md +728 -0
  1459. package/skills/research/research-paper-writing/references/human-evaluation.md +476 -0
  1460. package/skills/research/research-paper-writing/references/paper-types.md +481 -0
  1461. package/skills/research/research-paper-writing/references/reviewer-guidelines.md +433 -0
  1462. package/skills/research/research-paper-writing/references/sources.md +191 -0
  1463. package/skills/research/research-paper-writing/references/writing-guide.md +474 -0
  1464. package/skills/research/research-paper-writing/templates/README.md +251 -0
  1465. package/skills/research/research-paper-writing/templates/aaai2026/README.md +534 -0
  1466. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
  1467. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026-unified-template.tex +952 -0
  1468. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.bib +111 -0
  1469. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.bst +1493 -0
  1470. package/skills/research/research-paper-writing/templates/aaai2026/aaai2026.sty +315 -0
  1471. package/skills/research/research-paper-writing/templates/acl/README.md +50 -0
  1472. package/skills/research/research-paper-writing/templates/acl/acl.sty +312 -0
  1473. package/skills/research/research-paper-writing/templates/acl/acl_latex.tex +377 -0
  1474. package/skills/research/research-paper-writing/templates/acl/acl_lualatex.tex +101 -0
  1475. package/skills/research/research-paper-writing/templates/acl/acl_natbib.bst +1940 -0
  1476. package/skills/research/research-paper-writing/templates/acl/anthology.bib.txt +26 -0
  1477. package/skills/research/research-paper-writing/templates/acl/custom.bib +70 -0
  1478. package/skills/research/research-paper-writing/templates/acl/formatting.md +326 -0
  1479. package/skills/research/research-paper-writing/templates/colm2025/README.md +3 -0
  1480. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bib +11 -0
  1481. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.bst +1440 -0
  1482. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.pdf +0 -0
  1483. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.sty +218 -0
  1484. package/skills/research/research-paper-writing/templates/colm2025/colm2025_conference.tex +305 -0
  1485. package/skills/research/research-paper-writing/templates/colm2025/fancyhdr.sty +485 -0
  1486. package/skills/research/research-paper-writing/templates/colm2025/math_commands.tex +508 -0
  1487. package/skills/research/research-paper-writing/templates/colm2025/natbib.sty +1246 -0
  1488. package/skills/research/research-paper-writing/templates/iclr2026/fancyhdr.sty +485 -0
  1489. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bib +24 -0
  1490. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.bst +1440 -0
  1491. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.pdf +0 -0
  1492. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.sty +246 -0
  1493. package/skills/research/research-paper-writing/templates/iclr2026/iclr2026_conference.tex +414 -0
  1494. package/skills/research/research-paper-writing/templates/iclr2026/math_commands.tex +508 -0
  1495. package/skills/research/research-paper-writing/templates/iclr2026/natbib.sty +1246 -0
  1496. package/skills/research/research-paper-writing/templates/icml2026/algorithm.sty +79 -0
  1497. package/skills/research/research-paper-writing/templates/icml2026/algorithmic.sty +201 -0
  1498. package/skills/research/research-paper-writing/templates/icml2026/example_paper.bib +75 -0
  1499. package/skills/research/research-paper-writing/templates/icml2026/example_paper.pdf +0 -0
  1500. package/skills/research/research-paper-writing/templates/icml2026/example_paper.tex +662 -0
  1501. package/skills/research/research-paper-writing/templates/icml2026/fancyhdr.sty +864 -0
  1502. package/skills/research/research-paper-writing/templates/icml2026/icml2026.bst +1443 -0
  1503. package/skills/research/research-paper-writing/templates/icml2026/icml2026.sty +767 -0
  1504. package/skills/research/research-paper-writing/templates/icml2026/icml_numpapers.pdf +0 -0
  1505. package/skills/research/research-paper-writing/templates/neurips2025/Makefile +36 -0
  1506. package/skills/research/research-paper-writing/templates/neurips2025/extra_pkgs.tex +53 -0
  1507. package/skills/research/research-paper-writing/templates/neurips2025/main.tex +38 -0
  1508. package/skills/research/research-paper-writing/templates/neurips2025/neurips.sty +382 -0
  1509. package/skills/smart-home/DESCRIPTION.md +3 -0
  1510. package/skills/smart-home/openhue/SKILL.md +109 -0
  1511. package/skills/social-media/DESCRIPTION.md +3 -0
  1512. package/skills/social-media/xurl/SKILL.md +414 -0
  1513. package/skills/software-development/debugging-hermes-tui-commands/SKILL.md +152 -0
  1514. package/skills/software-development/hermes-agent-skill-authoring/SKILL.md +165 -0
  1515. package/skills/software-development/node-inspect-debugger/SKILL.md +319 -0
  1516. package/skills/software-development/plan/SKILL.md +58 -0
  1517. package/skills/software-development/python-debugpy/SKILL.md +375 -0
  1518. package/skills/software-development/requesting-code-review/SKILL.md +280 -0
  1519. package/skills/software-development/spike/SKILL.md +197 -0
  1520. package/skills/software-development/subagent-driven-development/SKILL.md +352 -0
  1521. package/skills/software-development/subagent-driven-development/references/context-budget-discipline.md +53 -0
  1522. package/skills/software-development/subagent-driven-development/references/gates-taxonomy.md +93 -0
  1523. package/skills/software-development/systematic-debugging/SKILL.md +367 -0
  1524. package/skills/software-development/test-driven-development/SKILL.md +343 -0
  1525. package/skills/software-development/writing-plans/SKILL.md +297 -0
  1526. package/skills/yuanbao/SKILL.md +108 -0
  1527. package/tools/__init__.py +25 -0
  1528. package/tools/__pycache__/__init__.cpython-312.pyc +0 -0
  1529. package/tools/__pycache__/approval.cpython-312.pyc +0 -0
  1530. package/tools/__pycache__/binary_extensions.cpython-312.pyc +0 -0
  1531. package/tools/__pycache__/browser_camofox.cpython-312.pyc +0 -0
  1532. package/tools/__pycache__/browser_camofox_state.cpython-312.pyc +0 -0
  1533. package/tools/__pycache__/browser_cdp_tool.cpython-312.pyc +0 -0
  1534. package/tools/__pycache__/browser_dialog_tool.cpython-312.pyc +0 -0
  1535. package/tools/__pycache__/browser_supervisor.cpython-312.pyc +0 -0
  1536. package/tools/__pycache__/browser_tool.cpython-312.pyc +0 -0
  1537. package/tools/__pycache__/budget_config.cpython-312.pyc +0 -0
  1538. package/tools/__pycache__/checkpoint_manager.cpython-312.pyc +0 -0
  1539. package/tools/__pycache__/clarify_gateway.cpython-312.pyc +0 -0
  1540. package/tools/__pycache__/clarify_tool.cpython-312.pyc +0 -0
  1541. package/tools/__pycache__/code_execution_tool.cpython-312.pyc +0 -0
  1542. package/tools/__pycache__/computer_use_tool.cpython-312.pyc +0 -0
  1543. package/tools/__pycache__/cronjob_tools.cpython-312.pyc +0 -0
  1544. package/tools/__pycache__/debug_helpers.cpython-312.pyc +0 -0
  1545. package/tools/__pycache__/delegate_tool.cpython-312.pyc +0 -0
  1546. package/tools/__pycache__/discord_tool.cpython-312.pyc +0 -0
  1547. package/tools/__pycache__/feishu_doc_tool.cpython-312.pyc +0 -0
  1548. package/tools/__pycache__/feishu_drive_tool.cpython-312.pyc +0 -0
  1549. package/tools/__pycache__/file_operations.cpython-312.pyc +0 -0
  1550. package/tools/__pycache__/file_state.cpython-312.pyc +0 -0
  1551. package/tools/__pycache__/file_tools.cpython-312.pyc +0 -0
  1552. package/tools/__pycache__/homeassistant_tool.cpython-312.pyc +0 -0
  1553. package/tools/__pycache__/image_generation_tool.cpython-312.pyc +0 -0
  1554. package/tools/__pycache__/interrupt.cpython-312.pyc +0 -0
  1555. package/tools/__pycache__/kanban_tools.cpython-312.pyc +0 -0
  1556. package/tools/__pycache__/lazy_deps.cpython-312.pyc +0 -0
  1557. package/tools/__pycache__/managed_tool_gateway.cpython-312.pyc +0 -0
  1558. package/tools/__pycache__/mcp_tool.cpython-312.pyc +0 -0
  1559. package/tools/__pycache__/memory_tool.cpython-312.pyc +0 -0
  1560. package/tools/__pycache__/mixture_of_agents_tool.cpython-312.pyc +0 -0
  1561. package/tools/__pycache__/openrouter_client.cpython-312.pyc +0 -0
  1562. package/tools/__pycache__/process_registry.cpython-312.pyc +0 -0
  1563. package/tools/__pycache__/registry.cpython-312.pyc +0 -0
  1564. package/tools/__pycache__/schema_sanitizer.cpython-312.pyc +0 -0
  1565. package/tools/__pycache__/send_message_tool.cpython-312.pyc +0 -0
  1566. package/tools/__pycache__/session_search_tool.cpython-312.pyc +0 -0
  1567. package/tools/__pycache__/skill_manager_tool.cpython-312.pyc +0 -0
  1568. package/tools/__pycache__/skill_provenance.cpython-312.pyc +0 -0
  1569. package/tools/__pycache__/skill_usage.cpython-312.pyc +0 -0
  1570. package/tools/__pycache__/skills_guard.cpython-312.pyc +0 -0
  1571. package/tools/__pycache__/skills_sync.cpython-312.pyc +0 -0
  1572. package/tools/__pycache__/skills_tool.cpython-312.pyc +0 -0
  1573. package/tools/__pycache__/slash_confirm.cpython-312.pyc +0 -0
  1574. package/tools/__pycache__/terminal_tool.cpython-312.pyc +0 -0
  1575. package/tools/__pycache__/tirith_security.cpython-312.pyc +0 -0
  1576. package/tools/__pycache__/todo_tool.cpython-312.pyc +0 -0
  1577. package/tools/__pycache__/tool_backend_helpers.cpython-312.pyc +0 -0
  1578. package/tools/__pycache__/tool_result_storage.cpython-312.pyc +0 -0
  1579. package/tools/__pycache__/tts_tool.cpython-312.pyc +0 -0
  1580. package/tools/__pycache__/url_safety.cpython-312.pyc +0 -0
  1581. package/tools/__pycache__/video_generation_tool.cpython-312.pyc +0 -0
  1582. package/tools/__pycache__/vision_tools.cpython-312.pyc +0 -0
  1583. package/tools/__pycache__/voice_mode.cpython-312.pyc +0 -0
  1584. package/tools/__pycache__/web_tools.cpython-312.pyc +0 -0
  1585. package/tools/__pycache__/website_policy.cpython-312.pyc +0 -0
  1586. package/tools/__pycache__/x_search_tool.cpython-312.pyc +0 -0
  1587. package/tools/__pycache__/xai_http.cpython-312.pyc +0 -0
  1588. package/tools/__pycache__/yuanbao_tools.cpython-312.pyc +0 -0
  1589. package/tools/ansi_strip.py +44 -0
  1590. package/tools/approval.py +1392 -0
  1591. package/tools/binary_extensions.py +42 -0
  1592. package/tools/browser_camofox.py +700 -0
  1593. package/tools/browser_camofox_state.py +48 -0
  1594. package/tools/browser_cdp_tool.py +569 -0
  1595. package/tools/browser_dialog_tool.py +148 -0
  1596. package/tools/browser_providers/__init__.py +10 -0
  1597. package/tools/browser_providers/__pycache__/__init__.cpython-312.pyc +0 -0
  1598. package/tools/browser_providers/__pycache__/base.cpython-312.pyc +0 -0
  1599. package/tools/browser_providers/__pycache__/browser_use.cpython-312.pyc +0 -0
  1600. package/tools/browser_providers/__pycache__/browserbase.cpython-312.pyc +0 -0
  1601. package/tools/browser_providers/__pycache__/firecrawl.cpython-312.pyc +0 -0
  1602. package/tools/browser_providers/base.py +59 -0
  1603. package/tools/browser_providers/browser_use.py +225 -0
  1604. package/tools/browser_providers/browserbase.py +222 -0
  1605. package/tools/browser_providers/firecrawl.py +112 -0
  1606. package/tools/browser_supervisor.py +1457 -0
  1607. package/tools/browser_tool.py +3676 -0
  1608. package/tools/budget_config.py +51 -0
  1609. package/tools/checkpoint_manager.py +1639 -0
  1610. package/tools/clarify_gateway.py +278 -0
  1611. package/tools/clarify_tool.py +141 -0
  1612. package/tools/code_execution_tool.py +1782 -0
  1613. package/tools/computer_use/__init__.py +43 -0
  1614. package/tools/computer_use/__pycache__/__init__.cpython-312.pyc +0 -0
  1615. package/tools/computer_use/__pycache__/backend.cpython-312.pyc +0 -0
  1616. package/tools/computer_use/__pycache__/schema.cpython-312.pyc +0 -0
  1617. package/tools/computer_use/__pycache__/tool.cpython-312.pyc +0 -0
  1618. package/tools/computer_use/backend.py +150 -0
  1619. package/tools/computer_use/cua_backend.py +682 -0
  1620. package/tools/computer_use/schema.py +191 -0
  1621. package/tools/computer_use/tool.py +521 -0
  1622. package/tools/computer_use_tool.py +39 -0
  1623. package/tools/credential_files.py +437 -0
  1624. package/tools/cronjob_tools.py +719 -0
  1625. package/tools/debug_helpers.py +106 -0
  1626. package/tools/delegate_tool.py +2797 -0
  1627. package/tools/discord_tool.py +959 -0
  1628. package/tools/env_passthrough.py +145 -0
  1629. package/tools/environments/__init__.py +14 -0
  1630. package/tools/environments/__pycache__/__init__.cpython-312.pyc +0 -0
  1631. package/tools/environments/__pycache__/base.cpython-312.pyc +0 -0
  1632. package/tools/environments/__pycache__/docker.cpython-312.pyc +0 -0
  1633. package/tools/environments/__pycache__/file_sync.cpython-312.pyc +0 -0
  1634. package/tools/environments/__pycache__/local.cpython-312.pyc +0 -0
  1635. package/tools/environments/__pycache__/managed_modal.cpython-312.pyc +0 -0
  1636. package/tools/environments/__pycache__/modal.cpython-312.pyc +0 -0
  1637. package/tools/environments/__pycache__/modal_utils.cpython-312.pyc +0 -0
  1638. package/tools/environments/__pycache__/singularity.cpython-312.pyc +0 -0
  1639. package/tools/environments/__pycache__/ssh.cpython-312.pyc +0 -0
  1640. package/tools/environments/base.py +844 -0
  1641. package/tools/environments/daytona.py +270 -0
  1642. package/tools/environments/docker.py +656 -0
  1643. package/tools/environments/file_sync.py +400 -0
  1644. package/tools/environments/local.py +658 -0
  1645. package/tools/environments/managed_modal.py +282 -0
  1646. package/tools/environments/modal.py +479 -0
  1647. package/tools/environments/modal_utils.py +199 -0
  1648. package/tools/environments/singularity.py +263 -0
  1649. package/tools/environments/ssh.py +295 -0
  1650. package/tools/environments/vercel_sandbox.py +655 -0
  1651. package/tools/feishu_doc_tool.py +138 -0
  1652. package/tools/feishu_drive_tool.py +431 -0
  1653. package/tools/file_operations.py +1825 -0
  1654. package/tools/file_state.py +332 -0
  1655. package/tools/file_tools.py +1172 -0
  1656. package/tools/fuzzy_match.py +703 -0
  1657. package/tools/homeassistant_tool.py +513 -0
  1658. package/tools/image_generation_tool.py +1098 -0
  1659. package/tools/interrupt.py +98 -0
  1660. package/tools/kanban_tools.py +1139 -0
  1661. package/tools/lazy_deps.py +608 -0
  1662. package/tools/managed_tool_gateway.py +168 -0
  1663. package/tools/mcp_oauth.py +633 -0
  1664. package/tools/mcp_oauth_manager.py +607 -0
  1665. package/tools/mcp_tool.py +3483 -0
  1666. package/tools/memory_tool.py +584 -0
  1667. package/tools/microsoft_graph_auth.py +245 -0
  1668. package/tools/microsoft_graph_client.py +408 -0
  1669. package/tools/mixture_of_agents_tool.py +542 -0
  1670. package/tools/neutts_samples/jo.txt +1 -0
  1671. package/tools/neutts_samples/jo.wav +0 -0
  1672. package/tools/neutts_synth.py +104 -0
  1673. package/tools/openrouter_client.py +33 -0
  1674. package/tools/osv_check.py +155 -0
  1675. package/tools/patch_parser.py +592 -0
  1676. package/tools/path_security.py +43 -0
  1677. package/tools/process_registry.py +1534 -0
  1678. package/tools/registry.py +589 -0
  1679. package/tools/schema_sanitizer.py +370 -0
  1680. package/tools/send_message_tool.py +1900 -0
  1681. package/tools/session_search_tool.py +613 -0
  1682. package/tools/skill_manager_tool.py +932 -0
  1683. package/tools/skill_provenance.py +78 -0
  1684. package/tools/skill_usage.py +610 -0
  1685. package/tools/skills_guard.py +932 -0
  1686. package/tools/skills_hub.py +3263 -0
  1687. package/tools/skills_sync.py +432 -0
  1688. package/tools/skills_tool.py +1569 -0
  1689. package/tools/slash_confirm.py +167 -0
  1690. package/tools/terminal_tool.py +2376 -0
  1691. package/tools/tirith_security.py +775 -0
  1692. package/tools/todo_tool.py +277 -0
  1693. package/tools/tool_backend_helpers.py +144 -0
  1694. package/tools/tool_output_limits.py +92 -0
  1695. package/tools/tool_result_storage.py +232 -0
  1696. package/tools/transcription_tools.py +936 -0
  1697. package/tools/tts_tool.py +2285 -0
  1698. package/tools/url_safety.py +330 -0
  1699. package/tools/video_generation_tool.py +561 -0
  1700. package/tools/vision_tools.py +1422 -0
  1701. package/tools/voice_mode.py +1019 -0
  1702. package/tools/web_tools.py +1551 -0
  1703. package/tools/website_policy.py +283 -0
  1704. package/tools/x_search_tool.py +424 -0
  1705. package/tools/xai_http.py +83 -0
  1706. package/tools/yuanbao_tools.py +736 -0
  1707. package/toolset_distributions.py +364 -0
  1708. package/toolsets.py +866 -0
  1709. package/trajectory_compressor.py +1509 -0
  1710. package/tui_gateway/__init__.py +0 -0
  1711. package/tui_gateway/entry.py +251 -0
  1712. package/tui_gateway/event_publisher.py +126 -0
  1713. package/tui_gateway/render.py +49 -0
  1714. package/tui_gateway/server.py +6623 -0
  1715. package/tui_gateway/slash_worker.py +76 -0
  1716. package/tui_gateway/transport.py +219 -0
  1717. package/tui_gateway/ws.py +178 -0
  1718. package/utils.py +361 -0
@@ -0,0 +1,2087 @@
1
+ """Anthropic Messages API adapter for Hermes Agent.
2
+
3
+ Translates between Hermes's internal OpenAI-style message format and
4
+ Anthropic's Messages API. Follows the same pattern as the codex_responses
5
+ adapter — all provider-specific logic is isolated here.
6
+
7
+ Auth supports:
8
+ - Regular API keys (sk-ant-api*) → x-api-key header
9
+ - OAuth setup-tokens (sk-ant-oat*) → Bearer auth + beta header
10
+ - Claude Code credentials (~/.claude.json or ~/.claude/.credentials.json) → Bearer auth
11
+ """
12
+
13
+ import copy
14
+ import json
15
+ import logging
16
+ import os
17
+ import platform
18
+ import subprocess
19
+ from pathlib import Path
20
+
21
+ from calvyn_constants import get_hermes_home
22
+ from typing import Any, Dict, List, Optional, Tuple
23
+ from utils import base_url_host_matches, normalize_proxy_env_vars
24
+
25
+ # NOTE: `import anthropic` is deliberately NOT at module top — the SDK pulls
26
+ # ~220 ms of imports (anthropic.types, anthropic.lib.tools._beta_runner, etc.)
27
+ # and the 3 usage sites (build_anthropic_client, build_anthropic_bedrock_client,
28
+ # read_claude_code_credentials_from_keychain) are all on cold user-triggered
29
+ # paths. Access via the `_get_anthropic_sdk()` accessor below, which caches
30
+ # the module after the first call and returns None on ImportError.
31
+ _anthropic_sdk: Any = ... # sentinel — None means "tried and missing"
32
+
33
+
34
+ def _get_anthropic_sdk():
35
+ """Return the ``anthropic`` SDK module, importing lazily. None if not installed."""
36
+ global _anthropic_sdk
37
+ if _anthropic_sdk is ...:
38
+ try:
39
+ from tools.lazy_deps import ensure as _lazy_ensure
40
+ _lazy_ensure("provider.anthropic", prompt=False)
41
+ except ImportError:
42
+ pass
43
+ except Exception:
44
+ # FeatureUnavailable — fall through to ImportError handling below
45
+ pass
46
+ try:
47
+ import anthropic as _sdk
48
+ _anthropic_sdk = _sdk
49
+ except ImportError:
50
+ _anthropic_sdk = None
51
+ return _anthropic_sdk
52
+
53
+ logger = logging.getLogger(__name__)
54
+
55
+ THINKING_BUDGET = {"xhigh": 32000, "high": 16000, "medium": 8000, "low": 4000}
56
+ # Hermes effort → Anthropic adaptive-thinking effort (output_config.effort).
57
+ # Anthropic exposes 5 levels on 4.7+: low, medium, high, xhigh, max.
58
+ # Opus/Sonnet 4.6 only expose 4 levels: low, medium, high, max — no xhigh.
59
+ # We preserve xhigh as xhigh on 4.7+ (the recommended default for coding/
60
+ # agentic work) and downgrade it to max on pre-4.7 adaptive models (which
61
+ # is the strongest level they accept). "minimal" is a legacy alias that
62
+ # maps to low on every model. See:
63
+ # https://platform.claude.com/docs/en/about-claude/models/migration-guide
64
+ ADAPTIVE_EFFORT_MAP = {
65
+ "max": "max",
66
+ "xhigh": "xhigh",
67
+ "high": "high",
68
+ "medium": "medium",
69
+ "low": "low",
70
+ "minimal": "low",
71
+ }
72
+
73
+ # Models that accept the "xhigh" output_config.effort level. Opus 4.7 added
74
+ # xhigh as a distinct level between high and max; older adaptive-thinking
75
+ # models (4.6) reject it with a 400. Keep this substring list in sync with
76
+ # the Anthropic migration guide as new model families ship.
77
+ _XHIGH_EFFORT_SUBSTRINGS = ("4-7", "4.7")
78
+
79
+ # Models where extended thinking is deprecated/removed (4.6+ behavior: adaptive
80
+ # is the only supported mode; 4.7 additionally forbids manual thinking entirely
81
+ # and drops temperature/top_p/top_k).
82
+ _ADAPTIVE_THINKING_SUBSTRINGS = ("4-6", "4.6", "4-7", "4.7")
83
+
84
+ # Models where temperature/top_p/top_k return 400 if set to non-default values.
85
+ # This is the Opus 4.7 contract; future 4.x+ models are expected to follow it.
86
+ _NO_SAMPLING_PARAMS_SUBSTRINGS = ("4-7", "4.7")
87
+ _FAST_MODE_SUPPORTED_SUBSTRINGS = ("opus-4-6", "opus-4.6")
88
+
89
+ # ── Max output token limits per Anthropic model ───────────────────────
90
+ # Source: Anthropic docs + Cline model catalog. Anthropic's API requires
91
+ # max_tokens as a mandatory field. Previously we hardcoded 16384, which
92
+ # starves thinking-enabled models (thinking tokens count toward the limit).
93
+ _ANTHROPIC_OUTPUT_LIMITS = {
94
+ # Claude 4.7
95
+ "claude-opus-4-7": 128_000,
96
+ # Claude 4.6
97
+ "claude-opus-4-6": 128_000,
98
+ "claude-sonnet-4-6": 64_000,
99
+ # Claude 4.5
100
+ "claude-opus-4-5": 64_000,
101
+ "claude-sonnet-4-5": 64_000,
102
+ "claude-haiku-4-5": 64_000,
103
+ # Claude 4
104
+ "claude-opus-4": 32_000,
105
+ "claude-sonnet-4": 64_000,
106
+ # Claude 3.7
107
+ "claude-3-7-sonnet": 128_000,
108
+ # Claude 3.5
109
+ "claude-3-5-sonnet": 8_192,
110
+ "claude-3-5-haiku": 8_192,
111
+ # Claude 3
112
+ "claude-3-opus": 4_096,
113
+ "claude-3-sonnet": 4_096,
114
+ "claude-3-haiku": 4_096,
115
+ # Third-party Anthropic-compatible providers
116
+ "minimax": 131_072,
117
+ # Qwen models via DashScope Anthropic-compatible endpoint
118
+ # DashScope enforces max_tokens ∈ [1, 65536]
119
+ "qwen3": 65_536,
120
+ }
121
+
122
+ # For any model not in the table, assume the highest current limit.
123
+ # Future Anthropic models are unlikely to have *less* output capacity.
124
+ _ANTHROPIC_DEFAULT_OUTPUT_LIMIT = 128_000
125
+
126
+
127
+ def _get_anthropic_max_output(model: str) -> int:
128
+ """Look up the max output token limit for an Anthropic model.
129
+
130
+ Uses substring matching against _ANTHROPIC_OUTPUT_LIMITS so date-stamped
131
+ model IDs (claude-sonnet-4-5-20250929) and variant suffixes (:1m, :fast)
132
+ resolve correctly. Longest-prefix match wins to avoid e.g. "claude-3-5"
133
+ matching before "claude-3-5-sonnet".
134
+
135
+ Normalizes dots to hyphens so that model names like
136
+ ``anthropic/claude-opus-4.6`` match the ``claude-opus-4-6`` table key.
137
+ """
138
+ m = model.lower().replace(".", "-")
139
+ best_key = ""
140
+ best_val = _ANTHROPIC_DEFAULT_OUTPUT_LIMIT
141
+ for key, val in _ANTHROPIC_OUTPUT_LIMITS.items():
142
+ if key in m and len(key) > len(best_key):
143
+ best_key = key
144
+ best_val = val
145
+ return best_val
146
+
147
+
148
+ def _resolve_positive_anthropic_max_tokens(value) -> Optional[int]:
149
+ """Return ``value`` floored to a positive int, or ``None`` if it is not a
150
+ finite positive number. Ported from openclaw/openclaw#66664.
151
+
152
+ Anthropic's Messages API rejects ``max_tokens`` values that are 0,
153
+ negative, non-integer, or non-finite with HTTP 400. Python's ``or``
154
+ idiom (``max_tokens or fallback``) correctly catches ``0`` but lets
155
+ negative ints and fractional floats (``-1``, ``0.5``) through to the
156
+ API, producing a user-visible failure instead of a local error.
157
+ """
158
+ # Booleans are a subclass of int — exclude explicitly so ``True`` doesn't
159
+ # silently become 1 and ``False`` doesn't become 0.
160
+ if isinstance(value, bool):
161
+ return None
162
+ if not isinstance(value, (int, float)):
163
+ return None
164
+ try:
165
+ import math
166
+ if not math.isfinite(value):
167
+ return None
168
+ except Exception:
169
+ return None
170
+ floored = int(value) # truncates toward zero for floats
171
+ return floored if floored > 0 else None
172
+
173
+
174
+ def _resolve_anthropic_messages_max_tokens(
175
+ requested,
176
+ model: str,
177
+ context_length: Optional[int] = None,
178
+ ) -> int:
179
+ """Resolve the ``max_tokens`` budget for an Anthropic Messages call.
180
+
181
+ Prefers ``requested`` when it is a positive finite number; otherwise
182
+ falls back to the model's output ceiling. Raises ``ValueError`` if no
183
+ positive budget can be resolved (should not happen with current model
184
+ table defaults, but guards against a future regression where
185
+ ``_get_anthropic_max_output`` could return ``0``).
186
+
187
+ Separately, callers apply a context-window clamp — this resolver does
188
+ not, to keep the positive-value contract independent of endpoint
189
+ specifics.
190
+
191
+ Ported from openclaw/openclaw#66664 (resolveAnthropicMessagesMaxTokens).
192
+ """
193
+ resolved = _resolve_positive_anthropic_max_tokens(requested)
194
+ if resolved is not None:
195
+ return resolved
196
+ fallback = _get_anthropic_max_output(model)
197
+ if fallback > 0:
198
+ return fallback
199
+ raise ValueError(
200
+ f"Anthropic Messages adapter requires a positive max_tokens value for "
201
+ f"model {model!r}; got {requested!r} and no model default resolved."
202
+ )
203
+
204
+
205
+ def _supports_adaptive_thinking(model: str) -> bool:
206
+ """Return True for Claude 4.6+ models that support adaptive thinking."""
207
+ return any(v in model for v in _ADAPTIVE_THINKING_SUBSTRINGS)
208
+
209
+
210
+ def _supports_xhigh_effort(model: str) -> bool:
211
+ """Return True for models that accept the 'xhigh' adaptive effort level.
212
+
213
+ Opus 4.7 introduced xhigh as a distinct level between high and max.
214
+ Pre-4.7 adaptive models (Opus/Sonnet 4.6) only accept low/medium/high/max
215
+ and reject xhigh with an HTTP 400. Callers should downgrade xhigh→max
216
+ when this returns False.
217
+ """
218
+ return any(v in model for v in _XHIGH_EFFORT_SUBSTRINGS)
219
+
220
+
221
+ def _forbids_sampling_params(model: str) -> bool:
222
+ """Return True for models that 400 on any non-default temperature/top_p/top_k.
223
+
224
+ Opus 4.7 explicitly rejects sampling parameters; later Claude releases are
225
+ expected to follow suit. Callers should omit these fields entirely rather
226
+ than passing zero/default values (the API rejects anything non-null).
227
+ """
228
+ return any(v in model for v in _NO_SAMPLING_PARAMS_SUBSTRINGS)
229
+
230
+
231
+ def _supports_fast_mode(model: str) -> bool:
232
+ """Return True for models that support Anthropic Fast Mode (speed=fast).
233
+
234
+ Per Anthropic docs, fast mode is currently supported on Opus 4.6 only.
235
+ Sending ``speed: "fast"`` to any other Claude model (including Opus 4.7)
236
+ returns HTTP 400. This guard prevents silently 400'ing when stale config
237
+ or older callers leave fast mode enabled across a model upgrade.
238
+ """
239
+ return any(v in model for v in _FAST_MODE_SUPPORTED_SUBSTRINGS)
240
+
241
+
242
+ # Beta headers for enhanced features that are safe on ordinary/native Anthropic
243
+ # requests. As of Opus 4.7 (2026-04-16), these are GA on Claude 4.6+ — the
244
+ # beta headers are still accepted (harmless no-op) but not required. Kept
245
+ # here so older Claude (4.5, 4.1) + compatible endpoints that still gate on
246
+ # the headers continue to get the enhanced features.
247
+ #
248
+ # Do NOT include ``context-1m-2025-08-07`` here. Anthropic returns HTTP 400
249
+ # ("long context beta is not yet available for this subscription") for
250
+ # accounts without the long-context beta, which breaks normal short auxiliary
251
+ # calls like title generation/session summarization.
252
+ #
253
+ # ``context-1m-2025-08-07`` is still required to unlock the 1M context window
254
+ # on Claude Opus 4.6/4.7 and Sonnet 4.6 when served via AWS Bedrock or Azure
255
+ # AI Foundry. Add it only for those endpoint-specific paths below.
256
+ _COMMON_BETAS = [
257
+ "interleaved-thinking-2025-05-14",
258
+ "fine-grained-tool-streaming-2025-05-14",
259
+ ]
260
+ # MiniMax's Anthropic-compatible endpoints fail tool-use requests when
261
+ # the fine-grained tool streaming beta is present. Omit it so tool calls
262
+ # fall back to the provider's default response path.
263
+ _TOOL_STREAMING_BETA = "fine-grained-tool-streaming-2025-05-14"
264
+ # 1M context beta. Native Anthropic does not get this by default because some
265
+ # subscriptions reject it, but Bedrock/Azure still need it for 1M context.
266
+ _CONTEXT_1M_BETA = "context-1m-2025-08-07"
267
+
268
+ # Fast mode beta — enables the ``speed: "fast"`` request parameter for
269
+ # significantly higher output token throughput on Opus 4.6 (~2.5x).
270
+ # See https://platform.claude.com/docs/en/build-with-claude/fast-mode
271
+ _FAST_MODE_BETA = "fast-mode-2026-02-01"
272
+
273
+ # Additional beta headers required for OAuth/subscription auth.
274
+ # Matches what Claude Code (and pi-ai / OpenCode) send.
275
+ _OAUTH_ONLY_BETAS = [
276
+ "claude-code-20250219",
277
+ "oauth-2025-04-20",
278
+ ]
279
+
280
+ # Claude Code identity — required for OAuth requests to be routed correctly.
281
+ # Without these, Anthropic's infrastructure intermittently 500s OAuth traffic.
282
+ # The version must stay reasonably current — Anthropic rejects OAuth requests
283
+ # when the spoofed user-agent version is too far behind the actual release.
284
+ _CLAUDE_CODE_VERSION_FALLBACK = "2.1.74"
285
+ _claude_code_version_cache: Optional[str] = None
286
+
287
+
288
+ def _detect_claude_code_version() -> str:
289
+ """Detect the installed Claude Code version, fall back to a static constant.
290
+
291
+ Anthropic's OAuth infrastructure validates the user-agent version and may
292
+ reject requests with a version that's too old. Detecting dynamically means
293
+ users who keep Claude Code updated never hit stale-version 400s.
294
+ """
295
+ import subprocess as _sp
296
+
297
+ for cmd in ("claude", "claude-code"):
298
+ try:
299
+ result = _sp.run(
300
+ [cmd, "--version"],
301
+ capture_output=True, text=True, timeout=5,
302
+ )
303
+ if result.returncode == 0 and result.stdout.strip():
304
+ # Output is like "2.1.74 (Claude Code)" or just "2.1.74"
305
+ version = result.stdout.strip().split()[0]
306
+ if version and version[0].isdigit():
307
+ return version
308
+ except Exception:
309
+ pass
310
+ return _CLAUDE_CODE_VERSION_FALLBACK
311
+
312
+
313
+ _CLAUDE_CODE_SYSTEM_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude."
314
+ _MCP_TOOL_PREFIX = "mcp_"
315
+
316
+
317
+ def _get_claude_code_version() -> str:
318
+ """Lazily detect the installed Claude Code version when OAuth headers need it."""
319
+ global _claude_code_version_cache
320
+ if _claude_code_version_cache is None:
321
+ _claude_code_version_cache = _detect_claude_code_version()
322
+ return _claude_code_version_cache
323
+
324
+
325
+ def _is_oauth_token(key: str) -> bool:
326
+ """Check if the key is an Anthropic OAuth/setup token.
327
+
328
+ Positively identifies Anthropic OAuth tokens by their key format:
329
+ - ``sk-ant-`` prefix (but NOT ``sk-ant-api``) → setup tokens, managed keys
330
+ - ``eyJ`` prefix → JWTs from the Anthropic OAuth flow
331
+ - ``cc-`` prefix → Claude Code OAuth access tokens (from CLAUDE_CODE_OAUTH_TOKEN)
332
+
333
+ Non-Anthropic keys (MiniMax, Alibaba, etc.) don't match any pattern
334
+ and correctly return False.
335
+ """
336
+ if not key:
337
+ return False
338
+ # Regular Anthropic Console API keys — x-api-key auth, never OAuth
339
+ if key.startswith("sk-ant-api"):
340
+ return False
341
+ # Anthropic-issued tokens (setup-tokens sk-ant-oat-*, managed keys)
342
+ if key.startswith("sk-ant-"):
343
+ return True
344
+ # JWTs from Anthropic OAuth flow
345
+ if key.startswith("eyJ"):
346
+ return True
347
+ # Claude Code OAuth access tokens (opaque, from CLAUDE_CODE_OAUTH_TOKEN)
348
+ if key.startswith("cc-"):
349
+ return True
350
+ return False
351
+
352
+
353
+ def _normalize_base_url_text(base_url) -> str:
354
+ """Normalize SDK/base transport URL values to a plain string for inspection.
355
+
356
+ Some client objects expose ``base_url`` as an ``httpx.URL`` instead of a raw
357
+ string. Provider/auth detection should accept either shape.
358
+ """
359
+ if not base_url:
360
+ return ""
361
+ return str(base_url).strip()
362
+
363
+
364
+ def _is_third_party_anthropic_endpoint(base_url: str | None) -> bool:
365
+ """Return True for non-Anthropic endpoints using the Anthropic Messages API.
366
+
367
+ Third-party proxies (Azure AI Foundry, AWS Bedrock, self-hosted) authenticate
368
+ with their own API keys via x-api-key, not Anthropic OAuth tokens. OAuth
369
+ detection should be skipped for these endpoints.
370
+ """
371
+ normalized = _normalize_base_url_text(base_url)
372
+ if not normalized:
373
+ return False # No base_url = direct Anthropic API
374
+ normalized = normalized.rstrip("/").lower()
375
+ if "anthropic.com" in normalized:
376
+ return False # Direct Anthropic API — OAuth applies
377
+ return True # Any other endpoint is a third-party proxy
378
+
379
+
380
+ def _is_kimi_coding_endpoint(base_url: str | None) -> bool:
381
+ """Return True for Kimi's /coding endpoint that requires claude-code UA."""
382
+ normalized = _normalize_base_url_text(base_url)
383
+ if not normalized:
384
+ return False
385
+ return normalized.rstrip("/").lower().startswith("https://api.kimi.com/coding")
386
+
387
+
388
+ # Model-name prefixes that identify the Kimi / Moonshot family. Covers
389
+ # - official slugs: ``kimi-k2.5``, ``kimi_thinking``, ``moonshot-v1-8k``
390
+ # - common release lines: ``k1.5-...``, ``k2-thinking``, ``k25-...``, ``k2.5-...``
391
+ # Matched case-insensitively against the post-``normalize_model_name`` form,
392
+ # so a caller's ``provider/vendor/model`` slug is handled the same as a
393
+ # bare name.
394
+ _KIMI_FAMILY_MODEL_PREFIXES = (
395
+ "kimi-", "kimi_",
396
+ "moonshot-", "moonshot_",
397
+ "k1.", "k1-",
398
+ "k2.", "k2-",
399
+ "k25", "k2.5",
400
+ )
401
+
402
+
403
+ def _model_name_is_kimi_family(model: str | None) -> bool:
404
+ if not isinstance(model, str):
405
+ return False
406
+ m = model.strip().lower()
407
+ if not m:
408
+ return False
409
+ # Strip vendor prefix (e.g. ``moonshotai/kimi-k2.5`` → ``kimi-k2.5``)
410
+ if "/" in m:
411
+ m = m.rsplit("/", 1)[-1]
412
+ return m.startswith(_KIMI_FAMILY_MODEL_PREFIXES)
413
+
414
+
415
+ def _is_kimi_family_endpoint(base_url: str | None, model: str | None = None) -> bool:
416
+ """Return True for any Kimi / Moonshot Anthropic-Messages-speaking endpoint.
417
+
418
+ Broader than ``_is_kimi_coding_endpoint`` — matches:
419
+
420
+ - Kimi's official ``/coding`` URL (legacy check, preserved)
421
+ - Any ``api.kimi.com`` / ``moonshot.ai`` / ``moonshot.cn`` host
422
+ - Custom or proxied endpoints whose *model* name is in the Kimi / Moonshot
423
+ family (``kimi-*``, ``moonshot-*``, ``k1.*``, ``k2.*``, …). Users with
424
+ ``api_mode: anthropic_messages`` on a private gateway fronting Kimi
425
+ fall into this branch — the upstream still enforces Kimi's thinking
426
+ semantics (reasoning_content required on every replayed tool-call
427
+ message) regardless of the gateway's hostname.
428
+
429
+ Used to decide whether to drop Anthropic's ``thinking`` kwarg and to
430
+ preserve unsigned reasoning_content-derived thinking blocks on replay.
431
+ See hermes-agent#13848, #17057.
432
+ """
433
+ if _is_kimi_coding_endpoint(base_url):
434
+ return True
435
+ for _domain in ("api.kimi.com", "moonshot.ai", "moonshot.cn"):
436
+ if base_url_host_matches(base_url or "", _domain):
437
+ return True
438
+ if _model_name_is_kimi_family(model):
439
+ return True
440
+ return False
441
+
442
+
443
+ def _is_deepseek_anthropic_endpoint(base_url: str | None) -> bool:
444
+ """Return True for DeepSeek's Anthropic-compatible endpoint.
445
+
446
+ DeepSeek's ``/anthropic`` route speaks the Anthropic Messages protocol
447
+ but, when thinking mode is enabled, requires the ``thinking`` blocks
448
+ from prior assistant turns to round-trip on subsequent requests — the
449
+ generic third-party path strips them and triggers HTTP 400::
450
+
451
+ The content[].thinking in the thinking mode must be passed back
452
+ to the API.
453
+
454
+ Per DeepSeek's published compatibility matrix the blocks are unsigned
455
+ (no Anthropic-proprietary signature, no ``redacted_thinking`` support),
456
+ so this endpoint is handled with the same strip-signed / keep-unsigned
457
+ policy used for Kimi's ``/coding`` endpoint. The match is pinned to
458
+ the ``/anthropic`` path so the OpenAI-compatible ``api.deepseek.com``
459
+ base URL (which never reaches this adapter) is not misclassified.
460
+ See hermes-agent#16748.
461
+ """
462
+ if not base_url_host_matches(base_url or "", "api.deepseek.com"):
463
+ return False
464
+ normalized = _normalize_base_url_text(base_url)
465
+ if not normalized:
466
+ return False
467
+ return "/anthropic" in normalized.rstrip("/").lower()
468
+
469
+
470
+ def _requires_bearer_auth(base_url: str | None) -> bool:
471
+ """Return True for Anthropic-compatible providers that require Bearer auth.
472
+
473
+ Some third-party /anthropic endpoints implement Anthropic's Messages API but
474
+ require Authorization: Bearer *** of Anthropic's native x-api-key header.
475
+ MiniMax's global and China Anthropic-compatible endpoints follow this pattern.
476
+ """
477
+ normalized = _normalize_base_url_text(base_url)
478
+ if not normalized:
479
+ return False
480
+ normalized = normalized.rstrip("/").lower()
481
+ return normalized.startswith(("https://api.minimax.io/anthropic", "https://api.minimaxi.com/anthropic"))
482
+
483
+
484
+ def _base_url_needs_context_1m_beta(base_url: str | None) -> bool:
485
+ """Return True for endpoints that still gate 1M context behind a beta."""
486
+ normalized = _normalize_base_url_text(base_url).lower()
487
+ if not normalized:
488
+ return False
489
+ return "azure.com" in normalized
490
+
491
+
492
+ def _common_betas_for_base_url(
493
+ base_url: str | None,
494
+ *,
495
+ drop_context_1m_beta: bool = False,
496
+ ) -> list[str]:
497
+ """Return the beta headers that are safe for the configured endpoint.
498
+
499
+ MiniMax's Anthropic-compatible endpoints (Bearer-auth) reject requests
500
+ that include Anthropic's ``fine-grained-tool-streaming`` beta — every
501
+ tool-use message triggers a connection error.
502
+
503
+ The ``context-1m-2025-08-07`` beta is not sent to native Anthropic by
504
+ default because some subscriptions reject it. Add it only for endpoint
505
+ families that still require it for 1M context, currently Azure AI Foundry.
506
+ Bedrock uses its own client helper below and opts in explicitly.
507
+
508
+ ``drop_context_1m_beta=True`` strips the 1M-context beta from any path that
509
+ would otherwise include it after a subscription/endpoint rejects the beta.
510
+ """
511
+ betas = list(_COMMON_BETAS)
512
+ if _base_url_needs_context_1m_beta(base_url) and not drop_context_1m_beta:
513
+ betas.append(_CONTEXT_1M_BETA)
514
+ if _requires_bearer_auth(base_url):
515
+ _stripped = {_TOOL_STREAMING_BETA, _CONTEXT_1M_BETA}
516
+ return [b for b in betas if b not in _stripped]
517
+ if drop_context_1m_beta:
518
+ return [b for b in betas if b != _CONTEXT_1M_BETA]
519
+ return betas
520
+
521
+
522
+ def build_anthropic_client(
523
+ api_key: str,
524
+ base_url: str = None,
525
+ timeout: float = None,
526
+ *,
527
+ drop_context_1m_beta: bool = False,
528
+ ):
529
+ """Create an Anthropic client, auto-detecting setup-tokens vs API keys.
530
+
531
+ If *timeout* is provided it overrides the default 900s read timeout. The
532
+ connect timeout stays at 10s. Callers pass this from the per-provider /
533
+ per-model ``request_timeout_seconds`` config so Anthropic-native and
534
+ Anthropic-compatible providers respect the same knob as OpenAI-wire
535
+ providers.
536
+
537
+ ``drop_context_1m_beta=True`` strips ``context-1m-2025-08-07`` from the
538
+ client-level ``anthropic-beta`` header. Used by the reactive OAuth retry
539
+ path in ``run_agent.py`` when a subscription rejects the beta; leave at
540
+ its default on fresh clients so 1M-capable subscriptions keep the
541
+ capability.
542
+
543
+ Returns an anthropic.Anthropic instance.
544
+ """
545
+ _anthropic_sdk = _get_anthropic_sdk()
546
+ if _anthropic_sdk is None:
547
+ raise ImportError(
548
+ "The 'anthropic' package is required for the Anthropic provider. "
549
+ "Install it with: pip install 'anthropic>=0.39.0'"
550
+ )
551
+
552
+ normalize_proxy_env_vars()
553
+
554
+ from httpx import Timeout
555
+
556
+ normalized_base_url = _normalize_base_url_text(base_url)
557
+ _read_timeout = timeout if (isinstance(timeout, (int, float)) and timeout > 0) else 900.0
558
+ kwargs = {
559
+ "timeout": Timeout(timeout=float(_read_timeout), connect=10.0),
560
+ }
561
+ if normalized_base_url:
562
+ # Azure Anthropic endpoints require an ``api-version`` query parameter.
563
+ # Pass it via default_query so the SDK appends it to every request URL
564
+ # without corrupting the base_url (appending it directly produces
565
+ # malformed paths like /anthropic?api-version=.../v1/messages).
566
+ _is_azure_endpoint = "azure.com" in normalized_base_url.lower()
567
+ if _is_azure_endpoint and "api-version" not in normalized_base_url:
568
+ kwargs["base_url"] = normalized_base_url.rstrip("/")
569
+ kwargs["default_query"] = {"api-version": "2025-04-15"}
570
+ else:
571
+ kwargs["base_url"] = normalized_base_url
572
+ common_betas = _common_betas_for_base_url(
573
+ normalized_base_url,
574
+ drop_context_1m_beta=drop_context_1m_beta,
575
+ )
576
+
577
+ if _is_kimi_coding_endpoint(base_url):
578
+ # Kimi's /coding endpoint requires User-Agent: claude-code/0.1.0
579
+ # to be recognized as a valid Coding Agent. Without it, returns 403.
580
+ # Check this BEFORE _requires_bearer_auth since both match api.kimi.com/coding.
581
+ kwargs["api_key"] = api_key
582
+ kwargs["default_headers"] = {
583
+ "User-Agent": "claude-code/0.1.0",
584
+ **( {"anthropic-beta": ",".join(common_betas)} if common_betas else {} )
585
+ }
586
+ elif _requires_bearer_auth(normalized_base_url):
587
+ # Some Anthropic-compatible providers (e.g. MiniMax) expect the API key in
588
+ # Authorization: Bearer *** for regular API keys. Route those endpoints
589
+ # through auth_token so the SDK sends Bearer auth instead of x-api-key.
590
+ # Check this before OAuth token shape detection because MiniMax secrets do
591
+ # not use Anthropic's sk-ant-api prefix and would otherwise be misread as
592
+ # Anthropic OAuth/setup tokens.
593
+ kwargs["auth_token"] = api_key
594
+ if common_betas:
595
+ kwargs["default_headers"] = {"anthropic-beta": ",".join(common_betas)}
596
+ elif _is_third_party_anthropic_endpoint(base_url):
597
+ # Third-party proxies (Azure AI Foundry, AWS Bedrock, etc.) use their
598
+ # own API keys with x-api-key auth. Skip OAuth detection — their keys
599
+ # don't follow Anthropic's sk-ant-* prefix convention and would be
600
+ # misclassified as OAuth tokens.
601
+ kwargs["api_key"] = api_key
602
+ if common_betas:
603
+ kwargs["default_headers"] = {"anthropic-beta": ",".join(common_betas)}
604
+ elif _is_oauth_token(api_key):
605
+ # OAuth access token / setup-token → Bearer auth + Claude Code identity.
606
+ # Anthropic routes OAuth requests based on user-agent and headers;
607
+ # without Claude Code's fingerprint, requests get intermittent 500s.
608
+ all_betas = common_betas + _OAUTH_ONLY_BETAS
609
+ kwargs["auth_token"] = api_key
610
+ kwargs["default_headers"] = {
611
+ "anthropic-beta": ",".join(all_betas),
612
+ "user-agent": f"claude-cli/{_get_claude_code_version()} (external, cli)",
613
+ "x-app": "cli",
614
+ }
615
+ else:
616
+ # Regular API key → x-api-key header + common betas
617
+ kwargs["api_key"] = api_key
618
+ if common_betas:
619
+ kwargs["default_headers"] = {"anthropic-beta": ",".join(common_betas)}
620
+
621
+ return _anthropic_sdk.Anthropic(**kwargs)
622
+
623
+
624
+ def build_anthropic_bedrock_client(region: str):
625
+ """Create an AnthropicBedrock client for Bedrock Claude models.
626
+
627
+ Uses the Anthropic SDK's native Bedrock adapter, which provides full
628
+ Claude feature parity: prompt caching, thinking budgets, adaptive
629
+ thinking, fast mode — features not available via the Converse API.
630
+
631
+ Attaches the common Anthropic beta headers as client-level defaults so
632
+ that Bedrock-hosted Claude models get the same enhanced features as
633
+ native Anthropic. The ``context-1m-2025-08-07`` beta in particular
634
+ unlocks the 1M context window for Opus 4.6/4.7 on Bedrock — without
635
+ it, Bedrock caps these models at 200K even though the Anthropic API
636
+ serves them with 1M natively.
637
+
638
+ Auth uses the boto3 default credential chain (IAM roles, SSO, env vars).
639
+ """
640
+ _anthropic_sdk = _get_anthropic_sdk()
641
+ if _anthropic_sdk is None:
642
+ raise ImportError(
643
+ "The 'anthropic' package is required for the Bedrock provider. "
644
+ "Install it with: pip install 'anthropic>=0.39.0'"
645
+ )
646
+ if not hasattr(_anthropic_sdk, "AnthropicBedrock"):
647
+ raise ImportError(
648
+ "anthropic.AnthropicBedrock not available. "
649
+ "Upgrade with: pip install 'anthropic>=0.39.0'"
650
+ )
651
+ from httpx import Timeout
652
+
653
+ return _anthropic_sdk.AnthropicBedrock(
654
+ aws_region=region,
655
+ timeout=Timeout(timeout=900.0, connect=10.0),
656
+ default_headers={"anthropic-beta": ",".join([*_COMMON_BETAS, _CONTEXT_1M_BETA])},
657
+ )
658
+
659
+
660
+ def _read_claude_code_credentials_from_keychain() -> Optional[Dict[str, Any]]:
661
+ """Read Claude Code OAuth credentials from the macOS Keychain.
662
+
663
+ Claude Code >=2.1.114 stores credentials in the macOS Keychain under the
664
+ service name "Claude Code-credentials" rather than (or in addition to)
665
+ the JSON file at ~/.claude/.credentials.json.
666
+
667
+ The password field contains a JSON string with the same claudeAiOauth
668
+ structure as the JSON file.
669
+
670
+ Returns dict with {accessToken, refreshToken?, expiresAt?} or None.
671
+ """
672
+ if platform.system() != "Darwin":
673
+ return None
674
+
675
+ try:
676
+ # Read the "Claude Code-credentials" generic password entry
677
+ result = subprocess.run(
678
+ ["security", "find-generic-password",
679
+ "-s", "Claude Code-credentials",
680
+ "-w"],
681
+ capture_output=True,
682
+ text=True,
683
+ timeout=5,
684
+ )
685
+ except (OSError, subprocess.TimeoutExpired):
686
+ logger.debug("Keychain: security command not available or timed out")
687
+ return None
688
+
689
+ if result.returncode != 0:
690
+ logger.debug("Keychain: no entry found for 'Claude Code-credentials'")
691
+ return None
692
+
693
+ raw = result.stdout.strip()
694
+ if not raw:
695
+ return None
696
+
697
+ try:
698
+ data = json.loads(raw)
699
+ except json.JSONDecodeError:
700
+ logger.debug("Keychain: credentials payload is not valid JSON")
701
+ return None
702
+
703
+ oauth_data = data.get("claudeAiOauth")
704
+ if oauth_data and isinstance(oauth_data, dict):
705
+ access_token = oauth_data.get("accessToken", "")
706
+ if access_token:
707
+ return {
708
+ "accessToken": access_token,
709
+ "refreshToken": oauth_data.get("refreshToken", ""),
710
+ "expiresAt": oauth_data.get("expiresAt", 0),
711
+ "source": "macos_keychain",
712
+ }
713
+
714
+ return None
715
+
716
+
717
+ def read_claude_code_credentials() -> Optional[Dict[str, Any]]:
718
+ """Read refreshable Claude Code OAuth credentials.
719
+
720
+ Checks two sources in order:
721
+ 1. macOS Keychain (Darwin only) — "Claude Code-credentials" entry
722
+ 2. ~/.claude/.credentials.json file
723
+
724
+ This intentionally excludes ~/.claude.json primaryApiKey. Opencode's
725
+ subscription flow is OAuth/setup-token based with refreshable credentials,
726
+ and native direct Anthropic provider usage should follow that path rather
727
+ than auto-detecting Claude's first-party managed key.
728
+
729
+ Returns dict with {accessToken, refreshToken?, expiresAt?} or None.
730
+ """
731
+ # Try macOS Keychain first (covers Claude Code >=2.1.114)
732
+ kc_creds = _read_claude_code_credentials_from_keychain()
733
+ if kc_creds:
734
+ return kc_creds
735
+
736
+ # Fall back to JSON file
737
+ cred_path = Path.home() / ".claude" / ".credentials.json"
738
+ if cred_path.exists():
739
+ try:
740
+ data = json.loads(cred_path.read_text(encoding="utf-8"))
741
+ oauth_data = data.get("claudeAiOauth")
742
+ if oauth_data and isinstance(oauth_data, dict):
743
+ access_token = oauth_data.get("accessToken", "")
744
+ if access_token:
745
+ return {
746
+ "accessToken": access_token,
747
+ "refreshToken": oauth_data.get("refreshToken", ""),
748
+ "expiresAt": oauth_data.get("expiresAt", 0),
749
+ "source": "claude_code_credentials_file",
750
+ }
751
+ except (json.JSONDecodeError, OSError, IOError) as e:
752
+ logger.debug("Failed to read ~/.claude/.credentials.json: %s", e)
753
+
754
+ return None
755
+
756
+
757
+ def read_claude_managed_key() -> Optional[str]:
758
+ """Read Claude's native managed key from ~/.claude.json for diagnostics only."""
759
+ claude_json = Path.home() / ".claude.json"
760
+ if claude_json.exists():
761
+ try:
762
+ data = json.loads(claude_json.read_text(encoding="utf-8"))
763
+ primary_key = data.get("primaryApiKey", "")
764
+ if isinstance(primary_key, str) and primary_key.strip():
765
+ return primary_key.strip()
766
+ except (json.JSONDecodeError, OSError, IOError) as e:
767
+ logger.debug("Failed to read ~/.claude.json: %s", e)
768
+ return None
769
+
770
+
771
+ def is_claude_code_token_valid(creds: Dict[str, Any]) -> bool:
772
+ """Check if Claude Code credentials have a non-expired access token."""
773
+ import time
774
+
775
+ expires_at = creds.get("expiresAt", 0)
776
+ if not expires_at:
777
+ # No expiry set (managed keys) — valid if token is present
778
+ return bool(creds.get("accessToken"))
779
+
780
+ # expiresAt is in milliseconds since epoch
781
+ now_ms = int(time.time() * 1000)
782
+ # Allow 60 seconds of buffer
783
+ return now_ms < (expires_at - 60_000)
784
+
785
+
786
+ def refresh_anthropic_oauth_pure(refresh_token: str, *, use_json: bool = False) -> Dict[str, Any]:
787
+ """Refresh an Anthropic OAuth token without mutating local credential files."""
788
+ import time
789
+ import urllib.parse
790
+ import urllib.request
791
+
792
+ if not refresh_token:
793
+ raise ValueError("refresh_token is required")
794
+
795
+ client_id = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
796
+ if use_json:
797
+ data = json.dumps({
798
+ "grant_type": "refresh_token",
799
+ "refresh_token": refresh_token,
800
+ "client_id": client_id,
801
+ }).encode()
802
+ content_type = "application/json"
803
+ else:
804
+ data = urllib.parse.urlencode({
805
+ "grant_type": "refresh_token",
806
+ "refresh_token": refresh_token,
807
+ "client_id": client_id,
808
+ }).encode()
809
+ content_type = "application/x-www-form-urlencoded"
810
+
811
+ token_endpoints = [
812
+ "https://platform.claude.com/v1/oauth/token",
813
+ "https://console.anthropic.com/v1/oauth/token",
814
+ ]
815
+ last_error = None
816
+ for endpoint in token_endpoints:
817
+ req = urllib.request.Request(
818
+ endpoint,
819
+ data=data,
820
+ headers={
821
+ "Content-Type": content_type,
822
+ "User-Agent": f"claude-cli/{_get_claude_code_version()} (external, cli)",
823
+ },
824
+ method="POST",
825
+ )
826
+ try:
827
+ with urllib.request.urlopen(req, timeout=10) as resp:
828
+ result = json.loads(resp.read().decode())
829
+ except Exception as exc:
830
+ last_error = exc
831
+ logger.debug("Anthropic token refresh failed at %s: %s", endpoint, exc)
832
+ continue
833
+
834
+ access_token = result.get("access_token", "")
835
+ if not access_token:
836
+ raise ValueError("Anthropic refresh response was missing access_token")
837
+ next_refresh = result.get("refresh_token", refresh_token)
838
+ expires_in = result.get("expires_in", 3600)
839
+ return {
840
+ "access_token": access_token,
841
+ "refresh_token": next_refresh,
842
+ "expires_at_ms": int(time.time() * 1000) + (expires_in * 1000),
843
+ }
844
+
845
+ if last_error is not None:
846
+ raise last_error
847
+ raise ValueError("Anthropic token refresh failed")
848
+
849
+
850
+ def _refresh_oauth_token(creds: Dict[str, Any]) -> Optional[str]:
851
+ """Attempt to refresh an expired Claude Code OAuth token."""
852
+ refresh_token = creds.get("refreshToken", "")
853
+ if not refresh_token:
854
+ logger.debug("No refresh token available — cannot refresh")
855
+ return None
856
+
857
+ try:
858
+ refreshed = refresh_anthropic_oauth_pure(refresh_token, use_json=False)
859
+ _write_claude_code_credentials(
860
+ refreshed["access_token"],
861
+ refreshed["refresh_token"],
862
+ refreshed["expires_at_ms"],
863
+ )
864
+ logger.debug("Successfully refreshed Claude Code OAuth token")
865
+ return refreshed["access_token"]
866
+ except Exception as e:
867
+ logger.debug("Failed to refresh Claude Code token: %s", e)
868
+ return None
869
+
870
+
871
+ def _write_claude_code_credentials(
872
+ access_token: str,
873
+ refresh_token: str,
874
+ expires_at_ms: int,
875
+ *,
876
+ scopes: Optional[list] = None,
877
+ ) -> None:
878
+ """Write refreshed credentials back to ~/.claude/.credentials.json.
879
+
880
+ The optional *scopes* list (e.g. ``["user:inference", "user:profile", ...]``)
881
+ is persisted so that Claude Code's own auth check recognises the credential
882
+ as valid. Claude Code >=2.1.81 gates on the presence of ``"user:inference"``
883
+ in the stored scopes before it will use the token.
884
+ """
885
+ cred_path = Path.home() / ".claude" / ".credentials.json"
886
+ try:
887
+ # Read existing file to preserve other fields
888
+ existing = {}
889
+ if cred_path.exists():
890
+ existing = json.loads(cred_path.read_text(encoding="utf-8"))
891
+
892
+ oauth_data: Dict[str, Any] = {
893
+ "accessToken": access_token,
894
+ "refreshToken": refresh_token,
895
+ "expiresAt": expires_at_ms,
896
+ }
897
+ if scopes is not None:
898
+ oauth_data["scopes"] = scopes
899
+ elif "claudeAiOauth" in existing and "scopes" in existing["claudeAiOauth"]:
900
+ # Preserve previously-stored scopes when the refresh response
901
+ # does not include a scope field.
902
+ oauth_data["scopes"] = existing["claudeAiOauth"]["scopes"]
903
+
904
+ existing["claudeAiOauth"] = oauth_data
905
+
906
+ cred_path.parent.mkdir(parents=True, exist_ok=True)
907
+ _tmp_cred = cred_path.with_suffix(".tmp")
908
+ _tmp_cred.write_text(json.dumps(existing, indent=2), encoding="utf-8")
909
+ _tmp_cred.replace(cred_path)
910
+ # Restrict permissions (credentials file)
911
+ cred_path.chmod(0o600)
912
+ except (OSError, IOError) as e:
913
+ logger.debug("Failed to write refreshed credentials: %s", e)
914
+
915
+
916
+ def _resolve_claude_code_token_from_credentials(creds: Optional[Dict[str, Any]] = None) -> Optional[str]:
917
+ """Resolve a token from Claude Code credential files, refreshing if needed."""
918
+ creds = creds or read_claude_code_credentials()
919
+ if creds and is_claude_code_token_valid(creds):
920
+ logger.debug("Using Claude Code credentials (auto-detected)")
921
+ return creds["accessToken"]
922
+ if creds:
923
+ logger.debug("Claude Code credentials expired — attempting refresh")
924
+ refreshed = _refresh_oauth_token(creds)
925
+ if refreshed:
926
+ return refreshed
927
+ logger.debug("Token refresh failed — re-run 'claude setup-token' to reauthenticate")
928
+ return None
929
+
930
+
931
+ def _prefer_refreshable_claude_code_token(env_token: str, creds: Optional[Dict[str, Any]]) -> Optional[str]:
932
+ """Prefer Claude Code creds when a persisted env OAuth token would shadow refresh.
933
+
934
+ Hermes historically persisted setup tokens into ANTHROPIC_TOKEN. That makes
935
+ later refresh impossible because the static env token wins before we ever
936
+ inspect Claude Code's refreshable credential file. If we have a refreshable
937
+ Claude Code credential record, prefer it over the static env OAuth token.
938
+ """
939
+ if not env_token or not _is_oauth_token(env_token) or not isinstance(creds, dict):
940
+ return None
941
+ if not creds.get("refreshToken"):
942
+ return None
943
+
944
+ resolved = _resolve_claude_code_token_from_credentials(creds)
945
+ if resolved and resolved != env_token:
946
+ logger.debug(
947
+ "Preferring Claude Code credential file over static env OAuth token so refresh can proceed"
948
+ )
949
+ return resolved
950
+ return None
951
+
952
+
953
+ def resolve_anthropic_token() -> Optional[str]:
954
+ """Resolve an Anthropic token from all available sources.
955
+
956
+ Priority:
957
+ 1. ANTHROPIC_TOKEN env var (OAuth/setup token saved by Hermes)
958
+ 2. CLAUDE_CODE_OAUTH_TOKEN env var
959
+ 3. Claude Code credentials (~/.claude.json or ~/.claude/.credentials.json)
960
+ — with automatic refresh if expired and a refresh token is available
961
+ 4. ANTHROPIC_API_KEY env var (regular API key, or legacy fallback)
962
+
963
+ Returns the token string or None.
964
+ """
965
+ creds = read_claude_code_credentials()
966
+
967
+ # 1. Hermes-managed OAuth/setup token env var
968
+ token = os.getenv("ANTHROPIC_TOKEN", "").strip()
969
+ if token:
970
+ preferred = _prefer_refreshable_claude_code_token(token, creds)
971
+ if preferred:
972
+ return preferred
973
+ return token
974
+
975
+ # 2. CLAUDE_CODE_OAUTH_TOKEN (used by Claude Code for setup-tokens)
976
+ cc_token = os.getenv("CLAUDE_CODE_OAUTH_TOKEN", "").strip()
977
+ if cc_token:
978
+ preferred = _prefer_refreshable_claude_code_token(cc_token, creds)
979
+ if preferred:
980
+ return preferred
981
+ return cc_token
982
+
983
+ # 3. Claude Code credential file
984
+ resolved_claude_token = _resolve_claude_code_token_from_credentials(creds)
985
+ if resolved_claude_token:
986
+ return resolved_claude_token
987
+
988
+ # 4. Regular API key, or a legacy OAuth token saved in ANTHROPIC_API_KEY.
989
+ # This remains as a compatibility fallback for pre-migration Hermes configs.
990
+ api_key = os.getenv("ANTHROPIC_API_KEY", "").strip()
991
+ if api_key:
992
+ return api_key
993
+
994
+ return None
995
+
996
+
997
+ def run_oauth_setup_token() -> Optional[str]:
998
+ """Run 'claude setup-token' interactively and return the resulting token.
999
+
1000
+ Checks multiple sources after the subprocess completes:
1001
+ 1. Claude Code credential files (may be written by the subprocess)
1002
+ 2. CLAUDE_CODE_OAUTH_TOKEN / ANTHROPIC_TOKEN env vars
1003
+
1004
+ Returns the token string, or None if no credentials were obtained.
1005
+ Raises FileNotFoundError if the 'claude' CLI is not installed.
1006
+ """
1007
+ import shutil
1008
+ import subprocess
1009
+
1010
+ claude_path = shutil.which("claude")
1011
+ if not claude_path:
1012
+ raise FileNotFoundError(
1013
+ "The 'claude' CLI is not installed. "
1014
+ "Install it with: npm install -g @anthropic-ai/claude-code"
1015
+ )
1016
+
1017
+ # Run interactively — stdin/stdout/stderr inherited so user can interact
1018
+ try:
1019
+ subprocess.run([claude_path, "setup-token"])
1020
+ except (KeyboardInterrupt, EOFError):
1021
+ return None
1022
+
1023
+ # Check if credentials were saved to Claude Code's config files
1024
+ creds = read_claude_code_credentials()
1025
+ if creds and is_claude_code_token_valid(creds):
1026
+ return creds["accessToken"]
1027
+
1028
+ # Check env vars that may have been set
1029
+ for env_var in ("CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_TOKEN"):
1030
+ val = os.getenv(env_var, "").strip()
1031
+ if val:
1032
+ return val
1033
+
1034
+ return None
1035
+
1036
+
1037
+ # ── Hermes-native PKCE OAuth flow ────────────────────────────────────────
1038
+ # Mirrors the flow used by Claude Code, pi-ai, and OpenCode.
1039
+ # Stores credentials in ~/.hermes/.anthropic_oauth.json (our own file).
1040
+
1041
+ _OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
1042
+ _OAUTH_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token"
1043
+ _OAUTH_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback"
1044
+ _OAUTH_SCOPES = "org:create_api_key user:profile user:inference"
1045
+ _HERMES_OAUTH_FILE = get_hermes_home() / ".anthropic_oauth.json"
1046
+
1047
+
1048
+ def _generate_pkce() -> tuple:
1049
+ """Generate PKCE code_verifier and code_challenge (S256)."""
1050
+ import base64
1051
+ import hashlib
1052
+ import secrets
1053
+
1054
+ verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b"=").decode()
1055
+ challenge = base64.urlsafe_b64encode(
1056
+ hashlib.sha256(verifier.encode()).digest()
1057
+ ).rstrip(b"=").decode()
1058
+ return verifier, challenge
1059
+
1060
+
1061
+ def run_hermes_oauth_login_pure() -> Optional[Dict[str, Any]]:
1062
+ """Run Hermes-native OAuth PKCE flow and return credential state."""
1063
+ import secrets
1064
+ import time
1065
+ import webbrowser
1066
+
1067
+ verifier, challenge = _generate_pkce()
1068
+ oauth_state = secrets.token_urlsafe(32)
1069
+
1070
+ params = {
1071
+ "code": "true",
1072
+ "client_id": _OAUTH_CLIENT_ID,
1073
+ "response_type": "code",
1074
+ "redirect_uri": _OAUTH_REDIRECT_URI,
1075
+ "scope": _OAUTH_SCOPES,
1076
+ "code_challenge": challenge,
1077
+ "code_challenge_method": "S256",
1078
+ "state": oauth_state,
1079
+ }
1080
+ from urllib.parse import urlencode
1081
+
1082
+ auth_url = f"https://claude.ai/oauth/authorize?{urlencode(params)}"
1083
+
1084
+ print()
1085
+ print("Authorize Hermes with your Claude Pro/Max subscription.")
1086
+ print()
1087
+ print("╭─ Claude Pro/Max Authorization ────────────────────╮")
1088
+ print("│ │")
1089
+ print("│ Open this link in your browser: │")
1090
+ print("╰───────────────────────────────────────────────────╯")
1091
+ print()
1092
+ print(f" {auth_url}")
1093
+ print()
1094
+
1095
+ try:
1096
+ webbrowser.open(auth_url)
1097
+ print(" (Browser opened automatically)")
1098
+ except Exception:
1099
+ pass
1100
+
1101
+ print()
1102
+ print("After authorizing, you'll see a code. Paste it below.")
1103
+ print()
1104
+ try:
1105
+ auth_code = input("Authorization code: ").strip()
1106
+ except (KeyboardInterrupt, EOFError):
1107
+ return None
1108
+
1109
+ if not auth_code:
1110
+ print("No code entered.")
1111
+ return None
1112
+
1113
+ splits = auth_code.split("#")
1114
+ code = splits[0]
1115
+ received_state = splits[1] if len(splits) > 1 else ""
1116
+
1117
+ # Validate state to prevent CSRF (RFC 6749 §10.12)
1118
+ if received_state != oauth_state:
1119
+ logger.warning("OAuth state mismatch — possible CSRF, aborting")
1120
+ return None
1121
+
1122
+ try:
1123
+ import urllib.request
1124
+
1125
+ exchange_data = json.dumps({
1126
+ "grant_type": "authorization_code",
1127
+ "client_id": _OAUTH_CLIENT_ID,
1128
+ "code": code,
1129
+ "state": received_state,
1130
+ "redirect_uri": _OAUTH_REDIRECT_URI,
1131
+ "code_verifier": verifier,
1132
+ }).encode()
1133
+
1134
+ req = urllib.request.Request(
1135
+ _OAUTH_TOKEN_URL,
1136
+ data=exchange_data,
1137
+ headers={
1138
+ "Content-Type": "application/json",
1139
+ "User-Agent": f"claude-cli/{_get_claude_code_version()} (external, cli)",
1140
+ },
1141
+ method="POST",
1142
+ )
1143
+
1144
+ with urllib.request.urlopen(req, timeout=15) as resp:
1145
+ result = json.loads(resp.read().decode())
1146
+ except Exception as e:
1147
+ print(f"Token exchange failed: {e}")
1148
+ return None
1149
+
1150
+ access_token = result.get("access_token", "")
1151
+ refresh_token = result.get("refresh_token", "")
1152
+ expires_in = result.get("expires_in", 3600)
1153
+
1154
+ if not access_token:
1155
+ print("No access token in response.")
1156
+ return None
1157
+
1158
+ expires_at_ms = int(time.time() * 1000) + (expires_in * 1000)
1159
+ return {
1160
+ "access_token": access_token,
1161
+ "refresh_token": refresh_token,
1162
+ "expires_at_ms": expires_at_ms,
1163
+ }
1164
+
1165
+
1166
+ def read_hermes_oauth_credentials() -> Optional[Dict[str, Any]]:
1167
+ """Read Hermes-managed OAuth credentials from ~/.hermes/.anthropic_oauth.json."""
1168
+ if _HERMES_OAUTH_FILE.exists():
1169
+ try:
1170
+ data = json.loads(_HERMES_OAUTH_FILE.read_text(encoding="utf-8"))
1171
+ if data.get("accessToken"):
1172
+ return data
1173
+ except (json.JSONDecodeError, OSError, IOError) as e:
1174
+ logger.debug("Failed to read Hermes OAuth credentials: %s", e)
1175
+ return None
1176
+
1177
+
1178
+ # ---------------------------------------------------------------------------
1179
+ # Message / tool / response format conversion
1180
+ # ---------------------------------------------------------------------------
1181
+
1182
+
1183
+ def _is_bedrock_model_id(model: str) -> bool:
1184
+ """Detect AWS Bedrock model IDs that use dots as namespace separators.
1185
+
1186
+ Bedrock model IDs come in two forms:
1187
+ - Bare: ``anthropic.claude-opus-4-7``
1188
+ - Regional (inference profiles): ``us.anthropic.claude-sonnet-4-5-v1:0``
1189
+
1190
+ In both cases the dots separate namespace components, not version
1191
+ numbers, and must be preserved verbatim for the Bedrock API.
1192
+ """
1193
+ lower = model.lower()
1194
+ # Regional inference-profile prefixes
1195
+ if any(lower.startswith(p) for p in ("global.", "us.", "eu.", "ap.", "jp.")):
1196
+ return True
1197
+ # Bare Bedrock model IDs: provider.model-family
1198
+ if lower.startswith("anthropic."):
1199
+ return True
1200
+ return False
1201
+
1202
+
1203
+ def normalize_model_name(model: str, preserve_dots: bool = False) -> str:
1204
+ """Normalize a model name for the Anthropic API.
1205
+
1206
+ - Strips 'anthropic/' prefix (OpenRouter format, case-insensitive)
1207
+ - Converts dots to hyphens in version numbers (OpenRouter uses dots,
1208
+ Anthropic uses hyphens: claude-opus-4.6 → claude-opus-4-6), unless
1209
+ preserve_dots is True (e.g. for Alibaba/DashScope: qwen3.5-plus).
1210
+ - Preserves Bedrock model IDs (``anthropic.claude-opus-4-7``) and
1211
+ regional inference profiles (``us.anthropic.claude-*``) whose dots
1212
+ are namespace separators, not version separators.
1213
+ """
1214
+ lower = model.lower()
1215
+ if lower.startswith("anthropic/"):
1216
+ model = model[len("anthropic/"):]
1217
+ if not preserve_dots:
1218
+ # Bedrock model IDs use dots as namespace separators
1219
+ # (e.g. "anthropic.claude-opus-4-7", "us.anthropic.claude-*").
1220
+ # These must not be converted to hyphens. See issue #12295.
1221
+ if _is_bedrock_model_id(model):
1222
+ return model
1223
+ # Only convert dots to hyphens for Anthropic/Claude models.
1224
+ # Non-Anthropic models (gpt-5.4, gemini-2.5, etc.) use dots
1225
+ # as part of their canonical names. See issue #17171.
1226
+ _lower = model.lower()
1227
+ if _lower.startswith("claude-") or _lower.startswith("anthropic/"):
1228
+ model = model.replace(".", "-")
1229
+ return model
1230
+
1231
+
1232
+ def _sanitize_tool_id(tool_id: str) -> str:
1233
+ """Sanitize a tool call ID for the Anthropic API.
1234
+
1235
+ Anthropic requires IDs matching [a-zA-Z0-9_-]. Replace invalid
1236
+ characters with underscores and ensure non-empty.
1237
+ """
1238
+ import re
1239
+ if not tool_id:
1240
+ return "tool_0"
1241
+ sanitized = re.sub(r"[^a-zA-Z0-9_-]", "_", tool_id)
1242
+ return sanitized or "tool_0"
1243
+
1244
+
1245
+ def _normalize_tool_input_schema(schema: Any) -> Dict[str, Any]:
1246
+ """Normalize tool schemas before sending them to Anthropic.
1247
+
1248
+ Anthropic's tool schema validator rejects nullable unions such as
1249
+ ``anyOf: [{"type": "string"}, {"type": "null"}]`` that Pydantic/MCP
1250
+ commonly emits for optional fields. Tool optionality is represented by
1251
+ the parent ``required`` array, so we delegate to the shared
1252
+ ``strip_nullable_unions`` helper to collapse nullable unions to the
1253
+ non-null branch while preserving metadata like description/default.
1254
+
1255
+ ``keep_nullable_hint=False`` because the Anthropic validator does not
1256
+ recognize the OpenAPI-style ``nullable: true`` extension and strict
1257
+ schema-to-grammar converters may reject unknown keywords.
1258
+
1259
+ Top-level ``oneOf``/``allOf``/``anyOf`` are also stripped here: the
1260
+ Anthropic API rejects union keywords at the schema root with a generic
1261
+ HTTP 400. Several upstream and plugin tools ship schemas with one of
1262
+ these keywords at the top level (commonly for Pydantic discriminated
1263
+ unions). If we land here with those keywords still present after
1264
+ nullable-union stripping, drop them and fall back to a plain object
1265
+ schema so the tool still validates at the Anthropic boundary.
1266
+ """
1267
+ if not schema:
1268
+ return {"type": "object", "properties": {}}
1269
+
1270
+ from tools.schema_sanitizer import strip_nullable_unions
1271
+
1272
+ normalized = strip_nullable_unions(schema, keep_nullable_hint=False)
1273
+ if not isinstance(normalized, dict):
1274
+ return {"type": "object", "properties": {}}
1275
+ # Strip top-level union keywords that Anthropic's validator rejects.
1276
+ banned = {"oneOf", "allOf", "anyOf"}
1277
+ if banned & normalized.keys():
1278
+ normalized = {k: v for k, v in normalized.items() if k not in banned}
1279
+ if "type" not in normalized:
1280
+ normalized["type"] = "object"
1281
+ if normalized.get("type") == "object" and not isinstance(normalized.get("properties"), dict):
1282
+ normalized = {**normalized, "properties": {}}
1283
+ return normalized
1284
+
1285
+
1286
+ def convert_tools_to_anthropic(tools: List[Dict]) -> List[Dict]:
1287
+ """Convert OpenAI tool definitions to Anthropic format."""
1288
+ if not tools:
1289
+ return []
1290
+ result = []
1291
+ seen_names: set = set()
1292
+ for t in tools:
1293
+ fn = t.get("function", {})
1294
+ name = fn.get("name", "")
1295
+ # Defensive dedup: Anthropic rejects requests with duplicate tool
1296
+ # names. Upstream injection paths already dedup, but this guard
1297
+ # converts a hard API failure into a warning. See: #18478
1298
+ if name and name in seen_names:
1299
+ logger.warning(
1300
+ "convert_tools_to_anthropic: duplicate tool name '%s' "
1301
+ "— dropping second occurrence",
1302
+ name,
1303
+ )
1304
+ continue
1305
+ if name:
1306
+ seen_names.add(name)
1307
+ anthropic_tool: Dict[str, Any] = {
1308
+ "name": name,
1309
+ "description": fn.get("description", ""),
1310
+ "input_schema": _normalize_tool_input_schema(
1311
+ fn.get("parameters", {"type": "object", "properties": {}})
1312
+ ),
1313
+ }
1314
+ # Forward cache_control marker when present on the OpenAI-format
1315
+ # tool dict. Anthropic's tools array supports cache_control on the
1316
+ # last tool to cache the entire schema cross-session.
1317
+ cache_control = t.get("cache_control")
1318
+ if isinstance(cache_control, dict):
1319
+ anthropic_tool["cache_control"] = dict(cache_control)
1320
+ result.append(anthropic_tool)
1321
+ return result
1322
+
1323
+
1324
+ def _image_source_from_openai_url(url: str) -> Dict[str, str]:
1325
+ """Convert an OpenAI-style image URL/data URL into Anthropic image source."""
1326
+ url = str(url or "").strip()
1327
+ if not url:
1328
+ return {"type": "url", "url": ""}
1329
+
1330
+ if url.startswith("data:"):
1331
+ header, _, data = url.partition(",")
1332
+ media_type = "image/jpeg"
1333
+ if header.startswith("data:"):
1334
+ mime_part = header[len("data:"):].split(";", 1)[0].strip()
1335
+ if mime_part.startswith("image/"):
1336
+ media_type = mime_part
1337
+ return {
1338
+ "type": "base64",
1339
+ "media_type": media_type,
1340
+ "data": data,
1341
+ }
1342
+
1343
+ return {"type": "url", "url": url}
1344
+
1345
+
1346
+ def _convert_content_part_to_anthropic(part: Any) -> Optional[Dict[str, Any]]:
1347
+ """Convert a single OpenAI-style content part to Anthropic format."""
1348
+ if part is None:
1349
+ return None
1350
+ if isinstance(part, str):
1351
+ return {"type": "text", "text": part}
1352
+ if not isinstance(part, dict):
1353
+ return {"type": "text", "text": str(part)}
1354
+
1355
+ ptype = part.get("type")
1356
+
1357
+ if ptype == "input_text":
1358
+ block: Dict[str, Any] = {"type": "text", "text": part.get("text", "")}
1359
+ elif ptype in {"image_url", "input_image"}:
1360
+ image_value = part.get("image_url", {})
1361
+ url = image_value.get("url", "") if isinstance(image_value, dict) else str(image_value or "")
1362
+ block = {"type": "image", "source": _image_source_from_openai_url(url)}
1363
+ else:
1364
+ block = dict(part)
1365
+
1366
+ if isinstance(part.get("cache_control"), dict) and "cache_control" not in block:
1367
+ block["cache_control"] = dict(part["cache_control"])
1368
+ return block
1369
+
1370
+
1371
+ def _to_plain_data(value: Any, *, _depth: int = 0, _path: Optional[set] = None) -> Any:
1372
+ """Recursively convert SDK objects to plain Python data structures.
1373
+
1374
+ Guards against circular references (``_path`` tracks ``id()`` of objects
1375
+ on the *current* recursion path) and runaway depth (capped at 20 levels).
1376
+ Uses path-based tracking so shared (but non-cyclic) objects referenced by
1377
+ multiple siblings are converted correctly rather than being stringified.
1378
+ """
1379
+ _MAX_DEPTH = 20
1380
+ if _depth > _MAX_DEPTH:
1381
+ return str(value)
1382
+
1383
+ if _path is None:
1384
+ _path = set()
1385
+
1386
+ obj_id = id(value)
1387
+ if obj_id in _path:
1388
+ return str(value)
1389
+
1390
+ if hasattr(value, "model_dump"):
1391
+ _path.add(obj_id)
1392
+ result = _to_plain_data(value.model_dump(), _depth=_depth + 1, _path=_path)
1393
+ _path.discard(obj_id)
1394
+ return result
1395
+ if isinstance(value, dict):
1396
+ _path.add(obj_id)
1397
+ result = {k: _to_plain_data(v, _depth=_depth + 1, _path=_path) for k, v in value.items()}
1398
+ _path.discard(obj_id)
1399
+ return result
1400
+ if isinstance(value, (list, tuple)):
1401
+ _path.add(obj_id)
1402
+ result = [_to_plain_data(v, _depth=_depth + 1, _path=_path) for v in value]
1403
+ _path.discard(obj_id)
1404
+ return result
1405
+ if hasattr(value, "__dict__"):
1406
+ _path.add(obj_id)
1407
+ result = {
1408
+ k: _to_plain_data(v, _depth=_depth + 1, _path=_path)
1409
+ for k, v in vars(value).items()
1410
+ if not k.startswith("_")
1411
+ }
1412
+ _path.discard(obj_id)
1413
+ return result
1414
+ return value
1415
+
1416
+
1417
+ def _extract_preserved_thinking_blocks(message: Dict[str, Any]) -> List[Dict[str, Any]]:
1418
+ """Return Anthropic thinking blocks previously preserved on the message."""
1419
+ raw_details = message.get("reasoning_details")
1420
+ if not isinstance(raw_details, list):
1421
+ return []
1422
+
1423
+ preserved: List[Dict[str, Any]] = []
1424
+ for detail in raw_details:
1425
+ if not isinstance(detail, dict):
1426
+ continue
1427
+ block_type = str(detail.get("type", "") or "").strip().lower()
1428
+ if block_type not in {"thinking", "redacted_thinking"}:
1429
+ continue
1430
+ preserved.append(copy.deepcopy(detail))
1431
+ return preserved
1432
+
1433
+
1434
+ def _convert_content_to_anthropic(content: Any) -> Any:
1435
+ """Convert OpenAI-style multimodal content arrays to Anthropic blocks."""
1436
+ if not isinstance(content, list):
1437
+ return content
1438
+
1439
+ converted = []
1440
+ for part in content:
1441
+ block = _convert_content_part_to_anthropic(part)
1442
+ if block is not None:
1443
+ converted.append(block)
1444
+ return converted
1445
+
1446
+
1447
+ def _content_parts_to_anthropic_blocks(parts: Any) -> List[Dict[str, Any]]:
1448
+ """Convert OpenAI-style tool-message content parts → Anthropic tool_result inner blocks.
1449
+
1450
+ Used for multimodal tool results (e.g. computer_use screenshots). Each
1451
+ part is normalized via `_convert_content_part_to_anthropic`, then
1452
+ filtered to the block types Anthropic tool_result accepts (text + image).
1453
+ """
1454
+ if not isinstance(parts, list):
1455
+ return []
1456
+ out: List[Dict[str, Any]] = []
1457
+ for part in parts:
1458
+ block = _convert_content_part_to_anthropic(part)
1459
+ if not block:
1460
+ continue
1461
+ btype = block.get("type")
1462
+ if btype == "text":
1463
+ text_val = block.get("text")
1464
+ if isinstance(text_val, str) and text_val:
1465
+ out.append({"type": "text", "text": text_val})
1466
+ elif btype == "image":
1467
+ src = block.get("source")
1468
+ if isinstance(src, dict) and src:
1469
+ out.append({"type": "image", "source": src})
1470
+ return out
1471
+
1472
+
1473
+ def convert_messages_to_anthropic(
1474
+ messages: List[Dict],
1475
+ base_url: str | None = None,
1476
+ model: str | None = None,
1477
+ ) -> Tuple[Optional[Any], List[Dict]]:
1478
+ """Convert OpenAI-format messages to Anthropic format.
1479
+
1480
+ Returns (system_prompt, anthropic_messages).
1481
+ System messages are extracted since Anthropic takes them as a separate param.
1482
+ system_prompt is a string or list of content blocks (when cache_control present).
1483
+
1484
+ When *base_url* is provided and points to a third-party Anthropic-compatible
1485
+ endpoint, all thinking block signatures are stripped. Signatures are
1486
+ Anthropic-proprietary — third-party endpoints cannot validate them and will
1487
+ reject them with HTTP 400 "Invalid signature in thinking block".
1488
+
1489
+ When *model* is provided and matches the Kimi / Moonshot family (or
1490
+ *base_url* is a Kimi / Moonshot host), unsigned thinking blocks
1491
+ synthesised from ``reasoning_content`` are preserved on replayed
1492
+ assistant tool-call messages — Kimi requires the field to exist, even
1493
+ if empty.
1494
+ """
1495
+ system = None
1496
+ result = []
1497
+
1498
+ for m in messages:
1499
+ role = m.get("role", "user")
1500
+ content = m.get("content", "")
1501
+
1502
+ if role == "system":
1503
+ if isinstance(content, list):
1504
+ # Preserve cache_control markers on content blocks
1505
+ has_cache = any(
1506
+ p.get("cache_control") for p in content if isinstance(p, dict)
1507
+ )
1508
+ if has_cache:
1509
+ system = [p for p in content if isinstance(p, dict)]
1510
+ else:
1511
+ system = "\n".join(
1512
+ p["text"] for p in content if p.get("type") == "text"
1513
+ )
1514
+ else:
1515
+ system = content
1516
+ continue
1517
+
1518
+ if role == "assistant":
1519
+ blocks = _extract_preserved_thinking_blocks(m)
1520
+ if content:
1521
+ if isinstance(content, list):
1522
+ converted_content = _convert_content_to_anthropic(content)
1523
+ if isinstance(converted_content, list):
1524
+ blocks.extend(converted_content)
1525
+ else:
1526
+ blocks.append({"type": "text", "text": str(content)})
1527
+ for tc in m.get("tool_calls", []):
1528
+ if not tc or not isinstance(tc, dict):
1529
+ continue
1530
+ fn = tc.get("function", {})
1531
+ args = fn.get("arguments", "{}")
1532
+ try:
1533
+ parsed_args = json.loads(args) if isinstance(args, str) else args
1534
+ except (json.JSONDecodeError, ValueError):
1535
+ parsed_args = {}
1536
+ blocks.append({
1537
+ "type": "tool_use",
1538
+ "id": _sanitize_tool_id(tc.get("id", "")),
1539
+ "name": fn.get("name", ""),
1540
+ "input": parsed_args,
1541
+ })
1542
+ # Kimi's /coding endpoint (Anthropic protocol) requires assistant
1543
+ # tool-call messages to carry reasoning_content when thinking is
1544
+ # enabled server-side. Preserve it as a thinking block so Kimi
1545
+ # can validate the message history. See hermes-agent#13848.
1546
+ #
1547
+ # Accept empty string "" — _copy_reasoning_content_for_api()
1548
+ # injects "" as a tier-3 fallback for Kimi tool-call messages
1549
+ # that had no reasoning. Kimi requires the field to exist, even
1550
+ # if empty.
1551
+ #
1552
+ # Prepend (not append): Anthropic protocol requires thinking
1553
+ # blocks before text and tool_use blocks.
1554
+ #
1555
+ # Guard: only add when reasoning_details didn't already contribute
1556
+ # thinking blocks. On native Anthropic, reasoning_details produces
1557
+ # signed thinking blocks — adding another unsigned one from
1558
+ # reasoning_content would create a duplicate (same text) that gets
1559
+ # downgraded to a spurious text block on the last assistant message.
1560
+ reasoning_content = m.get("reasoning_content")
1561
+ _already_has_thinking = any(
1562
+ isinstance(b, dict) and b.get("type") in {"thinking", "redacted_thinking"}
1563
+ for b in blocks
1564
+ )
1565
+ if isinstance(reasoning_content, str) and not _already_has_thinking:
1566
+ blocks.insert(0, {"type": "thinking", "thinking": reasoning_content})
1567
+ # Anthropic rejects empty assistant content
1568
+ effective = blocks or content
1569
+ if not effective or effective == "":
1570
+ effective = [{"type": "text", "text": "(empty)"}]
1571
+ result.append({"role": "assistant", "content": effective})
1572
+ continue
1573
+
1574
+ if role == "tool":
1575
+ # Sanitize tool_use_id and ensure non-empty content.
1576
+ # Computer-use (and other multimodal) tool results arrive as
1577
+ # either a list of OpenAI-style content parts, or a dict
1578
+ # marked `_multimodal` with an embedded `content` list. Convert
1579
+ # both into Anthropic `tool_result` inner blocks (text + image).
1580
+ multimodal_blocks: Optional[List[Dict[str, Any]]] = None
1581
+ if isinstance(content, dict) and content.get("_multimodal"):
1582
+ multimodal_blocks = _content_parts_to_anthropic_blocks(
1583
+ content.get("content") or []
1584
+ )
1585
+ # Fallback text if the conversion produced nothing usable.
1586
+ if not multimodal_blocks and content.get("text_summary"):
1587
+ multimodal_blocks = [
1588
+ {"type": "text", "text": str(content["text_summary"])}
1589
+ ]
1590
+ elif isinstance(content, list):
1591
+ converted = _content_parts_to_anthropic_blocks(content)
1592
+ if any(b.get("type") == "image" for b in converted):
1593
+ multimodal_blocks = converted
1594
+ # Back-compat: some callers stash blocks under a private key.
1595
+ if multimodal_blocks is None:
1596
+ stashed = m.get("_anthropic_content_blocks")
1597
+ if isinstance(stashed, list) and stashed:
1598
+ text_content = content if isinstance(content, str) and content.strip() else None
1599
+ multimodal_blocks = (
1600
+ [{"type": "text", "text": text_content}] + stashed
1601
+ if text_content else list(stashed)
1602
+ )
1603
+
1604
+ if multimodal_blocks:
1605
+ result_content: Any = multimodal_blocks
1606
+ elif isinstance(content, str):
1607
+ result_content = content
1608
+ else:
1609
+ result_content = json.dumps(content) if content else "(no output)"
1610
+ if not result_content:
1611
+ result_content = "(no output)"
1612
+ tool_result = {
1613
+ "type": "tool_result",
1614
+ "tool_use_id": _sanitize_tool_id(m.get("tool_call_id", "")),
1615
+ "content": result_content,
1616
+ }
1617
+ if isinstance(m.get("cache_control"), dict):
1618
+ tool_result["cache_control"] = dict(m["cache_control"])
1619
+ # Merge consecutive tool results into one user message
1620
+ if (
1621
+ result
1622
+ and result[-1]["role"] == "user"
1623
+ and isinstance(result[-1]["content"], list)
1624
+ and result[-1]["content"]
1625
+ and result[-1]["content"][0].get("type") == "tool_result"
1626
+ ):
1627
+ result[-1]["content"].append(tool_result)
1628
+ else:
1629
+ result.append({"role": "user", "content": [tool_result]})
1630
+ continue
1631
+
1632
+ # Regular user message — validate non-empty content (Anthropic rejects empty)
1633
+ if isinstance(content, list):
1634
+ converted_blocks = _convert_content_to_anthropic(content)
1635
+ # Check if all text blocks are empty
1636
+ if not converted_blocks or all(
1637
+ b.get("text", "").strip() == ""
1638
+ for b in converted_blocks
1639
+ if isinstance(b, dict) and b.get("type") == "text"
1640
+ ):
1641
+ converted_blocks = [{"type": "text", "text": "(empty message)"}]
1642
+ result.append({"role": "user", "content": converted_blocks})
1643
+ else:
1644
+ # Validate string content is non-empty
1645
+ if not content or (isinstance(content, str) and not content.strip()):
1646
+ content = "(empty message)"
1647
+ result.append({"role": "user", "content": content})
1648
+
1649
+ # Strip orphaned tool_use blocks (no matching tool_result follows)
1650
+ tool_result_ids = set()
1651
+ for m in result:
1652
+ if m["role"] == "user" and isinstance(m["content"], list):
1653
+ for block in m["content"]:
1654
+ if block.get("type") == "tool_result":
1655
+ tool_result_ids.add(block.get("tool_use_id"))
1656
+ for m in result:
1657
+ if m["role"] == "assistant" and isinstance(m["content"], list):
1658
+ m["content"] = [
1659
+ b
1660
+ for b in m["content"]
1661
+ if b.get("type") != "tool_use" or b.get("id") in tool_result_ids
1662
+ ]
1663
+ if not m["content"]:
1664
+ m["content"] = [{"type": "text", "text": "(tool call removed)"}]
1665
+
1666
+ # Strip orphaned tool_result blocks (no matching tool_use precedes them).
1667
+ # This is the mirror of the above: context compression or session truncation
1668
+ # can remove an assistant message containing a tool_use while leaving the
1669
+ # subsequent tool_result intact. Anthropic rejects these with a 400.
1670
+ tool_use_ids = set()
1671
+ for m in result:
1672
+ if m["role"] == "assistant" and isinstance(m["content"], list):
1673
+ for block in m["content"]:
1674
+ if block.get("type") == "tool_use":
1675
+ tool_use_ids.add(block.get("id"))
1676
+ for m in result:
1677
+ if m["role"] == "user" and isinstance(m["content"], list):
1678
+ m["content"] = [
1679
+ b
1680
+ for b in m["content"]
1681
+ if b.get("type") != "tool_result" or b.get("tool_use_id") in tool_use_ids
1682
+ ]
1683
+ if not m["content"]:
1684
+ m["content"] = [{"type": "text", "text": "(tool result removed)"}]
1685
+
1686
+ # Enforce strict role alternation (Anthropic rejects consecutive same-role messages)
1687
+ fixed = []
1688
+ for m in result:
1689
+ if fixed and fixed[-1]["role"] == m["role"]:
1690
+ if m["role"] == "user":
1691
+ # Merge consecutive user messages
1692
+ prev_content = fixed[-1]["content"]
1693
+ curr_content = m["content"]
1694
+ if isinstance(prev_content, str) and isinstance(curr_content, str):
1695
+ fixed[-1]["content"] = prev_content + "\n" + curr_content
1696
+ elif isinstance(prev_content, list) and isinstance(curr_content, list):
1697
+ fixed[-1]["content"] = prev_content + curr_content
1698
+ else:
1699
+ # Mixed types — wrap string in list
1700
+ if isinstance(prev_content, str):
1701
+ prev_content = [{"type": "text", "text": prev_content}]
1702
+ if isinstance(curr_content, str):
1703
+ curr_content = [{"type": "text", "text": curr_content}]
1704
+ fixed[-1]["content"] = prev_content + curr_content
1705
+ else:
1706
+ # Consecutive assistant messages — merge text content.
1707
+ # Drop thinking blocks from the *second* message: their
1708
+ # signature was computed against a different turn boundary
1709
+ # and becomes invalid once merged.
1710
+ if isinstance(m["content"], list):
1711
+ m["content"] = [
1712
+ b for b in m["content"]
1713
+ if not (isinstance(b, dict) and b.get("type") in {"thinking", "redacted_thinking"})
1714
+ ]
1715
+ prev_blocks = fixed[-1]["content"]
1716
+ curr_blocks = m["content"]
1717
+ if isinstance(prev_blocks, list) and isinstance(curr_blocks, list):
1718
+ fixed[-1]["content"] = prev_blocks + curr_blocks
1719
+ elif isinstance(prev_blocks, str) and isinstance(curr_blocks, str):
1720
+ fixed[-1]["content"] = prev_blocks + "\n" + curr_blocks
1721
+ else:
1722
+ # Mixed types — normalize both to list and merge
1723
+ if isinstance(prev_blocks, str):
1724
+ prev_blocks = [{"type": "text", "text": prev_blocks}]
1725
+ if isinstance(curr_blocks, str):
1726
+ curr_blocks = [{"type": "text", "text": curr_blocks}]
1727
+ fixed[-1]["content"] = prev_blocks + curr_blocks
1728
+ else:
1729
+ fixed.append(m)
1730
+ result = fixed
1731
+
1732
+ # ── Thinking block signature management ──────────────────────────
1733
+ # Anthropic signs thinking blocks against the full turn content.
1734
+ # Any upstream mutation (context compression, session truncation,
1735
+ # orphan stripping, message merging) invalidates the signature,
1736
+ # causing HTTP 400 "Invalid signature in thinking block".
1737
+ #
1738
+ # Signatures are Anthropic-proprietary. Third-party endpoints
1739
+ # (MiniMax, Azure AI Foundry, self-hosted proxies) cannot validate
1740
+ # them and will reject them outright. When targeting a third-party
1741
+ # endpoint, strip ALL thinking/redacted_thinking blocks from every
1742
+ # assistant message — the third-party will generate its own
1743
+ # thinking blocks if it supports extended thinking.
1744
+ #
1745
+ # For direct Anthropic (strategy following clawdbot/OpenClaw):
1746
+ # 1. Strip thinking/redacted_thinking from all assistant messages
1747
+ # EXCEPT the last one — preserves reasoning continuity on the
1748
+ # current tool-use chain while avoiding stale signature errors.
1749
+ # 2. Downgrade unsigned thinking blocks (no signature) to text —
1750
+ # Anthropic can't validate them and will reject them.
1751
+ # 3. Strip cache_control from thinking/redacted_thinking blocks —
1752
+ # cache markers can interfere with signature validation.
1753
+ _THINKING_TYPES = frozenset(("thinking", "redacted_thinking"))
1754
+ _is_third_party = _is_third_party_anthropic_endpoint(base_url)
1755
+ # Kimi /coding and DeepSeek /anthropic share a contract: both speak the
1756
+ # Anthropic Messages protocol upstream but require that thinking blocks
1757
+ # synthesised from reasoning_content round-trip on subsequent turns when
1758
+ # thinking is enabled. Signed Anthropic blocks still have to be stripped
1759
+ # (neither endpoint can validate Anthropic's signatures); unsigned blocks
1760
+ # are preserved. See hermes-agent#13848 (Kimi) and #16748 (DeepSeek).
1761
+ _preserve_unsigned_thinking = (
1762
+ _is_kimi_family_endpoint(base_url, model)
1763
+ or _is_deepseek_anthropic_endpoint(base_url)
1764
+ )
1765
+
1766
+ last_assistant_idx = None
1767
+ for i in range(len(result) - 1, -1, -1):
1768
+ if result[i].get("role") == "assistant":
1769
+ last_assistant_idx = i
1770
+ break
1771
+
1772
+ for idx, m in enumerate(result):
1773
+ if m.get("role") != "assistant" or not isinstance(m.get("content"), list):
1774
+ continue
1775
+
1776
+ if _preserve_unsigned_thinking:
1777
+ # Kimi's /coding and DeepSeek's /anthropic endpoints both enable
1778
+ # thinking server-side and require unsigned thinking blocks on
1779
+ # replayed assistant tool-call messages. Strip signed Anthropic
1780
+ # blocks (neither upstream can validate Anthropic signatures) but
1781
+ # preserve the unsigned ones we synthesised from reasoning_content.
1782
+ new_content = []
1783
+ for b in m["content"]:
1784
+ if not isinstance(b, dict) or b.get("type") not in _THINKING_TYPES:
1785
+ new_content.append(b)
1786
+ continue
1787
+ if b.get("signature") or b.get("data"):
1788
+ # Anthropic-signed block — upstream can't validate, strip
1789
+ continue
1790
+ # Unsigned thinking (synthesised from reasoning_content) —
1791
+ # keep it: the upstream needs it for message-history validation.
1792
+ new_content.append(b)
1793
+ m["content"] = new_content or [{"type": "text", "text": "(empty)"}]
1794
+ elif _is_third_party or idx != last_assistant_idx:
1795
+ # Third-party endpoint: strip ALL thinking blocks from every
1796
+ # assistant message — signatures are Anthropic-proprietary.
1797
+ # Direct Anthropic: strip from non-latest assistant messages only.
1798
+ stripped = [
1799
+ b for b in m["content"]
1800
+ if not (isinstance(b, dict) and b.get("type") in _THINKING_TYPES)
1801
+ ]
1802
+ m["content"] = stripped or [{"type": "text", "text": "(thinking elided)"}]
1803
+ else:
1804
+ # Latest assistant on direct Anthropic: keep signed thinking
1805
+ # blocks for reasoning continuity; downgrade unsigned ones to
1806
+ # plain text.
1807
+ new_content = []
1808
+ for b in m["content"]:
1809
+ if not isinstance(b, dict) or b.get("type") not in _THINKING_TYPES:
1810
+ new_content.append(b)
1811
+ continue
1812
+ if b.get("type") == "redacted_thinking":
1813
+ # Redacted blocks use 'data' for the signature payload
1814
+ if b.get("data"):
1815
+ new_content.append(b)
1816
+ # else: drop — no data means it can't be validated
1817
+ elif b.get("signature"):
1818
+ # Signed thinking block — keep it
1819
+ new_content.append(b)
1820
+ else:
1821
+ # Unsigned thinking — downgrade to text so it's not lost
1822
+ thinking_text = b.get("thinking", "")
1823
+ if thinking_text:
1824
+ new_content.append({"type": "text", "text": thinking_text})
1825
+ m["content"] = new_content or [{"type": "text", "text": "(empty)"}]
1826
+
1827
+ # Strip cache_control from any remaining thinking/redacted_thinking
1828
+ # blocks — cache markers interfere with signature validation.
1829
+ for b in m["content"]:
1830
+ if isinstance(b, dict) and b.get("type") in _THINKING_TYPES:
1831
+ b.pop("cache_control", None)
1832
+
1833
+ # ── Image eviction: keep only the most recent N screenshots ─────
1834
+ # computer_use screenshots (base64 images) sit inside tool_result
1835
+ # blocks: they accumulate and are sent with every API call. Each
1836
+ # costs ~1,465 tokens; after 10+ the conversation becomes slow
1837
+ # even for simple text queries. Walk backward, keep the most recent
1838
+ # _MAX_KEEP_IMAGES, replace older ones with a text placeholder.
1839
+ _MAX_KEEP_IMAGES = 3
1840
+ _image_count = 0
1841
+ for msg in reversed(result):
1842
+ content = msg.get("content")
1843
+ if not isinstance(content, list):
1844
+ continue
1845
+ for block in content:
1846
+ if not isinstance(block, dict) or block.get("type") != "tool_result":
1847
+ continue
1848
+ inner = block.get("content")
1849
+ if not isinstance(inner, list):
1850
+ continue
1851
+ has_image = any(
1852
+ isinstance(b, dict) and b.get("type") == "image"
1853
+ for b in inner
1854
+ )
1855
+ if not has_image:
1856
+ continue
1857
+ _image_count += 1
1858
+ if _image_count > _MAX_KEEP_IMAGES:
1859
+ block["content"] = [
1860
+ b if b.get("type") != "image"
1861
+ else {"type": "text", "text": "[screenshot removed to save context]"}
1862
+ for b in inner
1863
+ ]
1864
+
1865
+ return system, result
1866
+
1867
+
1868
+ def build_anthropic_kwargs(
1869
+ model: str,
1870
+ messages: List[Dict],
1871
+ tools: Optional[List[Dict]],
1872
+ max_tokens: Optional[int],
1873
+ reasoning_config: Optional[Dict[str, Any]],
1874
+ tool_choice: Optional[str] = None,
1875
+ is_oauth: bool = False,
1876
+ preserve_dots: bool = False,
1877
+ context_length: Optional[int] = None,
1878
+ base_url: str | None = None,
1879
+ fast_mode: bool = False,
1880
+ drop_context_1m_beta: bool = False,
1881
+ ) -> Dict[str, Any]:
1882
+ """Build kwargs for anthropic.messages.create().
1883
+
1884
+ Naming note — two distinct concepts, easily confused:
1885
+ max_tokens = OUTPUT token cap for a single response.
1886
+ Anthropic's API calls this "max_tokens" but it only
1887
+ limits the *output*. Anthropic's own native SDK
1888
+ renamed it "max_output_tokens" for clarity.
1889
+ context_length = TOTAL context window (input tokens + output tokens).
1890
+ The API enforces: input_tokens + max_tokens ≤ context_length.
1891
+ Stored on the ContextCompressor; reduced on overflow errors.
1892
+
1893
+ When *max_tokens* is None the model's native output ceiling is used
1894
+ (e.g. 128K for Opus 4.6, 64K for Sonnet 4.6).
1895
+
1896
+ When *context_length* is provided and the model's native output ceiling
1897
+ exceeds it (e.g. a local endpoint with an 8K window), the output cap is
1898
+ clamped to context_length − 1. This only kicks in for unusually small
1899
+ context windows; for full-size models the native output cap is always
1900
+ smaller than the context window so no clamping happens.
1901
+ NOTE: this clamping does not account for prompt size — if the prompt is
1902
+ large, Anthropic may still reject the request. The caller must detect
1903
+ "max_tokens too large given prompt" errors and retry with a smaller cap
1904
+ (see parse_available_output_tokens_from_error + _ephemeral_max_output_tokens).
1905
+
1906
+ When *is_oauth* is True, applies Claude Code compatibility transforms:
1907
+ system prompt prefix, tool name prefixing, and prompt sanitization.
1908
+
1909
+ When *preserve_dots* is True, model name dots are not converted to hyphens
1910
+ (for Alibaba/DashScope anthropic-compatible endpoints: qwen3.5-plus).
1911
+
1912
+ When *base_url* points to a third-party Anthropic-compatible endpoint,
1913
+ thinking block signatures are stripped (they are Anthropic-proprietary).
1914
+
1915
+ When *fast_mode* is True, adds ``extra_body["speed"] = "fast"`` and the
1916
+ fast-mode beta header for ~2.5x faster output throughput on Opus 4.6.
1917
+ Currently only supported on native Anthropic endpoints (not third-party
1918
+ compatible ones).
1919
+ """
1920
+ system, anthropic_messages = convert_messages_to_anthropic(
1921
+ messages, base_url=base_url, model=model
1922
+ )
1923
+ anthropic_tools = convert_tools_to_anthropic(tools) if tools else []
1924
+
1925
+ model = normalize_model_name(model, preserve_dots=preserve_dots)
1926
+ # effective_max_tokens = output cap for this call (≠ total context window)
1927
+ # Use the resolver helper so non-positive values (negative ints,
1928
+ # fractional floats, NaN, non-numeric) fail locally with a clear error
1929
+ # rather than 400-ing at the Anthropic API. See openclaw/openclaw#66664.
1930
+ effective_max_tokens = _resolve_anthropic_messages_max_tokens(
1931
+ max_tokens, model, context_length=context_length
1932
+ )
1933
+
1934
+ # Clamp output cap to fit inside the total context window.
1935
+ # Only matters for small custom endpoints where context_length < native
1936
+ # output ceiling. For standard Anthropic models context_length (e.g.
1937
+ # 200K) is always larger than the output ceiling (e.g. 128K), so this
1938
+ # branch is not taken.
1939
+ if context_length and effective_max_tokens > context_length:
1940
+ effective_max_tokens = max(context_length - 1, 1)
1941
+
1942
+ # ── OAuth: Claude Code identity ──────────────────────────────────
1943
+ if is_oauth:
1944
+ # 1. Prepend Claude Code system prompt identity
1945
+ cc_block = {"type": "text", "text": _CLAUDE_CODE_SYSTEM_PREFIX}
1946
+ if isinstance(system, list):
1947
+ system = [cc_block] + system
1948
+ elif isinstance(system, str) and system:
1949
+ system = [cc_block, {"type": "text", "text": system}]
1950
+ else:
1951
+ system = [cc_block]
1952
+
1953
+ # 2. Sanitize system prompt — replace product name references
1954
+ # to avoid Anthropic's server-side content filters.
1955
+ for block in system:
1956
+ if isinstance(block, dict) and block.get("type") == "text":
1957
+ text = block.get("text", "")
1958
+ text = text.replace("Hermes Agent", "Claude Code")
1959
+ text = text.replace("Hermes agent", "Claude Code")
1960
+ text = text.replace("hermes-agent", "claude-code")
1961
+ text = text.replace("Nous Research", "Anthropic")
1962
+ block["text"] = text
1963
+
1964
+ # 3. Prefix tool names with mcp_ (Claude Code convention)
1965
+ if anthropic_tools:
1966
+ for tool in anthropic_tools:
1967
+ if "name" in tool:
1968
+ tool["name"] = _MCP_TOOL_PREFIX + tool["name"]
1969
+
1970
+ # 4. Prefix tool names in message history (tool_use and tool_result blocks)
1971
+ for msg in anthropic_messages:
1972
+ content = msg.get("content")
1973
+ if isinstance(content, list):
1974
+ for block in content:
1975
+ if isinstance(block, dict):
1976
+ if block.get("type") == "tool_use" and "name" in block:
1977
+ if not block["name"].startswith(_MCP_TOOL_PREFIX):
1978
+ block["name"] = _MCP_TOOL_PREFIX + block["name"]
1979
+ elif block.get("type") == "tool_result" and "tool_use_id" in block:
1980
+ pass # tool_result uses ID, not name
1981
+
1982
+ kwargs: Dict[str, Any] = {
1983
+ "model": model,
1984
+ "messages": anthropic_messages,
1985
+ "max_tokens": effective_max_tokens,
1986
+ }
1987
+
1988
+ if system:
1989
+ kwargs["system"] = system
1990
+
1991
+ if anthropic_tools:
1992
+ kwargs["tools"] = anthropic_tools
1993
+ # Map OpenAI tool_choice to Anthropic format
1994
+ if tool_choice == "auto" or tool_choice is None:
1995
+ kwargs["tool_choice"] = {"type": "auto"}
1996
+ elif tool_choice == "required":
1997
+ kwargs["tool_choice"] = {"type": "any"}
1998
+ elif tool_choice == "none":
1999
+ # Anthropic has no tool_choice "none" — omit tools entirely to prevent use
2000
+ kwargs.pop("tools", None)
2001
+ elif isinstance(tool_choice, str):
2002
+ # Specific tool name
2003
+ kwargs["tool_choice"] = {"type": "tool", "name": tool_choice}
2004
+
2005
+ # Map reasoning_config to Anthropic's thinking parameter.
2006
+ # Claude 4.6+ models use adaptive thinking + output_config.effort.
2007
+ # Older models use manual thinking with budget_tokens.
2008
+ # MiniMax Anthropic-compat endpoints support thinking (manual mode only,
2009
+ # not adaptive). Haiku does NOT support extended thinking — skip entirely.
2010
+ #
2011
+ # Kimi's /coding endpoint speaks the Anthropic Messages protocol but has
2012
+ # its own thinking semantics: when ``thinking.enabled`` is sent, Kimi
2013
+ # validates the message history and requires every prior assistant
2014
+ # tool-call message to carry OpenAI-style ``reasoning_content``. The
2015
+ # Anthropic path never populates that field, and
2016
+ # ``convert_messages_to_anthropic`` strips all Anthropic thinking blocks
2017
+ # on third-party endpoints — so the request fails with HTTP 400
2018
+ # "thinking is enabled but reasoning_content is missing in assistant
2019
+ # tool call message at index N". Kimi's reasoning is driven server-side
2020
+ # on the /coding route, so skip Anthropic's thinking parameter entirely
2021
+ # for that host. (Kimi on chat_completions enables thinking via
2022
+ # extra_body in the ChatCompletionsTransport — see #13503.)
2023
+ #
2024
+ # On 4.7+ the `thinking.display` field defaults to "omitted", which
2025
+ # silently hides reasoning text that Hermes surfaces in its CLI. We
2026
+ # request "summarized" so the reasoning blocks stay populated — matching
2027
+ # 4.6 behavior and preserving the activity-feed UX during long tool runs.
2028
+ _is_kimi_coding = _is_kimi_family_endpoint(base_url, model)
2029
+ if reasoning_config and isinstance(reasoning_config, dict) and not _is_kimi_coding:
2030
+ if reasoning_config.get("enabled") is not False and "haiku" not in model.lower():
2031
+ effort = str(reasoning_config.get("effort", "medium")).lower()
2032
+ budget = THINKING_BUDGET.get(effort, 8000)
2033
+ if _supports_adaptive_thinking(model):
2034
+ kwargs["thinking"] = {
2035
+ "type": "adaptive",
2036
+ "display": "summarized",
2037
+ }
2038
+ adaptive_effort = ADAPTIVE_EFFORT_MAP.get(effort, "medium")
2039
+ # Downgrade xhigh→max on models that don't list xhigh as a
2040
+ # supported level (Opus/Sonnet 4.6). Opus 4.7+ keeps xhigh.
2041
+ if adaptive_effort == "xhigh" and not _supports_xhigh_effort(model):
2042
+ adaptive_effort = "max"
2043
+ kwargs["output_config"] = {
2044
+ "effort": adaptive_effort,
2045
+ }
2046
+ else:
2047
+ kwargs["thinking"] = {"type": "enabled", "budget_tokens": budget}
2048
+ # Anthropic requires temperature=1 when thinking is enabled on older models
2049
+ kwargs["temperature"] = 1
2050
+ kwargs["max_tokens"] = max(effective_max_tokens, budget + 4096)
2051
+
2052
+ # ── Strip sampling params on 4.7+ ─────────────────────────────────
2053
+ # Opus 4.7 rejects any non-default temperature/top_p/top_k with a 400.
2054
+ # Callers (auxiliary_client, etc.) may set these for older models;
2055
+ # drop them here as a safety net so upstream 4.6 → 4.7 migrations
2056
+ # don't require coordinated edits everywhere.
2057
+ if _forbids_sampling_params(model):
2058
+ for _sampling_key in ("temperature", "top_p", "top_k"):
2059
+ kwargs.pop(_sampling_key, None)
2060
+
2061
+ # ── Fast mode (Opus 4.6 only) ────────────────────────────────────
2062
+ # Adds extra_body.speed="fast" + the fast-mode beta header for ~2.5x
2063
+ # output speed. Per Anthropic docs, fast mode is only supported on
2064
+ # Opus 4.6 — Opus 4.7 and other models 400 on the speed parameter.
2065
+ # Only for native Anthropic endpoints — third-party providers would
2066
+ # reject the unknown beta header and speed parameter.
2067
+ if (
2068
+ fast_mode
2069
+ and not _is_third_party_anthropic_endpoint(base_url)
2070
+ and _supports_fast_mode(model)
2071
+ ):
2072
+ kwargs.setdefault("extra_body", {})["speed"] = "fast"
2073
+ # Build extra_headers with ALL applicable betas (the per-request
2074
+ # extra_headers override the client-level anthropic-beta header).
2075
+ betas = list(_common_betas_for_base_url(
2076
+ base_url,
2077
+ drop_context_1m_beta=drop_context_1m_beta,
2078
+ ))
2079
+ if is_oauth:
2080
+ betas.extend(_OAUTH_ONLY_BETAS)
2081
+ betas.append(_FAST_MODE_BETA)
2082
+ kwargs["extra_headers"] = {"anthropic-beta": ",".join(betas)}
2083
+
2084
+ return kwargs
2085
+
2086
+
2087
+