feat: release v1.0.1 CADWorld 网站与 LeKiwi 智能抓放
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
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 验收仍待用户凭据。
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
"""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},
|
||||
}
|
||||
Reference in New Issue
Block a user