Repository navigation
[Bug]: OAuth provider reconciliation deletes user-set modelInputModalities on every startup (kiro) #3154
Description
opencodex version: 2.39.0 (bun runtime, macOS LaunchAgent, Apple Silicon)
Summary
Any user-set modelInputModalities on an OAuth-managed provider (e.g. kiro) is silently deleted on every service start. Both edit paths are affected: hand-editing ~/.opencodex/config.json while the service is stopped, and the sanctioned POST /api/providers management route. Reproduced 3/3 restarts before patching.
Key-auth providers (deepseek, kimi-code) don't go through the reconciliation, so identical config edits persist there — the asymmetry makes it look like "config edits don't work for kiro", but it's a wipe, not a write failure.
Root cause
reconcileOAuthProviders() (src/oauth/index.ts) reconciles providers that are registry-managed and authMode: "oauth" against the registry preset, field by field over OAUTH_RECONCILE_FIELDS:
for (const field of OAUTH_RECONCILE_FIELDS) {
if (JSON.stringify(prov[field]) === JSON.stringify(preset[field])) continue;
if (preset[field] !== undefined) {
prov[field] = cloneProviderField(preset[field]) as never;
} else {
delete prov[field]; // ← kiro preset has no modelInputModalities, so user values die here
}
}modelInputModalities is in OAUTH_RECONCILE_FIELDS, but the kiro registry entry seeds no modelInputModalities (and kiro is absent from PROVIDER_ALIASES, so the models.dev metadata fallback doesn't fire either). Result: preset-undefined → delete prov[field] on every boot.
Notably the same file already guards against exactly this hazard for another field — requiresReasoningPlaceholderModels is deliberately excluded from reconciliation ("the delete-when-preset-undefined branch would wipe an explicit user opt-out on every startup"). modelInputModalities hits the same trap via the delete branch.
Steps to reproduce
kiroprovider configured via OAuth (authMode: "oauth").- Add to its provider block in
~/.opencodex/config.json:"modelInputModalities": { "claude-opus-4.6": ["text", "image"] }
- Start the service;
GET /api/modelsshows the row as image-capable. ocx stop && ocx service.- The key is gone from
config.json, and/api/modelsreports the row as text-only again.
Impact
- Vision-capable upstream models (kiro's Claude / GPT-5.6 rows — the kiro adapter already sends image blocks per
docs/reference/adapters.md) can never be advertised as image-capable, so modality-respecting clients block image attachments. - Same symptom class as [Bug]: GitHub Copilot provider: all models report text-only input — image attachments blocked #2941 (GitHub Copilot: all models text-only), which was fixed by seeding the registry; kiro just never got the same treatment, and user-side self-service is wiped by the reconciliation.
Suggested fixes (either or both)
- Seed
modelInputModalitiesin the kiro registry entry (same approach as the [Bug]: GitHub Copilot provider: all models report text-only input — image attachments blocked #2941 fix) for the multimodal lineup (claude-, gpt-5.6-). - Preserve explicit user values in
reconcileOAuthProviders()— e.g. only overwrite (never delete) fields the user has set, or movemodelInputModalitiesout ofOAUTH_RECONCILE_FIELDSand rely on the fill-onlyenrichProviderFromRegistry()for preset propagation, as already done forrequiresReasoningPlaceholderModels.
Local workaround currently in place
Removed "modelInputModalities" from OAUTH_RECONCILE_FIELDS in the installed 2.39.0 and re-submitted the provider block via POST /api/providers; modalities now survive restarts. Happy to send a PR if you tell me which approach you prefer.
Side note: while verifying, I also noticed the catalog advertises image input for deepseek-v4-flash / deepseek-v4-pro because they're sidecar-covered (noVisionModels) — documented behavior per sidecars.md / #3053, but in the GUI the badge is indistinguishable from native vision. Might be worth a UX tweak in a future release (distinguish native vision from sidecar coverage); not part of this bug report.
Activity
github-actions commentedon Sep 1, 2026
Automated translation bookkeeping — detected language: English.
github-actions commentedon Sep 1, 2026
Issue closed: insufficient detail
Thanks for taking the time to submit this issue. It was closed automatically because the structured report is missing information needed to evaluate or reproduce it.
Please edit the issue to add:
See the Contributing guide for details.
Once the report passes the automated checks, it will be reopened automatically unless a maintainer has changed its state.