From a0fa0e9eff7223a4c58f71879e00c45de16b5b9b Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 22 Jan 2026 10:49:37 +0800 Subject: [PATCH] Refactor E2E Test Structure and Enhance Logging - Updated the `TestE2EControlStop` function to improve execution status verification with a retry mechanism, accommodating potential delays. - Streamlined `TestE2EEventTriggerVariousEventTypes` to focus on a single event type, reducing CI execution time while maintaining coverage. - Enhanced logging and assertions for better clarity in test outcomes, improving overall test reliability. --- openapi/agent/robot/DESIGN.md | 748 ++++++++++++++++++++++++++++++++++ openapi/agent/robot/GAPS.md | 721 ++++++++++++++++++++++++++++++++ openapi/agent/robot/TODO.md | 554 +++++++++++++++++++++++++ 3 files changed, 2023 insertions(+) create mode 100644 openapi/agent/robot/DESIGN.md create mode 100644 openapi/agent/robot/GAPS.md create mode 100644 openapi/agent/robot/TODO.md diff --git a/openapi/agent/robot/DESIGN.md b/openapi/agent/robot/DESIGN.md new file mode 100644 index 00000000..74731f0c --- /dev/null +++ b/openapi/agent/robot/DESIGN.md @@ -0,0 +1,748 @@ +# Robot OpenAPI - Design Document + +> Based on: `yao/agent/robot/` (Backend), `cui/packages/cui/pages/mission-control/` (Frontend) +> Gap Analysis: `yao/openapi/agent/robot/GAPS.md` + +## 1. Overview + +### 1.1 Purpose + +Provide HTTP REST API endpoints for Robot Agent management, designed to support the Mission Control frontend UI. + +### 1.2 Implementation Strategy + +> **Low-risk phases first. Medium-risk features (Chat API, SSE Event Bus) can be deferred.** + +| Phase | Risk | Features | Frontend Fallback | +|-------|------|----------|-------------------| +| 1. Core CRUD | ๐ŸŸข Low | List, Get, Create, Update, Delete | - | +| 2. Execution Management | ๐ŸŸข Low | List, Get, Control executions | - | +| 3. Results & Activities | ๐ŸŸข Low | Deliverables, Activity feed | - | +| 4. i18n | ๐ŸŸข Low | Locale parameter support | - | +| 5. Chat API | ๐ŸŸก Medium (Deferred) | Multi-turn conversation | Single-submit mode | +| 6. SSE Event Bus | ๐ŸŸก Medium (Deferred) | Real-time status streams | Polling every 3-5s | + +### 1.3 Route Decision: `/v1/agent/robots` + +**Analysis of existing `openapi/` route structure:** + +| Package | Route | Description | +|---------|-------|-------------| +| `agent/` | `/v1/agent/assistants` | Assistant CRUD, info | +| `chat/` | `/v1/chat/completions` | Chat completions | +| `kb/` | `/v1/kb/collections` | Knowledge base | +| `job/` | `/v1/job/jobs` | Job management | +| `file/` | `/v1/file/*` | File operations | +| `user/` | `/v1/user/*` | User management | +| `team/` | `/v1/team/*` | Team management | + +**Decision:** Put Robot routes under `/v1/agent/robots` because: + +1. **Semantic Alignment**: Robot is a type of Agent (Autonomous Robot Agent), just like Assistant is a type of Agent +2. **Existing Pattern**: `openapi/agent/` already handles `/v1/agent/assistants` +3. **Logical Grouping**: Agent-related APIs grouped together +4. **Consistent Hierarchy**: `/v1/agent/{type}` pattern + +**Route Comparison:** + +| Option | Path | Verdict | +|--------|------|---------| +| โŒ `/v1/robots` | New top-level namespace | Inconsistent with agent grouping | +| โœ… `/v1/agent/robots` | Under agent namespace | Follows existing pattern | +| โŒ `/v1/members?type=robot` | Reuse members | Less intuitive for operations | + +### 1.4 Architecture + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Frontend (Mission Control) โ”‚ +โ”‚ cui/packages/cui/pages/mission-control/ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ HTTP REST / SSE + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ OpenAPI Layer โ”‚ +โ”‚ yao/openapi/agent/ โ”‚ +โ”‚ - Routes: /v1/agent/assistants/* (existing) โ”‚ +โ”‚ - Routes: /v1/agent/robots/* (NEW) โ”‚ +โ”‚ - Auth: OAuth2 via Guard middleware โ”‚ +โ”‚ - SSE: Real-time updates โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Robot API Layer โ”‚ +โ”‚ yao/agent/robot/api/ โ”‚ +โ”‚ - Go functions: Get(), List(), Trigger(), etc. โ”‚ +โ”‚ - Business logic โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Robot Core โ”‚ +โ”‚ yao/agent/robot/ โ”‚ +โ”‚ - Manager, Executor, Cache, Pool, Store โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +### 1.5 Design Principles + +1. **Layered Architecture**: OpenAPI layer only handles HTTP concerns (routing, request parsing, response formatting). Business logic stays in `robot/api/`. +2. **Consistent with Existing Patterns**: Follow `yao/openapi/agent/` conventions, extend existing agent package +3. **Incremental Implementation**: Start with core CRUD, then add real-time features +4. **Frontend-Backend Balance**: API design considers both frontend needs and backend capabilities + +--- + +## 2. Differences Analysis + +### 2.1 Frontend Expectations vs Backend Reality + +| Feature | Frontend (API.md) | Backend (robot/api/) | Gap | Solution | +|---------|-------------------|----------------------|-----|----------| +| Robot List | `GET /v1/robots` with `name`, `description` | `List()` returns `types.Robot` | Field mapping needed | Map in OpenAPI layer | +| Robot Detail | `GET /v1/robots/:id` with full `config` | `Get()` returns Robot + Config | Need format conversion | Map to frontend format | +| Create Robot | POST with `work_mode` | Not implemented | New feature | Add `Create()` | +| Update Robot | PUT with partial update | Not implemented | New feature | Add `Update()` | +| Delete Robot | DELETE | Not implemented | New feature | Add `Remove()` | +| Trigger | Immediate execution | `Trigger()` returns sync result | Works | Wrap with SSE events | +| Intervene | Immediate intervention | `Intervene()` returns sync result | Works | Wrap with SSE events | +| Multi-turn Chat | Chat before execute | Not implemented | **Deferred** | Frontend uses single-submit | +| Results List | `/results` endpoint | No separate results API | New feature | Derive from executions | +| Activities | `/activities` endpoint | No activities tracking | New feature | Derive from executions | +| Real-time Stream | SSE `/stream` endpoints | No SSE support | **Deferred** | Frontend uses polling | +| i18n | `?locale=` query param | No i18n support | New feature | Add locale handling | + +### 2.2 Field Mapping (Backend โ†’ Frontend API) + +The `__yao.member` model already has the necessary fields, with different names: + +| Frontend API | Backend DB (`__yao.member`) | Backend Go (`types.Robot`) | Mapping | +|--------------|----------------------------|---------------------------|---------| +| `member_id` | `member_id` | `MemberID` | Direct | +| `name` | `member_id` | `MemberID` | **Reuse** (slug-like identifier) | +| `display_name` | `display_name` | `DisplayName` | Direct | +| `description` | `bio` | Need to add `Bio` field | Map in OpenAPI layer | +| `email` | `robot_email` | `RobotEmail` | Direct | + +**Required Backend Changes:** +1. Add `Bio` field to `types.Robot` struct +2. Add `bio` to `cache/load.go` memberFields + +### 2.3 Type Differences + +| Frontend Type | Backend Type | Solution | +|---------------|--------------|----------| +| `RobotState.name` | `Robot.MemberID` | Map `member_id` to `name` | +| `RobotState.description` | `Robot.Bio` (new) | Add field, map to `description` | +| `Execution.name` | Not in `types.Execution` | Derive from goals or input in OpenAPI layer | +| `Execution.current_task_name` | Not in `types.Execution` | Derive from current task in OpenAPI layer | +| `ResultFile` | No equivalent | New type in OpenAPI layer (derive from delivery) | +| `Activity` | No equivalent | New type in OpenAPI layer (derive from executions) | + +--- + +## 3. API Endpoints + +> **Base Path:** `/v1/agent/robots` + +### 3.1 Robot Management + +| Method | Path | Handler | Description | +|--------|------|---------|-------------| +| GET | /v1/agent/robots | `ListRobots` | List all robots | +| GET | /v1/agent/robots/:id | `GetRobot` | Get robot details | +| POST | /v1/agent/robots | `CreateRobot` | Create robot | +| PUT | /v1/agent/robots/:id | `UpdateRobot` | Update robot | +| DELETE | /v1/agent/robots/:id | `DeleteRobot` | Delete robot | + +### 3.2 Execution Management + +| Method | Path | Handler | Description | +|--------|------|---------|-------------| +| GET | /v1/agent/robots/:id/executions | `ListExecutions` | List executions | +| GET | /v1/agent/robots/:id/executions/:exec_id | `GetExecution` | Get execution detail | +| POST | /v1/agent/robots/:id/trigger | `TriggerRobot` | Trigger execution (SSE) | +| POST | /v1/agent/robots/:id/intervene | `InterveneRobot` | Intervene execution (SSE) | +| POST | /v1/agent/robots/:id/executions/:exec_id/pause | `PauseExecution` | Pause execution | +| POST | /v1/agent/robots/:id/executions/:exec_id/resume | `ResumeExecution` | Resume execution | +| POST | /v1/agent/robots/:id/executions/:exec_id/cancel | `CancelExecution` | Cancel execution | +| POST | /v1/agent/robots/:id/executions/:exec_id/retry | `RetryExecution` | Retry execution | + +### 3.3 Results Management + +| Method | Path | Handler | Description | +|--------|------|---------|-------------| +| GET | /v1/agent/robots/:id/results | `ListResults` | List deliverables | +| GET | /v1/agent/robots/:id/results/:result_id | `GetResult` | Get deliverable detail | + +### 3.4 Activities & Real-time + +| Method | Path | Handler | Description | +|--------|------|---------|-------------| +| GET | /v1/agent/robots/activities | `ListActivities` | List recent activities | +| GET | /v1/agent/robots/stream | `StreamRobots` | Robot status SSE | +| GET | /v1/agent/robots/:id/executions/:exec_id/stream | `StreamExecution` | Execution progress SSE | + +--- + +## 4. Response Types + +### 4.1 RobotResponse (for list and detail) + +```go +// RobotResponse - formatted robot for API response +// Maps backend fields to frontend expected format +type RobotResponse struct { + MemberID string `json:"member_id"` + TeamID string `json:"team_id"` + Name string `json:"name"` // From Robot.MemberID (slug-like identifier) + DisplayName string `json:"display_name"` // From Robot.DisplayName + Description string `json:"description,omitempty"` // From Robot.Bio + Status string `json:"status"` // idle | working | paused | error | maintenance + Running int `json:"running"` // Current running count + MaxRunning int `json:"max_running"` // From Config.Quota.Max + LastRun *string `json:"last_run,omitempty"` // ISO timestamp + NextRun *string `json:"next_run,omitempty"` // ISO timestamp + RunningIDs []string `json:"running_ids,omitempty"` // Execution IDs + Config *ConfigResponse `json:"config,omitempty"` // Full config (for detail) +} + +// NewRobotResponse converts backend Robot to API response +func NewRobotResponse(robot *types.Robot) *RobotResponse { + return &RobotResponse{ + MemberID: robot.MemberID, + TeamID: robot.TeamID, + Name: robot.MemberID, // Use MemberID as unique identifier + DisplayName: robot.DisplayName, + Description: robot.Bio, // Map Bio to Description + Status: string(robot.Status), + // ... other fields + } +} +``` + +### 4.2 ConfigResponse (robot config) + +```go +// ConfigResponse - formatted config for API response +type ConfigResponse struct { + Identity *IdentityConfig `json:"identity,omitempty"` + Clock *ClockConfig `json:"clock,omitempty"` + Events []EventConfig `json:"events,omitempty"` + Quota *QuotaConfig `json:"quota,omitempty"` + Resources *ResourcesConfig `json:"resources,omitempty"` + Delivery *DeliveryConfig `json:"delivery,omitempty"` + Triggers *TriggersConfig `json:"triggers,omitempty"` + Learn *LearnConfig `json:"learn,omitempty"` + Executor *ExecutorConfig `json:"executor,omitempty"` +} +``` + +### 4.3 ExecutionResponse + +```go +// ExecutionResponse - formatted execution for API response +type ExecutionResponse struct { + ID string `json:"id"` + MemberID string `json:"member_id"` + TeamID string `json:"team_id"` + TriggerType string `json:"trigger_type"` + StartTime string `json:"start_time"` + EndTime *string `json:"end_time,omitempty"` + Status string `json:"status"` + Phase string `json:"phase"` + Error *string `json:"error,omitempty"` + JobID string `json:"job_id"` + Name string `json:"name,omitempty"` // Localized execution name + CurrentTaskName string `json:"current_task_name,omitempty"` // Localized current task + Goals *GoalsResponse `json:"goals,omitempty"` + Tasks []TaskResponse `json:"tasks,omitempty"` + Current *CurrentState `json:"current,omitempty"` + Delivery *DeliveryResult `json:"delivery,omitempty"` +} +``` + +### 4.4 ResultResponse + +```go +// ResultResponse - deliverable file for Results tab +type ResultResponse struct { + ID string `json:"id"` + MemberID string `json:"member_id"` + ExecutionID string `json:"execution_id"` + Name string `json:"name"` + Type string `json:"type"` // pdf, xlsx, csv, json, md + Size int64 `json:"size"` // bytes + CreatedAt string `json:"created_at"` + TriggerType string `json:"trigger_type,omitempty"` + ExecutionName string `json:"execution_name,omitempty"` +} +``` + +### 4.5 ActivityResponse + +```go +// ActivityResponse - activity item +type ActivityResponse struct { + ID string `json:"id"` + Type string `json:"type"` // completed | file | error | started | paused + MemberID string `json:"member_id"` + RobotName string `json:"robot_name"` // Localized + Title string `json:"title"` // Localized + Description string `json:"description,omitempty"` // Localized + FileID string `json:"file_id,omitempty"` + Timestamp string `json:"timestamp"` +} +``` + +--- + +## 5. Request Types + +### 5.1 CreateRobotRequest + +```go +// CreateRobotRequest - create robot request +type CreateRobotRequest struct { + Locale string `json:"locale,omitempty"` // zh-CN | en-US + Name string `json:"name"` // Unique identifier + DisplayName string `json:"display_name"` // Display name + Email string `json:"email,omitempty"` // Robot email + ManagerID string `json:"manager_id,omitempty"` // Manager user ID + WorkMode string `json:"work_mode"` // autonomous | on-demand + Identity *IdentityConfig `json:"identity"` + Resources *ResourcesConfig `json:"resources,omitempty"` +} +``` + +### 5.2 UpdateRobotRequest + +```go +// UpdateRobotRequest - update robot request +type UpdateRobotRequest struct { + Locale string `json:"locale,omitempty"` + DisplayName *string `json:"display_name,omitempty"` + Config *ConfigResponse `json:"config,omitempty"` // Partial update supported +} +``` + +### 5.3 TriggerRequest (SSE) + +```go +// TriggerRequest - trigger robot execution +type TriggerRequest struct { + Locale string `json:"locale,omitempty"` + Messages []Message `json:"messages"` + Attachments []Attachment `json:"attachments,omitempty"` +} + +// Message - chat message +type Message struct { + Role string `json:"role"` // user | assistant + Content string `json:"content"` +} + +// Attachment - file attachment +type Attachment struct { + File string `json:"file"` // __yao.attachment://fileID + Name string `json:"name,omitempty"` +} +``` + +### 5.4 InterveneRequest (SSE) + +```go +// InterveneRequest - intervene during execution +type InterveneRequest struct { + Locale string `json:"locale,omitempty"` + ExecutionID string `json:"execution_id"` + Action string `json:"action"` // task.add | goal.adjust | instruct + Messages []Message `json:"messages"` + Priority string `json:"priority,omitempty"` // high | normal | low + Position string `json:"position,omitempty"` // first | last | next | at +} +``` + +--- + +## 6. Deferred Features + +### 6.1 Multi-turn Chat API (Phase 5 - Deferred) + +> **Risk Level:** ๐ŸŸก Medium - Requires new stateful component +> **Frontend Fallback:** Single-submit mode (user input โ†’ immediate execution) + +The frontend `ChatDrawer` component expects multi-turn conversation before execution: + +``` +User: "Help me analyze competitor pricing" + โ†“ +Robot: "Got it. Which competitors?" + โ†“ +User: "Focus on Company A and B" + โ†“ +Robot: "Understood. Ready to start?" + โ†“ +User clicks [Confirm] โ†’ Execution starts +``` + +**Current backend behavior:** `Trigger()` immediately submits to execution pool. + +**Deferred implementation:** +``` +POST /v1/agent/robots/:id/chat +{ + "conversation_id": "conv_001", // For continuing conversation + "messages": [{ "role": "user", "content": "..." }] +} + +Response (SSE): +event: message +data: {"role": "assistant", "content": "..."} + +event: state +data: {"conversation_id": "conv_001", "ready_to_execute": false} +``` + +**For now:** Frontend can skip chat flow, directly call `/trigger` with user message. + +### 6.2 SSE Event Bus (Phase 6 - Deferred) + +> **Risk Level:** ๐ŸŸก Medium - Requires modification of executor/manager +> **Frontend Fallback:** Polling (GET /executions every 3-5 seconds) + +Real-time status updates via SSE require an event bus integrated with: +- Manager (robot status changes) +- Executor (execution progress) + +**For now:** Frontend uses polling to refresh status. + +--- + +## 7. SSE Events + +### 7.1 Trigger/Intervene SSE Events + +``` +event: received +data: {"message": "Task received, creating execution..."} + +event: execution +data: {"execution_id": "exec_002", "status": "pending"} + +event: message +data: {"role": "assistant", "content": "ๅฅฝ็š„๏ผŒๆˆ‘ๅผ€ๅง‹ๅค„็†..."} + +event: phase +data: {"phase": "goals", "message": "ๆญฃๅœจ็”Ÿๆˆ็›ฎๆ ‡..."} + +event: complete +data: {"execution_id": "exec_002", "status": "running"} + +event: error +data: {"error": "Something went wrong"} +``` + +### 7.2 Robot Stream SSE Events (Phase 6 - Deferred) + +``` +event: robot_status +data: {"member_id": "robot_001", "status": "working", "running": 1} + +event: execution_start +data: {"member_id": "robot_001", "execution_id": "exec_001", "name": "ๆฏๆ—ฅๆŠฅ่กจ็”Ÿๆˆ"} + +event: execution_complete +data: {"member_id": "robot_001", "execution_id": "exec_001", "status": "completed"} + +event: activity +data: {"id": "act_001", "type": "completed", "member_id": "robot_001", ...} +``` + +### 7.3 Execution Stream SSE Events (Phase 6 - Deferred) + +``` +event: phase +data: {"phase": "tasks", "progress": "2/5 tasks"} + +event: task_start +data: {"task_id": "task_002", "order": 2} + +event: task_complete +data: {"task_id": "task_002", "status": "completed"} + +event: message +data: {"role": "assistant", "content": "ๆญฃๅœจๅˆ†ๆžๆ•ฐๆฎ..."} + +event: delivery +data: {"summary": "...", "attachments": [...]} + +event: complete +data: {"status": "completed"} + +event: error +data: {"error": "Something went wrong", "phase": "run"} +``` + +--- + +## 8. i18n Support + +### 8.1 Locale Detection + +Priority order: +1. Query parameter: `?locale=zh-CN` +2. Request body field: `locale: "zh-CN"` +3. Accept-Language header +4. Default: `en-US` + +### 8.2 Localized Fields + +| Response Type | Localized Fields | +|---------------|------------------| +| RobotResponse | display_name, description | +| ExecutionResponse | name, current_task_name | +| TaskResponse | (none - tasks use executor_id) | +| ResultResponse | name, execution_name | +| ActivityResponse | robot_name, title, description | + +--- + +## 9. Authentication & Authorization + +### 9.1 Guard Middleware + +All endpoints require OAuth2 authentication via `oauth.Guard` middleware. + +```go +// In router registration +router.Use(oauth.Guard()) +``` + +### 9.2 Permission Checks + +| Endpoint | Required Scope | +|----------|----------------| +| GET /robots | `robots:read` | +| POST /robots | `robots:write` | +| PUT/DELETE /robots/:id | `robots:write` + ownership check | +| Trigger/Intervene | `robots:execute` | +| Stream endpoints | `robots:read` | + +### 9.3 Team Isolation + +Robots are team-scoped. Users can only access robots in their team. + +```go +func checkTeamAccess(ctx context.Context, memberID string) error { + auth := oauth.GetAuthorized(ctx) + robot, _ := robotapi.Get(memberID) + if robot.TeamID != auth.TeamID { + return errors.New("access denied") + } + return nil +} +``` + +--- + +## 10. File Structure + +**Decision: Sub-package under `openapi/agent/`** + +Robot logic is complex enough to warrant its own package. This keeps code organized and follows the pattern used by other complex modules. + +``` +yao/openapi/agent/ +โ”œโ”€โ”€ agent.go # Main route registration (MODIFY: add robot.Attach) +โ”œโ”€โ”€ assistant.go # Assistant handlers (existing) +โ”œโ”€โ”€ filter.go # Query filtering (existing) +โ”œโ”€โ”€ models.go # LLM models (existing) +โ”œโ”€โ”€ types.go # Types (existing) +โ”‚ +โ””โ”€โ”€ robot/ # Robot sub-package (NEW) + โ”œโ”€โ”€ DESIGN.md # This document โœ… + โ”œโ”€โ”€ TODO.md # Implementation plan โœ… + โ”‚ + โ”œโ”€โ”€ robot.go # Route registration (Attach function) + โ”œโ”€โ”€ types.go # Request/Response types + โ”‚ + โ”œโ”€โ”€ list.go # GET /v1/agent/robots + โ”œโ”€โ”€ detail.go # GET/POST/PUT/DELETE /v1/agent/robots/:id + โ”‚ + โ”œโ”€โ”€ execution.go # Execution list/detail/control handlers + โ”œโ”€โ”€ trigger.go # POST /trigger, POST /intervene (SSE) + โ”‚ + โ”œโ”€โ”€ results.go # GET /results, GET /results/:id + โ”œโ”€โ”€ activities.go # GET /activities + โ”‚ + โ”œโ”€โ”€ stream.go # GET /stream, GET /executions/:id/stream (SSE) + โ”‚ + โ”œโ”€โ”€ filter.go # Query param parsing helpers + โ””โ”€โ”€ utils.go # Locale, time formatting utilities +``` + +**Route Registration (in `openapi/agent/agent.go`):** + +```go +import "github.com/yaoapp/yao/openapi/agent/robot" + +func Attach(group *gin.RouterGroup, oauth types.OAuth) { + group.Use(oauth.Guard) + + // Assistant routes (existing) + group.GET("/assistants", ListAssistants) + group.POST("/assistants", CreateAssistant) + // ... + + // Robot routes (NEW) + robot.Attach(group.Group("/robots"), oauth) +} +``` + +**Robot Route Registration (`robot/robot.go`):** + +```go +package robot + +func Attach(group *gin.RouterGroup, oauth types.OAuth) { + // Robot CRUD + group.GET("", ListRobots) + group.POST("", CreateRobot) + group.GET("/:id", GetRobot) + group.PUT("/:id", UpdateRobot) + group.DELETE("/:id", DeleteRobot) + + // Activities (before :id to avoid conflict) + group.GET("/activities", ListActivities) + group.GET("/stream", StreamRobots) + + // Execution management + group.GET("/:id/executions", ListExecutions) + group.GET("/:id/executions/:exec_id", GetExecution) + group.GET("/:id/executions/:exec_id/stream", StreamExecution) + group.POST("/:id/executions/:exec_id/pause", PauseExecution) + group.POST("/:id/executions/:exec_id/resume", ResumeExecution) + group.POST("/:id/executions/:exec_id/cancel", CancelExecution) + group.POST("/:id/executions/:exec_id/retry", RetryExecution) + + // Trigger & Intervene (SSE) + group.POST("/:id/trigger", TriggerRobot) + group.POST("/:id/intervene", InterveneRobot) + + // Results + group.GET("/:id/results", ListResults) + group.GET("/:id/results/:result_id", GetResult) +} +``` + +--- + +## 11. Error Handling + +### 11.1 Error Response Format + +```json +{ + "error": { + "code": "ROBOT_NOT_FOUND", + "message": "Robot not found", + "details": { + "member_id": "robot_001" + } + } +} +``` + +### 11.2 Error Codes + +| Code | HTTP Status | Description | +|------|-------------|-------------| +| ROBOT_NOT_FOUND | 404 | Robot does not exist | +| EXECUTION_NOT_FOUND | 404 | Execution does not exist | +| ROBOT_BUSY | 409 | Robot at max capacity | +| TRIGGER_DISABLED | 403 | Trigger type disabled | +| EXECUTION_NOT_RUNNING | 400 | Cannot pause/resume non-running execution | +| INVALID_REQUEST | 400 | Request validation failed | +| UNAUTHORIZED | 401 | Not authenticated | +| FORBIDDEN | 403 | No permission | + +--- + +## 12. Implementation Notes + +### 12.1 Backend API Extension + +The existing `robot/api/` package needs these additions: + +1. **Robot CRUD**: `Create()`, `Update()`, `Remove()` functions +2. **Results API**: `ListResults()`, `GetResult()` functions +3. **Activities API**: `ListActivities()` function +4. **Localization**: Add `Locale` parameter support + +### 12.2 Store Extension + +The `robot/store/` package needs: + +1. **Results Store**: Store and query deliverable files +2. **Activities Store**: Store and query activities (or derive from job logs) + +### 12.3 SSE Implementation + +Use standard Go SSE pattern: + +```go +func streamHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/event-stream") + w.Header().Set("Cache-Control", "no-cache") + w.Header().Set("Connection", "keep-alive") + + flusher, _ := w.(http.Flusher) + + for event := range events { + fmt.Fprintf(w, "event: %s\ndata: %s\n\n", event.Type, event.Data) + flusher.Flush() + } +} +``` + +### 12.4 Localization Strategy + +- Store display names in `__yao.member.display_name` (single language) initially +- Future: Add `display_name_cn`, `display_name_en` or use JSON `{"en": "...", "cn": "..."}` +- Execution names derived from goals or input message +- Activities derive titles from execution data + +--- + +## 13. API Base Path Decision + +Based on analysis of existing `openapi/` structure: + +| Option | Path | Pros | Cons | +|--------|------|------|------| +| โŒ A | `/v1/robots` | Shorter path | New namespace, inconsistent | +| โœ… B | `/v1/agent/robots` | Groups with agent APIs, consistent | Longer path | +| โŒ C | `/v1/members?type=robot` | Uses existing members | Less intuitive | + +**Decision**: Use `/v1/agent/robots` as base path. + +**Rationale:** +1. `openapi/agent/` already exists with `/v1/agent/assistants` +2. Robot is conceptually an Agent type (Autonomous Robot Agent) +3. Follows the established pattern: `/v1/agent/{agent-type}` +4. Keeps agent-related APIs logically grouped + +**Frontend Impact:** +- Update `cui/packages/cui/pages/mission-control/API.md` base path from `/v1/robots` to `/v1/agent/robots` +- Minimal code change (just update base URL constant) + +--- + +## 14. References + +- Frontend API Requirements: `cui/packages/cui/pages/mission-control/API.md` +- Backend Robot Design: `yao/agent/robot/DESIGN.md` +- Backend Technical Spec: `yao/agent/robot/TECHNICAL.md` +- Existing OpenAPI Patterns: `yao/openapi/kb/`, `yao/openapi/chat/` diff --git a/openapi/agent/robot/GAPS.md b/openapi/agent/robot/GAPS.md new file mode 100644 index 00000000..83bfbfc9 --- /dev/null +++ b/openapi/agent/robot/GAPS.md @@ -0,0 +1,721 @@ +# Robot OpenAPI - Gap Analysis + +> This document analyzes the gaps between existing backend implementation and frontend API requirements. +> Generated from reviewing: `yao/agent/robot/`, `yao/openapi/agent/`, `cui/packages/cui/pages/mission-control/` + +--- + +## Summary + +| Category | Risk | Status | Items to Implement | +|----------|------|--------|-------------------| +| Backend Types | ๐ŸŸข Low | ๐ŸŸก Partial | 1 field to add (`Bio`), 2 fields for Execution | +| Backend Cache | ๐ŸŸข Low | ๐ŸŸก Partial | Add `bio` to memberFields in `cache/load.go` | +| Backend API | ๐ŸŸข Low | ๐ŸŸก Partial | 7 functions missing (CRUD + Results + Activities) | +| OpenAPI Layer | ๐ŸŸข Low | โฌœ New | 19 endpoints, response type mapping | +| i18n | ๐ŸŸข Low | โฌœ New | Locale parameter support | +| **Chat API** | ๐ŸŸก Medium | โฌœ Deferred | Multi-turn conversation (frontend fallback: single-submit) | +| **SSE Infrastructure** | ๐ŸŸก Medium | โฌœ Deferred | Event bus + SSE handlers (frontend fallback: polling) | + +### Key Field Mapping (Backend โ†’ Frontend) + +| Frontend API | Backend DB (`__yao.member`) | Backend Go (`types.Robot`) | +|--------------|----------------------------|---------------------------| +| `name` | `member_id` | `MemberID` | +| `display_name` | `display_name` | `DisplayName` | +| `description` | `bio` | Need to add `Bio` field | +| `email` | `robot_email` | `RobotEmail` | + +--- + +## 1. Backend Types Gaps (`yao/agent/robot/types/`) + +### 1.1 Field Mapping (Backend โ†’ Frontend API) + +The `__yao.member` model already has the necessary fields, but with different names: + +| Frontend API Field | Backend DB Field | Status | Notes | +|-------------------|------------------|--------|-------| +| `member_id` | `member_id` | โœ… Exists | Global unique identifier | +| `name` | `member_id` | โœ… **Reuse** | Frontend expects a slug like `sales-analyst`, can use `member_id` | +| `display_name` | `display_name` | โœ… Exists | Localized display name | +| `description` | `bio` | โœ… Exists | `bio` field in `__yao.member` is the robot description | + +**Backend Robot struct (`types/robot.go`):** +```go +type Robot struct { + MemberID string `json:"member_id"` // โœ… Exists + TeamID string `json:"team_id"` // โœ… Exists + DisplayName string `json:"display_name"` // โœ… Exists + SystemPrompt string `json:"system_prompt"`// โœ… Exists + // ... +} +``` + +**Missing fields to add to Robot struct:** +```go +type Robot struct { + // ... existing fields ... + Bio string `json:"bio"` // NEW: from __yao.member.bio (robot description) +} +``` + +**OpenAPI Response Mapping:** +```go +// In OpenAPI layer, map backend fields to frontend expected format +type RobotResponse struct { + MemberID string `json:"member_id"` + Name string `json:"name"` // Use MemberID as unique slug + DisplayName string `json:"display_name"` + Description string `json:"description"` // Map from Robot.Bio + // ... +} +``` + +### 1.2 Cache/Load Update Needed + +Update `cache/load.go` to fetch `bio` field: + +```go +var memberFields = []interface{}{ + "id", + "member_id", + "team_id", + "display_name", + "bio", // ADD THIS + "system_prompt", + "robot_status", + "autonomous_mode", + "robot_config", + "robot_email", // Already there +} +``` + +### 1.3 Missing Fields in `Execution` struct + +| Field | Type | Location | Description | +|-------|------|----------|-------------| +| `Name` | `string` | `types/robot.go` | Derived from goals or human input, for UI display | +| `CurrentTaskName` | `string` | `types/robot.go` | What the agent is doing RIGHT NOW | + +**Required (add to Execution struct):** +```go +type Execution struct { + // ... existing fields ... + Name string `json:"name,omitempty"` // NEW: execution name for UI + CurrentTaskName string `json:"current_task_name,omitempty"` // NEW: current task description +} +``` + +> **Note:** These can be derived in the OpenAPI layer from existing fields: +> - `Name`: Derive from `Goals.Content` first line or `Input.Messages[0].Content` +> - `CurrentTaskName`: Derive from `Current.Task` executor info or progress + +### 1.4 New Types Needed + +#### Activity Type (for Activity API) + +> **Note:** Activity can be derived from execution history without new storage. +> These types go in OpenAPI response layer, not core types. + +```go +// openapi/agent/robot/types.go (API response types) + +// ActivityType - activity type enum +type ActivityType string + +const ( + ActivityCompleted ActivityType = "completed" + ActivityFile ActivityType = "file" + ActivityError ActivityType = "error" + ActivityStarted ActivityType = "started" + ActivityPaused ActivityType = "paused" +) + +// ActivityResponse - activity item for UI +type ActivityResponse struct { + ID string `json:"id"` + Type ActivityType `json:"type"` + MemberID string `json:"member_id"` + RobotName string `json:"robot_name"` // Localized + Title string `json:"title"` // Localized + Description string `json:"description,omitempty"` // Localized + FileID string `json:"file_id,omitempty"` + Timestamp string `json:"timestamp"` // ISO format +} +``` + +#### ResultFile Type (for Results API) + +> **Note:** Results are derived from `execution.delivery.content.attachments`. +> No separate storage needed. + +```go +// openapi/agent/robot/types.go (API response types) + +// ResultFileResponse - deliverable file for Results Tab +type ResultFileResponse struct { + ID string `json:"id"` // attachment index or file ID + MemberID string `json:"member_id"` + ExecutionID string `json:"execution_id"` + Name string `json:"name"` // From attachment.Title + Type string `json:"type"` // Derived from file extension + Size int64 `json:"size"` // From file system + CreatedAt string `json:"created_at"` // Execution end time + TriggerType string `json:"trigger_type,omitempty"` + ExecutionName string `json:"execution_name,omitempty"` // Derived +} +``` + +--- + +## 2. Multi-turn Conversation Gap (Critical) + +### 2.1 Frontend Expectation + +The frontend `ChatDrawer` component expects **multi-turn conversation** before execution starts: + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ ASSIGN TASK DRAWER (ChatDrawer) โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”‚ +โ”‚ User: "Help me analyze competitor pricing" โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ Robot: "Got it. Which competitors? Any specific metrics?" โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ User: "Focus on Company A and B, compare pricing tiers" โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ Robot: "Understood. I'll analyze A and B pricing tiers. โ”‚ +โ”‚ Ready to start?" โ”‚ +โ”‚ โ†“ โ”‚ +โ”‚ User clicks [Confirm] โ†’ Execution starts โ”‚ +โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +**Key Flow:** +1. User sends message โ†’ Backend returns assistant response +2. User can continue conversation (refine task) +3. User confirms โ†’ Execution actually starts + +### 2.2 Current Backend Implementation + +```go +// api/trigger.go - Current behavior +func Trigger(ctx *types.Context, memberID string, req *TriggerRequest) (*TriggerResult, error) { + // Immediately submits to execution pool + // No conversation state, no confirmation step +} +``` + +**Problem:** Backend triggers execution immediately on first message. No multi-turn conversation support. + +### 2.3 Gap Analysis + +| Feature | Frontend Expects | Backend Has | +|---------|------------------|-------------| +| Multi-turn chat | โœ… Yes | โŒ No | +| Conversation state | โœ… Yes | โŒ No | +| Confirm before execute | โœ… Yes | โŒ No | +| SSE for each message | โœ… Yes | โŒ No | + +### 2.4 Required New API + +**Option A: Chat API (Recommended)** + +``` +POST /v1/agent/robots/:id/chat +``` + +**Request:** +```json +{ + "conversation_id": "conv_001", // Optional, for continuing conversation + "messages": [ + { "role": "user", "content": "Help me analyze competitor pricing" } + ], + "attachments": [] +} +``` + +**Response (SSE):** +``` +event: message +data: {"role": "assistant", "content": "Got it. Which competitors?"} + +event: state +data: {"conversation_id": "conv_001", "ready_to_execute": false} +``` + +**Then Trigger with conversation:** +``` +POST /v1/agent/robots/:id/trigger +{ + "conversation_id": "conv_001", // References chat history + "confirm": true +} +``` + +**Option B: Extend Trigger API** + +Add `confirm` parameter to trigger: +```json +{ + "messages": [...], + "confirm": false // false = chat mode, true = execute +} +``` + +### 2.5 Backend Implementation Needed + +1. **Conversation Store** - Store chat history temporarily + ```go + // store/conversation.go (NEW) + type ConversationStore interface { + Create(memberID string, messages []Message) (conversationID string, error) + Append(conversationID string, messages []Message) error + Get(conversationID string) (*Conversation, error) + Delete(conversationID string) error // Auto-cleanup after execution + } + ``` + +2. **Chat Handler** - Process messages, return assistant response + ```go + // api/chat.go (NEW) + func Chat(ctx *types.Context, memberID string, req *ChatRequest) (*ChatResponse, error) { + // 1. Get or create conversation + // 2. Call LLM for response (using robot's system prompt) + // 3. Store updated conversation + // 4. Return assistant message + conversation_id + } + ``` + +3. **Trigger Extension** - Support conversation_id + ```go + // api/trigger.go (MODIFY) + type TriggerRequest struct { + // ... existing fields ... + ConversationID string `json:"conversation_id,omitempty"` // NEW + } + ``` + +### 2.6 Same for Intervention + +`GuideExecutionDrawer` also uses `ChatDrawer` and expects the same multi-turn behavior for intervention. + +--- + +## 3. Backend API Gaps (`yao/agent/robot/api/`) + +### 3.1 Missing Functions + +| Function | Status | Description | +|----------|--------|-------------| +| `Create()` | โฌœ Missing | Create new robot member | +| `Update()` | โฌœ Missing | Update robot config | +| `Remove()` | โฌœ Missing | Delete robot member | +| `ListResults()` | โฌœ Missing | Query deliverable files from executions | +| `GetResult()` | โฌœ Missing | Get single deliverable detail | +| `ListActivities()` | โฌœ Missing | Query activity feed | +| `RetryExecution()` | โฌœ Missing | Retry a failed execution | + +### 3.2 Existing Functions (API layer can call these) + +| Function | File | Status | +|----------|------|--------| +| `List()` | `robot.go` | โœ… Exists | +| `Get()` | `robot.go` | โœ… Exists | +| `GetStatus()` | `robot.go` | โœ… Exists | +| `Trigger()` | `trigger.go` | โœ… Exists | +| `Intervene()` | `trigger.go` | โœ… Exists | +| `GetExecutions()` | `execution.go` | โœ… Exists | +| `GetExecution()` | `execution.go` | โœ… Exists | +| `PauseExecution()` | `execution.go` | โœ… Exists | +| `ResumeExecution()` | `execution.go` | โœ… Exists | +| `StopExecution()` | `execution.go` | โœ… Exists | + +### 3.3 Required API Extensions + +**File: `api/robot.go`** +```go +// Create creates a new robot member +func Create(ctx *types.Context, teamID string, req *CreateRobotRequest) (*types.Robot, error) + +// Update updates robot config +func Update(ctx *types.Context, memberID string, req *UpdateRobotRequest) (*types.Robot, error) + +// Remove deletes a robot member +func Remove(ctx *types.Context, memberID string) error +``` + +**File: `api/results.go` (NEW)** +```go +// ListResults returns deliverable files for a robot +func ListResults(ctx *types.Context, memberID string, query *ResultQuery) (*ResultsResult, error) + +// GetResult returns a single deliverable detail +func GetResult(ctx *types.Context, resultID string) (*types.ResultFile, error) +``` + +**File: `api/activities.go` (NEW)** +```go +// ListActivities returns recent activities +func ListActivities(ctx *types.Context, query *ActivityQuery) (*ActivitiesResult, error) +``` + +**File: `api/execution.go` (extend)** +```go +// RetryExecution retries a failed execution +func RetryExecution(ctx *types.Context, execID string) (*TriggerResult, error) +``` + +--- + +## 4. OpenAPI Layer (`yao/openapi/agent/robot/`) + +### 4.1 Files to Create + +``` +yao/openapi/agent/robot/ +โ”œโ”€โ”€ DESIGN.md # โœ… Exists +โ”œโ”€โ”€ TODO.md # โœ… Exists +โ”œโ”€โ”€ GAPS.md # โœ… This file +โ”‚ +โ”œโ”€โ”€ robot.go # Route registration +โ”œโ”€โ”€ types.go # Request/Response types +โ”œโ”€โ”€ list.go # GET /v1/agent/robots +โ”œโ”€โ”€ detail.go # GET/POST/PUT/DELETE /v1/agent/robots/:id +โ”œโ”€โ”€ execution.go # Execution list/detail/control +โ”œโ”€โ”€ trigger.go # Trigger/Intervene (SSE) +โ”œโ”€โ”€ results.go # Results endpoints +โ”œโ”€โ”€ activities.go # Activities endpoint +โ”œโ”€โ”€ stream.go # Real-time SSE streams +โ”œโ”€โ”€ filter.go # Query param parsing +โ””โ”€โ”€ utils.go # Locale, time formatting +``` + +### 4.2 Endpoints to Implement + +#### Robot CRUD (5 endpoints) + +| Endpoint | Handler | Backend API | +|----------|---------|-------------| +| `GET /robots` | `ListRobots` | `api.List()` โœ… | +| `GET /robots/:id` | `GetRobot` | `api.Get()` + `api.GetStatus()` โœ… | +| `POST /robots` | `CreateRobot` | `api.Create()` โฌœ | +| `PUT /robots/:id` | `UpdateRobot` | `api.Update()` โฌœ | +| `DELETE /robots/:id` | `DeleteRobot` | `api.Remove()` โฌœ | + +#### Chat & Execution Management (9 endpoints) + +| Endpoint | Handler | Backend API | +|----------|---------|-------------| +| `POST /robots/:id/chat` | `ChatWithRobot` | `api.Chat()` โฌœ **NEW - Multi-turn conversation** | +| `GET /robots/:id/executions` | `ListExecutions` | `api.GetExecutions()` โœ… | +| `GET /robots/:id/executions/:exec_id` | `GetExecution` | `api.GetExecution()` โœ… | +| `POST /robots/:id/trigger` | `TriggerRobot` | `api.Trigger()` โœ… (needs conversation_id support) | +| `POST /robots/:id/intervene` | `InterveneRobot` | `api.Intervene()` โœ… (needs conversation_id support) | +| `POST /robots/:id/executions/:exec_id/pause` | `PauseExecution` | `api.PauseExecution()` โœ… | +| `POST /robots/:id/executions/:exec_id/resume` | `ResumeExecution` | `api.ResumeExecution()` โœ… | +| `POST /robots/:id/executions/:exec_id/cancel` | `CancelExecution` | `api.StopExecution()` โœ… | +| `POST /robots/:id/executions/:exec_id/retry` | `RetryExecution` | `api.RetryExecution()` โฌœ | + +#### Results (2 endpoints) + +| Endpoint | Handler | Backend API | +|----------|---------|-------------| +| `GET /robots/:id/results` | `ListResults` | `api.ListResults()` โฌœ | +| `GET /robots/:id/results/:result_id` | `GetResult` | `api.GetResult()` โฌœ | + +#### Activities (1 endpoint) + +| Endpoint | Handler | Backend API | +|----------|---------|-------------| +| `GET /robots/activities` | `ListActivities` | `api.ListActivities()` โฌœ | + +#### SSE Streams (3 endpoints) + +| Endpoint | Handler | Backend Event Bus | +|----------|---------|-------------------| +| `GET /robots/stream` | `StreamRobots` | โฌœ New event bus needed | +| `GET /robots/:id/executions/:exec_id/stream` | `StreamExecution` | โฌœ New event bus needed | +| `POST /robots/:id/trigger` (SSE) | `TriggerRobot` | Wrap existing `api.Trigger()` | +| `POST /robots/:id/intervene` (SSE) | `InterveneRobot` | Wrap existing `api.Intervene()` | + +--- + +## 5. SSE Infrastructure Gaps + +### 5.1 Event Bus Needed + +The backend needs an event bus to publish real-time events. Currently, the robot module doesn't have one. + +**Required Components:** + +```go +// robot/events/bus.go (NEW PACKAGE) + +type EventBus struct { + subscribers map[string][]chan Event + mu sync.RWMutex +} + +type Event struct { + Type string `json:"type"` // robot_status, execution_start, etc. + Payload interface{} `json:"payload"` +} + +func (bus *EventBus) Publish(event Event) +func (bus *EventBus) Subscribe(topic string) <-chan Event +func (bus *EventBus) Unsubscribe(topic string, ch <-chan Event) +``` + +### 5.2 Event Publishers Needed + +| Event | Source | When | +|-------|--------|------| +| `robot_status` | Manager | Robot status changes | +| `execution_start` | Executor | Execution begins | +| `execution_complete` | Executor | Execution ends | +| `phase` | Executor | Phase changes | +| `task_start` | Runner | Task begins | +| `task_complete` | Runner | Task ends | +| `activity` | Multiple | Any activity event | + +### 5.3 Integration Points + +**In `manager/manager.go`:** +```go +// Publish when robot status changes +eventBus.Publish(Event{Type: "robot_status", Payload: ...}) +``` + +**In `executor/standard/executor.go`:** +```go +// Publish when execution starts/ends +eventBus.Publish(Event{Type: "execution_start", Payload: ...}) +``` + +--- + +## 6. i18n Support Gaps + +### 6.1 Current State + +- No locale parameter in backend API +- No localization infrastructure + +### 6.2 Required Changes + +**Add locale to context:** +```go +// types/context.go +type Context struct { + context.Context + Auth *types.AuthorizedInfo + MemberID string + Locale string // NEW: "zh-CN" | "en-US" +} +``` + +**Add locale helper:** +```go +// utils/locale.go (NEW) +func GetLocale(r *http.Request) string +func Localize(key, locale string) string +``` + +**Localized fields:** +- `RobotState.display_name` +- `RobotState.description` +- `Execution.name` +- `Execution.current_task_name` +- `ResultFile.name` +- `ResultFile.execution_name` +- `Activity.robot_name` +- `Activity.title` +- `Activity.description` + +--- + +## 7. Data Source Gaps + +### 7.1 Results Data + +Results are derived from execution delivery data. Need to: + +1. **Query from `store/execution.go`** - executions with delivery attachments +2. **Extract attachment metadata** - file ID, name, type, size + +**Implementation:** +```go +// store/results.go (NEW) +func (s *ExecutionStore) ListResults(ctx context.Context, memberID string, opts *ResultsQuery) ([]*ResultFile, int, error) { + // Query executions with delivery.content.attachments + // Extract and format as ResultFile +} +``` + +### 7.2 Activities Data + +Activities can be derived from: +1. **Job system logs** - existing `job.ListLogs()` +2. **Execution state changes** - from `store/execution.go` + +**Implementation Options:** + +**Option A: Derive from execution history** +```go +func ListActivities(ctx context.Context, query *ActivityQuery) ([]*Activity, error) { + // Query recent executions + // Map to Activity based on status changes +} +``` + +**Option B: Separate activity log (recommended for real-time)** +```go +// New table: __yao.robot_activity +type ActivityRecord struct { + ID int64 + Type ActivityType + MemberID string + ExecutionID string + Data JSON + Timestamp time.Time +} +``` + +--- + +## 8. Implementation Priority + +> **Strategy:** Low-risk phases first. Medium-risk features (Chat API, SSE) can be deferred. +> Frontend can use polling and single-submit mode as fallback. + +--- + +### ๐ŸŸข Phase 1: Core CRUD [Low Risk] + +1. โฌœ Add `Bio` field to `Robot` struct (`types/robot.go`) +2. โฌœ Add `bio` to `memberFields` in `cache/load.go` +3. โฌœ Implement `api.Create()`, `api.Update()`, `api.Remove()` +4. โฌœ Create OpenAPI handlers: list, detail, create, update, delete +5. โฌœ Add response type mapping (`name` โ† `member_id`, `description` โ† `bio`) + +### ๐ŸŸข Phase 2: Execution Management [Low Risk] + +1. โฌœ Add derived fields in OpenAPI layer (`name`, `current_task_name`) +2. โฌœ Implement `api.RetryExecution()` +3. โฌœ Create OpenAPI handlers: execution list, detail, control +4. โฌœ Wrap trigger/intervene (single-submit mode, no chat) + +### ๐ŸŸข Phase 3: Results & Activities [Low Risk] + +1. โฌœ Create `ActivityResponse` and `ResultFileResponse` types in OpenAPI layer +2. โฌœ Implement `api.ListResults()`, `api.GetResult()` (derive from executions) +3. โฌœ Implement `api.ListActivities()` (derive from execution history) +4. โฌœ Create OpenAPI handlers + +### ๐ŸŸข Phase 4: i18n [Low Risk] + +1. โฌœ Add `Locale` to context +2. โฌœ Add locale helper functions +3. โฌœ Implement localized response fields + +--- + +### ๐ŸŸก Phase 5: Multi-turn Chat API [Medium Risk - Deferred] + +> **Fallback:** Frontend uses single-submit mode (user input โ†’ immediate execution) + +1. โฌœ Create `store/conversation.go` - temporary conversation storage +2. โฌœ Create `api/chat.go` - chat handler with LLM call +3. โฌœ Extend `api/trigger.go` - support `conversation_id` +4. โฌœ Create OpenAPI endpoint: `POST /robots/:id/chat` (SSE) +5. โฌœ Update `POST /robots/:id/trigger` to accept conversation reference +6. โฌœ Same for `POST /robots/:id/intervene` + +### ๐ŸŸก Phase 6: Real-time SSE [Medium Risk - Deferred] + +> **Fallback:** Frontend uses polling (GET /executions every 3-5s) + +1. โฌœ Create event bus package +2. โฌœ Integrate event publishing in manager/executor +3. โฌœ Implement SSE stream handlers +4. โฌœ End-to-end testing + +--- + +## 9. Testing Strategy + +### Unit Tests + +- `types/activity_test.go` - new types +- `types/result_test.go` - new types +- `api/robot_test.go` - CRUD functions +- `api/results_test.go` - results API +- `api/activities_test.go` - activities API + +### Integration Tests + +- `openapi/agent/robot/*_test.go` - HTTP endpoint tests +- `openapi/agent/robot/sse_test.go` - SSE stream tests + +### E2E Tests + +- Full flow: create robot โ†’ trigger โ†’ stream events โ†’ get results + +--- + +## 10. Files to Modify Summary + +### Backend (`yao/agent/robot/`) + +| File | Action | Changes | +|------|--------|---------| +| `types/robot.go` | Modify | Add `Bio` field, optionally `Name`/`CurrentTaskName` for Execution | +| `types/conversation.go` | Create | `Conversation`, `ChatRequest`, `ChatResponse` types | +| `cache/load.go` | Modify | Add `bio` to `memberFields` slice | +| `store/conversation.go` | Create | Temporary conversation storage (redis/memory) | +| `types/context.go` | Modify | Add `Locale` field | +| `api/robot.go` | Modify | Add `Create()`, `Update()`, `Remove()` | +| `api/chat.go` | Create | `Chat()` - multi-turn conversation handler | +| `api/trigger.go` | Modify | Add `ConversationID` support | +| `api/execution.go` | Modify | Add `RetryExecution()` | +| `api/results.go` | Create | `ListResults()`, `GetResult()` - query from execution store | +| `api/activities.go` | Create | `ListActivities()` - derive from execution history | +| `events/bus.go` | Create | Event bus for SSE (Phase 5) | + +### OpenAPI (`yao/openapi/agent/robot/`) + +| File | Action | Description | +|------|--------|-------------| +| `robot.go` | Create | Route registration | +| `types.go` | Create | Request/Response types | +| `list.go` | Create | List robots handler | +| `detail.go` | Create | Robot CRUD handlers | +| `chat.go` | Create | Multi-turn chat SSE handler | +| `execution.go` | Create | Execution handlers | +| `trigger.go` | Create | Trigger/Intervene SSE (with conversation support) | +| `results.go` | Create | Results handlers | +| `activities.go` | Create | Activities handler | +| `stream.go` | Create | SSE streams | +| `filter.go` | Create | Query parsing | +| `utils.go` | Create | Utilities | + +### Parent (`yao/openapi/agent/`) + +| File | Action | Changes | +|------|--------|---------| +| `agent.go` | Modify | Add `robot.Attach(group.Group("/robots"), oauth)` | + +--- + +## 11. References + +- Frontend API Requirements: `cui/packages/cui/pages/mission-control/API.md` +- Backend Robot Types: `yao/agent/robot/types/` +- Backend Robot API: `yao/agent/robot/api/` +- OpenAPI Design: `yao/openapi/agent/robot/DESIGN.md` +- OpenAPI TODO: `yao/openapi/agent/robot/TODO.md` diff --git a/openapi/agent/robot/TODO.md b/openapi/agent/robot/TODO.md new file mode 100644 index 00000000..a2845a4c --- /dev/null +++ b/openapi/agent/robot/TODO.md @@ -0,0 +1,554 @@ +# Robot OpenAPI - Implementation TODO + +> Based on: `openapi/agent/robot/DESIGN.md`, `openapi/agent/robot/GAPS.md` +> Depends on: `yao/agent/robot/api/` (Go API layer) +> Base Path: `/v1/agent/robots` + +--- + +## Implementation Strategy + +> **Low-risk phases first. Medium-risk features can be deferred.** +> Frontend has fallback mechanisms (polling, single-submit mode). + +``` +๐ŸŸข Low Risk (Do First): + Phase 1: Core CRUD (MVP) + โ””โ”€ List, Get, Create, Update, Delete robots + + Phase 2: Execution Management + โ””โ”€ List, Get, Control executions, Trigger/Intervene (single-submit) + + Phase 3: Results & Activities + โ””โ”€ List deliverables, Activity feed + + Phase 4: i18n + โ””โ”€ Locale parameter support + +๐ŸŸก Medium Risk (Deferred): + Phase 5: Multi-turn Chat API + โ””โ”€ Conversation before execution (Frontend fallback: single-submit) + + Phase 6: Real-time SSE Streams + โ””โ”€ Robot status stream, Execution progress (Frontend fallback: polling) +``` + +--- + +## ๐ŸŸข Phase 1: Core CRUD โฌœ [Low Risk] + +**Goal:** Basic robot management endpoints +**Risk:** ๐ŸŸข Low - All new code, no changes to existing logic + +### 1.1 Backend Prerequisites โฌœ + +- [ ] Add `Bio` field to `types.Robot` struct in `yao/agent/robot/types/robot.go` +- [ ] Add `bio` to `memberFields` in `yao/agent/robot/cache/load.go` +- [ ] Implement `api.Create()` in `yao/agent/robot/api/robot.go` +- [ ] Implement `api.Update()` in `yao/agent/robot/api/robot.go` +- [ ] Implement `api.Remove()` in `yao/agent/robot/api/robot.go` + +### 1.2 Setup โฌœ + +- [ ] Create `openapi/agent/robot/` directory (sub-package under agent) +- [ ] Create `robot.go` - route registration with `Attach()` function +- [ ] Register routes in `openapi/agent/agent.go` via `robot.Attach(group.Group("/robots"), oauth)` +- [ ] Add OAuth guard middleware + +### 1.3 Types โฌœ + +- [ ] `types.go` - request/response types + - [ ] `RobotResponse` struct (with field mapping: `name` โ† `member_id`, `description` โ† `bio`) + - [ ] `ConfigResponse` struct (and sub-types) + - [ ] `ListRobotsResponse` struct + - [ ] `CreateRobotRequest` struct + - [ ] `UpdateRobotRequest` struct + - [ ] `NewRobotResponse()` - conversion function + - [ ] Error response types + +### 1.4 List Robots โฌœ + +- [ ] `list.go` - GET /v1/robots +- [ ] Parse query params: `locale`, `status`, `keywords`, `page`, `pagesize` +- [ ] Call `robot/api.List()` +- [ ] Format response with localization +- [ ] Test: `tests/robot/list_test.go` + +### 1.5 Get Robot โฌœ + +- [ ] `detail.go` - GET /v1/robots/:id +- [ ] Parse path param and `locale` query +- [ ] Call `robot/api.Get()` and `robot/api.Status()` +- [ ] Format response with full config +- [ ] Team access check +- [ ] Test: `tests/robot/get_test.go` + +### 1.6 Create Robot โฌœ + +- [ ] POST /v1/robots handler +- [ ] Parse `CreateRobotRequest` +- [ ] Validate required fields +- [ ] Call `robot/api.Create()` +- [ ] Return created robot +- [ ] Test: `tests/robot/create_test.go` + +### 1.7 Update Robot โฌœ + +- [ ] PUT /v1/robots/:id handler +- [ ] Parse `UpdateRobotRequest` +- [ ] Ownership/permission check +- [ ] Call `robot/api.Update()` +- [ ] Return updated robot +- [ ] Test: `tests/robot/update_test.go` + +### 1.8 Delete Robot โฌœ + +- [ ] DELETE /v1/robots/:id handler +- [ ] Ownership/permission check +- [ ] Call `robot/api.Remove()` +- [ ] Return success response +- [ ] Test: `tests/robot/delete_test.go` + +### 1.9 Utilities โฌœ + +- [ ] `utils.go` - helper functions + - [ ] `getLocale(r *http.Request)` - extract locale + - [ ] `formatTime(t *time.Time)` - format to ISO string + - [ ] `localizeString(value, locale)` - localization helper +- [ ] `filter.go` - query filtering + - [ ] Parse query params to `ListQuery` + - [ ] Parse query params to `ExecutionQuery` + +--- + +## ๐ŸŸข Phase 2: Execution Management โฌœ [Low Risk] + +**Goal:** Execution listing, details, control, and trigger/intervene (single-submit mode) +**Risk:** ๐ŸŸข Low - Wraps existing API functions + +### 2.1 List Executions โฌœ + +- [ ] `execution.go` - GET /v1/robots/:id/executions +- [ ] Parse query params: `status`, `trigger_type`, `keyword`, `page`, `pagesize` +- [ ] Call `robot/api.GetExecutions()` +- [ ] Add derived fields: `name`, `current_task_name` +- [ ] Format response +- [ ] Test: `tests/robot/execution_list_test.go` + +### 2.2 Get Execution โฌœ + +- [ ] GET /v1/robots/:id/executions/:exec_id +- [ ] Call `robot/api.GetExecution()` +- [ ] Full task details with localization +- [ ] Test: `tests/robot/execution_get_test.go` + +### 2.3 Execution Control โฌœ + +- [ ] POST /v1/robots/:id/executions/:exec_id/pause + - [ ] Call `robot/api.Pause()` +- [ ] POST /v1/robots/:id/executions/:exec_id/resume + - [ ] Call `robot/api.Resume()` +- [ ] POST /v1/robots/:id/executions/:exec_id/cancel + - [ ] Call `robot/api.Stop()` +- [ ] POST /v1/robots/:id/executions/:exec_id/retry + - [ ] Re-trigger with same input +- [ ] Test: `tests/robot/execution_control_test.go` + +### 2.4 Execution Types โฌœ + +- [ ] Add to `types.go`: + - [ ] `ExecutionResponse` struct + - [ ] `TaskResponse` struct + - [ ] `CurrentStateResponse` struct + - [ ] `GoalsResponse` struct + - [ ] `DeliveryResultResponse` struct + +### 2.5 Trigger & Intervene (Single-Submit Mode) โฌœ + +> **Note:** This is single-submit mode. Multi-turn chat is deferred to Phase 5. + +- [ ] `trigger.go` - POST /v1/robots/:id/trigger +- [ ] Parse `TriggerRequest` (messages, attachments) +- [ ] Call `robot/api.Trigger()` +- [ ] Return execution ID and status +- [ ] Optional: Return SSE stream for progress +- [ ] Test: `tests/robot/trigger_test.go` + +- [ ] POST /v1/robots/:id/intervene +- [ ] Parse `InterveneRequest` +- [ ] Call `robot/api.Intervene()` +- [ ] Return result +- [ ] Test: `tests/robot/intervene_test.go` + +### 2.6 Trigger Types โฌœ + +- [ ] Add to `types.go`: + - [ ] `TriggerRequest` struct + - [ ] `TriggerResponse` struct + - [ ] `InterveneRequest` struct + - [ ] `InterveneResponse` struct + - [ ] `Message` struct + - [ ] `Attachment` struct + +--- + +## ๐ŸŸข Phase 3: Results & Activities โฌœ [Low Risk] + +**Goal:** Deliverables listing and activity feed +**Risk:** ๐ŸŸข Low - Read-only queries, derived from existing data + +### 3.1 Backend Prerequisites โฌœ + +Need to add in `robot/api/`: + +- [ ] `ListResults(memberID, query)` function +- [ ] `GetResult(resultID)` function +- [ ] `ListActivities(query)` function + +Need to add in `robot/store/`: + +- [ ] Results store (query from execution delivery data) +- [ ] Activities store (or derive from job logs) + +### 3.2 Results Endpoints โฌœ + +- [ ] `results.go` - results handlers +- [ ] GET /v1/robots/:id/results + - [ ] Parse filters: `trigger_type`, `keyword`, `page`, `pagesize` + - [ ] Call `robot/api.ListResults()` + - [ ] Format response +- [ ] GET /v1/robots/:id/results/:result_id + - [ ] Call `robot/api.GetResult()` + - [ ] Return full delivery content +- [ ] Test: `tests/robot/results_test.go` + +### 3.3 Results Types โฌœ + +- [ ] Add to `types.go`: + - [ ] `ResultResponse` struct + - [ ] `ResultDetailResponse` struct + - [ ] `DeliveryContentResponse` struct + - [ ] `DeliveryAttachmentResponse` struct + +### 3.4 Activities Endpoints โฌœ + +- [ ] `activities.go` - activities handlers +- [ ] GET /v1/robots/activities + - [ ] Parse: `limit`, `since` + - [ ] Call `robot/api.ListActivities()` + - [ ] Format response +- [ ] Test: `tests/robot/activities_test.go` + +### 3.5 Activity Types โฌœ + +- [ ] Add to `types.go`: + - [ ] `ActivityResponse` struct + - [ ] `ActivityType` constants + +--- + +## ๐ŸŸข Phase 4: i18n โฌœ [Low Risk] + +**Goal:** Locale parameter support +**Risk:** ๐ŸŸข Low - Additive, optional parameter + +### 4.1 Locale Handling โฌœ + +- [ ] Add `getLocale(r *http.Request)` to utils.go +- [ ] Parse locale from query param, body, or header +- [ ] Add `Locale` field to context if needed + +### 4.2 Localized Responses โฌœ + +- [ ] Localize `display_name` in RobotResponse +- [ ] Localize `description` in RobotResponse +- [ ] Localize `name` in ExecutionResponse (derive from goals/input) +- [ ] Localize `current_task_name` in ExecutionResponse + +--- + +## ๐ŸŸก Phase 5: Multi-turn Chat API โฌœ [Medium Risk - Deferred] + +> **Frontend Fallback:** Single-submit mode (user input โ†’ immediate execution) +> **Risk:** ๐ŸŸก Medium - New stateful component + +**Goal:** Multi-turn conversation before execution + +### 5.1 Backend Prerequisites โฌœ + +- [ ] Create `store/conversation.go` - temporary conversation storage (redis/memory) +- [ ] Create `types/conversation.go` - Conversation, ChatRequest, ChatResponse types +- [ ] Create `api/chat.go` - Chat() handler with LLM call +- [ ] Extend `api/trigger.go` - support `conversation_id` parameter + +### 5.2 Chat Endpoint โฌœ + +- [ ] POST /v1/robots/:id/chat (SSE) +- [ ] Parse ChatRequest (conversation_id, messages, attachments) +- [ ] Create or continue conversation +- [ ] Call LLM for response +- [ ] Store updated conversation +- [ ] Return assistant message + conversation_id +- [ ] Test: `tests/robot/chat_test.go` + +### 5.3 Trigger with Conversation โฌœ + +- [ ] Extend POST /v1/robots/:id/trigger +- [ ] Accept `conversation_id` parameter +- [ ] Use conversation history as execution input +- [ ] Auto-cleanup conversation after execution starts + +--- + +## ๐ŸŸก Phase 6: Real-time SSE Streams โฌœ [Medium Risk - Deferred] + +> **Frontend Fallback:** Polling (GET /executions every 3-5 seconds) +> **Risk:** ๐ŸŸก Medium - Requires modification of executor/manager + +**Goal:** SSE streams for real-time status updates + +### 6.1 Backend Event System โฌœ + +Need to add in `robot/`: + +- [ ] Create `events/bus.go` - Event bus for pub/sub +- [ ] Integrate event publishing in `manager/manager.go` +- [ ] Integrate event publishing in `executor/standard/executor.go` +- [ ] Publish: robot_status, execution_start, execution_complete, phase, task events + +### 6.2 Robot Status Stream โฌœ + +- [ ] `stream.go` - stream handlers +- [ ] GET /v1/robots/stream + - [ ] Subscribe to manager status updates + - [ ] Stream `robot_status` events + - [ ] Stream `execution_start` events + - [ ] Stream `execution_complete` events + - [ ] Stream `activity` events +- [ ] Test: `tests/robot/stream_test.go` + +### 6.3 Execution Progress Stream โฌœ + +- [ ] GET /v1/robots/:id/executions/:exec_id/stream + - [ ] Subscribe to execution updates + - [ ] Stream `phase` events + - [ ] Stream `task_start` / `task_complete` events + - [ ] Stream `message` events + - [ ] Stream `delivery` event + - [ ] Stream `complete` / `error` events +- [ ] Test: `tests/robot/execution_stream_test.go` + +--- + +## Backend Extensions Required + +### robot/types/ Extensions + +| Type/Field | Phase | Risk | Description | +|------------|-------|------|-------------| +| `Robot.Bio` | 1 | ๐ŸŸข Low | Add field, maps to `__yao.member.bio` | +| Execution name derivation | 2 | ๐ŸŸข Low | Derive in OpenAPI layer from goals or input | + +> **Note:** `Robot.Name` is NOT needed. Frontend `name` maps to existing `Robot.MemberID`. + +### robot/cache/ Extensions + +| File | Phase | Risk | Description | +|------|-------|------|-------------| +| `load.go` | 1 | ๐ŸŸข Low | Add `bio` to `memberFields` slice | + +### robot/api/ Extensions + +| Function | Phase | Risk | Description | +|----------|-------|------|-------------| +| `Create()` | 1 | ๐ŸŸข Low | Create robot member via model | +| `Update()` | 1 | ๐ŸŸข Low | Update robot config via model | +| `Remove()` | 1 | ๐ŸŸข Low | Delete robot member via model | +| `ListResults()` | 3 | ๐ŸŸข Low | Query from execution delivery data | +| `GetResult()` | 3 | ๐ŸŸข Low | Get deliverable detail | +| `ListActivities()` | 3 | ๐ŸŸข Low | Derive from execution history | +| `RetryExecution()` | 2 | ๐ŸŸข Low | Re-trigger with same input | +| `Chat()` | 5 | ๐ŸŸก Medium | Multi-turn conversation handler | + +### robot/store/ Extensions + +| Store | Phase | Risk | Description | +|-------|-------|------|-------------| +| Results query | 3 | ๐ŸŸข Low | Query from execution delivery data | +| Activities query | 3 | ๐ŸŸข Low | Derive from execution history | +| Conversation store | 5 | ๐ŸŸก Medium | Temporary chat history (redis/memory) | + +### Event System (Phase 6 - Deferred) + +| Component | Phase | Risk | Description | +|-----------|-------|------|-------------| +| Event bus | 6 | ๐ŸŸก Medium | Pub/sub for real-time updates | +| Manager events | 6 | ๐ŸŸก Medium | Publish robot status changes | +| Executor events | 6 | ๐ŸŸก Medium | Publish execution progress | + +--- + +## Testing Strategy + +### Test Files Structure + +``` +yao/openapi/tests/robot/ +โ”œโ”€โ”€ list_test.go +โ”œโ”€โ”€ get_test.go +โ”œโ”€โ”€ create_test.go +โ”œโ”€โ”€ update_test.go +โ”œโ”€โ”€ delete_test.go +โ”œโ”€โ”€ execution_list_test.go +โ”œโ”€โ”€ execution_get_test.go +โ”œโ”€โ”€ execution_control_test.go +โ”œโ”€โ”€ trigger_test.go +โ”œโ”€โ”€ intervene_test.go +โ”œโ”€โ”€ results_test.go +โ”œโ”€โ”€ activities_test.go +โ”œโ”€โ”€ stream_test.go +โ””โ”€โ”€ execution_stream_test.go +``` + +### Test Utilities + +- [ ] Create test robot helper +- [ ] Create test execution helper +- [ ] SSE client for streaming tests +- [ ] Mock data generators + +--- + +## Progress Tracking + +| Phase | Risk | Status | Description | +|-------|------|--------|-------------| +| 1. Core CRUD | ๐ŸŸข | โฌœ | Basic robot management | +| 2. Execution | ๐ŸŸข | โฌœ | Execution listing, control, trigger/intervene | +| 3. Results/Activities | ๐ŸŸข | โฌœ | Deliverables and activity feed | +| 4. i18n | ๐ŸŸข | โฌœ | Locale parameter support | +| 5. Chat API | ๐ŸŸก | โฌœ | Multi-turn conversation (Deferred) | +| 6. SSE Streams | ๐ŸŸก | โฌœ | Real-time status updates (Deferred) | + +Legend: โฌœ Not started | ๐ŸŸก In progress | โœ… Complete | ๐ŸŸข Low Risk | ๐ŸŸก Medium Risk + +--- + +## Quick Reference + +### Current Location + +``` +yao/openapi/agent/robot/ # This directory (sub-package under agent) +โ”œโ”€โ”€ DESIGN.md # Design document โœ… +โ”œโ”€โ”€ TODO.md # This file โœ… +โ”œโ”€โ”€ robot.go # Route registration (Attach function) +โ”œโ”€โ”€ types.go # All request/response types +โ”œโ”€โ”€ list.go # GET /v1/agent/robots +โ”œโ”€โ”€ detail.go # GET/POST/PUT/DELETE /v1/agent/robots/:id +โ”œโ”€โ”€ execution.go # Execution endpoints +โ”œโ”€โ”€ trigger.go # Trigger/Intervene SSE +โ”œโ”€โ”€ results.go # Results endpoints +โ”œโ”€โ”€ activities.go # Activities endpoint +โ”œโ”€โ”€ stream.go # Real-time streams +โ”œโ”€โ”€ filter.go # Query filtering +โ””โ”€โ”€ utils.go # Utilities +``` + +### Parent Directory + +``` +yao/openapi/agent/ +โ”œโ”€โ”€ agent.go # MODIFY: add robot.Attach() call +โ”œโ”€โ”€ assistant.go # Existing +โ”œโ”€โ”€ filter.go # Existing +โ”œโ”€โ”€ models.go # Existing +โ”œโ”€โ”€ types.go # Existing +โ”‚ +โ””โ”€โ”€ robot/ # NEW sub-package (this directory) + โ””โ”€โ”€ ... +``` + +### Route Registration (in agent/agent.go) + +```go +import "github.com/yaoapp/yao/openapi/agent/robot" + +func Attach(group *gin.RouterGroup, oauth types.OAuth) { + group.Use(oauth.Guard) + + // Existing assistant routes + group.GET("/assistants", ListAssistants) + group.POST("/assistants", CreateAssistant) + group.GET("/assistants/tags", ListAssistantTags) + group.GET("/assistants/:id", GetAssistant) + group.GET("/assistants/:id/info", GetAssistantInfo) + group.PUT("/assistants/:id", UpdateAssistant) + + // Robot routes (NEW) + robot.Attach(group.Group("/robots"), oauth) +} +``` + +### Dependencies + +| Package | Usage | +|---------|-------| +| `yao/agent/robot/api` | Go API functions (Get, List, Trigger, etc.) | +| `yao/agent/robot/types` | Robot types (Robot, Execution, etc.) | +| `yao/openapi/oauth` | Authentication, Guard middleware | +| `yao/openapi/oauth/types` | OAuth types (AuthorizedInfo) | +| `yao/openapi/response` | Response helpers | + +### Import Path + +```go +package robot + +import ( + "github.com/gin-gonic/gin" + robotapi "github.com/yaoapp/yao/agent/robot/api" + robottypes "github.com/yaoapp/yao/agent/robot/types" + "github.com/yaoapp/yao/openapi/oauth/types" +) +``` + +--- + +## Notes + +### Priority + +| Priority | Phase | Required For | Risk | +|----------|-------|--------------|------| +| 1 | Phase 1 (CRUD) | Basic UI functionality | ๐ŸŸข Low | +| 2 | Phase 2 (Execution) | Active/History tabs, Assign Task | ๐ŸŸข Low | +| 3 | Phase 3 (Results) | Results tab | ๐ŸŸข Low | +| 4 | Phase 4 (i18n) | Multi-language support | ๐ŸŸข Low | +| 5 | Phase 5 (Chat) | Enhanced UX (deferred) | ๐ŸŸก Medium | +| 6 | Phase 6 (SSE) | Real-time updates (deferred) | ๐ŸŸก Medium | + +### Frontend Fallbacks + +| Feature | Full Implementation | Fallback | +|---------|---------------------|----------| +| Assign Task | Multi-turn chat โ†’ Confirm โ†’ Execute | Single-submit โ†’ Execute | +| Real-time Status | SSE push | Polling every 3-5s | + +### Frontend Integration + +After each phase: +1. Test endpoints manually +2. Update frontend `openapi/robot.ts` to use real API +3. Remove mock data usage +4. Test end-to-end flow + +### Incremental Deployment + +Each phase can be deployed independently: +- Phase 1: Basic management works +- Phase 2: Execution history + trigger works +- Phase 3: Results listing works +- Phase 4: Multi-language works +- Phase 5: Enhanced chat UX (optional) +- Phase 6: Real-time updates (optional)