fix: bug-hunt pass — 35 fixes across streaming, usage, providers, models and tooling - #157
Conversation
…ck-overflow crash)
…ache in whole-conversation mode
|
Hi @ltmoerdani 👋 — I know this is a big PR, so a few words up front to make it easy. 1. It's 35 commits because they're deliberately one-fix-each and tiny. No mega-diff hiding refactors — every commit is a single, self-contained bug fix with its own message ( 2. Scope is strictly corrective, not creative. I did not restructure anything. The largest single file change is the tool-schema cycle guard (~30 lines + tests); everything else is a few lines. No renames, no reorgs, no behavior I invented. 3. Every commit passed the pre-commit gate, and the full 4. Honesty about confidence. The description separates verified fixes from the ones that really want a quick live smoke test:
5. A few things I deliberately did NOT touch, so you're not surprised they're absent: the 6. Three "bugs" I found turned out to be false positives — I rejected them and noted why in the PR thread (fragmented tool-call names are intentional + tested; the token-estimate "double count" isn't one; the Qwen vision-proxy thinking path was already guarded). I'd rather say "I checked and it's fine" than churn code for nothing. If any fix feels wrong or too aggressive, I'm happy to drop or rework that single commit — they're all independent, so carving any out is trivial. Happy to walk through any specific one. |
What these fixes prevent in the real world1. Crashes that users would actually hit
2. Requests that fail for no good reason
3. Wrong or silent usage/cost data (the worst kind)
4. Broken tool calling / multi-turn reasoning
5. Annoying / confusing UX
6. Money-display mistakes
— Every one of these is now fixed or explicitly verified-not-a-bug; the list maps 1:1 to the commits in this PR. |
|
Hi @Fahad090NP, Reviewed this the slow way: checked out the branch, ran the full unit suite (324/324 green), typecheck clean, then spot-checked the riskier claims against
Two small things before merge, both doc-level:
One judgment call I want to flag rather than ask you to change: Plan: merge as a merge commit per repo convention (never squash, I want all 35 commits in the history), then live smoke test the streaming paths (5xx retry, Google tool calls, vision placeholder) before the next release. No code changes requested. Thanks for this. The honesty in the checklist and the rejected false-positives writeup made reviewing a 35-commit PR a lot easier than it usually is. |
|
Both review notes are addressed:
The 5xx retry / Google tool-call / vision placeholder live smoke test plan still stands for after merge. Thanks for the thorough review. |
|
Hi @Fahad090NP, Both confirmed on my end. Pulled the branch again, checked the new commit, and the Nothing else from me. The plan stands: merge as a merge commit (never squash, I want all 36 commits in the history), then live smoke test the streaming paths (5xx retry, Google tool calls, vision placeholder) before the next release. Nice work on this one. The one-fix-per-commit structure and the honest checklist made it a genuinely easy PR to review. |
📝 What does this change?
A bug-hunt pass over the whole codebase — 35 small, atomic, one-fix-per-commit changes (32 files, +505/−128). Every fix was verified against the OpenCode gateway source and VS Code source, and the full lint gate (eslint strict + tsc + prettier + markdownlint + shellcheck + all unit tests) is green.
Highlights (confirmed bugs)
Crashes / dangerous
ReferenceError: esc is not defined— added the missing HTML-escape helper.Streaming
Router.Unavailableretry branch was dead (the 5xx body was never read) — now read + classified.Usage / cost
Math.round→ afternoon events landed in the next day — nowfloor(+ regression test).serverUsage/everTrackedstale keys — now cleared.formatUsdrendered$-5.00;escapeHtmlmissed'— fixed.Provider / models
familywas a per-model unique string, breaking VS Code's family selection/grouping — now a real family name.reasoning_effort→ 400) — now validated against the allowed enums; the picker derives from the same allowlist.temperatureand the timeout settings were unclamped — now bounded.pattern/format/default) — preserved (+ tests).ring-2.6-1t, missingminimax-m3in the Go fallback) — cleaned up.Agents / vision / misc
autoEnableAgentsWindowoff never reverted the auto-enabled core settings — now reverts.reasoning_contentpreserved when consecutive assistant messages merge.retry-afterdurations are capped.🧪 How did you test it?
npm run lint— all 7 steps green, incl. the full unit suite.tmp/vscode+tmp/opencodereference sources where behavior depended on VS Code / the gateway.✅ Checklist
npm run compilepassesnpm run lintpassesnpm testpassesnpm run packageproduces a VSIX (not run — code + tests only)