fix: Projekt-Fokus pro Geraet unabhaengig (Diagnostic/App/Multi-Instanz)
Zwei Kopplungs-Bugs behoben: - set_project_kind nutzte den globalen active_project statt des Request-Projekts → markierte das falsche Projekt (belegt: global aktiv war mac_os_update_fehler, das kind=code bekam, obwohl die App in basic_os war). _dispatch_tool bekommt jetzt die project_id des Requests durchgereicht; set_project_kind wirkt darauf. - Die App erzwang bei project_changed-Broadcasts (ARIA-Tool/Diagnostic/andere App-Instanz) einen Fokuswechsel → alle Geraete wurden mitgezogen. Fokus ist jetzt rein geraetelokal; Broadcasts aktualisieren nur Namen/Typ. Wechseln nur noch lokal ueber den Drawer. py-compile + tsc clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,19 @@ Alle Änderungen am Projekt. Format: [Keep a Changelog](https://keepachangelog.c
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [0.2.2.1] — 2026-07-17 — Projekt-Fokus wirklich pro Gerät unabhängig
|
||||||
|
|
||||||
|
### Behoben
|
||||||
|
|
||||||
|
- **`set_project_kind` markierte das falsche Projekt.** Es nutzte den **globalen** `active_project` (geräteübergreifend) statt des Projekts, in dem der aktuelle Request läuft. Folge: Obwohl auf der App „Basic os" aktiv war, bekam das global-aktive „Mac OS Update Fehler" `kind=code`. Jetzt wirkt das Tool auf die pro Request mitgesendete `project_id` (in `_dispatch_tool` durchgereicht) — jede App-/Diagnostic-Instanz markiert ihr eigenes Projekt.
|
||||||
|
- **App wurde von fremden `project_changed`-Broadcasts ins andere Projekt gezogen.** Ein Projektwechsel/‑anlegen durch ARIA, das Diagnostic oder eine andere App-Instanz erzwang auf **allen** Geräten einen Fokuswechsel. Der Projekt-Fokus ist jetzt **rein gerätelokal**: Broadcasts aktualisieren nur Namen + Typ, wechseln aber nicht mehr das Projekt. Umschalten geht ausschließlich lokal über den Projekt-Drawer. So arbeitet jedes Gerät unabhängig in seinem eigenen Projekt (auch mehrere App-Instanzen).
|
||||||
|
- Hinweis: „ARIA, geh in Projekt X" per Sprache wechselt das App-Projekt dadurch **nicht mehr** automatisch — bewusst, damit Geräte unabhängig bleiben. Wechseln über den Drawer.
|
||||||
|
|
||||||
|
### Deploy
|
||||||
|
`git pull && docker compose up -d --build brain` + APK 0.2.2.1 neu bauen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [0.2.2.0] — 2026-07-17 — Workbench: Taskleisten-Dock statt Zoom-Landkarte + bedienbare VNC-Konsole
|
## [0.2.2.0] — 2026-07-17 — Workbench: Taskleisten-Dock statt Zoom-Landkarte + bedienbare VNC-Konsole
|
||||||
|
|
||||||
### Geändert
|
### Geändert
|
||||||
|
|||||||
@@ -992,11 +992,14 @@ const ChatScreen: React.FC = () => {
|
|||||||
if (p.id && (p.kind === 'code' || p.kind === 'chat')) {
|
if (p.id && (p.kind === 'code' || p.kind === 'chat')) {
|
||||||
projectFocus.setKind(p.id, p.kind);
|
projectFocus.setKind(p.id, p.kind);
|
||||||
}
|
}
|
||||||
if (action === 'entered' || action === 'created') {
|
// KEIN erzwungener Fokuswechsel mehr: Projekt-Fokus ist rein GERAETE-
|
||||||
if (p.id) setFocusedProjectId(p.id);
|
// LOKAL. project_changed-Broadcasts (von ARIA-Tools / Diagnostic / einer
|
||||||
} else if (action === 'exited') {
|
// anderen App-Instanz) aktualisieren nur Namen + Typ, ziehen dieses
|
||||||
setFocusedProjectId('');
|
// Geraet aber NICHT in ein anderes Projekt. So arbeitet jede App-/
|
||||||
}
|
// Diagnostic-Instanz unabhaengig in ihrem eigenen Projekt. Wechseln
|
||||||
|
// geht ausschliesslich lokal ueber den Projekt-Drawer.
|
||||||
|
// (action wird bewusst nicht mehr fuer setFocusedProjectId genutzt.)
|
||||||
|
void action;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-8
@@ -1515,7 +1515,7 @@ class Agent:
|
|||||||
targs = {}
|
targs = {}
|
||||||
logger.info("[router] lokal Tool-Call: %s(%s)", tname,
|
logger.info("[router] lokal Tool-Call: %s(%s)", tname,
|
||||||
", ".join(targs.keys()))
|
", ".join(targs.keys()))
|
||||||
tresult = self._dispatch_tool(tname, targs)
|
tresult = self._dispatch_tool(tname, targs, active_project_id)
|
||||||
# Echter Skill (run_*) erfolgreich? Dann uebernimmt dieser
|
# Echter Skill (run_*) erfolgreich? Dann uebernimmt dieser
|
||||||
# Turn das speak-Flag des Skills (Steuerbefehl=stumm,
|
# Turn das speak-Flag des Skills (Steuerbefehl=stumm,
|
||||||
# Antwort-Skill=vorlesen). Letzter Skill gewinnt.
|
# Antwort-Skill=vorlesen). Letzter Skill gewinnt.
|
||||||
@@ -1807,7 +1807,7 @@ class Agent:
|
|||||||
))
|
))
|
||||||
# Tools ausfuehren + Ergebnis als role=tool zurueck
|
# Tools ausfuehren + Ergebnis als role=tool zurueck
|
||||||
for tc in result.tool_calls:
|
for tc in result.tool_calls:
|
||||||
tool_result = self._dispatch_tool(tc["name"], tc["arguments"])
|
tool_result = self._dispatch_tool(tc["name"], tc["arguments"], active_project_id)
|
||||||
# Steuerbefehl-Skill (run_*, speak=false) erfolgreich
|
# Steuerbefehl-Skill (run_*, speak=false) erfolgreich
|
||||||
# ausgefuehrt → Antwort nicht vorlesen (letzter Skill gewinnt).
|
# ausgefuehrt → Antwort nicht vorlesen (letzter Skill gewinnt).
|
||||||
_tn = tc.get("name") or ""
|
_tn = tc.get("name") or ""
|
||||||
@@ -1895,10 +1895,12 @@ class Agent:
|
|||||||
|
|
||||||
# ── Tool-Dispatcher ───────────────────────────────────────
|
# ── Tool-Dispatcher ───────────────────────────────────────
|
||||||
|
|
||||||
def _dispatch_tool(self, name: str, arguments: dict) -> str:
|
def _dispatch_tool(self, name: str, arguments: dict, project_id: str = "") -> str:
|
||||||
"""Fuehrt einen Tool-Call aus und gibt ein kurzes Text-Resultat zurueck.
|
"""Fuehrt einen Tool-Call aus und gibt ein kurzes Text-Resultat zurueck.
|
||||||
Niemals werfen — Fehler werden als Text-Resultat reportet damit Claude
|
Niemals werfen — Fehler werden als Text-Resultat reportet damit Claude
|
||||||
weitermachen kann."""
|
weitermachen kann. project_id = Projekt DIESES Requests (fuer Tools die
|
||||||
|
aufs aktuelle Projekt wirken, z.B. set_project_kind) — NICHT der globale
|
||||||
|
active_project (geraeteuebergreifend)."""
|
||||||
try:
|
try:
|
||||||
if name == "skill_create":
|
if name == "skill_create":
|
||||||
# ARIA-Skills sind immer Python — execution ist nicht mehr im Schema
|
# ARIA-Skills sind immer Python — execution ist nicht mehr im Schema
|
||||||
@@ -2602,13 +2604,18 @@ class Agent:
|
|||||||
kind = (arguments.get("kind") or "").strip().lower()
|
kind = (arguments.get("kind") or "").strip().lower()
|
||||||
if kind not in ("code", "chat"):
|
if kind not in ("code", "chat"):
|
||||||
return "FEHLER: kind muss 'code' oder 'chat' sein."
|
return "FEHLER: kind muss 'code' oder 'chat' sein."
|
||||||
active_id = projects_mod.get_active()
|
# WICHTIG: das Projekt des AKTUELLEN Requests markieren, NICHT den
|
||||||
|
# globalen active_project — der ist geraeteuebergreifend und wuerde
|
||||||
|
# (bei mehreren App-/Diagnostic-Instanzen) das falsche Projekt
|
||||||
|
# treffen. project_id kommt pro Request vom Client.
|
||||||
|
active_id = (project_id or "").strip()
|
||||||
if not active_id:
|
if not active_id:
|
||||||
return ("Kein aktives Projekt — Du bist im Hauptthread. Erst ein Projekt "
|
return ("Kein aktives Projekt — dieser Chat laeuft im Hauptthread. "
|
||||||
"anlegen/betreten (project_create/project_enter), dann set_project_kind.")
|
"set_project_kind wirkt nur, wenn der Request in einem Projekt "
|
||||||
|
"laeuft (der Client sendet die project_id mit).")
|
||||||
updated = projects_mod.update_project(active_id, {"kind": kind})
|
updated = projects_mod.update_project(active_id, {"kind": kind})
|
||||||
if not updated:
|
if not updated:
|
||||||
return f"FEHLER: aktives Projekt '{active_id}' nicht gefunden."
|
return f"FEHLER: Projekt '{active_id}' nicht gefunden."
|
||||||
self._pending_events.append({
|
self._pending_events.append({
|
||||||
"type": "project_changed",
|
"type": "project_changed",
|
||||||
"project": updated,
|
"project": updated,
|
||||||
|
|||||||
Reference in New Issue
Block a user