pi-claude-billing-router 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/subscription-guard.ts +62 -0
- package/package.json +1 -1
|
@@ -1347,6 +1347,54 @@ function stripAliasStubs(payload: Record<string, unknown>): Record<string, unkno
|
|
|
1347
1347
|
return { ...payload, tools: kept };
|
|
1348
1348
|
}
|
|
1349
1349
|
|
|
1350
|
+
// Project request-local transcript state BEFORE providers serialize/cache/seal it.
|
|
1351
|
+
// In particular pi-background-tasks protects both cache positions and lineage;
|
|
1352
|
+
// changing the serialized tool list in before_provider_request is too late.
|
|
1353
|
+
function transformTranscript(messages: unknown[], plan: boolean, disableFilter: boolean): unknown[] {
|
|
1354
|
+
const active = new Map<string, Record<string, unknown>>();
|
|
1355
|
+
let previous = new Map<string, Record<string, unknown>>();
|
|
1356
|
+
return messages.map((message) => {
|
|
1357
|
+
if (!isPlainObject(message)) return message;
|
|
1358
|
+
if (message.role !== "system") {
|
|
1359
|
+
if (!plan || message.role !== "assistant" || !Array.isArray(message.content)) return message;
|
|
1360
|
+
const content = remapBlockNames(message.content, "toolCall", (name) => {
|
|
1361
|
+
const alias = FLAT_TO_MCP.get(lower(name));
|
|
1362
|
+
return alias && registeredMcpAliases.has(lower(alias)) ? alias : undefined;
|
|
1363
|
+
});
|
|
1364
|
+
return content === message.content ? message : { ...message, content };
|
|
1365
|
+
}
|
|
1366
|
+
if (Array.isArray(message.toolsRemoved)) {
|
|
1367
|
+
for (const tool of message.toolsRemoved) {
|
|
1368
|
+
if (isPlainObject(tool) && typeof tool.name === "string") active.delete(lower(tool.name));
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
if (Array.isArray(message.toolsAdded)) {
|
|
1372
|
+
for (const tool of message.toolsAdded) {
|
|
1373
|
+
if (isPlainObject(tool) && typeof tool.name === "string") active.set(lower(tool.name), tool);
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
const tools = [...active.values()];
|
|
1377
|
+
const projected = plan
|
|
1378
|
+
? filterAndRemapTools(tools, disableFilter)!
|
|
1379
|
+
: (stripAliasStubs({ tools }).tools as unknown[]);
|
|
1380
|
+
const next = collectToolsByName(projected);
|
|
1381
|
+
const toolsRemoved = [...previous.keys()].filter((name) => !next.has(name))
|
|
1382
|
+
.map((name) => ({ name: previous.get(name)!.name }));
|
|
1383
|
+
const toolsAdded = [...next.entries()].filter(([name, tool]) =>
|
|
1384
|
+
JSON.stringify(previous.get(name)) !== JSON.stringify(tool)).map(([, tool]) => tool);
|
|
1385
|
+
previous = next;
|
|
1386
|
+
const result: Record<string, unknown> = { ...message, toolsAdded, toolsRemoved };
|
|
1387
|
+
if (plan) {
|
|
1388
|
+
result.content = rewriteSystemField(message.content);
|
|
1389
|
+
if (isPlainObject(message.sections)) {
|
|
1390
|
+
result.sections = Object.fromEntries(Object.entries(message.sections).map(([key, value]) =>
|
|
1391
|
+
[key, typeof value === "string" ? rewritePromptText(value) : value]));
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
return result;
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1350
1398
|
// ============================================================================
|
|
1351
1399
|
// Extension entry point
|
|
1352
1400
|
// ============================================================================
|
|
@@ -1377,6 +1425,18 @@ export default async function piClaudeCodeUse(pi: ExtensionAPI): Promise<void> {
|
|
|
1377
1425
|
return { message: rewritten as typeof event.message };
|
|
1378
1426
|
});
|
|
1379
1427
|
|
|
1428
|
+
pi.on("context_with_system", (event, ctx) => {
|
|
1429
|
+
const model = ctx.model;
|
|
1430
|
+
if (model?.provider !== "anthropic" || !ctx.modelRegistry.isUsingOAuth(model)) return;
|
|
1431
|
+
// Refresh before serialization, including tools registered after our
|
|
1432
|
+
// before_agent_start handler. Keep the existing best-effort semantics.
|
|
1433
|
+
try {
|
|
1434
|
+
registerMcpAliases(pi, { cwd: typeof ctx.cwd === "string" ? ctx.cwd : undefined });
|
|
1435
|
+
} catch { /* The existing aliases remain usable. */ }
|
|
1436
|
+
return { messages: transformTranscript(event.messages, useSubscription(),
|
|
1437
|
+
process.env.PI_CLAUDE_CODE_USE_DISABLE_TOOL_FILTER === "1") as typeof event.messages };
|
|
1438
|
+
});
|
|
1439
|
+
|
|
1380
1440
|
pi.on("before_provider_request", (event, ctx) => {
|
|
1381
1441
|
const model = ctx.model;
|
|
1382
1442
|
if (model?.provider !== "anthropic" || !ctx.modelRegistry.isUsingOAuth(model)) {
|
|
@@ -1452,6 +1512,8 @@ export const _test = {
|
|
|
1452
1512
|
},
|
|
1453
1513
|
syncAliasActivation,
|
|
1454
1514
|
transformPayload,
|
|
1515
|
+
transformTranscript,
|
|
1516
|
+
stripAliasStubs,
|
|
1455
1517
|
unaliasDisplayedProse,
|
|
1456
1518
|
unaliasToolCalls,
|
|
1457
1519
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-claude-billing-router",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Route Claude Pro/Max OAuth requests in pi between your plan and extra-usage credits: plan first, automatic fallback to credits when the 5h window is exhausted, /billing override, live usage in the footer.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|