Skip to content

Extract Task usage tracking#28

Draft
doctarock wants to merge 5 commits into
Zoo-Code-Org:mainfrom
doctarock:issue-18-usage-tracker
Draft

Extract Task usage tracking#28
doctarock wants to merge 5 commits into
Zoo-Code-Org:mainfrom
doctarock:issue-18-usage-tracker

Conversation

@doctarock
Copy link
Copy Markdown
Contributor

@doctarock doctarock commented May 6, 2026

Related GitHub Issue

Refs #18

Description

Extract token and tool usage tracking from Task.ts into src/core/task/UsageTracker.ts.

The new tracker owns:

  • token usage snapshots and debounce/throttle emission
  • tool usage counters
  • final usage emission flushing
  • metrics combination helpers used by Task

Task keeps the existing public methods/properties (getTokenUsage, recordToolUsage, recordToolError, emitFinalTokenUsageUpdate, toolUsage, tokenUsage) as thin delegates so existing call sites keep the same surface.

Test Procedure

  • pnpm --dir src check-types
  • pnpm --dir src exec vitest run core/task/__tests__/Task.throttle.test.ts

Notes

This is scoped to the usage-tracking extraction described in #18.

Summary by CodeRabbit

  • Refactor

    • Centralized token and tool usage tracking and emission flow; task APIs now delegate to the centralized tracker and finalization/flush uses it.
    • Added per-operation consecutive mistake counters for finer-grained monitoring.
    • Disposal now cancels pending usage emissions and cleans up tracker state.
  • Tests

    • Added/updated tests covering usage tracking, emission timing/flush behavior, snapshot preservation, and disposal.

Review Change Stack

@doctarock doctarock requested a review from hannesrudolph as a code owner May 6, 2026 11:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f0d12cf-f3e7-48bb-96df-ecbe8916f0fa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Task delegates token/tool usage tracking to a new UsageTracker that computes metrics, debounces emissions, exposes token/tool state, is instantiated/disposed by Task; tests updated and new UsageTracker unit tests added.

Changes

Usage Tracking Extraction

Layer / File(s) Summary
Data Structure
src/core/task/UsageTracker.ts
New UsageTracker class and UsageTrackerOptions added; internal snapshots, debounce emit interval, and per-tool counters implemented.
Core Implementation
src/core/task/UsageTracker.ts
Implements combineMessages, getTokenUsage, emitTokenUsageUpdate (debounced), emitFinalTokenUsageUpdate (flush), recordToolUsage, recordToolError, dispose, and token/tool accessors.
Task Integration
src/core/task/Task.ts
Task imports and instantiates UsageTracker, removes legacy debounce/state, delegates public metrics methods to the tracker, proxies token/tool getters/setter, calls tracker for final emission and disposal, and adds consecutiveMistakeCountForApplyDiff / consecutiveMistakeCountForEditFile.
Tests / Assertions
src/core/task/__tests__/Task.throttle.test.ts, src/core/task/__tests__/UsageTracker.spec.ts, src/core/task/__tests__/Task.dispose.test.ts
Throttle tests updated to use usageTracker.tokenUsageSnapshot/usageTracker.toolUsageSnapshot; new UsageTracker unit tests added; dispose test ensures Task.dispose() calls usageTracker.dispose().

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Task
  participant UsageTracker
  participant EventBus
  Client->>Task: call recordToolUsage / getTokenUsage / combineMessages
  Task->>UsageTracker: delegate call
  UsageTracker->>EventBus: emit TaskTokenUsageUpdated / TaskToolFailed
  EventBus-->>Client: notifications/handlers
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

"🐰 I hopped through code with a curious twitch,

UsageTracker rose, tidy and rich,
Tasks now delegate metrics with grace,
Debounced updates find their place,
A rabbit's cheer for cleaner code — swift!"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Extract Task usage tracking' directly and clearly describes the main refactoring: moving usage tracking logic into a dedicated module.
Description check ✅ Passed The description includes a linked issue (Refs #18), explains the implementation approach, lists public API preservation strategy, and provides test procedures. However, the Pre-Submission Checklist is not completed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/core/task/__tests__/Task.throttle.test.ts (1)

299-326: ⚡ Quick win

Assert the public Task contract instead of usageTracker internals.

These cases now cast through any and inspect private snapshot fields, so they won’t catch regressions in the delegated Task.tokenUsage / final-emission behavior even though preserving the Task surface is the goal of this PR. Prefer asserting task.tokenUsage and emitted payloads here, or move snapshot-specific checks into dedicated UsageTracker unit tests.

Also applies to: 461-495

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/task/__tests__/Task.throttle.test.ts` around lines 299 - 326, The
test is inspecting private internals (usageTracker.tokenUsageSnapshot) via
casts; change assertions to use the public Task API instead: call
task.tokenUsage and assert its values change (and/or assert the emitted payloads
from addToClineMessages) rather than touching usageTracker.tokenUsageSnapshot;
if you need snapshot-specific behavior keep those assertions in a dedicated
UsageTracker unit test that directly exercises UsageTracker methods (or expose a
test-only accessor there) and remove any (task as any).usageTracker assertions
from this Task.throttle.test.ts file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/task/UsageTracker.ts`:
- Around line 105-113: The tokenUsage getter in UsageTracker currently returns
the cached tokenUsageSnapshot forever once set, causing stale values; change the
getter to always return this.getTokenUsage() (i.e., recompute on reads) while
leaving tokenUsageSnapshot and tokenUsageSnapshotAt in place for emitted-state
comparisons and for whichever emit/save logic relies on them; keep
getLastMessageTs(), getTokenUsage(), and any emit/update code unchanged so only
the read path of tokenUsage is modified to return fresh data.

---

Nitpick comments:
In `@src/core/task/__tests__/Task.throttle.test.ts`:
- Around line 299-326: The test is inspecting private internals
(usageTracker.tokenUsageSnapshot) via casts; change assertions to use the public
Task API instead: call task.tokenUsage and assert its values change (and/or
assert the emitted payloads from addToClineMessages) rather than touching
usageTracker.tokenUsageSnapshot; if you need snapshot-specific behavior keep
those assertions in a dedicated UsageTracker unit test that directly exercises
UsageTracker methods (or expose a test-only accessor there) and remove any (task
as any).usageTracker assertions from this Task.throttle.test.ts file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d244e906-88f4-44aa-8554-61cadf064b40

📥 Commits

Reviewing files that changed from the base of the PR and between 81afb6c and 60ded846820391282bbc03fd1e40c3eb49225be3.

📒 Files selected for processing (3)
  • src/core/task/Task.ts
  • src/core/task/UsageTracker.ts
  • src/core/task/__tests__/Task.throttle.test.ts

Comment thread src/core/task/UsageTracker.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/task/Task.ts`:
- Around line 531-535: Add proper disposal for the UsageTracker debounce:
implement a cancel() or dispose() method on the UsageTracker class that calls
this.debouncedEmitTokenUsage.cancel() (and any other cleanup), and then call
that new method from Task.dispose() (alongside existing cleanup like
fileContextTracker.dispose(), e.g., right after that call) so pending lodash
debounce timers are cancelled when a Task is disposed; update any references to
UsageTracker (created in the Task constructor where this.usageTracker is
assigned) and ensure Task.dispose() invokes usageTracker.cancel()/dispose().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 50612190-45c1-4b03-a572-d9e2cb4d25aa

📥 Commits

Reviewing files that changed from the base of the PR and between 60ded846820391282bbc03fd1e40c3eb49225be3 and d0705354a7ed696af15d929a409a9870cdeea91b.

📒 Files selected for processing (3)
  • src/core/task/Task.ts
  • src/core/task/UsageTracker.ts
  • src/core/task/__tests__/UsageTracker.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/task/UsageTracker.ts

Comment thread src/core/task/Task.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/task/UsageTracker.ts`:
- Around line 68-79: UsageTracker can be reactivated after dispose because
dispose() only cancels pending debounce work; change dispose() to mark the
tracker inert (e.g., set a this.disposed flag) and then make
emitTokenUsageUpdate and emitFinalTokenUsageUpdate check that flag and return
immediately when disposed, and ensure dispose still calls
debouncedEmitTokenUsage.cancel() and debouncedEmitTokenUsage.flush() (or
replaces debouncedEmitTokenUsage with a no-op object) so no new timers or
flushes can be scheduled after disposal; update references in the class to use
the disposed flag and guard all public emission methods (emitTokenUsageUpdate,
emitFinalTokenUsageUpdate) accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6261fe1c-d3d2-4a01-8871-616e88ece917

📥 Commits

Reviewing files that changed from the base of the PR and between d0705354a7ed696af15d929a409a9870cdeea91b and 76bf595c2d13926a3bcb2679fa97fb8fa6687043.

📒 Files selected for processing (4)
  • src/core/task/Task.ts
  • src/core/task/UsageTracker.ts
  • src/core/task/__tests__/Task.dispose.test.ts
  • src/core/task/__tests__/UsageTracker.spec.ts

Comment thread src/core/task/UsageTracker.ts
@doctarock
Copy link
Copy Markdown
Contributor Author

Addressed the dispose follow-up in 86ddd51fc.

UsageTracker.dispose() now marks the tracker as disposed, and both public emission paths return early after disposal so no new debounce timers can be scheduled. I also extended the unit coverage to call both emission methods after disposal.

Validation: corepack pnpm --dir src exec vitest run core/task/__tests__/UsageTracker.spec.ts core/task/__tests__/Task.dispose.test.ts passed.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 16, 2026

Codecov Report

❌ Patch coverage is 81.57895% with 21 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/task/UsageTracker.ts 84.09% 14 Missing ⚠️
src/core/task/Task.ts 73.07% 7 Missing ⚠️

📢 Thoughts on this report? Let us know!

@edelauna
Copy link
Copy Markdown
Contributor

Converting to draft - lets resolve conflicts before reopening.

@edelauna edelauna marked this pull request as draft May 20, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants