Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6b72ee6
fix(agent): coerce AgentPolicyConfig fields to string to resolve #169
Amresh-01 Jul 25, 2026
e7385de
fix(agent): comment param coercion, use dummy env in tests, and updat…
Amresh-01 Jul 26, 2026
2eb84bd
fix error
Amresh-01 Jul 26, 2026
67726a1
fix(agent): reject non-string config options with ConfigError
Amresh-01 Jul 30, 2026
77f4fc2
fix lint check
Amresh-01 Jul 30, 2026
e44c73f
fix(agent): update test parameterization and types for strict string …
Amresh-01 Jul 30, 2026
be7d20f
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Jul 30, 2026
27eb0d3
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Jul 30, 2026
28509c3
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Jul 31, 2026
ea2ee96
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 2, 2026
2a2103e
Merge branch 'main' into fix/agent-config-coercion
jeqcho Aug 2, 2026
7556f15
fix(agent): skip _UNSET sentinel in config validation and clean up te…
Amresh-01 Aug 2, 2026
b0cf8c5
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 3, 2026
39ae568
Merge remote-tracking branch 'upstream/main' into fix/agent-config-co…
Amresh-01 Aug 5, 2026
d67d8c1
Merge remote-tracking branch 'origin/fix/agent-config-coercion' into …
Amresh-01 Aug 5, 2026
155dd9e
chore: remove unused importlib.util in test_rerun_sink.py
Amresh-01 Aug 5, 2026
029f664
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 7, 2026
8742f8c
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 8, 2026
d09876e
fix(agent): use isinstance for _Unset sentinel check
Amresh-01 Aug 8, 2026
ff3d5c0
fix(agent): remove effort from strict string validation loop to suppo…
Amresh-01 Aug 8, 2026
75a451c
fix(agent): address PR review comments, remove Unset branch, and para…
Amresh-01 Aug 9, 2026
9a27d03
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 9, 2026
8f5835e
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 11, 2026
8fb903d
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 13, 2026
e5b46da
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 14, 2026
846f80b
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 15, 2026
8b25dc1
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 18, 2026
ed23c70
Merge branch 'main' into fix/agent-config-coercion
Amresh-01 Aug 19, 2026
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,11 @@ All notable changes to this project are documented here. The format is based on
regression (`eef_delta_pose` + `rot6d` already reached the displacement
clamp path before #143/#144). `euler_xyz` and `axis_angle` deltas have no
such problem and remain guardrail-conformant.
- **Agent policy configuration parameters now strictly reject non-strings**
in `LLMAgentPolicy` constructor, raising a guided `ConfigError` (#169). This
prevents unquoted CLI values (e.g., `-P model=42` or `-P api_key_env=false`)
from causing downstream errors or incorrect fallback logic, prompting the
user to pass quoted strings instead.
- **An explicit invalid `--max-action-delta` now fails fast instead of silently
running with weaker guardrails** (#154). Non-finite or non-positive values
were previously caught by `_build_guardrails`'s degrade-per-component path
Expand Down
15 changes: 15 additions & 0 deletions plugins/inspect-robots-agent/src/inspect_robots_agent/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,21 @@ def __init__(
env: dict[str, str] | None = None,
pre_check: PreCheck | None = None,
) -> None:
# Reject non-strings with a guided ConfigError to prevent unquoted CLI
# values (e.g. -P model=42) from causing downstream errors or silent bypasses.
for name, val in [
("model", model),
("base_url", base_url),
("api_key_env", api_key_env),
("speed", speed),
]:
if val is not None and not isinstance(val, str):
raise ConfigError(
f"{name} must be a string, got {val!r}.\n"
f"fix: the -P parser coerces unquoted values; pass "
f"-P '{name}=\"value\"'"
)

prior_learnings_path: str | None = None
prior_learnings_text: str | None = None
prior_learnings_sha256: str | None = None
Expand Down
13 changes: 6 additions & 7 deletions plugins/inspect-robots-agent/tests/test_anthropic.py
Original file line number Diff line number Diff line change
Expand Up @@ -1288,20 +1288,19 @@ def test_variant_strip_keeps_fine_tune_colons() -> None:
)


@pytest.mark.parametrize("api_key_env", [None, "", False, 0, 0.0])
@pytest.mark.parametrize("api_key_env", [None, ""])
def test_falsy_api_key_env_does_not_send_the_openrouter_key_to_a_gateway(
api_key_env: object,
api_key_env: str | None,
) -> None:
# '-P api_key_env=' parses to '', and 'false'/'0' to other falsy values,
# all of which resolve_provider treats as unset and answers with
# $OPENROUTER_API_KEY. An `is None` test would hand a third-party gateway
# the OpenRouter secret.
# '-P api_key_env=' parses to '', which resolve_provider treats as unset
# and answers with $OPENROUTER_API_KEY. An `is None` test would hand a
# third-party gateway the OpenRouter secret.
seen, handler = _capture(_anthropic_response(_text("ok"), stop_reason="end_turn"))
policy = LLMAgentPolicy(
model="claude-opus-5",
wire="messages",
base_url="https://gw.example/v1",
api_key_env=api_key_env, # type: ignore[arg-type]
api_key_env=api_key_env,
transport=httpx.MockTransport(handler),
env={"ANTHROPIC_API_KEY": "sk-ant", "OPENROUTER_API_KEY": "sk-or"},
)
Expand Down
35 changes: 35 additions & 0 deletions plugins/inspect-robots-agent/tests/test_policy_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -2791,3 +2791,38 @@ def test_chat_wire_usage_metadata_counts_calls_only(tmp_path: Path) -> None:
)

assert sink.records[0].metadata["llm_usage"] == {"llm_calls": 2}


@pytest.mark.parametrize(
"param, val",
[
("model", 42),
("model", 0),
("base_url", True),
("base_url", False),
("api_key_env", True),
("api_key_env", False),
("speed", False),
],
)
def test_non_string_params_rejected(param: str, val: Any) -> None:
kwargs: dict[str, Any] = {
"model": "test-model",
"base_url": "http://localhost:8000",
"api_key_env": "TEST_KEY",
"effort": "low",
"speed": None,
"wire": "chat",
}
kwargs[param] = val

# speed requires wire='anthropic'
if param == "speed":
kwargs["wire"] = "anthropic"

with pytest.raises(ConfigError) as exc_info:
LLMAgentPolicy(**kwargs)

assert f"{param} must be a string, got {val!r}." in str(exc_info.value)
expected_fix = f"fix: the -P parser coerces unquoted values; pass -P '{param}=\"value\"'"
assert expected_fix in str(exc_info.value)
1 change: 1 addition & 0 deletions tests/test_rerun_sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -1861,6 +1861,7 @@ def test_real_rerun_accepts_the_blueprint(tmp_path: Path) -> None:
def test_real_rerun_process_exits_when_tcp_peer_never_reads() -> None:
"""The real SDK atexit path is bounded after a connected peer stops reading."""
rr = pytest.importorskip("rerun")

if not hasattr(rr, "connect_grpc"):
pytest.skip("pre-gRPC rerun-sdk cannot run the connect-mode wedge scenario")
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Expand Down
Loading