mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-07 12:18:44 +02:00
feat: improve agent status and thinking indicator UX
- Show agent activity label in chat header (Thinking…, Using bash…, etc.) instead of an anonymous pulsing dot - Fix ThinkingProcess elapsed timer to tick live every second using useElapsedTimer hook instead of stale useMemo computation - Show completed/failed subagents for 3s grace period with fade-out transition instead of instantly hiding them - Transition activity labels to Completed state for 1.5s grace period on session idle instead of abrupt removal - Eliminate message flash during thinking reclassification by folding trailing pending assistant messages into the thinking group optimistically when they follow existing thinking messages - Stabilize ThinkingProcess isActive flag by checking for pending messages in the group rather than relying solely on array position - Skip rendering empty pending messages inside ThinkingProcess steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -13,6 +13,8 @@ import {
|
||||
isAgentActivityCompleted,
|
||||
pruneSessionActivities,
|
||||
pruneSessionRequestUsage,
|
||||
purgeCompletedActivity,
|
||||
summarizeSessionActivity,
|
||||
type SessionActivityMap,
|
||||
type SessionRequestUsageMap,
|
||||
} from '@renderer/lib/sessionActivity';
|
||||
@@ -202,6 +204,7 @@ describe('session activity helpers', () => {
|
||||
},
|
||||
};
|
||||
|
||||
// Active agents transition to 'completed' on idle (grace period before purge)
|
||||
expect(
|
||||
applySessionEventActivity(current, {
|
||||
sessionId: 'session-1',
|
||||
@@ -216,6 +219,11 @@ describe('session activity helpers', () => {
|
||||
agentName: 'Architect',
|
||||
activityType: 'completed',
|
||||
},
|
||||
reviewer: {
|
||||
agentId: 'reviewer',
|
||||
agentName: 'Reviewer',
|
||||
activityType: 'completed',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -236,6 +244,7 @@ describe('session activity helpers', () => {
|
||||
},
|
||||
};
|
||||
|
||||
// Active agents transition to 'completed' on cancel (grace period before purge)
|
||||
expect(
|
||||
applySessionEventActivity(current, {
|
||||
sessionId: 'session-1',
|
||||
@@ -265,6 +274,11 @@ describe('session activity helpers', () => {
|
||||
agentName: 'Architect',
|
||||
activityType: 'completed',
|
||||
},
|
||||
reviewer: {
|
||||
agentId: 'reviewer',
|
||||
agentName: 'Reviewer',
|
||||
activityType: 'completed',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -385,6 +399,92 @@ describe('session activity helpers', () => {
|
||||
'session-2': current['session-2'],
|
||||
});
|
||||
});
|
||||
|
||||
test('purgeCompletedActivity removes completed entries after grace period', () => {
|
||||
const current: SessionActivityMap = {
|
||||
'session-1': {
|
||||
architect: {
|
||||
agentId: 'architect',
|
||||
agentName: 'Architect',
|
||||
activityType: 'completed',
|
||||
},
|
||||
reviewer: {
|
||||
agentId: 'reviewer',
|
||||
agentName: 'Reviewer',
|
||||
activityType: 'completed',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = purgeCompletedActivity(current, 'session-1');
|
||||
expect(result['session-1']).toBeUndefined();
|
||||
});
|
||||
|
||||
test('purgeCompletedActivity is a no-op when nothing is completed', () => {
|
||||
const current: SessionActivityMap = {
|
||||
'session-1': {
|
||||
architect: {
|
||||
agentId: 'architect',
|
||||
agentName: 'Architect',
|
||||
activityType: 'thinking',
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(purgeCompletedActivity(current, 'session-1')).toBe(current);
|
||||
});
|
||||
|
||||
test('summarizeSessionActivity returns the most relevant label', () => {
|
||||
expect(summarizeSessionActivity(undefined)).toBeUndefined();
|
||||
expect(summarizeSessionActivity({})).toBeUndefined();
|
||||
|
||||
expect(
|
||||
summarizeSessionActivity({
|
||||
architect: {
|
||||
agentId: 'architect',
|
||||
agentName: 'Architect',
|
||||
activityType: 'thinking',
|
||||
},
|
||||
}),
|
||||
).toBe('Thinking…');
|
||||
|
||||
expect(
|
||||
summarizeSessionActivity({
|
||||
architect: {
|
||||
agentId: 'architect',
|
||||
agentName: 'Architect',
|
||||
activityType: 'tool-calling',
|
||||
toolName: 'bash',
|
||||
},
|
||||
}),
|
||||
).toBe('Using bash…');
|
||||
|
||||
// Thinking takes priority over tool-calling
|
||||
expect(
|
||||
summarizeSessionActivity({
|
||||
architect: {
|
||||
agentId: 'architect',
|
||||
agentName: 'Architect',
|
||||
activityType: 'thinking',
|
||||
},
|
||||
reviewer: {
|
||||
agentId: 'reviewer',
|
||||
agentName: 'Reviewer',
|
||||
activityType: 'tool-calling',
|
||||
toolName: 'read_file',
|
||||
},
|
||||
}),
|
||||
).toBe('Thinking…');
|
||||
|
||||
expect(
|
||||
summarizeSessionActivity({
|
||||
architect: {
|
||||
agentId: 'architect',
|
||||
agentName: 'Architect',
|
||||
activityType: 'completed',
|
||||
},
|
||||
}),
|
||||
).toBe('Completed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('assistant usage accumulator', () => {
|
||||
|
||||
Reference in New Issue
Block a user