Skip to content

Fix server deletion, Ollama analysis, and stale/missing AI analysis state - #56

Open
nilsanmy wants to merge 3 commits into
itz4blitz:masterfrom
nilsanmy:fix-delete-servers
Open

Fix server deletion, Ollama analysis, and stale/missing AI analysis state#56
nilsanmy wants to merge 3 commits into
itz4blitz:masterfrom
nilsanmy:fix-delete-servers

Conversation

@nilsanmy

@nilsanmy nilsanmy commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Three independent bugs found while running Logarr against a local
Ollama instance for AI-powered issue analysis:

  1. Deleting a server silently failed but showed a success toast
  2. Local AI providers (Ollama, LM Studio) couldn't run analysis at all
  3. AI analysis results leaked across issues and weren't restored from
    the database when reopening an issue

Changes

1. Server deletion silently fails (apps/frontend/src/lib/api.ts)

deleteServer() called fetch() directly instead of going through the
shared request() helper, so it never attached the Authorization
header. The backend correctly rejected the request with 401, but the
response status was never checked, so the UI showed "server deleted"
and removed the row from view even though nothing was deleted from the
database.

Fix: route deleteServer() through request() like every other
ApiClient method, restoring the auth header and response validation.

2. AI analysis fails for providers that don't require an API key (apps/backend/src/modules/settings/ai-provider.service.ts)

generateAnalysis() and generateAnalysisWithSystemPrompt() both threw
AI provider has no API key configured whenever the stored apiKey
was empty — even for providers like Ollama and LM Studio that are
intentionally configured with an empty key since they don't need one.
This made AI analysis unusable for any local/self-hosted provider.

Fix: extracted a shared resolveApiKeyOrThrow() helper that only
throws when providerConfig.requiresApiKey is true, used by both
methods so the check can't drift out of sync again (the previous
duplicated logic was fixed in one method but missed in the other).
Also fails closed with a clear error if setting.provider doesn't
match a known provider, instead of silently treating it as key-optional.

3. Ollama analysis output frequently fails to parse

Even with 2 fixed, structured analysis from Ollama often failed with
"The AI analysis could not be parsed as structured data" — the app
only asked for JSON via the system prompt, with no structural
guarantee the model would comply. Weaker/local models often prepended
text, used unclosed markdown fences, or produced near-valid JSON.

Fix: added a jsonMode option to AiGenerationOptions and pass
Ollama's native format: "json" request field when set (enabled for
generateAnalysisWithSystemPrompt(), since that's the method whose
callers always expect structured JSON back). This constrains Ollama's
token sampling to valid JSON rather than relying on instruction
following alone.

4. Stale/missing AI analysis in the issue detail modal (apps/frontend/src/app/(dashboard)/issues/page.tsx, apps/frontend/src/hooks/use-api.ts)

Two related bugs in IssueDetailModal:

  • Stale state across issues: the modal is a single component instance
    reused across different issues (only the issueId prop changes), so
    local state (analysisResult, conversationHistory, etc.) persisted
    from whichever issue was last viewed, making one issue's analysis
    appear on every subsequently opened issue.
  • Existing analysis never loaded: analysisResult was only ever
    populated by generating a new analysis in the current session.
    Opening an issue that already had a stored analysis (visible on the
    Overview tab via issue.aiAnalysis) showed an empty Full Analysis
    tab until you regenerated it — even though the backend already had a
    working endpoint for this (GET /issues/:id/analyze/conversation).

Fix:

  • Added key={detailIssueId} to force a full remount on issue change,
    resetting all local state at once.
  • Added a useLatestAnalysisConversation() query hook and a useEffect
    that restores analysisResult/conversationHistory from the stored
    analysisConversations record when one exists and nothing's been
    generated yet in the current session.

Known limitation

Restored analyses show 0 for the context summary counts
(occurrences/users/sessions included) since these aren't persisted on
the analysisConversations record — only available for a freshly
generated analysis in the current session. A follow-up could persist
contextSnapshot counts to fix this fully.

root added 3 commits August 27, 2026 09:32
…eader

deleteServer() called fetch() directly, bypassing the shared request()
helper, so it never attached the Authorization header. The backend
correctly rejected it with 401, but the response was never checked,
so the UI showed a false success and left the server undeleted.
generateAnalysis() and generateAnalysisWithSystemPrompt() threw 'AI
provider has no API key configured' for any empty apiKey, even for
providers like Ollama/LM Studio that are intentionally configured
without one. Extracted a shared resolveApiKeyOrThrow() helper that
checks providerConfig.requiresApiKey, used by both methods.

Also pass Ollama's native format:"json" request field (via a new
jsonMode option) when structured output is expected, since relying on
prompt text alone let weaker/local models return unparseable output.

Includes regression tests for the Ollama empty-key case, unrecognized
providers, and the format:"json" request body.
IssueDetailModal reused local state (analysisResult, conversationHistory,
etc.) across different issues since only props changed, not the
component instance - causing one issue's AI analysis to appear on
every other issue. Added key={detailIssueId} to force remount.

Also, analysisResult was never populated from the DB when opening an
issue with a pre-existing analysis, so Full Analysis appeared empty
until regenerated. Added useLatestAnalysisConversation() to load and
restore it from the existing analysisConversations record.
@codecov-commenter

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

@nilsanmy
nilsanmy marked this pull request as ready for review August 27, 2026 10:19
@nilsanmy
nilsanmy marked this pull request as draft August 27, 2026 10:29
@nilsanmy
nilsanmy marked this pull request as ready for review August 27, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants