feat(orc): centralize host-aware routing

This commit is contained in:
2026-08-01 20:04:55 +08:00
parent 34bbb97406
commit f5bf35c722
9 changed files with 499 additions and 275 deletions
+133 -105
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Validate ORC config and build a worktree-bound Codex launch plan."""
"""Validate shared ORC config and build a worktree-bound Agent launch plan."""
from __future__ import annotations
@@ -18,16 +18,17 @@ from typing import Any
LEVELS = ("low", "mid", "high")
STAGES = ("code", "release", "deb", "docker")
CLIS = ("codex", "cursor-agent")
EXPECTED_EFFORT = {"low": "low", "mid": "medium", "high": "high"}
TOP_LEVEL_KEYS = {
"version",
"cliPolicy",
"defaultLevel",
"stageDefaults",
"allowedWorktrees",
"worktreePolicy",
"profiles",
}
PROFILE_KEYS = {
"cli",
"model",
"reasoningEffort",
"permissionMode",
@@ -37,7 +38,7 @@ MODEL_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}\Z")
MAX_CONFIG_SIZE = 64 * 1024
MAX_CONTROL_OUTPUT = 64 * 1024
CONTROL_TIMEOUT_SECONDS = 15
CONFIG_RELATIVE_PATH = Path("docs/orc/config.yaml")
SHARED_CONFIG_PATH = Path(__file__).resolve().parents[1] / "config.yaml"
COMMON_ENVIRONMENT_NAMES = {
"COLORTERM",
"LANG",
@@ -50,6 +51,16 @@ MODEL_AUTH_ENVIRONMENT = {
"codex-login": frozenset(),
"openai": frozenset({"OPENAI_API_KEY"}),
"azure-openai": frozenset({"AZURE_OPENAI_API_KEY"}),
"cursor-login": frozenset(),
"cursor-api-key": frozenset({"CURSOR_API_KEY"}),
}
CLI_MODEL_AUTH = {
"codex": frozenset({"codex-login", "openai", "azure-openai"}),
"cursor-agent": frozenset({"cursor-login", "cursor-api-key"}),
}
DEFAULT_MODEL_AUTH = {
"codex": "codex-login",
"cursor-agent": "cursor-login",
}
REMOTE_AUTH_ENVIRONMENT = {
"none": frozenset(),
@@ -169,9 +180,11 @@ def validate_config(document: Any) -> dict[str, Any]:
_exact_keys(config, required=TOP_LEVEL_KEYS, path="config")
version = config["version"]
if isinstance(version, bool) or version != 1:
raise ConfigError("version must be integer 1")
if isinstance(version, bool) or version != 2:
raise ConfigError("version must be integer 2")
if config["cliPolicy"] != "current-host":
raise ConfigError("cliPolicy must be current-host in ORC v2")
_enum(config["defaultLevel"], LEVELS, "defaultLevel")
stage_defaults = _mapping(config["stageDefaults"], "stageDefaults")
@@ -183,53 +196,51 @@ def validate_config(document: Any) -> dict[str, Any]:
for stage, level in stage_defaults.items():
_enum(level, LEVELS, f"stageDefaults.{stage}")
allowed = config["allowedWorktrees"]
if not isinstance(allowed, list) or not allowed:
raise ConfigError("allowedWorktrees must be a non-empty list")
seen_worktrees: set[str] = set()
for index, entry in enumerate(allowed):
if (
not isinstance(entry, str)
or not entry
or entry != entry.strip()
or any(character in entry for character in ("\x00", "\n", "\r"))
):
raise ConfigError(
f"allowedWorktrees[{index}] must be a safe non-empty path"
)
if entry != "." and not Path(entry).is_absolute():
raise ConfigError(
f"allowedWorktrees[{index}] must be '.' or an absolute path"
)
normalized = entry if entry == "." else str(Path(entry).absolute())
if normalized in seen_worktrees:
raise ConfigError(f"allowedWorktrees contains duplicate path: {entry}")
seen_worktrees.add(normalized)
if config["worktreePolicy"] != "registered-same-repository":
raise ConfigError(
"worktreePolicy must be registered-same-repository in ORC v2"
)
profiles = _mapping(config["profiles"], "profiles")
_exact_keys(profiles, required=set(LEVELS), path="profiles")
for level in LEVELS:
profile = _mapping(profiles[level], f"profiles.{level}")
_exact_keys(profile, required=PROFILE_KEYS, path=f"profiles.{level}")
if profile["cli"] != "codex":
raise ConfigError(f"profiles.{level}.cli must be codex in ORC v1")
model = profile["model"]
if not isinstance(model, str) or not MODEL_RE.fullmatch(model):
raise ConfigError(f"profiles.{level}.model is not a safe exact model ID")
expected_effort = EXPECTED_EFFORT[level]
if profile["reasoningEffort"] != expected_effort:
raise ConfigError(
f"profiles.{level}.reasoningEffort must be {expected_effort}"
)
if profile["permissionMode"] != "workspace-write":
raise ConfigError(
f"profiles.{level}.permissionMode must be workspace-write in ORC v1"
)
_enum(
profile["approvalPolicy"],
{"untrusted", "on-request", "never"},
f"profiles.{level}.approvalPolicy",
)
_exact_keys(profiles, required=set(CLIS), path="profiles")
for cli in CLIS:
cli_profiles = _mapping(profiles[cli], f"profiles.{cli}")
_exact_keys(cli_profiles, required=set(LEVELS), path=f"profiles.{cli}")
for level in LEVELS:
path = f"profiles.{cli}.{level}"
profile = _mapping(cli_profiles[level], path)
_exact_keys(profile, required=PROFILE_KEYS, path=path)
model = profile["model"]
if not isinstance(model, str) or not MODEL_RE.fullmatch(model):
raise ConfigError(f"{path}.model is not a safe exact model ID")
if cli == "codex":
expected_effort = EXPECTED_EFFORT[level]
if profile["reasoningEffort"] != expected_effort:
raise ConfigError(
f"{path}.reasoningEffort must be {expected_effort}"
)
_enum(
profile["approvalPolicy"],
{"untrusted", "on-request", "never"},
f"{path}.approvalPolicy",
)
else:
if profile["reasoningEffort"] is not None:
raise ConfigError(f"{path}.reasoningEffort: Cursor requires null")
model_tokens = set(re.split(r"[^a-z0-9]+", model.lower()))
expected_token = "medium" if level == "mid" else level
if model != "auto" and expected_token not in model_tokens:
raise ConfigError(
f"{path}.model must encode the {expected_token} effort level"
)
if profile["approvalPolicy"] != "auto-review":
raise ConfigError(
f"{path}.approvalPolicy must be auto-review for Cursor"
)
if profile["permissionMode"] != "workspace-write":
raise ConfigError(
f"{path}.permissionMode must be workspace-write in ORC v2"
)
return config
@@ -260,7 +271,8 @@ def resolve_profile(
stage: str,
global_level: str | None = None,
stage_level: str | None = None,
model_auth: str = "codex-login",
host_cli: str | None = None,
model_auth: str | None = None,
remote_auth: str = "none",
) -> dict[str, Any]:
_enum(stage, STAGES, "stage")
@@ -268,9 +280,19 @@ def resolve_profile(
_enum(global_level, LEVELS, "global level")
if stage_level is not None:
_enum(stage_level, LEVELS, "stage level")
_enum(model_auth, set(MODEL_AUTH_ENVIRONMENT), "model auth")
_enum(remote_auth, STAGE_REMOTE_AUTH[stage], f"{stage} remote auth")
if host_cli is None:
raise ConfigError("host CLI is required; resolve it from the current Agent")
selected_cli = _enum(host_cli, CLIS, "host CLI")
cli_source = "runtime.host"
selected_auth = model_auth or DEFAULT_MODEL_AUTH[selected_cli]
_enum(selected_auth, set(MODEL_AUTH_ENVIRONMENT), "model auth")
if selected_auth not in CLI_MODEL_AUTH[selected_cli]:
raise ConfigError(
f"model auth {selected_auth} is not valid for {selected_cli}"
)
if stage_level is not None:
level, source = stage_level, "request.stage"
elif global_level is not None:
@@ -280,25 +302,36 @@ def resolve_profile(
else:
level, source = config["defaultLevel"], "config.defaultLevel"
profile = config["profiles"].get(level)
profile = config["profiles"][selected_cli].get(level)
if profile is None:
raise ConfigError(f"requested profile does not exist: {level}")
worker_args = [
"--model",
profile["model"],
"-c",
f'model_reasoning_effort="{profile["reasoningEffort"]}"',
"--sandbox",
profile["permissionMode"],
"--ask-for-approval",
profile["approvalPolicy"],
"--strict-config",
]
raise ConfigError(f"requested profile does not exist: {selected_cli}/{level}")
if selected_cli == "codex":
worker_args = [
"--model",
profile["model"],
"-c",
f'model_reasoning_effort="{profile["reasoningEffort"]}"',
"--sandbox",
profile["permissionMode"],
"--ask-for-approval",
profile["approvalPolicy"],
"--strict-config",
]
else:
worker_args = [
"--model",
profile["model"],
"--auto-review",
"--sandbox",
"enabled",
]
return {
"stage": stage,
"cli": selected_cli,
"cliSelectionSource": cli_source,
"level": level,
"selectionSource": source,
"modelAuth": model_auth,
"modelAuth": selected_auth,
"remoteAuth": remote_auth,
"profile": dict(profile),
"workerArgs": worker_args,
@@ -400,7 +433,7 @@ def _trusted_executable(path: Path, expected_name: str) -> Path | None:
def resolve_trusted_executable(name: str) -> Path:
if name not in {"codex", "git", "orca"}:
if name not in {"codex", "cursor-agent", "git", "orca"}:
raise ConfigError(f"unsupported executable: {name}")
search_paths = trusted_path_entries()
if name == "git":
@@ -572,17 +605,10 @@ def validate_worktree(
except ConfigError:
continue
allowed: set[Path] = set()
for entry in config["allowedWorktrees"]:
allowed.add(
project_root
if entry == "."
else canonical_directory(entry, "allowed worktree")
)
if not allowed <= registered:
raise ConfigError("allowedWorktrees contains an unregistered Git worktree")
if worktree not in allowed:
raise ConfigError("target worktree is not in allowedWorktrees")
if config["worktreePolicy"] != "registered-same-repository":
raise ConfigError("unsupported worktree policy")
if worktree not in registered:
raise ConfigError("target worktree is not registered in the project repository")
target_top = canonical_directory(
_run_control(
@@ -631,7 +657,7 @@ def _file_facts(path: Path) -> dict[str, Any]:
def _executable_facts(path: Path) -> dict[str, Any]:
return {
**_file_facts(path),
"version": _run_control([str(path), "--version"], "Codex version check"),
"version": _run_control([str(path), "--version"], "Agent CLI version check"),
}
@@ -663,22 +689,19 @@ def _fingerprint(value: dict[str, Any]) -> str:
def build_launch_plan(
config_path: Path,
*,
project_root: str | Path,
worktree: str | Path,
stage: str,
host_cli: str,
global_level: str | None = None,
stage_level: str | None = None,
model_auth: str = "codex-login",
model_auth: str | None = None,
remote_auth: str = "none",
) -> dict[str, Any]:
project = canonical_directory(project_root, "project root")
expected_config = project / CONFIG_RELATIVE_PATH
if config_path.absolute() != expected_config:
raise ConfigError(f"config path must be {expected_config}")
_assert_no_symlink_components(expected_config, "config path")
config, config_snapshot = load_config_snapshot(expected_config)
_assert_no_symlink_components(SHARED_CONFIG_PATH, "shared config path")
config, config_snapshot = load_config_snapshot(SHARED_CONFIG_PATH)
worktree_facts = validate_worktree(
config,
project_root_value=project,
@@ -689,16 +712,17 @@ def build_launch_plan(
stage=stage,
global_level=global_level,
stage_level=stage_level,
host_cli=host_cli,
model_auth=model_auth,
remote_auth=remote_auth,
)
selected_credential_names(
stage,
model_auth=model_auth,
model_auth=profile["modelAuth"],
remote_auth=remote_auth,
)
codex = resolve_trusted_executable("codex")
executable = _executable_facts(codex)
agent_cli = resolve_trusted_executable(profile["cli"])
executable = _executable_facts(agent_cli)
orca = resolve_trusted_executable("orca")
orca_executable = _file_facts(orca)
python = resolve_trusted_python()
@@ -710,7 +734,7 @@ def build_launch_plan(
**profile,
**worktree_facts,
"config": {
"path": str(expected_config),
"path": str(SHARED_CONFIG_PATH),
**config_snapshot,
},
"executable": executable,
@@ -726,14 +750,15 @@ def build_launch_plan(
},
}
fingerprint = _fingerprint(launch_facts)
worker_argv = [str(codex), *profile["workerArgs"]]
worker_argv = [str(agent_cli), *profile["workerArgs"]]
if profile["cli"] == "cursor-agent":
worker_argv.extend(["--workspace", str(worktree_facts["worktree"])])
launcher_argv = [
str(python),
"-I",
"-S",
str(script),
"_launch",
str(expected_config),
"--project-root",
str(project),
"--worktree",
@@ -747,13 +772,17 @@ def build_launch_plan(
launcher_argv.extend(["--global-level", global_level])
if stage_level is not None:
launcher_argv.extend(["--stage-level", stage_level])
if model_auth != "codex-login":
launcher_argv.extend(["--host-cli", host_cli])
if model_auth is not None:
launcher_argv.extend(["--model-auth", model_auth])
if remote_auth != "none":
launcher_argv.extend(["--remote-auth", remote_auth])
terminal_command = shlex.join(launcher_argv)
worktree_selector = "path:" + str(worktree_facts["worktree"])
terminal_title = f"ORC-{stage}-{profile['level']}-{fingerprint[7:15]}"
cli_label = "CODEX" if profile["cli"] == "codex" else "CURSOR"
terminal_title = (
f"ORC-{stage}-{cli_label}-{profile['level']}-{fingerprint[7:15]}"
)
terminal_create_argv = [
str(orca),
"terminal",
@@ -781,10 +810,10 @@ def build_launch_plan(
def execute_launch(args: argparse.Namespace) -> int:
plan = build_launch_plan(
args.config,
project_root=args.project_root,
worktree=args.worktree,
stage=args.stage,
host_cli=args.host_cli,
global_level=args.global_level,
stage_level=args.stage_level,
model_auth=args.model_auth,
@@ -802,7 +831,7 @@ def execute_launch(args: argparse.Namespace) -> int:
raise ConfigError("Python executable changed before launch")
executable = Path(plan["executable"]["path"])
if _executable_facts(executable) != plan["executable"]:
raise ConfigError("Codex executable changed before launch")
raise ConfigError("Agent CLI executable changed before launch")
try:
os.execve(
executable,
@@ -814,21 +843,20 @@ def execute_launch(args: argparse.Namespace) -> int:
),
)
except OSError as exc:
raise ConfigError("Codex worker could not be launched") from exc
raise ConfigError("Agent worker could not be launched") from exc
return 1 # pragma: no cover - os.execve does not return on success
def _add_resolution_arguments(parser: argparse.ArgumentParser) -> None:
parser.add_argument("config", type=Path)
parser.add_argument("--project-root", required=True)
parser.add_argument("--worktree", required=True)
parser.add_argument("--stage", required=True, choices=STAGES)
parser.add_argument("--global-level", choices=LEVELS)
parser.add_argument("--stage-level", choices=LEVELS)
parser.add_argument("--host-cli", required=True, choices=CLIS)
parser.add_argument(
"--model-auth",
choices=tuple(MODEL_AUTH_ENVIRONMENT),
default="codex-login",
)
parser.add_argument(
"--remote-auth",
@@ -842,8 +870,6 @@ def build_parser() -> argparse.ArgumentParser:
subparsers = parser.add_subparsers(dest="command", required=True)
validate = subparsers.add_parser("validate", help="validate config only")
validate.add_argument("config", type=Path)
resolve = subparsers.add_parser("resolve", help="resolve a bound launch plan")
_add_resolution_arguments(resolve)
@@ -857,20 +883,22 @@ def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
try:
if args.command == "validate":
config = load_config(args.config)
config = load_config(SHARED_CONFIG_PATH)
result: dict[str, Any] = {
"ok": True,
"config": str(args.config.absolute()),
"config": str(SHARED_CONFIG_PATH),
"clis": list(CLIS),
"levels": list(LEVELS),
"stages": list(STAGES),
"cliPolicy": config["cliPolicy"],
"defaultLevel": config["defaultLevel"],
}
elif args.command == "resolve":
result = build_launch_plan(
args.config,
project_root=args.project_root,
worktree=args.worktree,
stage=args.stage,
host_cli=args.host_cli,
global_level=args.global_level,
stage_level=args.stage_level,
model_auth=args.model_auth,