Repository navigation
fix(android): AI Coach fixes for #1074 (crash, Disconnect UI, truncation, real errors, model scan) - #1083
Merged
Conversation
ryanbr
force-pushed
the
android-coach-error-crash-robustness
branch
from
August 5, 2026 08:33
eec53bc to
8c165b1
Compare
…truncation, Disconnect UI)
Five fixes for the AI Coach + custom OpenAI-compatible (DeepSeek) provider report,
all confirmed against the reporter's screenshots:
1. Crash — `error!!` read inside a `semantics {}` contentDescription closure NPE'd
when the accessibility pass ran after a recomposition cleared `error`. Snapshot
into a stable local first.
2. Surface the provider's real error — on a 200 with empty assistant content (a
hand-set model the provider doesn't offer), some servers put the error IN the 200
body. Surface it instead of a blanket "empty reply"; all three provider paths.
3. Custom base-URL normalization — a pasted full chat URL made the model scan hit
.../chat/completions/models and return nothing; strip the chat suffix so /models
and /chat/completions resolve either way.
4. Truncation — max_tokens 900 cut detailed cloud replies mid-sentence (the screenshot
showed it on DeepSeek). Raise to 4096 (a cap, not a target; the Gemini leg already
used 4096). The cut-off note gave Ollama-specific `num_ctx` advice that is wrong for
cloud providers — rewritten accurate and provider-agnostic.
5. Disconnect UI — a long model id in the provider pill squeezed the Disconnect into a
one-char vertical stack (or off-screen). StatePill now ellipsizes (a pill is one
line); the Disconnect keeps its intrinsic single-line width.
Pure helpers unit-tested (AiCoachEmptyReplyTest, AiCoachCustomUrlTest);
compileFullDebugKotlin + i18n audit green. Layout changes not device-verified
(Compose won't render on this box). Android-only; the Swift AICoach twin has the
empty-reply + base-URL gaps as a follow-up.
ryanbr
force-pushed
the
android-coach-error-crash-robustness
branch
from
August 5, 2026 08:50
8c165b1 to
c5a1427
Compare
ryanbr
added a commit
that referenced
this pull request
Aug 5, 2026
Mirrors the Swift side of the Android AI Coach fixes (#1083 for #1074): - Raise the reply cap 900 -> 4096 tokens on OpenAI, Anthropic and the Custom (OpenAI-compatible) provider. 900 truncated detailed coaching replies mid-sentence; Gemini was already 4096. It is a cap, not a target - the system prompt keeps replies short. - Provider-agnostic truncation note (was Ollama-specific num_ctx advice that is wrong for cloud providers hitting the response-length cap). - Surface the provider's real error when a 200 body carries no assistant content: some OpenAI-compatible servers return the error INSIDE the 200 body. New emptyReplyError() + AICoachError.emptyReply case render the same user-facing text as Android emptyReplyMessage, byte-for-byte. Wired into the Custom / OpenAI / Anthropic / Gemini parses. - Trim assistant content before the empty-check and return, matching Android's ?.trim(): a whitespace-only 200 reply is treated as empty (so emptyReplyError fires) rather than returned as blank text. - Normalise the Custom base URL (normalizeCustomBaseURL): strip a trailing /chat/completions or /completions so a pasted full chat URL no longer makes the model scan hit .../chat/completions/models and return nothing. Byte-identical to Android normalizeCustomBaseUrl. Adds AICoachEmptyReplyAndUrlTests mirroring the Android parity tests. App-target Swift (no default CI); compiled via app-build (Strand macOS + NOOPiOS).
The modern-params leg (max_completion_tokens) fronts reasoning models, which count hidden thinking tokens against that budget - so the old 900 starved them into truncated/empty replies even more readily than the standard path. Match the standard leg's 4096 cap. A cap, not a target; short answers are unaffected. Keeps this at parity with the iOS/macOS side, which uses 4096 on both legs.
The emptyReplyMessage KDoc was stranded above normalizeCustomBaseUrl's own doc block, so it documented nothing (Dokka/IDE hover would miss it) and tripped the detached-doc-comment regression gate. Move it down onto emptyReplyMessage. No code change.
ryanbr
added a commit
that referenced
this pull request
Aug 5, 2026
iOS/macOS parity for the Android AI Coach fixes (#1083, tracking #1074): 4096 reply cap on all provider legs, provider-agnostic truncation note, real provider-error surfacing on empty 200s, trim-before-empty-check, and Custom base-URL normalisation. Byte-identical user-facing text to Android. App-build (Strand macOS + NOOPiOS) green.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
iOS/macOS parity for the Android AI Coach fixes (ryanbr#1083, tracking ryanbr#1074): 4096 reply cap on all provider legs, provider-agnostic truncation note, real provider-error surfacing on empty 200s, trim-before-empty-check, and Custom base-URL normalisation. Byte-identical user-facing text to Android. App-build (Strand macOS + NOOPiOS) green.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…runcation, real errors, model scan) (ryanbr#1083) Android AI Coach robustness for ryanbr#1074: crash fix, Disconnect row layout, 4096 reply cap on both legs, provider-agnostic truncation note, real provider-error surfacing on empty 200s, and Custom base-URL normalisation so the model scan resolves. iOS/macOS parity landed in ryanbr#1087.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1074 (AI Coach + custom DeepSeek provider, Android)
After reviewing the reporter's screenshots, this addresses all the reported symptoms:
1. Crash (
NullPointerExceptionin the Coach error line)error!!read inside asemantics {}closure that the accessibility pass runs later; a recomposition can clearerrorfirst, so the deferred!!throws. Snapshot a stable local first.2. Disconnect button broken / invisible (screenshots 2 & 3)
A long model id in the provider pill (
Custom (OpenAI-compatible) · deepseek-v4-pro) consumed the row and squeezed "Disconnect" into a one-letter-per-line vertical stack (or pushed it off-screen).StatePillnow ellipsizes (a pill is single-line); the Disconnect keeps its intrinsic single-line width.3. Reply truncated / "context window" (screenshot 1)
max_tokens = 900cut detailed replies mid-sentence on cloud providers → 4096 (a cap, not a target; the Gemini leg already used 4096). And the cut-off note gave Ollama-specificnum_ctxadvice that's wrong for a cloud provider — rewritten accurate + provider-agnostic.4. Empty response → surface the real error
On a 200 with empty content (a hand-set model the provider doesn't offer — the reporter's model names were Gemini's), the app threw a blanket "empty reply". Now it surfaces the provider's actual error, or points at the hand-set model. All three provider paths.
5. Model scan not working
A pasted full chat URL made the scan derive
…/chat/completions/models.normalizeCustomBaseUrlstrips the chat suffix so/modelsand/chat/completionsresolve either way.Testing
:app:compileFullDebugKotlin— BUILD SUCCESSFUL.AiCoachEmptyReplyTest(3) +AiCoachCustomUrlTest(4) pass.Tools/i18n_audit.py --ci— exit 0.Follow-up
Swift
AICoachtwin (Custom.swift) has the same empty-reply + base-URL gaps — a mirrored change + app-build to follow. Android-only; no analytics/decoder/stored-data/BLE change.