Changeset 0.9.3 (#53)
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
capspkg "git.gobha.me/xcaliber/chat-switchboard/capabilities"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/database"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/providers"
|
||||
"git.gobha.me/xcaliber/chat-switchboard/tools"
|
||||
)
|
||||
|
||||
// ── Request / Response types ────────────────
|
||||
@@ -443,74 +443,43 @@ func (h *MessageHandler) Regenerate(c *gin.Context) {
|
||||
provReq.Temperature = temperature
|
||||
}
|
||||
|
||||
// ── Stream the response ──
|
||||
|
||||
ch, err := provider.StreamCompletion(c.Request.Context(), providerCfg, provReq)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadGateway, gin.H{"error": "provider error: " + err.Error()})
|
||||
return
|
||||
// Attach tool definitions (same as normal completion)
|
||||
if caps.ToolCalling && tools.HasTools() {
|
||||
provReq.Tools = comp.buildToolDefs()
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "text/event-stream")
|
||||
c.Header("Cache-Control", "no-cache")
|
||||
c.Header("Connection", "keep-alive")
|
||||
c.Header("X-Accel-Buffering", "no")
|
||||
c.Status(http.StatusOK)
|
||||
// ── Stream the response (shared loop handles tools, reasoning, SSE) ──
|
||||
|
||||
var fullContent string
|
||||
flusher, _ := c.Writer.(http.Flusher)
|
||||
result := streamWithToolLoop(c, provider, providerCfg, &provReq, model, userID, channelID)
|
||||
|
||||
for event := range ch {
|
||||
if event.Error != nil {
|
||||
fmt.Fprintf(c.Writer, "data: {\"error\":\"%s\"}\n\n", event.Error.Error())
|
||||
if flusher != nil {
|
||||
flusher.Flush()
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if event.Delta != "" {
|
||||
fullContent += event.Delta
|
||||
fmt.Fprintf(c.Writer, "data: {\"choices\":[{\"delta\":{\"content\":%q},\"finish_reason\":null}],\"model\":%q}\n\n",
|
||||
event.Delta, model)
|
||||
if flusher != nil {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
if event.Done {
|
||||
finishReason := event.FinishReason
|
||||
if finishReason == "" {
|
||||
finishReason = "stop"
|
||||
}
|
||||
fmt.Fprintf(c.Writer, "data: {\"choices\":[{\"delta\":{},\"finish_reason\":%q}],\"model\":%q}\n\n",
|
||||
finishReason, model)
|
||||
io.WriteString(c.Writer, "data: [DONE]\n\n")
|
||||
if flusher != nil {
|
||||
flusher.Flush()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Persist as child or sibling depending on target role
|
||||
if fullContent != "" {
|
||||
// Persist as sibling (regen) with tool activity
|
||||
if result.Content != "" {
|
||||
siblingIdx := nextSiblingIndex(channelID, newParentID)
|
||||
|
||||
// Match persistMessage pattern: nil interface{} → SQL NULL,
|
||||
// non-nil string → valid JSONB. A nil json.RawMessage ([]byte)
|
||||
// is sent by pq as empty bytes, not NULL, causing "invalid input
|
||||
// syntax for type json".
|
||||
var tcVal interface{}
|
||||
if len(result.ToolActivity) > 0 {
|
||||
b, _ := json.Marshal(result.ToolActivity)
|
||||
tcVal = string(b)
|
||||
}
|
||||
|
||||
var newID string
|
||||
err := database.DB.QueryRow(`
|
||||
INSERT INTO messages (channel_id, role, content, model,
|
||||
INSERT INTO messages (channel_id, role, content, model, tool_calls,
|
||||
parent_id, participant_type, participant_id, sibling_index)
|
||||
VALUES ($1, 'assistant', $2, $3, $4, 'model', $5, $6)
|
||||
VALUES ($1, 'assistant', $2, $3, $4, $5, 'model', $6, $7)
|
||||
RETURNING id
|
||||
`, channelID, fullContent, model, newParentID, model, siblingIdx).Scan(&newID)
|
||||
`, channelID, result.Content, model, tcVal, newParentID, model, siblingIdx).Scan(&newID)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to persist regenerated message: %v", err)
|
||||
} else {
|
||||
_ = updateCursor(channelID, userID, newID)
|
||||
|
||||
// Send message metadata in a final SSE event so frontend can update
|
||||
flusher, _ := c.Writer.(http.Flusher)
|
||||
msgJSON, _ := json.Marshal(gin.H{
|
||||
"id": newID,
|
||||
"parent_id": newParentID,
|
||||
|
||||
Reference in New Issue
Block a user