Spaces:
Runtime error
Runtime error
| import litellm | |
| from rich.console import Console | |
| from rich.panel import Panel | |
| from rich.markdown import Markdown | |
| from rich.table import Table | |
| from rich.box import SIMPLE | |
| from local.engine import WikiRunEnvironment | |
| from langsmith import traceable | |
| import os | |
| from openai import OpenAI | |
| from langsmith.wrappers import wrap_openai | |
| openai_client = wrap_openai(OpenAI()) | |
| class WikiRunAgent: | |
| def __init__(self, wiki_data_path, model="gemini/gemini-2.5-pro-exp-03-25"): | |
| self.env = WikiRunEnvironment(wiki_data_path) | |
| self.model = model | |
| self.console = Console() | |
| def run_game(self, start_article=None, target_article=None): | |
| """Play the WikiRun game with LLM agent""" | |
| state = self.env.reset(start_article, target_article) | |
| self.console.print(Panel(f"[bold cyan]Starting WikiRun![/bold cyan]")) | |
| self.console.print(f"[bold green]Starting at:[/bold green] {state['current_article']}") | |
| self.console.print(f"[bold red]Target:[/bold red] {state['target_article']}\n") | |
| while not state['is_complete']: | |
| # Display current game status | |
| self._display_game_status(state) | |
| # Get LLM's choice | |
| choice = self._get_llm_choice(state) | |
| self.console.print(f"\n[bold yellow]Agent chooses:[/bold yellow] {choice}") | |
| # Process the choice | |
| available_links = self._get_available_links(state['available_links']) | |
| if not available_links: | |
| self.console.print("[bold red]No available links to choose from![/bold red]") | |
| break | |
| try: | |
| # If choice is a number | |
| idx = int(choice) - 1 | |
| if 0 <= idx < len(available_links): | |
| next_article = available_links[idx] | |
| self.console.print(f"[bold cyan]Moving to:[/bold cyan] {next_article}\n") | |
| state, message = self.env.step(next_article) | |
| if message: | |
| self.console.print(f"[bold]{message}[/bold]") | |
| else: | |
| self.console.print("[bold red]Invalid choice. Trying again.[/bold red]\n") | |
| except ValueError: | |
| self.console.print("[bold red]Invalid choice format. Trying again.[/bold red]\n") | |
| self.console.print(Panel(f"[bold green]Game completed in {state['steps_taken']} steps[/bold green]")) | |
| self.console.print(f"[bold]Path:[/bold] {' β '.join(state['path_taken'])}") | |
| return state | |
| def _display_game_status(self, state): | |
| """Display current game status with rich formatting""" | |
| # Display current article | |
| self.console.print(Panel(f"[bold cyan]{state['current_article']}[/bold cyan]", | |
| expand=False, | |
| border_style="cyan")) | |
| # Display article links | |
| self.console.print("[bold green]Available Links:[/bold green]") | |
| self._display_links(state['available_links']) | |
| # Display path so far | |
| self.console.print(f"\n[bold yellow]Steps taken:[/bold yellow] {state['steps_taken']}") | |
| if state['path_taken']: | |
| self.console.print(f"[bold yellow]Path so far:[/bold yellow] {' β '.join(state['path_taken'])}") | |
| def _display_links(self, links): | |
| """Display links in a nicely formatted table""" | |
| table = Table(show_header=False, box=SIMPLE) | |
| table.add_column("Number", style="dim") | |
| table.add_column("Link", style="green") | |
| table.add_column("Available", style="bold") | |
| for i, link in enumerate(links): | |
| # Check if link is available | |
| is_available = self.env.article_exists(link) | |
| status = "[green]β[/green]" if is_available else "[red]β[/red]" | |
| color = "green" if is_available else "red" | |
| table.add_row( | |
| f"{i+1}", | |
| f"[{color}]{link}[/{color}]", | |
| status | |
| ) | |
| self.console.print(table) | |
| def _get_available_links(self, links): | |
| """Filter links to only those available in the wiki data""" | |
| return [link for link in links if self.env.article_exists(link)] | |
| def _get_llm_choice(self, state): | |
| """Ask LLM for next move""" | |
| current = state['current_article'] | |
| target = state['target_article'] | |
| all_links = state['available_links'] | |
| available_links = self._get_available_links(all_links) | |
| path_so_far = state['path_taken'] | |
| # Create prompt with relevant context (not the full article) | |
| prompt = f"""You are playing WikiRun, trying to navigate from one Wikipedia article to another using only links. | |
| Current article: {current} | |
| Target article: {target} | |
| Available links (numbered): | |
| {self._format_links(available_links)} | |
| Your path so far: {' -> '.join(path_so_far)} | |
| Think about which link is most likely to lead you toward the target article. | |
| First, think step by step about your strategy. | |
| Then output your choice as a number in this format: <choice>N</choice> where N is the link number. | |
| """ | |
| # Call LLM via litellm with langsmith tracing | |
| response = litellm.completion( | |
| model=self.model, | |
| messages=[{"role": "user", "content": prompt}], | |
| # metadata={ | |
| # "current_article": current, | |
| # "target_article": target, | |
| # "available_links": available_links, | |
| # "steps_taken": state['steps_taken'], | |
| # "path_so_far": path_so_far | |
| # } | |
| ) | |
| # Extract the choice from response | |
| content = response.choices[0].message.content | |
| self.console.print(Panel(Markdown(content), title="[bold]Agent Thinking[/bold]", border_style="yellow")) | |
| # Extract choice using format <choice>N</choice> | |
| import re | |
| choice_match = re.search(r'<choice>(\d+)</choice>', content) | |
| if choice_match: | |
| return choice_match.group(1) | |
| else: | |
| # Fallback: try to find any number in the response | |
| numbers = re.findall(r'\d+', content) | |
| if numbers: | |
| for num in numbers: | |
| if 1 <= int(num) <= len(available_links): | |
| return num | |
| # Default to first link if no valid choice found | |
| return "1" if available_links else "0" | |
| def _format_links(self, links): | |
| """Format the list of links for the prompt""" | |
| return "\n".join([f"{i+1}. {link}" for i, link in enumerate(links)]) | |
| def setup_langsmith(): | |
| """Print instructions for setting up LangSmith tracing""" | |
| console = Console() | |
| console.print(Panel("[bold yellow]LangSmith Setup Instructions[/bold yellow]")) | |
| console.print("To enable LangSmith tracing, set the following environment variables:") | |
| console.print("[bold]export LANGSMITH_API_KEY='your-api-key'[/bold]") | |
| console.print("Get your API key from: https://smith.langchain.com/settings") | |
| console.print("Once set, your WikiRun agent will log traces to your LangSmith dashboard") | |
| if __name__ == "__main__": | |
| import sys | |
| if len(sys.argv) < 2: | |
| console = Console() | |
| console.print("[bold red]Please provide the path to Wikipedia data[/bold red]") | |
| console.print("Usage: python agent.py <wiki_data_path>") | |
| sys.exit(1) | |
| # Remind about LangSmith setup | |
| if not os.environ.get("LANGSMITH_API_KEY"): | |
| setup_langsmith() | |
| wiki_data_path = sys.argv[1] | |
| agent = WikiRunAgent(wiki_data_path) | |
| agent.run_game(start_article="Peanut", target_article="Silicon Valley") | |
| # agent.run_game(start_article="Silicon Valley", target_article="Peanut") | |