feat(cli): add codex init templates (sync / async / temporal)#436
Open
declan-scale wants to merge 18 commits into
Open
feat(cli): add codex init templates (sync / async / temporal)#436declan-scale wants to merge 18 commits into
declan-scale wants to merge 18 commits into
Conversation
a92d37b to
ff359de
Compare
9d0ea68 to
a891d35
Compare
Contributor
Author
|
@greptile review |
ff359de to
e031d5d
Compare
a891d35 to
be6b158
Compare
Contributor
Author
|
@greptile review |
e031d5d to
8f7854a
Compare
be6b158 to
2eefec2
Compare
Contributor
Author
|
@greptile review |
8f7854a to
6e3f0cf
Compare
2eefec2 to
42db83c
Compare
Contributor
Author
|
@greptile review |
42db83c to
889f793
Compare
Contributor
Author
|
@greptile review |
889f793 to
ace66e2
Compare
Contributor
Author
|
@greptile review |
Contributor
Author
|
@greptile review |
47ea82c to
2003757
Compare
d489113 to
412b1c6
Compare
2003757 to
755d18e
Compare
412b1c6 to
3aaa35e
Compare
danielmillerp
approved these changes
Jun 23, 2026
755d18e to
63904c2
Compare
3aaa35e to
5d5a0e8
Compare
3 tasks
… handler Collapse _langgraph_async / _langgraph_messages / _langgraph_tracing into _langgraph_sync (emit_langgraph_messages, convert helpers) and _langgraph_turn (stream_langgraph_events). Span tracing is now derived from the canonical stream by UnifiedEmitter, so create_langgraph_tracing_handler is removed. Public facade names are unchanged except the removed handler. All in-repo consumers were migrated to the unified surface in the preceding PRs. BREAKING CHANGE: create_langgraph_tracing_handler is removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Greptile review: the breaking-change entry listed create_pydantic_ai_tracing_handler as removed, but that handler is still exported here and is only removed in the following PR. Narrow this entry to the LangGraph handler actually removed in this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ng handler Collapse _pydantic_ai_async / _pydantic_ai_tracing into _pydantic_ai_sync (convert helper) and _pydantic_ai_turn (stream_pydantic_ai_events). Span tracing is derived from the canonical stream by UnifiedEmitter, so create_pydantic_ai_tracing_handler is removed. BREAKING CHANGE: create_pydantic_ai_tracing_handler is removed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR removes create_pydantic_ai_tracing_handler from the public adk surface; document it here (the previous PR's entry was narrowed to the LangGraph handler it actually removed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… at facade
Promote the OpenAI Turn and sync tap to the canonical adk/_modules layout
(_openai_turn.py, _openai_sync.py), matching every other harness. Leave
back-compat shims at providers/_modules/{openai_turn,sync_provider}.py so
existing import paths keep working; the larger Temporal/MCP provider stays
under adk.providers.
Export OpenAITurn, openai_usage_to_turn_usage and convert_openai_to_agentex_events
from agentex.lib.adk so the OpenAI harness is a first-class facade citizen like
ClaudeCodeTurn / CodexTurn (fixes Greptile follow-up: templates can import from
the package facade instead of a private module path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add offline sync/async/temporal integration suites for the openai, claude_code and codex harnesses (+76 tests), mirroring the existing langgraph/pydantic_ai coverage. Extend the harness-integration live-matrix to all five harnesses and switch the path trigger to a test_harness_*.py glob so new suites are picked up automatically. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the missing async-base OpenAI Agents SDK template, wiring DEFAULT_OPENAI_AGENTS into the init flow (enum, project files, async prompt). The scaffolded acp.py imports OpenAITurn from the agentex.lib.adk facade, matching the other Turn-based templates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Greptile review: the async base handler ran each turn with only the current user_message, so multi-turn context was dropped. Persist the OpenAI input list per task via adk.state and replay it into Runner.run_streamed, matching the sync and temporal openai-agents templates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add default-claude-code, sync-claude-code and temporal-claude-code templates across all three tiers, wiring the new TemplateType entries into the init flow. Scaffolded code imports ClaudeCodeTurn from the agentex.lib.adk facade. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Install the Claude Code CLI (@anthropic-ai/claude-code) in all three Dockerfiles so deployed images can actually run `claude`. - Wire ANTHROPIC_API_KEY (credential + env) in the default, sync and temporal manifests; the `claude` subprocess does not read LITELLM_API_KEY. - Surface CLI failures: capture a bounded stderr tail and raise on a non-zero exit instead of silently completing the turn. - Serialize temporal turns with an asyncio.Lock so overlapping signals don't race on _session_id, and raise the activity timeout to 30m for agentic runs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the manifest fix: the claude-code templates spawn the `claude` CLI, which reads ANTHROPIC_API_KEY rather than LITELLM_API_KEY. Update the default, sync and temporal .env.example scaffolds accordingly. 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 `claude` CLI, leaving use_uv=True containers non-functional. Mirror the npm install -g @anthropic-ai/claude-code step already added to the pip Dockerfiles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Round-4 Greptile review: - await proc.stdin.drain() before close() in all three claude-code subprocess helpers (matches the codex helpers; flushes large prompts before EOF). - Stop the manifest env block from setting ANTHROPIC_API_KEY to an empty string, which would shadow the credential mapping / .env value at runtime. The key now comes solely from the credential mapping (deploy) or .env (local). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
63904c2 to
f819115
Compare
5d5a0e8 to
b5cbe37
Compare
f819115 to
4f2002c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


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
This PR completes the Codex CLI harness templates slice by adding
default-codex,sync-codex, andtemporal-codexscaffolds and wiring them intoagentex init. All three tiers share the sameCodexTurn+UnifiedEmitterharness pattern used by the sibling claude-code templates.@openai/codexis installed in every Dockerfile,OPENAI_API_KEYis mapped in every manifest and.env.example, subprocess cleanup usestry/finallywithprocess.kill()+process.wait()in all threeacp.pytemplates, and the temporal workflow serializes concurrent signal handlers withasyncio.Lock().ENV PYTHONPATH=/appthat is present in the non-uv counterpart and in the default-codex uv variant — a minor inconsistency that is unlikely to cause runtime failures given the current import structure but is worth aligning.Confidence Score: 5/5
Safe to merge; all blocking issues from previous review rounds have been resolved and the new code follows established harness patterns.
All previously raised issues (subprocess leaks, wrong credential in manifests, missing CLI install, concurrent-turn state forking, undefined notebook variable) are demonstrably fixed in the current diff. The remaining note is a minor inconsistency between two Dockerfile variants that does not affect runtime behaviour.
temporal-codex/Dockerfile-uv.j2 — missing PYTHONPATH alignment with its non-uv sibling.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant UI participant ACP as ACP Server (FastACP) participant Handler as on_task_event_send / on_message_send participant Codex as codex exec subprocess participant Redis participant State as adk.state UI->>ACP: task/event/send (user message) ACP->>Handler: dispatch params Handler->>State: get ConversationState (thread_id) Handler->>Codex: asyncio.create_subprocess_exec codex exec json Handler->>Codex: write prompt to stdin, close stdin loop CodexTurn streaming Codex-->>Handler: stdout JSON line Handler->>Redis: UnifiedEmitter event push Redis-->>UI: real-time token stream end Handler->>Codex: process.kill() + wait() finally Handler->>State: update codex_thread_id Handler-->>ACP: return / generator exhausted%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant UI participant ACP as ACP Server (FastACP) participant Handler as on_task_event_send / on_message_send participant Codex as codex exec subprocess participant Redis participant State as adk.state UI->>ACP: task/event/send (user message) ACP->>Handler: dispatch params Handler->>State: get ConversationState (thread_id) Handler->>Codex: asyncio.create_subprocess_exec codex exec json Handler->>Codex: write prompt to stdin, close stdin loop CodexTurn streaming Codex-->>Handler: stdout JSON line Handler->>Redis: UnifiedEmitter event push Redis-->>UI: real-time token stream end Handler->>Codex: process.kill() + wait() finally Handler->>State: update codex_thread_id Handler-->>ACP: return / generator exhaustedComments 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
Reviews (17): Last reviewed commit: "fix(cli): wire OPENAI_API_KEY and serial..." | Re-trigger Greptile