pi-free 2.0.1 → 2.0.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 +179 -3
- package/README.md +495 -393
- package/config.ts +46 -54
- package/constants.ts +6 -0
- package/index.ts +39 -12
- package/lib/built-in-toggle.ts +63 -43
- 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 +193 -144
- package/lib/toggle-state.ts +86 -0
- package/lib/types.ts +101 -108
- package/package.json +8 -8
- package/provider-failover/benchmark-lookup.ts +637 -247
- package/provider-helper.ts +279 -260
- package/providers/cline/cline-auth.ts +473 -473
- package/providers/cline/cline-models.ts +129 -128
- package/providers/cline/cline.ts +311 -298
- package/providers/crofai/crofai.ts +170 -0
- package/providers/dynamic-built-in/index.ts +259 -308
- package/providers/kilo/kilo-auth.ts +155 -155
- package/providers/kilo/kilo-models.ts +2 -1
- package/providers/kilo/kilo.ts +263 -235
- package/providers/nvidia/nvidia.ts +476 -152
- package/providers/ollama/ollama.ts +130 -7
- package/providers/opencode-session.ts +3 -4
- package/providers/qwen/qwen-models.ts +101 -101
- package/providers/zenmux/zenmux.ts +176 -0
- package/scripts/check-extensions.mjs +64 -55
- package/provider-factory.ts +0 -207
- package/providers/cloudflare/cloudflare.ts +0 -368
- package/providers/modal/modal.ts +0 -44
package/provider-helper.ts
CHANGED
|
@@ -1,260 +1,279 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared provider setup helpers for pi-free-providers.
|
|
3
|
-
* Extracts the common boilerplate pattern repeated across providers:
|
|
4
|
-
* - toggle-{provider} command to switch between free/paid models
|
|
5
|
-
* - model_select handler (clear status for other providers)
|
|
6
|
-
* - turn_end handler (provider-specific error hook)
|
|
7
|
-
* - before_agent_start handler (one-time ToS notice)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
ExtensionAPI,
|
|
12
|
-
ProviderModelConfig,
|
|
13
|
-
} from "@mariozechner/pi-coding-agent";
|
|
14
|
-
import { saveConfig } from "./config.ts";
|
|
15
|
-
import { createLogger } from "./lib/logger.ts";
|
|
16
|
-
import { enhanceModelNameWithCodingIndex } from "./provider-failover/benchmark-lookup.ts";
|
|
17
|
-
|
|
18
|
-
const _logger = createLogger("provider-helper");
|
|
19
|
-
|
|
20
|
-
// =============================================================================
|
|
21
|
-
// Types
|
|
22
|
-
// =============================================================================
|
|
23
|
-
|
|
24
|
-
export interface ProviderSetupConfig {
|
|
25
|
-
/** Provider identifier (e.g., "kilo", "openrouter"). */
|
|
26
|
-
providerId: string;
|
|
27
|
-
/** Terms of service URL. If set, shows a one-time notice on first free use. */
|
|
28
|
-
tosUrl?: string;
|
|
29
|
-
/** When true, suppresses the "free models / set API key" ToS notice. */
|
|
30
|
-
hasKey?: boolean;
|
|
31
|
-
/** Initial mode - auto-detected from config at startup. */
|
|
32
|
-
initialShowPaid?: boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Called by toggle-{provider} command to re-register
|
|
35
|
-
* the provider with the given model set.
|
|
36
|
-
*/
|
|
37
|
-
reRegister: (models: ProviderModelConfig[], stored: StoredModels) => void;
|
|
38
|
-
/** Optional custom error handler. Return true if handled. */
|
|
39
|
-
onError?: (
|
|
40
|
-
error: unknown,
|
|
41
|
-
ctx: {
|
|
42
|
-
ui: { notify: (m: string, t: "info" | "warning" | "error") => void };
|
|
43
|
-
},
|
|
44
|
-
) => Promise<boolean>;
|
|
45
|
-
/** When true, skips creating the toggle-{provider} command. Useful for providers with only one model. */
|
|
46
|
-
skipToggle?: boolean;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface StoredModels {
|
|
50
|
-
free: ProviderModelConfig[];
|
|
51
|
-
all: ProviderModelConfig[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// =============================================================================
|
|
55
|
-
// Provider Registration Helpers
|
|
56
|
-
// =============================================================================
|
|
57
|
-
|
|
58
|
-
export interface OpenAICompatibleConfig {
|
|
59
|
-
/** Provider identifier (e.g., "nvidia", "modal") */
|
|
60
|
-
providerId: string;
|
|
61
|
-
/** Base URL for the API */
|
|
62
|
-
baseUrl: string;
|
|
63
|
-
/** Environment variable name for the API key */
|
|
64
|
-
apiKey: string;
|
|
65
|
-
/** Additional headers to include */
|
|
66
|
-
headers?: Record<string, string>;
|
|
67
|
-
/** OAuth configuration (optional) */
|
|
68
|
-
oauth?: {
|
|
69
|
-
name: string;
|
|
70
|
-
login: (callbacks: unknown) => Promise<unknown>;
|
|
71
|
-
refreshToken?: (cred: unknown) => Promise<unknown>;
|
|
72
|
-
getApiKey?: (cred: unknown) => string;
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Enhance all model names with Coding Index scores
|
|
78
|
-
* Use this for direct provider registration (not through setupProvider)
|
|
79
|
-
*/
|
|
80
|
-
export function enhanceWithCI(
|
|
81
|
-
models: ProviderModelConfig[],
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
*
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
*
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Shared provider setup helpers for pi-free-providers.
|
|
3
|
+
* Extracts the common boilerplate pattern repeated across providers:
|
|
4
|
+
* - toggle-{provider} command to switch between free/paid models
|
|
5
|
+
* - model_select handler (clear status for other providers)
|
|
6
|
+
* - turn_end handler (provider-specific error hook)
|
|
7
|
+
* - before_agent_start handler (one-time ToS notice)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
ExtensionAPI,
|
|
12
|
+
ProviderModelConfig,
|
|
13
|
+
} from "@mariozechner/pi-coding-agent";
|
|
14
|
+
import { saveConfig } from "./config.ts";
|
|
15
|
+
import { createLogger } from "./lib/logger.ts";
|
|
16
|
+
import { enhanceModelNameWithCodingIndex } from "./provider-failover/benchmark-lookup.ts";
|
|
17
|
+
|
|
18
|
+
const _logger = createLogger("provider-helper");
|
|
19
|
+
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// Types
|
|
22
|
+
// =============================================================================
|
|
23
|
+
|
|
24
|
+
export interface ProviderSetupConfig {
|
|
25
|
+
/** Provider identifier (e.g., "kilo", "openrouter"). */
|
|
26
|
+
providerId: string;
|
|
27
|
+
/** Terms of service URL. If set, shows a one-time notice on first free use. */
|
|
28
|
+
tosUrl?: string;
|
|
29
|
+
/** When true, suppresses the "free models / set API key" ToS notice. */
|
|
30
|
+
hasKey?: boolean;
|
|
31
|
+
/** Initial mode - auto-detected from config at startup. */
|
|
32
|
+
initialShowPaid?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Called by toggle-{provider} command to re-register
|
|
35
|
+
* the provider with the given model set.
|
|
36
|
+
*/
|
|
37
|
+
reRegister: (models: ProviderModelConfig[], stored: StoredModels) => void;
|
|
38
|
+
/** Optional custom error handler. Return true if handled. */
|
|
39
|
+
onError?: (
|
|
40
|
+
error: unknown,
|
|
41
|
+
ctx: {
|
|
42
|
+
ui: { notify: (m: string, t: "info" | "warning" | "error") => void };
|
|
43
|
+
},
|
|
44
|
+
) => Promise<boolean>;
|
|
45
|
+
/** When true, skips creating the toggle-{provider} command. Useful for providers with only one model. */
|
|
46
|
+
skipToggle?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface StoredModels {
|
|
50
|
+
free: ProviderModelConfig[];
|
|
51
|
+
all: ProviderModelConfig[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// =============================================================================
|
|
55
|
+
// Provider Registration Helpers
|
|
56
|
+
// =============================================================================
|
|
57
|
+
|
|
58
|
+
export interface OpenAICompatibleConfig {
|
|
59
|
+
/** Provider identifier (e.g., "nvidia", "modal") */
|
|
60
|
+
providerId: string;
|
|
61
|
+
/** Base URL for the API */
|
|
62
|
+
baseUrl: string;
|
|
63
|
+
/** Environment variable name for the API key */
|
|
64
|
+
apiKey: string;
|
|
65
|
+
/** Additional headers to include */
|
|
66
|
+
headers?: Record<string, string>;
|
|
67
|
+
/** OAuth configuration (optional) */
|
|
68
|
+
oauth?: {
|
|
69
|
+
name: string;
|
|
70
|
+
login: (callbacks: unknown) => Promise<unknown>;
|
|
71
|
+
refreshToken?: (cred: unknown) => Promise<unknown>;
|
|
72
|
+
getApiKey?: (cred: unknown) => string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Enhance all model names with Coding Index scores
|
|
78
|
+
* Use this for direct provider registration (not through setupProvider)
|
|
79
|
+
*/
|
|
80
|
+
export function enhanceWithCI(
|
|
81
|
+
models: ProviderModelConfig[],
|
|
82
|
+
providerId?: string,
|
|
83
|
+
): ProviderModelConfig[] {
|
|
84
|
+
return models.map((m) => ({
|
|
85
|
+
...m,
|
|
86
|
+
name: enhanceModelNameWithCodingIndex(m.name, m.id, providerId),
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Register an OpenAI-compatible provider with standard headers.
|
|
92
|
+
* Reduces boilerplate across providers that use the OpenAI API format.
|
|
93
|
+
*/
|
|
94
|
+
export function registerOpenAICompatible(
|
|
95
|
+
pi: ExtensionAPI,
|
|
96
|
+
config: OpenAICompatibleConfig,
|
|
97
|
+
models: ProviderModelConfig[],
|
|
98
|
+
): void {
|
|
99
|
+
const { providerId, baseUrl, apiKey, headers, oauth } = config;
|
|
100
|
+
|
|
101
|
+
pi.registerProvider(providerId, {
|
|
102
|
+
baseUrl,
|
|
103
|
+
apiKey,
|
|
104
|
+
api: "openai-completions" as const,
|
|
105
|
+
headers: {
|
|
106
|
+
"User-Agent": "pi-free-providers",
|
|
107
|
+
...headers,
|
|
108
|
+
},
|
|
109
|
+
models: enhanceWithCI(models, providerId),
|
|
110
|
+
...(oauth && { oauth: oauth as any }),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Create a reRegister function for use with setupProvider.
|
|
116
|
+
* Returns a function that re-registers the provider with new models.
|
|
117
|
+
*/
|
|
118
|
+
export function createReRegister(
|
|
119
|
+
pi: ExtensionAPI,
|
|
120
|
+
config: OpenAICompatibleConfig,
|
|
121
|
+
): (models: ProviderModelConfig[]) => void {
|
|
122
|
+
return (models: ProviderModelConfig[]) => {
|
|
123
|
+
registerOpenAICompatible(pi, config, models);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a reRegister function that uses ctx.modelRegistry.registerProvider.
|
|
129
|
+
* Used by providers that need to register with runtime context (session_start handlers).
|
|
130
|
+
*/
|
|
131
|
+
export function createCtxReRegister(
|
|
132
|
+
ctx: {
|
|
133
|
+
modelRegistry: { registerProvider: (id: string, config: unknown) => void };
|
|
134
|
+
},
|
|
135
|
+
config: OpenAICompatibleConfig,
|
|
136
|
+
): (models: ProviderModelConfig[]) => void {
|
|
137
|
+
const { providerId, baseUrl, apiKey, headers, oauth } = config;
|
|
138
|
+
|
|
139
|
+
return (models: ProviderModelConfig[]) => {
|
|
140
|
+
ctx.modelRegistry.registerProvider(providerId, {
|
|
141
|
+
baseUrl,
|
|
142
|
+
apiKey,
|
|
143
|
+
api: "openai-completions" as const,
|
|
144
|
+
headers: {
|
|
145
|
+
"User-Agent": "pi-free-providers",
|
|
146
|
+
...headers,
|
|
147
|
+
},
|
|
148
|
+
models: enhanceWithCI(models, providerId),
|
|
149
|
+
...(oauth && { oauth: oauth as any }),
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get the config key name for a provider's show_paid setting.
|
|
156
|
+
*/
|
|
157
|
+
function getShowPaidConfigKey(providerId: string): string {
|
|
158
|
+
return `${providerId}_show_paid`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function setupProvider(
|
|
162
|
+
pi: ExtensionAPI,
|
|
163
|
+
config: ProviderSetupConfig,
|
|
164
|
+
stored: StoredModels,
|
|
165
|
+
): void {
|
|
166
|
+
const { providerId, tosUrl, initialShowPaid = false } = config;
|
|
167
|
+
|
|
168
|
+
// Track current mode (synced with config)
|
|
169
|
+
let currentShowPaid = initialShowPaid;
|
|
170
|
+
|
|
171
|
+
// Wrap reRegister to automatically add CI scores to all models
|
|
172
|
+
const reRegister = (models: ProviderModelConfig[], _s: StoredModels) => {
|
|
173
|
+
const enhanced = enhanceWithCI(models, providerId);
|
|
174
|
+
config.reRegister(enhanced, _s);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// ── Single toggle command (skip if requested) ──────────────────────
|
|
178
|
+
|
|
179
|
+
if (!config.skipToggle) {
|
|
180
|
+
pi.registerCommand(`toggle-${providerId}`, {
|
|
181
|
+
description: `Toggle between free and all ${providerId} models`,
|
|
182
|
+
handler: async (_args, ctx) => {
|
|
183
|
+
// Toggle the mode
|
|
184
|
+
currentShowPaid = !currentShowPaid;
|
|
185
|
+
|
|
186
|
+
// Persist to config file
|
|
187
|
+
const configKey = getShowPaidConfigKey(providerId);
|
|
188
|
+
saveConfig({ [configKey]: currentShowPaid });
|
|
189
|
+
|
|
190
|
+
// Re-register with appropriate model set
|
|
191
|
+
if (currentShowPaid) {
|
|
192
|
+
if (stored.all.length === 0) {
|
|
193
|
+
ctx.ui.notify("No models available", "warning");
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
reRegister(stored.all, stored);
|
|
197
|
+
ctx.ui.notify(
|
|
198
|
+
`${providerId}: showing all ${stored.all.length} models (including paid)`,
|
|
199
|
+
"info",
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
if (stored.free.length === 0) {
|
|
203
|
+
ctx.ui.notify("No free models loaded", "warning");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
reRegister(stored.free, stored);
|
|
207
|
+
ctx.ui.notify(
|
|
208
|
+
`${providerId}: showing ${stored.free.length} free models`,
|
|
209
|
+
"info",
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ── Status bar for selected provider ───────────────────────────
|
|
217
|
+
|
|
218
|
+
pi.on("model_select", (_event, ctx) => {
|
|
219
|
+
if (_event.model?.provider !== providerId) {
|
|
220
|
+
ctx.ui.setStatus(`${providerId}-status`, undefined);
|
|
221
|
+
return;
|
|
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);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// ── Error handling / usage tracking are temporarily deprecated ─────────
|
|
243
|
+
|
|
244
|
+
pi.on("turn_end", async (event, ctx) => {
|
|
245
|
+
if (ctx.model?.provider !== providerId) return;
|
|
246
|
+
|
|
247
|
+
const msg = (
|
|
248
|
+
event as { message?: { role?: string; errorMessage?: string } }
|
|
249
|
+
).message;
|
|
250
|
+
|
|
251
|
+
if (msg?.role === "assistant" && msg.errorMessage) {
|
|
252
|
+
_logger.info("Provider error (auto model hopping disabled)", {
|
|
253
|
+
provider: providerId,
|
|
254
|
+
error: msg.errorMessage.slice(0, 100),
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Keep custom handlers working for provider-specific logic.
|
|
258
|
+
if (config.onError) {
|
|
259
|
+
await config.onError(msg.errorMessage, ctx);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// ── ToS notice on first use ────────────────────────────────
|
|
265
|
+
if (tosUrl) {
|
|
266
|
+
let tosShown = false;
|
|
267
|
+
pi.on("model_select", async (_event, ctx) => {
|
|
268
|
+
if (tosShown || ctx.model?.provider !== providerId) return;
|
|
269
|
+
tosShown = true;
|
|
270
|
+
if (config.hasKey) return;
|
|
271
|
+
const cred = ctx.modelRegistry.authStorage.get(providerId);
|
|
272
|
+
if (cred?.type === "oauth") return;
|
|
273
|
+
ctx.ui.notify(
|
|
274
|
+
`Using ${providerId} free models. Set API key for paid access. Terms: ${tosUrl}`,
|
|
275
|
+
"info",
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|