@madgagarin/pi-agentrouter 1.1.0 → 1.2.0
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/index.ts +124 -7
- package/package.json +12 -4
package/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as fs from "fs";
|
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
|
|
6
6
|
const CONFIG_FILE = path.join(process.env.HOME || "", ".pi/agent/agentrouter.json");
|
|
7
|
+
const SETTINGS_FILE = path.join(process.env.HOME || "", ".pi/agent/settings.json");
|
|
7
8
|
|
|
8
9
|
export interface AgentRouterConfig {
|
|
9
10
|
apiKey?: string;
|
|
@@ -34,10 +35,62 @@ export function normalizeApiKey(key?: string): string {
|
|
|
34
35
|
return key.trim().replace(/^["']|["']$/g, "").trim();
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
export interface PackageOrderState {
|
|
39
|
+
agentRouterIndex: number;
|
|
40
|
+
cacheOptimizerIndex: number;
|
|
41
|
+
needsFix: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getPackageOrderState(): PackageOrderState {
|
|
45
|
+
try {
|
|
46
|
+
if (!fs.existsSync(SETTINGS_FILE)) {
|
|
47
|
+
return { agentRouterIndex: -1, cacheOptimizerIndex: -1, needsFix: false };
|
|
48
|
+
}
|
|
49
|
+
const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, "utf-8"));
|
|
50
|
+
if (!Array.isArray(settings.packages)) {
|
|
51
|
+
return { agentRouterIndex: -1, cacheOptimizerIndex: -1, needsFix: false };
|
|
52
|
+
}
|
|
53
|
+
const arIdx = settings.packages.findIndex((p: string) =>
|
|
54
|
+
typeof p === "string" && (p.includes("@madgagarin/pi-agentrouter") || p.includes("pi-agentrouter"))
|
|
55
|
+
);
|
|
56
|
+
const cacheIdx = settings.packages.findIndex((p: string) =>
|
|
57
|
+
typeof p === "string" && p.includes("pi-cache-optimizer")
|
|
58
|
+
);
|
|
59
|
+
const needsFix = cacheIdx !== -1 && arIdx !== -1 && arIdx > cacheIdx;
|
|
60
|
+
return { agentRouterIndex: arIdx, cacheOptimizerIndex: cacheIdx, needsFix };
|
|
61
|
+
} catch {
|
|
62
|
+
return { agentRouterIndex: -1, cacheOptimizerIndex: -1, needsFix: false };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function fixPackagePriorityInSettings(): boolean {
|
|
67
|
+
try {
|
|
68
|
+
if (!fs.existsSync(SETTINGS_FILE)) return false;
|
|
69
|
+
const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, "utf-8"));
|
|
70
|
+
if (!Array.isArray(settings.packages)) return false;
|
|
71
|
+
const arIdx = settings.packages.findIndex((p: string) =>
|
|
72
|
+
typeof p === "string" && (p.includes("@madgagarin/pi-agentrouter") || p.includes("pi-agentrouter"))
|
|
73
|
+
);
|
|
74
|
+
const cacheIdx = settings.packages.findIndex((p: string) =>
|
|
75
|
+
typeof p === "string" && p.includes("pi-cache-optimizer")
|
|
76
|
+
);
|
|
77
|
+
if (cacheIdx !== -1 && arIdx !== -1 && arIdx > cacheIdx) {
|
|
78
|
+
const pkg = settings.packages.splice(arIdx, 1)[0];
|
|
79
|
+
const targetCacheIdx = settings.packages.findIndex((p: string) =>
|
|
80
|
+
typeof p === "string" && p.includes("pi-cache-optimizer")
|
|
81
|
+
);
|
|
82
|
+
settings.packages.splice(targetCacheIdx, 0, pkg);
|
|
83
|
+
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
} catch {}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
37
90
|
const initialConfig = loadConfig();
|
|
38
91
|
let currentApiKey = normalizeApiKey(process.env.AGENTROUTER_API_KEY || initialConfig.apiKey || "");
|
|
39
92
|
let minIntervalMs = initialConfig.minIntervalMs ?? 2500;
|
|
40
|
-
let
|
|
93
|
+
let lastRequestEndTime = 0;
|
|
41
94
|
|
|
42
95
|
export function isAgentRouter(providerName?: string, baseUrl?: string): boolean {
|
|
43
96
|
if (providerName && providerName.toLowerCase().includes("agentrouter")) return true;
|
|
@@ -120,7 +173,25 @@ export default function (pi: ExtensionAPI) {
|
|
|
120
173
|
|
|
121
174
|
pi.on("session_start", async (_event, ctx) => {
|
|
122
175
|
updatePromptRewriteEnvForModel(ctx.model);
|
|
123
|
-
|
|
176
|
+
lastRequestEndTime = Date.now();
|
|
177
|
+
|
|
178
|
+
const order = getPackageOrderState();
|
|
179
|
+
if (order.needsFix && ctx.hasUI && typeof (ctx.ui as any).confirm === "function") {
|
|
180
|
+
try {
|
|
181
|
+
const confirmed = await (ctx.ui as any).confirm(
|
|
182
|
+
"Pi AgentRouter Package Priority",
|
|
183
|
+
"@madgagarin/pi-agentrouter is listed AFTER pi-cache-optimizer in settings.json packages.\n\n" +
|
|
184
|
+
"It must be placed before pi-cache-optimizer so prompt cache bypass takes effect before cache-optimizer transforms the prompt.\n\n" +
|
|
185
|
+
"Move @madgagarin/pi-agentrouter directly above pi-cache-optimizer in settings.json?"
|
|
186
|
+
);
|
|
187
|
+
if (confirmed) {
|
|
188
|
+
const success = fixPackagePriorityInSettings();
|
|
189
|
+
if (success) {
|
|
190
|
+
ctx.ui.notify("@madgagarin/pi-agentrouter moved above pi-cache-optimizer in settings.json. Please restart Pi for changes to take full effect.", "info");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
} catch {}
|
|
194
|
+
}
|
|
124
195
|
});
|
|
125
196
|
|
|
126
197
|
pi.on("model_select", async (event) => {
|
|
@@ -139,14 +210,26 @@ export default function (pi: ExtensionAPI) {
|
|
|
139
210
|
}
|
|
140
211
|
|
|
141
212
|
const now = Date.now();
|
|
142
|
-
const elapsed = now -
|
|
213
|
+
const elapsed = now - lastRequestEndTime;
|
|
143
214
|
|
|
144
|
-
if (
|
|
215
|
+
if (lastRequestEndTime > 0 && elapsed < minIntervalMs) {
|
|
145
216
|
const waitMs = minIntervalMs - elapsed;
|
|
146
217
|
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
147
218
|
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
222
|
+
const model = ctx.model;
|
|
223
|
+
if (isAgentRouter(model?.provider, (model as any)?.baseUrl)) {
|
|
224
|
+
lastRequestEndTime = Date.now();
|
|
225
|
+
}
|
|
226
|
+
});
|
|
148
227
|
|
|
149
|
-
|
|
228
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
229
|
+
const model = ctx.model;
|
|
230
|
+
if (isAgentRouter(model?.provider, (model as any)?.baseUrl)) {
|
|
231
|
+
lastRequestEndTime = Date.now();
|
|
232
|
+
}
|
|
150
233
|
});
|
|
151
234
|
|
|
152
235
|
pi.on("session_before_compact", async (event, ctx) => {
|
|
@@ -241,6 +324,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
241
324
|
return;
|
|
242
325
|
}
|
|
243
326
|
|
|
327
|
+
if (action === "fix-order" || action === "order") {
|
|
328
|
+
const order = getPackageOrderState();
|
|
329
|
+
if (!order.needsFix) {
|
|
330
|
+
if (order.cacheOptimizerIndex === -1) {
|
|
331
|
+
ctx.ui.notify("pi-cache-optimizer is not installed in settings.json. Package order is optimal.", "info");
|
|
332
|
+
} else if (order.agentRouterIndex !== -1 && order.agentRouterIndex < order.cacheOptimizerIndex) {
|
|
333
|
+
ctx.ui.notify("@madgagarin/pi-agentrouter is already placed before pi-cache-optimizer (Optimal).", "info");
|
|
334
|
+
} else {
|
|
335
|
+
ctx.ui.notify("@madgagarin/pi-agentrouter was not found in settings.json packages.", "warning");
|
|
336
|
+
}
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const success = fixPackagePriorityInSettings();
|
|
340
|
+
if (success) {
|
|
341
|
+
ctx.ui.notify("@madgagarin/pi-agentrouter moved directly above pi-cache-optimizer in settings.json. Please restart Pi for changes to take full effect.", "info");
|
|
342
|
+
} else {
|
|
343
|
+
ctx.ui.notify("Failed to update settings.json.", "error");
|
|
344
|
+
}
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
244
348
|
if (action === "pacing" || action === "throttle") {
|
|
245
349
|
const val = parseInt(parts[1], 10);
|
|
246
350
|
if (isNaN(val) || val < 0) {
|
|
@@ -256,16 +360,29 @@ export default function (pi: ExtensionAPI) {
|
|
|
256
360
|
const maskedKey = currentApiKey.length > 8 ? `${currentApiKey.slice(0, 7)}...${currentApiKey.slice(-4)}` : "not set";
|
|
257
361
|
const activeModel = ctx.model;
|
|
258
362
|
const isAR = isAgentRouter(activeModel?.provider, (activeModel as any)?.baseUrl);
|
|
363
|
+
const order = getPackageOrderState();
|
|
364
|
+
let priorityStatus = "Optimal";
|
|
365
|
+
if (order.needsFix) {
|
|
366
|
+
priorityStatus = "Listed AFTER pi-cache-optimizer (Run: /agentrouter fix-order)";
|
|
367
|
+
} else if (order.cacheOptimizerIndex !== -1 && order.agentRouterIndex < order.cacheOptimizerIndex) {
|
|
368
|
+
priorityStatus = "Before pi-cache-optimizer (Optimal)";
|
|
369
|
+
} else if (order.agentRouterIndex !== -1) {
|
|
370
|
+
priorityStatus = "Active (Optimal)";
|
|
371
|
+
} else {
|
|
372
|
+
priorityStatus = "Not in packages";
|
|
373
|
+
}
|
|
259
374
|
|
|
260
375
|
ctx.ui.notify(
|
|
261
376
|
`[AgentRouter Plugin]\n` +
|
|
262
377
|
`- Active model: ${activeModel?.id || "none"} (${isAR ? "AgentRouter [yes]" : "Other Provider"})\n` +
|
|
378
|
+
`- Package Priority: ${priorityStatus}\n` +
|
|
263
379
|
`- API Key: ${maskedKey}\n` +
|
|
264
380
|
`- Caching: Enabled (Prompt Cache + Session Affinity + Adaptive Thinking)\n` +
|
|
265
|
-
`- Pacing Interval: ${minIntervalMs} ms\n` +
|
|
381
|
+
`- Pacing Interval: ${minIntervalMs} ms (Measured from turn completion)\n` +
|
|
266
382
|
`- Commands:\n` +
|
|
267
383
|
` /agentrouter key <key> (update API key)\n` +
|
|
268
|
-
` /agentrouter pacing <ms> (set
|
|
384
|
+
` /agentrouter pacing <ms> (set request delay after completion)\n` +
|
|
385
|
+
` /agentrouter fix-order (move plugin above pi-cache-optimizer in settings.json)`,
|
|
269
386
|
"info"
|
|
270
387
|
);
|
|
271
388
|
},
|
package/package.json
CHANGED
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madgagarin/pi-agentrouter",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Pi coding agent extension for AgentRouter (GPT-5.6 Sol & Claude Opus 5) with rate-limit pacing and caching.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"keywords": [
|
|
9
9
|
"pi-package",
|
|
10
|
+
"pi-extension",
|
|
11
|
+
"pi-coding-agent",
|
|
10
12
|
"pi",
|
|
11
13
|
"agentrouter",
|
|
14
|
+
"agentrouter-org",
|
|
15
|
+
"agentrouter.org",
|
|
16
|
+
"agent-router",
|
|
17
|
+
"gpt-5.6-sol",
|
|
18
|
+
"claude-opus-5",
|
|
19
|
+
"claude-opus-4-8",
|
|
20
|
+
"prompt-caching",
|
|
12
21
|
"openai",
|
|
13
22
|
"claude",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"extension"
|
|
23
|
+
"llm-gateway",
|
|
24
|
+
"ai-coding"
|
|
17
25
|
],
|
|
18
26
|
"author": "madgagarin (https://github.com/madgagarin)",
|
|
19
27
|
"license": "MIT",
|