Skip to content
5 changes: 0 additions & 5 deletions docker/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,6 @@ OSS_ACCESS_KEY_ID=
OSS_ACCESS_KEY_SECRET=
OSS_PUBLIC_BASE_URL=

## Logging / external sink
CUSTOM_LOGGER_URL=
CUSTOM_LOGGER_TOKEN=
CUSTOM_LOGGER_WORKERS=2

## SDK / external client
MEMOS_API_KEY=
MEMOS_BASE_URL=https://memos.memtensor.cn/api/openmem/v1
138 changes: 78 additions & 60 deletions src/memos/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@
MemOSAddFeedBackResponse,
MemOSAddKnowledgebaseFileResponse,
MemOSAddResponse,
MemOSChatResponse,
MemOSCreateKnowledgebaseResponse,
MemOSDeleteKnowledgebaseResponse,
MemOSDeleteMemoryResponse,
MemOSGetKnowledgebaseFileResponse,
MemOSGetMemoryResponse,
MemOSGetMessagesResponse,
MemOSGetTaskStatusResponse,
MemOSSearchResponse, MemOSChatResponse,
MemOSSearchResponse,
)

from memos.log import get_logger


logger = get_logger(__name__)

MAX_RETRY_COUNT = 3
Expand All @@ -32,7 +33,7 @@ class MemOSClient:

def __init__(self, api_key: str | None = None, base_url: str | None = None):
self.base_url = (
base_url or os.getenv("MEMOS_BASE_URL") or "https://memos.memtensor.cn/api/openmem/v1"
base_url or os.getenv("MEMOS_BASE_URL") or "https://memos.memtensor.cn/api/openmem/v1"
)
api_key = api_key or os.getenv("MEMOS_API_KEY")

Expand All @@ -48,12 +49,12 @@ def _validate_required_params(self, **params):
raise ValueError(f"{param_name} is required")

def get_message(
self,
user_id: str,
conversation_id: str | None = None,
conversation_limit_number: int = 6,
message_limit_number: int = 6,
source: str | None = None,
self,
user_id: str,
conversation_id: str | None = None,
conversation_limit_number: int = 6,
message_limit_number: int = 6,
source: str | None = None,
) -> MemOSGetMessagesResponse | None:
"""Get messages"""
# Validate required parameters
Expand Down Expand Up @@ -82,18 +83,18 @@ def get_message(
raise

def add_message(
self,
messages: list[dict[str, Any]],
user_id: str,
conversation_id: str,
info: dict[str, Any] | None = None,
source: str | None = None,
app_id: str | None = None,
agent_id: str | None = None,
async_mode: bool = True,
tags: list[str] | None = None,
allow_public: bool = False,
allow_knowledgebase_ids: list[str] | None = None,
self,
messages: list[dict[str, Any]],
user_id: str,
conversation_id: str,
info: dict[str, Any] | None = None,
source: str | None = None,
app_id: str | None = None,
agent_id: str | None = None,
async_mode: bool = True,
tags: list[str] | None = None,
allow_public: bool = False,
allow_knowledgebase_ids: list[str] | None = None,
) -> MemOSAddResponse | None:
"""Add message"""
# Validate required parameters
Expand Down Expand Up @@ -130,18 +131,18 @@ def add_message(
raise

def search_memory(
self,
query: str,
user_id: str,
conversation_id: str,
memory_limit_number: int = 6,
include_preference: bool = True,
knowledgebase_ids: list[str] | None = None,
filter: dict[str, Any] | None = None,
source: str | None = None,
include_tool_memory: bool = False,
preference_limit_number: int = 6,
tool_memory_limit_number: int = 6,
self,
query: str,
user_id: str,
conversation_id: str,
memory_limit_number: int = 6,
include_preference: bool = True,
knowledgebase_ids: list[str] | None = None,
filter: dict[str, Any] | None = None,
source: str | None = None,
include_tool_memory: bool = False,
preference_limit_number: int = 6,
tool_memory_limit_number: int = 6,
) -> MemOSSearchResponse | None:
"""Search memories"""
# Validate required parameters
Expand Down Expand Up @@ -202,7 +203,7 @@ def get_memory(self, user_id: str, include_preference: str) -> MemOSGetMemoryRes
raise

def create_knowledgebase(
self, knowledgebase_name: str, knowledgebase_description: str
self, knowledgebase_name: str, knowledgebase_description: str
) -> MemOSCreateKnowledgebaseResponse | None:
"""
Create knowledgebase
Expand Down Expand Up @@ -234,7 +235,7 @@ def create_knowledgebase(
raise

def delete_knowledgebase(
self, knowledgebase_id: str
self, knowledgebase_id: str
) -> MemOSDeleteKnowledgebaseResponse | None:
"""
Delete knowledgebase
Expand Down Expand Up @@ -262,7 +263,7 @@ def delete_knowledgebase(
raise

def add_knowledgebase_file_json(
self, knowledgebase_id: str, file: list[dict[str, Any]]
self, knowledgebase_id: str, file: list[dict[str, Any]]
) -> MemOSAddKnowledgebaseFileResponse | None:
"""
add knowledgebase-file from json
Expand Down Expand Up @@ -291,7 +292,7 @@ def add_knowledgebase_file_json(
raise

def add_knowledgebase_file_form(
self, knowledgebase_id: str, files: list[str]
self, knowledgebase_id: str, files: list[str]
) -> MemOSAddKnowledgebaseFileResponse | None:
"""
add knowledgebase-file from form
Expand Down Expand Up @@ -328,7 +329,6 @@ def build_file_form_param(file_path):
headers=headers,
timeout=30,
files=[build_file_form_param(file_path) for file_path in files],

)
response.raise_for_status()
response_data = response.json()
Expand All @@ -341,7 +341,7 @@ def build_file_form_param(file_path):
raise

def delete_knowledgebase_file(
self, file_ids: list[str]
self, file_ids: list[str]
) -> MemOSDeleteKnowledgebaseResponse | None:
"""
delete knowledgebase-file
Expand Down Expand Up @@ -369,7 +369,7 @@ def delete_knowledgebase_file(
raise

def get_knowledgebase_file(
self, file_ids: list[str]
self, file_ids: list[str]
) -> MemOSGetKnowledgebaseFileResponse | None:
"""
get knowledgebase-file
Expand Down Expand Up @@ -423,15 +423,15 @@ def get_task_status(self, task_id: str) -> MemOSGetTaskStatusResponse | None:
raise

def add_feedback(
self,
user_id: str,
conversation_id: str,
feedback_content: str,
agent_id: str | None = None,
app_id: str | None = None,
feedback_time: str | None = None,
allow_public: bool = False,
allow_knowledgebase_ids: list[str] | None = None,
self,
user_id: str,
conversation_id: str,
feedback_content: str,
agent_id: str | None = None,
app_id: str | None = None,
feedback_time: str | None = None,
allow_public: bool = False,
allow_knowledgebase_ids: list[str] | None = None,
) -> MemOSAddFeedBackResponse | None:
"""Add feedback"""
# Validate required parameters
Expand Down Expand Up @@ -465,7 +465,7 @@ def add_feedback(
raise

def delete_memory(
self, user_ids: list[str], memory_ids: list[str]
self, user_ids: list[str], memory_ids: list[str]
) -> MemOSDeleteMemoryResponse | None:
"""delete_memory memories"""
# Validate required parameters
Expand All @@ -492,18 +492,37 @@ def delete_memory(
raise

def chat(
self, user_id: str, conversation_id: str, query: str, internet_search: bool = False,
force_stop: bool = False, use_mem_os_cube: bool = False, source: str | None = None,
system_prompt: str | None = None, model_name: str | None = None, knowledgebase_ids: list[str] | None = None,
filter: dict[str: Any] | None = None, add_message_on_answer: bool = False, app_id: str | None = None,
agent_id: str | None = None, async_mode: bool = True, tags: list[str] | None = None,
info: dict[str:Any] | None = None, allow_public: bool = False, max_tokens: int = 8192,
temperature: float | None = None, top_p: float | None = None, include_preference: bool = True,
preference_limit_number: int = 6, memory_limit_number: int = 6,
self,
user_id: str,
conversation_id: str,
query: str,
internet_search: bool = False,
force_stop: bool = False,
use_mem_os_cube: bool = False,
source: str | None = None,
system_prompt: str | None = None,
model_name: str | None = None,
knowledgebase_ids: list[str] | None = None,
filter: dict[str:Any] | None = None,
add_message_on_answer: bool = False,
app_id: str | None = None,
agent_id: str | None = None,
async_mode: bool = True,
tags: list[str] | None = None,
info: dict[str:Any] | None = None,
allow_public: bool = False,
max_tokens: int = 8192,
temperature: float | None = None,
top_p: float | None = None,
include_preference: bool = True,
preference_limit_number: int = 6,
memory_limit_number: int = 6,
) -> MemOSChatResponse | None:
"""chat"""
# Validate required parameters
self._validate_required_params(user_id=user_id, conversation_id=conversation_id, query=query)
self._validate_required_params(
user_id=user_id, conversation_id=conversation_id, query=query
)

url = f"{self.base_url}/chat"
payload = {
Expand Down Expand Up @@ -531,7 +550,6 @@ def chat(
"include_preference": include_preference,
"preference_limit_number": preference_limit_number,
"memory_limit_number": memory_limit_number,

}

for retry in range(MAX_RETRY_COUNT):
Expand Down
8 changes: 5 additions & 3 deletions src/memos/api/product_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,7 @@ class DeleteMessageData(BaseModel):

success: bool = Field(..., description="Operation success status")


class ChatMessageData(BaseModel):
"""Data model for chat Message based on actual API."""

Expand Down Expand Up @@ -950,6 +951,7 @@ def success(self) -> bool:
"""Convenient access to success status."""
return self.data.success


class MemOSChatResponse(BaseModel):
"""Response model for chat operation based on actual API."""

Expand All @@ -968,11 +970,11 @@ class MemOSGetTaskStatusResponse(BaseModel):

code: int = Field(..., description="Response status code")
message: str = Field(..., description="Response message")
data: list[GetTaskStatusMessageData] = Field(..., description="delete results data")
data: list[GetTaskStatusMessageData] = Field(..., description="Task status data")

@property
def data(self) -> list[GetTaskStatusMessageData]:
"""Convenient access to task status."""
def messages(self) -> list[GetTaskStatusMessageData]:
"""Convenient access to task status messages."""
return self.data


Expand Down
49 changes: 27 additions & 22 deletions src/memos/llms/openai.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,23 @@ def __init__(self, config: OpenAILLMConfig):
@timed_with_status(
log_prefix="OpenAI LLM",
log_extra_args=lambda self, messages, **kwargs: {
"model_name_or_path": kwargs.get("model_name_or_path", self.config.model_name_or_path)
"model_name_or_path": kwargs.get("model_name_or_path", self.config.model_name_or_path),
"messages": messages,
},
)
def generate(self, messages: MessageList, **kwargs) -> str:
"""Generate a response from OpenAI LLM, optionally overriding generation params."""
response = self.client.chat.completions.create(
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),
timeout=kwargs.get("timeout", 30),
)
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),
}
logger.info(f"OpenAI LLM Request body: {request_body}")
response = self.client.chat.completions.create(**request_body)
logger.info(f"Response from OpenAI: {response.model_dump_json()}")
tool_calls = getattr(response.choices[0].message, "tool_calls", None)
if isinstance(tool_calls, list) and len(tool_calls) > 0:
Expand All @@ -61,7 +63,7 @@ def generate(self, messages: MessageList, **kwargs) -> str:
return response_content

@timed_with_status(
log_prefix="OpenAI LLM",
log_prefix="OpenAI LLM Stream",
log_extra_args=lambda self, messages, **kwargs: {
"model_name_or_path": self.config.model_name_or_path
},
Expand All @@ -72,16 +74,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),
tools=kwargs.get("tools", NOT_GIVEN),
)
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),
}

logger.info(f"OpenAI LLM Stream Request body: {request_body}")
response = self.client.chat.completions.create(**request_body)

reasoning_started = False

Expand Down
Loading