@theokit/sdk 4.13.0 → 4.14.0
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 +12 -0
- package/dist/{cron-C7catiH8.d.ts → cron-DY0uC1ng.d.ts} +7 -0
- package/dist/{cron-DK1WVZnI.d.cts → cron-ElTj1cSH.d.cts} +7 -0
- package/dist/cron.cjs +183 -20
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +1 -1
- package/dist/cron.d.ts +1 -1
- package/dist/cron.js +183 -20
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +183 -20
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +183 -20
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +183 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +183 -20
- package/dist/index.js.map +1 -1
- package/dist/internal/llm/openai.d.ts +1 -0
- package/dist/internal/providers/builtin/cerebras.d.ts +5 -0
- package/dist/internal/providers/builtin/cohere.d.ts +6 -0
- package/dist/internal/providers/builtin/deepinfra.d.ts +2 -0
- package/dist/internal/providers/builtin/google.d.ts +6 -0
- package/dist/internal/providers/builtin/groq.d.ts +2 -0
- package/dist/internal/providers/builtin/mistral.d.ts +2 -0
- package/dist/internal/providers/builtin/openai-compatible.d.ts +1 -0
- package/dist/internal/providers/builtin/perplexity.d.ts +5 -0
- package/dist/internal/providers/builtin/together.d.ts +2 -0
- package/dist/internal/providers/builtin/xai.d.ts +2 -0
- package/dist/models.cjs +753 -17
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +754 -18
- package/dist/models.js.map +1 -1
- package/dist/provider-catalog.json +473 -146
- package/dist/types/provider-profile.d.ts +7 -0
- package/package.json +1 -1
package/dist/models.cjs
CHANGED
|
@@ -44,8 +44,34 @@ var catalogModelSchema = zod.z.object({
|
|
|
44
44
|
}).loose();
|
|
45
45
|
|
|
46
46
|
// src/internal/providers/registry.ts
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
function globalSingleton(key, create) {
|
|
48
|
+
const g = globalThis;
|
|
49
|
+
const sym = Symbol.for(key);
|
|
50
|
+
if (g[sym] === void 0) g[sym] = create();
|
|
51
|
+
return g[sym];
|
|
52
|
+
}
|
|
53
|
+
var REGISTRY = globalSingleton(
|
|
54
|
+
"theokit-sdk.providers.registry",
|
|
55
|
+
() => /* @__PURE__ */ new Map()
|
|
56
|
+
);
|
|
57
|
+
var ALIASES = globalSingleton("theokit-sdk.providers.aliases", () => /* @__PURE__ */ new Map());
|
|
58
|
+
function registerProvider(profile) {
|
|
59
|
+
if (REGISTRY.has(profile.name)) {
|
|
60
|
+
process.stderr.write(`[theokit-sdk] Provider "${profile.name}" overridden by user plugin.
|
|
61
|
+
`);
|
|
62
|
+
}
|
|
63
|
+
REGISTRY.set(profile.name, profile);
|
|
64
|
+
for (const alias of profile.aliases ?? []) {
|
|
65
|
+
const previous = ALIASES.get(alias);
|
|
66
|
+
if (previous !== void 0 && previous !== profile.name) {
|
|
67
|
+
process.stderr.write(
|
|
68
|
+
`[theokit-sdk] Alias "${alias}" collision: was "${previous}", now "${profile.name}".
|
|
69
|
+
`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
ALIASES.set(alias, profile.name);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
49
75
|
function getProviderProfile(name) {
|
|
50
76
|
const canonical = ALIASES.get(name) ?? name;
|
|
51
77
|
return REGISTRY.get(canonical);
|
|
@@ -53,22 +79,46 @@ function getProviderProfile(name) {
|
|
|
53
79
|
|
|
54
80
|
// src/internal/providers/catalog-loader.ts
|
|
55
81
|
var __dirname_resolved = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('models.cjs', document.baseURI).href))));
|
|
56
|
-
|
|
82
|
+
function globalSingleton2(key, create) {
|
|
83
|
+
const g = globalThis;
|
|
84
|
+
const sym = Symbol.for(key);
|
|
85
|
+
if (g[sym] === void 0) g[sym] = create();
|
|
86
|
+
return g[sym];
|
|
87
|
+
}
|
|
88
|
+
var modelInfoIndex = globalSingleton2(
|
|
89
|
+
"theokit-sdk.providers.model-info-index",
|
|
90
|
+
() => /* @__PURE__ */ new Map()
|
|
91
|
+
);
|
|
92
|
+
var patchedModelKeys = globalSingleton2(
|
|
93
|
+
"theokit-sdk.providers.model-info-patched",
|
|
94
|
+
() => /* @__PURE__ */ new Set()
|
|
95
|
+
);
|
|
96
|
+
var indexState = globalSingleton2("theokit-sdk.providers.model-info-loaded", () => ({
|
|
97
|
+
loaded: false
|
|
98
|
+
}));
|
|
57
99
|
function getCatalogModelInfo(key) {
|
|
58
100
|
ensureModelIndexLoaded();
|
|
59
101
|
return modelInfoIndex.get(key);
|
|
60
102
|
}
|
|
61
103
|
function patchModelInfo(key, model) {
|
|
62
104
|
ensureModelIndexLoaded();
|
|
63
|
-
modelInfoIndex.
|
|
105
|
+
const existing = modelInfoIndex.get(key);
|
|
106
|
+
modelInfoIndex.set(key, existing === void 0 ? model : { ...existing, ...model });
|
|
107
|
+
patchedModelKeys.add(key);
|
|
64
108
|
}
|
|
65
|
-
var _modelIndexLoaded = false;
|
|
66
109
|
function ensureModelIndexLoaded() {
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
110
|
+
if (indexState.loaded) return;
|
|
111
|
+
indexState.loaded = true;
|
|
112
|
+
try {
|
|
113
|
+
const catalog = loadProviderCatalog();
|
|
114
|
+
for (const entry of Object.values(catalog)) {
|
|
115
|
+
indexEntryModels(entry);
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
process.stderr.write(
|
|
119
|
+
`[theokit-sdk] WARN: provider catalog unavailable (${err.message}) \u2014 per-model data disabled
|
|
120
|
+
`
|
|
121
|
+
);
|
|
72
122
|
}
|
|
73
123
|
}
|
|
74
124
|
function indexEntryModels(entry) {
|
|
@@ -113,6 +163,27 @@ function loadProviderCatalog(opts) {
|
|
|
113
163
|
}
|
|
114
164
|
return result;
|
|
115
165
|
}
|
|
166
|
+
function registerCatalogProviders(opts) {
|
|
167
|
+
const catalog = loadProviderCatalog();
|
|
168
|
+
for (const entry of Object.values(catalog)) {
|
|
169
|
+
if (getProviderProfile(entry.id) !== void 0) continue;
|
|
170
|
+
if (entry.aliases?.some((a) => getProviderProfile(a) !== void 0)) continue;
|
|
171
|
+
const profile = {
|
|
172
|
+
name: entry.id,
|
|
173
|
+
apiMode: entry.apiMode,
|
|
174
|
+
authType: entry.authType,
|
|
175
|
+
baseUrl: entry.baseUrl,
|
|
176
|
+
envVars: entry.envVars,
|
|
177
|
+
fallbackModels: entry.fallbackModels,
|
|
178
|
+
displayName: entry.displayName,
|
|
179
|
+
aliases: entry.aliases,
|
|
180
|
+
modelsUrl: entry.modelsUrl,
|
|
181
|
+
hostname: entry.hostname,
|
|
182
|
+
extraHeaders: entry.extraHeaders
|
|
183
|
+
};
|
|
184
|
+
registerProvider(profile);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
116
187
|
|
|
117
188
|
// src/internal/llm/model-capabilities.ts
|
|
118
189
|
var CONSERVATIVE_DEFAULTS = {
|
|
@@ -302,12 +373,616 @@ var Retry = class {
|
|
|
302
373
|
}
|
|
303
374
|
};
|
|
304
375
|
|
|
376
|
+
// src/internal/providers/builtin/anthropic.ts
|
|
377
|
+
var ANTHROPIC = {
|
|
378
|
+
name: "anthropic",
|
|
379
|
+
apiMode: "anthropic_messages",
|
|
380
|
+
envVars: ["ANTHROPIC_API_KEY"],
|
|
381
|
+
authType: "api_key",
|
|
382
|
+
baseUrl: "https://api.anthropic.com",
|
|
383
|
+
modelsUrl: "https://api.anthropic.com/v1/models",
|
|
384
|
+
hostname: "api.anthropic.com",
|
|
385
|
+
fallbackModels: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5-20251001"],
|
|
386
|
+
// M45 — the Anthropic beta-features header (interleaved thinking + fine-grained tool streaming). An
|
|
387
|
+
// Anthropic API constant, adapted verbatim from OpenCode's anthropic plugin (MIT © 2025 opencode). The
|
|
388
|
+
// SANCTIONED behavior delta of M45 (ADR D4) — consumed by the anthropic transport's extraHeaders wiring.
|
|
389
|
+
extraHeaders: {
|
|
390
|
+
"anthropic-beta": "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// src/internal/providers/builtin/bedrock.ts
|
|
395
|
+
var BEDROCK = {
|
|
396
|
+
name: "bedrock",
|
|
397
|
+
apiMode: "bedrock_anthropic",
|
|
398
|
+
envVars: ["AWS_BEARER_TOKEN_BEDROCK"],
|
|
399
|
+
authType: "aws_bearer",
|
|
400
|
+
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
|
|
401
|
+
modelsUrl: void 0,
|
|
402
|
+
hostname: "bedrock-runtime.amazonaws.com",
|
|
403
|
+
fallbackModels: [
|
|
404
|
+
"bedrock/us.anthropic.claude-sonnet-4-5-v1:0",
|
|
405
|
+
"bedrock/us.anthropic.claude-opus-4-7-v1:0",
|
|
406
|
+
"bedrock/global.anthropic.claude-haiku-4-5-v1:0"
|
|
407
|
+
]
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// src/internal/providers/builtin/openai-compatible.ts
|
|
411
|
+
function openAiCompatibleProfile(p) {
|
|
412
|
+
return {
|
|
413
|
+
apiMode: "chat_completions",
|
|
414
|
+
authType: "api_key",
|
|
415
|
+
fallbackModels: [],
|
|
416
|
+
...p
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/internal/providers/builtin/cerebras.ts
|
|
421
|
+
var CEREBRAS = openAiCompatibleProfile({
|
|
422
|
+
name: "cerebras",
|
|
423
|
+
baseUrl: "https://api.cerebras.ai/v1",
|
|
424
|
+
envVars: ["CEREBRAS_API_KEY"],
|
|
425
|
+
fallbackModels: ["gpt-oss-120b", "zai-glm-4.7"],
|
|
426
|
+
extraHeaders: { "X-Cerebras-3rd-Party-Integration": "theokit" },
|
|
427
|
+
hostname: "api.cerebras.ai"
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// src/internal/providers/builtin/cohere.ts
|
|
431
|
+
var COHERE = openAiCompatibleProfile({
|
|
432
|
+
name: "cohere",
|
|
433
|
+
baseUrl: "https://api.cohere.ai/compatibility/v1",
|
|
434
|
+
envVars: ["COHERE_API_KEY", "CO_API_KEY"],
|
|
435
|
+
fallbackModels: ["command-a-03-2025"],
|
|
436
|
+
hostname: "api.cohere.ai"
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
// src/internal/providers/builtin/deepinfra.ts
|
|
440
|
+
var DEEPINFRA = openAiCompatibleProfile({
|
|
441
|
+
name: "deepinfra",
|
|
442
|
+
baseUrl: "https://api.deepinfra.com/v1/openai",
|
|
443
|
+
envVars: ["DEEPINFRA_API_KEY"],
|
|
444
|
+
fallbackModels: ["Qwen/Qwen3-32B"],
|
|
445
|
+
hostname: "api.deepinfra.com"
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// src/internal/providers/builtin/google.ts
|
|
449
|
+
var GOOGLE = openAiCompatibleProfile({
|
|
450
|
+
name: "google",
|
|
451
|
+
baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
452
|
+
envVars: ["GOOGLE_API_KEY", "GEMINI_API_KEY"],
|
|
453
|
+
fallbackModels: ["gemini-2.5-pro", "gemini-2.5-flash"],
|
|
454
|
+
hostname: "generativelanguage.googleapis.com"
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// src/internal/providers/builtin/groq.ts
|
|
458
|
+
var GROQ = openAiCompatibleProfile({
|
|
459
|
+
name: "groq",
|
|
460
|
+
baseUrl: "https://api.groq.com/openai/v1",
|
|
461
|
+
envVars: ["GROQ_API_KEY"],
|
|
462
|
+
fallbackModels: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant"],
|
|
463
|
+
hostname: "api.groq.com"
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// src/internal/providers/builtin/mistral.ts
|
|
467
|
+
var MISTRAL = openAiCompatibleProfile({
|
|
468
|
+
name: "mistral",
|
|
469
|
+
baseUrl: "https://api.mistral.ai/v1",
|
|
470
|
+
envVars: ["MISTRAL_API_KEY"],
|
|
471
|
+
fallbackModels: ["mistral-large-latest", "codestral-latest"],
|
|
472
|
+
hostname: "api.mistral.ai"
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
// src/internal/providers/builtin/perplexity.ts
|
|
476
|
+
var PERPLEXITY = openAiCompatibleProfile({
|
|
477
|
+
name: "perplexity",
|
|
478
|
+
baseUrl: "https://api.perplexity.ai",
|
|
479
|
+
chatCompletionsPath: "/chat/completions",
|
|
480
|
+
envVars: ["PERPLEXITY_API_KEY"],
|
|
481
|
+
fallbackModels: ["sonar-pro", "sonar"],
|
|
482
|
+
hostname: "api.perplexity.ai"
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// src/internal/providers/builtin/together.ts
|
|
486
|
+
var TOGETHER = openAiCompatibleProfile({
|
|
487
|
+
name: "together",
|
|
488
|
+
aliases: ["togetherai"],
|
|
489
|
+
baseUrl: "https://api.together.xyz/v1",
|
|
490
|
+
envVars: ["TOGETHER_API_KEY"],
|
|
491
|
+
fallbackModels: ["Qwen/Qwen2.5-7B-Instruct-Turbo"],
|
|
492
|
+
hostname: "api.together.xyz"
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
// src/internal/providers/builtin/xai.ts
|
|
496
|
+
var XAI = openAiCompatibleProfile({
|
|
497
|
+
name: "xai",
|
|
498
|
+
aliases: ["grok"],
|
|
499
|
+
baseUrl: "https://api.x.ai/v1",
|
|
500
|
+
envVars: ["XAI_API_KEY"],
|
|
501
|
+
fallbackModels: ["grok-4.5", "grok-4.3"],
|
|
502
|
+
hostname: "api.x.ai"
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// src/internal/providers/builtin/gemini.ts
|
|
506
|
+
var GEMINI = {
|
|
507
|
+
name: "gemini",
|
|
508
|
+
apiMode: "chat_completions",
|
|
509
|
+
envVars: ["OPENROUTER_API_KEY"],
|
|
510
|
+
authType: "api_key",
|
|
511
|
+
baseUrl: "https://openrouter.ai/api",
|
|
512
|
+
hostname: "openrouter.ai",
|
|
513
|
+
fallbackModels: ["google/gemini-2.0-flash-001"]
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
// src/internal/providers/builtin/llamacpp.ts
|
|
517
|
+
var LLAMACPP = {
|
|
518
|
+
name: "llamacpp",
|
|
519
|
+
aliases: ["llama-cpp", "llama.cpp"],
|
|
520
|
+
apiMode: "chat_completions",
|
|
521
|
+
envVars: ["LLAMACPP_API_KEY"],
|
|
522
|
+
authType: "none",
|
|
523
|
+
baseUrl: "http://localhost:8080",
|
|
524
|
+
modelsUrl: "http://localhost:8080/v1/models",
|
|
525
|
+
hostname: "localhost",
|
|
526
|
+
fallbackModels: ["loaded-model"]
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// src/internal/providers/builtin/lmstudio.ts
|
|
530
|
+
var LMSTUDIO = {
|
|
531
|
+
name: "lmstudio",
|
|
532
|
+
aliases: ["lm-studio", "lm_studio"],
|
|
533
|
+
apiMode: "chat_completions",
|
|
534
|
+
envVars: ["LMSTUDIO_API_KEY"],
|
|
535
|
+
authType: "none",
|
|
536
|
+
baseUrl: "http://localhost:1234",
|
|
537
|
+
modelsUrl: "http://localhost:1234/v1/models",
|
|
538
|
+
hostname: "localhost",
|
|
539
|
+
fallbackModels: ["loaded-model"]
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// src/internal/providers/builtin/ollama.ts
|
|
543
|
+
var OLLAMA = {
|
|
544
|
+
name: "ollama",
|
|
545
|
+
apiMode: "chat_completions",
|
|
546
|
+
envVars: ["OLLAMA_API_KEY"],
|
|
547
|
+
authType: "none",
|
|
548
|
+
baseUrl: "http://localhost:11434",
|
|
549
|
+
modelsUrl: "http://localhost:11434/v1/models",
|
|
550
|
+
hostname: "localhost",
|
|
551
|
+
fallbackModels: ["llama3.2", "qwen2.5", "mistral"]
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
// src/internal/providers/builtin/openai.ts
|
|
555
|
+
var OPENAI = {
|
|
556
|
+
name: "openai",
|
|
557
|
+
apiMode: "chat_completions",
|
|
558
|
+
envVars: ["OPENAI_API_KEY"],
|
|
559
|
+
authType: "api_key",
|
|
560
|
+
baseUrl: "https://api.openai.com",
|
|
561
|
+
modelsUrl: "https://api.openai.com/v1/models",
|
|
562
|
+
hostname: "api.openai.com",
|
|
563
|
+
fallbackModels: ["gpt-4o", "gpt-4o-mini"]
|
|
564
|
+
};
|
|
565
|
+
function credentialHome(config, env = {}) {
|
|
566
|
+
const override = config.homeEnvVar !== void 0 ? env[config.homeEnvVar]?.trim() : void 0;
|
|
567
|
+
return override !== void 0 && override.length > 0 ? override : path.join(config.home, config.dirName);
|
|
568
|
+
}
|
|
569
|
+
function authFilePath(config, env = {}) {
|
|
570
|
+
return path.join(credentialHome(config, env), config.fileName);
|
|
571
|
+
}
|
|
572
|
+
var CredentialError = class extends Error {
|
|
573
|
+
constructor(message) {
|
|
574
|
+
super(message);
|
|
575
|
+
this.name = "CredentialError";
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
var apiFileSchema = zod.z.object({
|
|
579
|
+
type: zod.z.literal("api").optional(),
|
|
580
|
+
provider: zod.z.string().min(1).optional(),
|
|
581
|
+
api_key: zod.z.string()
|
|
582
|
+
}).strict();
|
|
583
|
+
var oauthFileSchema = zod.z.object({
|
|
584
|
+
type: zod.z.literal("oauth"),
|
|
585
|
+
provider: zod.z.string().min(1),
|
|
586
|
+
access: zod.z.string().min(1),
|
|
587
|
+
refresh: zod.z.string().min(1),
|
|
588
|
+
expires: zod.z.number(),
|
|
589
|
+
account_id: zod.z.string().optional()
|
|
590
|
+
}).strict();
|
|
591
|
+
var fileSchema = zod.z.union([oauthFileSchema, apiFileSchema]);
|
|
592
|
+
function assertSecureModes(dirPath, path) {
|
|
593
|
+
const dirMode = fs.statSync(dirPath).mode & 511;
|
|
594
|
+
if ((dirMode & 18) !== 0) {
|
|
595
|
+
throw new CredentialError(
|
|
596
|
+
`${dirPath} is writable by other users (mode ${dirMode.toString(8)}), so the credential file inside it can be replaced. Fix it with: chmod 700 ${dirPath}`
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
const mode = fs.statSync(path).mode & 511;
|
|
600
|
+
if ((mode & 63) !== 0) {
|
|
601
|
+
throw new CredentialError(
|
|
602
|
+
`${path} is readable by other users (mode ${mode.toString(8)}). A credential file must not be. Fix it with: chmod 600 ${path}`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
function describeUnionError(parsed, err, path) {
|
|
607
|
+
const looksOAuth = typeof parsed === "object" && parsed !== null && parsed.type === "oauth";
|
|
608
|
+
const specific = looksOAuth ? oauthFileSchema.safeParse(parsed) : apiFileSchema.safeParse(parsed);
|
|
609
|
+
let issue;
|
|
610
|
+
if (!specific.success) {
|
|
611
|
+
issue = specific.error.issues[0];
|
|
612
|
+
} else if (err instanceof zod.z.ZodError) {
|
|
613
|
+
issue = err.issues[0];
|
|
614
|
+
}
|
|
615
|
+
return new CredentialError(
|
|
616
|
+
`${path}: ${issue?.message ?? String(err)} [${issue?.path.join(".") || "root"}]`
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
function parseStoredFile(raw, path) {
|
|
620
|
+
let parsed;
|
|
621
|
+
try {
|
|
622
|
+
parsed = JSON.parse(raw);
|
|
623
|
+
} catch {
|
|
624
|
+
throw new CredentialError(
|
|
625
|
+
`${path} is not valid JSON. Expected: {"provider": "<name>", "api_key": "..."}`
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
try {
|
|
629
|
+
return fileSchema.parse(parsed);
|
|
630
|
+
} catch (err) {
|
|
631
|
+
throw describeUnionError(parsed, err, path);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function readAuthFile(config, env = {}) {
|
|
635
|
+
const path = authFilePath(config, env);
|
|
636
|
+
let raw;
|
|
637
|
+
try {
|
|
638
|
+
raw = fs.readFileSync(path, "utf8");
|
|
639
|
+
} catch (err) {
|
|
640
|
+
if (err.code === "ENOENT") return void 0;
|
|
641
|
+
throw new CredentialError(`cannot read ${path}: ${err.message}`);
|
|
642
|
+
}
|
|
643
|
+
assertSecureModes(credentialHome(config, env), path);
|
|
644
|
+
return parseStoredFile(raw, path);
|
|
645
|
+
}
|
|
646
|
+
function readStoredOAuth(config, env = {}) {
|
|
647
|
+
const stored = readAuthFile(config, env);
|
|
648
|
+
return stored !== void 0 && stored.type === "oauth" ? stored : void 0;
|
|
649
|
+
}
|
|
650
|
+
function isOAuthWrite(c) {
|
|
651
|
+
return "type" in c && c.type === "oauth";
|
|
652
|
+
}
|
|
653
|
+
function buildStorePayload(cred) {
|
|
654
|
+
if (isOAuthWrite(cred)) {
|
|
655
|
+
if (cred.access.length === 0 || cred.refresh.length === 0) {
|
|
656
|
+
throw new CredentialError(
|
|
657
|
+
"refusing to write an oauth credential with an empty access/refresh token"
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
type: "oauth",
|
|
662
|
+
provider: cred.provider,
|
|
663
|
+
access: cred.access,
|
|
664
|
+
refresh: cred.refresh,
|
|
665
|
+
expires: cred.expires,
|
|
666
|
+
...cred.account_id !== void 0 ? { account_id: cred.account_id } : {}
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
if (typeof cred.apiKey !== "string" || cred.apiKey.length === 0) {
|
|
670
|
+
throw new CredentialError("refusing to write an empty API key");
|
|
671
|
+
}
|
|
672
|
+
return { provider: cred.provider, api_key: cred.apiKey };
|
|
673
|
+
}
|
|
674
|
+
function writeCredential(cred, config, env = {}) {
|
|
675
|
+
const payload = buildStorePayload(cred);
|
|
676
|
+
const dir = credentialHome(config, env);
|
|
677
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
678
|
+
fs.chmodSync(dir, 448);
|
|
679
|
+
const path = authFilePath(config, env);
|
|
680
|
+
const tmp = `${path}.tmp-${crypto.randomBytes(8).toString("hex")}`;
|
|
681
|
+
try {
|
|
682
|
+
const fd = fs.openSync(tmp, "wx", 384);
|
|
683
|
+
try {
|
|
684
|
+
fs.writeFileSync(fd, `${JSON.stringify(payload, null, 2)}
|
|
685
|
+
`);
|
|
686
|
+
fs.fsyncSync(fd);
|
|
687
|
+
} finally {
|
|
688
|
+
fs.closeSync(fd);
|
|
689
|
+
}
|
|
690
|
+
fs.chmodSync(tmp, 384);
|
|
691
|
+
fs.renameSync(tmp, path);
|
|
692
|
+
} catch (err) {
|
|
693
|
+
try {
|
|
694
|
+
fs.unlinkSync(tmp);
|
|
695
|
+
} catch {
|
|
696
|
+
}
|
|
697
|
+
throw new CredentialError(`cannot write ${path}: ${err.message}`);
|
|
698
|
+
}
|
|
699
|
+
return path;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// src/server/auth/errors.ts
|
|
703
|
+
var AuthCallbackError = class extends Error {
|
|
704
|
+
name = "AuthCallbackError";
|
|
705
|
+
code;
|
|
706
|
+
constructor(code, message) {
|
|
707
|
+
super(message ?? `OAuth callback error: ${code}`);
|
|
708
|
+
this.code = code;
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
// src/internal/auth/oauth-engine.ts
|
|
713
|
+
var REFRESH_SKEW_MS = 6e4;
|
|
714
|
+
function parseTokenResponse(body, now) {
|
|
715
|
+
const b = body;
|
|
716
|
+
if (typeof b.access_token !== "string" || b.access_token.length === 0) {
|
|
717
|
+
throw new AuthCallbackError(
|
|
718
|
+
"oauth_token_exchange_failed",
|
|
719
|
+
"token response had no access_token"
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
if (typeof b.refresh_token !== "string" || b.refresh_token.length === 0) {
|
|
723
|
+
throw new AuthCallbackError(
|
|
724
|
+
"oauth_token_exchange_failed",
|
|
725
|
+
"token response had no refresh_token"
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
const expiresIn = typeof b.expires_in === "number" ? b.expires_in : 3600;
|
|
729
|
+
return {
|
|
730
|
+
access: b.access_token,
|
|
731
|
+
refresh: b.refresh_token,
|
|
732
|
+
expires: now + expiresIn * 1e3,
|
|
733
|
+
...typeof b.account_id === "string" ? { accountId: b.account_id } : {}
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
async function postGrant(config, form, deps) {
|
|
737
|
+
let res;
|
|
738
|
+
try {
|
|
739
|
+
res = await deps.fetch(config.tokenEndpoint, {
|
|
740
|
+
method: "POST",
|
|
741
|
+
headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
|
|
742
|
+
body: new URLSearchParams(form).toString()
|
|
743
|
+
});
|
|
744
|
+
} catch (err) {
|
|
745
|
+
throw new AuthCallbackError(
|
|
746
|
+
"oauth_token_exchange_failed",
|
|
747
|
+
`token endpoint request failed: ${err.message}`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
if (!res.ok) {
|
|
751
|
+
throw new AuthCallbackError(
|
|
752
|
+
"oauth_token_exchange_failed",
|
|
753
|
+
`token endpoint returned HTTP ${res.status}`
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
let json;
|
|
757
|
+
try {
|
|
758
|
+
json = await res.json();
|
|
759
|
+
} catch {
|
|
760
|
+
throw new AuthCallbackError("oauth_token_exchange_failed", "token response was not valid JSON");
|
|
761
|
+
}
|
|
762
|
+
return parseTokenResponse(json, deps.now());
|
|
763
|
+
}
|
|
764
|
+
function refreshOAuthTokens(config, refresh, deps) {
|
|
765
|
+
return postGrant(
|
|
766
|
+
config,
|
|
767
|
+
{ grant_type: "refresh_token", refresh_token: refresh, client_id: config.clientId },
|
|
768
|
+
deps
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
function persistOAuthTokens(provider, tokens, store, env = {}) {
|
|
772
|
+
return writeCredential(
|
|
773
|
+
{
|
|
774
|
+
type: "oauth",
|
|
775
|
+
provider,
|
|
776
|
+
access: tokens.access,
|
|
777
|
+
refresh: tokens.refresh,
|
|
778
|
+
expires: tokens.expires,
|
|
779
|
+
...tokens.accountId !== void 0 ? { account_id: tokens.accountId } : {}
|
|
780
|
+
},
|
|
781
|
+
store,
|
|
782
|
+
env
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
var inFlightRefresh = /* @__PURE__ */ new Map();
|
|
786
|
+
async function ensureFreshCredential(resolved, opts, deps) {
|
|
787
|
+
if (resolved.kind !== "oauth") return resolved;
|
|
788
|
+
const now = deps.now();
|
|
789
|
+
if (resolved.expiresAt !== void 0 && resolved.expiresAt > now + REFRESH_SKEW_MS) {
|
|
790
|
+
return resolved;
|
|
791
|
+
}
|
|
792
|
+
const env = opts.env ?? {};
|
|
793
|
+
const path = authFilePath(opts.store, env);
|
|
794
|
+
let refresh = inFlightRefresh.get(path);
|
|
795
|
+
if (refresh === void 0) {
|
|
796
|
+
refresh = (async () => {
|
|
797
|
+
const stored = readStoredOAuth(opts.store, env);
|
|
798
|
+
if (stored === void 0) {
|
|
799
|
+
throw new AuthCallbackError(
|
|
800
|
+
"oauth_token_exchange_failed",
|
|
801
|
+
"no stored oauth credential to refresh"
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
const fresh2 = await refreshOAuthTokens(opts.config, stored.refresh, deps);
|
|
805
|
+
const merged = {
|
|
806
|
+
...fresh2,
|
|
807
|
+
accountId: fresh2.accountId ?? stored.account_id
|
|
808
|
+
};
|
|
809
|
+
persistOAuthTokens(resolved.provider, merged, opts.store, env);
|
|
810
|
+
return merged;
|
|
811
|
+
})();
|
|
812
|
+
inFlightRefresh.set(path, refresh);
|
|
813
|
+
refresh.finally(() => inFlightRefresh.delete(path)).catch(() => {
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
const fresh = await refresh;
|
|
817
|
+
return {
|
|
818
|
+
kind: "oauth",
|
|
819
|
+
provider: resolved.provider,
|
|
820
|
+
apiKey: fresh.access,
|
|
821
|
+
source: resolved.source,
|
|
822
|
+
inferred: false,
|
|
823
|
+
expiresAt: fresh.expires
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// src/internal/auth/resolve-credential.ts
|
|
828
|
+
async function resolveOAuth(stored, path, opts, env) {
|
|
829
|
+
if (stored.provider !== opts.provider) return void 0;
|
|
830
|
+
const base = {
|
|
831
|
+
kind: "oauth",
|
|
832
|
+
provider: opts.provider,
|
|
833
|
+
apiKey: stored.access,
|
|
834
|
+
source: path,
|
|
835
|
+
inferred: false,
|
|
836
|
+
expiresAt: stored.expires
|
|
837
|
+
};
|
|
838
|
+
if (opts.oauth === void 0) return base;
|
|
839
|
+
const deps = {
|
|
840
|
+
fetch: opts.deps?.fetch ?? fetch,
|
|
841
|
+
now: opts.deps?.now ?? (() => Date.now())
|
|
842
|
+
};
|
|
843
|
+
return ensureFreshCredential(base, { config: opts.oauth, store: opts.store, env }, deps);
|
|
844
|
+
}
|
|
845
|
+
async function resolveCredential(opts) {
|
|
846
|
+
const env = opts.env ?? {};
|
|
847
|
+
const stored = readAuthFile(opts.store, env);
|
|
848
|
+
if (stored === void 0) return void 0;
|
|
849
|
+
const path = authFilePath(opts.store, env);
|
|
850
|
+
if (stored.type === "oauth") {
|
|
851
|
+
return resolveOAuth(stored, path, opts, env);
|
|
852
|
+
}
|
|
853
|
+
if (stored.api_key.length === 0) return void 0;
|
|
854
|
+
if (stored.provider !== opts.provider) return void 0;
|
|
855
|
+
return {
|
|
856
|
+
kind: "api",
|
|
857
|
+
provider: opts.provider,
|
|
858
|
+
apiKey: stored.api_key,
|
|
859
|
+
source: path,
|
|
860
|
+
inferred: false
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// src/internal/providers/builtin/openai-chatgpt.ts
|
|
865
|
+
var DEFAULT_STORE = {
|
|
866
|
+
home: os.homedir(),
|
|
867
|
+
dirName: ".theokit",
|
|
868
|
+
fileName: "auth.json",
|
|
869
|
+
homeEnvVar: "THEOKIT_AUTH_HOME"
|
|
870
|
+
};
|
|
871
|
+
var OPENAI_OAUTH_CONFIG = {
|
|
872
|
+
provider: "openai",
|
|
873
|
+
authorizeEndpoint: "https://auth.openai.com/oauth/authorize",
|
|
874
|
+
tokenEndpoint: "https://auth.openai.com/oauth/token",
|
|
875
|
+
clientId: "app_EMoamEEZ73f0CkXaXp7hrann",
|
|
876
|
+
scopes: ["openid", "profile", "email", "offline_access"],
|
|
877
|
+
redirectUri: "https://auth.openai.com/deviceauth/callback"
|
|
878
|
+
};
|
|
879
|
+
function codexFetch() {
|
|
880
|
+
return (async (input, init) => {
|
|
881
|
+
const env = process.env;
|
|
882
|
+
const resolved = await resolveCredential({
|
|
883
|
+
provider: "openai",
|
|
884
|
+
store: DEFAULT_STORE,
|
|
885
|
+
oauth: OPENAI_OAUTH_CONFIG,
|
|
886
|
+
env
|
|
887
|
+
});
|
|
888
|
+
if (resolved === void 0) {
|
|
889
|
+
throw new Error(
|
|
890
|
+
'openai-chatgpt: no ChatGPT credential found \u2014 run the OpenAI device login (e.g. "/login openai") first.'
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
const accountId = readStoredOAuth(DEFAULT_STORE, env)?.account_id;
|
|
894
|
+
const headers = new Headers(init?.headers);
|
|
895
|
+
headers.set("authorization", `Bearer ${resolved.apiKey}`);
|
|
896
|
+
if (accountId !== void 0) headers.set("ChatGPT-Account-Id", accountId);
|
|
897
|
+
return fetch(input, { ...init, headers });
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
var OPENAI_CHATGPT = {
|
|
901
|
+
name: "openai-chatgpt",
|
|
902
|
+
apiMode: "responses_api",
|
|
903
|
+
authType: "oauth_device_code",
|
|
904
|
+
baseUrl: "https://chatgpt.com/backend-api/codex",
|
|
905
|
+
envVars: [],
|
|
906
|
+
fallbackModels: [
|
|
907
|
+
"openai-chatgpt/gpt-5.4",
|
|
908
|
+
"openai-chatgpt/gpt-5.4-mini",
|
|
909
|
+
"openai-chatgpt/gpt-5.5"
|
|
910
|
+
],
|
|
911
|
+
extraHeaders: { originator: "codex_cli_rs" },
|
|
912
|
+
transform: {
|
|
913
|
+
// Only `fetch` (async) can await the credential refresh; `headers` is sync and cannot.
|
|
914
|
+
fetch: () => codexFetch()
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
// src/internal/providers/builtin/openrouter.ts
|
|
919
|
+
var OPENROUTER = {
|
|
920
|
+
name: "openrouter",
|
|
921
|
+
apiMode: "chat_completions",
|
|
922
|
+
aliases: ["or"],
|
|
923
|
+
// Ordered fallback (EC-10): OPENROUTER_API_KEY preferred, OPENAI_API_KEY as compat.
|
|
924
|
+
envVars: ["OPENROUTER_API_KEY", "OPENAI_API_KEY"],
|
|
925
|
+
authType: "api_key",
|
|
926
|
+
baseUrl: "https://openrouter.ai/api",
|
|
927
|
+
modelsUrl: "https://openrouter.ai/api/v1/models",
|
|
928
|
+
hostname: "openrouter.ai",
|
|
929
|
+
// M45 — models refreshed (claude-3-haiku retired upstream).
|
|
930
|
+
fallbackModels: ["openai/gpt-4o-mini", "anthropic/claude-haiku-4-5"],
|
|
931
|
+
// M45 — OpenRouter app-attribution headers (mechanism from OpenCode's openrouter plugin, MIT; VALUES are
|
|
932
|
+
// theokit's own — copying another app's referer would misattribute traffic).
|
|
933
|
+
extraHeaders: { "HTTP-Referer": "https://usetheo.dev", "X-Title": "theokit" }
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
// src/internal/providers/builtin/vertex.ts
|
|
937
|
+
var VERTEX = {
|
|
938
|
+
name: "vertex",
|
|
939
|
+
apiMode: "anthropic_messages",
|
|
940
|
+
// sub-dispatched in selectTransport by profile.name
|
|
941
|
+
envVars: ["GOOGLE_APPLICATION_CREDENTIALS"],
|
|
942
|
+
authType: "gcp_oauth",
|
|
943
|
+
baseUrl: "https://us-central1-aiplatform.googleapis.com",
|
|
944
|
+
modelsUrl: void 0,
|
|
945
|
+
hostname: "aiplatform.googleapis.com",
|
|
946
|
+
fallbackModels: [
|
|
947
|
+
"vertex/anthropic/claude-sonnet-4-5@20250929",
|
|
948
|
+
"vertex/google/gemini-2.0-flash-001"
|
|
949
|
+
]
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
// src/internal/providers/builtin/index.ts
|
|
953
|
+
var registered = false;
|
|
954
|
+
function registerBuiltins() {
|
|
955
|
+
if (registered) return;
|
|
956
|
+
registered = true;
|
|
957
|
+
registerProvider(ANTHROPIC);
|
|
958
|
+
registerProvider(OPENAI);
|
|
959
|
+
registerProvider(OPENAI_CHATGPT);
|
|
960
|
+
registerProvider(OPENROUTER);
|
|
961
|
+
registerProvider(GEMINI);
|
|
962
|
+
registerProvider(OLLAMA);
|
|
963
|
+
registerProvider(LMSTUDIO);
|
|
964
|
+
registerProvider(LLAMACPP);
|
|
965
|
+
registerProvider(BEDROCK);
|
|
966
|
+
registerProvider(VERTEX);
|
|
967
|
+
registerProvider(GOOGLE);
|
|
968
|
+
registerProvider(MISTRAL);
|
|
969
|
+
registerProvider(GROQ);
|
|
970
|
+
registerProvider(COHERE);
|
|
971
|
+
registerProvider(DEEPINFRA);
|
|
972
|
+
registerProvider(TOGETHER);
|
|
973
|
+
registerProvider(XAI);
|
|
974
|
+
registerProvider(PERPLEXITY);
|
|
975
|
+
registerProvider(CEREBRAS);
|
|
976
|
+
registerCatalogProviders();
|
|
977
|
+
}
|
|
978
|
+
|
|
305
979
|
// src/internal/providers/catalog-source-models-dev.ts
|
|
306
980
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
307
981
|
var TTL_MS = 60 * 60 * 1e3;
|
|
308
982
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
309
983
|
function cachePathFor(url) {
|
|
310
|
-
const
|
|
984
|
+
const base = process.env.THEOKIT_HOME?.trim() || path.join(os.homedir(), ".theokit");
|
|
985
|
+
const dir = path.join(base, "cache", "models-dev");
|
|
311
986
|
if (url === DEFAULT_URL) return path.join(dir, "api.json");
|
|
312
987
|
const hash = crypto.createHash("sha256").update(url).digest("hex").slice(0, 12);
|
|
313
988
|
return path.join(dir, `api-${hash}.json`);
|
|
@@ -326,21 +1001,62 @@ function writeCacheAtomic(path$1, body) {
|
|
|
326
1001
|
throw err;
|
|
327
1002
|
}
|
|
328
1003
|
}
|
|
1004
|
+
var MODELS_DEV_ID_MAP = {
|
|
1005
|
+
google: "google-gemini",
|
|
1006
|
+
zai: "zhipu",
|
|
1007
|
+
togetherai: "together",
|
|
1008
|
+
"fireworks-ai": "fireworks",
|
|
1009
|
+
"amazon-bedrock": "bedrock",
|
|
1010
|
+
"google-vertex": "vertex"
|
|
1011
|
+
};
|
|
1012
|
+
var _catalogTargets;
|
|
1013
|
+
function catalogTargets() {
|
|
1014
|
+
if (_catalogTargets !== void 0) return _catalogTargets;
|
|
1015
|
+
_catalogTargets = /* @__PURE__ */ new Map();
|
|
1016
|
+
try {
|
|
1017
|
+
for (const entry of Object.values(loadProviderCatalog())) {
|
|
1018
|
+
const keys = [entry.id, ...entry.aliases ?? []];
|
|
1019
|
+
for (const k of keys) {
|
|
1020
|
+
if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
} catch {
|
|
1024
|
+
}
|
|
1025
|
+
return _catalogTargets;
|
|
1026
|
+
}
|
|
1027
|
+
function resolvePatchKeys(externalId) {
|
|
1028
|
+
const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;
|
|
1029
|
+
const fromCatalog = catalogTargets().get(mapped);
|
|
1030
|
+
if (fromCatalog !== void 0) return fromCatalog.keys;
|
|
1031
|
+
const profile = getProviderProfile(mapped);
|
|
1032
|
+
if (profile !== void 0) return [profile.name, ...profile.aliases ?? []];
|
|
1033
|
+
return void 0;
|
|
1034
|
+
}
|
|
329
1035
|
function patchIndexFromApiJson(raw) {
|
|
330
1036
|
if (typeof raw !== "object" || raw === null) return 0;
|
|
331
1037
|
let patched = 0;
|
|
1038
|
+
const skipped = [];
|
|
332
1039
|
for (const [providerId, provider] of Object.entries(raw)) {
|
|
333
1040
|
const models = provider?.models;
|
|
334
1041
|
if (models === void 0 || typeof models !== "object") continue;
|
|
335
|
-
const
|
|
336
|
-
if (
|
|
1042
|
+
const keys = resolvePatchKeys(providerId);
|
|
1043
|
+
if (keys === void 0) {
|
|
1044
|
+
skipped.push(providerId);
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
337
1047
|
for (const [modelId, rawModel] of Object.entries(models)) {
|
|
338
1048
|
const parsed = catalogModelSchema.safeParse(rawModel);
|
|
339
1049
|
if (!parsed.success) continue;
|
|
340
|
-
patchModelInfo(`${
|
|
1050
|
+
for (const key of keys) patchModelInfo(`${key}/${modelId}`, parsed.data);
|
|
341
1051
|
patched++;
|
|
342
1052
|
}
|
|
343
1053
|
}
|
|
1054
|
+
if (skipped.length > 0) {
|
|
1055
|
+
process.stderr.write(
|
|
1056
|
+
`[theokit-sdk] WARN: models-dev refresh skipped ${skipped.length} unknown provider(s) (e.g. ${skipped.slice(0, 3).join(", ")})
|
|
1057
|
+
`
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
344
1060
|
return patched;
|
|
345
1061
|
}
|
|
346
1062
|
function loadCacheIntoIndex(url = DEFAULT_URL) {
|
|
@@ -351,8 +1067,9 @@ function loadCacheIntoIndex(url = DEFAULT_URL) {
|
|
|
351
1067
|
} catch {
|
|
352
1068
|
return 0;
|
|
353
1069
|
}
|
|
1070
|
+
let parsed;
|
|
354
1071
|
try {
|
|
355
|
-
|
|
1072
|
+
parsed = JSON.parse(body);
|
|
356
1073
|
} catch {
|
|
357
1074
|
try {
|
|
358
1075
|
fs.unlinkSync(path);
|
|
@@ -362,9 +1079,20 @@ function loadCacheIntoIndex(url = DEFAULT_URL) {
|
|
|
362
1079
|
`);
|
|
363
1080
|
return 0;
|
|
364
1081
|
}
|
|
1082
|
+
try {
|
|
1083
|
+
return patchIndexFromApiJson(parsed);
|
|
1084
|
+
} catch (err) {
|
|
1085
|
+
process.stderr.write(
|
|
1086
|
+
`[theokit-sdk] WARN: models-dev cache patch failed (${err.message})
|
|
1087
|
+
`
|
|
1088
|
+
);
|
|
1089
|
+
return 0;
|
|
1090
|
+
}
|
|
365
1091
|
}
|
|
366
1092
|
async function refreshModelCatalog(opts = {}) {
|
|
367
|
-
|
|
1093
|
+
registerBuiltins();
|
|
1094
|
+
const kill = process.env.THEOKIT_DISABLE_MODELS_FETCH;
|
|
1095
|
+
if (kill !== void 0 && kill !== "" && kill !== "0" && kill.toLowerCase() !== "false") {
|
|
368
1096
|
return { source: "skipped", models: 0 };
|
|
369
1097
|
}
|
|
370
1098
|
const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;
|
|
@@ -409,7 +1137,15 @@ async function refreshModelCatalog(opts = {}) {
|
|
|
409
1137
|
`
|
|
410
1138
|
);
|
|
411
1139
|
}
|
|
412
|
-
|
|
1140
|
+
try {
|
|
1141
|
+
return { source: "network", models: patchIndexFromApiJson(JSON.parse(body)) };
|
|
1142
|
+
} catch (err) {
|
|
1143
|
+
process.stderr.write(
|
|
1144
|
+
`[theokit-sdk] WARN: models-dev patch failed (${err.message}) \u2014 serving existing data
|
|
1145
|
+
`
|
|
1146
|
+
);
|
|
1147
|
+
return { source: "cache", models: 0 };
|
|
1148
|
+
}
|
|
413
1149
|
}
|
|
414
1150
|
function getModelInfo(modelId) {
|
|
415
1151
|
return getCatalogModelInfo(modelId);
|