Skip to content

Commit f3f1cd6

Browse files
declan-scaleclaude
andcommitted
fix(codex): record duration_ms after streaming in tutorials [greptile]
The sync and async-base harness_codex tutorials computed duration_ms before the stream was consumed, so TurnUsage.duration_ms captured only subprocess spawn overhead, not inference time — monitoring on that field would show wrong data. Make CodexTurn.duration_ms / cost_usd public mutable attributes (the true wall-clock is only known after the stream ends), and set turn.duration_ms after process.wait() in both tutorials so it measures the full turn. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 8594802 commit f3f1cd6

3 files changed

Lines changed: 15 additions & 8 deletions

File tree

  • examples/tutorials
    • 00_sync/harness_codex/project
    • 10_async/00_base/harness_codex/project
  • src/agentex/lib/adk/_modules

examples/tutorials/00_sync/harness_codex/project/acp.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,9 @@ async def handle_message_send(
136136
await process.stdin.drain()
137137
process.stdin.close()
138138

139-
duration_ms = int(time.monotonic() * 1000) - start_ms
140139
turn = CodexTurn(
141140
events=_process_stdout(process),
142141
model=MODEL,
143-
duration_ms=duration_ms,
144142
)
145143

146144
emitter = UnifiedEmitter(
@@ -154,6 +152,10 @@ async def handle_message_send(
154152

155153
await process.wait()
156154

155+
# Record the real wall-clock duration AFTER streaming completes; setting
156+
# it before the stream ran would capture only subprocess spawn overhead.
157+
turn.duration_ms = int(time.monotonic() * 1000) - start_ms
158+
157159
if turn_span:
158160
usage = turn.usage()
159161
turn_span.output = {

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,9 @@ async def handle_task_event_send(params: SendEventParams):
172172
await process.stdin.drain()
173173
process.stdin.close()
174174

175-
duration_ms = int(time.monotonic() * 1000) - start_ms
176175
turn = CodexTurn(
177176
events=_process_stdout(process),
178177
model=MODEL,
179-
duration_ms=duration_ms,
180178
)
181179

182180
emitter = UnifiedEmitter(
@@ -189,6 +187,10 @@ async def handle_task_event_send(params: SendEventParams):
189187

190188
await process.wait()
191189

190+
# Record the real wall-clock duration AFTER streaming completes; setting
191+
# it before the stream ran would capture only subprocess spawn overhead.
192+
turn.duration_ms = int(time.monotonic() * 1000) - start_ms
193+
192194
# Persist the new thread ID so subsequent turns resume the same session.
193195
usage = turn.usage()
194196
if usage.model:

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,11 @@ def __init__(
152152
) -> None:
153153
self._raw_events = events
154154
self._model = model
155-
self._duration_ms = duration_ms
156-
self._cost_usd = cost_usd
155+
# Public + mutable: the true wall-clock duration (and cost) is usually
156+
# only known after the stream is consumed, so callers may set these
157+
# after construction and before calling usage().
158+
self.duration_ms = duration_ms
159+
self.cost_usd = cost_usd
157160

158161
# Populated by the on_result callback once the stream is exhausted.
159162
self._result: dict[str, Any] | None = None
@@ -196,6 +199,6 @@ def usage(self) -> TurnUsage:
196199
model=self._model,
197200
tool_call_count=self._result.get("tool_call_count", 0),
198201
reasoning_count=self._result.get("reasoning_count", 0),
199-
duration_ms=self._duration_ms,
200-
cost_usd=self._cost_usd,
202+
duration_ms=self.duration_ms,
203+
cost_usd=self.cost_usd,
201204
)

0 commit comments

Comments
 (0)