Spaces:
Runtime error
Runtime error
| import os | |
| import json | |
| from dataclasses import dataclass, asdict, field | |
| from typing import Optional, List | |
| import gradio as gr | |
| from openai import OpenAI | |
| # ============================================================ | |
| # CONFIG | |
| # ============================================================ | |
| OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY") | |
| if not OPENROUTER_API_KEY: | |
| raise RuntimeError( | |
| "OPENROUTER_API_KEY environment variable not found." | |
| ) | |
| MODEL = os.getenv( | |
| "OPENROUTER_MODEL", | |
| "openai/gpt-oss-120b:free" | |
| ) | |
| client = OpenAI( | |
| base_url="https://openrouter.ai/api/v1", | |
| api_key=OPENROUTER_API_KEY | |
| ) | |
| # ============================================================ | |
| # STATE | |
| # ============================================================ | |
| class AgentState: | |
| name: Optional[str] = None | |
| role: Optional[str] = None | |
| goal: Optional[str] = None | |
| greeting: Optional[str] = None | |
| tone: Optional[str] = None | |
| memory: Optional[str] = None | |
| audience: Optional[str] = None | |
| domain: Optional[str] = None | |
| tools: List[str] = field(default_factory=list) | |
| policies: List[str] = field(default_factory=list) | |
| def to_dict(self): | |
| return asdict(self) | |
| # ============================================================ | |
| # PROMPTS | |
| # ============================================================ | |
| DISCOVERY_PROMPT = """ | |
| You are an Agent Architect. | |
| Your job is to help users create AI agents entirely through conversation. | |
| Rules: | |
| - Talk naturally. | |
| - Gather requirements progressively. | |
| - Ask only ONE important follow-up question. | |
| - Never mention prompts. | |
| - Never mention JSON. | |
| - Never mention implementation. | |
| - Focus on understanding the user's vision. | |
| The user's natural language is the source of truth. | |
| """ | |
| ARCHITECT_PROMPT = """ | |
| Extract structured information from the user's message. | |
| Return ONLY JSON. | |
| Schema: | |
| { | |
| "name": null, | |
| "role": null, | |
| "goal": null, | |
| "greeting": null, | |
| "tone": null, | |
| "memory": null, | |
| "audience": null, | |
| "domain": null, | |
| "tools": [], | |
| "policies": [] | |
| } | |
| """ | |
| CAPABILITY_PROMPT = """ | |
| You are a Capability Planner. | |
| Given an agent specification, | |
| suggest useful capabilities. | |
| Return ONLY JSON. | |
| { | |
| "tools": [] | |
| } | |
| """ | |
| COMPILER_PROMPT = """ | |
| You generate system prompts. | |
| Convert the specification into | |
| a production-grade runtime prompt. | |
| Output ONLY the prompt. | |
| """ | |
| # ============================================================ | |
| # ORCHESTRATOR | |
| # ============================================================ | |
| class AgentOrchestrator: | |
| def __init__(self): | |
| self.state = AgentState() | |
| self.runtime_prompt = "" | |
| # ======================================================== | |
| def llm( | |
| self, | |
| messages, | |
| max_tokens=500, | |
| response_format=None | |
| ): | |
| kwargs = { | |
| "model": MODEL, | |
| "messages": messages, | |
| "max_tokens": max_tokens | |
| } | |
| if response_format: | |
| kwargs["response_format"] = response_format | |
| response = client.chat.completions.create(**kwargs) | |
| content = response.choices[0].message.content | |
| if not content: | |
| return "" | |
| return content.strip() | |
| # ======================================================== | |
| def update_architecture( | |
| self, | |
| user_message: str | |
| ): | |
| try: | |
| result = self.llm( | |
| [ | |
| { | |
| "role": "system", | |
| "content": ARCHITECT_PROMPT | |
| }, | |
| { | |
| "role": "user", | |
| "content": user_message | |
| } | |
| ], | |
| response_format={ | |
| "type": "json_object" | |
| } | |
| ) | |
| data = json.loads(result) | |
| for key, value in data.items(): | |
| if value in [None, "", []]: | |
| continue | |
| if hasattr(self.state, key): | |
| setattr( | |
| self.state, | |
| key, | |
| value | |
| ) | |
| except Exception as e: | |
| print("Architect error:", e) | |
| # ======================================================== | |
| def update_capabilities(self): | |
| try: | |
| result = self.llm( | |
| [ | |
| { | |
| "role": "system", | |
| "content": CAPABILITY_PROMPT | |
| }, | |
| { | |
| "role": "user", | |
| "content": json.dumps( | |
| self.state.to_dict(), | |
| indent=2 | |
| ) | |
| } | |
| ], | |
| response_format={ | |
| "type": "json_object" | |
| } | |
| ) | |
| data = json.loads(result) | |
| tools = data.get("tools", []) | |
| if isinstance(tools, list): | |
| merged = set( | |
| self.state.tools | |
| ) | |
| merged.update(tools) | |
| self.state.tools = list( | |
| merged | |
| ) | |
| except Exception as e: | |
| print("Capability error:", e) | |
| # ======================================================== | |
| def compile_runtime_prompt(self): | |
| try: | |
| self.runtime_prompt = self.llm( | |
| [ | |
| { | |
| "role": "system", | |
| "content": COMPILER_PROMPT | |
| }, | |
| { | |
| "role": "user", | |
| "content": json.dumps( | |
| self.state.to_dict(), | |
| indent=2 | |
| ) | |
| } | |
| ], | |
| max_tokens=700 | |
| ) | |
| except Exception as e: | |
| print("Compile error:", e) | |
| # ======================================================== | |
| def developer_chat( | |
| self, | |
| message: str | |
| ): | |
| self.update_architecture(message) | |
| self.update_capabilities() | |
| self.compile_runtime_prompt() | |
| reply = self.llm( | |
| [ | |
| { | |
| "role": "system", | |
| "content": DISCOVERY_PROMPT | |
| }, | |
| { | |
| "role": "user", | |
| "content": | |
| f""" | |
| Agent State: | |
| {json.dumps(self.state.to_dict(), indent=2)} | |
| Developer Message: | |
| {message} | |
| """ | |
| } | |
| ], | |
| max_tokens=250 | |
| ) | |
| return reply | |
| # ======================================================== | |
| def client_chat( | |
| self, | |
| message, | |
| history | |
| ): | |
| if not self.runtime_prompt: | |
| self.compile_runtime_prompt() | |
| messages = [ | |
| { | |
| "role": "system", | |
| "content": self.runtime_prompt | |
| } | |
| ] | |
| for item in history: | |
| messages.append( | |
| { | |
| "role": item["role"], | |
| "content": item["content"] | |
| } | |
| ) | |
| messages.append( | |
| { | |
| "role": "user", | |
| "content": message | |
| } | |
| ) | |
| return self.llm( | |
| messages, | |
| max_tokens=700 | |
| ) | |
| # ============================================================ | |
| # APP STATE | |
| # ============================================================ | |
| orchestrator = AgentOrchestrator() | |
| # ============================================================ | |
| # UI CALLBACK | |
| # ============================================================ | |
| def chat_handler( | |
| message, | |
| history, | |
| mode | |
| ): | |
| history = history or [] | |
| if mode == "Developer": | |
| reply = orchestrator.developer_chat( | |
| message | |
| ) | |
| else: | |
| reply = orchestrator.client_chat( | |
| message, | |
| history | |
| ) | |
| history.append( | |
| { | |
| "role": "user", | |
| "content": message | |
| } | |
| ) | |
| history.append( | |
| { | |
| "role": "assistant", | |
| "content": reply | |
| } | |
| ) | |
| state = orchestrator.state.to_dict() | |
| return ( | |
| "", | |
| history, | |
| state.get("name") or "", | |
| state.get("role") or "", | |
| state.get("goal") or "", | |
| state.get("greeting") or "", | |
| state.get("memory") or "", | |
| state.get("tone") or "", | |
| ", ".join(state.get("tools", [])), | |
| orchestrator.runtime_prompt | |
| ) | |
| # ============================================================ | |
| # UI | |
| # ============================================================ | |
| with gr.Blocks( | |
| title="Agent Platform", | |
| fill_height=True | |
| ) as demo: | |
| gr.Markdown("# Agent Platform") | |
| with gr.Row(): | |
| # LEFT PANEL | |
| with gr.Column(scale=2): | |
| mode = gr.Dropdown( | |
| choices=[ | |
| "Developer", | |
| "Client" | |
| ], | |
| value="Developer", | |
| label="Mode" | |
| ) | |
| chatbot = gr.Chatbot( | |
| type="messages", | |
| height=700 | |
| ) | |
| message = gr.Textbox( | |
| placeholder="Describe your agent..." | |
| ) | |
| # RIGHT PANEL | |
| with gr.Column(scale=1): | |
| gr.Markdown("## Agent Definition") | |
| name = gr.Textbox( | |
| label="Name" | |
| ) | |
| role = gr.Textbox( | |
| label="Role" | |
| ) | |
| goal = gr.Textbox( | |
| label="Goal" | |
| ) | |
| greeting = gr.Textbox( | |
| label="Greeting" | |
| ) | |
| memory = gr.Textbox( | |
| label="Memory" | |
| ) | |
| tone = gr.Textbox( | |
| label="Tone" | |
| ) | |
| tools = gr.Textbox( | |
| label="Tools" | |
| ) | |
| runtime_prompt = gr.Textbox( | |
| label="Compiled Runtime Prompt", | |
| lines=18 | |
| ) | |
| message.submit( | |
| chat_handler, | |
| inputs=[ | |
| message, | |
| chatbot, | |
| mode | |
| ], | |
| outputs=[ | |
| message, | |
| chatbot, | |
| name, | |
| role, | |
| goal, | |
| greeting, | |
| memory, | |
| tone, | |
| tools, | |
| runtime_prompt | |
| ] | |
| ) | |
| # ============================================================ | |
| # RUN | |
| # ============================================================ | |
| if __name__ == "__main__": | |
| demo.launch( | |
| share=True, | |
| debug=True | |
| ) |