"""Website configuration: explicit provider catalog, atomic in-memory credentials.""" from urllib.parse import urlsplit from .connections import Connections from .credentials import OPENROUTER_ENDPOINT, OPENROUTER_JEV from .protocol import DecisionError, fields DEEPSEEK_MODELS = ("deepseek-flash",) COOKIE = "__Host-cadworld-session" def website_origin(value, *, development=False): url = urlsplit(value) if ( url.scheme != "https" and not ( development and url.scheme == "http" and url.hostname in ("localhost", "127.0.0.1") ) ) or ( not url.hostname or url.username or url.password or url.path or url.query or url.fragment ): raise DecisionError("invalid_website_origin") return url.netloc class MemoryConnections(Connections): def __init__(self): self.values = {} def set(self, data): raise DecisionError("website_configuration_required") def configure(values, data, openrouter_models, codex_models=()): """Return new values without mutation. Omitted key retains it only at the same provider.""" fields(data, ["llm", "jev"]) llm = fields(data["llm"], ["provider", "model"], ["apiKey"]) jev = fields(data["jev"], [], ["apiKey"]) provider, model = llm["provider"], llm["model"] if not isinstance(provider, str) or not isinstance(model, str): raise DecisionError("invalid_provider") choices = { "deepseek": ("responses", "https://api.deepseek.com", DEEPSEEK_MODELS), "openrouter": ("chat-completions", "https://openrouter.ai/api/v1", openrouter_models), "codex": ("codex", "", codex_models), } if provider not in choices: raise DecisionError("invalid_provider") protocol, url, models = choices[provider] if model not in models: raise DecisionError("model_unavailable", 409) def connection(role, protocol, url, model, draft): old = values.get(role) key = draft.get("apiKey") if key is None and "apiKey" not in draft: key = old.key if old and old.protocol == protocol and old.base_url == url else "" if protocol != "codex" and not key: raise DecisionError("api_key_required", 409) return Connections.parse( { "role": role, "protocol": protocol, "baseUrl": url, "model": model, "apiKey": key or "", } ) result = { "llm": connection("llm", protocol, url, model, llm), "jev": connection("jev", "openrouter-decisions", OPENROUTER_ENDPOINT, OPENROUTER_JEV, jev), } # Do not allow a credential to escape through any other role's public metadata. metadata = str(public_config(result)) if any(c.key and c.key in metadata for c in [*values.values(), *result.values()]): raise DecisionError("credential_in_metadata") return result def public_config(values): llm, jev = values.get("llm"), values.get("jev") provider = ( "codex" if llm and llm.protocol == "codex" else "openrouter" if llm and llm.protocol == "chat-completions" else "deepseek" ) return { "llm": { "provider": provider, "model": llm.model if llm else DEEPSEEK_MODELS[0], "hasKey": bool(llm and llm.key), }, "jev": {"hasKey": bool(jev and jev.key), "model": OPENROUTER_JEV}, }