Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/memos/configs/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class OpenAILLMConfig(BaseLLMConfig):
default="https://api.openai.com/v1", description="Base URL for OpenAI API"
)
extra_body: Any = Field(default=None, description="extra body")
enable_thinking: bool | None = Field(
default=None,
description="Enable/disable thinking mode for models that support it (e.g. Qwen3, DeepSeek-R1). "
"When None (default), the provider's default behavior is preserved.",
)
backup_client: bool = Field(
default=False,
description="Whether to enable backup client for fallback on primary failure",
Expand Down Expand Up @@ -91,6 +96,12 @@ class AzureLLMConfig(BaseLLMConfig):
description="API version for Azure OpenAI",
)
api_key: str = Field(..., description="API key for Azure OpenAI")
extra_body: Any = Field(default=None, description="Extra request body parameters")
enable_thinking: bool | None = Field(
default=None,
description="Enable/disable thinking mode for models that support it. "
"When None (default), the provider's default behavior is preserved.",
)


class AzureResponsesLLMConfig(BaseLLMConfig):
Expand Down
90 changes: 53 additions & 37 deletions src/memos/llms/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import time

from collections.abc import Generator
from typing import Any

import openai

Expand All @@ -19,6 +20,13 @@
logger = get_logger(__name__)


def _merge_enable_thinking(extra_body: Any, enable_thinking: bool | None) -> Any:
"""Merge provider-specific thinking control into the SDK's extra request body."""
if enable_thinking is None:
return extra_body
return {**(extra_body or {}), "enable_thinking": enable_thinking}


class OpenAILLM(BaseLLM):
"""OpenAI LLM class via openai.chat.completions.create."""

Expand Down Expand Up @@ -61,6 +69,22 @@ def _parse_response(self, response) -> str:
return reasoning_content + (response_content or "")
return response_content or ""

def _build_request_body(self, messages: MessageList, **kwargs) -> dict:
enable_thinking = kwargs.get("enable_thinking", self.config.enable_thinking)
extra_body = _merge_enable_thinking(
kwargs.get("extra_body", self.config.extra_body), enable_thinking
)
request_body = {
"model": kwargs.get("model_name_or_path", self.config.model_name_or_path),
"messages": messages,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
"top_p": kwargs.get("top_p", self.config.top_p),
"extra_body": extra_body,
"tools": kwargs.get("tools", NOT_GIVEN),
}
return request_body

@timed_with_status(
log_prefix="OpenAI LLM",
log_extra_args=lambda self, messages, **kwargs: {
Expand All @@ -70,15 +94,7 @@ def _parse_response(self, response) -> str:
)
def generate(self, messages: MessageList, **kwargs) -> str:
"""Generate a response from OpenAI LLM, optionally overriding generation params."""
request_body = {
"model": kwargs.get("model_name_or_path", self.config.model_name_or_path),
"messages": messages,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
"top_p": kwargs.get("top_p", self.config.top_p),
"extra_body": kwargs.get("extra_body", self.config.extra_body),
"tools": kwargs.get("tools", NOT_GIVEN),
}
request_body = self._build_request_body(messages, **kwargs)
start_time = time.perf_counter()
logger.info(f"OpenAI LLM Request body: {request_body}")

Expand Down Expand Up @@ -121,16 +137,8 @@ def generate_stream(self, messages: MessageList, **kwargs) -> Generator[str, Non
logger.info("stream api not support tools")
return

request_body = {
"model": self.config.model_name_or_path,
"messages": messages,
"stream": True,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
"top_p": kwargs.get("top_p", self.config.top_p),
"extra_body": kwargs.get("extra_body", self.config.extra_body),
"tools": kwargs.get("tools", NOT_GIVEN),
}
request_body = self._build_request_body(messages, **kwargs)
request_body["stream"] = True

logger.info(f"OpenAI LLM Stream Request body: {request_body}")
response = self.client.chat.completions.create(**request_body)
Expand Down Expand Up @@ -184,15 +192,19 @@ def __init__(self, config: AzureLLMConfig):

def generate(self, messages: MessageList, **kwargs) -> str:
"""Generate a response from Azure OpenAI LLM."""
response = self.client.chat.completions.create(
model=self.config.model_name_or_path,
messages=messages,
temperature=kwargs.get("temperature", self.config.temperature),
max_tokens=kwargs.get("max_tokens", self.config.max_tokens),
top_p=kwargs.get("top_p", self.config.top_p),
tools=kwargs.get("tools", NOT_GIVEN),
extra_body=kwargs.get("extra_body", self.config.extra_body),
)
enable_thinking = kwargs.get("enable_thinking", self.config.enable_thinking)
request_body = {
"model": self.config.model_name_or_path,
"messages": messages,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
"top_p": kwargs.get("top_p", self.config.top_p),
"tools": kwargs.get("tools", NOT_GIVEN),
"extra_body": _merge_enable_thinking(
kwargs.get("extra_body", self.config.extra_body), enable_thinking
),
}
response = self.client.chat.completions.create(**request_body)
logger.info(f"Response from Azure OpenAI: {response.model_dump_json()}")
if not response.choices:
logger.warning("Azure OpenAI response has no choices")
Expand All @@ -212,15 +224,19 @@ def generate_stream(self, messages: MessageList, **kwargs) -> Generator[str, Non
logger.info("stream api not support tools")
return

response = self.client.chat.completions.create(
model=self.config.model_name_or_path,
messages=messages,
stream=True,
temperature=kwargs.get("temperature", self.config.temperature),
max_tokens=kwargs.get("max_tokens", self.config.max_tokens),
top_p=kwargs.get("top_p", self.config.top_p),
extra_body=kwargs.get("extra_body", self.config.extra_body),
)
enable_thinking = kwargs.get("enable_thinking", self.config.enable_thinking)
request_body = {
"model": self.config.model_name_or_path,
"messages": messages,
"stream": True,
"temperature": kwargs.get("temperature", self.config.temperature),
"max_tokens": kwargs.get("max_tokens", self.config.max_tokens),
"top_p": kwargs.get("top_p", self.config.top_p),
"extra_body": _merge_enable_thinking(
kwargs.get("extra_body", self.config.extra_body), enable_thinking
),
}
response = self.client.chat.completions.create(**request_body)

reasoning_started = False

Expand Down
2 changes: 2 additions & 0 deletions tests/configs/test_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def test_openai_llm_config():
"remove_think_prefix",
"extra_body",
"default_headers",
"enable_thinking",
"backup_client",
"backup_api_key",
"backup_api_base",
Expand Down Expand Up @@ -159,6 +160,7 @@ def test_minimax_llm_config():
"remove_think_prefix",
"extra_body",
"default_headers",
"enable_thinking",
"backup_client",
"backup_api_key",
"backup_api_base",
Expand Down
Loading
Loading