Skip to content

Commit 59d5a41

Browse files
committed
fix: harden prompt cache telemetry and masking
1 parent b42430c commit 59d5a41

3 files changed

Lines changed: 28 additions & 10 deletions

File tree

index.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2036,6 +2036,11 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
20362036
);
20372037
runtimeMetrics.lastRequestAt = Date.now();
20382038
runtimeMetrics.lastPromptCacheKey = promptCacheKey ?? null;
2039+
if (promptCacheKey) {
2040+
runtimeMetrics.promptCacheEnabledRequests++;
2041+
} else {
2042+
runtimeMetrics.promptCacheMissingRequests++;
2043+
}
20392044
const retryBudget = new RetryBudgetTracker(retryBudgetLimits);
20402045
const consumeRetryBudget = (
20412046
bucket: RetryBudgetClass,
@@ -2336,17 +2341,19 @@ while (attempted.size < Math.max(1, accountCount)) {
23362341
// in-memory only and run on Node's single-threaded event loop, so no
23372342
// filesystem locking or token-redaction concerns are introduced here.
23382343
runtimeMetrics.totalRequests++;
2339-
if (promptCacheKey) {
2340-
runtimeMetrics.promptCacheEnabledRequests++;
2341-
} else {
2342-
runtimeMetrics.promptCacheMissingRequests++;
2343-
}
23442344
response = await fetch(url, {
23452345
...requestInit,
23462346
headers,
23472347
signal: fetchController.signal,
23482348
});
23492349
} catch (networkError) {
2350+
if (abortSignal?.aborted && fetchController.signal.aborted) {
2351+
accountManager.refundToken(account, modelFamily, model);
2352+
if (networkError instanceof Error) {
2353+
throw networkError;
2354+
}
2355+
throw new Error(String(networkError));
2356+
}
23502357
const errorMsg = networkError instanceof Error ? networkError.message : String(networkError);
23512358
logWarn(`Network error for account ${account.index + 1}: ${errorMsg}`);
23522359
if (

lib/ui/beginner.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { createHash } from "node:crypto";
2+
13
export type BeginnerDiagnosticSeverity = "ok" | "warning" | "error";
24

35
export interface BeginnerAccountSnapshot {
@@ -53,7 +55,8 @@ export interface BeginnerAccountSummary {
5355
export function formatPromptCacheKey(value: string | null | undefined): string {
5456
const normalized = value?.trim();
5557
if (!normalized) return "none";
56-
return `${normalized.slice(0, 8)}...`;
58+
const fingerprint = createHash("sha256").update(normalized).digest("hex").slice(0, 12);
59+
return `masked-${fingerprint}`;
5760
}
5861

5962
export function formatPromptCacheSnapshot(runtime: Pick<

test/beginner-ui.test.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { describe, it, expect } from "vitest";
2+
import { createHash } from "node:crypto";
3+
24
import {
35
buildBeginnerChecklist,
46
buildBeginnerDoctorFindings,
@@ -238,11 +240,15 @@ describe("formatPromptCacheKey", () => {
238240
});
239241

240242
it("redacts short values too", () => {
241-
expect(formatPromptCacheKey("ses_1234")).toBe("ses_1234...");
243+
expect(formatPromptCacheKey("ses_1234")).toBe(
244+
`masked-${createHash("sha256").update("ses_1234").digest("hex").slice(0, 12)}`,
245+
);
242246
});
243247

244-
it("redacts longer values to an 8-char prefix", () => {
245-
expect(formatPromptCacheKey("ses_prompt_cache_key_123")).toBe("ses_prom...");
248+
it("redacts longer values to a stable masked fingerprint", () => {
249+
expect(formatPromptCacheKey("ses_prompt_cache_key_123")).toBe(
250+
`masked-${createHash("sha256").update("ses_prompt_cache_key_123").digest("hex").slice(0, 12)}`,
251+
);
246252
});
247253
});
248254

@@ -254,7 +260,9 @@ describe("formatPromptCacheSnapshot", () => {
254260
lastPromptCacheKey: "ses_prompt_cache_key_123",
255261
});
256262

257-
expect(rendered).toBe("enabled=4, missing=1, lastKey=ses_prom...");
263+
expect(rendered).toBe(
264+
`enabled=4, missing=1, lastKey=masked-${createHash("sha256").update("ses_prompt_cache_key_123").digest("hex").slice(0, 12)}`,
265+
);
258266
expect(rendered).not.toContain("ses_prompt_cache_key_123");
259267
});
260268
});

0 commit comments

Comments
 (0)