core/config: default OpenAI preset and model catalog

Missing preset becomes openai; omitted models seed gpt-5.4 / mini / nano.
This commit is contained in:
2026-07-15 21:40:43 +08:00
parent 16992be743
commit 84a83e0485
5 changed files with 47 additions and 5 deletions
+13
View File
@@ -53,14 +53,27 @@ class ProviderConfig(Struct, tag_field="preset", omit_defaults=True):
models: dict[str, ModelConfig] = field(default_factory=dict)
def _default_openai_models() -> dict[str, ModelConfig]:
"""Current OpenAI text catalog when TOML omits ``models``."""
return {
"gpt-5.4": ModelConfig(text=True),
"gpt-5.4-mini": ModelConfig(text=True),
"gpt-5.4-nano": ModelConfig(text=True),
}
class OpenAIProvider(ProviderConfig, tag="openai"):
"""OpenAI platform provider (agent uses Responses API).
``provider_tools`` are hosted/provider-side tools (e.g. web_search) passed
through to ``POST /responses`` as opaque dicts. They are **not** local
``ToolRegistry`` handlers and are ignored by non-OpenAI clients.
When ``models`` is omitted in TOML, seeds a small default catalog (same idea
as DeepSeek). Explicit ``models = {}`` stays empty (recoverable / free-form).
"""
models: dict[str, ModelConfig] = field(default_factory=_default_openai_models)
provider_tools: list[dict[str, Any]] = field(default_factory=list)
+10 -4
View File
@@ -60,9 +60,14 @@ def _parse_providers(
bad_providers[name] = raw_entry
continue
entry = cast("dict[str, object]", raw_entry)
# Missing preset → OpenAI platform (Responses-capable defaults).
if "preset" not in entry:
entry = {**entry, "preset": "openai"}
# Try tagged-union dispatch via msgspec
try:
provider: Provider = msgspec.convert(raw_entry, Provider)
provider: Provider = msgspec.convert(entry, Provider)
except msgspec.ValidationError:
bad_providers[name] = raw_entry
continue
@@ -72,12 +77,13 @@ def _parse_providers(
cls = type(provider)
known = set(cls.__struct_fields__)
known.add("preset") # tag_field, excluded from __struct_fields__
if set(cast("dict[str, object]", raw_entry).keys()) - known:
# Validate against the entry we actually converted (may have injected preset).
if set(entry.keys()) - known:
bad_providers[name] = raw_entry
continue
# Empty models: keep as recoverable (DeepSeek seeds defaults when
# models is omitted, so only explicit models={} lands here).
# Empty models: recoverable. OpenAI/DeepSeek seed defaults when
# ``models`` is omitted; only explicit models={} lands here.
if not provider.models:
recoverable[name] = provider
continue