diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 851df91e6c..6381683007 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2036,7 +2036,7 @@ export class Task extends EventEmitter implements TaskLike { const drainStreamInBackgroundToFindAllUsage = async (apiReqIndex: number) => { const timeoutMs = DEFAULT_USAGE_COLLECTION_TIMEOUT_MS - const startTime = Date.now() + const startTime = performance.now() const modelId = getModelId(this.apiConfiguration) // Local variables to accumulate usage data without affecting the main flow @@ -2107,7 +2107,7 @@ export class Task extends EventEmitter implements TaskLike { // Use the same iterator that the main loop was using while (!item.done) { // Check for timeout - if (Date.now() - startTime > timeoutMs) { + if (performance.now() - startTime > timeoutMs) { console.warn( `[Background Usage Collection] Timed out after ${timeoutMs}ms for model: ${modelId}, processed ${chunkCount} chunks`, ) @@ -2559,10 +2559,10 @@ export class Task extends EventEmitter implements TaskLike { // Use the shared timestamp so that subtasks respect the same rate-limit // window as their parent tasks. if (Task.lastGlobalApiRequestTime) { - const now = Date.now() + const now = performance.now() const timeSinceLastRequest = now - Task.lastGlobalApiRequestTime const rateLimit = apiConfiguration?.rateLimitSeconds || 0 - rateLimitDelay = Math.ceil(Math.max(0, rateLimit * 1000 - timeSinceLastRequest) / 1000) + rateLimitDelay = Math.ceil(Math.min(rateLimit, Math.max(0, rateLimit * 1000 - timeSinceLastRequest) / 1000)) } // Only show rate limiting message if we're not retrying. If retrying, we'll include the delay there. @@ -2577,7 +2577,7 @@ export class Task extends EventEmitter implements TaskLike { // Update last request time before making the request so that subsequent // requests — even from new subtasks — will honour the provider's rate-limit. - Task.lastGlobalApiRequestTime = Date.now() + Task.lastGlobalApiRequestTime = performance.now() const systemPrompt = await this.getSystemPrompt() this.lastUsedInstructions = systemPrompt diff --git a/src/core/task/__tests__/Task.spec.ts b/src/core/task/__tests__/Task.spec.ts index 116c78d760..3fa25679ee 100644 --- a/src/core/task/__tests__/Task.spec.ts +++ b/src/core/task/__tests__/Task.spec.ts @@ -1098,9 +1098,9 @@ describe("Cline", () => { await parentIterator.next() // Simulate time passing (more than rate limit) - const originalDateNow = Date.now - const mockTime = Date.now() + (mockApiConfig.rateLimitSeconds + 1) * 1000 - Date.now = vi.fn(() => mockTime) + const originalPerformanceNow = performance.now + const mockTime = performance.now() + (mockApiConfig.rateLimitSeconds + 1) * 1000 + performance.now = vi.fn(() => mockTime) // Create a subtask after time has passed const child = new Task({ @@ -1121,8 +1121,8 @@ describe("Cline", () => { // Verify no rate limiting was applied expect(mockDelay).not.toHaveBeenCalled() - // Restore Date.now - Date.now = originalDateNow + // Restore performance.now + performance.now = originalPerformanceNow }) it("should share rate limiting across multiple subtasks", async () => {