Skip to content

Commit 62fd94b

Browse files
committed
fix(telemetry): cover all task launch paths for idle timer; fix pop guard
1 parent 39ab054 commit 62fd94b

1 file changed

Lines changed: 30 additions & 32 deletions

File tree

src/core/task/Task.ts

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
902902
const { images, task, historyItem } = options
903903
let promise
904904

905+
instance.startIdleTelemetryCheck()
906+
905907
if (images || task) {
906908
promise = instance.startTask(task, images)
907909
} else if (historyItem) {
@@ -1924,6 +1926,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
19241926
return Promise.resolve()
19251927
}
19261928
this._started = true
1929+
this.startIdleTelemetryCheck()
19271930

19281931
const { task, images } = this.metadata
19291932

@@ -3689,22 +3692,17 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
36893692
// we need to remove that message before retrying to avoid having two consecutive
36903693
// user messages (which would cause tool_result validation errors).
36913694
const state = await this.providerRef.deref()?.getState()
3692-
if (this.apiConversationHistory.length > 0) {
3695+
// Only pop the user message that this iteration added. When
3696+
// shouldAddUserMessage is false (empty continuation, resumed history,
3697+
// or flushPendingToolResultsToHistory message) there is nothing to
3698+
// remove, and popping would corrupt history.
3699+
let removedCurrentUserMessage = false
3700+
if (shouldAddUserMessage && this.apiConversationHistory.length > 0) {
36933701
const lastMessage = this.apiConversationHistory[this.apiConversationHistory.length - 1]
36943702
if (lastMessage.role === "user") {
3695-
// Remove the last user message that we added earlier. Decrement
3696-
// messageCounts.user to match -- both retry branches below mark
3697-
// userMessageWasRemoved so the message (and its count) is restored
3698-
// exactly once when the retry succeeds, keeping the total symmetric
3699-
// regardless of how many empty-response cycles occur first.
3700-
// Guard: only reverse a count this iteration actually added. The
3701-
// popped message may predate this turn (resumed history, or a
3702-
// message appended by flushPendingToolResultsToHistory, neither
3703-
// of which incremented messageCounts.user).
37043703
this.apiConversationHistory.pop()
3705-
if (shouldAddUserMessage) {
3706-
this.messageCounts.user--
3707-
}
3704+
this.messageCounts.user--
3705+
removedCurrentUserMessage = true
37083706
}
37093707
}
37103708

@@ -3727,13 +3725,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
37273725
break
37283726
}
37293727

3730-
// Push the same content back onto the stack to retry, incrementing the retry attempt counter
3731-
// Mark that user message was removed so it gets re-added on retry
3728+
// Push the same content back onto the stack to retry, incrementing the retry attempt counter.
3729+
// Only mark userMessageWasRemoved when we actually removed one -- the
3730+
// restore branch in shouldAddUserMessageToHistory must only fire once.
37323731
stack.push({
37333732
userContent: currentUserContent,
37343733
includeFileDetails: false,
37353734
retryAttempt: (currentItem.retryAttempt ?? 0) + 1,
3736-
userMessageWasRemoved: true,
3735+
userMessageWasRemoved: removedCurrentUserMessage,
37373736
})
37383737

37393738
// Continue to retry the request
@@ -3748,31 +3747,27 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
37483747
if (response === "yesButtonClicked") {
37493748
await this.say("api_req_retried")
37503749

3751-
// Push the same content back to retry. Mark that user message was
3752-
// removed (same as the auto-retry path above) so it gets re-added --
3753-
// and messageCounts.user re-incremented -- on the retried attempt;
3754-
// otherwise shouldAddUserMessageToHistory sees retryAttempt > 0 with
3755-
// userMessageWasRemoved unset and skips re-adding it entirely.
3750+
// Push the same content back to retry. Only mark userMessageWasRemoved
3751+
// when we actually removed one so the restore fires exactly once.
37563752
stack.push({
37573753
userContent: currentUserContent,
37583754
includeFileDetails: false,
37593755
retryAttempt: (currentItem.retryAttempt ?? 0) + 1,
3760-
userMessageWasRemoved: true,
3756+
userMessageWasRemoved: removedCurrentUserMessage,
37613757
})
37623758

37633759
// Continue to retry the request
37643760
continue
37653761
} else {
3766-
// User declined to retry
3767-
// Re-add the user message we removed (see messageCounts.user-- above)
3768-
// and increment messageCounts.user to match, same as the normal
3769-
// add-to-history path -- otherwise this abandoned-task path
3770-
// permanently undercounts by one.
3771-
await this.addToApiConversationHistory({
3772-
role: "user",
3773-
content: currentUserContent,
3774-
})
3775-
this.messageCounts.user++
3762+
// User declined to retry. Re-add the user message only if this
3763+
// iteration removed one, so the history and counter stay consistent.
3764+
if (removedCurrentUserMessage) {
3765+
await this.addToApiConversationHistory({
3766+
role: "user",
3767+
content: currentUserContent,
3768+
})
3769+
this.messageCounts.user++
3770+
}
37763771

37773772
await this.say(
37783773
"error",
@@ -4781,6 +4776,9 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
47814776
}
47824777

47834778
startIdleTelemetryCheck(): void {
4779+
if (this.idleTelemetryCheckInterval !== undefined) {
4780+
return
4781+
}
47844782
this.idleTelemetryCheckInterval = setInterval(() => {
47854783
// Measure idleness from the later of the last activity and the last flush.
47864784
// Using lastMessageTs alone would keep the condition true forever after the

0 commit comments

Comments
 (0)