fix(coding): limit unread badges to attention transitions

This commit is contained in:
inman
2026-09-03 10:44:59 +08:00
parent 301c1496b0
commit f2c3755b69
5 changed files with 436 additions and 5 deletions

View File

@@ -364,6 +364,33 @@ function completesOrdinaryPrompt(
return false;
}
function taskHasSettled(snapshot: ConversationSnapshot): boolean {
return snapshot.run.status === 'error'
|| (snapshot.run.status === 'idle' && snapshot.run.terminalReason !== undefined);
}
function newlyNeedsUserAttention(
current: ConversationSnapshot | null,
next: ConversationSnapshot | null,
): boolean {
if (!next) return false;
const currentPendingInteractions = new Set(
current?.pendingInteractions
.filter((interaction) => interaction.status === 'pending')
.map((interaction) => interaction.id) ?? [],
);
if (next.pendingInteractions.some((interaction) => (
interaction.status === 'pending' && !currentPendingInteractions.has(interaction.id)
))) {
return true;
}
if (!taskHasSettled(next)) return false;
return !current
|| !taskHasSettled(current)
|| current.run.runId !== next.run.runId
|| current.run.terminalReason !== next.run.terminalReason;
}
export function createCodingConversationStore(
dependencies: Partial<CodingConversationStoreDependencies> = {},
): StoreApi<CodingConversationStoreState> {
@@ -979,11 +1006,8 @@ export function createCodingConversationStore(
}
if (reducer === current.reducer) return state;
applied = true;
const incomingMessages = applicableEvent.items.flatMap((item) => (
item.patch.op === 'message.upsert' ? [item.patch.node] : []
));
const unread = state.selectedConversationId !== applicableEvent.conversationId
&& incomingMessages.some((message) => message.role === 'assistant')
&& newlyNeedsUserAttention(current.reducer.snapshot, reducer.snapshot)
? true
: current.unread;
const entry: CodingConversationEntry = {