Compare commits
4 Commits
v0.1.8.7
...
86f20d3b64
| Author | SHA1 | Date | |
|---|---|---|---|
| 86f20d3b64 | |||
| 78211f09ce | |||
| b2edee9adb | |||
| bb13477ef9 |
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(ssh root@172.0.2.33 \"ls -la /root/ARIA-AGENT/aria-shared/logs/\")"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,8 +79,8 @@ android {
|
|||||||
applicationId "com.ariacockpit"
|
applicationId "com.ariacockpit"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 10807
|
versionCode 10808
|
||||||
versionName "0.1.8.7"
|
versionName "0.1.8.8"
|
||||||
// Fallback fuer Libraries mit Product Flavors
|
// Fallback fuer Libraries mit Product Flavors
|
||||||
missingDimensionStrategy 'react-native-camera', 'general'
|
missingDimensionStrategy 'react-native-camera', 'general'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aria-cockpit",
|
"name": "aria-cockpit",
|
||||||
"version": "0.1.8.7",
|
"version": "0.1.8.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
|
|||||||
@@ -344,23 +344,38 @@ class WakeWordService {
|
|||||||
/** Konversation beenden — User hat im Window nichts gesagt.
|
/** Konversation beenden — User hat im Window nichts gesagt.
|
||||||
* Mit Wake-Word: zurueck zu 'armed' (Listener wieder an).
|
* Mit Wake-Word: zurueck zu 'armed' (Listener wieder an).
|
||||||
* Ohne: zurueck zu 'off'.
|
* Ohne: zurueck zu 'off'.
|
||||||
|
*
|
||||||
|
* WICHTIG: setzt bargeListening=false BEVOR OpenWakeWord.start() laeuft.
|
||||||
|
* Grund: wenn endConversation aus dem onPlaybackFinished-Handler kommt,
|
||||||
|
* feuert direkt danach ein zweiter Listener (stopBargeListening) — der
|
||||||
|
* wuerde sonst OpenWakeWord.stop() rufen weil bargeListening noch true
|
||||||
|
* ist, und unseren frisch re-armierten Listener killen.
|
||||||
*/
|
*/
|
||||||
async endConversation(): Promise<void> {
|
async endConversation(): Promise<void> {
|
||||||
if (this.state !== 'conversing') {
|
if (this.state !== 'conversing') {
|
||||||
// Nicht in conversing — typ. nach App-Resume bevor Streaming endete.
|
|
||||||
// Trotzdem loggen damit wir's im Diagnostic sehen.
|
|
||||||
import('./logger').then(m => m.reportAppDebug('wake.end',
|
import('./logger').then(m => m.reportAppDebug('wake.end',
|
||||||
`endConversation called but state=${this.state} → noop`)).catch(()=>{});
|
`endConversation called but state=${this.state} → noop`)).catch(()=>{});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const wasBarge = this.bargeListening;
|
||||||
|
// Flag NULLEN bevor wir die Listener triggern. Sonst killt der parallele
|
||||||
|
// stopBargeListening-Listener (TTS-end) gleich danach unseren Native-
|
||||||
|
// OpenWakeWord, weil er bargeListening=true sieht und annimmt er muss
|
||||||
|
// den Listener stoppen.
|
||||||
|
this.bargeListening = false;
|
||||||
import('./logger').then(m => m.reportAppDebug('wake.end',
|
import('./logger').then(m => m.reportAppDebug('wake.end',
|
||||||
`endConversation called, nativeReady=${this.nativeReady}, calling OpenWakeWord.start()`)).catch(()=>{});
|
`endConversation called, wasBarge=${wasBarge}, nativeReady=${this.nativeReady}`)).catch(()=>{});
|
||||||
if (this.nativeReady && OpenWakeWord) {
|
if (this.nativeReady && OpenWakeWord) {
|
||||||
|
// Wenn wakeword schon laeuft (war Barge-Listener waehrend TTS):
|
||||||
|
// OpenWakeWord.start() ist idempotent (Kotlin checkt running.get()
|
||||||
|
// und resolved sofort). Wir koennen es trotzdem rufen — billiger
|
||||||
|
// als state extra zu fragen, garantiert dass nach diesem Pfad
|
||||||
|
// Native auch wirklich an ist falls es out-of-band gestoppt wurde.
|
||||||
try {
|
try {
|
||||||
await OpenWakeWord.start();
|
await OpenWakeWord.start();
|
||||||
console.log('[WakeWord] Konversation zu Ende — zurueck zu armed');
|
console.log('[WakeWord] Konversation zu Ende — zurueck zu armed (wasBarge=%s)', wasBarge);
|
||||||
import('./logger').then(m => m.reportAppDebug('wake.end',
|
import('./logger').then(m => m.reportAppDebug('wake.end',
|
||||||
`OpenWakeWord.start() OK → state=armed, keyword=${this.keyword}`)).catch(()=>{});
|
`OpenWakeWord.start() OK → state=armed, wasBarge=${wasBarge}`)).catch(()=>{});
|
||||||
ToastAndroid.show(`Lausche wieder auf "${KEYWORD_LABELS[this.keyword]}"`, ToastAndroid.SHORT);
|
ToastAndroid.show(`Lausche wieder auf "${KEYWORD_LABELS[this.keyword]}"`, ToastAndroid.SHORT);
|
||||||
this.setState('armed');
|
this.setState('armed');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -602,6 +602,61 @@ SEED_RULES: List[dict] = [
|
|||||||
"'API Key' im Auth-Kapitel). Nicht raten."
|
"'API Key' im Auth-Kapitel). Nicht raten."
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"migration_key": "seed/skill-rule/list-api-pagination-snapshot",
|
||||||
|
"type": "rule",
|
||||||
|
"title": "Listen-API: einmal vollstaendig laden, DANN entscheiden",
|
||||||
|
"category": "verhalten",
|
||||||
|
"content": (
|
||||||
|
"Wenn ein Tool-Resultat ein Pagination-Schema hat (limit/offset/"
|
||||||
|
"next oder total > limit): ALLE Seiten in EINEM Tool-Call holen, "
|
||||||
|
"in EINEM Snapshot durchsuchen, ERST DANN handeln.\n"
|
||||||
|
"\n"
|
||||||
|
"Antipattern (31.05.2026, Stefan reproduziert mit 'Playlist Prodigy "
|
||||||
|
"raussuchen'):\n"
|
||||||
|
" - run_spotify path=/v1/me/playlists?limit=50\n"
|
||||||
|
" → 'nicht dabei'\n"
|
||||||
|
" - run_spotify path=/v1/me/playlists?limit=50&offset=50\n"
|
||||||
|
" → 'gefunden, ID=X' (46 Tracks)\n"
|
||||||
|
" - run_spotify path=/v1/me/player/play body={context_uri: ...:X}\n"
|
||||||
|
" → spielt aber FALSCHE Playlist\n"
|
||||||
|
" - Neue Suche, wieder paginiert → drittes Match ID=Y (15 Tracks)\n"
|
||||||
|
" - Insgesamt drei verschiedene IDs fuer dieselbe gesuchte Playlist\n"
|
||||||
|
" generiert, am Ende die falsche gespielt.\n"
|
||||||
|
"\n"
|
||||||
|
"Wurzel: Spotify sortiert /v1/me/playlists nach recently-played. "
|
||||||
|
"Zwischen aufeinanderfolgenden paginierten Calls AENDERT SICH die "
|
||||||
|
"Reihenfolge wenn parallel was abgespielt wird. Teilresultate aus "
|
||||||
|
"verschiedenen Calls vergleichen → inkonsistent.\n"
|
||||||
|
"\n"
|
||||||
|
"Richtig fuer Spotify (seit 31.05.2026 unterstuetzt):\n"
|
||||||
|
" run_spotify path=/v1/me/playlists?limit=50&_all=true\n"
|
||||||
|
" → Skill paginiert intern, liefert {items, total, fetched_count}.\n"
|
||||||
|
" → In items[] suchen, EINE ID waehlen, sofort handeln.\n"
|
||||||
|
" → Match-Logik: bevorzugt exakter Name (case-insensitive). "
|
||||||
|
"Wenn mehrere Substring-Matches: explizit nachfragen statt raten.\n"
|
||||||
|
"\n"
|
||||||
|
"Wann _all=true sinnvoll:\n"
|
||||||
|
" - /v1/me/playlists (alle eigenen Playlists)\n"
|
||||||
|
" - /v1/playlists/{id}/tracks (alle Tracks einer Playlist)\n"
|
||||||
|
" - /v1/me/tracks (Liked Songs)\n"
|
||||||
|
" - /v1/search?type=playlist&q=... (Such-Ergebnisse mit next)\n"
|
||||||
|
" - Andere Endpunkte mit items+next-Schema.\n"
|
||||||
|
"\n"
|
||||||
|
"Wann NICHT _all=true:\n"
|
||||||
|
" - /v1/me/player/currently-playing (kein Listen-Endpunkt)\n"
|
||||||
|
" - /v1/me/player/devices (kurze Liste, kein next)\n"
|
||||||
|
" - Wenn Du explizit nur 'die ersten 10' willst.\n"
|
||||||
|
"\n"
|
||||||
|
"Fuer andere Skills (yt-dlp, andere APIs) die noch kein _all "
|
||||||
|
"unterstuetzen: manuell paginieren bis total erreicht, ALLES in "
|
||||||
|
"EINEM mentalen Snapshot mergen, NIEMALS auf Teilresultaten "
|
||||||
|
"Entscheidungen treffen. Wenn zwei Pagination-Runs unterschiedliche "
|
||||||
|
"Matches liefern: ehrlich melden ('zwei verschiedene Playlists "
|
||||||
|
"namens X gefunden — welche meinst Du?') statt sich auf eine "
|
||||||
|
"festzulegen."
|
||||||
|
),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+21
-5
@@ -683,8 +683,13 @@ def run_skill(name: str, args: Optional[dict] = None, timeout_sec: int = 300) ->
|
|||||||
timed_out = True
|
timed_out = True
|
||||||
duration = time.time() - t0
|
duration = time.time() - t0
|
||||||
|
|
||||||
# Log schreiben (gekuerzt damit es nicht explodiert)
|
# Log auf der Disk wird gekuerzt (8000 chars) — sonst sammeln sich
|
||||||
record = {
|
# logs/*.json mit MBs an grossen Skill-Outputs an. Der Return-Value
|
||||||
|
# an den Caller (Agent) bekommt aber den vollen Output, dort wird
|
||||||
|
# nochmal in agent.py auf 50000 gecappt. Stefan-Fall: spotify-Skill
|
||||||
|
# mit _all=true liefert 50+ KB JSON, das hier wurde vorher auf 8 KB
|
||||||
|
# gekappt → ARIA sah immer nur den Anfang der Liste.
|
||||||
|
log_record = {
|
||||||
"ts": _now(),
|
"ts": _now(),
|
||||||
"args": args or {},
|
"args": args or {},
|
||||||
"exit_code": exit_code,
|
"exit_code": exit_code,
|
||||||
@@ -694,7 +699,7 @@ def run_skill(name: str, args: Optional[dict] = None, timeout_sec: int = 300) ->
|
|||||||
"timed_out": timed_out,
|
"timed_out": timed_out,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
log_path.write_text(json.dumps(record, indent=2, ensure_ascii=False), encoding="utf-8")
|
log_path.write_text(json.dumps(log_record, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -703,8 +708,19 @@ def run_skill(name: str, args: Optional[dict] = None, timeout_sec: int = 300) ->
|
|||||||
manifest["use_count"] = int(manifest.get("use_count", 0)) + 1
|
manifest["use_count"] = int(manifest.get("use_count", 0)) + 1
|
||||||
write_manifest(name, manifest)
|
write_manifest(name, manifest)
|
||||||
|
|
||||||
record["ok"] = exit_code == 0
|
# Return-Value: nicht kuerzen (Agent kuerzt downstream selbst). Nur
|
||||||
record["log_path"] = str(log_path)
|
# die Disk-Log-Variante war beschnitten.
|
||||||
|
record = {
|
||||||
|
"ts": log_record["ts"],
|
||||||
|
"args": log_record["args"],
|
||||||
|
"exit_code": exit_code,
|
||||||
|
"duration_sec": log_record["duration_sec"],
|
||||||
|
"stdout": out_text or "",
|
||||||
|
"stderr": err_text or "",
|
||||||
|
"timed_out": timed_out,
|
||||||
|
"ok": exit_code == 0,
|
||||||
|
"log_path": str(log_path),
|
||||||
|
}
|
||||||
return record
|
return record
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user