hotfix(paliadin): ship user_id on /chat/turn (aichat tenant-DB requirement)
m reported "ai chat seems not to be wired anymore" + the frontend
showed "Verbindung verloren. Antwort wird nachgereicht…".
Root cause: aichat on mRiver added a tenant-DB layer that demands
`user_id` on every /chat/turn request:
{"error":{"code":"bad_request",
"message":"user_id is required when a tenant DB is
configured","retryable":false}}
aichat itself is healthy (/chat/health 200, paliadin session ok:true,
last successful turn was ~2.6h ago). The paliad side built and shipped
an aichatTurnRequest without user_id, so every turn since the tenant-DB
flip 400s; paliad's SSE relay receives no upstream data and closes
empty, producing the user-visible "Verbindung verloren".
Fix: add UserID to aichatTurnRequest (json: user_id, mandatory now),
populate from req.UserID.String() at the call site. The userID was
already in scope (used for JWT mint + username lookup); the struct just
wasn't shipping it.
Regression test in TestRunTurn_HappyPath_ViaCallHTTP asserts
captured.UserID == request UUID so a future struct edit that drops the
field fails CI instead of production.
This commit is contained in:
@@ -217,6 +217,7 @@ func (s *AichatPaliadinService) RunTurn(ctx context.Context, req TurnRequest) (*
|
||||
body := aichatTurnRequest{
|
||||
Persona: s.cfg.Persona,
|
||||
Username: username,
|
||||
UserID: req.UserID.String(),
|
||||
SessionID: req.SessionID,
|
||||
Message: sanitiseForTmux(req.UserMessage),
|
||||
JWT: jwt,
|
||||
@@ -611,8 +612,13 @@ func (s *AichatPaliadinService) clearPrimed(session string) {
|
||||
// =============================================================================
|
||||
|
||||
type aichatTurnRequest struct {
|
||||
Persona string `json:"persona"`
|
||||
Username string `json:"username"`
|
||||
Persona string `json:"persona"`
|
||||
Username string `json:"username"`
|
||||
// UserID is the paliad user UUID, required by aichat now that a
|
||||
// tenant DB is configured ("user_id is required when a tenant DB
|
||||
// is configured"). Without it /chat/turn 400s and the SSE relay
|
||||
// closes empty → "Verbindung verloren" on the frontend.
|
||||
UserID string `json:"user_id"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Message string `json:"message"`
|
||||
JWT string `json:"jwt,omitempty"`
|
||||
|
||||
@@ -501,6 +501,7 @@ func TestRunTurn_HappyPath_ViaCallHTTP(t *testing.T) {
|
||||
body := aichatTurnRequest{
|
||||
Persona: s.cfg.Persona,
|
||||
Username: s.usernameFor(context.Background(), uid),
|
||||
UserID: uid.String(),
|
||||
Message: "Hello",
|
||||
JWT: jwtTok,
|
||||
Meta: buildAichatMeta(TurnRequest{PageOrigin: "/dashboard"}),
|
||||
@@ -516,6 +517,12 @@ func TestRunTurn_HappyPath_ViaCallHTTP(t *testing.T) {
|
||||
if captured.Username != "user-aaaaaaaa" {
|
||||
t.Errorf("username = %q; want user-aaaaaaaa (nil DB fallback)", captured.Username)
|
||||
}
|
||||
// Regression for the 2026-05-21 outage: aichat now requires user_id
|
||||
// when a tenant DB is configured; missing → 400 → SSE drop on the
|
||||
// frontend ("Verbindung verloren"). The struct must carry it.
|
||||
if captured.UserID != uid.String() {
|
||||
t.Errorf("user_id = %q; want %q", captured.UserID, uid.String())
|
||||
}
|
||||
if captured.Message != "Hello" {
|
||||
t.Errorf("message = %q; want Hello", captured.Message)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user