- Renamed ListRobots function to ListAllRobots for clarity and consistency across the codebase. - Updated related API endpoints and tests to reflect the new function name. - Improved caching logic to ensure both autonomous and non-autonomous robots are loaded correctly. - Enhanced filtering and pagination capabilities within the ListAllRobots function. - Added new test cases to validate the updated functionality and ensure robust performance.
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
package robot
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
|
|
"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"
|
|
)
|
|
|
|
// ListAllRobots lists robots with pagination and filtering
|
|
// GET /v1/agent/robots
|
|
func ListAllRobots(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.ListAllRobots(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 with runtime status
|
|
robots := make([]*Response, len(result.Data))
|
|
var wg sync.WaitGroup
|
|
|
|
for i, r := range result.Data {
|
|
wg.Add(1)
|
|
go func(idx int, robot *robottypes.Robot) {
|
|
defer wg.Done()
|
|
resp := newResponseFromRobot(robot)
|
|
|
|
// Fetch runtime status for each robot
|
|
if status, err := robotapi.GetRobotStatus(ctx, robot.MemberID); err == nil && status != nil {
|
|
resp.Running = status.Running
|
|
resp.MaxRunning = status.MaxRunning
|
|
resp.LastRun = status.LastRun
|
|
resp.NextRun = status.NextRun
|
|
// Use runtime status instead of stored status
|
|
resp.RobotStatus = string(status.Status)
|
|
}
|
|
|
|
robots[idx] = resp
|
|
}(i, r)
|
|
}
|
|
wg.Wait()
|
|
|
|
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,
|
|
}
|
|
}
|