Skip to content

Commit 68bc11e

Browse files
cursoragenthassiebp
andcommitted
Fix priority tier token detail parsing
Co-authored-by: Hassieb Pakzad <hassiebp@users.noreply.github.com>
1 parent 1ae2923 commit 68bc11e

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

langfuse/langchain/CallbackHandler.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,24 @@ def _flatten_comprehension(matrix: Any) -> Any:
11021102
return [item for row in matrix for item in row]
11031103

11041104

1105+
_TOKEN_DETAIL_SUBTRACT_KEYS = {
1106+
"audio",
1107+
"cache_read",
1108+
"cache_creation",
1109+
"reasoning",
1110+
}
1111+
1112+
1113+
def _should_subtract_token_detail(detail_key: str) -> bool:
1114+
normalized_key = detail_key.lower()
1115+
for subtract_key in _TOKEN_DETAIL_SUBTRACT_KEYS:
1116+
if normalized_key == subtract_key or normalized_key.endswith(
1117+
f"_{subtract_key}"
1118+
):
1119+
return True
1120+
return False
1121+
1122+
11051123
def _parse_usage_model(usage: Union[pydantic.BaseModel, dict]) -> Any:
11061124
# maintains a list of key translations. For each key, the usage model is checked
11071125
# and a new object will be created with the new key if the key exists in the usage model
@@ -1177,7 +1195,7 @@ def _parse_usage_model(usage: Union[pydantic.BaseModel, dict]) -> Any:
11771195
for key, value in input_token_details.items():
11781196
usage_model[f"input_{key}"] = value
11791197

1180-
if "input" in usage_model:
1198+
if "input" in usage_model and _should_subtract_token_detail(key):
11811199
usage_model["input"] = max(0, usage_model["input"] - value)
11821200

11831201
if "output_token_details" in usage_model:
@@ -1186,7 +1204,7 @@ def _parse_usage_model(usage: Union[pydantic.BaseModel, dict]) -> Any:
11861204
for key, value in output_token_details.items():
11871205
usage_model[f"output_{key}"] = value
11881206

1189-
if "output" in usage_model:
1207+
if "output" in usage_model and _should_subtract_token_detail(key):
11901208
usage_model["output"] = max(0, usage_model["output"] - value)
11911209

11921210
# Vertex AI

tests/test_langchain_usage.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from langfuse.langchain.CallbackHandler import _parse_usage_model
2+
3+
4+
def test_parse_usage_model_skips_priority_subtraction():
5+
usage = {
6+
"input": 13,
7+
"output": 1,
8+
"total": 14,
9+
"input_token_details": {
10+
"audio": 0,
11+
"priority_cache_read": 0,
12+
"priority": 13,
13+
},
14+
"output_token_details": {
15+
"audio": 0,
16+
"priority_reasoning": 0,
17+
"priority": 1,
18+
},
19+
}
20+
21+
parsed = _parse_usage_model(usage)
22+
23+
assert parsed["input"] == 13
24+
assert parsed["output"] == 1
25+
assert parsed["total"] == 14
26+
27+
28+
def test_parse_usage_model_subtracts_known_details():
29+
usage = {
30+
"input": 100,
31+
"output": 50,
32+
"total": 150,
33+
"input_token_details": {
34+
"cache_read": 20,
35+
"audio": 5,
36+
},
37+
"output_token_details": {
38+
"reasoning": 10,
39+
},
40+
}
41+
42+
parsed = _parse_usage_model(usage)
43+
44+
assert parsed["input"] == 75
45+
assert parsed["output"] == 40
46+
assert parsed["input_cache_read"] == 20
47+
assert parsed["input_audio"] == 5
48+
assert parsed["output_reasoning"] == 10
49+
assert parsed["total"] == 150

0 commit comments

Comments
 (0)