revert: remove cross-agent worker direction synchronization
This commit is contained in:
1 parent
7e633b2056
commit
76210b9933
9 files changed
+11
-425
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user