feat(multitask): kontext-getaggte Activity + kontext-scoped Cancel (Restpunkte 1+2)
Beide Restpunkte teilen eine Verkabelung: die projectId fliesst jetzt bis zum
Proxy und zurueck in die agent_activity-Events.
Restpunkt 1 — per-Kontext Activity-Indikator:
- Brain: proxy_client.chat_full(project_id) → payload.aria_project_id;
agent.py gibt active_project_id mit.
- Proxy routes.js: liest aria_project_id, taggt Tool-/Stream-Hooks damit,
trackt Subprozesse pro Kontext.
- Bridge: _emit_activity(project_id) + payload.projectId; /internal/agent-activity
reicht projectId durch; send_to_core/_process_core_response taggen thinking/idle
mit dem Turn-Kontext.
- App: agentActivityByCtx-Map; „ARIA denkt"-Indikator zeigt nur den
fokussierten Kontext statt global zu flackern.
Restpunkt 2 — kontext-scoped Cancel (Barge-In):
- Proxy: neuer /cancel {projectId} killt NUR die Subprozesse eines Kontexts
(_cancelByProject); /cancel-all bleibt fuers NOT-AUS.
- Bridge: soft cancel_request → _cancel_proxy_for_project(projectId) statt des
toten Diagnostic /api/cancel. Hard bleibt /cancel-all.
- App: cancel_request + Abbrechen-Button tragen die fokussierte projectId.
Damit laufen Kontexte in der App echt parallel: Arbeit in Projekt A wird durch
Senden/Abbrechen in Hauptchat oder Projekt B nicht mehr abgewuergt, und der
Indikator gehoert zum sichtbaren Chat.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -301,6 +301,9 @@ const ChatScreen: React.FC = () => {
|
||||
const [searchIndex, setSearchIndex] = useState(0); // welcher Treffer aktiv ist
|
||||
const [pendingAttachments, setPendingAttachments] = useState<{file: any, isPhoto: boolean}[]>([]);
|
||||
const [agentActivity, setAgentActivity] = useState<{activity: string, tool: string}>({activity: 'idle', tool: ''});
|
||||
// Multi-Threading: Activity pro Kontext (key = projectId, '' = Hauptchat).
|
||||
// Der Indikator zeigt nur den fokussierten Kontext — nicht global.
|
||||
const [agentActivityByCtx, setAgentActivityByCtx] = useState<Record<string, {activity: string; tool: string}>>({});
|
||||
// Gedanken-Stream: chronologisches Log dessen was ARIA intern macht.
|
||||
// Wird aus agent_activity-Events gefuettert und in AsyncStorage persistiert.
|
||||
const [thoughts, setThoughts] = useState<ThoughtEntry[]>([]);
|
||||
@@ -1209,7 +1212,11 @@ const ChatScreen: React.FC = () => {
|
||||
if (message.type === 'agent_activity') {
|
||||
const activity = (message.payload.activity as string) || 'idle';
|
||||
const tool = (message.payload.tool as string) || '';
|
||||
const actPid = ((message.payload as any).projectId as string) || '';
|
||||
// Global (fuer die bestehende ACK-/Watchdog-Logik) UND per-Kontext
|
||||
// (fuer den fokussierten Indikator) fuehren.
|
||||
setAgentActivity({ activity, tool });
|
||||
setAgentActivityByCtx(prev => ({ ...prev, [actPid]: { activity, tool } }));
|
||||
// Implizite ACK-Bestaetigung: Brain hat angefangen zu arbeiten →
|
||||
// unsere Nachricht ist offensichtlich angekommen, auch wenn das
|
||||
// chat_ack aus irgendeinem Grund nicht durchkam. Alle laufenden
|
||||
@@ -1930,11 +1937,13 @@ const ChatScreen: React.FC = () => {
|
||||
});
|
||||
}, [inputText, getCurrentLocation, pendingAttachments, sendPendingAttachments, interruptAriaIfBusy, dispatchWithAck]);
|
||||
|
||||
// Anfrage abbrechen — sofort lokalen Indicator weg, Bridge triggert doctor --fix
|
||||
// Anfrage abbrechen — nur den fokussierten Kontext (kontext-scoped Cancel).
|
||||
const cancelRequest = useCallback(() => {
|
||||
const pid = focusedProjectIdRef.current || '';
|
||||
setAgentActivity({ activity: 'idle', tool: '' });
|
||||
setAgentActivityByCtx(prev => ({ ...prev, [pid]: { activity: 'idle', tool: '' } }));
|
||||
clearStuckWatchdog();
|
||||
rvs.send('cancel_request' as any, {});
|
||||
rvs.send('cancel_request' as any, { projectId: pid });
|
||||
}, []);
|
||||
|
||||
// Barge-In: wenn der User waehrend ARIA arbeitet/spricht eine neue Sprach-
|
||||
@@ -2759,13 +2768,18 @@ const ChatScreen: React.FC = () => {
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Thinking-Indicator */}
|
||||
{agentActivity.activity !== 'idle' && (
|
||||
{/* Thinking-Indicator \u2014 NUR fuer den fokussierten Kontext (Multi-Threading).
|
||||
ARIA kann in anderen Kontexten parallel arbeiten, ohne dass hier ein
|
||||
Indikator flackert der nicht zum sichtbaren Chat gehoert. */}
|
||||
{(() => {
|
||||
const focusAct = agentActivityByCtx[focusedProjectId] || { activity: 'idle', tool: '' };
|
||||
if (focusAct.activity === 'idle') return null;
|
||||
return (
|
||||
<View style={styles.thinkingBar}>
|
||||
<Text style={styles.thinkingText}>
|
||||
{agentActivity.activity === 'tool' && agentActivity.tool
|
||||
? `\uD83D\uDD27 ${agentActivity.tool}`
|
||||
: agentActivity.activity === 'assistant'
|
||||
{focusAct.activity === 'tool' && focusAct.tool
|
||||
? `\uD83D\uDD27 ${focusAct.tool}`
|
||||
: focusAct.activity === 'assistant'
|
||||
? '\u270D\uFE0F ARIA schreibt...'
|
||||
: '\uD83D\uDCAD ARIA denkt...'}
|
||||
</Text>
|
||||
@@ -2775,7 +2789,8 @@ const ChatScreen: React.FC = () => {
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
);
|
||||
})()}
|
||||
|
||||
{/* Pending Anhaenge Vorschau */}
|
||||
{pendingAttachments.length > 0 && (
|
||||
|
||||
Reference in New Issue
Block a user