zizi 856a583325 feat(tier2): Phaser 自治生成引擎全栈首落(workflow 9 agent 建·6c6g 静态全过)
override spike-first(创始人 06-23 裁),全栈铺 Phaser tier2 引擎。recon→契约→6模块并行→集成 workflow 产出 ~60 文件,全 6c6g 静态校验过、红线零碰 Tier0/1 产线:
- 契约(6):tier2-source-project.schema / tier2-verdict.schema(fork·round放开·三层校验+富游戏门)/ toolkit 签名 / 探针钩子 / boot-phaser-host.d.ts / mini-肥鹅 fixture 规格
- M1 Phaser scaffold+装载 host+引擎能力面(19;logic-smoke 13/13:五耦合点真接线+赢输双路径+latch不回弹)
- M2 CDP 探针 Phaser 重写+business-sim driver+九门+富游戏三门(5;verdict 过 schema)
- M3 Python 单写 ReAct agent loop+9 工具 toolkit+M3 Anthropic接法+四熔断(9;mini-desktop 真 2.0.2 venv 验:import/9工具/中间件注册 OK)
- M4 datatable schema+金标+资产占位(4)/ M5 prompt+Phaser skill+rag(13)/ M6 成本 RecordingChatModel+trace adapter(3)
- 集成:run_engine.py 入口 + 接线断点已修 + RUN-ON-MINI-DESKTOP.md

待 mini-desktop 真跑(esbuild build + CDP 九门 + M3 生成 = 本质即 0号 spike)。AgentScope 2.0.2 API 逐条对 /root/oss/agentscope 源码核验。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 20:13:44 +00:00

86 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""client.py —— tier2 富游戏自治线 · new-api 凭据加载 + 代理旁路工具。
职责tier2 .agent 红线:复用只走显式传参,绝不读 wg1 模块级全局):
① 从环境 / 本地 .env 读 NEWAPI_KEY(密钥绝不硬编码进源码,只入 docs/内网凭据与端点.md 或 env);
② 把 new-api 网关 host 并入 NO_PROXY —— 必须在 import anthropic / openai / httpx 之前调用,
否则本机 clash 代理(HTTP(S)_PROXY)会把发往内网网关(100.64.0.8)的请求转走 → 502
(wg1 spike VERDICT 头号坑;tier2 走 AgentScope AnthropicChatModel 内部用 anthropic SDK + httpx,同样中招)。
与 wg1/_client.py 的区别(tier2 纪律):
- wg1 的 BASE_URL / DEFAULT_MODEL 是模块级全局,且默认带 /v1(OpenAI 兼容路);
- tier2 不在这里写死任何 base_url —— base_url / model / max_tokens / thinking 预算全部由调用方
(config.build_model)显式传参。本模块只提供「读 key」与「装代理旁路」两个纯工具函数。
- M3 走 Anthropic 原生 /v1/messages:anthropic SDK 拿到的 base_url 是 host 根
(http://100.64.0.8:3000),SDK 自己拼 /v1/messages —— 故 base_url 不带 /v1
(区别于 OpenAI 兼容路要带 /v1,见 docs/内网凭据与端点.md line 11-15)。
"""
import os
from pathlib import Path
from urllib.parse import urlparse
# ── new-api 网关默认端点(host 根,Anthropic 原生路;凭据见 docs/内网凭据与端点.md)──
# 可被环境变量 NEWAPI_BASE_URL 覆盖。注意:这是 host 根、不带 /v1
# (Anthropic SDK 内部自拼 /v1/messages;OpenAI 兼容路才要带 /v1)。
DEFAULT_NEWAPI_BASE_URL = "http://100.64.0.8:3000"
# 本地 .env 加载点:tier2/gen-worker/.env(gitignored,密钥外置不落代码)。
# 本文件在 tier2/gen-worker/worker/client.py → .env 在上一级 gen-worker/。
_ENV_PATH = Path(__file__).resolve().parent.parent / ".env"
def load_env() -> None:
"""把 tier2/gen-worker/.env 里的 KEY=VAL 注入环境(已存在的不覆盖)。
.env 缺失则静默返回(CI / 6c6g 上可能用真 env;mini-desktop 真跑前先写 .env 或 export)。
"""
if not _ENV_PATH.exists():
return
for line in _ENV_PATH.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
# setdefault:已经在真实环境里设过的 key 优先,不被 .env 覆盖。
os.environ.setdefault(k.strip(), v.strip())
def install_proxy_bypass(base_url: str) -> str:
"""把 base_url 的 host 并入大小写两个 NO_PROXY,返回该 host。
必须在 import anthropic / openai / httpx **之前**调用 —— httpx(trust_env=True)
默认吃 HTTP(S)_PROXY,会把发往内网网关的请求经 clash 代理转发 → 502。
把网关 host 写进 NO_PROXY 才直连(wg1 spike VERDICT §4-坑1 同款)。
"""
host = urlparse(base_url).hostname or "100.64.0.8"
for key in ("NO_PROXY", "no_proxy"):
cur = os.environ.get(key, "")
if host not in cur:
os.environ[key] = (cur + "," + host) if cur else host
return host
def get_api_key() -> str:
"""读 NEWAPI_KEY(缺失即抛 —— 密钥不入库,真跑前先写 .env 或 export)。
key 的权威来源 = docs/内网凭据与端点.md(NEWAPI_KEY);本函数只从环境读,绝不在代码里写死值。
"""
load_env()
key = os.environ.get("NEWAPI_KEY")
if not key:
raise RuntimeError(
"NEWAPI_KEY 未设:请在 tier2/gen-worker/.env 写入,或 export NEWAPI_KEY=...;"
"权威来源见 docs/内网凭据与端点.md。"
)
return key
def resolve_base_url(explicit: str | None = None) -> str:
"""决定 new-api base_url(host 根):显式入参 > 环境 NEWAPI_BASE_URL > 默认端点。
决定后立刻装好代理旁路(把 host 并入 NO_PROXY),保证后续 import anthropic 直连网关。
"""
base_url = explicit or os.environ.get("NEWAPI_BASE_URL") or DEFAULT_NEWAPI_BASE_URL
install_proxy_bypass(base_url)
return base_url