Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/benchflow/acp/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ def _format_acp_model(model: str, agent: str) -> str:
return f"litellm/{model}"
return model if find_provider(model) else bare
if not agent_cfg or agent_cfg.acp_model_format != "provider/model":
if agent == "gemini" and bare.startswith("google/gemini-"):
return bare.removeprefix("google/")
return bare
# Already has a slash — assume it's provider/model already
if "/" in bare:
Expand Down
4 changes: 3 additions & 1 deletion tests/integration/agent_judge.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def _mask_scratch_paths(command: str) -> str:
# tampering. Only the command after ``: $ `` is the agent's actual action, so the
# execute scan must strip the description first.
_ACP_EXECUTE_PREFIX_RE = re.compile(r".*?: \$ ", re.DOTALL)
_ACP_EDIT_PATH_RE = re.compile(r"\bEditing\s+(?P<path>\S+)\s*$")


def _acp_execute_command(title: str) -> str:
Expand All @@ -155,7 +156,8 @@ def _acp_write_target(title: str) -> str:
stripped = title.strip()
prefix = "file_editor:"
if not stripped.startswith(prefix):
return title
match = _ACP_EDIT_PATH_RE.search(stripped)
return match.group("path") if match else title
# Titles carry trailing prose after the JSON payload (observed live:
# ``file_editor: {...}: Editing /tmp/test_rnn.py``), so parse the LEADING
# object with raw_decode instead of json.loads — a whole-title fallback
Expand Down
24 changes: 15 additions & 9 deletions tests/test_acp.py
Original file line number Diff line number Diff line change
Expand Up @@ -1110,22 +1110,28 @@ def _make_mocks():

@pytest.mark.asyncio
@pytest.mark.parametrize(
"model_in, expected_model",
"agent, model_in, expected_model",
[
# Registered vllm/ prefix stripped; HF org/model intact — this is
# what pi-acp and other ACP agents need for downstream routing.
("vllm/Qwen/Qwen3.5-35B-A3B", "Qwen/Qwen3.5-35B-A3B"),
("zai/glm-5", "glm-5"),
("test-agent", "vllm/Qwen/Qwen3.5-35B-A3B", "Qwen/Qwen3.5-35B-A3B"),
("test-agent", "zai/glm-5", "glm-5"),
# Bare HF ID (no registered prefix) passes through unchanged.
("Qwen/Qwen3-Coder", "Qwen/Qwen3-Coder"),
("test-agent", "Qwen/Qwen3-Coder", "Qwen/Qwen3-Coder"),
# Vertex ADC provider — prefix stripped like any other registered one.
("anthropic-vertex/claude-sonnet-4-6", "claude-sonnet-4-6"),
("test-agent", "anthropic-vertex/claude-sonnet-4-6", "claude-sonnet-4-6"),
# No prefix at all — unchanged.
("claude-sonnet-4-6", "claude-sonnet-4-6"),
("test-agent", "claude-sonnet-4-6", "claude-sonnet-4-6"),
# Gemini CLI expects a bare model ID, unlike models.dev agents.
(
"gemini",
"google/gemini-3.1-flash-lite-preview",
"gemini-3.1-flash-lite-preview",
),
],
ids=["vllm-hf", "zai", "bare-hf", "vertex", "no-prefix"],
ids=["vllm-hf", "zai", "bare-hf", "vertex", "no-prefix", "gemini-google"],
)
async def test_model_id_selection(self, model_in, expected_model, tmp_path):
async def test_model_id_selection(self, agent, model_in, expected_model, tmp_path):
from benchflow.acp.runtime import connect_acp

mock_acp = self._make_mocks()
Expand All @@ -1137,7 +1143,7 @@ async def test_model_id_selection(self, model_in, expected_model, tmp_path):
):
await connect_acp(
env=mock_env,
agent="test-agent",
agent=agent,
agent_launch="test-agent",
agent_env={},
sandbox_user=None,
Expand Down
1 change: 1 addition & 0 deletions tests/test_judge_robustness.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def test_scan_verifier_tamper(event, should_flag):
),
False,
),
(_native("edit", "Create test script: Editing /tmp/test_rnn.py"), False),
(
_native(
"edit",
Expand Down
Loading