This document describes named, reusable AI upstream profiles for QuantMesh: goals, configuration shape, resolution rules, and migration. It is a blueprint for implementation; not every field may be wired up in the current release—refer to code and CHANGELOG.
- Maintain multiple distinct credentials and endpoints in the primary app config (Web-saved
app_configor a one-shot YAML import) (e.g. office OpenAI, home Poe, regional gateway). - Allow feature-level selection (news analysis, inspector, AI submodules) instead of a single global key/base URL.
- Backward compatibility: if new fields are unused, behavior matches historical flat
aiconfiguration.
- Automatic failover / rotation across upstreams: defer to avoid coupling with async task retries and timeouts.
- Restoring removed
ai.proxy.*: unless explicitly revived elsewhere; this design assumes direct access plus optionalbase_url.
| Term | Meaning |
|---|---|
| Upstream | One combination of provider + endpoint + credentials for an LLM call. |
| Profile | A key under ai.upstreams mapping to provider, model, api_key, base_url. |
| Flat / legacy fields | Top-level ai.provider, ai.api_key, ai.gemini_api_key, ai.base_url. |
| upstream_ref | A string referencing which profile a feature block uses. |
| default_upstream | Which upstreams key is the global default (optional). |
- Global
aiexposes a single credential set (config/config.go). news_monitor.ai_providercan override;ApplyDefaultsmay inherit keys from globalai.ai.NewAIClient(provider, model, apiKey, baseURL)has no profile id; supported providers:gemini,openai,claude,poe(ai/factory.go).
ai:
enabled: true
default_upstream: ""
upstreams:
my-openai:
provider: openai
model: gpt-4o-mini
api_key: "sk-..."
base_url: ""
office-poe:
provider: poe
model: "..."
api_key: "..."
base_url: "https://..."
provider: gemini
api_key: ""
gemini_api_key: ""
base_url: ""| Field | Notes |
|---|---|
provider |
gemini, openai, claude, poe (factory). |
model |
Model name; empty defaults follow existing rules. |
api_key |
Same encryption/decryption path as global ai when applicable. |
base_url |
Custom API root; required for poe. Gemini may ignore until supported. |
Resolver should yield provider, model, api_key, base_url (or a struct) with keys decrypted when applicable.
- Ignore
default_upstream. - Behavior matches today’s flat fields and
news_monitorinheritance.
- If
default_upstreamis set: must reference a key inupstreams; defines global default credentials (exact merge rules with flat fields should be fixed in code + tests). - If
default_upstreamis empty: recommended convention—flatai.*still acts as default;upstreamsis used only when referenced byupstream_refor explicit logic.
If a module sets upstream_ref to an existing profile, prefer that profile’s tuple. Optional fallback if api_key is empty: document one strategy only (global flat vs default_upstream profile).
flowchart TD
req[Consumer needs AI credentials]
ref{upstream_ref set and valid?}
prof[Load profile from ai.upstreams]
flat[Use legacy ai flat fields]
def{default_upstream set?}
merge[Apply defaults and key decryption]
req --> ref
ref -->|yes| prof
ref -->|no| def
def -->|yes| prof
def -->|no| flat
prof --> merge
flat --> merge
| Consumer | Field | Notes |
|---|---|---|
| Global default / Web | ai.default_upstream or flat ai |
Align with web/api.go after central resolver. |
news_monitor |
news_monitor.ai_provider.upstream_ref |
Prefer profile over duplicate inline keys when both exist. |
inspector |
inspector.ai.upstream_ref |
Inspector-specific upstream. |
ai.modules.* |
per-module upstream_ref |
e.g. market vs risk analysis. |
- Logs: may record upstream id and
provider; never log rawapi_key. - Sanitize
upstreams.*.api_keylike flat keys in exports/APIs. - Validate
default_upstreamandupstream_refat startup or reload.
Reserved for future custom endpoints; current NewGeminiProvider may ignore it—see implementation.
- Flat-only users: no change.
- Multi-upstream: add
upstreams, optionallydefault_upstream, then setupstream_refwhere needed; avoid duplicating secrets in flat + profiles without intent.
Q: Precedence between default_upstream and flat fields?
A: See §5.3; implementation must lock behavior with tests.
Q: Same profile referenced from multiple features?
A: Supported.
Q: Poe without base_url?
A: Factory error, same as today; validate early in config.
- Extend
config.Configwithdefault_upstreamandupstreams. - Wire
ApplyDefaults, decrypt, sanitize. - Add
ResolveAIUpstream(or equivalent). - Replace scattered reads in
main,web,monitor, etc. - Tests for missing/invalid profiles.
- WebUI types and i18n.
- News monitor integration
- Configuration guide
- Chinese full design: AI_UPSTREAM_PROFILES.md