Skip to content

symfonic.core.contracts.model_config

model_config

ModelConfig โ€” the model-configuration value type, stdlib-only.

Three layers have to be able to say this name: the facade compiles it into a plan, the model-resolution runtime service reads and constructs it (services.models.resolution, .capabilities, .contract), and the platform threads it through assembly. kernel-contracts is the one column every row of dependency-matrix.md reads yes on, so that is where a name shared that widely has to live.

It used to be declared in :mod:symfonic.core.config alongside AgentConfig, whose with_anthropic convenience constructor imports :mod:symfonic.core.providers โ€” the whole provider stack. That import is fine for a facade-compiler module and disqualifying for a kernel-contracts one, so TA2.2 split the value type out rather than rule the provider stack into the kernel. symfonic.core.config re-exports ModelConfig, so from symfonic.core.config import ModelConfig keeps working and there is still exactly one definition.

Imports here are stdlib only, and kernel-purity fails the build if that stops being true.

ModelConfig dataclass

ModelConfig(model_name: str = 'claude-sonnet-4-5', temperature: float = 1.0, max_tokens: int = 16384, max_retries: int = 5, structured_output_repair_attempts: int = 0, top_p: float | None = None, top_k: int | None = None, thinking: dict[str, object] | None = None, extra_headers: dict[str, str] = dict(), context_window: int | None = None, timeout_seconds: float | None = None, http_client: Any | None = None)

LLM model configuration. Provider-agnostic.

context_window (added in v7.1.2) declares the model's native context-window budget in tokens. When set, ContextWindowNode uses it as the hard ceiling unless CompactionConfig.context_window_tokens explicitly overrides it. None (default) preserves pre-v7.1.2 behaviour: the node falls through to the 200_000 safety net. Typical values: Claude 3/4 = 200_000, GPT-4 Turbo = 128_000, GPT-4 = 8_192, Llama-3 32k = 32_000.

http_client class-attribute instance-attribute

http_client: Any | None = None

Underlying HTTP client (typically httpx.AsyncClient) for true per-chunk idle bound. Threaded to providers whose LangChain class accepts the kwarg -- http_async_client on OpenAI / DeepSeek / Kimi. Providers whose class does NOT accept it (Anthropic, Google, Ollama at the time of v7.25.0) emit a one-shot :class:HttpClientUnsupportedWarning on first encounter and ignore the field; timeout_seconds still threads. Typed Any so symfonic-core does not import httpx at module load -- adopters who don't pin a client pay no import cost. None (default) preserves the provider's own default client lifecycle.

structured_output_repair_attempts class-attribute instance-attribute

structured_output_repair_attempts: int = 0

Additional schema-repair calls after a malformed structured result.

0 preserves the single-pass contract. Values up to 3 are accepted; the hard ceiling prevents an unreliable schema from creating an unbounded bill after the ordinary model loop has already completed.

timeout_seconds class-attribute instance-attribute

timeout_seconds: float | None = None

Total-request timeout in seconds. Threaded to the provider's LangChain-class kwarg whose name varies by provider: default_request_timeout on Anthropic, timeout on OpenAI / DeepSeek / Kimi / Google. Coarse-grained; bounds the entire HTTP round-trip but does NOT enforce per-chunk idle. None (default) leaves the provider's own default in place (typically 600 for the OpenAI family; httpx-driven for Anthropic).

top_k class-attribute instance-attribute

top_k: int | None = None

Top-k sampling: sample only from the k most likely tokens. Honoured by Anthropic, Google, and Ollama (their LangChain classes expose top_k). The OpenAI chat API has NO top_k parameter, so OpenAI / DeepSeek / Kimi ignore it and emit a one-shot warning. None leaves the provider default.

top_p class-attribute instance-attribute

top_p: float | None = None

Nucleus sampling: keep the smallest token set whose cumulative probability >= top_p (0-1). Threaded to every provider's LangChain class (all accept top_p). None leaves the provider default. Note: most providers advise tuning EITHER temperature OR top_p, not both.