pi-free 2.0.2 → 2.0.5
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 +84 -12
- package/README.md +44 -97
- package/banner.svg +132 -0
- package/config.ts +24 -52
- package/constants.ts +6 -0
- package/index.ts +175 -148
- package/lib/built-in-toggle.ts +40 -1
- package/lib/model-detection.ts +176 -139
- package/lib/model-enhancer.ts +20 -20
- package/lib/open-browser.ts +1 -1
- package/lib/provider-compat.ts +46 -0
- package/lib/registry.ts +200 -144
- package/lib/types.ts +101 -108
- package/lib/util.ts +262 -256
- package/package.json +9 -8
- package/provider-failover/benchmark-lookup.ts +191 -140
- package/provider-helper.ts +19 -1
- package/providers/cline/cline-auth.ts +473 -473
- package/providers/cline/cline.ts +58 -14
- package/providers/crofai/crofai.ts +170 -0
- package/providers/dynamic-built-in/index.ts +260 -308
- package/providers/kilo/kilo-auth.ts +155 -155
- package/providers/kilo/kilo.ts +263 -235
- package/providers/nvidia/nvidia.ts +474 -415
- package/providers/ollama/ollama.ts +295 -280
- package/providers/opencode-session.ts +3 -4
- package/providers/qwen/qwen-models.ts +101 -101
- package/providers/qwen/qwen.ts +47 -49
- package/providers/zenmux/zenmux.ts +176 -0
- package/scripts/check-extensions.mjs +71 -55
- package/provider-factory.ts +0 -207
- package/providers/cloudflare/cloudflare.ts +0 -526
- package/providers/modal/modal.ts +0 -47
|
@@ -78,7 +78,7 @@ function logDebug(entry: {
|
|
|
78
78
|
entry.codingIndex !== undefined ? entry.codingIndex.toFixed(1) : "",
|
|
79
79
|
entry.details || "",
|
|
80
80
|
]
|
|
81
|
-
.map((f) => f.replace(
|
|
81
|
+
.map((f) => f.replace(/[\\|]/g, "\\$&")) // Escape backslashes and pipes
|
|
82
82
|
.join("|");
|
|
83
83
|
|
|
84
84
|
appendFileSync(LOG_FILE, `${line}\n`);
|
|
@@ -128,7 +128,7 @@ function applyProviderNormalization(
|
|
|
128
128
|
if (provider === "nvidia") {
|
|
129
129
|
// NVIDIA uses prefixes like meta/, mistralai/, microsoft/, qwen/
|
|
130
130
|
const prefixMatch = normalized.match(
|
|
131
|
-
/^(meta|mistralai|microsoft|qwen|nvidia|ibm|google|ai21labs|bigcode|databricks|deepseek-ai|01-ai|adept|aisingapore|baai|
|
|
131
|
+
/^(meta|mistralai|microsoft|qwen|nvidia|ibm|google|ai21labs|bigcode|databricks|deepseek-ai|01-ai|adept|aisingapore|baai|bytedance|luma|stabilityai|fireworks|upstage|voyage|snowflake|recursal|kdan|unity|cloudflare|fblgit|nttdata|dito|nousresearch|espressomodels|ftmsh|huggingface|isolationai|pinglab|functionnetwork|huggingfaceh4|mcw|shutterstock)[^/]*\//,
|
|
132
132
|
);
|
|
133
133
|
if (prefixMatch) {
|
|
134
134
|
normalized = normalized.replace(/^[^/]+\//, "");
|
|
@@ -370,24 +370,46 @@ function findBestVariantByPrefix(
|
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
// =============================================================================
|
|
373
|
-
//
|
|
373
|
+
// Variant alias mappings
|
|
374
374
|
// =============================================================================
|
|
375
375
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
376
|
+
const MODEL_VARIANTS: Record<string, string[]> = {
|
|
377
|
+
"gpt-4o-aug-24": ["gpt-4o", "gpt-4-o"],
|
|
378
|
+
"gpt-4": ["gpt-4", "gpt4"],
|
|
379
|
+
"claude-3.5-sonnet-oct-24": [
|
|
380
|
+
"claude-3.5-sonnet",
|
|
381
|
+
"claude-3-5-sonnet",
|
|
382
|
+
"sonnet-3.5",
|
|
383
|
+
],
|
|
384
|
+
"claude-3-opus": ["claude-3-opus", "opus-3"],
|
|
385
|
+
"llama-3.1-instruct-405b": ["llama-3.1-405b", "llama3.1-405b", "llama-405b"],
|
|
386
|
+
"llama-3.1-instruct-70b": ["llama-3.1-70b", "llama3.1-70b", "llama-70b"],
|
|
387
|
+
"gemini-1.5-pro": ["gemini-1.5-pro", "gemini1.5-pro", "gemini-pro-1.5"],
|
|
388
|
+
"qwen2.5-instruct-72b": ["qwen2.5-72b", "qwen-2.5-72b"],
|
|
389
|
+
"deepseek-v3.2-non-reasoning": ["deepseek-v3", "deepseekv3", "deepseek-chat"],
|
|
390
|
+
"mimo-v2-pro": ["mimo-v2-pro", "mimo-v2-pro-free", "mimo-pro"],
|
|
391
|
+
"mimo-v2-omni": ["mimo-v2-omni", "mimo-v2-omni-free", "mimo-omni"],
|
|
392
|
+
"mimo-v2-flash": ["mimo-v2-flash", "mimo-v2-flash-free", "mimo-flash"],
|
|
393
|
+
"big-pickle": ["big-pickle", "bigpickle"],
|
|
394
|
+
"minimax-m2.5": ["minimax-m2.5", "minimax-m2.5-free", "minimax-m25"],
|
|
395
|
+
"nvidia-nemotron-3-super-120b-a12b-reasoning": [
|
|
396
|
+
"nemotron-3-super",
|
|
397
|
+
"nemotron-3-super-free",
|
|
398
|
+
"nemotron-super",
|
|
399
|
+
"nemotron-3",
|
|
400
|
+
],
|
|
401
|
+
};
|
|
382
402
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
modelName,
|
|
387
|
-
action: "attempt",
|
|
388
|
-
});
|
|
403
|
+
// =============================================================================
|
|
404
|
+
// Strategy steps
|
|
405
|
+
// =============================================================================
|
|
389
406
|
|
|
390
|
-
|
|
407
|
+
function tryDirectSubstringMatch(
|
|
408
|
+
search: string,
|
|
409
|
+
provider: string | undefined,
|
|
410
|
+
modelId: string,
|
|
411
|
+
modelName: string,
|
|
412
|
+
): HardcodedBenchmark | null {
|
|
391
413
|
for (const [key, data] of Object.entries(HARDCODED_BENCHMARKS) as [
|
|
392
414
|
string,
|
|
393
415
|
HardcodedBenchmark,
|
|
@@ -405,44 +427,16 @@ export function findHardcodedBenchmark(
|
|
|
405
427
|
return data;
|
|
406
428
|
}
|
|
407
429
|
}
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
408
432
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
"sonnet-3.5",
|
|
417
|
-
],
|
|
418
|
-
"claude-3-opus": ["claude-3-opus", "opus-3"],
|
|
419
|
-
"llama-3.1-instruct-405b": [
|
|
420
|
-
"llama-3.1-405b",
|
|
421
|
-
"llama3.1-405b",
|
|
422
|
-
"llama-405b",
|
|
423
|
-
],
|
|
424
|
-
"llama-3.1-instruct-70b": ["llama-3.1-70b", "llama3.1-70b", "llama-70b"],
|
|
425
|
-
"gemini-1.5-pro": ["gemini-1.5-pro", "gemini1.5-pro", "gemini-pro-1.5"],
|
|
426
|
-
"qwen2.5-instruct-72b": ["qwen2.5-72b", "qwen-2.5-72b"],
|
|
427
|
-
"deepseek-v3.2-non-reasoning": [
|
|
428
|
-
"deepseek-v3",
|
|
429
|
-
"deepseekv3",
|
|
430
|
-
"deepseek-chat",
|
|
431
|
-
],
|
|
432
|
-
"mimo-v2-pro": ["mimo-v2-pro", "mimo-v2-pro-free", "mimo-pro"],
|
|
433
|
-
"mimo-v2-omni": ["mimo-v2-omni", "mimo-v2-omni-free", "mimo-omni"],
|
|
434
|
-
"mimo-v2-flash": ["mimo-v2-flash", "mimo-v2-flash-free", "mimo-flash"],
|
|
435
|
-
"big-pickle": ["big-pickle", "bigpickle"],
|
|
436
|
-
"minimax-m2.5": ["minimax-m2.5", "minimax-m2.5-free", "minimax-m25"],
|
|
437
|
-
"nvidia-nemotron-3-super-120b-a12b-reasoning": [
|
|
438
|
-
"nemotron-3-super",
|
|
439
|
-
"nemotron-3-super-free",
|
|
440
|
-
"nemotron-super",
|
|
441
|
-
"nemotron-3",
|
|
442
|
-
],
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
for (const [canonical, names] of Object.entries(variants)) {
|
|
433
|
+
function tryVariantAliasMatch(
|
|
434
|
+
search: string,
|
|
435
|
+
provider: string | undefined,
|
|
436
|
+
modelId: string,
|
|
437
|
+
modelName: string,
|
|
438
|
+
): HardcodedBenchmark | null {
|
|
439
|
+
for (const [canonical, names] of Object.entries(MODEL_VARIANTS)) {
|
|
446
440
|
if (names.some((n) => search.includes(n.toLowerCase()))) {
|
|
447
441
|
const data = HARDCODED_BENCHMARKS[canonical];
|
|
448
442
|
if (data) {
|
|
@@ -459,66 +453,115 @@ export function findHardcodedBenchmark(
|
|
|
459
453
|
}
|
|
460
454
|
}
|
|
461
455
|
}
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
462
458
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
action: "normalized",
|
|
473
|
-
strategy: providerStrategy,
|
|
474
|
-
normalizedId: providerNormalized,
|
|
475
|
-
});
|
|
459
|
+
function tryProviderNormalizedMatch(
|
|
460
|
+
modelId: string,
|
|
461
|
+
provider: string | undefined,
|
|
462
|
+
modelName: string,
|
|
463
|
+
): { result: HardcodedBenchmark | null; normalized: string } {
|
|
464
|
+
const { normalized, strategy } = applyProviderNormalization(
|
|
465
|
+
modelId,
|
|
466
|
+
provider,
|
|
467
|
+
);
|
|
476
468
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
string,
|
|
480
|
-
HardcodedBenchmark,
|
|
481
|
-
][]) {
|
|
482
|
-
if (providerNormalized.includes(key.toLowerCase())) {
|
|
483
|
-
logDebug({
|
|
484
|
-
provider,
|
|
485
|
-
modelId,
|
|
486
|
-
modelName,
|
|
487
|
-
action: "match",
|
|
488
|
-
strategy: `provider-normalized:${providerStrategy}`,
|
|
489
|
-
matchKey: key,
|
|
490
|
-
codingIndex: data.codingIndex,
|
|
491
|
-
});
|
|
492
|
-
return data;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
469
|
+
if (normalized === modelId.toLowerCase()) {
|
|
470
|
+
return { result: null, normalized };
|
|
495
471
|
}
|
|
496
472
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
473
|
+
logDebug({
|
|
474
|
+
provider,
|
|
475
|
+
modelId,
|
|
476
|
+
modelName,
|
|
477
|
+
action: "normalized",
|
|
478
|
+
strategy,
|
|
479
|
+
normalizedId: normalized,
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
for (const [key, data] of Object.entries(HARDCODED_BENCHMARKS) as [
|
|
483
|
+
string,
|
|
484
|
+
HardcodedBenchmark,
|
|
485
|
+
][]) {
|
|
486
|
+
if (normalized.includes(key.toLowerCase())) {
|
|
509
487
|
logDebug({
|
|
510
488
|
provider,
|
|
511
489
|
modelId,
|
|
512
490
|
modelName,
|
|
513
|
-
action: "
|
|
514
|
-
strategy:
|
|
515
|
-
|
|
491
|
+
action: "match",
|
|
492
|
+
strategy: `provider-normalized:${strategy}`,
|
|
493
|
+
matchKey: key,
|
|
494
|
+
codingIndex: data.codingIndex,
|
|
516
495
|
});
|
|
517
|
-
|
|
518
|
-
if (best) return best;
|
|
496
|
+
return { result: data, normalized };
|
|
519
497
|
}
|
|
520
498
|
}
|
|
521
499
|
|
|
500
|
+
return { result: null, normalized };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function tryPrefixFallback(
|
|
504
|
+
normalizedId: string,
|
|
505
|
+
provider: string | undefined,
|
|
506
|
+
modelId: string,
|
|
507
|
+
modelName: string,
|
|
508
|
+
): HardcodedBenchmark | null {
|
|
509
|
+
const baseId = extractBaseModelId(normalizedId);
|
|
510
|
+
if (!baseId) return null;
|
|
511
|
+
|
|
512
|
+
const best = findBestVariantByPrefix(baseId, provider, modelId);
|
|
513
|
+
if (best) return best;
|
|
514
|
+
|
|
515
|
+
// Try with word-order normalization
|
|
516
|
+
// (e.g., llama-3.3-70b-instruct → llama-3.3-instruct-70b)
|
|
517
|
+
const reordered = normalizeSizeTokenOrder(baseId);
|
|
518
|
+
if (reordered === baseId) return null;
|
|
519
|
+
|
|
520
|
+
logDebug({
|
|
521
|
+
provider,
|
|
522
|
+
modelId,
|
|
523
|
+
modelName,
|
|
524
|
+
action: "normalized",
|
|
525
|
+
strategy: "size-token-reorder",
|
|
526
|
+
normalizedId: reordered,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
return findBestVariantByPrefix(reordered, provider, modelId);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// =============================================================================
|
|
533
|
+
// Main lookup
|
|
534
|
+
// =============================================================================
|
|
535
|
+
|
|
536
|
+
export function findHardcodedBenchmark(
|
|
537
|
+
modelName: string,
|
|
538
|
+
modelId: string,
|
|
539
|
+
provider?: string,
|
|
540
|
+
): HardcodedBenchmark | null {
|
|
541
|
+
const search = `${modelName} ${modelId}`.toLowerCase();
|
|
542
|
+
|
|
543
|
+
logDebug({ provider, modelId, modelName, action: "attempt" });
|
|
544
|
+
|
|
545
|
+
// 1. Direct substring match
|
|
546
|
+
const direct = tryDirectSubstringMatch(search, provider, modelId, modelName);
|
|
547
|
+
if (direct) return direct;
|
|
548
|
+
|
|
549
|
+
// 2. Variant alias matching
|
|
550
|
+
const variant = tryVariantAliasMatch(search, provider, modelId, modelName);
|
|
551
|
+
if (variant) return variant;
|
|
552
|
+
|
|
553
|
+
// 3. Provider-specific normalization
|
|
554
|
+
const { result: normalizedResult, normalized } = tryProviderNormalizedMatch(
|
|
555
|
+
modelId,
|
|
556
|
+
provider,
|
|
557
|
+
modelName,
|
|
558
|
+
);
|
|
559
|
+
if (normalizedResult) return normalizedResult;
|
|
560
|
+
|
|
561
|
+
// 4. Prefix fallback with base model extraction
|
|
562
|
+
const prefix = tryPrefixFallback(normalized, provider, modelId, modelName);
|
|
563
|
+
if (prefix) return prefix;
|
|
564
|
+
|
|
522
565
|
// No match found
|
|
523
566
|
logDebug({
|
|
524
567
|
provider,
|
|
@@ -526,8 +569,8 @@ export function findHardcodedBenchmark(
|
|
|
526
569
|
modelName,
|
|
527
570
|
action: "miss",
|
|
528
571
|
strategy: "all-strategies-failed",
|
|
529
|
-
normalizedId:
|
|
530
|
-
details: `Final normalized: ${
|
|
572
|
+
normalizedId: normalized,
|
|
573
|
+
details: `Final normalized: ${normalized}`,
|
|
531
574
|
});
|
|
532
575
|
|
|
533
576
|
return null;
|
|
@@ -569,6 +612,45 @@ export function enhanceModelNameWithCodingIndex(
|
|
|
569
612
|
* Get statistics about model matching from the current session
|
|
570
613
|
* Note: This reads the log file and computes stats
|
|
571
614
|
*/
|
|
615
|
+
interface LogStats {
|
|
616
|
+
totalAttempts: number;
|
|
617
|
+
matches: number;
|
|
618
|
+
misses: number;
|
|
619
|
+
byProvider: Record<
|
|
620
|
+
string,
|
|
621
|
+
{ attempts: number; matches: number; misses: number }
|
|
622
|
+
>;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function parseLogLine(stats: LogStats, line: string): void {
|
|
626
|
+
if (!line.trim()) return;
|
|
627
|
+
const parts = line.split("|");
|
|
628
|
+
if (parts.length < 5) return;
|
|
629
|
+
|
|
630
|
+
const provider = parts[1] || "unknown";
|
|
631
|
+
const action = parts[4];
|
|
632
|
+
|
|
633
|
+
if (!stats.byProvider[provider]) {
|
|
634
|
+
stats.byProvider[provider] = { attempts: 0, matches: 0, misses: 0 };
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (action === "attempt") {
|
|
638
|
+
stats.totalAttempts++;
|
|
639
|
+
stats.byProvider[provider].attempts++;
|
|
640
|
+
} else if (action === "match") {
|
|
641
|
+
stats.matches++;
|
|
642
|
+
stats.byProvider[provider].matches++;
|
|
643
|
+
} else if (action === "miss") {
|
|
644
|
+
stats.misses++;
|
|
645
|
+
stats.byProvider[provider].misses++;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function computeMatchRate(stats: LogStats): number {
|
|
650
|
+
const total = stats.matches + stats.misses;
|
|
651
|
+
return total > 0 ? Math.round((stats.matches / total) * 100) : 0;
|
|
652
|
+
}
|
|
653
|
+
|
|
572
654
|
export function getMatchingStats(): {
|
|
573
655
|
totalAttempts: number;
|
|
574
656
|
matches: number;
|
|
@@ -579,58 +661,27 @@ export function getMatchingStats(): {
|
|
|
579
661
|
{ attempts: number; matches: number; misses: number }
|
|
580
662
|
>;
|
|
581
663
|
} {
|
|
582
|
-
const stats = {
|
|
664
|
+
const stats: LogStats = {
|
|
583
665
|
totalAttempts: 0,
|
|
584
666
|
matches: 0,
|
|
585
667
|
misses: 0,
|
|
586
|
-
|
|
587
|
-
byProvider: {} as Record<
|
|
588
|
-
string,
|
|
589
|
-
{ attempts: number; matches: number; misses: number }
|
|
590
|
-
>,
|
|
668
|
+
byProvider: {},
|
|
591
669
|
};
|
|
592
670
|
|
|
593
671
|
try {
|
|
594
672
|
if (!existsSync(LOG_FILE)) {
|
|
595
|
-
return stats;
|
|
673
|
+
return { ...stats, matchRate: 0 };
|
|
596
674
|
}
|
|
597
675
|
|
|
598
676
|
const content = readFileSync(LOG_FILE, "utf-8");
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
for (const line of lines) {
|
|
602
|
-
if (!line.trim()) continue;
|
|
603
|
-
const parts = line.split("|");
|
|
604
|
-
if (parts.length < 5) continue;
|
|
605
|
-
|
|
606
|
-
const provider = parts[1] || "unknown";
|
|
607
|
-
const action = parts[4];
|
|
608
|
-
|
|
609
|
-
if (!stats.byProvider[provider]) {
|
|
610
|
-
stats.byProvider[provider] = { attempts: 0, matches: 0, misses: 0 };
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
if (action === "attempt") {
|
|
614
|
-
stats.totalAttempts++;
|
|
615
|
-
stats.byProvider[provider].attempts++;
|
|
616
|
-
} else if (action === "match") {
|
|
617
|
-
stats.matches++;
|
|
618
|
-
stats.byProvider[provider].matches++;
|
|
619
|
-
} else if (action === "miss") {
|
|
620
|
-
stats.misses++;
|
|
621
|
-
stats.byProvider[provider].misses++;
|
|
622
|
-
}
|
|
677
|
+
for (const line of content.split("\n").slice(1)) {
|
|
678
|
+
parseLogLine(stats, line);
|
|
623
679
|
}
|
|
624
|
-
|
|
625
|
-
stats.matchRate =
|
|
626
|
-
stats.totalAttempts > 0
|
|
627
|
-
? Math.round((stats.matches / (stats.matches + stats.misses)) * 100)
|
|
628
|
-
: 0;
|
|
629
680
|
} catch {
|
|
630
681
|
// Return empty stats on error
|
|
631
682
|
}
|
|
632
683
|
|
|
633
|
-
return stats;
|
|
684
|
+
return { ...stats, matchRate: computeMatchRate(stats) };
|
|
634
685
|
}
|
|
635
686
|
|
|
636
687
|
// Need to import readFileSync for stats
|
package/provider-helper.ts
CHANGED
|
@@ -213,12 +213,30 @@ export function setupProvider(
|
|
|
213
213
|
});
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// ──
|
|
216
|
+
// ── Status bar for selected provider ───────────────────────────
|
|
217
217
|
|
|
218
218
|
pi.on("model_select", (_event, ctx) => {
|
|
219
219
|
if (_event.model?.provider !== providerId) {
|
|
220
220
|
ctx.ui.setStatus(`${providerId}-status`, undefined);
|
|
221
|
+
return;
|
|
221
222
|
}
|
|
223
|
+
|
|
224
|
+
// Build status line for this provider
|
|
225
|
+
const free = stored.free.length;
|
|
226
|
+
const total = stored.all.length || free;
|
|
227
|
+
const paid = total - free;
|
|
228
|
+
let status: string;
|
|
229
|
+
|
|
230
|
+
if (paid === 0) {
|
|
231
|
+
status = `${providerId}: ${free} free models`;
|
|
232
|
+
} else if (currentShowPaid) {
|
|
233
|
+
status = `${providerId}: ${total} models (free + paid)`;
|
|
234
|
+
} else {
|
|
235
|
+
status = `${providerId}: ${free} free · ${paid} paid`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (config.hasKey) status += " 🔑";
|
|
239
|
+
ctx.ui.setStatus(`${providerId}-status`, status);
|
|
222
240
|
});
|
|
223
241
|
|
|
224
242
|
// ── Error handling / usage tracking are temporarily deprecated ─────────
|