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>
86 lines
4.1 KiB
Python
86 lines
4.1 KiB
Python
"""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
|