feat(nonlinear-static-newton-raphson): step 0 - cli-output-lease-and-derived-names
This commit is contained in:
+53
-2
@@ -66,8 +66,12 @@ class StepExecutor:
|
||||
"""Phase 디렉토리 안의 step들을 순차 실행하는 하네스."""
|
||||
|
||||
MAX_RETRIES = 3
|
||||
CODEX_TIMEOUT_SECONDS = 1800
|
||||
CODEX_SANDBOX_ENV = "FESA_HARNESS_CODEX_SANDBOX"
|
||||
CODEX_SANDBOX_MODES = frozenset({"workspace-write", "danger-full-access"})
|
||||
IMPLEMENTATION_AGENT_PROFILE = Path(
|
||||
".codex/agents/implementation-agent.toml"
|
||||
)
|
||||
FEAT_MSG = "feat({phase}): step {num} - {name}"
|
||||
CHORE_MSG = "chore({phase}): step {num} output"
|
||||
TZ = timezone(timedelta(hours=9))
|
||||
@@ -253,6 +257,35 @@ class StepExecutor:
|
||||
)
|
||||
return mode
|
||||
|
||||
def _implementation_agent_settings(self) -> tuple[str, str]:
|
||||
profile_path = Path(self._root) / self.IMPLEMENTATION_AGENT_PROFILE
|
||||
try:
|
||||
profile_lines = profile_path.read_text(encoding="utf-8").splitlines()
|
||||
except OSError as exc:
|
||||
raise CodexEnvironmentError(
|
||||
f"Implementation Agent profile을 읽을 수 없습니다: {profile_path}"
|
||||
) from exc
|
||||
|
||||
settings = {}
|
||||
for line in profile_lines:
|
||||
key, separator, value = line.partition("=")
|
||||
key = key.strip()
|
||||
if separator and key in {"model", "model_reasoning_effort"}:
|
||||
try:
|
||||
settings[key] = json.loads(value.strip())
|
||||
except json.JSONDecodeError as exc:
|
||||
raise CodexEnvironmentError(
|
||||
f"Implementation Agent profile의 {key} 값이 올바른 문자열이 아닙니다."
|
||||
) from exc
|
||||
|
||||
model = settings.get("model")
|
||||
reasoning_effort = settings.get("model_reasoning_effort")
|
||||
if not isinstance(model, str) or not isinstance(reasoning_effort, str):
|
||||
raise CodexEnvironmentError(
|
||||
"Implementation Agent profile에 model과 model_reasoning_effort 문자열이 필요합니다."
|
||||
)
|
||||
return model, reasoning_effort
|
||||
|
||||
def _invoke_codex(self, step: dict, preamble: str) -> dict:
|
||||
step_num, step_name = step["step"], step["name"]
|
||||
step_file = self._phase_dir / f"step{step_num}.md"
|
||||
@@ -262,12 +295,20 @@ class StepExecutor:
|
||||
sys.exit(1)
|
||||
|
||||
prompt = preamble + step_file.read_text(encoding="utf-8")
|
||||
sandbox_mode = self._codex_sandbox_mode()
|
||||
model, reasoning_effort = self._implementation_agent_settings()
|
||||
command = [
|
||||
"codex",
|
||||
"exec",
|
||||
"--disable",
|
||||
"unified_exec",
|
||||
"--json",
|
||||
"--model",
|
||||
model,
|
||||
"--config",
|
||||
f"model_reasoning_effort={json.dumps(reasoning_effort)}",
|
||||
"--sandbox",
|
||||
self._codex_sandbox_mode(),
|
||||
sandbox_mode,
|
||||
"--dangerously-bypass-hook-trust",
|
||||
"--cd",
|
||||
self._root,
|
||||
@@ -281,12 +322,22 @@ class StepExecutor:
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
timeout=1800,
|
||||
timeout=self.CODEX_TIMEOUT_SECONDS,
|
||||
)
|
||||
except FileNotFoundError as exc:
|
||||
raise CodexEnvironmentError(
|
||||
"Codex CLI를 찾을 수 없습니다. codex를 설치하고 PATH를 확인하세요."
|
||||
) from exc
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
timeout_message = f"Codex timed out after {exc.timeout} seconds."
|
||||
stderr = exc.stderr or ""
|
||||
if stderr:
|
||||
stderr = f"{timeout_message}\n{stderr}"
|
||||
else:
|
||||
stderr = timeout_message
|
||||
result = subprocess.CompletedProcess(
|
||||
command, 124, stdout=exc.stdout or "", stderr=stderr
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"\n WARN: Codex가 비정상 종료됨 (code {result.returncode})")
|
||||
|
||||
Reference in New Issue
Block a user