Files
letta-server/letta/schemas/agent.py
Kian Jones a206f7f345 feat: add ID format validation to agent and user schemas (#9151)
* feat: add ID format validation to agent and user schemas

Reuse existing validator types (ToolId, SourceId, BlockId, MessageId,
IdentityId, UserId) from letta.validators to enforce ID format validation
at the schema level. This ensures malformed IDs are rejected with a 422
validation error instead of causing 500 database errors.

Changes:
- CreateAgent: validate tool_ids, source_ids, folder_ids, block_ids, identity_ids
- UpdateAgent: validate tool_ids, source_ids, folder_ids, block_ids, message_ids, identity_ids
- UserUpdate: validate id

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* chore: regenerate API spec and SDK

* fix: override ID validation in AgentSchema for agent file portability

AgentSchema extends CreateAgent but needs to allow arbitrary short IDs
(e.g., tool-0, block-0) for portable agent files. Override the validated
ID fields to use plain List[str] instead of the validated types.

Also fix test_agent.af to use proper UUID-format IDs.

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* chore: regenerate API spec and SDK

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* fix: revert test_agent.af - short IDs are valid for agent files

🤖 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* fix openapi schema

---------

Co-authored-by: Letta <noreply@letta.com>
2026-02-24 10:52:06 -08:00

564 lines
30 KiB
Python

from datetime import datetime
from enum import Enum
from typing import Dict, List, Literal, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from letta.constants import (
CORE_MEMORY_LINE_NUMBER_WARNING,
DEFAULT_EMBEDDING_CHUNK_SIZE,
MAX_FILES_OPEN_LIMIT,
MAX_PER_FILE_VIEW_WINDOW_CHAR_LIMIT,
)
from letta.errors import AgentExportProcessingError, LettaInvalidArgumentError
from letta.schemas.block import Block, CreateBlock
from letta.schemas.embedding_config import EmbeddingConfig
from letta.schemas.enums import PrimitiveType
from letta.schemas.environment_variables import AgentEnvironmentVariable
from letta.schemas.file import FileStatus
from letta.schemas.group import Group
from letta.schemas.identity import Identity
from letta.schemas.letta_base import OrmMetadataBase
from letta.schemas.letta_message import ApprovalRequestMessage
from letta.schemas.letta_stop_reason import StopReasonType
from letta.schemas.llm_config import LLMConfig
from letta.schemas.memory import Memory
from letta.schemas.message import Message, MessageCreate
from letta.schemas.model import ModelSettingsUnion
from letta.schemas.openai.chat_completion_response import UsageStatistics
from letta.schemas.response_format import ResponseFormatUnion
from letta.schemas.source import Source
from letta.schemas.tool import Tool
from letta.schemas.tool_rule import ToolRule
from letta.services.summarizer.summarizer_config import CompactionSettings
from letta.utils import calculate_file_defaults_based_on_context_window, create_random_username
from letta.validators import BlockId, IdentityId, MessageId, SourceId, ToolId
# TODO: Remove this upon next OSS release, there's a duplicate AgentType in enums
# TODO: This is done in the interest of time to avoid needing to update the sandbox template IDs on cloud/rebuild
class AgentType(str, Enum):
"""
Enum to represent the type of agent.
"""
memgpt_agent = "memgpt_agent" # the OG set of memgpt tools
memgpt_v2_agent = "memgpt_v2_agent" # memgpt style tools, but refreshed
letta_v1_agent = "letta_v1_agent" # simplification of the memgpt loop, no heartbeats or forced tool calls
react_agent = "react_agent" # basic react agent, no memory tools
workflow_agent = "workflow_agent" # workflow with auto-clearing message buffer
split_thread_agent = "split_thread_agent"
sleeptime_agent = "sleeptime_agent"
voice_convo_agent = "voice_convo_agent"
voice_sleeptime_agent = "voice_sleeptime_agent"
# Relationship field literal type for AgentState include field to join related objects
AgentRelationships = Literal[
"agent.blocks",
"agent.identities",
"agent.managed_group",
"agent.pending_approval",
"agent.secrets",
"agent.sources",
"agent.tags",
"agent.tools",
]
class AgentState(OrmMetadataBase, validate_assignment=True):
"""Representation of an agent's state. This is the state of the agent at a given time, and is persisted in the DB backend. The state has all the information needed to recreate a persisted agent."""
__id_prefix__ = PrimitiveType.AGENT.value
# NOTE: this is what is returned to the client and also what is used to initialize `Agent`
id: str = Field(..., description="The id of the agent. Assigned by the database.")
name: str = Field(..., description="The name of the agent.")
# tool rules
tool_rules: Optional[List[ToolRule]] = Field(default=None, description="The list of tool rules.")
# in-context memory
message_ids: Optional[List[str]] = Field(default=None, description="The ids of the messages in the agent's in-context memory.")
# system prompt
system: str = Field(..., description="The system prompt used by the agent.")
# agent configuration
agent_type: AgentType = Field(..., description="The type of agent.")
# model information
llm_config: LLMConfig = Field(
..., description="Deprecated: Use `model` field instead. The LLM configuration used by the agent.", deprecated=True
)
embedding_config: Optional[EmbeddingConfig] = Field(
None, description="Deprecated: Use `embedding` field instead. The embedding configuration used by the agent.", deprecated=True
)
model: Optional[str] = Field(None, description="The model handle used by the agent (format: provider/model-name).")
embedding: Optional[str] = Field(None, description="The embedding model handle used by the agent (format: provider/model-name).")
model_settings: Optional[ModelSettingsUnion] = Field(None, description="The model settings used by the agent.")
compaction_settings: Optional[CompactionSettings] = Field(
None, description="The compaction settings configuration used for compaction."
)
response_format: Optional[ResponseFormatUnion] = Field(
None,
description="The response format used by the agent",
)
# This is an object representing the in-process state of a running `Agent`
# Field in this object can be theoretically edited by tools, and will be persisted by the ORM
description: Optional[str] = Field(None, description="The description of the agent.")
metadata: Optional[Dict] = Field(None, description="The metadata of the agent.")
memory: Memory = Field(..., description="Deprecated: Use `blocks` field instead. The in-context memory of the agent.", deprecated=True)
blocks: List[Block] = Field(..., description="The memory blocks used by the agent.")
tools: List[Tool] = Field(..., description="The tools used by the agent.")
sources: List[Source] = Field(
..., description="Deprecated: Use `folders` field instead. The sources used by the agent.", deprecated=True
)
tags: List[str] = Field(..., description="The tags associated with the agent.")
tool_exec_environment_variables: List[AgentEnvironmentVariable] = Field(
default_factory=list,
description="Deprecated: use `secrets` field instead.",
deprecated=True,
)
secrets: List[AgentEnvironmentVariable] = Field(
default_factory=list, description="The environment variables for tool execution specific to this agent."
)
project_id: Optional[str] = Field(None, description="The id of the project the agent belongs to.")
template_id: Optional[str] = Field(None, description="The id of the template the agent belongs to.")
base_template_id: Optional[str] = Field(None, description="The base template id of the agent.")
deployment_id: Optional[str] = Field(None, description="The id of the deployment.")
entity_id: Optional[str] = Field(None, description="The id of the entity within the template.")
identity_ids: List[str] = Field(
[], description="Deprecated: Use `identities` field instead. The ids of the identities associated with this agent.", deprecated=True
)
identities: List[Identity] = Field([], description="The identities associated with this agent.")
pending_approval: Optional[ApprovalRequestMessage] = Field(
None, description="The latest approval request message pending for this agent, if any."
)
# An advanced configuration that makes it so this agent does not remember any previous messages
message_buffer_autoclear: bool = Field(
False,
description="If set to True, the agent will not remember previous messages (though the agent will still retain state via core memory blocks and archival/recall memory). Not recommended unless you have an advanced use case.",
)
enable_sleeptime: Optional[bool] = Field(
None,
description="If set to True, memory management will move to a background agent thread.",
)
multi_agent_group: Optional[Group] = Field(
None, description="Deprecated: Use `managed_group` field instead. The multi-agent group that this agent manages.", deprecated=True
)
managed_group: Optional[Group] = Field(None, description="The multi-agent group that this agent manages")
# Run metrics
last_run_completion: Optional[datetime] = Field(None, description="The timestamp when the agent last completed a run.")
last_run_duration_ms: Optional[int] = Field(None, description="The duration in milliseconds of the agent's last run.")
last_stop_reason: Optional[StopReasonType] = Field(None, description="The stop reason from the agent's last run.")
# timezone
timezone: Optional[str] = Field(None, description="The timezone of the agent (IANA format).")
# file related controls
max_files_open: Optional[int] = Field(
None,
description="Maximum number of files that can be open at once for this agent. Setting this too high may exceed the context window, which will break the agent.",
)
per_file_view_window_char_limit: Optional[int] = Field(
None,
description="The per-file view window character limit for this agent. Setting this too high may exceed the context window, which will break the agent.",
)
# indexing controls
hidden: Optional[bool] = Field(
None,
description="If set to True, the agent will be hidden.",
)
def get_agent_env_vars_as_dict(self) -> Dict[str, str]:
# Get environment variables for this agent (value is already decrypted via from_orm_async)
per_agent_env_vars = {}
for agent_env_var_obj in self.secrets:
# Use the pre-decrypted value field (populated by from_orm_async)
per_agent_env_vars[agent_env_var_obj.key] = agent_env_var_obj.value or ""
return per_agent_env_vars
@model_validator(mode="after")
def set_file_defaults_based_on_context_window(self) -> "AgentState":
"""Set reasonable defaults for file-related fields based on the model's context window size."""
# Only set defaults if not explicitly provided
if self.max_files_open is not None and self.per_file_view_window_char_limit is not None:
return self
# Get context window size from llm_config
context_window = self.llm_config.context_window if self.llm_config and self.llm_config.context_window else None
# Calculate defaults using the helper function
default_max_files, default_char_limit = calculate_file_defaults_based_on_context_window(context_window)
# Apply defaults only if not set
if self.max_files_open is None:
self.max_files_open = default_max_files
if self.per_file_view_window_char_limit is None:
self.per_file_view_window_char_limit = default_char_limit
return self
class CreateAgent(BaseModel, validate_assignment=True): #
# all optional as server can generate defaults
name: str = Field(default_factory=lambda: create_random_username(), description="The name of the agent.")
# memory creation
memory_blocks: Optional[List[CreateBlock]] = Field(
None,
description="The blocks to create in the agent's in-context memory.",
)
# TODO: This is a legacy field and should be removed ASAP to force `tool_ids` usage
tools: Optional[List[str]] = Field(None, description="The tools used by the agent.")
tool_ids: Optional[List[ToolId]] = Field(None, description="The ids of the tools used by the agent.")
source_ids: Optional[List[SourceId]] = Field(
None, description="Deprecated: Use `folder_ids` field instead. The ids of the sources used by the agent.", deprecated=True
)
folder_ids: Optional[List[SourceId]] = Field(None, description="The ids of the folders used by the agent.")
block_ids: Optional[List[BlockId]] = Field(None, description="The ids of the blocks used by the agent.")
tool_rules: Optional[List[ToolRule]] = Field(None, description="The tool rules governing the agent.")
tags: Optional[List[str]] = Field(None, description="The tags associated with the agent.")
system: Optional[str] = Field(None, description="The system prompt used by the agent.")
agent_type: AgentType = Field(default_factory=lambda: AgentType.letta_v1_agent, description="The type of agent.")
# Note: if this is None, then we'll populate with the standard "more human than human" initial message sequence
# If the client wants to make this empty, then the client can set the arg to an empty list
initial_message_sequence: Optional[List[MessageCreate]] = Field(
None, description="The initial set of messages to put in the agent's in-context memory."
)
include_base_tools: bool = Field(True, description="If true, attaches the Letta core tools (e.g. core_memory related functions).")
include_multi_agent_tools: bool = Field(
False, description="If true, attaches the Letta multi-agent tools (e.g. sending a message to another agent)."
)
include_base_tool_rules: Optional[bool] = Field(
None, description="If true, attaches the Letta base tool rules (e.g. deny all tools not explicitly allowed)."
)
include_default_source: bool = Field( # TODO: get rid of this
False, description="If true, automatically creates and attaches a default data source for this agent.", deprecated=True
)
description: Optional[str] = Field(None, description="The description of the agent.")
metadata: Optional[Dict] = Field(None, description="The metadata of the agent.")
# model configuration
llm_config: Optional[LLMConfig] = Field(
None, description="Deprecated: Use `model` field instead. The LLM configuration used by the agent.", deprecated=True
)
embedding_config: Optional[EmbeddingConfig] = Field(
None, description="Deprecated: Use `embedding` field instead. The embedding configuration used by the agent.", deprecated=True
)
model: Optional[str] = Field( # TODO: make this required (breaking change)
None,
description="The model handle for the agent to use (format: provider/model-name).",
)
embedding: Optional[str] = Field(None, description="The embedding model handle used by the agent (format: provider/model-name).")
model_settings: Optional[ModelSettingsUnion] = Field(None, description="The model settings for the agent.")
compaction_settings: Optional[CompactionSettings] = Field(
None, description="The compaction settings configuration used for compaction."
)
context_window_limit: Optional[int] = Field(None, description="The context window limit used by the agent.")
embedding_chunk_size: Optional[int] = Field(
DEFAULT_EMBEDDING_CHUNK_SIZE, description="Deprecated: No longer used. The embedding chunk size used by the agent.", deprecated=True
)
max_tokens: Optional[int] = Field(
None,
description="Deprecated: Use `model` field to configure max output tokens instead. The maximum number of tokens to generate, including reasoning step.",
deprecated=True,
)
max_reasoning_tokens: Optional[int] = Field(
None,
description="Deprecated: Use `model` field to configure reasoning tokens instead. The maximum number of tokens to generate for reasoning step.",
deprecated=True,
)
enable_reasoner: Optional[bool] = Field(
True,
description="Deprecated: Use `model` field to configure reasoning instead. Whether to enable internal extended thinking step for a reasoner model.",
deprecated=True,
)
reasoning: Optional[bool] = Field(
None,
description="Deprecated: Use `model` field to configure reasoning instead. Whether to enable reasoning for this agent.",
deprecated=True,
)
from_template: Optional[str] = Field(
None, description="Deprecated: please use the 'create agents from a template' endpoint instead.", deprecated=True
)
template: bool = Field(False, description="Deprecated: No longer used.", deprecated=True)
project: Optional[str] = Field(
None,
deprecated=True,
description="Deprecated: Project should now be passed via the X-Project header instead of in the request body. If using the SDK, this can be done via the x_project parameter.",
)
tool_exec_environment_variables: Optional[Dict[str, str]] = Field(
None, description="Deprecated: Use `secrets` field instead. Environment variables for tool execution.", deprecated=True
)
secrets: Optional[Dict[str, str]] = Field(None, description="The environment variables for tool execution specific to this agent.")
memory_variables: Optional[Dict[str, str]] = Field(
None,
description="Deprecated: Only relevant for creating agents from a template. Use the 'create agents from a template' endpoint instead.",
deprecated=True,
)
project_id: Optional[str] = Field(
None, description="Deprecated: No longer used. The id of the project the agent belongs to.", deprecated=True
)
template_id: Optional[str] = Field(
None, description="Deprecated: No longer used. The id of the template the agent belongs to.", deprecated=True
)
base_template_id: Optional[str] = Field(
None, description="Deprecated: No longer used. The base template id of the agent.", deprecated=True
)
identity_ids: Optional[List[IdentityId]] = Field(None, description="The ids of the identities associated with this agent.")
message_buffer_autoclear: bool = Field(
False,
description="If set to True, the agent will not remember previous messages (though the agent will still retain state via core memory blocks and archival/recall memory). Not recommended unless you have an advanced use case.",
)
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="Deprecated: Use `model_settings` field to configure response format instead. The response format for the agent.",
deprecated=True,
)
timezone: Optional[str] = Field(None, description="The timezone of the agent (IANA format).")
max_files_open: Optional[int] = Field(
None,
description="Maximum number of files that can be open at once for this agent. Setting this too high may exceed the context window, which will break the agent.",
)
per_file_view_window_char_limit: Optional[int] = Field(
None,
description="The per-file view window character limit for this agent. Setting this too high may exceed the context window, which will break the agent.",
)
hidden: Optional[bool] = Field(
None,
description="Deprecated: No longer used. If set to True, the agent will be hidden.",
deprecated=True,
)
parallel_tool_calls: Optional[bool] = Field(
None,
description="Deprecated: Use `model_settings` to configure parallel tool calls instead. If set to True, enables parallel tool calling.",
deprecated=True,
)
@field_validator("name")
@classmethod
def validate_name(cls, name: str) -> str:
"""Validate the requested new agent name (prevent bad inputs)"""
import re
if not name:
# don't check if not provided
return name
# Regex for allowed characters (Unicode letters, digits, spaces, hyphens, underscores, apostrophes)
# \w in Python 3 with re.UNICODE matches Unicode letters, digits, and underscores
# We explicitly allow: letters (any language), digits, spaces, hyphens, underscores, apostrophes
# We block filesystem-unsafe characters: / \ : * ? " < > |
if not re.match(r"^[\w '\-]+$", name, re.UNICODE):
raise AgentExportProcessingError(
f"Agent name '{name}' contains invalid characters. Only letters (any language), digits, spaces, "
f"hyphens, underscores, and apostrophes are allowed. Please avoid filesystem-unsafe characters "
f'like: / \\ : * ? " < > |'
)
# Further checks can be added here...
# TODO
return name
@field_validator("model")
@classmethod
def validate_model(cls, model: Optional[str]) -> Optional[str]:
if not model:
return model
if "/" not in model:
raise LettaInvalidArgumentError("The model handle should be in the format provider/model-name", argument_name="model")
provider_name, model_name = model.split("/", 1)
if not provider_name or not model_name:
raise LettaInvalidArgumentError("The model handle should be in the format provider/model-name", argument_name="model")
return model
@field_validator("embedding")
@classmethod
def validate_embedding(cls, embedding: Optional[str]) -> Optional[str]:
if not embedding:
return embedding
if "/" not in embedding:
raise ValueError("The embedding handle should be in the format provider/model-name")
provider_name, embedding_name = embedding.split("/", 1)
if not provider_name or not embedding_name:
raise ValueError("The embedding handle should be in the format provider/model-name")
return embedding
@field_validator("max_files_open")
@classmethod
def validate_max_files_open(cls, value: Optional[int]) -> Optional[int]:
"""Validate max_files_open is within acceptable range."""
if value is not None and value > MAX_FILES_OPEN_LIMIT:
raise LettaInvalidArgumentError(
f"max_files_open cannot exceed {MAX_FILES_OPEN_LIMIT}. Got: {value}",
argument_name="max_files_open",
)
return value
@field_validator("per_file_view_window_char_limit")
@classmethod
def validate_per_file_view_window_char_limit(cls, value: Optional[int]) -> Optional[int]:
"""Validate per_file_view_window_char_limit is within int32 range for database compatibility."""
if value is not None and value > MAX_PER_FILE_VIEW_WINDOW_CHAR_LIMIT:
raise LettaInvalidArgumentError(
f"per_file_view_window_char_limit cannot exceed {MAX_PER_FILE_VIEW_WINDOW_CHAR_LIMIT}. Got: {value}",
argument_name="per_file_view_window_char_limit",
)
return value
@model_validator(mode="after")
def validate_sleeptime_for_agent_type(self) -> "CreateAgent":
"""Validate that enable_sleeptime is True when agent_type is a specific value"""
AGENT_TYPES_REQUIRING_SLEEPTIME = {AgentType.voice_convo_agent}
if self.agent_type in AGENT_TYPES_REQUIRING_SLEEPTIME:
if not self.enable_sleeptime:
raise ValueError(f"Agent type {self.agent_type} requires enable_sleeptime to be True")
return self
class InternalTemplateAgentCreate(CreateAgent):
"""Used for Letta Cloud"""
base_template_id: str = Field(..., description="The id of the base template.")
template_id: str = Field(..., description="The id of the template.")
deployment_id: str = Field(..., description="The id of the deployment.")
entity_id: str = Field(..., description="The id of the entity within the template.")
class UpdateAgent(BaseModel):
name: Optional[str] = Field(None, description="The name of the agent.")
tool_ids: Optional[List[ToolId]] = Field(None, description="The ids of the tools used by the agent.")
source_ids: Optional[List[SourceId]] = Field(
None, description="Deprecated: Use `folder_ids` field instead. The ids of the sources used by the agent.", deprecated=True
)
folder_ids: Optional[List[SourceId]] = Field(None, description="The ids of the folders used by the agent.")
block_ids: Optional[List[BlockId]] = Field(None, description="The ids of the blocks used by the agent.")
tags: Optional[List[str]] = Field(None, description="The tags associated with the agent.")
system: Optional[str] = Field(None, description="The system prompt used by the agent.")
tool_rules: Optional[List[ToolRule]] = Field(None, description="The tool rules governing the agent.")
message_ids: Optional[List[MessageId]] = Field(None, description="The ids of the messages in the agent's in-context memory.")
description: Optional[str] = Field(None, description="The description of the agent.")
metadata: Optional[Dict] = Field(None, description="The metadata of the agent.")
tool_exec_environment_variables: Optional[Dict[str, str]] = Field(None, description="Deprecated: use `secrets` field instead")
secrets: Optional[Dict[str, str]] = Field(None, description="The environment variables for tool execution specific to this agent.")
project_id: Optional[str] = Field(None, description="The id of the project the agent belongs to.")
template_id: Optional[str] = Field(None, description="The id of the template the agent belongs to.")
base_template_id: Optional[str] = Field(None, description="The base template id of the agent.")
identity_ids: Optional[List[IdentityId]] = Field(None, description="The ids of the identities associated with this agent.")
message_buffer_autoclear: Optional[bool] = Field(
None,
description="If set to True, the agent will not remember previous messages (though the agent will still retain state via core memory blocks and archival/recall memory). Not recommended unless you have an advanced use case.",
)
# model configuration
model: Optional[str] = Field(
None,
description="The model handle used by the agent (format: provider/model-name).",
)
embedding: Optional[str] = Field(None, description="The embedding model handle used by the agent (format: provider/model-name).")
model_settings: Optional[ModelSettingsUnion] = Field(None, description="The model settings for the agent.")
compaction_settings: Optional[CompactionSettings] = Field(
None, description="The compaction settings configuration used for compaction."
)
context_window_limit: Optional[int] = Field(None, description="The context window limit used by the agent.")
reasoning: Optional[bool] = Field(
None,
description="Deprecated: Use `model` field to configure reasoning instead. Whether to enable reasoning for this agent.",
deprecated=True,
)
llm_config: Optional[LLMConfig] = Field(
None, description="Deprecated: Use `model` field instead. The LLM configuration used by the agent.", deprecated=True
)
embedding_config: Optional[EmbeddingConfig] = Field(None, description="The embedding configuration used by the agent.")
parallel_tool_calls: Optional[bool] = Field(
None,
description="Deprecated: Use `model_settings` to configure parallel tool calls instead. If set to True, enables parallel tool calling.",
deprecated=True,
)
response_format: Optional[ResponseFormatUnion] = Field(
None,
description="Deprecated: Use `model_settings` field to configure response format instead. The response format for the agent.",
deprecated=True,
)
max_tokens: Optional[int] = Field(
None,
description="Deprecated: Use `model` field to configure max output tokens instead. The maximum number of tokens to generate, including reasoning step.",
deprecated=True,
)
enable_sleeptime: Optional[bool] = Field(None, description="If set to True, memory management will move to a background agent thread.")
last_run_completion: Optional[datetime] = Field(None, description="The timestamp when the agent last completed a run.")
last_run_duration_ms: Optional[int] = Field(None, description="The duration in milliseconds of the agent's last run.")
last_stop_reason: Optional[StopReasonType] = Field(None, description="The stop reason from the agent's last run.")
timezone: Optional[str] = Field(None, description="The timezone of the agent (IANA format).")
max_files_open: Optional[int] = Field(
None,
description="Maximum number of files that can be open at once for this agent. Setting this too high may exceed the context window, which will break the agent.",
)
per_file_view_window_char_limit: Optional[int] = Field(
None,
description="The per-file view window character limit for this agent. Setting this too high may exceed the context window, which will break the agent.",
)
hidden: Optional[bool] = Field(
None,
description="If set to True, the agent will be hidden.",
)
model_config = ConfigDict(extra="ignore") # Ignores extra fields
@field_validator("max_files_open")
@classmethod
def validate_max_files_open(cls, value: Optional[int]) -> Optional[int]:
"""Validate max_files_open is within acceptable range."""
if value is not None and value > MAX_FILES_OPEN_LIMIT:
raise LettaInvalidArgumentError(
f"max_files_open cannot exceed {MAX_FILES_OPEN_LIMIT}. Got: {value}",
argument_name="max_files_open",
)
return value
@field_validator("per_file_view_window_char_limit")
@classmethod
def validate_per_file_view_window_char_limit(cls, value: Optional[int]) -> Optional[int]:
"""Validate per_file_view_window_char_limit is within int32 range for database compatibility."""
if value is not None and value > MAX_PER_FILE_VIEW_WINDOW_CHAR_LIMIT:
raise LettaInvalidArgumentError(
f"per_file_view_window_char_limit cannot exceed {MAX_PER_FILE_VIEW_WINDOW_CHAR_LIMIT}. Got: {value}",
argument_name="per_file_view_window_char_limit",
)
return value
class AgentStepResponse(BaseModel):
messages: List[Message] = Field(..., description="The messages generated during the agent's step.")
heartbeat_request: bool = Field(..., description="Whether the agent requested a heartbeat (i.e. follow-up execution).")
function_failed: bool = Field(..., description="Whether the agent step ended because a function call failed.")
in_context_memory_warning: bool = Field(
..., description="Whether the agent step ended because the in-context memory is near its limit."
)
usage: UsageStatistics = Field(..., description="Usage statistics of the LLM call during the agent's step.")
def get_prompt_template_for_agent_type(agent_type: Optional[AgentType] = None):
"""Deprecated. Templates are not used anymore; fast renderer handles formatting."""
return ""