agent.py aktualisiert

This commit is contained in:
2026-07-04 21:56:31 +00:00
parent ec7bad6d1b
commit 01eddde642
+30 -78
View File
@@ -1,5 +1,4 @@
import json import json
import re
from config import OPENROUTER_MODEL from config import OPENROUTER_MODEL
from openrouter_client import client from openrouter_client import client
@@ -14,88 +13,43 @@ class Agent:
{ {
"role": "system", "role": "system",
"content": ( "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 bist JARVIS, ein Smart-Home Assistent.\n"
"Du kannst MCP Tools verwenden.\n\n" "Du steuerst ein Haus über MCP Tools.\n"
"Wenn du ein Tool benutzen willst, antworte STRICT als JSON:\n" "Antworte normal oder nutze Tools wenn nötig."
"{\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"
) )
} }
] ]
async def load_tools(self): async def load_tools(self):
""" res = await self.mcp.list_tools()
MCP Tools holen und in OpenRouter Format konvertieren
"""
response = await self.mcp.list_tools()
self.tools = [] self.tools = []
for t in response.tools: for t in res.tools:
self.tools.append({ self.tools.append({
"type": "function", "type": "function",
"function": { "function": {
"name": t.name, "name": t.name,
"description": t.description, "description": t.description,
"parameters": t.inputSchema, "parameters": t.inputSchema
} }
}) })
print(f"[JARVIS] {len(self.tools)} Tools geladen") print(f"[JARVIS] {len(self.tools)} Tools geladen")
def _extract_json(self, text: str): async def _run_tool(self, tool_call):
""" name = tool_call.function.name
Repariert kaputte LLM JSON Outputs args = json.loads(tool_call.function.arguments or "{}")
"""
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", {})
result = await self.mcp.call_tool(name, args) result = await self.mcp.call_tool(name, args)
return result return result
async def run(self, user_input: str): async def run(self, user_input: str):
"""
Vollständiger Tool-Calling Loop
"""
self.messages.append({ self.messages.append({
"role": "user", "role": "user",
"content": user_input "content": user_input
}) })
MAX_STEPS = 8 for _ in range(8):
for _ in range(MAX_STEPS):
response = await client.chat.completions.create( response = await client.chat.completions.create(
model=OPENROUTER_MODEL, model=OPENROUTER_MODEL,
@@ -103,38 +57,36 @@ class Agent:
tools=self.tools 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 self.messages.append(message)
if not parsed:
return msg
# 🧠 Tool Call for tool_call in message.tool_calls:
if "tool" in parsed:
tool_result = await self._execute_tool(parsed) result = await self._run_tool(tool_call)
self.messages.append({ self.messages.append({
"role": "assistant", "role": "tool",
"content": msg "tool_call_id": tool_call.id,
}) "content": str(result)
})
self.messages.append({
"role": "tool",
"content": str(tool_result)
})
continue continue
# ✅ Final Response # 🧠 NORMAL RESPONSE PATH
if "response" in parsed: if message.content:
self.messages.append({ self.messages.append({
"role": "assistant", "role": "assistant",
"content": parsed["response"] "content": message.content
}) })
return parsed["response"] return message.content
return "⚠️ Tool Loop Limit erreicht" # 🧠 SAFETY FALLBACK
return "Ich konnte keine gültige Antwort generieren."
return "Tool Loop Limit erreicht."