Support custom AI gateway auth#766
Conversation
6e506c2 to
c07d499
Compare
ryanbr
left a comment
There was a problem hiding this comment.
Nice, clean cross-platform feature — thanks. The code is solid; I verified it fairly thoroughly and there's just one merge-order fix needed before this can land.
Code review — looks good
- Auth-header parity (Swift ↔ Kotlin): the new
CustomAIAuthHeader/CustomAiAuthHeaderenum (Bearer / x-api-key, default Bearer) matches on both platforms.applyCustomAuthHeaderis applied to both the chat POST and the model-list GET, only for the Custom provider (no leakage into the OpenAI/Anthropic/Gemini paths), and it's keyless-guarded so local servers still get no auth header. Good. - Security: key handling is unchanged and correct — still Keychain / encrypted store, still owner-gated so one provider's key never hits another's endpoint, and only the user-selected header carries it. The persisted values differ per platform (
"bearer"vs"BEARER"), which is fine since this setting isn't part of the.noopbakcontract. catalog[].modelsparsing: parity — both add a deduped catalog path alongside the existingdata[].idpath.max_completion_tokensretry: the Android side now mirrors Swift's existing retry-on-400 (Custom.swift), which is the right direction (Android catching up). Functionally equivalent; the heuristic wording differs slightly but that's harmless.- Tests on both sides cover the catalog parsing.
Blocking: pt-PT Android coverage (branch-timing)
The green i18n check on this PR is stale — it ran before #769 made pt-PT a focus locale. Merging this onto current main and running the audit fails with pt-PT: 2 gap(s): the two new Android strings were added to values/de/es/fr but not values-pt-rPT (which didn't exist when this branched). The Apple .xcstrings already include pt-PT for the equivalents, so the Portuguese text exists — it just needs mirroring into Android.
Please add these two lines to android/app/src/main/res/values-pt-rPT/strings.xml:
<string name="l10n_coach_screen_key_header_3f2a9b10">Cabeçalho da chave</string>
<string name="l10n_coach_screen_use_bearer_for_most_local_servers_4429ab64">Usa Bearer para a maioria dos servidores locais; usa x-api-key para gateways que exigem a chave nesse cabeçalho.</string>(Text lifted from this PR's own .xcstrings pt-PT entries; no apostrophes, so no escaping needed.) After that, python3 Tools/i18n_audit.py --full reports pt-PT missing=0 and the gate is clean.
Note
These are app-target changes with no default CI coverage, so the local Strand build + compileFullDebugKotlin you ran are the only compile validation — worth keeping in mind for the reviewer merging.
Summary
/modelsresponses and add Android fallback tomax_completion_tokensCloses #765
Verification
xcodegen generate && xcodebuild -project Strand.xcodeproj -scheme Strand -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO buildxcodegen generate && xcodebuild -project Strand.xcodeproj -scheme Strand -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO -only-testing:StrandTests/AIProviderModelListTests testJAVA_HOME=/opt/homebrew/opt/openjdk@21 ANDROID_HOME=$HOME/Library/Android/sdk ./gradlew --dependency-verification lenient compileFullDebugKotlinDeviceRegistryDaoimplementations do not implementsetModel; app Kotlin compile passes.