Skip to content

Commit 9b70f28

Browse files
authored
Merge pull request #1429 from trheyi/main
Enhance ListRobots API to Include Runtime Status
2 parents e937636 + 6fa808c commit 9b70f28

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed

openapi/agent/robot/list.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package robot
33
import (
44
"strconv"
55
"strings"
6+
"sync"
67

78
"github.com/gin-gonic/gin"
89
"github.com/yaoapp/kun/log"
@@ -80,11 +81,30 @@ func ListRobots(c *gin.Context) {
8081
return
8182
}
8283

83-
// Convert to HTTP response format
84-
robots := make([]*Response, 0, len(result.Data))
85-
for _, r := range result.Data {
86-
robots = append(robots, newResponseFromRobot(r))
84+
// Convert to HTTP response format with runtime status
85+
robots := make([]*Response, len(result.Data))
86+
var wg sync.WaitGroup
87+
88+
for i, r := range result.Data {
89+
wg.Add(1)
90+
go func(idx int, robot *robottypes.Robot) {
91+
defer wg.Done()
92+
resp := newResponseFromRobot(robot)
93+
94+
// Fetch runtime status for each robot
95+
if status, err := robotapi.GetRobotStatus(ctx, robot.MemberID); err == nil && status != nil {
96+
resp.Running = status.Running
97+
resp.MaxRunning = status.MaxRunning
98+
resp.LastRun = status.LastRun
99+
resp.NextRun = status.NextRun
100+
// Use runtime status instead of stored status
101+
resp.RobotStatus = string(status.Status)
102+
}
103+
104+
robots[idx] = resp
105+
}(i, r)
87106
}
107+
wg.Wait()
88108

89109
resp := &ListResponse{
90110
Data: robots,

openapi/agent/robot/types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ type Response struct {
126126
// Timestamps
127127
CreatedAt *time.Time `json:"created_at,omitempty"`
128128
UpdatedAt *time.Time `json:"updated_at,omitempty"`
129+
130+
// Runtime Status (populated in list view for dashboard)
131+
Running int `json:"running"` // Current running executions count
132+
MaxRunning int `json:"max_running,omitempty"` // Maximum concurrent executions
133+
LastRun *time.Time `json:"last_run,omitempty"` // Last execution time
134+
NextRun *time.Time `json:"next_run,omitempty"` // Next scheduled run time
129135
}
130136

131137
// StatusResponse - runtime status response

openapi/tests/agent/robot_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ func TestListRobots(t *testing.T) {
5252
assert.Contains(t, response, "page")
5353
assert.Contains(t, response, "pagesize")
5454
assert.Contains(t, response, "total")
55+
56+
// Verify runtime status fields are included in robot items
57+
if data, ok := response["data"].([]interface{}); ok && len(data) > 0 {
58+
robot := data[0].(map[string]interface{})
59+
// Runtime status fields should be present (added for dashboard optimization)
60+
assert.Contains(t, robot, "running", "Robot should include running count")
61+
assert.Contains(t, robot, "max_running", "Robot should include max_running")
62+
// last_run and next_run are optional (omitempty)
63+
}
5564
})
5665

5766
t.Run("ListRobotsWithPagination", func(t *testing.T) {
@@ -136,6 +145,50 @@ func TestListRobots(t *testing.T) {
136145
}
137146
})
138147

148+
t.Run("ListRobotsIncludesRuntimeStatus", func(t *testing.T) {
149+
// Verify that list response includes runtime status fields for dashboard optimization
150+
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots", nil)
151+
require.NoError(t, err)
152+
153+
req.Header.Set("Authorization", "Bearer "+tokenInfo.AccessToken)
154+
155+
resp, err := http.DefaultClient.Do(req)
156+
require.NoError(t, err)
157+
defer resp.Body.Close()
158+
159+
assert.Equal(t, http.StatusOK, resp.StatusCode)
160+
161+
var response map[string]interface{}
162+
err = json.NewDecoder(resp.Body).Decode(&response)
163+
require.NoError(t, err)
164+
165+
// Verify we have robots to test
166+
data, ok := response["data"].([]interface{})
167+
require.True(t, ok, "Response should have data array")
168+
169+
if len(data) > 0 {
170+
robot := data[0].(map[string]interface{})
171+
172+
// Runtime status fields (running is always present, defaults to 0)
173+
_, hasRunning := robot["running"]
174+
assert.True(t, hasRunning, "Robot should include 'running' field for dashboard")
175+
176+
// max_running should be present (with omitempty, only if > 0)
177+
// The field is returned by GetRobotStatus, so it should be there
178+
if maxRunning, ok := robot["max_running"]; ok {
179+
assert.GreaterOrEqual(t, maxRunning.(float64), float64(0), "max_running should be >= 0")
180+
}
181+
182+
// robot_status should reflect runtime status
183+
robotStatus, hasStatus := robot["robot_status"]
184+
assert.True(t, hasStatus, "Robot should include 'robot_status' field")
185+
if hasStatus {
186+
validStatuses := []string{"idle", "working", "paused", "error", "maintenance"}
187+
assert.Contains(t, validStatuses, robotStatus.(string), "robot_status should be a valid status")
188+
}
189+
}
190+
})
191+
139192
t.Run("ListRobotsUnauthorized", func(t *testing.T) {
140193
req, err := http.NewRequest("GET", serverURL+baseURL+"/agent/robots", nil)
141194
require.NoError(t, err)

0 commit comments

Comments
 (0)