@game-infra/ai-schemas 0.3.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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/dist/catalog.d.ts +137 -0
  4. package/dist/catalog.d.ts.map +1 -0
  5. package/dist/catalog.js +209 -0
  6. package/dist/catalog.js.map +1 -0
  7. package/dist/contracts.d.ts +1073 -0
  8. package/dist/contracts.d.ts.map +1 -0
  9. package/dist/contracts.js +243 -0
  10. package/dist/contracts.js.map +1 -0
  11. package/dist/featuredModels.d.ts +95 -0
  12. package/dist/featuredModels.d.ts.map +1 -0
  13. package/dist/featuredModels.js +189 -0
  14. package/dist/featuredModels.js.map +1 -0
  15. package/dist/index.d.ts +35 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +39 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/inference.d.ts +323 -0
  20. package/dist/inference.d.ts.map +1 -0
  21. package/dist/inference.js +162 -0
  22. package/dist/inference.js.map +1 -0
  23. package/dist/preference.d.ts +49 -0
  24. package/dist/preference.d.ts.map +1 -0
  25. package/dist/preference.js +74 -0
  26. package/dist/preference.js.map +1 -0
  27. package/dist/preset.d.ts +422 -0
  28. package/dist/preset.d.ts.map +1 -0
  29. package/dist/preset.js +212 -0
  30. package/dist/preset.js.map +1 -0
  31. package/dist/provider.d.ts +487 -0
  32. package/dist/provider.d.ts.map +1 -0
  33. package/dist/provider.js +224 -0
  34. package/dist/provider.js.map +1 -0
  35. package/dist/schemaRegistry.d.ts +71 -0
  36. package/dist/schemaRegistry.d.ts.map +1 -0
  37. package/dist/schemaRegistry.js +35 -0
  38. package/dist/schemaRegistry.js.map +1 -0
  39. package/dist/service.d.ts +143 -0
  40. package/dist/service.d.ts.map +1 -0
  41. package/dist/service.js +103 -0
  42. package/dist/service.js.map +1 -0
  43. package/dist/subscription.d.ts +275 -0
  44. package/dist/subscription.d.ts.map +1 -0
  45. package/dist/subscription.js +198 -0
  46. package/dist/subscription.js.map +1 -0
  47. package/package.json +50 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Savin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # @game-infra/ai-schemas
2
+
3
+ The [`ai-service`](../../../services/ai-service/README.md) API contract: how a
4
+ provider, a coding-plan subscription and a routing preset are described, what an
5
+ inference request and its answer look like, and the endpoint definitions that
6
+ carry them.
7
+
8
+ Published to npm, like the other `*-schemas` packages, because a game repo
9
+ calling ai-service needs the contract without checking out the service.
10
+
11
+ ## Install
12
+
13
+ ```jsonc
14
+ // package.json, in a sibling checkout
15
+ {
16
+ "dependencies": {
17
+ "@game-infra/ai-schemas": "link:../game-infra/packages/schemas/ai-schemas",
18
+ },
19
+ }
20
+ ```
21
+
22
+ Or from the registry: `pnpm add @game-infra/ai-schemas`.
23
+
24
+ ## Usage
25
+
26
+ Contracts carry their own method, path and schemas, so a client never restates a
27
+ path:
28
+
29
+ ```ts
30
+ import { aiGenerateTextContract, aiPresetRoutePlanContract } from "@game-infra/ai-schemas";
31
+ import { sendByApiContract } from "@toad-contracts/frontend-http-client";
32
+
33
+ const { result } = await sendByApiContract(client, aiGenerateTextContract, {
34
+ body: {
35
+ preset: "narrative",
36
+ messages: [{ role: "user", content: "A rusted door in a flooded corridor." }],
37
+ },
38
+ });
39
+
40
+ // Every answer reports which route served it, which failed on the way, and
41
+ // which were never tried.
42
+ result.body.route?.served.providerId;
43
+ ```
44
+
45
+ ```ts
46
+ aiPresetRoutePlanContract.pathResolver({ slug: "narrative" }); // '/presets/narrative/route'
47
+ ```
48
+
49
+ ## What is in here
50
+
51
+ | Module | What it describes |
52
+ | ------------------- | ------------------------------------------------------------------- |
53
+ | `provider.ts` | Providers, their tiers, dialects and model routes |
54
+ | `subscription.ts` | Coding-plan credentials and the vendor profiles that reach them |
55
+ | `preset.ts` | Routing presets, route candidates, and why a route was excluded |
56
+ | `inference.ts` | Messages, the three inference requests, and what an answer reports |
57
+ | `schemaRegistry.ts` | How a registered response schema is published |
58
+ | `catalog.ts` | Provider blueprints, and model discovery |
59
+ | `featuredModels.ts` | The models surfaced by name, and the id each is reached under |
60
+ | `preference.ts` | The two ordering folds the service and the console must agree about |
61
+ | `contracts.ts` | Every endpoint definition |
62
+
63
+ ## The two tables worth knowing
64
+
65
+ **Tiers** (`PROVIDER_TIERS`) are `subscription`, `direct`, `local`, `umbrella`,
66
+ in the order they are tried by default. The axis is who pays: a coding plan is
67
+ flat-rate quota already bought, a direct key is metered by the vendor that
68
+ trained the model, a local server costs whatever the hardware costs, and a
69
+ gateway resells at a markup. Expressing preference over tiers rather than over
70
+ provider ids is what lets a deployment state its policy once instead of per
71
+ model.
72
+
73
+ **Subscription vendors** (`SUBSCRIPTION_VENDOR_PROFILES`) carry each plan's
74
+ dialect, endpoint and auth scheme. Four of the five speak the Anthropic Messages
75
+ dialect, because Claude Code is an Anthropic-API client and Z.ai, Moonshot and
76
+ DeepSeek each publish an Anthropic-compatible endpoint precisely so it can be
77
+ pointed at them; `codex` is the exception and speaks the OpenAI Responses shape.
78
+ Every field is a default rather than a constant, and a stored subscription can
79
+ override any of them: a vendor moving an endpoint should be a console edit
80
+ rather than a release of this package.
81
+
82
+ ## Surfaced models
83
+
84
+ `FEATURED_MODELS` names the handful of models worth reaching for a kind of work,
85
+ and the id a gateway serves each under. Today that is creative writing —
86
+ narration, dialogue, in-world prose — and all of it is reached through
87
+ OpenRouter, because none of those four families is worth a direct account on its
88
+ own and one key already reaches all of them.
89
+
90
+ ```ts
91
+ import { featuredModelRoutes, featuredModelsFor } from "@game-infra/ai-schemas";
92
+
93
+ featuredModelsFor("creative-writing").filter((model) => model.flagship);
94
+ // aion, euryale, mistral-large, hermes
95
+
96
+ featuredModelRoutes("openrouter");
97
+ // [{ model: 'aion', providerModelId: 'aion-labs/aion-3.0' }, …] — save these on
98
+ // the provider and a preset naming `aion` plans like any other model.
99
+ ```
100
+
101
+ The list is advisory and reaches routing through exactly one door: an operator
102
+ saves those routes onto a provider. Until then a surfaced model is a
103
+ recommendation with an id attached, which is why nothing in the planner reads
104
+ this table. Consumers should read it from ai-service's `GET /catalog` rather
105
+ than importing it, so a repinned id arrives without a release.
106
+
107
+ ## Extension points
108
+
109
+ - **`orderedTierPreference` / `orderedProviderPreference`** are exported because
110
+ the service and the console must not disagree about them: the preset editor
111
+ shows the resulting order as somebody drags rows, and a second copy of the
112
+ rule in Vue is a copy that eventually differs from the one a request takes.
113
+ Both **reorder and never filter**, so a preference stored before a tier
114
+ existed cannot silently make that tier unreachable.
115
+ - **`SUBSCRIPTION_PASSWORD_HEADER`** names the header a request carries a
116
+ subscription unlock in. A header rather than a body field, for the same reason
117
+ the bearer token is one, and exported so a browser client can list it in its
118
+ CORS allowance — without which a preflight drops it and every subscription
119
+ route silently falls through to a metered provider.
120
+
121
+ ## What is deliberately not here
122
+
123
+ **A model catalog.** A list of every model id baked into a released package is
124
+ wrong within weeks, and wrong in the direction that hurts: it advertises models
125
+ a deployment cannot actually reach, so the mistake surfaces as a failed request
126
+ rather than as an empty picker. Model routes come from the provider itself,
127
+ through ai-service's discovery endpoint, or from an operator typing them in.
128
+ `PROVIDER_BLUEPRINTS` holds only the parts that do not go stale: which tier a
129
+ provider belongs to, which dialect it speaks, and where it lives.
130
+
131
+ `FEATURED_MODELS` is not that catalog and does not reintroduce it. It claims no
132
+ inventory — it answers "which model should write this", which no `/models` call
133
+ answers and no gateway's refresh changes — and it routes nothing until an
134
+ operator saves it onto a provider.
135
+
136
+ Three of the four dialects are HTTP shapes. `workers-ai` is the exception and
137
+ names a transport rather than a wire format: Cloudflare Workers AI is reached
138
+ through the consuming Worker's own `AI` binding, so a provider on that dialect
139
+ has no base URL and no credential — the platform authorises the call.
140
+
141
+ ## Dependencies
142
+
143
+ `@game-infra/api-schemas-core` (the shared response wrappers),
144
+ `@toad-contracts/core` and `@toad-contracts/valibot`. `valibot` is a peer.
145
+
146
+ ## Consumers
147
+
148
+ `services/ai-service`, `apps/ai-console`, and any game-repo service calling
149
+ ai-service.
@@ -0,0 +1,137 @@
1
+ import { type InferOutput } from "valibot";
2
+ import { type CredentialKind, type ProviderDialect, type ProviderTier } from "./provider.js";
3
+ /**
4
+ * The out-of-the-box provider blueprints.
5
+ *
6
+ * A blueprint is the part of a provider nobody should have to look up: which
7
+ * tier it belongs to, which dialect it speaks, and where it lives. It is not a
8
+ * configured provider and holds no credential; the console offers these as
9
+ * starting points and writes a real provider record from the one an operator
10
+ * picks, at which point every field becomes editable.
11
+ *
12
+ * What is deliberately NOT here is a list of models. A model list baked into a
13
+ * released package is wrong within weeks and wrong in the direction that
14
+ * matters, because it advertises models a deployment cannot actually reach.
15
+ * Model routes come from the provider itself, through the discovery endpoint,
16
+ * or from an operator typing them in.
17
+ *
18
+ * The surfaced models in `featuredModels.ts` are not that list and do not
19
+ * contradict this one. They claim no inventory: they name the handful of models
20
+ * worth reaching for a kind of work, which is a judgement no `/models` call
21
+ * answers, and they become routable only once an operator saves them onto a
22
+ * provider.
23
+ */
24
+ export interface ProviderBlueprint {
25
+ /** The `providerId` a created provider gets by default. */
26
+ providerId: string;
27
+ /** Display name. */
28
+ name: string;
29
+ tier: ProviderTier;
30
+ dialect: ProviderDialect;
31
+ credentialKind: CredentialKind;
32
+ /**
33
+ * Where it lives. Absent for the two first-party dialects, whose SDKs carry
34
+ * their own host, and for the self-hosted gateways and local runners, which
35
+ * have no public instance to point at and resolve only once an operator says
36
+ * where theirs is.
37
+ */
38
+ baseUrl?: string;
39
+ /** One line on what this provider is for, shown under its name in the picker. */
40
+ note: string;
41
+ }
42
+ /**
43
+ * The blueprints, in the order the console offers them: the model vendors
44
+ * first, then the gateways that resell them, then the servers an operator runs.
45
+ */
46
+ export declare const PROVIDER_BLUEPRINTS: readonly ProviderBlueprint[];
47
+ /** A blueprint, on the wire. */
48
+ export declare const ProviderBlueprintSchema: import("valibot").ObjectSchema<{
49
+ readonly providerId: import("valibot").StringSchema<undefined>;
50
+ readonly name: import("valibot").StringSchema<undefined>;
51
+ readonly tier: import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>;
52
+ readonly dialect: import("valibot").PicklistSchema<readonly ["openai", "anthropic", "openai-compatible", "workers-ai"], undefined>;
53
+ readonly credentialKind: import("valibot").PicklistSchema<readonly ["api-key", "subscription", "none"], undefined>;
54
+ readonly baseUrl: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
55
+ readonly note: import("valibot").StringSchema<undefined>;
56
+ }, undefined>;
57
+ /** A subscription vendor the console can offer, with what it takes to store one. */
58
+ export declare const SubscriptionVendorOptionSchema: import("valibot").ObjectSchema<{
59
+ readonly vendor: import("valibot").StringSchema<undefined>;
60
+ readonly label: import("valibot").StringSchema<undefined>;
61
+ readonly baseUrl: import("valibot").StringSchema<undefined>;
62
+ readonly dialect: import("valibot").StringSchema<undefined>;
63
+ /** Where the credential goes: `bearer` or `api-key`. */
64
+ readonly authScheme: import("valibot").StringSchema<undefined>;
65
+ /** Whether the vendor licenses the plan to one named individual. */
66
+ readonly individualOnly: import("valibot").BooleanSchema<undefined>;
67
+ }, undefined>;
68
+ /**
69
+ * Everything the console needs to render its "add a provider" screens without
70
+ * restating this package's tables in Vue.
71
+ */
72
+ export declare const CatalogResponseSchema: import("valibot").ObjectSchema<{
73
+ readonly success: import("valibot").BooleanSchema<undefined>;
74
+ readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
75
+ } & {
76
+ providers: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
77
+ readonly providerId: import("valibot").StringSchema<undefined>;
78
+ readonly name: import("valibot").StringSchema<undefined>;
79
+ readonly tier: import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>;
80
+ readonly dialect: import("valibot").PicklistSchema<readonly ["openai", "anthropic", "openai-compatible", "workers-ai"], undefined>;
81
+ readonly credentialKind: import("valibot").PicklistSchema<readonly ["api-key", "subscription", "none"], undefined>;
82
+ readonly baseUrl: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
83
+ readonly note: import("valibot").StringSchema<undefined>;
84
+ }, undefined>, undefined>, undefined>;
85
+ subscriptionVendors: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
86
+ readonly vendor: import("valibot").StringSchema<undefined>;
87
+ readonly label: import("valibot").StringSchema<undefined>;
88
+ readonly baseUrl: import("valibot").StringSchema<undefined>;
89
+ readonly dialect: import("valibot").StringSchema<undefined>;
90
+ /** Where the credential goes: `bearer` or `api-key`. */
91
+ readonly authScheme: import("valibot").StringSchema<undefined>;
92
+ /** Whether the vendor licenses the plan to one named individual. */
93
+ readonly individualOnly: import("valibot").BooleanSchema<undefined>;
94
+ }, undefined>, undefined>, undefined>;
95
+ tiers: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>, undefined>, undefined>;
96
+ /** The built-in tier order, so the preset editor can show what "default" means. */
97
+ defaultTierPreference: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>, undefined>, undefined>;
98
+ /**
99
+ * The models this deployment surfaces by name, with the id each is reached
100
+ * under. Served rather than imported for the same reason the blueprints are:
101
+ * a consumer built against an older contract package would otherwise offer a
102
+ * model this service has since repinned, and the mistake would surface as a
103
+ * request that stopped answering.
104
+ */
105
+ featuredModels: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").ObjectSchema<{
106
+ readonly model: import("valibot").StringSchema<undefined>;
107
+ readonly label: import("valibot").StringSchema<undefined>;
108
+ readonly purpose: import("valibot").PicklistSchema<readonly ["creative-writing"], undefined>;
109
+ readonly providerId: import("valibot").StringSchema<undefined>;
110
+ readonly providerModelId: import("valibot").StringSchema<undefined>;
111
+ readonly flagship: import("valibot").BooleanSchema<undefined>;
112
+ readonly note: import("valibot").StringSchema<undefined>;
113
+ }, undefined>, undefined>, undefined>;
114
+ }, undefined>;
115
+ export type CatalogResponse = InferOutput<typeof CatalogResponseSchema>;
116
+ /**
117
+ * Model ids a provider says it serves.
118
+ *
119
+ * Read from the provider, never from a table here: an operator adding a gateway
120
+ * wants the models that gateway has today, and the endpoint that answers that
121
+ * question is the gateway's own. A provider whose dialect has no such endpoint
122
+ * reports `supported: false` rather than an empty list, because "this provider
123
+ * serves nothing" and "there is no way to ask" are different facts and only one
124
+ * of them means the operator should type the ids in by hand.
125
+ */
126
+ export declare const DiscoveredModelsResponseSchema: import("valibot").ObjectSchema<{
127
+ readonly success: import("valibot").BooleanSchema<undefined>;
128
+ readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
129
+ } & {
130
+ providerId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
131
+ supported: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
132
+ models: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
133
+ /** Why discovery could not answer, when it could not. */
134
+ failure: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
135
+ }, undefined>;
136
+ export type DiscoveredModelsResponse = InferOutput<typeof DiscoveredModelsResponseSchema>;
137
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,WAAW,EAA4C,MAAM,SAAS,CAAC;AAErF,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,eAAe,EAEpB,KAAK,YAAY,EAGlB,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,iBAAiB;IAChC,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,cAAc,EAAE,cAAc,CAAC;IAC/B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,iBAAiB,EAgJ3D,CAAC;AAEF,gCAAgC;AAChC,eAAO,MAAM,uBAAuB;;;;;;;;aAQlC,CAAC;AAEH,oFAAoF;AACpF,eAAO,MAAM,8BAA8B;;;;;IAKzC,wDAAwD;;IAExD,oEAAoE;;aAEpE,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;QAVhC,wDAAwD;;QAExD,oEAAoE;;;;IAYpE,mFAAmF;;IAEnF;;;;;;OAMG;;;;;;;;;;aAEH,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAExE;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B;;;;;;;IAIzC,yDAAyD;;aAEzD,CAAC;AAEH,MAAM,MAAM,wBAAwB,GAAG,WAAW,CAAC,OAAO,8BAA8B,CAAC,CAAC"}
@@ -0,0 +1,209 @@
1
+ import { createSuccessResponseSchema } from "@game-infra/api-schemas-core";
2
+ import { array, boolean, object, optional, string } from "valibot";
3
+ import { FeaturedModelSchema } from "./featuredModels.js";
4
+ import { ProviderDialectSchema, CredentialKindSchema, ProviderTierSchema, } from "./provider.js";
5
+ /**
6
+ * The blueprints, in the order the console offers them: the model vendors
7
+ * first, then the gateways that resell them, then the servers an operator runs.
8
+ */
9
+ export const PROVIDER_BLUEPRINTS = [
10
+ {
11
+ providerId: "openai",
12
+ name: "OpenAI",
13
+ tier: "direct",
14
+ dialect: "openai",
15
+ credentialKind: "api-key",
16
+ note: "OpenAI's own API. Native structured outputs.",
17
+ },
18
+ {
19
+ providerId: "anthropic",
20
+ name: "Anthropic",
21
+ tier: "direct",
22
+ dialect: "anthropic",
23
+ credentialKind: "api-key",
24
+ note: "Anthropic's own API. Native tool-schema structured outputs and prompt caching.",
25
+ },
26
+ {
27
+ providerId: "google",
28
+ name: "Google Gemini",
29
+ tier: "direct",
30
+ dialect: "openai-compatible",
31
+ credentialKind: "api-key",
32
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
33
+ note: "Gemini through Google's OpenAI-compatible endpoint.",
34
+ },
35
+ {
36
+ providerId: "mistral",
37
+ name: "Mistral",
38
+ tier: "direct",
39
+ dialect: "openai-compatible",
40
+ credentialKind: "api-key",
41
+ baseUrl: "https://api.mistral.ai/v1",
42
+ note: "Mistral's own API.",
43
+ },
44
+ {
45
+ providerId: "deepseek",
46
+ name: "DeepSeek",
47
+ tier: "direct",
48
+ dialect: "openai-compatible",
49
+ credentialKind: "api-key",
50
+ baseUrl: "https://api.deepseek.com",
51
+ note: "DeepSeek's own API.",
52
+ },
53
+ {
54
+ providerId: "qwen",
55
+ name: "Qwen (DashScope)",
56
+ tier: "direct",
57
+ dialect: "openai-compatible",
58
+ credentialKind: "api-key",
59
+ baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
60
+ note: "Alibaba's shared DashScope domain. An account with a workspace-dedicated domain " +
61
+ "replaces this base URL with its own.",
62
+ },
63
+ {
64
+ providerId: "moonshot",
65
+ name: "Moonshot (Kimi)",
66
+ tier: "direct",
67
+ dialect: "openai-compatible",
68
+ credentialKind: "api-key",
69
+ baseUrl: "https://api.moonshot.ai/v1",
70
+ note: "Moonshot's own API.",
71
+ },
72
+ {
73
+ providerId: "xai",
74
+ name: "xAI",
75
+ tier: "direct",
76
+ dialect: "openai-compatible",
77
+ credentialKind: "api-key",
78
+ baseUrl: "https://api.x.ai/v1",
79
+ note: "xAI's own API.",
80
+ },
81
+ {
82
+ providerId: "openrouter",
83
+ name: "OpenRouter",
84
+ tier: "umbrella",
85
+ dialect: "openai-compatible",
86
+ credentialKind: "api-key",
87
+ baseUrl: "https://openrouter.ai/api/v1",
88
+ note: "One key for most vendors' models, at a resale price. The usual first fallback.",
89
+ },
90
+ {
91
+ providerId: "workers-ai",
92
+ name: "Cloudflare Workers AI",
93
+ tier: "umbrella",
94
+ dialect: "workers-ai",
95
+ credentialKind: "none",
96
+ note: "Cloudflare's hosted models through ai-service's own AI binding. No account id, no API " +
97
+ "token and no egress: the call is served inside the runtime. Add it and it works.",
98
+ },
99
+ {
100
+ providerId: "bifrost",
101
+ name: "Bifrost",
102
+ tier: "umbrella",
103
+ dialect: "openai-compatible",
104
+ credentialKind: "api-key",
105
+ note: "A self-hosted gateway. No public instance, so it resolves only once its URL is set.",
106
+ },
107
+ {
108
+ providerId: "litellm",
109
+ name: "LiteLLM",
110
+ tier: "umbrella",
111
+ dialect: "openai-compatible",
112
+ credentialKind: "api-key",
113
+ note: "A self-hosted gateway. Model ids are the operator's own config.yaml aliases.",
114
+ },
115
+ {
116
+ providerId: "vllm",
117
+ name: "vLLM",
118
+ tier: "local",
119
+ dialect: "openai-compatible",
120
+ credentialKind: "none",
121
+ baseUrl: "http://localhost:8000/v1",
122
+ note: "A vLLM server. Serves whatever weights it was started with.",
123
+ },
124
+ {
125
+ providerId: "ollama",
126
+ name: "Ollama",
127
+ tier: "local",
128
+ dialect: "openai-compatible",
129
+ credentialKind: "none",
130
+ baseUrl: "http://localhost:11434/v1",
131
+ note: "An Ollama server. Model ids are the tags it has pulled.",
132
+ },
133
+ {
134
+ providerId: "lmstudio",
135
+ name: "LM Studio",
136
+ tier: "local",
137
+ dialect: "openai-compatible",
138
+ credentialKind: "none",
139
+ baseUrl: "http://localhost:1234/v1",
140
+ note: "An LM Studio server.",
141
+ },
142
+ {
143
+ providerId: "llamacpp",
144
+ name: "llama.cpp",
145
+ tier: "local",
146
+ dialect: "openai-compatible",
147
+ credentialKind: "none",
148
+ baseUrl: "http://localhost:8080/v1",
149
+ note: "A llama-server instance.",
150
+ },
151
+ ];
152
+ /** A blueprint, on the wire. */
153
+ export const ProviderBlueprintSchema = object({
154
+ providerId: string(),
155
+ name: string(),
156
+ tier: ProviderTierSchema,
157
+ dialect: ProviderDialectSchema,
158
+ credentialKind: CredentialKindSchema,
159
+ baseUrl: optional(string()),
160
+ note: string(),
161
+ });
162
+ /** A subscription vendor the console can offer, with what it takes to store one. */
163
+ export const SubscriptionVendorOptionSchema = object({
164
+ vendor: string(),
165
+ label: string(),
166
+ baseUrl: string(),
167
+ dialect: string(),
168
+ /** Where the credential goes: `bearer` or `api-key`. */
169
+ authScheme: string(),
170
+ /** Whether the vendor licenses the plan to one named individual. */
171
+ individualOnly: boolean(),
172
+ });
173
+ /**
174
+ * Everything the console needs to render its "add a provider" screens without
175
+ * restating this package's tables in Vue.
176
+ */
177
+ export const CatalogResponseSchema = createSuccessResponseSchema({
178
+ providers: optional(array(ProviderBlueprintSchema)),
179
+ subscriptionVendors: optional(array(SubscriptionVendorOptionSchema)),
180
+ tiers: optional(array(ProviderTierSchema)),
181
+ /** The built-in tier order, so the preset editor can show what "default" means. */
182
+ defaultTierPreference: optional(array(ProviderTierSchema)),
183
+ /**
184
+ * The models this deployment surfaces by name, with the id each is reached
185
+ * under. Served rather than imported for the same reason the blueprints are:
186
+ * a consumer built against an older contract package would otherwise offer a
187
+ * model this service has since repinned, and the mistake would surface as a
188
+ * request that stopped answering.
189
+ */
190
+ featuredModels: optional(array(FeaturedModelSchema)),
191
+ });
192
+ /**
193
+ * Model ids a provider says it serves.
194
+ *
195
+ * Read from the provider, never from a table here: an operator adding a gateway
196
+ * wants the models that gateway has today, and the endpoint that answers that
197
+ * question is the gateway's own. A provider whose dialect has no such endpoint
198
+ * reports `supported: false` rather than an empty list, because "this provider
199
+ * serves nothing" and "there is no way to ask" are different facts and only one
200
+ * of them means the operator should type the ids in by hand.
201
+ */
202
+ export const DiscoveredModelsResponseSchema = createSuccessResponseSchema({
203
+ providerId: optional(string()),
204
+ supported: optional(boolean()),
205
+ models: optional(array(string())),
206
+ /** Why discovery could not answer, when it could not. */
207
+ failure: optional(string()),
208
+ });
209
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}