mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
- pricing.py: add grok-build-0.1 rates ($1/1M input, $0.20 cached, $2/1M output), verified against xAI's published pricing. Grok is a priced non-Anthropic model, so cost computes the moment usage is captured. - secret-scrub.js: an opencode tool.execute.before plugin porting the security-critical bash-guard deny rules (git network ops, credential-file reads, /proc env, internal-host HTTP, roboco.* imports, ROBOCO_AGENT_ID forgery, env dumps, destructive rm) to the opencode runtime — restoring the guard the Claude Code hook can't provide there. Throwing denies the call (confirmed by opencode's env-protection example). Wired into the generated opencode.json plugin array + baked into the grok image. Deny logic verified via node (9 deny + 5 allow cases). UNVALIDATED against a live opencode runtime: confirm it fires in the live E2E spawn before a Grok dev-agent touches a real repo; the bash permission is operator-tunable as a second gate. Cost CAPTURE (distinct from pricing) is intentionally NOT built yet: opencode's plugin hooks expose model info but no token/usage object, so the capture path is unconfirmed and needs the live spawn to settle.
96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
"""Tests for the Grok opencode.json generator (RoboCo MCP -> opencode config)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from roboco.llm.providers.opencode_config import (
|
|
XaiTarget,
|
|
build_opencode_config,
|
|
translate_mcp_servers,
|
|
)
|
|
|
|
_TARGET = XaiTarget(
|
|
base_url="https://api.x.ai/v1", api_key="xai-key", model="grok-build-0.1"
|
|
)
|
|
|
|
_MCP = {
|
|
"mcpServers": {
|
|
"roboco-flow": {
|
|
"command": "uv",
|
|
"args": ["run", "--no-sync", "python", "-m", "roboco.mcp.flow_server"],
|
|
"env": {
|
|
"ROBOCO_AGENT_ID": "uuid-1",
|
|
"UV_PROJECT_ENVIRONMENT": "/app/.venv",
|
|
},
|
|
},
|
|
"roboco-do": {
|
|
"command": "uv",
|
|
"args": ["run", "--no-sync", "python", "-m", "roboco.mcp.do_server"],
|
|
"env": {"ROBOCO_AGENT_ID": "uuid-1"},
|
|
},
|
|
}
|
|
}
|
|
|
|
|
|
def test_translate_mcp_servers_shape() -> None:
|
|
out = translate_mcp_servers(_MCP)
|
|
flow = out["roboco-flow"]
|
|
assert flow["type"] == "local"
|
|
assert flow["enabled"] is True
|
|
# command + args collapse into a single command array (opencode shape).
|
|
assert flow["command"] == [
|
|
"uv",
|
|
"run",
|
|
"--no-sync",
|
|
"python",
|
|
"-m",
|
|
"roboco.mcp.flow_server",
|
|
]
|
|
# env -> environment (opencode key).
|
|
assert flow["environment"]["ROBOCO_AGENT_ID"] == "uuid-1"
|
|
assert "env" not in flow
|
|
assert set(out) == {"roboco-flow", "roboco-do"}
|
|
|
|
|
|
def test_translate_mcp_servers_empty() -> None:
|
|
assert translate_mcp_servers({}) == {}
|
|
assert translate_mcp_servers({"mcpServers": {}}) == {}
|
|
|
|
|
|
def test_translate_mcp_servers_omits_environment_when_no_env() -> None:
|
|
out = translate_mcp_servers(
|
|
{"mcpServers": {"x": {"command": "uv", "args": ["run"]}}}
|
|
)
|
|
assert "environment" not in out["x"]
|
|
assert out["x"]["command"] == ["uv", "run"]
|
|
|
|
|
|
def test_build_opencode_config_provider_and_model() -> None:
|
|
cfg = build_opencode_config(
|
|
_MCP,
|
|
_TARGET,
|
|
instruction_paths=["/app/system-prompt.md"],
|
|
)
|
|
provider = cfg["provider"]["xai"]
|
|
assert provider["npm"] == "@ai-sdk/openai-compatible"
|
|
assert provider["options"]["baseURL"] == "https://api.x.ai/v1"
|
|
assert provider["options"]["apiKey"] == "xai-key"
|
|
assert "grok-build-0.1" in provider["models"]
|
|
# Top-level model selector is "<provider>/<model>".
|
|
assert cfg["model"] == "xai/grok-build-0.1"
|
|
# Gateway servers carried through.
|
|
assert "roboco-flow" in cfg["mcp"]
|
|
assert cfg["instructions"] == ["/app/system-prompt.md"]
|
|
# The secret-scrub command guard is wired in by default.
|
|
assert cfg["plugin"] == ["/app/opencode-plugins/secret-scrub.js"]
|
|
|
|
|
|
def test_build_opencode_config_bash_permission_is_tunable() -> None:
|
|
cfg = build_opencode_config(
|
|
{},
|
|
_TARGET,
|
|
instruction_paths=[],
|
|
bash_permission="deny",
|
|
)
|
|
assert cfg["permission"]["bash"] == "deny"
|
|
assert cfg["permission"]["edit"] == "allow"
|