Source code for rath.config.schema
"""Pydantic v2 schema for ``~/.openrath/config.json``.
Every model uses ``extra="allow"`` so unknown fields written by a newer
OpenRath or a third-party tool round-trip through load → save without loss.
Schema is versioned via :attr:`RathConfig.version`; no migration code yet,
but the field is reserved so v2 can detect older files.
"""
from __future__ import annotations
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field
__all__ = [
"LLMProviderConfig",
"LLMConfig",
"MemoryProviderConfig",
"MemoryConfig",
"MCPServerConfig",
"MCPConfig",
"RathConfig",
"SCHEMA_VERSION",
]
SCHEMA_VERSION = 1
[docs]
class LLMProviderConfig(BaseModel):
"""One named entry under ``llm.providers``.
Mirrors the most common :class:`~rath.llm.Provider` fields. Less-common
knobs (``frequency_penalty``, ``logit_bias``, …) stay on explicit
``Provider(...)`` kwargs — adding fields here later is non-breaking thanks
to ``extra="allow"``.
"""
provider_kind: Literal["openai", "anthropic"] = "openai"
model: str | None = None
api_key: str | None = None
base_url: str | None = None
temperature: float | None = None
max_tokens: int | None = None
model_config = ConfigDict(extra="allow")
[docs]
class LLMConfig(BaseModel):
"""The ``llm`` section: named providers + which one is the default.
``default_provider`` is the chat fallback. ``embedding_provider`` and
``vlm_provider`` are independent overrides used by
:class:`rath.llm.embedding.EmbeddingProvider` and
:class:`rath.llm.vlm.VLMProvider`; when unset, those clients fall back
to ``default_provider``'s ``api_key``/``base_url`` with a sensible
default model.
"""
default_provider: str | None = None
embedding_provider: str | None = None
vlm_provider: str | None = None
providers: dict[str, LLMProviderConfig] = Field(default_factory=dict)
model_config = ConfigDict(extra="allow")
[docs]
class MCPServerConfig(BaseModel):
"""One named entry under ``mcp.servers``.
``command`` is the full argv list passed to the stdio MCP server (the
OpenRath adapter never shells out, so no string-form). ``env`` is
merged into the subprocess environment by the adapter.
"""
command: list[str]
env: dict[str, str] = Field(default_factory=dict)
model_config = ConfigDict(extra="allow")
[docs]
class MCPConfig(BaseModel):
"""The ``mcp`` section: named server defs + which are enabled by default."""
default_enabled: list[str] = Field(default_factory=list)
servers: dict[str, MCPServerConfig] = Field(default_factory=dict)
model_config = ConfigDict(extra="allow")
[docs]
class MemoryProviderConfig(BaseModel):
"""One named entry under ``memory.providers`` (local backend only).
``embedding_provider`` and ``chat_provider`` name entries under
``llm.providers`` used by :class:`~rath.memory.adapters.local.LocalMemoryBackend`
for vector search and commit-time memo extraction respectively.
OpenViking connection settings stay on ``MemoryStoreSpec.options`` or
environment variables — they are not modeled here.
"""
backend_kind: Literal["local"] = "local"
path: str | None = None
embedding_provider: str | None = None
chat_provider: str | None = None
model_config = ConfigDict(extra="allow")
[docs]
class MemoryConfig(BaseModel):
"""The ``memory`` section: named local store presets."""
default_provider: str | None = None
providers: dict[str, MemoryProviderConfig] = Field(default_factory=dict)
model_config = ConfigDict(extra="allow")
[docs]
class RathConfig(BaseModel):
"""Top-level on-disk schema.
Sections currently in use: ``llm``, ``mcp``, and ``memory``. Future
sections (e.g. ``backend`` for OpenSandbox routing) can be added without
touching callers because ``extra="allow"`` preserves them on round-trip.
"""
version: int = SCHEMA_VERSION
llm: LLMConfig = Field(default_factory=LLMConfig)
mcp: MCPConfig = Field(default_factory=MCPConfig)
memory: MemoryConfig = Field(default_factory=MemoryConfig)
model_config = ConfigDict(extra="allow")