@theokit/sdk 5.15.3 → 5.16.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 +16 -0
- package/dist/{agent-MOSFFVPU.js → agent-FB56RAXD.js} +11 -10
- package/dist/{agent-MOSFFVPU.js.map → agent-FB56RAXD.js.map} +1 -1
- package/dist/{agent-LTJYDRWI.cjs → agent-TM634NHQ.cjs} +12 -11
- package/dist/{agent-LTJYDRWI.cjs.map → agent-TM634NHQ.cjs.map} +1 -1
- package/dist/chunk-22HVMMXX.cjs +13 -0
- package/dist/chunk-22HVMMXX.cjs.map +1 -0
- package/dist/{chunk-QJVTDW3G.cjs → chunk-3JGRKXA7.cjs} +4 -4
- package/dist/{chunk-QJVTDW3G.cjs.map → chunk-3JGRKXA7.cjs.map} +1 -1
- package/dist/{chunk-CMDM4VF6.js → chunk-4XYCF5PA.js} +3 -3
- package/dist/{chunk-CMDM4VF6.js.map → chunk-4XYCF5PA.js.map} +1 -1
- package/dist/{chunk-4OMRDNPY.js → chunk-6WPNFZH3.js} +4 -4
- package/dist/{chunk-4OMRDNPY.js.map → chunk-6WPNFZH3.js.map} +1 -1
- package/dist/{chunk-5L7S2VOL.js → chunk-A3T2A2WU.js} +3 -69
- package/dist/chunk-A3T2A2WU.js.map +1 -0
- package/dist/{chunk-LAZTNGNR.cjs → chunk-BJB6RDEA.cjs} +59 -59
- package/dist/{chunk-LAZTNGNR.cjs.map → chunk-BJB6RDEA.cjs.map} +1 -1
- package/dist/{chunk-3ZRJ4RNB.cjs → chunk-BXEHUUDJ.cjs} +27 -27
- package/dist/{chunk-3ZRJ4RNB.cjs.map → chunk-BXEHUUDJ.cjs.map} +1 -1
- package/dist/{chunk-4TTR63O7.js → chunk-DLCYS5RI.js} +3 -3
- package/dist/{chunk-4TTR63O7.js.map → chunk-DLCYS5RI.js.map} +1 -1
- package/dist/chunk-GA4ZRKYF.cjs +75 -0
- package/dist/chunk-GA4ZRKYF.cjs.map +1 -0
- package/dist/chunk-ICBNSAO4.js +11 -0
- package/dist/chunk-ICBNSAO4.js.map +1 -0
- package/dist/{chunk-HFEAU2L2.js → chunk-MNE4633K.js} +3 -3
- package/dist/{chunk-HFEAU2L2.js.map → chunk-MNE4633K.js.map} +1 -1
- package/dist/{chunk-WAKGYSQ6.js → chunk-NHD5IN3E.js} +10 -10
- package/dist/{chunk-WAKGYSQ6.js.map → chunk-NHD5IN3E.js.map} +1 -1
- package/dist/{chunk-Q4UOCMAO.cjs → chunk-S5WTJ6LL.cjs} +5 -5
- package/dist/{chunk-Q4UOCMAO.cjs.map → chunk-S5WTJ6LL.cjs.map} +1 -1
- package/dist/chunk-SGKMTBCO.cjs +18 -0
- package/dist/{chunk-EDIYR4VR.cjs.map → chunk-SGKMTBCO.cjs.map} +1 -1
- package/dist/{chunk-RB3ZMMUU.cjs → chunk-TDKLSWHU.cjs} +4 -4
- package/dist/{chunk-RB3ZMMUU.cjs.map → chunk-TDKLSWHU.cjs.map} +1 -1
- package/dist/{chunk-AQ23NII7.js → chunk-UNUGF36D.js} +3 -3
- package/dist/{chunk-AQ23NII7.js.map → chunk-UNUGF36D.js.map} +1 -1
- package/dist/{chunk-Z5MB2HAN.cjs → chunk-WVQRE7CO.cjs} +4 -70
- package/dist/chunk-WVQRE7CO.cjs.map +1 -0
- package/dist/chunk-Z2UVCAYS.js +72 -0
- package/dist/chunk-Z2UVCAYS.js.map +1 -0
- package/dist/{compact-session-PIDZQ7AR.cjs → compact-session-OHA543HN.cjs} +14 -13
- package/dist/{compact-session-PIDZQ7AR.cjs.map → compact-session-OHA543HN.cjs.map} +1 -1
- package/dist/{compact-session-ZPEJSTLA.js → compact-session-XPJS27JD.js} +5 -4
- package/dist/{compact-session-ZPEJSTLA.js.map → compact-session-XPJS27JD.js.map} +1 -1
- package/dist/cron.cjs +11 -10
- package/dist/cron.js +10 -9
- package/dist/eval.cjs +10 -9
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +9 -8
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +219 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -1
- package/dist/index.d.ts +106 -1
- package/dist/index.js +185 -14
- package/dist/index.js.map +1 -1
- package/dist/{inject-session-Z2HIB6P6.cjs → inject-session-NTL2UAE6.cjs} +5 -5
- package/dist/{inject-session-Z2HIB6P6.cjs.map → inject-session-NTL2UAE6.cjs.map} +1 -1
- package/dist/{inject-session-OMBJKMVD.js → inject-session-SCJ6MTUT.js} +4 -4
- package/dist/{inject-session-OMBJKMVD.js.map → inject-session-SCJ6MTUT.js.map} +1 -1
- package/dist/internal/providers/builtin/openai-chatgpt.d.ts +8 -0
- package/dist/internal/trim-trailing-slashes.d.ts +6 -0
- package/dist/models.cjs +12 -16
- package/dist/models.cjs.map +1 -1
- package/dist/models.js +4 -8
- package/dist/models.js.map +1 -1
- package/dist/openai-chatgpt-IVAL4MW6.cjs +22 -0
- package/dist/openai-chatgpt-IVAL4MW6.cjs.map +1 -0
- package/dist/openai-chatgpt-ZFNZWT2L.js +9 -0
- package/dist/openai-chatgpt-ZFNZWT2L.js.map +1 -0
- package/dist/providers.cjs +5 -4
- package/dist/providers.js +3 -2
- package/dist/sandbox/e2b-sandbox.d.cts +61 -0
- package/dist/sandbox/e2b-sandbox.d.ts +61 -0
- package/dist/sandbox/index.cjs +55 -0
- package/dist/sandbox/index.cjs.map +1 -1
- package/dist/sandbox/index.d.cts +1 -0
- package/dist/sandbox/index.d.ts +1 -0
- package/dist/sandbox/index.js +54 -1
- package/dist/sandbox/index.js.map +1 -1
- package/docs/error-codes.md +2 -1
- package/docs/harness-capability-map.md +21 -1
- package/package.json +5 -1
- package/dist/chunk-5L7S2VOL.js.map +0 -1
- package/dist/chunk-EDIYR4VR.cjs +0 -18
- package/dist/chunk-Z5MB2HAN.cjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var chunkYJNYDJ2T_cjs = require('./chunk-YJNYDJ2T.cjs');
|
|
3
|
+
var chunk3JGRKXA7_cjs = require('./chunk-3JGRKXA7.cjs');
|
|
5
4
|
require('./chunk-EOWIUDKG.cjs');
|
|
5
|
+
var chunkYJNYDJ2T_cjs = require('./chunk-YJNYDJ2T.cjs');
|
|
6
6
|
var chunk6EHOJLJ3_cjs = require('./chunk-6EHOJLJ3.cjs');
|
|
7
7
|
require('./chunk-IZV72OEI.cjs');
|
|
8
8
|
require('./chunk-NVXXWAU7.cjs');
|
|
@@ -10,7 +10,7 @@ require('./chunk-RNXXYF22.cjs');
|
|
|
10
10
|
|
|
11
11
|
// src/internal/session/inject-session.ts
|
|
12
12
|
async function injectSessionTurn(opts) {
|
|
13
|
-
await
|
|
13
|
+
await chunk3JGRKXA7_cjs.enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {
|
|
14
14
|
const prior = await opts.store.readRecords(opts.loc.agentId);
|
|
15
15
|
const transcript = chunk6EHOJLJ3_cjs.SessionTranscript.fromRecords(prior, {
|
|
16
16
|
cwd: opts.loc.cwd,
|
|
@@ -25,5 +25,5 @@ async function injectSessionTurn(opts) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
exports.injectSessionTurn = injectSessionTurn;
|
|
28
|
-
//# sourceMappingURL=inject-session-
|
|
29
|
-
//# sourceMappingURL=inject-session-
|
|
28
|
+
//# sourceMappingURL=inject-session-NTL2UAE6.cjs.map
|
|
29
|
+
//# sourceMappingURL=inject-session-NTL2UAE6.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":["enqueueSessionWrite","SessionTranscript","invalidateSessionCache"],"mappings":";;;;;;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAMA,sCAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAaC,mCAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAAC,wCAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-
|
|
1
|
+
{"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":["enqueueSessionWrite","SessionTranscript","invalidateSessionCache"],"mappings":";;;;;;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAMA,sCAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAaC,mCAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAAC,wCAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-NTL2UAE6.cjs","sourcesContent":["/**\n * M51 (agent-builder) — inject a SYNTHETIC user+assistant pair into a session's persisted transcript\n * WITHOUT running an LLM turn. This is the Codex review-exit mechanism (`exit_success.xml` appended to\n * the parent thread history so follow-ups like \"fix finding 2\" work): the pair chains onto the DAG\n * leaf (M50 pattern) and the in-memory cache is invalidated so the NEXT send re-hydrates with it.\n */\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { SessionTranscript } from \"../persistence/session-transcript.js\";\nimport { enqueueSessionWrite, invalidateSessionCache } from \"./agent-session.js\";\nimport type { CompactLocation } from \"./compact-session.js\";\n\nexport async function injectSessionTurn(opts: {\n store: SessionStore;\n loc: CompactLocation;\n sessionId: string;\n userText: string;\n assistantText: string;\n}): Promise<void> {\n await enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {\n const prior = await opts.store.readRecords(opts.loc.agentId);\n const transcript = SessionTranscript.fromRecords(prior, {\n cwd: opts.loc.cwd,\n sessionId: opts.sessionId,\n model: opts.loc.model ?? \"unknown\",\n });\n transcript.appendUserTurn(opts.userText);\n transcript.appendAssistantTurn({ text: opts.assistantText });\n await opts.store.appendRecords(opts.loc.agentId, transcript.records().slice(prior.length));\n invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);\n });\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { enqueueSessionWrite } from './chunk-
|
|
2
|
-
import { invalidateSessionCache } from './chunk-2XC6KDJM.js';
|
|
1
|
+
import { enqueueSessionWrite } from './chunk-6WPNFZH3.js';
|
|
3
2
|
import './chunk-4E4D6H77.js';
|
|
3
|
+
import { invalidateSessionCache } from './chunk-2XC6KDJM.js';
|
|
4
4
|
import { SessionTranscript } from './chunk-3VX7JHJI.js';
|
|
5
5
|
import './chunk-AZK3QM36.js';
|
|
6
6
|
import './chunk-AGACYRJ2.js';
|
|
@@ -23,5 +23,5 @@ async function injectSessionTurn(opts) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export { injectSessionTurn };
|
|
26
|
-
//# sourceMappingURL=inject-session-
|
|
27
|
-
//# sourceMappingURL=inject-session-
|
|
26
|
+
//# sourceMappingURL=inject-session-SCJ6MTUT.js.map
|
|
27
|
+
//# sourceMappingURL=inject-session-SCJ6MTUT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":[],"mappings":";;;;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAM,oBAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAA,sBAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-
|
|
1
|
+
{"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":[],"mappings":";;;;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAM,oBAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAA,sBAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-SCJ6MTUT.js","sourcesContent":["/**\n * M51 (agent-builder) — inject a SYNTHETIC user+assistant pair into a session's persisted transcript\n * WITHOUT running an LLM turn. This is the Codex review-exit mechanism (`exit_success.xml` appended to\n * the parent thread history so follow-ups like \"fix finding 2\" work): the pair chains onto the DAG\n * leaf (M50 pattern) and the in-memory cache is invalidated so the NEXT send re-hydrates with it.\n */\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { SessionTranscript } from \"../persistence/session-transcript.js\";\nimport { enqueueSessionWrite, invalidateSessionCache } from \"./agent-session.js\";\nimport type { CompactLocation } from \"./compact-session.js\";\n\nexport async function injectSessionTurn(opts: {\n store: SessionStore;\n loc: CompactLocation;\n sessionId: string;\n userText: string;\n assistantText: string;\n}): Promise<void> {\n await enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {\n const prior = await opts.store.readRecords(opts.loc.agentId);\n const transcript = SessionTranscript.fromRecords(prior, {\n cwd: opts.loc.cwd,\n sessionId: opts.sessionId,\n model: opts.loc.model ?? \"unknown\",\n });\n transcript.appendUserTurn(opts.userText);\n transcript.appendAssistantTurn({ text: opts.assistantText });\n await opts.store.appendRecords(opts.loc.agentId, transcript.records().slice(prior.length));\n invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);\n });\n}\n"]}
|
|
@@ -11,4 +11,12 @@
|
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
import type { ProviderProfile } from "../types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Build the per-request fetch: resolve a FRESH (refreshed) Bearer + the LIVE account-id from the ambient
|
|
16
|
+
* store, and inject them as headers. Re-resolves on EVERY call → mid-turn refresh with no rebuild. A
|
|
17
|
+
* `Headers` object is used so `authorization` is set case-insensitively (never doubled). If no credential is
|
|
18
|
+
* logged in, throw a clear error rather than putting the router's `__oauth_lazy_token__` placeholder on the
|
|
19
|
+
* wire (fail-closed — missing-credential semantics).
|
|
20
|
+
*/
|
|
21
|
+
export declare function codexFetch(): typeof fetch;
|
|
14
22
|
export declare const OPENAI_CHATGPT: ProviderProfile;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes trailing `/` characters in one linear pass. Not `/\/+$/`: on caller input such as a
|
|
3
|
+
* model id or a base URL, a long run of slashes followed by anything else makes that regex
|
|
4
|
+
* quadratic (CodeQL `js/polynomial-redos`, measured in tests/llm/model-option-redos.test.ts).
|
|
5
|
+
*/
|
|
6
|
+
export declare function trimTrailingSlashes(value: string): string;
|
package/dist/models.cjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunk7INPXUJI_cjs = require('./chunk-7INPXUJI.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunk22HVMMXX_cjs = require('./chunk-22HVMMXX.cjs');
|
|
5
|
+
var chunkS5WTJ6LL_cjs = require('./chunk-S5WTJ6LL.cjs');
|
|
5
6
|
var chunk3EE6LVWT_cjs = require('./chunk-3EE6LVWT.cjs');
|
|
6
|
-
var
|
|
7
|
+
var chunkWVQRE7CO_cjs = require('./chunk-WVQRE7CO.cjs');
|
|
7
8
|
require('./chunk-NVXXWAU7.cjs');
|
|
9
|
+
require('./chunk-GA4ZRKYF.cjs');
|
|
8
10
|
require('./chunk-UMCCYXFZ.cjs');
|
|
9
11
|
require('./chunk-PXYINWBC.cjs');
|
|
10
12
|
require('./chunk-IOFMRS6T.cjs');
|
|
@@ -26,7 +28,7 @@ function humanizeModelName(modelId) {
|
|
|
26
28
|
const { name } = chunk3EE6LVWT_cjs.parseModelId(modelId);
|
|
27
29
|
if (name.length === 0) return "";
|
|
28
30
|
const colon = name.indexOf(":");
|
|
29
|
-
const base = trimTrailingSlashes(colon >= 0 ? name.slice(0, colon) : name);
|
|
31
|
+
const base = chunk22HVMMXX_cjs.trimTrailingSlashes(colon >= 0 ? name.slice(0, colon) : name);
|
|
30
32
|
const variant = colon >= 0 ? name.slice(colon + 1) : "";
|
|
31
33
|
const lastSlash = base.lastIndexOf("/");
|
|
32
34
|
const core = lastSlash >= 0 ? base.slice(lastSlash + 1) : base;
|
|
@@ -41,12 +43,6 @@ function toModelOption(modelId) {
|
|
|
41
43
|
provider: chunk3EE6LVWT_cjs.parseModelId(modelId).provider
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
|
-
var SLASH_CODE = 47;
|
|
45
|
-
function trimTrailingSlashes(value) {
|
|
46
|
-
let end = value.length;
|
|
47
|
-
while (end > 0 && value.charCodeAt(end - 1) === SLASH_CODE) end--;
|
|
48
|
-
return end === value.length ? value : value.slice(0, end);
|
|
49
|
-
}
|
|
50
46
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
51
47
|
var MAX_CATALOG_BYTES = 32 * 1024 * 1024;
|
|
52
48
|
var TTL_MS = 60 * 60 * 1e3;
|
|
@@ -85,7 +81,7 @@ function catalogTargets() {
|
|
|
85
81
|
if (_catalogTargets !== void 0) return _catalogTargets;
|
|
86
82
|
_catalogTargets = /* @__PURE__ */ new Map();
|
|
87
83
|
try {
|
|
88
|
-
for (const entry of Object.values(
|
|
84
|
+
for (const entry of Object.values(chunkWVQRE7CO_cjs.loadProviderCatalog())) {
|
|
89
85
|
const keys = [entry.id, ...entry.aliases ?? []];
|
|
90
86
|
for (const k of keys) {
|
|
91
87
|
if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });
|
|
@@ -99,7 +95,7 @@ function resolvePatchKeys(externalId) {
|
|
|
99
95
|
const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;
|
|
100
96
|
const fromCatalog = catalogTargets().get(mapped);
|
|
101
97
|
if (fromCatalog !== void 0) return fromCatalog.keys;
|
|
102
|
-
const profile =
|
|
98
|
+
const profile = chunkWVQRE7CO_cjs.getProviderProfile(mapped);
|
|
103
99
|
if (profile !== void 0) return [profile.name, ...profile.aliases ?? []];
|
|
104
100
|
return void 0;
|
|
105
101
|
}
|
|
@@ -116,9 +112,9 @@ function patchIndexFromApiJson(raw) {
|
|
|
116
112
|
continue;
|
|
117
113
|
}
|
|
118
114
|
for (const [modelId, rawModel] of Object.entries(models)) {
|
|
119
|
-
const parsed =
|
|
115
|
+
const parsed = chunkWVQRE7CO_cjs.catalogModelSchema.safeParse(rawModel);
|
|
120
116
|
if (!parsed.success) continue;
|
|
121
|
-
for (const key of keys)
|
|
117
|
+
for (const key of keys) chunkWVQRE7CO_cjs.patchModelInfo(`${key}/${modelId}`, parsed.data);
|
|
122
118
|
patched++;
|
|
123
119
|
}
|
|
124
120
|
}
|
|
@@ -218,7 +214,7 @@ function persistAndPatch(path, body) {
|
|
|
218
214
|
}
|
|
219
215
|
}
|
|
220
216
|
async function refreshModelCatalog(opts = {}) {
|
|
221
|
-
|
|
217
|
+
chunkWVQRE7CO_cjs.registerBuiltins();
|
|
222
218
|
if (fetchDisabledByEnv()) return { source: "skipped", models: 0 };
|
|
223
219
|
const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;
|
|
224
220
|
const path = cachePathFor(url);
|
|
@@ -232,12 +228,12 @@ async function refreshModelCatalog(opts = {}) {
|
|
|
232
228
|
return persistAndPatch(path, body);
|
|
233
229
|
}
|
|
234
230
|
function getModelInfo(modelId) {
|
|
235
|
-
return
|
|
231
|
+
return chunkWVQRE7CO_cjs.getCatalogModelInfo(modelId);
|
|
236
232
|
}
|
|
237
233
|
|
|
238
234
|
Object.defineProperty(exports, "resolveModelCapabilities", {
|
|
239
235
|
enumerable: true,
|
|
240
|
-
get: function () { return
|
|
236
|
+
get: function () { return chunkS5WTJ6LL_cjs.resolveModelCapabilities; }
|
|
241
237
|
});
|
|
242
238
|
Object.defineProperty(exports, "parseModelId", {
|
|
243
239
|
enumerable: true,
|
package/dist/models.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/llm/model-option.ts","../src/internal/providers/catalog-source-models-dev.ts"],"names":["parseModelId","join","homedir","createHash","mkdirSync","dirname","randomBytes","writeFileSync","renameSync","unlinkSync","loadProviderCatalog","getProviderProfile","catalogModelSchema","patchModelInfo","diag","readFileSync","statSync","Retry","registerBuiltins","boundFetch","getCatalogModelInfo"],"mappings":"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","file":"models.cjs","sourcesContent":["import { parseModelId } from \"./model-identifier.js\";\n\n/**\n * A UI-friendly model option — the shape a `<select>`/dropdown consumes.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport interface ModelOption {\n /** The original model id (what you pass back to the SDK). */\n value: string;\n /** Best-effort human label (see {@link humanizeModelName}). */\n label: string;\n /** Provider from the slug prefix, or `undefined` when none. */\n provider: string | undefined;\n}\n\n/** Tokens rendered upper-case rather than title-case. */\nconst ACRONYMS = new Set([\"gpt\", \"ai\", \"hd\", \"ui\", \"api\", \"sdk\", \"llm\", \"xl\"]);\n\nfunction prettyToken(token: string): string {\n if (ACRONYMS.has(token.toLowerCase())) return token.toUpperCase();\n return token.charAt(0).toUpperCase() + token.slice(1);\n}\n\n/**\n * Turn a model id into a best-effort human label: strip the routing/vendor\n * prefix to the core model segment, split on `-`/`_`/`.`/whitespace, title-case\n * each token (known acronyms upper-cased), and append an OpenRouter `:variant`\n * in parentheses. Deterministic, pure, dependency-free.\n *\n * Best-effort, NOT vendor-canonical: `\"anthropic/claude-3-5-sonnet\"` →\n * `\"Claude 3 5 Sonnet\"`. A UI wanting exact marketing names overrides per id.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function humanizeModelName(modelId: string): string {\n const { name } = parseModelId(modelId);\n if (name.length === 0) return \"\";\n const colon = name.indexOf(\":\");\n // Strip a trailing slash so a typo'd `gpt-4o/` keeps its name (not lost to an\n // empty last segment).\n //\n // Done by index rather than with `/\\/+$/`, and the difference is not stylistic: that pattern\n // consumes slashes to the end of the string at every start position and then backtracks\n // looking for an end-anchor that is not there (CodeQL js/polynomial-redos #6). This function\n // is `@public` and takes a caller-supplied model id. Measured on a run of slashes followed by\n // one other character: 25_000 took 496 ms, 100_000 took 31_305 ms — half a minute of pinned\n // CPU to render a label. Walking back from the end is linear and cannot backtrack.\n const base = trimTrailingSlashes(colon >= 0 ? name.slice(0, colon) : name);\n const variant = colon >= 0 ? name.slice(colon + 1) : \"\";\n const lastSlash = base.lastIndexOf(\"/\");\n const core = lastSlash >= 0 ? base.slice(lastSlash + 1) : base;\n const label = core\n .split(/[-_.\\s]+/)\n .filter((t) => t.length > 0)\n .map(prettyToken)\n .join(\" \");\n if (label.length === 0) return variant; // no base label (e.g. \":free\") → bare variant\n return variant.length > 0 ? `${label} (${variant})` : label;\n}\n\n/**\n * Build a {@link ModelOption} (`{ value, label, provider }`) for a model id —\n * a dropdown-ready entry composing {@link humanizeModelName} + `parseModelId`.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function toModelOption(modelId: string): ModelOption {\n return {\n value: modelId,\n label: humanizeModelName(modelId),\n provider: parseModelId(modelId).provider,\n };\n}\n\nconst SLASH_CODE = 47; // \"/\"\n\n/** Removes trailing `/` characters in one linear pass. See the call site for why not a regex. */\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === SLASH_CODE) end--;\n return end === value.length ? value : value.slice(0, end);\n}\n","import { createHash, randomBytes } from \"node:crypto\";\nimport { mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { Retry } from \"../../retry.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { boundFetch } from \"../runtime-fetch.js\";\nimport { registerBuiltins } from \"./builtin/index.js\";\nimport { getCatalogModelInfo, loadProviderCatalog, patchModelInfo } from \"./catalog-loader.js\";\nimport { catalogModelSchema } from \"./catalog-schema.js\";\nimport { getProviderProfile } from \"./registry.js\";\n\n/**\n * M44 — the OPTIONAL models.dev catalog source. Explicit opt-in ONLY (`refreshModelCatalog()`): the SDK\n * NEVER fetches at startup or per-request — the vendored catalog + any existing disk cache are the offline\n * base, and every failure mode fails CLOSED back to them (ROADMAP constraint: no runtime hard network dep).\n *\n * The models.dev consumption mechanism:\n * disk cache with mtime TTL, atomic tempfile+rename write, corrupt-cache delete-and-fall-through, kill-switch\n * env. Library adaptations: NO background refresh loop (a consumer composes refresh with the SDK's cron);\n * TTL 1h (not 5min — no background refresher to keep it warm); no cross-process flock v1 (atomic rename +\n * idempotent upstream content — at most one wasted fetch).\n *\n * @internal (the public surface is `refreshModelCatalog` re-exported via `@theokit/sdk/models`)\n */\n\nconst DEFAULT_URL = \"https://models.dev/api.json\";\n\n/**\n * Ceiling on a fetched catalog, before it is parsed or written to the cache.\n *\n * The response body was read with `res.text()` and persisted with no bound, so a host serving a\n * multi-gigabyte document would have been materialised in memory and then written to disk. The\n * default URL is trusted, but `THEOKIT_MODELS_URL` lets an operator point this anywhere, and a\n * limit is the difference between \"we only fetch from a host we trust\" and \"we cannot be hurt by\n * one we do not\".\n *\n * 32 MiB is roughly 40x the real catalog (~800 KiB in 2026-08), so it bounds the failure without\n * being a number anyone has to tune when models.dev grows.\n */\nconst MAX_CATALOG_BYTES = 32 * 1024 * 1024;\nconst TTL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000;\n\n/**\n * Arguments to `refreshModelCatalog`, the SDK's only network trigger for model metadata.\n *\n * `url` wins over the `THEOKIT_MODELS_URL` environment variable, which in turn wins over\n * `https://models.dev/api.json`. A non-default URL gets its own cache file, named by a hash of\n * the URL, so switching sources never reads another source's cache.\n *\n * `force` skips only the freshness check — it does not skip the kill switch. When\n * `THEOKIT_DISABLE_MODELS_FETCH` is set to anything other than an empty string, `\"0\"` or\n * `\"false\"`, the call returns `source: \"skipped\"` with no fetch and no cache read, whatever\n * `force` says.\n *\n * Without `force`, a cache file whose mtime is under an hour old is served directly and no\n * request is made.\n *\n * `deps` exists so tests can drive the fetch and the clock; production leaves it unset.\n */\nexport interface RefreshModelCatalogOptions {\n /** Override the source URL (`THEOKIT_MODELS_URL` env also honored). */\n url?: string;\n /** Bypass the TTL freshness gate. */\n force?: boolean;\n /** Injected for tests. */\n deps?: { fetch?: typeof fetch; now?: () => number };\n}\n\n/**\n * What `refreshModelCatalog` did. It never throws on a failed refresh, so this is the only place\n * the outcome is reported.\n *\n * `source` is `\"network\"` only when a request succeeded, its body parsed as JSON, and the models\n * were patched in. Every failure path — kill switch aside — returns `\"cache\"`: an HTTP error\n * after retries, a timeout, an unparseable body, or a patch that threw. `\"cache\"` therefore means\n * \"serving what was already there\", which may be a fresh cache, a stale one, or nothing but the\n * vendored catalog. Read `models` to tell those apart. `\"skipped\"` means the kill switch was set.\n *\n * `models` counts the models patched into the index during this call, not the catalog's size. It\n * counts each model once even when the provider has aliases and the model is written under several\n * index keys, and it excludes models whose payload failed schema validation and models under\n * providers the SDK does not know. It is 0 whenever there was no cache to fall back on, and 0 for\n * `\"skipped\"`.\n *\n * A cache write that fails is logged and otherwise ignored: the result can still say `\"network\"`\n * with the data live in memory and nothing on disk.\n */\nexport interface RefreshModelCatalogResult {\n /** Where the data came from: a fresh network fetch, the still-fresh disk cache, or skipped entirely. */\n source: \"network\" | \"cache\" | \"skipped\";\n /** How many models were patched into the index. */\n models: number;\n}\n\n/** The cache file for a source URL (custom URLs get a hash-suffixed name). */\nexport function cachePathFor(url: string): string {\n // M44 L8 fix — honor the SDK home override so tests and multi-home setups never touch the real ~/.theokit.\n const base = process.env.THEOKIT_HOME?.trim() || join(homedir(), \".theokit\");\n const dir = join(base, \"cache\", \"models-dev\");\n if (url === DEFAULT_URL) return join(dir, \"api.json\");\n const hash = createHash(\"sha256\").update(url).digest(\"hex\").slice(0, 12);\n return join(dir, `api-${hash}.json`);\n}\n\n/** Atomic write: temp file + rename (crash mid-write never leaves a partial cache). */\nfunction writeCacheAtomic(path: string, body: string): void {\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${randomBytes(6).toString(\"hex\")}`;\n try {\n writeFileSync(tmp, body);\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // best effort\n }\n throw err;\n }\n}\n\n/**\n * M44 H3 fix — models.dev provider ids ≠ theokit ids (google↔google-gemini, zai↔zhipu, togetherai↔together,\n * fireworks-ai↔fireworks, amazon-bedrock↔bedrock, google-vertex↔vertex). The RUNTIME mapping mirrors the\n * maintenance script's table; targets resolve against the CATALOG entries (id + aliases — the same namespace\n * the vendored index uses) first, then the registry.\n */\nconst MODELS_DEV_ID_MAP: Record<string, string> = {\n google: \"google-gemini\",\n zai: \"zhipu\",\n togetherai: \"together\",\n \"fireworks-ai\": \"fireworks\",\n \"amazon-bedrock\": \"bedrock\",\n \"google-vertex\": \"vertex\",\n};\n\nlet _catalogTargets: Map<string, { keys: string[] }> | undefined;\n/** external-id → the index keys (entry id + aliases) its models patch under. Lazy; catalog-first. */\nfunction catalogTargets(): Map<string, { keys: string[] }> {\n if (_catalogTargets !== undefined) return _catalogTargets;\n _catalogTargets = new Map();\n try {\n for (const entry of Object.values(loadProviderCatalog())) {\n const keys = [entry.id, ...(entry.aliases ?? [])];\n for (const k of keys) {\n if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });\n }\n }\n } catch {\n // catalog unavailable — registry fallback below still works\n }\n return _catalogTargets;\n}\n\nfunction resolvePatchKeys(externalId: string): string[] | undefined {\n const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;\n const fromCatalog = catalogTargets().get(mapped);\n if (fromCatalog !== undefined) return fromCatalog.keys;\n const profile = getProviderProfile(mapped);\n if (profile !== undefined) return [profile.name, ...(profile.aliases ?? [])];\n return undefined;\n}\n\n/** Parse + patch the index from an api.json payload. Unknown providers are skipped with WARN (once each). */\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: validates and merges an UNTRUSTED upstream payload (models.dev api.json) shape by shape, dropping a single bad model rather than the file. Each branch is a distinct malformed input; merging them loses which one was seen.\nfunction patchIndexFromApiJson(raw: unknown): number {\n if (typeof raw !== \"object\" || raw === null) return 0;\n let patched = 0;\n const skipped: string[] = [];\n for (const [providerId, provider] of Object.entries(raw as Record<string, unknown>)) {\n const models = (provider as { models?: Record<string, unknown> })?.models;\n if (models === undefined || typeof models !== \"object\") continue;\n // Enrich ONLY providers the SDK knows — models.dev's npm/api fields cannot be mapped to a theokit\n // apiMode/authType safely, so unknown providers are data we cannot route.\n const keys = resolvePatchKeys(providerId);\n if (keys === undefined) {\n skipped.push(providerId);\n continue;\n }\n for (const [modelId, rawModel] of Object.entries(models)) {\n const parsed = catalogModelSchema.safeParse(rawModel);\n if (!parsed.success) continue; // malformed model — drop silently (live data, additive drift expected)\n for (const key of keys) patchModelInfo(`${key}/${modelId}`, parsed.data);\n patched++;\n }\n }\n if (skipped.length > 0) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh skipped ${skipped.length} unknown provider(s) (e.g. ${skipped.slice(0, 3).join(\", \")})\\n`,\n );\n }\n return patched;\n}\n\n/**\n * Load an existing disk cache into the index (called by refresh when fresh, or opportunistically by a\n * consumer at startup — NEVER fetches). Corrupt cache → delete + fall through to vendored data.\n */\nexport function loadCacheIntoIndex(url: string = DEFAULT_URL): number {\n const path = cachePathFor(url);\n let body: string;\n try {\n body = readFileSync(path, \"utf-8\");\n } catch {\n return 0; // no cache — vendored data only\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n // corrupt cache: delete and fall through to the vendored catalog.\n // M44 L9 fix — only a PARSE failure is cache corruption; a patch error must never delete a valid cache.\n try {\n unlinkSync(path);\n } catch {\n // best effort\n }\n diag(`[theokit-sdk] WARN: corrupt models-dev cache deleted (${path})\\n`);\n return 0;\n }\n try {\n return patchIndexFromApiJson(parsed);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache patch failed (${(err as Error).message})\\n`);\n return 0;\n }\n}\n\n/**\n * The kill switch, read from the environment.\n *\n * Truthy-only by design (M44 L11): a presence check would treat `THEOKIT_DISABLE_MODELS_FETCH=0`\n * and `=false` as \"disabled\", which is the opposite of what anyone writing them means.\n */\nfunction fetchDisabledByEnv(): boolean {\n const kill = process.env.THEOKIT_DISABLE_MODELS_FETCH;\n return kill !== undefined && kill !== \"\" && kill !== \"0\" && kill.toLowerCase() !== \"false\";\n}\n\n/**\n * The TTL gate: a cache file younger than {@link TTL_MS} serves without touching the network.\n *\n * Returns `undefined` when there is no usable cache — including when `statSync` throws, which is\n * how \"no cache file\" arrives. That is the ONE failure this step owns, and its fallback is simply\n * to let the caller proceed to the fetch.\n */\nfunction servedFromFreshCache(\n url: string,\n path: string,\n now: () => number,\n): RefreshModelCatalogResult | undefined {\n try {\n if (now() - statSync(path).mtimeMs >= TTL_MS) return undefined;\n } catch {\n return undefined; // no cache — proceed to fetch\n }\n return { source: \"cache\", models: loadCacheIntoIndex(url) };\n}\n\n/**\n * Fetch the catalog, bound its size, and prove it parses before anyone persists it.\n *\n * Returns `undefined` after logging when ANY of that fails — timeout, non-2xx, oversize, unparseable\n * body. The fallback this step owns is \"serve what we already have\", and the caller applies it.\n * Splitting the step from its fallback was the objection recorded in the suppression this replaces;\n * the fallback is not separated, it is named — `undefined` means \"this step could not produce a\n * body\", and there is exactly one thing to do about that.\n */\nasync function fetchCatalogBody(url: string, fetchImpl: typeof fetch): Promise<string | undefined> {\n try {\n const res = await Retry.run(\n async () => {\n const r = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r;\n },\n // 2 transient retries with backoff; every error here is worth one more try —\n // the whole call is already fail-closed at the caller.\n { retries: 2, isRetryable: () => true, initialDelayMs: 200 },\n );\n const declaredLength = Number(res.headers.get(\"content-length\") ?? Number.NaN);\n if (Number.isFinite(declaredLength) && declaredLength > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${declaredLength} bytes declared`);\n }\n const body = await res.text();\n // Checked again after reading: `content-length` is the server's claim, and a server that\n // omits it or lies about it is exactly the one worth bounding. Both checks are cheap and\n // neither alone is sufficient.\n if (body.length > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${body.length} bytes received`);\n }\n JSON.parse(body); // validate before persisting — never cache garbage\n return body;\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return undefined;\n }\n}\n\n/**\n * Persist the fetched body and patch it into the index.\n *\n * Two independent failures with two different consequences, which is why they are two try blocks\n * and not one: a cache write that fails costs the NEXT process a fetch and nothing more, so the run\n * continues; a patch that fails means this body never reached the index, so the index is whatever it\n * was and the result says `cache`.\n */\nfunction persistAndPatch(path: string, body: string): RefreshModelCatalogResult {\n try {\n writeCacheAtomic(path, body);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache write failed (${(err as Error).message})\\n`);\n }\n try {\n return { source: \"network\", models: patchIndexFromApiJson(JSON.parse(body)) };\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev patch failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return { source: \"cache\", models: 0 };\n }\n}\n\n/**\n * Explicitly refresh the model catalog from models.dev (the ONLY network trigger in the subsystem).\n * Fail-closed: any failure keeps serving the current index (cache or vendored). Kill-switch:\n * `THEOKIT_DISABLE_MODELS_FETCH`.\n *\n * The sequence carried a cognitive-complexity suppression whose reason said splitting it would\n * \"separate a step from the fallback it owns\". The four helpers above each KEEP their fallback: the\n * TTL gate owns \"no cache\", the fetch owns every network and validation failure, the persist owns\n * the write and the patch. What is left here is the order they run in, which is what this function\n * was always for.\n *\n * Still true, and NOT fixed by the split: three of the paths return `{ source: \"cache\" }`, so a\n * caller cannot tell a timeout from an unparseable body from a patch failure. Distinguishing them\n * means adding a field to the PUBLIC `RefreshModelCatalogResult`, which is a release decision rather\n * than a refactor. The `diag` line already names the cause for an operator.\n */\nexport async function refreshModelCatalog(\n opts: RefreshModelCatalogOptions = {},\n): Promise<RefreshModelCatalogResult> {\n // M44 M4 fix — self-initialize provider registration so the `@theokit/sdk/models` subpath works\n // standalone (without the consumer having built an Agent first).\n registerBuiltins();\n if (fetchDisabledByEnv()) return { source: \"skipped\", models: 0 };\n\n const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;\n const path = cachePathFor(url);\n const now = opts.deps?.now ?? (() => Date.now());\n\n if (opts.force !== true) {\n const cached = servedFromFreshCache(url, path, now);\n if (cached !== undefined) return cached;\n }\n\n const body = await fetchCatalogBody(url, boundFetch(opts.deps?.fetch));\n // fail-closed: serve whatever we already have (stale cache if present, else vendored)\n if (body === undefined) return { source: \"cache\", models: loadCacheIntoIndex(url) };\n\n return persistAndPatch(path, body);\n}\n\n/** The enriched per-model view (public via `@theokit/sdk/models`): index lookup by (possibly prefixed) id. */\nexport function getModelInfo(modelId: string): ReturnType<typeof getCatalogModelInfo> {\n return getCatalogModelInfo(modelId);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/llm/model-option.ts","../src/internal/providers/catalog-source-models-dev.ts"],"names":["parseModelId","trimTrailingSlashes","join","homedir","createHash","mkdirSync","dirname","randomBytes","writeFileSync","renameSync","unlinkSync","loadProviderCatalog","getProviderProfile","catalogModelSchema","patchModelInfo","diag","readFileSync","statSync","Retry","registerBuiltins","boundFetch","getCatalogModelInfo"],"mappings":"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","file":"models.cjs","sourcesContent":["import { trimTrailingSlashes } from \"../trim-trailing-slashes.js\";\nimport { parseModelId } from \"./model-identifier.js\";\n\n/**\n * A UI-friendly model option — the shape a `<select>`/dropdown consumes.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport interface ModelOption {\n /** The original model id (what you pass back to the SDK). */\n value: string;\n /** Best-effort human label (see {@link humanizeModelName}). */\n label: string;\n /** Provider from the slug prefix, or `undefined` when none. */\n provider: string | undefined;\n}\n\n/** Tokens rendered upper-case rather than title-case. */\nconst ACRONYMS = new Set([\"gpt\", \"ai\", \"hd\", \"ui\", \"api\", \"sdk\", \"llm\", \"xl\"]);\n\nfunction prettyToken(token: string): string {\n if (ACRONYMS.has(token.toLowerCase())) return token.toUpperCase();\n return token.charAt(0).toUpperCase() + token.slice(1);\n}\n\n/**\n * Turn a model id into a best-effort human label: strip the routing/vendor\n * prefix to the core model segment, split on `-`/`_`/`.`/whitespace, title-case\n * each token (known acronyms upper-cased), and append an OpenRouter `:variant`\n * in parentheses. Deterministic, pure, dependency-free.\n *\n * Best-effort, NOT vendor-canonical: `\"anthropic/claude-3-5-sonnet\"` →\n * `\"Claude 3 5 Sonnet\"`. A UI wanting exact marketing names overrides per id.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function humanizeModelName(modelId: string): string {\n const { name } = parseModelId(modelId);\n if (name.length === 0) return \"\";\n const colon = name.indexOf(\":\");\n // Strip a trailing slash so a typo'd `gpt-4o/` keeps its name (not lost to an\n // empty last segment).\n //\n // Done by index rather than with `/\\/+$/`, and the difference is not stylistic: that pattern\n // consumes slashes to the end of the string at every start position and then backtracks\n // looking for an end-anchor that is not there (CodeQL js/polynomial-redos #6). This function\n // is `@public` and takes a caller-supplied model id. Measured on a run of slashes followed by\n // one other character: 25_000 took 496 ms, 100_000 took 31_305 ms — half a minute of pinned\n // CPU to render a label. Walking back from the end is linear and cannot backtrack.\n const base = trimTrailingSlashes(colon >= 0 ? name.slice(0, colon) : name);\n const variant = colon >= 0 ? name.slice(colon + 1) : \"\";\n const lastSlash = base.lastIndexOf(\"/\");\n const core = lastSlash >= 0 ? base.slice(lastSlash + 1) : base;\n const label = core\n .split(/[-_.\\s]+/)\n .filter((t) => t.length > 0)\n .map(prettyToken)\n .join(\" \");\n if (label.length === 0) return variant; // no base label (e.g. \":free\") → bare variant\n return variant.length > 0 ? `${label} (${variant})` : label;\n}\n\n/**\n * Build a {@link ModelOption} (`{ value, label, provider }`) for a model id —\n * a dropdown-ready entry composing {@link humanizeModelName} + `parseModelId`.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function toModelOption(modelId: string): ModelOption {\n return {\n value: modelId,\n label: humanizeModelName(modelId),\n provider: parseModelId(modelId).provider,\n };\n}\n","import { createHash, randomBytes } from \"node:crypto\";\nimport { mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { Retry } from \"../../retry.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { boundFetch } from \"../runtime-fetch.js\";\nimport { registerBuiltins } from \"./builtin/index.js\";\nimport { getCatalogModelInfo, loadProviderCatalog, patchModelInfo } from \"./catalog-loader.js\";\nimport { catalogModelSchema } from \"./catalog-schema.js\";\nimport { getProviderProfile } from \"./registry.js\";\n\n/**\n * M44 — the OPTIONAL models.dev catalog source. Explicit opt-in ONLY (`refreshModelCatalog()`): the SDK\n * NEVER fetches at startup or per-request — the vendored catalog + any existing disk cache are the offline\n * base, and every failure mode fails CLOSED back to them (ROADMAP constraint: no runtime hard network dep).\n *\n * The models.dev consumption mechanism:\n * disk cache with mtime TTL, atomic tempfile+rename write, corrupt-cache delete-and-fall-through, kill-switch\n * env. Library adaptations: NO background refresh loop (a consumer composes refresh with the SDK's cron);\n * TTL 1h (not 5min — no background refresher to keep it warm); no cross-process flock v1 (atomic rename +\n * idempotent upstream content — at most one wasted fetch).\n *\n * @internal (the public surface is `refreshModelCatalog` re-exported via `@theokit/sdk/models`)\n */\n\nconst DEFAULT_URL = \"https://models.dev/api.json\";\n\n/**\n * Ceiling on a fetched catalog, before it is parsed or written to the cache.\n *\n * The response body was read with `res.text()` and persisted with no bound, so a host serving a\n * multi-gigabyte document would have been materialised in memory and then written to disk. The\n * default URL is trusted, but `THEOKIT_MODELS_URL` lets an operator point this anywhere, and a\n * limit is the difference between \"we only fetch from a host we trust\" and \"we cannot be hurt by\n * one we do not\".\n *\n * 32 MiB is roughly 40x the real catalog (~800 KiB in 2026-08), so it bounds the failure without\n * being a number anyone has to tune when models.dev grows.\n */\nconst MAX_CATALOG_BYTES = 32 * 1024 * 1024;\nconst TTL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000;\n\n/**\n * Arguments to `refreshModelCatalog`, the SDK's only network trigger for model metadata.\n *\n * `url` wins over the `THEOKIT_MODELS_URL` environment variable, which in turn wins over\n * `https://models.dev/api.json`. A non-default URL gets its own cache file, named by a hash of\n * the URL, so switching sources never reads another source's cache.\n *\n * `force` skips only the freshness check — it does not skip the kill switch. When\n * `THEOKIT_DISABLE_MODELS_FETCH` is set to anything other than an empty string, `\"0\"` or\n * `\"false\"`, the call returns `source: \"skipped\"` with no fetch and no cache read, whatever\n * `force` says.\n *\n * Without `force`, a cache file whose mtime is under an hour old is served directly and no\n * request is made.\n *\n * `deps` exists so tests can drive the fetch and the clock; production leaves it unset.\n */\nexport interface RefreshModelCatalogOptions {\n /** Override the source URL (`THEOKIT_MODELS_URL` env also honored). */\n url?: string;\n /** Bypass the TTL freshness gate. */\n force?: boolean;\n /** Injected for tests. */\n deps?: { fetch?: typeof fetch; now?: () => number };\n}\n\n/**\n * What `refreshModelCatalog` did. It never throws on a failed refresh, so this is the only place\n * the outcome is reported.\n *\n * `source` is `\"network\"` only when a request succeeded, its body parsed as JSON, and the models\n * were patched in. Every failure path — kill switch aside — returns `\"cache\"`: an HTTP error\n * after retries, a timeout, an unparseable body, or a patch that threw. `\"cache\"` therefore means\n * \"serving what was already there\", which may be a fresh cache, a stale one, or nothing but the\n * vendored catalog. Read `models` to tell those apart. `\"skipped\"` means the kill switch was set.\n *\n * `models` counts the models patched into the index during this call, not the catalog's size. It\n * counts each model once even when the provider has aliases and the model is written under several\n * index keys, and it excludes models whose payload failed schema validation and models under\n * providers the SDK does not know. It is 0 whenever there was no cache to fall back on, and 0 for\n * `\"skipped\"`.\n *\n * A cache write that fails is logged and otherwise ignored: the result can still say `\"network\"`\n * with the data live in memory and nothing on disk.\n */\nexport interface RefreshModelCatalogResult {\n /** Where the data came from: a fresh network fetch, the still-fresh disk cache, or skipped entirely. */\n source: \"network\" | \"cache\" | \"skipped\";\n /** How many models were patched into the index. */\n models: number;\n}\n\n/** The cache file for a source URL (custom URLs get a hash-suffixed name). */\nexport function cachePathFor(url: string): string {\n // M44 L8 fix — honor the SDK home override so tests and multi-home setups never touch the real ~/.theokit.\n const base = process.env.THEOKIT_HOME?.trim() || join(homedir(), \".theokit\");\n const dir = join(base, \"cache\", \"models-dev\");\n if (url === DEFAULT_URL) return join(dir, \"api.json\");\n const hash = createHash(\"sha256\").update(url).digest(\"hex\").slice(0, 12);\n return join(dir, `api-${hash}.json`);\n}\n\n/** Atomic write: temp file + rename (crash mid-write never leaves a partial cache). */\nfunction writeCacheAtomic(path: string, body: string): void {\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${randomBytes(6).toString(\"hex\")}`;\n try {\n writeFileSync(tmp, body);\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // best effort\n }\n throw err;\n }\n}\n\n/**\n * M44 H3 fix — models.dev provider ids ≠ theokit ids (google↔google-gemini, zai↔zhipu, togetherai↔together,\n * fireworks-ai↔fireworks, amazon-bedrock↔bedrock, google-vertex↔vertex). The RUNTIME mapping mirrors the\n * maintenance script's table; targets resolve against the CATALOG entries (id + aliases — the same namespace\n * the vendored index uses) first, then the registry.\n */\nconst MODELS_DEV_ID_MAP: Record<string, string> = {\n google: \"google-gemini\",\n zai: \"zhipu\",\n togetherai: \"together\",\n \"fireworks-ai\": \"fireworks\",\n \"amazon-bedrock\": \"bedrock\",\n \"google-vertex\": \"vertex\",\n};\n\nlet _catalogTargets: Map<string, { keys: string[] }> | undefined;\n/** external-id → the index keys (entry id + aliases) its models patch under. Lazy; catalog-first. */\nfunction catalogTargets(): Map<string, { keys: string[] }> {\n if (_catalogTargets !== undefined) return _catalogTargets;\n _catalogTargets = new Map();\n try {\n for (const entry of Object.values(loadProviderCatalog())) {\n const keys = [entry.id, ...(entry.aliases ?? [])];\n for (const k of keys) {\n if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });\n }\n }\n } catch {\n // catalog unavailable — registry fallback below still works\n }\n return _catalogTargets;\n}\n\nfunction resolvePatchKeys(externalId: string): string[] | undefined {\n const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;\n const fromCatalog = catalogTargets().get(mapped);\n if (fromCatalog !== undefined) return fromCatalog.keys;\n const profile = getProviderProfile(mapped);\n if (profile !== undefined) return [profile.name, ...(profile.aliases ?? [])];\n return undefined;\n}\n\n/** Parse + patch the index from an api.json payload. Unknown providers are skipped with WARN (once each). */\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: validates and merges an UNTRUSTED upstream payload (models.dev api.json) shape by shape, dropping a single bad model rather than the file. Each branch is a distinct malformed input; merging them loses which one was seen.\nfunction patchIndexFromApiJson(raw: unknown): number {\n if (typeof raw !== \"object\" || raw === null) return 0;\n let patched = 0;\n const skipped: string[] = [];\n for (const [providerId, provider] of Object.entries(raw as Record<string, unknown>)) {\n const models = (provider as { models?: Record<string, unknown> })?.models;\n if (models === undefined || typeof models !== \"object\") continue;\n // Enrich ONLY providers the SDK knows — models.dev's npm/api fields cannot be mapped to a theokit\n // apiMode/authType safely, so unknown providers are data we cannot route.\n const keys = resolvePatchKeys(providerId);\n if (keys === undefined) {\n skipped.push(providerId);\n continue;\n }\n for (const [modelId, rawModel] of Object.entries(models)) {\n const parsed = catalogModelSchema.safeParse(rawModel);\n if (!parsed.success) continue; // malformed model — drop silently (live data, additive drift expected)\n for (const key of keys) patchModelInfo(`${key}/${modelId}`, parsed.data);\n patched++;\n }\n }\n if (skipped.length > 0) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh skipped ${skipped.length} unknown provider(s) (e.g. ${skipped.slice(0, 3).join(\", \")})\\n`,\n );\n }\n return patched;\n}\n\n/**\n * Load an existing disk cache into the index (called by refresh when fresh, or opportunistically by a\n * consumer at startup — NEVER fetches). Corrupt cache → delete + fall through to vendored data.\n */\nexport function loadCacheIntoIndex(url: string = DEFAULT_URL): number {\n const path = cachePathFor(url);\n let body: string;\n try {\n body = readFileSync(path, \"utf-8\");\n } catch {\n return 0; // no cache — vendored data only\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n // corrupt cache: delete and fall through to the vendored catalog.\n // M44 L9 fix — only a PARSE failure is cache corruption; a patch error must never delete a valid cache.\n try {\n unlinkSync(path);\n } catch {\n // best effort\n }\n diag(`[theokit-sdk] WARN: corrupt models-dev cache deleted (${path})\\n`);\n return 0;\n }\n try {\n return patchIndexFromApiJson(parsed);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache patch failed (${(err as Error).message})\\n`);\n return 0;\n }\n}\n\n/**\n * The kill switch, read from the environment.\n *\n * Truthy-only by design (M44 L11): a presence check would treat `THEOKIT_DISABLE_MODELS_FETCH=0`\n * and `=false` as \"disabled\", which is the opposite of what anyone writing them means.\n */\nfunction fetchDisabledByEnv(): boolean {\n const kill = process.env.THEOKIT_DISABLE_MODELS_FETCH;\n return kill !== undefined && kill !== \"\" && kill !== \"0\" && kill.toLowerCase() !== \"false\";\n}\n\n/**\n * The TTL gate: a cache file younger than {@link TTL_MS} serves without touching the network.\n *\n * Returns `undefined` when there is no usable cache — including when `statSync` throws, which is\n * how \"no cache file\" arrives. That is the ONE failure this step owns, and its fallback is simply\n * to let the caller proceed to the fetch.\n */\nfunction servedFromFreshCache(\n url: string,\n path: string,\n now: () => number,\n): RefreshModelCatalogResult | undefined {\n try {\n if (now() - statSync(path).mtimeMs >= TTL_MS) return undefined;\n } catch {\n return undefined; // no cache — proceed to fetch\n }\n return { source: \"cache\", models: loadCacheIntoIndex(url) };\n}\n\n/**\n * Fetch the catalog, bound its size, and prove it parses before anyone persists it.\n *\n * Returns `undefined` after logging when ANY of that fails — timeout, non-2xx, oversize, unparseable\n * body. The fallback this step owns is \"serve what we already have\", and the caller applies it.\n * Splitting the step from its fallback was the objection recorded in the suppression this replaces;\n * the fallback is not separated, it is named — `undefined` means \"this step could not produce a\n * body\", and there is exactly one thing to do about that.\n */\nasync function fetchCatalogBody(url: string, fetchImpl: typeof fetch): Promise<string | undefined> {\n try {\n const res = await Retry.run(\n async () => {\n const r = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r;\n },\n // 2 transient retries with backoff; every error here is worth one more try —\n // the whole call is already fail-closed at the caller.\n { retries: 2, isRetryable: () => true, initialDelayMs: 200 },\n );\n const declaredLength = Number(res.headers.get(\"content-length\") ?? Number.NaN);\n if (Number.isFinite(declaredLength) && declaredLength > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${declaredLength} bytes declared`);\n }\n const body = await res.text();\n // Checked again after reading: `content-length` is the server's claim, and a server that\n // omits it or lies about it is exactly the one worth bounding. Both checks are cheap and\n // neither alone is sufficient.\n if (body.length > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${body.length} bytes received`);\n }\n JSON.parse(body); // validate before persisting — never cache garbage\n return body;\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return undefined;\n }\n}\n\n/**\n * Persist the fetched body and patch it into the index.\n *\n * Two independent failures with two different consequences, which is why they are two try blocks\n * and not one: a cache write that fails costs the NEXT process a fetch and nothing more, so the run\n * continues; a patch that fails means this body never reached the index, so the index is whatever it\n * was and the result says `cache`.\n */\nfunction persistAndPatch(path: string, body: string): RefreshModelCatalogResult {\n try {\n writeCacheAtomic(path, body);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache write failed (${(err as Error).message})\\n`);\n }\n try {\n return { source: \"network\", models: patchIndexFromApiJson(JSON.parse(body)) };\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev patch failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return { source: \"cache\", models: 0 };\n }\n}\n\n/**\n * Explicitly refresh the model catalog from models.dev (the ONLY network trigger in the subsystem).\n * Fail-closed: any failure keeps serving the current index (cache or vendored). Kill-switch:\n * `THEOKIT_DISABLE_MODELS_FETCH`.\n *\n * The sequence carried a cognitive-complexity suppression whose reason said splitting it would\n * \"separate a step from the fallback it owns\". The four helpers above each KEEP their fallback: the\n * TTL gate owns \"no cache\", the fetch owns every network and validation failure, the persist owns\n * the write and the patch. What is left here is the order they run in, which is what this function\n * was always for.\n *\n * Still true, and NOT fixed by the split: three of the paths return `{ source: \"cache\" }`, so a\n * caller cannot tell a timeout from an unparseable body from a patch failure. Distinguishing them\n * means adding a field to the PUBLIC `RefreshModelCatalogResult`, which is a release decision rather\n * than a refactor. The `diag` line already names the cause for an operator.\n */\nexport async function refreshModelCatalog(\n opts: RefreshModelCatalogOptions = {},\n): Promise<RefreshModelCatalogResult> {\n // M44 M4 fix — self-initialize provider registration so the `@theokit/sdk/models` subpath works\n // standalone (without the consumer having built an Agent first).\n registerBuiltins();\n if (fetchDisabledByEnv()) return { source: \"skipped\", models: 0 };\n\n const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;\n const path = cachePathFor(url);\n const now = opts.deps?.now ?? (() => Date.now());\n\n if (opts.force !== true) {\n const cached = servedFromFreshCache(url, path, now);\n if (cached !== undefined) return cached;\n }\n\n const body = await fetchCatalogBody(url, boundFetch(opts.deps?.fetch));\n // fail-closed: serve whatever we already have (stale cache if present, else vendored)\n if (body === undefined) return { source: \"cache\", models: loadCacheIntoIndex(url) };\n\n return persistAndPatch(path, body);\n}\n\n/** The enriched per-model view (public via `@theokit/sdk/models`): index lookup by (possibly prefixed) id. */\nexport function getModelInfo(modelId: string): ReturnType<typeof getCatalogModelInfo> {\n return getCatalogModelInfo(modelId);\n}\n"]}
|
package/dist/models.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Retry } from './chunk-2S4HQCDF.js';
|
|
2
|
-
|
|
2
|
+
import { trimTrailingSlashes } from './chunk-ICBNSAO4.js';
|
|
3
|
+
export { resolveModelCapabilities } from './chunk-4XYCF5PA.js';
|
|
3
4
|
import { parseModelId } from './chunk-R7WIIPUR.js';
|
|
4
5
|
export { parseModelId } from './chunk-R7WIIPUR.js';
|
|
5
|
-
import { registerBuiltins, getCatalogModelInfo, catalogModelSchema, patchModelInfo, getProviderProfile, loadProviderCatalog } from './chunk-
|
|
6
|
+
import { registerBuiltins, getCatalogModelInfo, catalogModelSchema, patchModelInfo, getProviderProfile, loadProviderCatalog } from './chunk-A3T2A2WU.js';
|
|
6
7
|
import './chunk-AGACYRJ2.js';
|
|
8
|
+
import './chunk-Z2UVCAYS.js';
|
|
7
9
|
import './chunk-UNP4NCMZ.js';
|
|
8
10
|
import './chunk-L2KC2G7H.js';
|
|
9
11
|
import './chunk-5IUDICRK.js';
|
|
@@ -40,12 +42,6 @@ function toModelOption(modelId) {
|
|
|
40
42
|
provider: parseModelId(modelId).provider
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
|
-
var SLASH_CODE = 47;
|
|
44
|
-
function trimTrailingSlashes(value) {
|
|
45
|
-
let end = value.length;
|
|
46
|
-
while (end > 0 && value.charCodeAt(end - 1) === SLASH_CODE) end--;
|
|
47
|
-
return end === value.length ? value : value.slice(0, end);
|
|
48
|
-
}
|
|
49
45
|
var DEFAULT_URL = "https://models.dev/api.json";
|
|
50
46
|
var MAX_CATALOG_BYTES = 32 * 1024 * 1024;
|
|
51
47
|
var TTL_MS = 60 * 60 * 1e3;
|
package/dist/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/llm/model-option.ts","../src/internal/providers/catalog-source-models-dev.ts"],"names":[],"mappings":"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","file":"models.js","sourcesContent":["import { parseModelId } from \"./model-identifier.js\";\n\n/**\n * A UI-friendly model option — the shape a `<select>`/dropdown consumes.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport interface ModelOption {\n /** The original model id (what you pass back to the SDK). */\n value: string;\n /** Best-effort human label (see {@link humanizeModelName}). */\n label: string;\n /** Provider from the slug prefix, or `undefined` when none. */\n provider: string | undefined;\n}\n\n/** Tokens rendered upper-case rather than title-case. */\nconst ACRONYMS = new Set([\"gpt\", \"ai\", \"hd\", \"ui\", \"api\", \"sdk\", \"llm\", \"xl\"]);\n\nfunction prettyToken(token: string): string {\n if (ACRONYMS.has(token.toLowerCase())) return token.toUpperCase();\n return token.charAt(0).toUpperCase() + token.slice(1);\n}\n\n/**\n * Turn a model id into a best-effort human label: strip the routing/vendor\n * prefix to the core model segment, split on `-`/`_`/`.`/whitespace, title-case\n * each token (known acronyms upper-cased), and append an OpenRouter `:variant`\n * in parentheses. Deterministic, pure, dependency-free.\n *\n * Best-effort, NOT vendor-canonical: `\"anthropic/claude-3-5-sonnet\"` →\n * `\"Claude 3 5 Sonnet\"`. A UI wanting exact marketing names overrides per id.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function humanizeModelName(modelId: string): string {\n const { name } = parseModelId(modelId);\n if (name.length === 0) return \"\";\n const colon = name.indexOf(\":\");\n // Strip a trailing slash so a typo'd `gpt-4o/` keeps its name (not lost to an\n // empty last segment).\n //\n // Done by index rather than with `/\\/+$/`, and the difference is not stylistic: that pattern\n // consumes slashes to the end of the string at every start position and then backtracks\n // looking for an end-anchor that is not there (CodeQL js/polynomial-redos #6). This function\n // is `@public` and takes a caller-supplied model id. Measured on a run of slashes followed by\n // one other character: 25_000 took 496 ms, 100_000 took 31_305 ms — half a minute of pinned\n // CPU to render a label. Walking back from the end is linear and cannot backtrack.\n const base = trimTrailingSlashes(colon >= 0 ? name.slice(0, colon) : name);\n const variant = colon >= 0 ? name.slice(colon + 1) : \"\";\n const lastSlash = base.lastIndexOf(\"/\");\n const core = lastSlash >= 0 ? base.slice(lastSlash + 1) : base;\n const label = core\n .split(/[-_.\\s]+/)\n .filter((t) => t.length > 0)\n .map(prettyToken)\n .join(\" \");\n if (label.length === 0) return variant; // no base label (e.g. \":free\") → bare variant\n return variant.length > 0 ? `${label} (${variant})` : label;\n}\n\n/**\n * Build a {@link ModelOption} (`{ value, label, provider }`) for a model id —\n * a dropdown-ready entry composing {@link humanizeModelName} + `parseModelId`.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function toModelOption(modelId: string): ModelOption {\n return {\n value: modelId,\n label: humanizeModelName(modelId),\n provider: parseModelId(modelId).provider,\n };\n}\n\nconst SLASH_CODE = 47; // \"/\"\n\n/** Removes trailing `/` characters in one linear pass. See the call site for why not a regex. */\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === SLASH_CODE) end--;\n return end === value.length ? value : value.slice(0, end);\n}\n","import { createHash, randomBytes } from \"node:crypto\";\nimport { mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { Retry } from \"../../retry.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { boundFetch } from \"../runtime-fetch.js\";\nimport { registerBuiltins } from \"./builtin/index.js\";\nimport { getCatalogModelInfo, loadProviderCatalog, patchModelInfo } from \"./catalog-loader.js\";\nimport { catalogModelSchema } from \"./catalog-schema.js\";\nimport { getProviderProfile } from \"./registry.js\";\n\n/**\n * M44 — the OPTIONAL models.dev catalog source. Explicit opt-in ONLY (`refreshModelCatalog()`): the SDK\n * NEVER fetches at startup or per-request — the vendored catalog + any existing disk cache are the offline\n * base, and every failure mode fails CLOSED back to them (ROADMAP constraint: no runtime hard network dep).\n *\n * The models.dev consumption mechanism:\n * disk cache with mtime TTL, atomic tempfile+rename write, corrupt-cache delete-and-fall-through, kill-switch\n * env. Library adaptations: NO background refresh loop (a consumer composes refresh with the SDK's cron);\n * TTL 1h (not 5min — no background refresher to keep it warm); no cross-process flock v1 (atomic rename +\n * idempotent upstream content — at most one wasted fetch).\n *\n * @internal (the public surface is `refreshModelCatalog` re-exported via `@theokit/sdk/models`)\n */\n\nconst DEFAULT_URL = \"https://models.dev/api.json\";\n\n/**\n * Ceiling on a fetched catalog, before it is parsed or written to the cache.\n *\n * The response body was read with `res.text()` and persisted with no bound, so a host serving a\n * multi-gigabyte document would have been materialised in memory and then written to disk. The\n * default URL is trusted, but `THEOKIT_MODELS_URL` lets an operator point this anywhere, and a\n * limit is the difference between \"we only fetch from a host we trust\" and \"we cannot be hurt by\n * one we do not\".\n *\n * 32 MiB is roughly 40x the real catalog (~800 KiB in 2026-08), so it bounds the failure without\n * being a number anyone has to tune when models.dev grows.\n */\nconst MAX_CATALOG_BYTES = 32 * 1024 * 1024;\nconst TTL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000;\n\n/**\n * Arguments to `refreshModelCatalog`, the SDK's only network trigger for model metadata.\n *\n * `url` wins over the `THEOKIT_MODELS_URL` environment variable, which in turn wins over\n * `https://models.dev/api.json`. A non-default URL gets its own cache file, named by a hash of\n * the URL, so switching sources never reads another source's cache.\n *\n * `force` skips only the freshness check — it does not skip the kill switch. When\n * `THEOKIT_DISABLE_MODELS_FETCH` is set to anything other than an empty string, `\"0\"` or\n * `\"false\"`, the call returns `source: \"skipped\"` with no fetch and no cache read, whatever\n * `force` says.\n *\n * Without `force`, a cache file whose mtime is under an hour old is served directly and no\n * request is made.\n *\n * `deps` exists so tests can drive the fetch and the clock; production leaves it unset.\n */\nexport interface RefreshModelCatalogOptions {\n /** Override the source URL (`THEOKIT_MODELS_URL` env also honored). */\n url?: string;\n /** Bypass the TTL freshness gate. */\n force?: boolean;\n /** Injected for tests. */\n deps?: { fetch?: typeof fetch; now?: () => number };\n}\n\n/**\n * What `refreshModelCatalog` did. It never throws on a failed refresh, so this is the only place\n * the outcome is reported.\n *\n * `source` is `\"network\"` only when a request succeeded, its body parsed as JSON, and the models\n * were patched in. Every failure path — kill switch aside — returns `\"cache\"`: an HTTP error\n * after retries, a timeout, an unparseable body, or a patch that threw. `\"cache\"` therefore means\n * \"serving what was already there\", which may be a fresh cache, a stale one, or nothing but the\n * vendored catalog. Read `models` to tell those apart. `\"skipped\"` means the kill switch was set.\n *\n * `models` counts the models patched into the index during this call, not the catalog's size. It\n * counts each model once even when the provider has aliases and the model is written under several\n * index keys, and it excludes models whose payload failed schema validation and models under\n * providers the SDK does not know. It is 0 whenever there was no cache to fall back on, and 0 for\n * `\"skipped\"`.\n *\n * A cache write that fails is logged and otherwise ignored: the result can still say `\"network\"`\n * with the data live in memory and nothing on disk.\n */\nexport interface RefreshModelCatalogResult {\n /** Where the data came from: a fresh network fetch, the still-fresh disk cache, or skipped entirely. */\n source: \"network\" | \"cache\" | \"skipped\";\n /** How many models were patched into the index. */\n models: number;\n}\n\n/** The cache file for a source URL (custom URLs get a hash-suffixed name). */\nexport function cachePathFor(url: string): string {\n // M44 L8 fix — honor the SDK home override so tests and multi-home setups never touch the real ~/.theokit.\n const base = process.env.THEOKIT_HOME?.trim() || join(homedir(), \".theokit\");\n const dir = join(base, \"cache\", \"models-dev\");\n if (url === DEFAULT_URL) return join(dir, \"api.json\");\n const hash = createHash(\"sha256\").update(url).digest(\"hex\").slice(0, 12);\n return join(dir, `api-${hash}.json`);\n}\n\n/** Atomic write: temp file + rename (crash mid-write never leaves a partial cache). */\nfunction writeCacheAtomic(path: string, body: string): void {\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${randomBytes(6).toString(\"hex\")}`;\n try {\n writeFileSync(tmp, body);\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // best effort\n }\n throw err;\n }\n}\n\n/**\n * M44 H3 fix — models.dev provider ids ≠ theokit ids (google↔google-gemini, zai↔zhipu, togetherai↔together,\n * fireworks-ai↔fireworks, amazon-bedrock↔bedrock, google-vertex↔vertex). The RUNTIME mapping mirrors the\n * maintenance script's table; targets resolve against the CATALOG entries (id + aliases — the same namespace\n * the vendored index uses) first, then the registry.\n */\nconst MODELS_DEV_ID_MAP: Record<string, string> = {\n google: \"google-gemini\",\n zai: \"zhipu\",\n togetherai: \"together\",\n \"fireworks-ai\": \"fireworks\",\n \"amazon-bedrock\": \"bedrock\",\n \"google-vertex\": \"vertex\",\n};\n\nlet _catalogTargets: Map<string, { keys: string[] }> | undefined;\n/** external-id → the index keys (entry id + aliases) its models patch under. Lazy; catalog-first. */\nfunction catalogTargets(): Map<string, { keys: string[] }> {\n if (_catalogTargets !== undefined) return _catalogTargets;\n _catalogTargets = new Map();\n try {\n for (const entry of Object.values(loadProviderCatalog())) {\n const keys = [entry.id, ...(entry.aliases ?? [])];\n for (const k of keys) {\n if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });\n }\n }\n } catch {\n // catalog unavailable — registry fallback below still works\n }\n return _catalogTargets;\n}\n\nfunction resolvePatchKeys(externalId: string): string[] | undefined {\n const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;\n const fromCatalog = catalogTargets().get(mapped);\n if (fromCatalog !== undefined) return fromCatalog.keys;\n const profile = getProviderProfile(mapped);\n if (profile !== undefined) return [profile.name, ...(profile.aliases ?? [])];\n return undefined;\n}\n\n/** Parse + patch the index from an api.json payload. Unknown providers are skipped with WARN (once each). */\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: validates and merges an UNTRUSTED upstream payload (models.dev api.json) shape by shape, dropping a single bad model rather than the file. Each branch is a distinct malformed input; merging them loses which one was seen.\nfunction patchIndexFromApiJson(raw: unknown): number {\n if (typeof raw !== \"object\" || raw === null) return 0;\n let patched = 0;\n const skipped: string[] = [];\n for (const [providerId, provider] of Object.entries(raw as Record<string, unknown>)) {\n const models = (provider as { models?: Record<string, unknown> })?.models;\n if (models === undefined || typeof models !== \"object\") continue;\n // Enrich ONLY providers the SDK knows — models.dev's npm/api fields cannot be mapped to a theokit\n // apiMode/authType safely, so unknown providers are data we cannot route.\n const keys = resolvePatchKeys(providerId);\n if (keys === undefined) {\n skipped.push(providerId);\n continue;\n }\n for (const [modelId, rawModel] of Object.entries(models)) {\n const parsed = catalogModelSchema.safeParse(rawModel);\n if (!parsed.success) continue; // malformed model — drop silently (live data, additive drift expected)\n for (const key of keys) patchModelInfo(`${key}/${modelId}`, parsed.data);\n patched++;\n }\n }\n if (skipped.length > 0) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh skipped ${skipped.length} unknown provider(s) (e.g. ${skipped.slice(0, 3).join(\", \")})\\n`,\n );\n }\n return patched;\n}\n\n/**\n * Load an existing disk cache into the index (called by refresh when fresh, or opportunistically by a\n * consumer at startup — NEVER fetches). Corrupt cache → delete + fall through to vendored data.\n */\nexport function loadCacheIntoIndex(url: string = DEFAULT_URL): number {\n const path = cachePathFor(url);\n let body: string;\n try {\n body = readFileSync(path, \"utf-8\");\n } catch {\n return 0; // no cache — vendored data only\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n // corrupt cache: delete and fall through to the vendored catalog.\n // M44 L9 fix — only a PARSE failure is cache corruption; a patch error must never delete a valid cache.\n try {\n unlinkSync(path);\n } catch {\n // best effort\n }\n diag(`[theokit-sdk] WARN: corrupt models-dev cache deleted (${path})\\n`);\n return 0;\n }\n try {\n return patchIndexFromApiJson(parsed);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache patch failed (${(err as Error).message})\\n`);\n return 0;\n }\n}\n\n/**\n * The kill switch, read from the environment.\n *\n * Truthy-only by design (M44 L11): a presence check would treat `THEOKIT_DISABLE_MODELS_FETCH=0`\n * and `=false` as \"disabled\", which is the opposite of what anyone writing them means.\n */\nfunction fetchDisabledByEnv(): boolean {\n const kill = process.env.THEOKIT_DISABLE_MODELS_FETCH;\n return kill !== undefined && kill !== \"\" && kill !== \"0\" && kill.toLowerCase() !== \"false\";\n}\n\n/**\n * The TTL gate: a cache file younger than {@link TTL_MS} serves without touching the network.\n *\n * Returns `undefined` when there is no usable cache — including when `statSync` throws, which is\n * how \"no cache file\" arrives. That is the ONE failure this step owns, and its fallback is simply\n * to let the caller proceed to the fetch.\n */\nfunction servedFromFreshCache(\n url: string,\n path: string,\n now: () => number,\n): RefreshModelCatalogResult | undefined {\n try {\n if (now() - statSync(path).mtimeMs >= TTL_MS) return undefined;\n } catch {\n return undefined; // no cache — proceed to fetch\n }\n return { source: \"cache\", models: loadCacheIntoIndex(url) };\n}\n\n/**\n * Fetch the catalog, bound its size, and prove it parses before anyone persists it.\n *\n * Returns `undefined` after logging when ANY of that fails — timeout, non-2xx, oversize, unparseable\n * body. The fallback this step owns is \"serve what we already have\", and the caller applies it.\n * Splitting the step from its fallback was the objection recorded in the suppression this replaces;\n * the fallback is not separated, it is named — `undefined` means \"this step could not produce a\n * body\", and there is exactly one thing to do about that.\n */\nasync function fetchCatalogBody(url: string, fetchImpl: typeof fetch): Promise<string | undefined> {\n try {\n const res = await Retry.run(\n async () => {\n const r = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r;\n },\n // 2 transient retries with backoff; every error here is worth one more try —\n // the whole call is already fail-closed at the caller.\n { retries: 2, isRetryable: () => true, initialDelayMs: 200 },\n );\n const declaredLength = Number(res.headers.get(\"content-length\") ?? Number.NaN);\n if (Number.isFinite(declaredLength) && declaredLength > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${declaredLength} bytes declared`);\n }\n const body = await res.text();\n // Checked again after reading: `content-length` is the server's claim, and a server that\n // omits it or lies about it is exactly the one worth bounding. Both checks are cheap and\n // neither alone is sufficient.\n if (body.length > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${body.length} bytes received`);\n }\n JSON.parse(body); // validate before persisting — never cache garbage\n return body;\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return undefined;\n }\n}\n\n/**\n * Persist the fetched body and patch it into the index.\n *\n * Two independent failures with two different consequences, which is why they are two try blocks\n * and not one: a cache write that fails costs the NEXT process a fetch and nothing more, so the run\n * continues; a patch that fails means this body never reached the index, so the index is whatever it\n * was and the result says `cache`.\n */\nfunction persistAndPatch(path: string, body: string): RefreshModelCatalogResult {\n try {\n writeCacheAtomic(path, body);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache write failed (${(err as Error).message})\\n`);\n }\n try {\n return { source: \"network\", models: patchIndexFromApiJson(JSON.parse(body)) };\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev patch failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return { source: \"cache\", models: 0 };\n }\n}\n\n/**\n * Explicitly refresh the model catalog from models.dev (the ONLY network trigger in the subsystem).\n * Fail-closed: any failure keeps serving the current index (cache or vendored). Kill-switch:\n * `THEOKIT_DISABLE_MODELS_FETCH`.\n *\n * The sequence carried a cognitive-complexity suppression whose reason said splitting it would\n * \"separate a step from the fallback it owns\". The four helpers above each KEEP their fallback: the\n * TTL gate owns \"no cache\", the fetch owns every network and validation failure, the persist owns\n * the write and the patch. What is left here is the order they run in, which is what this function\n * was always for.\n *\n * Still true, and NOT fixed by the split: three of the paths return `{ source: \"cache\" }`, so a\n * caller cannot tell a timeout from an unparseable body from a patch failure. Distinguishing them\n * means adding a field to the PUBLIC `RefreshModelCatalogResult`, which is a release decision rather\n * than a refactor. The `diag` line already names the cause for an operator.\n */\nexport async function refreshModelCatalog(\n opts: RefreshModelCatalogOptions = {},\n): Promise<RefreshModelCatalogResult> {\n // M44 M4 fix — self-initialize provider registration so the `@theokit/sdk/models` subpath works\n // standalone (without the consumer having built an Agent first).\n registerBuiltins();\n if (fetchDisabledByEnv()) return { source: \"skipped\", models: 0 };\n\n const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;\n const path = cachePathFor(url);\n const now = opts.deps?.now ?? (() => Date.now());\n\n if (opts.force !== true) {\n const cached = servedFromFreshCache(url, path, now);\n if (cached !== undefined) return cached;\n }\n\n const body = await fetchCatalogBody(url, boundFetch(opts.deps?.fetch));\n // fail-closed: serve whatever we already have (stale cache if present, else vendored)\n if (body === undefined) return { source: \"cache\", models: loadCacheIntoIndex(url) };\n\n return persistAndPatch(path, body);\n}\n\n/** The enriched per-model view (public via `@theokit/sdk/models`): index lookup by (possibly prefixed) id. */\nexport function getModelInfo(modelId: string): ReturnType<typeof getCatalogModelInfo> {\n return getCatalogModelInfo(modelId);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/internal/llm/model-option.ts","../src/internal/providers/catalog-source-models-dev.ts"],"names":[],"mappings":"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","file":"models.js","sourcesContent":["import { trimTrailingSlashes } from \"../trim-trailing-slashes.js\";\nimport { parseModelId } from \"./model-identifier.js\";\n\n/**\n * A UI-friendly model option — the shape a `<select>`/dropdown consumes.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport interface ModelOption {\n /** The original model id (what you pass back to the SDK). */\n value: string;\n /** Best-effort human label (see {@link humanizeModelName}). */\n label: string;\n /** Provider from the slug prefix, or `undefined` when none. */\n provider: string | undefined;\n}\n\n/** Tokens rendered upper-case rather than title-case. */\nconst ACRONYMS = new Set([\"gpt\", \"ai\", \"hd\", \"ui\", \"api\", \"sdk\", \"llm\", \"xl\"]);\n\nfunction prettyToken(token: string): string {\n if (ACRONYMS.has(token.toLowerCase())) return token.toUpperCase();\n return token.charAt(0).toUpperCase() + token.slice(1);\n}\n\n/**\n * Turn a model id into a best-effort human label: strip the routing/vendor\n * prefix to the core model segment, split on `-`/`_`/`.`/whitespace, title-case\n * each token (known acronyms upper-cased), and append an OpenRouter `:variant`\n * in parentheses. Deterministic, pure, dependency-free.\n *\n * Best-effort, NOT vendor-canonical: `\"anthropic/claude-3-5-sonnet\"` →\n * `\"Claude 3 5 Sonnet\"`. A UI wanting exact marketing names overrides per id.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function humanizeModelName(modelId: string): string {\n const { name } = parseModelId(modelId);\n if (name.length === 0) return \"\";\n const colon = name.indexOf(\":\");\n // Strip a trailing slash so a typo'd `gpt-4o/` keeps its name (not lost to an\n // empty last segment).\n //\n // Done by index rather than with `/\\/+$/`, and the difference is not stylistic: that pattern\n // consumes slashes to the end of the string at every start position and then backtracks\n // looking for an end-anchor that is not there (CodeQL js/polynomial-redos #6). This function\n // is `@public` and takes a caller-supplied model id. Measured on a run of slashes followed by\n // one other character: 25_000 took 496 ms, 100_000 took 31_305 ms — half a minute of pinned\n // CPU to render a label. Walking back from the end is linear and cannot backtrack.\n const base = trimTrailingSlashes(colon >= 0 ? name.slice(0, colon) : name);\n const variant = colon >= 0 ? name.slice(colon + 1) : \"\";\n const lastSlash = base.lastIndexOf(\"/\");\n const core = lastSlash >= 0 ? base.slice(lastSlash + 1) : base;\n const label = core\n .split(/[-_.\\s]+/)\n .filter((t) => t.length > 0)\n .map(prettyToken)\n .join(\" \");\n if (label.length === 0) return variant; // no base label (e.g. \":free\") → bare variant\n return variant.length > 0 ? `${label} (${variant})` : label;\n}\n\n/**\n * Build a {@link ModelOption} (`{ value, label, provider }`) for a model id —\n * a dropdown-ready entry composing {@link humanizeModelName} + `parseModelId`.\n *\n * Public via `@theokit/sdk/models`.\n *\n * @public\n */\nexport function toModelOption(modelId: string): ModelOption {\n return {\n value: modelId,\n label: humanizeModelName(modelId),\n provider: parseModelId(modelId).provider,\n };\n}\n","import { createHash, randomBytes } from \"node:crypto\";\nimport { mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { Retry } from \"../../retry.js\";\nimport { diag } from \"../diagnostics.js\";\nimport { boundFetch } from \"../runtime-fetch.js\";\nimport { registerBuiltins } from \"./builtin/index.js\";\nimport { getCatalogModelInfo, loadProviderCatalog, patchModelInfo } from \"./catalog-loader.js\";\nimport { catalogModelSchema } from \"./catalog-schema.js\";\nimport { getProviderProfile } from \"./registry.js\";\n\n/**\n * M44 — the OPTIONAL models.dev catalog source. Explicit opt-in ONLY (`refreshModelCatalog()`): the SDK\n * NEVER fetches at startup or per-request — the vendored catalog + any existing disk cache are the offline\n * base, and every failure mode fails CLOSED back to them (ROADMAP constraint: no runtime hard network dep).\n *\n * The models.dev consumption mechanism:\n * disk cache with mtime TTL, atomic tempfile+rename write, corrupt-cache delete-and-fall-through, kill-switch\n * env. Library adaptations: NO background refresh loop (a consumer composes refresh with the SDK's cron);\n * TTL 1h (not 5min — no background refresher to keep it warm); no cross-process flock v1 (atomic rename +\n * idempotent upstream content — at most one wasted fetch).\n *\n * @internal (the public surface is `refreshModelCatalog` re-exported via `@theokit/sdk/models`)\n */\n\nconst DEFAULT_URL = \"https://models.dev/api.json\";\n\n/**\n * Ceiling on a fetched catalog, before it is parsed or written to the cache.\n *\n * The response body was read with `res.text()` and persisted with no bound, so a host serving a\n * multi-gigabyte document would have been materialised in memory and then written to disk. The\n * default URL is trusted, but `THEOKIT_MODELS_URL` lets an operator point this anywhere, and a\n * limit is the difference between \"we only fetch from a host we trust\" and \"we cannot be hurt by\n * one we do not\".\n *\n * 32 MiB is roughly 40x the real catalog (~800 KiB in 2026-08), so it bounds the failure without\n * being a number anyone has to tune when models.dev grows.\n */\nconst MAX_CATALOG_BYTES = 32 * 1024 * 1024;\nconst TTL_MS = 60 * 60 * 1000; // 1 hour\nconst FETCH_TIMEOUT_MS = 10_000;\n\n/**\n * Arguments to `refreshModelCatalog`, the SDK's only network trigger for model metadata.\n *\n * `url` wins over the `THEOKIT_MODELS_URL` environment variable, which in turn wins over\n * `https://models.dev/api.json`. A non-default URL gets its own cache file, named by a hash of\n * the URL, so switching sources never reads another source's cache.\n *\n * `force` skips only the freshness check — it does not skip the kill switch. When\n * `THEOKIT_DISABLE_MODELS_FETCH` is set to anything other than an empty string, `\"0\"` or\n * `\"false\"`, the call returns `source: \"skipped\"` with no fetch and no cache read, whatever\n * `force` says.\n *\n * Without `force`, a cache file whose mtime is under an hour old is served directly and no\n * request is made.\n *\n * `deps` exists so tests can drive the fetch and the clock; production leaves it unset.\n */\nexport interface RefreshModelCatalogOptions {\n /** Override the source URL (`THEOKIT_MODELS_URL` env also honored). */\n url?: string;\n /** Bypass the TTL freshness gate. */\n force?: boolean;\n /** Injected for tests. */\n deps?: { fetch?: typeof fetch; now?: () => number };\n}\n\n/**\n * What `refreshModelCatalog` did. It never throws on a failed refresh, so this is the only place\n * the outcome is reported.\n *\n * `source` is `\"network\"` only when a request succeeded, its body parsed as JSON, and the models\n * were patched in. Every failure path — kill switch aside — returns `\"cache\"`: an HTTP error\n * after retries, a timeout, an unparseable body, or a patch that threw. `\"cache\"` therefore means\n * \"serving what was already there\", which may be a fresh cache, a stale one, or nothing but the\n * vendored catalog. Read `models` to tell those apart. `\"skipped\"` means the kill switch was set.\n *\n * `models` counts the models patched into the index during this call, not the catalog's size. It\n * counts each model once even when the provider has aliases and the model is written under several\n * index keys, and it excludes models whose payload failed schema validation and models under\n * providers the SDK does not know. It is 0 whenever there was no cache to fall back on, and 0 for\n * `\"skipped\"`.\n *\n * A cache write that fails is logged and otherwise ignored: the result can still say `\"network\"`\n * with the data live in memory and nothing on disk.\n */\nexport interface RefreshModelCatalogResult {\n /** Where the data came from: a fresh network fetch, the still-fresh disk cache, or skipped entirely. */\n source: \"network\" | \"cache\" | \"skipped\";\n /** How many models were patched into the index. */\n models: number;\n}\n\n/** The cache file for a source URL (custom URLs get a hash-suffixed name). */\nexport function cachePathFor(url: string): string {\n // M44 L8 fix — honor the SDK home override so tests and multi-home setups never touch the real ~/.theokit.\n const base = process.env.THEOKIT_HOME?.trim() || join(homedir(), \".theokit\");\n const dir = join(base, \"cache\", \"models-dev\");\n if (url === DEFAULT_URL) return join(dir, \"api.json\");\n const hash = createHash(\"sha256\").update(url).digest(\"hex\").slice(0, 12);\n return join(dir, `api-${hash}.json`);\n}\n\n/** Atomic write: temp file + rename (crash mid-write never leaves a partial cache). */\nfunction writeCacheAtomic(path: string, body: string): void {\n mkdirSync(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${randomBytes(6).toString(\"hex\")}`;\n try {\n writeFileSync(tmp, body);\n renameSync(tmp, path);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // best effort\n }\n throw err;\n }\n}\n\n/**\n * M44 H3 fix — models.dev provider ids ≠ theokit ids (google↔google-gemini, zai↔zhipu, togetherai↔together,\n * fireworks-ai↔fireworks, amazon-bedrock↔bedrock, google-vertex↔vertex). The RUNTIME mapping mirrors the\n * maintenance script's table; targets resolve against the CATALOG entries (id + aliases — the same namespace\n * the vendored index uses) first, then the registry.\n */\nconst MODELS_DEV_ID_MAP: Record<string, string> = {\n google: \"google-gemini\",\n zai: \"zhipu\",\n togetherai: \"together\",\n \"fireworks-ai\": \"fireworks\",\n \"amazon-bedrock\": \"bedrock\",\n \"google-vertex\": \"vertex\",\n};\n\nlet _catalogTargets: Map<string, { keys: string[] }> | undefined;\n/** external-id → the index keys (entry id + aliases) its models patch under. Lazy; catalog-first. */\nfunction catalogTargets(): Map<string, { keys: string[] }> {\n if (_catalogTargets !== undefined) return _catalogTargets;\n _catalogTargets = new Map();\n try {\n for (const entry of Object.values(loadProviderCatalog())) {\n const keys = [entry.id, ...(entry.aliases ?? [])];\n for (const k of keys) {\n if (!_catalogTargets.has(k)) _catalogTargets.set(k, { keys });\n }\n }\n } catch {\n // catalog unavailable — registry fallback below still works\n }\n return _catalogTargets;\n}\n\nfunction resolvePatchKeys(externalId: string): string[] | undefined {\n const mapped = MODELS_DEV_ID_MAP[externalId] ?? externalId;\n const fromCatalog = catalogTargets().get(mapped);\n if (fromCatalog !== undefined) return fromCatalog.keys;\n const profile = getProviderProfile(mapped);\n if (profile !== undefined) return [profile.name, ...(profile.aliases ?? [])];\n return undefined;\n}\n\n/** Parse + patch the index from an api.json payload. Unknown providers are skipped with WARN (once each). */\n// PRE-EXISTING debt, exposed when M75 fixed the Biome config that used to abort before\n// sweeping these files (a nested root under refactor/). It is not new code and was not touched\n// by M75; refactoring SDK internals without review would trade a visible problem for a diff\n// risky. Tracked in usetheodev/theokit-sdk#151.\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: validates and merges an UNTRUSTED upstream payload (models.dev api.json) shape by shape, dropping a single bad model rather than the file. Each branch is a distinct malformed input; merging them loses which one was seen.\nfunction patchIndexFromApiJson(raw: unknown): number {\n if (typeof raw !== \"object\" || raw === null) return 0;\n let patched = 0;\n const skipped: string[] = [];\n for (const [providerId, provider] of Object.entries(raw as Record<string, unknown>)) {\n const models = (provider as { models?: Record<string, unknown> })?.models;\n if (models === undefined || typeof models !== \"object\") continue;\n // Enrich ONLY providers the SDK knows — models.dev's npm/api fields cannot be mapped to a theokit\n // apiMode/authType safely, so unknown providers are data we cannot route.\n const keys = resolvePatchKeys(providerId);\n if (keys === undefined) {\n skipped.push(providerId);\n continue;\n }\n for (const [modelId, rawModel] of Object.entries(models)) {\n const parsed = catalogModelSchema.safeParse(rawModel);\n if (!parsed.success) continue; // malformed model — drop silently (live data, additive drift expected)\n for (const key of keys) patchModelInfo(`${key}/${modelId}`, parsed.data);\n patched++;\n }\n }\n if (skipped.length > 0) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh skipped ${skipped.length} unknown provider(s) (e.g. ${skipped.slice(0, 3).join(\", \")})\\n`,\n );\n }\n return patched;\n}\n\n/**\n * Load an existing disk cache into the index (called by refresh when fresh, or opportunistically by a\n * consumer at startup — NEVER fetches). Corrupt cache → delete + fall through to vendored data.\n */\nexport function loadCacheIntoIndex(url: string = DEFAULT_URL): number {\n const path = cachePathFor(url);\n let body: string;\n try {\n body = readFileSync(path, \"utf-8\");\n } catch {\n return 0; // no cache — vendored data only\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(body);\n } catch {\n // corrupt cache: delete and fall through to the vendored catalog.\n // M44 L9 fix — only a PARSE failure is cache corruption; a patch error must never delete a valid cache.\n try {\n unlinkSync(path);\n } catch {\n // best effort\n }\n diag(`[theokit-sdk] WARN: corrupt models-dev cache deleted (${path})\\n`);\n return 0;\n }\n try {\n return patchIndexFromApiJson(parsed);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache patch failed (${(err as Error).message})\\n`);\n return 0;\n }\n}\n\n/**\n * The kill switch, read from the environment.\n *\n * Truthy-only by design (M44 L11): a presence check would treat `THEOKIT_DISABLE_MODELS_FETCH=0`\n * and `=false` as \"disabled\", which is the opposite of what anyone writing them means.\n */\nfunction fetchDisabledByEnv(): boolean {\n const kill = process.env.THEOKIT_DISABLE_MODELS_FETCH;\n return kill !== undefined && kill !== \"\" && kill !== \"0\" && kill.toLowerCase() !== \"false\";\n}\n\n/**\n * The TTL gate: a cache file younger than {@link TTL_MS} serves without touching the network.\n *\n * Returns `undefined` when there is no usable cache — including when `statSync` throws, which is\n * how \"no cache file\" arrives. That is the ONE failure this step owns, and its fallback is simply\n * to let the caller proceed to the fetch.\n */\nfunction servedFromFreshCache(\n url: string,\n path: string,\n now: () => number,\n): RefreshModelCatalogResult | undefined {\n try {\n if (now() - statSync(path).mtimeMs >= TTL_MS) return undefined;\n } catch {\n return undefined; // no cache — proceed to fetch\n }\n return { source: \"cache\", models: loadCacheIntoIndex(url) };\n}\n\n/**\n * Fetch the catalog, bound its size, and prove it parses before anyone persists it.\n *\n * Returns `undefined` after logging when ANY of that fails — timeout, non-2xx, oversize, unparseable\n * body. The fallback this step owns is \"serve what we already have\", and the caller applies it.\n * Splitting the step from its fallback was the objection recorded in the suppression this replaces;\n * the fallback is not separated, it is named — `undefined` means \"this step could not produce a\n * body\", and there is exactly one thing to do about that.\n */\nasync function fetchCatalogBody(url: string, fetchImpl: typeof fetch): Promise<string | undefined> {\n try {\n const res = await Retry.run(\n async () => {\n const r = await fetchImpl(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n if (!r.ok) throw new Error(`HTTP ${r.status}`);\n return r;\n },\n // 2 transient retries with backoff; every error here is worth one more try —\n // the whole call is already fail-closed at the caller.\n { retries: 2, isRetryable: () => true, initialDelayMs: 200 },\n );\n const declaredLength = Number(res.headers.get(\"content-length\") ?? Number.NaN);\n if (Number.isFinite(declaredLength) && declaredLength > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${declaredLength} bytes declared`);\n }\n const body = await res.text();\n // Checked again after reading: `content-length` is the server's claim, and a server that\n // omits it or lies about it is exactly the one worth bounding. Both checks are cheap and\n // neither alone is sufficient.\n if (body.length > MAX_CATALOG_BYTES) {\n throw new Error(`catalog too large: ${body.length} bytes received`);\n }\n JSON.parse(body); // validate before persisting — never cache garbage\n return body;\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev refresh failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return undefined;\n }\n}\n\n/**\n * Persist the fetched body and patch it into the index.\n *\n * Two independent failures with two different consequences, which is why they are two try blocks\n * and not one: a cache write that fails costs the NEXT process a fetch and nothing more, so the run\n * continues; a patch that fails means this body never reached the index, so the index is whatever it\n * was and the result says `cache`.\n */\nfunction persistAndPatch(path: string, body: string): RefreshModelCatalogResult {\n try {\n writeCacheAtomic(path, body);\n } catch (err) {\n diag(`[theokit-sdk] WARN: models-dev cache write failed (${(err as Error).message})\\n`);\n }\n try {\n return { source: \"network\", models: patchIndexFromApiJson(JSON.parse(body)) };\n } catch (err) {\n diag(\n `[theokit-sdk] WARN: models-dev patch failed (${(err as Error).message}) — serving existing data\\n`,\n );\n return { source: \"cache\", models: 0 };\n }\n}\n\n/**\n * Explicitly refresh the model catalog from models.dev (the ONLY network trigger in the subsystem).\n * Fail-closed: any failure keeps serving the current index (cache or vendored). Kill-switch:\n * `THEOKIT_DISABLE_MODELS_FETCH`.\n *\n * The sequence carried a cognitive-complexity suppression whose reason said splitting it would\n * \"separate a step from the fallback it owns\". The four helpers above each KEEP their fallback: the\n * TTL gate owns \"no cache\", the fetch owns every network and validation failure, the persist owns\n * the write and the patch. What is left here is the order they run in, which is what this function\n * was always for.\n *\n * Still true, and NOT fixed by the split: three of the paths return `{ source: \"cache\" }`, so a\n * caller cannot tell a timeout from an unparseable body from a patch failure. Distinguishing them\n * means adding a field to the PUBLIC `RefreshModelCatalogResult`, which is a release decision rather\n * than a refactor. The `diag` line already names the cause for an operator.\n */\nexport async function refreshModelCatalog(\n opts: RefreshModelCatalogOptions = {},\n): Promise<RefreshModelCatalogResult> {\n // M44 M4 fix — self-initialize provider registration so the `@theokit/sdk/models` subpath works\n // standalone (without the consumer having built an Agent first).\n registerBuiltins();\n if (fetchDisabledByEnv()) return { source: \"skipped\", models: 0 };\n\n const url = opts.url ?? process.env.THEOKIT_MODELS_URL ?? DEFAULT_URL;\n const path = cachePathFor(url);\n const now = opts.deps?.now ?? (() => Date.now());\n\n if (opts.force !== true) {\n const cached = servedFromFreshCache(url, path, now);\n if (cached !== undefined) return cached;\n }\n\n const body = await fetchCatalogBody(url, boundFetch(opts.deps?.fetch));\n // fail-closed: serve whatever we already have (stale cache if present, else vendored)\n if (body === undefined) return { source: \"cache\", models: loadCacheIntoIndex(url) };\n\n return persistAndPatch(path, body);\n}\n\n/** The enriched per-model view (public via `@theokit/sdk/models`): index lookup by (possibly prefixed) id. */\nexport function getModelInfo(modelId: string): ReturnType<typeof getCatalogModelInfo> {\n return getCatalogModelInfo(modelId);\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkGA4ZRKYF_cjs = require('./chunk-GA4ZRKYF.cjs');
|
|
4
|
+
require('./chunk-UMCCYXFZ.cjs');
|
|
5
|
+
require('./chunk-PXYINWBC.cjs');
|
|
6
|
+
require('./chunk-IOFMRS6T.cjs');
|
|
7
|
+
require('./chunk-EHD25JBZ.cjs');
|
|
8
|
+
require('./chunk-CEGU5AVD.cjs');
|
|
9
|
+
require('./chunk-RNXXYF22.cjs');
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, "OPENAI_CHATGPT", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function () { return chunkGA4ZRKYF_cjs.OPENAI_CHATGPT; }
|
|
16
|
+
});
|
|
17
|
+
Object.defineProperty(exports, "codexFetch", {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return chunkGA4ZRKYF_cjs.codexFetch; }
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=openai-chatgpt-IVAL4MW6.cjs.map
|
|
22
|
+
//# sourceMappingURL=openai-chatgpt-IVAL4MW6.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"openai-chatgpt-IVAL4MW6.cjs"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { OPENAI_CHATGPT, codexFetch } from './chunk-Z2UVCAYS.js';
|
|
2
|
+
import './chunk-UNP4NCMZ.js';
|
|
3
|
+
import './chunk-L2KC2G7H.js';
|
|
4
|
+
import './chunk-5IUDICRK.js';
|
|
5
|
+
import './chunk-Q7GYMXVC.js';
|
|
6
|
+
import './chunk-TNFOU6SB.js';
|
|
7
|
+
import './chunk-3OY6H3I7.js';
|
|
8
|
+
//# sourceMappingURL=openai-chatgpt-ZFNZWT2L.js.map
|
|
9
|
+
//# sourceMappingURL=openai-chatgpt-ZFNZWT2L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"openai-chatgpt-ZFNZWT2L.js"}
|
package/dist/providers.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
3
|
+
var chunkSGKMTBCO_cjs = require('./chunk-SGKMTBCO.cjs');
|
|
4
|
+
require('./chunk-WVQRE7CO.cjs');
|
|
5
5
|
require('./chunk-NVXXWAU7.cjs');
|
|
6
|
+
require('./chunk-GA4ZRKYF.cjs');
|
|
6
7
|
require('./chunk-UMCCYXFZ.cjs');
|
|
7
8
|
require('./chunk-PXYINWBC.cjs');
|
|
8
9
|
require('./chunk-IOFMRS6T.cjs');
|
|
@@ -14,11 +15,11 @@ require('./chunk-RNXXYF22.cjs');
|
|
|
14
15
|
|
|
15
16
|
Object.defineProperty(exports, "getProviderProfile", {
|
|
16
17
|
enumerable: true,
|
|
17
|
-
get: function () { return
|
|
18
|
+
get: function () { return chunkSGKMTBCO_cjs.getProviderProfile; }
|
|
18
19
|
});
|
|
19
20
|
Object.defineProperty(exports, "listProviders", {
|
|
20
21
|
enumerable: true,
|
|
21
|
-
get: function () { return
|
|
22
|
+
get: function () { return chunkSGKMTBCO_cjs.listProviders; }
|
|
22
23
|
});
|
|
23
24
|
//# sourceMappingURL=providers.cjs.map
|
|
24
25
|
//# sourceMappingURL=providers.cjs.map
|
package/dist/providers.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { getProviderProfile, listProviders } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { getProviderProfile, listProviders } from './chunk-UNUGF36D.js';
|
|
2
|
+
import './chunk-A3T2A2WU.js';
|
|
3
3
|
import './chunk-AGACYRJ2.js';
|
|
4
|
+
import './chunk-Z2UVCAYS.js';
|
|
4
5
|
import './chunk-UNP4NCMZ.js';
|
|
5
6
|
import './chunk-L2KC2G7H.js';
|
|
6
7
|
import './chunk-5IUDICRK.js';
|