feat: sub-agent streaming progress — TaskTool emits real-time status events
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
- Rust: LoopEvent::SubtaskStatus variant added to loop_runner.rs - Rust: ToolContext.event_sender field for streaming tool progress - Rust: TaskTool emits started/running/completed/failed via event_sender - Rust: StreamChatEvent::SubtaskStatus mapped in Tauri chat command - TS: StreamEventSubtaskStatus type + onSubtaskStatus callback added - TS: kernel-chat.ts handles subtaskStatus event from Tauri - TS: streamStore.ts wires callback, maps backend→frontend status, updates assistant message subtasks array in real-time
This commit is contained in:
@@ -146,6 +146,17 @@ export function installChatMethods(ClientClass: { prototype: KernelClient }): vo
|
||||
}
|
||||
break;
|
||||
|
||||
case 'subtaskStatus':
|
||||
log.debug('Subtask status:', streamEvent.description, streamEvent.status, streamEvent.detail);
|
||||
if (callbacks.onSubtaskStatus) {
|
||||
callbacks.onSubtaskStatus(
|
||||
streamEvent.description,
|
||||
streamEvent.status,
|
||||
streamEvent.detail ?? undefined
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'iterationStart':
|
||||
log.debug('Iteration started:', streamEvent.iteration, '/', streamEvent.maxIterations);
|
||||
// Don't need to notify user about iterations
|
||||
|
||||
@@ -69,6 +69,7 @@ export interface StreamCallbacks {
|
||||
onThinkingDelta?: (delta: string) => void;
|
||||
onTool?: (tool: string, input: string, output: string) => void;
|
||||
onHand?: (name: string, status: string, result?: unknown) => void;
|
||||
onSubtaskStatus?: (description: string, status: string, detail?: string) => void;
|
||||
onComplete: (inputTokens?: number, outputTokens?: number) => void;
|
||||
onError: (error: string) => void;
|
||||
}
|
||||
@@ -126,6 +127,13 @@ export interface StreamEventHandEnd {
|
||||
result: unknown;
|
||||
}
|
||||
|
||||
export interface StreamEventSubtaskStatus {
|
||||
type: 'subtaskStatus';
|
||||
description: string;
|
||||
status: string;
|
||||
detail?: string;
|
||||
}
|
||||
|
||||
export type StreamChatEvent =
|
||||
| StreamEventDelta
|
||||
| StreamEventThinkingDelta
|
||||
@@ -134,6 +142,7 @@ export type StreamChatEvent =
|
||||
| StreamEventIterationStart
|
||||
| StreamEventHandStart
|
||||
| StreamEventHandEnd
|
||||
| StreamEventSubtaskStatus
|
||||
| StreamEventComplete
|
||||
| StreamEventError;
|
||||
|
||||
|
||||
@@ -382,6 +382,35 @@ export const useStreamStore = create<StreamState>()(
|
||||
}
|
||||
}
|
||||
},
|
||||
onSubtaskStatus: (description: string, status: string, detail?: string) => {
|
||||
// Map backend status to frontend Subtask status
|
||||
const statusMap: Record<string, Subtask['status']> = {
|
||||
started: 'pending',
|
||||
running: 'in_progress',
|
||||
completed: 'completed',
|
||||
failed: 'failed',
|
||||
};
|
||||
const mappedStatus = statusMap[status] || 'in_progress';
|
||||
|
||||
_chat?.updateMessages(msgs =>
|
||||
msgs.map(m => {
|
||||
if (m.id !== assistantId) return m;
|
||||
const subtasks = [...(m.subtasks || [])];
|
||||
const existingIdx = subtasks.findIndex(st => st.description === description);
|
||||
if (existingIdx >= 0) {
|
||||
subtasks[existingIdx] = { ...subtasks[existingIdx], status: mappedStatus, result: detail };
|
||||
} else {
|
||||
subtasks.push({
|
||||
id: `subtask_${Date.now()}_${generateRandomString(4)}`,
|
||||
description,
|
||||
status: mappedStatus,
|
||||
result: detail,
|
||||
});
|
||||
}
|
||||
return { ...m, subtasks };
|
||||
})
|
||||
);
|
||||
},
|
||||
onComplete: (inputTokens?: number, outputTokens?: number) => {
|
||||
const currentMsgs = _chat?.getMessages();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user