pi-free 1.0.8 → 2.0.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +107 -1
  2. package/README.md +95 -46
  3. package/config.ts +165 -120
  4. package/constants.ts +22 -61
  5. package/index.ts +186 -0
  6. package/lib/json-persistence.ts +11 -10
  7. package/lib/logger.ts +2 -2
  8. package/lib/model-enhancer.ts +20 -20
  9. package/lib/open-browser.ts +41 -0
  10. package/lib/provider-cache.ts +106 -0
  11. package/lib/registry.ts +144 -0
  12. package/package.json +67 -82
  13. package/provider-factory.ts +25 -41
  14. package/provider-failover/benchmark-lookup.ts +247 -0
  15. package/provider-failover/benchmarks-chunk-0.ts +2010 -0
  16. package/provider-failover/benchmarks-chunk-1.ts +1988 -0
  17. package/provider-failover/benchmarks-chunk-2.ts +2010 -0
  18. package/provider-failover/benchmarks-chunk-3.ts +2010 -0
  19. package/provider-failover/benchmarks-chunk-4.ts +1969 -0
  20. package/provider-failover/hardcoded-benchmarks.ts +22 -10025
  21. package/provider-helper.ts +38 -37
  22. package/providers/{cline-auth.ts → cline/cline-auth.ts} +2 -2
  23. package/providers/cline/cline-models.ts +128 -0
  24. package/providers/{cline.ts → cline/cline.ts} +300 -257
  25. package/providers/cloudflare/cloudflare.ts +368 -0
  26. package/providers/dynamic-built-in/index.ts +513 -0
  27. package/providers/{kilo-auth.ts → kilo/kilo-auth.ts} +3 -20
  28. package/providers/{kilo-models.ts → kilo/kilo-models.ts} +2 -2
  29. package/providers/kilo/kilo.ts +235 -0
  30. package/providers/{modal.ts → modal/modal.ts} +4 -3
  31. package/providers/{nvidia.ts → nvidia/nvidia.ts} +152 -113
  32. package/providers/ollama/ollama.ts +172 -0
  33. package/providers/opencode-session.ts +34 -34
  34. package/providers/{qwen-auth.ts → qwen/qwen-auth.ts} +24 -40
  35. package/providers/{qwen-models.ts → qwen/qwen-models.ts} +101 -95
  36. package/providers/qwen/qwen.ts +202 -0
  37. package/provider-failover/auto-switch.ts +0 -350
  38. package/provider-failover/errors.ts +0 -275
  39. package/provider-failover/index.ts +0 -238
  40. package/providers/cline-models.ts +0 -77
  41. package/providers/factory.ts +0 -125
  42. package/providers/fireworks.ts +0 -49
  43. package/providers/go.ts +0 -216
  44. package/providers/kilo.ts +0 -146
  45. package/providers/mistral.ts +0 -144
  46. package/providers/ollama.ts +0 -113
  47. package/providers/openrouter.ts +0 -175
  48. package/providers/qwen.ts +0 -127
  49. package/providers/zen.ts +0 -371
  50. package/usage/commands.ts +0 -17
  51. package/usage/cumulative.ts +0 -193
  52. package/usage/formatters.ts +0 -115
  53. package/usage/index.ts +0 -46
  54. package/usage/limits.ts +0 -148
  55. package/usage/metrics.ts +0 -222
  56. package/usage/sessions.ts +0 -355
  57. package/usage/store.ts +0 -99
  58. package/usage/tracking.ts +0 -329
  59. package/usage/types.ts +0 -26
  60. package/usage/widget.ts +0 -90
  61. package/widget/data.ts +0 -113
  62. package/widget/format.ts +0 -26
  63. package/widget/render.ts +0 -117
@@ -1,193 +0,0 @@
1
- /**
2
- * Cumulative usage persistence - disk storage for all-time stats
3
- */
4
-
5
- import { join } from "node:path";
6
- import { createJSONStore } from "../lib/json-persistence.ts";
7
- import { createLogger } from "../lib/logger.ts";
8
-
9
- const _logger = createLogger("usage:cumulative");
10
-
11
- const PI_DIR = join(process.env.HOME || process.env.USERPROFILE || "", ".pi");
12
- const USAGE_FILE = join(PI_DIR, "free-cumulative-usage.json");
13
-
14
- interface CumulativeProviderStats {
15
- totalRequests: number;
16
- totalTokensIn: number;
17
- totalTokensOut: number;
18
- totalCacheRead: number;
19
- totalCacheWrite: number;
20
- totalCost: number;
21
- models: Record<
22
- string,
23
- {
24
- count: number;
25
- tokensIn: number;
26
- tokensOut: number;
27
- cacheRead: number;
28
- cacheWrite: number;
29
- cost: number;
30
- }
31
- >;
32
- firstUsed: string;
33
- lastUsed: string;
34
- }
35
-
36
- interface CumulativeUsage {
37
- providers: Record<string, CumulativeProviderStats>;
38
- grandTotalRequests: number;
39
- grandTotalTokensIn: number;
40
- grandTotalTokensOut: number;
41
- grandTotalCacheRead: number;
42
- grandTotalCacheWrite: number;
43
- grandTotalCost: number;
44
- }
45
-
46
- const cumulativeStore = createJSONStore<CumulativeUsage>(USAGE_FILE, {
47
- providers: {},
48
- grandTotalRequests: 0,
49
- grandTotalTokensIn: 0,
50
- grandTotalTokensOut: 0,
51
- grandTotalCacheRead: 0,
52
- grandTotalCacheWrite: 0,
53
- grandTotalCost: 0,
54
- });
55
-
56
- export function persistUsage(
57
- provider: string,
58
- modelId: string,
59
- tokensIn: number,
60
- tokensOut: number,
61
- cacheRead: number,
62
- cacheWrite: number,
63
- cost: number,
64
- ): void {
65
- const data = cumulativeStore.load();
66
- const now = new Date().toISOString();
67
-
68
- let providerStats = data.providers[provider];
69
- if (!providerStats) {
70
- providerStats = {
71
- totalRequests: 0,
72
- totalTokensIn: 0,
73
- totalTokensOut: 0,
74
- totalCacheRead: 0,
75
- totalCacheWrite: 0,
76
- totalCost: 0,
77
- models: {},
78
- firstUsed: now,
79
- lastUsed: now,
80
- };
81
- data.providers[provider] = providerStats;
82
- }
83
-
84
- providerStats.totalRequests++;
85
- providerStats.totalTokensIn += tokensIn;
86
- providerStats.totalTokensOut += tokensOut;
87
- providerStats.totalCacheRead += cacheRead;
88
- providerStats.totalCacheWrite += cacheWrite;
89
- providerStats.totalCost += cost;
90
- providerStats.lastUsed = now;
91
-
92
- const modelStats = providerStats.models[modelId] ?? {
93
- count: 0,
94
- tokensIn: 0,
95
- tokensOut: 0,
96
- cacheRead: 0,
97
- cacheWrite: 0,
98
- cost: 0,
99
- };
100
- modelStats.count++;
101
- modelStats.tokensIn += tokensIn;
102
- modelStats.tokensOut += tokensOut;
103
- modelStats.cacheRead += cacheRead;
104
- modelStats.cacheWrite += cacheWrite;
105
- modelStats.cost += cost;
106
- providerStats.models[modelId] = modelStats;
107
-
108
- data.grandTotalRequests++;
109
- data.grandTotalTokensIn += tokensIn;
110
- data.grandTotalTokensOut += tokensOut;
111
- data.grandTotalCacheRead += cacheRead;
112
- data.grandTotalCacheWrite += cacheWrite;
113
- data.grandTotalCost += cost;
114
-
115
- cumulativeStore.save(data);
116
- }
117
-
118
- export interface CumulativeUsageReport {
119
- providers: Array<{
120
- name: string;
121
- totalRequests: number;
122
- totalTokensIn: number;
123
- totalTokensOut: number;
124
- totalCacheRead: number;
125
- totalCacheWrite: number;
126
- totalCost: number;
127
- modelCount: number;
128
- firstUsed: string;
129
- lastUsed: string;
130
- topModels: Array<{
131
- modelId: string;
132
- count: number;
133
- tokensIn: number;
134
- tokensOut: number;
135
- cacheRead: number;
136
- cacheWrite: number;
137
- cost: number;
138
- }>;
139
- }>;
140
- grandTotalRequests: number;
141
- grandTotalTokensIn: number;
142
- grandTotalTokensOut: number;
143
- grandTotalCacheRead: number;
144
- grandTotalCacheWrite: number;
145
- grandTotalCost: number;
146
- }
147
-
148
- export function getCumulativeUsage(): CumulativeUsageReport {
149
- const data = cumulativeStore.load();
150
-
151
- const providers: CumulativeUsageReport["providers"] = [];
152
-
153
- for (const [name, stats] of Object.entries(data.providers)) {
154
- const topModels = Object.entries(stats.models)
155
- .map(([modelId, m]) => ({
156
- modelId,
157
- count: m.count,
158
- tokensIn: m.tokensIn,
159
- tokensOut: m.tokensOut,
160
- cacheRead: m.cacheRead,
161
- cacheWrite: m.cacheWrite,
162
- cost: m.cost,
163
- }))
164
- .sort((a, b) => b.count - a.count)
165
- .slice(0, 5);
166
-
167
- providers.push({
168
- name,
169
- totalRequests: stats.totalRequests,
170
- totalTokensIn: stats.totalTokensIn,
171
- totalTokensOut: stats.totalTokensOut,
172
- totalCacheRead: stats.totalCacheRead,
173
- totalCacheWrite: stats.totalCacheWrite,
174
- totalCost: stats.totalCost,
175
- modelCount: Object.keys(stats.models).length,
176
- firstUsed: stats.firstUsed,
177
- lastUsed: stats.lastUsed,
178
- topModels,
179
- });
180
- }
181
-
182
- providers.sort((a, b) => b.totalRequests - a.totalRequests);
183
-
184
- return {
185
- providers,
186
- grandTotalRequests: data.grandTotalRequests,
187
- grandTotalTokensIn: data.grandTotalTokensIn,
188
- grandTotalTokensOut: data.grandTotalTokensOut,
189
- grandTotalCacheRead: data.grandTotalCacheRead,
190
- grandTotalCacheWrite: data.grandTotalCacheWrite,
191
- grandTotalCost: data.grandTotalCost,
192
- };
193
- }
@@ -1,115 +0,0 @@
1
- /**
2
- * Usage report formatters - text formatting for display
3
- */
4
-
5
- import type { CumulativeUsageReport } from "./cumulative.ts";
6
- import { getFreeTierUsage, getLimitWarning } from "./limits.ts";
7
- import type { SessionUsageReport } from "./tracking.ts";
8
- // Types imported via limits.ts (which re-exports from types.ts)
9
-
10
- export function formatSessionUsage(report: SessionUsageReport): string {
11
- if (report.providers.length === 0) {
12
- return "No usage recorded in this session yet.";
13
- }
14
-
15
- const lines: string[] = [];
16
- lines.push("━".repeat(50));
17
- lines.push(`📊 Session Usage (${report.durationFormatted})`);
18
- lines.push("━".repeat(50));
19
- lines.push("");
20
-
21
- for (const p of report.providers) {
22
- const warning = getLimitWarning(p.name);
23
- const statusEmoji = warning ? (warning.includes("⚠️") ? "🔴" : "🟡") : "🟢";
24
- lines.push(`${statusEmoji} ${p.name}`);
25
- lines.push(` Requests: ${p.requests}`);
26
- lines.push(
27
- ` Tokens: ~${Math.round(p.tokensIn / 1000)}K in, ~${Math.round(p.tokensOut / 1000)}K out`,
28
- );
29
-
30
- if (p.topModels.length > 0) {
31
- lines.push(` Top models:`);
32
- for (const m of p.topModels.slice(0, 3)) {
33
- lines.push(` • ${m.modelId.split("/").pop()}: ${m.count} req`);
34
- }
35
- }
36
- lines.push("");
37
- }
38
-
39
- lines.push("━".repeat(50));
40
- lines.push(
41
- `📈 Totals: ${report.totalRequests} requests, ~${Math.round(report.totalTokensIn / 1000)}K tokens`,
42
- );
43
- lines.push("━".repeat(50));
44
-
45
- return lines.join("\n");
46
- }
47
-
48
- export function formatCumulativeUsage(report: CumulativeUsageReport): string {
49
- if (report.providers.length === 0) {
50
- return "No cumulative usage data yet. Start using free models!";
51
- }
52
-
53
- const lines: string[] = [];
54
- lines.push("━".repeat(50));
55
- lines.push("📊 Total Usage (All Time)");
56
- lines.push("━".repeat(50));
57
- lines.push("");
58
-
59
- for (const p of report.providers) {
60
- lines.push(`🔹 ${p.name}`);
61
- lines.push(` Requests: ${p.totalRequests.toLocaleString()}`);
62
- lines.push(
63
- ` Tokens: ~${Math.round(p.totalTokensIn / 1000).toLocaleString()}K in, ~${Math.round(p.totalTokensOut / 1000).toLocaleString()}K out`,
64
- );
65
- lines.push(` Models used: ${p.modelCount}`);
66
-
67
- if (p.topModels.length > 0) {
68
- lines.push(` Top models:`);
69
- for (const m of p.topModels.slice(0, 3)) {
70
- lines.push(
71
- ` • ${m.modelId.split("/").pop()}: ${m.count.toLocaleString()} req`,
72
- );
73
- }
74
- }
75
-
76
- lines.push(` Active since: ${p.firstUsed.split("T")[0]}`);
77
- lines.push("");
78
- }
79
-
80
- lines.push("━".repeat(50));
81
- lines.push(`📈 Grand Totals:`);
82
- lines.push(` ${report.grandTotalRequests.toLocaleString()} requests`);
83
- lines.push(
84
- ` ~${Math.round(report.grandTotalTokensIn / 1000).toLocaleString()}K input tokens`,
85
- );
86
- lines.push(
87
- ` ~${Math.round(report.grandTotalTokensOut / 1000).toLocaleString()}K output tokens`,
88
- );
89
- lines.push("━".repeat(50));
90
-
91
- return lines.join("\n");
92
- }
93
-
94
- export function formatFreeTierStatus(provider: string): string {
95
- const usage = getFreeTierUsage(provider);
96
- const parts: string[] = [];
97
-
98
- if (usage.limit.requestsPerHour) {
99
- parts.push(`${usage.requestsThisHour}/${usage.limit.requestsPerHour}/h`);
100
- }
101
- if (usage.limit.requestsPerDay) {
102
- parts.push(`${usage.requestsToday}/${usage.limit.requestsPerDay}/d`);
103
- }
104
- if (usage.limit.requestsPerMonth) {
105
- parts.push(
106
- `${usage.requestsThisMonth ?? 0}/${usage.limit.requestsPerMonth}/mo`,
107
- );
108
- }
109
-
110
- if (parts.length === 0) {
111
- return `${provider}: ${usage.limit.description}`;
112
- }
113
-
114
- return `${provider}: ${parts.join(" | ")}`;
115
- }
package/usage/index.ts DELETED
@@ -1,46 +0,0 @@
1
- /**
2
- * Usage tracking module
3
- *
4
- * Exports:
5
- * - Commands: /free-sessionusage, /free-totalusage
6
- * - Tracking: per-model and per-provider usage counts
7
- * - Cumulative: persistent storage across sessions
8
- * - Formatters: display formatting with rate limits
9
- */
10
-
11
- // Commands
12
- export { registerUsageCommands } from "./commands.ts";
13
- // Cumulative (persistent)
14
- export {
15
- type CumulativeUsageReport,
16
- getCumulativeUsage,
17
- } from "./cumulative.ts";
18
- // Formatters
19
- export {
20
- formatCumulativeUsage,
21
- formatFreeTierStatus,
22
- formatSessionUsage,
23
- } from "./formatters.ts";
24
- // Limits
25
- export {
26
- FREE_TIER_LIMITS,
27
- type FreeTierLimit,
28
- type FreeTierUsage,
29
- getFreeTierUsage,
30
- getLimitWarning,
31
- isApproachingLimit,
32
- } from "./limits.ts";
33
- // Metrics (internal)
34
- export { getDailyRequestCount, incrementRequestCount } from "./metrics.ts";
35
- // Tracking (runtime)
36
- export {
37
- getModelUsage,
38
- getProviderModelUsage,
39
- getSessionUsage,
40
- getTopModels,
41
- incrementModelRequestCount,
42
- logModelUsageReport,
43
- type ModelUsageEntry,
44
- resetUsageStats,
45
- type SessionUsageReport,
46
- } from "./tracking.ts";
package/usage/limits.ts DELETED
@@ -1,148 +0,0 @@
1
- /**
2
- * Free Tier Rate Limits and Usage Tracking
3
- *
4
- * Main entry point - delegates to specialized modules:
5
- * - usage/tracking.ts - runtime session tracking
6
- * - usage/cumulative.ts - persistent cumulative storage
7
- * - usage/formatters.ts - display formatting
8
- */
9
-
10
- import { createLogger } from "../lib/logger.ts";
11
- import { getDailyRequestCount } from "./metrics.ts";
12
- import type { FreeTierLimit, FreeTierUsage } from "./types.ts";
13
-
14
- export {
15
- type CumulativeUsageReport,
16
- getCumulativeUsage,
17
- } from "./cumulative.ts";
18
- export {
19
- formatCumulativeUsage,
20
- formatFreeTierStatus,
21
- formatSessionUsage,
22
- } from "./formatters.ts";
23
- // Re-export from specialized modules
24
- export {
25
- getModelUsage,
26
- getProviderModelUsage,
27
- getSessionUsage,
28
- getTopModels,
29
- incrementModelRequestCount,
30
- logModelUsageReport,
31
- resetUsageStats,
32
- type SessionUsageReport,
33
- } from "./tracking.ts";
34
- // Re-export types for consumers
35
- export type { FreeTierLimit, FreeTierUsage } from "./types.ts";
36
-
37
- const _logger = createLogger("free-tier");
38
-
39
- // =============================================================================
40
- // Free Tier Limits Configuration
41
- // =============================================================================
42
-
43
- export const FREE_TIER_LIMITS: Record<string, FreeTierLimit> = {
44
- kilo: {
45
- provider: "kilo",
46
- requestsPerHour: 200,
47
- description: "200 requests/hour per IP (anonymous) or account",
48
- },
49
- openrouter: {
50
- provider: "openrouter",
51
- requestsPerDay: 1000,
52
- description: "1000 requests/day for free tier (no API key)",
53
- },
54
- nvidia: {
55
- provider: "nvidia",
56
- requestsPerMonth: 1000,
57
- description: "1000 requests/month for NIM free tier",
58
- },
59
- fireworks: {
60
- provider: "fireworks",
61
- requestsPerMonth: 1000,
62
- description: "1000 requests/month for free tier",
63
- },
64
- zen: {
65
- provider: "zen",
66
- description: "Fair use policy - no hard limits",
67
- },
68
- cline: {
69
- provider: "cline",
70
- description: "Rate limited but limits undocumented",
71
- },
72
- };
73
-
74
- // =============================================================================
75
- // Usage Status and Warnings
76
- // =============================================================================
77
-
78
- export function getFreeTierUsage(provider: string): FreeTierUsage {
79
- const limit = FREE_TIER_LIMITS[provider];
80
- if (!limit) {
81
- return {
82
- provider,
83
- requestsToday: 0,
84
- requestsThisHour: 0,
85
- limit: { provider, description: "Unknown" },
86
- percentUsed: 0,
87
- status: "unknown",
88
- };
89
- }
90
-
91
- const requestsToday = getDailyRequestCount(provider);
92
- // For hour tracking, estimate based on session count (capped at 50)
93
- const requestsThisHour = Math.min(requestsToday, 50);
94
-
95
- let percentUsed = 0;
96
- let status: FreeTierUsage["status"] = "ok";
97
-
98
- if (limit.requestsPerHour) {
99
- percentUsed = Math.max(
100
- percentUsed,
101
- (requestsThisHour / limit.requestsPerHour) * 100,
102
- );
103
- }
104
- if (limit.requestsPerDay) {
105
- percentUsed = Math.max(
106
- percentUsed,
107
- (requestsToday / limit.requestsPerDay) * 100,
108
- );
109
- }
110
-
111
- if (percentUsed >= 90) status = "critical";
112
- else if (percentUsed >= 70) status = "warning";
113
-
114
- return {
115
- provider,
116
- requestsToday,
117
- requestsThisHour,
118
- limit,
119
- remainingToday: limit.requestsPerDay
120
- ? limit.requestsPerDay - requestsToday
121
- : undefined,
122
- remainingThisHour: limit.requestsPerHour
123
- ? limit.requestsPerHour - requestsThisHour
124
- : undefined,
125
- percentUsed: Math.round(percentUsed),
126
- status,
127
- };
128
- }
129
-
130
- export function isApproachingLimit(provider: string): boolean {
131
- const usage = getFreeTierUsage(provider);
132
- return usage.status === "warning" || usage.status === "critical";
133
- }
134
-
135
- export function getLimitWarning(provider: string): string | null {
136
- const usage = getFreeTierUsage(provider);
137
-
138
- if (usage.status === "critical") {
139
- const remaining = usage.remainingThisHour ?? usage.remainingToday ?? 0;
140
- return `⚠️ ${provider}: ${usage.percentUsed}% of free tier used. ~${remaining} requests remaining.`;
141
- }
142
-
143
- if (usage.status === "warning") {
144
- return `ℹ️ ${provider}: ${usage.percentUsed}% of free tier used.`;
145
- }
146
-
147
- return null;
148
- }