mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(gateway): Wave 1 pre-gateway parity — sessions, progress, notify inbox
Closes empty-panel complaints (Sessions, Progress) and the i_am_idle notification-inbox deadlock identified in the 2026-05-11 gap analysis. All backend service methods already exist; this is pure MCP-surface widening on top of the existing choreographer + ContentActions. New MCP tools (roboco-do): - progress(task_id, message, percentage) — Progress tab writer - open_session(task_id, channel, topic, ...) — Sessions tab writer (PM+) - link_session(session_id, task_id, ...) — Idempotent task↔session - notify_list(unread_only, pending_ack_only, limit) - notify_get(notification_id) - notify_ack(notification_id) Wired through: - roboco/api/schemas/v2/do.py — six new request schemas with Field constraints (Progress.percentage: ge=0, le=100; OpenSession.topic: max_length=200; etc.) - roboco/api/routes/v2/do.py — six new POST routes, thin dispatchers - roboco/services/gateway/content_actions.py — six new ContentActions methods forwarding to TaskService.add_progress, MessagingService.create_session_for_tasks /link_session_to_task, NotificationDeliveryService.list_for_agent / get_for_ recipient_and_mark_read / acknowledge - roboco/mcp/do_server.py — six new typed tool wrappers + registered in _TOOLS - roboco/services/gateway/role_config.py — receivers (list/get/ack) added to every role except auditor (who gets list/get, no ack). Session verbs to PM-or-up. Progress to dev + doc. - agents/prompts/roles/*.md — verb tables updated for developer / QA / documenter / cell_pm / main_pm. i_am_idle line points to notify_list as the deadlock resolution path. Authorization: - progress: assignee + active status (in_progress / verifying / awaiting_qa / awaiting_documentation) - open_session: cell_pm / main_pm / product_owner / head_marketing / ceo - link_session: caller must own the task - notify_ack: caller must be a recipient (ValueError from service maps to not_authorized envelope) Per-file ignore extended: - roboco/services/gateway/**/*.py = [PLC0415, PLR0913] — same rationale as roboco/mcp/**: typed verb signatures are the agent-facing contract; bundling into dataclasses hides field-level schema the LLM needs at the tool layer. Quality: ruff + mypy clean. 503 unit tests pass on touched surfaces. Spec ref: docs/superpowers/specs/2026-05-11-pre-gateway-parity-design.md
This commit is contained in:
@@ -204,6 +204,123 @@ def evidence(task_id: str) -> dict[str, Any]:
|
||||
return _post("/api/v2/do/evidence", {"task_id": task_id})
|
||||
|
||||
|
||||
# ---------- Wave 1 — pre-gateway parity ----------
|
||||
|
||||
|
||||
def progress(task_id: str, message: str, percentage: int) -> dict[str, Any]:
|
||||
"""Append a narrative progress update to YOUR active task.
|
||||
|
||||
Args:
|
||||
task_id: UUID of the task you're working on.
|
||||
message: One-paragraph summary of what just landed.
|
||||
percentage: 0..100 inclusive. Rough completion estimate; bump it as
|
||||
you make progress so PM/QA can see velocity.
|
||||
|
||||
Populates the panel's Progress tab. Use this in addition to ``commit``
|
||||
— commits are git refs; progress is narrative.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/progress",
|
||||
{"task_id": task_id, "message": message, "percentage": percentage},
|
||||
)
|
||||
|
||||
|
||||
def open_session(
|
||||
task_id: str,
|
||||
channel: str,
|
||||
topic: str,
|
||||
relationship_type: str = "discussion",
|
||||
group_id: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""PM creates a discussion session linked to a task.
|
||||
|
||||
Args:
|
||||
task_id: UUID of the task this session discusses.
|
||||
channel: Channel slug without `#` (e.g. ``backend-cell``).
|
||||
topic: Short topic for the session (≤200 chars).
|
||||
relationship_type: ``discussion`` | ``planning`` | ``review`` |
|
||||
``retrospective``.
|
||||
group_id: Optional UUID to place the session under a specific group.
|
||||
|
||||
Populates the panel's Sessions tab. Only PM-or-up roles can open sessions
|
||||
— devs / QA / docs participate via channels and DMs.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/open_session",
|
||||
{
|
||||
"task_id": task_id,
|
||||
"channel": channel,
|
||||
"topic": topic,
|
||||
"relationship_type": relationship_type,
|
||||
"group_id": group_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def link_session(
|
||||
session_id: str,
|
||||
task_id: str,
|
||||
is_primary: bool = False,
|
||||
relationship_type: str = "discussion",
|
||||
) -> dict[str, Any]:
|
||||
"""Link an existing session to a task (idempotent).
|
||||
|
||||
Use when an existing discussion now covers a new task too. You must
|
||||
own the task you're linking; cross-agent linking is denied.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/link_session",
|
||||
{
|
||||
"session_id": session_id,
|
||||
"task_id": task_id,
|
||||
"is_primary": is_primary,
|
||||
"relationship_type": relationship_type,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def notify_list(
|
||||
unread_only: bool = True,
|
||||
pending_ack_only: bool = False,
|
||||
limit: int = 20,
|
||||
) -> dict[str, Any]:
|
||||
"""Read your notification inbox.
|
||||
|
||||
Call this when ``i_am_idle()`` soft-blocks you with an "unread A2A or
|
||||
@mentions" message — list, read each one with ``notify_get``, ack with
|
||||
``notify_ack``, then idle again.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/notify_list",
|
||||
{
|
||||
"unread_only": unread_only,
|
||||
"pending_ack_only": pending_ack_only,
|
||||
"limit": limit,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def notify_get(notification_id: str) -> dict[str, Any]:
|
||||
"""Read one notification (marks it as read)."""
|
||||
return _post(
|
||||
"/api/v2/do/notify_get",
|
||||
{"notification_id": notification_id},
|
||||
)
|
||||
|
||||
|
||||
def notify_ack(notification_id: str) -> dict[str, Any]:
|
||||
"""Acknowledge a notification you've handled.
|
||||
|
||||
The gateway tracks who has acked which notification — required for
|
||||
``requires_ack=true`` notifications before ``i_am_idle`` will let you
|
||||
exit cleanly.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/notify_ack",
|
||||
{"notification_id": notification_id},
|
||||
)
|
||||
|
||||
|
||||
# ---------- Tool registry ----------
|
||||
#
|
||||
# Maps the tool name an agent calls (matches manifest entries and the
|
||||
@@ -216,6 +333,12 @@ _TOOLS: dict[str, Any] = {
|
||||
"dm": dm,
|
||||
"notify": notify,
|
||||
"evidence": evidence,
|
||||
"progress": progress,
|
||||
"open_session": open_session,
|
||||
"link_session": link_session,
|
||||
"notify_list": notify_list,
|
||||
"notify_get": notify_get,
|
||||
"notify_ack": notify_ack,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user