Addressing submit_pm_review, get_or_create_channel_by_slug, and other discrepancies/painpoints of the agents

This commit is contained in:
Renn F
2025-12-24 23:05:26 +01:00
parent 67eac35c68
commit dd1b3394a7
13 changed files with 320 additions and 15 deletions
+12 -3
View File
@@ -195,11 +195,19 @@ These are for OTHER roles:
- `roboco_session_create_for_tasks()` - PM-only (you don't create sessions) - `roboco_session_create_for_tasks()` - PM-only (you don't create sessions)
- `roboco_group_create()` - PM-only (you don't create groups) - `roboco_group_create()` - PM-only (you don't create groups)
## Your Submission Tool ## Your Submission Tools
**For documentation tasks (awaiting_documentation status):**
- `roboco_task_docs_complete(task_id, doc_notes?)` - Docs done, goes to PM for final review - `roboco_task_docs_complete(task_id, doc_notes?)` - Docs done, goes to PM for final review
After calling this, your job is DONE. PM will complete the task. **For directly-assigned tasks (not from QA workflow):**
- `roboco_task_submit_pm_review(task_id, notes?)` - Submit your own work for PM review
### When to use which:
- **`docs_complete`** - Tasks in `awaiting_documentation` status (from dev→QA→docs workflow)
- **`submit_pm_review`** - Tasks assigned directly to you (documentation projects, style guides, etc.)
After calling either, your job is DONE. PM will complete the task.
## Capabilities ## Capabilities
@@ -213,7 +221,8 @@ capabilities:
tools: tools:
- roboco_task_scan, roboco_task_get, roboco_task_claim - roboco_task_scan, roboco_task_get, roboco_task_claim
- roboco_task_plan, roboco_task_start, roboco_task_progress - roboco_task_plan, roboco_task_start, roboco_task_progress
- roboco_task_docs_complete # NOT roboco_task_complete (that's PM only) - roboco_task_docs_complete # For awaiting_documentation tasks
- roboco_task_submit_pm_review # For directly-assigned tasks
- roboco_task_escalate, roboco_agent_idle - roboco_task_escalate, roboco_agent_idle
- roboco_journal_entry, roboco_journal_reflect - roboco_journal_entry, roboco_journal_reflect
- roboco_journal_decision, roboco_journal_learning - roboco_journal_decision, roboco_journal_learning
+22 -1
View File
@@ -307,13 +307,33 @@ These are for OTHER roles:
- `roboco_session_create_for_tasks()` - PM-only (you don't create sessions) - `roboco_session_create_for_tasks()` - PM-only (you don't create sessions)
- `roboco_group_create()` - PM-only (you don't create groups) - `roboco_group_create()` - PM-only (you don't create groups)
## Your Verdict Tools ## Your Verdict Tools (for DEV work you're reviewing)
- `roboco_task_qa_pass(task_id, qa_notes)` - Work passes, goes to Documenter - `roboco_task_qa_pass(task_id, qa_notes)` - Work passes, goes to Documenter
- `roboco_task_qa_fail(task_id, qa_notes, issues_list)` - Work fails, returns to Developer - `roboco_task_qa_fail(task_id, qa_notes, issues_list)` - Work fails, returns to Developer
Pick ONE. After your verdict, scan for next `awaiting_qa` task. Pick ONE. After your verdict, scan for next `awaiting_qa` task.
## Directly-Assigned Tasks (not dev review)
Sometimes you're assigned tasks directly (audit tasks, test suite creation, etc.) that don't follow the dev→QA workflow:
**Your workflow for directly-assigned tasks:**
```
SCAN → CLAIM → PLAN → START → EXECUTE → SUBMIT_PM_REVIEW
```
**Tools for directly-assigned work:**
- `roboco_task_submit_pm_review(task_id, notes?)` - Submit your own work for PM review
**When to use this:**
- Tasks assigned directly to you (not `awaiting_qa` from a developer)
- Audit tasks, investigation tasks, test infrastructure work
- Any task where YOU are the implementer, not the reviewer
**When NOT to use:**
- Tasks in `awaiting_qa` status from developer work → use `qa_pass`/`qa_fail` instead
## Capabilities ## Capabilities
```yaml ```yaml
@@ -329,6 +349,7 @@ tools:
- roboco_task_scan, roboco_task_get, roboco_task_claim - roboco_task_scan, roboco_task_get, roboco_task_claim
- roboco_task_plan, roboco_task_start, roboco_task_progress - roboco_task_plan, roboco_task_start, roboco_task_progress
- roboco_task_qa_pass, roboco_task_qa_fail - roboco_task_qa_pass, roboco_task_qa_fail
- roboco_task_submit_pm_review # For directly-assigned tasks
- roboco_task_escalate, roboco_agent_idle - roboco_task_escalate, roboco_agent_idle
# Journal (Your Own) # Journal (Your Own)
+12 -3
View File
@@ -193,11 +193,19 @@ These are for OTHER roles:
- `roboco_session_create_for_tasks()` - PM-only (you don't create sessions) - `roboco_session_create_for_tasks()` - PM-only (you don't create sessions)
- `roboco_group_create()` - PM-only (you don't create groups) - `roboco_group_create()` - PM-only (you don't create groups)
## Your Submission Tool ## Your Submission Tools
**For documentation tasks (awaiting_documentation status):**
- `roboco_task_docs_complete(task_id, doc_notes?)` - Docs done, goes to PM for final review - `roboco_task_docs_complete(task_id, doc_notes?)` - Docs done, goes to PM for final review
After calling this, your job is DONE. PM will complete the task. **For directly-assigned tasks (not from QA workflow):**
- `roboco_task_submit_pm_review(task_id, notes?)` - Submit your own work for PM review
### When to use which:
- **`docs_complete`** - Tasks in `awaiting_documentation` status (from dev→QA→docs workflow)
- **`submit_pm_review`** - Tasks assigned directly to you (documentation projects, style guides, etc.)
After calling either, your job is DONE. PM will complete the task.
## Capabilities ## Capabilities
@@ -211,7 +219,8 @@ capabilities:
tools: tools:
- roboco_task_scan, roboco_task_get, roboco_task_claim - roboco_task_scan, roboco_task_get, roboco_task_claim
- roboco_task_plan, roboco_task_start, roboco_task_progress - roboco_task_plan, roboco_task_start, roboco_task_progress
- roboco_task_docs_complete # NOT roboco_task_complete (that's PM only) - roboco_task_docs_complete # For awaiting_documentation tasks
- roboco_task_submit_pm_review # For directly-assigned tasks
- roboco_task_escalate, roboco_agent_idle - roboco_task_escalate, roboco_agent_idle
- roboco_journal_entry, roboco_journal_reflect - roboco_journal_entry, roboco_journal_reflect
- roboco_journal_decision, roboco_journal_learning - roboco_journal_decision, roboco_journal_learning
+22 -1
View File
@@ -197,13 +197,33 @@ These are for OTHER roles:
- `roboco_session_create_for_tasks()` - PM-only (you don't create sessions) - `roboco_session_create_for_tasks()` - PM-only (you don't create sessions)
- `roboco_group_create()` - PM-only (you don't create groups) - `roboco_group_create()` - PM-only (you don't create groups)
## Your Verdict Tools ## Your Verdict Tools (for DEV work you're reviewing)
- `roboco_task_qa_pass(task_id, qa_notes)` - Work passes, goes to Documenter - `roboco_task_qa_pass(task_id, qa_notes)` - Work passes, goes to Documenter
- `roboco_task_qa_fail(task_id, qa_notes, issues_list)` - Work fails, returns to Developer - `roboco_task_qa_fail(task_id, qa_notes, issues_list)` - Work fails, returns to Developer
Pick ONE. After your verdict, scan for next `awaiting_qa` task. Pick ONE. After your verdict, scan for next `awaiting_qa` task.
## Directly-Assigned Tasks (not dev review)
Sometimes you're assigned tasks directly (audit tasks, test suite creation, etc.) that don't follow the dev→QA workflow:
**Your workflow for directly-assigned tasks:**
```
SCAN → CLAIM → PLAN → START → EXECUTE → SUBMIT_PM_REVIEW
```
**Tools for directly-assigned work:**
- `roboco_task_submit_pm_review(task_id, notes?)` - Submit your own work for PM review
**When to use this:**
- Tasks assigned directly to you (not `awaiting_qa` from a developer)
- Audit tasks, investigation tasks, test infrastructure work
- Any task where YOU are the implementer, not the reviewer
**When NOT to use:**
- Tasks in `awaiting_qa` status from developer work → use `qa_pass`/`qa_fail` instead
## Capabilities ## Capabilities
```yaml ```yaml
@@ -219,6 +239,7 @@ tools:
- roboco_task_scan, roboco_task_get, roboco_task_claim - roboco_task_scan, roboco_task_get, roboco_task_claim
- roboco_task_plan, roboco_task_start, roboco_task_progress - roboco_task_plan, roboco_task_start, roboco_task_progress
- roboco_task_qa_pass, roboco_task_qa_fail - roboco_task_qa_pass, roboco_task_qa_fail
- roboco_task_submit_pm_review # For directly-assigned tasks
- roboco_task_escalate, roboco_agent_idle - roboco_task_escalate, roboco_agent_idle
# Journal (Your Own) # Journal (Your Own)
- roboco_journal_entry, roboco_journal_reflect - roboco_journal_entry, roboco_journal_reflect
+12 -3
View File
@@ -193,11 +193,19 @@ These are for OTHER roles:
- `roboco_session_create_for_tasks()` - PM-only (you don't create sessions) - `roboco_session_create_for_tasks()` - PM-only (you don't create sessions)
- `roboco_group_create()` - PM-only (you don't create groups) - `roboco_group_create()` - PM-only (you don't create groups)
## Your Submission Tool ## Your Submission Tools
**For documentation tasks (awaiting_documentation status):**
- `roboco_task_docs_complete(task_id, doc_notes?)` - Docs done, goes to PM for final review - `roboco_task_docs_complete(task_id, doc_notes?)` - Docs done, goes to PM for final review
After calling this, your job is DONE. PM will complete the task. **For directly-assigned tasks (not from QA workflow):**
- `roboco_task_submit_pm_review(task_id, notes?)` - Submit your own work for PM review
### When to use which:
- **`docs_complete`** - Tasks in `awaiting_documentation` status (from dev→QA→docs workflow)
- **`submit_pm_review`** - Tasks assigned directly to you (documentation projects, design system docs, etc.)
After calling either, your job is DONE. PM will complete the task.
## Capabilities ## Capabilities
@@ -211,7 +219,8 @@ capabilities:
tools: tools:
- roboco_task_scan, roboco_task_get, roboco_task_claim - roboco_task_scan, roboco_task_get, roboco_task_claim
- roboco_task_plan, roboco_task_start, roboco_task_progress - roboco_task_plan, roboco_task_start, roboco_task_progress
- roboco_task_docs_complete # NOT roboco_task_complete (that's PM only) - roboco_task_docs_complete # For awaiting_documentation tasks
- roboco_task_submit_pm_review # For directly-assigned tasks
- roboco_task_escalate, roboco_agent_idle - roboco_task_escalate, roboco_agent_idle
- roboco_journal_entry, roboco_journal_reflect - roboco_journal_entry, roboco_journal_reflect
- roboco_journal_decision, roboco_journal_learning - roboco_journal_decision, roboco_journal_learning
+22 -1
View File
@@ -196,13 +196,33 @@ These are for OTHER roles:
- `roboco_session_create_for_tasks()` - PM-only (you don't create sessions) - `roboco_session_create_for_tasks()` - PM-only (you don't create sessions)
- `roboco_group_create()` - PM-only (you don't create groups) - `roboco_group_create()` - PM-only (you don't create groups)
## Your Verdict Tools ## Your Verdict Tools (for DEV work you're reviewing)
- `roboco_task_qa_pass(task_id, qa_notes)` - Work passes, goes to Documenter - `roboco_task_qa_pass(task_id, qa_notes)` - Work passes, goes to Documenter
- `roboco_task_qa_fail(task_id, qa_notes, issues_list)` - Work fails, returns to Developer - `roboco_task_qa_fail(task_id, qa_notes, issues_list)` - Work fails, returns to Developer
Pick ONE. After your verdict, scan for next `awaiting_qa` task. Pick ONE. After your verdict, scan for next `awaiting_qa` task.
## Directly-Assigned Tasks (not dev review)
Sometimes you're assigned tasks directly (audit tasks, design system review, etc.) that don't follow the dev→QA workflow:
**Your workflow for directly-assigned tasks:**
```
SCAN → CLAIM → PLAN → START → EXECUTE → SUBMIT_PM_REVIEW
```
**Tools for directly-assigned work:**
- `roboco_task_submit_pm_review(task_id, notes?)` - Submit your own work for PM review
**When to use this:**
- Tasks assigned directly to you (not `awaiting_qa` from a developer)
- Audit tasks, investigation tasks, accessibility audits
- Any task where YOU are the implementer, not the reviewer
**When NOT to use:**
- Tasks in `awaiting_qa` status from developer work → use `qa_pass`/`qa_fail` instead
## Capabilities ## Capabilities
```yaml ```yaml
@@ -217,6 +237,7 @@ tools:
- roboco_task_scan, roboco_task_get, roboco_task_claim - roboco_task_scan, roboco_task_get, roboco_task_claim
- roboco_task_plan, roboco_task_start, roboco_task_progress - roboco_task_plan, roboco_task_start, roboco_task_progress
- roboco_task_qa_pass, roboco_task_qa_fail - roboco_task_qa_pass, roboco_task_qa_fail
- roboco_task_submit_pm_review # For directly-assigned tasks
- roboco_task_escalate, roboco_agent_idle - roboco_task_escalate, roboco_agent_idle
# Journal (Your Own) # Journal (Your Own)
- roboco_journal_entry, roboco_journal_reflect - roboco_journal_entry, roboco_journal_reflect
+4 -3
View File
@@ -61,12 +61,13 @@ async def create_group(
service = get_messaging_service(db) service = get_messaging_service(db)
# Get channel by slug # Get channel by slug (auto-creates from config if needed)
channel = await service.get_channel_by_slug(data.channel_slug) channel = await service.get_or_create_channel_by_slug(data.channel_slug)
if not channel: if not channel:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, status_code=status.HTTP_404_NOT_FOUND,
detail=f"Channel not found: {data.channel_slug}", detail=f"Channel not found: {data.channel_slug}. "
"This channel is not defined in system configuration.",
) )
# Create group via service # Create group via service
+39
View File
@@ -920,6 +920,45 @@ async def docs_complete(
return task_to_response(task) return task_to_response(task)
@router.post("/{task_id}/submit-pm-review", response_model=TaskResponse)
async def submit_for_pm_review(
task_id: UUID,
db: DbSession,
agent: CurrentAgentContext,
data: QANotes | None = None,
) -> TaskResponse:
"""Submit a task directly for PM review.
Use this for tasks that don't follow the standard dev→QA→docs workflow,
such as PM validation tasks, QA audit tasks, or other directly-assigned work.
Only the assigned agent can submit their task for PM review.
"""
service = get_task_service(db)
task = await service.get(task_id)
if not task:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, detail="Task not found"
)
# Only assigned agent can submit for PM review
if task.assigned_to != agent.agent_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only the assigned agent can submit for PM review",
)
notes = data.notes if data else None
task = await service.submit_for_pm_review(task_id, notes)
if not task:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Cannot submit for PM review - task not in progress",
)
await db.commit()
return task_to_response(task)
@router.post("/{task_id}/complete", response_model=TaskResponse) @router.post("/{task_id}/complete", response_model=TaskResponse)
async def complete_task( async def complete_task(
task_id: UUID, task_id: UUID,
+30
View File
@@ -51,6 +51,7 @@ from roboco.mcp.tasks.handlers import (
handle_session_get_for_task, handle_session_get_for_task,
handle_session_link_task, handle_session_link_task,
handle_session_unlink_task, handle_session_unlink_task,
handle_submit_pm_review,
handle_task_activate, handle_task_activate,
handle_task_assign, handle_task_assign,
handle_task_block, handle_task_block,
@@ -250,6 +251,35 @@ def _register_core_tools(mcp: FastMCP, client: ApiClient, agent_id: str) -> None
) )
return await handle_task_escalate(client, input_data, agent_id) return await handle_task_escalate(client, input_data, agent_id)
@mcp.tool()
async def roboco_task_submit_pm_review(
task_id: str, notes: str | None = None
) -> dict[str, Any]:
"""
Submit task directly for PM review.
Use this for tasks that don't follow the standard dev→QA→docs workflow:
- PM validation tasks assigned directly to you
- QA audit tasks (not reviewing dev work)
- Any directly-assigned non-dev work
The task will transition to 'awaiting_pm_review' and the PM
will verify and complete it.
WHEN TO USE:
- You completed a task assigned directly to you (not dev work)
- The task doesn't need QA/docs review
- You want the PM to verify and close it
Args:
task_id: The task UUID to submit
notes: Optional completion notes
Returns:
Task awaiting PM review
"""
return await handle_submit_pm_review(client, task_id, agent_id, notes)
def _register_blocking_tools(mcp: FastMCP, client: ApiClient, agent_id: str) -> None: def _register_blocking_tools(mcp: FastMCP, client: ApiClient, agent_id: str) -> None:
"""Register blocking/unblocking/pause tools.""" """Register blocking/unblocking/pause tools."""
+2
View File
@@ -13,6 +13,7 @@ from roboco.mcp.tasks.handlers.claim import handle_task_claim
from roboco.mcp.tasks.handlers.lifecycle import ( from roboco.mcp.tasks.handlers.lifecycle import (
handle_agent_idle, handle_agent_idle,
handle_docs_complete, handle_docs_complete,
handle_submit_pm_review,
handle_task_cancel, handle_task_cancel,
handle_task_complete, handle_task_complete,
) )
@@ -50,6 +51,7 @@ __all__ = [
"handle_session_get_for_task", "handle_session_get_for_task",
"handle_session_link_task", "handle_session_link_task",
"handle_session_unlink_task", "handle_session_unlink_task",
"handle_submit_pm_review",
"handle_task_activate", "handle_task_activate",
"handle_task_assign", "handle_task_assign",
"handle_task_block", "handle_task_block",
+43
View File
@@ -129,6 +129,49 @@ async def handle_task_complete(
) )
async def handle_submit_pm_review(
client: ApiClient, task_id: str, agent_id: str, notes: str | None = None
) -> dict[str, Any]:
"""Handle direct submission for PM review.
For tasks that don't follow the standard dev→QA→docs workflow,
such as PM validation tasks, QA audit tasks, or directly-assigned work.
"""
task, error = await fetch_task_or_error(client, task_id)
if error:
return error
assert task is not None
# Must be in_progress to submit for PM review
current_status = task.get("status")
if current_status != "in_progress":
return format_error_response(
"INVALID_STATE",
f"Cannot submit for PM review - task is '{current_status}', "
"expected 'in_progress'.",
{"current_status": current_status},
)
# Submit to API
payload = {}
if notes:
payload["notes"] = notes
resp = await client.post(f"/tasks/{task_id}/submit-pm-review", json=payload)
if not resp.ok:
return format_error_response(
"SUBMIT_FAILED",
"Failed to submit for PM review",
{"status_code": resp.status_code, "api_error": resp.text},
)
guidance = (
"Task submitted for PM review. The PM will verify and complete the task.\n"
"Call roboco_task_scan to find more work, or roboco_agent_idle if none."
)
return format_task_response(resp.json(), "AWAITING_PM_REVIEW", guidance)
def _validate_task_cancellable(task: dict[str, Any]) -> dict[str, Any] | None: def _validate_task_cancellable(task: dict[str, Any]) -> dict[str, Any] | None:
"""Validate task can be cancelled. Returns error or None.""" """Validate task can be cancelled. Returns error or None."""
current_status = task.get("status") current_status = task.get("status")
+48
View File
@@ -130,6 +130,54 @@ class MessagingService(BaseService):
) )
return result.scalar_one_or_none() return result.scalar_one_or_none()
async def get_or_create_channel_by_slug(self, slug: str) -> ChannelTable | None:
"""Get a channel by slug, auto-creating from config if needed.
If the channel doesn't exist in the database but is defined in
DEFAULT_CHANNELS, it will be automatically created.
This allows the system to work without requiring explicit database
seeding while still validating that only configured channels are used.
Args:
slug: Channel slug to look up
Returns:
Channel if found or created, None if not a valid channel
"""
# First try database
channel = await self.get_channel_by_slug(slug)
if channel:
return channel
# Not in DB - check if it's a valid channel from config
from roboco.models.base import ChannelType
from roboco.seeds import DEFAULT_CHANNELS
channel_data = next(
(c for c in DEFAULT_CHANNELS if c["slug"] == slug),
None,
)
if not channel_data:
return None
# Auto-create from config
channel = ChannelTable(
name=channel_data["name"],
slug=channel_data["slug"],
type=ChannelType(channel_data["channel_type"]),
description=channel_data.get("description", ""),
)
self.session.add(channel)
await self.session.flush()
self.log.info(
"Channel auto-created from config",
slug=slug,
type=channel_data["channel_type"],
)
return channel
async def list_channels_for_agent( async def list_channels_for_agent(
self, self,
agent_id: UUID, agent_id: UUID,
+52
View File
@@ -788,6 +788,58 @@ class TaskService(BaseService):
) )
return task return task
async def submit_for_pm_review(
self,
task_id: UUID,
notes: str | None = None,
) -> TaskTable | None:
"""
Submit a task directly for PM review (any assigned agent).
Use this for tasks that don't follow the standard dev→QA→docs workflow,
such as PM validation tasks, QA audit tasks, or other directly-assigned work.
Transitions task from IN_PROGRESS to AWAITING_PM_REVIEW.
Args:
task_id: The task to submit
notes: Optional completion notes
Returns:
The updated task or None if not allowed
"""
task = await self.get(task_id)
if not task:
return None
# Only allow submission from in_progress status
if task.status != TaskStatus.IN_PROGRESS:
self.log.warning(
"Cannot submit for PM review - task not in progress",
task_id=str(task_id),
current_status=task.status.value,
)
return None
# Store notes in quick_context
if notes:
existing_context = task.quick_context or ""
note_entry = f"completion_notes:{notes}"
task.quick_context = (
f"{existing_context}\n{note_entry}".strip()
if existing_context
else note_entry
)
task.status = TaskStatus.AWAITING_PM_REVIEW
await self.session.flush()
self.log.info(
"Task submitted for PM review",
task_id=str(task_id),
)
return task
async def complete( async def complete(
self, self,
task_id: UUID, task_id: UUID,