yao/openapi/agent/robot/list.go
Max bb7638f1e5 Implement Autonomous Mode Filtering in Robot API
- Added support for filtering robots by `autonomous_mode` in the ListRobots API.
- Enhanced ListQuery structure to include an optional `AutonomousMode` field.
- Updated listRobotsFromDB function to apply the autonomous mode filter based on the query.
- Created new test cases to validate the filtering functionality for both autonomous and on-demand robots.
- Revised related OpenAPI endpoints and frontend integration to accommodate the new filtering options.
2026-01-22 16:14:59 +08:00

117 lines
3.2 KiB
Go

package robot
import (
"strconv"
"strings"
"github.com/gin-gonic/gin"
"github.com/yaoapp/kun/log"
robotapi "github.com/yaoapp/yao/agent/robot/api"
robottypes "github.com/yaoapp/yao/agent/robot/types"
"github.com/yaoapp/yao/openapi/oauth/authorized"
"github.com/yaoapp/yao/openapi/response"
)
// ListRobots lists robots with pagination and filtering
// GET /v1/agent/robots
func ListRobots(c *gin.Context) {
// Get authorized information
authInfo := authorized.GetInfo(c)
// Parse pagination parameters
page := 1
if pageStr := c.Query("page"); pageStr != "" {
if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
page = p
}
}
pageSize := 20
if pageSizeStr := c.Query("pagesize"); pageSizeStr != "" {
if ps, err := strconv.Atoi(pageSizeStr); err == nil && ps > 0 && ps <= 100 {
pageSize = ps
}
}
// Parse filter parameters
requestedTeamID := strings.TrimSpace(c.Query("team_id"))
status := strings.TrimSpace(c.Query("status"))
keywords := strings.TrimSpace(c.Query("keywords"))
autonomousModeStr := strings.TrimSpace(c.Query("autonomous_mode"))
// Apply permission-based filtering
// This ensures users only see robots they have access to:
// - No constraints: use requested team_id or no filter
// - TeamOnly: force filter to user's team
// - OwnerOnly: filter by user_id (personal resources)
effectiveTeamID := BuildListFilter(c, authInfo, requestedTeamID)
// Build query
query := &robotapi.ListQuery{
TeamID: effectiveTeamID,
Keywords: keywords,
Page: page,
PageSize: pageSize,
}
if status != "" {
query.Status = robottypes.RobotStatus(status)
}
// Parse autonomous_mode filter: "true" or "false" to filter, empty/other to show all
if autonomousModeStr == "true" {
autonomousMode := true
query.AutonomousMode = &autonomousMode
} else if autonomousModeStr == "false" {
autonomousMode := false
query.AutonomousMode = &autonomousMode
}
// Create robot context
ctx := &robottypes.Context{}
// Call API layer
result, err := robotapi.ListRobots(ctx, query)
if err != nil {
log.Error("Failed to list robots: %v", err)
errorResp := &response.ErrorResponse{
Code: response.ErrServerError.Code,
ErrorDescription: "Failed to list robots: " + err.Error(),
}
response.RespondWithError(c, response.StatusInternalServerError, errorResp)
return
}
// Convert to HTTP response format
robots := make([]*Response, 0, len(result.Data))
for _, r := range result.Data {
robots = append(robots, newResponseFromRobot(r))
}
resp := &ListResponse{
Data: robots,
Total: result.Total,
Page: result.Page,
PageSize: result.PageSize,
}
response.RespondWithSuccess(c, response.StatusOK, resp)
}
// newResponseFromRobot converts types.Robot to Response
func newResponseFromRobot(r *robottypes.Robot) *Response {
if r == nil {
return nil
}
return &Response{
Name: r.MemberID, // Frontend mapping: name ← member_id
Description: r.Bio, // Frontend mapping: description ← bio
MemberID: r.MemberID,
TeamID: r.TeamID,
RobotStatus: string(r.Status),
AutonomousMode: r.AutonomousMode,
DisplayName: r.DisplayName,
Bio: r.Bio,
SystemPrompt: r.SystemPrompt,
RobotEmail: r.RobotEmail,
}
}