Files
aryx/src/main/sidecar/runTurnPending.ts
T
David KayaandCopilot deb5c96d58 feat: render thinking process UI for intermediate agent messages
Wire message-reclassified sidecar events through the main process to
the renderer, where reclassified messages are filtered out of the main
transcript and collected into a collapsible ThinkingProcess component.

Main process changes:
- Route message-reclassified via dedicated onMessageReclassified callback
- Add applyMessageReclassified handler that sets messageKind and emits
  the session event for the renderer
- Forward assistant-intent and reasoning-delta as turn-scoped events

Renderer changes:
- Split session.messages into visibleMessages and thinkingMessages
- Render ThinkingProcess above the last assistant message
- ThinkingProcess auto-expands during active turns, collapses on finish
- Update messagePhase to skip thinking-kind messages for final detection

Tests:
- 3 new sessionWorkspace tests for reclassification apply/dedup/ignore
- 2 new messagePhase tests for thinking-kind handling
- Updated runTurnPending test fixtures for new callback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-30 16:16:37 +01:00

63 lines
1.9 KiB
TypeScript

import type {
AgentActivityEvent,
ApprovalRequestedEvent,
ExitPlanModeRequestedEvent,
McpOauthRequiredEvent,
MessageReclassifiedEvent,
TurnDeltaEvent,
UserInputRequestedEvent,
SubagentEvent,
SkillInvokedEvent,
HookLifecycleEvent,
SessionUsageEvent,
SessionCompactionEvent,
PendingMessagesModifiedEvent,
AssistantUsageEvent,
AssistantIntentEvent,
ReasoningDeltaEvent,
} from '@shared/contracts/sidecar';
import type { ChatMessageRecord } from '@shared/domain/session';
export type TurnScopedEvent =
| SubagentEvent
| SkillInvokedEvent
| HookLifecycleEvent
| SessionUsageEvent
| SessionCompactionEvent
| PendingMessagesModifiedEvent
| AssistantUsageEvent
| AssistantIntentEvent
| ReasoningDeltaEvent;
export interface RunTurnPendingCommand {
kind: 'run-turn';
resolve: (messages: ChatMessageRecord[]) => void;
reject: (error: Error) => void;
onDelta: (event: TurnDeltaEvent) => void | Promise<void>;
onActivity: (event: AgentActivityEvent) => void | Promise<void>;
onApproval: (event: ApprovalRequestedEvent) => void | Promise<void>;
onUserInput: (event: UserInputRequestedEvent) => void | Promise<void>;
onMcpOAuthRequired: (event: McpOauthRequiredEvent) => void | Promise<void>;
onExitPlanMode: (event: ExitPlanModeRequestedEvent) => void | Promise<void>;
onMessageReclassified: (event: MessageReclassifiedEvent) => void | Promise<void>;
onTurnScopedEvent: (event: TurnScopedEvent) => void | Promise<void>;
errored: boolean;
}
export function markRunTurnPendingErrored(
pending: RunTurnPendingCommand,
error: unknown,
): Error {
const normalized = error instanceof Error ? error : new Error(String(error));
if (!pending.errored) {
pending.errored = true;
pending.reject(normalized);
}
return normalized;
}
export function shouldHandleRunTurnEvent(pending: RunTurnPendingCommand): boolean {
return !pending.errored;
}