Skip to content

Support custom AI gateway auth#766

Open
tigercraft4 wants to merge 1 commit into
ryanbr:mainfrom
tigercraft4:feature/custom-ai-gateway-options
Open

Support custom AI gateway auth#766
tigercraft4 wants to merge 1 commit into
ryanbr:mainfrom
tigercraft4:feature/custom-ai-gateway-options

Conversation

@tigercraft4

Copy link
Copy Markdown

Summary

  • add a Custom AI Coach auth-header selector for Bearer vs x-api-key on Apple and Android
  • use the selected header for Custom chat and model-list requests while keeping Bearer as the default
  • parse catalog-shaped custom /models responses and add Android fallback to max_completion_tokens

Closes #765

Verification

  • xcodegen generate && xcodebuild -project Strand.xcodeproj -scheme Strand -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO build
  • xcodegen generate && xcodebuild -project Strand.xcodeproj -scheme Strand -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO -only-testing:StrandTests/AIProviderModelListTests test
  • JAVA_HOME=/opt/homebrew/opt/openjdk@21 ANDROID_HOME=$HOME/Library/Android/sdk ./gradlew --dependency-verification lenient compileFullDebugKotlin
  • Android unit-test command was attempted, but this checkout currently fails compiling unrelated tests whose fake DeviceRegistryDao implementations do not implement setModel; app Kotlin compile passes.

@tigercraft4
tigercraft4 force-pushed the feature/custom-ai-gateway-options branch from 6e506c2 to c07d499 Compare July 23, 2026 18:16

@ryanbr ryanbr left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

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/CustomAiAuthHeader enum (Bearer / x-api-key, default Bearer) matches on both platforms. applyCustomAuthHeader is 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 .noopbak contract.
  • catalog[].models parsing: parity — both add a deduped catalog path alongside the existing data[].id path.
  • max_completion_tokens retry: 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.

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.

Support x-api-key custom AI gateways

2 participants