mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix: restore pre-gateway structured verb surfaces (5 fixes)
Smoke run 2026-05-11 showed five regressions stemming from the gateway consolidating multiple typed endpoints into thin verbs with collapsed signatures. The choreography is fine; the verb signatures lost the structured shape that pre-gateway forced agents to fill. Each fix restores a structured surface so the LLM's tool schema again carries the constraints that prevent the observed bugs. A) do_server: list valid channel slugs in say()/dm() docstrings. Stops invented channels (`backend`, `backend-dev`) — the LLM now sees the closed set in the tool schema. B) choreographer: add _delegate_sibling_dedup_guard. Rejects a delegate that would create a non-terminal sibling with the same assigned_to + task_type under the same parent — the dupe shape observed on smoke (Main PM creating two planning tasks for be-pm; Cell PM creating two code tasks for be-dev-1). C) choreographer: extend _validate_assignee_task_type to all roles. Devs may only get code|documentation|research (not planning/design/ administrative). QA gets code only. Documenters get documentation only. Catches the misroute observed on smoke (Cell PM gave be-dev-2 a 'research' coordination task that should have stayed with the PM). D) i_will_plan: thread approach / technical_considerations / risks / open_questions from MCP through to TaskService.set_plan as a TaskPlan-shaped dict. Empty default keeps back-compat. Panel's Plan tab now renders Approach / Sub-Tasks / Technical Considerations / Risks / Open Questions instead of an empty pane. E) note(): scope-specific structured fields restored. For 'decision' scope: context, options[], chosen, rationale, consequences. For 'reflect' scope: what_done, what_learned, what_struggled, next_steps. Rendered as markdown sections into the journal entry content so the Decisions and Reflections views show named blocks instead of a one-line phrase. Pre-gateway parity. Files changed: - roboco/mcp/do_server.py (A, E) - roboco/mcp/flow_server.py (D) - roboco/services/gateway/choreographer/_impl.py (B, C, D) - roboco/services/gateway/content_actions.py (E) - roboco/api/schemas/v2/flow.py (D) - roboco/api/schemas/v2/do.py (E) - roboco/api/routes/v2/flow_main_pm.py (D) - roboco/api/routes/v2/flow_cell_pm.py (D) - roboco/api/routes/v2/do.py (E) Quality: ruff + mypy clean. 89 unit tests pass on the touched surfaces.
This commit is contained in:
+69
-5
@@ -86,13 +86,70 @@ def commit(message: str, files: list[str] | None = None) -> dict[str, Any]:
|
||||
return _post("/api/v2/do/commit", {"message": message, "files": files})
|
||||
|
||||
|
||||
def note(text: str, scope: str = "note", task_id: str | None = None) -> dict[str, Any]:
|
||||
"""Write a journal entry. scope in note|decision|reflect|learning|struggle."""
|
||||
return _post("/api/v2/do/note", {"text": text, "scope": scope, "task_id": task_id})
|
||||
def note(
|
||||
text: str,
|
||||
scope: str = "note",
|
||||
task_id: str | None = None,
|
||||
title: str | None = None,
|
||||
context: str | None = None,
|
||||
options: list[str] | None = None,
|
||||
chosen: str | None = None,
|
||||
rationale: str | None = None,
|
||||
consequences: str | None = None,
|
||||
what_done: str | None = None,
|
||||
what_learned: str | None = None,
|
||||
what_struggled: str | None = None,
|
||||
next_steps: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Write a journal entry. scope in note|decision|reflect|learning|struggle.
|
||||
|
||||
``text`` is always the short summary (one paragraph max). For ``decision``
|
||||
and ``reflect`` scopes, fill the scope-specific structured fields so the
|
||||
panel renders them as named sections — pre-gateway parity:
|
||||
|
||||
- decision: ``context`` (the situation), ``options`` (list of strings,
|
||||
one per alternative considered), ``chosen`` (the alternative you took),
|
||||
``rationale`` (why), ``consequences`` (what this commits us to)
|
||||
- reflect: ``what_done`` (literal output), ``what_learned`` (new info),
|
||||
``what_struggled`` (where you got stuck), ``next_steps`` (follow-ups)
|
||||
|
||||
Other scopes (note / learning / struggle) just need ``text``.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/note",
|
||||
{
|
||||
"text": text,
|
||||
"scope": scope,
|
||||
"task_id": task_id,
|
||||
"title": title,
|
||||
"context": context,
|
||||
"options": options,
|
||||
"chosen": chosen,
|
||||
"rationale": rationale,
|
||||
"consequences": consequences,
|
||||
"what_done": what_done,
|
||||
"what_learned": what_learned,
|
||||
"what_struggled": what_struggled,
|
||||
"next_steps": next_steps,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def say(channel: str, text: str, task_id: str | None = None) -> dict[str, Any]:
|
||||
"""Post to a channel. task_id auto-injected if you have an active task."""
|
||||
"""Post to a channel. task_id auto-injected if you have an active task.
|
||||
|
||||
Args:
|
||||
channel: Channel slug WITHOUT leading `#`. Valid values:
|
||||
- Cell channels: `backend-cell`, `frontend-cell`, `uxui-cell`
|
||||
- Cross-cell: `dev-all`, `qa-all`, `pm-all`, `doc-all`
|
||||
- Management: `main-pm-board`, `board-private`
|
||||
- Broadcast: `announcements`, `all-hands`
|
||||
Write access varies by role — gateway returns `not_authorized` if
|
||||
you cannot write to the requested channel; the error lists which
|
||||
channels you can write to.
|
||||
text: Message body.
|
||||
task_id: Optional; auto-filled from your active task if omitted.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/say",
|
||||
{"channel": channel, "text": text, "task_id": task_id},
|
||||
@@ -105,7 +162,14 @@ def dm(
|
||||
task_id: str | None = None,
|
||||
skill: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""A2A message. Auto-creates conversation; auto-resolves skill if needed."""
|
||||
"""A2A message. Auto-creates conversation; auto-resolves skill if needed.
|
||||
|
||||
Args:
|
||||
recipient: Target agent slug (e.g. `be-pm`, `be-dev-1`, `ceo`).
|
||||
text: Message body.
|
||||
task_id: Optional; auto-filled from your active task if omitted.
|
||||
skill: Optional skill slug to scope the conversation.
|
||||
"""
|
||||
return _post(
|
||||
"/api/v2/do/dm",
|
||||
{"recipient": recipient, "text": text, "task_id": task_id, "skill": skill},
|
||||
|
||||
Reference in New Issue
Block a user