pi-free 2.2.3 → 2.2.4

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/banner.svg CHANGED
@@ -88,28 +88,31 @@
88
88
  </g>
89
89
 
90
90
  <!-- Provider cards (right side) -->
91
- <g transform="translate(700, 55)">
92
- <rect x="0" y="0" width="250" height="170" rx="12" fill="url(#card1)" stroke="#7c3aed" stroke-width="0.5" stroke-opacity="0.2" filter="url(#shadow)"/>
93
- <rect x="0" y="0" width="250" height="170" rx="12" fill="none" stroke="url(#accent)" stroke-width="0.5" opacity="0.1"/>
94
- <text x="20" y="28" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#c4b5fd">Providers</text>
95
- <text x="20" y="50" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Kilo · Cline · OpenCode</text>
96
- <text x="20" y="70" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Ollama Cloud · SambaNova</text>
97
- <text x="20" y="90" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Codestral · LLM7 · Novita</text>
98
- <text x="20" y="110" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">ZenMux · CrofAI · DeepInfra</text>
99
- <text x="20" y="130" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Together · TokenRouter · b.ai</text>
91
+ <g transform="translate(700, 45)">
92
+ <rect x="0" y="0" width="250" height="200" rx="12" fill="url(#card1)" stroke="#7c3aed" stroke-width="0.5" stroke-opacity="0.2" filter="url(#shadow)"/>
93
+ <rect x="0" y="0" width="250" height="200" rx="12" fill="none" stroke="url(#accent)" stroke-width="0.5" opacity="0.1"/>
94
+ <text x="20" y="26" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#c4b5fd">Providers</text>
95
+ <text x="20" y="46" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Kilo · Cline · OpenCode</text>
96
+ <text x="20" y="66" font-family="system-ui, sans-serif" font-size="11" fill="#a78bfa">OpenModel · AgentRouter</text>
97
+ <text x="20" y="86" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Ollama Cloud · SambaNova</text>
98
+ <text x="20" y="106" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Codestral · LLM7 · Novita</text>
99
+ <text x="20" y="126" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">ZenMux · CrofAI · DeepInfra</text>
100
+ <text x="20" y="146" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Together · TokenRouter · FastRouter</text>
101
+ <text x="20" y="166" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">+ dynamic (Mistral, Groq, …)</text>
100
102
  </g>
101
103
 
102
- <g transform="translate(970, 55)">
103
- <rect x="0" y="0" width="250" height="170" rx="12" fill="url(#card2)" stroke="#06b6d4" stroke-width="0.5" stroke-opacity="0.2" filter="url(#shadow)"/>
104
- <rect x="0" y="0" width="250" height="170" rx="12" fill="none" stroke="url(#accent2)" stroke-width="0.5" opacity="0.1"/>
105
- <text x="20" y="28" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#67e8f9">Features</text>
106
- <text x="20" y="50" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Free model auto-detection</text>
107
- <text x="20" y="68" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Per-provider toggles</text>
108
- <text x="20" y="86" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">OAuth flows (Kilo, Cline)</text>
109
- <text x="20" y="104" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Coding Index (CI) scores</text>
110
- <text x="20" y="122" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Model health probes</text>
111
- <text x="20" y="140" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Thinking level maps</text>
112
- <text x="20" y="158" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">404/403 auto-hide on probe</text>
104
+ <g transform="translate(970, 45)">
105
+ <rect x="0" y="0" width="250" height="200" rx="12" fill="url(#card2)" stroke="#06b6d4" stroke-width="0.5" stroke-opacity="0.2" filter="url(#shadow)"/>
106
+ <rect x="0" y="0" width="250" height="200" rx="12" fill="none" stroke="url(#accent2)" stroke-width="0.5" opacity="0.1"/>
107
+ <text x="20" y="26" font-family="system-ui, sans-serif" font-size="13" font-weight="700" fill="#67e8f9">Features</text>
108
+ <text x="20" y="46" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Free model auto-detection</text>
109
+ <text x="20" y="64" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Per-provider toggles</text>
110
+ <text x="20" y="82" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">OAuth flows (Kilo, Cline)</text>
111
+ <text x="20" y="100" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Coding Index (CI) scores</text>
112
+ <text x="20" y="118" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Model health probes</text>
113
+ <text x="20" y="136" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">Thinking level maps</text>
114
+ <text x="20" y="154" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">404/403 auto-hide on probe</text>
115
+ <text x="20" y="172" font-family="system-ui, sans-serif" font-size="11" fill="#8b9aaa">+ dynamic built-in fetch</text>
113
116
  </g>
114
117
 
115
118
  <!-- Bottom tagline -->
package/config.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  PROVIDER_KILO,
19
19
  PROVIDER_OLLAMA,
20
20
  PROVIDER_OPENCODE,
21
+ PROVIDER_OPENMODEL,
21
22
  PROVIDER_OPENROUTER,
22
23
  PROVIDER_ROUTEWAY,
23
24
  PROVIDER_TOKENROUTER,
@@ -72,6 +73,9 @@ interface PiFreeConfig {
72
73
  fastrouter_api_key?: string;
73
74
  tokenrouter_api_key?: string;
74
75
  bai_api_key?: string;
76
+ openmodel_api_key?: string;
77
+ kilo_api_key?: string;
78
+ cline_api_key?: string;
75
79
  kilo_free_only?: boolean;
76
80
  hidden_models?: string[];
77
81
  free_only?: boolean;
@@ -90,6 +94,7 @@ interface PiFreeConfig {
90
94
  fastrouter_show_paid?: boolean;
91
95
  tokenrouter_show_paid?: boolean;
92
96
  bai_show_paid?: boolean;
97
+ openmodel_show_paid?: boolean;
93
98
  openrouter_show_paid?: boolean;
94
99
  opencode_show_paid?: boolean;
95
100
  }
@@ -109,6 +114,9 @@ const CONFIG_TEMPLATE: PiFreeConfig = {
109
114
  fastrouter_api_key: "",
110
115
  tokenrouter_api_key: "",
111
116
  bai_api_key: "",
117
+ openmodel_api_key: "",
118
+ kilo_api_key: "",
119
+ cline_api_key: "",
112
120
 
113
121
  kilo_free_only: false,
114
122
  hidden_models: [],
@@ -128,6 +136,7 @@ const CONFIG_TEMPLATE: PiFreeConfig = {
128
136
  fastrouter_show_paid: false,
129
137
  tokenrouter_show_paid: false,
130
138
  bai_show_paid: false,
139
+ openmodel_show_paid: false,
131
140
  openrouter_show_paid: false,
132
141
  opencode_show_paid: false,
133
142
  };
@@ -262,19 +271,60 @@ const PROVIDER_META: readonly ProviderMeta[] = [
262
271
  { id: PROVIDER_CLINE, prefix: "CLINE", showPaidKey: "cline_show_paid" },
263
272
  { id: PROVIDER_ZENMUX, prefix: "ZENMUX", showPaidKey: "zenmux_show_paid" },
264
273
  { id: PROVIDER_CROFAI, prefix: "CROFAI", showPaidKey: "crofai_show_paid" },
265
- { id: PROVIDER_CODESTRAL, prefix: "CODESTRAL", showPaidKey: "codestral_show_paid" },
274
+ {
275
+ id: PROVIDER_CODESTRAL,
276
+ prefix: "CODESTRAL",
277
+ showPaidKey: "codestral_show_paid",
278
+ },
266
279
  { id: PROVIDER_LLM7, prefix: "LLM7", showPaidKey: "llm7_show_paid" },
267
- { id: PROVIDER_DEEPINFRA, prefix: "DEEPINFRA", showPaidKey: "deepinfra_show_paid" },
268
- { id: PROVIDER_SAMBANOVA, prefix: "SAMBANOVA", showPaidKey: "sambanova_show_paid" },
269
- { id: PROVIDER_TOGETHER, prefix: "TOGETHER", showPaidKey: "together_show_paid" },
280
+ {
281
+ id: PROVIDER_DEEPINFRA,
282
+ prefix: "DEEPINFRA",
283
+ showPaidKey: "deepinfra_show_paid",
284
+ },
285
+ {
286
+ id: PROVIDER_SAMBANOVA,
287
+ prefix: "SAMBANOVA",
288
+ showPaidKey: "sambanova_show_paid",
289
+ },
290
+ {
291
+ id: PROVIDER_TOGETHER,
292
+ prefix: "TOGETHER",
293
+ showPaidKey: "together_show_paid",
294
+ },
270
295
  { id: PROVIDER_NOVITA, prefix: "NOVITA", showPaidKey: "novita_show_paid" },
271
- { id: PROVIDER_ROUTEWAY, prefix: "ROUTEWAY", showPaidKey: "routeway_show_paid" },
272
- { id: PROVIDER_TOKENROUTER, prefix: "TOKENROUTER", showPaidKey: "tokenrouter_show_paid" },
296
+ {
297
+ id: PROVIDER_ROUTEWAY,
298
+ prefix: "ROUTEWAY",
299
+ showPaidKey: "routeway_show_paid",
300
+ },
301
+ {
302
+ id: PROVIDER_TOKENROUTER,
303
+ prefix: "TOKENROUTER",
304
+ showPaidKey: "tokenrouter_show_paid",
305
+ },
273
306
  { id: PROVIDER_BAI, prefix: "BAI", showPaidKey: "bai_show_paid" },
274
- { id: PROVIDER_FASTROUTER, prefix: "FASTROUTER", showPaidKey: "fastrouter_show_paid" },
307
+ {
308
+ id: PROVIDER_OPENMODEL,
309
+ prefix: "OPENMODEL",
310
+ showPaidKey: "openmodel_show_paid",
311
+ },
312
+ {
313
+ id: PROVIDER_FASTROUTER,
314
+ prefix: "FASTROUTER",
315
+ showPaidKey: "fastrouter_show_paid",
316
+ },
275
317
  { id: PROVIDER_OLLAMA, prefix: "OLLAMA", showPaidKey: "ollama_show_paid" },
276
- { id: PROVIDER_OPENROUTER, prefix: "OPENROUTER", showPaidKey: "openrouter_show_paid" },
277
- { id: PROVIDER_OPENCODE, prefix: "OPENCODE", showPaidKey: "opencode_show_paid" },
318
+ {
319
+ id: PROVIDER_OPENROUTER,
320
+ prefix: "OPENROUTER",
321
+ showPaidKey: "openrouter_show_paid",
322
+ },
323
+ {
324
+ id: PROVIDER_OPENCODE,
325
+ prefix: "OPENCODE",
326
+ showPaidKey: "opencode_show_paid",
327
+ },
278
328
  ];
279
329
 
280
330
  const PROVIDER_META_BY_ID = new Map(PROVIDER_META.map((m) => [m.id, m]));
@@ -288,7 +338,10 @@ function resolveShowPaidForProvider(providerId: string): boolean {
288
338
  if (!meta) return false;
289
339
  const cfg = loadConfigFile();
290
340
  const fileVal = cfg[meta.showPaidKey];
291
- return resolveBool(`${meta.prefix}_SHOW_PAID`, fileVal as boolean | undefined);
341
+ return resolveBool(
342
+ `${meta.prefix}_SHOW_PAID`,
343
+ fileVal as boolean | undefined,
344
+ );
292
345
  }
293
346
 
294
347
  // =============================================================================
@@ -359,6 +412,13 @@ export function getBaiShowPaid(): boolean {
359
412
  return resolveBool("BAI_SHOW_PAID", loadConfigFile().bai_show_paid);
360
413
  }
361
414
 
415
+ export function getOpenmodelShowPaid(): boolean {
416
+ return resolveBool(
417
+ "OPENMODEL_SHOW_PAID",
418
+ loadConfigFile().openmodel_show_paid,
419
+ );
420
+ }
421
+
362
422
  export function getFastrouterShowPaid(): boolean {
363
423
  return resolveBool(
364
424
  "FASTROUTER_SHOW_PAID",
@@ -453,6 +513,18 @@ export function getBaiApiKey(): string | undefined {
453
513
  return resolve("BAI_API_KEY", loadConfigFile().bai_api_key);
454
514
  }
455
515
 
516
+ export function getOpenmodelApiKey(): string | undefined {
517
+ return resolve("OPENMODEL_API_KEY", loadConfigFile().openmodel_api_key);
518
+ }
519
+
520
+ export function getKiloApiKey(): string | undefined {
521
+ return resolve("KILO_API_KEY", loadConfigFile().kilo_api_key);
522
+ }
523
+
524
+ export function getClineApiKey(): string | undefined {
525
+ return resolve("CLINE_API_KEY", loadConfigFile().cline_api_key);
526
+ }
527
+
456
528
  export function getOllamaApiKey(): string | undefined {
457
529
  return resolve("OLLAMA_API_KEY", loadConfigFile().ollama_api_key);
458
530
  }
package/constants.ts CHANGED
@@ -25,6 +25,8 @@ export const PROVIDER_NOVITA = "novita";
25
25
  export const PROVIDER_ROUTEWAY = "routeway";
26
26
  export const PROVIDER_TOKENROUTER = "tokenrouter";
27
27
  export const PROVIDER_BAI = "bai";
28
+ export const PROVIDER_OPENMODEL = "openmodel";
29
+ export const PROVIDER_QODER = "qoder";
28
30
 
29
31
  // Built-in pi providers that pi-free wraps with toggles
30
32
  export const PROVIDER_OPENROUTER = "openrouter";
@@ -49,6 +51,8 @@ export const ALL_UNIQUE_PROVIDERS = [
49
51
  PROVIDER_ROUTEWAY,
50
52
  PROVIDER_TOKENROUTER,
51
53
  PROVIDER_BAI,
54
+ PROVIDER_OPENMODEL,
55
+ PROVIDER_QODER,
52
56
  ] as const;
53
57
 
54
58
  // =============================================================================
@@ -73,7 +77,13 @@ export const BASE_URL_NOVITA = "https://api.novita.ai/openai/v1";
73
77
  export const BASE_URL_ROUTEWAY = "https://api.routeway.ai/v1";
74
78
  export const BASE_URL_TOKENROUTER = "https://api.tokenrouter.com/v1";
75
79
  export const BASE_URL_BAI = "https://api.b.ai/v1";
76
-
80
+ /**
81
+ * OpenModel is registered with `api: "anthropic-messages"`. The pi-ai
82
+ * Anthropic SDK appends `/v1/messages` to `baseURL`, so the base must
83
+ * NOT include `/v1`. See {@link PROVIDER_OPENMODEL}.
84
+ */
85
+ export const BASE_URL_OPENMODEL = "https://api.openmodel.ai";
86
+ export const BASE_URL_QODER = "https://api3.qoder.sh";
77
87
 
78
88
  /** Cline fetches free models from OpenRouter */
79
89
  export const BASE_URL_OPENROUTER = "https://openrouter.ai/api/v1";
package/index.ts CHANGED
@@ -44,6 +44,8 @@ import tokenRouter from "./providers/tokenrouter/tokenrouter.ts";
44
44
  import ollama from "./providers/ollama/ollama.ts";
45
45
  import zenmux from "./providers/zenmux/zenmux.ts";
46
46
  import bai from "./providers/bai/bai.ts";
47
+ import openmodel from "./providers/openmodel/openmodel.ts";
48
+ import qoder from "./providers/qoder/qoder.ts";
47
49
 
48
50
  /**
49
51
  * Single source of truth for unique provider extensions (providers NOT
@@ -68,6 +70,8 @@ const UNIQUE_PROVIDERS: ReadonlyArray<(pi: ExtensionAPI) => Promise<void>> = [
68
70
  routeway,
69
71
  tokenRouter,
70
72
  bai,
73
+ openmodel,
74
+ qoder,
71
75
  ];
72
76
 
73
77
  const _logger = createLogger("pi-free");
@@ -188,7 +192,17 @@ function setupGlobalCommands(pi: ExtensionAPI) {
188
192
 
189
193
  const lines = ["📊 Model Telemetry:", ""];
190
194
  lines.push(
191
- `${`Model`.padEnd(40)} ${`Calls`.padEnd(6)} ${`OK%`.padEnd(6)} ${`Lat`.padEnd(7)} ${`tok/s`.padEnd(7)} ${`Cost`}`,
195
+ "Model".padEnd(40) +
196
+ " " +
197
+ "Calls".padEnd(6) +
198
+ " " +
199
+ "OK%".padEnd(6) +
200
+ " " +
201
+ "Lat".padEnd(7) +
202
+ " " +
203
+ "tok/s".padEnd(7) +
204
+ " " +
205
+ "Cost",
192
206
  );
193
207
  lines.push(`─`.repeat(75));
194
208