feat(cli): add codex init templates (sync / async / temporal)#436
Conversation
a92d37b to
ff359de
Compare
9d0ea68 to
a891d35
Compare
|
@greptile review |
ff359de to
e031d5d
Compare
a891d35 to
be6b158
Compare
|
@greptile review |
e031d5d to
8f7854a
Compare
be6b158 to
2eefec2
Compare
|
@greptile review |
8f7854a to
6e3f0cf
Compare
2eefec2 to
42db83c
Compare
|
@greptile review |
42db83c to
889f793
Compare
|
@greptile review |
889f793 to
ace66e2
Compare
|
@greptile review |
|
@greptile review |
47ea82c to
2003757
Compare
d489113 to
412b1c6
Compare
2003757 to
755d18e
Compare
412b1c6 to
3aaa35e
Compare
755d18e to
63904c2
Compare
3aaa35e to
5d5a0e8
Compare
63904c2 to
f819115
Compare
5d5a0e8 to
b5cbe37
Compare
f819115 to
4f2002c
Compare
Add default-codex, sync-codex and temporal-codex templates across all three tiers, wiring the new TemplateType entries into the init flow. Scaffolded code imports CodexTurn from the agentex.lib.adk facade. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Greptile review: wrap the streaming call in try/finally across the default, sync and temporal codex templates so the codex subprocess is killed and reaped even when auto_send_turn / yield_turn raises or the async generator is abandoned. Previously a failed turn left codex blocked on a full stdout pipe buffer, leaking an OS process per failure until the server/worker restarted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Greptile review: the default, sync and temporal codex Dockerfiles installed nodejs/npm but never the codex CLI, so scaffolded containers hit FileNotFoundError on `codex` for every request. Add `npm install -g @openai/codex`, matching the claude-code templates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Round-3 Greptile parity: the uv-path Dockerfile-uv.j2 variants (default, sync, temporal) installed node/npm but not the `codex` CLI. Mirror the npm install -g @openai/codex step already added to the pip Dockerfiles so use_uv=True containers are functional. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Round-5 Greptile review (parity with the claude-code fixes): - default/sync/temporal codex manifests now map OPENAI_API_KEY (the key the codex CLI actually reads) instead of LITELLM_API_KEY, and no longer set an empty-string env value that would shadow it at runtime. - temporal-codex workflow serializes signal turns with an asyncio.Lock so overlapping messages don't race on _codex_thread_id and fork the session. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
b5cbe37 to
e089205
Compare
| COPY {{ project_path_from_build_root }}/pyproject.toml {{ project_path_from_build_root }}/uv.lock ./ | ||
|
|
||
| # Install dependencies (without project itself, for layer caching) | ||
| RUN --mount=type=cache,target=/root/.cache/uv \ | ||
| uv sync --locked --no-install-project --no-dev |
There was a problem hiding this comment.
The uv Dockerfile requires uv.lock, but agentex init only renders pyproject.toml for uv projects and does not create a lockfile. A freshly scaffolded Codex project generated with the uv option can fail its Docker build at this COPY or at uv sync --locked before the agent starts. The same lockfile assumption should be fixed in the sync and Temporal Codex uv Dockerfiles.
Artifacts
Repro: scaffold render and Dockerfile COPY validation script
- Contains supporting evidence from the run (text/x-python; charset=utf-8).
Repro: generated scaffold listing and missing uv.lock COPY validation failure
- Keeps the command output available without making the summary code-heavy.
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/cli/templates/default-codex/Dockerfile-uv.j2
Line: 34-38
Comment:
**Missing generated lockfile**
The uv Dockerfile requires `uv.lock`, but `agentex init` only renders `pyproject.toml` for uv projects and does not create a lockfile. A freshly scaffolded Codex project generated with the uv option can fail its Docker build at this `COPY` or at `uv sync --locked` before the agent starts. The same lockfile assumption should be fixed in the sync and Temporal Codex uv Dockerfiles.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| task_state = await adk.state.get_by_task_and_agent(task_id=task_id, agent_id=agent_id) | ||
| if task_state is None: | ||
| state = ConversationState() | ||
| task_state = await adk.state.create(task_id=task_id, agent_id=agent_id, state=state) | ||
| else: | ||
| state = ConversationState.model_validate(task_state.state) | ||
|
|
||
| state.turn_number += 1 | ||
|
|
||
| async with adk.tracing.span( | ||
| trace_id=task_id, | ||
| task_id=task_id, | ||
| name=f"Turn {state.turn_number}", | ||
| input={"message": user_message}, | ||
| data={"__span_type__": "AGENT_WORKFLOW"}, | ||
| ) as turn_span: | ||
| start_ms = int(time.monotonic() * 1000) | ||
|
|
||
| process = await _spawn_codex(MODEL, thread_id=state.codex_thread_id) |
There was a problem hiding this comment.
This handler reads state.codex_thread_id, then awaits the full Codex subprocess stream before saving the new turn.session_id. If two task/event/send calls for the same async task arrive close together, both handlers can read the same old thread id or None, run independent Codex turns, and then race to overwrite the stored thread id. The next user message resumes only one branch, so the Codex conversation history can lose one of the messages.
Artifacts
Repro: async harness generated from the template handler with mocked Codex and state services
- Contains supporting evidence from the run (text/x-python; charset=utf-8).
Repro: verbose harness output showing forked thread IDs, write order, final state, and assertions
- Keeps the command output available without making the summary code-heavy.
Ran code and verified through T-Rex
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/cli/templates/default-codex/project/acp.py.j2
Line: 159-177
Comment:
**Concurrent turns fork state**
This handler reads `state.codex_thread_id`, then awaits the full Codex subprocess stream before saving the new `turn.session_id`. If two `task/event/send` calls for the same async task arrive close together, both handlers can read the same old thread id or `None`, run independent Codex turns, and then race to overwrite the stored thread id. The next user message resumes only one branch, so the Codex conversation history can lose one of the messages.
How can I resolve this? If you propose a fix, please make it concise.
Summary
Final slice of #425. Adds the codex
agentex inittemplates across all three tiers.default-codex,sync-codex,temporal-codextemplate dirs.DEFAULT_CODEX,SYNC_CODEX,TEMPORAL_CODEXintoinit.py(enum, project-files map, prompts).TemplateTypeis now complete at 19.CodexTurnfrom theagentex.lib.adkfacade.Test plan
pytest tests/lib/cli/— 66 passed (all 19 template types render to valid Python)Notes
Stacked on #435. Retarget to
nextafter the chain merges.🤖 Generated with Claude Code
Greptile Summary
Confidence Score: 4/5
The Codex scaffold templates need fixes before merge because fresh generated projects can fail to build and async Codex task handling can fork conversation state.
Focused runtime checks reproduced the Docker template parsing issue, the uv lockfile mismatch, and the concurrent task state overwrite while the rest of the change is localized template wiring.
src/agentex/lib/cli/templates/default-codex/Dockerfile.j2, src/agentex/lib/cli/templates/default-codex/Dockerfile-uv.j2, src/agentex/lib/cli/templates/default-codex/project/acp.py.j2, plus the sibling sync and Temporal Codex templates with the same Dockerfile patterns.
What T-Rex did
Comments Outside Diff (1)
src/agentex/lib/cli/templates/default-codex/manifest.yaml.j2, line 599-613 (link)LITELLM_API_KEYcredential won't satisfycodex execThe active credentials entry maps
LITELLM_API_KEYinto the container, butcodex execreadsOPENAI_API_KEYdirectly from the environment. When a user scaffolds this template and deploys, the Kubernetes secret forlitellm-api-keyis mounted butOPENAI_API_KEYis never set, so everycodex execinvocation will fail with an auth error. The credential name (and theenv:entry below it) should referenceOPENAI_API_KEY/openai-api-keyto match what the CLI actually consumes. The same issue is present insync-codex/manifest.yaml.j2.Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (18): Last reviewed commit: "fix(cli): wire OPENAI_API_KEY and serial..." | Re-trigger Greptile