From 7beccb84a2b67e656a2423a1187ed7f68668f82b Mon Sep 17 00:00:00 2001 From: Grail Finder Date: Fri, 11 Jul 2025 14:12:05 +0300 Subject: [PATCH] Enha: llm errors to journal --- llmapi/main.go | 57 ++++++++++++++++++++++++++++++++++++++------------ todos.md | 1 + 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/llmapi/main.go b/llmapi/main.go index a3e5a2d..8d18853 100644 --- a/llmapi/main.go +++ b/llmapi/main.go @@ -222,21 +222,27 @@ func (b *Bot) BotMove() { // call llm llmResp, err := b.CallLLM(prompt) if err != nil { - room.LogJournal = append(room.LogJournal, models.Journal{ - Entry: "send call got error: " + err.Error(), + lj := models.Journal{ + Entry: fmt.Sprintf("bot '%s' exceeded attempts to call llm;", b.BotName), Username: b.BotName, - RoomID: room.ID, - }) + RoomID: b.RoomID, + } + if err := repo.JournalCreate(context.Background(), &lj); err != nil { + b.log.Warn("failed to write to journal", "entry", lj) + } b.log.Error("bot loop", "error", err) return } tempMap, err := b.LLMParser.ParseBytes(llmResp) if err != nil { - room.LogJournal = append(room.LogJournal, models.Journal{ - Entry: "parse resp got error: " + err.Error(), + lj := models.Journal{ + Entry: fmt.Sprintf("bot '%s' parsing resp failed;", b.BotName), Username: b.BotName, - RoomID: room.ID, - }) + RoomID: b.RoomID, + } + if err := repo.JournalCreate(context.Background(), &lj); err != nil { + b.log.Warn("failed to write to journal", "entry", lj) + } b.log.Error("bot loop", "error", err, "resp", string(llmResp)) return } @@ -245,6 +251,22 @@ func (b *Bot) BotMove() { mimeResp := MimeResp{} b.log.Info("mime resp log", "mimeResp", tempMap) mimeResp.Clue = strings.ToLower(tempMap["clue"].(string)) + for _, card := range room.Cards { + if strings.ToLower(card.Word) == mimeResp.Clue { + b.log.Warn("bot-mime clue is one of the words on the board; retrying", "clue", mimeResp.Clue, "bot", b.BotName) + entry := fmt.Sprintf("bot-mime '%s' gave a clue '%s' which is one of the words on the board. retrying.", b.BotName, mimeResp.Clue) + lj := models.Journal{ + Entry: entry, + Username: b.BotName, + RoomID: room.ID, + } + room.LogJournal = append(room.LogJournal, lj) + if err := repo.JournalCreate(context.Background(), &lj); err != nil { + b.log.Warn("failed to write to journal", "entry", lj) + } + return + } + } var ok bool mimeResp.Number, ok = tempMap["number"].(string) if !ok { @@ -596,7 +618,7 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) { req, err := http.NewRequest(method, b.cfg.LLMConfig.URL, payloadReader) if err != nil { if attempt == maxRetries-1 { - return nil, fmt.Errorf("failed to create request: %w", err) + return nil, fmt.Errorf("LLM call failed after %d retries on request creation: %w", maxRetries, err) } b.log.Error("failed to make new request; will retry", "error", err, "url", b.cfg.LLMConfig.URL, "attempt", attempt) time.Sleep(time.Duration(baseDelay) * time.Second * time.Duration(attempt+1)) @@ -608,7 +630,7 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) { resp, err := client.Do(req) if err != nil { if attempt == maxRetries-1 { - return nil, fmt.Errorf("http request failed: %w", err) + return nil, fmt.Errorf("LLM call failed after %d retries on client.Do: %w", maxRetries, err) } b.log.Error("http request failed; will retry", "error", err, "url", b.cfg.LLMConfig.URL, "attempt", attempt) delay := time.Duration(baseDelay*(attempt+1)) * time.Second @@ -619,7 +641,7 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) { resp.Body.Close() if err != nil { if attempt == maxRetries-1 { - return nil, fmt.Errorf("failed to read response body: %w", err) + return nil, fmt.Errorf("LLM call failed after %d retries on reading body: %w", maxRetries, err) } b.log.Error("failed to read response body; will retry", "error", err, "url", b.cfg.LLMConfig.URL, "attempt", attempt) delay := time.Duration(baseDelay*(attempt+1)) * time.Second @@ -629,7 +651,7 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) { // Check status code if resp.StatusCode >= 400 && resp.StatusCode < 600 { if attempt == maxRetries-1 { - return nil, fmt.Errorf("after %d retries, still got status %d", maxRetries, resp.StatusCode) + return nil, fmt.Errorf("LLM call failed after %d retries, got status %d", maxRetries, resp.StatusCode) } b.log.Warn("retriable status code; will retry", "code", resp.StatusCode, "attempt", attempt) delay := time.Duration((baseDelay * (1 << attempt))) * time.Second @@ -644,7 +666,16 @@ func (b *Bot) CallLLM(prompt string) ([]byte, error) { b.log.Debug("llm resp", "body", string(body), "url", b.cfg.LLMConfig.URL, "attempt", attempt) return body, nil } + entry := fmt.Sprintf("bot '%s' exceeded attempts to call llm;", b.BotName) + lj := models.Journal{ + Entry: entry, + Username: b.BotName, + RoomID: b.RoomID, + } + if err := repo.JournalCreate(context.Background(), &lj); err != nil { + b.log.Warn("failed to write to journal", "entry", lj) + } + // notify room // This line should not be reached because each error path returns in the loop. return nil, errors.New("unknown error in retry loop") } - diff --git a/todos.md b/todos.md index ab591ac..92987da 100644 --- a/todos.md +++ b/todos.md @@ -34,6 +34,7 @@ - at game creation list languages and support them at backend; + - sql ping goroutine with reconnect on fail; + - player stats: played games, lost, won, rating elo, opened opposite words, opened white words, opened black words. +- at the end of the game, all colors should be revealed; #### sse points - clue sse update;