Changeset 0.32.0 (#206)

This commit is contained in:
2026-03-19 18:50:27 +00:00
parent 6668e546fe
commit b1266b0d7c
283 changed files with 2187 additions and 1055 deletions

View File

@@ -170,9 +170,17 @@ func (h *Hub) IsConnected(userID string) bool {
return false
}
// SendToUser sends an event directly to all WebSocket connections for a user,
// bypassing room filtering. Used for targeted tool.call delivery.
func (h *Hub) SendToUser(userID string, event Event) {
// PublishToUser sends an event to a specific user via the bus.
// v0.32.0: Cross-pod safe — the bus broadcast hook fans out via pg_notify.
// All replicas receive the event; only the one with the user's connection delivers it.
func (h *Hub) PublishToUser(userID string, event Event) {
event.TargetUserID = userID
h.bus.Publish(event)
}
// sendToUserLocal sends an event directly to local WebSocket connections for a user.
// Unexported — callers should use PublishToUser for cross-pod delivery.
func (h *Hub) sendToUserLocal(userID string, event Event) {
data, err := json.Marshal(event)
if err != nil {
return
@@ -226,6 +234,18 @@ func (c *Conn) subscribeToBus() {
return
}
// v0.32.0: Targeted delivery — only deliver to the intended user.
// Targeted events skip room filtering (user-scoped, not room-scoped).
if e.TargetUserID != "" && e.TargetUserID != c.userID {
return
}
// v0.32.0: tool.result travels cross-pod for WaitFor (DirBoth) but
// must not be forwarded to WebSocket clients — they sent it.
if strings.HasPrefix(e.Label, "tool.result.") {
return
}
// Don't echo typing events back to the sender
if e.Label == "chat.typing" || e.ConnID == c.id {
if e.SenderID == c.userID && e.ConnID == c.id {