Skip to content

Commit d3ead8f

Browse files
authored
fix(mobile): fire completion notifications for cloud task turns (#2405)
1 parent 5daaae2 commit d3ead8f

1 file changed

Lines changed: 52 additions & 6 deletions

File tree

apps/mobile/src/features/tasks/stores/taskSessionStore.ts

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ const TURN_END_METHODS = new Set([
151151
interface BatchAnalysis {
152152
hasTurnEnd: boolean;
153153
hasAwaitingUserInput: boolean;
154+
hasTurnCompleted: boolean;
155+
hasTurnFailed: boolean;
154156
hasVisibleAgentOutput: boolean;
155157
externalUserMessageCount: number;
156158
agentMessageFinalized: boolean;
@@ -162,6 +164,8 @@ function analyzeEntries(
162164
): BatchAnalysis {
163165
let hasTurnEnd = false;
164166
let hasAwaitingUserInput = false;
167+
let hasTurnCompleted = false;
168+
let hasTurnFailed = false;
165169
let hasVisibleAgentOutput = false;
166170
let externalUserMessageCount = 0;
167171
let agentMessageFinalized = false;
@@ -173,6 +177,15 @@ function analyzeEntries(
173177
if (method === "_posthog/awaiting_user_input") {
174178
hasAwaitingUserInput = true;
175179
}
180+
if (
181+
method === "_posthog/turn_complete" ||
182+
method === "_posthog/task_complete"
183+
) {
184+
hasTurnCompleted = true;
185+
}
186+
if (method === "_posthog/error") {
187+
hasTurnFailed = true;
188+
}
176189
}
177190

178191
if (
@@ -200,6 +213,8 @@ function analyzeEntries(
200213
return {
201214
hasTurnEnd,
202215
hasAwaitingUserInput,
216+
hasTurnCompleted,
217+
hasTurnFailed,
203218
hasVisibleAgentOutput,
204219
externalUserMessageCount,
205220
agentMessageFinalized,
@@ -897,21 +912,52 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
897912
};
898913
});
899914

900-
// Live `logs` deltas only fire pings for the "agent is blocked on the
901-
// user" case. Terminal completion / failure is handled by the status
902-
// block below, so we don't double-fire on every intermediate turn.
903-
// Snapshots are historical replay — never ping for those.
904-
const shouldPingNow =
915+
// Live `logs` deltas fire pings for three turn-boundary cases:
916+
// * agent is blocked on the user (_posthog/awaiting_user_input)
917+
// * agent finished its turn (_posthog/turn_complete / task_complete)
918+
// * agent errored out the turn (_posthog/error)
919+
// The terminal-status block below can't be relied on for these: the
920+
// turn-end log entry arrives first and clears `awaitingPing`, so by
921+
// the time status terminal fires its `preState.awaitingPing` is
922+
// already false. Status-only termination (sandbox killed without a
923+
// turn-end log) still falls through to the status block. Snapshots
924+
// are historical replay — never ping for those.
925+
const shouldPingForAwaitingInput =
905926
!isSnapshot && wasAwaitingPing && analysis.hasAwaitingUserInput;
927+
const shouldPingForTurnComplete =
928+
!isSnapshot &&
929+
wasAwaitingPing &&
930+
analysis.hasTurnCompleted &&
931+
!analysis.hasAwaitingUserInput;
932+
const shouldPingForTurnFailed =
933+
!isSnapshot &&
934+
wasAwaitingPing &&
935+
analysis.hasTurnFailed &&
936+
!analysis.hasAwaitingUserInput &&
937+
!analysis.hasTurnCompleted;
938+
const shouldPingNow =
939+
shouldPingForAwaitingInput ||
940+
shouldPingForTurnComplete ||
941+
shouldPingForTurnFailed;
906942
if (shouldPingNow && usePreferencesStore.getState().pingsEnabled) {
907943
playMeepSound().catch(() => {});
908944
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
909945
}
910-
if (shouldPingNow) {
946+
if (shouldPingForAwaitingInput) {
911947
maybePresentLocalNotification({
912948
taskRunId,
913949
kind: "awaiting_user_input",
914950
});
951+
} else if (shouldPingForTurnComplete) {
952+
maybePresentLocalNotification({
953+
taskRunId,
954+
kind: "turn_complete",
955+
});
956+
} else if (shouldPingForTurnFailed) {
957+
maybePresentLocalNotification({
958+
taskRunId,
959+
kind: "task_failed",
960+
});
915961
}
916962
}
917963

0 commit comments

Comments
 (0)