Files
Mujoco_WASM/decision_server/providers/codex_gate.py
T
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

154 lines
5.7 KiB
Python

"""Offline native capability gate: no advertised tools AND injected calls rejected.
Runs only against a private loopback fake Responses service with synthetic output.
No account login, remote inference, inherited credentials or agent delegation occurs.
"""
import asyncio
import hmac
import json
from aiohttp import web
from ..protocol import DecisionError
from .codex import CodexAccount
async def verify_no_tools(directory, model, evidence=None):
completed = asyncio.get_running_loop().create_future()
count = 0
first_tools = None
client = None
names = ["apply_patch", "shell_command", "exec_command", "view_image"]
async def receive(request):
nonlocal count, first_tools
if not client or not hmac.compare_digest(
request.headers.get("Authorization", ""), "Bearer " + client.probe_token
):
return web.Response(status=403)
body = await request.json()
count += 1
if count == 1:
first_tools = body.get("tools", [])
items = []
for i, name in enumerate(names):
item = {
"id": f"tool_{i}",
"call_id": f"gate_{i}",
"name": name,
"status": "completed",
}
if name == "apply_patch":
item.update(
type="custom_tool_call",
input=(
"*** Begin Patch\n*** Add File: MUST_NOT_WRITE\n+test\n*** End Patch"
),
)
else:
item.update(
type="function_call",
arguments=json.dumps(
{
"command": "touch MUST_NOT_WRITE",
"cmd": "touch MUST_NOT_WRITE",
"path": str(client.cwd / "nonexistent-image.png"),
}
),
)
items.append(item)
events = [
{
"type": "response.created",
"response": {"id": "gate_response", "status": "in_progress"},
}
]
events.extend(
{"type": "response.output_item.done", "output_index": i, "item": item}
for i, item in enumerate(items)
)
events.append(
{
"type": "response.completed",
"response": {
"id": "gate_response",
"status": "completed",
"output": items,
"usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2},
},
}
)
return web.Response(
content_type="text/event-stream",
text="".join(
"event: " + event["type"] + "\ndata: " + json.dumps(event) + "\n\n"
for event in events
),
)
feedback = {
item.get("call_id"): item.get("output")
for item in body.get("input", [])
if item.get("type") in ("function_call_output", "custom_tool_call_output")
}
passed = (
first_tools == []
and body.get("tools", []) == []
and all(
isinstance(feedback.get(f"gate_{i}"), str)
and "unsupported" in feedback[f"gate_{i}"].lower()
and name in feedback[f"gate_{i}"]
for i, name in enumerate(names)
)
and not (client.cwd / "MUST_NOT_WRITE").exists()
)
if evidence is not None:
evidence.update(model=model, tools=first_tools, feedback=feedback, passed=passed)
if not completed.done():
completed.set_result(passed)
return web.Response(status=400, text="offline gate finished")
app = web.Application(client_max_size=262144)
app.router.add_post("/v1/responses", receive)
runner = web.AppRunner(app, access_log=None)
await runner.setup()
site = web.TCPSite(runner, "127.0.0.1", 0)
await site.start()
port = site._server.sockets[0].getsockname()[1]
client = CodexAccount(directory, probe_url=f"http://127.0.0.1:{port}/v1")
try:
async with asyncio.timeout(25):
await client.start()
thread = await client.rpc(
"thread/start",
{
"cwd": str(client.cwd),
"ephemeral": True,
"approvalPolicy": "never",
"sandbox": "read-only",
"model": model,
"modelProvider": "offline_probe",
"baseInstructions": "Return JSON only. Do not call tools.",
},
)
await client.rpc(
"turn/start",
{
"threadId": thread["thread"]["id"],
"input": [{"type": "text", "text": 'Return {"ok":true}'}],
"outputSchema": {
"type": "object",
"additionalProperties": False,
"required": ["ok"],
"properties": {"ok": {"type": "boolean"}},
},
},
)
if not await completed:
raise DecisionError("codex_tool_gate_failed", 409)
except TimeoutError:
raise DecisionError("codex_tool_gate_timeout", 504) from None
finally:
await client.close()
await runner.cleanup()