fix: post-finale completeness sweep — routing surface, provider config, budgets, compose env, interactive exemption (#661)

This commit is contained in:
Renzo F
2026-07-23 09:41:27 +02:00
committed by GitHub
parent 21d6730400
commit d4b7e1e7b8
45 changed files with 2064 additions and 256 deletions
+9 -1
View File
@@ -1,5 +1,5 @@
## Purpose
This slice is the agent-runtime + LLM-provider seam plus the in-container agent SDK. The provider layer (roboco/llm/providers/) abstracts how agents are spawned/stopped/health-checked/removed across LLM backends (Claude Code default, Grok CLI) behind an AgentProvider ABC + ProviderRegistry, with a Grok auth-token refresh loop keeping the SuperGrok credential live. The agent SDK (roboco/agent_sdk/) is the FastAPI sidecar running inside every agent container handling A2A messaging, tool-budget/loop/verb-circuit breakers, token-usage capture, and the interactive intake/secretary chat drivers (Claude SDK + Grok CLI). The runtime helpers (spawn_manifest, streaming, transcript_retention) build the per-role tool manifest, wire reasoning-stream callbacks, and select old agent transcripts to prune.
This slice is the agent-runtime + LLM-provider seam plus the in-container agent SDK. The provider layer (roboco/llm/providers/) abstracts how agents are spawned/stopped/health-checked/removed across LLM backends (Claude Code default, Grok CLI, Codex CLI, Gemini CLI) behind an AgentProvider ABC + ProviderRegistry, with a Grok auth-token refresh loop keeping the SuperGrok credential live and an orchestrator-side Codex refresh loop keeping the ChatGPT-subscription credential live (Gemini needs neither — its OAuth refresh token is reusable, so each container refreshes its own local copy in-process). The agent SDK (roboco/agent_sdk/) is the FastAPI sidecar running inside every agent container handling A2A messaging, tool-budget/loop/verb-circuit breakers, token-usage capture, and the interactive intake/secretary chat drivers (Claude SDK + Grok CLI — Codex and Gemini are one-shot delivery roles only, no interactive intake/secretary support). The runtime helpers (spawn_manifest, streaming, transcript_retention) build the per-role tool manifest, wire reasoning-stream callbacks, and select old agent transcripts to prune.
## Files
@@ -23,6 +23,14 @@ This slice is the agent-runtime + LLM-provider seam plus the in-container agent
| roboco/llm/providers/grok_auth.py | SuperGrok token refresh-token grant loop + --check backstop CLI; atomic auth.json rewrite | 317 |
| roboco/llm/providers/grok_cli_config.py | Entrypoint renderer: mcp-config -> ~/.grok/config.toml, per-role grok flags, AGENTS.md, bash-guard hook, + default-off fable-mode honesty-nudge hook | 317 |
| roboco/llm/providers/grok_cli_usage.py | Capture token usage from grok sessions/updates.jsonl -> usage.json (notional cost) | 201 |
| roboco/llm/providers/codex.py | CodexCliProvider: spawns roboco-agent-codex container, mounts ~/.codex dir (RO) + usage dir + codex env | 239 |
| roboco/llm/providers/codex_auth.py | ChatGPT-subscription refresh-token grant loop + --check backstop CLI; JWT-exp decode (only expiry signal), atomic auth.json rewrite | 298 |
| roboco/llm/providers/codex_cli_config.py | Entrypoint renderer: mcp-config -> ~/.codex/config.toml, Starlark execpolicy deny rules, per-role --sandbox level, combined system+task prompt (no verified system-prompt-file mechanism) | 277 |
| roboco/llm/providers/codex_cli_usage.py | Capture token usage from codex exec --json turn.completed events -> usage.json (real input/output/cache-read/cache-write split, priced per-bucket) | 184 |
| roboco/llm/providers/codex_cli_sniff.py | Classify a codex run's terminal state (rate_limit/auth/none) from ONLY structured error.message JSONL fields + stderr, never the model's own transcript | 124 |
| roboco/llm/providers/gemini.py | GeminiCliProvider: spawns roboco-agent-gemini container, copies host ~/.gemini OAuth creds into a container-local writable copy + usage dir + gemini env | 264 |
| roboco/llm/providers/gemini_cli_config.py | Entrypoint renderer: mcp-config -> ~/.gemini/settings.json + per-role TOML Policy Engine deny rules (no native tool-removal flag), GEMINI.md blueprint | 293 |
| roboco/llm/providers/gemini_cli_usage.py | Capture token usage from gemini --output-format stream-json terminal result event -> usage.json (per-GA-model pricing); remaps quota/rate-limit errors to exit 75 | 290 |
| roboco/agent_sdk/__init__.py | Package docstring only | 10 |
| roboco/agent_sdk/models.py | Pydantic models: A2A messages, budget/terminal/verb-circuit/token-usage request+status | 258 |
| roboco/agent_sdk/prompt_guard.py | Prompt-injection detector (5 patterns) + CLI for grok entrypoint turn scan | 93 |
@@ -10,6 +10,8 @@ RoboCo's HTTP request layer is protected by `fastapi-guard` (v7.2.1), implemente
|----------|---------|--------|
| `ROBOCO_GUARD_ENABLED` | `false` | Master switch. Off = completely inert — no middleware is mounted, the request path is entirely unchanged, and nothing is logged or blocked. |
| `ROBOCO_GUARD_PASSIVE_MODE` | see below | When the guard is enabled, controls whether it blocks matching requests or only logs them. |
| `ROBOCO_GUARD_EMERGENCY_WHITELIST` | `` (empty) | Comma-separated IPs/CIDRs always allowed through in an active `ROBOCO_GUARD_EMERGENCY` lockdown, in addition to loopback. Empty = loopback only. |
| `ROBOCO_GUARD_TRUSTED_CHAIN_PEERS` | `` (empty) | Comma-separated exact IP address(es) — never a CIDR range — trusted to appear as a recorded proxy hop inside `X-Forwarded-For` beyond loopback, e.g. the docker bridge gateway a host-proxied Tailscale Serve chain terminates behind, so the resolved client is the real tailnet/LAN peer instead of that hop's own address. Empty = only a loopback rightmost hop ever peels. |
As of 2026-07-19 the guard is gated off by default in config, but the NAS build compose arms it ON in ACTIVE enforcement (`ROBOCO_GUARD_PASSIVE_MODE=false`) — passive/log-only calibration came back clean, and the CEO approved the flip now that cloud auth + Tailscale are armed. A matching request on that deploy is actually blocked, not just logged. The registry compose still ships it fully off (see Enforcement Posture below).
+4
View File
@@ -25,3 +25,7 @@ notify_ack(notification_id) # acknowledge after handling
```
When `i_am_idle()` reports unread A2A or @mentions, clear A2A with `read_a2a()` (see `a2a-tools.md`) and clear notifications with list -> get -> ack, then idle again. (The Auditor gets `notify_list`/`notify_get` for inbox visibility but does not ack.)
## Unacked notifications re-escalate
An ack-required `notify` left unacked past its `expires_at` is re-escalated to the recipient's up-role (your PM's PM, or the CEO) — but not on every sweep tick. The first re-escalation fires at expiry, each one after that doubles the wait (1h, 2h, 4h, ... capped at 24h), and after a fixed number of attempts it stops and is logged as permanently unacked. Acking promptly is the only way to stop the clock — there is no way to snooze or dismiss a notification other than `notify_ack`.
+1
View File
@@ -50,6 +50,7 @@ If your task has `dependency_ids` in the same repo, the fresh branch cut also ba
- **Self-documentation prevention**: Documenter cannot claim tasks they developed
- **Branch requirement**: Branch auto-created on `i_will_work_on`
- **Sequence order (strict, assignee-blind)**: if a task has a parent and a `sequence` number, it cannot be claimed while any sibling with a strictly lower sequence is still non-terminal — regardless of who owns which task. Siblings on the SAME sequence run in parallel (independent work ties at 0, or at the wave a delegating PM stamped from the collision graph). This is independent of, and stricter than, `dependency_ids`: a claim attempt on a sequence-held task fails even with no unmet dependency. The error names the blocking sibling by title — `unclaim`/wait is the only remedy, there is no override verb. The dispatcher pre-filters sequence-held (and dependency-held) tasks before attempting a claim, so you should rarely see this in practice — but a claim you make directly (rather than via `give_me_work`) can still hit it.
- **Project budget cap** (when task budgets are armed): `i_will_work_on` / `i_will_plan` are refused once the project's `monthly_budget_usd` has been reached this calendar month — a WORK-STARTING claim only, so a QA/doc/PR-review/PM-merge claim on already-in-flight work is never blocked by this. There is no override; wait for the next month or ask the CEO to raise the cap.
## Releasing a Claimed Task