Expose the original acting sender ID in agent events so group-chat
telemetry and audit logs stay aligned with the real Telegram user
instead of only the group-scoped UserID.
v3 pipeline's parallel path (makeExecuteToolRaw) skipped the tool.call
WebSocket event, so web UI and desktop UI silently dropped tool cards
during real-time streaming. Only page refresh (which reloads history)
revealed the tool calls. Both UIs rely on tool.call to create entries
that later tool.result events can update.
Fix: mirror the sequential path's emission in makeExecuteToolRaw.
Bus.Broadcast is RWMutex-guarded, safe to call from parallel goroutines.
Add tests at two layers to prevent regression:
- Pipeline layer (stages_test.go): guards the dispatch contract —
multiple tool calls route through ExecuteToolRaw + ProcessToolResult
rather than ExecuteToolCall. Previously the parallel path had zero
test coverage, which is why this bug escaped.
- Agent layer (loop_pipeline_tool_callbacks_test.go): guards the
emission contract — both sequential and parallel wrappers emit
tool.call with correct payload and routing context. Mutation-verified.