From 497849f7464e94cb9bb130e9339a535f805be8da Mon Sep 17 00:00:00 2001 From: viettranx Date: Sat, 18 Apr 2026 14:53:42 +0700 Subject: [PATCH] fix(teams): propagate local_key in team task completion/fail broadcasts (#877) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forum topic routing (Telegram supergroup threads) relies on local_key carried through team task events to pick the correct thread for notifications. Four broadcast sites dropped local_key by relying on WithContextInfo(ctx) alone — but the member agent's isolated context does not carry the originating local_key. Read task.Metadata[TaskMetaLocalKey] explicitly and pass via WithLocalKey() to match the already-correct pattern in team_tool_dispatch.go and team_tasks_blocker.go. Covered sites: - team_tasks_lifecycle.executeComplete → EventTeamTaskCompleted - gateway_consumer_post_turn agent-error → EventTeamTaskFailed - gateway_consumer_post_turn loop-kill → EventTeamTaskFailed - gateway_consumer_post_turn auto-complete → EventTeamTaskCompleted --- cmd/gateway_consumer_post_turn.go | 16 +++++++++++++--- internal/tools/team_tasks_lifecycle.go | 5 +++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cmd/gateway_consumer_post_turn.go b/cmd/gateway_consumer_post_turn.go index 8239e9c2..faada3ce 100644 --- a/cmd/gateway_consumer_post_turn.go +++ b/cmd/gateway_consumer_post_turn.go @@ -98,6 +98,7 @@ func resolveTeamTaskOutcome( taskChannel := meta.Channel taskChatID := meta.ChatID taskPeerKind := meta.PeerKind + var taskLocalKey string // Enrich with live task data if available. if currentTask != nil { @@ -113,9 +114,15 @@ func resolveTeamTaskOutcome( if currentTask.ChatID != "" { taskChatID = currentTask.ChatID } - if taskPeerKind == "" && currentTask.Metadata != nil { - if pk, ok := currentTask.Metadata[tools.TaskMetaPeerKind].(string); ok && pk != "" { - taskPeerKind = pk + if currentTask.Metadata != nil { + if taskPeerKind == "" { + if pk, ok := currentTask.Metadata[tools.TaskMetaPeerKind].(string); ok && pk != "" { + taskPeerKind = pk + } + } + // local_key is required for forum topic routing (e.g. Telegram supergroup threads). + if lk, ok := currentTask.Metadata[tools.TaskMetaLocalKey].(string); ok { + taskLocalKey = lk } } } @@ -137,6 +144,7 @@ func resolveTeamTaskOutcome( tools.WithChannel(taskChannel), tools.WithChatID(taskChatID), tools.WithPeerKind(taskPeerKind), + tools.WithLocalKey(taskLocalKey), tools.WithTimestamp(now), )) } @@ -171,6 +179,7 @@ func resolveTeamTaskOutcome( tools.WithChannel(taskChannel), tools.WithChatID(taskChatID), tools.WithPeerKind(taskPeerKind), + tools.WithLocalKey(taskLocalKey), tools.WithTimestamp(now), )) } @@ -205,6 +214,7 @@ func resolveTeamTaskOutcome( tools.WithChannel(taskChannel), tools.WithChatID(taskChatID), tools.WithPeerKind(taskPeerKind), + tools.WithLocalKey(taskLocalKey), tools.WithTimestamp(now), )) } diff --git a/internal/tools/team_tasks_lifecycle.go b/internal/tools/team_tasks_lifecycle.go index b271c1a1..1adb1cc4 100644 --- a/internal/tools/team_tasks_lifecycle.go +++ b/internal/tools/team_tasks_lifecycle.go @@ -88,9 +88,13 @@ func (t *TeamTasksTool) executeComplete(ctx context.Context, args map[string]any completedTask, _ := t.manager.Store().GetTask(ctx, taskID) var taskNumber int var taskSubject string + var taskLocalKey string if completedTask != nil { taskNumber = completedTask.TaskNumber taskSubject = completedTask.Subject + if lk, ok := completedTask.Metadata[TaskMetaLocalKey].(string); ok { + taskLocalKey = lk + } } t.manager.BroadcastTeamEvent(ctx, protocol.EventTeamTaskCompleted, BuildTaskEventPayload( team.ID.String(), taskID.String(), @@ -99,6 +103,7 @@ func (t *TeamTasksTool) executeComplete(ctx context.Context, args map[string]any WithTaskInfo(taskNumber, taskSubject), WithOwner(ownerKey, t.manager.AgentDisplayName(ctx, ownerKey)), WithContextInfo(ctx), + WithLocalKey(taskLocalKey), )) // Dependent tasks are dispatched by the consumer after this agent's turn ends