for assorted things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at e83c0050f1eeb3bf7a7477fec1c07c4046a55d6a 109 lines 3.5 kB view raw
1#!/usr/bin/env -S uv run --script --quiet 2# /// script 3# requires-python = ">=3.12" 4# dependencies = ["pydantic-ai", "pydantic-settings", "rich"] 5# /// 6""" 7Make some change to my phillips hue network of lights via agent + MCP server. 8 9Usage: 10 11```bash 12./update-lights -m "turn on sahara in the living room and nightlight in the kitchen" 13``` 14 15Details: 16- uses a [`pydantic-ai`](https://github.com/pydantic/pydantic-ai) agent 17- the agent spins up a [`fastmcp`](https://github.com/jlowin/fastmcp) MCP server that talks to my [`phue`](https://github.com/studioimaginaire/phue) bridge 18- set `HUE_BRIDGE_IP` and `HUE_BRIDGE_USERNAME` in `.env` or otherwise in environment 19- uses `ANTHROPIC_API_KEY` and defaults to claude-sonnet-4-5, but you can set `AI_MODEL` in `.env` to use a different model 20""" 21 22import argparse 23import asyncio 24from pydantic_settings import BaseSettings, SettingsConfigDict 25from pydantic import Field 26from pydantic_ai import Agent 27from pydantic_ai.mcp import MCPServerStdio 28from pydantic_ai.models import KnownModelName 29from rich.console import Console 30from rich.panel import Panel 31from rich.prompt import Prompt 32 33 34class Settings(BaseSettings): 35 model_config = SettingsConfigDict(env_file=".env", extra="ignore") 36 37 hue_bridge_ip: str = Field(default=...) 38 hue_bridge_username: str = Field(default=...) 39 anthropic_api_key: str | None = Field(default=None) 40 41 ai_model: KnownModelName = Field(default="anthropic:claude-sonnet-4-5") 42 43 44settings = Settings() 45console = Console() 46 47async def run_agent(): 48 hub_mcp = MCPServerStdio( 49 command="uvx", 50 args=[ 51 "smart-home@git+https://github.com/jlowin/fastmcp.git#subdirectory=examples/smart_home" 52 ], 53 env={ 54 "HUE_BRIDGE_IP": settings.hue_bridge_ip, 55 "HUE_BRIDGE_USERNAME": settings.hue_bridge_username, 56 }, 57 ) 58 59 agent = Agent( 60 settings.ai_model, 61 mcp_servers=[hub_mcp], 62 ) 63 64 console.print( 65 Panel.fit( 66 f"[bold cyan]🏠 lights agent[/bold cyan]\n" 67 f"[dim]model: {settings.ai_model}[/dim]", 68 border_style="blue", 69 ) 70 ) 71 72 parser = argparse.ArgumentParser(description="Send a command to the lights agent.") 73 parser.add_argument( 74 "--message", 75 "-m", 76 type=str, 77 default="soft and dim - Jessica Pratt energy, all areas", 78 help="The message to send to the agent (defaults to 'soft and dim - Jessica Pratt energy, all areas').", 79 ) 80 parser.add_argument( 81 "--once", 82 action="store_true", 83 help="Run once and exit instead of entering interactive mode.", 84 ) 85 args = parser.parse_args() 86 87 console.print(f"\n[bold yellow]→[/bold yellow] {args.message}") 88 result = await agent.run(args.message) 89 console.print(f"[dim green]{result.output}[/dim green]") 90 91 if not args.once: 92 while True: 93 try: 94 user_input = Prompt.ask("\n[bold green]enter a message[/bold green]") 95 console.print(f"[bold yellow]→[/bold yellow] {user_input}") 96 result = await agent.run(user_input) 97 console.print(f"[dim green]{result.output}[/dim green]") 98 except KeyboardInterrupt: 99 console.print("\n[dim red]exiting...[/dim red]") 100 break 101 102 103if __name__ == "__main__": 104 import os 105 106 if settings.anthropic_api_key: 107 os.environ["ANTHROPIC_API_KEY"] = settings.anthropic_api_key 108 109 asyncio.run(run_agent())