From ba7841ca3b35074afc42d0d5c1440a078a47e073 Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 28 Sep 2026 11:31:43 -0500 Subject: [PATCH] Label Pi pricing estimates and ignore duplicate stale failure receipts Co-Authored-By: Paperclip --- .../src/drivers/acpx/pi-acp-runtime.test.ts | 2 ++ .../src/drivers/acpx/pi-acp-runtime.ts | 9 ++++++--- patches/pi-acp@0.0.33.patch | 11 +++++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.test.ts b/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.test.ts index 013810c8eb5..f1142176d4e 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.test.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.test.ts @@ -73,7 +73,9 @@ describe("Pi ACP bridge", () => { expect(usage.response()).toMatchObject({ usage: { totalTokens: 10 }, _meta: { jetbrains: { air: { sessionFailure: { severity: "error" } } } } }); usage.accept({ ...failed, timestamp: 2, stopReason: "stop" }); expect(usage.response()).toMatchObject({ usage: { inputTokens: 8, totalTokens: 20 } }); + usage.accept(failed); // A duplicate old failure cannot undo a successful retry. expect(usage.response()._meta).toBeUndefined(); + expect(usage.response()).toMatchObject({ usage: { _meta: { paperclipPi: { costUsd: 0.02, costSource: "pi_pricing_estimate" } } } }); usage.reset(); expect(usage.response()).toEqual({}); }); diff --git a/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.ts b/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.ts index c8f576e9b38..b5628aa4303 100644 --- a/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.ts +++ b/packages/paperclip-runner/src/drivers/acpx/pi-acp-runtime.ts @@ -222,12 +222,15 @@ export class PiTurnUsage { accept(value: unknown): void { const message = record(value); if (message.role !== "assistant") return; - this.failed = message.stopReason === "error"; - if (!message.usage || typeof message.usage !== "object") return; + if (!message.usage || typeof message.usage !== "object") { + this.failed = message.stopReason === "error"; + return; + } const key = JSON.stringify([message.timestamp, message.id, message.usage, message.content]); if (this.seen.has(key)) return; if (this.seen.size >= 8192) throw new Error("Pi usage receipts exceed their bound"); this.seen.add(key); + this.failed = message.stopReason === "error"; const usage = record(message.usage); const valid = (value: unknown): value is number => typeof value === "number" && Number.isSafeInteger(value) && value >= 0; const fields = ["inputTokens", "outputTokens", "cachedReadTokens", "cachedWriteTokens"] as const; @@ -249,7 +252,7 @@ export class PiTurnUsage { response(): RecordValue { return { - ...(this.observed ? { usage: { ...Object.fromEntries(Object.entries(this.total).filter(([name]) => !this.unknown.has(name as keyof typeof this.total))), _meta: { paperclipPi: { provenance: "assistant_message_receipts", ...(this.costObserved && !this.costIncomplete ? { costUsd: this.cost } : {}) } } } } : {}), + ...(this.observed ? { usage: { ...Object.fromEntries(Object.entries(this.total).filter(([name]) => !this.unknown.has(name as keyof typeof this.total))), _meta: { paperclipPi: { provenance: "assistant_message_receipts", ...(this.costObserved && !this.costIncomplete ? { costUsd: this.cost, costSource: "pi_pricing_estimate" } : {}) } } } } : {}), ...(this.failed ? { _meta: { jetbrains: { air: { version: 1, sessionFailure: { severity: "error", category: "service", title: "Pi provider request failed" } } } } } : {}), }; } diff --git a/patches/pi-acp@0.0.33.patch b/patches/pi-acp@0.0.33.patch index 01ab2699b1c..ce405ca69a2 100644 --- a/patches/pi-acp@0.0.33.patch +++ b/patches/pi-acp@0.0.33.patch @@ -426,7 +426,7 @@ diff --git a/dist/paperclip-runtime.js b/dist/paperclip-runtime.js new file mode 100644 --- /dev/null +++ b/dist/paperclip-runtime.js -@@ -0,0 +1,256 @@ +@@ -0,0 +1,259 @@ +/** Source for the helper embedded in patches/pi-acp@0.0.33.patch. */ +import { StringDecoder } from "node:string_decoder"; +import { isAbsolute, relative, resolve, sep } from "node:path"; @@ -651,12 +651,15 @@ new file mode 100644 + accept(value ) { + const message = record(value); + if (message.role !== "assistant") return; -+ this.failed = message.stopReason === "error"; -+ if (!message.usage || typeof message.usage !== "object") return; ++ if (!message.usage || typeof message.usage !== "object") { ++ this.failed = message.stopReason === "error"; ++ return; ++ } + const key = JSON.stringify([message.timestamp, message.id, message.usage, message.content]); + if (this.seen.has(key)) return; + if (this.seen.size >= 8192) throw new Error("Pi usage receipts exceed their bound"); + this.seen.add(key); ++ this.failed = message.stopReason === "error"; + const usage = record(message.usage); + const valid = (value ) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0; + const fields = ["inputTokens", "outputTokens", "cachedReadTokens", "cachedWriteTokens"] ; @@ -678,7 +681,7 @@ new file mode 100644 + + response() { + return { -+ ...(this.observed ? { usage: { ...Object.fromEntries(Object.entries(this.total).filter(([name]) => !this.unknown.has(name ))), _meta: { paperclipPi: { provenance: "assistant_message_receipts", ...(this.costObserved && !this.costIncomplete ? { costUsd: this.cost } : {}) } } } } : {}), ++ ...(this.observed ? { usage: { ...Object.fromEntries(Object.entries(this.total).filter(([name]) => !this.unknown.has(name ))), _meta: { paperclipPi: { provenance: "assistant_message_receipts", ...(this.costObserved && !this.costIncomplete ? { costUsd: this.cost, costSource: "pi_pricing_estimate" } : {}) } } } } : {}), + ...(this.failed ? { _meta: { jetbrains: { air: { version: 1, sessionFailure: { severity: "error", category: "service", title: "Pi provider request failed" } } } } } : {}), + }; + }