Tyler AI Agent Framework

website·Indexed 31 days ago

https://adamwdraper.github.io/tyler

A framework for building AI agents capable of managing conversations via threads, executing built-in and custom tools, and integrating with the Model Context Protocol (MCP). Tyler includes core components like the Agent class for task execution, ThreadStore and FileStore for persistent storage, and specialized modules for web search, Slack, and system command-line access.

Tokens
34.4K
Snippets
209
Records
242
Agent score
73%

What's inside Tyler

  1. Understand the Tyler agent processing loop

    Tyler uses an iterative loop to process messages and execute tools. When agent.go() or go_stream() is called, the system follows these steps:

    1. Message Processing: Loads the conversation thread, processes attached files, and ensures the system prompt is set.
    2. Step Execution: Makes an LLM call with current context and processes the response for content and tool calls.
    3. Tool Execution: If tool calls are present, they are executed in sequence, results are added back to the conversation, and the loop returns to Step Execution if more tools are needed.
    4. Completion: Saves the final thread state and returns the processed thread and new messages.
  2. Integrate MCP tools into Tyler agents

    Tyler supports the Model Context Protocol (MCP), allowing AI agents to discover and invoke tools from external MCP servers. The integration supports WebSocket, SSE, and STDIO transport protocols. To use MCP tools, you must initialize the MCP service with server configurations, retrieve the tools for the agent, and pass those tools to the Agent instance.
  3. Use the Chat with Tyler web interface

    In addition to the library, Tyler offers a separate web-based chat interface for interacting with agents. This interface supports real-time interaction, file attachments, and message history preservation. The interface is hosted in a separate repository.
    Repository: https://github.com/adamwdraper/tyler-chat
  4. Understand Tyler core component relationships

    Tyler's architecture relies on three primary interacting components:

    • Agent: The central orchestrator that processes threads and manages tools.
    • Thread: A container for messages that maintains the conversation context.
    • Message: The individual unit of interaction containing content and metadata.
  5. Tyler AI agent core capabilities and features

    Tyler provides several built-in capabilities for AI agent development:

    • Model Support: Compatible with 100+ providers via LiteLLM (e.g., OpenAI, Anthropic).
    • Protocol Support: Seamless integration with Model Context Protocol (MCP) compatible servers and tools.
    • Storage: Supports in-memory, SQLite, or PostgreSQL for conversation history and file storage.
    • Data Modeling: Built-in structured models for threads, messages, and attachments.
    • Observability: Integrated with W&B Weave for tracing and debugging.
    • Multimodality: Out-of-the-box processing for images, audio, and PDFs.
  6. Integrate Model Context Protocol (MCP) tools

    Tyler supports the Model Context Protocol (MCP), allowing it to connect to MCP servers via WebSocket, SSE, or STDIO. This enables automatic discovery and invocation of MCP tools as if they were native Tyler tools.
  7. Understand the Tyler command line security model

    The command line module provides safe access to system commands through three primary security layers:

    1. Whitelisted Commands: Only pre-approved commands are allowed, categorized by risk level. Workspace-modifying operations are restricted.
    2. Workspace Containment: File operations are restricted to the workspace. Absolute paths are resolved relative to the workspace, and parent directory traversal (e.g., ../) is prevented.
    3. Permission Model: Read operations are generally unrestricted, while write operations are scoped to the workspace and system operations are strictly limited.
  8. Integrate FileStore with the Attachment model

    The FileStore instance is used by the Attachment model to process and persist files. When attachment.process_and_store(file_store) is called, the attachment is updated with a file_id, storage_path, and attributes (including the generated URL).
    from tyler import Attachment, FileStore
    
    # Create a FileStore instance
    file_store = await FileStore.create()
    
    # Create an attachment
    attachment = Attachment(
        filename="document.pdf",
        content=pdf_bytes,
        mime_type="application/pdf"
    )
    
    # Process and store the attachment
    await attachment.process_and_store(file_store)
  9. Implement persistent PostgreSQL storage for Tyler agents

    To use persistent database storage with Tyler, use the ThreadStore class. You must provide a database URL (using the postgresql+asyncpg driver for PostgreSQL) and call initialize() to create the necessary database tables before use. The ThreadStore is then passed to the Agent configuration to ensure conversation threads are persisted.
    from tyler import Agent, Thread, Message, ThreadStore
    import asyncio
    
    async def main():
        # Construct PostgreSQL URL
        db_url = "postgresql+asyncpg://user:password@localhost:5432/dbname"
    
        # Initialize ThreadStore and create tables
        store = ThreadStore(db_url)
        await store.initialize()
    
        # Create agent with database storage
        agent = Agent(
            model_name="gpt-4.1",
            purpose="To help with general questions",
            thread_store=store
        )
    
        # Create and save a new thread
        thread = Thread()
        await store.save(thread)
    
        # Add a message and persist
        message = Message(role="user", content="Hello!")
        thread.add_message(message)
        await store.save(thread)
    
        # Process the thread
        processed_thread, new_messages = await agent.go(thread)
    
    asyncio.run(main())
  10. Configure database persistence with ThreadStore

    Tyler uses the ThreadStore class to manage the persistence of threads and messages. It supports three backends: Memory (default, non-persistent), PostgreSQL (production-ready, async), and SQLite. When using database storage, you must explicitly call store.save(thread) to persist changes and use thread.id when calling agent.go().
    from tyler import ThreadStore, Agent, Thread
    from tyler.utils.registry import register_thread_store
    
    # 1. Create store using factory pattern (PostgreSQL example)
    db_url = "postgresql+asyncpg://user:pass@localhost/dbname"
    try:
        store = await ThreadStore.create(db_url)
    except Exception as e:
        # Fallback to memory storage
        store = await ThreadStore.create()
    
    # 2. Register the store
    register_thread_store("default_db_store", store)
    
    # 3. Initialize Agent with the store
    agent = Agent(
        model_name="gpt-4.1",
        purpose="To help with tasks",
        thread_store=store
    )
    
    # 4. Persist data
    thread = Thread()
    await store.save(thread)  # Initial save
    thread.add_message(message)
    await store.save(thread)  # Save updates
    
    # 5. Use thread ID for interaction
    result = await agent.go(thread.id)
  11. Manage and retrieve file attachments

    Tyler handles file attachments automatically when saving threads, but also allows for manual storage control and content retrieval. Attachments track their status (e.g., 'stored' or 'failed') and provide access to storage paths and extracted metadata like text or overviews.
    # Storage is handled automatically when saving threads
    thread.add_message(message_with_attachment)
    await thread_store.save(thread)  # Stores attachments automatically
    
    # Manual storage if needed
    await attachment.ensure_stored()
    
    # Check storage status
    if attachment.status == "stored":
        print(f"File stored at: {attachment.storage_path}")
        print(f"Access URL: {attachment.attributes['url']}")
    
    # Get content as bytes
    try:
        content = await attachment.get_content_bytes()
    except ValueError as e:
        print(f"Content not available: {e}")
    
    # Access attributes
    if attachment.attributes:
        if "text" in attachment.attributes:
            print("Extracted text:", attachment.attributes["text"])
  12. Manage conversation threads and system prompts

    Conversations are handled via Thread objects. You can specify a custom system prompt during thread initialization to override or augment agent behavior for a specific session.
    from tyler import Thread
    
    # Create a thread with a custom system prompt
    thread = Thread(
        system_prompt="You are a weather expert..."
    )