f3a8a38acd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
"""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},
|
|
}
|