""" Claude Model Adapter. Provides Claude-specific context formatting using XML tags which Claude models understand natively. """ from typing import Any from ..types import BaseContext, ContextType from .base import ModelAdapter class ClaudeAdapter(ModelAdapter): """ Claude-specific context formatting adapter. Claude models have native understanding of XML structure, so we use XML tags for clear delineation of context types. Features: - XML tags for each context type - Document structure for knowledge contexts - Role-based message formatting for conversations - Tool result wrapping with tool names """ MODEL_PATTERNS: list[str] = ["claude", "anthropic"] def format( self, contexts: list[BaseContext], **kwargs: Any, ) -> str: """ Format contexts for Claude models. Uses XML tags for structured content that Claude understands natively. Args: contexts: List of contexts to format **kwargs: Additional formatting options Returns: XML-structured context string """ if not contexts: return "" by_type = self.group_by_type(contexts) parts: list[str] = [] for ct in self.get_type_order(): if ct in by_type: formatted = self.format_type(by_type[ct], ct, **kwargs) if formatted: parts.append(formatted) return self.get_separator().join(parts) def format_type( self, contexts: list[BaseContext], context_type: ContextType, **kwargs: Any, ) -> str: """ Format contexts of a specific type for Claude. Args: contexts: List of contexts of the same type context_type: The type of contexts **kwargs: Additional formatting options Returns: XML-formatted string for this context type """ if not contexts: return "" if context_type == ContextType.SYSTEM: return self._format_system(contexts) elif context_type == ContextType.TASK: return self._format_task(contexts) elif context_type == ContextType.KNOWLEDGE: return self._format_knowledge(contexts) elif context_type == ContextType.CONVERSATION: return self._format_conversation(contexts) elif context_type == ContextType.TOOL: return self._format_tool(contexts) return "\n".join(c.content for c in contexts) def _format_system(self, contexts: list[BaseContext]) -> str: """Format system contexts.""" content = "\n\n".join(c.content for c in contexts) return f"\n{content}\n" def _format_task(self, contexts: list[BaseContext]) -> str: """Format task contexts.""" content = "\n\n".join(c.content for c in contexts) return f"\n{content}\n" def _format_knowledge(self, contexts: list[BaseContext]) -> str: """ Format knowledge contexts as structured documents. Each knowledge context becomes a document with source attribution. """ parts = [""] for ctx in contexts: source = self._escape_xml(ctx.source) content = ctx.content score = ctx.metadata.get("score", ctx.metadata.get("relevance_score", "")) if score: parts.append(f'') else: parts.append(f'') parts.append(content) parts.append("") parts.append("") return "\n".join(parts) def _format_conversation(self, contexts: list[BaseContext]) -> str: """ Format conversation contexts as message history. Uses role-based message tags for clear turn delineation. """ parts = [""] for ctx in contexts: role = ctx.metadata.get("role", "user") parts.append(f'') parts.append(ctx.content) parts.append("") parts.append("") return "\n".join(parts) def _format_tool(self, contexts: list[BaseContext]) -> str: """ Format tool contexts as tool results. Each tool result is wrapped with the tool name. """ parts = [""] for ctx in contexts: tool_name = ctx.metadata.get("tool_name", "unknown") status = ctx.metadata.get("status", "") if status: parts.append(f'') else: parts.append(f'') parts.append(ctx.content) parts.append("") parts.append("") return "\n".join(parts) @staticmethod def _escape_xml(text: str) -> str: """Escape XML special characters in attribute values.""" return ( text.replace("&", "&") .replace("<", "<") .replace(">", ">") .replace('"', """) .replace("'", "'") )