@x12i/ai-tools 1.0.4 → 2.0.1

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.
Files changed (162) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +146 -204
  3. package/dist/AiModelsCatalogClient-B5FMI9gj.d.cts +58 -0
  4. package/dist/AiModelsCatalogClient-CPPNI6Ry.d.ts +58 -0
  5. package/dist/aliases/index.cjs +4 -3
  6. package/dist/aliases/index.cjs.map +1 -1
  7. package/dist/aliases/index.d.cts +3 -5
  8. package/dist/aliases/index.d.ts +3 -5
  9. package/dist/aliases/index.js +2 -2
  10. package/dist/catalog/index.cjs +18 -9
  11. package/dist/catalog/index.cjs.map +1 -1
  12. package/dist/catalog/index.d.cts +13 -100
  13. package/dist/catalog/index.d.ts +13 -100
  14. package/dist/catalog/index.js +31 -23
  15. package/dist/{chunk-AJEKEWWB.js → chunk-2PTCWPHV.js} +17 -3
  16. package/dist/chunk-2PTCWPHV.js.map +1 -0
  17. package/dist/chunk-56R4XA2S.js +1 -0
  18. package/dist/chunk-5GUKLOEK.cjs +1 -0
  19. package/dist/chunk-5GUKLOEK.cjs.map +1 -0
  20. package/dist/chunk-5IZ7PLY2.cjs +51 -0
  21. package/dist/chunk-5IZ7PLY2.cjs.map +1 -0
  22. package/dist/chunk-5XAAMBDO.cjs +1988 -0
  23. package/dist/chunk-5XAAMBDO.cjs.map +1 -0
  24. package/dist/chunk-6BQBKROR.js +95 -0
  25. package/dist/chunk-6BQBKROR.js.map +1 -0
  26. package/dist/chunk-AB5GNXJ4.js +46 -0
  27. package/dist/chunk-AB5GNXJ4.js.map +1 -0
  28. package/dist/{chunk-O2A6OVEH.js → chunk-ANVONYJF.js} +2 -2
  29. package/dist/{chunk-O2A6OVEH.js.map → chunk-ANVONYJF.js.map} +1 -1
  30. package/dist/chunk-B3V2EHRY.js +225 -0
  31. package/dist/chunk-B3V2EHRY.js.map +1 -0
  32. package/dist/{chunk-QWAX7VQO.cjs → chunk-BAHBDADJ.cjs} +11 -11
  33. package/dist/{chunk-QWAX7VQO.cjs.map → chunk-BAHBDADJ.cjs.map} +1 -1
  34. package/dist/chunk-CTM35DMA.js +948 -0
  35. package/dist/chunk-CTM35DMA.js.map +1 -0
  36. package/dist/{chunk-TF4L2NEC.cjs → chunk-DXZOL3VN.cjs} +62 -313
  37. package/dist/chunk-DXZOL3VN.cjs.map +1 -0
  38. package/dist/chunk-EDMCKHO6.cjs +225 -0
  39. package/dist/chunk-EDMCKHO6.cjs.map +1 -0
  40. package/dist/{chunk-DJ5SWJDY.js → chunk-EYHMQVAL.js} +48 -299
  41. package/dist/chunk-EYHMQVAL.js.map +1 -0
  42. package/dist/chunk-GS7T56RP.cjs +8 -0
  43. package/dist/chunk-GS7T56RP.cjs.map +1 -0
  44. package/dist/chunk-OPN6BGNH.js +1985 -0
  45. package/dist/chunk-OPN6BGNH.js.map +1 -0
  46. package/dist/{chunk-7Q742NI3.cjs → chunk-PADNCGZB.cjs} +17 -3
  47. package/dist/chunk-PADNCGZB.cjs.map +1 -0
  48. package/dist/chunk-PRCICORG.cjs +95 -0
  49. package/dist/chunk-PRCICORG.cjs.map +1 -0
  50. package/dist/{chunk-6QGDZTGH.js → chunk-SIH4GPV4.js} +4 -29
  51. package/dist/chunk-SIH4GPV4.js.map +1 -0
  52. package/dist/{chunk-4NAY6HRP.js → chunk-VJHLO2R3.js} +7 -58
  53. package/dist/chunk-VJHLO2R3.js.map +1 -0
  54. package/dist/chunk-WOHMHXRZ.cjs +951 -0
  55. package/dist/chunk-WOHMHXRZ.cjs.map +1 -0
  56. package/dist/chunk-XAWBTX3N.cjs +46 -0
  57. package/dist/chunk-XAWBTX3N.cjs.map +1 -0
  58. package/dist/{chunk-AV6OE2YQ.cjs → chunk-XOKUDUUI.cjs} +14 -39
  59. package/dist/chunk-XOKUDUUI.cjs.map +1 -0
  60. package/dist/chunk-YQDSN6R6.cjs +86 -0
  61. package/dist/chunk-YQDSN6R6.cjs.map +1 -0
  62. package/dist/chunk-YQVY7CWT.js +51 -0
  63. package/dist/chunk-YQVY7CWT.js.map +1 -0
  64. package/dist/cli/index.cjs +59 -201
  65. package/dist/cli/index.cjs.map +1 -1
  66. package/dist/cli/index.js +53 -198
  67. package/dist/cli/index.js.map +1 -1
  68. package/dist/cost/index.cjs +19 -3
  69. package/dist/cost/index.cjs.map +1 -1
  70. package/dist/cost/index.d.cts +10 -50
  71. package/dist/cost/index.d.ts +10 -50
  72. package/dist/cost/index.js +18 -3
  73. package/dist/index.cjs +36 -14
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.d.cts +15 -13
  76. package/dist/index.d.ts +15 -13
  77. package/dist/index.js +56 -35
  78. package/dist/modelCache-BzRn6t_C.d.ts +113 -0
  79. package/dist/modelCache-CJftI-Ko.d.cts +113 -0
  80. package/dist/{modelNameResolver-DqFt7g6W.d.ts → modelNameResolver-5XkBMctP.d.ts} +2 -6
  81. package/dist/{modelNameResolver-D9V_GfUK.d.cts → modelNameResolver-C5CSTGFF.d.cts} +2 -6
  82. package/dist/models/index.cjs +9 -6
  83. package/dist/models/index.cjs.map +1 -1
  84. package/dist/models/index.d.cts +9 -31
  85. package/dist/models/index.d.ts +9 -31
  86. package/dist/models/index.js +9 -7
  87. package/dist/profiles/index.cjs +18 -0
  88. package/dist/profiles/index.cjs.map +1 -0
  89. package/dist/profiles/index.d.cts +40 -0
  90. package/dist/profiles/index.d.ts +40 -0
  91. package/dist/profiles/index.js +17 -0
  92. package/dist/resolveUsageModel-BFwf80Hz.d.ts +140 -0
  93. package/dist/resolveUsageModel-C_YmGR1M.d.cts +140 -0
  94. package/dist/sync/index.cjs +7 -9
  95. package/dist/sync/index.cjs.map +1 -1
  96. package/dist/sync/index.d.cts +3 -8
  97. package/dist/sync/index.d.ts +3 -8
  98. package/dist/sync/index.js +8 -11
  99. package/dist/toolbox/index.cjs +1 -0
  100. package/dist/toolbox/index.cjs.map +1 -1
  101. package/dist/types-BrzJWsTU.d.cts +277 -0
  102. package/dist/types-BrzJWsTU.d.ts +277 -0
  103. package/package.json +14 -20
  104. package/src/data/models-catalog.json +670 -0
  105. package/src/data/openrouter-models-catalog.json +857 -0
  106. package/dist/AiModelsCatalogClient-4RF5BCDL.cjs +0 -9
  107. package/dist/AiModelsCatalogClient-4RF5BCDL.cjs.map +0 -1
  108. package/dist/AiModelsCatalogClient-CNeqFiFs.d.cts +0 -30
  109. package/dist/AiModelsCatalogClient-NUF3CBLW.js +0 -9
  110. package/dist/AiModelsCatalogClient-nwFoEaqL.d.ts +0 -30
  111. package/dist/catalox/index.cjs +0 -21
  112. package/dist/catalox/index.cjs.map +0 -1
  113. package/dist/catalox/index.d.cts +0 -11
  114. package/dist/catalox/index.d.ts +0 -11
  115. package/dist/catalox/index.js +0 -21
  116. package/dist/chunk-4NAY6HRP.js.map +0 -1
  117. package/dist/chunk-6QGDZTGH.js.map +0 -1
  118. package/dist/chunk-7Q742NI3.cjs.map +0 -1
  119. package/dist/chunk-AJEKEWWB.js.map +0 -1
  120. package/dist/chunk-AV6OE2YQ.cjs.map +0 -1
  121. package/dist/chunk-C3H7RTFR.cjs +0 -1
  122. package/dist/chunk-C3H7RTFR.cjs.map +0 -1
  123. package/dist/chunk-DJ5SWJDY.js.map +0 -1
  124. package/dist/chunk-DKHGWHXP.cjs +0 -169
  125. package/dist/chunk-DKHGWHXP.cjs.map +0 -1
  126. package/dist/chunk-F2F4UEFD.cjs +0 -75
  127. package/dist/chunk-F2F4UEFD.cjs.map +0 -1
  128. package/dist/chunk-FGP3QXWL.cjs +0 -163
  129. package/dist/chunk-FGP3QXWL.cjs.map +0 -1
  130. package/dist/chunk-G2G4KSC5.js +0 -30
  131. package/dist/chunk-G2G4KSC5.js.map +0 -1
  132. package/dist/chunk-HN6UAQAE.cjs +0 -83
  133. package/dist/chunk-HN6UAQAE.cjs.map +0 -1
  134. package/dist/chunk-HS74X2OJ.cjs +0 -172
  135. package/dist/chunk-HS74X2OJ.cjs.map +0 -1
  136. package/dist/chunk-HYGXZY25.js +0 -163
  137. package/dist/chunk-HYGXZY25.js.map +0 -1
  138. package/dist/chunk-KQOALKKX.js +0 -75
  139. package/dist/chunk-KQOALKKX.js.map +0 -1
  140. package/dist/chunk-LYOU7CA2.cjs +0 -30
  141. package/dist/chunk-LYOU7CA2.cjs.map +0 -1
  142. package/dist/chunk-M5TMA73F.js +0 -1
  143. package/dist/chunk-M5TMA73F.js.map +0 -1
  144. package/dist/chunk-MX3AMQFC.js +0 -172
  145. package/dist/chunk-MX3AMQFC.js.map +0 -1
  146. package/dist/chunk-QCRLKVB3.cjs +0 -137
  147. package/dist/chunk-QCRLKVB3.cjs.map +0 -1
  148. package/dist/chunk-TF4L2NEC.cjs.map +0 -1
  149. package/dist/chunk-VRFVF5RH.js +0 -169
  150. package/dist/chunk-VRFVF5RH.js.map +0 -1
  151. package/dist/chunk-YHO57D2V.js +0 -83
  152. package/dist/chunk-YHO57D2V.js.map +0 -1
  153. package/dist/syncAiModelsCatalog-CnXRLm2c.d.cts +0 -32
  154. package/dist/syncAiModelsCatalog-DpkN_w7S.d.ts +0 -32
  155. package/dist/types-BYXnCvKx.d.cts +0 -137
  156. package/dist/types-BYXnCvKx.d.ts +0 -137
  157. package/dist/types-CX6QFNNy.d.cts +0 -144
  158. package/dist/types-CuiPDcVs.d.ts +0 -144
  159. package/dist/upsertAiModelRecord-C831wOIF.d.ts +0 -35
  160. package/dist/upsertAiModelRecord-CjY-sny0.d.cts +0 -35
  161. /package/dist/{AiModelsCatalogClient-NUF3CBLW.js.map → chunk-56R4XA2S.js.map} +0 -0
  162. /package/dist/{catalox → profiles}/index.js.map +0 -0
@@ -0,0 +1,277 @@
1
+ /** OpenRouter Models API — https://openrouter.ai/api/v1/models */
2
+ type OpenRouterOutputModality = "text" | "image" | "audio" | "embeddings" | "video" | "speech" | "transcription" | "all";
3
+ type OpenRouterModelsQuery = {
4
+ /** Comma-separated or "all" — default on our sync is "all". */
5
+ output_modalities?: string;
6
+ supported_parameters?: string;
7
+ };
8
+ type OpenRouterPricingApi = {
9
+ prompt: string;
10
+ completion: string;
11
+ request: string;
12
+ image: string;
13
+ web_search?: string;
14
+ internal_reasoning?: string;
15
+ input_cache_read?: string;
16
+ input_cache_write?: string;
17
+ };
18
+ type OpenRouterArchitectureApi = {
19
+ modality?: string;
20
+ input_modalities: string[];
21
+ output_modalities: string[];
22
+ tokenizer: string;
23
+ instruct_type: string | null;
24
+ };
25
+ type OpenRouterTopProviderApi = {
26
+ context_length: number;
27
+ max_completion_tokens: number | null;
28
+ is_moderated: boolean;
29
+ };
30
+ type OpenRouterDefaultParametersApi = {
31
+ temperature?: number | null;
32
+ top_p?: number | null;
33
+ top_k?: number | null;
34
+ frequency_penalty?: number | null;
35
+ presence_penalty?: number | null;
36
+ repetition_penalty?: number | null;
37
+ };
38
+ type OpenRouterModelApi = {
39
+ id: string;
40
+ canonical_slug: string;
41
+ hugging_face_id?: string | null;
42
+ name: string;
43
+ created: number;
44
+ description: string;
45
+ context_length: number;
46
+ architecture: OpenRouterArchitectureApi;
47
+ pricing: OpenRouterPricingApi;
48
+ top_provider: OpenRouterTopProviderApi;
49
+ per_request_limits: unknown | null;
50
+ supported_parameters: string[];
51
+ default_parameters: OpenRouterDefaultParametersApi | null;
52
+ supported_voices?: unknown | null;
53
+ knowledge_cutoff?: string | null;
54
+ expiration_date?: string | null;
55
+ links?: {
56
+ details?: string;
57
+ } | null;
58
+ };
59
+ type OpenRouterModelsResponse = {
60
+ data: OpenRouterModelApi[];
61
+ };
62
+
63
+ type AiModelPricing = {
64
+ promptUsdPerToken: number;
65
+ completionUsdPerToken: number;
66
+ imageUsdPerUnit: number;
67
+ requestUsdPerRequest: number;
68
+ cacheReadUsdPerToken?: number;
69
+ cacheWriteUsdPerToken?: number;
70
+ reasoningUsdPerToken?: number;
71
+ webSearchUsdPerRequest?: number;
72
+ openRouterMarkupUsdPerInputToken?: number;
73
+ openRouterMarkupUsdPerOutputToken?: number;
74
+ pricedAt: string;
75
+ source: "openrouter" | "direct" | "manual";
76
+ };
77
+ /**
78
+ * Canonical catalog record — mirrors OpenRouter Models API fields plus normalized pricing.
79
+ * Canonical catalog record loaded from x12i open-assets JSON catalogs.
80
+ */
81
+ type AiModelRecord = {
82
+ modelId: string;
83
+ name: string;
84
+ providerId: string;
85
+ canonicalSlug: string;
86
+ status: "active" | "deprecated" | "unknown";
87
+ description: string;
88
+ created: number;
89
+ expirationDate: string | null;
90
+ contextLength: number;
91
+ maxCompletionTokens: number | null;
92
+ isModerated: boolean;
93
+ modality: string;
94
+ inputModalities: string[];
95
+ outputModalities: string[];
96
+ tokenizer: string;
97
+ instructType: string | null;
98
+ supportedParameters: string[];
99
+ defaultParameters: OpenRouterDefaultParametersApi | null;
100
+ perRequestLimits: unknown | null;
101
+ pricing: AiModelPricing;
102
+ /** Raw OpenRouter pricing strings (USD per token/request/unit). */
103
+ openRouterPricing: OpenRouterPricingApi;
104
+ architecture: OpenRouterArchitectureApi;
105
+ topProvider: OpenRouterTopProviderApi;
106
+ /** Full OpenRouter API object — complete mirror for forward compatibility. */
107
+ openRouter: OpenRouterModelApi;
108
+ aliases: string[];
109
+ availableOnOpenRouter: boolean;
110
+ supportsStreaming: boolean;
111
+ supportsTools: boolean;
112
+ /** Exposes reasoning/thinking tokens (OpenRouter `reasoning` param and/or `internal_reasoning` pricing). */
113
+ supportsReasoning: boolean;
114
+ primaryOutputModality: string;
115
+ syncedAt: string;
116
+ syncSource: "openrouter" | "manual";
117
+ };
118
+ type ModelListFilters = {
119
+ providerId?: string;
120
+ status?: AiModelRecord["status"];
121
+ outputModality?: string;
122
+ inputModality?: string;
123
+ supportedParameter?: string;
124
+ supportsTools?: boolean;
125
+ supportsReasoning?: boolean;
126
+ search?: string;
127
+ limit?: number;
128
+ offset?: number;
129
+ };
130
+ type ModelListResult = {
131
+ models: AiModelRecord[];
132
+ total: number;
133
+ limit: number;
134
+ offset: number;
135
+ };
136
+
137
+ type AliasEntry = {
138
+ modelId: string;
139
+ provider: string;
140
+ description?: string;
141
+ tags?: string[];
142
+ addedAt: string;
143
+ updatedAt: string;
144
+ };
145
+ type AliasFileSchema = {
146
+ $schema?: string;
147
+ version: 1;
148
+ updatedAt: string;
149
+ aliases: Record<string, AliasEntry>;
150
+ };
151
+ type ResolvedModelRef = {
152
+ alias: string;
153
+ entry: AliasEntry;
154
+ modelRecord: AiModelRecord | null;
155
+ modelId: string;
156
+ provider: string;
157
+ name: string;
158
+ };
159
+ type AliasValidationReport = {
160
+ total: number;
161
+ ok: number;
162
+ unknown: number;
163
+ broken: number;
164
+ entries: Array<{
165
+ name: string;
166
+ status: "ok" | "unknown" | "broken";
167
+ modelId: string;
168
+ resolvedName?: string;
169
+ issue?: string;
170
+ }>;
171
+ };
172
+
173
+ type AliasRegistryOptions = {
174
+ aliasesPath?: string;
175
+ };
176
+ declare class AliasRegistry {
177
+ private readonly aliasesPath;
178
+ constructor(options?: AliasRegistryOptions);
179
+ get path(): string;
180
+ exists(): boolean;
181
+ init(): void;
182
+ load(): AliasFileSchema;
183
+ get(aliasName: string): AliasEntry | null;
184
+ list(filter?: {
185
+ tag?: string;
186
+ }): Array<{
187
+ name: string;
188
+ } & AliasEntry>;
189
+ set(aliasName: string, entry: Omit<AliasEntry, "addedAt" | "updatedAt">): AliasEntry;
190
+ remove(aliasName: string): boolean;
191
+ rename(from: string, to: string, options?: {
192
+ force?: boolean;
193
+ }): void;
194
+ private writeFile;
195
+ }
196
+
197
+ /**
198
+ * Env naming for vendor direct API keys: `{VENDOR}_API_KEY`
199
+ * where VENDOR is the provider id in UPPER_SNAKE (hyphens → underscores).
200
+ *
201
+ * Examples: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `META_LLAMA_API_KEY`, `X_AI_API_KEY`
202
+ */
203
+ declare function providerIdToEnvKeyPrefix(providerId: string): string;
204
+ declare function vendorApiKeyEnvName(providerId: string): string;
205
+ type OpenRouterRoutingConfig = {
206
+ /** OPENROUTER_API_KEY is set and non-empty */
207
+ hasOpenRouterKey: boolean;
208
+ /** USE_OPENROUTER=true or USE_OPENROUTER=1 */
209
+ useOpenRouterExplicit: boolean;
210
+ /** Read `{PROVIDER}_API_KEY` for a catalog provider id */
211
+ getVendorApiKey(providerId: string): string | undefined;
212
+ };
213
+ /**
214
+ * Load routing hints from process env and optional `.env` (via @x12/env).
215
+ */
216
+ declare function loadOpenRouterRoutingEnv(env?: Record<string, string | undefined>): OpenRouterRoutingConfig;
217
+ /**
218
+ * Default route via OpenRouter when:
219
+ * 1. OPENROUTER_API_KEY is set AND USE_OPENROUTER=true|1, or
220
+ * 2. OPENROUTER_API_KEY is set AND the vendor's `{VENDOR}_API_KEY` is missing.
221
+ */
222
+ declare function shouldDefaultRouteViaOpenRouter(providerId: string | undefined, config: OpenRouterRoutingConfig): boolean;
223
+
224
+ type ModelResolutionInput = {
225
+ /** Provider hint (openrouter, openai, anthropic, …). May be omitted. */
226
+ provider?: string;
227
+ /** Model id, alias, shorthand, or partial name. Required. */
228
+ model: string;
229
+ };
230
+ type ResolutionStrategy = "alias-registry" | "alias-as-provider-correction" | "exact-match" | "catalog-alias-match" | "canonical-slug-match" | "provider-prefix-injection" | "cross-provider-correction" | "version-suffix-strip" | "date-suffix-strip" | "shorthand-expansion" | "partial-name-match" | "local-provider-passthrough";
231
+ type ModelResolutionSuccess = {
232
+ found: true;
233
+ modelId: string;
234
+ record: AiModelRecord | null;
235
+ routedViaOpenRouter: boolean;
236
+ confidence: number;
237
+ resolvedVia: ResolutionStrategy[];
238
+ resolvedReason: string;
239
+ normalisedInput: string;
240
+ };
241
+ type ModelResolutionNotFound = {
242
+ found: false;
243
+ modelId: null;
244
+ record: null;
245
+ attemptedStrategies: ResolutionStrategy[];
246
+ bestRejectedCandidate?: {
247
+ modelId: string;
248
+ confidence: number;
249
+ reason: string;
250
+ };
251
+ reason: string;
252
+ };
253
+ type ModelResolutionResult = ModelResolutionSuccess | ModelResolutionNotFound;
254
+ type ModelResolverOptions = {
255
+ confidenceThreshold?: number;
256
+ aliasRegistry?: AliasRegistry;
257
+ additionalShorthands?: Record<string, string>;
258
+ additionalProviderPatterns?: Array<{
259
+ pattern: RegExp;
260
+ provider: string;
261
+ }>;
262
+ additionalLocalProviders?: string[];
263
+ /** Env-based OpenRouter vs direct routing. Defaults to loadOpenRouterRoutingEnv(). */
264
+ routingEnv?: OpenRouterRoutingConfig;
265
+ };
266
+ type CatalogIndexes = {
267
+ aliasIndex: Map<string, string>;
268
+ slugIndex: Map<string, string>;
269
+ providerPrefixesBySize: string[];
270
+ };
271
+ type ResolvedModel = {
272
+ catalogModel: AiModelRecord;
273
+ matchedAlias: string;
274
+ routedViaOpenRouter: boolean;
275
+ };
276
+
277
+ export { type AiModelPricing as A, type CatalogIndexes as C, type ModelListFilters as M, type OpenRouterArchitectureApi as O, type ResolutionStrategy as R, type AiModelRecord as a, type AliasEntry as b, type AliasFileSchema as c, AliasRegistry as d, type AliasRegistryOptions as e, type AliasValidationReport as f, type ModelListResult as g, type ModelResolutionInput as h, type ModelResolutionNotFound as i, type ModelResolutionResult as j, type ModelResolutionSuccess as k, type ModelResolverOptions as l, type OpenRouterModelApi as m, type OpenRouterModelsQuery as n, type OpenRouterModelsResponse as o, type OpenRouterOutputModality as p, type OpenRouterPricingApi as q, type OpenRouterRoutingConfig as r, type OpenRouterTopProviderApi as s, type ResolvedModel as t, type ResolvedModelRef as u, loadOpenRouterRoutingEnv as v, providerIdToEnvKeyPrefix as w, shouldDefaultRouteViaOpenRouter as x, vendorApiKeyEnvName as y };
@@ -0,0 +1,277 @@
1
+ /** OpenRouter Models API — https://openrouter.ai/api/v1/models */
2
+ type OpenRouterOutputModality = "text" | "image" | "audio" | "embeddings" | "video" | "speech" | "transcription" | "all";
3
+ type OpenRouterModelsQuery = {
4
+ /** Comma-separated or "all" — default on our sync is "all". */
5
+ output_modalities?: string;
6
+ supported_parameters?: string;
7
+ };
8
+ type OpenRouterPricingApi = {
9
+ prompt: string;
10
+ completion: string;
11
+ request: string;
12
+ image: string;
13
+ web_search?: string;
14
+ internal_reasoning?: string;
15
+ input_cache_read?: string;
16
+ input_cache_write?: string;
17
+ };
18
+ type OpenRouterArchitectureApi = {
19
+ modality?: string;
20
+ input_modalities: string[];
21
+ output_modalities: string[];
22
+ tokenizer: string;
23
+ instruct_type: string | null;
24
+ };
25
+ type OpenRouterTopProviderApi = {
26
+ context_length: number;
27
+ max_completion_tokens: number | null;
28
+ is_moderated: boolean;
29
+ };
30
+ type OpenRouterDefaultParametersApi = {
31
+ temperature?: number | null;
32
+ top_p?: number | null;
33
+ top_k?: number | null;
34
+ frequency_penalty?: number | null;
35
+ presence_penalty?: number | null;
36
+ repetition_penalty?: number | null;
37
+ };
38
+ type OpenRouterModelApi = {
39
+ id: string;
40
+ canonical_slug: string;
41
+ hugging_face_id?: string | null;
42
+ name: string;
43
+ created: number;
44
+ description: string;
45
+ context_length: number;
46
+ architecture: OpenRouterArchitectureApi;
47
+ pricing: OpenRouterPricingApi;
48
+ top_provider: OpenRouterTopProviderApi;
49
+ per_request_limits: unknown | null;
50
+ supported_parameters: string[];
51
+ default_parameters: OpenRouterDefaultParametersApi | null;
52
+ supported_voices?: unknown | null;
53
+ knowledge_cutoff?: string | null;
54
+ expiration_date?: string | null;
55
+ links?: {
56
+ details?: string;
57
+ } | null;
58
+ };
59
+ type OpenRouterModelsResponse = {
60
+ data: OpenRouterModelApi[];
61
+ };
62
+
63
+ type AiModelPricing = {
64
+ promptUsdPerToken: number;
65
+ completionUsdPerToken: number;
66
+ imageUsdPerUnit: number;
67
+ requestUsdPerRequest: number;
68
+ cacheReadUsdPerToken?: number;
69
+ cacheWriteUsdPerToken?: number;
70
+ reasoningUsdPerToken?: number;
71
+ webSearchUsdPerRequest?: number;
72
+ openRouterMarkupUsdPerInputToken?: number;
73
+ openRouterMarkupUsdPerOutputToken?: number;
74
+ pricedAt: string;
75
+ source: "openrouter" | "direct" | "manual";
76
+ };
77
+ /**
78
+ * Canonical catalog record — mirrors OpenRouter Models API fields plus normalized pricing.
79
+ * Canonical catalog record loaded from x12i open-assets JSON catalogs.
80
+ */
81
+ type AiModelRecord = {
82
+ modelId: string;
83
+ name: string;
84
+ providerId: string;
85
+ canonicalSlug: string;
86
+ status: "active" | "deprecated" | "unknown";
87
+ description: string;
88
+ created: number;
89
+ expirationDate: string | null;
90
+ contextLength: number;
91
+ maxCompletionTokens: number | null;
92
+ isModerated: boolean;
93
+ modality: string;
94
+ inputModalities: string[];
95
+ outputModalities: string[];
96
+ tokenizer: string;
97
+ instructType: string | null;
98
+ supportedParameters: string[];
99
+ defaultParameters: OpenRouterDefaultParametersApi | null;
100
+ perRequestLimits: unknown | null;
101
+ pricing: AiModelPricing;
102
+ /** Raw OpenRouter pricing strings (USD per token/request/unit). */
103
+ openRouterPricing: OpenRouterPricingApi;
104
+ architecture: OpenRouterArchitectureApi;
105
+ topProvider: OpenRouterTopProviderApi;
106
+ /** Full OpenRouter API object — complete mirror for forward compatibility. */
107
+ openRouter: OpenRouterModelApi;
108
+ aliases: string[];
109
+ availableOnOpenRouter: boolean;
110
+ supportsStreaming: boolean;
111
+ supportsTools: boolean;
112
+ /** Exposes reasoning/thinking tokens (OpenRouter `reasoning` param and/or `internal_reasoning` pricing). */
113
+ supportsReasoning: boolean;
114
+ primaryOutputModality: string;
115
+ syncedAt: string;
116
+ syncSource: "openrouter" | "manual";
117
+ };
118
+ type ModelListFilters = {
119
+ providerId?: string;
120
+ status?: AiModelRecord["status"];
121
+ outputModality?: string;
122
+ inputModality?: string;
123
+ supportedParameter?: string;
124
+ supportsTools?: boolean;
125
+ supportsReasoning?: boolean;
126
+ search?: string;
127
+ limit?: number;
128
+ offset?: number;
129
+ };
130
+ type ModelListResult = {
131
+ models: AiModelRecord[];
132
+ total: number;
133
+ limit: number;
134
+ offset: number;
135
+ };
136
+
137
+ type AliasEntry = {
138
+ modelId: string;
139
+ provider: string;
140
+ description?: string;
141
+ tags?: string[];
142
+ addedAt: string;
143
+ updatedAt: string;
144
+ };
145
+ type AliasFileSchema = {
146
+ $schema?: string;
147
+ version: 1;
148
+ updatedAt: string;
149
+ aliases: Record<string, AliasEntry>;
150
+ };
151
+ type ResolvedModelRef = {
152
+ alias: string;
153
+ entry: AliasEntry;
154
+ modelRecord: AiModelRecord | null;
155
+ modelId: string;
156
+ provider: string;
157
+ name: string;
158
+ };
159
+ type AliasValidationReport = {
160
+ total: number;
161
+ ok: number;
162
+ unknown: number;
163
+ broken: number;
164
+ entries: Array<{
165
+ name: string;
166
+ status: "ok" | "unknown" | "broken";
167
+ modelId: string;
168
+ resolvedName?: string;
169
+ issue?: string;
170
+ }>;
171
+ };
172
+
173
+ type AliasRegistryOptions = {
174
+ aliasesPath?: string;
175
+ };
176
+ declare class AliasRegistry {
177
+ private readonly aliasesPath;
178
+ constructor(options?: AliasRegistryOptions);
179
+ get path(): string;
180
+ exists(): boolean;
181
+ init(): void;
182
+ load(): AliasFileSchema;
183
+ get(aliasName: string): AliasEntry | null;
184
+ list(filter?: {
185
+ tag?: string;
186
+ }): Array<{
187
+ name: string;
188
+ } & AliasEntry>;
189
+ set(aliasName: string, entry: Omit<AliasEntry, "addedAt" | "updatedAt">): AliasEntry;
190
+ remove(aliasName: string): boolean;
191
+ rename(from: string, to: string, options?: {
192
+ force?: boolean;
193
+ }): void;
194
+ private writeFile;
195
+ }
196
+
197
+ /**
198
+ * Env naming for vendor direct API keys: `{VENDOR}_API_KEY`
199
+ * where VENDOR is the provider id in UPPER_SNAKE (hyphens → underscores).
200
+ *
201
+ * Examples: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `META_LLAMA_API_KEY`, `X_AI_API_KEY`
202
+ */
203
+ declare function providerIdToEnvKeyPrefix(providerId: string): string;
204
+ declare function vendorApiKeyEnvName(providerId: string): string;
205
+ type OpenRouterRoutingConfig = {
206
+ /** OPENROUTER_API_KEY is set and non-empty */
207
+ hasOpenRouterKey: boolean;
208
+ /** USE_OPENROUTER=true or USE_OPENROUTER=1 */
209
+ useOpenRouterExplicit: boolean;
210
+ /** Read `{PROVIDER}_API_KEY` for a catalog provider id */
211
+ getVendorApiKey(providerId: string): string | undefined;
212
+ };
213
+ /**
214
+ * Load routing hints from process env and optional `.env` (via @x12/env).
215
+ */
216
+ declare function loadOpenRouterRoutingEnv(env?: Record<string, string | undefined>): OpenRouterRoutingConfig;
217
+ /**
218
+ * Default route via OpenRouter when:
219
+ * 1. OPENROUTER_API_KEY is set AND USE_OPENROUTER=true|1, or
220
+ * 2. OPENROUTER_API_KEY is set AND the vendor's `{VENDOR}_API_KEY` is missing.
221
+ */
222
+ declare function shouldDefaultRouteViaOpenRouter(providerId: string | undefined, config: OpenRouterRoutingConfig): boolean;
223
+
224
+ type ModelResolutionInput = {
225
+ /** Provider hint (openrouter, openai, anthropic, …). May be omitted. */
226
+ provider?: string;
227
+ /** Model id, alias, shorthand, or partial name. Required. */
228
+ model: string;
229
+ };
230
+ type ResolutionStrategy = "alias-registry" | "alias-as-provider-correction" | "exact-match" | "catalog-alias-match" | "canonical-slug-match" | "provider-prefix-injection" | "cross-provider-correction" | "version-suffix-strip" | "date-suffix-strip" | "shorthand-expansion" | "partial-name-match" | "local-provider-passthrough";
231
+ type ModelResolutionSuccess = {
232
+ found: true;
233
+ modelId: string;
234
+ record: AiModelRecord | null;
235
+ routedViaOpenRouter: boolean;
236
+ confidence: number;
237
+ resolvedVia: ResolutionStrategy[];
238
+ resolvedReason: string;
239
+ normalisedInput: string;
240
+ };
241
+ type ModelResolutionNotFound = {
242
+ found: false;
243
+ modelId: null;
244
+ record: null;
245
+ attemptedStrategies: ResolutionStrategy[];
246
+ bestRejectedCandidate?: {
247
+ modelId: string;
248
+ confidence: number;
249
+ reason: string;
250
+ };
251
+ reason: string;
252
+ };
253
+ type ModelResolutionResult = ModelResolutionSuccess | ModelResolutionNotFound;
254
+ type ModelResolverOptions = {
255
+ confidenceThreshold?: number;
256
+ aliasRegistry?: AliasRegistry;
257
+ additionalShorthands?: Record<string, string>;
258
+ additionalProviderPatterns?: Array<{
259
+ pattern: RegExp;
260
+ provider: string;
261
+ }>;
262
+ additionalLocalProviders?: string[];
263
+ /** Env-based OpenRouter vs direct routing. Defaults to loadOpenRouterRoutingEnv(). */
264
+ routingEnv?: OpenRouterRoutingConfig;
265
+ };
266
+ type CatalogIndexes = {
267
+ aliasIndex: Map<string, string>;
268
+ slugIndex: Map<string, string>;
269
+ providerPrefixesBySize: string[];
270
+ };
271
+ type ResolvedModel = {
272
+ catalogModel: AiModelRecord;
273
+ matchedAlias: string;
274
+ routedViaOpenRouter: boolean;
275
+ };
276
+
277
+ export { type AiModelPricing as A, type CatalogIndexes as C, type ModelListFilters as M, type OpenRouterArchitectureApi as O, type ResolutionStrategy as R, type AiModelRecord as a, type AliasEntry as b, type AliasFileSchema as c, AliasRegistry as d, type AliasRegistryOptions as e, type AliasValidationReport as f, type ModelListResult as g, type ModelResolutionInput as h, type ModelResolutionNotFound as i, type ModelResolutionResult as j, type ModelResolutionSuccess as k, type ModelResolverOptions as l, type OpenRouterModelApi as m, type OpenRouterModelsQuery as n, type OpenRouterModelsResponse as o, type OpenRouterOutputModality as p, type OpenRouterPricingApi as q, type OpenRouterRoutingConfig as r, type OpenRouterTopProviderApi as s, type ResolvedModel as t, type ResolvedModelRef as u, loadOpenRouterRoutingEnv as v, providerIdToEnvKeyPrefix as w, shouldDefaultRouteViaOpenRouter as x, vendorApiKeyEnvName as y };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@x12i/ai-tools",
3
- "version": "1.0.4",
4
- "description": "AI model catalog, cost calculation, and LLM utility belt backed by Catalox",
3
+ "version": "2.0.1",
4
+ "description": "AI model catalogs (open-assets JSON), cost calculation, and LLM utilities",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs",
@@ -31,11 +31,6 @@
31
31
  "import": "./dist/sync/index.js",
32
32
  "require": "./dist/sync/index.cjs"
33
33
  },
34
- "./catalox": {
35
- "types": "./dist/catalox/index.d.ts",
36
- "import": "./dist/catalox/index.js",
37
- "require": "./dist/catalox/index.cjs"
38
- },
39
34
  "./aliases": {
40
35
  "types": "./dist/aliases/index.d.ts",
41
36
  "import": "./dist/aliases/index.js",
@@ -50,11 +45,19 @@
50
45
  "types": "./dist/catalog/index.d.ts",
51
46
  "import": "./dist/catalog/index.js",
52
47
  "require": "./dist/catalog/index.cjs"
48
+ },
49
+ "./profiles": {
50
+ "types": "./dist/profiles/index.d.ts",
51
+ "import": "./dist/profiles/index.js",
52
+ "require": "./dist/profiles/index.cjs"
53
53
  }
54
54
  },
55
55
  "files": [
56
56
  "dist",
57
- "schemas"
57
+ "schemas",
58
+ "src/data",
59
+ "CHANGELOG.md",
60
+ "README.md"
58
61
  ],
59
62
  "engines": {
60
63
  "node": ">=20"
@@ -66,22 +69,14 @@
66
69
  "test:all": "npm test && npm run test:live",
67
70
  "test:watch": "vitest",
68
71
  "test:coverage": "vitest run --coverage",
69
- "seed": "tsx scripts/seed.ts",
70
- "seed:verbose": "tsx scripts/seed.ts --verbose",
71
- "verify:sync": "tsx scripts/verify-catalog-sync.ts",
72
- "verify:seed": "tsx scripts/verify-catalog-sync.ts --sync",
72
+ "catalog:refresh": "tsx scripts/seed.ts",
73
+ "catalog:verify": "tsx scripts/verify-catalog-sync.ts",
73
74
  "prepublishOnly": "npm run build && npm test"
74
75
  },
75
- "peerDependencies": {
76
- "@x12i/catalox": "^4.0.0"
77
- },
78
76
  "peerDependenciesMeta": {
79
77
  "@x12i/helpers": {
80
78
  "optional": true
81
79
  },
82
- "firebase-admin": {
83
- "optional": true
84
- },
85
80
  "openai": {
86
81
  "optional": true
87
82
  },
@@ -90,6 +85,7 @@
90
85
  }
91
86
  },
92
87
  "dependencies": {
88
+ "@x12i/ai-profiles": "^1.2.0",
93
89
  "@x12i/env": "^4.0.1",
94
90
  "commander": "^12.1.0",
95
91
  "dotenv": "^16.4.7",
@@ -98,7 +94,6 @@
98
94
  },
99
95
  "devDependencies": {
100
96
  "@types/node": "^22.13.10",
101
- "@x12i/catalox": "^4.0.0",
102
97
  "tsup": "^8.4.0",
103
98
  "tsx": "^4.19.3",
104
99
  "typescript": "^5.8.2",
@@ -107,7 +102,6 @@
107
102
  "keywords": [
108
103
  "ai",
109
104
  "openrouter",
110
- "catalox",
111
105
  "llm",
112
106
  "cost",
113
107
  "models"