diff --git a/internal/agent/loop_pipeline_callbacks.go b/internal/agent/loop_pipeline_callbacks.go index e2789528..017ec498 100644 --- a/internal/agent/loop_pipeline_callbacks.go +++ b/internal/agent/loop_pipeline_callbacks.go @@ -28,6 +28,7 @@ func (l *Loop) pipelineCallbacks(req *RunRequest, bridgeRS *runState) pipelineCa event.TeamID = req.TeamID event.TeamTaskID = req.TeamTaskID event.ParentAgentID = req.ParentAgentID + event.SenderID = req.SenderID event.UserID = req.UserID event.Channel = req.Channel event.ChatID = req.ChatID diff --git a/internal/agent/loop_pipeline_tool_callbacks.go b/internal/agent/loop_pipeline_tool_callbacks.go index f0f85668..51d49638 100644 --- a/internal/agent/loop_pipeline_tool_callbacks.go +++ b/internal/agent/loop_pipeline_tool_callbacks.go @@ -222,6 +222,7 @@ func makeToolEmitRun(l *Loop, req *RunRequest) func(AgentEvent) { return func(event AgentEvent) { event.RunKind = req.RunKind event.SessionKey = req.SessionKey + event.SenderID = req.SenderID event.UserID = req.UserID event.Channel = req.Channel l.emit(event) diff --git a/internal/agent/loop_pipeline_tool_callbacks_test.go b/internal/agent/loop_pipeline_tool_callbacks_test.go index 866806c5..e1df4dd9 100644 --- a/internal/agent/loop_pipeline_tool_callbacks_test.go +++ b/internal/agent/loop_pipeline_tool_callbacks_test.go @@ -71,6 +71,7 @@ func TestMakeExecuteToolCall_EmitsToolCallEvent(t *testing.T) { RunID: "run-1", SessionKey: "sess-A", UserID: "u-1", + SenderID: "sender-1", Channel: "ws", RunKind: "", } @@ -102,6 +103,7 @@ func TestMakeExecuteToolRaw_EmitsToolCallEvent(t *testing.T) { RunID: "run-2", SessionKey: "sess-B", UserID: "u-2", + SenderID: "sender-2", Channel: "ws", RunKind: "", } @@ -133,7 +135,7 @@ func TestMakeExecuteToolRaw_ConcurrentCallsEmitAllEvents(t *testing.T) { col := &eventCollector{} l := newTestLoopForToolCallbacks(col.onEvent) - req := &RunRequest{RunID: "run-3", SessionKey: "sess-C", UserID: "u-3", Channel: "ws"} + req := &RunRequest{RunID: "run-3", SessionKey: "sess-C", UserID: "u-3", SenderID: "sender-3", Channel: "ws"} exec := l.makeExecuteToolRaw(req) const n = 5 @@ -175,6 +177,9 @@ func assertToolCallPayload(t *testing.T, ev AgentEvent, tc providers.ToolCall, r if ev.UserID != req.UserID { t.Errorf("UserID: got %q, want %q", ev.UserID, req.UserID) } + if ev.SenderID != req.SenderID { + t.Errorf("SenderID: got %q, want %q", ev.SenderID, req.SenderID) + } payload, ok := ev.Payload.(map[string]any) if !ok { t.Fatalf("Payload is not map[string]any: %T", ev.Payload) diff --git a/internal/agent/loop_run.go b/internal/agent/loop_run.go index 82be8488..6231a6dd 100644 --- a/internal/agent/loop_run.go +++ b/internal/agent/loop_run.go @@ -26,6 +26,7 @@ func (l *Loop) Run(ctx context.Context, req RunRequest) (*RunResult, error) { event.TeamID = req.TeamID event.TeamTaskID = req.TeamTaskID event.ParentAgentID = req.ParentAgentID + event.SenderID = req.SenderID event.UserID = req.UserID event.Channel = req.Channel event.ChatID = req.ChatID diff --git a/internal/agent/loop_types.go b/internal/agent/loop_types.go index 8dd106e8..a9e72e07 100644 --- a/internal/agent/loop_types.go +++ b/internal/agent/loop_types.go @@ -277,6 +277,7 @@ type AgentEvent struct { ParentAgentID string `json:"parentAgentId,omitempty"` // Routing context (helps WS clients filter by user/channel/session) + SenderID string `json:"senderId,omitempty"` // original acting user; differs from UserID in group chats UserID string `json:"userId,omitempty"` Channel string `json:"channel,omitempty"` ChatID string `json:"chatId,omitempty"`