@@ -28,7 +28,8 @@ import {
2828 type Task ,
2929} from "../types" ;
3030import { convertStoredEntriesToEvents } from "../utils/parseSessionLogs" ;
31- import { playMeepSound } from "../utils/sounds" ;
31+ import { playbackRateForTaskDuration } from "../utils/playbackRate" ;
32+ import { playCompletionSound } from "../utils/sounds" ;
3233import { useAttachmentEchoStore } from "./attachmentEchoStore" ;
3334import {
3435 combineQueuedMessages ,
@@ -38,6 +39,16 @@ import { useTaskStore } from "./taskStore";
3839
3940const log = logger . scope ( "task-session-store" ) ;
4041
42+ function completionPlaybackRate ( promptStartedAt ?: number ) : number {
43+ if (
44+ ! usePreferencesStore . getState ( ) . scaleSoundWithTaskLength ||
45+ promptStartedAt == null
46+ ) {
47+ return 1 ;
48+ }
49+ return playbackRateForTaskDuration ( Date . now ( ) - promptStartedAt ) ;
50+ }
51+
4152// Match historical `user_message_chunk` events (text-only, as the cloud
4253// stores them) against locally-cached attachment echoes by position+text.
4354// Echoes are written in send-order; we walk user messages in receive-order
@@ -289,6 +300,9 @@ export interface TaskSession {
289300 // we should play a sound when control returns. False when reconnecting
290301 // to an already-running task to avoid spurious pings.
291302 awaitingPing ?: boolean ;
303+ // Timestamp when the current prompt started on this device. Used to scale
304+ // the completion sound's playback rate by how long the turn ran.
305+ promptStartedAt ?: number ;
292306 // True after a user prompt is sent, cleared when the first piece of
293307 // agent output (tool call, message, etc.) arrives.
294308 awaitingAgentOutput ?: boolean ;
@@ -425,6 +439,7 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
425439 // us otherwise — the SSE watcher will refine these fields.
426440 isPromptPending : true ,
427441 awaitingPing,
442+ promptStartedAt : awaitingPing ? Date . now ( ) : undefined ,
428443 awaitingAgentOutput : true ,
429444 } ,
430445 } ,
@@ -513,6 +528,7 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
513528 localUserEchoes : nextLocalEchoes ,
514529 isPromptPending : true ,
515530 awaitingPing : true ,
531+ promptStartedAt : ts ,
516532 awaitingAgentOutput : true ,
517533 } ,
518534 } ,
@@ -624,6 +640,7 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
624640 localUserEchoes : nextLocalEchoes ,
625641 isPromptPending : true ,
626642 awaitingPing : true ,
643+ promptStartedAt : ts ,
627644 awaitingAgentOutput : true ,
628645 } ,
629646 } ,
@@ -775,6 +792,7 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
775792 ...state . sessions [ session . taskRunId ] ,
776793 isPromptPending : false ,
777794 awaitingPing : false ,
795+ promptStartedAt : undefined ,
778796 awaitingAgentOutput : false ,
779797 } ,
780798 } ,
@@ -1037,7 +1055,11 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
10371055 shouldPingForTurnComplete ||
10381056 shouldPingForTurnFailed ;
10391057 if ( shouldPingNow && usePreferencesStore . getState ( ) . pingsEnabled ) {
1040- playMeepSound ( ) . catch ( ( ) => { } ) ;
1058+ playCompletionSound (
1059+ undefined ,
1060+ undefined ,
1061+ completionPlaybackRate ( existing ?. promptStartedAt ) ,
1062+ ) . catch ( ( ) => { } ) ;
10411063 Haptics . notificationAsync ( Haptics . NotificationFeedbackType . Success ) ;
10421064 }
10431065 if ( shouldPingForAwaitingInput ) {
@@ -1100,7 +1122,11 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
11001122 } ;
11011123 } ) ;
11021124 if ( shouldPing && usePreferencesStore . getState ( ) . pingsEnabled ) {
1103- playMeepSound ( ) . catch ( ( ) => { } ) ;
1125+ playCompletionSound (
1126+ undefined ,
1127+ undefined ,
1128+ completionPlaybackRate ( preState ?. promptStartedAt ) ,
1129+ ) . catch ( ( ) => { } ) ;
11041130 Haptics . notificationAsync ( Haptics . NotificationFeedbackType . Success ) ;
11051131 }
11061132 if ( shouldPing ) {
@@ -1161,6 +1187,7 @@ export const useTaskSessionStore = create<TaskSessionStore>((set, get) => ({
11611187 status : "connecting" ,
11621188 isPromptPending : true ,
11631189 awaitingPing : true ,
1190+ promptStartedAt : Date . now ( ) ,
11641191 awaitingAgentOutput : true ,
11651192 } ,
11661193 } ,
0 commit comments