Skip to content

feat(policy): add a resilient agent profile - #99

Merged
jmlago merged 1 commit into
mainfrom
feat/agent-policy-default
Aug 12, 2026
Merged

feat(policy): add a resilient agent profile#99
jmlago merged 1 commit into
mainfrom
feat/agent-policy-default

Conversation

@jmlago

@jmlago jmlago commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary

  • add a reusable agent template and profile:agent for autonomous tool clients
  • enforce tools, 128k context, top-ten intelligence, reliability, price, and trusted AntSeed gates
  • bound each provider attempt with a 10s first-token and 22s request timeout, then fail over to a different candidate
  • retain breaker-open routes only as tail fallbacks instead of making the cascade empty during a broad outage
  • add a GitOps bootstrap caller-key channel that is converted to hash-only storage at process start
  • expose the profile in the dashboard and document profile ownership

Why

Micromarkets was carrying a frozen raw policy. Recent calls spent the complete 50s outer deadline on the first provider and returned 504, so the declared fallback cascade never ran. The shared profile keeps policy fixes centralized and preserves enough deadline for real failover.

Verification

  • python -m pytest tests -q: 737 passed, 2 skipped
  • lua tests/run_lua.lua: 637 passed
  • live-config parity test proves the published template and profile:agent normalize to the same policy
  • execution test proves a timed-out first candidate switches to a second candidate with both timeout parameters applied

Deployment dependency

Merge this first and wait for the Unhardcoded image bump and router rollout before merging the Micromarkets code PR or the devexp wiring PR.

Summary by CodeRabbit

  • New Features

    • Added an autonomous-agent policy profile with provider preferences, reliability and context requirements, trusted-source filtering, quality-based selection, pricing limits, and bounded timeouts.
    • Added fallback behavior that advances to alternate candidates after eligible failures.
    • Added support for securely bootstrapping workload keys by hashing plaintext values before dashboard exposure.
    • Added the “Stable tool agent” option to the dashboard policy builder.
  • Documentation

    • Documented the new agent profile, policy templates, configuration options, and workload-token deployment requirements.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds an agent policy template and profile with ranked provider failover. It also adds hash-only bootstrap caller-key loading and updates dashboard, deployment, authoring, and test coverage.

Changes

Agent policy

Layer / File(s) Summary
Agent template compilation
policy_templates.py, tests/test_policy_templates.py
Adds agent routing constraints, trusted AntSeed filtering, scoring, top-k selection, timeouts, failure actions, catalog registration, and compiler tests.
Agent profile and failover wiring
config.live.lua, auth_proxy.py, tests/test_policy_templates.py, tests/test_auth_proxy_dashboard_full.py, README.md, SKILL.md
Adds the live agent profile, alternate-candidate retry behavior, dashboard selection, documentation, and integration validation.

Bootstrap caller keys

Layer / File(s) Summary
Hash-only bootstrap key loading
auth_proxy.py, tests/test_auth_proxy_dashboard_full.py, docs/DEPLOY.md
Loads bootstrap tokens from JSON, hashes them in memory, preserves ownership, merges hashed keys, and documents Secret storage requirements.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant AgentProfile as profiles.agent
  participant Policy as agent_policy_ir
  participant Providers
  participant Retry as retry_policies.agent
  Caller->>AgentProfile: submit agent request
  AgentProfile->>Policy: filter and rank candidates
  Policy->>Providers: attempt selected candidate
  Providers-->>AgentProfile: result or timeout
  AgentProfile->>Retry: classify recoverable failure
  Retry->>Providers: advance to next candidate
  Providers-->>AgentProfile: fallback result
  AgentProfile-->>Caller: return response
Loading

Suggested reviewers: muncleuscles

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a resilient agent policy profile.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-policy-default

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jmlago
jmlago merged commit a0a1503 into main Aug 12, 2026
3 of 4 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
policy_templates.py (2)

398-408: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider one shared fail-plan builder.

_agent_fail_plan repeats the fold that _balanced_fail_plan already performs, only over a different action map. Extract one helper that takes the action map and returns the plan. This keeps the plan shape identical for both templates and for the Lua fail_plan helper in config.live.lua.

♻️ Proposed refactor
-def _agent_fail_plan() -> list:
-    plan: list = ["always", dict(_AGENT_FAILURE_ACTIONS["unknown"])]
-    for reason in sorted(_AGENT_FAILURE_ACTIONS):
-        if reason != "unknown":
-            plan = [
-                "override",
-                plan,
-                reason,
-                dict(_AGENT_FAILURE_ACTIONS[reason]),
-            ]
-    return plan
+def _fail_plan(actions: dict[str, dict[str, Any]]) -> list:
+    plan: list = ["always", dict(actions["unknown"])]
+    for reason in sorted(actions):
+        if reason != "unknown":
+            plan = ["override", plan, reason, dict(actions[reason])]
+    return plan

Then call _fail_plan(_AGENT_FAILURE_ACTIONS) and _fail_plan(_BALANCED_FAILURE_ACTIONS).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy_templates.py` around lines 398 - 408, Extract the shared fold logic
from _agent_fail_plan and _balanced_fail_plan into a helper such as _fail_plan
that accepts an action map and produces the same nested plan shape. Update both
builders to delegate to this helper with their respective action maps,
preserving the ordering and handling of the "unknown" entry used by the Lua
fail_plan equivalent.

44-76: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The agent rails are defined twice and can drift. Both files hold the same provider order, thresholds, scoring weights, timeouts, and the five trusted AntSeed peer identities. Only the fingerprint parity test in tests/test_policy_templates.py couples them, so any edit to one side breaks that test instead of updating the other side automatically.

  • policy_templates.py#L44-L76: add a comment that names config.live.lua as the mirror of these constants, and state that both sides must change together.
  • config.live.lua#L49-L76: add the same cross-reference to policy_templates.py, or load the peer identities from a single shared data file that both the Lua config and the Python compiler read.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@policy_templates.py` around lines 44 - 76, Document the synchronization
contract for the duplicated agent rails: in policy_templates.py around
AGENT_PROVIDER_ORDER and the related constants, add a comment naming
config.live.lua as the mirror and requiring both sides to change together; add
the reciprocal cross-reference comment around the corresponding constants in
config.live.lua (49-76). Do not alter the provider values, thresholds, weights,
timeouts, or trusted peer identities.
config.live.lua (1)

726-730: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the profile-level selector field. When policy_ir is present, the router compiles that term directly and ignores profile.selector. agent_policy_ir() already embeds {"top_k", AGENT_TOP_K, ...} with AGENT_TOP_K = 8.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@config.live.lua` around lines 726 - 730, Remove the profile-level selector
assignment from the agent configuration. In the agent table near policy_ir and
retry_policy, delete selector = "top_k" and retain agent_policy_ir() as the
source of the top_k behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 146-152: Update the README `agent` template bullet to state its
actual $15 input and $30 output per-million-token price ceilings, matching
`AGENT_MAX_PRICE_IN` and `AGENT_MAX_PRICE_OUT` in `policy_templates.py`.

In `@tests/test_auth_proxy_dashboard_full.py`:
- Around line 1306-1314: Add an inline Ruff S105 suppression to the test fixture
assignment for token in test_gitops_bootstrap_keys_are_loaded_hash_only, keeping
the existing fixture value and assertions unchanged.

---

Nitpick comments:
In `@config.live.lua`:
- Around line 726-730: Remove the profile-level selector assignment from the
agent configuration. In the agent table near policy_ir and retry_policy, delete
selector = "top_k" and retain agent_policy_ir() as the source of the top_k
behavior.

In `@policy_templates.py`:
- Around line 398-408: Extract the shared fold logic from _agent_fail_plan and
_balanced_fail_plan into a helper such as _fail_plan that accepts an action map
and produces the same nested plan shape. Update both builders to delegate to
this helper with their respective action maps, preserving the ordering and
handling of the "unknown" entry used by the Lua fail_plan equivalent.
- Around line 44-76: Document the synchronization contract for the duplicated
agent rails: in policy_templates.py around AGENT_PROVIDER_ORDER and the related
constants, add a comment naming config.live.lua as the mirror and requiring both
sides to change together; add the reciprocal cross-reference comment around the
corresponding constants in config.live.lua (49-76). Do not alter the provider
values, thresholds, weights, timeouts, or trusted peer identities.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 37f59d03-8b83-4af5-a1fc-f7fc1835f79c

📥 Commits

Reviewing files that changed from the base of the PR and between 3085c1e and 14bc9e0.

📒 Files selected for processing (8)
  • README.md
  • SKILL.md
  • auth_proxy.py
  • config.live.lua
  • docs/DEPLOY.md
  • policy_templates.py
  • tests/test_auth_proxy_dashboard_full.py
  • tests/test_policy_templates.py

Comment thread README.md
Comment on lines +146 to +152
- `agent` — the reusable `profile:agent` policy for autonomous tool users:
require tools, 128k context, top-ten measured intelligence and reliable,
priced routes; prefer healthy Codex/direct providers before gateways and
trusted AntSeed peers; cap the cascade at eight candidates. The policy also
sets a 10s first-token and 22s per-attempt timeout and moves immediately to a
different candidate on provider failures, so a stalled first route cannot
consume the complete request deadline.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

State the agent price ceilings in this bullet.

The paragraph below this list says all templates default to $5 input / $25 output per-million-token ceilings. The agent template uses $15 input and $30 output (AGENT_MAX_PRICE_IN, AGENT_MAX_PRICE_OUT in policy_templates.py). Add the actual rails here so the document stays accurate.

📝 Proposed fix
 - `agent` — the reusable `profile:agent` policy for autonomous tool users:
   require tools, 128k context, top-ten measured intelligence and reliable,
-  priced routes; prefer healthy Codex/direct providers before gateways and
+  priced routes under $15 input / $30 output per million tokens; prefer
+  healthy Codex/direct providers before gateways and
   trusted AntSeed peers; cap the cascade at eight candidates. The policy also
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `agent` — the reusable `profile:agent` policy for autonomous tool users:
require tools, 128k context, top-ten measured intelligence and reliable,
priced routes; prefer healthy Codex/direct providers before gateways and
trusted AntSeed peers; cap the cascade at eight candidates. The policy also
sets a 10s first-token and 22s per-attempt timeout and moves immediately to a
different candidate on provider failures, so a stalled first route cannot
consume the complete request deadline.
- `agent` — the reusable `profile:agent` policy for autonomous tool users:
require tools, 128k context, top-ten measured intelligence and reliable,
priced routes under $15 input / $30 output per million tokens; prefer
healthy Codex/direct providers before gateways and
trusted AntSeed peers; cap the cascade at eight candidates. The policy also
sets a 10s first-token and 22s per-attempt timeout and moves immediately to a
different candidate on provider failures, so a stalled first route cannot
consume the complete request deadline.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 146 - 152, Update the README `agent` template bullet
to state its actual $15 input and $30 output per-million-token price ceilings,
matching `AGENT_MAX_PRICE_IN` and `AGENT_MAX_PRICE_OUT` in
`policy_templates.py`.

Comment on lines +1306 to +1314
def test_gitops_bootstrap_keys_are_loaded_hash_only():
token = "llmr_reconciled"
loaded = auth_proxy._bootstrap_caller_key_hashes(
f'{{"{token}":"micromarkets-dev"}}')

assert loaded == {
hashlib.sha256(token.encode()).hexdigest(): "micromarkets-dev",
}
assert token not in loaded

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Silence the Ruff S105 finding on the test token.

Ruff flags token = "llmr_reconciled" as a possible hardcoded password (S105). The value is a test fixture, so add an inline suppression to keep the lint run clean.

🧹 Proposed fix
-    token = "llmr_reconciled"
+    token = "llmr_reconciled"  # noqa: S105 - test fixture, not a real secret
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_gitops_bootstrap_keys_are_loaded_hash_only():
token = "llmr_reconciled"
loaded = auth_proxy._bootstrap_caller_key_hashes(
f'{{"{token}":"micromarkets-dev"}}')
assert loaded == {
hashlib.sha256(token.encode()).hexdigest(): "micromarkets-dev",
}
assert token not in loaded
def test_gitops_bootstrap_keys_are_loaded_hash_only():
token = "llmr_reconciled" # noqa: S105 - test fixture, not a real secret
loaded = auth_proxy._bootstrap_caller_key_hashes(
f'{{"{token}":"micromarkets-dev"}}')
assert loaded == {
hashlib.sha256(token.encode()).hexdigest(): "micromarkets-dev",
}
assert token not in loaded
🧰 Tools
🪛 Ruff (0.16.1)

[error] 1307-1307: Possible hardcoded password assigned to: "token"

(S105)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_auth_proxy_dashboard_full.py` around lines 1306 - 1314, Add an
inline Ruff S105 suppression to the test fixture assignment for token in
test_gitops_bootstrap_keys_are_loaded_hash_only, keeping the existing fixture
value and assertions unchanged.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant