Changeset 0.37.14 (#226)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-23 16:47:48 +00:00
committed by xcaliber
parent fcb998bff9
commit b7746c3004
164 changed files with 6972 additions and 3527 deletions

View File

@@ -267,46 +267,14 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
SELECT COALESCE(ai_mode, 'auto') FROM channels WHERE id = $1
`), channelID).Scan(&aiMode)
if aiMode == "off" {
c.JSON(http.StatusForbidden, gin.H{"error": "AI responses are disabled for this channel"})
return
}
if aiMode == "mention_only" && extractFirstMention(req.Content) == "" {
if aiMode == "off" || (aiMode == "mention_only" && extractFirstMention(req.Content) == "") {
// Persist the user message before returning
msgID, err := h.persistMessage(channelID, userID, "user", req.Content, "", 0, 0, nil, nil, "", "")
if err != nil {
log.Printf("[mention_only] Failed to persist user message: %v", err)
log.Printf("[ai_skip] Failed to persist user message: %v", err)
}
// Broadcast via WS to ALL user participants (not just sender)
if h.hub != nil && msgID != "" {
payload, _ := json.Marshal(map[string]any{
"id": msgID,
"channel_id": channelID,
"role": "user",
"content": req.Content,
"user_id": userID,
})
evt := events.Event{
Label: "message.created",
Payload: payload,
Ts: time.Now().UnixMilli(),
}
// Send to sender
h.hub.PublishToUser(userID, evt)
// Send to other user participants in the channel
pRows, pErr := database.DB.QueryContext(c.Request.Context(), database.Q(`
SELECT participant_id FROM channel_participants
WHERE channel_id = $1 AND participant_type = 'user' AND participant_id != $2
`), channelID, userID)
if pErr == nil {
defer pRows.Close()
for pRows.Next() {
var pid string
if pRows.Scan(&pid) == nil {
h.hub.PublishToUser(pid, evt)
}
}
}
broadcastUserMessage(c.Request.Context(), h.hub, channelID, msgID, req.Content, userID)
}
c.JSON(http.StatusOK, gin.H{"status": "delivered", "ai_skipped": true, "message_id": msgID})
return
@@ -532,6 +500,11 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
log.Printf("Failed to persist user message: %v", err)
}
// Broadcast user message to all channel participants
if h.hub != nil && msgID != "" {
broadcastUserMessage(c.Request.Context(), h.hub, channelID, msgID, req.Content, userID)
}
// Link files to the persisted message
if msgID != "" && len(req.FileIDs) > 0 {
for _, fID := range req.FileIDs {
@@ -963,7 +936,7 @@ func (h *CompletionHandler) ListTools(c *gin.Context) {
}
}
c.JSON(http.StatusOK, gin.H{"tools": result})
c.JSON(http.StatusOK, gin.H{"data": result})
}
// ── Streaming Completion (SSE) with Tool Loop ──
@@ -985,10 +958,16 @@ func (h *CompletionHandler) streamCompletion(
// Persist assistant response
if result.Content != "" {
if _, err := h.persistMessage(channelID, userID, "assistant", result.Content, model, result.InputTokens, result.OutputTokens, nil, toolActivityJSON(result.ToolActivity), configID, personaID); err != nil {
asstMsgID, err := h.persistMessage(channelID, userID, "assistant", result.Content, model, result.InputTokens, result.OutputTokens, nil, toolActivityJSON(result.ToolActivity), configID, personaID)
if err != nil {
log.Printf("Failed to persist assistant message: %v", err)
}
// Broadcast assistant message to other channel participants
if h.hub != nil && asstMsgID != "" {
broadcastAssistantMessage(c.Request.Context(), h.hub, channelID, asstMsgID, result.Content, model, userID, personaID)
}
// AI-to-AI chaining: if the response @mentions another persona participant,
// trigger a follow-up completion asynchronously via WebSocket delivery.
go func() {