Add execution retry and emergency profile settings
Why: Routing needs an explicit per-profile attempt limit and a named Codex emergency profile before controller enforcement can be implemented. Evidence: The new parser test failed on unknown keys before implementation; all 15 config test executions now pass and git diff --check is clean. Impact: Adds backward-compatible optional configuration fields only; routing behavior is unchanged in this commit. Refs: feature/agent-cli-enforcement
This commit is contained in:
@@ -54,9 +54,13 @@ EXECUTION_KEYS = frozenset(
|
||||
"idle_timeout_seconds",
|
||||
"summary_bytes",
|
||||
"raw_output_bytes",
|
||||
"max_attempts_per_profile",
|
||||
"emergency_profile",
|
||||
}
|
||||
)
|
||||
EXECUTION_REQUIRED = EXECUTION_KEYS - frozenset({"idle_timeout_seconds"})
|
||||
EXECUTION_REQUIRED = EXECUTION_KEYS - frozenset(
|
||||
{"idle_timeout_seconds", "max_attempts_per_profile", "emergency_profile"}
|
||||
)
|
||||
PROFILE_KEYS = frozenset({"adapter", "executable", "model", "enabled"})
|
||||
CUSTOM_ADAPTER_KEYS = frozenset(
|
||||
{
|
||||
@@ -84,6 +88,8 @@ class ExecutionPolicy:
|
||||
summary_bytes: int
|
||||
raw_output_bytes: int
|
||||
idle_timeout_seconds: int = DEFAULT_IDLE_TIMEOUT_SECONDS
|
||||
max_attempts_per_profile: int = 1
|
||||
emergency_profile: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -391,6 +397,23 @@ def _build_execution(raw: Any) -> ExecutionPolicy:
|
||||
if raw_output_bytes < summary_bytes:
|
||||
raise ConfigError("raw_output_bytes must be >= summary_bytes")
|
||||
|
||||
if "max_attempts_per_profile" in raw:
|
||||
max_attempts_per_profile = _positive_bounded(
|
||||
raw["max_attempts_per_profile"],
|
||||
"max_attempts_per_profile",
|
||||
1,
|
||||
10,
|
||||
)
|
||||
else:
|
||||
max_attempts_per_profile = 1
|
||||
|
||||
if "emergency_profile" in raw:
|
||||
emergency_profile = raw["emergency_profile"]
|
||||
if not isinstance(emergency_profile, str) or not emergency_profile:
|
||||
raise ConfigError("emergency_profile must be a non-empty string")
|
||||
else:
|
||||
emergency_profile = None
|
||||
|
||||
return ExecutionPolicy(
|
||||
fresh_process_per_unit=True,
|
||||
permission=permission,
|
||||
@@ -400,6 +423,8 @@ def _build_execution(raw: Any) -> ExecutionPolicy:
|
||||
summary_bytes=summary_bytes,
|
||||
raw_output_bytes=raw_output_bytes,
|
||||
idle_timeout_seconds=idle_timeout_seconds,
|
||||
max_attempts_per_profile=max_attempts_per_profile,
|
||||
emergency_profile=emergency_profile,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -405,6 +405,35 @@ class AgentExecConfigTests(unittest.TestCase):
|
||||
with self.assertRaises(ConfigError):
|
||||
load_config(self.repo)
|
||||
|
||||
def test_exposes_max_attempts_per_profile_and_emergency_profile(self) -> None:
|
||||
block = MINIMAL_BLOCK.replace(
|
||||
" raw_output_bytes: 10485760\n",
|
||||
" raw_output_bytes: 10485760\n"
|
||||
" max_attempts_per_profile: 3\n"
|
||||
" emergency_profile: codex\n",
|
||||
).replace(
|
||||
" claude:\n"
|
||||
" adapter: claude\n"
|
||||
" executable: claude\n"
|
||||
" model: auto\n"
|
||||
" enabled: true\n",
|
||||
" claude:\n"
|
||||
" adapter: claude\n"
|
||||
" executable: claude\n"
|
||||
" model: auto\n"
|
||||
" enabled: true\n"
|
||||
"\n"
|
||||
" codex:\n"
|
||||
" adapter: codex\n"
|
||||
" executable: codex\n"
|
||||
" model: auto\n"
|
||||
" enabled: true\n",
|
||||
)
|
||||
write_repo(self.repo, block)
|
||||
cfg = load_config(self.repo)
|
||||
self.assertEqual(cfg.execution.max_attempts_per_profile, 3)
|
||||
self.assertEqual(cfg.execution.emergency_profile, "codex")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user