12
12
@pytest .mark .allow_call_model_methods
13
13
@pytest .mark .asyncio
14
14
async def test_cost_extracted_when_track_cost_enabled (monkeypatch ):
15
- """Test that cost is extracted from LiteLLM response when track_cost=True."""
15
+ """Test that cost is calculated using LiteLLM's completion_cost API when track_cost=True."""
16
16
17
17
async def fake_acompletion (model , messages = None , ** kwargs ):
18
18
msg = Message (role = "assistant" , content = "Test response" )
@@ -21,11 +21,14 @@ async def fake_acompletion(model, messages=None, **kwargs):
21
21
choices = [choice ],
22
22
usage = Usage (prompt_tokens = 10 , completion_tokens = 20 , total_tokens = 30 ),
23
23
)
24
- # Simulate LiteLLM's hidden params with cost.
25
- response ._hidden_params = {"response_cost" : 0.00042 }
26
24
return response
27
25
26
+ def fake_completion_cost (completion_response ):
27
+ """Mock litellm.completion_cost to return a test cost value."""
28
+ return 0.00042
29
+
28
30
monkeypatch .setattr (litellm , "acompletion" , fake_acompletion )
31
+ monkeypatch .setattr (litellm , "completion_cost" , fake_completion_cost )
29
32
30
33
model = LitellmModel (model = "test-model" , api_key = "test-key" )
31
34
result = await model .get_response (
@@ -39,7 +42,7 @@ async def fake_acompletion(model, messages=None, **kwargs):
39
42
previous_response_id = None ,
40
43
)
41
44
42
- # Verify that cost was extracted .
45
+ # Verify that cost was calculated .
43
46
assert result .usage .cost == 0.00042
44
47
45
48
@@ -55,11 +58,10 @@ async def fake_acompletion(model, messages=None, **kwargs):
55
58
choices = [choice ],
56
59
usage = Usage (prompt_tokens = 10 , completion_tokens = 20 , total_tokens = 30 ),
57
60
)
58
- # Even if LiteLLM provides cost, it should be ignored.
59
- response ._hidden_params = {"response_cost" : 0.00042 }
60
61
return response
61
62
62
63
monkeypatch .setattr (litellm , "acompletion" , fake_acompletion )
64
+ # Note: completion_cost should not be called when track_cost=False
63
65
64
66
model = LitellmModel (model = "test-model" , api_key = "test-key" )
65
67
result = await model .get_response (
@@ -80,7 +82,7 @@ async def fake_acompletion(model, messages=None, **kwargs):
80
82
@pytest .mark .allow_call_model_methods
81
83
@pytest .mark .asyncio
82
84
async def test_cost_none_when_not_provided (monkeypatch ):
83
- """Test that cost is None when LiteLLM doesn't provide it ."""
85
+ """Test that cost is None when completion_cost raises an exception ."""
84
86
85
87
async def fake_acompletion (model , messages = None , ** kwargs ):
86
88
msg = Message (role = "assistant" , content = "Test response" )
@@ -89,10 +91,14 @@ async def fake_acompletion(model, messages=None, **kwargs):
89
91
choices = [choice ],
90
92
usage = Usage (prompt_tokens = 10 , completion_tokens = 20 , total_tokens = 30 ),
91
93
)
92
- # No _hidden_params or no cost in hidden params.
93
94
return response
94
95
96
+ def fake_completion_cost (completion_response ):
97
+ """Mock completion_cost to raise an exception (e.g., unknown model)."""
98
+ raise Exception ("Model not found in pricing database" )
99
+
95
100
monkeypatch .setattr (litellm , "acompletion" , fake_acompletion )
101
+ monkeypatch .setattr (litellm , "completion_cost" , fake_completion_cost )
96
102
97
103
model = LitellmModel (model = "test-model" , api_key = "test-key" )
98
104
result = await model .get_response (
@@ -106,14 +112,14 @@ async def fake_acompletion(model, messages=None, **kwargs):
106
112
previous_response_id = None ,
107
113
)
108
114
109
- # Verify that cost is None when not provided .
115
+ # Verify that cost is None when completion_cost fails .
110
116
assert result .usage .cost is None
111
117
112
118
113
119
@pytest .mark .allow_call_model_methods
114
120
@pytest .mark .asyncio
115
- async def test_cost_with_empty_hidden_params (monkeypatch ):
116
- """Test that cost extraction handles empty _hidden_params gracefully ."""
121
+ async def test_cost_zero_when_completion_cost_returns_zero (monkeypatch ):
122
+ """Test that cost is 0 when completion_cost returns 0 (e.g., free model) ."""
117
123
118
124
async def fake_acompletion (model , messages = None , ** kwargs ):
119
125
msg = Message (role = "assistant" , content = "Test response" )
@@ -122,11 +128,14 @@ async def fake_acompletion(model, messages=None, **kwargs):
122
128
choices = [choice ],
123
129
usage = Usage (prompt_tokens = 10 , completion_tokens = 20 , total_tokens = 30 ),
124
130
)
125
- # Empty hidden params.
126
- response ._hidden_params = {}
127
131
return response
128
132
133
+ def fake_completion_cost (completion_response ):
134
+ """Mock completion_cost to return 0 (e.g., free model)."""
135
+ return 0.0
136
+
129
137
monkeypatch .setattr (litellm , "acompletion" , fake_acompletion )
138
+ monkeypatch .setattr (litellm , "completion_cost" , fake_completion_cost )
130
139
131
140
model = LitellmModel (model = "test-model" , api_key = "test-key" )
132
141
result = await model .get_response (
@@ -140,14 +149,14 @@ async def fake_acompletion(model, messages=None, **kwargs):
140
149
previous_response_id = None ,
141
150
)
142
151
143
- # Verify that cost is None with empty hidden params .
144
- assert result .usage .cost is None
152
+ # Verify that cost is 0 for free models .
153
+ assert result .usage .cost == 0.0
145
154
146
155
147
156
@pytest .mark .allow_call_model_methods
148
157
@pytest .mark .asyncio
149
158
async def test_cost_extraction_preserves_other_usage_fields (monkeypatch ):
150
- """Test that cost extraction doesn't affect other usage fields."""
159
+ """Test that cost calculation doesn't affect other usage fields."""
151
160
152
161
async def fake_acompletion (model , messages = None , ** kwargs ):
153
162
msg = Message (role = "assistant" , content = "Test response" )
@@ -156,10 +165,14 @@ async def fake_acompletion(model, messages=None, **kwargs):
156
165
choices = [choice ],
157
166
usage = Usage (prompt_tokens = 100 , completion_tokens = 50 , total_tokens = 150 ),
158
167
)
159
- response ._hidden_params = {"response_cost" : 0.001 }
160
168
return response
161
169
170
+ def fake_completion_cost (completion_response ):
171
+ """Mock litellm.completion_cost to return a test cost value."""
172
+ return 0.001
173
+
162
174
monkeypatch .setattr (litellm , "acompletion" , fake_acompletion )
175
+ monkeypatch .setattr (litellm , "completion_cost" , fake_completion_cost )
163
176
164
177
model = LitellmModel (model = "test-model" , api_key = "test-key" )
165
178
result = await model .get_response (
0 commit comments