@@ -223,6 +223,57 @@ def test_chat_completions_applies_template(self):
223223 passed_messages = call_args [0 ][0 ] if call_args [0 ] else call_args [1 ].get ("conversation" )
224224 self .assertIsNotNone (passed_messages )
225225
226+ def test_completions_token_id_prompt_normalised_as_single (self ):
227+ """A list-of-ints prompt must be treated as one token-ID prompt, not a batch of ints."""
228+ mock_output = _make_mock_output (generated_text = "out" , prompt_token_ids = [1 , 2 , 3 ], generated_token_ids = [7 ])
229+ self .mock_llm .generate .return_value = [mock_output ]
230+
231+ resp = self .client .post (
232+ "/v1/completions" ,
233+ json = {"model" : "m" , "prompt" : [1 , 2 , 3 ], "max_tokens" : 5 },
234+ )
235+ self .assertEqual (resp .status_code , 200 )
236+ data = resp .json ()
237+ self .assertEqual (len (data ["choices" ]), 1 )
238+ self .assertEqual (data ["choices" ][0 ]["text" ], "out" )
239+ # generate() must be called with a single-element list containing the token-ID list
240+ call_prompts = self .mock_llm .generate .call_args [0 ][0 ]
241+ self .assertEqual (call_prompts , [[1 , 2 , 3 ]])
242+
243+ def test_completions_top_logprobs_populated (self ):
244+ """When logprobs is requested, top_logprobs entries must be non-None dicts."""
245+ mock_output = _make_mock_output (generated_text = "hi" , prompt_token_ids = [1 ], generated_token_ids = [4 , 5 ])
246+ mock_output .outputs [0 ].logprobs = [
247+ {4 : SimpleNamespace (logprob = - 0.5 ), 6 : SimpleNamespace (logprob = - 1.0 )},
248+ {5 : SimpleNamespace (logprob = - 0.8 )},
249+ ]
250+ self .mock_llm .generate .return_value = [mock_output ]
251+
252+ resp = self .client .post (
253+ "/v1/completions" ,
254+ json = {"model" : "m" , "prompt" : "x" , "max_tokens" : 5 , "logprobs" : 2 },
255+ )
256+ self .assertEqual (resp .status_code , 200 )
257+ lp = resp .json ()["choices" ][0 ]["logprobs" ]
258+ self .assertIsNotNone (lp )
259+ self .assertIsInstance (lp ["top_logprobs" ][0 ], dict )
260+ self .assertGreater (len (lp ["top_logprobs" ][0 ]), 0 )
261+
262+ def test_completions_echo_with_token_id_prompt (self ):
263+ """echo=True with a token-ID prompt must decode the prompt and prepend it to text."""
264+ mock_output = _make_mock_output (generated_text = " world" , prompt_token_ids = [1 , 2 , 3 ], generated_token_ids = [4 ])
265+ self .mock_llm .generate .return_value = [mock_output ]
266+
267+ resp = self .client .post (
268+ "/v1/completions" ,
269+ json = {"model" : "m" , "prompt" : [1 , 2 , 3 ], "max_tokens" : 5 , "echo" : True },
270+ )
271+ self .assertEqual (resp .status_code , 200 )
272+ text = resp .json ()["choices" ][0 ]["text" ]
273+ # tokenizer.decode([1, 2, 3]) → "tok1tok2tok3" (see _make_mock_llm side_effect)
274+ self .assertTrue (text .startswith ("tok1tok2tok3" ), f"Expected decoded prompt prefix, got: { text !r} " )
275+ self .assertIn (" world" , text )
276+
226277
227278if __name__ == "__main__" :
228279 unittest .main ()
0 commit comments