Skip to content

fix(langfuse): restore usage/cost when post_api_request sends a sanitized response#40560

Merged
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kamonspecial:fix/langfuse-usage-sanitized-response
Jun 8, 2026
Merged

fix(langfuse): restore usage/cost when post_api_request sends a sanitized response#40560
kshitijk4poor merged 1 commit into
NousResearch:mainfrom
kamonspecial:fix/langfuse-usage-sanitized-response

Conversation

@kamonspecial

Copy link
Copy Markdown
Contributor

What does this PR do?

The bundled Langfuse plugin stopped recording token usage and cost for gateway
turns: traces show usage 0 / cost 0 even though the provider returned usage.

Root cause: on_post_llm_call extracts usage with if response is not None:,
taking the response-object branch. post_api_request passes response as a
sanitized dict (no .usage attribute) plus a separate usage summary dict, so
getattr(response, "usage") is always None and the usage-dict fallback below is
never reached — token/cost data is silently dropped.

Fix: gate the response-object branch on a real .usage attribute
(getattr(response, "usage", None) is not None). Sanitized dict responses fall
through to the usage dict; genuine response objects (post_llm_call / legacy)
still take the response-object path.

Related Issue

N/A — no existing issue; happy to file one if preferred.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • plugins/observability/langfuse/__init__.py: gate usage extraction on a real
    .usage attribute so the usage-dict fallback is reached for sanitized
    post_api_request responses.
  • tests/plugins/test_langfuse_plugin.py: regression tests for both the
    sanitized-dict path (usage read from the usage dict) and the real-object
    path (response object still takes precedence).

How to Test

  1. pytest tests/plugins/test_langfuse_plugin.py -q → 39 pass (37 existing + 2 new).
  2. The new test_sanitized_dict_response_uses_usage_dict fails on main
    (usage dropped) and passes with this change.

Checklist

  • My commit messages follow Conventional Commits
  • My PR contains only changes related to this fix
  • Ran pytest tests/plugins/test_langfuse_plugin.py -q — 39 pass (37 existing + 2 new); did not run the full suite locally
  • I've added regression tests (fail on main, pass here)
  • Tested on macOS

…ized response

on_post_llm_call extracted usage via `if response is not None:`, taking the
response-object path. But post_api_request delivers `response` as a sanitized
dict (no `.usage` attribute) alongside a separate `usage` summary dict, so
`getattr(response, "usage")` was always None and token/cost data was dropped
for every gateway turn (traces showed usage 0 / cost 0).

Gate on a real `.usage` attribute so the existing usage-dict fallback is
reached. Real response objects (post_llm_call / legacy) still take the
response-object path. Adds regression tests for both paths.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins labels Jun 6, 2026
@kshitijk4poor kshitijk4poor merged commit 1e3b3df into NousResearch:main Jun 8, 2026
alt-glitch pushed a commit that referenced this pull request Jun 14, 2026
…zed-response

fix(langfuse): restore usage/cost when post_api_request sends a sanitized response
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants