Skip to content

Commit 1009edc

Browse files
authored
Merge pull request #346 from Cai-Tang-www/feat(subagent)
feat(subagent): 完成 #278 子代理取消/重试/恢复与标准事件流
2 parents e009864 + a80164d commit 1009edc

9 files changed

Lines changed: 903 additions & 18 deletions

File tree

internal/runtime/events_subagent.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const (
2424
EventSubAgentStarted EventType = "subagent_started"
2525
// EventSubAgentProgress 在子代理执行每一步后触发。
2626
EventSubAgentProgress EventType = "subagent_progress"
27+
// EventSubAgentRetried 在子代理任务进入重试后触发。
28+
EventSubAgentRetried EventType = "subagent_retried"
2729
// EventSubAgentCompleted 在子代理成功结束后触发。
2830
EventSubAgentCompleted EventType = "subagent_completed"
2931
// EventSubAgentFailed 在子代理失败结束后触发。

internal/runtime/subagent_run.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,22 @@ func (s *Service) RunSubAgentTask(ctx context.Context, input SubAgentTaskInput)
7272
emitSubAgentProgress(s, input, stepResult, stepErr)
7373

7474
if stepErr != nil {
75-
if errors.Is(stepErr, context.Canceled) || errors.Is(stepErr, context.DeadlineExceeded) {
75+
if errors.Is(stepErr, context.DeadlineExceeded) {
76+
_ = worker.Stop(subagent.StopReasonTimeout)
77+
result, resultErr := worker.Result()
78+
if resultErr != nil {
79+
result = subagent.Result{
80+
Role: input.Role,
81+
TaskID: input.Task.ID,
82+
State: subagent.StateFailed,
83+
StopReason: subagent.StopReasonTimeout,
84+
Error: errorText(stepErr),
85+
}
86+
}
87+
emitSubAgentTerminal(s, ctx, input, result)
88+
return result, stepErr
89+
}
90+
if errors.Is(stepErr, context.Canceled) {
7691
_ = worker.Stop(subagent.StopReasonCanceled)
7792
result, resultErr := worker.Result()
7893
if resultErr != nil {

internal/runtime/subagent_run_test.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"strings"
77
"testing"
8-
"time"
98

109
"neo-code/internal/runtime/controlplane"
1110
"neo-code/internal/subagent"
@@ -182,6 +181,50 @@ func TestServiceRunSubAgentTaskFailureFlows(t *testing.T) {
182181
})
183182
})
184183

184+
t.Run("context deadline should emit failed timeout", func(t *testing.T) {
185+
t.Parallel()
186+
187+
service := NewWithFactory(nil, nil, nil, nil, nil)
188+
service.SetSubAgentFactory(stubSubAgentFactory{
189+
create: func(role subagent.Role) (subagent.WorkerRuntime, error) {
190+
return &stubSubAgentWorker{
191+
current: subagent.StateRunning,
192+
stepErr: context.DeadlineExceeded,
193+
resultErr: errors.New("no result"),
194+
result: subagent.Result{
195+
Role: role,
196+
TaskID: "task-timeout",
197+
},
198+
}, nil
199+
},
200+
})
201+
202+
result, err := service.RunSubAgentTask(context.Background(), SubAgentTaskInput{
203+
RunID: "sub-run-timeout-emit",
204+
Role: subagent.RoleReviewer,
205+
Task: subagent.Task{
206+
ID: "task-timeout",
207+
Goal: "review",
208+
},
209+
})
210+
if err == nil || !errors.Is(err, context.DeadlineExceeded) {
211+
t.Fatalf("error = %v, want context deadline exceeded", err)
212+
}
213+
if result.State != subagent.StateFailed {
214+
t.Fatalf("result state = %q, want %q", result.State, subagent.StateFailed)
215+
}
216+
if result.StopReason != subagent.StopReasonTimeout {
217+
t.Fatalf("stop reason = %q, want %q", result.StopReason, subagent.StopReasonTimeout)
218+
}
219+
220+
events := collectRuntimeEvents(service.Events())
221+
assertEventSequence(t, events, []EventType{
222+
EventSubAgentStarted,
223+
EventSubAgentProgress,
224+
EventSubAgentFailed,
225+
})
226+
})
227+
185228
t.Run("worker start failed by disallowed capability", func(t *testing.T) {
186229
t.Parallel()
187230

@@ -340,9 +383,8 @@ func TestServiceRunSubAgentTaskInputValidation(t *testing.T) {
340383
t.Fatalf("expected invalid role error")
341384
}
342385

343-
ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
344-
defer cancel()
345-
time.Sleep(2 * time.Millisecond)
386+
ctx, cancel := context.WithCancel(context.Background())
387+
cancel()
346388
if _, err := service.RunSubAgentTask(ctx, SubAgentTaskInput{
347389
RunID: "sub-run-timeout",
348390
Role: subagent.RoleCoder,

0 commit comments

Comments
 (0)