import json import os from typing import Dict, List, Optional, Union from openai import OpenAI from mem0.configs.llms.base import BaseLlmConfig from mem0.configs.llms.xai import XAIConfig from mem0.llms.base import LLMBase from mem0.memory.utils import extract_json class XAILLM(LLMBase): def __init__(self, config: Optional[Union[BaseLlmConfig, XAIConfig, Dict]] = None): # Convert to XAIConfig if needed if config is None: config = XAIConfig() elif isinstance(config, dict): config = XAIConfig(**config) elif isinstance(config, BaseLlmConfig) and not isinstance(config, XAIConfig): # Convert BaseLlmConfig to XAIConfig so xai_base_url is available config = XAIConfig( model=config.model, temperature=config.temperature, api_key=config.api_key, max_tokens=config.max_tokens, top_p=config.top_p, top_k=config.top_k, enable_vision=config.enable_vision, vision_details=config.vision_details, http_client_proxies=config.http_client, ) super().__init__(config) if not self.config.model: self.config.model = "grok-4.3" api_key = self.config.api_key or os.getenv("XAI_API_KEY") base_url = self.config.xai_base_url or os.getenv("XAI_API_BASE") or "https://api.x.ai/v1" self.client = OpenAI(api_key=api_key, base_url=base_url) def _parse_response(self, response, tools): """ Process the response based on whether tools are used or not. Args: response: The raw response from API. tools: The list of tools provided in the request. Returns: str or dict: The processed response. """ if tools: processed_response = { "content": response.choices[0].message.content, "tool_calls": [], } if response.choices[0].message.tool_calls: for tool_call in response.choices[0].message.tool_calls: processed_response["tool_calls"].append( { "name": tool_call.function.name, "arguments": json.loads(extract_json(tool_call.function.arguments)), } ) return processed_response else: return response.choices[0].message.content def generate_response( self, messages: List[Dict[str, str]], response_format=None, tools: Optional[List[Dict]] = None, tool_choice: str = "auto", **kwargs, ): """ Generate a response based on the given messages using X.AI (Grok). Args: messages (list): List of message dicts containing 'role' and 'content'. response_format (str or object, optional): Format of the response. Defaults to None. tools (list, optional): List of tools that the model can call. Defaults to None. tool_choice (str, optional): Tool choice method. Defaults to "auto". **kwargs: Additional X.AI-specific parameters. Returns: str or dict: The generated response. A string when tools are not requested; a dict ``{"content": ..., "tool_calls": [...]}`` when tools are requested. """ params = self._get_supported_params(messages=messages, **kwargs) params.update( { "model": self.config.model, "messages": messages, } ) if response_format: params["response_format"] = response_format if tools: params["tools"] = tools params["tool_choice"] = tool_choice response = self.client.chat.completions.create(**params) return self._parse_response(response, tools)