From cd14d223292769034ed599b3ffb091adafa47af0 Mon Sep 17 00:00:00 2001 From: XyLearningProgramming Date: Mon, 23 Feb 2026 20:26:30 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=90=9B=20forced=20assist=20content=20?= =?UTF-8?q?to=20be=20not=20empty=20for=20llama=20cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slm_server/model.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/slm_server/model.py b/slm_server/model.py index 6686e82..64f0663 100644 --- a/slm_server/model.py +++ b/slm_server/model.py @@ -13,7 +13,7 @@ ChatCompletionTool, ChatCompletionToolChoiceOption, ) -from pydantic import BaseModel, ConfigDict, Field, conlist, model_validator +from pydantic import BaseModel, ConfigDict, Field, conlist, field_validator, model_validator # --------------------------------------------------------------------------- @@ -93,6 +93,27 @@ class ChatCompletionRequest(BaseModel): default=None, description="Number of top log probabilities to return" ) + @field_validator("messages", mode="before") + @classmethod + def _normalize_assistant_content(cls, v: Any) -> Any: + """Allow ``content: null`` on assistant messages (OpenAI spec compat). + + llama-cpp's TypedDict defines ``content: NotRequired[str]`` which + rejects ``None`` when the key is present. The OpenAI spec allows + ``null`` on assistant messages that carry ``tool_calls``, and + langchain-openai sends it that way, so we normalise here. + """ + if isinstance(v, list): + for msg in v: + if ( + isinstance(msg, dict) + and msg.get("role") == "assistant" + and "content" in msg + and msg["content"] is None + ): + msg["content"] = "" + return v + @model_validator(mode="after") def _default_tool_choice_auto(self) -> Self: """Match OpenAI: default to "auto" when tools are present.""" From ed92c4fc21aaf4b1e367fe6e0368a8aa8275b729 Mon Sep 17 00:00:00 2001 From: XyLearningProgramming Date: Mon, 23 Feb 2026 20:29:05 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=90=9B=20fixed=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slm_server/model.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/slm_server/model.py b/slm_server/model.py index 64f0663..23a4338 100644 --- a/slm_server/model.py +++ b/slm_server/model.py @@ -13,7 +13,14 @@ ChatCompletionTool, ChatCompletionToolChoiceOption, ) -from pydantic import BaseModel, ConfigDict, Field, conlist, field_validator, model_validator +from pydantic import ( + BaseModel, + ConfigDict, + Field, + conlist, + field_validator, + model_validator +) # --------------------------------------------------------------------------- From 1dcc7f8c0b4dca8769c9eedbaa93befac78d8804 Mon Sep 17 00:00:00 2001 From: XyLearningProgramming Date: Mon, 23 Feb 2026 20:32:14 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=90=9B=20fixed=20lint=20again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slm_server/model.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/slm_server/model.py b/slm_server/model.py index 23a4338..608ad46 100644 --- a/slm_server/model.py +++ b/slm_server/model.py @@ -14,11 +14,11 @@ ChatCompletionToolChoiceOption, ) from pydantic import ( - BaseModel, - ConfigDict, - Field, - conlist, - field_validator, + BaseModel, + ConfigDict, + Field, + conlist, + field_validator, model_validator ) From d889ffaa123dc46a5872cc8f742ae2e949f3695e Mon Sep 17 00:00:00 2001 From: XyLearningProgramming Date: Mon, 23 Feb 2026 20:34:51 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=90=9B=20fixed=20lint=20again=20again?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- slm_server/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slm_server/model.py b/slm_server/model.py index 608ad46..b640281 100644 --- a/slm_server/model.py +++ b/slm_server/model.py @@ -19,7 +19,7 @@ Field, conlist, field_validator, - model_validator + model_validator, )