@xopcai/xopc 0.0.102 → 0.0.103
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/transport/webhook/monitor.js +2 -2
- package/dist/extensions/feishu/src/transport/webhook/monitor.js.map +1 -1
- package/dist/extensions/telegram/src/send-options.js +8 -5
- package/dist/extensions/telegram/src/send-options.js.map +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agents-DQ0mQxIA.js → agents-BwXkia_W.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-Uv4kOmDE.js → apps-page-C5RmwmTT.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BEtP53V6.js → channels-settings-tlOTdaXw.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-CxTtS1hI.js → channels-status-swr-D4XjqwqC.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-CznlPIZT.js → cron-api-DcmfGuj0.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-Dx6dE3eD.js → cron-page-CijJ4G6F.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-DH4IuRV0.js → dist-CWm8hTXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BNkhvRQW.js → extension-debug-page-BzYgTkS9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CcIGQah2.js → extension-page-BmTZH6gL.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DuDCSb3J.js → extension-settings-page-CyJk_G64.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-drJUxxKP.js → fetch-CMoWY2Si.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-BUwUiDf5.js → field-primitives-C4GpxsDo.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BjFW1cl-.js → heartbeat-config-api-CLD0Gpi3.js} +1 -1
- package/dist/gateway/static/root/assets/index-0HmunJW9.js +4845 -0
- package/dist/gateway/static/root/assets/index-Bk75Phrd.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-CiG0m81R.js → logs-page-BjdQjHwk.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-DG3DVFTf.js → note-detail-page-8Er4197b.js} +1 -1
- package/dist/gateway/static/root/assets/{note-time-DjlllCF3.js → note-time-CF3vf1jm.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-D40ZpS0Y.js → notes-page-BBnTh0uI.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-BvtdbmW8.js → sessions-page-B0riYK7j.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-BQamRjkV.js → settings-advanced-gate-DiP_WHu_.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-C3_sEFfD.js → settings-form-section-C7qA7y0J.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-D972_jaS.js → settings-page-1ZPhcCZ9.js} +2 -2
- package/dist/gateway/static/root/assets/share-preview-page-Tvr5Mtq5.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page-QwFCB4yV.js → skills-page-BQ1hllKD.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-B6KXPHgK.js → theme-store-HTvJlFLL.js} +1 -1
- package/dist/gateway/static/root/assets/url-F3_D_6zZ.js +3 -0
- package/dist/gateway/static/root/assets/{utils-DCm11_KW.js → utils-CPr3FBh2.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CywiB7Dw.js → voice-api-key-field-BkbDl6dH.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-g57BRfEd.js → workflow-page.utils-CeBkAjP7.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-Be7l_SWw.js → workflows-page-D059ysoF.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/inbound/attachment-pipeline.js +2 -2
- package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -1
- package/dist/src/agent/tools/send-media.js +1 -2
- package/dist/src/agent/tools/send-media.js.map +1 -1
- package/dist/src/auth/credentials.d.ts +7 -0
- package/dist/src/auth/credentials.js +35 -2
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/auth/index.d.ts +1 -1
- package/dist/src/auth/index.js.map +1 -1
- package/dist/src/auth/oauth/github-copilot.d.ts +1 -1
- package/dist/src/auth/oauth/google-antigravity.d.ts +1 -3
- package/dist/src/auth/oauth/google-antigravity.js +1 -1
- package/dist/src/auth/oauth/google-gemini-cli.d.ts +1 -3
- package/dist/src/auth/oauth/google-gemini-cli.js +1 -1
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.js +3 -5
- package/dist/src/auth/oauth/google-oauth/google-antigravity.js.map +1 -0
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.js +4 -5
- package/dist/src/auth/oauth/google-oauth/google-gemini-cli.js.map +1 -0
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.js +12 -4
- package/dist/src/auth/oauth/google-oauth/oauth-page.js.map +1 -0
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.d.ts +1 -1
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.js +2 -2
- package/dist/src/auth/oauth/google-oauth/pkce.js.map +1 -0
- package/dist/src/auth/oauth/index.js +2 -2
- package/dist/src/auth/oauth/kimi-coding.d.ts +1 -1
- package/dist/src/auth/oauth/kimi-coding.js +1 -1
- package/dist/src/auth/oauth/kimi-coding.js.map +1 -1
- package/dist/src/auth/oauth/minimax-cn.js +1 -1
- package/dist/src/auth/oauth/minimax-cn.js.map +1 -1
- package/dist/src/auth/oauth/minimax.js +1 -1
- package/dist/src/auth/oauth/minimax.js.map +1 -1
- package/dist/src/auth/oauth/openai-codex.d.ts +7 -2
- package/dist/src/auth/oauth/openai-codex.js +318 -1
- package/dist/src/auth/oauth/openai-codex.js.map +1 -0
- package/dist/src/auth/profiles/store.js +3 -2
- package/dist/src/auth/profiles/store.js.map +1 -1
- package/dist/src/channels/attachments/attachment-classifiers.d.ts +1 -0
- package/dist/src/channels/attachments/attachment-classifiers.js +13 -2
- package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -1
- package/dist/src/chat-commands/builtins/model.js +2 -2
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- package/dist/src/cli/command-manifest.js +1 -1
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/auth.js +39 -51
- package/dist/src/cli/commands/auth.js.map +1 -1
- package/dist/src/cli/commands/models.js +189 -54
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.d.ts +1 -4
- package/dist/src/cli/commands/onboard/model.js +253 -183
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/utils/oauth-login.d.ts +17 -0
- package/dist/src/cli/utils/oauth-login.js +93 -0
- package/dist/src/cli/utils/oauth-login.js.map +1 -0
- package/dist/src/cli/utils/oauth-providers.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/oauth-async.js +2 -2
- package/dist/src/gateway/hono/oauth.js +2 -2
- package/dist/src/gateway/hono/routes/models.js +25 -5
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/media/store.js +3 -0
- package/dist/src/media/store.js.map +1 -1
- package/dist/src/notes/service.js +1 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/index.d.ts +3 -3
- package/dist/src/providers/index.js +23 -15
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/presentation.d.ts +34 -0
- package/dist/src/providers/presentation.js +162 -0
- package/dist/src/providers/presentation.js.map +1 -0
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/index-DKgHC1Ta.js +0 -4840
- package/dist/gateway/static/root/assets/index-DjNDHzwG.css +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-CKCTMo0_.js +0 -2
- package/dist/gateway/static/root/assets/url-q28QhI7l.js +0 -3
- package/dist/src/auth/oauth/vendor-pi-google/google-antigravity.js.map +0 -1
- package/dist/src/auth/oauth/vendor-pi-google/google-gemini-cli.js.map +0 -1
- package/dist/src/auth/oauth/vendor-pi-google/oauth-page.js.map +0 -1
- package/dist/src/auth/oauth/vendor-pi-google/pkce.js.map +0 -1
- /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.d.ts +0 -0
- /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.d.ts +0 -0
- /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.d.ts +0 -0
|
@@ -38,6 +38,13 @@ var providers_exports = /* @__PURE__ */ __exportAll({
|
|
|
38
38
|
resetModelRegistry: () => resetModelRegistry,
|
|
39
39
|
resolveModel: () => resolveModel
|
|
40
40
|
});
|
|
41
|
+
function normalizeProviderModel(model) {
|
|
42
|
+
if (model.provider === "openai-codex" && model.api === "openai-codex-responses") return {
|
|
43
|
+
...model,
|
|
44
|
+
baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL
|
|
45
|
+
};
|
|
46
|
+
return model;
|
|
47
|
+
}
|
|
41
48
|
/** Map a plugin registry model to the pi-ai {@link Model} shape. */
|
|
42
49
|
function pluginModelToModel(providerId, definition) {
|
|
43
50
|
return {
|
|
@@ -80,7 +87,7 @@ function resolveModel(ref) {
|
|
|
80
87
|
if (ref.includes("/")) {
|
|
81
88
|
const [provider, modelId] = ref.split("/");
|
|
82
89
|
const piAiModel = getModel(provider, modelId);
|
|
83
|
-
if (piAiModel) return piAiModel;
|
|
90
|
+
if (piAiModel) return normalizeProviderModel(piAiModel);
|
|
84
91
|
const plugin = getProviderRegistry().get(provider);
|
|
85
92
|
if (plugin) {
|
|
86
93
|
const pluginModel = plugin.models.find((m) => m.id === modelId);
|
|
@@ -90,7 +97,7 @@ function resolveModel(ref) {
|
|
|
90
97
|
}
|
|
91
98
|
for (const provider of getProviders()) try {
|
|
92
99
|
const found = getModels(provider).find((m) => m.id === ref);
|
|
93
|
-
if (found) return found;
|
|
100
|
+
if (found) return normalizeProviderModel(found);
|
|
94
101
|
} catch {
|
|
95
102
|
continue;
|
|
96
103
|
}
|
|
@@ -102,7 +109,7 @@ function resolveModel(ref) {
|
|
|
102
109
|
throw new Error(`Model not found: ${ref}. Use format: provider/model-id`);
|
|
103
110
|
}
|
|
104
111
|
function getModelsByProvider(provider) {
|
|
105
|
-
const fromRegistry = getModelRegistry().getAll().filter((m) => m.provider === provider);
|
|
112
|
+
const fromRegistry = getModelRegistry().getAll().filter((m) => m.provider === provider).map(normalizeProviderModel);
|
|
106
113
|
const plugin = getProviderRegistry().get(provider);
|
|
107
114
|
if (!plugin) return fromRegistry;
|
|
108
115
|
const pluginModels = plugin.models.map((m) => pluginModelToModel(provider, m));
|
|
@@ -191,7 +198,7 @@ async function getConfiguredProviders() {
|
|
|
191
198
|
return configured;
|
|
192
199
|
}
|
|
193
200
|
function getAllModels() {
|
|
194
|
-
const registryModels = getModelRegistry().getAll();
|
|
201
|
+
const registryModels = getModelRegistry().getAll().map(normalizeProviderModel);
|
|
195
202
|
const pluginProviders = getProviderRegistry().listAll();
|
|
196
203
|
if (pluginProviders.length === 0) return registryModels;
|
|
197
204
|
const existingIds = new Set(registryModels.map((m) => `${m.provider}/${m.id}`));
|
|
@@ -245,7 +252,7 @@ function providerSupportsApiKey(provider) {
|
|
|
245
252
|
* Get a default model reference.
|
|
246
253
|
* Priority:
|
|
247
254
|
* 1. Explicitly configured model in agents.defaults.model (if set and available)
|
|
248
|
-
* 2. Default fallback:
|
|
255
|
+
* 2. Default fallback: openai/gpt-5.5
|
|
249
256
|
*/
|
|
250
257
|
async function getDefaultModel(config) {
|
|
251
258
|
const defaultModel = config?.agents?.defaults?.model;
|
|
@@ -264,8 +271,8 @@ async function getDefaultModel(config) {
|
|
|
264
271
|
* Uses catalog/registry only (no async credential checks).
|
|
265
272
|
*
|
|
266
273
|
* When no model is explicitly configured, returns the preferred default
|
|
267
|
-
* (`
|
|
268
|
-
*
|
|
274
|
+
* (`openai/gpt-5.5`) rather than picking an arbitrary first model from the
|
|
275
|
+
* full catalog.
|
|
269
276
|
*/
|
|
270
277
|
function getDefaultModelSync(config) {
|
|
271
278
|
const defaultModel = config?.agents?.defaults?.model;
|
|
@@ -275,7 +282,7 @@ function getDefaultModelSync(config) {
|
|
|
275
282
|
}
|
|
276
283
|
return DEFAULT_FALLBACK_MODEL;
|
|
277
284
|
}
|
|
278
|
-
var EXTENSION_PROVIDER_BASE_URL, PROVIDER_META, DEFAULT_FALLBACK_MODEL;
|
|
285
|
+
var EXTENSION_PROVIDER_BASE_URL, OPENAI_CODEX_CANONICAL_BASE_URL, PROVIDER_META, DEFAULT_FALLBACK_MODEL;
|
|
279
286
|
var init_providers = __esmMin((() => {
|
|
280
287
|
init_model_registry();
|
|
281
288
|
init_credentials();
|
|
@@ -283,14 +290,15 @@ var init_providers = __esmMin((() => {
|
|
|
283
290
|
init_env_keys();
|
|
284
291
|
init_plugin_registry();
|
|
285
292
|
EXTENSION_PROVIDER_BASE_URL = "extension://provider-plugin";
|
|
293
|
+
OPENAI_CODEX_CANONICAL_BASE_URL = "https://chatgpt.com/backend-api/codex";
|
|
286
294
|
PROVIDER_META = {
|
|
287
295
|
"openai": {
|
|
288
|
-
name: "OpenAI
|
|
296
|
+
name: "OpenAI",
|
|
289
297
|
category: "common",
|
|
290
298
|
supportsApiKey: true
|
|
291
299
|
},
|
|
292
300
|
"anthropic": {
|
|
293
|
-
name: "Anthropic
|
|
301
|
+
name: "Anthropic",
|
|
294
302
|
category: "common",
|
|
295
303
|
supportsApiKey: true,
|
|
296
304
|
supportsOAuth: true
|
|
@@ -301,12 +309,12 @@ var init_providers = __esmMin((() => {
|
|
|
301
309
|
supportsApiKey: true
|
|
302
310
|
},
|
|
303
311
|
"google": {
|
|
304
|
-
name: "Google
|
|
312
|
+
name: "Google AI",
|
|
305
313
|
category: "common",
|
|
306
314
|
supportsApiKey: true
|
|
307
315
|
},
|
|
308
316
|
"groq": {
|
|
309
|
-
name: "Groq
|
|
317
|
+
name: "Groq",
|
|
310
318
|
category: "common",
|
|
311
319
|
supportsApiKey: true
|
|
312
320
|
},
|
|
@@ -329,7 +337,7 @@ var init_providers = __esmMin((() => {
|
|
|
329
337
|
supportsOAuth: true
|
|
330
338
|
},
|
|
331
339
|
"xai": {
|
|
332
|
-
name: "xAI
|
|
340
|
+
name: "xAI",
|
|
333
341
|
category: "specialty",
|
|
334
342
|
supportsApiKey: true
|
|
335
343
|
},
|
|
@@ -344,7 +352,7 @@ var init_providers = __esmMin((() => {
|
|
|
344
352
|
supportsApiKey: true
|
|
345
353
|
},
|
|
346
354
|
"openrouter": {
|
|
347
|
-
name: "OpenRouter
|
|
355
|
+
name: "OpenRouter",
|
|
348
356
|
category: "specialty",
|
|
349
357
|
supportsApiKey: true
|
|
350
358
|
},
|
|
@@ -470,7 +478,7 @@ var init_providers = __esmMin((() => {
|
|
|
470
478
|
supportsApiKey: false
|
|
471
479
|
}
|
|
472
480
|
};
|
|
473
|
-
DEFAULT_FALLBACK_MODEL = "
|
|
481
|
+
DEFAULT_FALLBACK_MODEL = "openai/gpt-5.5";
|
|
474
482
|
}));
|
|
475
483
|
//#endregion
|
|
476
484
|
init_providers();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@earendil-works/pi-ai';\nimport type { Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(ref);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (ref.includes('/')) {\n\t\tconst [provider, modelId] = ref.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return piAiModel as Model<Api>;\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${ref}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === ref);\n\t\t\tif (found) return found as Model<Api>;\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === ref);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${ref}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport type ProviderAuthMode = ProviderActiveKeySource;\nexport type ProviderAuthStatus = 'connected' | 'expired' | 'not_connected';\n\nexport interface ProviderAuthState {\n authMode: ProviderAuthMode;\n authStatus: ProviderAuthStatus;\n expiresAt?: number;\n}\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n const authState = await getProviderAuthState(provider);\n return authState.authMode;\n}\n\nexport async function getProviderAuthState(provider: string): Promise<ProviderAuthState> {\n if (getProviderRegistry().has(provider)) {\n return { authMode: 'extension', authStatus: 'connected' };\n }\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return { authMode: 'agent', authStatus: 'connected' };\n if (fromCredentials === 'global') return { authMode: 'gateway', authStatus: 'connected' };\n if (fromCredentials === 'oauth') {\n const token = await resolver.loadOAuthTokenRecord(provider);\n const expired = Boolean(token?.expiresAt && token.expiresAt < Date.now());\n return {\n authMode: 'oauth',\n authStatus: expired ? 'expired' : 'connected',\n ...(token?.expiresAt ? { expiresAt: token.expiresAt } : {}),\n };\n }\n if (fromCredentials === 'env') return { authMode: 'env', authStatus: 'connected' };\n\n const expiredOAuthToken = await resolver.loadOAuthTokenRecord(provider);\n if (expiredOAuthToken?.expiresAt && expiredOAuthToken.expiresAt < Date.now()) {\n return {\n authMode: 'oauth',\n authStatus: 'expired',\n expiresAt: expiredOAuthToken.expiresAt,\n };\n }\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return { authMode: 'models_json', authStatus: 'connected' };\n }\n\n return { authMode: 'none', authStatus: 'not_connected' };\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll();\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t} else if (await isProviderConfigured(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@earendil-works/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI (GPT-4, o1, o3)', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic Claude', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google Gemini', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq (Fast Inference)', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI (Grok)', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter (Multi-provider)', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n moonshotai: { name: 'Moonshot AI (Kimi · International)', category: 'common', supportsApiKey: true },\n 'moonshotai-cn': { name: 'Moonshot AI (Kimi · China)', category: 'common', supportsApiKey: true },\n fireworks: { name: 'Fireworks AI', category: 'specialty', supportsApiKey: true },\n together: { name: 'Together AI', category: 'specialty', supportsApiKey: true },\n 'cloudflare-workers-ai': { name: 'Cloudflare Workers AI', category: 'enterprise', supportsApiKey: true },\n 'cloudflare-ai-gateway': { name: 'Cloudflare AI Gateway', category: 'enterprise', supportsApiKey: true },\n xiaomi: { name: 'Xiaomi Mimo', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-cn': { name: 'Xiaomi Token Plan (CN)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-ams': { name: 'Xiaomi Token Plan (AMS)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-sgp': { name: 'Xiaomi Token Plan (SGP)', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/** Preferred default model when no explicit model is configured. */\nconst DEFAULT_FALLBACK_MODEL = 'deepseek/deepseek-v4-flash';\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Explicitly configured model in agents.defaults.model (if set and available)\n * 2. Default fallback: deepseek/deepseek-v4-flash\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m => \n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is explicitly configured, returns the preferred default\n * (`deepseek/deepseek-v4-flash`) rather than picking an arbitrary first\n * model from the full catalog.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n return modelRef;\n }\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@earendil-works/pi-ai';\nimport type { Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\nconst OPENAI_CODEX_CANONICAL_BASE_URL = 'https://chatgpt.com/backend-api/codex';\n\nfunction normalizeProviderModel(model: Model<Api>): Model<Api> {\n\tif (model.provider === 'openai-codex' && model.api === 'openai-codex-responses') {\n\t\treturn { ...model, baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL } as Model<Api>;\n\t}\n\treturn model;\n}\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(ref);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (ref.includes('/')) {\n\t\tconst [provider, modelId] = ref.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return normalizeProviderModel(piAiModel as Model<Api>);\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${ref}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === ref);\n\t\t\tif (found) return normalizeProviderModel(found as Model<Api>);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === ref);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${ref}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider).map(normalizeProviderModel);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport type ProviderAuthMode = ProviderActiveKeySource;\nexport type ProviderAuthStatus = 'connected' | 'expired' | 'not_connected';\n\nexport interface ProviderAuthState {\n authMode: ProviderAuthMode;\n authStatus: ProviderAuthStatus;\n expiresAt?: number;\n}\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n const authState = await getProviderAuthState(provider);\n return authState.authMode;\n}\n\nexport async function getProviderAuthState(provider: string): Promise<ProviderAuthState> {\n if (getProviderRegistry().has(provider)) {\n return { authMode: 'extension', authStatus: 'connected' };\n }\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return { authMode: 'agent', authStatus: 'connected' };\n if (fromCredentials === 'global') return { authMode: 'gateway', authStatus: 'connected' };\n if (fromCredentials === 'oauth') {\n const token = await resolver.loadOAuthTokenRecord(provider);\n const expired = Boolean(token?.expiresAt && token.expiresAt < Date.now());\n return {\n authMode: 'oauth',\n authStatus: expired ? 'expired' : 'connected',\n ...(token?.expiresAt ? { expiresAt: token.expiresAt } : {}),\n };\n }\n if (fromCredentials === 'env') return { authMode: 'env', authStatus: 'connected' };\n\n const expiredOAuthToken = await resolver.loadOAuthTokenRecord(provider);\n if (expiredOAuthToken?.expiresAt && expiredOAuthToken.expiresAt < Date.now()) {\n return {\n authMode: 'oauth',\n authStatus: 'expired',\n expiresAt: expiredOAuthToken.expiresAt,\n };\n }\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return { authMode: 'models_json', authStatus: 'connected' };\n }\n\n return { authMode: 'none', authStatus: 'not_connected' };\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll().map(normalizeProviderModel);\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t} else if (await isProviderConfigured(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@earendil-works/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google AI', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n moonshotai: { name: 'Moonshot AI (Kimi · International)', category: 'common', supportsApiKey: true },\n 'moonshotai-cn': { name: 'Moonshot AI (Kimi · China)', category: 'common', supportsApiKey: true },\n fireworks: { name: 'Fireworks AI', category: 'specialty', supportsApiKey: true },\n together: { name: 'Together AI', category: 'specialty', supportsApiKey: true },\n 'cloudflare-workers-ai': { name: 'Cloudflare Workers AI', category: 'enterprise', supportsApiKey: true },\n 'cloudflare-ai-gateway': { name: 'Cloudflare AI Gateway', category: 'enterprise', supportsApiKey: true },\n xiaomi: { name: 'Xiaomi Mimo', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-cn': { name: 'Xiaomi Token Plan (CN)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-ams': { name: 'Xiaomi Token Plan (AMS)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-sgp': { name: 'Xiaomi Token Plan (SGP)', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/** Preferred default model when no explicit model is configured. */\nconst DEFAULT_FALLBACK_MODEL = 'openai/gpt-5.5';\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Explicitly configured model in agents.defaults.model (if set and available)\n * 2. Default fallback: openai/gpt-5.5\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m => \n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is explicitly configured, returns the preferred default\n * (`openai/gpt-5.5`) rather than picking an arbitrary first model from the\n * full catalog.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const defaultModel = config?.agents?.defaults?.model;\n if (defaultModel) {\n const modelRef = typeof defaultModel === 'string' ? defaultModel : defaultModel.primary;\n if (modelRef) {\n return modelRef;\n }\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Api, Model } from '@earendil-works/pi-ai';
|
|
2
|
+
import { type ProviderCategory } from './index.js';
|
|
3
|
+
export interface ModelCatalogView {
|
|
4
|
+
ref: string;
|
|
5
|
+
provider: string;
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
reasoning: boolean;
|
|
9
|
+
input: Array<'text' | 'image'>;
|
|
10
|
+
contextWindow?: number;
|
|
11
|
+
maxTokens?: number;
|
|
12
|
+
vision: boolean;
|
|
13
|
+
recommended: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ProviderCatalogView {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
category: ProviderCategory;
|
|
19
|
+
supportsOAuth: boolean;
|
|
20
|
+
supportsApiKey: boolean;
|
|
21
|
+
configured: boolean;
|
|
22
|
+
onboardingFeatured: boolean;
|
|
23
|
+
recommendedModels: ModelCatalogView[];
|
|
24
|
+
modelCount: number;
|
|
25
|
+
hint?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function isRecommendedModel(provider: string, modelId: string): boolean;
|
|
28
|
+
export declare function modelToCatalogView(model: Model<Api>): ModelCatalogView;
|
|
29
|
+
export declare function sortModelsForPicker(models: readonly Model<Api>[]): Model<Api>[];
|
|
30
|
+
export declare function getRecommendedModelsForProvider(provider: string, limit?: number): ModelCatalogView[];
|
|
31
|
+
export declare function getProviderHint(provider: string): string | undefined;
|
|
32
|
+
export declare function getOnboardingFeaturedProviders(): string[];
|
|
33
|
+
export declare function sortProvidersForPicker(providers: readonly string[]): string[];
|
|
34
|
+
export declare function getProviderCatalogViews(): Promise<ProviderCatalogView[]>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { getProviderRegistry, init_plugin_registry } from "./plugin-registry.js";
|
|
2
|
+
import { PROVIDER_META, getAllModels, getAllProviders, getModelsByProvider, getProviderDisplayName, init_providers, isProviderConfigured } from "./index.js";
|
|
3
|
+
//#region src/providers/presentation.ts
|
|
4
|
+
init_providers();
|
|
5
|
+
init_plugin_registry();
|
|
6
|
+
const FEATURED_PROVIDER_ORDER = [
|
|
7
|
+
"openai",
|
|
8
|
+
"anthropic",
|
|
9
|
+
"xai",
|
|
10
|
+
"google",
|
|
11
|
+
"openrouter",
|
|
12
|
+
"deepseek"
|
|
13
|
+
];
|
|
14
|
+
const PROVIDER_HINTS = {
|
|
15
|
+
openai: "Frontier OpenAI models from the official API.",
|
|
16
|
+
anthropic: "Claude models for coding, long context, and reasoning.",
|
|
17
|
+
xai: "Grok models from xAI.",
|
|
18
|
+
google: "Gemini models with strong multimodal and long-context support.",
|
|
19
|
+
openrouter: "Route many hosted models through one API key.",
|
|
20
|
+
deepseek: "DeepSeek V4 models with strong price/performance.",
|
|
21
|
+
"openai-codex": "OpenAI Codex models through OAuth.",
|
|
22
|
+
"google-gemini-cli": "Gemini through Google Cloud Code Assist OAuth.",
|
|
23
|
+
"google-antigravity": "Gemini/Antigravity OAuth model access."
|
|
24
|
+
};
|
|
25
|
+
const RECOMMENDED_MODEL_PATTERNS = {
|
|
26
|
+
openai: [
|
|
27
|
+
/^gpt-5\.5$/i,
|
|
28
|
+
/^gpt-5\.4$/i,
|
|
29
|
+
/^gpt-5\.4-mini$/i,
|
|
30
|
+
/^gpt-5\.4-pro$/i
|
|
31
|
+
],
|
|
32
|
+
"openai-codex": [
|
|
33
|
+
/^gpt-5\.5$/i,
|
|
34
|
+
/^gpt-5\.4$/i,
|
|
35
|
+
/^gpt-5\.4-mini$/i
|
|
36
|
+
],
|
|
37
|
+
anthropic: [
|
|
38
|
+
/^claude-sonnet-4/i,
|
|
39
|
+
/^claude-opus-4/i,
|
|
40
|
+
/^claude-haiku-4/i
|
|
41
|
+
],
|
|
42
|
+
google: [
|
|
43
|
+
/^gemini-3/i,
|
|
44
|
+
/^gemini-2\.5-pro$/i,
|
|
45
|
+
/^gemini-2\.5-flash$/i
|
|
46
|
+
],
|
|
47
|
+
"google-vertex": [
|
|
48
|
+
/^gemini-3/i,
|
|
49
|
+
/^gemini-2\.5-pro$/i,
|
|
50
|
+
/^gemini-2\.5-flash$/i
|
|
51
|
+
],
|
|
52
|
+
xai: [
|
|
53
|
+
/^grok-4/i,
|
|
54
|
+
/^grok-3/i,
|
|
55
|
+
/^grok-code/i
|
|
56
|
+
],
|
|
57
|
+
deepseek: [/^deepseek-v4-flash$/i, /^deepseek-v4-pro$/i],
|
|
58
|
+
openrouter: [
|
|
59
|
+
/^openai\/gpt-5/i,
|
|
60
|
+
/^anthropic\/claude-sonnet-4/i,
|
|
61
|
+
/^google\/gemini-3/i
|
|
62
|
+
],
|
|
63
|
+
moonshotai: [
|
|
64
|
+
/^kimi-k2\.6$/i,
|
|
65
|
+
/^kimi-k2\.5$/i,
|
|
66
|
+
/^kimi-k2-thinking/i
|
|
67
|
+
],
|
|
68
|
+
"moonshotai-cn": [
|
|
69
|
+
/^kimi-k2\.6$/i,
|
|
70
|
+
/^kimi-k2\.5$/i,
|
|
71
|
+
/^kimi-k2-thinking/i
|
|
72
|
+
]
|
|
73
|
+
};
|
|
74
|
+
function modelRef(model) {
|
|
75
|
+
return `${model.provider}/${model.id}`;
|
|
76
|
+
}
|
|
77
|
+
function recommendedRank(provider, modelId) {
|
|
78
|
+
const idx = (RECOMMENDED_MODEL_PATTERNS[provider] ?? []).findIndex((pattern) => pattern.test(modelId));
|
|
79
|
+
return idx === -1 ? Number.POSITIVE_INFINITY : idx;
|
|
80
|
+
}
|
|
81
|
+
function isRecommendedModel(provider, modelId) {
|
|
82
|
+
return Number.isFinite(recommendedRank(provider, modelId));
|
|
83
|
+
}
|
|
84
|
+
function modelToCatalogView(model) {
|
|
85
|
+
const input = model.input ?? ["text"];
|
|
86
|
+
return {
|
|
87
|
+
ref: modelRef(model),
|
|
88
|
+
provider: model.provider,
|
|
89
|
+
id: model.id,
|
|
90
|
+
name: model.name || model.id,
|
|
91
|
+
reasoning: model.reasoning ?? false,
|
|
92
|
+
input,
|
|
93
|
+
...model.contextWindow ? { contextWindow: model.contextWindow } : {},
|
|
94
|
+
...model.maxTokens ? { maxTokens: model.maxTokens } : {},
|
|
95
|
+
vision: input.includes("image"),
|
|
96
|
+
recommended: isRecommendedModel(model.provider, model.id)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function sortModelsForPicker(models) {
|
|
100
|
+
return [...models].sort((a, b) => {
|
|
101
|
+
const aRank = recommendedRank(a.provider, a.id);
|
|
102
|
+
const bRank = recommendedRank(b.provider, b.id);
|
|
103
|
+
if (aRank !== bRank) return aRank - bRank;
|
|
104
|
+
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
105
|
+
return (a.name || a.id).localeCompare(b.name || b.id, void 0, { sensitivity: "base" });
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function getRecommendedModelsForProvider(provider, limit = 4) {
|
|
109
|
+
return sortModelsForPicker(getModelsByProvider(provider)).filter((model) => isRecommendedModel(provider, model.id)).slice(0, limit).map(modelToCatalogView);
|
|
110
|
+
}
|
|
111
|
+
function getProviderHint(provider) {
|
|
112
|
+
return PROVIDER_HINTS[provider];
|
|
113
|
+
}
|
|
114
|
+
function getOnboardingFeaturedProviders() {
|
|
115
|
+
const providers = new Set(getAllProviders());
|
|
116
|
+
return FEATURED_PROVIDER_ORDER.filter((provider) => providers.has(provider));
|
|
117
|
+
}
|
|
118
|
+
function sortProvidersForPicker(providers) {
|
|
119
|
+
const featuredRank = new Map(FEATURED_PROVIDER_ORDER.map((provider, index) => [provider, index]));
|
|
120
|
+
return [...providers].sort((a, b) => {
|
|
121
|
+
const aRank = featuredRank.get(a) ?? Number.POSITIVE_INFINITY;
|
|
122
|
+
const bRank = featuredRank.get(b) ?? Number.POSITIVE_INFINITY;
|
|
123
|
+
if (aRank !== bRank) return aRank - bRank;
|
|
124
|
+
const catA = PROVIDER_META[a]?.category ?? "specialty";
|
|
125
|
+
const catB = PROVIDER_META[b]?.category ?? "specialty";
|
|
126
|
+
const catOrder = {
|
|
127
|
+
common: 0,
|
|
128
|
+
specialty: 1,
|
|
129
|
+
enterprise: 2,
|
|
130
|
+
oauth: 3,
|
|
131
|
+
extension: 4
|
|
132
|
+
};
|
|
133
|
+
if (catOrder[catA] !== catOrder[catB]) return catOrder[catA] - catOrder[catB];
|
|
134
|
+
return getProviderDisplayName(a).localeCompare(getProviderDisplayName(b), void 0, { sensitivity: "base" });
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async function getProviderCatalogViews() {
|
|
138
|
+
const pluginRegistry = getProviderRegistry();
|
|
139
|
+
const providers = sortProvidersForPicker(getAllProviders());
|
|
140
|
+
const modelCounts = /* @__PURE__ */ new Map();
|
|
141
|
+
for (const model of getAllModels()) modelCounts.set(model.provider, (modelCounts.get(model.provider) ?? 0) + 1);
|
|
142
|
+
return Promise.all(providers.map(async (provider) => {
|
|
143
|
+
const plugin = pluginRegistry.get(provider);
|
|
144
|
+
const meta = PROVIDER_META[provider];
|
|
145
|
+
return {
|
|
146
|
+
id: provider,
|
|
147
|
+
name: plugin?.name ?? getProviderDisplayName(provider),
|
|
148
|
+
category: plugin ? "extension" : meta?.category ?? "specialty",
|
|
149
|
+
supportsOAuth: plugin ? false : meta?.supportsOAuth ?? false,
|
|
150
|
+
supportsApiKey: plugin ? false : meta?.supportsApiKey ?? true,
|
|
151
|
+
configured: plugin ? true : await isProviderConfigured(provider),
|
|
152
|
+
onboardingFeatured: FEATURED_PROVIDER_ORDER.includes(provider),
|
|
153
|
+
recommendedModels: getRecommendedModelsForProvider(provider),
|
|
154
|
+
modelCount: modelCounts.get(provider) ?? 0,
|
|
155
|
+
...getProviderHint(provider) ? { hint: getProviderHint(provider) } : {}
|
|
156
|
+
};
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
export { getOnboardingFeaturedProviders, getProviderCatalogViews, getProviderHint, getRecommendedModelsForProvider, isRecommendedModel, modelToCatalogView, sortModelsForPicker, sortProvidersForPicker };
|
|
161
|
+
|
|
162
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.js","names":[],"sources":["../../../src/providers/presentation.ts"],"sourcesContent":["import type { Api, Model } from '@earendil-works/pi-ai';\n\nimport {\n getAllModels,\n getAllProviders,\n getModelsByProvider,\n getProviderDisplayName,\n isProviderConfigured,\n PROVIDER_META,\n type ProviderCategory,\n} from './index.js';\nimport { getProviderRegistry } from './plugin-registry.js';\n\nexport interface ModelCatalogView {\n ref: string;\n provider: string;\n id: string;\n name: string;\n reasoning: boolean;\n input: Array<'text' | 'image'>;\n contextWindow?: number;\n maxTokens?: number;\n vision: boolean;\n recommended: boolean;\n}\n\nexport interface ProviderCatalogView {\n id: string;\n name: string;\n category: ProviderCategory;\n supportsOAuth: boolean;\n supportsApiKey: boolean;\n configured: boolean;\n onboardingFeatured: boolean;\n recommendedModels: ModelCatalogView[];\n modelCount: number;\n hint?: string;\n}\n\nconst FEATURED_PROVIDER_ORDER = ['openai', 'anthropic', 'xai', 'google', 'openrouter', 'deepseek'];\n\nconst PROVIDER_HINTS: Record<string, string> = {\n openai: 'Frontier OpenAI models from the official API.',\n anthropic: 'Claude models for coding, long context, and reasoning.',\n xai: 'Grok models from xAI.',\n google: 'Gemini models with strong multimodal and long-context support.',\n openrouter: 'Route many hosted models through one API key.',\n deepseek: 'DeepSeek V4 models with strong price/performance.',\n 'openai-codex': 'OpenAI Codex models through OAuth.',\n 'google-gemini-cli': 'Gemini through Google Cloud Code Assist OAuth.',\n 'google-antigravity': 'Gemini/Antigravity OAuth model access.',\n};\n\nconst RECOMMENDED_MODEL_PATTERNS: Record<string, RegExp[]> = {\n openai: [/^gpt-5\\.5$/i, /^gpt-5\\.4$/i, /^gpt-5\\.4-mini$/i, /^gpt-5\\.4-pro$/i],\n 'openai-codex': [/^gpt-5\\.5$/i, /^gpt-5\\.4$/i, /^gpt-5\\.4-mini$/i],\n anthropic: [/^claude-sonnet-4/i, /^claude-opus-4/i, /^claude-haiku-4/i],\n google: [/^gemini-3/i, /^gemini-2\\.5-pro$/i, /^gemini-2\\.5-flash$/i],\n 'google-vertex': [/^gemini-3/i, /^gemini-2\\.5-pro$/i, /^gemini-2\\.5-flash$/i],\n xai: [/^grok-4/i, /^grok-3/i, /^grok-code/i],\n deepseek: [/^deepseek-v4-flash$/i, /^deepseek-v4-pro$/i],\n openrouter: [/^openai\\/gpt-5/i, /^anthropic\\/claude-sonnet-4/i, /^google\\/gemini-3/i],\n moonshotai: [/^kimi-k2\\.6$/i, /^kimi-k2\\.5$/i, /^kimi-k2-thinking/i],\n 'moonshotai-cn': [/^kimi-k2\\.6$/i, /^kimi-k2\\.5$/i, /^kimi-k2-thinking/i],\n};\n\nfunction modelRef(model: Pick<Model<Api>, 'provider' | 'id'>): string {\n return `${model.provider}/${model.id}`;\n}\n\nfunction recommendedRank(provider: string, modelId: string): number {\n const patterns = RECOMMENDED_MODEL_PATTERNS[provider] ?? [];\n const idx = patterns.findIndex((pattern) => pattern.test(modelId));\n return idx === -1 ? Number.POSITIVE_INFINITY : idx;\n}\n\nexport function isRecommendedModel(provider: string, modelId: string): boolean {\n return Number.isFinite(recommendedRank(provider, modelId));\n}\n\nexport function modelToCatalogView(model: Model<Api>): ModelCatalogView {\n const input = (model.input ?? ['text']) as Array<'text' | 'image'>;\n return {\n ref: modelRef(model),\n provider: model.provider,\n id: model.id,\n name: model.name || model.id,\n reasoning: model.reasoning ?? false,\n input,\n ...(model.contextWindow ? { contextWindow: model.contextWindow } : {}),\n ...(model.maxTokens ? { maxTokens: model.maxTokens } : {}),\n vision: input.includes('image'),\n recommended: isRecommendedModel(model.provider, model.id),\n };\n}\n\nexport function sortModelsForPicker(models: readonly Model<Api>[]): Model<Api>[] {\n return [...models].sort((a, b) => {\n const aRank = recommendedRank(a.provider, a.id);\n const bRank = recommendedRank(b.provider, b.id);\n if (aRank !== bRank) return aRank - bRank;\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return (a.name || a.id).localeCompare(b.name || b.id, undefined, { sensitivity: 'base' });\n });\n}\n\nexport function getRecommendedModelsForProvider(provider: string, limit = 4): ModelCatalogView[] {\n const models = sortModelsForPicker(getModelsByProvider(provider));\n return models\n .filter((model) => isRecommendedModel(provider, model.id))\n .slice(0, limit)\n .map(modelToCatalogView);\n}\n\nexport function getProviderHint(provider: string): string | undefined {\n return PROVIDER_HINTS[provider];\n}\n\nexport function getOnboardingFeaturedProviders(): string[] {\n const providers = new Set(getAllProviders());\n return FEATURED_PROVIDER_ORDER.filter((provider) => providers.has(provider));\n}\n\nexport function sortProvidersForPicker(providers: readonly string[]): string[] {\n const featuredRank = new Map(FEATURED_PROVIDER_ORDER.map((provider, index) => [provider, index] as const));\n return [...providers].sort((a, b) => {\n const aRank = featuredRank.get(a) ?? Number.POSITIVE_INFINITY;\n const bRank = featuredRank.get(b) ?? Number.POSITIVE_INFINITY;\n if (aRank !== bRank) return aRank - bRank;\n const catA = PROVIDER_META[a]?.category ?? 'specialty';\n const catB = PROVIDER_META[b]?.category ?? 'specialty';\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n if (catOrder[catA] !== catOrder[catB]) return catOrder[catA] - catOrder[catB];\n return getProviderDisplayName(a).localeCompare(getProviderDisplayName(b), undefined, { sensitivity: 'base' });\n });\n}\n\nexport async function getProviderCatalogViews(): Promise<ProviderCatalogView[]> {\n const pluginRegistry = getProviderRegistry();\n const providers = sortProvidersForPicker(getAllProviders());\n const modelCounts = new Map<string, number>();\n for (const model of getAllModels()) {\n modelCounts.set(model.provider, (modelCounts.get(model.provider) ?? 0) + 1);\n }\n\n return Promise.all(\n providers.map(async (provider) => {\n const plugin = pluginRegistry.get(provider);\n const meta = PROVIDER_META[provider];\n return {\n id: provider,\n name: plugin?.name ?? getProviderDisplayName(provider),\n category: plugin ? 'extension' : (meta?.category ?? 'specialty'),\n supportsOAuth: plugin ? false : (meta?.supportsOAuth ?? false),\n supportsApiKey: plugin ? false : (meta?.supportsApiKey ?? true),\n configured: plugin ? true : await isProviderConfigured(provider),\n onboardingFeatured: FEATURED_PROVIDER_ORDER.includes(provider),\n recommendedModels: getRecommendedModelsForProvider(provider),\n modelCount: modelCounts.get(provider) ?? 0,\n ...(getProviderHint(provider) ? { hint: getProviderHint(provider) } : {}),\n };\n }),\n );\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
4
4
|
"description": "The OPC workstation that grows with you: AI assistant for One Person Companies — CLI, gateway, multi-channel (Telegram/WeChat), 20+ LLM providers via pi-ai, extensions and skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|