Skip to content

fix: duplicate assistant replies and flickering conversation list - #6

Open
naruto-91 wants to merge 1 commit into
devfrom
hotfix/duplicate_response_etc
Open

fix: duplicate assistant replies and flickering conversation list#6
naruto-91 wants to merge 1 commit into
devfrom
hotfix/duplicate_response_etc

Conversation

@naruto-91

Copy link
Copy Markdown
Collaborator

What's fixed

1. Backend: assistant reply duplicated, then run fails with "Exceeded maximum output retries"

Root cause: Gemini's thinking models draw reasoning tokens from the same
budget as max_tokens. On the post-tool-call turn, the model could burn the
entire 8192-token cap thinking and return neither text nor a tool call.
pydantic-ai treats that as invalid output and force-retries — the model
re-answers the whole turn from scratch (full text + all display-tool calls
again), which the streaming layer forwards verbatim, so the user sees the
reply twice. The retry fails the same way a second time and the run dies with
UnexpectedModelBehavior: Exceeded maximum output retries (1).

Fix (backend/src/agent/builder.py): cap reasoning explicitly, per
provider, on the same branch that already selects the model —

  • Gemini: google_thinking_config.thinking_budget=8192, with max_tokens
    raised to 16384 so real output always has headroom left over.
  • OpenAI (o-series/gpt-5, same failure class, no numeric budget knob):
    openai_reasoning_effort="low".

2. Frontend: conversation list refetched (and visibly flashed) on every load and thread switch

Root cause: ConversationSidebar had two effects both firing on mount —
a [fetchPage] mount effect and a [activeThreadId, fetchPage] effect meant
to refresh the list after switching threads. Effects with no prior render to
diff against always run on mount regardless of deps, so every page load fired
/api/conversations twice, and the second effect's fetchPage(1) also set
loading=true, blanking the whole list behind skeleton rows — visible as
"the chat list refreshes" every time a chat was clicked.

Fix (frontend/app/components/ConversationSidebar.tsx):

  • Skip the thread-switch effect's first run with a didMount ref — no more
    duplicate fetch on initial load.
  • Added a silent fetch mode used by that background refresh so it updates
    data without touching loading/error — list stays on screen, no skeleton
    flash, while it still quietly re-syncs title/message-count after a switch.

Verification

  • backend: pytest — 71 passed, 2 deselected, 2 xfailed (no regressions)
  • backend: agent builds successfully against both provider branches
  • frontend: tsc --noEmit — clean

@ASahu16
ASahu16 changed the base branch from main to dev August 28, 2026 04:09
@ASahu16
ASahu16 self-requested a review August 28, 2026 11:52

@ASahu16 ASahu16 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@naruto-91 I'm not fully convinced this is the right fix here. It feels more like it's addressing the symptom than the underlying cause.

One concern: capping the reasoning budget this way stops the duplicate-reply/retry failure, but it also means the model has noticeably less room to actually think on harder queries. I'd expect that to show up as shallower or lower-quality answers on the more complex cases, even though the crash itself goes away trading one visible bug for a quieter one.

@PrashantShuklaa, @predator094 could you take a look too when you get a chance? Want a second pair of eyes before this goes in.

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