feat(agent-runtime): unify agent bindings and sessions
This commit is contained in:
@@ -13,6 +13,11 @@ description: >-
|
||||
开始时解析本 `SKILL.md` 所在目录为 `<skill-dir>`。项目根用
|
||||
`git rev-parse --show-toplevel`。目录固定为 `<root>/.pouch/tester/`。
|
||||
|
||||
Agent 执行目标优先来自项目根 `.pouch/agent.yaml` 的 `tester.<name>` binding,由共享
|
||||
`agent-runtime` 解析 environment、host、project、path 和 profile。`.pouch/tester/local.yaml`
|
||||
仍是兼容覆盖层:解析 binding 后可 materialize 为旧 `agent` mapping,但不应再维护两套
|
||||
互相矛盾的主配置;binding 名称不是固定枚举。
|
||||
|
||||
用脚本读写目录,不要把 `cases/` 整库灌进上下文。术语与命名理由见 [references/concepts.md](references/concepts.md):
|
||||
|
||||
```bash
|
||||
@@ -24,6 +29,9 @@ python3 <skill-dir>/scripts/catalog.py <list|select|show|validate|next-id|run-sc
|
||||
`.pouch/tester/local.yaml` 的 `agent` 配置;配置更新完成后输出生效配置列表。该列表是
|
||||
更新结果,不是测试启动前的人工确认门槛。
|
||||
|
||||
用户给出 `tester.<name>` 时,先用共享 `agent-runtime` 校验并精确解析,再写入兼容的
|
||||
tester agent 配置。
|
||||
|
||||
## 选择模式
|
||||
|
||||
- 还没有 `.pouch/tester/catalog.yaml`,或用户说初始化 tester:执行「初始化」。
|
||||
|
||||
@@ -6,6 +6,20 @@
|
||||
|
||||
## 配置
|
||||
|
||||
推荐在项目根统一配置:
|
||||
|
||||
```yaml
|
||||
bindings:
|
||||
tester.test:
|
||||
adapter: tester
|
||||
location: local-app
|
||||
profile: test-agent
|
||||
```
|
||||
|
||||
`locations` 和 `profiles` 的定义见共享 `agent-runtime`。tester adapter 只把它 materialize
|
||||
到本轮兼容配置;每轮 terminal 仍然新建并在结束时关闭,不能因为 binding 是 persistent
|
||||
就复用测试 terminal。
|
||||
|
||||
`catalog.yaml` 提供可提交的默认值,`.pouch/tester/local.yaml` 可以覆盖同名字段。
|
||||
机器名、远程环境、项目路径和 Agent 选择优先写在 `local.yaml`,不要把个人机器路径
|
||||
或临时 Agent 选择提交到项目。
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -176,6 +177,41 @@ def clean_config(config: dict[str, Any]) -> dict[str, Any]:
|
||||
return {key: value for key, value in config.items() if not key.startswith("_")}
|
||||
|
||||
|
||||
def config_from_binding(root: Path, selector: str) -> dict[str, Any]:
|
||||
"""Materialize a common agent-runtime tester binding for legacy local.yaml."""
|
||||
|
||||
runtime_path = Path(__file__).resolve().parents[2] / "skills" / "agent-runtime" / "scripts" / "agent.py"
|
||||
if not runtime_path.is_file():
|
||||
raise RuntimeError(f"找不到共享 agent-runtime: {runtime_path}")
|
||||
spec = importlib.util.spec_from_file_location("pouch_agent_runtime", runtime_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"无法加载共享 agent-runtime: {runtime_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
try:
|
||||
common = module.load_config(root)
|
||||
value = module.binding(common, selector)
|
||||
except (ValueError, OSError) as exc:
|
||||
raise RuntimeError(str(exc)) from exc
|
||||
if value.get("adapter") != "tester":
|
||||
raise RuntimeError(f"binding {selector} 的 adapter 不是 tester")
|
||||
location = value["location"]
|
||||
profile = value["profile"]
|
||||
return {
|
||||
"environment": "" if location.get("environment") == "local" else str(location.get("environment") or ""),
|
||||
"host": str(location.get("host") or "local"),
|
||||
"project": str(location.get("project") or ""),
|
||||
"path": str(location.get("path") or ""),
|
||||
"role": "test",
|
||||
"cli": str(profile.get("cli") or "codex"),
|
||||
"tier": str(profile.get("tier") or "standard"),
|
||||
"model": profile.get("model"),
|
||||
"reasoningEffort": profile.get("reasoningEffort"),
|
||||
"permissionMode": str(profile.get("permissionMode") or "workspace-write"),
|
||||
"_source": f"binding:{selector}",
|
||||
}
|
||||
|
||||
|
||||
def write_local(root: Path, config: dict[str, Any]) -> tuple[Path, dict[str, Any]]:
|
||||
path = root / ".pouch" / "tester" / "local.yaml"
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
@@ -233,16 +269,21 @@ def main(argv: list[str] | None = None) -> int:
|
||||
source = parser.add_mutually_exclusive_group(required=True)
|
||||
source.add_argument("--terminal", help="Orca terminal handle")
|
||||
source.add_argument("--project", help="Orca project id、名称或路径")
|
||||
source.add_argument("--binding", help="common agent.yaml 中的 tester.<name> binding")
|
||||
parser.add_argument("--path", help="项目有多个 worktree 时按目标机器上的绝对路径消歧")
|
||||
parser.add_argument("--environment", help="限定 Orca environment")
|
||||
parser.add_argument("--write", action="store_true", help="写入 .pouch/tester/local.yaml")
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
config = (
|
||||
config_from_terminal(args.terminal, args.environment)
|
||||
if args.terminal
|
||||
else config_from_project(args.project, args.environment, args.path)
|
||||
)
|
||||
root = Path(args.root).resolve()
|
||||
if args.binding:
|
||||
config = config_from_binding(root, args.binding)
|
||||
else:
|
||||
config = (
|
||||
config_from_terminal(args.terminal, args.environment)
|
||||
if args.terminal
|
||||
else config_from_project(args.project, args.environment, args.path)
|
||||
)
|
||||
if args.write:
|
||||
path, saved_agent = write_local(Path(args.root).resolve(), config)
|
||||
config = {**config, **saved_agent}
|
||||
|
||||
Reference in New Issue
Block a user