{{ message }}
Repository navigation
Conversation
A generation span that finishes with `usage=None` -- which is how the agents SDK ends a span whose model call failed -- crashed in `update_span_properties_from_generation_span_data`: `input_tokens` and `output_tokens` were only bound inside the `if usage:` guard but read unconditionally further down. The UnboundLocalError aborts `on_span_end` before the observer is exited, so the LlmSpan stays in `current_span_context`/`active_spans` and its observer stays registered. Initialise the token locals to None before the guard, the way the sibling response-span extractor already does. The same function also raised TypeError on `span.metadata[...]` whenever the LlmSpan was created by the tracing processor, since those spans carry no metadata, so the update could never run to completion.
This branch has not been deployed
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
A generation span that finishes with
usage=None-- which is how the agents SDK ends a span whose model call raised (bad API key, 429, connection error, timeout) -- crashedupdate_span_properties_from_generation_span_data. The exception escapesDeepEvalTracingProcessor.on_span_end, which the SDK swallows (agents/tracing/provider.py:170), so the observer is never exited: theLlmSpanstays incurrent_span_contextandtrace_manager.active_spans, itsObserverstays inself.span_observers, and every later span in the process parents onto that stale, never-finished span.Why
deepeval/openai_agents/extractors.py:155-158(pre-fix numbering) bindsinput_tokens/output_tokensonly inside theif usage:guard, butextractors.py:168-169reads them unconditionally:usage is Noneis a contractually valid input --GenerationSpanData.usageis typeddict[str, Any] | None = None, and it is assigned only after a successful response -- so this raisesUnboundLocalError. The siblingupdate_span_properties_from_response_span_dataalready initialises its optional locals toNonebefore the same kind of guard (extractors.py:101-102); this function was missing that.A second defect on the same code path makes the first one fatal rather than merely wrong.
extractors.py:175indexesspan.metadata["invocation_params"], but anLlmSpancreated by the tracing processor carries no metadata (BaseSpan.metadata: Optional[Dict[str, Any]] = None,deepeval/tracing/types.py:98). With the unbound-local crash fixed and nothing else changed, the update raisesTypeError: 'NoneType' object does not support item assignmentinstead -- so the span still never closes. Both fixes are required together; I verified each in isolation (see Testing).Changes
deepeval/openai_agents/extractors.pyinput_tokens/output_tokenstoNonebefore theif usage:guard, mirroringupdate_span_properties_from_response_span_data. A usage-less span now recordsinput_token_count=None/output_token_count=None, matching the optional field types onLlmSpan.span.metadatato{}before assigningspan.metadata["invocation_params"].tests/test_integrations/test_openai_agents/test_generation_span_without_usage.py(new)generation_span(...)and leavespan_data.usageat its defaultNone. The first asserts theLlmSpanis finalized (end_timeset,modelrecorded, token countsNone,invocation_params.model_configpreserved); the second assertscurrent_span_contextandtrace_manager.active_spansare empty afterwards. They use the existing session-scopedDeepEvalTracingProcessorfixture from the directory'sconftest.py, need no API key, and make no network call.Testing
Red -- the new test against the unpatched tree (
origin/main):The processor exception the SDK swallows is:
With only the token-local hunk applied and the metadata hunk omitted, the same span still fails to close, now with:
Green -- both tests on this branch:
Existing tests in the module:
The same directory on
origin/mainwith the new test file absent reports15 failed, 1 skipped-- the identical 15 test ids, each the openai SDK's ownOpenAIErrorfrom building a client withapi_key=None(openai/_client.py:1027). Those tests call the live OpenAI API and are gated upstream in.github/workflows/test_integrations.ymlonif: ${{ env.OPENAI_API_KEY != '' }}. No new failures.Lint/format (the repo's configured tools,
pyproject.toml):Notes
I could not run the recorded-schema integration tests (
test_sync.py,test_async.py,test_scenerios/) locally because they require anOPENAI_API_KEY; the change only affects theGenerationSpanDatapath, and the response-span extractor is untouched.Fixes #3314