iteration 8
This commit is contained in:
@@ -1025,8 +1025,13 @@ gelesen (`~/.cline/data/settings/providers.json`, Provider `tensorx`). Alternati
|
||||
er per `--api-key` oder Umgebungsvariable `TENSORX_API_KEY` übergeben werden. Der Key
|
||||
wird **nicht** in Laufartefakten gespeichert.
|
||||
|
||||
**Unterstützter Agentenmodus:** Nur `solo`. Der Adapter implementiert keine Subagenten;
|
||||
`builtin` und `custom` sind nicht freigegeben und führen zum Abbruch.
|
||||
**Unterstützter Agentenmodus:** `solo` (V1) und `builtin` (V1b). Der Modus wird per
|
||||
`--mode solo|builtin` gesteuert. Im Modus `solo` steht das `spawn_subagent`-Tool nicht
|
||||
zur Verfügung. Im Modus `builtin` kann der Hauptagent Subagenten mit eigenem Kontext
|
||||
starten (`spawn_subagent`-Tool) – diese erhalten Read-Only-Tools (kein `write_file`) und
|
||||
eine eigene, vom Hauptagenten unabhängige Konversation. Der Subagent-Typ (`explore` oder
|
||||
`general-purpose`) bestimmt den System-Prompt. Subagent-Token fließen vollständig in
|
||||
`usage` und `modelUsage` ein. `custom` ist nicht freigegeben und führt zum Abbruch.
|
||||
|
||||
**Isolation.** Der Adapter ist ein eigenständiges Python-Skript, das nur die
|
||||
Python-Standardbibliothek und `requests` benötigt. Es liest die Codebasis über die
|
||||
@@ -1067,7 +1072,8 @@ python "$skillDir\glm-kimi-adapter.py" `
|
||||
--output "$lauf\Ergebnisse" `
|
||||
--model $modell `
|
||||
--effort $effort `
|
||||
--max-turns 50 `
|
||||
--mode $modus `
|
||||
--max-turns 80 `
|
||||
--result-dir $lauf `
|
||||
2> "$lauf\Stderr.log"
|
||||
|
||||
@@ -1089,6 +1095,8 @@ Set-Content -Path "$lauf\_meta\endzeit.txt" -Value (Get-Date -Format o)
|
||||
| Agent-Turns | `num_turns` |
|
||||
| Tatsächlich eingesetztes Modell | `model` (aus API-Antwort; mit `model_requested` abzugleichen) |
|
||||
| Tool-Aufrufe | `tool_call_count`, `tool_call_types` (nach Werkzeugname) |
|
||||
| Subagenten | `subagent_stats` (`spawned`, `completed`, `failed`, `by_type`) – nur im Modus `builtin` |
|
||||
| Subagenten-Details | `subagent_details` (je Subagent: Typ, Beschreibung, Turns, Tokens, Status) |
|
||||
| Erzeugte Artefakte | `written_files` (Pfad und Größe je Datei) |
|
||||
| Abschlusstext | `result` |
|
||||
|
||||
|
||||
Binary file not shown.
@@ -206,8 +206,77 @@ TOOLS = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "spawn_subagent",
|
||||
"description": (
|
||||
"Starte einen Subagenten mit eigenem Kontext fuer eine isolierte Teilaufgabe. "
|
||||
"Der Subagent kann Dateien lesen, Verzeichnisse auflisten, suchen und "
|
||||
"Befehle ausfuehren – aber keine Ergebnisdateien schreiben. Verwende dies, "
|
||||
"um einen Teil der Codebasis parallel oder isoliert zu analysieren. "
|
||||
"Der Subagent erhaelt nur die Beschreibung, nicht den bisherigen "
|
||||
"Konversationsverlauf. Gib eine praegnante Aufgabenbeschreibung."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Die Aufgabe fuer den Subagenten (z.B. 'Analysiere alle Berechtigungspruefungen in src/backend/Centron.BL/Security und erstelle eine Zusammenfassung der gefundenen Pruefungen mit Dateipfaden und Methodennamen')",
|
||||
},
|
||||
"subagent_type": {
|
||||
"type": "string",
|
||||
"description": "Typ des Subagenten: 'explore' fuer Code-Erkundung, 'general-purpose' fuer allgemeine Analyse",
|
||||
},
|
||||
},
|
||||
"required": ["description"],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
# Read-Only-Tools fuer Subagenten (kein write_file, kein spawn_subagent)
|
||||
SUBAGENT_TOOLS = [t for t in TOOLS if t["function"]["name"] not in ("write_file", "spawn_subagent")]
|
||||
|
||||
# Standard-Subagent-Typen (fuer Modus 'builtin')
|
||||
BUILTIN_SUBAGENT_PROMPTS = {
|
||||
"explore": (
|
||||
"Du bist ein Code-Explorations-Agent. Deine Aufgabe ist es, einen Teil der "
|
||||
"Codebasis zu untersuchen und eine strukturierte Zusammenfassung deiner "
|
||||
"Erkenntnisse zurueckzugeben. Nutze die Werkzeuge aktiv, um Dateien zu lesen "
|
||||
"und zu durchsuchen. Gib am Ende eine kompakte Zusammenfassung mit konkreten "
|
||||
"Dateipfaden, Klassennamen und Methodennamen zurueck."
|
||||
),
|
||||
"general-purpose": (
|
||||
"Du bist ein Analyse-Agent. Du untersuchst die Codebasis und beantwortest "
|
||||
"die dir gestellte Aufgabe. Nutze die Werkzeuge aktiv. Gib am Ende eine "
|
||||
"praegnante Antwort mit konkreten Belegen (Dateipfade, Methodennamen) zurueck."
|
||||
),
|
||||
}
|
||||
|
||||
# Aktive Subagent-Prompts (wird je Modus gesetzt)
|
||||
SUBAGENT_SYSTEM_PROMPTS = dict(BUILTIN_SUBAGENT_PROMPTS)
|
||||
|
||||
|
||||
def load_custom_agents(agents_file):
|
||||
"""
|
||||
Laedt Agenten-Definitionen aus einer JSON-Datei fuer Modus 'custom'.
|
||||
Format: { "agent_name": { "description": "...", "prompt": "..." }, ... }
|
||||
Rueckgabe: dict agent_name -> system_prompt
|
||||
"""
|
||||
agents_path = Path(agents_file)
|
||||
if not agents_path.is_file():
|
||||
raise FileNotFoundError(f"Agenten-Datei nicht gefunden: {agents_file}")
|
||||
data = json.loads(agents_path.read_text(encoding="utf-8"))
|
||||
prompts = {}
|
||||
for name, spec in data.items():
|
||||
desc = spec.get("description", "")
|
||||
prompt = spec.get("prompt", "")
|
||||
prompts[name] = prompt
|
||||
return prompts
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pfad-Sicherheit
|
||||
@@ -322,7 +391,8 @@ def tool_execute_command(root: str, args: dict) -> str:
|
||||
return "ABGELEHNT: Befehl enthaelt verbotenes Muster. Schreibende und bauende Kommandos sind gesperrt."
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command, shell=True, cwd=root, capture_output=True, text=True, timeout=60,
|
||||
command, shell=True, cwd=root, capture_output=True, text=True,
|
||||
timeout=60, encoding="utf-8", errors="replace",
|
||||
)
|
||||
output = result.stdout or ""
|
||||
if result.stderr:
|
||||
@@ -341,6 +411,13 @@ def tool_write_file(output_dir: str, args: dict) -> str:
|
||||
content = args.get("content", "")
|
||||
if not path:
|
||||
return "FEHLER: Kein Dateipfad angegeben"
|
||||
# Modell gibt oft "Ergebnisse/<name>" als Pfad – Präfix entfernen
|
||||
# da output_dir bereits das Ergebnisse-Verzeichnis ist.
|
||||
path = path.replace("\\", "/")
|
||||
for prefix in ("Ergebnisse/", "./Ergebnisse/", "ergebnisse/"):
|
||||
if path.startswith(prefix):
|
||||
path = path[len(prefix):]
|
||||
break
|
||||
try:
|
||||
base = Path(output_dir).resolve()
|
||||
target = (base / path).resolve()
|
||||
@@ -368,6 +445,106 @@ def execute_tool(name: str, args: dict, root: str, output_dir: str) -> str:
|
||||
return f"FEHLER: Unbekanntes Werkzeug: {name}"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Subagent
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def run_subagent(provider, model, api_key, effort, root, description,
|
||||
subagent_type, temperature, timeout, max_turns=15):
|
||||
"""
|
||||
Startet einen Subagenten mit eigenem Kontext.
|
||||
Der Subagent erhaelt Read-Only-Tools und eine begrenzte Turn-Anzahl.
|
||||
Rueckgabe: dict mit result, usage, turns, tool_calls, status.
|
||||
"""
|
||||
sys_prompt = SUBAGENT_SYSTEM_PROMPTS.get(
|
||||
subagent_type, SUBAGENT_SYSTEM_PROMPTS["general-purpose"]
|
||||
)
|
||||
messages = [
|
||||
{"role": "system", "content": sys_prompt},
|
||||
{"role": "user", "content": description},
|
||||
]
|
||||
sub_usage = {"prompt_tokens": 0, "completion_tokens": 0,
|
||||
"total_tokens": 0, "cached_tokens": 0, "reasoning_tokens": 0}
|
||||
sub_turns = 0
|
||||
sub_tool_calls = 0
|
||||
sub_result = ""
|
||||
sub_errors = []
|
||||
|
||||
while sub_turns < max_turns:
|
||||
sub_turns += 1
|
||||
try:
|
||||
resp = call_api_subagent(provider, model, messages, api_key,
|
||||
effort, temperature, timeout)
|
||||
except Exception as e:
|
||||
sub_errors.append(str(e))
|
||||
break
|
||||
u = resp.get("usage", {})
|
||||
sub_usage["prompt_tokens"] += u.get("prompt_tokens", 0)
|
||||
sub_usage["completion_tokens"] += u.get("completion_tokens", 0)
|
||||
sub_usage["total_tokens"] += u.get("total_tokens", 0)
|
||||
sub_usage["cached_tokens"] += u.get("prompt_tokens_details", {}).get("cached_tokens", 0)
|
||||
sub_usage["reasoning_tokens"] += u.get("completion_tokens_details", {}).get("reasoning_tokens", 0)
|
||||
|
||||
choices = resp.get("choices", [])
|
||||
if not choices:
|
||||
sub_errors.append("Keine choices in Subagent-Antwort")
|
||||
break
|
||||
msg = choices[0].get("message", {})
|
||||
messages.append(msg)
|
||||
content = msg.get("content", "")
|
||||
if content:
|
||||
sub_result = content
|
||||
tool_calls = msg.get("tool_calls", [])
|
||||
if not tool_calls:
|
||||
break
|
||||
for tc in tool_calls:
|
||||
func = tc.get("function", {})
|
||||
tname = func.get("name", "")
|
||||
try:
|
||||
targs = json.loads(func.get("arguments", "{}"))
|
||||
except json.JSONDecodeError:
|
||||
targs = {}
|
||||
sub_tool_calls += 1
|
||||
# Subagent darf nur Read-Only-Tools nutzen
|
||||
if tname in ("read_file", "list_directory", "search_files", "execute_command"):
|
||||
tresult = execute_tool(tname, targs, root, "")
|
||||
else:
|
||||
tresult = f"FEHLER: Werkzeug '{tname}' ist fuer Subagenten nicht freigegeben."
|
||||
messages.append({"role": "tool", "tool_call_id": tc.get("id", ""),
|
||||
"name": tname, "content": tresult})
|
||||
|
||||
return {
|
||||
"result": sub_result or "(Subagent ohne Ergebnis)",
|
||||
"usage": sub_usage,
|
||||
"turns": sub_turns,
|
||||
"tool_calls": sub_tool_calls,
|
||||
"errors": sub_errors,
|
||||
"status": "completed" if sub_result else "failed",
|
||||
}
|
||||
|
||||
|
||||
def call_api_subagent(provider, model, messages, api_key, effort, temperature, timeout):
|
||||
"""API-Aufruf fuer Subagenten (mit SUBAGENT_TOOLS statt TOOLS)."""
|
||||
url = f"{provider['base_url']}/chat/completions"
|
||||
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
||||
body = {
|
||||
"model": model, "messages": messages, "tools": SUBAGENT_TOOLS,
|
||||
"tool_choice": "auto", "temperature": temperature, "stream": False,
|
||||
}
|
||||
model_prefix = model.split("/")[0] if "/" in model else ""
|
||||
effort_type = MODEL_EFFORT_TYPE.get(model_prefix, "thinking")
|
||||
effort_val = EFFORT_MAP.get(effort, {}).get(effort_type, "medium")
|
||||
if effort_type == "thinking":
|
||||
body["thinking"] = {"type": "enabled", "level": effort_val}
|
||||
elif effort_type == "reasoning_effort":
|
||||
body["reasoning_effort"] = effort_val
|
||||
resp = requests.post(url, headers=headers, json=body,
|
||||
timeout=timeout if timeout > 0 else 1800)
|
||||
if resp.status_code != 200:
|
||||
raise RuntimeError(f"API-Fehler {resp.status_code}: {resp.text[:2000]}")
|
||||
return resp.json()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# API-Aufruf
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -400,8 +577,35 @@ def call_api(provider, model, messages, api_key, effort, temperature, timeout):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def run_agent_loop(provider, model, system_prompt, user_prompt, api_key, effort,
|
||||
root, output_dir, max_turns, temperature, timeout):
|
||||
root, output_dir, max_turns, temperature, timeout, mode="solo"):
|
||||
"""Fuehrt den Agent-Loop durch und sammelt Metriken."""
|
||||
# Tools je nach Modus waehlen
|
||||
if mode == "builtin":
|
||||
active_tools = TOOLS # inklusive spawn_subagent
|
||||
else:
|
||||
active_tools = [t for t in TOOLS if t["function"]["name"] != "spawn_subagent"]
|
||||
|
||||
# call_api mit den aktiven Tools parametrisieren
|
||||
def _call_api(messages):
|
||||
url = f"{provider['base_url']}/chat/completions"
|
||||
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
|
||||
body = {
|
||||
"model": model, "messages": messages, "tools": active_tools,
|
||||
"tool_choice": "auto", "temperature": temperature, "stream": False,
|
||||
}
|
||||
model_prefix = model.split("/")[0] if "/" in model else ""
|
||||
effort_type = MODEL_EFFORT_TYPE.get(model_prefix, "thinking")
|
||||
effort_val = EFFORT_MAP.get(effort, {}).get(effort_type, "medium")
|
||||
if effort_type == "thinking":
|
||||
body["thinking"] = {"type": "enabled", "level": effort_val}
|
||||
elif effort_type == "reasoning_effort":
|
||||
body["reasoning_effort"] = effort_val
|
||||
resp = requests.post(url, headers=headers, json=body,
|
||||
timeout=timeout if timeout > 0 else 1800)
|
||||
if resp.status_code != 200:
|
||||
raise RuntimeError(f"API-Fehler {resp.status_code}: {resp.text[:2000]}")
|
||||
return resp.json()
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt},
|
||||
@@ -415,12 +619,51 @@ def run_agent_loop(provider, model, system_prompt, user_prompt, api_key, effort,
|
||||
finish_reason = None
|
||||
errors = []
|
||||
start_time = time.time()
|
||||
# Subagent-Tracking
|
||||
subagent_stats = {"spawned": 0, "completed": 0, "failed": 0, "by_type": {}}
|
||||
subagent_details = []
|
||||
MAX_SUBAGENTS = 10 # Hartes Limit: danach wird spawn_subagent verweigert
|
||||
write_file_count = 0 # Zaehlt write_file-Aufrufe
|
||||
write_reminder_sent = False # Wurde schon eine Schreib-Erinnerung gesendet?
|
||||
|
||||
while turns < max_turns:
|
||||
turns += 1
|
||||
|
||||
# Schreib-Erinnerung: Wenn nach 1/3 der Turns noch kein write_file,
|
||||
# oder nach 2/3 der Turns weniger als 3 write_file-Aufrufe
|
||||
if not write_reminder_sent and turns >= max_turns // 3 and write_file_count == 0:
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": (
|
||||
"WICHTIG: Du hast bisher keine Ergebnisdateien geschrieben. "
|
||||
"Beginne JETZT damit, deine Analyseergebnisse mit write_file "
|
||||
"in die vorgegebenen Dateien (StRS.md, SyRS.md, SwRS.md, "
|
||||
"Traceability.md, Hypothesen.md, Glossar.md, Analysebericht.md) "
|
||||
"zu schreiben. Schreibe nicht weiter Subagenten — formalisiere "
|
||||
"deine bisherigen Erkenntnisse in Anforderungen."
|
||||
),
|
||||
})
|
||||
write_reminder_sent = True
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Schreib-Erinnerung gesendet "
|
||||
f"(Turn {turns}, 0 write_file-Aufrufe)\n")
|
||||
elif (not write_reminder_sent and turns >= max_turns * 2 // 3
|
||||
and write_file_count < 3):
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": (
|
||||
f"WICHTIG: Du hast bisher nur {write_file_count} Ergebnisdatei(en) "
|
||||
f"geschrieben. Es fehlen noch mehrere der 7 vorgegebenen Dateien "
|
||||
f"(StRS.md, SyRS.md, SwRS.md, Traceability.md, Hypothesen.md, "
|
||||
f"Glossar.md, Analysebericht.md). Schreibe die fehlenden Dateien "
|
||||
f"JETZT mit write_file."
|
||||
),
|
||||
})
|
||||
write_reminder_sent = True
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Schreib-Erinnerung gesendet "
|
||||
f"(Turn {turns}, {write_file_count} write_file-Aufrufe)\n")
|
||||
|
||||
try:
|
||||
response = call_api(provider, model, messages, api_key,
|
||||
effort, temperature, timeout)
|
||||
response = _call_api(messages)
|
||||
except Exception as e:
|
||||
errors.append(f"Turn {turns}: API-Fehler: {e}")
|
||||
break
|
||||
@@ -430,7 +673,6 @@ def run_agent_loop(provider, model, system_prompt, user_prompt, api_key, effort,
|
||||
total_usage["total_tokens"] += usage.get("total_tokens", 0)
|
||||
cached = usage.get("prompt_tokens_details", {}).get("cached_tokens", 0)
|
||||
total_usage["cached_tokens"] += cached
|
||||
# Reasoning/Thinking-Tokens aus completion_tokens_details
|
||||
comp_details = usage.get("completion_tokens_details", {})
|
||||
total_usage["reasoning_tokens"] += comp_details.get("reasoning_tokens", 0)
|
||||
if response.get("model"):
|
||||
@@ -459,7 +701,60 @@ def run_agent_loop(provider, model, system_prompt, user_prompt, api_key, effort,
|
||||
except json.JSONDecodeError:
|
||||
tool_args = {}
|
||||
tool_calls_log.append({"turn": turns, "name": tool_name, "args": tool_args})
|
||||
result = execute_tool(tool_name, tool_args, root, output_dir)
|
||||
|
||||
# write_file-Zaehler erhoehen
|
||||
if tool_name == "write_file":
|
||||
write_file_count += 1
|
||||
|
||||
# Subagent-Spawning behandeln
|
||||
if tool_name == "spawn_subagent":
|
||||
if subagent_stats["spawned"] >= MAX_SUBAGENTS:
|
||||
# Hartes Limit erreicht: verweigere und erzwinge Schreibphase
|
||||
result = (
|
||||
"ABGELEHNT: Subagent-Limit erreicht (10/10). "
|
||||
"Du hast bereits 10 Subagenten gestartet. "
|
||||
"Schreibe JETZT deine Ergebnisdateien mit write_file: "
|
||||
"StRS.md, SyRS.md, SwRS.md, Traceability.md, "
|
||||
"Hypothesen.md, Glossar.md, Analysebericht.md. "
|
||||
"Starte keine weiteren Subagenten."
|
||||
)
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Subagent verweigert "
|
||||
f"(Limit {MAX_SUBAGENTS} erreicht)\n")
|
||||
else:
|
||||
sa_desc = tool_args.get("description", "")
|
||||
sa_type = tool_args.get("subagent_type", "general-purpose")
|
||||
subagent_stats["spawned"] += 1
|
||||
subagent_stats["by_type"][sa_type] = subagent_stats["by_type"].get(sa_type, 0) + 1
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Subagent "
|
||||
f"{subagent_stats['spawned']}/{MAX_SUBAGENTS} "
|
||||
f"gestartet (Typ: {sa_type})\n")
|
||||
try:
|
||||
sa_result = run_subagent(
|
||||
provider, model, api_key, effort, root,
|
||||
sa_desc, sa_type, temperature, timeout
|
||||
)
|
||||
subagent_stats["completed" if sa_result["status"] == "completed" else "failed"] += 1
|
||||
sa_u = sa_result["usage"]
|
||||
total_usage["prompt_tokens"] += sa_u["prompt_tokens"]
|
||||
total_usage["completion_tokens"] += sa_u["completion_tokens"]
|
||||
total_usage["total_tokens"] += sa_u["total_tokens"]
|
||||
total_usage["cached_tokens"] += sa_u["cached_tokens"]
|
||||
total_usage["reasoning_tokens"] += sa_u["reasoning_tokens"]
|
||||
subagent_details.append({
|
||||
"id": subagent_stats["spawned"],
|
||||
"type": sa_type,
|
||||
"description": sa_desc[:200],
|
||||
"turns": sa_result["turns"],
|
||||
"tool_calls": sa_result["tool_calls"],
|
||||
"tokens": sa_u["total_tokens"],
|
||||
"status": sa_result["status"],
|
||||
})
|
||||
result = sa_result["result"]
|
||||
except Exception as e:
|
||||
subagent_stats["failed"] += 1
|
||||
result = f"FEHLER: Subagent fehlgeschlagen: {e}"
|
||||
else:
|
||||
result = execute_tool(tool_name, tool_args, root, output_dir)
|
||||
messages.append({"role": "tool", "tool_call_id": tc_id,
|
||||
"name": tool_name, "content": result})
|
||||
|
||||
@@ -511,7 +806,10 @@ def run_agent_loop(provider, model, system_prompt, user_prompt, api_key, effort,
|
||||
"tool_call_types": tool_call_types,
|
||||
"written_files": written_files, "result": final_content,
|
||||
"finish_reason": finish_reason, "errors": errors, "session_id": "",
|
||||
"adapter": "python-glm-kimi", "adapter_version": "1.0.0",
|
||||
"adapter": "python-glm-kimi", "adapter_version": "1.1.0",
|
||||
"mode": mode,
|
||||
"subagent_stats": subagent_stats,
|
||||
"subagent_details": subagent_details,
|
||||
}
|
||||
|
||||
|
||||
@@ -528,6 +826,8 @@ def main():
|
||||
parser.add_argument("--provider", default="tensorx", help="API-Provider (default: tensorx)")
|
||||
parser.add_argument("--api-key", default=None, help="API-Key (default: aus Cline providers.json)")
|
||||
parser.add_argument("--effort", default="high", choices=["low", "medium", "high", "xhigh", "max"])
|
||||
parser.add_argument("--mode", default="solo", choices=["solo", "builtin", "custom"], help="Agentenmodus (solo=keine Subagenten, builtin=eingebaute, custom=vordefinierte Agenten aus Datei)")
|
||||
parser.add_argument("--agents", default=None, help="Pfad zu Agenten-Definitionen (JSON) fuer Modus 'custom'")
|
||||
parser.add_argument("--max-turns", type=int, default=50)
|
||||
parser.add_argument("--temperature", type=float, default=1.0)
|
||||
parser.add_argument("--timeout", type=int, default=0, help="Timeout in Sek (0=keins)")
|
||||
@@ -567,8 +867,50 @@ def main():
|
||||
"Du bist ein Requirements Engineer im Reverse Requirements Engineering "
|
||||
"eines Legacy-ERP-Systems. Du analysierst die Codebasis im Arbeitsverzeichnis "
|
||||
"und erstellst eine Anforderungsspezifikation nach ISO/IEC/IEEE 29148:2018.\n\n"
|
||||
"Werkzeuge: read_file, list_directory, search_files, execute_command, write_file.\n"
|
||||
"Die Codebasis wird ausschliesslich GELESEN. Schreibe Ergebnisdateien mit "
|
||||
"Werkzeuge: read_file, list_directory, search_files, execute_command, write_file.\n\n"
|
||||
"WICHTIG: Beginne deine Arbeit mit dem Schreiben von Ergebnisdateien (write_file), "
|
||||
"nicht mit dem Erkunden. Erstelle zuerst die Skelette der 7 Ergebnisdateien "
|
||||
"(StRS.md, SyRS.md, SwRS.md, Traceability.md, Hypothesen.md, Glossar.md, "
|
||||
"Analysebericht.md) mit Platzhalter-Inhalt, bevor du in die Details gehst. "
|
||||
"Wenn du Ergebnisse hast, schreibe sie SOFORT mit write_file — beschreibe nicht, "
|
||||
"was du schreiben wirst, schreibe es."
|
||||
)
|
||||
if args.mode == "builtin":
|
||||
system_prompt += (
|
||||
"\nZusaetzlich steht spawn_subagent zur Verfuegung: Starte einen "
|
||||
"Subagenten mit eigenem Kontext fuer isolierte Teilaufgaben (z.B. "
|
||||
"Analyse eines einzelnen Moduls). Der Subagent kann nur lesen, nicht "
|
||||
"schreiben. Nutze Subagenten, um die Breite der Analyse zu erhoehen: "
|
||||
"delegiere Modul-Analysen an Subagenten, waehrend du die "
|
||||
"Gesamtstruktur und die Ergebnisdateien verwaltest."
|
||||
)
|
||||
elif args.mode == "custom":
|
||||
# Custom agents laden
|
||||
if args.agents:
|
||||
custom_prompts = load_custom_agents(args.agents)
|
||||
SUBAGENT_SYSTEM_PROMPTS.clear()
|
||||
SUBAGENT_SYSTEM_PROMPTS.update(custom_prompts)
|
||||
agent_list = ", ".join(SUBAGENT_SYSTEM_PROMPTS.keys())
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Custom agents geladen: {agent_list}\n")
|
||||
system_prompt += (
|
||||
f"\nDu orchestrierst spezialisierte Subagenten. Verfuegbare Agenten-Typen: "
|
||||
f"{agent_list}. Nutze spawn_subagent mit dem passenden subagent_type, "
|
||||
f"um Teilaufgaben zu delegieren. Vorgehen: "
|
||||
f"1. Starte 'modulinventar' fuer das vollstaendige Inventar. "
|
||||
f"2. Starte 'faktenermittler' fuer Modulausschnitte, die du analysieren willst. "
|
||||
f"3. Schreibe die Anforderungen selbst mit write_file (die Autoren-Agenten "
|
||||
f"sind nur fuer Vorbereitung da, nicht fuer das Schreiben der Ergebnisdateien). "
|
||||
f"4. Fuehre den Konsistenzcheck selbst durch. "
|
||||
f"Der Subagent kann nur lesen, nicht schreiben."
|
||||
)
|
||||
else:
|
||||
sys.stderr.write("[glm-kimi-adapter] WARNUNG: Modus 'custom' ohne --agents, falle auf 'builtin' zurueck\n")
|
||||
args.mode = "builtin"
|
||||
system_prompt += (
|
||||
"\nZusaetzlich steht spawn_subagent zur Verfuegung."
|
||||
)
|
||||
system_prompt += (
|
||||
"\nDie Codebasis wird ausschliesslich GELESEN. Schreibe Ergebnisdateien mit "
|
||||
"write_file ins Ausgabeverzeichnis. Sprache: Deutsch fuer Anforderungen."
|
||||
)
|
||||
|
||||
@@ -582,13 +924,14 @@ def main():
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Provider: {provider['name']}\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Modell: {args.model}\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Effort: {args.effort}\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Mode: {args.mode}\n")
|
||||
|
||||
try:
|
||||
result = run_agent_loop(
|
||||
provider=provider, model=args.model, system_prompt=system_prompt,
|
||||
user_prompt=user_prompt, api_key=api_key, effort=args.effort,
|
||||
root=args.root, output_dir=str(output_dir), max_turns=args.max_turns,
|
||||
temperature=args.temperature, timeout=args.timeout,
|
||||
temperature=args.temperature, timeout=args.timeout, mode=args.mode,
|
||||
)
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
@@ -602,7 +945,10 @@ def main():
|
||||
"reasoning_tokens": 0},
|
||||
"modelUsage": {}, "tool_calls": [], "tool_call_count": 0,
|
||||
"tool_call_types": {}, "written_files": [], "result": "",
|
||||
"errors": [str(e)], "adapter": "python-glm-kimi", "adapter_version": "1.0.0",
|
||||
"errors": [str(e)], "adapter": "python-glm-kimi", "adapter_version": "1.1.0",
|
||||
"mode": args.mode,
|
||||
"subagent_stats": {"spawned": 0, "completed": 0, "failed": 0, "by_type": {}},
|
||||
"subagent_details": [],
|
||||
}
|
||||
|
||||
end_iso = datetime.now(timezone.utc).isoformat()
|
||||
@@ -616,6 +962,8 @@ def main():
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Turns: {result['num_turns']}\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Tokens gesamt: {result['usage']['total_tokens']:,}\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Tool-Calls: {result['tool_call_count']}\n")
|
||||
sa = result.get("subagent_stats", {})
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Subagenten: {sa.get('spawned',0)} (completed: {sa.get('completed',0)}, failed: {sa.get('failed',0)})\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] Ergebnisdateien: {len(result['written_files'])}\n")
|
||||
sys.stderr.write(f"[glm-kimi-adapter] RawResult: {raw_result_path}\n")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user