@madgagarin/pi-agentrouter 2.0.0 → 2.1.1

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.
Files changed (3) hide show
  1. package/README.md +30 -28
  2. package/index.ts +205 -19
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  [![Pi Plugin](https://img.shields.io/badge/Pi-Extension-purple.svg)](https://pi.dev)
6
6
  [![AgentRouter Gateway](https://img.shields.io/badge/Gateway-agentrouter.org-orange.svg)](https://agentrouter.org)
7
7
 
8
- Use **GPT-5.6 Sol**, **Claude Opus 5**, **Claude Opus 4.8**, **DeepSeek V4 Flash**, and **GLM 5.3** in your [Pi Coding Agent](https://pi.dev) using a single API key from [AgentRouter](https://agentrouter.org).
8
+ Use **GPT-6 Astra**, **GPT-5.6 Sol**, **Claude Opus 5**, **Claude Opus 4.8**, and **DeepSeek V4 Flash** in your [Pi Coding Agent](https://pi.dev) using a single API key from [AgentRouter](https://agentrouter.org).
9
9
 
10
- > 🎁 **Free Trial Credits:** New to AgentRouter? Get up to **$175 in free credits** (including a **+$50 bonus**) to test GPT-5.6, Claude Opus 5, and DeepSeek V4 — no credit card needed. That's enough for **over 80,000,000 tokens** on DeepSeek V4!
10
+ > 🎁 **Free Trial Credits:** New to AgentRouter? Get up to **$175 in free credits** (including a **+$50 bonus**) to test GPT-6 Astra, Claude Opus 5, and DeepSeek V4 — no credit card needed. That's enough for **millions of tokens** on DeepSeek V4!
11
11
  > 👉 **[Claim your free trial credits on AgentRouter.org →](https://agentrouter.org/register?aff=34dc)**
12
12
 
13
13
  ---
@@ -34,48 +34,49 @@ pi install npm:@madgagarin/pi-agentrouter
34
34
 
35
35
  ---
36
36
 
37
- ## Why use this plugin?
37
+ ## Features
38
38
 
39
- [AgentRouter](https://agentrouter.org) ([agentrouter.org](https://agentrouter.org)) provides affordable unified access to frontier LLMs, but using raw OpenAI/Anthropic proxy configurations in Pi often runs into edge cases: Cloudflare WAF checks, rate-limit bursts from parallel subagents, prompt caching cache misses, and role naming conflicts.
40
-
41
- This plugin fixes all of that automatically:
42
-
43
- - **Live USD Pricing in Pi:** Pulls current rates from [agentrouter.org/api/pricing](https://agentrouter.org/api/pricing) on startup so Pi's built-in cost tracking shows your exact spend in dollars.
44
- - **Live Quota Monitor (`/agentrouter check`):** Quick health check that pings all models to see if daily batch quotas are open, and displays your monthly usage in USD.
45
- - **1M Context Windows:** All models are configured with their full 1,048,576 token context limits and native reasoning/adaptive thinking.
46
- - **Cross-Process Rate Pacing:** Uses a shared lock file (`~/.pi/agent/.agentrouter-pacing`) so background subagents (`pi-subagents`) and the main chat won't trip 429 rate limits.
47
- - **Zero 400 & 401 Errors:** Handles canonical `pi-code` prompt header placement for WAF authorization and automatically normalizes OpenAI `developer` roles to `system`.
48
- - **High Cache Hit Rates (>80%):** Preserves session affinity headers and disables destructive prompt rewriting on AgentRouter routes.
39
+ - **Model Synchronization:** Automatically registers and adds active models to `enabledModels` in `settings.json` for quick selection via `Ctrl+P`.
40
+ - **DeepSeek Multi-Turn Tool Calling:** Preserves `reasoning_content` and handles thinking blocks across multi-step tool execution, avoiding API 400 errors.
41
+ - **Schema Sanitization:** Automatically normalizes tool definitions (e.g. converting `required: null` to empty arrays) for strict OpenAI schema validation compatibility.
42
+ - **WAF Diagnostics:** Intercepts upstream `content-blocked` responses and displays a clear notification in the terminal and UI.
43
+ - **Dual Endpoint Protocols:** Supports both OpenAI (`agentrouter-openai`) and Anthropic Messages API (`agentrouter-clode`) routes for models like `deepseek-v4-flash`.
44
+ - **Isolated Credential Storage:** Manages API keys exclusively within `agentrouter-*` provider namespaces in `auth.json` without modifying default third-party provider keys.
45
+ - **Live Pricing & Quota Probing:** Fetches current rates from the gateway API on startup and provides `/agentrouter check` to probe model availability and track usage.
46
+ - **Subagent Rate Pacing:** Uses a file-based lock (`~/.pi/agent/.agentrouter-pacing`) across concurrent subagents to prevent 429 rate limit errors.
47
+ - **Prompt Caching Compatibility:** Preserves affinity headers and formatting required for upstream prompt cache reuse.
49
48
 
50
49
  ---
51
50
 
52
51
  ## Models & Pricing
53
52
 
54
- Rates are pulled directly from the [agentrouter.org](https://agentrouter.org) gateway API ($2.00 / 1M tokens base unit):
53
+ Rates are fetched from the [agentrouter.org](https://agentrouter.org) gateway API ($2.00 / 1M tokens base unit):
55
54
 
56
55
  | Model | Provider | Context | Output | Reasoning | Input / 1M | Output / 1M | Quota Policy |
57
56
  | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
58
- | `deepseek-v4-flash` | `agentrouter-openai` | 1M | 64K | Yes | $2.00 | $6.00 | Unlimited |
57
+ | `deepseek-v4-flash` | `agentrouter-openai` / `agentrouter-clode` | 1M | 64K | Yes | $4.00 | $12.00 | Unlimited |
59
58
  | `glm-5.3` | `agentrouter-openai` | 1M | 128K | Yes | $3.00 | $12.00 | Unlimited |
59
+ | `gpt-6-astra` | `agentrouter-openai` | 1M | 128K | Yes | $3.00 | $15.00 | Daily batch drops |
60
60
  | `gpt-5.6-sol` | `agentrouter-openai` | 1M | 128K | Yes | $3.00 | $15.00 | Daily batch drops |
61
- | `claude-opus-5` | `agentrouter-clode` | 1M | 64K | Yes (Adaptive) | $8.00 | $40.00 | Daily batch drops |
61
+ | `claude-opus-5` | `agentrouter-clode` | 1M | 64K | Yes (Adaptive) | $6.00 | $30.00 | Daily batch drops |
62
62
  | `claude-opus-4-8` | `agentrouter-clode` | 1M | 64K | Yes (Adaptive) | $8.00 | $40.00 | Daily batch drops |
63
63
 
64
- *Note: Claude and GPT models are released in daily batches on AgentRouter. If you hit a 402, run `/agentrouter check` to verify, and switch to `deepseek-v4-flash` or `glm-5.3` for unlimited coding.*
64
+ *Note: Claude and GPT models are released in daily batches on AgentRouter. When a batch is exhausted (HTTP 402), use `/agentrouter check` to monitor status or switch to `deepseek-v4-flash` / `glm-5.3` for unrestricted usage.*
65
65
 
66
66
  ---
67
67
 
68
68
  ## In-Chat Commands
69
69
 
70
- | Command | What it does |
70
+ | Command | Description |
71
71
  | :--- | :--- |
72
- | `/agentrouter` | Overview of active model, current monthly USD spend, package order, and pacing delay. |
73
- | `/agentrouter check` | Live preflight probe of all model quotas (200 OK vs 402) and monthly usage. |
74
- | `/agentrouter pricing` | Fetches and prints the latest official pricing table from [agentrouter.org](https://agentrouter.org). |
75
- | `/agentrouter key <key>` | Sets API key and syncs it across `agentrouter.json` and Pi's `auth.json`. |
76
- | `/agentrouter pacing <ms>` | Sets delay between consecutive requests (default: `3500` ms). |
77
- | `/agentrouter fix-order` | Places this plugin above `pi-cache-optimizer` in `settings.json` if needed. |
78
- | `/compact` | Compresses chat history safely without 401 authorization drops. |
72
+ | `/agentrouter` | Show active model, current monthly spend, extension ordering, and pacing delay. |
73
+ | `/agentrouter check` | Probe model availability (200 OK vs 402) and display monthly usage. |
74
+ | `/agentrouter pricing` | Display current pricing table from [agentrouter.org](https://agentrouter.org). |
75
+ | `/agentrouter sync` | Sync active flagship models into `enabledModels` in `settings.json`. |
76
+ | `/agentrouter key <key>` | Set API key and store it in `agentrouter.json` and `auth.json`. |
77
+ | `/agentrouter pacing <ms>` | Configure delay between requests (default: `3500` ms). |
78
+ | `/agentrouter fix-order` | Reorder extension before `pi-cache-optimizer` in `settings.json` if necessary. |
79
+ | `/compact` | Compact conversation history while preserving required gateway headers. |
79
80
 
80
81
  ---
81
82
 
@@ -83,7 +84,7 @@ Rates are pulled directly from the [agentrouter.org](https://agentrouter.org) ga
83
84
 
84
85
  | Shortcut | Action |
85
86
  | :--- | :--- |
86
- | `Ctrl + P` | Cycle to next model (`deepseek-v4-flash` ➔ `glm-5.3` ➔ `gpt-5.6-sol` ➔ `claude-opus-5` ➔ `claude-opus-4-8`) |
87
+ | `Ctrl + P` | Cycle to next model (`deepseek-v4-flash` ➔ `gpt-6-astra` ➔ `gpt-5.6-sol` ➔ `claude-opus-5` ➔ `claude-opus-4-8`) |
87
88
  | `Shift + Ctrl + P` | Cycle to previous model |
88
89
  | `Shift + Tab` | Toggle reasoning depth (`off` ➔ `minimal` ➔ `low` ➔ `medium` ➔ `high`) |
89
90
  | `Ctrl + T` | Toggle reasoning block visibility |
@@ -93,7 +94,7 @@ Rates are pulled directly from the [agentrouter.org](https://agentrouter.org) ga
93
94
 
94
95
  ## Recommended `settings.json`
95
96
 
96
- Add this to `~/.pi/agent/settings.json` for convenient model switching:
97
+ Add this to `~/.pi/agent/settings.json` for model switching:
97
98
 
98
99
  ```json
99
100
  {
@@ -102,7 +103,7 @@ Add this to `~/.pi/agent/settings.json` for convenient model switching:
102
103
  "defaultThinkingLevel": "low",
103
104
  "enabledModels": [
104
105
  "agentrouter-openai/deepseek-v4-flash",
105
- "agentrouter-openai/glm-5.3",
106
+ "agentrouter-openai/gpt-6-astra",
106
107
  "agentrouter-openai/gpt-5.6-sol",
107
108
  "agentrouter-clode/claude-opus-5",
108
109
  "agentrouter-clode/claude-opus-4-8"
@@ -128,3 +129,4 @@ AgentRouter requires the base `pi-code` prompt signature for authentication. If
128
129
  ## License
129
130
 
130
131
  MIT © [madgagarin](https://github.com/madgagarin)
132
+
package/index.ts CHANGED
@@ -41,6 +41,16 @@ export interface ApiPricingModel {
41
41
  }
42
42
 
43
43
  export const KNOWN_MODEL_SPECS: Record<string, ModelSpec> = {
44
+ "gpt-6-astra": {
45
+ id: "gpt-6-astra",
46
+ name: "gpt-6-astra",
47
+ providerType: "openai",
48
+ contextWindow: 1048576,
49
+ maxTokens: 131072,
50
+ reasoning: true,
51
+ compat: { sendSessionAffinityHeaders: true },
52
+ cost: { input: 3.0 / 1_000_000, output: 15.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
53
+ },
44
54
  "deepseek-v4-flash": {
45
55
  id: "deepseek-v4-flash",
46
56
  name: "deepseek-v4-flash",
@@ -49,7 +59,7 @@ export const KNOWN_MODEL_SPECS: Record<string, ModelSpec> = {
49
59
  maxTokens: 65536,
50
60
  reasoning: true,
51
61
  compat: { sendSessionAffinityHeaders: true },
52
- cost: { input: 2.0 / 1_000_000, output: 6.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
62
+ cost: { input: 4.0 / 1_000_000, output: 12.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
53
63
  },
54
64
  "deepseek-v4f": {
55
65
  id: "deepseek-v4f",
@@ -59,7 +69,7 @@ export const KNOWN_MODEL_SPECS: Record<string, ModelSpec> = {
59
69
  maxTokens: 65536,
60
70
  reasoning: true,
61
71
  compat: { sendSessionAffinityHeaders: true },
62
- cost: { input: 2.0 / 1_000_000, output: 6.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
72
+ cost: { input: 4.0 / 1_000_000, output: 12.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
63
73
  },
64
74
  "glm-5.3": {
65
75
  id: "glm-5.3",
@@ -129,7 +139,7 @@ export const KNOWN_MODEL_SPECS: Record<string, ModelSpec> = {
129
139
  sendSessionAffinityHeaders: true,
130
140
  supportsEagerToolInputStreaming: false,
131
141
  },
132
- cost: { input: 8.0 / 1_000_000, output: 40.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
142
+ cost: { input: 6.0 / 1_000_000, output: 30.0 / 1_000_000, cacheRead: 0, cacheWrite: 0 },
133
143
  },
134
144
  "claude-opus-4-7": {
135
145
  id: "claude-opus-4-7",
@@ -197,7 +207,6 @@ export function saveConfig(cfg: AgentRouterConfig): void {
197
207
  }
198
208
  auth["agentrouter-openai"] = { type: "api_key", key: cfg.apiKey };
199
209
  auth["agentrouter-clode"] = { type: "api_key", key: cfg.apiKey };
200
- auth["anthropic"] = { type: "api_key", key: cfg.apiKey };
201
210
  fs.writeFileSync(authPath, JSON.stringify(auth, null, 2), "utf-8");
202
211
  }
203
212
  } catch {}
@@ -272,6 +281,36 @@ export function fixPackagePriorityInSettings(): boolean {
272
281
  return false;
273
282
  }
274
283
 
284
+ export const FLAGSHIP_MODELS: string[] = [
285
+ "agentrouter-openai/deepseek-v4-flash",
286
+ "agentrouter-openai/gpt-6-astra",
287
+ "agentrouter-openai/gpt-5.6-sol",
288
+ "agentrouter-clode/claude-opus-5",
289
+ "agentrouter-clode/claude-opus-4-8",
290
+ ];
291
+
292
+ export function syncEnabledModelsInSettings(): { added: string[]; count: number } {
293
+ try {
294
+ if (!fs.existsSync(SETTINGS_FILE)) return { added: [], count: 0 };
295
+ const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, "utf-8"));
296
+ if (!Array.isArray(settings.enabledModels)) return { added: [], count: 0 };
297
+
298
+ const added: string[] = [];
299
+ for (const m of FLAGSHIP_MODELS) {
300
+ if (!settings.enabledModels.includes(m)) {
301
+ settings.enabledModels.push(m);
302
+ added.push(m);
303
+ }
304
+ }
305
+ if (added.length > 0) {
306
+ fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
307
+ }
308
+ return { added, count: settings.enabledModels.length };
309
+ } catch {
310
+ return { added: [], count: 0 };
311
+ }
312
+ }
313
+
275
314
  export function getLastRequestEndTime(): number {
276
315
  try {
277
316
  if (fs.existsSync(PACING_FILE)) {
@@ -338,6 +377,107 @@ export function enforceCanonicalRootPrompt(systemPrompt: string | any[] | undefi
338
377
  return systemPrompt;
339
378
  }
340
379
 
380
+ export function cleanJsonSchemaObject(schema: any): void {
381
+ if (!schema || typeof schema !== "object") return;
382
+
383
+ if (schema.type === "object" || schema.properties) {
384
+ if (schema.required === null || schema.required === undefined || !Array.isArray(schema.required)) {
385
+ schema.required = [];
386
+ }
387
+ }
388
+
389
+ if (schema.properties && typeof schema.properties === "object") {
390
+ for (const [propName, propDef] of Object.entries(schema.properties)) {
391
+ if (propDef && typeof propDef === "object") {
392
+ cleanJsonSchemaObject(propDef);
393
+ }
394
+ }
395
+ }
396
+
397
+ if (schema.items) {
398
+ if (typeof schema.items === "object") {
399
+ cleanJsonSchemaObject(schema.items);
400
+ } else if (schema.items === null) {
401
+ delete schema.items;
402
+ }
403
+ }
404
+ }
405
+
406
+ export function sanitizeOpenAiTools(tools: any[]): void {
407
+ if (!Array.isArray(tools)) return;
408
+ for (const tool of tools) {
409
+ if (!tool || typeof tool !== "object") continue;
410
+ const fn = tool.function || tool;
411
+ if (fn.parameters && typeof fn.parameters === "object") {
412
+ cleanJsonSchemaObject(fn.parameters);
413
+ }
414
+ }
415
+ }
416
+
417
+ export function normalizeMessagesForAgentRouter(messages: any[]): void {
418
+ if (!Array.isArray(messages)) return;
419
+ for (const msg of messages) {
420
+ if (!msg || typeof msg !== "object") continue;
421
+ if (msg.role === "developer") {
422
+ msg.role = "system";
423
+ }
424
+ if (msg.role === "assistant") {
425
+ let extractedThinking: string | undefined;
426
+
427
+ if (Array.isArray(msg.content)) {
428
+ const thinkingParts: string[] = [];
429
+ const nonThinkingParts: any[] = [];
430
+
431
+ for (const part of msg.content) {
432
+ if (part && typeof part === "object" && (part.type === "thinking" || part.type === "reasoning")) {
433
+ const text = part.thinking || part.text;
434
+ if (text) thinkingParts.push(text);
435
+ } else {
436
+ nonThinkingParts.push(part);
437
+ }
438
+ }
439
+
440
+ if (thinkingParts.length > 0) {
441
+ extractedThinking = thinkingParts.join("\n");
442
+ }
443
+
444
+ if (nonThinkingParts.length === 0) {
445
+ msg.content = "";
446
+ } else if (nonThinkingParts.length === 1 && nonThinkingParts[0].type === "text") {
447
+ msg.content = nonThinkingParts[0].text;
448
+ } else {
449
+ msg.content = nonThinkingParts;
450
+ }
451
+ }
452
+
453
+ if (extractedThinking && !msg.reasoning_content) {
454
+ msg.reasoning_content = extractedThinking;
455
+ }
456
+
457
+ // If assistant executed tool calls, AgentRouter DeepSeek proxy strictly requires reasoning_content
458
+ if (Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && !msg.reasoning_content) {
459
+ msg.reasoning_content = "Executing tools...";
460
+ }
461
+ }
462
+ }
463
+ }
464
+
465
+ let lastWarnedErrorTimestamp = 0;
466
+ export function checkAndNotifyContentBlocked(errMessage: string | undefined, ctx: any): void {
467
+ if (!errMessage) return;
468
+ const now = Date.now();
469
+ if (now - lastWarnedErrorTimestamp < 2000) return;
470
+ if (errMessage.includes("content-blocked")) {
471
+ lastWarnedErrorTimestamp = now;
472
+ const tip = "[AgentRouter] Request was blocked by upstream gateway content filter (content-blocked).";
473
+ if (ctx?.hasUI) {
474
+ ctx.ui.notify(tip, "warning");
475
+ } else {
476
+ console.warn(`\n⚠️ ${tip}\n`);
477
+ }
478
+ }
479
+ }
480
+
341
481
  export async function fetchLivePricing(): Promise<ApiPricingModel[] | null> {
342
482
  try {
343
483
  const res = await fetch("https://agentrouter.org/api/pricing", {
@@ -427,10 +567,12 @@ export async function probeModelQuota(modelId: string, apiKey: string, isAnthrop
427
567
  return { model: modelId, status: "READY", code: res.status };
428
568
  }
429
569
 
430
- const data = await res.json().catch(() => ({}));
431
- const msg = data.error?.message || data.message || "";
432
-
433
- if (res.status === 402 || msg.toLowerCase().includes("quota") || msg.toLowerCase().includes("exhausted")) {
570
+ if (
571
+ res.status === 402 ||
572
+ msg.toLowerCase().includes("quota") ||
573
+ msg.toLowerCase().includes("exhausted") ||
574
+ msg.toLowerCase().includes("budget pool")
575
+ ) {
434
576
  return { model: modelId, status: "QUOTA_EXHAUSTED", code: 402, message: msg };
435
577
  }
436
578
  if (res.status === 403) {
@@ -487,6 +629,17 @@ export default function (pi: ExtensionAPI) {
487
629
  } else {
488
630
  openaiModels.push(modelObj);
489
631
  }
632
+ if (spec.id === "deepseek-v4-flash" && item.supported_endpoint_types.includes("anthropic")) {
633
+ claudeModels.push({
634
+ ...modelObj,
635
+ compat: {
636
+ forceAdaptiveThinking: true,
637
+ allowEmptySignature: true,
638
+ sendSessionAffinityHeaders: true,
639
+ supportsEagerToolInputStreaming: false,
640
+ },
641
+ });
642
+ }
490
643
  } else {
491
644
  newModels.push(id);
492
645
  const isAnthropic =
@@ -535,6 +688,17 @@ export default function (pi: ExtensionAPI) {
535
688
  } else {
536
689
  openaiModels.push(modelObj);
537
690
  }
691
+ if (spec.id === "deepseek-v4-flash") {
692
+ claudeModels.push({
693
+ ...modelObj,
694
+ compat: {
695
+ forceAdaptiveThinking: true,
696
+ allowEmptySignature: true,
697
+ sendSessionAffinityHeaders: true,
698
+ supportsEagerToolInputStreaming: false,
699
+ },
700
+ });
701
+ }
538
702
  }
539
703
  }
540
704
 
@@ -602,11 +766,8 @@ export default function (pi: ExtensionAPI) {
602
766
  payload.system = enforceCanonicalRootPrompt(payload.system);
603
767
  }
604
768
  if (Array.isArray(payload.messages) && payload.messages.length > 0) {
605
- for (const msg of payload.messages) {
606
- if (msg && msg.role === "developer") {
607
- msg.role = "system";
608
- }
609
- }
769
+ normalizeMessagesForAgentRouter(payload.messages);
770
+
610
771
  const firstMsg = payload.messages[0];
611
772
  if (firstMsg && (firstMsg.role === "system" || firstMsg.role === "developer")) {
612
773
  firstMsg.role = "system";
@@ -617,22 +778,33 @@ export default function (pi: ExtensionAPI) {
617
778
  }
618
779
  }
619
780
  }
781
+ if (Array.isArray(payload.tools) && payload.tools.length > 0) {
782
+ sanitizeOpenAiTools(payload.tools);
783
+ }
620
784
  }
621
785
  }
622
786
  return undefined;
623
787
  });
624
788
 
625
- pi.on("message_end", async (_event, ctx) => {
789
+ pi.on("message_end", async (event, ctx) => {
626
790
  const model = ctx?.model;
627
791
  if (isAgentRouter(model?.provider, (model as any)?.baseUrl)) {
628
792
  setLastRequestEndTime(Date.now());
793
+ const msg = (event as any)?.message;
794
+ if (msg && msg.role === "assistant" && msg.stopReason === "error") {
795
+ checkAndNotifyContentBlocked(msg.errorMessage, ctx);
796
+ }
629
797
  }
630
798
  });
631
799
 
632
- pi.on("turn_end", async (_event, ctx) => {
800
+ pi.on("turn_end", async (event, ctx) => {
633
801
  const model = ctx?.model;
634
802
  if (isAgentRouter(model?.provider, (model as any)?.baseUrl)) {
635
803
  setLastRequestEndTime(Date.now());
804
+ const msg = (event as any)?.message;
805
+ if (msg && msg.role === "assistant" && msg.stopReason === "error") {
806
+ checkAndNotifyContentBlocked(msg.errorMessage, ctx);
807
+ }
636
808
  }
637
809
  });
638
810
 
@@ -647,11 +819,13 @@ export default function (pi: ExtensionAPI) {
647
819
  currentApiKey = getEffectiveApiKey();
648
820
  updatePromptRewriteEnvForModel(ctx.model);
649
821
  setLastRequestEndTime(Date.now());
822
+ syncEnabledModelsInSettings();
650
823
 
651
824
  fetchLivePricing().then((livePricing) => {
652
825
  if (livePricing) {
653
826
  saveCachedPricing(livePricing);
654
827
  const newModels = registerAgentRouterProviders(currentApiKey, livePricing);
828
+ syncEnabledModelsInSettings();
655
829
  if (newModels.length > 0 && ctx.hasUI) {
656
830
  ctx.ui.notify(
657
831
  `[AgentRouter] Discovered new models on gateway: ${newModels.join(", ")}.\n` +
@@ -798,10 +972,21 @@ export default function (pi: ExtensionAPI) {
798
972
  currentApiKey = cleanKey;
799
973
  saveConfig({ apiKey: cleanKey, minIntervalMs });
800
974
  registerAgentRouterProviders(cleanKey, loadCachedPricing());
975
+ syncEnabledModelsInSettings();
801
976
  ctx.ui.notify("AgentRouter API key updated successfully for all models.", "info");
802
977
  return;
803
978
  }
804
979
 
980
+ if (action === "sync" || action === "enable-models") {
981
+ const res = syncEnabledModelsInSettings();
982
+ if (res.added.length > 0) {
983
+ ctx.ui.notify(`[AgentRouter] Added to enabledModels: ${res.added.join(", ")} (total: ${res.count}).`, "info");
984
+ } else {
985
+ ctx.ui.notify(`[AgentRouter] All flagship models already enabled in settings.json (total: ${res.count}).`, "info");
986
+ }
987
+ return;
988
+ }
989
+
805
990
  if (action === "fix-order" || action === "order") {
806
991
  const order = getPackageOrderState();
807
992
  if (!order.needsFix) {
@@ -893,10 +1078,10 @@ export default function (pi: ExtensionAPI) {
893
1078
  }))
894
1079
  : [
895
1080
  { id: "deepseek-v4-flash", isAnthropic: false },
896
- { id: "glm-5.3", isAnthropic: false },
1081
+ { id: "gpt-6-astra", isAnthropic: false },
897
1082
  { id: "gpt-5.6-sol", isAnthropic: false },
898
- { id: "claude-opus-4-8", isAnthropic: true },
899
1083
  { id: "claude-opus-5", isAnthropic: true },
1084
+ { id: "claude-opus-4-8", isAnthropic: true },
900
1085
  ];
901
1086
 
902
1087
  const probeResults = await Promise.all(
@@ -924,7 +1109,7 @@ export default function (pi: ExtensionAPI) {
924
1109
  }
925
1110
 
926
1111
  report +=
927
- `\nTip: Claude and GPT models use daily batch quotas. If exhausted, switch to DeepSeek V4 or GLM 5.3 which have unlimited availability.`;
1112
+ `\nTip: Claude and GPT models use daily batch quotas. If exhausted, switch to DeepSeek V4 Flash which has unlimited availability.`;
928
1113
 
929
1114
  ctx.ui.notify(report, "info");
930
1115
  return;
@@ -948,7 +1133,7 @@ export default function (pi: ExtensionAPI) {
948
1133
  }
949
1134
 
950
1135
  ctx.ui.notify(
951
- `[AgentRouter Plugin v2.0.0]\n` +
1136
+ `[AgentRouter Plugin v2.1.1]\n` +
952
1137
  `- Active model: ${activeModel?.id || "none"} (${isAR ? "AgentRouter [yes]" : "Other Provider"})\n` +
953
1138
  `- Package Priority: ${priorityStatus}\n` +
954
1139
  `- API Key: ${maskedKey}\n` +
@@ -956,6 +1141,7 @@ export default function (pi: ExtensionAPI) {
956
1141
  `- Commands:\n` +
957
1142
  ` /agentrouter check (probe live batch quotas & spending)\n` +
958
1143
  ` /agentrouter pricing (fetch live pricing table $/1M)\n` +
1144
+ ` /agentrouter sync (sync enabledModels in settings.json)\n` +
959
1145
  ` /agentrouter key <key> (update API key)\n` +
960
1146
  ` /agentrouter pacing <ms> (adjust rate limit delay)\n` +
961
1147
  ` /agentrouter fix-order (move plugin above pi-cache-optimizer)`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@madgagarin/pi-agentrouter",
3
- "version": "2.0.0",
4
- "description": "Official Pi Coding Agent extension for AgentRouter (agentrouter.org). Connects GPT-5.6 Sol, Claude Opus 5, DeepSeek V4 Flash, and GLM 5.3 with live USD pricing, batch quota health probe, prompt caching, and WAF protection.",
3
+ "version": "2.1.1",
4
+ "description": "Official Pi Coding Agent extension for AgentRouter (agentrouter.org). Connects GPT-6 Astra, GPT-5.6 Sol, Claude Opus 5, DeepSeek V4 Flash, and GLM 5.3 with live USD pricing, auto-sync settings, batch quota probe, prompt caching, and WAF protection.",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -15,6 +15,8 @@
15
15
  "agentrouter-org",
16
16
  "agent-router",
17
17
  "pi-agentrouter",
18
+ "gpt-6-astra",
19
+ "gpt-6",
18
20
  "gpt-5.6-sol",
19
21
  "claude-opus-5",
20
22
  "claude-opus-4-8",