revert: remove cross-agent worker direction synchronization

This commit is contained in:
pphua committed 2026-08-29 22:05:28 +08:00
1 parent 7e633b2056
commit 76210b9933
9 files changed
+11 -425

No files matched your search

-5
View File
@@ -687,7 +687,6 @@ func (e *Engine) interveneWork(ctx context.Context, t *Task, intentID int64, req
}
if !duplicate {
e.publishStoredActivity(t, activity)
t.NotifyWorkerMessage(intentID, activity.ID, message)
}
e.readyDirectedClaim(intentID)
t.NotifyWorker()
@@ -752,10 +751,6 @@ func (e *Engine) recoverWorkerMessages(ctx context.Context, t *Task, allowAdmiss
log.Printf("[worker chat] task %s 恢复意图 #%d 待处理消息失败: %v", t.ID, item.IntentID, recoverErr)
}
case db.IntentInterventionAccepted:
// Reconstruct the Planner-facing event while the Worker hand-off is still
// pending. The durable graph_overview view remains authoritative even if
// this notification was already consumed before a later restart.
t.NotifyWorkerMessage(item.IntentID, item.ActivityID, item.Message)
if item.IntentState == "paused" {
if changed, setErr := t.Store.CompareAndSetIntentState(item.IntentID, "paused", "open"); setErr != nil {
return setErr
@@ -181,11 +181,6 @@ func TestWorkerMessageCancelsBeforeAcceptAndContinuesSameSessionFirst(t *testing
if accepted.err != nil || accepted.result.ActivityID <= pending.ActivityID || accepted.result.Duplicate || accepted.result.State != "open" {
t.Fatalf("accepted Worker message=%+v control=%+v err=%v", accepted.result, pending, accepted.err)
}
triggers := f.task.drainTriggers()
if len(triggers) != 1 || triggers[0].Kind != agent.TriggerWorkerMessage ||
triggers[0].ActivityID != accepted.result.ActivityID || triggers[0].IntentID != f.intentID || triggers[0].Detail != message {
t.Fatalf("accepted Worker message triggers=%+v, want one matching persistent event", triggers)
}
node, err := f.task.Store.GetNode(f.intentID)
if err != nil || node == nil || node.State != "open" {
t.Fatalf("reopened target=%+v err=%v", node, err)
@@ -253,39 +248,12 @@ func TestWorkerMessageCancelsBeforeAcceptAndContinuesSameSessionFirst(t *testing
if _, err := f.engine.InterveneWork(context.Background(), f.task, f.intentID, requestID, "同 request_id 的另一条消息"); !errors.Is(err, errWorkInterventionConflict) {
t.Fatalf("same request_id different message error=%v, want conflict", err)
}
if triggers := f.task.drainTriggers(); len(triggers) != 0 {
t.Fatalf("idempotent retries emitted Planner triggers: %+v", triggers)
}
count, _ = countTranscriptWorkerMessages(t, f.tx, sessionID, requestID)
if count != 1 {
t.Fatalf("engine retries appended %d Worker messages, want 1", count)
}
}
func TestRecoverAcceptedWorkerMessageReconstructsPlannerTrigger(t *testing.T) {
f := newInterventionProtocolFixture(t, 1)
const requestID = "worker-message-recovery-1"
const message = "恢复后优先验证人工指定的权限边界"
if _, err := f.task.Store.ReserveIntentIntervention(f.intentID, requestID, message); err != nil {
t.Fatal(err)
}
if changed, err := f.task.Store.CompareAndSetIntentState(f.intentID, "running", "paused"); err != nil || !changed {
t.Fatalf("pause before recovery acceptance: changed=%v err=%v", changed, err)
}
activity, duplicate, err := f.task.Store.AcceptIntentIntervention(f.intentID, requestID, message)
if err != nil || duplicate {
t.Fatalf("accept before recovery: activity=%+v duplicate=%v err=%v", activity, duplicate, err)
}
if err := f.engine.RecoverWorkerMessages(context.Background(), f.task); err != nil {
t.Fatal(err)
}
triggers := f.task.drainTriggers()
if len(triggers) != 1 || triggers[0].Kind != agent.TriggerWorkerMessage || triggers[0].ActivityID != activity.ID ||
triggers[0].IntentID != f.intentID || triggers[0].Detail != message {
t.Fatalf("recovered Planner triggers=%+v", triggers)
}
}
func TestSendWorkerMessageContinuesAfterRequestContextCancellation(t *testing.T) {
f := newInterventionProtocolFixture(t, 1)
workCtx, cancelWork := context.WithCancelCause(context.Background())
+4 -26
View File
@@ -1639,10 +1639,10 @@ func (t *Task) Notify() {
}
}
// NotifyWorker wakes one idle execution slot without itself scheduling a Planner
// round. Worker-message acceptance separately records a persistent planning event
// and calls NotifyWorkerMessage; keeping execution wake-up independent prevents
// Planner debounce from delaying the directed Worker claim.
// NotifyWorker wakes one idle execution slot without also scheduling a Planner
// round. The channel is separate from notify because human intervention needs
// the reopened intent reclaimed immediately, while graph-change notifications
// are Planner-facing and debounced. A nil channel is tolerated by test fixtures.
func (t *Task) NotifyWorker() {
if t == nil || t.workerWake == nil {
return
@@ -1653,28 +1653,6 @@ func (t *Task) NotifyWorker() {
}
}
// NotifyWorkerMessage immediately schedules a Planner round for an accepted,
// persistent Worker direction. ActivityID identifies the durable kind=user row
// and prevents retries in the same debounce window from duplicating the prompt.
func (t *Task) NotifyWorkerMessage(intentID, activityID int64, message string) {
message = strings.TrimSpace(message)
if intentID <= 0 || activityID <= 0 || message == "" {
return
}
t.trigMu.Lock()
for _, event := range t.pendingTriggers {
if event.Kind == agent.TriggerWorkerMessage && event.ActivityID == activityID {
t.trigMu.Unlock()
return
}
}
t.pendingTriggers = append(t.pendingTriggers, agent.TriggerEvent{
Kind: agent.TriggerWorkerMessage, ActivityID: activityID, IntentID: intentID, Detail: message,
})
t.trigMu.Unlock()
t.Notify()
}
// NotifyDone is Notify plus a hint: a worker just finished intentID and that is
// what triggered this wake-up. The planner reads the accumulated triggers next
// round so it can spell out which intent finished (+ its output). Events pile up