mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
Killed "active" session dependency:
1. roboco/mcp/schemas/__init__.py:
- SendMessageInput.task_id → required
- AskQuestionInput.task_id → required
- ReportBlockerInput.task_id → required
2. roboco/mcp/message_server.py:
- Removed _get_active_session() entirely (dead code)
- Simplified _handle_message_send() - no fallback, just uses task's linked session
- Updated tool signatures for roboco_ask_question and roboco_report_blocker
3. roboco/api/routes/tasks.py (earlier fix):
- Added subtask validation before parent completion
New behavior:
- All messages MUST have task_id
- Task's linked session is the only source of truth
- No session? → Clear error: "Cell PM must create one"
- No more "active" status guessing
This commit is contained in:
@@ -163,55 +163,6 @@ async def _get_default_group(
|
||||
return str(groups[0]["id"])
|
||||
|
||||
|
||||
async def _get_active_session(
|
||||
client: ApiClient,
|
||||
channel_id: str,
|
||||
agent_id: str | None = None,
|
||||
channel_slug: str | None = None,
|
||||
) -> str | dict[str, Any]:
|
||||
"""Get active session for channel. Returns session_id or error dict.
|
||||
|
||||
NOTE: This function does NOT create sessions. Sessions must be created
|
||||
by PMs using roboco_session_create_for_tasks. If no active session exists,
|
||||
returns an error guiding the agent to use task_id or ask their PM.
|
||||
"""
|
||||
# First get the default group for this channel
|
||||
group_result = await _get_default_group(
|
||||
client, channel_id, agent_id=agent_id, channel_slug=channel_slug
|
||||
)
|
||||
if isinstance(group_result, dict):
|
||||
return group_result # Error response (NO_GROUPS with guidance)
|
||||
group_id = group_result
|
||||
|
||||
# Check if group has an active session
|
||||
resp = await client.get("/sessions", params={"group_id": group_id, "limit": 10})
|
||||
|
||||
if resp.ok:
|
||||
data = resp.json()
|
||||
items = data.get("items", [])
|
||||
# Find an active session
|
||||
for session in items:
|
||||
if session.get("status") == "active":
|
||||
return str(session["id"])
|
||||
|
||||
# NO auto-creation! Return helpful error instead
|
||||
return format_error_response(
|
||||
"NO_ACTIVE_SESSION",
|
||||
"No active session in this channel. Sessions are created by PMs for tasks.",
|
||||
{
|
||||
"guidance": (
|
||||
"To send messages, you should:\n"
|
||||
"1. Include task_id in your message call if working on a task "
|
||||
"(routes to task's session)\n"
|
||||
"2. If no task session exists, ask your PM to create one using "
|
||||
"roboco_session_create_for_tasks\n"
|
||||
"3. All work communication should happen within task sessions"
|
||||
),
|
||||
"channel_id": channel_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TOOL IMPLEMENTATIONS
|
||||
# =============================================================================
|
||||
@@ -394,29 +345,23 @@ async def _handle_message_send(
|
||||
):
|
||||
return validation_error
|
||||
|
||||
session_id: str | None = None
|
||||
routed_to_task_session = False
|
||||
|
||||
# If task_id provided, try to route to task's primary session
|
||||
if data.task_id:
|
||||
session_id = await _get_task_primary_session(client, data.task_id)
|
||||
if session_id:
|
||||
routed_to_task_session = True
|
||||
|
||||
# Fall back to channel's active session (NO auto-creation)
|
||||
# task_id is required - use task's linked session
|
||||
session_id = await _get_task_primary_session(client, data.task_id)
|
||||
if not session_id:
|
||||
# Get channel by slug
|
||||
channel_result = await _get_channel_by_slug(client, data.channel_slug)
|
||||
if isinstance(channel_result, dict):
|
||||
return channel_result # Error response
|
||||
channel_id = channel_result
|
||||
|
||||
session_result = await _get_active_session(
|
||||
client, channel_id, agent_id=agent_id, channel_slug=data.channel_slug
|
||||
# Task has no linked session - PM setup issue
|
||||
return format_error_response(
|
||||
"NO_TASK_SESSION",
|
||||
f"Task {data.task_id} has no linked session.",
|
||||
{
|
||||
"guidance": (
|
||||
"This task doesn't have a work session yet.\n"
|
||||
"Cell PM must create one using "
|
||||
"roboco_session_create_for_tasks.\n"
|
||||
"Escalate to your PM if you need a session for this task."
|
||||
),
|
||||
"task_id": data.task_id,
|
||||
},
|
||||
)
|
||||
if isinstance(session_result, dict):
|
||||
return session_result # Returns NO_GROUPS/NO_ACTIVE_SESSION with guidance
|
||||
session_id = session_result
|
||||
|
||||
# Resolve mentions (slugs) to UUIDs using shared cache
|
||||
resolved_mentions: list[str] = []
|
||||
@@ -444,16 +389,12 @@ async def _handle_message_send(
|
||||
"SEND_FAILED", "Failed to send message", {"api_error": resp.text}
|
||||
)
|
||||
|
||||
guidance = "Message sent successfully."
|
||||
if routed_to_task_session:
|
||||
guidance = f"Message sent to task {data.task_id}'s session."
|
||||
|
||||
return {
|
||||
"status": "sent",
|
||||
"message": resp.json(),
|
||||
"channel": data.channel_slug,
|
||||
"routed_to_task_session": routed_to_task_session,
|
||||
"guidance": guidance,
|
||||
"task_id": data.task_id,
|
||||
"guidance": f"Message sent to task {data.task_id}'s session.",
|
||||
}
|
||||
|
||||
|
||||
@@ -590,8 +531,8 @@ def create_message_mcp_server(agent_id: str) -> FastMCP:
|
||||
async def roboco_ask_question(
|
||||
channel_slug: str,
|
||||
question: str,
|
||||
task_id: str,
|
||||
context: str | None = None,
|
||||
task_id: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Ask a question in a channel.
|
||||
@@ -601,8 +542,8 @@ def create_message_mcp_server(agent_id: str) -> FastMCP:
|
||||
data = AskQuestionInput(
|
||||
channel_slug=channel_slug,
|
||||
question=question,
|
||||
context=context,
|
||||
task_id=task_id,
|
||||
context=context,
|
||||
)
|
||||
return await _handle_ask_question(client, agent_id, data)
|
||||
|
||||
@@ -611,7 +552,7 @@ def create_message_mcp_server(agent_id: str) -> FastMCP:
|
||||
channel_slug: str,
|
||||
blocker_description: str,
|
||||
what_needed: str,
|
||||
task_id: str | None = None,
|
||||
task_id: str,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Report a blocker in a channel.
|
||||
|
||||
@@ -111,11 +111,11 @@ class SendMessageInput(BaseModel):
|
||||
|
||||
channel_slug: str = Field(..., description="Channel slug (e.g., 'backend-cell')")
|
||||
content: str = Field(..., description="Message content")
|
||||
task_id: str = Field(..., description="Task ID (routes to task's session)")
|
||||
message_type: str = Field(
|
||||
default="dialogue",
|
||||
description="Type: reasoning, dialogue, decision, action, blocker, technical",
|
||||
)
|
||||
task_id: str | None = Field(default=None, description="Optional related task ID")
|
||||
reply_to: str | None = Field(default=None, description="Message ID to reply to")
|
||||
mentions: list[str] = Field(default_factory=list, description="Agents to mention")
|
||||
|
||||
@@ -125,8 +125,8 @@ class AskQuestionInput(BaseModel):
|
||||
|
||||
channel_slug: str
|
||||
question: str
|
||||
task_id: str # Required - routes to task's session
|
||||
context: str | None = None
|
||||
task_id: str | None = None
|
||||
|
||||
|
||||
class ReportBlockerInput(BaseModel):
|
||||
@@ -135,7 +135,7 @@ class ReportBlockerInput(BaseModel):
|
||||
channel_slug: str
|
||||
blocker_description: str
|
||||
what_needed: str
|
||||
task_id: str | None = None
|
||||
task_id: str # Required - routes to task's session
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user