Skip to content

Commit 52a8cc0

Browse files
feat(privacy): remove extension LLM telemetry; gateway-only server logs (#346)
* feat(privacy): remove extension LLM telemetry and observability section Delete the extension-side LLM telemetry path (zoo-telemetry.ts and its Task.ts hook) so BYOK requests no longer send usage metadata to zoocode.dev. Drop the "Zoo Code Observability" section from PRIVACY.md entirely: server-side gateway request logging is not extension behavior and is documented at zoocode.dev like any other provider's, so the extension privacy policy should not single it out. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor(zoo-code-auth): drop subscription-status helpers with telemetry The checkSubscriptionStatus / getCachedSubscriptionStatus helpers existed only to gate the now-removed LLM telemetry path. Remove them and their tests. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 75d4eee commit 52a8cc0

6 files changed

Lines changed: 11 additions & 437 deletions

File tree

PRIVACY.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ go—and, importantly, where they don't.
4040
We retain telemetry only as long as needed for product analytics and debugging.
4141
Telemetry does **not** collect your code or AI prompts, and you can opt out at
4242
any time through the settings.
43-
- **Zoo Code Observability (Authenticated Subscribers Only):** If you sign in to
44-
Zoo Code and have an active subscription, Zoo Code will send LLM usage
45-
telemetry to the Zoo Code backend (zoocode.dev). This includes task ID, AI
46-
provider name, model name, token counts (input/output/cache), and estimated
47-
cost. This data is linked to your authenticated Zoo Code account. You can stop
48-
this collection at any time by signing out via the Zoo Code badge in the chat
49-
area.
5043
- **Marketplace Requests**: When you browse or search the Marketplace for Model
5144
Configuration Profiles (MCPs) or Custom Modes, Zoo Code makes a secure API
5245
call to Zoo Code's backend servers to retrieve listing information. These

src/core/task/Task.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3013,27 +3013,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
30133013
cacheReadTokens: tokens.cacheRead,
30143014
cost: tokens.total ?? costResult.totalCost,
30153015
})
3016-
3017-
// Zoo Code observability telemetry
3018-
import("../../services/zoo-telemetry")
3019-
.then(async ({ sendLlmTelemetry }) => {
3020-
const mode = await this.getTaskMode().catch(() => "unknown")
3021-
return sendLlmTelemetry({
3022-
taskId: this.taskId,
3023-
provider: this.apiConfiguration?.apiProvider ?? "unknown",
3024-
model: this.apiConfiguration
3025-
? (getModelId(this.apiConfiguration) ?? "unknown")
3026-
: "unknown",
3027-
mode,
3028-
inputTokens: costResult.totalInputTokens,
3029-
outputTokens: costResult.totalOutputTokens,
3030-
cacheReadTokens: tokens.cacheRead ?? 0,
3031-
cacheWriteTokens: tokens.cacheWrite ?? 0,
3032-
totalCost: tokens.total ?? costResult.totalCost,
3033-
status,
3034-
}).catch(() => {})
3035-
})
3036-
.catch(() => {})
30373016
}
30383017
}
30393018

src/services/__tests__/zoo-code-auth.test.ts

Lines changed: 9 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
22
import * as vscode from "vscode"
33

44
import {
5-
checkSubscriptionStatus,
65
clearZooCodeToken,
76
clearZooCodeUserInfo,
87
disconnectZooCode,
9-
getCachedSubscriptionStatus,
108
getCachedZooCodeToken,
119
getCachedZooCodeUserInfo,
1210
getZooCodeBaseUrl,
@@ -68,98 +66,6 @@ describe("zoo-code-auth", () => {
6866
vi.restoreAllMocks()
6967
})
7068

71-
describe("getCachedSubscriptionStatus", () => {
72-
it("returns unknown initially", () => {
73-
expect(getCachedSubscriptionStatus()).toBe("unknown")
74-
})
75-
})
76-
77-
describe("checkSubscriptionStatus", () => {
78-
it("returns inactive when no token is present", async () => {
79-
await initZooCodeAuth(mockContext)
80-
81-
const status = await checkSubscriptionStatus()
82-
83-
expect(status).toBe("inactive")
84-
expect(mockFetch).not.toHaveBeenCalled()
85-
})
86-
87-
it("returns active when the API reports an active subscriber", async () => {
88-
await initZooCodeAuth(mockContext)
89-
await setZooCodeToken("zoo_ext_test_token")
90-
91-
mockFetch.mockResolvedValueOnce({
92-
ok: true,
93-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
94-
})
95-
96-
const status = await checkSubscriptionStatus()
97-
98-
expect(status).toBe("active")
99-
expect(mockFetch).toHaveBeenCalledWith(
100-
expect.stringContaining("/api/subscription/status"),
101-
expect.objectContaining({
102-
headers: { Authorization: "Bearer zoo_ext_test_token" },
103-
}),
104-
)
105-
})
106-
107-
it("returns inactive when the API reports a free user", async () => {
108-
await initZooCodeAuth(mockContext)
109-
await setZooCodeToken("zoo_ext_test_token")
110-
111-
mockFetch.mockResolvedValueOnce({
112-
ok: true,
113-
json: async () => ({ isSubscriber: false, planId: "free", status: "active" }),
114-
})
115-
116-
await expect(checkSubscriptionStatus()).resolves.toBe("inactive")
117-
})
118-
119-
it("returns unknown when the API request fails", async () => {
120-
await initZooCodeAuth(mockContext)
121-
await setZooCodeToken("zoo_ext_test_token")
122-
123-
mockFetch.mockResolvedValueOnce({
124-
ok: false,
125-
status: 500,
126-
statusText: "Internal Server Error",
127-
})
128-
129-
await expect(checkSubscriptionStatus()).resolves.toBe("unknown")
130-
})
131-
132-
it("returns unknown when the API throws", async () => {
133-
await initZooCodeAuth(mockContext)
134-
await setZooCodeToken("zoo_ext_test_token")
135-
mockFetch.mockRejectedValueOnce(new Error("Network error"))
136-
137-
await expect(checkSubscriptionStatus()).resolves.toBe("unknown")
138-
})
139-
140-
it("reuses the cached status when it was checked recently", async () => {
141-
await initZooCodeAuth(mockContext)
142-
await setZooCodeToken("zoo_ext_test_token")
143-
144-
mockFetch.mockResolvedValueOnce({
145-
ok: true,
146-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
147-
})
148-
149-
expect(await checkSubscriptionStatus()).toBe("active")
150-
expect(await checkSubscriptionStatus()).toBe("active")
151-
expect(mockFetch).toHaveBeenCalledTimes(1)
152-
})
153-
154-
it("handles AbortSignal timeouts", async () => {
155-
await initZooCodeAuth(mockContext)
156-
await setZooCodeToken("zoo_ext_test_token")
157-
mockFetch.mockRejectedValueOnce(new DOMException("Aborted", "AbortError"))
158-
159-
await expect(checkSubscriptionStatus()).resolves.toBe("unknown")
160-
})
161-
})
162-
16369
describe("getCachedZooCodeToken", () => {
16470
it("returns an empty string when no token is set", async () => {
16571
await clearZooCodeToken()
@@ -169,15 +75,10 @@ describe("zoo-code-auth", () => {
16975

17076
it("preloads the cached token during initialization", async () => {
17177
await mockSecrets.store("zoo-code-session-token", "zoo_ext_cached_token")
172-
mockFetch
173-
.mockResolvedValueOnce({
174-
ok: true,
175-
json: async () => ({ valid: true }),
176-
})
177-
.mockResolvedValueOnce({
178-
ok: true,
179-
json: async () => ({ isSubscriber: true }),
180-
})
78+
mockFetch.mockResolvedValueOnce({
79+
ok: true,
80+
json: async () => ({ valid: true }),
81+
})
18182

18283
await initZooCodeAuth(mockContext)
18384
await Promise.resolve()
@@ -237,10 +138,8 @@ describe("zoo-code-auth", () => {
237138

238139
await initZooCodeAuth(mockContext)
239140

240-
// Token and user info should be kept; subscription status should be unknown
241141
expect(getCachedZooCodeToken()).toBe("zoo_ext_valid_token")
242142
expect(getCachedZooCodeUserInfo().name).toBe("Jane Doe")
243-
expect(getCachedSubscriptionStatus()).toBe("unknown")
244143
})
245144

246145
it("preserves token and user info when verify returns 5xx (transient backend error)", async () => {
@@ -257,39 +156,16 @@ describe("zoo-code-auth", () => {
257156

258157
expect(getCachedZooCodeToken()).toBe("zoo_ext_valid_token")
259158
expect(getCachedZooCodeUserInfo().name).toBe("Jane Doe")
260-
expect(getCachedSubscriptionStatus()).toBe("unknown")
261-
})
262-
})
263-
264-
describe("setZooCodeToken", () => {
265-
it("resets the cached subscription status when the token changes", async () => {
266-
await initZooCodeAuth(mockContext)
267-
await setZooCodeToken("zoo_ext_token1")
268-
mockFetch.mockResolvedValueOnce({
269-
ok: true,
270-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
271-
})
272-
await checkSubscriptionStatus()
273-
274-
await setZooCodeToken("zoo_ext_token2")
275-
276-
expect(getCachedSubscriptionStatus()).toBe("unknown")
277159
})
278160
})
279161

280162
describe("clearZooCodeToken", () => {
281-
it("resets the cached subscription status when the token is cleared", async () => {
163+
it("clears the cached token", async () => {
282164
await initZooCodeAuth(mockContext)
283165
await setZooCodeToken("zoo_ext_test_token")
284-
mockFetch.mockResolvedValueOnce({
285-
ok: true,
286-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
287-
})
288-
await checkSubscriptionStatus()
289166

290167
await clearZooCodeToken()
291168

292-
expect(getCachedSubscriptionStatus()).toBe("unknown")
293169
expect(getCachedZooCodeToken()).toBe("")
294170
})
295171
})
@@ -337,15 +213,10 @@ describe("zoo-code-auth", () => {
337213

338214
it("persists a token only after backend verification succeeds", async () => {
339215
await initZooCodeAuth(mockContext)
340-
mockFetch
341-
.mockResolvedValueOnce({
342-
ok: true,
343-
json: async () => ({ valid: true }),
344-
})
345-
.mockResolvedValueOnce({
346-
ok: true,
347-
json: async () => ({ isSubscriber: true }),
348-
})
216+
mockFetch.mockResolvedValueOnce({
217+
ok: true,
218+
json: async () => ({ valid: true }),
219+
})
349220

350221
const success = await handleAuthCallback("zoo_ext_real_token")
351222

src/services/__tests__/zoo-telemetry.test.ts

Lines changed: 0 additions & 132 deletions
This file was deleted.

0 commit comments

Comments
 (0)