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.
- acp_adapter/__init__.py +1 -0
- acp_adapter/__main__.py +5 -0
- acp_adapter/auth.py +85 -0
- acp_adapter/edit_approval.py +286 -0
- acp_adapter/entry.py +266 -0
- acp_adapter/events.py +279 -0
- acp_adapter/permissions.py +168 -0
- acp_adapter/server.py +1952 -0
- acp_adapter/session.py +623 -0
- acp_adapter/tools.py +1291 -0
- agent/__init__.py +8 -0
- agent/account_usage.py +550 -0
- agent/agent_init.py +1739 -0
- agent/agent_runtime_helpers.py +2482 -0
- agent/anthropic_adapter.py +2303 -0
- agent/async_utils.py +68 -0
- agent/auxiliary_client.py +5928 -0
- agent/azure_identity_adapter.py +555 -0
- agent/background_review.py +597 -0
- agent/bedrock_adapter.py +1277 -0
- agent/browser_provider.py +175 -0
- agent/browser_registry.py +192 -0
- agent/chat_completion_helpers.py +2472 -0
- agent/codex_responses_adapter.py +1260 -0
- agent/codex_runtime.py +535 -0
- agent/context_compressor.py +2078 -0
- agent/context_engine.py +226 -0
- agent/context_references.py +518 -0
- agent/conversation_compression.py +785 -0
- agent/conversation_loop.py +4965 -0
- agent/copilot_acp_client.py +686 -0
- agent/credential_persistence.py +174 -0
- agent/credential_pool.py +2183 -0
- agent/credential_sources.py +448 -0
- agent/credits_tracker.py +723 -0
- agent/curator.py +1843 -0
- agent/curator_backup.py +695 -0
- agent/display.py +1033 -0
- agent/error_classifier.py +1319 -0
- agent/file_safety.py +640 -0
- agent/gemini_cloudcode_adapter.py +909 -0
- agent/gemini_native_adapter.py +990 -0
- agent/gemini_schema.py +99 -0
- agent/google_code_assist.py +451 -0
- agent/google_oauth.py +1067 -0
- agent/i18n.py +302 -0
- agent/image_gen_provider.py +324 -0
- agent/image_gen_registry.py +145 -0
- agent/image_routing.py +511 -0
- agent/insights.py +930 -0
- agent/iteration_budget.py +62 -0
- agent/jiter_preload.py +39 -0
- agent/lmstudio_reasoning.py +48 -0
- agent/lsp/__init__.py +106 -0
- agent/lsp/cli.py +299 -0
- agent/lsp/client.py +943 -0
- agent/lsp/eventlog.py +213 -0
- agent/lsp/install.py +400 -0
- agent/lsp/manager.py +639 -0
- agent/lsp/protocol.py +196 -0
- agent/lsp/range_shift.py +149 -0
- agent/lsp/reporter.py +78 -0
- agent/lsp/servers.py +1040 -0
- agent/lsp/workspace.py +223 -0
- agent/manual_compression_feedback.py +49 -0
- agent/markdown_tables.py +309 -0
- agent/memory_manager.py +683 -0
- agent/memory_provider.py +296 -0
- agent/message_sanitization.py +444 -0
- agent/model_metadata.py +1925 -0
- agent/models_dev.py +725 -0
- agent/moonshot_schema.py +231 -0
- agent/nous_rate_guard.py +325 -0
- agent/onboarding.py +193 -0
- agent/plugin_llm.py +1046 -0
- agent/portal_tags.py +64 -0
- agent/process_bootstrap.py +167 -0
- agent/prompt_builder.py +1660 -0
- agent/prompt_caching.py +79 -0
- agent/rate_limit_tracker.py +246 -0
- agent/redact.py +497 -0
- agent/retry_utils.py +57 -0
- agent/runtime_cwd.py +62 -0
- agent/secret_registry.py +223 -0
- agent/secret_sources/__init__.py +13 -0
- agent/secret_sources/bitwarden.py +690 -0
- agent/shell_hooks.py +847 -0
- agent/skill_bundles.py +410 -0
- agent/skill_commands.py +527 -0
- agent/skill_preprocessing.py +139 -0
- agent/skill_utils.py +677 -0
- agent/stream_diag.py +280 -0
- agent/subdirectory_hints.py +270 -0
- agent/system_prompt.py +412 -0
- agent/think_scrubber.py +386 -0
- agent/title_generator.py +171 -0
- agent/tool_dispatch_helpers.py +424 -0
- agent/tool_executor.py +1422 -0
- agent/tool_guardrails.py +475 -0
- agent/tool_result_classification.py +26 -0
- agent/trajectory.py +56 -0
- agent/transcription_provider.py +193 -0
- agent/transcription_registry.py +122 -0
- agent/transports/__init__.py +68 -0
- agent/transports/anthropic.py +189 -0
- agent/transports/base.py +89 -0
- agent/transports/bedrock.py +154 -0
- agent/transports/chat_completions.py +704 -0
- agent/transports/codex.py +359 -0
- agent/transports/codex_app_server.py +399 -0
- agent/transports/codex_app_server_session.py +849 -0
- agent/transports/codex_event_projector.py +312 -0
- agent/transports/hermes_tools_mcp_server.py +233 -0
- agent/transports/types.py +162 -0
- agent/tts_provider.py +274 -0
- agent/tts_registry.py +133 -0
- agent/usage_pricing.py +905 -0
- agent/video_gen_provider.py +299 -0
- agent/video_gen_registry.py +117 -0
- agent/web_search_provider.py +185 -0
- agent/web_search_registry.py +245 -0
- batch_runner.py +1321 -0
- bridge_bootstrap.py +129 -0
- bridge_cli/__init__.py +47 -0
- bridge_cli/_parser.py +397 -0
- bridge_cli/_subprocess_compat.py +234 -0
- bridge_cli/auth.py +7706 -0
- bridge_cli/auth_commands.py +821 -0
- bridge_cli/azure_detect.py +406 -0
- bridge_cli/backup.py +1043 -0
- bridge_cli/banner.py +797 -0
- bridge_cli/browser_connect.py +217 -0
- bridge_cli/build_info.py +51 -0
- bridge_cli/bundles.py +229 -0
- bridge_cli/callbacks.py +242 -0
- bridge_cli/checkpoints.py +244 -0
- bridge_cli/claw.py +809 -0
- bridge_cli/cli_output.py +77 -0
- bridge_cli/clipboard.py +494 -0
- bridge_cli/codex_models.py +206 -0
- bridge_cli/codex_runtime_plugin_migration.py +757 -0
- bridge_cli/codex_runtime_switch.py +266 -0
- bridge_cli/colors.py +38 -0
- bridge_cli/commands.py +1743 -0
- bridge_cli/completion.py +319 -0
- bridge_cli/config.py +6478 -0
- bridge_cli/container_boot.py +395 -0
- bridge_cli/copilot_auth.py +392 -0
- bridge_cli/cron.py +374 -0
- bridge_cli/curator.py +598 -0
- bridge_cli/curses_ui.py +872 -0
- bridge_cli/dashboard_auth/__init__.py +42 -0
- bridge_cli/dashboard_auth/audit.py +87 -0
- bridge_cli/dashboard_auth/base.py +220 -0
- bridge_cli/dashboard_auth/cookies.py +247 -0
- bridge_cli/dashboard_auth/login_page.py +534 -0
- bridge_cli/dashboard_auth/middleware.py +367 -0
- bridge_cli/dashboard_auth/prefix.py +157 -0
- bridge_cli/dashboard_auth/public_paths.py +49 -0
- bridge_cli/dashboard_auth/registry.py +58 -0
- bridge_cli/dashboard_auth/routes.py +621 -0
- bridge_cli/dashboard_auth/ws_tickets.py +161 -0
- bridge_cli/dashboard_register.py +300 -0
- bridge_cli/debug.py +829 -0
- bridge_cli/default_soul.py +11 -0
- bridge_cli/dep_ensure.py +159 -0
- bridge_cli/dingtalk_auth.py +293 -0
- bridge_cli/doctor.py +2183 -0
- bridge_cli/dump.py +349 -0
- bridge_cli/env_loader.py +344 -0
- bridge_cli/fallback_cmd.py +354 -0
- bridge_cli/fallback_config.py +72 -0
- bridge_cli/gateway.py +6755 -0
- bridge_cli/gateway_windows.py +1311 -0
- bridge_cli/goals.py +912 -0
- bridge_cli/gui_uninstall.py +290 -0
- bridge_cli/hooks.py +385 -0
- bridge_cli/inventory.py +410 -0
- bridge_cli/kanban.py +2830 -0
- bridge_cli/kanban_db.py +7659 -0
- bridge_cli/kanban_decompose.py +477 -0
- bridge_cli/kanban_diagnostics.py +1107 -0
- bridge_cli/kanban_specify.py +271 -0
- bridge_cli/kanban_swarm.py +279 -0
- bridge_cli/logs.py +394 -0
- bridge_cli/loop.py +367 -0
- bridge_cli/main.py +16632 -0
- bridge_cli/managed_uv.py +254 -0
- bridge_cli/mcp_catalog.py +775 -0
- bridge_cli/mcp_config.py +1217 -0
- bridge_cli/mcp_picker.py +322 -0
- bridge_cli/mcp_startup.py +59 -0
- bridge_cli/memory_setup.py +472 -0
- bridge_cli/middleware.py +313 -0
- bridge_cli/migrate.py +115 -0
- bridge_cli/model_catalog.py +363 -0
- bridge_cli/model_normalize.py +472 -0
- bridge_cli/model_switch.py +2023 -0
- bridge_cli/models.py +4092 -0
- bridge_cli/nous_account.py +764 -0
- bridge_cli/nous_subscription.py +1121 -0
- bridge_cli/oneshot.py +381 -0
- bridge_cli/pairing.py +115 -0
- bridge_cli/partial_compress.py +235 -0
- bridge_cli/platforms.py +83 -0
- bridge_cli/plugins.py +1946 -0
- bridge_cli/plugins_cmd.py +1691 -0
- bridge_cli/portal_cli.py +245 -0
- bridge_cli/profile_describer.py +298 -0
- bridge_cli/profile_distribution.py +721 -0
- bridge_cli/profiles.py +1664 -0
- bridge_cli/prompt_size.py +153 -0
- bridge_cli/providers.py +731 -0
- bridge_cli/proxy/__init__.py +20 -0
- bridge_cli/proxy/adapters/__init__.py +37 -0
- bridge_cli/proxy/adapters/base.py +108 -0
- bridge_cli/proxy/adapters/nous_portal.py +189 -0
- bridge_cli/proxy/adapters/xai.py +145 -0
- bridge_cli/proxy/cli.py +142 -0
- bridge_cli/proxy/server.py +296 -0
- bridge_cli/psutil_android.py +108 -0
- bridge_cli/pt_input_extras.py +120 -0
- bridge_cli/pty_bridge.py +276 -0
- bridge_cli/relaunch.py +206 -0
- bridge_cli/runtime_provider.py +1694 -0
- bridge_cli/scripts/install.ps1 +3231 -0
- bridge_cli/scripts/install.sh +2913 -0
- bridge_cli/secret_prompt.py +126 -0
- bridge_cli/secrets_cli.py +600 -0
- bridge_cli/security_advisories.py +453 -0
- bridge_cli/security_audit.py +576 -0
- bridge_cli/send_cmd.py +445 -0
- bridge_cli/service_manager.py +937 -0
- bridge_cli/session_recap.py +316 -0
- bridge_cli/setup.py +3361 -0
- bridge_cli/skills_config.py +199 -0
- bridge_cli/skills_hub.py +1913 -0
- bridge_cli/skin_engine.py +926 -0
- bridge_cli/slack_cli.py +159 -0
- bridge_cli/status.py +586 -0
- bridge_cli/stdio.py +256 -0
- bridge_cli/telegram_managed_bot.py +358 -0
- bridge_cli/timeouts.py +82 -0
- bridge_cli/tips.py +486 -0
- bridge_cli/tools_config.py +3933 -0
- bridge_cli/tui_dist/entry.js +74917 -0
- bridge_cli/uninstall.py +934 -0
- bridge_cli/voice.py +846 -0
- bridge_cli/web_dist/assets/Collapse-Bold-mgICk9-_.woff2 +0 -0
- bridge_cli/web_dist/assets/Collapse-Regular-DysayoTY.woff2 +0 -0
- bridge_cli/web_dist/assets/Mondwest-Regular-CWscgue7.woff2 +0 -0
- bridge_cli/web_dist/assets/RulesCompressed-Medium-CA76_CrB.woff2 +0 -0
- bridge_cli/web_dist/assets/RulesCompressed-Regular-BSXFyF4x.woff2 +0 -0
- bridge_cli/web_dist/assets/RulesExpanded-Bold-DZA7s8Pa.woff2 +0 -0
- bridge_cli/web_dist/assets/RulesExpanded-Regular-l8uVympt.woff2 +0 -0
- bridge_cli/web_dist/assets/filler-bg0-DxMaWJpb.webp +0 -0
- bridge_cli/web_dist/assets/index-DHRxol4O.js +170 -0
- bridge_cli/web_dist/assets/index-Drzx8NO1.css +1 -0
- bridge_cli/web_dist/favicon.ico +0 -0
- bridge_cli/web_dist/fonts/Collapse-Bold.woff2 +0 -0
- bridge_cli/web_dist/fonts/Collapse-Regular.woff2 +0 -0
- bridge_cli/web_dist/fonts/Mondwest-Regular.woff2 +0 -0
- bridge_cli/web_dist/fonts/RulesCompressed-Medium.woff2 +0 -0
- bridge_cli/web_dist/fonts/RulesCompressed-Regular.woff2 +0 -0
- bridge_cli/web_dist/fonts/RulesExpanded-Bold.woff2 +0 -0
- bridge_cli/web_dist/fonts/RulesExpanded-Regular.woff2 +0 -0
- bridge_cli/web_dist/fonts-terminal/JetBrainsMono-Bold.woff2 +0 -0
- bridge_cli/web_dist/fonts-terminal/JetBrainsMono-Italic.woff2 +0 -0
- bridge_cli/web_dist/fonts-terminal/JetBrainsMono-Regular.woff2 +0 -0
- bridge_cli/web_dist/index.html +17 -0
- bridge_cli/web_server.py +10028 -0
- bridge_cli/webhook.py +298 -0
- bridge_cli/xai_retirement.py +253 -0
- bridge_constants.py +482 -0
- bridge_logging.py +536 -0
- bridge_state.py +4491 -0
- bridge_time.py +104 -0
- bridgeagent-0.16.0.data/data/locales/af.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/de.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/en.yaml +372 -0
- bridgeagent-0.16.0.data/data/locales/es.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/fr.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/ga.yaml +361 -0
- bridgeagent-0.16.0.data/data/locales/hu.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/it.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/ja.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/ko.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/pt.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/ru.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/tr.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/uk.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/zh-hant.yaml +357 -0
- bridgeagent-0.16.0.data/data/locales/zh.yaml +357 -0
- bridgeagent-0.16.0.dist-info/METADATA +374 -0
- bridgeagent-0.16.0.dist-info/RECORD +709 -0
- bridgeagent-0.16.0.dist-info/WHEEL +5 -0
- bridgeagent-0.16.0.dist-info/entry_points.txt +7 -0
- bridgeagent-0.16.0.dist-info/licenses/LICENSE +25 -0
- bridgeagent-0.16.0.dist-info/top_level.txt +23 -0
- cli.py +16290 -0
- cron/__init__.py +42 -0
- cron/jobs.py +1306 -0
- cron/scheduler.py +2339 -0
- gateway/__init__.py +35 -0
- gateway/assets/telegram-botfather-threads-settings.jpg +0 -0
- gateway/builtin_hooks/__init__.py +1 -0
- gateway/channel_directory.py +357 -0
- gateway/config.py +2004 -0
- gateway/delivery.py +433 -0
- gateway/display_config.py +240 -0
- gateway/hooks.py +210 -0
- gateway/memory_monitor.py +230 -0
- gateway/mirror.py +168 -0
- gateway/pairing.py +450 -0
- gateway/platform_registry.py +260 -0
- gateway/platforms/__init__.py +45 -0
- gateway/platforms/_http_client_limits.py +84 -0
- gateway/platforms/api_server.py +4359 -0
- gateway/platforms/base.py +4818 -0
- gateway/platforms/bluebubbles.py +1038 -0
- gateway/platforms/dingtalk.py +1503 -0
- gateway/platforms/email.py +773 -0
- gateway/platforms/feishu.py +5163 -0
- gateway/platforms/feishu_comment.py +1382 -0
- gateway/platforms/feishu_comment_rules.py +429 -0
- gateway/platforms/feishu_meeting_invite.py +212 -0
- gateway/platforms/helpers.py +278 -0
- gateway/platforms/matrix.py +2983 -0
- gateway/platforms/msgraph_webhook.py +421 -0
- gateway/platforms/qqbot/__init__.py +91 -0
- gateway/platforms/qqbot/adapter.py +3196 -0
- gateway/platforms/qqbot/chunked_upload.py +602 -0
- gateway/platforms/qqbot/constants.py +74 -0
- gateway/platforms/qqbot/crypto.py +45 -0
- gateway/platforms/qqbot/keyboards.py +473 -0
- gateway/platforms/qqbot/onboard.py +220 -0
- gateway/platforms/qqbot/utils.py +74 -0
- gateway/platforms/signal.py +1543 -0
- gateway/platforms/signal_rate_limit.py +369 -0
- gateway/platforms/slack.py +3519 -0
- gateway/platforms/sms.py +379 -0
- gateway/platforms/telegram.py +6081 -0
- gateway/platforms/telegram_network.py +259 -0
- gateway/platforms/webhook.py +934 -0
- gateway/platforms/wecom.py +1635 -0
- gateway/platforms/wecom_callback.py +425 -0
- gateway/platforms/wecom_crypto.py +142 -0
- gateway/platforms/weixin.py +2247 -0
- gateway/platforms/whatsapp.py +1387 -0
- gateway/platforms/yuanbao.py +4941 -0
- gateway/platforms/yuanbao_media.py +645 -0
- gateway/platforms/yuanbao_proto.py +1209 -0
- gateway/platforms/yuanbao_sticker.py +558 -0
- gateway/restart.py +20 -0
- gateway/run.py +20137 -0
- gateway/runtime_footer.py +149 -0
- gateway/session.py +1400 -0
- gateway/session_context.py +194 -0
- gateway/shutdown_forensics.py +462 -0
- gateway/slash_access.py +229 -0
- gateway/status.py +1115 -0
- gateway/sticker_cache.py +124 -0
- gateway/stream_consumer.py +1358 -0
- gateway/stream_dispatch.py +132 -0
- gateway/stream_events.py +171 -0
- gateway/whatsapp_identity.py +155 -0
- mcp_serve.py +897 -0
- model_tools.py +1217 -0
- plugins/__init__.py +1 -0
- plugins/browser/browser_use/__init__.py +14 -0
- plugins/browser/browser_use/plugin.yaml +7 -0
- plugins/browser/browser_use/provider.py +317 -0
- plugins/browser/browserbase/__init__.py +15 -0
- plugins/browser/browserbase/plugin.yaml +7 -0
- plugins/browser/browserbase/provider.py +297 -0
- plugins/browser/firecrawl/__init__.py +16 -0
- plugins/browser/firecrawl/plugin.yaml +7 -0
- plugins/browser/firecrawl/provider.py +168 -0
- plugins/context_engine/__init__.py +285 -0
- plugins/dashboard_auth/basic/__init__.py +491 -0
- plugins/dashboard_auth/basic/plugin.yaml +7 -0
- plugins/dashboard_auth/nous/__init__.py +667 -0
- plugins/dashboard_auth/nous/plugin.yaml +7 -0
- plugins/dashboard_auth/self_hosted/__init__.py +736 -0
- plugins/dashboard_auth/self_hosted/plugin.yaml +8 -0
- plugins/disk-cleanup/README.md +51 -0
- plugins/disk-cleanup/__init__.py +316 -0
- plugins/disk-cleanup/disk_cleanup.py +560 -0
- plugins/disk-cleanup/plugin.yaml +7 -0
- plugins/google_meet/README.md +131 -0
- plugins/google_meet/__init__.py +103 -0
- plugins/google_meet/audio_bridge.py +244 -0
- plugins/google_meet/cli.py +477 -0
- plugins/google_meet/meet_bot.py +852 -0
- plugins/google_meet/node/__init__.py +54 -0
- plugins/google_meet/node/cli.py +125 -0
- plugins/google_meet/node/client.py +107 -0
- plugins/google_meet/node/protocol.py +124 -0
- plugins/google_meet/node/registry.py +112 -0
- plugins/google_meet/node/server.py +200 -0
- plugins/google_meet/plugin.yaml +16 -0
- plugins/google_meet/process_manager.py +323 -0
- plugins/google_meet/realtime/__init__.py +10 -0
- plugins/google_meet/realtime/openai_client.py +332 -0
- plugins/google_meet/tools.py +348 -0
- plugins/hermes-achievements/README.md +150 -0
- plugins/hermes-achievements/dashboard/dist/index.js +726 -0
- plugins/hermes-achievements/dashboard/dist/style.css +146 -0
- plugins/hermes-achievements/dashboard/manifest.json +11 -0
- plugins/hermes-achievements/dashboard/plugin_api.py +1061 -0
- plugins/hermes-achievements/tests/test_achievement_engine.py +156 -0
- plugins/image_gen/fal/__init__.py +182 -0
- plugins/image_gen/fal/plugin.yaml +7 -0
- plugins/image_gen/krea/__init__.py +548 -0
- plugins/image_gen/krea/plugin.yaml +7 -0
- plugins/image_gen/openai/__init__.py +316 -0
- plugins/image_gen/openai/plugin.yaml +7 -0
- plugins/image_gen/openai-codex/__init__.py +442 -0
- plugins/image_gen/openai-codex/plugin.yaml +5 -0
- plugins/image_gen/xai/__init__.py +334 -0
- plugins/image_gen/xai/plugin.yaml +7 -0
- plugins/kanban/dashboard/dist/index.js +3875 -0
- plugins/kanban/dashboard/dist/style.css +1583 -0
- plugins/kanban/dashboard/manifest.json +14 -0
- plugins/kanban/dashboard/plugin_api.py +2454 -0
- plugins/memory/__init__.py +450 -0
- plugins/memory/byterover/README.md +41 -0
- plugins/memory/byterover/__init__.py +383 -0
- plugins/memory/byterover/plugin.yaml +9 -0
- plugins/memory/hindsight/README.md +147 -0
- plugins/memory/hindsight/__init__.py +1777 -0
- plugins/memory/hindsight/plugin.yaml +8 -0
- plugins/memory/holographic/README.md +36 -0
- plugins/memory/holographic/__init__.py +408 -0
- plugins/memory/holographic/holographic.py +203 -0
- plugins/memory/holographic/plugin.yaml +5 -0
- plugins/memory/holographic/retrieval.py +593 -0
- plugins/memory/holographic/store.py +578 -0
- plugins/memory/honcho/README.md +368 -0
- plugins/memory/honcho/__init__.py +1419 -0
- plugins/memory/honcho/cli.py +1685 -0
- plugins/memory/honcho/client.py +872 -0
- plugins/memory/honcho/plugin.yaml +7 -0
- plugins/memory/honcho/session.py +1341 -0
- plugins/memory/mem0/README.md +38 -0
- plugins/memory/mem0/__init__.py +374 -0
- plugins/memory/mem0/plugin.yaml +5 -0
- plugins/memory/openviking/README.md +40 -0
- plugins/memory/openviking/__init__.py +978 -0
- plugins/memory/openviking/plugin.yaml +9 -0
- plugins/memory/retaindb/README.md +40 -0
- plugins/memory/retaindb/__init__.py +766 -0
- plugins/memory/retaindb/plugin.yaml +7 -0
- plugins/memory/supermemory/README.md +111 -0
- plugins/memory/supermemory/__init__.py +897 -0
- plugins/memory/supermemory/plugin.yaml +5 -0
- plugins/model-providers/README.md +70 -0
- plugins/model-providers/alibaba/__init__.py +13 -0
- plugins/model-providers/alibaba/plugin.yaml +5 -0
- plugins/model-providers/alibaba-coding-plan/__init__.py +21 -0
- plugins/model-providers/alibaba-coding-plan/plugin.yaml +5 -0
- plugins/model-providers/anthropic/__init__.py +52 -0
- plugins/model-providers/anthropic/plugin.yaml +5 -0
- plugins/model-providers/arcee/__init__.py +13 -0
- plugins/model-providers/arcee/plugin.yaml +5 -0
- plugins/model-providers/azure-foundry/__init__.py +21 -0
- plugins/model-providers/azure-foundry/plugin.yaml +5 -0
- plugins/model-providers/bedrock/__init__.py +29 -0
- plugins/model-providers/bedrock/plugin.yaml +5 -0
- plugins/model-providers/copilot/__init__.py +58 -0
- plugins/model-providers/copilot/plugin.yaml +5 -0
- plugins/model-providers/copilot-acp/__init__.py +34 -0
- plugins/model-providers/copilot-acp/plugin.yaml +5 -0
- plugins/model-providers/custom/__init__.py +68 -0
- plugins/model-providers/custom/plugin.yaml +5 -0
- plugins/model-providers/deepseek/__init__.py +100 -0
- plugins/model-providers/deepseek/plugin.yaml +5 -0
- plugins/model-providers/gemini/__init__.py +72 -0
- plugins/model-providers/gemini/plugin.yaml +5 -0
- plugins/model-providers/gmi/__init__.py +31 -0
- plugins/model-providers/gmi/plugin.yaml +5 -0
- plugins/model-providers/huggingface/__init__.py +20 -0
- plugins/model-providers/huggingface/plugin.yaml +5 -0
- plugins/model-providers/kilocode/__init__.py +14 -0
- plugins/model-providers/kilocode/plugin.yaml +5 -0
- plugins/model-providers/kimi-coding/__init__.py +80 -0
- plugins/model-providers/kimi-coding/plugin.yaml +5 -0
- plugins/model-providers/minimax/__init__.py +45 -0
- plugins/model-providers/minimax/plugin.yaml +5 -0
- plugins/model-providers/nous/__init__.py +54 -0
- plugins/model-providers/nous/plugin.yaml +5 -0
- plugins/model-providers/novita/__init__.py +27 -0
- plugins/model-providers/novita/plugin.yaml +5 -0
- plugins/model-providers/nvidia/__init__.py +21 -0
- plugins/model-providers/nvidia/plugin.yaml +5 -0
- plugins/model-providers/ollama-cloud/__init__.py +14 -0
- plugins/model-providers/ollama-cloud/plugin.yaml +5 -0
- plugins/model-providers/openai-codex/__init__.py +15 -0
- plugins/model-providers/openai-codex/plugin.yaml +5 -0
- plugins/model-providers/opencode-zen/__init__.py +126 -0
- plugins/model-providers/opencode-zen/plugin.yaml +5 -0
- plugins/model-providers/openrouter/__init__.py +117 -0
- plugins/model-providers/openrouter/plugin.yaml +5 -0
- plugins/model-providers/qwen-oauth/__init__.py +82 -0
- plugins/model-providers/qwen-oauth/plugin.yaml +5 -0
- plugins/model-providers/stepfun/__init__.py +14 -0
- plugins/model-providers/stepfun/plugin.yaml +5 -0
- plugins/model-providers/xai/__init__.py +15 -0
- plugins/model-providers/xai/plugin.yaml +5 -0
- plugins/model-providers/xiaomi/__init__.py +15 -0
- plugins/model-providers/xiaomi/plugin.yaml +5 -0
- plugins/model-providers/zai/__init__.py +21 -0
- plugins/model-providers/zai/plugin.yaml +5 -0
- plugins/observability/langfuse/README.md +53 -0
- plugins/observability/langfuse/__init__.py +1004 -0
- plugins/observability/langfuse/plugin.yaml +14 -0
- plugins/observability/nemo_relay/README.md +553 -0
- plugins/observability/nemo_relay/__init__.py +836 -0
- plugins/observability/nemo_relay/plugin.yaml +20 -0
- plugins/platforms/discord/__init__.py +3 -0
- plugins/platforms/discord/adapter.py +6520 -0
- plugins/platforms/discord/plugin.yaml +34 -0
- plugins/platforms/discord/voice_mixer.py +378 -0
- plugins/platforms/google_chat/__init__.py +3 -0
- plugins/platforms/google_chat/adapter.py +3342 -0
- plugins/platforms/google_chat/oauth.py +667 -0
- plugins/platforms/google_chat/plugin.yaml +39 -0
- plugins/platforms/homeassistant/__init__.py +3 -0
- plugins/platforms/homeassistant/adapter.py +577 -0
- plugins/platforms/homeassistant/plugin.yaml +22 -0
- plugins/platforms/irc/__init__.py +3 -0
- plugins/platforms/irc/adapter.py +968 -0
- plugins/platforms/irc/plugin.yaml +54 -0
- plugins/platforms/line/__init__.py +3 -0
- plugins/platforms/line/adapter.py +1652 -0
- plugins/platforms/line/plugin.yaml +65 -0
- plugins/platforms/mattermost/__init__.py +3 -0
- plugins/platforms/mattermost/adapter.py +1192 -0
- plugins/platforms/mattermost/plugin.yaml +49 -0
- plugins/platforms/ntfy/__init__.py +3 -0
- plugins/platforms/ntfy/adapter.py +593 -0
- plugins/platforms/ntfy/plugin.yaml +56 -0
- plugins/platforms/simplex/__init__.py +3 -0
- plugins/platforms/simplex/adapter.py +760 -0
- plugins/platforms/simplex/plugin.yaml +37 -0
- plugins/platforms/teams/__init__.py +3 -0
- plugins/platforms/teams/adapter.py +1197 -0
- plugins/platforms/teams/plugin.yaml +48 -0
- plugins/security-guidance/README.md +88 -0
- plugins/security-guidance/__init__.py +259 -0
- plugins/security-guidance/patterns.py +368 -0
- plugins/security-guidance/plugin.yaml +7 -0
- plugins/spotify/__init__.py +66 -0
- plugins/spotify/client.py +435 -0
- plugins/spotify/plugin.yaml +13 -0
- plugins/spotify/tools.py +454 -0
- plugins/teams_pipeline/__init__.py +23 -0
- plugins/teams_pipeline/cli.py +461 -0
- plugins/teams_pipeline/meetings.py +333 -0
- plugins/teams_pipeline/models.py +350 -0
- plugins/teams_pipeline/pipeline.py +689 -0
- plugins/teams_pipeline/plugin.yaml +9 -0
- plugins/teams_pipeline/runtime.py +135 -0
- plugins/teams_pipeline/store.py +193 -0
- plugins/teams_pipeline/subscriptions.py +249 -0
- plugins/video_gen/fal/__init__.py +613 -0
- plugins/video_gen/fal/plugin.yaml +7 -0
- plugins/video_gen/xai/__init__.py +504 -0
- plugins/video_gen/xai/plugin.yaml +7 -0
- plugins/web/__init__.py +7 -0
- plugins/web/brave_free/__init__.py +14 -0
- plugins/web/brave_free/plugin.yaml +7 -0
- plugins/web/brave_free/provider.py +137 -0
- plugins/web/ddgs/__init__.py +15 -0
- plugins/web/ddgs/plugin.yaml +7 -0
- plugins/web/ddgs/provider.py +104 -0
- plugins/web/exa/__init__.py +15 -0
- plugins/web/exa/plugin.yaml +7 -0
- plugins/web/exa/provider.py +212 -0
- plugins/web/firecrawl/__init__.py +28 -0
- plugins/web/firecrawl/plugin.yaml +7 -0
- plugins/web/firecrawl/provider.py +594 -0
- plugins/web/parallel/__init__.py +16 -0
- plugins/web/parallel/plugin.yaml +7 -0
- plugins/web/parallel/provider.py +291 -0
- plugins/web/searxng/__init__.py +15 -0
- plugins/web/searxng/plugin.yaml +7 -0
- plugins/web/searxng/provider.py +140 -0
- plugins/web/tavily/__init__.py +10 -0
- plugins/web/tavily/plugin.yaml +7 -0
- plugins/web/tavily/provider.py +220 -0
- plugins/web/xai/__init__.py +14 -0
- plugins/web/xai/plugin.yaml +7 -0
- plugins/web/xai/provider.py +557 -0
- providers/__init__.py +191 -0
- providers/base.py +208 -0
- run_agent.py +5307 -0
- tools/__init__.py +25 -0
- tools/ansi_strip.py +44 -0
- tools/approval.py +1793 -0
- tools/binary_extensions.py +42 -0
- tools/browser_camofox.py +794 -0
- tools/browser_camofox_state.py +49 -0
- tools/browser_cdp_tool.py +569 -0
- tools/browser_dialog_tool.py +148 -0
- tools/browser_supervisor.py +1475 -0
- tools/browser_tool.py +3863 -0
- tools/budget_config.py +51 -0
- tools/checkpoint_manager.py +1669 -0
- tools/clarify_gateway.py +278 -0
- tools/clarify_tool.py +141 -0
- tools/code_execution_tool.py +1831 -0
- tools/computer_use/__init__.py +43 -0
- tools/computer_use/backend.py +158 -0
- tools/computer_use/cua_backend.py +779 -0
- tools/computer_use/schema.py +213 -0
- tools/computer_use/tool.py +750 -0
- tools/computer_use/vision_routing.py +204 -0
- tools/computer_use_tool.py +39 -0
- tools/credential_files.py +454 -0
- tools/cronjob_tools.py +919 -0
- tools/debug_helpers.py +105 -0
- tools/delegate_tool.py +2860 -0
- tools/discord_tool.py +959 -0
- tools/env_passthrough.py +163 -0
- tools/env_probe.py +247 -0
- tools/environments/__init__.py +14 -0
- tools/environments/base.py +895 -0
- tools/environments/daytona.py +270 -0
- tools/environments/docker.py +1326 -0
- tools/environments/file_sync.py +403 -0
- tools/environments/local.py +697 -0
- tools/environments/managed_modal.py +282 -0
- tools/environments/modal.py +478 -0
- tools/environments/modal_utils.py +204 -0
- tools/environments/singularity.py +262 -0
- tools/environments/ssh.py +375 -0
- tools/fal_common.py +163 -0
- tools/feishu_doc_tool.py +138 -0
- tools/feishu_drive_tool.py +431 -0
- tools/file_operations.py +2292 -0
- tools/file_state.py +332 -0
- tools/file_tools.py +1533 -0
- tools/fuzzy_match.py +860 -0
- tools/homeassistant_tool.py +513 -0
- tools/image_generation_tool.py +1180 -0
- tools/interrupt.py +98 -0
- tools/kanban_tools.py +1431 -0
- tools/lazy_deps.py +639 -0
- tools/loop_tools.py +302 -0
- tools/managed_tool_gateway.py +192 -0
- tools/mcp_oauth.py +776 -0
- tools/mcp_oauth_manager.py +607 -0
- tools/mcp_tool.py +3915 -0
- tools/memory_tool.py +723 -0
- tools/microsoft_graph_auth.py +245 -0
- tools/microsoft_graph_client.py +408 -0
- tools/mixture_of_agents_tool.py +542 -0
- tools/neutts_synth.py +104 -0
- tools/openrouter_client.py +33 -0
- tools/osv_check.py +169 -0
- tools/patch_parser.py +622 -0
- tools/path_security.py +43 -0
- tools/process_registry.py +1616 -0
- tools/registry.py +589 -0
- tools/schema_sanitizer.py +445 -0
- tools/send_message_tool.py +1787 -0
- tools/session_search_tool.py +783 -0
- tools/skill_manager_tool.py +1043 -0
- tools/skill_provenance.py +78 -0
- tools/skill_usage.py +852 -0
- tools/skills_ast_audit.py +133 -0
- tools/skills_guard.py +1086 -0
- tools/skills_hub.py +3756 -0
- tools/skills_sync.py +897 -0
- tools/skills_tool.py +1604 -0
- tools/slash_confirm.py +167 -0
- tools/terminal_tool.py +2612 -0
- tools/thread_context.py +120 -0
- tools/threat_patterns.py +252 -0
- tools/tirith_security.py +820 -0
- tools/todo_tool.py +277 -0
- tools/tool_backend_helpers.py +182 -0
- tools/tool_output_limits.py +110 -0
- tools/tool_result_storage.py +232 -0
- tools/tool_search.py +735 -0
- tools/transcription_tools.py +1797 -0
- tools/tts_tool.py +2551 -0
- tools/url_safety.py +361 -0
- tools/video_generation_tool.py +562 -0
- tools/vision_tools.py +1591 -0
- tools/voice_mode.py +1217 -0
- tools/web_tools.py +1347 -0
- tools/website_policy.py +282 -0
- tools/x_search_tool.py +525 -0
- tools/xai_http.py +128 -0
- tools/yuanbao_tools.py +737 -0
- toolset_distributions.py +364 -0
- toolsets.py +916 -0
- trajectory_compressor.py +1579 -0
- tui_gateway/__init__.py +0 -0
- tui_gateway/entry.py +298 -0
- tui_gateway/event_publisher.py +126 -0
- tui_gateway/render.py +49 -0
- tui_gateway/server.py +8522 -0
- tui_gateway/slash_worker.py +76 -0
- tui_gateway/transport.py +219 -0
- tui_gateway/ws.py +327 -0
- utils.py +376 -0
acp_adapter/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""ACP (Agent Communication Protocol) adapter for BridgeAgent."""
|
acp_adapter/__main__.py
ADDED
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()
|