Files
chenlin 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
feat: release v1.0.1 CADWorld 网站与 LeKiwi 智能抓放
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
2026-09-24 09:57:41 +08:00

64 lines
2.1 KiB
Python

"""Bounded, non-redirecting HTTP. No SDK retries or environment credential discovery."""
import asyncio
import math
import aiohttp
from ..protocol import DecisionError, loads
async def post(session, connection, path, payload):
try:
async with session.post(
connection.base_url + path,
json=payload,
headers={"Authorization": "Bearer " + connection.key},
allow_redirects=False,
timeout=aiohttp.ClientTimeout(total=45),
) as response:
if response.status != 200:
raise DecisionError(f"upstream_http_{response.status}", 502)
# read(n) may return a partial chunk: accumulate with an explicit byte bound.
data = bytearray()
async for chunk in response.content.iter_chunked(16384):
data.extend(chunk)
if len(data) > 262144:
raise DecisionError("upstream_response_too_large", 502)
try:
result = loads(data.decode("utf-8"))
except UnicodeError as exc:
raise DecisionError("invalid_upstream_encoding", 502) from exc
if not isinstance(result, dict):
raise DecisionError("invalid_upstream_response", 502)
return result
except TimeoutError as exc:
raise DecisionError("upstream_timeout", 504) from exc
except (aiohttp.ClientError, OSError) as exc:
raise DecisionError("upstream_transport_error", 502) from exc
except asyncio.CancelledError:
raise
def usage(result):
"""Only real numeric counters, no inferred price, upstream strings or raw body."""
raw = result.get("usage", {})
if not isinstance(raw, dict):
return {}
return {
k: v
for k, v in raw.items()
if k
in (
"input_tokens",
"output_tokens",
"total_tokens",
"prompt_tokens",
"completion_tokens",
"cost",
)
and type(v) in (int, float)
and math.isfinite(v)
and 0 <= v <= 1e9
}