feat: Add cli for interacting with Axiom agent
Browse files- cli.py +131 -0
 - pyproject.toml +2 -0
 - src/axiom/agent.py +1 -0
 - src/axiom/config.py +0 -3
 - uv.lock +68 -0
 
    	
        cli.py
    ADDED
    
    | 
         @@ -0,0 +1,131 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            import asyncio
         
     | 
| 2 | 
         
            +
            from typing import List, Dict, Optional
         
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
            from src.axiom.agent import AxiomAgent
         
     | 
| 5 | 
         
            +
            from src.axiom.config import settings, load_mcp_servers_from_config 
         
     | 
| 6 | 
         
            +
            from agents.mcp import MCPServer 
         
     | 
| 7 | 
         
            +
            import logging
         
     | 
| 8 | 
         
            +
             
     | 
| 9 | 
         
            +
            # --- Configure Logging ---
         
     | 
| 10 | 
         
            +
            httpx_logger = logging.getLogger("httpx")
         
     | 
| 11 | 
         
            +
            httpx_logger.setLevel(logging.WARNING) 
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
            # Use Rich for pretty output
         
     | 
| 14 | 
         
            +
            from rich.console import Console
         
     | 
| 15 | 
         
            +
            from rich.markdown import Markdown
         
     | 
| 16 | 
         
            +
            from rich.rule import Rule
         
     | 
| 17 | 
         
            +
            from rich.text import Text
         
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
            console = Console()
         
     | 
| 20 | 
         
            +
             
     | 
| 21 | 
         
            +
            async def get_user_input(prompt_text: str) -> str:
         
     | 
| 22 | 
         
            +
                """Gets user input asynchronously with a styled prompt."""
         
     | 
| 23 | 
         
            +
                # Render the prompt text using Rich
         
     | 
| 24 | 
         
            +
                prompt_markup = Text.from_markup(prompt_text, style="bold blue")
         
     | 
| 25 | 
         
            +
                return await asyncio.to_thread(console.input, prompt_markup)
         
     | 
| 26 | 
         
            +
             
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
            async def main():
         
     | 
| 29 | 
         
            +
                console.print(Rule("[bold blue] Welcome to Axiom CLI [/bold blue]", style="blue"))
         
     | 
| 30 | 
         
            +
                console.print("[dim]Type 'quit' or 'exit' to end the chat.[/dim]")
         
     | 
| 31 | 
         
            +
                console.print("") # Blank line
         
     | 
| 32 | 
         
            +
             
     | 
| 33 | 
         
            +
                loaded_mcp_servers: List[MCPServer] = []
         
     | 
| 34 | 
         
            +
                started_mcp_servers: List[MCPServer] = []
         
     | 
| 35 | 
         
            +
                agent: Optional[AxiomAgent] = None
         
     | 
| 36 | 
         
            +
                chat_history: List[Dict[str, str]] = []
         
     | 
| 37 | 
         
            +
             
     | 
| 38 | 
         
            +
                try:
         
     | 
| 39 | 
         
            +
                    # 1. Load MCP Servers
         
     | 
| 40 | 
         
            +
                    console.print("[bold]Loading MCP configurations...[/bold]")
         
     | 
| 41 | 
         
            +
                    try:
         
     | 
| 42 | 
         
            +
                        loaded_mcp_servers = load_mcp_servers_from_config()
         
     | 
| 43 | 
         
            +
                        if loaded_mcp_servers:
         
     | 
| 44 | 
         
            +
                             console.print(f"[green]Loaded {len(loaded_mcp_servers)} server(s) config.[/green] Attempting to start...")
         
     | 
| 45 | 
         
            +
                        else:
         
     | 
| 46 | 
         
            +
                             console.print("[yellow]No MCP server configurations found or loaded.[/yellow]")
         
     | 
| 47 | 
         
            +
             
     | 
| 48 | 
         
            +
                    except Exception as e:
         
     | 
| 49 | 
         
            +
                        console.print(f"[bold red]Error loading MCP config:[/bold red] [red]{e}[/red]")
         
     | 
| 50 | 
         
            +
             
     | 
| 51 | 
         
            +
                    # 2. Start MCP Servers
         
     | 
| 52 | 
         
            +
                    if loaded_mcp_servers:
         
     | 
| 53 | 
         
            +
                        for server in loaded_mcp_servers:
         
     | 
| 54 | 
         
            +
                            try:
         
     | 
| 55 | 
         
            +
                                await server.__aenter__()
         
     | 
| 56 | 
         
            +
                                started_mcp_servers.append(server)
         
     | 
| 57 | 
         
            +
                                console.print(f"  [green]Started:[/green] {server.name}")
         
     | 
| 58 | 
         
            +
                            except Exception as e:
         
     | 
| 59 | 
         
            +
                                console.print(f"  [yellow]Failed to start:[/yellow] {server.name} - [yellow]{e}[/yellow]")
         
     | 
| 60 | 
         
            +
             
     | 
| 61 | 
         
            +
                    if loaded_mcp_servers and not started_mcp_servers:
         
     | 
| 62 | 
         
            +
                         console.print("[yellow]Warning: All configured MCP servers failed to start. Agent will operate without MCP tools.[/yellow]")
         
     | 
| 63 | 
         
            +
                    elif started_mcp_servers:
         
     | 
| 64 | 
         
            +
                         console.print(f"[green]Successfully started {len(started_mcp_servers)} MCP server(s).[/green]")
         
     | 
| 65 | 
         
            +
             
     | 
| 66 | 
         
            +
                    # 3. Initialize the Agent
         
     | 
| 67 | 
         
            +
                    console.print("[bold]Initializing Agent...[/bold]")
         
     | 
| 68 | 
         
            +
                    try:
         
     | 
| 69 | 
         
            +
                        agent = AxiomAgent(mcp_servers=started_mcp_servers)
         
     | 
| 70 | 
         
            +
                        console.print(f"[bold green]{settings.AGENT_NAME} is ready![/bold green]")
         
     | 
| 71 | 
         
            +
                    except Exception as e:
         
     | 
| 72 | 
         
            +
                        console.print(f"[bold red]Fatal Error: Could not initialize Agent:[/bold red] [red]{e}[/red]")
         
     | 
| 73 | 
         
            +
                        raise
         
     | 
| 74 | 
         
            +
             
     | 
| 75 | 
         
            +
                    console.print(Rule(style="blue"))
         
     | 
| 76 | 
         
            +
             
     | 
| 77 | 
         
            +
                    # 4. Main chat loop
         
     | 
| 78 | 
         
            +
                    while True:
         
     | 
| 79 | 
         
            +
                        # Get user input with styled prompt
         
     | 
| 80 | 
         
            +
                        user_input = await get_user_input("You: ")
         
     | 
| 81 | 
         
            +
             
     | 
| 82 | 
         
            +
                        if user_input.lower() in ['quit', 'exit']:
         
     | 
| 83 | 
         
            +
                            break
         
     | 
| 84 | 
         
            +
             
     | 
| 85 | 
         
            +
                        chat_history.append({"role": "user", "content": user_input})
         
     | 
| 86 | 
         
            +
             
     | 
| 87 | 
         
            +
                        console.print("[bold green]Axiom:[/bold green]") # Print Agent prefix before response
         
     | 
| 88 | 
         
            +
             
     | 
| 89 | 
         
            +
                        full_response = ""
         
     | 
| 90 | 
         
            +
                        # Use Rich Status for the thinking indicator while streaming
         
     | 
| 91 | 
         
            +
                        with console.status("[bold green]Thinking...[/bold green]", spinner="dots", speed=0.5) as status:
         
     | 
| 92 | 
         
            +
                             try:
         
     | 
| 93 | 
         
            +
                                response_generator = agent.stream_agent(chat_history)
         
     | 
| 94 | 
         
            +
                                async for token in response_generator:
         
     | 
| 95 | 
         
            +
                                    full_response += token
         
     | 
| 96 | 
         
            +
                                status.stop()
         
     | 
| 97 | 
         
            +
             
     | 
| 98 | 
         
            +
                             except Exception as e:
         
     | 
| 99 | 
         
            +
                                 status.stop()
         
     | 
| 100 | 
         
            +
                                 console.print(f"\n[bold red]Error during response:[/bold red] [red]{e}[/red]", style="red")
         
     | 
| 101 | 
         
            +
                                 full_response = f"[Error: {e}]"
         
     | 
| 102 | 
         
            +
             
     | 
| 103 | 
         
            +
             
     | 
| 104 | 
         
            +
                        # Render the full response using Markdown
         
     | 
| 105 | 
         
            +
                        if full_response:
         
     | 
| 106 | 
         
            +
                             console.print(Markdown(full_response)) # Renders code blocks, lists, etc.
         
     | 
| 107 | 
         
            +
                        else:
         
     | 
| 108 | 
         
            +
                             console.print("[dim](No response generated)[/dim]")
         
     | 
| 109 | 
         
            +
             
     | 
| 110 | 
         
            +
                        chat_history.append({"role": "assistant", "content": full_response})
         
     | 
| 111 | 
         
            +
                        console.print(Rule(style="blue")) # Print a rule after each turn
         
     | 
| 112 | 
         
            +
             
     | 
| 113 | 
         
            +
                except Exception as e:
         
     | 
| 114 | 
         
            +
                    # Catch any unexpected errors from Agent init or loop setup
         
     | 
| 115 | 
         
            +
                    console.print(f"\n[bold red]An unhandled error occurred:[/bold red] [red]{e}[/red]", style="red", highlight=True)
         
     | 
| 116 | 
         
            +
             
     | 
| 117 | 
         
            +
                finally:
         
     | 
| 118 | 
         
            +
                    # 5. Cleanup: Stop MCP Servers
         
     | 
| 119 | 
         
            +
                    if started_mcp_servers:
         
     | 
| 120 | 
         
            +
                        console.print(Rule("[dim]Stopping MCP servers[/dim]", style="blue"))
         
     | 
| 121 | 
         
            +
                        for server in started_mcp_servers:
         
     | 
| 122 | 
         
            +
                            try:
         
     | 
| 123 | 
         
            +
                                await server.__aexit__(None, None, None)
         
     | 
| 124 | 
         
            +
                                console.print(f"  [dim]Stopped:[/dim] {server.name}")
         
     | 
| 125 | 
         
            +
                            except Exception as e:
         
     | 
| 126 | 
         
            +
                                console.print(f"  [red]Error stopping:[/red] {server.name} - [red]{e}[/red]")
         
     | 
| 127 | 
         
            +
             
     | 
| 128 | 
         
            +
                    console.print(Rule("[bold blue] Chat ended. Goodbye! [/bold blue]", style="blue"))
         
     | 
| 129 | 
         
            +
             
     | 
| 130 | 
         
            +
            if __name__ == "__main__":
         
     | 
| 131 | 
         
            +
                asyncio.run(main())
         
     | 
    	
        pyproject.toml
    CHANGED
    
    | 
         @@ -7,7 +7,9 @@ requires-python = ">=3.11" 
     | 
|
| 7 | 
         
             
            dependencies = [
         
     | 
| 8 | 
         
             
                "chainlit>=2.5.5",
         
     | 
| 9 | 
         
             
                "openai-agents>=0.0.11",
         
     | 
| 
         | 
|
| 10 | 
         
             
                "python-dotenv>=1.1.0",
         
     | 
| 
         | 
|
| 11 | 
         
             
            ]
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            [tool.hatch.build.targets.wheel]
         
     | 
| 
         | 
|
| 7 | 
         
             
            dependencies = [
         
     | 
| 8 | 
         
             
                "chainlit>=2.5.5",
         
     | 
| 9 | 
         
             
                "openai-agents>=0.0.11",
         
     | 
| 10 | 
         
            +
                "prompt-toolkit>=3.0.51",
         
     | 
| 11 | 
         
             
                "python-dotenv>=1.1.0",
         
     | 
| 12 | 
         
            +
                "rich>=14.0.0",
         
     | 
| 13 | 
         
             
            ]
         
     | 
| 14 | 
         | 
| 15 | 
         
             
            [tool.hatch.build.targets.wheel]
         
     | 
    	
        src/axiom/agent.py
    CHANGED
    
    | 
         @@ -93,6 +93,7 @@ class AxiomAgent: 
     | 
|
| 93 | 
         
             
                        result = Runner.run_streamed(
         
     | 
| 94 | 
         
             
                            starting_agent=self.agent,
         
     | 
| 95 | 
         
             
                            input=chat_history,
         
     | 
| 
         | 
|
| 96 | 
         
             
                            run_config=config
         
     | 
| 97 | 
         
             
                        )
         
     | 
| 98 | 
         
             
                        async for event in result.stream_events():
         
     | 
| 
         | 
|
| 93 | 
         
             
                        result = Runner.run_streamed(
         
     | 
| 94 | 
         
             
                            starting_agent=self.agent,
         
     | 
| 95 | 
         
             
                            input=chat_history,
         
     | 
| 96 | 
         
            +
                            max_turns=20,
         
     | 
| 97 | 
         
             
                            run_config=config
         
     | 
| 98 | 
         
             
                        )
         
     | 
| 99 | 
         
             
                        async for event in result.stream_events():
         
     | 
    	
        src/axiom/config.py
    CHANGED
    
    | 
         @@ -80,8 +80,6 @@ def load_mcp_servers_from_config(config_path: Path = settings.MCP_CONFIG_PATH) - 
     | 
|
| 80 | 
         
             
                    logger.error(f"MCP configuration file not found: {config_path}")
         
     | 
| 81 | 
         
             
                    raise FileNotFoundError(f"MCP configuration file not found: {config_path}")
         
     | 
| 82 | 
         | 
| 83 | 
         
            -
                logger.info(f"Loading MCP servers from: {config_path}")
         
     | 
| 84 | 
         
            -
                
         
     | 
| 85 | 
         
             
                # Allow json.JSONDecodeError to propagate if file is invalid JSON
         
     | 
| 86 | 
         
             
                with open(config_path, 'r', encoding='utf-8') as f:
         
     | 
| 87 | 
         
             
                    data = json.load(f)
         
     | 
| 
         @@ -104,7 +102,6 @@ def load_mcp_servers_from_config(config_path: Path = settings.MCP_CONFIG_PATH) - 
     | 
|
| 104 | 
         
             
                                }
         
     | 
| 105 | 
         
             
                            )
         
     | 
| 106 | 
         
             
                        servers.append(server_instance)
         
     | 
| 107 | 
         
            -
                        logger.info(f"Prepared MCP Server: {name}")
         
     | 
| 108 | 
         | 
| 109 | 
         
             
                    except (ValidationError, Exception) as e:
         
     | 
| 110 | 
         
             
                        logger.warning(f"Skipping MCP server '{name}' due to configuration error: {e}")
         
     | 
| 
         | 
|
| 80 | 
         
             
                    logger.error(f"MCP configuration file not found: {config_path}")
         
     | 
| 81 | 
         
             
                    raise FileNotFoundError(f"MCP configuration file not found: {config_path}")
         
     | 
| 82 | 
         | 
| 
         | 
|
| 
         | 
|
| 83 | 
         
             
                # Allow json.JSONDecodeError to propagate if file is invalid JSON
         
     | 
| 84 | 
         
             
                with open(config_path, 'r', encoding='utf-8') as f:
         
     | 
| 85 | 
         
             
                    data = json.load(f)
         
     | 
| 
         | 
|
| 102 | 
         
             
                                }
         
     | 
| 103 | 
         
             
                            )
         
     | 
| 104 | 
         
             
                        servers.append(server_instance)
         
     | 
| 
         | 
|
| 105 | 
         | 
| 106 | 
         
             
                    except (ValidationError, Exception) as e:
         
     | 
| 107 | 
         
             
                        logger.warning(f"Skipping MCP server '{name}' due to configuration error: {e}")
         
     | 
    	
        uv.lock
    CHANGED
    
    | 
         @@ -169,14 +169,18 @@ source = { editable = "." } 
     | 
|
| 169 | 
         
             
            dependencies = [
         
     | 
| 170 | 
         
             
                { name = "chainlit" },
         
     | 
| 171 | 
         
             
                { name = "openai-agents" },
         
     | 
| 
         | 
|
| 172 | 
         
             
                { name = "python-dotenv" },
         
     | 
| 
         | 
|
| 173 | 
         
             
            ]
         
     | 
| 174 | 
         | 
| 175 | 
         
             
            [package.metadata]
         
     | 
| 176 | 
         
             
            requires-dist = [
         
     | 
| 177 | 
         
             
                { name = "chainlit", specifier = ">=2.5.5" },
         
     | 
| 178 | 
         
             
                { name = "openai-agents", specifier = ">=0.0.11" },
         
     | 
| 
         | 
|
| 179 | 
         
             
                { name = "python-dotenv", specifier = ">=1.1.0" },
         
     | 
| 
         | 
|
| 180 | 
         
             
            ]
         
     | 
| 181 | 
         | 
| 182 | 
         
             
            [[package]]
         
     | 
| 
         @@ -707,6 +711,18 @@ dependencies = [ 
     | 
|
| 707 | 
         
             
            ]
         
     | 
| 708 | 
         
             
            sdist = { url = "https://files.pythonhosted.org/packages/7e/c1/7bd34ad0ae6cfd99512f8a40b28b9624c3b1f4e1d40c9038eabc2f870b15/literalai-0.1.201.tar.gz", hash = "sha256:29e4ccadd9d68bfea319a7f0b4fc32611b081990d9195f98e5e97a14d24d3713", size = 67832 }
         
     | 
| 709 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 710 | 
         
             
            [[package]]
         
     | 
| 711 | 
         
             
            name = "markupsafe"
         
     | 
| 712 | 
         
             
            version = "3.0.2"
         
     | 
| 
         @@ -786,6 +802,15 @@ wheels = [ 
     | 
|
| 786 | 
         
             
                { url = "https://files.pythonhosted.org/packages/10/30/20a7f33b0b884a9d14dd3aa94ff1ac9da1479fe2ad66dd9e2736075d2506/mcp-1.6.0-py3-none-any.whl", hash = "sha256:7bd24c6ea042dbec44c754f100984d186620d8b841ec30f1b19eda9b93a634d0", size = 76077 },
         
     | 
| 787 | 
         
             
            ]
         
     | 
| 788 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 789 | 
         
             
            [[package]]
         
     | 
| 790 | 
         
             
            name = "monotonic"
         
     | 
| 791 | 
         
             
            version = "1.6"
         
     | 
| 
         @@ -1567,6 +1592,18 @@ wheels = [ 
     | 
|
| 1567 | 
         
             
                { url = "https://files.pythonhosted.org/packages/54/e2/c158366e621562ef224f132e75c1d1c1fce6b078a19f7d8060451a12d4b9/posthog-3.25.0-py2.py3-none-any.whl", hash = "sha256:85db78c13d1ecb11aed06fad53759c4e8fb3633442c2f3d0336bc0ce8a585d30", size = 89115 },
         
     | 
| 1568 | 
         
             
            ]
         
     | 
| 1569 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 1570 | 
         
             
            [[package]]
         
     | 
| 1571 | 
         
             
            name = "propcache"
         
     | 
| 1572 | 
         
             
            version = "0.3.1"
         
     | 
| 
         @@ -1748,6 +1785,15 @@ wheels = [ 
     | 
|
| 1748 | 
         
             
                { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356 },
         
     | 
| 1749 | 
         
             
            ]
         
     | 
| 1750 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 1751 | 
         
             
            [[package]]
         
     | 
| 1752 | 
         
             
            name = "pyjwt"
         
     | 
| 1753 | 
         
             
            version = "2.10.1"
         
     | 
| 
         @@ -1915,6 +1961,19 @@ wheels = [ 
     | 
|
| 1915 | 
         
             
                { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
         
     | 
| 1916 | 
         
             
            ]
         
     | 
| 1917 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 1918 | 
         
             
            [[package]]
         
     | 
| 1919 | 
         
             
            name = "simple-websocket"
         
     | 
| 1920 | 
         
             
            version = "1.1.0"
         
     | 
| 
         @@ -2252,6 +2311,15 @@ wheels = [ 
     | 
|
| 2252 | 
         
             
                { url = "https://files.pythonhosted.org/packages/3f/82/45dddf4f5bf8b73ba27382cebb2bb3c0ee922c7ef77d936b86276aa39dca/watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c", size = 265344 },
         
     | 
| 2253 | 
         
             
            ]
         
     | 
| 2254 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 2255 | 
         
             
            [[package]]
         
     | 
| 2256 | 
         
             
            name = "wrapt"
         
     | 
| 2257 | 
         
             
            version = "1.17.2"
         
     | 
| 
         | 
|
| 169 | 
         
             
            dependencies = [
         
     | 
| 170 | 
         
             
                { name = "chainlit" },
         
     | 
| 171 | 
         
             
                { name = "openai-agents" },
         
     | 
| 172 | 
         
            +
                { name = "prompt-toolkit" },
         
     | 
| 173 | 
         
             
                { name = "python-dotenv" },
         
     | 
| 174 | 
         
            +
                { name = "rich" },
         
     | 
| 175 | 
         
             
            ]
         
     | 
| 176 | 
         | 
| 177 | 
         
             
            [package.metadata]
         
     | 
| 178 | 
         
             
            requires-dist = [
         
     | 
| 179 | 
         
             
                { name = "chainlit", specifier = ">=2.5.5" },
         
     | 
| 180 | 
         
             
                { name = "openai-agents", specifier = ">=0.0.11" },
         
     | 
| 181 | 
         
            +
                { name = "prompt-toolkit", specifier = ">=3.0.51" },
         
     | 
| 182 | 
         
             
                { name = "python-dotenv", specifier = ">=1.1.0" },
         
     | 
| 183 | 
         
            +
                { name = "rich", specifier = ">=14.0.0" },
         
     | 
| 184 | 
         
             
            ]
         
     | 
| 185 | 
         | 
| 186 | 
         
             
            [[package]]
         
     | 
| 
         | 
|
| 711 | 
         
             
            ]
         
     | 
| 712 | 
         
             
            sdist = { url = "https://files.pythonhosted.org/packages/7e/c1/7bd34ad0ae6cfd99512f8a40b28b9624c3b1f4e1d40c9038eabc2f870b15/literalai-0.1.201.tar.gz", hash = "sha256:29e4ccadd9d68bfea319a7f0b4fc32611b081990d9195f98e5e97a14d24d3713", size = 67832 }
         
     | 
| 713 | 
         | 
| 714 | 
         
            +
            [[package]]
         
     | 
| 715 | 
         
            +
            name = "markdown-it-py"
         
     | 
| 716 | 
         
            +
            version = "3.0.0"
         
     | 
| 717 | 
         
            +
            source = { registry = "https://pypi.org/simple" }
         
     | 
| 718 | 
         
            +
            dependencies = [
         
     | 
| 719 | 
         
            +
                { name = "mdurl" },
         
     | 
| 720 | 
         
            +
            ]
         
     | 
| 721 | 
         
            +
            sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
         
     | 
| 722 | 
         
            +
            wheels = [
         
     | 
| 723 | 
         
            +
                { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
         
     | 
| 724 | 
         
            +
            ]
         
     | 
| 725 | 
         
            +
             
     | 
| 726 | 
         
             
            [[package]]
         
     | 
| 727 | 
         
             
            name = "markupsafe"
         
     | 
| 728 | 
         
             
            version = "3.0.2"
         
     | 
| 
         | 
|
| 802 | 
         
             
                { url = "https://files.pythonhosted.org/packages/10/30/20a7f33b0b884a9d14dd3aa94ff1ac9da1479fe2ad66dd9e2736075d2506/mcp-1.6.0-py3-none-any.whl", hash = "sha256:7bd24c6ea042dbec44c754f100984d186620d8b841ec30f1b19eda9b93a634d0", size = 76077 },
         
     | 
| 803 | 
         
             
            ]
         
     | 
| 804 | 
         | 
| 805 | 
         
            +
            [[package]]
         
     | 
| 806 | 
         
            +
            name = "mdurl"
         
     | 
| 807 | 
         
            +
            version = "0.1.2"
         
     | 
| 808 | 
         
            +
            source = { registry = "https://pypi.org/simple" }
         
     | 
| 809 | 
         
            +
            sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
         
     | 
| 810 | 
         
            +
            wheels = [
         
     | 
| 811 | 
         
            +
                { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
         
     | 
| 812 | 
         
            +
            ]
         
     | 
| 813 | 
         
            +
             
     | 
| 814 | 
         
             
            [[package]]
         
     | 
| 815 | 
         
             
            name = "monotonic"
         
     | 
| 816 | 
         
             
            version = "1.6"
         
     | 
| 
         | 
|
| 1592 | 
         
             
                { url = "https://files.pythonhosted.org/packages/54/e2/c158366e621562ef224f132e75c1d1c1fce6b078a19f7d8060451a12d4b9/posthog-3.25.0-py2.py3-none-any.whl", hash = "sha256:85db78c13d1ecb11aed06fad53759c4e8fb3633442c2f3d0336bc0ce8a585d30", size = 89115 },
         
     | 
| 1593 | 
         
             
            ]
         
     | 
| 1594 | 
         | 
| 1595 | 
         
            +
            [[package]]
         
     | 
| 1596 | 
         
            +
            name = "prompt-toolkit"
         
     | 
| 1597 | 
         
            +
            version = "3.0.51"
         
     | 
| 1598 | 
         
            +
            source = { registry = "https://pypi.org/simple" }
         
     | 
| 1599 | 
         
            +
            dependencies = [
         
     | 
| 1600 | 
         
            +
                { name = "wcwidth" },
         
     | 
| 1601 | 
         
            +
            ]
         
     | 
| 1602 | 
         
            +
            sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940 }
         
     | 
| 1603 | 
         
            +
            wheels = [
         
     | 
| 1604 | 
         
            +
                { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810 },
         
     | 
| 1605 | 
         
            +
            ]
         
     | 
| 1606 | 
         
            +
             
     | 
| 1607 | 
         
             
            [[package]]
         
     | 
| 1608 | 
         
             
            name = "propcache"
         
     | 
| 1609 | 
         
             
            version = "0.3.1"
         
     | 
| 
         | 
|
| 1785 | 
         
             
                { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356 },
         
     | 
| 1786 | 
         
             
            ]
         
     | 
| 1787 | 
         | 
| 1788 | 
         
            +
            [[package]]
         
     | 
| 1789 | 
         
            +
            name = "pygments"
         
     | 
| 1790 | 
         
            +
            version = "2.19.1"
         
     | 
| 1791 | 
         
            +
            source = { registry = "https://pypi.org/simple" }
         
     | 
| 1792 | 
         
            +
            sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
         
     | 
| 1793 | 
         
            +
            wheels = [
         
     | 
| 1794 | 
         
            +
                { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
         
     | 
| 1795 | 
         
            +
            ]
         
     | 
| 1796 | 
         
            +
             
     | 
| 1797 | 
         
             
            [[package]]
         
     | 
| 1798 | 
         
             
            name = "pyjwt"
         
     | 
| 1799 | 
         
             
            version = "2.10.1"
         
     | 
| 
         | 
|
| 1961 | 
         
             
                { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
         
     | 
| 1962 | 
         
             
            ]
         
     | 
| 1963 | 
         | 
| 1964 | 
         
            +
            [[package]]
         
     | 
| 1965 | 
         
            +
            name = "rich"
         
     | 
| 1966 | 
         
            +
            version = "14.0.0"
         
     | 
| 1967 | 
         
            +
            source = { registry = "https://pypi.org/simple" }
         
     | 
| 1968 | 
         
            +
            dependencies = [
         
     | 
| 1969 | 
         
            +
                { name = "markdown-it-py" },
         
     | 
| 1970 | 
         
            +
                { name = "pygments" },
         
     | 
| 1971 | 
         
            +
            ]
         
     | 
| 1972 | 
         
            +
            sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 }
         
     | 
| 1973 | 
         
            +
            wheels = [
         
     | 
| 1974 | 
         
            +
                { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 },
         
     | 
| 1975 | 
         
            +
            ]
         
     | 
| 1976 | 
         
            +
             
     | 
| 1977 | 
         
             
            [[package]]
         
     | 
| 1978 | 
         
             
            name = "simple-websocket"
         
     | 
| 1979 | 
         
             
            version = "1.1.0"
         
     | 
| 
         | 
|
| 2311 | 
         
             
                { url = "https://files.pythonhosted.org/packages/3f/82/45dddf4f5bf8b73ba27382cebb2bb3c0ee922c7ef77d936b86276aa39dca/watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c", size = 265344 },
         
     | 
| 2312 | 
         
             
            ]
         
     | 
| 2313 | 
         | 
| 2314 | 
         
            +
            [[package]]
         
     | 
| 2315 | 
         
            +
            name = "wcwidth"
         
     | 
| 2316 | 
         
            +
            version = "0.2.13"
         
     | 
| 2317 | 
         
            +
            source = { registry = "https://pypi.org/simple" }
         
     | 
| 2318 | 
         
            +
            sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 }
         
     | 
| 2319 | 
         
            +
            wheels = [
         
     | 
| 2320 | 
         
            +
                { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 },
         
     | 
| 2321 | 
         
            +
            ]
         
     | 
| 2322 | 
         
            +
             
     | 
| 2323 | 
         
             
            [[package]]
         
     | 
| 2324 | 
         
             
            name = "wrapt"
         
     | 
| 2325 | 
         
             
            version = "1.17.2"
         
     |