coderouter-cli 2.7.9__tar.gz → 2.7.10__tar.gz
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.
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/CHANGELOG.md +95 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/PKG-INFO +1 -1
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/adapters/agent_cli.py +248 -57
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/config/schemas.py +38 -12
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/external-agents.en.md +136 -14
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/external-agents.md +136 -14
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/designs/external-agents-adapter.md +24 -1
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers-agent-cli.yaml +105 -43
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/pyproject.toml +1 -1
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_agent_cli.py +282 -13
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/.gitignore +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/LICENSE +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/README.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/README.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/__main__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/adapters/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/adapters/anthropic_native.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/adapters/base.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/adapters/openai_compat.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/adapters/registry.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/cli.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/cli_stats.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/config/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/config/capability_registry.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/config/env_file.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/config/loader.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/cost.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/data/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/data/model-capabilities.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/doctor.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/doctor_apply.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/env_security.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/errors.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/gguf_introspect.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/_fingerprint.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/backend_health.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/context_budget.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/continuous_probe.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/drift_actions.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/drift_detection.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/memory_budget.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/memory_pressure.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/self_healing.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/guards/tool_loop.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/hardware.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/anthropic_routes.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/app.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/dashboard_routes.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/launcher_routes.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/metrics_routes.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/ingress/openai_routes.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/language_tax.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/launcher_speculative.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/logging.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/metrics/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/metrics/collector.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/metrics/prometheus.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/output_filters.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/plugins/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/plugins/base.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/plugins/loader.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/plugins/registry.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/routing/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/routing/adaptive.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/routing/auto_router.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/routing/budget.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/routing/capability.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/routing/fallback.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/state/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/state/audit_log.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/state/replay.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/state/request_log.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/state/store.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/state/suggest_rules.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/token_estimation.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/token_estimation_accurate.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/translation/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/translation/anthropic.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/translation/convert.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/coderouter/translation/tool_repair.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/README.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/README.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/assets/dashboard-demo.png +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/claude-code-llamacpp-vllm.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/claude-code-llamacpp-vllm.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/gguf_dl.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/gguf_dl.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/hf-ollama-models.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/hf-ollama-models.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/install-backends.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/install-backends.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/launcher-quickstart.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/launcher-quickstart.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/launcher.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/launcher.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/llamacpp-direct.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/llamacpp-direct.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/lmstudio-direct.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/lmstudio-direct.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/backends/verify-ollama-0.23.1.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/architecture.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/architecture.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/context-budget.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/context-budget.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/continuous-probing.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/continuous-probing.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/drift-detection.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/drift-detection.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/partial-stitch.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/concepts/partial-stitch.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/designs/v1.5-dashboard-mockup.html +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/designs/v1.6-auto-router-verification.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/designs/v1.6-auto-router.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/free-tier-guide.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/free-tier-guide.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/language-tax.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/language-tax.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/remote-access.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/remote-access.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/security.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/security.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/troubleshooting.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/troubleshooting.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/usage-guide.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/guides/usage-guide.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/low-memory-integration.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/low-memory-integration.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/openrouter-roster/CHANGES.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/openrouter-roster/README.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/openrouter-roster/latest.json +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v0.4.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v0.5-verify.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v0.5.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v0.6.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v0.7.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v1.0-verify.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/retrospectives/v1.0.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/start/quickstart.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/start/quickstart.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/start/when-do-i-need-coderouter.en.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/docs/start/when-do-i-need-coderouter.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/.env.example +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/README.md +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers-multiagent.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.context-budget-test.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.llamacpp-vllm.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.nvidia-nim.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.ollama-auto-custom.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.ollama-auto.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.ollama-free-chain.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.raspberrypi.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/examples/providers.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/demo_traffic.sh +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/openrouter_roster_diff.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/smoke_v2_2.sh +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/verify-providers.yaml +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/verify_ollama_0_23.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/verify_v0_5.sh +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/scripts/verify_v1_0.sh +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/__init__.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/conftest.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_adapter_anthropic.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_audit_log.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_auto_router.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_auto_router_cjk.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_backend_health.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_budget.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_capability.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_capability_degraded_payload.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_capability_registry.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_capability_registry_cache_control.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_capability_tool_choice.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_claude_code_suitability.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_cli.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_cli_bind_warning.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_cli_stats.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_config.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_config_shim_actions.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_context_budget.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_continuous_probe.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_dashboard_endpoint.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_doctor.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_doctor_apply.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_doctor_cache_probe.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_drift_actions.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_drift_detection.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_drift_detection_integration.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_env_file.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_env_security.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_errors.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_examples_yaml.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_anthropic.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_cache_control.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_cache_observed.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_cache_strip.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_empty_response.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_misconfig_warn.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_paid_gate.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_thinking.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fallback_tool_choice_emulate.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_h1_prometheus_drift.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_h2_h6_translation.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_h3_client_reuse.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_h4_h5_guards.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_h7_probe_restore.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_h8_launcher_auth.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_mA_routing.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_mB_adapters.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_mC_convert.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_mD_logging_metrics.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_mE_config_validation.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_fix_mF_ingress.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_gguf_introspect.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_guards_tool_loop.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_hardware.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_ingress_anthropic.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_ingress_count_tokens.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_ingress_profile.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_language_tax.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_language_tax_integration.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_launcher_mtp.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_launcher_mtp_fallback.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_launcher_provider_sync.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_memory_budget.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_memory_pressure.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_cache.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_collector.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_cost.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_endpoint.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_jsonl.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_prometheus.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_metrics_prometheus_cache.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_models_passthrough.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_openai_compat.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_openrouter_roster_diff.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_output_filters.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_output_filters_adapters.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_partial_stitch.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_plugins_integration.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_plugins_loader.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_plugins_registry.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_reasoning_strip.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_repair_byte_fallback.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_request_log.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_role_normalization.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_routing_adaptive.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_self_healing.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_setup_sh.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_state_store.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_token_estimation.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_token_estimation_accurate.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_tokens_saved_metric.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_tool_repair.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_tool_repair_lenient.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_tool_repair_r4.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_toolrepair_bench.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_translation_anthropic.py +0 -0
- {coderouter_cli-2.7.9 → coderouter_cli-2.7.10}/tests/test_translation_reverse.py +0 -0
|
@@ -9,6 +9,101 @@ are kept verbatim where the Japanese text itself is the subject).
|
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
+
## [v2.7.10] — 2026-07-11 (agent_cli Phase 1c: antigravity — Phase 1 complete)
|
|
13
|
+
|
|
14
|
+
Completes agent_cli Phase 1: `agent: antigravity` (the Google Antigravity
|
|
15
|
+
CLI, command `agy`) is now implemented, joining `claude` (1a), `codex`
|
|
16
|
+
(1b), and `grok` (1d) — all four Phase 1 backends are now in place. This
|
|
17
|
+
target replaces the originally-planned `gemini`: on the author's Mac, the
|
|
18
|
+
legacy Gemini CLI (`@google/gemini-cli` 0.50.x) now fails individual-account
|
|
19
|
+
OAuth outright with a verified `IneligibleTierError: This client is no
|
|
20
|
+
longer supported for Gemini Code Assist for individuals. To continue using
|
|
21
|
+
Gemini, please migrate to the Antigravity suite of products:
|
|
22
|
+
https://antigravity.google` (`reasonCode: UNSUPPORTED_CLIENT`,
|
|
23
|
+
`tierId: free-tier`) — Google discontinued Gemini CLI for individual
|
|
24
|
+
accounts on 2026-06-18. The same legacy CLI also still hits the
|
|
25
|
+
trusted-directory gate with exit 55 (`--skip-trust` /
|
|
26
|
+
`GEMINI_CLI_TRUST_WORKSPACE=true`), a pre-existing constraint unrelated to
|
|
27
|
+
the discontinuation. Google's stated successor is the Antigravity CLI
|
|
28
|
+
(`agy`) — a separate Go rewrite, not a fork of gemini-cli — which keeps
|
|
29
|
+
individual Google-account OAuth alive, including the free tier. Verified
|
|
30
|
+
against agy **1.1.1** (author's Mac, 2026-07-11), its flag surface differs
|
|
31
|
+
meaningfully from gemini-cli's: no `--output-format json` (plain-text
|
|
32
|
+
output only), `--mode plan|accept-edits` instead of an approval-mode flag,
|
|
33
|
+
a `--dangerously-skip-permissions` full-bypass flag, a CLI-side
|
|
34
|
+
`--print-timeout` (the first agent_cli target with its own timeout), no
|
|
35
|
+
`--max-turns`, and no stdin channel for the prompt at all — piping stdin to
|
|
36
|
+
`agy` hangs (field-verified). `agent: gemini` remains schema-declared but
|
|
37
|
+
is now rejected with a migration-pointer message instead of a generic
|
|
38
|
+
not-implemented one.
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- **`agent: antigravity` builder/parser in `AgentCliAdapter`**
|
|
43
|
+
(`coderouter/adapters/agent_cli.py`) — invokes the Antigravity CLI
|
|
44
|
+
one-shot as `agy -p <prompt> --model <model> --mode plan --print-timeout
|
|
45
|
+
<exec_timeout_s>s` (read_only default). The prompt rides on argv as the
|
|
46
|
+
value of `-p` — agy has no `--prompt-file` equivalent and hangs if stdin
|
|
47
|
+
is piped (field-verified), so this is the fourth prompt-delivery pattern
|
|
48
|
+
among the four backends (claude/codex use stdin, grok uses
|
|
49
|
+
`--prompt-file`, antigravity uses argv). Documented limitation: Linux's
|
|
50
|
+
`MAX_ARG_STRLEN` (~128KiB) caps prompt size, and the prompt is visible in
|
|
51
|
+
`ps` output — there is no way around this with agy's current flag
|
|
52
|
+
surface. Output is plain text: stdout is decoded UTF-8, defensively
|
|
53
|
+
stripped of ANSI escapes, and trimmed; an empty result raises a
|
|
54
|
+
retryable `AdapterError`. There is no `--output-format json`, so token
|
|
55
|
+
usage, session id, and structured errors are all unavailable — usage is
|
|
56
|
+
reported as all zeros (same treatment as grok), and
|
|
57
|
+
`coderouter_session_id` is never populated.
|
|
58
|
+
- **`sandbox_mode` → antigravity flag mapping** — `read_only` →
|
|
59
|
+
`--mode plan`; `edit` → `--mode accept-edits`; `full_auto` →
|
|
60
|
+
`--mode accept-edits --dangerously-skip-permissions`. As with the other
|
|
61
|
+
three backends, the effective mode is clamped to read-only whenever
|
|
62
|
+
`allow_file_writes=false`.
|
|
63
|
+
- **`--print-timeout` as a CLI-side first wall** — generated from
|
|
64
|
+
`AgentCliConfig.exec_timeout_s` (e.g. `exec_timeout_s=600` →
|
|
65
|
+
`--print-timeout 600s`), letting agy self-terminate before the outer
|
|
66
|
+
`asyncio.wait_for` + process-group `SIGKILL` fires. antigravity is the
|
|
67
|
+
only agent_cli target with a double timeout wall.
|
|
68
|
+
- **`max_turns` ignored for antigravity** — agy has no
|
|
69
|
+
`--max-turns`-equivalent flag; `AgentCliConfig.max_turns` has no effect
|
|
70
|
+
when `agent: antigravity`, same as codex.
|
|
71
|
+
- **`command` defaults to `"agy"`** — the only agent_cli target whose
|
|
72
|
+
default executable name differs from the `agent` field value (the binary
|
|
73
|
+
is named for the CLI, not the product).
|
|
74
|
+
- **5th `Literal` value on `AgentCliConfig.agent`** — `"antigravity"` joins
|
|
75
|
+
`claude`/`codex`/`gemini`/`grok`.
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- **`agent: gemini` now rejected with a migration message** instead of the
|
|
80
|
+
generic "not implemented yet" wording — constructing the adapter with
|
|
81
|
+
`agent: gemini` now raises `AdapterError: Google discontinued Gemini CLI
|
|
82
|
+
for individual accounts (June 2026). Use agent='antigravity' instead.`
|
|
83
|
+
(`retryable=False`).
|
|
84
|
+
- **Schema docstrings** (`coderouter/config/schemas.py`) — `AgentCliConfig`
|
|
85
|
+
field descriptions updated for the four-backend reality
|
|
86
|
+
(claude/codex/antigravity/grok implemented, gemini rejected), including
|
|
87
|
+
the `command` and `max_turns` docstrings noting antigravity's `agy`
|
|
88
|
+
default and ignored `max_turns`.
|
|
89
|
+
- **Docs & examples** — `docs/backends/external-agents.md`/`.en.md` gain a
|
|
90
|
+
full antigravity section (config example, adapter argv, the
|
|
91
|
+
argv-vs-stdin-vs-`--prompt-file` prompt-delivery comparison across all
|
|
92
|
+
four backends, mode mapping table, plain-text parsing and zero usage,
|
|
93
|
+
the `--print-timeout` double wall, OAuth setup with the `agy models`
|
|
94
|
+
smoke check, the display-string model-name caveat including that Claude
|
|
95
|
+
models are reachable through agy, the stdin-pipe-hang warning, and the
|
|
96
|
+
version-pin caveat) and lead with the gemini-discontinuation story
|
|
97
|
+
(updated implementation-status wording: Phase 1 complete, all four
|
|
98
|
+
backends). The design doc `docs/designs/external-agents-adapter.md` gets
|
|
99
|
+
a new appendix §11.5 recording the gemini-to-antigravity delta (body
|
|
100
|
+
text left as the historical record); its header status line now reads
|
|
101
|
+
Phase 1 (1a/1b/1c/1d) complete. `examples/providers-agent-cli.yaml`
|
|
102
|
+
replaces the Phase 1c gemini preview block with a documented (still
|
|
103
|
+
commented-out) antigravity block, with the now-empty
|
|
104
|
+
"unimplemented preview" framing removed since nothing remains
|
|
105
|
+
unimplemented.
|
|
106
|
+
|
|
12
107
|
## [v2.7.9] — 2026-07-11 (agent_cli Phase 1b: codex)
|
|
13
108
|
|
|
14
109
|
Adds the third target to the `agent_cli` adapter: `agent: codex` (the OpenAI
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: coderouter-cli
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.10
|
|
4
4
|
Summary: Local-first, free-first, fallback-built-in LLM router. Claude Code / OpenAI compatible.
|
|
5
5
|
Project-URL: Homepage, https://github.com/zephel01/CodeRouter
|
|
6
6
|
Project-URL: Repository, https://github.com/zephel01/CodeRouter
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""External coding-agent CLI adapter (``kind="agent_cli"``).
|
|
2
2
|
|
|
3
3
|
This adapter invokes an external coding-agent CLI (Claude Code / Codex /
|
|
4
|
-
|
|
5
|
-
answer as one ``prompt in → text out`` transformation. It is the
|
|
6
|
-
implementation of the external-agents-adapter design
|
|
4
|
+
Antigravity / Grok) as a single one-shot ``exec`` and returns the agent's
|
|
5
|
+
final answer as one ``prompt in → text out`` transformation. It is the
|
|
6
|
+
in-core implementation of the external-agents-adapter design
|
|
7
7
|
(``docs/designs/external-agents-adapter.md``).
|
|
8
8
|
|
|
9
9
|
Design in one paragraph
|
|
@@ -18,10 +18,10 @@ CodeRouter merely performs the one conversion. Following the
|
|
|
18
18
|
``openai_compat`` precedent, a *single* adapter class fronts *multiple*
|
|
19
19
|
target agents, dispatched on the ``agent`` field.
|
|
20
20
|
|
|
21
|
-
Implemented agents (Phase 1a + 1b + 1d)
|
|
22
|
-
|
|
21
|
+
Implemented agents (Phase 1 complete: 1a + 1b + 1c + 1d)
|
|
22
|
+
==========================================================
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Four targets are implemented here:
|
|
25
25
|
|
|
26
26
|
* ``claude`` (Claude Code CLI, Phase 1a) — the most stable CLI, the most
|
|
27
27
|
fine-grained safety controls, and the only one that emits
|
|
@@ -42,22 +42,44 @@ Three targets are implemented here:
|
|
|
42
42
|
``ProviderConfig.cost``, design §5.1.6). ``--no-memory`` is always passed
|
|
43
43
|
so a user-level cross-session memory setting cannot leak state between
|
|
44
44
|
requests.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
* ``antigravity`` (Antigravity CLI, command ``agy``, Phase 1c, in lieu of
|
|
46
|
+
``gemini``) — headless one-shot via ``agy -p <prompt> --mode ...``.
|
|
47
|
+
Google discontinued the legacy Gemini CLI's OAuth for individual
|
|
48
|
+
accounts in June 2026 (field-verified ``IneligibleTierError`` /
|
|
49
|
+
``UNSUPPORTED_CLIENT``); its successor, the Antigravity CLI, is a
|
|
50
|
+
separate Go implementation (not a gemini-cli fork) fulfilling the design's
|
|
51
|
+
"gemini" slot. It has no stdin or ``--prompt-file`` channel — piped stdin
|
|
52
|
+
hangs the CLI (field-verified on agy 1.1.1) — so the prompt rides argv
|
|
53
|
+
(see the security note below). Output is plain text with no
|
|
54
|
+
``--output-format`` flag, no token/cost figures, and no session id, so
|
|
55
|
+
usage is reported as zeros and meta is empty, mirroring grok's rationale.
|
|
56
|
+
It is also the only agent with a CLI-side self-termination flag
|
|
57
|
+
(``--print-timeout``), layered *underneath* the adapter's own
|
|
58
|
+
``asyncio.wait_for`` + PGID SIGKILL rather than replacing it.
|
|
59
|
+
|
|
60
|
+
``gemini`` itself is declared in the config schema for backward-compatible
|
|
61
|
+
config parsing, but constructing an adapter for it raises a clear
|
|
62
|
+
``AdapterError`` with a migration pointer to ``agent="antigravity"``.
|
|
49
63
|
|
|
50
64
|
Security (design §6, non-negotiable)
|
|
51
65
|
====================================
|
|
52
66
|
|
|
53
67
|
* **allowlist argv only** — the child is launched with
|
|
54
68
|
:func:`asyncio.create_subprocess_exec` and a list argv. ``shell=True`` is
|
|
55
|
-
never used
|
|
56
|
-
and codex read it from stdin
|
|
57
|
-
sentinel making that explicit; grok reads it from a
|
|
58
|
-
prompt file inside the resolved workdir
|
|
59
|
-
as an argv value, and argv would both hit Linux's
|
|
60
|
-
``MAX_ARG_STRLEN`` on huge prompts and leak the text into ``ps``
|
|
69
|
+
never used. Prompt delivery is one of three mechanisms depending on the
|
|
70
|
+
agent: claude and codex read it from stdin (codex's argv carries a
|
|
71
|
+
trailing ``-`` sentinel making that explicit); grok reads it from a
|
|
72
|
+
private ``0600`` prompt file inside the resolved workdir (its ``-p``
|
|
73
|
+
requires the prompt as an argv value, and argv would both hit Linux's
|
|
74
|
+
~128KiB ``MAX_ARG_STRLEN`` on huge prompts and leak the text into ``ps``
|
|
75
|
+
output); antigravity has neither a stdin nor a ``--prompt-file`` channel
|
|
76
|
+
(piped stdin hangs the CLI, field-verified), so its prompt is carried on
|
|
77
|
+
argv — accepting the same ``MAX_ARG_STRLEN`` cap and local ``ps``
|
|
78
|
+
visibility that grok's file delivery was specifically designed to avoid.
|
|
79
|
+
No shell is involved in any case (list argv, never shell text), and the
|
|
80
|
+
documented threat model (an isolated, single-operator workstation) treats
|
|
81
|
+
local ``ps`` visibility as an accepted, documented limitation for
|
|
82
|
+
antigravity rather than a defect.
|
|
61
83
|
* **default read-only** — ``allow_file_writes=False`` /
|
|
62
84
|
``sandbox_mode="read_only"`` are the defaults, mapped to claude's
|
|
63
85
|
``--permission-mode plan``. Writes require explicit opt-in and the sandbox
|
|
@@ -82,6 +104,7 @@ import asyncio
|
|
|
82
104
|
import contextlib
|
|
83
105
|
import json
|
|
84
106
|
import os
|
|
107
|
+
import re
|
|
85
108
|
import shutil
|
|
86
109
|
import signal
|
|
87
110
|
import time
|
|
@@ -148,6 +171,29 @@ _CODEX_SANDBOX_ARGS = {
|
|
|
148
171
|
"full_auto": ["-s", "workspace-write"],
|
|
149
172
|
}
|
|
150
173
|
|
|
174
|
+
# sandbox_mode → antigravity ``--mode`` flags (design §5.4, Antigravity CLI
|
|
175
|
+
# 1.1.1, verified via facts-antigravity.md). ``agy --help`` only enumerates
|
|
176
|
+
# two ``--mode`` values (``plan`` / ``accept-edits``), so ``full_auto`` maps
|
|
177
|
+
# onto ``accept-edits`` plus the separate ``--dangerously-skip-permissions``
|
|
178
|
+
# flag (auto-approves all tool executions) rather than a third ``--mode``
|
|
179
|
+
# value. ``--sandbox`` is deliberately never used here: it has a known bypass
|
|
180
|
+
# bug when combined with ``--dangerously-skip-permissions`` (agy issue #36).
|
|
181
|
+
_ANTIGRAVITY_MODE_ARGS = {
|
|
182
|
+
"read_only": ["--mode", "plan"],
|
|
183
|
+
"edit": ["--mode", "accept-edits"],
|
|
184
|
+
"full_auto": ["--mode", "accept-edits", "--dangerously-skip-permissions"],
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Compiled ANSI escape sequence stripper for antigravity's plain-text output
|
|
188
|
+
# (design §5.1.6). Covers CSI sequences (``ESC [ ... final-byte``) plus bare
|
|
189
|
+
# OSC-style ``ESC ]`` sequences terminated by BEL or ``ESC \`` (kept simple —
|
|
190
|
+
# antigravity's TUI chrome is not fully specified, so this is a defensive
|
|
191
|
+
# best-effort strip, not a full ANSI parser).
|
|
192
|
+
_ANSI_RE = re.compile(
|
|
193
|
+
r"\x1b\[[0-9;?]*[ -/]*[@-~]" # CSI ... final byte
|
|
194
|
+
r"|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)" # OSC ... BEL or ST
|
|
195
|
+
)
|
|
196
|
+
|
|
151
197
|
|
|
152
198
|
def _chunk_text(text: str, size: int = _STREAM_CHUNK_CHARS) -> Iterator[str]:
|
|
153
199
|
"""Split ``text`` into ``size``-char pieces for the pseudo-stream."""
|
|
@@ -156,20 +202,26 @@ def _chunk_text(text: str, size: int = _STREAM_CHUNK_CHARS) -> Iterator[str]:
|
|
|
156
202
|
|
|
157
203
|
|
|
158
204
|
class AgentCliAdapter(BaseAdapter):
|
|
159
|
-
"""Invoke an external coding-agent CLI one-shot (claude + codex + grok
|
|
205
|
+
"""Invoke an external coding-agent CLI one-shot (claude + codex + grok +
|
|
206
|
+
antigravity).
|
|
160
207
|
|
|
161
208
|
The ``agent`` field selects the argv builder / output parser via the
|
|
162
209
|
dispatch tables built in :meth:`__init__`, mirroring how
|
|
163
210
|
``openai_compat`` fronts many HTTP backends from one class.
|
|
164
211
|
"""
|
|
165
212
|
|
|
213
|
+
_IMPLEMENTED_AGENTS = ("claude", "codex", "grok", "antigravity")
|
|
214
|
+
|
|
166
215
|
def __init__(self, config: ProviderConfig) -> None:
|
|
167
216
|
"""Bind to a ``ProviderConfig`` and reject unsupported agents.
|
|
168
217
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
218
|
+
``gemini`` gets its own rejection message (non-retryable): Google
|
|
219
|
+
discontinued the Gemini CLI's OAuth for individual accounts in June
|
|
220
|
+
2026, so this adapter points the operator at ``antigravity``
|
|
221
|
+
instead of a generic "not implemented" message. Any other
|
|
222
|
+
unimplemented value (future-proofing; currently none, since the
|
|
223
|
+
schema's ``Literal`` only allows the five known agents) falls back
|
|
224
|
+
to a generic message listing what IS implemented.
|
|
173
225
|
"""
|
|
174
226
|
super().__init__(config)
|
|
175
227
|
if config.agent_cli is None: # pragma: no cover - schema enforces this
|
|
@@ -179,34 +231,50 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
179
231
|
retryable=False,
|
|
180
232
|
)
|
|
181
233
|
self.acfg: AgentCliConfig = config.agent_cli
|
|
182
|
-
if self.acfg.agent not in
|
|
234
|
+
if self.acfg.agent not in self._IMPLEMENTED_AGENTS:
|
|
235
|
+
if self.acfg.agent == "gemini":
|
|
236
|
+
raise AdapterError(
|
|
237
|
+
"agent 'gemini' is not supported: Google discontinued "
|
|
238
|
+
"the Gemini CLI for individual accounts (June 2026; "
|
|
239
|
+
"IneligibleTierError). Use agent='antigravity' "
|
|
240
|
+
"(Antigravity CLI, command 'agy') instead.",
|
|
241
|
+
provider=config.name,
|
|
242
|
+
retryable=False,
|
|
243
|
+
)
|
|
183
244
|
raise AdapterError(
|
|
184
|
-
f"agent {self.acfg.agent!r} is not implemented
|
|
185
|
-
f"(implemented:
|
|
245
|
+
f"agent {self.acfg.agent!r} is not implemented "
|
|
246
|
+
f"(implemented: {', '.join(self._IMPLEMENTED_AGENTS)}).",
|
|
186
247
|
provider=config.name,
|
|
187
248
|
retryable=False,
|
|
188
249
|
)
|
|
189
250
|
# agent → argv builder / output parser dispatch tables. claude landed
|
|
190
|
-
# in Phase 1a, codex in Phase 1b, grok in Phase 1d
|
|
191
|
-
#
|
|
251
|
+
# in Phase 1a, codex in Phase 1b, grok in Phase 1d, antigravity in
|
|
252
|
+
# Phase 1c — all four (design §9) are now implemented.
|
|
192
253
|
self._builders = {
|
|
193
254
|
"claude": self._build_claude_argv,
|
|
194
255
|
"codex": self._build_codex_argv,
|
|
195
256
|
"grok": self._build_grok_argv,
|
|
257
|
+
"antigravity": self._build_antigravity_argv,
|
|
196
258
|
}
|
|
197
259
|
self._parsers = {
|
|
198
260
|
"claude": self._parse_claude,
|
|
199
261
|
"codex": self._parse_codex,
|
|
200
262
|
"grok": self._parse_grok,
|
|
263
|
+
"antigravity": self._parse_antigravity,
|
|
201
264
|
}
|
|
202
|
-
# Prompt delivery is per-agent
|
|
203
|
-
# from stdin (10MB cap; codex's argv carries
|
|
204
|
-
# making that explicit), which keeps argv
|
|
205
|
-
# huge) prompt text. grok's ``-p``
|
|
206
|
-
# value (piped stdin is only
|
|
207
|
-
# v0.2.93), so grok gets the
|
|
208
|
-
# see ``_write_prompt_file``
|
|
265
|
+
# Prompt delivery is per-agent, one of three mechanisms: claude and
|
|
266
|
+
# codex read their prompt from stdin (10MB cap; codex's argv carries
|
|
267
|
+
# a trailing "-" sentinel making that explicit), which keeps argv
|
|
268
|
+
# free of the (potentially huge) prompt text. grok's ``-p``
|
|
269
|
+
# REQUIRES the prompt as its argv value (piped stdin is only
|
|
270
|
+
# appended as extra context, verified on v0.2.93), so grok gets the
|
|
271
|
+
# prompt via ``--prompt-file`` instead — see ``_write_prompt_file``
|
|
272
|
+
# for the rationale. antigravity has NEITHER a stdin nor a
|
|
273
|
+
# ``--prompt-file`` channel — piped stdin hangs the CLI outright
|
|
274
|
+
# (field-verified on agy 1.1.1) — so its prompt rides argv instead;
|
|
275
|
+
# see ``_build_antigravity_argv`` for the tradeoff this accepts.
|
|
209
276
|
self._uses_stdin = self.acfg.agent in ("claude", "codex")
|
|
277
|
+
self._uses_argv = self.acfg.agent == "antigravity"
|
|
210
278
|
|
|
211
279
|
# ------------------------------------------------------------------
|
|
212
280
|
# BaseAdapter contract
|
|
@@ -255,10 +323,16 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
255
323
|
|
|
256
324
|
# Agents that cannot take the prompt on stdin (grok) get it through a
|
|
257
325
|
# private temp file inside the workdir; it is ALWAYS removed in the
|
|
258
|
-
# ``finally`` below, including on timeout / exception paths.
|
|
259
|
-
|
|
326
|
+
# ``finally`` below, including on timeout / exception paths. Argv
|
|
327
|
+
# agents (antigravity) get neither a file nor stdin bytes — the
|
|
328
|
+
# prompt text is handed straight to the builder instead.
|
|
329
|
+
prompt_file = (
|
|
330
|
+
None
|
|
331
|
+
if self._uses_stdin or self._uses_argv
|
|
332
|
+
else self._write_prompt_file(prompt, workdir)
|
|
333
|
+
)
|
|
260
334
|
try:
|
|
261
|
-
argv = self._builders[self.acfg.agent](workdir, prompt_file)
|
|
335
|
+
argv = self._builders[self.acfg.agent](workdir, prompt_file, prompt)
|
|
262
336
|
# Resolve the executable to an absolute path so argv[0] is a
|
|
263
337
|
# concrete binary independent of the child's minimal PATH
|
|
264
338
|
# (design §6 allowlist).
|
|
@@ -297,6 +371,10 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
297
371
|
retryable=False,
|
|
298
372
|
) from exc
|
|
299
373
|
|
|
374
|
+
# Non-stdin agents (grok's file delivery, antigravity's argv
|
|
375
|
+
# delivery) get None here, so ``communicate()`` closes stdin
|
|
376
|
+
# immediately without writing to it — verified required for
|
|
377
|
+
# antigravity, whose CLI hangs if anything is piped to stdin.
|
|
300
378
|
stdin_bytes = prompt.encode("utf-8") if self._uses_stdin else None
|
|
301
379
|
try:
|
|
302
380
|
stdout, stderr = await asyncio.wait_for(
|
|
@@ -366,7 +444,9 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
366
444
|
# claude argv builder + output parser
|
|
367
445
|
# ------------------------------------------------------------------
|
|
368
446
|
|
|
369
|
-
def _build_claude_argv(
|
|
447
|
+
def _build_claude_argv(
|
|
448
|
+
self, workdir: str, prompt_file: str | None = None, prompt: str | None = None
|
|
449
|
+
) -> list[str]:
|
|
370
450
|
"""Assemble the ``claude -p`` argv (design §5.1.5 / §5.4).
|
|
371
451
|
|
|
372
452
|
Shape::
|
|
@@ -375,12 +455,13 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
375
455
|
--permission-mode <plan|acceptEdits> --add-dir <workdir>
|
|
376
456
|
|
|
377
457
|
The prompt is fed on stdin (not argv), so it never appears here and
|
|
378
|
-
``prompt_file``
|
|
379
|
-
signature uniform across agents
|
|
380
|
-
|
|
381
|
-
|
|
458
|
+
both ``prompt_file`` and ``prompt`` are ignored (they exist only to
|
|
459
|
+
keep the builder signature uniform across agents — see
|
|
460
|
+
``_build_antigravity_argv`` for the one agent that needs ``prompt``).
|
|
461
|
+
``--bare`` is deliberately NOT added — it would skip OAuth/keychain
|
|
462
|
+
reads and break subscription auth (design §5.3.4).
|
|
382
463
|
"""
|
|
383
|
-
del prompt_file # claude takes the prompt on stdin
|
|
464
|
+
del prompt_file, prompt # claude takes the prompt on stdin.
|
|
384
465
|
model = self.acfg.model or self.config.model
|
|
385
466
|
argv = [self.acfg.command, "-p", "--output-format", "json", "--model", model]
|
|
386
467
|
if self.acfg.max_turns is not None:
|
|
@@ -494,7 +575,9 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
494
575
|
# codex argv builder + output parser (Phase 1b)
|
|
495
576
|
# ------------------------------------------------------------------
|
|
496
577
|
|
|
497
|
-
def _build_codex_argv(
|
|
578
|
+
def _build_codex_argv(
|
|
579
|
+
self, workdir: str, prompt_file: str | None = None, prompt: str | None = None
|
|
580
|
+
) -> list[str]:
|
|
498
581
|
"""Assemble the ``codex exec`` argv (design §5.1.5 / §5.4, verified
|
|
499
582
|
against codex-cli 0.144.1 — see ``_codex/facts-codex.md``).
|
|
500
583
|
|
|
@@ -504,19 +587,20 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
504
587
|
-m <model> -C <workdir> -s <read-only|workspace-write> -
|
|
505
588
|
|
|
506
589
|
The prompt is fed on stdin (not argv), so it never appears here and
|
|
507
|
-
``prompt_file``
|
|
508
|
-
signature uniform across agents) — the trailing
|
|
509
|
-
stdin intent explicit to ``codex exec``, which
|
|
510
|
-
bare invocation with no PROMPT arg the same way
|
|
511
|
-
ambiguously in a fixed argv list. ``--skip-git-repo-
|
|
512
|
-
ALWAYS passed because the isolated workdir is not a git
|
|
513
|
-
(without it the CLI exits 1). ``--ephemeral`` is ALWAYS
|
|
514
|
-
session state persists to disk, matching the adapter's
|
|
515
|
-
one-shot ethos (the same rationale as grok's
|
|
516
|
-
has no ``--max-turns`` equivalent, so
|
|
517
|
-
silently ignored here (documented in
|
|
590
|
+
both ``prompt_file`` and ``prompt`` are ignored (they exist only to
|
|
591
|
+
keep the builder signature uniform across agents) — the trailing
|
|
592
|
+
``-`` makes the stdin intent explicit to ``codex exec``, which
|
|
593
|
+
otherwise treats a bare invocation with no PROMPT arg the same way
|
|
594
|
+
but reads more ambiguously in a fixed argv list. ``--skip-git-repo-
|
|
595
|
+
check`` is ALWAYS passed because the isolated workdir is not a git
|
|
596
|
+
repository (without it the CLI exits 1). ``--ephemeral`` is ALWAYS
|
|
597
|
+
passed so no session state persists to disk, matching the adapter's
|
|
598
|
+
stateless one-shot ethos (the same rationale as grok's
|
|
599
|
+
``--no-memory``). codex has no ``--max-turns`` equivalent, so
|
|
600
|
+
``AgentCliConfig.max_turns`` is silently ignored here (documented in
|
|
601
|
+
the schema).
|
|
518
602
|
"""
|
|
519
|
-
del prompt_file # codex takes the prompt on stdin
|
|
603
|
+
del prompt_file, prompt # codex takes the prompt on stdin.
|
|
520
604
|
model = self.acfg.model or self.config.model
|
|
521
605
|
argv = [
|
|
522
606
|
self.acfg.command,
|
|
@@ -666,7 +750,9 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
666
750
|
# grok argv builder + output parser (Phase 1d)
|
|
667
751
|
# ------------------------------------------------------------------
|
|
668
752
|
|
|
669
|
-
def _build_grok_argv(
|
|
753
|
+
def _build_grok_argv(
|
|
754
|
+
self, workdir: str, prompt_file: str | None = None, prompt: str | None = None
|
|
755
|
+
) -> list[str]:
|
|
670
756
|
"""Assemble the grok headless argv (design §5, grok CLI v0.2.93).
|
|
671
757
|
|
|
672
758
|
Shape::
|
|
@@ -680,8 +766,11 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
680
766
|
would hit Linux's ~128KiB ``MAX_ARG_STRLEN`` on large prompts and
|
|
681
767
|
leak the text into ``ps`` output. ``--no-memory`` is deliberate: it
|
|
682
768
|
enforces the one-request-one-transformation statelessness even if
|
|
683
|
-
the user's grok config enables cross-session memory.
|
|
769
|
+
the user's grok config enables cross-session memory. ``prompt`` is
|
|
770
|
+
ignored (it exists only to keep the builder signature uniform across
|
|
771
|
+
agents — grok never takes it on argv).
|
|
684
772
|
"""
|
|
773
|
+
del prompt
|
|
685
774
|
if prompt_file is None: # pragma: no cover - generate() always supplies it
|
|
686
775
|
raise AdapterError(
|
|
687
776
|
"grok argv requires a prompt file",
|
|
@@ -774,6 +863,108 @@ class AgentCliAdapter(BaseAdapter):
|
|
|
774
863
|
meta["coderouter_session_id"] = session_id
|
|
775
864
|
return result, usage, meta
|
|
776
865
|
|
|
866
|
+
# ------------------------------------------------------------------
|
|
867
|
+
# antigravity argv builder + output parser (Phase 1c, in lieu of gemini)
|
|
868
|
+
# ------------------------------------------------------------------
|
|
869
|
+
|
|
870
|
+
def _build_antigravity_argv(
|
|
871
|
+
self, workdir: str, prompt_file: str | None = None, prompt: str | None = None
|
|
872
|
+
) -> list[str]:
|
|
873
|
+
"""Assemble the ``agy -p`` argv (design §5.1.5 / §5.4, verified
|
|
874
|
+
against Antigravity CLI 1.1.1 — see ``_codex/facts-antigravity.md``).
|
|
875
|
+
|
|
876
|
+
Shape::
|
|
877
|
+
|
|
878
|
+
agy -p <prompt> --model <m> --mode <plan|accept-edits>
|
|
879
|
+
[--dangerously-skip-permissions] --print-timeout <n>s
|
|
880
|
+
|
|
881
|
+
``workdir`` is unused here — antigravity picks up its working
|
|
882
|
+
directory from the child process's ``cwd`` (set by ``generate()``),
|
|
883
|
+
and this adapter deliberately never passes ``--add-dir`` (design
|
|
884
|
+
keeps the argv minimal; only claude's multi-root model needs it).
|
|
885
|
+
``prompt_file`` is unused (antigravity has no such flag).
|
|
886
|
+
|
|
887
|
+
Prompt-delivery tradeoff (read this before touching the ``-p``
|
|
888
|
+
line): agy has no stdin channel — piping content to stdin makes the
|
|
889
|
+
real CLI hang waiting for a response that never comes (field-
|
|
890
|
+
verified on 1.1.1) — and no ``--prompt-file`` equivalent either. The
|
|
891
|
+
prompt therefore rides argv as the ``-p`` value, which is the *only*
|
|
892
|
+
delivery mechanism the CLI offers. This caps practical prompt size
|
|
893
|
+
at Linux's ~128KiB ``MAX_ARG_STRLEN`` and exposes the prompt text to
|
|
894
|
+
``ps`` on the local host — exactly the two costs grok's
|
|
895
|
+
``--prompt-file`` delivery was built to avoid (see the module
|
|
896
|
+
docstring's security section). No shell is involved (list argv, not
|
|
897
|
+
shell text), and the adapter's threat model — an isolated,
|
|
898
|
+
single-operator workstation — accepts local ``ps`` visibility as a
|
|
899
|
+
documented limitation rather than a defect; there is no safer
|
|
900
|
+
channel to fall back to.
|
|
901
|
+
|
|
902
|
+
``--print-timeout`` is antigravity's own self-termination clock,
|
|
903
|
+
derived from ``exec_timeout_s`` — it is the CLI's *first* wall
|
|
904
|
+
against a hung call; the adapter's outer ``asyncio.wait_for`` +
|
|
905
|
+
process-group ``SIGKILL`` remains the second, unconditional wall
|
|
906
|
+
(design §6). ``max_turns`` is never emitted: agy has no ``--max-
|
|
907
|
+
turns``-equivalent flag (like codex), so ``AgentCliConfig.max_turns``
|
|
908
|
+
is silently ignored here (documented in the schema). No ``--sandbox``
|
|
909
|
+
(known bypass bug alongside ``--dangerously-skip-permissions``,
|
|
910
|
+
agy issue #36) and no ``--add-dir`` are ever passed.
|
|
911
|
+
"""
|
|
912
|
+
del prompt_file # antigravity has no prompt-file flag.
|
|
913
|
+
if prompt is None: # pragma: no cover - generate() always supplies it
|
|
914
|
+
raise AdapterError(
|
|
915
|
+
"antigravity argv requires the prompt text",
|
|
916
|
+
provider=self.name,
|
|
917
|
+
retryable=False,
|
|
918
|
+
)
|
|
919
|
+
model = self.acfg.model or self.config.model
|
|
920
|
+
argv = [self.acfg.command, "-p", prompt, "--model", model]
|
|
921
|
+
argv += self._antigravity_mode_args()
|
|
922
|
+
argv += ["--print-timeout", f"{int(self.acfg.exec_timeout_s)}s"]
|
|
923
|
+
return argv
|
|
924
|
+
|
|
925
|
+
def _antigravity_mode_args(self) -> list[str]:
|
|
926
|
+
"""Map ``sandbox_mode`` → antigravity ``--mode`` flags, clamped.
|
|
927
|
+
|
|
928
|
+
Same clamp as claude/codex/grok (design §5.4): when
|
|
929
|
+
``allow_file_writes`` is False the effective mode is forced to
|
|
930
|
+
``read_only`` regardless of ``sandbox_mode``, so writes always
|
|
931
|
+
require the explicit opt-in.
|
|
932
|
+
"""
|
|
933
|
+
mode = self.acfg.sandbox_mode if self.acfg.allow_file_writes else "read_only"
|
|
934
|
+
return list(_ANTIGRAVITY_MODE_ARGS[mode])
|
|
935
|
+
|
|
936
|
+
def _parse_antigravity(
|
|
937
|
+
self, stdout: bytes, stderr: bytes
|
|
938
|
+
) -> tuple[str, dict[str, Any], dict[str, Any]]:
|
|
939
|
+
"""Parse antigravity's plain-text ``-p`` output (verified agy 1.1.1).
|
|
940
|
+
|
|
941
|
+
There is no ``--output-format`` flag at all (agy's ``--help`` does
|
|
942
|
+
not list one) — output is whatever the model printed, decorated
|
|
943
|
+
with whatever terminal styling the CLI applied even in non-TTY runs.
|
|
944
|
+
Parsing is therefore: UTF-8 decode (defensively, replacing invalid
|
|
945
|
+
bytes) → strip ANSI escape sequences (``_ANSI_RE``, best-effort, see
|
|
946
|
+
its definition) → ``.strip()`` surrounding whitespace. Empty output
|
|
947
|
+
raises a retryable :class:`AdapterError` so the chain can fall
|
|
948
|
+
through. There is no token/cost figure and no session id anywhere
|
|
949
|
+
in agy's output, so ``usage`` is all-zeros (cost stays 0 unless the
|
|
950
|
+
operator sets ``ProviderConfig.cost``, same rationale as grok,
|
|
951
|
+
design §5.1.6) and ``meta`` is empty.
|
|
952
|
+
"""
|
|
953
|
+
text = _ANSI_RE.sub("", stdout.decode("utf-8", "replace")).strip()
|
|
954
|
+
if not text:
|
|
955
|
+
raise AdapterError(
|
|
956
|
+
"antigravity produced no stdout",
|
|
957
|
+
provider=self.name,
|
|
958
|
+
retryable=True,
|
|
959
|
+
)
|
|
960
|
+
usage: dict[str, Any] = {
|
|
961
|
+
"prompt_tokens": 0,
|
|
962
|
+
"completion_tokens": 0,
|
|
963
|
+
"total_tokens": 0,
|
|
964
|
+
}
|
|
965
|
+
meta: dict[str, Any] = {}
|
|
966
|
+
return text, usage, meta
|
|
967
|
+
|
|
777
968
|
# ------------------------------------------------------------------
|
|
778
969
|
# helpers: prompt rendering, response shaping, env, workdir, kill
|
|
779
970
|
# ------------------------------------------------------------------
|
|
@@ -168,13 +168,18 @@ class AgentCliConfig(BaseModel):
|
|
|
168
168
|
|
|
169
169
|
Introduced by the external-agents-adapter design (Phase 1). One
|
|
170
170
|
``agent_cli`` sub-config drives the :class:`AgentCliAdapter`, which
|
|
171
|
-
invokes an external coding-agent CLI (codex / gemini / grok / claude
|
|
172
|
-
in a single one-shot ``exec`` and returns the final answer
|
|
173
|
-
``prompt in → text out`` transformation. ``claude`` (Claude Code
|
|
174
|
-
Phase 1a), ``codex`` (codex CLI, Phase 1b)
|
|
175
|
-
Phase 1d)
|
|
176
|
-
|
|
177
|
-
|
|
171
|
+
invokes an external coding-agent CLI (codex / gemini / grok / claude /
|
|
172
|
+
antigravity) in a single one-shot ``exec`` and returns the final answer
|
|
173
|
+
as one ``prompt in → text out`` transformation. ``claude`` (Claude Code
|
|
174
|
+
CLI, Phase 1a), ``codex`` (codex CLI, Phase 1b), ``grok`` (grok CLI,
|
|
175
|
+
Phase 1d) and ``antigravity`` (Antigravity CLI, Phase 1c, in lieu of
|
|
176
|
+
``gemini``) are implemented. ``gemini`` is declared at the schema level
|
|
177
|
+
for backward-compatible config parsing, but the adapter rejects it with
|
|
178
|
+
a migration pointer: Google discontinued the (legacy) Gemini CLI's
|
|
179
|
+
OAuth for individual accounts in June 2026 (``IneligibleTierError`` /
|
|
180
|
+
``UNSUPPORTED_CLIENT`` on the real client) and its successor is the
|
|
181
|
+
Antigravity CLI (command ``agy``, a separate Go implementation, not a
|
|
182
|
+
gemini-cli fork) — set ``agent: "antigravity"`` instead.
|
|
178
183
|
|
|
179
184
|
Auth note (grok): the grok CLI uses OAuth credentials stored under
|
|
180
185
|
``~/.grok`` (``grok login``), which the adapter's HOME inheritance
|
|
@@ -190,25 +195,41 @@ class AgentCliConfig(BaseModel):
|
|
|
190
195
|
``CODEX_API_KEY`` (exec-only) or ``OPENAI_API_KEY`` (general) in
|
|
191
196
|
``passthrough_env``.
|
|
192
197
|
|
|
198
|
+
Auth note (antigravity): the Antigravity CLI uses a Google-account OAuth
|
|
199
|
+
login (free tier included), with credentials preferentially stored in
|
|
200
|
+
the OS keyring and mirrored under ``~/.gemini/antigravity-cli/``
|
|
201
|
+
(``credentials.enc`` / ``settings.json``) — the adapter's HOME (and, on
|
|
202
|
+
macOS, USER) inheritance already covers this, no extra config needed.
|
|
203
|
+
Any API-key environment variable for CI / non-interactive setups is
|
|
204
|
+
UNCONFIRMED (field reports disagree on the variable name) — this
|
|
205
|
+
docstring deliberately does not name one as authoritative; if you find
|
|
206
|
+
one that works, list it in ``passthrough_env``.
|
|
207
|
+
|
|
193
208
|
Follows the ``extra="forbid"`` convention used across this module so a
|
|
194
209
|
typo'd key fails at config-load rather than being silently ignored.
|
|
195
210
|
"""
|
|
196
211
|
|
|
197
212
|
model_config = ConfigDict(extra="forbid")
|
|
198
213
|
|
|
199
|
-
agent: Literal["codex", "gemini", "grok", "claude"] = Field(
|
|
214
|
+
agent: Literal["codex", "gemini", "grok", "claude", "antigravity"] = Field(
|
|
200
215
|
...,
|
|
201
216
|
description=(
|
|
202
217
|
"External coding-agent CLI to invoke. 'claude' (Phase 1a), "
|
|
203
|
-
"'codex' (Phase 1b)
|
|
204
|
-
"
|
|
218
|
+
"'codex' (Phase 1b), 'grok' (Phase 1d) and 'antigravity' "
|
|
219
|
+
"(Phase 1c, Google's Antigravity CLI, command 'agy') are "
|
|
220
|
+
"implemented. 'gemini' is rejected by the adapter — Google "
|
|
221
|
+
"discontinued the Gemini CLI for individual accounts in June "
|
|
222
|
+
"2026; use 'antigravity' instead."
|
|
205
223
|
),
|
|
206
224
|
)
|
|
207
225
|
command: str | None = Field(
|
|
208
226
|
default=None,
|
|
209
227
|
description=(
|
|
210
228
|
"CLI executable name or absolute path (resolved via PATH). "
|
|
211
|
-
"When unset, defaults to the ``agent`` name
|
|
229
|
+
"When unset, defaults to the ``agent`` name — EXCEPT "
|
|
230
|
+
"'antigravity', whose binary is named ``agy`` (the product is "
|
|
231
|
+
"'Antigravity CLI' but the executable keeps the short, "
|
|
232
|
+
"pre-rename command name)."
|
|
212
233
|
),
|
|
213
234
|
)
|
|
214
235
|
workdir: str | None = Field(
|
|
@@ -291,9 +312,14 @@ class AgentCliConfig(BaseModel):
|
|
|
291
312
|
``sandbox_mode="read_only"`` is contradictory — the operator asked
|
|
292
313
|
for writes while pinning a read-only sandbox. Fail fast at load,
|
|
293
314
|
matching the module's other cross-field validators.
|
|
315
|
+
|
|
316
|
+
``command`` defaults to the ``agent`` name for every agent EXCEPT
|
|
317
|
+
``antigravity``, whose binary is ``agy`` — the product renamed from
|
|
318
|
+
Gemini CLI to Antigravity CLI, but the executable kept its short
|
|
319
|
+
pre-rename name.
|
|
294
320
|
"""
|
|
295
321
|
if self.command is None:
|
|
296
|
-
self.command = self.agent
|
|
322
|
+
self.command = "agy" if self.agent == "antigravity" else self.agent
|
|
297
323
|
if self.allow_file_writes and self.sandbox_mode == "read_only":
|
|
298
324
|
raise ValueError(
|
|
299
325
|
"agent_cli: allow_file_writes=True conflicts with "
|