bridgeagent 0.16.0__py3-none-any.whl

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 (709) hide show
  1. acp_adapter/__init__.py +1 -0
  2. acp_adapter/__main__.py +5 -0
  3. acp_adapter/auth.py +85 -0
  4. acp_adapter/edit_approval.py +286 -0
  5. acp_adapter/entry.py +266 -0
  6. acp_adapter/events.py +279 -0
  7. acp_adapter/permissions.py +168 -0
  8. acp_adapter/server.py +1952 -0
  9. acp_adapter/session.py +623 -0
  10. acp_adapter/tools.py +1291 -0
  11. agent/__init__.py +8 -0
  12. agent/account_usage.py +550 -0
  13. agent/agent_init.py +1739 -0
  14. agent/agent_runtime_helpers.py +2482 -0
  15. agent/anthropic_adapter.py +2303 -0
  16. agent/async_utils.py +68 -0
  17. agent/auxiliary_client.py +5928 -0
  18. agent/azure_identity_adapter.py +555 -0
  19. agent/background_review.py +597 -0
  20. agent/bedrock_adapter.py +1277 -0
  21. agent/browser_provider.py +175 -0
  22. agent/browser_registry.py +192 -0
  23. agent/chat_completion_helpers.py +2472 -0
  24. agent/codex_responses_adapter.py +1260 -0
  25. agent/codex_runtime.py +535 -0
  26. agent/context_compressor.py +2078 -0
  27. agent/context_engine.py +226 -0
  28. agent/context_references.py +518 -0
  29. agent/conversation_compression.py +785 -0
  30. agent/conversation_loop.py +4965 -0
  31. agent/copilot_acp_client.py +686 -0
  32. agent/credential_persistence.py +174 -0
  33. agent/credential_pool.py +2183 -0
  34. agent/credential_sources.py +448 -0
  35. agent/credits_tracker.py +723 -0
  36. agent/curator.py +1843 -0
  37. agent/curator_backup.py +695 -0
  38. agent/display.py +1033 -0
  39. agent/error_classifier.py +1319 -0
  40. agent/file_safety.py +640 -0
  41. agent/gemini_cloudcode_adapter.py +909 -0
  42. agent/gemini_native_adapter.py +990 -0
  43. agent/gemini_schema.py +99 -0
  44. agent/google_code_assist.py +451 -0
  45. agent/google_oauth.py +1067 -0
  46. agent/i18n.py +302 -0
  47. agent/image_gen_provider.py +324 -0
  48. agent/image_gen_registry.py +145 -0
  49. agent/image_routing.py +511 -0
  50. agent/insights.py +930 -0
  51. agent/iteration_budget.py +62 -0
  52. agent/jiter_preload.py +39 -0
  53. agent/lmstudio_reasoning.py +48 -0
  54. agent/lsp/__init__.py +106 -0
  55. agent/lsp/cli.py +299 -0
  56. agent/lsp/client.py +943 -0
  57. agent/lsp/eventlog.py +213 -0
  58. agent/lsp/install.py +400 -0
  59. agent/lsp/manager.py +639 -0
  60. agent/lsp/protocol.py +196 -0
  61. agent/lsp/range_shift.py +149 -0
  62. agent/lsp/reporter.py +78 -0
  63. agent/lsp/servers.py +1040 -0
  64. agent/lsp/workspace.py +223 -0
  65. agent/manual_compression_feedback.py +49 -0
  66. agent/markdown_tables.py +309 -0
  67. agent/memory_manager.py +683 -0
  68. agent/memory_provider.py +296 -0
  69. agent/message_sanitization.py +444 -0
  70. agent/model_metadata.py +1925 -0
  71. agent/models_dev.py +725 -0
  72. agent/moonshot_schema.py +231 -0
  73. agent/nous_rate_guard.py +325 -0
  74. agent/onboarding.py +193 -0
  75. agent/plugin_llm.py +1046 -0
  76. agent/portal_tags.py +64 -0
  77. agent/process_bootstrap.py +167 -0
  78. agent/prompt_builder.py +1660 -0
  79. agent/prompt_caching.py +79 -0
  80. agent/rate_limit_tracker.py +246 -0
  81. agent/redact.py +497 -0
  82. agent/retry_utils.py +57 -0
  83. agent/runtime_cwd.py +62 -0
  84. agent/secret_registry.py +223 -0
  85. agent/secret_sources/__init__.py +13 -0
  86. agent/secret_sources/bitwarden.py +690 -0
  87. agent/shell_hooks.py +847 -0
  88. agent/skill_bundles.py +410 -0
  89. agent/skill_commands.py +527 -0
  90. agent/skill_preprocessing.py +139 -0
  91. agent/skill_utils.py +677 -0
  92. agent/stream_diag.py +280 -0
  93. agent/subdirectory_hints.py +270 -0
  94. agent/system_prompt.py +412 -0
  95. agent/think_scrubber.py +386 -0
  96. agent/title_generator.py +171 -0
  97. agent/tool_dispatch_helpers.py +424 -0
  98. agent/tool_executor.py +1422 -0
  99. agent/tool_guardrails.py +475 -0
  100. agent/tool_result_classification.py +26 -0
  101. agent/trajectory.py +56 -0
  102. agent/transcription_provider.py +193 -0
  103. agent/transcription_registry.py +122 -0
  104. agent/transports/__init__.py +68 -0
  105. agent/transports/anthropic.py +189 -0
  106. agent/transports/base.py +89 -0
  107. agent/transports/bedrock.py +154 -0
  108. agent/transports/chat_completions.py +704 -0
  109. agent/transports/codex.py +359 -0
  110. agent/transports/codex_app_server.py +399 -0
  111. agent/transports/codex_app_server_session.py +849 -0
  112. agent/transports/codex_event_projector.py +312 -0
  113. agent/transports/hermes_tools_mcp_server.py +233 -0
  114. agent/transports/types.py +162 -0
  115. agent/tts_provider.py +274 -0
  116. agent/tts_registry.py +133 -0
  117. agent/usage_pricing.py +905 -0
  118. agent/video_gen_provider.py +299 -0
  119. agent/video_gen_registry.py +117 -0
  120. agent/web_search_provider.py +185 -0
  121. agent/web_search_registry.py +245 -0
  122. batch_runner.py +1321 -0
  123. bridge_bootstrap.py +129 -0
  124. bridge_cli/__init__.py +47 -0
  125. bridge_cli/_parser.py +397 -0
  126. bridge_cli/_subprocess_compat.py +234 -0
  127. bridge_cli/auth.py +7706 -0
  128. bridge_cli/auth_commands.py +821 -0
  129. bridge_cli/azure_detect.py +406 -0
  130. bridge_cli/backup.py +1043 -0
  131. bridge_cli/banner.py +797 -0
  132. bridge_cli/browser_connect.py +217 -0
  133. bridge_cli/build_info.py +51 -0
  134. bridge_cli/bundles.py +229 -0
  135. bridge_cli/callbacks.py +242 -0
  136. bridge_cli/checkpoints.py +244 -0
  137. bridge_cli/claw.py +809 -0
  138. bridge_cli/cli_output.py +77 -0
  139. bridge_cli/clipboard.py +494 -0
  140. bridge_cli/codex_models.py +206 -0
  141. bridge_cli/codex_runtime_plugin_migration.py +757 -0
  142. bridge_cli/codex_runtime_switch.py +266 -0
  143. bridge_cli/colors.py +38 -0
  144. bridge_cli/commands.py +1743 -0
  145. bridge_cli/completion.py +319 -0
  146. bridge_cli/config.py +6478 -0
  147. bridge_cli/container_boot.py +395 -0
  148. bridge_cli/copilot_auth.py +392 -0
  149. bridge_cli/cron.py +374 -0
  150. bridge_cli/curator.py +598 -0
  151. bridge_cli/curses_ui.py +872 -0
  152. bridge_cli/dashboard_auth/__init__.py +42 -0
  153. bridge_cli/dashboard_auth/audit.py +87 -0
  154. bridge_cli/dashboard_auth/base.py +220 -0
  155. bridge_cli/dashboard_auth/cookies.py +247 -0
  156. bridge_cli/dashboard_auth/login_page.py +534 -0
  157. bridge_cli/dashboard_auth/middleware.py +367 -0
  158. bridge_cli/dashboard_auth/prefix.py +157 -0
  159. bridge_cli/dashboard_auth/public_paths.py +49 -0
  160. bridge_cli/dashboard_auth/registry.py +58 -0
  161. bridge_cli/dashboard_auth/routes.py +621 -0
  162. bridge_cli/dashboard_auth/ws_tickets.py +161 -0
  163. bridge_cli/dashboard_register.py +300 -0
  164. bridge_cli/debug.py +829 -0
  165. bridge_cli/default_soul.py +11 -0
  166. bridge_cli/dep_ensure.py +159 -0
  167. bridge_cli/dingtalk_auth.py +293 -0
  168. bridge_cli/doctor.py +2183 -0
  169. bridge_cli/dump.py +349 -0
  170. bridge_cli/env_loader.py +344 -0
  171. bridge_cli/fallback_cmd.py +354 -0
  172. bridge_cli/fallback_config.py +72 -0
  173. bridge_cli/gateway.py +6755 -0
  174. bridge_cli/gateway_windows.py +1311 -0
  175. bridge_cli/goals.py +912 -0
  176. bridge_cli/gui_uninstall.py +290 -0
  177. bridge_cli/hooks.py +385 -0
  178. bridge_cli/inventory.py +410 -0
  179. bridge_cli/kanban.py +2830 -0
  180. bridge_cli/kanban_db.py +7659 -0
  181. bridge_cli/kanban_decompose.py +477 -0
  182. bridge_cli/kanban_diagnostics.py +1107 -0
  183. bridge_cli/kanban_specify.py +271 -0
  184. bridge_cli/kanban_swarm.py +279 -0
  185. bridge_cli/logs.py +394 -0
  186. bridge_cli/loop.py +367 -0
  187. bridge_cli/main.py +16632 -0
  188. bridge_cli/managed_uv.py +254 -0
  189. bridge_cli/mcp_catalog.py +775 -0
  190. bridge_cli/mcp_config.py +1217 -0
  191. bridge_cli/mcp_picker.py +322 -0
  192. bridge_cli/mcp_startup.py +59 -0
  193. bridge_cli/memory_setup.py +472 -0
  194. bridge_cli/middleware.py +313 -0
  195. bridge_cli/migrate.py +115 -0
  196. bridge_cli/model_catalog.py +363 -0
  197. bridge_cli/model_normalize.py +472 -0
  198. bridge_cli/model_switch.py +2023 -0
  199. bridge_cli/models.py +4092 -0
  200. bridge_cli/nous_account.py +764 -0
  201. bridge_cli/nous_subscription.py +1121 -0
  202. bridge_cli/oneshot.py +381 -0
  203. bridge_cli/pairing.py +115 -0
  204. bridge_cli/partial_compress.py +235 -0
  205. bridge_cli/platforms.py +83 -0
  206. bridge_cli/plugins.py +1946 -0
  207. bridge_cli/plugins_cmd.py +1691 -0
  208. bridge_cli/portal_cli.py +245 -0
  209. bridge_cli/profile_describer.py +298 -0
  210. bridge_cli/profile_distribution.py +721 -0
  211. bridge_cli/profiles.py +1664 -0
  212. bridge_cli/prompt_size.py +153 -0
  213. bridge_cli/providers.py +731 -0
  214. bridge_cli/proxy/__init__.py +20 -0
  215. bridge_cli/proxy/adapters/__init__.py +37 -0
  216. bridge_cli/proxy/adapters/base.py +108 -0
  217. bridge_cli/proxy/adapters/nous_portal.py +189 -0
  218. bridge_cli/proxy/adapters/xai.py +145 -0
  219. bridge_cli/proxy/cli.py +142 -0
  220. bridge_cli/proxy/server.py +296 -0
  221. bridge_cli/psutil_android.py +108 -0
  222. bridge_cli/pt_input_extras.py +120 -0
  223. bridge_cli/pty_bridge.py +276 -0
  224. bridge_cli/relaunch.py +206 -0
  225. bridge_cli/runtime_provider.py +1694 -0
  226. bridge_cli/scripts/install.ps1 +3231 -0
  227. bridge_cli/scripts/install.sh +2913 -0
  228. bridge_cli/secret_prompt.py +126 -0
  229. bridge_cli/secrets_cli.py +600 -0
  230. bridge_cli/security_advisories.py +453 -0
  231. bridge_cli/security_audit.py +576 -0
  232. bridge_cli/send_cmd.py +445 -0
  233. bridge_cli/service_manager.py +937 -0
  234. bridge_cli/session_recap.py +316 -0
  235. bridge_cli/setup.py +3361 -0
  236. bridge_cli/skills_config.py +199 -0
  237. bridge_cli/skills_hub.py +1913 -0
  238. bridge_cli/skin_engine.py +926 -0
  239. bridge_cli/slack_cli.py +159 -0
  240. bridge_cli/status.py +586 -0
  241. bridge_cli/stdio.py +256 -0
  242. bridge_cli/telegram_managed_bot.py +358 -0
  243. bridge_cli/timeouts.py +82 -0
  244. bridge_cli/tips.py +486 -0
  245. bridge_cli/tools_config.py +3933 -0
  246. bridge_cli/tui_dist/entry.js +74917 -0
  247. bridge_cli/uninstall.py +934 -0
  248. bridge_cli/voice.py +846 -0
  249. bridge_cli/web_dist/assets/Collapse-Bold-mgICk9-_.woff2 +0 -0
  250. bridge_cli/web_dist/assets/Collapse-Regular-DysayoTY.woff2 +0 -0
  251. bridge_cli/web_dist/assets/Mondwest-Regular-CWscgue7.woff2 +0 -0
  252. bridge_cli/web_dist/assets/RulesCompressed-Medium-CA76_CrB.woff2 +0 -0
  253. bridge_cli/web_dist/assets/RulesCompressed-Regular-BSXFyF4x.woff2 +0 -0
  254. bridge_cli/web_dist/assets/RulesExpanded-Bold-DZA7s8Pa.woff2 +0 -0
  255. bridge_cli/web_dist/assets/RulesExpanded-Regular-l8uVympt.woff2 +0 -0
  256. bridge_cli/web_dist/assets/filler-bg0-DxMaWJpb.webp +0 -0
  257. bridge_cli/web_dist/assets/index-DHRxol4O.js +170 -0
  258. bridge_cli/web_dist/assets/index-Drzx8NO1.css +1 -0
  259. bridge_cli/web_dist/favicon.ico +0 -0
  260. bridge_cli/web_dist/fonts/Collapse-Bold.woff2 +0 -0
  261. bridge_cli/web_dist/fonts/Collapse-Regular.woff2 +0 -0
  262. bridge_cli/web_dist/fonts/Mondwest-Regular.woff2 +0 -0
  263. bridge_cli/web_dist/fonts/RulesCompressed-Medium.woff2 +0 -0
  264. bridge_cli/web_dist/fonts/RulesCompressed-Regular.woff2 +0 -0
  265. bridge_cli/web_dist/fonts/RulesExpanded-Bold.woff2 +0 -0
  266. bridge_cli/web_dist/fonts/RulesExpanded-Regular.woff2 +0 -0
  267. bridge_cli/web_dist/fonts-terminal/JetBrainsMono-Bold.woff2 +0 -0
  268. bridge_cli/web_dist/fonts-terminal/JetBrainsMono-Italic.woff2 +0 -0
  269. bridge_cli/web_dist/fonts-terminal/JetBrainsMono-Regular.woff2 +0 -0
  270. bridge_cli/web_dist/index.html +17 -0
  271. bridge_cli/web_server.py +10028 -0
  272. bridge_cli/webhook.py +298 -0
  273. bridge_cli/xai_retirement.py +253 -0
  274. bridge_constants.py +482 -0
  275. bridge_logging.py +536 -0
  276. bridge_state.py +4491 -0
  277. bridge_time.py +104 -0
  278. bridgeagent-0.16.0.data/data/locales/af.yaml +357 -0
  279. bridgeagent-0.16.0.data/data/locales/de.yaml +357 -0
  280. bridgeagent-0.16.0.data/data/locales/en.yaml +372 -0
  281. bridgeagent-0.16.0.data/data/locales/es.yaml +357 -0
  282. bridgeagent-0.16.0.data/data/locales/fr.yaml +357 -0
  283. bridgeagent-0.16.0.data/data/locales/ga.yaml +361 -0
  284. bridgeagent-0.16.0.data/data/locales/hu.yaml +357 -0
  285. bridgeagent-0.16.0.data/data/locales/it.yaml +357 -0
  286. bridgeagent-0.16.0.data/data/locales/ja.yaml +357 -0
  287. bridgeagent-0.16.0.data/data/locales/ko.yaml +357 -0
  288. bridgeagent-0.16.0.data/data/locales/pt.yaml +357 -0
  289. bridgeagent-0.16.0.data/data/locales/ru.yaml +357 -0
  290. bridgeagent-0.16.0.data/data/locales/tr.yaml +357 -0
  291. bridgeagent-0.16.0.data/data/locales/uk.yaml +357 -0
  292. bridgeagent-0.16.0.data/data/locales/zh-hant.yaml +357 -0
  293. bridgeagent-0.16.0.data/data/locales/zh.yaml +357 -0
  294. bridgeagent-0.16.0.dist-info/METADATA +374 -0
  295. bridgeagent-0.16.0.dist-info/RECORD +709 -0
  296. bridgeagent-0.16.0.dist-info/WHEEL +5 -0
  297. bridgeagent-0.16.0.dist-info/entry_points.txt +7 -0
  298. bridgeagent-0.16.0.dist-info/licenses/LICENSE +25 -0
  299. bridgeagent-0.16.0.dist-info/top_level.txt +23 -0
  300. cli.py +16290 -0
  301. cron/__init__.py +42 -0
  302. cron/jobs.py +1306 -0
  303. cron/scheduler.py +2339 -0
  304. gateway/__init__.py +35 -0
  305. gateway/assets/telegram-botfather-threads-settings.jpg +0 -0
  306. gateway/builtin_hooks/__init__.py +1 -0
  307. gateway/channel_directory.py +357 -0
  308. gateway/config.py +2004 -0
  309. gateway/delivery.py +433 -0
  310. gateway/display_config.py +240 -0
  311. gateway/hooks.py +210 -0
  312. gateway/memory_monitor.py +230 -0
  313. gateway/mirror.py +168 -0
  314. gateway/pairing.py +450 -0
  315. gateway/platform_registry.py +260 -0
  316. gateway/platforms/__init__.py +45 -0
  317. gateway/platforms/_http_client_limits.py +84 -0
  318. gateway/platforms/api_server.py +4359 -0
  319. gateway/platforms/base.py +4818 -0
  320. gateway/platforms/bluebubbles.py +1038 -0
  321. gateway/platforms/dingtalk.py +1503 -0
  322. gateway/platforms/email.py +773 -0
  323. gateway/platforms/feishu.py +5163 -0
  324. gateway/platforms/feishu_comment.py +1382 -0
  325. gateway/platforms/feishu_comment_rules.py +429 -0
  326. gateway/platforms/feishu_meeting_invite.py +212 -0
  327. gateway/platforms/helpers.py +278 -0
  328. gateway/platforms/matrix.py +2983 -0
  329. gateway/platforms/msgraph_webhook.py +421 -0
  330. gateway/platforms/qqbot/__init__.py +91 -0
  331. gateway/platforms/qqbot/adapter.py +3196 -0
  332. gateway/platforms/qqbot/chunked_upload.py +602 -0
  333. gateway/platforms/qqbot/constants.py +74 -0
  334. gateway/platforms/qqbot/crypto.py +45 -0
  335. gateway/platforms/qqbot/keyboards.py +473 -0
  336. gateway/platforms/qqbot/onboard.py +220 -0
  337. gateway/platforms/qqbot/utils.py +74 -0
  338. gateway/platforms/signal.py +1543 -0
  339. gateway/platforms/signal_rate_limit.py +369 -0
  340. gateway/platforms/slack.py +3519 -0
  341. gateway/platforms/sms.py +379 -0
  342. gateway/platforms/telegram.py +6081 -0
  343. gateway/platforms/telegram_network.py +259 -0
  344. gateway/platforms/webhook.py +934 -0
  345. gateway/platforms/wecom.py +1635 -0
  346. gateway/platforms/wecom_callback.py +425 -0
  347. gateway/platforms/wecom_crypto.py +142 -0
  348. gateway/platforms/weixin.py +2247 -0
  349. gateway/platforms/whatsapp.py +1387 -0
  350. gateway/platforms/yuanbao.py +4941 -0
  351. gateway/platforms/yuanbao_media.py +645 -0
  352. gateway/platforms/yuanbao_proto.py +1209 -0
  353. gateway/platforms/yuanbao_sticker.py +558 -0
  354. gateway/restart.py +20 -0
  355. gateway/run.py +20137 -0
  356. gateway/runtime_footer.py +149 -0
  357. gateway/session.py +1400 -0
  358. gateway/session_context.py +194 -0
  359. gateway/shutdown_forensics.py +462 -0
  360. gateway/slash_access.py +229 -0
  361. gateway/status.py +1115 -0
  362. gateway/sticker_cache.py +124 -0
  363. gateway/stream_consumer.py +1358 -0
  364. gateway/stream_dispatch.py +132 -0
  365. gateway/stream_events.py +171 -0
  366. gateway/whatsapp_identity.py +155 -0
  367. mcp_serve.py +897 -0
  368. model_tools.py +1217 -0
  369. plugins/__init__.py +1 -0
  370. plugins/browser/browser_use/__init__.py +14 -0
  371. plugins/browser/browser_use/plugin.yaml +7 -0
  372. plugins/browser/browser_use/provider.py +317 -0
  373. plugins/browser/browserbase/__init__.py +15 -0
  374. plugins/browser/browserbase/plugin.yaml +7 -0
  375. plugins/browser/browserbase/provider.py +297 -0
  376. plugins/browser/firecrawl/__init__.py +16 -0
  377. plugins/browser/firecrawl/plugin.yaml +7 -0
  378. plugins/browser/firecrawl/provider.py +168 -0
  379. plugins/context_engine/__init__.py +285 -0
  380. plugins/dashboard_auth/basic/__init__.py +491 -0
  381. plugins/dashboard_auth/basic/plugin.yaml +7 -0
  382. plugins/dashboard_auth/nous/__init__.py +667 -0
  383. plugins/dashboard_auth/nous/plugin.yaml +7 -0
  384. plugins/dashboard_auth/self_hosted/__init__.py +736 -0
  385. plugins/dashboard_auth/self_hosted/plugin.yaml +8 -0
  386. plugins/disk-cleanup/README.md +51 -0
  387. plugins/disk-cleanup/__init__.py +316 -0
  388. plugins/disk-cleanup/disk_cleanup.py +560 -0
  389. plugins/disk-cleanup/plugin.yaml +7 -0
  390. plugins/google_meet/README.md +131 -0
  391. plugins/google_meet/__init__.py +103 -0
  392. plugins/google_meet/audio_bridge.py +244 -0
  393. plugins/google_meet/cli.py +477 -0
  394. plugins/google_meet/meet_bot.py +852 -0
  395. plugins/google_meet/node/__init__.py +54 -0
  396. plugins/google_meet/node/cli.py +125 -0
  397. plugins/google_meet/node/client.py +107 -0
  398. plugins/google_meet/node/protocol.py +124 -0
  399. plugins/google_meet/node/registry.py +112 -0
  400. plugins/google_meet/node/server.py +200 -0
  401. plugins/google_meet/plugin.yaml +16 -0
  402. plugins/google_meet/process_manager.py +323 -0
  403. plugins/google_meet/realtime/__init__.py +10 -0
  404. plugins/google_meet/realtime/openai_client.py +332 -0
  405. plugins/google_meet/tools.py +348 -0
  406. plugins/hermes-achievements/README.md +150 -0
  407. plugins/hermes-achievements/dashboard/dist/index.js +726 -0
  408. plugins/hermes-achievements/dashboard/dist/style.css +146 -0
  409. plugins/hermes-achievements/dashboard/manifest.json +11 -0
  410. plugins/hermes-achievements/dashboard/plugin_api.py +1061 -0
  411. plugins/hermes-achievements/tests/test_achievement_engine.py +156 -0
  412. plugins/image_gen/fal/__init__.py +182 -0
  413. plugins/image_gen/fal/plugin.yaml +7 -0
  414. plugins/image_gen/krea/__init__.py +548 -0
  415. plugins/image_gen/krea/plugin.yaml +7 -0
  416. plugins/image_gen/openai/__init__.py +316 -0
  417. plugins/image_gen/openai/plugin.yaml +7 -0
  418. plugins/image_gen/openai-codex/__init__.py +442 -0
  419. plugins/image_gen/openai-codex/plugin.yaml +5 -0
  420. plugins/image_gen/xai/__init__.py +334 -0
  421. plugins/image_gen/xai/plugin.yaml +7 -0
  422. plugins/kanban/dashboard/dist/index.js +3875 -0
  423. plugins/kanban/dashboard/dist/style.css +1583 -0
  424. plugins/kanban/dashboard/manifest.json +14 -0
  425. plugins/kanban/dashboard/plugin_api.py +2454 -0
  426. plugins/memory/__init__.py +450 -0
  427. plugins/memory/byterover/README.md +41 -0
  428. plugins/memory/byterover/__init__.py +383 -0
  429. plugins/memory/byterover/plugin.yaml +9 -0
  430. plugins/memory/hindsight/README.md +147 -0
  431. plugins/memory/hindsight/__init__.py +1777 -0
  432. plugins/memory/hindsight/plugin.yaml +8 -0
  433. plugins/memory/holographic/README.md +36 -0
  434. plugins/memory/holographic/__init__.py +408 -0
  435. plugins/memory/holographic/holographic.py +203 -0
  436. plugins/memory/holographic/plugin.yaml +5 -0
  437. plugins/memory/holographic/retrieval.py +593 -0
  438. plugins/memory/holographic/store.py +578 -0
  439. plugins/memory/honcho/README.md +368 -0
  440. plugins/memory/honcho/__init__.py +1419 -0
  441. plugins/memory/honcho/cli.py +1685 -0
  442. plugins/memory/honcho/client.py +872 -0
  443. plugins/memory/honcho/plugin.yaml +7 -0
  444. plugins/memory/honcho/session.py +1341 -0
  445. plugins/memory/mem0/README.md +38 -0
  446. plugins/memory/mem0/__init__.py +374 -0
  447. plugins/memory/mem0/plugin.yaml +5 -0
  448. plugins/memory/openviking/README.md +40 -0
  449. plugins/memory/openviking/__init__.py +978 -0
  450. plugins/memory/openviking/plugin.yaml +9 -0
  451. plugins/memory/retaindb/README.md +40 -0
  452. plugins/memory/retaindb/__init__.py +766 -0
  453. plugins/memory/retaindb/plugin.yaml +7 -0
  454. plugins/memory/supermemory/README.md +111 -0
  455. plugins/memory/supermemory/__init__.py +897 -0
  456. plugins/memory/supermemory/plugin.yaml +5 -0
  457. plugins/model-providers/README.md +70 -0
  458. plugins/model-providers/alibaba/__init__.py +13 -0
  459. plugins/model-providers/alibaba/plugin.yaml +5 -0
  460. plugins/model-providers/alibaba-coding-plan/__init__.py +21 -0
  461. plugins/model-providers/alibaba-coding-plan/plugin.yaml +5 -0
  462. plugins/model-providers/anthropic/__init__.py +52 -0
  463. plugins/model-providers/anthropic/plugin.yaml +5 -0
  464. plugins/model-providers/arcee/__init__.py +13 -0
  465. plugins/model-providers/arcee/plugin.yaml +5 -0
  466. plugins/model-providers/azure-foundry/__init__.py +21 -0
  467. plugins/model-providers/azure-foundry/plugin.yaml +5 -0
  468. plugins/model-providers/bedrock/__init__.py +29 -0
  469. plugins/model-providers/bedrock/plugin.yaml +5 -0
  470. plugins/model-providers/copilot/__init__.py +58 -0
  471. plugins/model-providers/copilot/plugin.yaml +5 -0
  472. plugins/model-providers/copilot-acp/__init__.py +34 -0
  473. plugins/model-providers/copilot-acp/plugin.yaml +5 -0
  474. plugins/model-providers/custom/__init__.py +68 -0
  475. plugins/model-providers/custom/plugin.yaml +5 -0
  476. plugins/model-providers/deepseek/__init__.py +100 -0
  477. plugins/model-providers/deepseek/plugin.yaml +5 -0
  478. plugins/model-providers/gemini/__init__.py +72 -0
  479. plugins/model-providers/gemini/plugin.yaml +5 -0
  480. plugins/model-providers/gmi/__init__.py +31 -0
  481. plugins/model-providers/gmi/plugin.yaml +5 -0
  482. plugins/model-providers/huggingface/__init__.py +20 -0
  483. plugins/model-providers/huggingface/plugin.yaml +5 -0
  484. plugins/model-providers/kilocode/__init__.py +14 -0
  485. plugins/model-providers/kilocode/plugin.yaml +5 -0
  486. plugins/model-providers/kimi-coding/__init__.py +80 -0
  487. plugins/model-providers/kimi-coding/plugin.yaml +5 -0
  488. plugins/model-providers/minimax/__init__.py +45 -0
  489. plugins/model-providers/minimax/plugin.yaml +5 -0
  490. plugins/model-providers/nous/__init__.py +54 -0
  491. plugins/model-providers/nous/plugin.yaml +5 -0
  492. plugins/model-providers/novita/__init__.py +27 -0
  493. plugins/model-providers/novita/plugin.yaml +5 -0
  494. plugins/model-providers/nvidia/__init__.py +21 -0
  495. plugins/model-providers/nvidia/plugin.yaml +5 -0
  496. plugins/model-providers/ollama-cloud/__init__.py +14 -0
  497. plugins/model-providers/ollama-cloud/plugin.yaml +5 -0
  498. plugins/model-providers/openai-codex/__init__.py +15 -0
  499. plugins/model-providers/openai-codex/plugin.yaml +5 -0
  500. plugins/model-providers/opencode-zen/__init__.py +126 -0
  501. plugins/model-providers/opencode-zen/plugin.yaml +5 -0
  502. plugins/model-providers/openrouter/__init__.py +117 -0
  503. plugins/model-providers/openrouter/plugin.yaml +5 -0
  504. plugins/model-providers/qwen-oauth/__init__.py +82 -0
  505. plugins/model-providers/qwen-oauth/plugin.yaml +5 -0
  506. plugins/model-providers/stepfun/__init__.py +14 -0
  507. plugins/model-providers/stepfun/plugin.yaml +5 -0
  508. plugins/model-providers/xai/__init__.py +15 -0
  509. plugins/model-providers/xai/plugin.yaml +5 -0
  510. plugins/model-providers/xiaomi/__init__.py +15 -0
  511. plugins/model-providers/xiaomi/plugin.yaml +5 -0
  512. plugins/model-providers/zai/__init__.py +21 -0
  513. plugins/model-providers/zai/plugin.yaml +5 -0
  514. plugins/observability/langfuse/README.md +53 -0
  515. plugins/observability/langfuse/__init__.py +1004 -0
  516. plugins/observability/langfuse/plugin.yaml +14 -0
  517. plugins/observability/nemo_relay/README.md +553 -0
  518. plugins/observability/nemo_relay/__init__.py +836 -0
  519. plugins/observability/nemo_relay/plugin.yaml +20 -0
  520. plugins/platforms/discord/__init__.py +3 -0
  521. plugins/platforms/discord/adapter.py +6520 -0
  522. plugins/platforms/discord/plugin.yaml +34 -0
  523. plugins/platforms/discord/voice_mixer.py +378 -0
  524. plugins/platforms/google_chat/__init__.py +3 -0
  525. plugins/platforms/google_chat/adapter.py +3342 -0
  526. plugins/platforms/google_chat/oauth.py +667 -0
  527. plugins/platforms/google_chat/plugin.yaml +39 -0
  528. plugins/platforms/homeassistant/__init__.py +3 -0
  529. plugins/platforms/homeassistant/adapter.py +577 -0
  530. plugins/platforms/homeassistant/plugin.yaml +22 -0
  531. plugins/platforms/irc/__init__.py +3 -0
  532. plugins/platforms/irc/adapter.py +968 -0
  533. plugins/platforms/irc/plugin.yaml +54 -0
  534. plugins/platforms/line/__init__.py +3 -0
  535. plugins/platforms/line/adapter.py +1652 -0
  536. plugins/platforms/line/plugin.yaml +65 -0
  537. plugins/platforms/mattermost/__init__.py +3 -0
  538. plugins/platforms/mattermost/adapter.py +1192 -0
  539. plugins/platforms/mattermost/plugin.yaml +49 -0
  540. plugins/platforms/ntfy/__init__.py +3 -0
  541. plugins/platforms/ntfy/adapter.py +593 -0
  542. plugins/platforms/ntfy/plugin.yaml +56 -0
  543. plugins/platforms/simplex/__init__.py +3 -0
  544. plugins/platforms/simplex/adapter.py +760 -0
  545. plugins/platforms/simplex/plugin.yaml +37 -0
  546. plugins/platforms/teams/__init__.py +3 -0
  547. plugins/platforms/teams/adapter.py +1197 -0
  548. plugins/platforms/teams/plugin.yaml +48 -0
  549. plugins/security-guidance/README.md +88 -0
  550. plugins/security-guidance/__init__.py +259 -0
  551. plugins/security-guidance/patterns.py +368 -0
  552. plugins/security-guidance/plugin.yaml +7 -0
  553. plugins/spotify/__init__.py +66 -0
  554. plugins/spotify/client.py +435 -0
  555. plugins/spotify/plugin.yaml +13 -0
  556. plugins/spotify/tools.py +454 -0
  557. plugins/teams_pipeline/__init__.py +23 -0
  558. plugins/teams_pipeline/cli.py +461 -0
  559. plugins/teams_pipeline/meetings.py +333 -0
  560. plugins/teams_pipeline/models.py +350 -0
  561. plugins/teams_pipeline/pipeline.py +689 -0
  562. plugins/teams_pipeline/plugin.yaml +9 -0
  563. plugins/teams_pipeline/runtime.py +135 -0
  564. plugins/teams_pipeline/store.py +193 -0
  565. plugins/teams_pipeline/subscriptions.py +249 -0
  566. plugins/video_gen/fal/__init__.py +613 -0
  567. plugins/video_gen/fal/plugin.yaml +7 -0
  568. plugins/video_gen/xai/__init__.py +504 -0
  569. plugins/video_gen/xai/plugin.yaml +7 -0
  570. plugins/web/__init__.py +7 -0
  571. plugins/web/brave_free/__init__.py +14 -0
  572. plugins/web/brave_free/plugin.yaml +7 -0
  573. plugins/web/brave_free/provider.py +137 -0
  574. plugins/web/ddgs/__init__.py +15 -0
  575. plugins/web/ddgs/plugin.yaml +7 -0
  576. plugins/web/ddgs/provider.py +104 -0
  577. plugins/web/exa/__init__.py +15 -0
  578. plugins/web/exa/plugin.yaml +7 -0
  579. plugins/web/exa/provider.py +212 -0
  580. plugins/web/firecrawl/__init__.py +28 -0
  581. plugins/web/firecrawl/plugin.yaml +7 -0
  582. plugins/web/firecrawl/provider.py +594 -0
  583. plugins/web/parallel/__init__.py +16 -0
  584. plugins/web/parallel/plugin.yaml +7 -0
  585. plugins/web/parallel/provider.py +291 -0
  586. plugins/web/searxng/__init__.py +15 -0
  587. plugins/web/searxng/plugin.yaml +7 -0
  588. plugins/web/searxng/provider.py +140 -0
  589. plugins/web/tavily/__init__.py +10 -0
  590. plugins/web/tavily/plugin.yaml +7 -0
  591. plugins/web/tavily/provider.py +220 -0
  592. plugins/web/xai/__init__.py +14 -0
  593. plugins/web/xai/plugin.yaml +7 -0
  594. plugins/web/xai/provider.py +557 -0
  595. providers/__init__.py +191 -0
  596. providers/base.py +208 -0
  597. run_agent.py +5307 -0
  598. tools/__init__.py +25 -0
  599. tools/ansi_strip.py +44 -0
  600. tools/approval.py +1793 -0
  601. tools/binary_extensions.py +42 -0
  602. tools/browser_camofox.py +794 -0
  603. tools/browser_camofox_state.py +49 -0
  604. tools/browser_cdp_tool.py +569 -0
  605. tools/browser_dialog_tool.py +148 -0
  606. tools/browser_supervisor.py +1475 -0
  607. tools/browser_tool.py +3863 -0
  608. tools/budget_config.py +51 -0
  609. tools/checkpoint_manager.py +1669 -0
  610. tools/clarify_gateway.py +278 -0
  611. tools/clarify_tool.py +141 -0
  612. tools/code_execution_tool.py +1831 -0
  613. tools/computer_use/__init__.py +43 -0
  614. tools/computer_use/backend.py +158 -0
  615. tools/computer_use/cua_backend.py +779 -0
  616. tools/computer_use/schema.py +213 -0
  617. tools/computer_use/tool.py +750 -0
  618. tools/computer_use/vision_routing.py +204 -0
  619. tools/computer_use_tool.py +39 -0
  620. tools/credential_files.py +454 -0
  621. tools/cronjob_tools.py +919 -0
  622. tools/debug_helpers.py +105 -0
  623. tools/delegate_tool.py +2860 -0
  624. tools/discord_tool.py +959 -0
  625. tools/env_passthrough.py +163 -0
  626. tools/env_probe.py +247 -0
  627. tools/environments/__init__.py +14 -0
  628. tools/environments/base.py +895 -0
  629. tools/environments/daytona.py +270 -0
  630. tools/environments/docker.py +1326 -0
  631. tools/environments/file_sync.py +403 -0
  632. tools/environments/local.py +697 -0
  633. tools/environments/managed_modal.py +282 -0
  634. tools/environments/modal.py +478 -0
  635. tools/environments/modal_utils.py +204 -0
  636. tools/environments/singularity.py +262 -0
  637. tools/environments/ssh.py +375 -0
  638. tools/fal_common.py +163 -0
  639. tools/feishu_doc_tool.py +138 -0
  640. tools/feishu_drive_tool.py +431 -0
  641. tools/file_operations.py +2292 -0
  642. tools/file_state.py +332 -0
  643. tools/file_tools.py +1533 -0
  644. tools/fuzzy_match.py +860 -0
  645. tools/homeassistant_tool.py +513 -0
  646. tools/image_generation_tool.py +1180 -0
  647. tools/interrupt.py +98 -0
  648. tools/kanban_tools.py +1431 -0
  649. tools/lazy_deps.py +639 -0
  650. tools/loop_tools.py +302 -0
  651. tools/managed_tool_gateway.py +192 -0
  652. tools/mcp_oauth.py +776 -0
  653. tools/mcp_oauth_manager.py +607 -0
  654. tools/mcp_tool.py +3915 -0
  655. tools/memory_tool.py +723 -0
  656. tools/microsoft_graph_auth.py +245 -0
  657. tools/microsoft_graph_client.py +408 -0
  658. tools/mixture_of_agents_tool.py +542 -0
  659. tools/neutts_synth.py +104 -0
  660. tools/openrouter_client.py +33 -0
  661. tools/osv_check.py +169 -0
  662. tools/patch_parser.py +622 -0
  663. tools/path_security.py +43 -0
  664. tools/process_registry.py +1616 -0
  665. tools/registry.py +589 -0
  666. tools/schema_sanitizer.py +445 -0
  667. tools/send_message_tool.py +1787 -0
  668. tools/session_search_tool.py +783 -0
  669. tools/skill_manager_tool.py +1043 -0
  670. tools/skill_provenance.py +78 -0
  671. tools/skill_usage.py +852 -0
  672. tools/skills_ast_audit.py +133 -0
  673. tools/skills_guard.py +1086 -0
  674. tools/skills_hub.py +3756 -0
  675. tools/skills_sync.py +897 -0
  676. tools/skills_tool.py +1604 -0
  677. tools/slash_confirm.py +167 -0
  678. tools/terminal_tool.py +2612 -0
  679. tools/thread_context.py +120 -0
  680. tools/threat_patterns.py +252 -0
  681. tools/tirith_security.py +820 -0
  682. tools/todo_tool.py +277 -0
  683. tools/tool_backend_helpers.py +182 -0
  684. tools/tool_output_limits.py +110 -0
  685. tools/tool_result_storage.py +232 -0
  686. tools/tool_search.py +735 -0
  687. tools/transcription_tools.py +1797 -0
  688. tools/tts_tool.py +2551 -0
  689. tools/url_safety.py +361 -0
  690. tools/video_generation_tool.py +562 -0
  691. tools/vision_tools.py +1591 -0
  692. tools/voice_mode.py +1217 -0
  693. tools/web_tools.py +1347 -0
  694. tools/website_policy.py +282 -0
  695. tools/x_search_tool.py +525 -0
  696. tools/xai_http.py +128 -0
  697. tools/yuanbao_tools.py +737 -0
  698. toolset_distributions.py +364 -0
  699. toolsets.py +916 -0
  700. trajectory_compressor.py +1579 -0
  701. tui_gateway/__init__.py +0 -0
  702. tui_gateway/entry.py +298 -0
  703. tui_gateway/event_publisher.py +126 -0
  704. tui_gateway/render.py +49 -0
  705. tui_gateway/server.py +8522 -0
  706. tui_gateway/slash_worker.py +76 -0
  707. tui_gateway/transport.py +219 -0
  708. tui_gateway/ws.py +327 -0
  709. utils.py +376 -0
@@ -0,0 +1 @@
1
+ """ACP (Agent Communication Protocol) adapter for BridgeAgent."""
@@ -0,0 +1,5 @@
1
+ """Allow running the ACP adapter as ``python -m acp_adapter``."""
2
+
3
+ from .entry import main
4
+
5
+ main()
acp_adapter/auth.py ADDED
@@ -0,0 +1,85 @@
1
+ """ACP auth helpers — detect and advertise BridgeAgent authentication methods."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Optional
6
+
7
+
8
+ TERMINAL_SETUP_AUTH_METHOD_ID = "bridge-setup"
9
+ LEGACY_TERMINAL_SETUP_AUTH_METHOD_IDS = {"hermes-setup"}
10
+
11
+
12
+ def is_terminal_setup_auth_method(method_id: str) -> bool:
13
+ normalized = method_id.strip().lower()
14
+ return normalized == TERMINAL_SETUP_AUTH_METHOD_ID or normalized in LEGACY_TERMINAL_SETUP_AUTH_METHOD_IDS
15
+
16
+
17
+ def detect_provider() -> Optional[str]:
18
+ """Resolve the active BridgeAgent runtime provider, or None if unavailable.
19
+
20
+ Treats a ``Callable`` ``api_key`` (Azure Foundry Entra ID bearer
21
+ token provider — see :mod:`agent.azure_identity_adapter`) as a valid
22
+ credential. Without this, ACP sessions for Entra-configured Foundry
23
+ deployments silently default to ``"openrouter"`` and the ACP auth
24
+ handshake rejects the legitimate provider.
25
+ """
26
+ try:
27
+ from bridge_cli.runtime_provider import resolve_runtime_provider
28
+ runtime = resolve_runtime_provider()
29
+ api_key = runtime.get("api_key")
30
+ provider = runtime.get("provider")
31
+ if not isinstance(provider, str) or not provider.strip():
32
+ return None
33
+ is_string_key = isinstance(api_key, str) and api_key.strip()
34
+ is_callable_provider = callable(api_key) and not isinstance(api_key, str)
35
+ if is_string_key or is_callable_provider:
36
+ return provider.strip().lower()
37
+ except Exception:
38
+ return None
39
+ return None
40
+
41
+
42
+ def has_provider() -> bool:
43
+ """Return True if BridgeAgent can resolve any runtime provider credentials."""
44
+ return detect_provider() is not None
45
+
46
+
47
+ def build_auth_methods() -> list[Any]:
48
+ """Return registry-compatible ACP auth methods for BridgeAgent.
49
+
50
+ The official ACP registry validates that agents advertise at least one
51
+ usable auth method during the initial handshake. A fresh Zed install may
52
+ not have BridgeAgent provider credentials configured yet, so BridgeAgent always
53
+ advertises a terminal setup method. When credentials are already present,
54
+ it also advertises the resolved provider as the default agent-managed
55
+ runtime credential method.
56
+ """
57
+ from acp.schema import AuthMethodAgent, TerminalAuthMethod
58
+
59
+ methods: list[Any] = []
60
+ provider = detect_provider()
61
+ if provider:
62
+ methods.append(
63
+ AuthMethodAgent(
64
+ id=provider,
65
+ name=f"{provider} runtime credentials",
66
+ description=(
67
+ "Authenticate BridgeAgent using the currently configured "
68
+ f"{provider} runtime credentials."
69
+ ),
70
+ )
71
+ )
72
+
73
+ methods.append(
74
+ TerminalAuthMethod(
75
+ id=TERMINAL_SETUP_AUTH_METHOD_ID,
76
+ name="Configure BridgeAgent provider",
77
+ description=(
78
+ "Open BridgeAgent' interactive model/provider setup in a terminal. "
79
+ "Use this when BridgeAgent has not been configured on this machine yet."
80
+ ),
81
+ type="terminal",
82
+ args=["--setup"],
83
+ )
84
+ )
85
+ return methods
@@ -0,0 +1,286 @@
1
+ """Pre-execution ACP edit approval helpers.
2
+
3
+ This module is intentionally isolated from the generic tool registry. ACP binds
4
+ an edit approval requester in a ContextVar for the duration of one ACP agent run;
5
+ CLI, gateway, and other sessions leave it unset and therefore bypass this guard.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import json
12
+ import logging
13
+ import tempfile
14
+ from concurrent.futures import TimeoutError as FutureTimeout
15
+ from contextvars import ContextVar, Token
16
+ from dataclasses import dataclass
17
+ from itertools import count
18
+ from pathlib import Path
19
+ from typing import Any, Callable
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class EditProposal:
26
+ """A proposed single-file edit that can be shown to an ACP client."""
27
+
28
+ tool_name: str
29
+ path: str
30
+ old_text: str | None
31
+ new_text: str
32
+ arguments: dict[str, Any]
33
+
34
+
35
+ EditApprovalRequester = Callable[[EditProposal], bool]
36
+
37
+ _EDIT_APPROVAL_REQUESTER: ContextVar[EditApprovalRequester | None] = ContextVar(
38
+ "ACP_EDIT_APPROVAL_REQUESTER",
39
+ default=None,
40
+ )
41
+ _PERMISSION_REQUEST_IDS = count(1)
42
+
43
+
44
+ SENSITIVE_AUTO_APPROVE_NAMES = {".env", ".env.local", ".env.production", "id_rsa", "id_ed25519"}
45
+ AUTO_APPROVE_ASK = "ask"
46
+ AUTO_APPROVE_WORKSPACE = "workspace_session"
47
+ AUTO_APPROVE_SESSION = "session"
48
+
49
+
50
+ def set_edit_approval_requester(requester: EditApprovalRequester | None) -> Token:
51
+ """Bind an ACP edit approval requester for the current context."""
52
+
53
+ return _EDIT_APPROVAL_REQUESTER.set(requester)
54
+
55
+
56
+ def reset_edit_approval_requester(token: Token) -> None:
57
+ """Restore a previous edit approval requester binding."""
58
+
59
+ _EDIT_APPROVAL_REQUESTER.reset(token)
60
+
61
+
62
+ def clear_edit_approval_requester() -> None:
63
+ """Clear the current requester; primarily used by tests."""
64
+
65
+ _EDIT_APPROVAL_REQUESTER.set(None)
66
+
67
+
68
+ def get_edit_approval_requester() -> EditApprovalRequester | None:
69
+ return _EDIT_APPROVAL_REQUESTER.get()
70
+
71
+
72
+ def _read_text_if_exists(path: str) -> str | None:
73
+ p = Path(path).expanduser()
74
+ if not p.exists():
75
+ return None
76
+ if not p.is_file():
77
+ raise OSError(f"Cannot edit non-file path: {path}")
78
+ return p.read_text(encoding="utf-8", errors="replace")
79
+
80
+
81
+ def _proposal_for_write_file(arguments: dict[str, Any]) -> EditProposal:
82
+ path = str(arguments.get("path") or "")
83
+ if not path:
84
+ raise ValueError("path required")
85
+ content = arguments.get("content")
86
+ if content is None:
87
+ raise ValueError("content required")
88
+ return EditProposal(
89
+ tool_name="write_file",
90
+ path=path,
91
+ old_text=_read_text_if_exists(path),
92
+ new_text=str(content),
93
+ arguments=dict(arguments),
94
+ )
95
+
96
+
97
+ def _proposal_for_patch_replace(arguments: dict[str, Any]) -> EditProposal:
98
+ path = str(arguments.get("path") or "")
99
+ if not path:
100
+ raise ValueError("path required")
101
+ old_string = arguments.get("old_string")
102
+ new_string = arguments.get("new_string")
103
+ if old_string is None or new_string is None:
104
+ raise ValueError("old_string and new_string required")
105
+
106
+ old_text = _read_text_if_exists(path)
107
+ if old_text is None:
108
+ raise ValueError(f"Failed to read file: {path}")
109
+
110
+ from tools.fuzzy_match import fuzzy_find_and_replace
111
+
112
+ new_text, match_count, _strategy, error = fuzzy_find_and_replace(
113
+ old_text,
114
+ str(old_string),
115
+ str(new_string),
116
+ bool(arguments.get("replace_all", False)),
117
+ )
118
+ if error or match_count == 0:
119
+ raise ValueError(error or f"Could not find match for old_string in {path}")
120
+
121
+ return EditProposal(
122
+ tool_name="patch",
123
+ path=path,
124
+ old_text=old_text,
125
+ new_text=new_text,
126
+ arguments=dict(arguments),
127
+ )
128
+
129
+
130
+ def build_edit_proposal(tool_name: str, arguments: dict[str, Any]) -> EditProposal | None:
131
+ """Return an edit proposal for supported file mutation calls."""
132
+
133
+ if tool_name == "write_file":
134
+ return _proposal_for_write_file(arguments)
135
+ if tool_name == "patch" and arguments.get("mode", "replace") == "replace":
136
+ return _proposal_for_patch_replace(arguments)
137
+ return None
138
+
139
+
140
+ def _is_sensitive_auto_approve_path(path: str) -> bool:
141
+ parts = Path(path).expanduser().parts
142
+ lowered = {part.lower() for part in parts}
143
+ if ".git" in lowered or ".ssh" in lowered:
144
+ return True
145
+ return Path(path).name.lower() in SENSITIVE_AUTO_APPROVE_NAMES
146
+
147
+
148
+ def should_auto_approve_edit(proposal: EditProposal, policy: str, cwd: str | None = None) -> bool:
149
+ """Return whether an ACP edit proposal may bypass the prompt for this session.
150
+
151
+ This is intentionally session-scoped and conservative: sensitive paths still
152
+ ask even under autonomous policies.
153
+ """
154
+
155
+ policy = str(policy or AUTO_APPROVE_ASK).strip()
156
+ if policy == AUTO_APPROVE_ASK or _is_sensitive_auto_approve_path(proposal.path):
157
+ return False
158
+ path = Path(proposal.path).expanduser().resolve(strict=False)
159
+ if policy == AUTO_APPROVE_SESSION:
160
+ return True
161
+ if policy == AUTO_APPROVE_WORKSPACE:
162
+ # `/tmp` is the POSIX path but tempfile.gettempdir() is the real one on
163
+ # every platform: `/private/tmp` on macOS (because `/tmp` is a symlink
164
+ # and Path.resolve() follows it) and the per-user Temp dir on Windows.
165
+ tmp_root = Path(tempfile.gettempdir()).resolve(strict=False)
166
+ try:
167
+ path.relative_to(tmp_root)
168
+ return True
169
+ except ValueError:
170
+ pass
171
+ if cwd:
172
+ root = Path(cwd).expanduser().resolve(strict=False)
173
+ try:
174
+ path.relative_to(root)
175
+ return True
176
+ except ValueError:
177
+ return False
178
+ return False
179
+
180
+
181
+ def maybe_require_edit_approval(tool_name: str, arguments: dict[str, Any]) -> str | None:
182
+ """Run ACP edit approval if bound.
183
+
184
+ Returns a JSON tool-error string when the edit must be blocked, otherwise
185
+ ``None`` so dispatch can continue. Requester exceptions deny by default.
186
+ """
187
+
188
+ requester = get_edit_approval_requester()
189
+ if requester is None:
190
+ return None
191
+
192
+ try:
193
+ proposal = build_edit_proposal(tool_name, arguments)
194
+ except Exception as exc:
195
+ logger.warning("Could not build ACP edit approval proposal for %s: %s", tool_name, exc)
196
+ return json.dumps({"error": f"Edit approval denied: could not prepare diff ({exc})"}, ensure_ascii=False)
197
+
198
+ if proposal is None:
199
+ return None
200
+
201
+ try:
202
+ approved = bool(requester(proposal))
203
+ except Exception as exc:
204
+ logger.warning("ACP edit approval requester failed: %s", exc)
205
+ approved = False
206
+
207
+ if approved:
208
+ return None
209
+ return json.dumps({"error": "Edit approval denied by ACP client; file was not modified."}, ensure_ascii=False)
210
+
211
+
212
+ def build_acp_edit_tool_call(proposal: EditProposal):
213
+ """Build the ToolCallUpdate payload for ACP request_permission."""
214
+
215
+ import acp
216
+
217
+ tool_call_id = f"edit-approval-{next(_PERMISSION_REQUEST_IDS)}"
218
+ return acp.update_tool_call(
219
+ tool_call_id,
220
+ title=f"Approve edit: {proposal.path}",
221
+ kind="edit",
222
+ status="pending",
223
+ content=[
224
+ acp.tool_diff_content(
225
+ path=proposal.path,
226
+ old_text=proposal.old_text,
227
+ new_text=proposal.new_text,
228
+ )
229
+ ],
230
+ raw_input={"tool": proposal.tool_name, "arguments": proposal.arguments},
231
+ )
232
+
233
+
234
+ def make_acp_edit_approval_requester(
235
+ request_permission_fn: Callable,
236
+ loop: asyncio.AbstractEventLoop,
237
+ session_id: str,
238
+ timeout: float = 60.0,
239
+ auto_approve_getter: Callable[[], tuple[str, str | None]] | None = None,
240
+ ) -> EditApprovalRequester:
241
+ """Return a sync requester that bridges edit proposals to ACP permissions."""
242
+
243
+ def _requester(proposal: EditProposal) -> bool:
244
+ from acp.schema import PermissionOption
245
+ from agent.async_utils import safe_schedule_threadsafe
246
+
247
+ if auto_approve_getter is not None:
248
+ try:
249
+ policy, cwd = auto_approve_getter()
250
+ if should_auto_approve_edit(proposal, policy, cwd):
251
+ logger.info("Auto-approved ACP edit under policy %s: %s", policy, proposal.path)
252
+ return True
253
+ except Exception:
254
+ logger.debug("ACP edit auto-approval policy check failed", exc_info=True)
255
+
256
+ options = [
257
+ PermissionOption(option_id="allow_once", kind="allow_once", name="Allow edit"),
258
+ PermissionOption(option_id="deny", kind="reject_once", name="Deny"),
259
+ ]
260
+ tool_call = build_acp_edit_tool_call(proposal)
261
+ coro = request_permission_fn(
262
+ session_id=session_id,
263
+ tool_call=tool_call,
264
+ options=options,
265
+ )
266
+ future = safe_schedule_threadsafe(
267
+ coro,
268
+ loop,
269
+ logger=logger,
270
+ log_message="Edit approval request: failed to schedule on loop",
271
+ )
272
+ if future is None:
273
+ return False
274
+ try:
275
+ response = future.result(timeout=timeout)
276
+ except (FutureTimeout, Exception) as exc:
277
+ future.cancel()
278
+ logger.warning("Edit approval request timed out or failed: %s", exc)
279
+ return False
280
+ outcome = getattr(response, "outcome", None)
281
+ return (
282
+ getattr(outcome, "outcome", None) == "selected"
283
+ and getattr(outcome, "option_id", None) == "allow_once"
284
+ )
285
+
286
+ return _requester
acp_adapter/entry.py ADDED
@@ -0,0 +1,266 @@
1
+ """CLI entry point for the BridgeAgent ACP adapter.
2
+
3
+ Loads environment variables from ``~/.bridgeagent/.env``, configures logging
4
+ to write to stderr (so stdout is reserved for ACP JSON-RPC transport),
5
+ and starts the ACP agent server.
6
+
7
+ Usage::
8
+
9
+ python -m acp_adapter.entry
10
+ # or
11
+ bridge acp
12
+ # or
13
+ bridge-acp
14
+ """
15
+
16
+ # IMPORTANT: bridge_bootstrap must be the very first import — UTF-8 stdio
17
+ # on Windows. No-op on POSIX. See bridge_bootstrap.py for full rationale.
18
+ try:
19
+ import bridge_bootstrap # noqa: F401
20
+ except ModuleNotFoundError:
21
+ # Graceful fallback when bridge_bootstrap isn't registered in the venv
22
+ # yet — happens during partial ``bridge update`` where git-reset landed
23
+ # new code but ``uv pip install -e .`` didn't finish. Missing bootstrap
24
+ # means UTF-8 stdio setup is skipped on Windows; POSIX is unaffected.
25
+ pass
26
+
27
+ import argparse
28
+ import asyncio
29
+ import logging
30
+ import sys
31
+ from pathlib import Path
32
+ from bridge_constants import get_bridge_home
33
+
34
+
35
+ # Methods clients send as periodic liveness probes. They are not part of the
36
+ # ACP schema, so the acp router correctly returns JSON-RPC -32601 to the
37
+ # caller — but the supervisor task that dispatches the request then surfaces
38
+ # the raised RequestError via ``logging.exception("Background task failed")``,
39
+ # which dumps a traceback to stderr every probe interval. Clients like
40
+ # acp-bridge already treat the -32601 response as "agent alive", so the
41
+ # traceback is pure noise. We keep the protocol response intact and only
42
+ # silence the stderr noise for this specific benign case.
43
+ _BENIGN_PROBE_METHODS = frozenset({"ping", "health", "healthcheck"})
44
+
45
+
46
+ class _BenignProbeMethodFilter(logging.Filter):
47
+ """Suppress acp 'Background task failed' tracebacks caused by unknown
48
+ liveness-probe methods (e.g. ``ping``) while leaving every other
49
+ background-task error — including method_not_found for any non-probe
50
+ method — visible in stderr.
51
+ """
52
+
53
+ def filter(self, record: logging.LogRecord) -> bool:
54
+ if record.getMessage() != "Background task failed":
55
+ return True
56
+ exc_info = record.exc_info
57
+ if not exc_info:
58
+ return True
59
+ exc = exc_info[1]
60
+ # Imported lazily so this module stays importable when the optional
61
+ # ``agent-client-protocol`` dependency is not installed.
62
+ try:
63
+ from acp.exceptions import RequestError
64
+ except ImportError:
65
+ return True
66
+ if not isinstance(exc, RequestError):
67
+ return True
68
+ if getattr(exc, "code", None) != -32601:
69
+ return True
70
+ data = getattr(exc, "data", None)
71
+ method = data.get("method") if isinstance(data, dict) else None
72
+ return method not in _BENIGN_PROBE_METHODS
73
+
74
+
75
+ def _setup_logging() -> None:
76
+ """Route all logging to stderr so stdout stays clean for ACP stdio."""
77
+ handler = logging.StreamHandler(sys.stderr)
78
+ handler.setFormatter(
79
+ logging.Formatter(
80
+ "%(asctime)s [%(levelname)s] %(name)s: %(message)s",
81
+ datefmt="%Y-%m-%d %H:%M:%S",
82
+ )
83
+ )
84
+ handler.addFilter(_BenignProbeMethodFilter())
85
+ root = logging.getLogger()
86
+ root.handlers.clear()
87
+ root.addHandler(handler)
88
+ root.setLevel(logging.INFO)
89
+
90
+ # Quiet down noisy libraries
91
+ logging.getLogger("httpx").setLevel(logging.WARNING)
92
+ logging.getLogger("httpcore").setLevel(logging.WARNING)
93
+ logging.getLogger("openai").setLevel(logging.WARNING)
94
+
95
+
96
+ def _load_env() -> None:
97
+ """Load .env from BRIDGE_HOME (default ``~/.bridgeagent``)."""
98
+ from bridge_cli.env_loader import load_hermes_dotenv
99
+
100
+ bridge_home = get_bridge_home()
101
+ loaded = load_hermes_dotenv(bridge_home=bridge_home)
102
+ if loaded:
103
+ for env_file in loaded:
104
+ logging.getLogger(__name__).info("Loaded env from %s", env_file)
105
+ else:
106
+ logging.getLogger(__name__).info(
107
+ "No .env found at %s, using system env", bridge_home / ".env"
108
+ )
109
+
110
+
111
+ def _parse_args(argv: list[str] | None = None) -> argparse.Namespace:
112
+ parser = argparse.ArgumentParser(
113
+ prog="bridge-acp",
114
+ description="Run BridgeAgent as an ACP stdio server.",
115
+ )
116
+ parser.add_argument("--version", action="store_true", help="Print BridgeAgent version and exit")
117
+ parser.add_argument(
118
+ "--check",
119
+ action="store_true",
120
+ help="Verify ACP dependencies and adapter imports, then exit",
121
+ )
122
+ parser.add_argument(
123
+ "--setup",
124
+ action="store_true",
125
+ help="Run interactive BridgeAgent provider/model setup for ACP terminal auth",
126
+ )
127
+ parser.add_argument(
128
+ "--setup-browser",
129
+ action="store_true",
130
+ help="Install agent-browser + Playwright Chromium into ~/.bridgeagent/node/ "
131
+ "for browser tool support. Idempotent.",
132
+ )
133
+ parser.add_argument(
134
+ "--yes",
135
+ "-y",
136
+ action="store_true",
137
+ dest="assume_yes",
138
+ help="Accept all prompts (currently used by --setup-browser to skip the "
139
+ "~400 MB Chromium download confirmation).",
140
+ )
141
+ return parser.parse_args(argv)
142
+
143
+
144
+ def _print_version() -> None:
145
+ from bridge_cli import __version__ as bridge_version
146
+
147
+ print(bridge_version)
148
+
149
+
150
+ def _run_check() -> None:
151
+ import acp # noqa: F401
152
+ from acp_adapter.server import BridgeACPAgent # noqa: F401
153
+
154
+ print("BridgeAgent ACP check OK")
155
+
156
+
157
+ def _run_setup() -> None:
158
+ from bridge_cli.main import main as bridge_main
159
+
160
+ old_argv = sys.argv[:]
161
+ try:
162
+ sys.argv = [old_argv[0] if old_argv else "bridge", "model"]
163
+ bridge_main()
164
+ finally:
165
+ sys.argv = old_argv
166
+
167
+ # Offer browser-tools install as a follow-up. The terminal auth method
168
+ # is the one supported first-run UX for registry installs, so this is
169
+ # the natural moment to ask. Skip silently if stdin isn't a TTY (the
170
+ # answer can't be collected anyway).
171
+ if not sys.stdin.isatty():
172
+ return
173
+ try:
174
+ reply = input(
175
+ "\nInstall browser tools? Downloads agent-browser (npm) and "
176
+ "optionally Playwright Chromium (~400 MB). [y/N] "
177
+ ).strip().lower()
178
+ except (EOFError, KeyboardInterrupt):
179
+ return
180
+ if reply in {"y", "yes"}:
181
+ _run_setup_browser(assume_yes=False)
182
+
183
+
184
+ def _run_setup_browser(assume_yes: bool = False) -> int:
185
+ """Bootstrap agent-browser + Chromium.
186
+
187
+ Routes through dep_ensure -> install.{sh,ps1} --ensure, sharing code
188
+ with ``bridge postinstall`` and the runtime lazy installer.
189
+
190
+ Returns 0 on success, 1 on failure.
191
+ """
192
+ from bridge_cli.dep_ensure import ensure_dependency
193
+
194
+ try:
195
+ node_ok = ensure_dependency("node", interactive=not assume_yes)
196
+ if not node_ok:
197
+ print("Node.js installation failed — cannot proceed with browser tools.",
198
+ file=sys.stderr)
199
+ return 1
200
+
201
+ browser_ok = ensure_dependency("browser", interactive=not assume_yes)
202
+ if not browser_ok:
203
+ print("Browser tools installation failed.", file=sys.stderr)
204
+ return 1
205
+
206
+ return 0
207
+ except OSError as exc:
208
+ print(f"Browser bootstrap failed: {exc}", file=sys.stderr)
209
+ return 1
210
+
211
+
212
+ def main(argv: list[str] | None = None) -> None:
213
+ """Entry point: load env, configure logging, run the ACP agent."""
214
+ args = _parse_args(argv)
215
+ if args.version:
216
+ _print_version()
217
+ return
218
+ if args.check:
219
+ _run_check()
220
+ return
221
+ if args.setup:
222
+ _run_setup()
223
+ return
224
+ if args.setup_browser:
225
+ rc = _run_setup_browser(assume_yes=args.assume_yes)
226
+ if rc != 0:
227
+ sys.exit(rc)
228
+ return
229
+
230
+ _setup_logging()
231
+ _load_env()
232
+
233
+ logger = logging.getLogger(__name__)
234
+ logger.info("Starting BridgeAgent ACP adapter")
235
+
236
+ # Ensure the project root is on sys.path so ``from run_agent import AIAgent`` works
237
+ project_root = str(Path(__file__).resolve().parent.parent)
238
+ if project_root not in sys.path:
239
+ sys.path.insert(0, project_root)
240
+
241
+ import acp
242
+ from .server import BridgeACPAgent
243
+
244
+ # MCP tool discovery from config.yaml — run before asyncio.run() so
245
+ # it's safe to use blocking waits. (ACP also registers per-session
246
+ # MCP servers dynamically via asyncio.to_thread inside the event
247
+ # loop; that path is unaffected.) Moved from model_tools.py module
248
+ # scope to avoid freezing the gateway's loop on lazy import (#16856).
249
+ try:
250
+ from tools.mcp_tool import discover_mcp_tools
251
+ discover_mcp_tools()
252
+ except Exception:
253
+ logger.debug("MCP tool discovery failed at ACP startup", exc_info=True)
254
+
255
+ agent = BridgeACPAgent()
256
+ try:
257
+ asyncio.run(acp.run_agent(agent, use_unstable_protocol=True))
258
+ except KeyboardInterrupt:
259
+ logger.info("Shutting down (KeyboardInterrupt)")
260
+ except Exception:
261
+ logger.exception("ACP agent crashed")
262
+ sys.exit(1)
263
+
264
+
265
+ if __name__ == "__main__":
266
+ main()