From 97554877933df84ba7b8065d34c77cf7477656c7 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Sun, 15 Feb 2026 10:23:03 -0800 Subject: [PATCH] config: add per-tier auth_mode --- README.md | 2 ++ config/default.yaml | 2 ++ src/config/schema.test.ts | 31 +++++++++++++++++++++++++++++++ src/config/schema.ts | 2 ++ 4 files changed, 37 insertions(+) diff --git a/README.md b/README.md index 0fcea44..17b9e7a 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,8 @@ models: local: { provider: ollama, model: qwen2.5:14b } ``` +Each tier can optionally specify `auth_mode` (`auto` | `api_key` | `oauth`) to control whether Flynn uses API keys vs OAuth/token auth for that provider. `use_oauth: true` remains supported as a compatibility alias for `auth_mode: oauth`. + ### Native Audio Support Voice messages from channels can be handled in two ways: diff --git a/config/default.yaml b/config/default.yaml index dccf10a..f907639 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -39,6 +39,8 @@ models: default: provider: anthropic model: claude-sonnet-4-20250514 + # auth_mode: auto # auto | api_key | oauth (provider-specific) + # use_oauth: false # compat alias for auth_mode: oauth # supports_audio: false # Override native audio detection per tier local: provider: ollama diff --git a/src/config/schema.test.ts b/src/config/schema.test.ts index c1e84b9..4fb5791 100644 --- a/src/config/schema.test.ts +++ b/src/config/schema.test.ts @@ -140,6 +140,37 @@ describe('configSchema — per-tier fallback', () => { }); }); +describe('configSchema — models auth_mode', () => { + const minimalConfig = { + telegram: { bot_token: 'test', allowed_chat_ids: [1] }, + models: { default: { provider: 'anthropic', model: 'claude-3' } }, + }; + + it('accepts auth_mode values per tier', () => { + const result = configSchema.parse({ + ...minimalConfig, + models: { + default: { provider: 'openai', model: 'gpt-4o', auth_mode: 'api_key' }, + fast: { provider: 'openai', model: 'gpt-4o-mini', auth_mode: 'oauth' }, + }, + }); + + expect(result.models.default.auth_mode).toBe('api_key'); + expect(result.models.fast?.auth_mode).toBe('oauth'); + }); + + it('rejects invalid auth_mode values', () => { + expect(() => { + configSchema.parse({ + ...minimalConfig, + models: { + default: { provider: 'openai', model: 'gpt-4o', auth_mode: 'bogus' }, + }, + }); + }).toThrow(/auth_mode/i); + }); +}); + describe('configSchema — skills watcher', () => { const minimalConfig = { telegram: { bot_token: 'test', allowed_chat_ids: [1] }, diff --git a/src/config/schema.ts b/src/config/schema.ts index b795f3c..c0b1efb 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -49,6 +49,8 @@ const modelConfigBaseSchema = z.object({ endpoint: z.string().optional(), api_key: z.string().optional(), auth_token: z.string().optional(), + /** Credential selection strategy for this tier (provider-specific). */ + auth_mode: z.enum(['auto', 'api_key', 'oauth']).optional(), /** Use OAuth credential flow (provider-specific). */ use_oauth: z.boolean().optional(), for: z.array(z.string()).optional(),