mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(gateway): G8 part b — typed blocker_type + what_needed on i_am_blocked
Pre-gateway parity (G8 part b of the 2026-05-11 design). The pre-gateway TaskBlockInput at 254cc93:roboco/mcp/schemas/__init__.py required blocker_type (external|internal|question|dependency) and what_needed so PMs could triage their inbox by class. Current i_am_blocked dropped both fields — every blocked task looked the same to the PM. Now i_am_blocked accepts both as optional kwargs: - Back-compat: callers that omit them still work (blocker_type defaults to None → rendered as flat reason in the struggle entry). - New: when supplied, the struggle journal entry body is structured markdown (## Blocker Type / ## What Needed sections) so the panel's journal view renders named blocks instead of one flat sentence. Validator on blocker_type enforces the enum at the Pydantic boundary with a clear "must be one of: ..." error if the agent invents a value (same pattern as the Wave 3 G7 validators). G8 part a — typed `pause(checkpoint_summary, remaining_work)` — defers. That gap needs a new IntentSpec in foundation/policy/lifecycle.py (currently pause is an ActionSpec only; agents auto-pause via i_am_idle) plus checkpoint wiring through TaskService.add_checkpoint. Material work, deferred until after the user has deployed and verified G7 + G8b lands cleanly. Wired: - roboco/api/schemas/v2/flow.py — IAmBlockedRequest gains optional blocker_type + what_needed; @field_validator enforces the enum - roboco/api/routes/v2/flow_dev.py — passes the new fields through - roboco/services/gateway/choreographer/_impl.py — i_am_blocked signature + structured struggle-entry rendering - roboco/mcp/flow_server.py — typed wrapper with the kwargs - agents/prompts/roles/developer.md — updated verb table - tests/unit/mcp_servers/test_flow_server.py — updated to expect the new optional kwargs as None when omitted Quality: ruff + mypy clean. 505 tests pass.
This commit is contained in:
@@ -184,7 +184,16 @@ def test_i_am_blocked_sends_reason(flow_module: types.ModuleType) -> None:
|
||||
|
||||
assert result == {"status": "blocked"}
|
||||
_, kwargs = fake_client.post.call_args
|
||||
assert kwargs["json"] == {"task_id": "task-xyz", "reason": "waiting for env var"}
|
||||
# Pre-gateway parity (G8): i_am_blocked now also carries optional
|
||||
# blocker_type / what_needed — when caller omits them the wrapper
|
||||
# forwards `None` so the backend can fall back to the default
|
||||
# 'internal' classification.
|
||||
assert kwargs["json"] == {
|
||||
"task_id": "task-xyz",
|
||||
"reason": "waiting for env var",
|
||||
"blocker_type": None,
|
||||
"what_needed": None,
|
||||
}
|
||||
|
||||
|
||||
def test_i_am_idle_posts_empty_body(flow_module: types.ModuleType) -> None:
|
||||
|
||||
Reference in New Issue
Block a user