Skip to content

fix(telemetry): reduce PostHog event volume, fix consent dark pattern#835

Open
edelauna wants to merge 12 commits into
mainfrom
issue/830
Open

fix(telemetry): reduce PostHog event volume, fix consent dark pattern#835
edelauna wants to merge 12 commits into
mainfrom
issue/830

Conversation

@edelauna

@edelauna edelauna commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Closes: #830

Description

PostHog's Product Analytics quota was 2.7x over its free-tier limit (2.7M/1M events in the June 6 - July 6 cycle), driven mainly by a CODE_INDEX_ERROR retry-storm bug (309 people generating 254,786 events) and per-turn Conversation Message/Tool Used events. Separately, a telemetry gap analysis found the consent banner treated dismissal (and the default "unset" state) as opt-in rather than a real choice, and that the underlying default itself was undisclosed.

Volume reduction:

  • Circuit-breaker for CODE_INDEX_ERROR: sliding 10-minute window, trips after 50 occurrences, independent of any other telemetry the same install sends (so unrelated events can't mask or reset a burst).
  • Conversation Message/Tool Used are no longer emitted per-turn/per-tool-call. Instead, Task.messageCounts and Task.toolUsage are summarized into toolsUsed/messageCount on the Task Completed event. Tool usage is now recorded exactly once per attempt at a single central point (presentAssistantMessage), removing a double-count where several tool handlers also recorded success locally.
  • Task Completed now fires once per model-initiated attempt_completion call (tagged completionReason: "attempt_completion") rather than only when the user clicks Accept — a task the user declines, gives feedback on, or never explicitly accepts previously reported nothing at all. It also fires on a 30-minute idle timeout and on task/extension shutdown (completionReason: "idle"/"shutdown") so long-running or abandoned tasks aren't invisible either. Each installment reports only the delta since the previous one for that task (tracked separately from task.toolUsage/messageCounts, which stay full running totals for the public TaskCompleted API event and the UI), so summing a task's installments reconstructs its full counts without double-counting. Skips emission for stale replays of an already-completed subtask (revisiting it from history).
  • Model Cache Empty Response throttled to once per distinct provider+endpoint (matching the same compound cache-key identity the model cache itself uses) until a non-empty response is seen — including for auth-scoped providers (e.g. zoo-gateway), where the throttle now correctly re-arms after a later non-empty response even though those providers skip caching.

Consent / privacy:

  • Telemetry is opt-out by disclosed default: isTelemetryOptedIn() (packages/types) returns true unless the setting is explicitly "disabled". A fresh install ("unset") and an explicit "enabled" both capture telemetry; only an explicit Decline opts out. This replaces the previous ad hoc telemetrySetting !== "disabled" checks that were scattered across 5 call sites with a single source of truth, and keeps the default itself honestly disclosed in PRIVACY.md and the banner copy rather than silently opting users in via an ambiguous dismiss gesture.
  • Telemetry banner: the "×" is a neutral dismiss — it sends no message and leaves the setting "unset" (so the disclosed default stays in effect), and does not itself record a choice either way. Explicit Accept/Decline buttons let a user affirmatively opt in or out. Localized across all 18 supported locales.
  • Extension now reacts live to vscode.env.onDidChangeTelemetryEnabled, ANDing the current vscode.env.isTelemetryEnabled value into the gate so a live OS/editor-level telemetry-disable actually takes effect immediately, rather than only being caught on the next read of the deprecated telemetry.telemetryLevel setting.
  • TelemetryService.shutdown() is now properly awaited on deactivation, tracks in-flight capture()/captureException() promises and drains them before flushing/closing clients, and is wrapped so a shutdown failure can't skip terminal cleanup.
  • PRIVACY.md clarified: telemetry is enabled by default (opt-out, changeable in settings), and the "does not collect code or prompts" bullet now notes this applies to the PostHog path only — the separate Cloud task-sync pipeline does transmit task messages when enabled.
  • Tool usage is now recorded for analytics only after the tool name passes validation (or is bucketed under a static invalid_tool_call key for unrecognized/malformed calls), so a model-supplied name can never reach PostHog as an arbitrary toolsUsed property key.
  • webview-ui's PostHog client now explicitly disables autocapture, capture_pageview, and capture_pageleave on init, so the webview doesn't passively collect DOM interactions/navigation beyond the explicit events this PR already sends. (The src-side client uses posthog-node, the server SDK, which has no browser autocapture/session-recording/heatmap surface to begin with.)

Explicitly out of scope for this PR:

  • Hashing vscode.env.machineId — assessed and dropped; it's already a random per-install UUID, not a hostname/username-derived identifier, so hashing it would pseudonymize an already-non-identifying value while losing existing PostHog person continuity.
  • Error-tracking-specific fixes (redacting captureException payloads, potentially moving CODE_INDEX_ERROR from Product Analytics to Error Tracking) — Error Tracking was only 6% over quota vs. Product Analytics' 2.7x, so it wasn't the priority; flagged for a follow-up.

Test Procedure

  • pnpm check-types and pnpm lint clean across all packages.
  • Full test suite: 6753 tests in src, 1456 in webview-ui, 43 in @roo-code/telemetry, 238 in @roo-code/types — all passing. New/updated coverage includes:
    • the circuit breaker's sliding window and independence from unrelated events
    • tool usage recorded exactly once per attempt (no double-counting across handlers)
    • unrecognized/invalid tool calls bucketed under a static invalid_tool_call analytics key rather than the raw model-supplied name
    • per-endpoint empty-model throttling, including re-arming for auth-scoped providers after a non-empty response
    • the banner's Accept/Decline/neutral-dismiss behavior
    • isTelemetryOptedIn() opt-out-by-default semantics ("unset"/"enabled" both opted in, only "disabled" opts out) and the resulting opt-in/opt-out transition events
    • the live onDidChangeTelemetryEnabled listener honoring vscode.env.isTelemetryEnabled
    • shutdown draining/error-handling
    • Task Completed installment delta-tracking: first flush, second flush reporting only the new delta, no-op when nothing changed, idle-timer flush, shutdown flush, and skipping emission for a stale history replay of an already-completed subtask
  • Manual verification recommended: fresh profile shows the Accept/Decline banner with telemetry already active by default; "×" dismisses without recording a choice; Decline actually stops capture; a task whose model calls attempt_completion emits a Task Completed installment immediately regardless of whether the user accepts/declines/gives feedback, with correct (non-duplicated) toolsUsed/messageCount deltas and zero Conversation Message/Tool Used events.

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 (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Documentation Updates

  • No documentation updates are required.
  • Yes, documentation updates are required. PRIVACY.md updated to state telemetry is enabled by default (opt-out) and to clarify the Cloud task-sync pipeline's scope relative to PostHog telemetry.

Summary by CodeRabbit

  • New Features
    • Added explicit Accept/Decline buttons to the telemetry banner (closing the banner no longer submits a choice).
    • Telemetry consent now reacts live to VS Code’s telemetry enable/disable toggle.
    • Task completion analytics now include completion reason plus summarized tool usage and message counts.
  • Bug Fixes
    • Prevented telemetry “retry storms” by circuit-breaking repeated errors.
    • Improved telemetry throttling for repeated empty model-cache responses.
    • Hardened telemetry so unrecognized/invalid tool calls can’t use model-provided names.
    • Improved shutdown to drain in-flight telemetry capture promises.
  • Documentation
    • Updated privacy documentation with clearer telemetry wording and what is not collected.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2fe9737d-bd4b-4692-9f0c-dfb7fb1e782c

📥 Commits

Reviewing files that changed from the base of the PR and between 643c3cf and cdaf9ae.

📒 Files selected for processing (4)
  • apps/vscode-e2e/src/suite/providers/bedrock-empty-response-retry.test.ts
  • src/core/task/Task.ts
  • src/core/task/__tests__/messageCounting.retrySymmetry.spec.ts
  • webview-ui/src/i18n/locales/hi/welcome.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • webview-ui/src/i18n/locales/hi/welcome.json
  • apps/vscode-e2e/src/suite/providers/bedrock-empty-response-retry.test.ts
  • src/core/task/Task.ts

📝 Walkthrough

Walkthrough

Changes

Telemetry is aggregated into task-completion installments, with circuit breaking, pending-capture draining, and model-cache throttling. Consent handling now uses shared opt-in semantics, explicit banner actions, live VS Code telemetry state, and localized labels. Tool analytics use validated names and a fixed invalid-tool bucket.

Telemetry service and contracts

Layer / File(s) Summary
Telemetry service controls
packages/telemetry/src/*
Adds circuit breaking, pending capture tracking, awaited shutdown, richer completion payloads, and additional PostHog exclusions.
Telemetry contracts
packages/types/src/*
Adds shared consent evaluation, task-installment fields, schema tests, and invalid_tool_call as a valid tool name.

Task and tool telemetry

Layer / File(s) Summary
Task telemetry installments
src/core/task/*, src/core/tools/AttemptCompletionTool.ts
Tracks message/tool deltas and flushes task-completion telemetry on idle, completion, delegation, and shutdown.
Validated tool analytics
src/core/assistant-message/*, src/core/tools/*, src/shared/tools.ts
Centralizes usage recording after validation and uses invalid_tool_call for unknown or malformed tool names.

Consent and model-cache behavior

Layer / File(s) Summary
Consent runtime and UI
src/extension.ts, src/core/webview/*, webview-ui/src/**/*
Uses shared opt-in semantics, reacts to VS Code telemetry changes, adds explicit banner actions, and updates localized strings.
Model-cache and retry validation
src/api/providers/fetchers/*, apps/vscode-e2e/src/*
Deduplicates empty-response telemetry per cache key and validates preservation of the original prompt during Bedrock retry flows.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Task
  participant TelemetryService
  participant TelemetryClient
  Task->>Task: accumulate message and tool deltas
  Task->>TelemetryService: flush task-completion installment
  TelemetryService->>TelemetryClient: capture TASK_COMPLETED
  Task->>TelemetryService: flush shutdown installment
  TelemetryService->>TelemetryClient: drain captures and shut down
Loading

Possibly related PRs

Suggested reviewers: taltas, navedmerchant, hannesrudolph, jamesrobert20

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Most #830 objectives are implemented, but the requested machine-ID hashing is explicitly left out of scope and not addressed. Add a salted hash or separate installation UUID for vscode.env.machineId, or split that requirement into a follow-up PR.
Out of Scope Changes check ⚠️ Warning The GenerateImageTool behavior change removes its image response/toolResult path, which is unrelated to the telemetry-focused issue. Move that GenerateImageTool change into a separate PR unless it is required for #830 and explain the dependency in the description.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main telemetry and consent changes in the PR.
Description check ✅ Passed The PR description includes the required issue link, summary, test procedure, checklist, and docs notes; only optional sections are sparse or empty.
✨ 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 issue/830

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.

@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.26984% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/core/task/Task.ts 85.00% 5 Missing and 1 partial ⚠️
.../core/assistant-message/presentAssistantMessage.ts 66.66% 2 Missing and 1 partial ⚠️
packages/telemetry/src/TelemetryService.ts 95.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!


expect(mockTask.diffViewProvider.saveChanges).toHaveBeenCalled()
expect(mockTask.didEditFile).toBe(true)
expect(mockTask.recordToolUsage).toHaveBeenCalledWith("edit_file")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed since we're no longer emitting per message, but rather as a summary once the task completes

@edelauna edelauna marked this pull request as ready for review July 12, 2026 12:56

@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: 4

🧹 Nitpick comments (2)
src/__tests__/extension.spec.ts (1)

324-328: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clear onDidChangeTelemetryEnabled mock between tests to avoid stale handler references.

vi.resetModules() resets the module cache but does not clear vi.fn() call history. Since onDidChangeTelemetryEnabled is created once in the hoisted vi.mock("vscode", …) factory, its call history accumulates across tests. Tests at lines 357, 378, and 404 all retrieve mock.calls[0][0], which is always the handler registered by the first test — not the current test's own activate call. The tests pass today because the handler logic is identical and mock instances are shared, but this is fragile: removing or reordering the first test would silently break the others.

♻️ Proposed fix
 beforeEach(async () => {
 	vi.resetModules()
 	const vscode = await import("vscode")
 	;(vscode.env as any).isTelemetryEnabled = true
+	vi.mocked(vscode.env.onDidChangeTelemetryEnabled).mockClear()
 })
🤖 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/__tests__/extension.spec.ts` around lines 324 - 328, Update the
beforeEach setup in the extension tests to clear the shared
onDidChangeTelemetryEnabled mock, including its call history, after resetting
modules and before each test runs. Ensure tests retrieving mock.calls[0][0]
observe the handler registered by the current activate call rather than a prior
test.
src/core/assistant-message/__tests__/presentAssistantMessage-unknown-tool.spec.ts (1)

219-241: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Extend malicious-name coverage to the "mcp_" prefix case.

The chosen maliciousName doesn't start with "mcp_", so it doesn't exercise the isValidToolName prefix-heuristic bypass (see the corresponding comment in presentAssistantMessage.ts Lines 604-620). Consider adding a case where name is something like "mcp_'; DROP TABLE users; --" to lock in the expected fix once addressed.

🤖 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-unknown-tool.spec.ts`
around lines 219 - 241, Extend the test in “does not record raw model-supplied
tool names in tool usage analytics” to use a malicious tool name beginning with
“mcp_”, such as the existing injection payload with that prefix. Keep the
assertions covering both recordToolUsage and recordToolError so the
isValidToolName prefix-bypass path is exercised.
🤖 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 `@packages/telemetry/src/TelemetryService.ts`:
- Around line 373-377: Update the pending-call drain in TelemetryService
shutdown to repeatedly await pendingClientCalls until the set is empty, ensuring
calls added during an in-flight drain are also completed before invoking
client.shutdown(). Keep the existing client shutdown flow unchanged after the
drain stabilizes.

In `@src/core/task/Task.ts`:
- Around line 2627-2636: The retry flow around shouldAddUserMessageToHistory and
the yesButtonClicked branch must keep user history and counts symmetric. When
removing the temporary user turn, decrement messageCounts.user, mark
userMessageWasRemoved true for the retry item, and ensure the retried request
restores the user message; add a regression test covering manual retry after an
empty-assistant response.

In `@src/core/webview/webviewMessageHandler.ts`:
- Around line 632-636: Update the telemetry state handling in webviewDidLaunch
and the telemetrySetting handler to also require vscode.env.isTelemetryEnabled,
matching the logic in extension.ts. Ensure either path cannot re-enable
telemetry when VS Code’s global telemetry toggle is disabled, while preserving
the existing telemetrySetting preference behavior.

In `@webview-ui/src/i18n/locales/hi/welcome.json`:
- Line 15: Update the helpImproveMessage translation in the Hindi welcome locale
to replace the incorrect term “दूरसंचार कोड” with “टेलीमेट्री” or “टेलीमेट्री
डेटा,” while preserving the surrounding meaning and settingsLink markup.

---

Nitpick comments:
In `@src/__tests__/extension.spec.ts`:
- Around line 324-328: Update the beforeEach setup in the extension tests to
clear the shared onDidChangeTelemetryEnabled mock, including its call history,
after resetting modules and before each test runs. Ensure tests retrieving
mock.calls[0][0] observe the handler registered by the current activate call
rather than a prior test.

In
`@src/core/assistant-message/__tests__/presentAssistantMessage-unknown-tool.spec.ts`:
- Around line 219-241: Extend the test in “does not record raw model-supplied
tool names in tool usage analytics” to use a malicious tool name beginning with
“mcp_”, such as the existing injection payload with that prefix. Keep the
assertions covering both recordToolUsage and recordToolError so the
isValidToolName prefix-bypass path is exercised.
🪄 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: fe02bd8b-7937-4172-aa49-30937b9de55a

📥 Commits

Reviewing files that changed from the base of the PR and between a441e02 and d430a18.

📒 Files selected for processing (62)
  • PRIVACY.md
  • packages/telemetry/src/PostHogTelemetryClient.ts
  • packages/telemetry/src/TelemetryService.ts
  • packages/telemetry/src/__tests__/PostHogTelemetryClient.test.ts
  • packages/telemetry/src/__tests__/TelemetryService.circuit-breaker.test.ts
  • packages/telemetry/src/__tests__/TelemetryService.shutdown.test.ts
  • packages/telemetry/src/__tests__/TelemetryService.task-completed.test.ts
  • packages/types/src/__tests__/telemetry.isTelemetryOptedIn.test.ts
  • packages/types/src/__tests__/telemetry.taskProperties.test.ts
  • packages/types/src/telemetry.ts
  • packages/types/src/tool.ts
  • src/__tests__/extension.spec.ts
  • src/__tests__/nested-delegation-resume.spec.ts
  • src/api/providers/fetchers/__tests__/modelCache.spec.ts
  • src/api/providers/fetchers/modelCache.ts
  • src/core/assistant-message/__tests__/presentAssistantMessage-custom-tool.spec.ts
  • src/core/assistant-message/__tests__/presentAssistantMessage-unknown-tool.spec.ts
  • src/core/assistant-message/presentAssistantMessage.ts
  • src/core/task/Task.ts
  • src/core/task/__tests__/Task.persistence.spec.ts
  • src/core/task/__tests__/Task.spec.ts
  • src/core/task/__tests__/messageCounting.spec.ts
  • src/core/task/messageCounting.ts
  • src/core/tools/ApplyPatchTool.ts
  • src/core/tools/AttemptCompletionTool.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__/attemptCompletionTool.spec.ts
  • src/core/tools/__tests__/editFileTool.spec.ts
  • src/core/tools/__tests__/editTool.spec.ts
  • src/core/tools/__tests__/searchReplaceTool.spec.ts
  • src/core/webview/__tests__/telemetrySettingsTracking.spec.ts
  • src/core/webview/webviewMessageHandler.ts
  • src/extension.ts
  • src/shared/tools.ts
  • webview-ui/src/__tests__/TelemetryClient.spec.ts
  • webview-ui/src/components/chat/__tests__/ChatView.scroll-debug-repro.spec.tsx
  • webview-ui/src/components/common/TelemetryBanner.tsx
  • webview-ui/src/components/common/__tests__/TelemetryBanner.spec.tsx
  • webview-ui/src/components/settings/About.tsx
  • webview-ui/src/components/settings/__tests__/About.spec.tsx
  • webview-ui/src/i18n/locales/ca/welcome.json
  • webview-ui/src/i18n/locales/de/welcome.json
  • webview-ui/src/i18n/locales/en/welcome.json
  • webview-ui/src/i18n/locales/es/welcome.json
  • webview-ui/src/i18n/locales/fr/welcome.json
  • webview-ui/src/i18n/locales/hi/welcome.json
  • webview-ui/src/i18n/locales/id/welcome.json
  • webview-ui/src/i18n/locales/it/welcome.json
  • webview-ui/src/i18n/locales/ja/welcome.json
  • webview-ui/src/i18n/locales/ko/welcome.json
  • webview-ui/src/i18n/locales/nl/welcome.json
  • webview-ui/src/i18n/locales/pl/welcome.json
  • webview-ui/src/i18n/locales/pt-BR/welcome.json
  • webview-ui/src/i18n/locales/ru/welcome.json
  • webview-ui/src/i18n/locales/tr/welcome.json
  • webview-ui/src/i18n/locales/vi/welcome.json
  • webview-ui/src/i18n/locales/zh-CN/welcome.json
  • webview-ui/src/i18n/locales/zh-TW/welcome.json
  • webview-ui/src/utils/TelemetryClient.ts
💤 Files with no reviewable changes (6)
  • src/core/tools/tests/editTool.spec.ts
  • src/core/tools/tests/searchReplaceTool.spec.ts
  • src/core/tools/ApplyPatchTool.ts
  • src/core/tools/tests/editFileTool.spec.ts
  • src/core/tools/GenerateImageTool.ts
  • src/core/assistant-message/tests/presentAssistantMessage-custom-tool.spec.ts

Comment thread packages/telemetry/src/TelemetryService.ts
Comment thread src/core/task/Task.ts
Comment on lines +2627 to +2636
// See shouldAddUserMessageToHistory for the full add/skip rules (retry/empty/removed).
const isEmptyUserContent = currentUserContent.length === 0
const shouldAddUserMessage =
((currentItem.retryAttempt ?? 0) === 0 && !isEmptyUserContent) || currentItem.userMessageWasRemoved
const shouldAddUserMessage = shouldAddUserMessageToHistory({
retryAttempt: currentItem.retryAttempt,
isEmptyUserContent,
userMessageWasRemoved: currentItem.userMessageWasRemoved,
})
if (shouldAddUserMessage) {
await this.addToApiConversationHistory({ role: "user", content: finalUserContent })
TelemetryService.instance.captureConversationMessage(this.taskId, "user")
this.messageCounts.user++

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate relevant files and line ranges
printf '\n== Task.ts line map ==\n'
nl -ba src/core/task/Task.ts | sed -n '2608,2655p'
printf '\n== Task.ts retry handling around 3640-3715 ==\n'
nl -ba src/core/task/Task.ts | sed -n '3640,3715p'

printf '\n== Search for shouldAddUserMessageToHistory and userMessageWasRemoved ==\n'
rg -n "shouldAddUserMessageToHistory|userMessageWasRemoved|messageCounts\.user" src/core/task/Task.ts src -g '!**/dist/**' -g '!**/build/**'

printf '\n== Test files ==\n'
rg -n "messageCounting\.spec\.ts|Task\.spec\.ts|apiConversationHistory|messageCounts" src test . -g '*spec.ts' -g '*test.ts' -g '!**/dist/**' -g '!**/build/**'

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 223


🏁 Script executed:

#!/bin/bash
set -euo pipefail

nl -ba src/core/task/Task.ts | sed -n '2608,2655p'
printf '\n---\n'
nl -ba src/core/task/Task.ts | sed -n '3640,3715p'
printf '\n---\n'
rg -n "shouldAddUserMessageToHistory|userMessageWasRemoved|messageCounts\\.user" src/core/task/Task.ts src -g '!**/dist/**' -g '!**/build/**'
printf '\n---\n'
rg -n "messageCounting\\.spec\\.ts|Task\\.spec\\.ts|apiConversationHistory|messageCounts" . -g '*spec.ts' -g '*test.ts' -g '!**/dist/**' -g '!**/build/**'

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Print only the exact surrounding regions and the helper definition if present.
grep -n "function shouldAddUserMessageToHistory\|const shouldAddUserMessageToHistory\|userMessageWasRemoved" -n src/core/task/Task.ts || true
nl -ba src/core/task/Task.ts | sed -n '2588,2645p'
echo '---'
nl -ba src/core/task/Task.ts | sed -n '3638,3712p'
echo '---'
find . -name 'messageCounting.spec.ts' -o -name 'Task.spec.ts'

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 406


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== helper and nearby logic =='
sed -n '2478,2510p' src/core/task/Task.ts

echo '== message add/pop/counter region =='
sed -n '2624,2642p' src/core/task/Task.ts

echo '== no-assistant-response pop region =='
sed -n '3648,3664p' src/core/task/Task.ts

echo '== retry pushes region =='
sed -n '3680,3712p' src/core/task/Task.ts

echo '== search for counter decrements =='
grep -n 'messageCounts\.user' src/core/task/Task.ts

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 4624


🏁 Script executed:

#!/bin/bash
set -euo pipefail

grep -n "function shouldAddUserMessageToHistory\|const shouldAddUserMessageToHistory\|shouldAddUserMessageToHistory =" -n src/core/task/Task.ts || true
sed -n '2510,2565p' src/core/task/Task.ts
echo '---'
sed -n '4690,4710p' src/core/task/Task.ts
echo '---'
grep -n "telemetryMessageCountsBaseline\|messageCounts =" -n src/core/task/Task.ts

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 3423


🏁 Script executed:

#!/bin/bash
set -euo pipefail

find . \( -name 'messageCounting.spec.ts' -o -name 'Task.spec.ts' \) -print
echo '---'
grep -R -n "no assistant messages\|api_req_failed\|userMessageWasRemoved\|messageCounts.user" . --include='*spec.ts' --include='*test.ts' | head -200

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1397


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrow search for the helper definition if it is below the current section.
awk '
  /shouldAddUserMessageToHistory/ {print NR ":" $0}
' src/core/task/Task.ts

echo '--- helper vicinity ---'
sed -n '2565,2605p' src/core/task/Task.ts

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1774


🏁 Script executed:

#!/bin/bash
set -euo pipefail

grep -R -n "shouldAddUserMessageToHistory" . --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx'

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1877


🏁 Script executed:

#!/bin/bash
set -euo pipefail

grep -n "shouldAddUserMessageToHistory\|userMessageWasRemoved\|telemetryMessageCountsBaseline\|messageCounts.user" src/core/task/Task.ts
echo '--- helper vicinity ---'
sed -n '2518,2598p' src/core/task/Task.ts
echo '--- telemetry vicinity ---'
sed -n '4688,4710p' src/core/task/Task.ts

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 4787


🏁 Script executed:

#!/bin/bash
set -euo pipefail

find . \( -name 'messageCounting.spec.ts' -o -name 'Task.spec.ts' \) -print
echo '--- tests mentioning the retry flow ---'
grep -R -n "api_req_failed\|api_req_retried\|userMessageWasRemoved\|messageCounts.user\|no assistant messages" . --include='*spec.ts' --include='*test.ts' | head -200

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 1433


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== src/core/task/messageCounting.ts =='
sed -n '1,200p' src/core/task/messageCounting.ts

echo '== src/core/task/__tests__/messageCounting.spec.ts =='
sed -n '1,220p' src/core/task/__tests__/messageCounting.spec.ts

echo '== src/core/task/__tests__/Task.spec.ts (retry-related snippets) =='
grep -n "api_req_failed\|api_req_retried\|userMessageWasRemoved\|messageCounts.user\|shouldAddUserMessageToHistory" src/core/task/__tests__/Task.spec.ts

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 3154


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the Task.spec.ts sections around any retry/history tests.
grep -n "api_req_failed\|api_req_retried\|userMessageWasRemoved\|messageCounts.user\|shouldAddUserMessageToHistory" src/core/task/__tests__/Task.spec.ts | cut -d: -f1 | sort -n | uniq | while read -r line; do
  start=$((line-12))
  end=$((line+20))
  if [ "$start" -lt 1 ]; then start=1; fi
  sed -n "${start},${end}p" src/core/task/__tests__/Task.spec.ts
  echo '---'
done

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' src/core/task/messageCounting.ts
printf '\n---\n'
sed -n '1,220p' src/core/task/__tests__/messageCounting.spec.ts
printf '\n---\n'
grep -n "api_req_failed\|api_req_retried\|userMessageWasRemoved\|messageCounts.user\|shouldAddUserMessageToHistory" src/core/task/__tests__/Task.spec.ts

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 3003


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Focus only on the helper and the nearby Task tests if they exist.
sed -n '1,220p' src/core/task/messageCounting.ts
echo '---'
sed -n '1,220p' src/core/task/__tests__/messageCounting.spec.ts
echo '---'
grep -n "api_req_failed\|api_req_retried\|userMessageWasRemoved\|messageCounts.user\|shouldAddUserMessageToHistory" src/core/task/__tests__/Task.spec.ts || true

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 3001


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' src/core/task/messageCounting.ts
printf '\n---\n'
sed -n '1,220p' src/core/task/__tests__/messageCounting.spec.ts
printf '\n---\n'
grep -n "api_req_failed\|api_req_retried\|userMessageWasRemoved\|messageCounts.user\|shouldAddUserMessageToHistory" src/core/task/__tests__/Task.spec.ts || true

Repository: Zoo-Code-Org/Zoo-Code

Length of output: 3003


Keep the empty-assistant retry path symmetric

  • Decrement messageCounts.user when the temporary user turn is popped, and set userMessageWasRemoved: true in the yesButtonClicked retry branch; otherwise the retried request skips restoring the user message and the counter drifts on each failed cycle.
  • Add a regression test for the manual retry path.
🤖 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/Task.ts` around lines 2627 - 2636, The retry flow around
shouldAddUserMessageToHistory and the yesButtonClicked branch must keep user
history and counts symmetric. When removing the temporary user turn, decrement
messageCounts.user, mark userMessageWasRemoved true for the retry item, and
ensure the retried request restores the user message; add a regression test
covering manual retry after an empty-assistant response.

Comment thread src/core/webview/webviewMessageHandler.ts Outdated
"telemetry": {
"helpImprove": "Zoo Code को बेहतर बनाने में मदद करें",
"helpImproveMessage": "Zoo Code बग ठीक करने और एक्सटेंशन को बेहतर बनाने में हमारी मदद करने के लिए त्रुटि और उपयोग डेटा एकत्र करता है। यह दूरसंचार कोड, प्रॉम्प्ट या व्यक्तिगत जानकारी एकत्र नहीं करता है। आप इसे <settingsLink>सेटिंग्स</settingsLink> में अक्षम कर सकते हैं।"
"helpImproveMessage": "Zoo Code बग ठीक करने और एक्सटेंशन को बेहतर बनाने में हमारी मदद करने के लिए त्रुटि और उपयोग डेटा एकत्र करता है। यह दूरसंचार कोड, प्रॉम्प्ट या व्यक्तिगत जानकारी एकत्र नहीं करता है। आप इसे <settingsLink>सेटिंग्स</settingsLink> में अक्षम कर सकते हैं।",

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the Hindi term for telemetry.

दूरसंचार कोड means “telecommunications code,” which can mislead users about what data is collected. Use टेलीमेट्री or टेलीमेट्री डेटा instead.

🤖 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 `@webview-ui/src/i18n/locales/hi/welcome.json` at line 15, Update the
helpImproveMessage translation in the Hindi welcome locale to replace the
incorrect term “दूरसंचार कोड” with “टेलीमेट्री” or “टेलीमेट्री डेटा,” while
preserving the surrounding meaning and settingsLink markup.

@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 12, 2026
@github-actions github-actions Bot added awaiting-review PR changes are ready and waiting for maintainer re-review and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 12, 2026
@github-actions github-actions Bot added awaiting-review PR changes are ready and waiting for maintainer re-review and removed awaiting-review PR changes are ready and waiting for maintainer re-review labels Jul 12, 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.

Reduce PostHog event volume and fix telemetry consent/privacy gaps

1 participant