Skip to content

fix(telemetry): record tool usage once centrally, sanitize raw tool names - #1073

Open
edelauna wants to merge 3 commits into
mainfrom
fix/tool-usage-telemetry-attribution
Open

fix(telemetry): record tool usage once centrally, sanitize raw tool names#1073
edelauna wants to merge 3 commits into
mainfrom
fix/tool-usage-telemetry-attribution

Conversation

@edelauna

@edelauna edelauna commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Refs: #830 (tool-usage telemetry sanitization and single-point attribution half — split from #835; independent of #1069, #1070, #1071)

Description

presentAssistantMessage already recorded most tool-usage attempts at one central point, but two gaps remained:

  1. Double-counted attempts. Five tool handlers (EditTool, EditFileTool, SearchReplaceTool, GenerateImageTool, ApplyPatchTool) each called task.recordToolUsage(...) locally on success, on top of the central call in presentAssistantMessage. Every successful call through these tools counted as two attempts in task.toolUsage.
  2. Raw model-controlled tool names reaching telemetry. Several recordToolUsage/recordToolError call sites keyed off block.name directly: the missing-tool_use.id path, the malformed-nativeArgs path, and the final "unknown tool" branch. A malicious or malformed tool name from the model could become an arbitrary toolsUsed property key.

This PR:

  • Removes the five duplicate local recordToolUsage calls. Grepped every recordToolUsage/recordToolError call site first to confirm the central point in presentAssistantMessage covers each removed call before deleting it. recordToolError calls in these handlers are untouched — they're legitimate failure counts with no equivalent central coverage.
  • Adds toTelemetryToolName() in presentAssistantMessage.ts, mapping any tool name to a safe analytics key before it can reach recordToolUsage/recordToolError or PostHog:
    • known static tools → their own name
    • registered custom tools → custom_tool
    • mcp_-prefixed dynamic tool names (valid or malformed) → use_mcp_tool
    • anything else (malformed calls, arbitrary/unknown names) → invalid_tool_call
  • Applies the mapper at every remaining call site that previously used the raw name, including the missing-id and unknown-tool-name paths.
  • Moves the central recordToolUsage/captureToolUsage call to fire only after validateToolUse succeeds, so a tool that fails validation records a failure (via the mapper), never a spurious success.
  • Adds invalid_tool_call as a new static member of the ToolName union in packages/types/src/tool.ts (with a matching TOOL_DISPLAY_NAMES entry in src/shared/tools.ts) — the smallest self-contained type needed here, kept independent of feat(telemetry): aggregate task completion telemetry with delta installments #1071.

Out of scope

Kept narrow to tool-usage attribution, per the split from #835:

Test Procedure

  • New toTelemetryToolName.spec.ts: static tool keeps its name, custom tool → custom_tool, valid and malformed mcp_ names → use_mcp_tool, arbitrary unknown name → invalid_tool_call, and an explicit assertion that the raw name is never echoed back.
  • New presentAssistantMessage-tool-usage-attribution.spec.ts: a normal static tool records exactly one attempt; valid/malformed mcp_ names map correctly; a validation failure on a known tool records a failure under its own name (no success recorded); a validation failure on an arbitrary unknown name records invalid_tool_call and never the raw name.
  • Updated presentAssistantMessage-unknown-tool.spec.ts: both the missing-id and unknown-tool-name paths now assert recordToolError is called with invalid_tool_call, not the raw model-supplied name.
  • Updated editTool.spec.ts, editFileTool.spec.ts, searchReplaceTool.spec.ts: assert the handler itself no longer calls recordToolUsage on success, proving removal of the duplicate didn't lose the attempt (it's covered centrally instead).
  • pnpm check-types clean repo-wide. pnpm lint clean on src and @roo-code/types, eslint-suppressions.json only decreases (7→3 for presentAssistantMessage.ts, from removing any-casts on the deleted raw-name paths) — no suppression count increased and no new suppression entries added.
  • Narrowest suites: core/assistant-message + core/tools in src (591 tests) and @roo-code/types (268 tests), all passing.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes.
  • Visual Snapshot (UI changes only): N/A — no UI changes.
  • Documentation Impact: No documentation updates required (no user-facing behavior change).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Documentation Updates

  • No documentation updates are required.

Summary by CodeRabbit

  • New Features

    • Added clearer handling and display for invalid or unrecognized tool calls.
    • Standardized tool activity and error reporting across built-in, custom, and MCP tools.
  • Bug Fixes

    • Prevented malformed or unknown tool names from appearing directly in telemetry.
    • Improved attribution for validation failures and unsuccessful calls.
    • Ensured tool usage is recorded only after successful validation.
  • Tests

    • Added coverage for tool attribution, normalization, MCP validation, and unknown-tool handling.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@edelauna, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 49f8fad3-0c34-4496-bd86-a2b5b1474b45

📥 Commits

Reviewing files that changed from the base of the PR and between 13a9e95 and e4a416f.

📒 Files selected for processing (6)
  • src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts
  • src/core/assistant-message/__tests__/toTelemetryToolName.spec.ts
  • src/core/tools/BaseTool.ts
  • src/core/tools/UseMcpToolTool.ts
  • src/core/tools/__tests__/applyPatchTool.execute.spec.ts
  • src/core/tools/__tests__/generateImageTool.test.ts
📝 Walkthrough

Walkthrough

The PR adds invalid_tool_call, normalizes model-controlled tool names for telemetry, centralizes usage attribution after validation, removes duplicate handler-level recording, and updates related tests and display names.

Changes

Tool telemetry attribution

Layer / File(s) Summary
Telemetry name contract
packages/types/src/tool.ts, src/shared/tools.ts, src/core/assistant-message/presentAssistantMessage.ts, src/core/assistant-message/__tests__/toTelemetryToolName.spec.ts
Adds invalid_tool_call to recognized and display tool names. Adds and tests normalized telemetry mapping for static, custom, MCP, and unknown tools.
Central validation and attribution
src/core/tools/BaseTool.ts, src/core/tools/UseMcpToolTool.ts, src/core/assistant-message/presentAssistantMessage.ts, src/core/assistant-message/__tests__/*, src/eslint-suppressions.json
Records normalized errors and successful usage after validation. Unknown and malformed calls use invalid_tool_call. Tests cover native MCP and legacy tool-call paths.
Remove handler-level usage recording
src/core/tools/{ApplyPatchTool,EditFileTool,EditTool,GenerateImageTool,SearchReplaceTool}.ts, src/core/tools/__tests__/*
Removes successful usage recording from tool handlers. Approval workflow tests verify that handlers do not record usage locally.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: awaiting-review

Suggested reviewers: navedmerchant

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the central telemetry attribution and tool-name sanitization changes.
Description check ✅ Passed The description covers the issue, implementation, scope, testing, checklist, and documentation impact in sufficient detail.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tool-usage-telemetry-attribution

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.

@edelauna edelauna changed the title fix(telemetry): record tool usage once centrally, sanitize raw tool n… fix(telemetry): record tool usage once centrally, sanitize raw tool names Jul 31, 2026
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.36364% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../core/assistant-message/presentAssistantMessage.ts 85.00% 1 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@edelauna
edelauna marked this pull request as ready for review July 31, 2026 13:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/assistant-message/presentAssistantMessage.ts`:
- Around line 638-643: Route native mcp_tool_use handling through the same
validation boundary used by tool_use, removing its pre-validation
recordToolUsage and captureToolUsage calls near the native MCP branch. Ensure
validated native MCP calls use the centralized attribution symbols to record
exactly one attempt, while invalid or disallowed calls record none, and add a
regression test covering native MCP validation failure.
🪄 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: 78e54642-f04e-4195-9608-19f089b266fd

📥 Commits

Reviewing files that changed from the base of the PR and between cd29243 and 9d652bb.

📒 Files selected for processing (15)
  • packages/types/src/tool.ts
  • src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts
  • src/core/assistant-message/__tests__/presentAssistantMessage-unknown-tool.spec.ts
  • src/core/assistant-message/__tests__/toTelemetryToolName.spec.ts
  • src/core/assistant-message/presentAssistantMessage.ts
  • src/core/tools/ApplyPatchTool.ts
  • src/core/tools/EditFileTool.ts
  • src/core/tools/EditTool.ts
  • src/core/tools/GenerateImageTool.ts
  • src/core/tools/SearchReplaceTool.ts
  • src/core/tools/__tests__/editFileTool.spec.ts
  • src/core/tools/__tests__/editTool.spec.ts
  • src/core/tools/__tests__/searchReplaceTool.spec.ts
  • src/eslint-suppressions.json
  • src/shared/tools.ts
💤 Files with no reviewable changes (5)
  • src/core/tools/SearchReplaceTool.ts
  • src/core/tools/ApplyPatchTool.ts
  • src/core/tools/EditTool.ts
  • src/core/tools/EditFileTool.ts
  • src/core/tools/GenerateImageTool.ts

Comment thread src/core/assistant-message/presentAssistantMessage.ts
@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 31, 2026
@edelauna
edelauna force-pushed the fix/tool-usage-telemetry-attribution branch from a2d3157 to 13a9e95 Compare August 1, 2026 01:50
@github-actions github-actions Bot removed the awaiting-review PR changes are ready and waiting for maintainer re-review label Aug 1, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts (1)

236-267: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mocked getMcpHub skips the real MCP tool-existence check.

The mocked getMcpHub (line 243-245) only implements findServerNameBySanitizedName. UseMcpToolTool.validateToolExists calls mcpHub.getAllServers(), which is missing here. That call throws, and the surrounding try/catch in validateToolExists returns { isValid: true } on any error. The test passes because the error is silently swallowed, not because tool existence and enablement validation genuinely succeeded. The test name and comment claim the MCP tool's own validation passes.

Add getAllServers to the mock so the test exercises the real validation path.

🧪 Proposed fix to exercise genuine tool-existence validation
 				getMcpHub: () => ({
 					findServerNameBySanitizedName: () => "my_server",
+					getAllServers: () => [
+						{
+							name: "my_server",
+							tools: [{ name: "do_thing", enabledForPrompt: true }],
+						},
+					],
 				}),
🤖 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/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts`
around lines 236 - 267, Update the getMcpHub mock in the test around
presentAssistantMessage to implement getAllServers with a server/tool definition
that matches my_server and do_thing and is enabled, so
UseMcpToolTool.validateToolExists follows genuine MCP validation rather than its
error fallback. Preserve the existing findServerNameBySanitizedName behavior and
assertions.
🤖 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.

Nitpick comments:
In
`@src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts`:
- Around line 236-267: Update the getMcpHub mock in the test around
presentAssistantMessage to implement getAllServers with a server/tool definition
that matches my_server and do_thing and is enabled, so
UseMcpToolTool.validateToolExists follows genuine MCP validation rather than its
error fallback. Preserve the existing findServerNameBySanitizedName behavior and
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cf965c2a-39a9-4e09-b30a-b7baa0de6737

📥 Commits

Reviewing files that changed from the base of the PR and between 9d652bb and 13a9e95.

📒 Files selected for processing (17)
  • packages/types/src/tool.ts
  • src/core/assistant-message/__tests__/presentAssistantMessage-tool-usage-attribution.spec.ts
  • src/core/assistant-message/__tests__/presentAssistantMessage-unknown-tool.spec.ts
  • src/core/assistant-message/__tests__/toTelemetryToolName.spec.ts
  • src/core/assistant-message/presentAssistantMessage.ts
  • src/core/tools/ApplyPatchTool.ts
  • src/core/tools/BaseTool.ts
  • src/core/tools/EditFileTool.ts
  • src/core/tools/EditTool.ts
  • src/core/tools/GenerateImageTool.ts
  • src/core/tools/SearchReplaceTool.ts
  • src/core/tools/UseMcpToolTool.ts
  • src/core/tools/__tests__/editFileTool.spec.ts
  • src/core/tools/__tests__/editTool.spec.ts
  • src/core/tools/__tests__/searchReplaceTool.spec.ts
  • src/eslint-suppressions.json
  • src/shared/tools.ts
💤 Files with no reviewable changes (5)
  • src/core/tools/GenerateImageTool.ts
  • src/core/tools/EditTool.ts
  • src/core/tools/EditFileTool.ts
  • src/core/tools/SearchReplaceTool.ts
  • src/core/tools/ApplyPatchTool.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/core/tools/tests/editFileTool.spec.ts
  • src/core/assistant-message/tests/presentAssistantMessage-unknown-tool.spec.ts
  • src/core/assistant-message/tests/toTelemetryToolName.spec.ts
  • packages/types/src/tool.ts
  • src/core/tools/tests/searchReplaceTool.spec.ts
  • src/eslint-suppressions.json
  • src/shared/tools.ts
  • src/core/assistant-message/presentAssistantMessage.ts
  • src/core/tools/tests/editTool.spec.ts

@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant