@x12i/ai-profiles 1.4.0 → 1.5.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.
Files changed (144) hide show
  1. package/README.md +186 -16
  2. package/dist/buildCatalogFromOpenRouterApi.d.ts +29 -0
  3. package/dist/buildCatalogFromOpenRouterApi.d.ts.map +1 -0
  4. package/dist/buildCatalogFromOpenRouterApi.js +113 -0
  5. package/dist/buildCatalogFromOpenRouterApi.js.map +1 -0
  6. package/dist/buildModelsRegistry.d.ts +25 -0
  7. package/dist/buildModelsRegistry.d.ts.map +1 -0
  8. package/dist/buildModelsRegistry.js +190 -0
  9. package/dist/buildModelsRegistry.js.map +1 -0
  10. package/dist/buildResolvedProfile.d.ts +3 -1
  11. package/dist/buildResolvedProfile.d.ts.map +1 -1
  12. package/dist/buildResolvedProfile.js +94 -11
  13. package/dist/buildResolvedProfile.js.map +1 -1
  14. package/dist/catalogEnrichment.d.ts +19 -0
  15. package/dist/catalogEnrichment.d.ts.map +1 -0
  16. package/dist/catalogEnrichment.js +87 -0
  17. package/dist/catalogEnrichment.js.map +1 -0
  18. package/dist/computeRegistryStatistics.d.ts +15 -0
  19. package/dist/computeRegistryStatistics.d.ts.map +1 -0
  20. package/dist/computeRegistryStatistics.js +168 -0
  21. package/dist/computeRegistryStatistics.js.map +1 -0
  22. package/dist/constants.d.ts +6 -0
  23. package/dist/constants.d.ts.map +1 -1
  24. package/dist/constants.js +10 -0
  25. package/dist/constants.js.map +1 -1
  26. package/dist/data/models-catalog.json +2219 -0
  27. package/dist/data/models-profiles.json +1361 -193
  28. package/dist/data/models-profiles.schema.json +130 -0
  29. package/dist/data/models-registry.json +1606 -0
  30. package/dist/data/openrouter-models-catalog.json +857 -0
  31. package/dist/data/profiles-shortcuts.json +101 -2
  32. package/dist/errors.d.ts +1 -1
  33. package/dist/errors.d.ts.map +1 -1
  34. package/dist/errors.js.map +1 -1
  35. package/dist/formatRegistryStatistics.d.ts +4 -0
  36. package/dist/formatRegistryStatistics.d.ts.map +1 -0
  37. package/dist/formatRegistryStatistics.js +34 -0
  38. package/dist/formatRegistryStatistics.js.map +1 -0
  39. package/dist/getAIRegistryStatistics.d.ts +11 -0
  40. package/dist/getAIRegistryStatistics.d.ts.map +1 -0
  41. package/dist/getAIRegistryStatistics.js +52 -0
  42. package/dist/getAIRegistryStatistics.js.map +1 -0
  43. package/dist/index.d.ts +22 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +19 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/listAIProfiles.d.ts +6 -0
  48. package/dist/listAIProfiles.d.ts.map +1 -1
  49. package/dist/listAIProfiles.js +6 -0
  50. package/dist/listAIProfiles.js.map +1 -1
  51. package/dist/loadModelsRegistry.d.ts +6 -0
  52. package/dist/loadModelsRegistry.d.ts.map +1 -0
  53. package/dist/loadModelsRegistry.js +43 -0
  54. package/dist/loadModelsRegistry.js.map +1 -0
  55. package/dist/loader/catalogMemoryCache.d.ts +12 -0
  56. package/dist/loader/catalogMemoryCache.d.ts.map +1 -0
  57. package/dist/loader/catalogMemoryCache.js +14 -0
  58. package/dist/loader/catalogMemoryCache.js.map +1 -0
  59. package/dist/loader/loadBundledModelsCatalog.d.ts +3 -0
  60. package/dist/loader/loadBundledModelsCatalog.d.ts.map +1 -0
  61. package/dist/loader/loadBundledModelsCatalog.js +20 -0
  62. package/dist/loader/loadBundledModelsCatalog.js.map +1 -0
  63. package/dist/loader/loadBundledModelsProfiles.d.ts +4 -0
  64. package/dist/loader/loadBundledModelsProfiles.d.ts.map +1 -0
  65. package/dist/loader/loadBundledModelsProfiles.js +14 -0
  66. package/dist/loader/loadBundledModelsProfiles.js.map +1 -0
  67. package/dist/loader/loadBundledRegistry.d.ts.map +1 -1
  68. package/dist/loader/loadBundledRegistry.js +2 -1
  69. package/dist/loader/loadBundledRegistry.js.map +1 -1
  70. package/dist/loader/loadModelsCatalog.d.ts +9 -0
  71. package/dist/loader/loadModelsCatalog.d.ts.map +1 -0
  72. package/dist/loader/loadModelsCatalog.js +72 -0
  73. package/dist/loader/loadModelsCatalog.js.map +1 -0
  74. package/dist/loader/loadModelsProfilesJson.d.ts +3 -0
  75. package/dist/loader/loadModelsProfilesJson.d.ts.map +1 -0
  76. package/dist/loader/loadModelsProfilesJson.js +18 -0
  77. package/dist/loader/loadModelsProfilesJson.js.map +1 -0
  78. package/dist/loader/loadRemoteModelsCatalog.d.ts +3 -0
  79. package/dist/loader/loadRemoteModelsCatalog.d.ts.map +1 -0
  80. package/dist/loader/loadRemoteModelsCatalog.js +23 -0
  81. package/dist/loader/loadRemoteModelsCatalog.js.map +1 -0
  82. package/dist/loader/loadRemoteModelsProfiles.d.ts +3 -0
  83. package/dist/loader/loadRemoteModelsProfiles.d.ts.map +1 -0
  84. package/dist/loader/loadRemoteModelsProfiles.js +21 -0
  85. package/dist/loader/loadRemoteModelsProfiles.js.map +1 -0
  86. package/dist/loader/loadRemoteRegistry.d.ts.map +1 -1
  87. package/dist/loader/loadRemoteRegistry.js +2 -1
  88. package/dist/loader/loadRemoteRegistry.js.map +1 -1
  89. package/dist/mergeCatalogSupplement.d.ts +4 -0
  90. package/dist/mergeCatalogSupplement.d.ts.map +1 -0
  91. package/dist/mergeCatalogSupplement.js +26 -0
  92. package/dist/mergeCatalogSupplement.js.map +1 -0
  93. package/dist/modelIdentity.d.ts +33 -0
  94. package/dist/modelIdentity.d.ts.map +1 -0
  95. package/dist/modelIdentity.js +150 -0
  96. package/dist/modelIdentity.js.map +1 -0
  97. package/dist/modelsCatalog.d.ts +21 -0
  98. package/dist/modelsCatalog.d.ts.map +1 -0
  99. package/dist/modelsCatalog.js +187 -0
  100. package/dist/modelsCatalog.js.map +1 -0
  101. package/dist/profileCatalogSupplement.d.ts +7 -0
  102. package/dist/profileCatalogSupplement.d.ts.map +1 -0
  103. package/dist/profileCatalogSupplement.js +292 -0
  104. package/dist/profileCatalogSupplement.js.map +1 -0
  105. package/dist/profileRegistryV2.d.ts +19 -0
  106. package/dist/profileRegistryV2.d.ts.map +1 -0
  107. package/dist/profileRegistryV2.js +257 -0
  108. package/dist/profileRegistryV2.js.map +1 -0
  109. package/dist/profileRegistryV3.d.ts +11 -0
  110. package/dist/profileRegistryV3.d.ts.map +1 -0
  111. package/dist/profileRegistryV3.js +526 -0
  112. package/dist/profileRegistryV3.js.map +1 -0
  113. package/dist/resolveAIProfile.d.ts +8 -0
  114. package/dist/resolveAIProfile.d.ts.map +1 -1
  115. package/dist/resolveAIProfile.js +62 -18
  116. package/dist/resolveAIProfile.js.map +1 -1
  117. package/dist/resolveModelRouting.d.ts +2 -1
  118. package/dist/resolveModelRouting.d.ts.map +1 -1
  119. package/dist/resolveModelRouting.js +9 -10
  120. package/dist/resolveModelRouting.js.map +1 -1
  121. package/dist/types.d.ts +339 -4
  122. package/dist/types.d.ts.map +1 -1
  123. package/dist/types.js +10 -0
  124. package/dist/types.js.map +1 -1
  125. package/dist/validateProfileVendorCoverage.d.ts +12 -0
  126. package/dist/validateProfileVendorCoverage.d.ts.map +1 -0
  127. package/dist/validateProfileVendorCoverage.js +58 -0
  128. package/dist/validateProfileVendorCoverage.js.map +1 -0
  129. package/dist/validation/openRouterAlignment.d.ts +6 -15
  130. package/dist/validation/openRouterAlignment.d.ts.map +1 -1
  131. package/dist/validation/openRouterAlignment.js +9 -57
  132. package/dist/validation/openRouterAlignment.js.map +1 -1
  133. package/dist/validation/validateModelsCatalog.d.ts +3 -0
  134. package/dist/validation/validateModelsCatalog.d.ts.map +1 -0
  135. package/dist/validation/validateModelsCatalog.js +42 -0
  136. package/dist/validation/validateModelsCatalog.js.map +1 -0
  137. package/dist/validation/validateModelsProfilesJson.d.ts.map +1 -1
  138. package/dist/validation/validateModelsProfilesJson.js +38 -2
  139. package/dist/validation/validateModelsProfilesJson.js.map +1 -1
  140. package/dist/vendorPolicy.d.ts +20 -0
  141. package/dist/vendorPolicy.d.ts.map +1 -0
  142. package/dist/vendorPolicy.js +71 -0
  143. package/dist/vendorPolicy.js.map +1 -0
  144. package/package.json +12 -2
@@ -1,35 +1,50 @@
1
1
  import { buildResolvedProfile } from "./buildResolvedProfile.js";
2
2
  import { AIProfilesError } from "./errors.js";
3
3
  import { loadAIProfilesRegistryWithWarnings } from "./loader/loadAIProfilesRegistry.js";
4
+ import { loadModelsCatalogWithWarnings } from "./loader/loadModelsCatalog.js";
4
5
  import { matchProfileInput } from "./profileInputMatch.js";
6
+ import { pickProfileChoice } from "./vendorPolicy.js";
7
+ /**
8
+ * Resolve a profile primary key, alias, or shortcut to a concrete model and runtime config.
9
+ *
10
+ * `input` names **intent** (e.g. `balanced`, `cheapest`, `cost-sensitive`), not a vendor model id.
11
+ * Use `options.choice` to pick an alternative within the profile (e.g. `cheap` + `safer_provider`).
12
+ *
13
+ * @see README.md — “Why AI profiles”
14
+ */
5
15
  export async function resolveAIProfile(input, options = {}) {
6
- const { registry, warnings } = await loadAIProfilesRegistryWithWarnings({
7
- source: options.source,
8
- refresh: options.refresh,
9
- });
16
+ const [{ registry, warnings }, catalogResult] = await Promise.all([
17
+ loadAIProfilesRegistryWithWarnings({
18
+ source: options.source,
19
+ refresh: options.refresh,
20
+ }),
21
+ loadModelsCatalogWithWarnings({
22
+ source: options.source,
23
+ refresh: options.refresh,
24
+ }),
25
+ ]);
26
+ const loaderWarnings = [...warnings, ...catalogResult.warnings];
10
27
  const match = matchProfileInput(registry, input);
11
28
  if (!match) {
12
29
  throw new AIProfilesError("UNKNOWN_PROFILE", `Unknown AI profile, shortcut, or alias: ${input}`, { input });
13
30
  }
14
31
  let profileKey;
15
- let choiceKey;
32
+ let requestedChoiceKey;
16
33
  let matchedShortcut;
17
34
  switch (match.kind) {
18
35
  case "profile":
19
36
  profileKey = match.profileKey;
20
- choiceKey =
21
- options.choice ?? registry.profiles[profileKey].defaultChoice;
37
+ requestedChoiceKey = options.choice;
22
38
  matchedShortcut = undefined;
23
39
  break;
24
40
  case "shortcut":
25
41
  profileKey = match.profileKey;
26
- choiceKey = options.choice ?? match.shortcut.choice;
42
+ requestedChoiceKey = options.choice ?? match.shortcut.choice;
27
43
  matchedShortcut = match.shortcut;
28
44
  break;
29
45
  case "alias":
30
46
  profileKey = match.profileKey;
31
- choiceKey =
32
- options.choice ?? registry.profiles[profileKey].defaultChoice;
47
+ requestedChoiceKey = options.choice;
33
48
  matchedShortcut = undefined;
34
49
  break;
35
50
  }
@@ -37,15 +52,42 @@ export async function resolveAIProfile(input, options = {}) {
37
52
  if (!profile) {
38
53
  throw new AIProfilesError("UNKNOWN_PROFILE", `Unknown AI profile: ${profileKey}`, { input, profile: profileKey });
39
54
  }
40
- const finalChoiceKey = choiceKey ?? profile.defaultChoice;
41
- const choice = profile.choices[finalChoiceKey];
42
- if (!choice) {
43
- if (options.allowFallbackToDefaultChoice) {
44
- return resolveAIProfile(profileKey, {
45
- ...options,
46
- choice: profile.defaultChoice,
55
+ let finalChoiceKey;
56
+ let choice;
57
+ try {
58
+ const picked = pickProfileChoice(profile, {
59
+ choiceKey: requestedChoiceKey,
60
+ allowedProviders: options.allowedProviders,
61
+ preferLeadingVendors: options.preferLeadingVendors ?? true,
62
+ explicitChoiceRequested: options.choice !== undefined,
63
+ });
64
+ finalChoiceKey = picked.choiceKey;
65
+ choice = picked.choice;
66
+ }
67
+ catch (error) {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ if (message.includes("allowedProviders")) {
70
+ throw new AIProfilesError("NO_ALLOWED_VENDOR", message, {
71
+ input,
72
+ profile: profileKey,
73
+ allowedProviders: options.allowedProviders,
74
+ availableProviders: [
75
+ ...new Set(Object.values(profile.choices).map((c) => c.provider)),
76
+ ],
47
77
  });
48
78
  }
79
+ if (message.startsWith("Unknown choice")) {
80
+ if (options.allowFallbackToDefaultChoice) {
81
+ return resolveAIProfile(profileKey, {
82
+ ...options,
83
+ choice: profile.defaultChoice,
84
+ });
85
+ }
86
+ throw new AIProfilesError("UNKNOWN_CHOICE", message, { input, profile: profileKey, choice: requestedChoiceKey });
87
+ }
88
+ throw error;
89
+ }
90
+ if (!profile.choices[finalChoiceKey]) {
49
91
  throw new AIProfilesError("UNKNOWN_CHOICE", `Unknown choice '${finalChoiceKey}' for AI profile '${profileKey}'`, { input, profile: profileKey, choice: finalChoiceKey });
50
92
  }
51
93
  return buildResolvedProfile({
@@ -53,10 +95,12 @@ export async function resolveAIProfile(input, options = {}) {
53
95
  shortcutKey: match.kind === "shortcut" ? match.shortcutKey : undefined,
54
96
  profile,
55
97
  choice,
98
+ choiceKey: finalChoiceKey,
56
99
  shortcut: matchedShortcut,
57
100
  registry,
58
- loaderWarnings: warnings,
101
+ loaderWarnings,
59
102
  useOpenRouter: options.useOpenRouter,
103
+ catalog: catalogResult.catalog,
60
104
  });
61
105
  }
62
106
  //# sourceMappingURL=resolveAIProfile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveAIProfile.js","sourceRoot":"","sources":["../src/resolveAIProfile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolveAIProfile.js","sourceRoot":"","sources":["../src/resolveAIProfile.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { AIProfileBackend, AIProfileChoice, AIProvider } from "./types.js";
2
+ import { buildOpenRouterModelId } from "./modelIdentity.js";
2
3
  export type AIModelRoutingMode = "openrouter" | "direct";
3
4
  /** Reads `USE_OPENROUTER` from process env (loading `.env` once when unset). */
4
5
  export declare function readUseOpenRouterFromEnv(): boolean | undefined;
@@ -8,7 +9,7 @@ export declare function readUseOpenRouterFromEnv(): boolean | undefined;
8
9
  */
9
10
  export declare function resolveUseOpenRouter(explicit?: boolean): boolean;
10
11
  export declare function isRemoteProfileChoice(choice: AIProfileChoice): boolean;
11
- export declare function buildOpenRouterModelId(provider: string, modelId: string): string;
12
+ export { buildOpenRouterModelId };
12
13
  export interface AppliedModelRouting {
13
14
  provider: AIProvider;
14
15
  modelId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"resolveModelRouting.d.ts","sourceRoot":"","sources":["../src/resolveModelRouting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGhF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAyBzD,gFAAgF;AAChF,wBAAgB,wBAAwB,IAAI,OAAO,GAAG,SAAS,CAU9D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAMhE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAUtE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAOhF;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,OAAO,GACrB,mBAAmB,CAgBrB"}
1
+ {"version":3,"file":"resolveModelRouting.d.ts","sourceRoot":"","sources":["../src/resolveModelRouting.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,QAAQ,CAAC;AAyBzD,gFAAgF;AAChF,wBAAgB,wBAAwB,IAAI,OAAO,GAAG,SAAS,CAU9D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAMhE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAUtE;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,kBAAkB,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,gBAAgB,EACzB,aAAa,EAAE,OAAO,GACrB,mBAAmB,CAuBrB"}
@@ -1,5 +1,6 @@
1
1
  import { loadDotenv } from "@x12i/env";
2
- import { normalizeAnthropicVersionSlug } from "./validation/openRouterAlignment.js";
2
+ import { buildOpenRouterModelId } from "./modelIdentity.js";
3
+ import { buildModelInvocationFromChoice, getChoiceOpenRouterModelId, getChoiceVendorModelId, } from "./profileRegistryV2.js";
3
4
  let dotenvLoaded = false;
4
5
  function ensureDotenvLoaded() {
5
6
  if (!dotenvLoaded) {
@@ -45,25 +46,23 @@ export function isRemoteProfileChoice(choice) {
45
46
  }
46
47
  return true;
47
48
  }
48
- export function buildOpenRouterModelId(provider, modelId) {
49
- if (modelId.includes("/")) {
50
- return modelId;
51
- }
52
- const normalizedModel = normalizeAnthropicVersionSlug(modelId);
53
- return `${provider}/${normalizedModel}`;
54
- }
49
+ export { buildOpenRouterModelId };
55
50
  export function applyModelRouting(choice, backend, useOpenRouter) {
51
+ const vendorModelId = getChoiceVendorModelId(choice);
56
52
  if (!isRemoteProfileChoice(choice) || !useOpenRouter) {
57
53
  return {
58
54
  provider: choice.provider,
59
- modelId: choice.modelId,
55
+ modelId: vendorModelId,
60
56
  backend: useOpenRouter ? backend : backend === "openrouter" ? "custom" : backend,
61
57
  routing: "direct",
62
58
  };
63
59
  }
60
+ const openRouterModelId = getChoiceOpenRouterModelId(choice) ??
61
+ buildModelInvocationFromChoice(choice).openrouter?.modelId ??
62
+ buildOpenRouterModelId(choice.provider, vendorModelId);
64
63
  return {
65
64
  provider: "openrouter",
66
- modelId: buildOpenRouterModelId(choice.provider, choice.modelId),
65
+ modelId: openRouterModelId,
67
66
  backend: "openrouter",
68
67
  routing: "openrouter",
69
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"resolveModelRouting.js","sourceRoot":"","sources":["../src/resolveModelRouting.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolveModelRouting.js","sourceRoot":"","sources":["../src/resolveModelRouting.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,4 +1,14 @@
1
- export type AIProvider = "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "xai" | "local" | "custom" | "openrouter";
1
+ /**
2
+ * Registry types for {@link https://github.com/x12i/ai-profiles | @x12i/ai-profiles}.
3
+ *
4
+ * An **AI profile** is a capability contract (e.g. `cheap`, `deep`, `json`) — what kind of
5
+ * work is needed — not a specific model. Each profile has a **default choice** and optional
6
+ * **choices** (alternatives) that map intent to `provider`, `modelId`, pricing, and runtime
7
+ * defaults. Tasks should reference profiles (and optional choices), not vendor model names.
8
+ *
9
+ * @see README.md — “Why AI profiles” for the full design rationale.
10
+ */
11
+ export type AIProvider = "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "xai" | "local" | "custom" | "openrouter";
2
12
  export type InstructionTier = "default" | "cpu" | "reasoning";
3
13
  export type AIProfileBackend = "openrouter" | "llama-cpp" | "transformersjs" | "custom";
4
14
  export interface AIModelPricing {
@@ -31,27 +41,121 @@ export interface AIRuntimeDefaults {
31
41
  instructionTier?: InstructionTier;
32
42
  backend?: AIProfileBackend;
33
43
  }
44
+ /**
45
+ * One implementation option within a profile (e.g. `default`, `cost_floor`, `openai_deep`).
46
+ * Choices let the same profile intent use different providers, cost/quality trade-offs, or
47
+ * capabilities (long context, batch execution) without changing caller code.
48
+ */
49
+ export interface ProfileChoiceApi {
50
+ defaultTransport: "openrouter" | "direct";
51
+ vendorModelId: string;
52
+ openRouterModelId?: string | null;
53
+ }
54
+ export interface ProfileChoicePricingV2 {
55
+ billingModel: "token" | "self_hosted";
56
+ currency: "USD";
57
+ unit: "1M_tokens";
58
+ priceStatus?: "standard" | "promotional" | "estimated";
59
+ notes?: string;
60
+ standard?: {
61
+ input?: number;
62
+ output?: number;
63
+ cachedInput?: number;
64
+ };
65
+ batch?: {
66
+ input?: number;
67
+ output?: number;
68
+ };
69
+ cache?: {
70
+ write5m?: number;
71
+ write1h?: number;
72
+ hit?: number;
73
+ write?: number;
74
+ };
75
+ futureStandard?: {
76
+ input?: number;
77
+ output?: number;
78
+ validUntil?: string;
79
+ notes?: string;
80
+ };
81
+ }
82
+ export interface ProfileChoiceVerification {
83
+ lastVerifiedAt?: string;
84
+ sourceRefs?: string[];
85
+ }
86
+ export interface ProfileChoiceLimits {
87
+ contextWindow?: number;
88
+ maxOutputTokens?: number;
89
+ }
90
+ export type ModelAvailabilityStatus = "verified" | "predicted";
91
+ export type DeploymentType = "proprietary" | "openWeightsHosted" | "selfHosted";
92
+ export interface ProfileRequiredCapabilities {
93
+ reasoning?: "minimal" | "low" | "medium" | "high" | "max";
94
+ coding?: boolean;
95
+ context?: "standard" | "large" | "xlarge";
96
+ cost?: "low" | "medium" | "high";
97
+ speed?: "high";
98
+ latency?: "low";
99
+ quality?: "high" | "premium";
100
+ structuredOutput?: boolean;
101
+ supportsJsonSchema?: boolean;
102
+ supportsVision?: boolean;
103
+ supportsTools?: boolean;
104
+ }
105
+ export interface ModelCapabilitiesSnapshot {
106
+ contextWindow?: number;
107
+ maxOutputTokens?: number;
108
+ supportsVision?: boolean;
109
+ supportsTools?: boolean;
110
+ supportsReasoning?: boolean;
111
+ supportsJsonSchema?: boolean;
112
+ supportsCaching?: boolean;
113
+ supportsBatch?: boolean;
114
+ supportsStreaming?: boolean;
115
+ }
34
116
  export interface AIProfileChoice {
35
117
  choice: string;
36
118
  displayName: string;
37
119
  description: string;
120
+ /** Canonical vendor-native model identifier. */
38
121
  provider: AIProvider;
39
122
  modelId: string;
40
- pricing?: AIModelPricing;
123
+ /** Whether the SKU is production-stable or a forward-looking placeholder. */
124
+ modelStatus?: ModelAvailabilityStatus;
125
+ /** How the model is operated when not a proprietary vendor API. */
126
+ deploymentType?: DeploymentType;
127
+ /** Transport mapping (v2 registry). */
128
+ api?: ProfileChoiceApi;
129
+ /** Legacy flat pricing and/or v2 nested pricing blocks. */
130
+ pricing?: AIModelPricing | ProfileChoicePricingV2;
41
131
  runtime?: AIRuntimeDefaults;
42
132
  reason?: string;
43
133
  status?: "active" | "experimental" | "deprecated";
134
+ verification?: ProfileChoiceVerification;
135
+ limits?: ProfileChoiceLimits;
44
136
  metadata?: Record<string, unknown>;
45
137
  }
138
+ /**
139
+ * Capability contract for a class of AI work (cost, speed, reasoning, structured output,
140
+ * agentic tools, research, local inference). Resolved via {@link resolveAIProfile}.
141
+ */
46
142
  export interface AIProfileDefinition {
47
143
  profile: string;
48
144
  displayName: string;
49
145
  description: string;
146
+ /** Grouping for filtering (`cost`, `speed`, `standard`, `reasoning`, `output`, `agentic`, `research`, `local`). */
50
147
  category: string;
51
148
  /** Many alternate names for this profile (see `matchProfileInput`). */
52
149
  aliases?: string[];
53
150
  defaultChoice: string;
54
151
  choices: Record<string, AIProfileChoice>;
152
+ /** Intent contract for dynamic model selection (Optimixer). */
153
+ requiredCapabilities?: ProfileRequiredCapabilities;
154
+ /** Profile-level deployment strategy (e.g. open weights). */
155
+ deploymentType?: DeploymentType;
156
+ /** Deterministic failover order when trimming vendors or choices. */
157
+ fallbackChoiceOrder?: string[];
158
+ intendedUseCases?: string[];
55
159
  status?: "active" | "experimental" | "deprecated";
56
160
  runtime?: AIRuntimeDefaults;
57
161
  metadata?: Record<string, unknown>;
@@ -61,11 +165,25 @@ export interface AIProfileShortcut {
61
165
  choice?: string;
62
166
  description?: string;
63
167
  }
168
+ export type ModelsProfilesSchemaId = "x12i.ai-profiles.models-profiles" | "x12i.ai-profiles.model-registry.v2" | "x12i.ai-profiles.model-registry.v3";
64
169
  export interface ModelsProfilesJson {
65
- schema: "x12i.ai-profiles.models-profiles";
170
+ schema: ModelsProfilesSchemaId;
171
+ registryId?: string;
66
172
  /** Optional label in source JSON; not used for compatibility or selection logic. */
67
173
  version?: string;
68
174
  generatedAt?: string;
175
+ lastVerifiedAt?: string;
176
+ namingConvention?: string;
177
+ semantics?: Record<string, string>;
178
+ sourceCatalog?: {
179
+ providers: Array<{
180
+ id: string;
181
+ docsUrl?: string;
182
+ }>;
183
+ modelsCatalogUrl?: string;
184
+ /** @deprecated Use modelsCatalogUrl */
185
+ openRouterCatalogUrl?: string;
186
+ };
69
187
  currency: "USD";
70
188
  pricingUnit: "1M_tokens";
71
189
  profiles: Record<string, AIProfileDefinition>;
@@ -111,9 +229,149 @@ export interface AIShortcutSummary {
111
229
  description?: string;
112
230
  }
113
231
  export interface AIProfileWarning {
114
- code: "USING_BUNDLED_FALLBACK" | "PROFILE_DEPRECATED" | "CHOICE_DEPRECATED" | "PRICING_MISSING" | "REMOTE_REFRESH_FAILED_USING_CACHE";
232
+ code: "USING_BUNDLED_FALLBACK" | "PROFILE_DEPRECATED" | "CHOICE_DEPRECATED" | "PRICING_MISSING" | "MODEL_PREDICTED" | "PRICING_FROM_CATALOG" | "REMOTE_REFRESH_FAILED_USING_CACHE" | "OPENROUTER_UNAVAILABLE";
115
233
  message: string;
116
234
  }
235
+ export interface ModelInvocationEndpoint {
236
+ provider: AIProvider;
237
+ modelId: string;
238
+ }
239
+ export interface ModelInvocation {
240
+ direct: ModelInvocationEndpoint;
241
+ openrouter: ModelInvocationEndpoint | null;
242
+ }
243
+ export type ModelRegistryKind = "linked" | "openrouter-only" | "local-only" | "faulty";
244
+ export type ModelLinkageStatus = "matched" | "faulty" | "skipped" | "catalog-miss";
245
+ export interface ModelRegistryLinkage {
246
+ status: ModelLinkageStatus;
247
+ openRouterCatalogId?: string;
248
+ canonicalSlug?: string;
249
+ matchMethod?: string;
250
+ exemptReason?: string;
251
+ }
252
+ export interface ModelRegistryEntry {
253
+ registryKey: string;
254
+ kind: ModelRegistryKind;
255
+ vendor: ModelInvocationEndpoint;
256
+ invocation: ModelInvocation;
257
+ linkage: ModelRegistryLinkage;
258
+ usage: {
259
+ profileChoices: Array<{
260
+ profile: string;
261
+ choice: string;
262
+ }>;
263
+ };
264
+ }
265
+ export interface ModelsRegistryJson {
266
+ schema: "x12i.ai-profiles.models-registry";
267
+ version?: string;
268
+ generatedAt?: string;
269
+ inputs?: {
270
+ openRouterCatalog?: {
271
+ schema?: string;
272
+ version?: string;
273
+ generatedAt?: string;
274
+ modelCount?: number;
275
+ };
276
+ modelsProfiles?: {
277
+ version?: string;
278
+ generatedAt?: string;
279
+ choiceCount?: number;
280
+ };
281
+ };
282
+ models: Record<string, ModelRegistryEntry>;
283
+ }
284
+ export interface CatalogOpenRouterPricing {
285
+ input?: number;
286
+ output?: number;
287
+ cachedInput?: number;
288
+ cacheWrite?: number;
289
+ batchInput?: number;
290
+ batchOutput?: number;
291
+ imageInput?: number;
292
+ audioInput?: number;
293
+ internalReasoning?: number;
294
+ webSearchPerRequest?: number;
295
+ }
296
+ export interface CatalogOpenRouterCapabilities {
297
+ reasoning?: boolean;
298
+ toolCalling?: boolean;
299
+ structuredOutputs?: boolean;
300
+ imageGeneration?: boolean;
301
+ }
302
+ export interface CatalogDirectSlice {
303
+ provider: AIProvider;
304
+ modelId: string;
305
+ /**
306
+ * OpenRouter slug prefix when `provider` is `custom` (e.g. `qwen` for `qwen/qwen3.7-max`).
307
+ * Not used for API calls — documents the upstream vendor namespace.
308
+ */
309
+ vendorNamespace?: string;
310
+ }
311
+ export interface CatalogOpenRouterSlice {
312
+ provider: "openrouter";
313
+ modelId: string;
314
+ canonicalSlug?: string;
315
+ status?: string;
316
+ modalities?: {
317
+ input?: string[];
318
+ output?: string[];
319
+ };
320
+ contextWindow?: number;
321
+ maxCompletionTokens?: number;
322
+ knowledgeCutoff?: string;
323
+ pricing?: CatalogOpenRouterPricing;
324
+ capabilities?: CatalogOpenRouterCapabilities;
325
+ }
326
+ /**
327
+ * Unified catalog model: two explicit call shapes (never conflate them).
328
+ * - `direct` — vendor-native / direct API identity
329
+ * - `openrouter` — OpenRouter transport (`provider` is always `openrouter`)
330
+ */
331
+ export interface CatalogModelEntry {
332
+ direct: CatalogDirectSlice;
333
+ openrouter: CatalogOpenRouterSlice;
334
+ displayName?: string;
335
+ family?: string;
336
+ status?: string;
337
+ modalities?: CatalogOpenRouterSlice["modalities"];
338
+ contextWindow?: number;
339
+ maxCompletionTokens?: number;
340
+ knowledgeCutoff?: string;
341
+ }
342
+ export interface ModelsCatalogJson {
343
+ schema: "x12i.ai-profiles.models-catalog";
344
+ version?: string;
345
+ generatedAt?: string;
346
+ currency: "USD";
347
+ pricingUnit: "1M_tokens";
348
+ sources: {
349
+ openrouter: {
350
+ catalogUrl: string;
351
+ pricingUrl?: string;
352
+ verifiedAt?: string;
353
+ normalization?: string;
354
+ };
355
+ };
356
+ notes?: string[];
357
+ models: CatalogModelEntry[];
358
+ }
359
+ /** @deprecated Use {@link ModelsCatalogJson} */
360
+ export type OpenRouterModelsCatalogJson = ModelsCatalogJson;
361
+ export interface ProfileVendorCoverageResult {
362
+ profile: string;
363
+ leadingVendorsPresent: AIProvider[];
364
+ leadingVendorsMissing: AIProvider[];
365
+ nonLeadingChoices: Array<{
366
+ choice: string;
367
+ provider: AIProvider;
368
+ }>;
369
+ }
370
+ export interface ValidateProfileVendorCoverageResult {
371
+ ok: boolean;
372
+ profiles: ProfileVendorCoverageResult[];
373
+ }
374
+ /** Materialized profile + choice: model, pricing, runtime, and routing after registry resolution. */
117
375
  export interface ResolvedAIProfile {
118
376
  input: string;
119
377
  profile: string;
@@ -133,6 +391,12 @@ export interface ResolvedAIProfile {
133
391
  currency: "USD";
134
392
  unit: "1M_tokens";
135
393
  };
394
+ /** Echo of choice modelStatus when present. */
395
+ modelStatus?: ModelAvailabilityStatus;
396
+ limits?: ProfileChoiceLimits;
397
+ capabilities?: ModelCapabilitiesSnapshot;
398
+ /** Profile intent contract (from registry definition). */
399
+ requiredCapabilities?: ProfileRequiredCapabilities;
136
400
  runtime: Required<AIRuntimeDefaults>;
137
401
  metadata?: Record<string, unknown>;
138
402
  reason?: string;
@@ -146,6 +410,8 @@ export interface ResolvedAIProfile {
146
410
  profile: string;
147
411
  choice?: string;
148
412
  };
413
+ /** Direct and OpenRouter call shapes for the resolved choice. */
414
+ invocation: ModelInvocation;
149
415
  warnings?: AIProfileWarning[];
150
416
  }
151
417
  export interface ListAIProfilesOptions {
@@ -168,6 +434,10 @@ export interface ResolveAIProfileOptions {
168
434
  * `0`/`false` → direct). Azure and AWS routing are not supported yet.
169
435
  */
170
436
  useOpenRouter?: boolean;
437
+ /** Restrict resolution to these vendors; auto-picks when default is outside the set. */
438
+ allowedProviders?: AIProvider[];
439
+ /** When auto-picking, rank {@link LEADING_VENDORS} ahead of other providers (default true). */
440
+ preferLeadingVendors?: boolean;
171
441
  }
172
442
  export interface LoadRegistryOptions {
173
443
  source?: RegistrySourceMode;
@@ -177,4 +447,69 @@ export interface LoadRegistryResult {
177
447
  registry: AIProfilesRegistry;
178
448
  warnings: AIProfileWarning[];
179
449
  }
450
+ export interface ProfileStatisticsFilter {
451
+ includeDeprecated?: boolean;
452
+ includeExperimental?: boolean;
453
+ category?: string;
454
+ }
455
+ export interface GetAIRegistryStatisticsOptions extends LoadRegistryOptions {
456
+ /** Include models catalog counts (default true). */
457
+ includeCatalog?: boolean;
458
+ /** Include profile↔catalog linkage counts (default true). */
459
+ includeLinkage?: boolean;
460
+ includeDeprecated?: boolean;
461
+ includeExperimental?: boolean;
462
+ category?: string;
463
+ }
464
+ export interface AIRegistryStatistics {
465
+ schema: "x12i.ai-profiles.registry-statistics";
466
+ generatedAt: string;
467
+ sources: {
468
+ profiles: "remote" | "bundled";
469
+ catalog?: "remote" | "bundled";
470
+ };
471
+ registry: {
472
+ version?: string;
473
+ loadedAt: string;
474
+ currency: "USD";
475
+ pricingUnit: "1M_tokens";
476
+ };
477
+ profiles: {
478
+ total: number;
479
+ choices: number;
480
+ aliases: number;
481
+ uniqueProviders: number;
482
+ providers: AIProvider[];
483
+ uniqueModelKeys: number;
484
+ uniqueVendorModelIds: number;
485
+ byStatus: Record<string, number>;
486
+ byCategory: Record<string, number>;
487
+ categories: string[];
488
+ averageChoicesPerProfile: number;
489
+ };
490
+ shortcuts: {
491
+ total: number;
492
+ };
493
+ catalog?: {
494
+ totalModels: number;
495
+ uniqueDirectProviders: number;
496
+ directProviders: string[];
497
+ active: number;
498
+ deprecated: number;
499
+ withPricing: number;
500
+ withReasoningCapability: number;
501
+ catalogVersion?: string;
502
+ generatedAt?: string;
503
+ };
504
+ linkage?: {
505
+ registryEntries: number;
506
+ profileChoiceReferences: number;
507
+ byLinkageStatus: Record<string, number>;
508
+ byKind: Record<string, number>;
509
+ matched: number;
510
+ faulty: number;
511
+ catalogMiss: number;
512
+ skipped: number;
513
+ };
514
+ }
180
515
  //# sourceMappingURL=types.d.ts.map