pi-free 2.0.1 → 2.0.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.
@@ -1,128 +1,129 @@
1
- /**
2
- * Cline model fetching.
3
- *
4
- * Fetches ALL models from OpenRouter (Cline's gateway).
5
- * Free/paid filtering is handled by the global free-only filter.
6
- */
7
-
8
- import { applyHidden } from "../../config.ts";
9
- import {
10
- BASE_URL_OPENROUTER,
11
- DEFAULT_FETCH_TIMEOUT_MS,
12
- DEFAULT_MIN_SIZE_B,
13
- } from "../../constants.ts";
14
- import type { ProviderModelConfig } from "../../lib/types.ts";
15
- import {
16
- cleanModelName,
17
- fetchWithRetry,
18
- isUsableModel,
19
- } from "../../lib/util.ts";
20
-
21
- interface OpenRouterRaw {
22
- id: string;
23
- name: string;
24
- context_length?: number;
25
- supported_parameters?: string[];
26
- architecture?: { input_modalities?: string[]; output_modalities?: string[] };
27
- top_provider?: { max_completion_tokens?: number | null };
28
- pricing?: { prompt?: string; completion?: string };
29
- }
30
-
31
- function extractNameFromId(id: string): string {
32
- const part = id.split("/")[1] ?? id;
33
- return part
34
- .split(/[-_]/)
35
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
36
- .join(" ");
37
- }
38
-
39
- /**
40
- * Parse pricing string to cost per million tokens.
41
- * OpenRouter returns pricing as string (e.g., "0.0001" or "0").
42
- */
43
- function parsePricing(pricingStr: string | undefined): number {
44
- if (!pricingStr || pricingStr === "0") return 0;
45
- const parsed = parseFloat(pricingStr);
46
- return isNaN(parsed) ? 0 : parsed * 1_000_000; // Convert to per-million
47
- }
48
-
49
- /**
50
- * Check if a model is free (both prompt and completion pricing is 0).
51
- */
52
- function isFreeModel(info: OpenRouterRaw): boolean {
53
- return info.pricing?.prompt === "0" && info.pricing?.completion === "0";
54
- }
55
-
56
- /**
57
- * Fetch ALL models from OpenRouter.
58
- * @param freeOnly - If true, return only free models
59
- */
60
- export async function fetchClineModels(
61
- freeOnly = false,
62
- ): Promise<ProviderModelConfig[]> {
63
- const response = await fetchWithRetry(
64
- `${BASE_URL_OPENROUTER}/models`,
65
- {},
66
- 3,
67
- 1000,
68
- DEFAULT_FETCH_TIMEOUT_MS,
69
- );
70
-
71
- if (!response.ok)
72
- throw new Error(`Failed to fetch OpenRouter models: ${response.status}`);
73
-
74
- const json = (await response.json()) as { data?: OpenRouterRaw[] };
75
-
76
- // Filter to usable models (chat-capable, size threshold)
77
- let usableModels = (json.data ?? []).filter((m) =>
78
- isUsableModel(m.id, DEFAULT_MIN_SIZE_B),
79
- );
80
-
81
- // If freeOnly, filter to free models
82
- if (freeOnly) {
83
- usableModels = usableModels.filter(isFreeModel);
84
- }
85
-
86
- const models: ProviderModelConfig[] = [];
87
- for (const info of usableModels) {
88
- const isReasoning = !!(
89
- info.supported_parameters?.includes("include_reasoning") ||
90
- info.supported_parameters?.includes("reasoning")
91
- );
92
- const hasImage =
93
- info.architecture?.input_modalities?.includes("image") ?? false;
94
-
95
- // Calculate cost per million tokens
96
- const inputCost = parsePricing(info.pricing?.prompt);
97
- const outputCost = parsePricing(info.pricing?.completion);
98
- const isFree = inputCost === 0 && outputCost === 0;
99
-
100
- const cleanName = info.name
101
- ? cleanModelName(info.name)
102
- : extractNameFromId(info.id);
103
-
104
- models.push({
105
- id: info.id,
106
- name: `${cleanName} (Cline)${isFree ? "" : " 💰"}`,
107
- reasoning: isReasoning,
108
- input: hasImage ? ["text", "image"] : ["text"],
109
- cost: {
110
- input: inputCost,
111
- output: outputCost,
112
- cacheRead: 0,
113
- cacheWrite: 0,
114
- },
115
- contextWindow: info.context_length ?? 128_000,
116
- maxTokens: info.top_provider?.max_completion_tokens ?? 8_192,
117
- });
118
- }
119
-
120
- return applyHidden(models);
121
- }
122
-
123
- /**
124
- * Fetch only free models (backward compatibility).
125
- */
126
- export async function fetchClineFreeModels(): Promise<ProviderModelConfig[]> {
127
- return fetchClineModels(true);
128
- }
1
+ /**
2
+ * Cline model fetching.
3
+ *
4
+ * Fetches ALL models from OpenRouter (Cline's gateway).
5
+ * Free/paid filtering is handled by the global free-only filter.
6
+ */
7
+
8
+ import { applyHidden } from "../../config.ts";
9
+ import {
10
+ BASE_URL_OPENROUTER,
11
+ DEFAULT_FETCH_TIMEOUT_MS,
12
+ DEFAULT_MIN_SIZE_B,
13
+ PROVIDER_CLINE,
14
+ } from "../../constants.ts";
15
+ import type { ProviderModelConfig } from "../../lib/types.ts";
16
+ import {
17
+ cleanModelName,
18
+ fetchWithRetry,
19
+ isUsableModel,
20
+ } from "../../lib/util.ts";
21
+
22
+ interface OpenRouterRaw {
23
+ id: string;
24
+ name: string;
25
+ context_length?: number;
26
+ supported_parameters?: string[];
27
+ architecture?: { input_modalities?: string[]; output_modalities?: string[] };
28
+ top_provider?: { max_completion_tokens?: number | null };
29
+ pricing?: { prompt?: string; completion?: string };
30
+ }
31
+
32
+ function extractNameFromId(id: string): string {
33
+ const part = id.split("/")[1] ?? id;
34
+ return part
35
+ .split(/[-_]/)
36
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
37
+ .join(" ");
38
+ }
39
+
40
+ /**
41
+ * Parse pricing string to cost per million tokens.
42
+ * OpenRouter returns pricing as string (e.g., "0.0001" or "0").
43
+ */
44
+ function parsePricing(pricingStr: string | undefined): number {
45
+ if (!pricingStr || pricingStr === "0") return 0;
46
+ const parsed = parseFloat(pricingStr);
47
+ return isNaN(parsed) ? 0 : parsed * 1_000_000; // Convert to per-million
48
+ }
49
+
50
+ /**
51
+ * Check if a model is free (both prompt and completion pricing is 0).
52
+ */
53
+ function isFreeModel(info: OpenRouterRaw): boolean {
54
+ return info.pricing?.prompt === "0" && info.pricing?.completion === "0";
55
+ }
56
+
57
+ /**
58
+ * Fetch ALL models from OpenRouter.
59
+ * @param freeOnly - If true, return only free models
60
+ */
61
+ export async function fetchClineModels(
62
+ freeOnly = false,
63
+ ): Promise<ProviderModelConfig[]> {
64
+ const response = await fetchWithRetry(
65
+ `${BASE_URL_OPENROUTER}/models`,
66
+ {},
67
+ 3,
68
+ 1000,
69
+ DEFAULT_FETCH_TIMEOUT_MS,
70
+ );
71
+
72
+ if (!response.ok)
73
+ throw new Error(`Failed to fetch OpenRouter models: ${response.status}`);
74
+
75
+ const json = (await response.json()) as { data?: OpenRouterRaw[] };
76
+
77
+ // Filter to usable models (chat-capable, size threshold)
78
+ let usableModels = (json.data ?? []).filter((m) =>
79
+ isUsableModel(m.id, DEFAULT_MIN_SIZE_B),
80
+ );
81
+
82
+ // If freeOnly, filter to free models
83
+ if (freeOnly) {
84
+ usableModels = usableModels.filter(isFreeModel);
85
+ }
86
+
87
+ const models: ProviderModelConfig[] = [];
88
+ for (const info of usableModels) {
89
+ const isReasoning = !!(
90
+ info.supported_parameters?.includes("include_reasoning") ||
91
+ info.supported_parameters?.includes("reasoning")
92
+ );
93
+ const hasImage =
94
+ info.architecture?.input_modalities?.includes("image") ?? false;
95
+
96
+ // Calculate cost per million tokens
97
+ const inputCost = parsePricing(info.pricing?.prompt);
98
+ const outputCost = parsePricing(info.pricing?.completion);
99
+ const isFree = inputCost === 0 && outputCost === 0;
100
+
101
+ const cleanName = info.name
102
+ ? cleanModelName(info.name)
103
+ : extractNameFromId(info.id);
104
+
105
+ models.push({
106
+ id: info.id,
107
+ name: `${cleanName} (Cline)${isFree ? "" : " 💰"}`,
108
+ reasoning: isReasoning,
109
+ input: hasImage ? ["text", "image"] : ["text"],
110
+ cost: {
111
+ input: inputCost,
112
+ output: outputCost,
113
+ cacheRead: 0,
114
+ cacheWrite: 0,
115
+ },
116
+ contextWindow: info.context_length ?? 128_000,
117
+ maxTokens: info.top_provider?.max_completion_tokens ?? 8_192,
118
+ });
119
+ }
120
+
121
+ return applyHidden(models, PROVIDER_CLINE);
122
+ }
123
+
124
+ /**
125
+ * Fetch only free models (backward compatibility).
126
+ */
127
+ export async function fetchClineFreeModels(): Promise<ProviderModelConfig[]> {
128
+ return fetchClineModels(true);
129
+ }