from typing import Literal from pydantic import BaseModel, Field from letta.prompts.summarizer_prompt import ALL_PROMPT, SELF_ALL_PROMPT, SELF_SLIDING_PROMPT, SLIDING_PROMPT from letta.schemas.enums import ProviderType from letta.schemas.model import ModelSettingsUnion from letta.settings import summarizer_settings def get_default_summarizer_model(provider_type: ProviderType) -> str | None: """Get default model for summarization for given provider type.""" summarizer_defaults = { ProviderType.anthropic: "anthropic/claude-haiku-4-5-20251001", ProviderType.openai: "openai/gpt-5-mini", ProviderType.google_ai: "google_ai/gemini-2.5-flash", } return summarizer_defaults.get(provider_type) def get_default_prompt_for_mode(mode: Literal["all", "sliding_window", "self_compact_all", "self_compact_sliding_window"]) -> str: """Get the default prompt for a given compaction mode. Also used in /summarize endpoint if mode is changed and prompt is not explicitly set.""" if mode == "self_compact_sliding_window": return SELF_SLIDING_PROMPT elif mode == "self_compact_all": return SELF_ALL_PROMPT elif mode == "sliding_window": return SLIDING_PROMPT else: # all return ALL_PROMPT class CompactionSettings(BaseModel): """Configuration for conversation compaction / summarization. Per-model settings (temperature, max tokens, etc.) are derived from the default configuration for that handle. """ # Summarizer model handle (provider/model-name). # If None, uses lightweight provider-specific defaults (e.g., haiku for Anthropic, gpt-5-mini for OpenAI). model: str | None = Field( default=None, description="Model handle to use for sliding_window/all summarization (format: provider/model-name). If None, uses lightweight provider-specific defaults.", ) # Optional provider-specific model settings for the summarizer model model_settings: ModelSettingsUnion | None = Field( default=None, description="Optional model settings used to override defaults for the summarizer model.", ) prompt: str | None = Field(default=None, description="The prompt to use for summarization. If None, uses mode-specific default.") prompt_acknowledgement: bool = Field( default=False, description="Whether to include an acknowledgement post-prompt (helps prevent non-summary outputs)." ) clip_chars: int | None = Field( default=50000, description="The maximum length of the summary in characters. If none, no clipping is performed." ) mode: Literal["all", "sliding_window", "self_compact_all", "self_compact_sliding_window"] = Field( default="sliding_window", description="The type of summarization technique use." ) sliding_window_percentage: float = Field( default_factory=lambda: summarizer_settings.partial_evict_summarizer_percentage, description="The percentage of the context window to keep post-summarization (only used in sliding window modes).", ) # Called upon agent creation and if mode is changed in summarize endpoint request def set_mode_specific_prompt(self): """Set mode-specific default prompt if none provided.""" if self.prompt is None: self.prompt = get_default_prompt_for_mode(self.mode) return self