refactor(brain): Auto-Magie raus — ARIA entscheidet selbst, Stefan fragt im Zweifel
Mut zur Luecke: -595 Zeilen Auto-Magie-Code raus, weil sie heute Abend
4 Bugs verursacht und 0 echten Mehrwert geliefert hat. Plus Stefan
hat zu Recht erkannt dass das System mit Pentest/Audit-Workflows
kollidieren wuerde (Whitelist-Pflege noetig).
Weg:
- aria-brain/api_heuristic.py geloescht (282 Zeilen Cross-Session-
Tracking, Hint-Generation, Bypass-Detection)
- aria-brain/agent.py: Auto-Scaffold-Block, Bypass-Detection-Block,
_upsert_bypass_lesson-Methode (-146 Zeilen)
- aria-brain/main.py: /skills/can-bash-host Endpoint
- aria-brain/prompts.py: api_heuristic_section-Parameter
- docker-compose.yml: managed-settings-Copy aus proxy-Command
- proxy-patches/pre-tool-bash-block.js (PreToolUse-Hook)
- proxy-patches/managed-settings.json (claude-CLI Hook-Config)
Bleibt (kostet nichts, hilft):
- Alle 18 seed_rules (sind in DB, machen keine Last)
- skill_scaffold Tool (ARIA kann es manuell nutzen)
- Anti-Friedhof + snake_case + Safe-Name-Mapping (passive Validierung)
- Versionierung + Rollback (P4, hat sich bei PATH-Bug bewaehrt)
- 50k stdout Truncate-Fix
scaffold-reflex seed_rule umgeschrieben: kein 'SOFORT scaffold'-
Reflex mehr, stattdessen 4-Punkte-Heuristik (parametrisierbar?
wiederkehrend? exploratory? im Zweifel: Stefan fragen). Pentest-
Workflows bleiben damit ad-hoc Bash ohne false-positive
Skill-Vorschlaege.
Existierende auto-feedback-Memories in der DB bleiben — sind nuetzliche
Lehren, werden nicht mehr automatisch erweitert. Stefan kann sie via
Diagnostic-Gehirn-Tab loeschen wenn sie nerven.
Dank git ist alles rueckholbar. Wenn doch wieder Auto-Magie gewuenscht:
git revert auf 8d5991f.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-145
@@ -849,65 +849,6 @@ class Agent:
|
||||
self._pending_events = []
|
||||
return events
|
||||
|
||||
def _upsert_bypass_lesson(self, ev: dict) -> None:
|
||||
"""Speichert die Lehre aus einem Skill-Bypass als pinned Memory.
|
||||
Idempotent ueber migration_key — bei Wiederholung wird der vorhandene
|
||||
Punkt aktualisiert (Counter hoeher). So lernt ARIA cross-session,
|
||||
nicht nur in der aktuellen Konversation."""
|
||||
from datetime import datetime, timezone
|
||||
import uuid as _uuid
|
||||
from memory.vector_store import COLLECTION
|
||||
from qdrant_client.http import models as _qm
|
||||
|
||||
skill_name = ev["skill_name"]
|
||||
host = ev["host"]
|
||||
count = ev["count"]
|
||||
migration_key = f"auto/skill-bypass/{skill_name}"
|
||||
title = f"Skill '{skill_name}' nutzen, nicht curl"
|
||||
run_tool = "run_" + re.sub(r"[^a-zA-Z0-9_]", "_", skill_name)
|
||||
content = (
|
||||
f"WICHTIG fuer Performance + Stefans Wartezeit: "
|
||||
f"Skill '{skill_name}' existiert und deckt {host} ab. "
|
||||
f"Nutze `{run_tool}(...)` als Brain-Tool, NICHT Bash-curl gegen {host}. "
|
||||
f"Brain hat {count}× erkannt dass dieser Skill umgangen wurde "
|
||||
f"(letzter Vorfall: heute). Ein Skill-Aufruf = 1 Tool-Call (~3s) "
|
||||
f"vs. Bash-Wrapper = 3-5 Tool-Calls (~13-20s)."
|
||||
)
|
||||
|
||||
# Alte Version mit gleicher migration_key entfernen (Counter-Update)
|
||||
try:
|
||||
self.store.client.delete(
|
||||
collection_name=COLLECTION,
|
||||
points_selector=_qm.FilterSelector(filter=_qm.Filter(must=[
|
||||
_qm.FieldCondition(key="migration_key",
|
||||
match=_qm.MatchValue(value=migration_key))
|
||||
])),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
vec = self.embedder.embed(content)
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
payload = {
|
||||
"type": "rule",
|
||||
"title": title,
|
||||
"content": content,
|
||||
"pinned": True,
|
||||
"category": "skills",
|
||||
"source": "auto-feedback",
|
||||
"tags": [],
|
||||
"created_at": now,
|
||||
"updated_at": now,
|
||||
"migration_key": migration_key,
|
||||
"attachments": [],
|
||||
}
|
||||
self.store.client.upsert(
|
||||
collection_name=COLLECTION,
|
||||
points=[_qm.PointStruct(id=str(_uuid.uuid4()), vector=vec, payload=payload)],
|
||||
)
|
||||
logger.info("bypass-lesson upserted: skill=%s host=%s count=%d",
|
||||
skill_name, host, count)
|
||||
|
||||
# ── Hauptpfad: ein User-Turn → Tool-Loop → finaler Reply ──
|
||||
|
||||
MAX_TOOL_ITERATIONS = 8 # Schutz vor Endlos-Loops
|
||||
@@ -959,90 +900,6 @@ class Agent:
|
||||
oauth_port = os.environ.get("RVS_PORT_PUBLIC", os.environ.get("RVS_PORT", "443")).strip()
|
||||
oauth_tls = os.environ.get("RVS_TLS", "true").strip().lower() != "false"
|
||||
|
||||
# API-Heuristik: wenn ARIA gegen externe APIs wiederholt via Bash
|
||||
# gecurled hat (cross-session, aus persistiertem agent_stream.jsonl),
|
||||
# injiziert das einen Hinweis-Block der ihr scaffolden empfiehlt.
|
||||
api_heuristic_section = ""
|
||||
try:
|
||||
import api_heuristic as _ah
|
||||
hints = _ah.compute_hints(existing_skills=all_skills)
|
||||
|
||||
# AUTO-SCAFFOLD (Variante C): wenn ein Hinweis ein konkretes
|
||||
# (name, template, params) hat UND der Skill noch nicht existiert,
|
||||
# legt Brain ihn JETZT an — bevor ARIA wieder Bash-curl macht.
|
||||
# ARIA findet den Skill in den naechsten Tool-Listen vor und
|
||||
# nutzt ihn direkt via `run_<name>`. Toggle via ENV.
|
||||
auto_scaffold = os.environ.get("BRAIN_AUTO_SCAFFOLD", "true").strip().lower() != "false"
|
||||
if auto_scaffold and hints:
|
||||
existing_names = {s.get("name") for s in all_skills}
|
||||
scaffolded_any = False
|
||||
for hint in hints:
|
||||
sug = hint.get("suggestion")
|
||||
if not sug:
|
||||
continue
|
||||
sname, stpl, sparams = sug
|
||||
if sname in existing_names:
|
||||
continue
|
||||
try:
|
||||
new_manifest = skills_mod.scaffold_skill(
|
||||
name=sname, template=stpl, params=sparams, author="aria-auto",
|
||||
)
|
||||
logger.info("auto_scaffold: '%s' aus '%s' angelegt (trigger: %s mit %d Calls)",
|
||||
sname, stpl, hint["host"], hint["count"])
|
||||
self._pending_events.append({
|
||||
"type": "skill_created",
|
||||
"skill": {
|
||||
"name": new_manifest["name"],
|
||||
"description": new_manifest.get("description", ""),
|
||||
"execution": new_manifest.get("execution", ""),
|
||||
"active": new_manifest.get("active", True),
|
||||
"setup_error": new_manifest.get("setup_error"),
|
||||
"auto_scaffolded": True,
|
||||
"from_template": stpl,
|
||||
"trigger_host": hint["host"],
|
||||
"trigger_count": hint["count"],
|
||||
},
|
||||
})
|
||||
scaffolded_any = True
|
||||
except Exception as exc:
|
||||
logger.warning("auto_scaffold '%s' fehlgeschlagen: %s", sname, exc)
|
||||
if scaffolded_any:
|
||||
# Skills-Liste refresh damit der frische Skill im Prompt sichtbar ist
|
||||
all_skills = skills_mod.list_skills(active_only=False)
|
||||
active_skills = [s for s in all_skills if s.get("active", True)]
|
||||
# WICHTIG: tools NEU bauen, sonst kennt der claude-CLI-
|
||||
# Subprocess den frisch gescaffoldeten `run_<name>` NICHT
|
||||
# und ARIA muss `<tool_call>`-Tags halluzinieren.
|
||||
tools = list(META_TOOLS) + [_skill_to_tool(s) for s in active_skills]
|
||||
_ah.invalidate_cache()
|
||||
# Heuristik neu rechnen — die scaffold-targets sind jetzt weg
|
||||
hints = _ah.compute_hints(existing_skills=all_skills, force=True)
|
||||
|
||||
api_heuristic_section = _ah.build_section(hints)
|
||||
|
||||
# BYPASS-DETECTION (Variante 3 / Lerneffekt):
|
||||
# Hat ARIA in den letzten ~10min Bash-curl gegen einen Host
|
||||
# gemacht OBWOHL der Skill existiert? → drastischer Hint im
|
||||
# Prompt JETZT + pinned Memory speichern, damit's beim
|
||||
# naechsten Turn / naechster Session weiter sichtbar ist
|
||||
# ("echtes Lernen via Brain-Memory").
|
||||
bypass_events = _ah.detect_recent_bypass(all_skills, since_sec=600)
|
||||
if bypass_events:
|
||||
bypass_section = _ah.build_bypass_section(bypass_events)
|
||||
if bypass_section:
|
||||
api_heuristic_section = (
|
||||
(bypass_section + "\n\n" + api_heuristic_section)
|
||||
if api_heuristic_section else bypass_section
|
||||
)
|
||||
# Pinned-Memory pro Skill speichern, idempotent ueber migration_key
|
||||
for ev in bypass_events:
|
||||
try:
|
||||
self._upsert_bypass_lesson(ev)
|
||||
except Exception as exc:
|
||||
logger.warning("bypass-lesson upsert fehlgeschlagen: %s", exc)
|
||||
except Exception as exc:
|
||||
logger.warning("api_heuristic fehlgeschlagen: %s", exc)
|
||||
|
||||
system_prompt = build_system_prompt(hot, cold, skills=all_skills,
|
||||
triggers=all_triggers,
|
||||
condition_vars=condition_vars,
|
||||
@@ -1051,8 +908,7 @@ class Agent:
|
||||
oauth_services=oauth_services,
|
||||
oauth_callback_host=oauth_host,
|
||||
oauth_callback_port=oauth_port,
|
||||
oauth_callback_tls=oauth_tls,
|
||||
api_heuristic_section=api_heuristic_section)
|
||||
oauth_callback_tls=oauth_tls)
|
||||
messages = [ProxyMessage(role="system", content=system_prompt)]
|
||||
for t in self.conversation.window():
|
||||
messages.append(ProxyMessage(role=t.role, content=t.content))
|
||||
|
||||
Reference in New Issue
Block a user