diff --git a/python/freetoken/server/openai_api.py b/python/freetoken/server/openai_api.py index 99a4283549..15992930e3 100644 --- a/python/freetoken/server/openai_api.py +++ b/python/freetoken/server/openai_api.py @@ -396,6 +396,8 @@ async def handle_completion( unsupported = _completion_unsupported_reason(req) if unsupported is not None: return create_error_response(unsupported) + if req.n != 1: + return create_error_response("Only n=1 is supported", param="n") try: # surfaces an out-of-range max_tokens as a 400 rather than a 500 from the worker default_max_tokens = ( getattr(state.config, "max_output_tokens", None) or DEFAULT_MAX_OUTPUT_TOKENS diff --git a/tests/server/test_openai_api.py b/tests/server/test_openai_api.py index e33018e195..3dcef25f34 100644 --- a/tests/server/test_openai_api.py +++ b/tests/server/test_openai_api.py @@ -4,6 +4,7 @@ import json from types import SimpleNamespace +import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from freetoken.message import TokenizeMsg, UserReply @@ -356,6 +357,24 @@ def test_completion_rejects_token_id_prompts(): assert "token-id prompt" in body["error"]["message"] +@pytest.mark.parametrize("stream", [False, True]) +@pytest.mark.parametrize("n", [0, 2]) +def test_completion_refuses_n_other_than_one(n, stream): + state = FakeState([UserReply(uid=42, incremental_output="hello", finished=True)]) + response = run( + handle_completion( + CompletionRequest(model="client-model", prompt="say hi", n=n, stream=stream), + request=None, + state=state, + model_sampling={}, + ) + ) + + assert response.status_code == 400 + assert json.loads(response.body)["error"]["param"] == "n" + assert state.sent is None + + def test_completion_accepts_text_prompt(): state = FakeState( [UserReply(uid=42, incremental_output="hello", finished=True, prompt_tokens_delta=2, completion_tokens_delta=1)]