Skip to content

fix(openai): trace responses.retrieve so background responses get output and usage - #1833

Open
Kairick wants to merge 1 commit into
langfuse:mainfrom
Kairick:fix/trace-responses-retrieve
Open

fix(openai): trace responses.retrieve so background responses get output and usage#1833
Kairick wants to merge 1 commit into
langfuse:mainfrom
Kairick:fix/trace-responses-retrieve

Conversation

@Kairick

@Kairick Kairick commented Aug 24, 2026

Copy link
Copy Markdown

What does this PR do?

Instruments Responses.retrieve and AsyncResponses.retrieve, so background responses get their output, token counts and cost.

create and parse are instrumented, retrieve is not. With background=True the create call returns status="queued" with no usage, and the real result arrives through retrieve() — either directly, or via responses.stream(response_id=...), which delegates to retrieve(stream=True). The generation therefore stays in the trace with an input and a model but no output, no usage_details and no cost, which reads as a free call rather than a missing one.

The response id is recorded as the generation input, since retrieve() carries no prompt of its own. Model, output and usage come from the response, so both the streaming and non-streaming paths are handled by the existing extraction code.

A key-free reproduction of the routing is in the issue.

Open question: retrieving a response that was already traced at creation time (non-background usage) will now record its usage a second time. This PR implements the straightforward version — instrument every retrieve — but restricting it to stream=True, or skipping usage when the response was not queued, are both easy to switch to if you prefer one of those.

Fixes #1834

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactor
  • Documentation update
  • Tooling, CI, or repo maintenance

Verification

Both new tests fail on main and pass with the change.

uv run --frozen pytest tests/unit/test_openai.py -q -k retrieve   # 2 passed (2 failed before the fix)
uv run --frozen pytest tests/unit/test_openai.py -q               # 36 passed
bash scripts/codex/quick-check.sh                                 # ruff, mypy, 670 passed, 2 skipped, 18 errors
uv run --frozen ruff format --check langfuse/openai.py tests/unit/test_openai.py

The 18 errors in the unit run come from tests/unit/test_prompt.py, which needs Langfuse credentials in the environment. They reproduce unchanged on main.

Not run: tests/e2e and tests/live_provider, which need a Langfuse server and provider keys. Per AGENTS.md this change is covered by exporter-local unit assertions, so no e2e or live-provider coverage was added.

Checklist

  • I self-reviewed the diff using code_review.md.
  • I added or updated tests for behavior changes.
  • I updated docs, examples, or .env.template if needed. (Not needed: no public API surface or env variable changes.)
  • I did not hand-edit generated files; if generated files changed, I used the upstream regeneration path.
  • I did not commit secrets or credentials.

Greptile Summary

Instruments synchronous and asynchronous OpenAI Responses retrieval so completed background responses produce Langfuse generation telemetry.

  • Registers Responses.retrieve and AsyncResponses.retrieve for tracing.
  • Records the response ID as retrieval input while extracting model, output, and usage from the returned response.
  • Adds unit coverage for synchronous and asynchronous retrieval.

Confidence Score: 5/5

The PR appears safe to merge, with no unacknowledged blocking or independently actionable issues identified.

The new retrieval registrations use the existing synchronous, asynchronous, and Responses API extraction paths, and the added tests cover the primary non-streaming behavior.

Reviews (1): Last reviewed commit: "fix(openai): trace responses.retrieve so..." | Re-trigger Greptile

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@CLAassistant

CLAassistant commented Aug 24, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@Kairick

Kairick commented Aug 24, 2026

Copy link
Copy Markdown
Author

recheck

…put and usage

Responses.create and Responses.parse are instrumented, Responses.retrieve
is not. Background responses (background=True) return immediately with
status queued and no usage, and complete through retrieve() - either
directly or via responses.stream(response_id=...), which delegates to
retrieve(stream=True).

The result is a generation in the trace that never receives its output,
token counts or cost, which reads as a free call rather than a missing
one.

Instrument Responses.retrieve and AsyncResponses.retrieve. The response
id is recorded as the generation input, since retrieve() carries no
prompt of its own; model, output and usage come from the response, so
both the streaming and non-streaming paths are handled by the existing
extraction code.
@Kairick
Kairick force-pushed the fix/trace-responses-retrieve branch from e3b0671 to 9c417d3 Compare August 24, 2026 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Responses.retrieve is not instrumented, so background responses lose output, usage and cost

2 participants