pi-free 2.0.7 → 2.0.9
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 +96 -10
- package/README.md +572 -495
- package/config.ts +58 -11
- package/constants.ts +12 -0
- package/index.ts +67 -3
- package/lib/built-in-toggle.ts +2 -2
- package/lib/model-detection.ts +2 -1
- package/lib/model-enhancer.ts +1 -1
- package/lib/open-browser.ts +1 -1
- package/lib/provider-compat.ts +1 -1
- package/lib/quota-monitor.ts +123 -0
- package/lib/registry.ts +1 -1
- package/lib/types.ts +101 -101
- package/lib/util.ts +460 -351
- package/package.json +4 -4
- package/provider-failover/benchmark-lookup.ts +743 -702
- package/provider-failover/benchmarks-chunk-0.ts +48 -48
- package/provider-failover/benchmarks-chunk-1.ts +44 -44
- package/provider-failover/benchmarks-chunk-2.ts +39 -39
- package/provider-failover/benchmarks-chunk-3.ts +41 -41
- package/provider-failover/benchmarks-chunk-4.ts +33 -33
- package/provider-helper.ts +1 -1
- package/providers/cline/cline-auth.ts +473 -473
- package/providers/cline/cline-models.ts +2 -2
- package/providers/cline/cline.ts +3 -3
- package/providers/codestral/codestral.ts +139 -0
- package/providers/crofai/crofai.ts +14 -85
- package/providers/deepinfra/deepinfra.ts +109 -0
- package/providers/dynamic-built-in/index.ts +1 -1
- package/providers/kilo/kilo-auth.ts +155 -155
- package/providers/kilo/kilo.ts +3 -3
- package/providers/llm7/llm7.ts +156 -0
- package/providers/model-fetcher.ts +2 -2
- package/providers/nvidia/nvidia.ts +5 -5
- package/providers/ollama/ollama.ts +2 -2
- package/providers/opencode-session.ts +1 -1
- package/providers/qwen/qwen-auth.ts +1 -1
- package/providers/qwen/qwen-models.ts +1 -1
- package/providers/qwen/qwen.ts +3 -3
- package/providers/sambanova/sambanova.ts +109 -0
- package/providers/zenmux/zenmux.ts +6 -3
- package/scripts/check-extensions.mjs +6 -4
|
@@ -43,8 +43,8 @@ function extractNameFromId(id: string): string {
|
|
|
43
43
|
*/
|
|
44
44
|
function parsePricing(pricingStr: string | undefined): number {
|
|
45
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
|
|
46
|
+
const parsed = Number.parseFloat(pricingStr);
|
|
47
|
+
return Number.isNaN(parsed) ? 0 : parsed * 1_000_000; // Convert to per-million
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
package/providers/cline/cline.ts
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* # Models appear immediately; run /login cline to start chatting
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import type { OAuthCredentials } from "@
|
|
18
|
-
import type { ExtensionAPI } from "@
|
|
17
|
+
import type { OAuthCredentials } from "@earendil-works/pi-ai";
|
|
18
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
19
19
|
import { getClineShowPaid } from "../../config.ts";
|
|
20
20
|
import { BASE_URL_CLINE, PROVIDER_CLINE } from "../../constants.ts";
|
|
21
21
|
import { isFreeModel, registerWithGlobalToggle } from "../../lib/registry.ts";
|
|
@@ -210,7 +210,7 @@ function shapeMessagesForCline(messages: any[]): any[] {
|
|
|
210
210
|
// Extension entry point
|
|
211
211
|
// =============================================================================
|
|
212
212
|
|
|
213
|
-
export default async function (pi: ExtensionAPI) {
|
|
213
|
+
export default async function clineProvider(pi: ExtensionAPI) {
|
|
214
214
|
let allModels = await fetchClineModels(false).catch((err) => {
|
|
215
215
|
logWarning("cline", "Failed to fetch models at startup", err);
|
|
216
216
|
return [];
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codestral Provider Extension
|
|
3
|
+
*
|
|
4
|
+
* Codestral is Mistral AI's code-focused model. This provider registers it
|
|
5
|
+
* through the Codestral-specific endpoint (codestral.mistral.ai) using
|
|
6
|
+
* the Mistral SDK (api: "mistral-conversations") — separate from the built-in
|
|
7
|
+
* "mistral" provider which uses api.mistral.ai.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: Do NOT use api: "openai-completions" here. Codestral's API is
|
|
10
|
+
* Mistral-format (camelCase fields, maxTokens, no stream_options/store).
|
|
11
|
+
* The OpenAI completions adapter sends OpenAI-specific fields that Mistral
|
|
12
|
+
* rejects with HTTP 422 "Extra inputs are not permitted".
|
|
13
|
+
*
|
|
14
|
+
* Free tier (Experiment plan):
|
|
15
|
+
* - 2 req/min, 500K tokens/min, 1B tokens/month
|
|
16
|
+
* - No credit card — phone verification only
|
|
17
|
+
* - Sign up at https://console.mistral.ai/codestral
|
|
18
|
+
*
|
|
19
|
+
* Endpoints:
|
|
20
|
+
* Chat: https://codestral.mistral.ai/v1/chat/completions
|
|
21
|
+
* FIM: https://codestral.mistral.ai/v1/fim/completions (not used by pi)
|
|
22
|
+
*
|
|
23
|
+
* Setup:
|
|
24
|
+
* 1. Get API key from https://console.mistral.ai/codestral
|
|
25
|
+
* 2. Set CODESTRAL_API_KEY env var (or MISTRAL_API_KEY as fallback)
|
|
26
|
+
*
|
|
27
|
+
* Usage:
|
|
28
|
+
* pi install git:github.com/apmantza/pi-free
|
|
29
|
+
* # Set CODESTRAL_API_KEY env var
|
|
30
|
+
* # Models appear in /model selector as "codestral/codestral-latest"
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import type {
|
|
34
|
+
ExtensionAPI,
|
|
35
|
+
ProviderModelConfig,
|
|
36
|
+
} from "@earendil-works/pi-coding-agent";
|
|
37
|
+
import {
|
|
38
|
+
getCodestralApiKey,
|
|
39
|
+
getCodestralShowPaid,
|
|
40
|
+
getMistralApiKey,
|
|
41
|
+
} from "../../config.ts";
|
|
42
|
+
import { BASE_URL_CODESTRAL, PROVIDER_CODESTRAL } from "../../constants.ts";
|
|
43
|
+
import { createLogger } from "../../lib/logger.ts";
|
|
44
|
+
import { registerWithGlobalToggle } from "../../lib/registry.ts";
|
|
45
|
+
import { enhanceWithCI, setupProvider } from "../../provider-helper.ts";
|
|
46
|
+
|
|
47
|
+
const _logger = createLogger("codestral");
|
|
48
|
+
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// Model Definition
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
53
|
+
const CODESTRAL_MODEL: ProviderModelConfig = {
|
|
54
|
+
id: "codestral-latest",
|
|
55
|
+
name: "Codestral",
|
|
56
|
+
reasoning: false,
|
|
57
|
+
input: ["text"],
|
|
58
|
+
cost: {
|
|
59
|
+
input: 0.3,
|
|
60
|
+
output: 0.9,
|
|
61
|
+
cacheRead: 0,
|
|
62
|
+
cacheWrite: 0,
|
|
63
|
+
},
|
|
64
|
+
contextWindow: 256_000,
|
|
65
|
+
maxTokens: 4_096,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Extension Entry Point
|
|
70
|
+
// =============================================================================
|
|
71
|
+
|
|
72
|
+
export default async function codestralProvider(pi: ExtensionAPI) {
|
|
73
|
+
// Try CODESTRAL_API_KEY first, fall back to MISTRAL_API_KEY
|
|
74
|
+
const apiKey = getCodestralApiKey() || getMistralApiKey();
|
|
75
|
+
|
|
76
|
+
if (!apiKey) {
|
|
77
|
+
_logger.info(
|
|
78
|
+
"[codestral] Skipping — neither CODESTRAL_API_KEY nor MISTRAL_API_KEY set",
|
|
79
|
+
);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const keySource = getCodestralApiKey()
|
|
84
|
+
? "CODESTRAL_API_KEY"
|
|
85
|
+
: "MISTRAL_API_KEY";
|
|
86
|
+
_logger.info(`[codestral] Using key from ${keySource}`);
|
|
87
|
+
|
|
88
|
+
const allModels = [CODESTRAL_MODEL];
|
|
89
|
+
const freeModels = allModels; // All $0.30/$0.90 — still accessible via Experiment free tier
|
|
90
|
+
const stored = { free: freeModels, all: allModels };
|
|
91
|
+
|
|
92
|
+
// Re-register function — uses mistral-conversations API (Mistral SDK)
|
|
93
|
+
// NOT openai-completions: Codestral uses the same API format as Mistral
|
|
94
|
+
// and rejects OpenAI-specific fields (stream_options, store, max_completion_tokens) with 422.
|
|
95
|
+
const reRegister = (models: typeof freeModels) => {
|
|
96
|
+
pi.registerProvider(PROVIDER_CODESTRAL, {
|
|
97
|
+
baseUrl: BASE_URL_CODESTRAL,
|
|
98
|
+
apiKey,
|
|
99
|
+
api: "mistral-conversations" as const,
|
|
100
|
+
models: enhanceWithCI(models, PROVIDER_CODESTRAL),
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Register with global toggle
|
|
105
|
+
registerWithGlobalToggle(PROVIDER_CODESTRAL, stored, reRegister, true);
|
|
106
|
+
|
|
107
|
+
// Setup provider (toggle command, status bar, error handling)
|
|
108
|
+
setupProvider(
|
|
109
|
+
pi,
|
|
110
|
+
{
|
|
111
|
+
providerId: PROVIDER_CODESTRAL,
|
|
112
|
+
initialShowPaid: getCodestralShowPaid(),
|
|
113
|
+
skipToggle: true, // Only one model, no toggle needed
|
|
114
|
+
reRegister: (models) => {
|
|
115
|
+
stored.free = models;
|
|
116
|
+
stored.all = models;
|
|
117
|
+
reRegister(models);
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
stored,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// Initial registration — uses mistral-conversations API (Mistral SDK)
|
|
124
|
+
reRegister(freeModels);
|
|
125
|
+
|
|
126
|
+
_logger.info(`[codestral] Registered codestral-latest via ${keySource}`);
|
|
127
|
+
|
|
128
|
+
// Status bar
|
|
129
|
+
pi.on("model_select", (_event, ctx) => {
|
|
130
|
+
if (_event.model?.provider !== PROVIDER_CODESTRAL) {
|
|
131
|
+
ctx.ui.setStatus(`${PROVIDER_CODESTRAL}-status`, undefined);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
ctx.ui.setStatus(
|
|
135
|
+
`${PROVIDER_CODESTRAL}-status`,
|
|
136
|
+
`codestral: 1 model (free tier) 🔑`,
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
@@ -15,94 +15,16 @@
|
|
|
15
15
|
* # Models appear in /model selector
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type {
|
|
19
|
-
ExtensionAPI,
|
|
20
|
-
ProviderModelConfig,
|
|
21
|
-
} from "@mariozechner/pi-coding-agent";
|
|
18
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
22
19
|
import { getCrofaiApiKey, getCrofaiShowPaid } from "../../config.ts";
|
|
23
|
-
import {
|
|
24
|
-
BASE_URL_CROFAI,
|
|
25
|
-
DEFAULT_FETCH_TIMEOUT_MS,
|
|
26
|
-
PROVIDER_CROFAI,
|
|
27
|
-
} from "../../constants.ts";
|
|
20
|
+
import { BASE_URL_CROFAI, PROVIDER_CROFAI } from "../../constants.ts";
|
|
28
21
|
import { createLogger } from "../../lib/logger.ts";
|
|
29
|
-
import {
|
|
30
|
-
getProxyModelCompat,
|
|
31
|
-
isLikelyReasoningModel,
|
|
32
|
-
} from "../../lib/provider-compat.ts";
|
|
33
22
|
import { isFreeModel, registerWithGlobalToggle } from "../../lib/registry.ts";
|
|
34
|
-
import {
|
|
23
|
+
import { fetchOpenAICompatibleModels } from "../../lib/util.ts";
|
|
35
24
|
import { createReRegister, setupProvider } from "../../provider-helper.ts";
|
|
36
25
|
|
|
37
26
|
const _logger = createLogger("crofai");
|
|
38
27
|
|
|
39
|
-
// =============================================================================
|
|
40
|
-
// Fetch CrofAI models
|
|
41
|
-
// =============================================================================
|
|
42
|
-
|
|
43
|
-
interface CrofaiModel {
|
|
44
|
-
id: string;
|
|
45
|
-
object?: string;
|
|
46
|
-
created?: number;
|
|
47
|
-
owned_by?: string;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function fetchCrofaiModels(
|
|
51
|
-
apiKey: string,
|
|
52
|
-
): Promise<ProviderModelConfig[]> {
|
|
53
|
-
_logger.info("[crofai] Fetching models from CrofAI API...");
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const response = await fetchWithRetry(
|
|
57
|
-
`${BASE_URL_CROFAI}/models`,
|
|
58
|
-
{
|
|
59
|
-
headers: {
|
|
60
|
-
Authorization: `Bearer ${apiKey}`,
|
|
61
|
-
"Content-Type": "application/json",
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
3,
|
|
65
|
-
1000,
|
|
66
|
-
DEFAULT_FETCH_TIMEOUT_MS,
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
if (!response.ok) {
|
|
70
|
-
throw new Error(`CrofAI API error: ${response.status}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const data = (await response.json()) as { data?: CrofaiModel[] };
|
|
74
|
-
const models = data.data ?? [];
|
|
75
|
-
|
|
76
|
-
_logger.info(`[crofai] Fetched ${models.length} models`);
|
|
77
|
-
|
|
78
|
-
return models
|
|
79
|
-
.filter((m) => m.id) // Filter out any empty entries
|
|
80
|
-
.map((m) => {
|
|
81
|
-
const name = m.id.split("/").pop() || m.id;
|
|
82
|
-
return {
|
|
83
|
-
id: m.id,
|
|
84
|
-
name,
|
|
85
|
-
reasoning: isLikelyReasoningModel({ id: m.id, name }),
|
|
86
|
-
input: ["text"],
|
|
87
|
-
cost: {
|
|
88
|
-
input: 0, // CrofAI doesn't expose pricing via API
|
|
89
|
-
output: 0,
|
|
90
|
-
cacheRead: 0,
|
|
91
|
-
cacheWrite: 0,
|
|
92
|
-
},
|
|
93
|
-
contextWindow: 128000, // Default, varies by model
|
|
94
|
-
maxTokens: 4096,
|
|
95
|
-
compat: getProxyModelCompat({ id: m.id, name }),
|
|
96
|
-
} satisfies ProviderModelConfig;
|
|
97
|
-
});
|
|
98
|
-
} catch (error) {
|
|
99
|
-
_logger.error("[crofai] Failed to fetch models:", {
|
|
100
|
-
error: error instanceof Error ? error.message : String(error),
|
|
101
|
-
});
|
|
102
|
-
return [];
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
28
|
// =============================================================================
|
|
107
29
|
// Extension Entry Point
|
|
108
30
|
// =============================================================================
|
|
@@ -117,8 +39,12 @@ export default async function crofaiProvider(pi: ExtensionAPI) {
|
|
|
117
39
|
return;
|
|
118
40
|
}
|
|
119
41
|
|
|
120
|
-
// Fetch models
|
|
121
|
-
const allModels = await
|
|
42
|
+
// Fetch models via shared OpenAI-compatible helper
|
|
43
|
+
const allModels = await fetchOpenAICompatibleModels(
|
|
44
|
+
"crofai",
|
|
45
|
+
BASE_URL_CROFAI,
|
|
46
|
+
apiKey,
|
|
47
|
+
);
|
|
122
48
|
|
|
123
49
|
if (allModels.length === 0) {
|
|
124
50
|
_logger.warn("[crofai] No models available");
|
|
@@ -165,6 +91,9 @@ export default async function crofaiProvider(pi: ExtensionAPI) {
|
|
|
165
91
|
stored,
|
|
166
92
|
);
|
|
167
93
|
|
|
168
|
-
// Initial registration
|
|
169
|
-
|
|
94
|
+
// Initial registration — respect persisted toggle state
|
|
95
|
+
const showPaid = getCrofaiShowPaid();
|
|
96
|
+
const initialModels =
|
|
97
|
+
showPaid && stored.all.length > 0 ? stored.all : freeModels;
|
|
98
|
+
reRegister(initialModels);
|
|
170
99
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepInfra Provider Extension
|
|
3
|
+
*
|
|
4
|
+
* DeepInfra is an AI inference cloud with an OpenAI-compatible API for
|
|
5
|
+
* 100+ open-source models (Llama, DeepSeek, Mistral, Qwen, Mixtral, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Free tier:
|
|
8
|
+
* - $5 one-time credit on signup (no credit card)
|
|
9
|
+
* - ~5M tokens, expires after 90 days
|
|
10
|
+
* - 60 RPM (varies by model)
|
|
11
|
+
*
|
|
12
|
+
* Paid: pay-per-token after credits exhaust
|
|
13
|
+
*
|
|
14
|
+
* Endpoint:
|
|
15
|
+
* Chat: https://api.deepinfra.com/v1/openai/chat/completions
|
|
16
|
+
*
|
|
17
|
+
* Setup:
|
|
18
|
+
* 1. Sign up at https://deepinfra.com/ (GitHub or email)
|
|
19
|
+
* 2. Get API key from https://deepinfra.com/dash/api_keys
|
|
20
|
+
* 3. Set DEEPINFRA_TOKEN env var (or add to ~/.pi/free.json)
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
* pi install git:github.com/apmantza/pi-free
|
|
24
|
+
* # Set DEEPINFRA_TOKEN env var
|
|
25
|
+
* # Models appear in /model selector as "deepinfra/meta-llama/..."
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
ExtensionAPI,
|
|
30
|
+
ProviderModelConfig,
|
|
31
|
+
} from "@earendil-works/pi-coding-agent";
|
|
32
|
+
import { getDeepinfraApiKey } from "../../config.ts";
|
|
33
|
+
import { BASE_URL_DEEPINFRA, PROVIDER_DEEPINFRA } from "../../constants.ts";
|
|
34
|
+
import { createLogger } from "../../lib/logger.ts";
|
|
35
|
+
import { registerWithGlobalToggle } from "../../lib/registry.ts";
|
|
36
|
+
import { fetchOpenAICompatibleModels } from "../../lib/util.ts";
|
|
37
|
+
import { createReRegister, setupProvider } from "../../provider-helper.ts";
|
|
38
|
+
|
|
39
|
+
const _logger = createLogger("deepinfra");
|
|
40
|
+
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// Extension Entry Point
|
|
43
|
+
// =============================================================================
|
|
44
|
+
|
|
45
|
+
export default async function deepinfraProvider(pi: ExtensionAPI) {
|
|
46
|
+
const apiKey = getDeepinfraApiKey();
|
|
47
|
+
|
|
48
|
+
if (!apiKey) {
|
|
49
|
+
_logger.info(
|
|
50
|
+
"[deepinfra] Skipping — DEEPINFRA_TOKEN not set. Sign up at https://deepinfra.com/",
|
|
51
|
+
);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Fetch models via shared OpenAI-compatible helper
|
|
56
|
+
const allModels = await fetchOpenAICompatibleModels(
|
|
57
|
+
"deepinfra",
|
|
58
|
+
BASE_URL_DEEPINFRA,
|
|
59
|
+
apiKey,
|
|
60
|
+
{ cost: { input: 0.3, output: 0.9 } },
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (allModels.length === 0) {
|
|
64
|
+
_logger.warn("[deepinfra] No models available");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// DeepInfra is a trial credit provider — $5 one-time credit, no truly free models.
|
|
69
|
+
// All models are marked as paid. When free-only mode is ON, no models are shown.
|
|
70
|
+
// Toggle free-only OFF to see all models.
|
|
71
|
+
const freeModels: ProviderModelConfig[] = [];
|
|
72
|
+
const stored = { free: freeModels, all: allModels };
|
|
73
|
+
|
|
74
|
+
_logger.info(
|
|
75
|
+
`[deepinfra] Registered ${allModels.length} models (trial credit, 0 free)`,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Create re-register function
|
|
79
|
+
const reRegister = createReRegister(pi, {
|
|
80
|
+
providerId: PROVIDER_DEEPINFRA,
|
|
81
|
+
baseUrl: BASE_URL_DEEPINFRA,
|
|
82
|
+
apiKey,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Register with global toggle
|
|
86
|
+
registerWithGlobalToggle(PROVIDER_DEEPINFRA, stored, reRegister, true);
|
|
87
|
+
|
|
88
|
+
// Setup provider with toggle command
|
|
89
|
+
setupProvider(
|
|
90
|
+
pi,
|
|
91
|
+
{
|
|
92
|
+
providerId: PROVIDER_DEEPINFRA,
|
|
93
|
+
initialShowPaid: true, // trial credit: default to showing all models
|
|
94
|
+
tosUrl: "https://deepinfra.com/pricing",
|
|
95
|
+
reRegister: (models, _stored) => {
|
|
96
|
+
if (_stored) {
|
|
97
|
+
stored.free = _stored.free;
|
|
98
|
+
stored.all = _stored.all;
|
|
99
|
+
}
|
|
100
|
+
reRegister(models);
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
stored,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// Initial registration — DeepInfra is a trial-credit provider,
|
|
107
|
+
// so always show all models. Users see them immediately on setup.
|
|
108
|
+
reRegister(allModels);
|
|
109
|
+
}
|