diff --git a/letta/schemas/agent.py b/letta/schemas/agent.py index c507e202..b7cee629 100644 --- a/letta/schemas/agent.py +++ b/letta/schemas/agent.py @@ -212,6 +212,7 @@ class CreateAgent(BaseModel, validate_assignment=True): # None, description="The maximum number of tokens to generate for reasoning step. If not set, the model will use its default value." ) enable_reasoner: Optional[bool] = Field(False, description="Whether to enable internal extended thinking step for a reasoner model.") + reasoning: Optional[bool] = Field(None, description="Whether to enable reasoning for this agent.") from_template: Optional[str] = Field(None, description="The template id used to configure the agent") template: bool = Field(False, description="Whether the agent is a template") project: Optional[str] = Field( @@ -335,6 +336,7 @@ class UpdateAgent(BaseModel): embedding: Optional[str] = Field( None, description="The embedding configuration handle used by the agent, specified in the format provider/model-name." ) + reasoning: Optional[bool] = Field(None, description="Whether to enable reasoning for this agent.") enable_sleeptime: Optional[bool] = Field(None, description="If set to True, memory management will move to a background agent thread.") response_format: Optional[ResponseFormatUnion] = Field(None, description="The response format for the agent.") last_run_completion: Optional[datetime] = Field(None, description="The timestamp when the agent last completed a run.") diff --git a/letta/schemas/llm_config.py b/letta/schemas/llm_config.py index 0c9fc2cb..b1134154 100644 --- a/letta/schemas/llm_config.py +++ b/letta/schemas/llm_config.py @@ -183,3 +183,30 @@ class LLMConfig(BaseModel): + (f" [type={self.model_endpoint_type}]" if self.model_endpoint_type else "") + (f" [ip={self.model_endpoint}]" if self.model_endpoint else "") ) + + @classmethod + def apply_reasoning_setting_to_config(cls, config: "LLMConfig", reasoning: bool): + if reasoning: + if ( + config.model_endpoint_type == "anthropic" + and ("claude-opus-4" in config.model or "claude-sonnet-4" in config.model or "claude-3-7-sonnet" in config.model) + ) or ( + config.model_endpoint_type == "google_vertex" and ("gemini-2.5-flash" in config.model or "gemini-2.0-pro" in config.model) + ): + config.put_inner_thoughts_in_kwargs = False + config.enable_reasoner = True + if config.max_reasoning_tokens == 0: + config.max_reasoning_tokens = 1024 + elif config.model_endpoint_type == "openai" and ( + config.model.startswith("o1") or config.model.startswith("o3") or config.model.startswith("o4") + ): + config.put_inner_thoughts_in_kwargs = True + config.enable_reasoner = True + if config.reasoning_effort is None: + config.reasoning_effort = "medium" + else: + config.put_inner_thoughts_in_kwargs = True + config.enable_reasoner = False + else: + config.put_inner_thoughts_in_kwargs = False + config.enable_reasoner = False diff --git a/letta/services/agent_manager.py b/letta/services/agent_manager.py index c9302599..6d4d6404 100644 --- a/letta/services/agent_manager.py +++ b/letta/services/agent_manager.py @@ -51,6 +51,7 @@ from letta.schemas.enums import ProviderType, ToolType from letta.schemas.file import FileMetadata as PydanticFileMetadata from letta.schemas.group import Group as PydanticGroup from letta.schemas.group import ManagerType +from letta.schemas.llm_config import LLMConfig from letta.schemas.memory import ContextWindowOverview, Memory from letta.schemas.message import Message from letta.schemas.message import Message as PydanticMessage @@ -452,6 +453,9 @@ class AgentManager: if not agent_create.llm_config or not agent_create.embedding_config: raise ValueError("llm_config and embedding_config are required") + if agent_create.reasoning is not None: + agent_create.llm_config = LLMConfig.apply_reasoning_setting_to_config(agent_create.llm_config, agent_create.reasoning) + # blocks block_ids = list(agent_create.block_ids or []) if agent_create.memory_blocks: @@ -877,6 +881,10 @@ class AgentManager: agent.updated_at = datetime.now(timezone.utc) agent.last_updated_by_id = actor.id + if agent_update.reasoning is not None: + llm_config = agent_update.llm_config or agent.llm_config + agent_update.llm_config = LLMConfig.apply_reasoning_setting_to_config(llm_config, agent_update.reasoning) + scalar_updates = { "name": agent_update.name, "system": agent_update.system,