mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix: post-finale completeness sweep — routing surface, provider config, budgets, compose env, interactive exemption (#661)
This commit is contained in:
@@ -41,9 +41,30 @@ def test_render_config_toml_marks_gateway_pair_required() -> None:
|
||||
assert "required" not in parsed["mcp_servers"]["roboco-optimal"]
|
||||
|
||||
|
||||
def test_render_config_toml_empty_when_no_servers() -> None:
|
||||
assert cc.render_config_toml({}) == ""
|
||||
assert cc.render_config_toml({"mcpServers": {}}) == ""
|
||||
def test_render_config_toml_widens_startup_timeout_on_required_servers() -> None:
|
||||
# The CLI's default 10s MCP startup timeout fail-fast-aborts the session on
|
||||
# a cold uv wheel cache; the gateway pair gets a wider budget.
|
||||
parsed = tomllib.loads(cc.render_config_toml(_SAMPLE_MCP))
|
||||
timeout = cc._REQUIRED_MCP_STARTUP_TIMEOUT_SEC
|
||||
assert parsed["mcp_servers"]["roboco-flow"]["startup_timeout_sec"] == timeout
|
||||
assert parsed["mcp_servers"]["roboco-do"]["startup_timeout_sec"] == timeout
|
||||
assert "startup_timeout_sec" not in parsed["mcp_servers"]["roboco-optimal"]
|
||||
|
||||
|
||||
def test_render_config_toml_disables_subagents_unconditionally() -> None:
|
||||
# Fleet-wide subagent ban (CEO, 2026-07-09) — a global switch, not
|
||||
# per-role, so it renders even with no MCP servers configured at all.
|
||||
no_servers = tomllib.loads(cc.render_config_toml({}))
|
||||
empty_servers = tomllib.loads(cc.render_config_toml({"mcpServers": {}}))
|
||||
with_servers = tomllib.loads(cc.render_config_toml(_SAMPLE_MCP))
|
||||
assert no_servers["agents"]["enabled"] is False
|
||||
assert empty_servers["agents"]["enabled"] is False
|
||||
assert with_servers["agents"]["enabled"] is False
|
||||
|
||||
|
||||
def test_render_config_toml_no_mcp_servers_key_when_no_servers() -> None:
|
||||
assert "mcp_servers" not in tomllib.loads(cc.render_config_toml({}))
|
||||
assert "mcp_servers" not in tomllib.loads(cc.render_config_toml({"mcpServers": {}}))
|
||||
|
||||
|
||||
def test_sandbox_level_developer_is_workspace_write() -> None:
|
||||
|
||||
@@ -125,8 +125,13 @@ def test_write_policy_toml_writes_file(tmp_path: Path) -> None:
|
||||
assert "run_shell_command" in written
|
||||
|
||||
|
||||
def test_gemini_cli_args_is_yolo_only() -> None:
|
||||
assert gc.gemini_cli_args() == ["--approval-mode", "yolo"]
|
||||
def test_gemini_cli_args_is_yolo_plus_default_max_turns() -> None:
|
||||
assert gc.gemini_cli_args() == ["--approval-mode", "yolo", "--max-turns", "200"]
|
||||
|
||||
|
||||
def test_gemini_cli_args_max_turns_is_overridable() -> None:
|
||||
args = gc.gemini_cli_args(max_turns=7)
|
||||
assert args[args.index("--max-turns") + 1] == "7"
|
||||
|
||||
|
||||
def test_main_writes_settings_and_args(
|
||||
@@ -161,4 +166,50 @@ def test_main_writes_settings_and_args(
|
||||
assert args_path.read_text(encoding="utf-8").splitlines() == [
|
||||
"--approval-mode",
|
||||
"yolo",
|
||||
"--max-turns",
|
||||
"200",
|
||||
]
|
||||
|
||||
|
||||
def test_main_honors_max_turns_env_override(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
mcp_path = tmp_path / "mcp-config.json"
|
||||
mcp_path.write_text(json.dumps(_SAMPLE_MCP), encoding="utf-8")
|
||||
args_path = tmp_path / "gemini-args"
|
||||
|
||||
monkeypatch.setattr(gc, "GEMINI_SETTINGS_PATH", tmp_path / ".gemini" / "s.json")
|
||||
monkeypatch.setattr(gc, "GEMINI_MEMORY_PATH", tmp_path / ".gemini" / "GEMINI.md")
|
||||
monkeypatch.setattr(gc, "GEMINI_POLICIES_DIR", tmp_path / ".gemini" / "policies")
|
||||
monkeypatch.setattr(gc, "GEMINI_ARGS_PATH", args_path)
|
||||
monkeypatch.setenv("ROBOCO_AGENT_ID", "be-dev-1")
|
||||
monkeypatch.setenv("ROBOCO_MCP_CONFIG", str(mcp_path))
|
||||
monkeypatch.setenv("ROBOCO_GEMINI_MAX_TURNS", "42")
|
||||
|
||||
assert gc.main() == 0
|
||||
assert args_path.read_text(encoding="utf-8").splitlines()[-2:] == [
|
||||
"--max-turns",
|
||||
"42",
|
||||
]
|
||||
|
||||
|
||||
def test_main_falls_back_to_default_max_turns_on_bad_env(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
mcp_path = tmp_path / "mcp-config.json"
|
||||
mcp_path.write_text(json.dumps(_SAMPLE_MCP), encoding="utf-8")
|
||||
args_path = tmp_path / "gemini-args"
|
||||
|
||||
monkeypatch.setattr(gc, "GEMINI_SETTINGS_PATH", tmp_path / ".gemini" / "s.json")
|
||||
monkeypatch.setattr(gc, "GEMINI_MEMORY_PATH", tmp_path / ".gemini" / "GEMINI.md")
|
||||
monkeypatch.setattr(gc, "GEMINI_POLICIES_DIR", tmp_path / ".gemini" / "policies")
|
||||
monkeypatch.setattr(gc, "GEMINI_ARGS_PATH", args_path)
|
||||
monkeypatch.setenv("ROBOCO_AGENT_ID", "be-dev-1")
|
||||
monkeypatch.setenv("ROBOCO_MCP_CONFIG", str(mcp_path))
|
||||
monkeypatch.setenv("ROBOCO_GEMINI_MAX_TURNS", "not-a-number")
|
||||
|
||||
assert gc.main() == 0
|
||||
assert args_path.read_text(encoding="utf-8").splitlines()[-2:] == [
|
||||
"--max-turns",
|
||||
"200",
|
||||
]
|
||||
|
||||
@@ -15,10 +15,19 @@ from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from roboco.config import settings
|
||||
from roboco.llm.providers import GeminiCliProvider, ProviderError, SpawnResult
|
||||
from roboco.llm.providers import gemini as gemini_module
|
||||
from roboco.models.runtime import OrchestratorAgentConfig
|
||||
|
||||
|
||||
def test_gemini_cli_model_is_a_real_settings_field() -> None:
|
||||
# Parity with codex_cli_model (roboco.config.Settings.codex_cli_model) —
|
||||
# gemini.py reads settings.gemini_cli_model, not a raw os.environ.get.
|
||||
assert settings.gemini_cli_model == gemini_module._GEMINI_CLI_MODEL
|
||||
assert settings.gemini_cli_model == "gemini-2.5-pro"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _isolate_gemini_auth(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
|
||||
"""Point GEMINI_AUTH_HOST_PATH at a fresh tmp dir so tests never mount the
|
||||
|
||||
@@ -13,7 +13,7 @@ from __future__ import annotations
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from roboco.models.base import ModelProvider
|
||||
from roboco.models.base import AssignmentScope, ModelProvider
|
||||
from roboco.services.llm import ModelRoutingService, _ResolvedAssignment
|
||||
|
||||
_AGENT_SLUG = "be-dev-1"
|
||||
@@ -23,7 +23,9 @@ def _disabled_resolved() -> _ResolvedAssignment:
|
||||
provider = MagicMock(
|
||||
enabled=False, id="prov-disabled", type=ModelProvider.OLLAMA_CLOUD
|
||||
)
|
||||
return _ResolvedAssignment(provider=provider, model_name="grok-build")
|
||||
return _ResolvedAssignment(
|
||||
provider=provider, model_name="grok-build", scope=AssignmentScope.GLOBAL
|
||||
)
|
||||
|
||||
|
||||
def _svc() -> ModelRoutingService:
|
||||
|
||||
Reference in New Issue
Block a user