- Added `YaoCreatedBy` and `YaoTeamID` fields to `RobotState` and `RobotResponse` for improved access control. - Updated `GetRobotStatus` to retrieve permission fields from the store and populate the robot state. - Modified `robotFields` in the store to include new Yao permission fields for better management of access control. - Enhanced OpenAPI integration by registering robot routes and ensuring proper permission checks in handlers. - Updated documentation in TODO.md to reflect the completion of permission logic and API enhancements.
22 KiB
Robot OpenAPI - Implementation TODO
Based on:
openapi/agent/robot/DESIGN.md,openapi/agent/robot/GAPS.mdDepends 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 Status: ✅ Complete
1.1 Backend Prerequisites ✅
Types & Cache
- Add
Biofield totypes.Robotstruct inyao/agent/robot/types/robot.go - Add
biotomemberFieldsinyao/agent/robot/cache/load.go
Store Layer (Core CRUD - implement first)
- Create
store/robot.gowithRobotStorestruct - Implement
RobotStore.Save()- create/update robot member - Implement
RobotStore.Get()- get by member_id - Implement
RobotStore.List()- list with filters - Implement
RobotStore.Delete()- delete robot member - Implement
RobotStore.UpdateConfig()- update config only - Implement
RobotStore.UpdateStatus()- update status only - Add Yao permission fields support (
__yao_created_by,__yao_team_id, etc.) - Add tests:
store/robot_test.go
API Layer (Thin wrappers calling store)
- Implement
api.CreateRobot()- callstore.RobotStore.Save()+ cache refresh - Implement
api.UpdateRobot()- partial update + cache refresh - Implement
api.RemoveRobot()- callstore.RobotStore.Delete()+ cache invalidate - Implement
api.GetRobotResponse()- get robot as API response - Add
AuthScopefor Yao permission fields - Add request/response types in
api/types.go - Add tests:
api/robot_test.go
Utils Layer
- Create
utils/convert.gowith unified type conversion functions - Implement
To<Type>functions (ToBool, ToInt, ToFloat64, ToTimestamp, ToJSONValue) - Implement
Get<Type>functions for map value extraction - Add tests:
utils/convert_test.go
1.2 OpenAPI Setup ✅
- Create
openapi/agent/robot/directory (sub-package under agent) - Create
robot.go- route registration withAttach()function - Register routes in
openapi/agent/agent.goviarobot.Attach(group.Group("/robots"), oauth) - Add OAuth guard middleware
1.3 OpenAPI Types ✅
Note: Core types already exist in
agent/robot/api/types.go. OpenAPI layer needs HTTP-specific types.
types.go- HTTP request/response typesRobotResponsestruct (with field mapping:name←member_id,description←bio)RobotStatusResponsestructListRobotsResponsestructCreateRobotRequeststruct (HTTP binding)UpdateRobotRequeststruct (HTTP binding)NewRobotResponse()- conversion fromapi.RobotResponseNewRobotStatusResponse()- conversion fromapi.RobotState
1.4 List Robots ✅
list.go- GET /v1/agent/robots- Parse query params:
status,keywords,page,pagesize,team_id - Call
robot/api.ListRobots() - Team constraint from auth info
- Test:
tests/agent/robot_test.go#TestListRobots
1.5 Get Robot ✅
detail.go- GET /v1/agent/robots/:id- Parse path param
- Call
robot/api.GetRobotResponse() - Team access check
- Test:
tests/agent/robot_test.go#TestGetRobot
1.6 Create Robot ✅
- POST /v1/agent/robots handler
- Parse HTTP request to
CreateRobotRequest - Apply
AuthScopewith permission fields (CreatedBy, TeamID, TenantID) - Call
robot/api.CreateRobot() - Return created robot (201 Created)
- Handle duplicate (409 Conflict)
- Test:
tests/agent/robot_test.go#TestCreateRobot
1.7 Update Robot ✅
- PUT /v1/agent/robots/:id handler
- Parse HTTP request to
UpdateRobotRequest - Team permission check
- Apply
AuthScopewith UpdatedBy - Call
robot/api.UpdateRobot() - Return updated robot
- Test:
tests/agent/robot_test.go#TestUpdateRobot
1.8 Delete Robot ✅
- DELETE /v1/agent/robots/:id handler
- Team permission check
- Call
robot/api.RemoveRobot() - Handle running executions (409 Conflict)
- Return success response
- Test:
tests/agent/robot_test.go#TestDeleteRobot
1.9 Status Endpoint ✅
- GET /v1/agent/robots/:id/status handler
- Call
robot/api.GetRobotStatus() - Return runtime status (running count, max, last/next run)
- Test:
tests/agent/robot_test.go#TestGetRobotStatus
1.10 Utilities ✅
utils.go- helper functionsGetLocale(c *gin.Context)- extract locale from query/headerParseBoolValue()- parse bool from string
1.11 Permission Logic ✅
permission.go- permission check functionsCanRead()- read permission check (creator or team member)CanWrite()- write permission check (creator only)GetEffectiveTeamID()- get effective team_id (user_id for personal users)BuildListFilter()- build list filter based on permissions
- Apply permission checks in handlers:
GetRobot- checkCanRead()withYaoTeamIDandYaoCreatedByGetRobotStatus- checkCanRead()UpdateRobot- checkCanWrite()DeleteRobot- checkCanWrite()ListRobots- useBuildListFilter()for team filteringCreateRobot- auto-set__yao_team_idtouser_idfor personal users
- Add Yao permission fields to API layer:
api/types.go- addYaoCreatedBy,YaoTeamIDtoRobotResponseandRobotStateapi/robot.go- populate permission fields inrecordToResponse()andGetRobotStatus()store/robot.go- add__yao_*fields torobotFields
- Permission tests in
tests/agent/robot_test.go#TestRobotPermissions
🟢 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()
- Call
- POST /v1/robots/:id/executions/:exec_id/resume
- Call
robot/api.Resume()
- Call
- POST /v1/robots/:id/executions/:exec_id/cancel
- Call
robot/api.Stop()
- Call
- 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:ExecutionResponsestructTaskResponsestructCurrentStateResponsestructGoalsResponsestructDeliveryResultResponsestruct
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:TriggerRequeststructTriggerResponsestructInterveneRequeststructInterveneResponsestructMessagestructAttachmentstruct
🟢 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 ⬜
Store Layer (Core implementation)
- Add
ExecutionStore.ListResults()- query deliverables from execution delivery data - Add
ExecutionStore.GetResult()- get single deliverable detail - Add
ExecutionStore.ListActivities()- derive activities from execution history
API Layer (Thin wrappers)
- Create
api/results.gowithListResults(),GetResult()- call store - Create
api/activities.gowithListActivities()- call store
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
- Parse filters:
- GET /v1/robots/:id/results/:result_id
- Call
robot/api.GetResult() - Return full delivery content
- Call
- Test:
tests/robot/results_test.go
3.3 Results Types ⬜
- Add to
types.go:ResultResponsestructResultDetailResponsestructDeliveryContentResponsestructDeliveryAttachmentResponsestruct
3.4 Activities Endpoints ⬜
activities.go- activities handlers- GET /v1/robots/activities
- Parse:
limit,since - Call
robot/api.ListActivities() - Format response
- Parse:
- Test:
tests/robot/activities_test.go
3.5 Activity Types ⬜
- Add to
types.go:ActivityResponsestructActivityTypeconstants
🟢 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
Localefield to context if needed
4.2 Localized Responses ⬜
- Localize
display_namein RobotResponse - Localize
descriptionin RobotResponse - Localize
namein ExecutionResponse (derive from goals/input) - Localize
current_task_namein 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- supportconversation_idparameter
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_idparameter - 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_statusevents - Stream
execution_startevents - Stream
execution_completeevents - Stream
activityevents
- Test:
tests/robot/stream_test.go
6.3 Execution Progress Stream ⬜
- GET /v1/robots/:id/executions/:exec_id/stream
- Subscribe to execution updates
- Stream
phaseevents - Stream
task_start/task_completeevents - Stream
messageevents - Stream
deliveryevent - Stream
complete/errorevents
- Test:
tests/robot/execution_stream_test.go
Backend Extensions Required
Architecture: Store layer handles CRUD, API layer handles business logic. This enables reuse across Golang API, JSAPI, and Yao Process.
robot/store/ Extensions (Core CRUD)
| Function | Phase | Risk | Status | Description |
|---|---|---|---|---|
RobotStore.Save() |
1 | 🟢 Low | ✅ | Create/update robot member |
RobotStore.Get() |
1 | 🟢 Low | ✅ | Get robot by member_id |
RobotStore.List() |
1 | 🟢 Low | ✅ | List robots with filters |
RobotStore.Delete() |
1 | 🟢 Low | ✅ | Delete robot member |
RobotStore.UpdateConfig() |
1 | 🟢 Low | ✅ | Update config only |
RobotStore.UpdateStatus() |
1 | 🟢 Low | ✅ | Update status only |
ExecutionStore.ListResults() |
3 | 🟢 Low | ⬜ | Query deliverables from executions |
ExecutionStore.GetResult() |
3 | 🟢 Low | ⬜ | Get single deliverable |
ExecutionStore.ListActivities() |
3 | 🟢 Low | ⬜ | Derive activities from history |
| Conversation store | 5 | 🟡 Medium | ⬜ | Temporary chat history (Deferred) |
robot/types/ Extensions
| Type/Field | Phase | Risk | Status | 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.Nameis NOT needed. Frontendnamemaps to existingRobot.MemberID.
robot/cache/ Extensions
| File | Phase | Risk | Status | Description |
|---|---|---|---|---|
load.go |
1 | 🟢 Low | ✅ | Add bio to memberFields slice |
robot/utils/ Extensions
| File | Phase | Risk | Status | Description |
|---|---|---|---|---|
convert.go |
1 | 🟢 Low | ✅ | Unified type conversion utilities |
convert_test.go |
1 | 🟢 Low | ✅ | Tests for conversion utilities |
robot/api/ Extensions (Thin wrappers calling store)
| Function | Phase | Risk | Status | Description |
|---|---|---|---|---|
CreateRobot() |
1 | 🟢 Low | ✅ | Call store.RobotStore.Save() + cache refresh |
UpdateRobot() |
1 | 🟢 Low | ✅ | Partial update + cache refresh |
RemoveRobot() |
1 | 🟢 Low | ✅ | Call store.RobotStore.Delete() + cache invalidate |
GetRobotResponse() |
1 | 🟢 Low | ✅ | Get robot as API response |
ListResults() |
3 | 🟢 Low | ⬜ | Call store.ExecutionStore.ListResults() |
GetResult() |
3 | 🟢 Low | ⬜ | Call store.ExecutionStore.GetResult() |
ListActivities() |
3 | 🟢 Low | ⬜ | Call store.ExecutionStore.ListActivities() |
RetryExecution() |
2 | 🟢 Low | ⬜ | Re-trigger with same input |
Chat() |
5 | 🟡 Medium | ⬜ | Multi-turn conversation (Deferred) |
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 (Backend ✅, OpenAPI ✅) |
| 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
Phase 1 Detailed Status
| Component | Status | Notes |
|---|---|---|
types.Robot.Bio |
✅ | Field added |
cache/load.go |
✅ | bio in memberFields |
store/robot.go |
✅ | Full CRUD with permission fields |
store/robot_test.go |
✅ | Integration tests |
api/robot.go |
✅ | Create/Update/Remove/GetResponse |
api/types.go |
✅ | Request/Response types, AuthScope |
api/robot_test.go |
✅ | API tests |
utils/convert.go |
✅ | Type conversion utilities |
utils/convert_test.go |
✅ | Unit tests |
openapi/agent/robot/robot.go |
✅ | Route registration with Attach() |
openapi/agent/robot/types.go |
✅ | HTTP request/response types |
openapi/agent/robot/list.go |
✅ | List robots handler with permission filter |
openapi/agent/robot/detail.go |
✅ | CRUD handlers with permission checks |
openapi/agent/robot/permission.go |
✅ | Permission check functions (CanRead/CanWrite) |
openapi/agent/robot/utils.go |
✅ | Helper functions |
openapi/agent/agent.go |
✅ | Robot routes registered |
openapi/tests/agent/robot_test.go |
✅ | Integration tests + Permission tests |
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 ✅
├── permission.go # Permission check functions (CanRead/CanWrite) ✅
├── utils.go # Utilities ✅
├── execution.go # Execution endpoints (Phase 2)
├── trigger.go # Trigger/Intervene SSE (Phase 2)
├── results.go # Results endpoints (Phase 3)
├── activities.go # Activities endpoint (Phase 3)
├── stream.go # Real-time streams (Phase 6 - Deferred)
└── filter.go # Query filtering (optional)
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)
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
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:
- Test endpoints manually
- Update frontend
openapi/robot.tsto use real API - Remove mock data usage
- 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)