feat(voice): ear_control-Tool — ARIA versteht Ohr-Aus/-An in jeder Formulierung
Statt jede Schlaf-/Aus-Formulierung per Regex aufzuzählen: ein Tool ear_control
(action off|on), das ARIA aufruft, wenn Stefan sinngemäß "hör auf/wieder zu
zuhören" sagt — egal wie ("leg dich schlafen", "ich geh ins Bett, du kannst
aus", "mach Pause vom Zuhören"). Tools ruft ARIA zuverlässig (im Gegensatz zu
den [[..]]-Markern, die sie oft ignoriert).
Nutzt die komplette bestehende Plumbing: der Tool-Call setzt _ear_control →
answered_by wird "wake-off"/"wake-on" → main.py setzt wake_off/wake_on → Bridge
→ App stoppt/startet Listener. Reiner Steuerbefehl (still, kein Weiterlauschen).
Der deterministische Regex-Detektor bleibt als schnelles Netz für die
Standard-Sätze (instant, kein Claude-Call). Prompt-Hinweis in der Voice-Flow-
Sektion ergänzt. Brain-only — kein neues APK nötig.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+47
-1
@@ -132,6 +132,34 @@ WEB_SEARCH_TOOL = {
|
|||||||
|
|
||||||
# Meta-Tool: ARIA kann selbst neue Skills bauen
|
# Meta-Tool: ARIA kann selbst neue Skills bauen
|
||||||
META_TOOLS = [
|
META_TOOLS = [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "ear_control",
|
||||||
|
"description": (
|
||||||
|
"Schaltet dein Ohr (den Wake-Word-Listener) an oder aus. Nutze das, "
|
||||||
|
"wenn Stefan will dass du aufhoerst zuzuhoeren — EGAL wie er es "
|
||||||
|
"formuliert: 'leg dich schlafen', 'geh schlafen', 'Ohr aus', 'gute "
|
||||||
|
"Nacht', 'mach mal Pause vom Zuhoeren', 'ich geh ins Bett, du kannst "
|
||||||
|
"aus' → action='off'. Wenn er dich wieder aktivieren will ('Ohr an', "
|
||||||
|
"'wach auf', 'hoer wieder zu') → action='on'. Reiner Steuerbefehl: "
|
||||||
|
"die App stoppt/startet den Listener, du bestaetigst nur kurz (wird "
|
||||||
|
"nicht vorgelesen). Nach 'off' geht Wieder-An per 'Ohr an' (Text/"
|
||||||
|
"Aufnahme-Knopf) oder App-Button."
|
||||||
|
),
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"action": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["off", "on"],
|
||||||
|
"description": "off = Ohr aus (nicht mehr zuhoeren), on = Ohr wieder an",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": ["action"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
@@ -2135,6 +2163,7 @@ class Agent:
|
|||||||
# Konversation bleiben gesprochen.
|
# Konversation bleiben gesprochen.
|
||||||
self._claude_turn_speak = True
|
self._claude_turn_speak = True
|
||||||
self._claude_turn_converse = True # Default Gespraech; run_*-Skill setzt es
|
self._claude_turn_converse = True # Default Gespraech; run_*-Skill setzt es
|
||||||
|
self._ear_control = None # ear_control-Tool: 'off'|'on' oder None
|
||||||
try:
|
try:
|
||||||
for iteration in range(self.MAX_TOOL_ITERATIONS):
|
for iteration in range(self.MAX_TOOL_ITERATIONS):
|
||||||
result = self.proxy.chat_full(messages, tools=tools,
|
result = self.proxy.chat_full(messages, tools=tools,
|
||||||
@@ -2248,8 +2277,16 @@ class Agent:
|
|||||||
converse = False
|
converse = False
|
||||||
elif _wants_continue:
|
elif _wants_continue:
|
||||||
converse = True
|
converse = True
|
||||||
|
# ear_control-Tool aufgerufen → Ohr schalten. answered_by=wake-off/wake-on
|
||||||
|
# nutzt die bestehende Plumbing (main.py → wake_off/wake_on → Bridge → App).
|
||||||
|
# Reiner Steuerbefehl: still + kein Weiterlauschen.
|
||||||
|
answered_by = "claude"
|
||||||
|
if self._ear_control == "off":
|
||||||
|
answered_by, speak, converse = "wake-off", False, False
|
||||||
|
elif self._ear_control == "on":
|
||||||
|
answered_by, speak, converse = "wake-on", False, False
|
||||||
# awaiting_reply = ARIA stellt eine blockierende Rueckfrage (Queue pausiert).
|
# awaiting_reply = ARIA stellt eine blockierende Rueckfrage (Queue pausiert).
|
||||||
return (final_reply, "claude", speak, converse, awaiting_reply)
|
return (final_reply, answered_by, speak, converse, awaiting_reply)
|
||||||
|
|
||||||
# ── Tool-Dispatcher ───────────────────────────────────────
|
# ── Tool-Dispatcher ───────────────────────────────────────
|
||||||
|
|
||||||
@@ -2844,6 +2881,15 @@ class Agent:
|
|||||||
f"WICHTIG: Schreibe in deiner Antwort an Stefan den Pfad EXAKT als "
|
f"WICHTIG: Schreibe in deiner Antwort an Stefan den Pfad EXAKT als "
|
||||||
f"Marker: [FILE: {result['path']}] — dann zeigt die App das Bild inline."
|
f"Marker: [FILE: {result['path']}] — dann zeigt die App das Bild inline."
|
||||||
)
|
)
|
||||||
|
if name == "ear_control":
|
||||||
|
action = (arguments.get("action") or "").strip().lower()
|
||||||
|
if action not in ("off", "on"):
|
||||||
|
return "FEHLER: action muss 'off' oder 'on' sein."
|
||||||
|
self._ear_control = action
|
||||||
|
logger.info("[ear_control] action=%s — App schaltet den Listener", action)
|
||||||
|
return ("Ohr wird ausgeschaltet — Wieder-An per 'Ohr an' (Text/"
|
||||||
|
"Aufnahme-Knopf) oder App-Button." if action == "off"
|
||||||
|
else "Ohr wird wieder eingeschaltet.")
|
||||||
if name == "memory_search":
|
if name == "memory_search":
|
||||||
query = (arguments.get("query") or "").strip()
|
query = (arguments.get("query") or "").strip()
|
||||||
if not query:
|
if not query:
|
||||||
|
|||||||
@@ -199,6 +199,13 @@ def build_voice_flow_section() -> str:
|
|||||||
"- Ohne Marker = normales Gespraech: du wirst vorgelesen und ich lausche "
|
"- Ohne Marker = normales Gespraech: du wirst vorgelesen und ich lausche "
|
||||||
"danach kurz weiter (Stefan kann einfach antworten, ohne 'Computer').",
|
"danach kurz weiter (Stefan kann einfach antworten, ohne 'Computer').",
|
||||||
"- Nie widerspruechlich: `[[ENDE]]` schlaegt `[[WEITER]]`.",
|
"- Nie widerspruechlich: `[[ENDE]]` schlaegt `[[WEITER]]`.",
|
||||||
|
"",
|
||||||
|
"**Ohr aus/an:** Wenn Stefan will dass du aufhoerst zuzuhoeren — egal wie "
|
||||||
|
"formuliert ('leg dich schlafen', 'geh schlafen', 'Ohr aus', 'gute Nacht', "
|
||||||
|
"'mach Pause vom Zuhoeren') — ruf das Tool `ear_control(action='off')`. "
|
||||||
|
"Wieder aktivieren ('Ohr an', 'wach auf', 'hoer wieder zu') → "
|
||||||
|
"`ear_control(action='on')`. Die App stoppt/startet dann den Listener; du "
|
||||||
|
"bestaetigst nur kurz.",
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user