Skip to content

Commit 7e296bd

Browse files
declan-scaleclaude
andcommitted
fix(codex): public session_id accessor + fix pyright lint in test [greptile]
- Add CodexTurn.session_id property so multi-turn callers resume sessions without reaching into the private _result dict; update the async-base and temporal tutorials to use it. - Fix the CI pyright failure in test_codex_sync.py: pull tool_call_id inside the isinstance comprehension so the content-union narrowing holds (a later attribute access on req[0].content did not narrow, tripping reportAttribute). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f3f1cd6 commit 7e296bd

4 files changed

Lines changed: 30 additions & 10 deletions

File tree

examples/tutorials/10_async/00_base/harness_codex/project/acp.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,10 @@ async def handle_task_event_send(params: SendEventParams):
196196
if usage.model:
197197
# usage() is valid now that the stream is exhausted
198198
pass
199-
# CodexTurn exposes the session_id via its on_result callback; we access
200-
# it via the underlying processor through the result dict stored on the turn.
201-
if turn._result and turn._result.get("session_id"):
202-
state.codex_thread_id = turn._result["session_id"]
199+
# Persist the codex session id (public accessor; valid post-stream) so the
200+
# next turn resumes the same session.
201+
if turn.session_id:
202+
state.codex_thread_id = turn.session_id
203203

204204
await adk.state.update(
205205
state_id=task_state.id,

examples/tutorials/10_async/10_temporal/harness_codex/project/workflow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ async def on_task_event_send(self, params: SendEventParams) -> None:
173173

174174
await process.wait()
175175

176-
if turn._result and turn._result.get("session_id"):
177-
self._codex_thread_id = turn._result["session_id"]
176+
if turn.session_id:
177+
self._codex_thread_id = turn.session_id
178178

179179
if span:
180180
span.output = {

src/agentex/lib/adk/_modules/_codex_turn.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ def events(self) -> AsyncIterator[StreamTaskMessage]:
185185
def _on_result(self, result: dict[str, Any]) -> None:
186186
self._result = result
187187

188+
@property
189+
def session_id(self) -> str | None:
190+
"""The codex session id, for resuming a multi-turn session.
191+
192+
Valid only after ``events`` has been fully consumed (populated by the
193+
``on_result`` callback). Returns ``None`` if the stream is not yet
194+
exhausted or codex reported no session id.
195+
"""
196+
return self._result.get("session_id") if self._result else None
197+
188198
def usage(self) -> TurnUsage:
189199
"""Return normalized ``TurnUsage`` for this turn.
190200

tests/lib/adk/test_codex_sync.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,20 @@ async def test_empty_item_id_request_response_ids_match(self) -> None:
236236
},
237237
]
238238
out = await _collect(convert_codex_to_agentex_events(_aiter(events)))
239-
req = [e for e in out if isinstance(e, StreamTaskMessageStart) and isinstance(e.content, ToolRequestContent)]
240-
resp = [e for e in out if isinstance(e, StreamTaskMessageFull) and isinstance(e.content, ToolResponseContent)]
241-
assert len(req) == 1 and len(resp) == 1
242-
assert req[0].content.tool_call_id == resp[0].content.tool_call_id
239+
# Pull tool_call_id inside the comprehension so the isinstance narrows the
240+
# content union (the narrowing would not survive a later attribute access).
241+
req_ids = [
242+
e.content.tool_call_id
243+
for e in out
244+
if isinstance(e, StreamTaskMessageStart) and isinstance(e.content, ToolRequestContent)
245+
]
246+
resp_ids = [
247+
e.content.tool_call_id
248+
for e in out
249+
if isinstance(e, StreamTaskMessageFull) and isinstance(e.content, ToolResponseContent)
250+
]
251+
assert len(req_ids) == 1 and len(resp_ids) == 1
252+
assert req_ids[0] == resp_ids[0]
243253

244254
async def test_file_change_synthesizes_start(self) -> None:
245255
"""file_change items may only emit item.completed (no started)."""

0 commit comments

Comments
 (0)