refactor(input): bake codex cli runtime
This commit is contained in:
@@ -20,12 +20,12 @@ cd input/Docker
|
|||||||
./run-input-processor.sh up -d
|
./run-input-processor.sh up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Environment variables you can pass before the command:
|
- Environment variables you can pass before the command:
|
||||||
- `CODEX_COMMAND_TEMPLATE` – override the Codex CLI invocation for the resume customization run (defaults to `codex prompt --input {prompt} --output {output} --format markdown`).
|
- `POLL_INTERVAL_SECONDS` – watcher polling cadence (default `5`).
|
||||||
- `CODEX_NORMALIZER_COMMAND_TEMPLATE` – optional override for the job-description normalization run (defaults to the same value as `CODEX_COMMAND_TEMPLATE`).
|
- `CODEX_TIMEOUT_SECONDS` – hard timeout for Codex calls (default `600`).
|
||||||
- `POLL_INTERVAL_SECONDS` – watcher polling cadence (default `5`).
|
- `CODEX_CONFIG_DIR` – optional override for the host directory that should mount into `/home/codex/.codex`.
|
||||||
- `CODEX_TIMEOUT_SECONDS` – hard timeout for Codex calls (default `600`).
|
|
||||||
- `CODEX_CONFIG_DIR` – optional override for the host directory that should mount into `/home/codex/.codex`.
|
The container bundles the Codex CLI and expects the caller to mount their `~/.codex` directory for credentials.
|
||||||
|
|
||||||
Stop or inspect the stack with:
|
Stop or inspect the stack with:
|
||||||
|
|
||||||
@@ -44,4 +44,4 @@ cd input/Docker
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
- If Codex CLI fails, the job description moves to `ForCustomizing/failed/`. Check container logs, adjust the Markdown, then requeue it.
|
- If Codex CLI fails, the job description moves to `ForCustomizing/failed/`. Check container logs, adjust the Markdown, then requeue it.
|
||||||
- Fatal errors (multiple resumes, multiple job descriptions, missing template, or missing Codex binary) stop the container. Resolve the issue and restart via the wrapper.
|
- Fatal errors (multiple resumes, multiple job descriptions, missing template, or missing Codex binary) stop the container. Resolve the issue and restart via the wrapper.
|
||||||
- To change the Codex command format, pass a quoted template (e.g., `CODEX_COMMAND_TEMPLATE='codex run --input {prompt} --output {output}' ./run-input-processor.sh up -d'`). The template must include `{prompt}` and `{output}` placeholders.
|
- The watcher logs the exact `codex prompt --input … --output … --format markdown` command before each invocation; inspect container logs if troubleshooting is needed.
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ RUN apt-get update \
|
|||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN npm install --location=global codex-cli || true
|
# Install the official Codex CLI so the container can invoke `codex prompt`.
|
||||||
|
# The CLI expects credentials/configuration from the mounted ~/.codex directory.
|
||||||
|
RUN npm install --location=global @openai/codex
|
||||||
|
|
||||||
RUN groupadd -r codex && \
|
RUN groupadd -r codex && \
|
||||||
useradd -r -m -g codex -s /bin/bash codex
|
useradd -r -m -g codex -s /bin/bash codex
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ services:
|
|||||||
PGID: "${LOCAL_GID:-1000}"
|
PGID: "${LOCAL_GID:-1000}"
|
||||||
POLL_INTERVAL_SECONDS: "${POLL_INTERVAL_SECONDS:-5}"
|
POLL_INTERVAL_SECONDS: "${POLL_INTERVAL_SECONDS:-5}"
|
||||||
CODEX_TIMEOUT_SECONDS: "${CODEX_TIMEOUT_SECONDS:-600}"
|
CODEX_TIMEOUT_SECONDS: "${CODEX_TIMEOUT_SECONDS:-600}"
|
||||||
CODEX_COMMAND_TEMPLATE: "${CODEX_COMMAND_TEMPLATE:-codex prompt --input {prompt} --output {output} --format markdown}"
|
|
||||||
CODEX_NORMALIZER_COMMAND_TEMPLATE: "${CODEX_NORMALIZER_COMMAND_TEMPLATE:-codex prompt --input {prompt} --output {output} --format markdown}"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ../ForCustomizing/inbox:/workspace/inbox
|
- ../ForCustomizing/inbox:/workspace/inbox
|
||||||
- ../ForCustomizing/outbox:/workspace/outbox
|
- ../ForCustomizing/outbox:/workspace/outbox
|
||||||
@@ -22,3 +20,4 @@ services:
|
|||||||
- ../resume:/workspace/resume:ro
|
- ../resume:/workspace/resume:ro
|
||||||
- ../templates:/templates:ro
|
- ../templates:/templates:ro
|
||||||
- ${CODEX_CONFIG_DIR:-/workspace/.codex}:/home/codex/.codex
|
- ${CODEX_CONFIG_DIR:-/workspace/.codex}:/home/codex/.codex
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shlex
|
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
@@ -32,17 +31,9 @@ TEMPLATES_DIR = Path("/templates")
|
|||||||
TEMPLATE_CACHE = Path("/tmp/templates")
|
TEMPLATE_CACHE = Path("/tmp/templates")
|
||||||
PROMPT_TEMPLATE = TEMPLATES_DIR / "ResumeCustomizerPrompt.md"
|
PROMPT_TEMPLATE = TEMPLATES_DIR / "ResumeCustomizerPrompt.md"
|
||||||
PROMPT_TEMPLATE_EXAMPLE = TEMPLATES_DIR / "ResumeCustomizerPrompt.md.example"
|
PROMPT_TEMPLATE_EXAMPLE = TEMPLATES_DIR / "ResumeCustomizerPrompt.md.example"
|
||||||
NORMALIZER_TEMPLATE = Path('/app/JobDescriptionNormalizerPrompt.md')
|
NORMALIZER_TEMPLATE = Path("/app/JobDescriptionNormalizerPrompt.md")
|
||||||
|
|
||||||
POLL_INTERVAL_SECONDS = int(os.environ.get("POLL_INTERVAL_SECONDS", "5"))
|
POLL_INTERVAL_SECONDS = int(os.environ.get("POLL_INTERVAL_SECONDS", "5"))
|
||||||
CODEX_COMMAND_TEMPLATE = os.environ.get(
|
|
||||||
"CODEX_COMMAND_TEMPLATE",
|
|
||||||
"codex prompt --input {prompt} --output {output} --format markdown",
|
|
||||||
)
|
|
||||||
CODEX_NORMALIZER_COMMAND_TEMPLATE = os.environ.get(
|
|
||||||
"CODEX_NORMALIZER_COMMAND_TEMPLATE",
|
|
||||||
CODEX_COMMAND_TEMPLATE,
|
|
||||||
)
|
|
||||||
CODEX_TIMEOUT_SECONDS = int(os.environ.get("CODEX_TIMEOUT_SECONDS", "600"))
|
CODEX_TIMEOUT_SECONDS = int(os.environ.get("CODEX_TIMEOUT_SECONDS", "600"))
|
||||||
|
|
||||||
RESOLVED_PROMPT_TEMPLATE: Path | None = None
|
RESOLVED_PROMPT_TEMPLATE: Path | None = None
|
||||||
@@ -193,20 +184,19 @@ def slugify(component: str) -> str:
|
|||||||
return "-".join(parts)
|
return "-".join(parts)
|
||||||
|
|
||||||
|
|
||||||
def run_codex(prompt_path: Path, output_path: Path, command_template: str) -> None:
|
def run_codex(prompt_path: Path, output_path: Path) -> None:
|
||||||
"""Execute the Codex CLI using the provided command template."""
|
"""Execute the Codex CLI."""
|
||||||
command_text = command_template.format(
|
command = [
|
||||||
prompt=str(prompt_path),
|
"codex",
|
||||||
output=str(output_path),
|
"prompt",
|
||||||
)
|
"--input",
|
||||||
logging.info("Running Codex CLI command: %s", command_text)
|
str(prompt_path),
|
||||||
|
"--output",
|
||||||
try:
|
str(output_path),
|
||||||
command = shlex.split(command_text)
|
"--format",
|
||||||
except ValueError as exc:
|
"markdown",
|
||||||
raise FatalConfigurationError(
|
]
|
||||||
f"Unable to parse Codex command template into arguments: {exc}"
|
logging.info("Running Codex CLI command: %s", " ".join(command))
|
||||||
) from exc
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
@@ -217,7 +207,7 @@ def run_codex(prompt_path: Path, output_path: Path, command_template: str) -> No
|
|||||||
)
|
)
|
||||||
except FileNotFoundError as exc:
|
except FileNotFoundError as exc:
|
||||||
raise FatalConfigurationError(
|
raise FatalConfigurationError(
|
||||||
f"Executable not found while running Codex CLI command: {command[0]}"
|
"Codex CLI executable 'codex' not found in PATH"
|
||||||
) from exc
|
) from exc
|
||||||
except subprocess.TimeoutExpired as exc:
|
except subprocess.TimeoutExpired as exc:
|
||||||
raise RuntimeError("Codex CLI timed out") from exc
|
raise RuntimeError("Codex CLI timed out") from exc
|
||||||
@@ -301,7 +291,7 @@ def normalize_job_description(job_file: Path) -> NormalizedJobDescription:
|
|||||||
prompt_path.write_text(prompt_text, encoding="utf-8")
|
prompt_path.write_text(prompt_text, encoding="utf-8")
|
||||||
|
|
||||||
output_path = tmp_dir / "normalize_output.md"
|
output_path = tmp_dir / "normalize_output.md"
|
||||||
run_codex(prompt_path, output_path, CODEX_NORMALIZER_COMMAND_TEMPLATE)
|
run_codex(prompt_path, output_path)
|
||||||
normalized_text = output_path.read_text(encoding="utf-8").strip()
|
normalized_text = output_path.read_text(encoding="utf-8").strip()
|
||||||
|
|
||||||
return parse_normalized_output(normalized_text)
|
return parse_normalized_output(normalized_text)
|
||||||
@@ -356,7 +346,7 @@ def process_job(job_file: Path) -> None:
|
|||||||
prompt_path.write_text(prompt_text, encoding="utf-8")
|
prompt_path.write_text(prompt_text, encoding="utf-8")
|
||||||
|
|
||||||
output_path = tmp_dir / "codex_output.md"
|
output_path = tmp_dir / "codex_output.md"
|
||||||
run_codex(prompt_path, output_path, CODEX_COMMAND_TEMPLATE)
|
run_codex(prompt_path, output_path)
|
||||||
|
|
||||||
generated_output = out_dir / output_filename
|
generated_output = out_dir / output_filename
|
||||||
counter = 1
|
counter = 1
|
||||||
|
|||||||
@@ -24,9 +24,11 @@ The watcher lives in `input/Docker/`:
|
|||||||
- `templates/ResumeCustomizerPrompt.md.example` ships with default resume-customization instructions. Copy it to `ResumeCustomizerPrompt.md` to override.
|
- `templates/ResumeCustomizerPrompt.md.example` ships with default resume-customization instructions. Copy it to `ResumeCustomizerPrompt.md` to override.
|
||||||
- The `.gitignore` in `templates/` keeps local overrides out of version control.
|
- The `.gitignore` in `templates/` keeps local overrides out of version control.
|
||||||
|
|
||||||
|
### Codex CLI
|
||||||
|
- The container image installs the official Codex CLI and expects credentials/configuration from the mounted `~/.codex` directory on the host.
|
||||||
|
- No additional command-line customization is required; the watcher invokes `codex prompt --input … --output … --format markdown` internally for both passes.
|
||||||
|
|
||||||
### Key Environment Variables
|
### Key Environment Variables
|
||||||
- `CODEX_COMMAND_TEMPLATE` – format string for the resume-customization Codex run (placeholders: `{prompt}`, `{output}`).
|
|
||||||
- `CODEX_NORMALIZER_COMMAND_TEMPLATE` – optional override for the normalization Codex run (defaults to `CODEX_COMMAND_TEMPLATE`).
|
|
||||||
- `POLL_INTERVAL_SECONDS` – watch loop delay (defaults to 5).
|
- `POLL_INTERVAL_SECONDS` – watch loop delay (defaults to 5).
|
||||||
- `CODEX_TIMEOUT_SECONDS` – wall-clock timeout for each Codex call (defaults to 600).
|
- `CODEX_TIMEOUT_SECONDS` – wall-clock timeout for each Codex call (defaults to 600).
|
||||||
- `CODEX_CONFIG_DIR` – host path to mount as `/home/codex/.codex` (defaults to `${HOME}/.codex` via the wrapper).
|
- `CODEX_CONFIG_DIR` – host path to mount as `/home/codex/.codex` (defaults to `${HOME}/.codex` via the wrapper).
|
||||||
|
|||||||
Reference in New Issue
Block a user