pi-free 2.2.2 → 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/CHANGELOG.md +18 -39
- package/README.md +41 -532
- package/banner.svg +23 -20
- package/config.ts +774 -702
- package/constants.ts +11 -1
- package/index.ts +432 -419
- package/lib/model-detection.ts +296 -296
- package/lib/model-metadata.ts +10 -3
- package/lib/telemetry.ts +36 -44
- package/package.json +3 -2
- package/provider-failover/benchmark-lookup.ts +30 -15
- package/provider-helper.ts +27 -8
- package/providers/bai/bai.ts +232 -237
- package/providers/cline/cline-xml-bridge.ts +31 -25
- package/providers/cline/cline.ts +17 -8
- package/providers/kilo/kilo.ts +11 -6
- package/providers/model-fetcher.ts +1 -1
- package/providers/opencode-session.ts +2 -2
- package/providers/openmodel/openmodel.ts +525 -0
- package/providers/qoder/auth.ts +548 -0
- package/providers/qoder/cosy.ts +236 -0
- package/providers/qoder/encoding.ts +48 -0
- package/providers/qoder/models.ts +321 -0
- package/providers/qoder/qoder.ts +154 -0
- package/providers/qoder/stream.ts +677 -0
- package/providers/qoder/thinking-parser.ts +251 -0
- package/providers/qoder/transform.ts +189 -0
- package/providers/tokenrouter/tokenrouter.ts +3 -6
package/lib/telemetry.ts
CHANGED
|
@@ -105,67 +105,59 @@ const _store = createJSONStore<TelemetryStore>(TELEMETRY_FILE, {
|
|
|
105
105
|
// =============================================================================
|
|
106
106
|
|
|
107
107
|
function deriveModelTelemetry(
|
|
108
|
-
_modelKey: string,
|
|
109
108
|
entries: TelemetryEntry[],
|
|
110
109
|
): ModelTelemetry {
|
|
111
110
|
const recent = entries.slice(-MAX_RECENT_CALLS);
|
|
111
|
+
|
|
112
|
+
let successCalls = 0;
|
|
113
|
+
let totalTokensFromSuccessful = 0;
|
|
114
|
+
let totalLatencyFromSuccessful = 0;
|
|
115
|
+
let totalTokens = 0;
|
|
116
|
+
let totalPromptTokens = 0;
|
|
117
|
+
let totalCompletionTokens = 0;
|
|
118
|
+
let totalLatencyMs = 0;
|
|
119
|
+
let totalCost = 0;
|
|
120
|
+
|
|
121
|
+
for (const e of entries) {
|
|
122
|
+
totalTokens += e.totalTokens;
|
|
123
|
+
totalPromptTokens += e.promptTokens;
|
|
124
|
+
totalCompletionTokens += e.completionTokens;
|
|
125
|
+
totalLatencyMs += e.latencyMs;
|
|
126
|
+
totalCost += e.cost;
|
|
127
|
+
if (e.success) {
|
|
128
|
+
successCalls++;
|
|
129
|
+
totalTokensFromSuccessful += e.totalTokens;
|
|
130
|
+
totalLatencyFromSuccessful += e.latencyMs;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
112
134
|
const totalCalls = entries.length;
|
|
113
|
-
const successCalls = entries.filter((e) => e.success).length;
|
|
114
|
-
const errorCalls = totalCalls - successCalls;
|
|
115
|
-
|
|
116
|
-
const stats = entries.reduce(
|
|
117
|
-
(acc, e) => {
|
|
118
|
-
acc.totalTokens += e.totalTokens;
|
|
119
|
-
acc.totalPromptTokens += e.promptTokens;
|
|
120
|
-
acc.totalCompletionTokens += e.completionTokens;
|
|
121
|
-
acc.totalLatencyMs += e.latencyMs;
|
|
122
|
-
acc.totalCost += e.cost;
|
|
123
|
-
return acc;
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
totalTokens: 0,
|
|
127
|
-
totalPromptTokens: 0,
|
|
128
|
-
totalCompletionTokens: 0,
|
|
129
|
-
totalLatencyMs: 0,
|
|
130
|
-
totalCost: 0,
|
|
131
|
-
},
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
const totalSuccessEntries = entries.filter((e) => e.success);
|
|
135
|
-
const totalTokensFromSuccessful = totalSuccessEntries.reduce(
|
|
136
|
-
(s, e) => s + e.totalTokens,
|
|
137
|
-
0,
|
|
138
|
-
);
|
|
139
|
-
const totalLatencyFromSuccessful = totalSuccessEntries.reduce(
|
|
140
|
-
(s, e) => s + e.latencyMs,
|
|
141
|
-
0,
|
|
142
|
-
);
|
|
143
135
|
|
|
144
136
|
return {
|
|
145
137
|
totalCalls,
|
|
146
138
|
successCalls,
|
|
147
|
-
errorCalls,
|
|
148
|
-
totalTokens
|
|
149
|
-
totalPromptTokens
|
|
150
|
-
totalCompletionTokens
|
|
151
|
-
totalLatencyMs
|
|
152
|
-
totalCost
|
|
139
|
+
errorCalls: totalCalls - successCalls,
|
|
140
|
+
totalTokens,
|
|
141
|
+
totalPromptTokens,
|
|
142
|
+
totalCompletionTokens,
|
|
143
|
+
totalLatencyMs,
|
|
144
|
+
totalCost,
|
|
153
145
|
avgLatencyMs:
|
|
154
|
-
|
|
155
|
-
? Math.round(totalLatencyFromSuccessful /
|
|
146
|
+
successCalls > 0
|
|
147
|
+
? Math.round(totalLatencyFromSuccessful / successCalls)
|
|
156
148
|
: 0,
|
|
157
149
|
avgTokensPerSecond:
|
|
158
150
|
totalLatencyFromSuccessful > 0
|
|
159
|
-
? parseFloat(
|
|
151
|
+
? Number.parseFloat(
|
|
160
152
|
(
|
|
161
153
|
totalTokensFromSuccessful /
|
|
162
154
|
(totalLatencyFromSuccessful / 1000)
|
|
163
155
|
).toFixed(1),
|
|
164
|
-
|
|
156
|
+
)
|
|
165
157
|
: 0,
|
|
166
158
|
successRate:
|
|
167
159
|
totalCalls > 0
|
|
168
|
-
? parseFloat(((successCalls / totalCalls) * 100).toFixed(1))
|
|
160
|
+
? Number.parseFloat(((successCalls / totalCalls) * 100).toFixed(1))
|
|
169
161
|
: 0,
|
|
170
162
|
recentCalls: recent,
|
|
171
163
|
};
|
|
@@ -186,7 +178,7 @@ async function addEntry(entry: TelemetryEntry): Promise<void> {
|
|
|
186
178
|
...store,
|
|
187
179
|
models: {
|
|
188
180
|
...store.models,
|
|
189
|
-
[modelKey]: deriveModelTelemetry(
|
|
181
|
+
[modelKey]: deriveModelTelemetry(pruned),
|
|
190
182
|
},
|
|
191
183
|
lastUpdated: Date.now(),
|
|
192
184
|
};
|
|
@@ -310,7 +302,7 @@ export async function recordModelCall(
|
|
|
310
302
|
const totalTokens = usage.totalTokens || usage.input + usage.output;
|
|
311
303
|
const tokensPerSecond =
|
|
312
304
|
latencyMs > 0
|
|
313
|
-
? parseFloat((totalTokens / (latencyMs / 1000)).toFixed(1))
|
|
305
|
+
? Number.parseFloat((totalTokens / (latencyMs / 1000)).toFixed(1))
|
|
314
306
|
: 0;
|
|
315
307
|
|
|
316
308
|
const entry: TelemetryEntry = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-free",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI model providers for Pi with free model filtering and dynamic model fetching",
|
|
6
6
|
"keywords": [
|
|
@@ -52,7 +52,8 @@
|
|
|
52
52
|
"test": "vitest",
|
|
53
53
|
"test:ui": "vitest --ui",
|
|
54
54
|
"test:run": "vitest run",
|
|
55
|
-
"smoke:cline": "tsx scripts/smoke-cline-xml-bridge.ts"
|
|
55
|
+
"smoke:cline": "tsx scripts/smoke-cline-xml-bridge.ts",
|
|
56
|
+
"smoke:openmodel": "tsx scripts/smoke-openmodel-wire-format.ts"
|
|
56
57
|
},
|
|
57
58
|
"peerDependencies": {
|
|
58
59
|
"@earendil-works/pi-ai": "^0.79.8",
|
|
@@ -551,23 +551,35 @@ function tryDirectSubstringMatch(
|
|
|
551
551
|
modelId: string,
|
|
552
552
|
modelName: string,
|
|
553
553
|
): HardcodedBenchmark | null {
|
|
554
|
+
// Collect ALL substring matches, then return the LONGEST key. This
|
|
555
|
+
// prevents short general keys (e.g. "mistral-medium-3") from shadowing
|
|
556
|
+
// longer specific keys (e.g. "mistral-medium-3.5") when a provider
|
|
557
|
+
// uses a different separator convention in the model ID.
|
|
558
|
+
let bestKey: string | null = null;
|
|
559
|
+
let bestData: HardcodedBenchmark | null = null;
|
|
554
560
|
for (const [key, data] of Object.entries(HARDCODED_BENCHMARKS) as [
|
|
555
561
|
string,
|
|
556
562
|
HardcodedBenchmark,
|
|
557
563
|
][]) {
|
|
558
564
|
if (search.includes(key.toLowerCase())) {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
action: "match",
|
|
564
|
-
strategy: "direct-substring",
|
|
565
|
-
matchKey: key,
|
|
566
|
-
codingIndex: data.codingIndex,
|
|
567
|
-
});
|
|
568
|
-
return data;
|
|
565
|
+
if (bestKey === null || key.length > bestKey.length) {
|
|
566
|
+
bestKey = key;
|
|
567
|
+
bestData = data;
|
|
568
|
+
}
|
|
569
569
|
}
|
|
570
570
|
}
|
|
571
|
+
if (bestKey !== null && bestData !== null) {
|
|
572
|
+
logDebug({
|
|
573
|
+
provider,
|
|
574
|
+
modelId,
|
|
575
|
+
modelName,
|
|
576
|
+
action: "match",
|
|
577
|
+
strategy: "direct-substring",
|
|
578
|
+
matchKey: bestKey,
|
|
579
|
+
codingIndex: bestData.codingIndex,
|
|
580
|
+
});
|
|
581
|
+
return bestData;
|
|
582
|
+
}
|
|
571
583
|
return null;
|
|
572
584
|
}
|
|
573
585
|
|
|
@@ -685,14 +697,17 @@ export function findHardcodedBenchmark(
|
|
|
685
697
|
|
|
686
698
|
logDebug({ provider, modelId, modelName, action: "attempt" });
|
|
687
699
|
|
|
688
|
-
// 1.
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
// 2. Variant alias matching
|
|
700
|
+
// 1. Variant alias matching (human-curated, runs first so deliberate
|
|
701
|
+
// aliases for separator/suffix mismatches can override generic substring
|
|
702
|
+
// matches).
|
|
693
703
|
const variant = tryVariantAliasMatch(search, provider, modelId, modelName);
|
|
694
704
|
if (variant) return variant;
|
|
695
705
|
|
|
706
|
+
// 2. Direct substring match (longest-key wins, so "minimax-m2.5" beats
|
|
707
|
+
// "minimax-m2" when both could match).
|
|
708
|
+
const direct = tryDirectSubstringMatch(search, provider, modelId, modelName);
|
|
709
|
+
if (direct) return direct;
|
|
710
|
+
|
|
696
711
|
// 3. Provider-specific normalization
|
|
697
712
|
const { result: normalizedResult, normalized } = tryProviderNormalizedMatch(
|
|
698
713
|
modelId,
|
package/provider-helper.ts
CHANGED
|
@@ -13,14 +13,11 @@ import type {
|
|
|
13
13
|
} from "@earendil-works/pi-coding-agent";
|
|
14
14
|
import { saveConfig } from "./config.ts";
|
|
15
15
|
import { createLogger } from "./lib/logger.ts";
|
|
16
|
+
import type { ModelsDevEnrichedMetadata } from "./lib/types.ts";
|
|
16
17
|
import { enhanceModelNameWithCodingIndex } from "./provider-failover/benchmark-lookup.ts";
|
|
17
18
|
|
|
18
19
|
const _logger = createLogger("provider-helper");
|
|
19
20
|
|
|
20
|
-
type ModelsDevEnrichedMetadata = {
|
|
21
|
-
modelsDev?: Parameters<typeof enhanceModelNameWithCodingIndex>[3];
|
|
22
|
-
};
|
|
23
|
-
|
|
24
21
|
// =============================================================================
|
|
25
22
|
// Types
|
|
26
23
|
// =============================================================================
|
|
@@ -66,6 +63,14 @@ export interface OpenAICompatibleConfig {
|
|
|
66
63
|
baseUrl: string;
|
|
67
64
|
/** Environment variable name for the API key */
|
|
68
65
|
apiKey: string;
|
|
66
|
+
/**
|
|
67
|
+
* Wire API to use. Defaults to `"openai-completions"` for backward
|
|
68
|
+
* compatibility with the 17 existing providers that pass through
|
|
69
|
+
* this helper without setting it. Set to `"anthropic-messages"`
|
|
70
|
+
* for Anthropic-protocol gateways (e.g. OpenModel). The pi-ai
|
|
71
|
+
* runtime dispatches to the right client based on this value.
|
|
72
|
+
*/
|
|
73
|
+
api?: "openai-completions" | "anthropic-messages";
|
|
69
74
|
/** Additional headers to include */
|
|
70
75
|
headers?: Record<string, string>;
|
|
71
76
|
/** OAuth configuration (optional) */
|
|
@@ -105,12 +110,19 @@ export function registerOpenAICompatible(
|
|
|
105
110
|
config: OpenAICompatibleConfig,
|
|
106
111
|
models: ProviderModelConfig[],
|
|
107
112
|
): void {
|
|
108
|
-
const {
|
|
113
|
+
const {
|
|
114
|
+
providerId,
|
|
115
|
+
baseUrl,
|
|
116
|
+
apiKey,
|
|
117
|
+
api = "openai-completions",
|
|
118
|
+
headers,
|
|
119
|
+
oauth,
|
|
120
|
+
} = config;
|
|
109
121
|
|
|
110
122
|
pi.registerProvider(providerId, {
|
|
111
123
|
baseUrl,
|
|
112
124
|
apiKey,
|
|
113
|
-
api
|
|
125
|
+
api,
|
|
114
126
|
headers: {
|
|
115
127
|
"User-Agent": "pi-free-providers",
|
|
116
128
|
...headers,
|
|
@@ -143,13 +155,20 @@ export function createCtxReRegister(
|
|
|
143
155
|
},
|
|
144
156
|
config: OpenAICompatibleConfig,
|
|
145
157
|
): (models: ProviderModelConfig[]) => void {
|
|
146
|
-
const {
|
|
158
|
+
const {
|
|
159
|
+
providerId,
|
|
160
|
+
baseUrl,
|
|
161
|
+
apiKey,
|
|
162
|
+
api = "openai-completions",
|
|
163
|
+
headers,
|
|
164
|
+
oauth,
|
|
165
|
+
} = config;
|
|
147
166
|
|
|
148
167
|
return (models: ProviderModelConfig[]) => {
|
|
149
168
|
ctx.modelRegistry.registerProvider(providerId, {
|
|
150
169
|
baseUrl,
|
|
151
170
|
apiKey,
|
|
152
|
-
api
|
|
171
|
+
api,
|
|
153
172
|
headers: {
|
|
154
173
|
"User-Agent": "pi-free-providers",
|
|
155
174
|
...headers,
|