feat(agentic): add status filters

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-31 18:55:26 +00:00
parent f2f29ceb5f
commit 454f7a8e96
2 changed files with 94 additions and 2 deletions

View file

@ -101,7 +101,7 @@ func workspaceStatusValue(result core.Result) (*WorkspaceStatus, bool) {
return workspaceStatus, true
}
// input := agentic.StatusInput{Workspace: "core/go-io/task-42", Limit: 50}
// input := agentic.StatusInput{Workspace: "core/go-io/task-42", Status: "blocked", Limit: 50}
type StatusInput struct {
Workspace string `json:"workspace,omitempty"`
Limit int `json:"limit,omitempty"`
@ -129,7 +129,7 @@ type BlockedInfo struct {
func (s *PrepSubsystem) registerStatusTool(server *mcp.Server) {
mcp.AddTool(server, &mcp.Tool{
Name: "agentic_status",
Description: "List agent workspaces and their status (running, completed, blocked, failed). Shows blocked agents with their questions.",
Description: "List agent workspaces and their status (running, completed, blocked, failed). Supports workspace, status, and limit filters. Shows blocked agents with their questions.",
}, s.status)
}
@ -141,16 +141,30 @@ func (s *PrepSubsystem) status(ctx context.Context, _ *mcp.CallToolRequest, inpu
}
var statusSummary StatusOutput
matched := 0
for _, statusPath := range statusFiles {
workspaceDir := core.PathDir(statusPath)
name := WorkspaceName(workspaceDir)
if !statusInputMatchesWorkspace(input.Workspace, workspaceDir, name) {
continue
}
result := ReadStatusResult(workspaceDir)
workspaceStatus, ok := workspaceStatusValue(result)
if !ok {
if input.Status != "" && input.Status != "failed" {
continue
}
if !statusInputMatchesStatus(input.Status, "failed") {
continue
}
statusSummary.Total++
statusSummary.Failed++
matched++
if input.Limit > 0 && matched >= input.Limit {
break
}
continue
}
@ -172,6 +186,10 @@ func (s *PrepSubsystem) status(ctx context.Context, _ *mcp.CallToolRequest, inpu
}
}
if !statusInputMatchesStatus(input.Status, workspaceStatus.Status) {
continue
}
statusSummary.Total++
switch workspaceStatus.Status {
case "running":
@ -190,7 +208,31 @@ func (s *PrepSubsystem) status(ctx context.Context, _ *mcp.CallToolRequest, inpu
Question: workspaceStatus.Question,
})
}
matched++
if input.Limit > 0 && matched >= input.Limit {
break
}
}
return nil, statusSummary, nil
}
func statusInputMatchesWorkspace(requested, workspaceDir, workspaceName string) bool {
if requested == "" {
return true
}
if requested == workspaceName {
return true
}
if requested == workspaceDir {
return true
}
return false
}
func statusInputMatchesStatus(requested, current string) bool {
if requested == "" {
return true
}
return requested == current
}

View file

@ -104,6 +104,56 @@ func TestStatus_MixedWorkspaces_Good(t *testing.T) {
assert.Equal(t, "agent", out.Blocked[0].Repo)
}
func TestStatus_FilteredWorkspaces_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := core.JoinPath(root, "workspace")
ws1 := core.JoinPath(wsRoot, "task-1")
require.True(t, fs.EnsureDir(ws1).OK)
require.NoError(t, writeStatus(ws1, &WorkspaceStatus{
Status: "completed",
Repo: "go-io",
Agent: "codex",
}))
ws2 := core.JoinPath(wsRoot, "task-2")
require.True(t, fs.EnsureDir(ws2).OK)
require.NoError(t, writeStatus(ws2, &WorkspaceStatus{
Status: "blocked",
Repo: "go-log",
Agent: "claude",
Question: "Which log format?",
}))
ws3 := core.JoinPath(wsRoot, "task-3")
require.True(t, fs.EnsureDir(ws3).OK)
require.NoError(t, writeStatus(ws3, &WorkspaceStatus{
Status: "running",
Repo: "agent",
Agent: "gemini",
}))
s := &PrepSubsystem{
ServiceRuntime: core.NewServiceRuntime(testCore, AgentOptions{}),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, out, err := s.status(context.Background(), nil, StatusInput{
Workspace: "task-2",
Status: "blocked",
Limit: 1,
})
require.NoError(t, err)
assert.Equal(t, 1, out.Total)
assert.Equal(t, 0, out.Failed)
assert.Equal(t, 0, out.Completed)
assert.Len(t, out.Blocked, 1)
assert.Equal(t, "go-log", out.Blocked[0].Repo)
assert.Equal(t, "Which log format?", out.Blocked[0].Question)
}
func TestStatus_DeepLayout_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)