From 01eddde6421ef3d41f98b31cdec1be4dd660072d Mon Sep 17 00:00:00 2001 From: Till Immer Date: Sat, 4 Jul 2026 21:56:31 +0000 Subject: [PATCH] agent.py aktualisiert --- agent.py | 108 ++++++++++++++++--------------------------------------- 1 file changed, 30 insertions(+), 78 deletions(-) diff --git a/agent.py b/agent.py index 180b779..09ffab5 100644 --- a/agent.py +++ b/agent.py @@ -1,5 +1,4 @@ import json -import re from config import OPENROUTER_MODEL from openrouter_client import client @@ -14,88 +13,43 @@ class Agent: { "role": "system", "content": ( - "Du bist N.O.R.A. ( Neural Operations for Residential Automation), ein Smart-Home Assistent. Du bist höfflich zielorientiert und leicht ironisch und zynisch. Du bevorzugst kurze präzise Antworten ausser du wirst nach langen Erkärungen gefragt. Du kontrolierst das Smart-Home und bist perönlicher Assistent\n" - "Du kannst MCP Tools verwenden.\n\n" - "Wenn du ein Tool benutzen willst, antworte STRICT als JSON:\n" - "{\n" - ' "tool": "tool_name",\n' - ' "args": {...}\n' - "}\n\n" - "Wenn kein Tool nötig ist:\n" - "{\n" - ' "response": "Text"\n' - "}\n\n" - "WICHTIG:\n" - "- KEIN Markdown\n" - "- KEIN zusätzlicher Text\n" - "- NUR JSON\n" + "Du bist JARVIS, ein Smart-Home Assistent.\n" + "Du steuerst ein Haus über MCP Tools.\n" + "Antworte normal oder nutze Tools wenn nötig." ) } ] async def load_tools(self): - """ - MCP Tools holen und in OpenRouter Format konvertieren - """ - - response = await self.mcp.list_tools() + res = await self.mcp.list_tools() self.tools = [] - for t in response.tools: + for t in res.tools: self.tools.append({ "type": "function", "function": { "name": t.name, "description": t.description, - "parameters": t.inputSchema, + "parameters": t.inputSchema } }) print(f"[JARVIS] {len(self.tools)} Tools geladen") - def _extract_json(self, text: str): - """ - Repariert kaputte LLM JSON Outputs - """ - - try: - return json.loads(text) - except: - pass - - # JSON aus Text extrahieren - match = re.search(r"\{.*\}", text, re.DOTALL) - - if match: - try: - return json.loads(match.group(0)) - except: - pass - - return None - async def _execute_tool(self, tool_call): - """ - Führt MCP Tool aus - """ - - name = tool_call["tool"] - args = tool_call.get("args", {}) + async def _run_tool(self, tool_call): + name = tool_call.function.name + args = json.loads(tool_call.function.arguments or "{}") result = await self.mcp.call_tool(name, args) return result async def run(self, user_input: str): - """ - Vollständiger Tool-Calling Loop - """ self.messages.append({ "role": "user", "content": user_input }) - MAX_STEPS = 8 - - for _ in range(MAX_STEPS): + for _ in range(8): response = await client.chat.completions.create( model=OPENROUTER_MODEL, @@ -103,38 +57,36 @@ class Agent: tools=self.tools ) - msg = response.choices[0].message.content + message = response.choices[0].message - parsed = self._extract_json(msg) + # 🧠 TOOL CALL PATH + if getattr(message, "tool_calls", None): - # ❌ Falls kein gültiges JSON → direkte Antwort - if not parsed: - return msg + self.messages.append(message) - # 🧠 Tool Call - if "tool" in parsed: + for tool_call in message.tool_calls: - tool_result = await self._execute_tool(parsed) + result = await self._run_tool(tool_call) - self.messages.append({ - "role": "assistant", - "content": msg - }) - - self.messages.append({ - "role": "tool", - "content": str(tool_result) - }) + self.messages.append({ + "role": "tool", + "tool_call_id": tool_call.id, + "content": str(result) + }) continue - # ✅ Final Response - if "response" in parsed: + # 🧠 NORMAL RESPONSE PATH + if message.content: + self.messages.append({ "role": "assistant", - "content": parsed["response"] + "content": message.content }) - return parsed["response"] + return message.content - return "⚠️ Tool Loop Limit erreicht" \ No newline at end of file + # 🧠 SAFETY FALLBACK + return "Ich konnte keine gültige Antwort generieren." + + return "Tool Loop Limit erreicht." \ No newline at end of file