WU-A 迁移面 spike:便宜档生成核心(多轮 ReAct + 五工具沙箱 + done 门)用 Python 在新建 cheap-worker/ 重写成 AgentScope agent,import 复用 tier2 框架层(model client/四道熔断/历史压缩/observability), check/build/九门 shell-out 现有 node/cjs(不重写 esbuild/CDP/形状门)。 - U1 地基:跨包 sys.path import tier2 worker + 代理旁路 + key 从内网文档注入 env + M3 装配 - U2 五工具:read/list/write Python 实现 + check/build shell-out(形状门三态与 Node 一致) - U3 LittleJS system prompt:prompt.mjs Python 化(两条 footgun 正反例 + 输入契约) - U4 scaffold/stage/play 薄壳 + ensure_play_spec(据 state 形态产 play-spec 治链路假绿) - U5 ReAct 主编排:内置 Agent+ReActConfig+外层有界 resume + done 门 + 收口 stage/smoke/九门 - U6 对照 Node:产物形态 + 九门逐门 + 过门率对比 验收:同 brief Python 新路 vs Node 旧路,产物都真 src/ 6 文件、九门都 9/9 全 PASS、过门率 1.0=1.0 → spikePass=True。端到端单局 attempt 1 一次收敛、148s。落点 cheap-worker/ 对 tier2/amodel-gen 零改动(结构性零回归)。测试 38/38 全绿。 origin: docs/plans/2026-06-26-001-feat-cheap-worker-python-spike-plan.md Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
74 lines
2.9 KiB
Python
74 lines
2.9 KiB
Python
"""
|
||
test_studio_smoke.py — U5 端到端产物契约验证。
|
||
|
||
端到端真跑由 cheap_studio CLI 提供(落 evidence/run-summary.json + staged 工程 + 九门 verdict);
|
||
本 test 验证最近一次 run 的产物契约(真 src/ 多文件 + staged + 九门 verdict + run-summary 字段)。
|
||
|
||
真跑回归(~2.5min,真 M3 ReAct):
|
||
cheap-worker/.venv/bin/python cheap-worker/cheap_studio.py --id cheap-smoke1 --brief "一个简单的点击得分小游戏:屏幕上随机冒出可点的圆,点中加分"
|
||
然后:cheap-worker/.venv/bin/python cheap-worker/tests/test_studio_smoke.py
|
||
"""
|
||
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parents[1])) # → cheap-worker/
|
||
import cheap_run
|
||
|
||
GID = "cheap-smoke1"
|
||
|
||
|
||
def _require_run() -> dict:
|
||
p = cheap_run.game_dir(GID) / "evidence" / "run-summary.json"
|
||
if not p.exists():
|
||
raise AssertionError(
|
||
f"先跑端到端单局:cheap-worker/.venv/bin/python cheap-worker/cheap_studio.py --id {GID} --brief ...(缺 {p})")
|
||
return json.loads(p.read_text(encoding="utf-8"))
|
||
|
||
|
||
def test_run_summary_contract():
|
||
"""run-summary 含 finished/check/build/staged 字段且收敛。"""
|
||
s = _require_run()
|
||
assert s["finished"] is True, s
|
||
assert s["check"]["ok"] and s["build"]["ok"], s
|
||
assert s["staged"] is True, s
|
||
|
||
|
||
def test_real_src_multifile():
|
||
"""产真 src/ 多文件工程(非单文件 / JSON blob / new Function blob)——doc↔code 兑现门的便宜档侧。"""
|
||
src = cheap_run.game_dir(GID) / "src"
|
||
assert (src / "game-logic.js").exists(), "缺 src/game-logic.js"
|
||
js = list(src.glob("*.js"))
|
||
assert len(js) >= 2, f"应为真 src/ 多文件工程,实际 {len(js)} 个 .js"
|
||
|
||
|
||
def test_staged_artifact_exists():
|
||
"""stage 后 _wg1-gen/<id>/ 有自包含 bundle + index + 自动产的 play-spec。"""
|
||
dst = cheap_run.wg1_game_dir(GID)
|
||
assert (dst / "bundle.iife.js").exists()
|
||
assert (dst / "index.html").exists()
|
||
assert (dst / "play-spec.json").exists(), "play-spec 缺失 → 九门会 driven=false 假绿"
|
||
|
||
|
||
def test_nine_gates_verdict():
|
||
"""九门 verdict.json 存在且含逐门 guards(不假绿)。"""
|
||
v = cheap_run.wg1_game_dir(GID) / "evidence" / "verdict.json"
|
||
assert v.exists(), "缺九门 verdict.json"
|
||
d = json.loads(v.read_text(encoding="utf-8"))
|
||
assert isinstance(d.get("guards"), dict), "verdict 应含九门 guards"
|
||
|
||
|
||
if __name__ == "__main__":
|
||
_fns = [v for k, v in sorted(globals().items()) if k.startswith("test_") and callable(v)]
|
||
_failed = 0
|
||
for _fn in _fns:
|
||
try:
|
||
_fn()
|
||
print(f" PASS {_fn.__name__}")
|
||
except Exception as e: # noqa: BLE001
|
||
_failed += 1
|
||
print(f" FAIL {_fn.__name__}: {type(e).__name__}: {e}")
|
||
print(f"\n{len(_fns) - _failed}/{len(_fns)} passed")
|
||
sys.exit(1 if _failed else 0)
|