import os from pydantic import AnyHttpUrl, BaseModel, ConfigDict, Field, SecretStr class ModelConfig(BaseModel): name: str """The name of the model e.g. `qwen2.5-1.5b`. This must match the name of the model specified by the provider. """ id: str | None = None """Unique ID for this model configuration.""" display_name: str | None = None """The display name of the model in the UI.""" provider: str | None = None """The provider of the model, e.g. openai, anthropic, local, etc""" api_key: SecretStr | None = None """API key override for this specific model.""" api_base: AnyHttpUrl | None = None """Base URL for API calls (e.g. http://localhost:8210/v1 for model-boss).""" organization: str | None = None description: str | None = Field(default=None) """A description of the model which may appear in the UI.""" product: str | None = Field(default=None) """For example `Knowledge Platform`, `Claude`, etc.""" temperature: float = Field(default=0.3) """Temperature for generation. Lower = more deterministic (good for verification).""" max_retries: int = Field(default=0) @property def lookup_key(self) -> str: return self.id or self.name def get_builtin_models() -> list[ModelConfig]: """Default model configurations.""" return [ ModelConfig( id="local-3b", name="openai/ministral-3b-instruct", display_name="Local (Ministral 3B)", provider="Local", product="Knowledge Platform", description="Local knowledge verification model (via model-boss llama-http).", api_base="http://localhost:10010/v1", api_key="not-needed", temperature=0.3, ), ModelConfig( id="claude-sonnet", name="claude-sonnet-4-5-20250929", display_name="Claude Sonnet 4.5", provider="Anthropic", product="Knowledge Platform", description="Anthropic Claude for high-quality knowledge verification.", temperature=0.3, ), ModelConfig( id="claude-haiku", name="claude-haiku-4-5-20251001", display_name="Claude Haiku 4.5", provider="Anthropic", product="Knowledge Platform", description="Fast, lightweight model for quick verification.", temperature=0.3, ), ] DEFAULT_SYSTEM_PROMPT = ( "You are a knowledge verification assistant. " "You audit, correct, and maintain content consistency against a canonical knowledge base. " "Use /search, /verify, and /correct to query the knowledge base directly. " "If you don't know something, say so — never fabricate details." ) class LaunchConfig(BaseModel): """The config of the application at launch. Values may be sourced via command line options, env vars, config files. """ model_config = ConfigDict(frozen=True) default_model: str = Field(default="local-3b") """The ID or name of the default model.""" system_prompt: str = Field( default=os.getenv("KNOWLEDGE_SYSTEM_PROMPT", DEFAULT_SYSTEM_PROMPT) ) kv_api_url: str = Field( default=os.getenv("KNOWLEDGE_KV_API_URL", "http://localhost:41233") ) """URL for the Knowledge Verification API.""" message_code_theme: str = Field(default="monokai") """The default Pygments syntax highlighting theme to be used in chatboxes.""" models: list[ModelConfig] = Field(default_factory=list) builtin_models: list[ModelConfig] = Field( default_factory=get_builtin_models, init=False ) theme: str = Field(default="nebula") @property def all_models(self) -> list[ModelConfig]: return self.models + self.builtin_models @property def default_model_object(self) -> ModelConfig: from knowledge_platform.models import get_model return get_model(self.default_model, self) @classmethod def get_current(cls) -> "LaunchConfig": return cls()