Label Pi pricing estimates and ignore duplicate stale failure receipts

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-09-28 15:14:57 -05:00
1 parent 14e1e09a79
commit ba7841ca3b
3 files changed
+15 -7

No files matched your search

@@ -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({});
});
@@ -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" } } } } } : {}),
};
}
+7 -4
View File
@@ -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" } } } } } : {}),
+ };
+ }