@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/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @game-infra/ai-schemas
3
+ *
4
+ * The ai-service API contract: how a provider, a coding-plan subscription and a
5
+ * routing preset are described, what an inference request and its answer look
6
+ * like, and the endpoint definitions that carry them.
7
+ */
8
+ // Providers
9
+ export { CREDENTIAL_KINDS, CreateProviderRequestSchema, CredentialKindSchema, DEFAULT_TIER_PREFERENCE, PROVIDER_DIALECTS, PROVIDER_TIERS, ProviderDialectSchema, ProviderIdSchema, ProviderListResponseSchema, ProviderModelRouteSchema, ProviderProbeResponseSchema, ProviderResponseSchema, ProviderSchema, ProviderTierSchema, SetProviderCredentialRequestSchema, UpdateProviderRequestSchema, } from "./provider.js";
10
+ // Subscriptions
11
+ export { CreateSubscriptionRequestSchema, SUBSCRIPTION_AUTH_SCHEMES, SUBSCRIPTION_VENDOR_PROFILES, SUBSCRIPTION_VENDORS, SubscriptionListResponseSchema, SubscriptionResponseSchema, SubscriptionAuthSchemeSchema, SubscriptionSchema, SubscriptionVendorSchema, UnlockSubscriptionRequestSchema, UnlockSubscriptionResponseSchema, UpdateSubscriptionRequestSchema, } from "./subscription.js";
12
+ // Presets and routing
13
+ export { CreatePresetRequestSchema, LOCKED_SUBSCRIPTION_POLICIES, LockedSubscriptionPolicySchema, PresetListResponseSchema, PresetModelEntrySchema, PresetResponseSchema, PresetSchema, PresetSlugSchema, ROUTE_EXCLUSION_REASONS, RouteCandidateSchema, RouteExclusionReasonSchema, RouteExclusionSchema, RoutePlanResponseSchema, UpdatePresetRequestSchema, } from "./preset.js";
14
+ // Inference
15
+ export { AttemptFailureSchema, GenerateObjectRequestSchema, GenerateObjectResponseSchema, GenerateTextRequestSchema, GenerateTextResponseSchema, ImagePartSchema, MESSAGE_ROLES, MessageRoleSchema, MessageSchema, RouteOutcomeSchema, STREAM_EVENTS, StreamEventSchema, TextPartSchema, UsageSchema, } from "./inference.js";
16
+ // The named request-schema registry, as published
17
+ export { RegisteredSchemaSchema, SchemaListResponseSchema, SchemaResponseSchema, } from "./schemaRegistry.js";
18
+ // Provider blueprints and model discovery
19
+ export { CatalogResponseSchema, DiscoveredModelsResponseSchema, PROVIDER_BLUEPRINTS, ProviderBlueprintSchema, SubscriptionVendorOptionSchema, } from "./catalog.js";
20
+ // The models this deployment surfaces by name, and how they become routable
21
+ export { FEATURED_MODEL_PURPOSES, FEATURED_MODELS, FeaturedModelPurposeSchema, FeaturedModelSchema, featuredModelRoutes, featuredModelsFor, } from "./featuredModels.js";
22
+ // Service
23
+ export { AiReadinessResponseSchema, CALL_LIST_SCOPES, CallListQuerySchema, CallListResponseSchema, CallListScopeSchema, CallRecordSchema, DeleteResponseSchema, } from "./service.js";
24
+ // Typed endpoint contracts (toad-contracts). Each contract carries its own
25
+ // `pathResolver`; wire them into a client via @toad-contracts/frontend-http-client.
26
+ export { aiCallListContract, aiCatalogContract, aiGenerateObjectContract, aiGenerateStreamContract, aiGenerateTextContract, aiPresetCreateContract, aiPresetDeleteContract, aiPresetGetContract, aiPresetListContract, aiPresetRoutePlanContract, aiPresetUpdateContract, aiProviderCreateContract, aiProviderCredentialDeleteContract, aiProviderCredentialSetContract, aiProviderDeleteContract, aiProviderGetContract, aiProviderListContract, aiProviderModelsContract, aiProviderProbeContract, aiProviderUpdateContract, aiReadinessContract, aiSchemaGetContract, aiSchemaListContract, aiSubscriptionCreateContract, aiSubscriptionDeleteContract, aiSubscriptionListContract, aiSubscriptionUnlockContract, aiSubscriptionUpdateContract, } from "./contracts.js";
27
+ // Routing rules the service and the console must agree about, stated once here
28
+ // rather than restated on each side.
29
+ export { orderedProviderPreference, orderedTierPreference } from "./preference.js";
30
+ /**
31
+ * The header a request carries the subscription unlock password in.
32
+ *
33
+ * A header rather than a body field, for the same reason the bearer token is
34
+ * one: it is a credential rather than an argument, it must not vary between the
35
+ * text and the streaming forms of the same call, and a body field would end up
36
+ * copied into request logs by every client that logs what it posted.
37
+ */
38
+ export const SUBSCRIPTION_PASSWORD_HEADER = "X-AI-Subscription-Password";
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,YAAY;AACZ,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,0BAA0B,EAC1B,wBAAwB,EACxB,2BAA2B,EAC3B,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,kCAAkC,EAClC,2BAA2B,GAC5B,MAAM,eAAe,CAAC;AAevB,gBAAgB;AAChB,OAAO,EACL,+BAA+B,EAC/B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,8BAA8B,EAC9B,0BAA0B,EAC1B,4BAA4B,EAC5B,kBAAkB,EAClB,wBAAwB,EACxB,+BAA+B,EAC/B,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,mBAAmB,CAAC;AAc3B,sBAAsB;AACtB,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,8BAA8B,EAC9B,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,aAAa,CAAC;AAerB,YAAY;AACZ,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,4BAA4B,EAC5B,yBAAyB,EACzB,0BAA0B,EAC1B,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAcxB,kDAAkD;AAClD,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,qBAAqB,CAAC;AAG7B,0CAA0C;AAC1C,OAAO,EACL,qBAAqB,EACrB,8BAA8B,EAC9B,mBAAmB,EACnB,uBAAuB,EACvB,8BAA8B,GAC/B,MAAM,cAAc,CAAC;AAGtB,4EAA4E;AAC5E,OAAO,EACL,uBAAuB,EACvB,eAAe,EACf,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAG7B,UAAU;AACV,OAAO,EACL,yBAAyB,EACzB,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAUtB,2EAA2E;AAC3E,oFAAoF;AACpF,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,sBAAsB,EACtB,wBAAwB,EACxB,kCAAkC,EAClC,+BAA+B,EAC/B,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,4BAA4B,EAC5B,4BAA4B,EAC5B,0BAA0B,EAC1B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAExB,+EAA+E;AAC/E,qCAAqC;AACrC,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEnF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,4BAA4B,CAAC"}
@@ -0,0 +1,323 @@
1
+ import { type InferOutput } from "valibot";
2
+ /**
3
+ * The inference surface.
4
+ *
5
+ * ai-service defines no prompts. Every word a model sees comes from the caller,
6
+ * which is what keeps this a routing and credential service rather than a
7
+ * second place where a game's voice is decided. What it does own is the part no
8
+ * caller should have to: which provider serves the request, what to do when
9
+ * that provider is down, and what a structured response is allowed to look
10
+ * like.
11
+ */
12
+ /** Who a message is from. */
13
+ export declare const MESSAGE_ROLES: readonly ["system", "user", "assistant"];
14
+ export declare const MessageRoleSchema: import("valibot").PicklistSchema<readonly ["system", "user", "assistant"], undefined>;
15
+ export type MessageRole = InferOutput<typeof MessageRoleSchema>;
16
+ /** A piece of an image, given as a URL or as base64 bytes with their media type. */
17
+ export declare const ImagePartSchema: import("valibot").ObjectSchema<{
18
+ readonly type: import("valibot").PicklistSchema<["image"], undefined>;
19
+ /** `https:` or `data:` URL, or bare base64 when {@link mediaType} is set. */
20
+ readonly image: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 20000000, undefined>]>;
21
+ /** `image/png`, `image/jpeg`, … Required when `image` is bare base64. */
22
+ readonly mediaType: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>, undefined>;
23
+ }, undefined>;
24
+ /** A piece of text. */
25
+ export declare const TextPartSchema: import("valibot").ObjectSchema<{
26
+ readonly type: import("valibot").PicklistSchema<["text"], undefined>;
27
+ readonly text: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>;
28
+ }, undefined>;
29
+ /**
30
+ * One message.
31
+ *
32
+ * `content` is a plain string or a list of parts. The string form is what
33
+ * almost every caller wants and is not sugar over the other: a text-only
34
+ * request must be able to route to a model nobody has declared image support
35
+ * for, and that is decidable only if "no parts" and "parts that happen to be
36
+ * text" stay distinguishable.
37
+ */
38
+ export declare const MessageSchema: import("valibot").ObjectSchema<{
39
+ readonly role: import("valibot").PicklistSchema<readonly ["system", "user", "assistant"], undefined>;
40
+ readonly content: import("valibot").UnionSchema<[import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>, import("valibot").ArraySchema<import("valibot").UnionSchema<[import("valibot").ObjectSchema<{
41
+ readonly type: import("valibot").PicklistSchema<["text"], undefined>;
42
+ readonly text: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>;
43
+ }, undefined>, import("valibot").ObjectSchema<{
44
+ readonly type: import("valibot").PicklistSchema<["image"], undefined>;
45
+ /** `https:` or `data:` URL, or bare base64 when {@link mediaType} is set. */
46
+ readonly image: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 20000000, undefined>]>;
47
+ /** `image/png`, `image/jpeg`, … Required when `image` is bare base64. */
48
+ readonly mediaType: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>, undefined>;
49
+ }, undefined>], undefined>, undefined>], undefined>;
50
+ }, undefined>;
51
+ export type Message = InferOutput<typeof MessageSchema>;
52
+ /** A free-text completion. */
53
+ export declare const GenerateTextRequestSchema: import("valibot").ObjectSchema<{
54
+ /** Preset slug. Unknown or disabled slugs are refused rather than defaulted. */
55
+ readonly preset: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 64, undefined>, import("valibot").RegexAction<string, "must be lowercase words separated by single dashes">]>, undefined>;
56
+ /** Canonical model id, when the caller is naming one directly. */
57
+ readonly model: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 160, undefined>]>, undefined>;
58
+ /** Force one provider. Same meaning as a preset entry's pin: no fallback. */
59
+ readonly provider: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 64, undefined>, import("valibot").RegexAction<string, "must be lowercase words separated by single dashes">]>, undefined>;
60
+ /** The conversation. At least one message; the service adds none of its own. */
61
+ readonly messages: import("valibot").SchemaWithPipe<readonly [import("valibot").ArraySchema<import("valibot").ObjectSchema<{
62
+ readonly role: import("valibot").PicklistSchema<readonly ["system", "user", "assistant"], undefined>;
63
+ readonly content: import("valibot").UnionSchema<[import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>, import("valibot").ArraySchema<import("valibot").UnionSchema<[import("valibot").ObjectSchema<{
64
+ readonly type: import("valibot").PicklistSchema<["text"], undefined>;
65
+ readonly text: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>;
66
+ }, undefined>, import("valibot").ObjectSchema<{
67
+ readonly type: import("valibot").PicklistSchema<["image"], undefined>;
68
+ /** `https:` or `data:` URL, or bare base64 when {@link mediaType} is set. */
69
+ readonly image: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 20000000, undefined>]>;
70
+ /** `image/png`, `image/jpeg`, … Required when `image` is bare base64. */
71
+ readonly mediaType: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>, undefined>;
72
+ }, undefined>], undefined>, undefined>], undefined>;
73
+ }, undefined>, undefined>, import("valibot").MinLengthAction<{
74
+ role: "assistant" | "system" | "user";
75
+ content: string | ({
76
+ type: "text";
77
+ text: string;
78
+ } | {
79
+ type: "image";
80
+ image: string;
81
+ mediaType?: string | undefined;
82
+ })[];
83
+ }[], 1, undefined>]>;
84
+ /** Overrides the preset's temperature. */
85
+ readonly temperature: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").MinValueAction<number, 0, undefined>, import("valibot").MaxValueAction<number, 2, undefined>]>, undefined>;
86
+ /** Overrides the preset's output-token cap. */
87
+ readonly maxOutputTokens: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 1, undefined>, import("valibot").MaxValueAction<number, 200000, undefined>]>, undefined>;
88
+ /**
89
+ * Opaque label recorded with the call, so spend can be read back per caller.
90
+ * A service name or a job kind, never anything derived from a player.
91
+ */
92
+ readonly callLabel: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>, undefined>;
93
+ }, undefined>;
94
+ export type GenerateTextRequest = InferOutput<typeof GenerateTextRequestSchema>;
95
+ /**
96
+ * A completion shaped by one of this service's registered schemas.
97
+ *
98
+ * The schema is named, never sent. A caller that could post its own schema
99
+ * would be deciding, per call, what this deployment is willing to ask a model
100
+ * for, and the shapes would drift between the callers that share them. So the
101
+ * schemas live here, `schemaId` selects one, and an id this service does not
102
+ * know is an error rather than a fall back to free text.
103
+ */
104
+ export declare const GenerateObjectRequestSchema: import("valibot").ObjectSchema<{
105
+ /** Preset slug. Unknown or disabled slugs are refused rather than defaulted. */
106
+ readonly preset: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 64, undefined>, import("valibot").RegexAction<string, "must be lowercase words separated by single dashes">]>, undefined>;
107
+ /** Canonical model id, when the caller is naming one directly. */
108
+ readonly model: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 160, undefined>]>, undefined>;
109
+ /** Force one provider. Same meaning as a preset entry's pin: no fallback. */
110
+ readonly provider: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 64, undefined>, import("valibot").RegexAction<string, "must be lowercase words separated by single dashes">]>, undefined>;
111
+ /** The conversation. At least one message; the service adds none of its own. */
112
+ readonly messages: import("valibot").SchemaWithPipe<readonly [import("valibot").ArraySchema<import("valibot").ObjectSchema<{
113
+ readonly role: import("valibot").PicklistSchema<readonly ["system", "user", "assistant"], undefined>;
114
+ readonly content: import("valibot").UnionSchema<[import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>, import("valibot").ArraySchema<import("valibot").UnionSchema<[import("valibot").ObjectSchema<{
115
+ readonly type: import("valibot").PicklistSchema<["text"], undefined>;
116
+ readonly text: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 2000000, undefined>]>;
117
+ }, undefined>, import("valibot").ObjectSchema<{
118
+ readonly type: import("valibot").PicklistSchema<["image"], undefined>;
119
+ /** `https:` or `data:` URL, or bare base64 when {@link mediaType} is set. */
120
+ readonly image: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 20000000, undefined>]>;
121
+ /** `image/png`, `image/jpeg`, … Required when `image` is bare base64. */
122
+ readonly mediaType: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>, undefined>;
123
+ }, undefined>], undefined>, undefined>], undefined>;
124
+ }, undefined>, undefined>, import("valibot").MinLengthAction<{
125
+ role: "assistant" | "system" | "user";
126
+ content: string | ({
127
+ type: "text";
128
+ text: string;
129
+ } | {
130
+ type: "image";
131
+ image: string;
132
+ mediaType?: string | undefined;
133
+ })[];
134
+ }[], 1, undefined>]>;
135
+ /** Overrides the preset's temperature. */
136
+ readonly temperature: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").MinValueAction<number, 0, undefined>, import("valibot").MaxValueAction<number, 2, undefined>]>, undefined>;
137
+ /** Overrides the preset's output-token cap. */
138
+ readonly maxOutputTokens: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 1, undefined>, import("valibot").MaxValueAction<number, 200000, undefined>]>, undefined>;
139
+ /**
140
+ * Opaque label recorded with the call, so spend can be read back per caller.
141
+ * A service name or a job kind, never anything derived from a player.
142
+ */
143
+ readonly callLabel: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>, undefined>;
144
+ readonly schemaId: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 120, undefined>]>;
145
+ }, undefined>;
146
+ export type GenerateObjectRequest = InferOutput<typeof GenerateObjectRequestSchema>;
147
+ /** Tokens spent on one call, as the provider reported them. */
148
+ export declare const UsageSchema: import("valibot").ObjectSchema<{
149
+ /** Fresh input tokens, exclusive of anything served from a prompt cache. */
150
+ readonly inputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
151
+ readonly outputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
152
+ /** Cached input tokens read, where the provider reports them separately. */
153
+ readonly cachedInputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
154
+ readonly totalTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
155
+ }, undefined>;
156
+ export type Usage = InferOutput<typeof UsageSchema>;
157
+ /** Why one attempted route did not produce the answer. */
158
+ export declare const AttemptFailureSchema: import("valibot").ObjectSchema<{
159
+ readonly providerId: import("valibot").StringSchema<undefined>;
160
+ readonly model: import("valibot").StringSchema<undefined>;
161
+ /** The vendor or transport failure, verbatim. Secrets are stripped first. */
162
+ readonly failure: import("valibot").StringSchema<undefined>;
163
+ /** Whether the failure was one the next route could plausibly do better on. */
164
+ readonly retryable: import("valibot").BooleanSchema<undefined>;
165
+ }, undefined>;
166
+ export type AttemptFailure = InferOutput<typeof AttemptFailureSchema>;
167
+ /**
168
+ * What actually happened, reported on every answer.
169
+ *
170
+ * A response that said only what the model produced would hide the two facts a
171
+ * caller most needs when a preset is not behaving: which route served it, and
172
+ * which routes were skipped or failed on the way there. Both are here on
173
+ * success as well as on failure, because a preset degrading quietly to its last
174
+ * fallback looks exactly like one working.
175
+ */
176
+ export declare const RouteOutcomeSchema: import("valibot").ObjectSchema<{
177
+ /** The route that answered. */
178
+ readonly served: import("valibot").ObjectSchema<{
179
+ readonly order: import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
180
+ readonly model: import("valibot").StringSchema<undefined>;
181
+ readonly providerModelId: import("valibot").StringSchema<undefined>;
182
+ readonly providerId: import("valibot").StringSchema<undefined>;
183
+ readonly providerName: import("valibot").StringSchema<undefined>;
184
+ readonly tier: import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>;
185
+ readonly unlockable: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
186
+ }, undefined>;
187
+ /** Routes tried and failed before it, oldest first. */
188
+ readonly attempts: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
189
+ readonly providerId: import("valibot").StringSchema<undefined>;
190
+ readonly model: import("valibot").StringSchema<undefined>;
191
+ /** The vendor or transport failure, verbatim. Secrets are stripped first. */
192
+ readonly failure: import("valibot").StringSchema<undefined>;
193
+ /** Whether the failure was one the next route could plausibly do better on. */
194
+ readonly retryable: import("valibot").BooleanSchema<undefined>;
195
+ }, undefined>, undefined>;
196
+ /** Routes never tried, and why. */
197
+ readonly excluded: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
198
+ readonly model: import("valibot").StringSchema<undefined>;
199
+ readonly providerId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
200
+ readonly tier: import("valibot").OptionalSchema<import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>, undefined>;
201
+ readonly reason: import("valibot").PicklistSchema<readonly ["model_not_served", "provider_disabled", "credential_missing", "subscription_locked", "subscription_not_owned", "subscription_required", "pinned_provider_unavailable", "model_no_image_input", "unknown_model_image_input", "structured_output_unsupported", "attempt_budget_exhausted"], undefined>;
202
+ readonly detail: import("valibot").StringSchema<undefined>;
203
+ }, undefined>, undefined>;
204
+ }, undefined>;
205
+ export type RouteOutcome = InferOutput<typeof RouteOutcomeSchema>;
206
+ /** A free-text answer. */
207
+ export declare const GenerateTextResponseSchema: import("valibot").ObjectSchema<{
208
+ readonly success: import("valibot").BooleanSchema<undefined>;
209
+ readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
210
+ } & {
211
+ text: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
212
+ /** `stop`, `length`, `content-filter`, … as the provider reported it. */
213
+ finishReason: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
214
+ usage: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
215
+ /** Fresh input tokens, exclusive of anything served from a prompt cache. */
216
+ readonly inputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
217
+ readonly outputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
218
+ /** Cached input tokens read, where the provider reports them separately. */
219
+ readonly cachedInputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
220
+ readonly totalTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
221
+ }, undefined>, undefined>;
222
+ route: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
223
+ /** The route that answered. */
224
+ readonly served: import("valibot").ObjectSchema<{
225
+ readonly order: import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
226
+ readonly model: import("valibot").StringSchema<undefined>;
227
+ readonly providerModelId: import("valibot").StringSchema<undefined>;
228
+ readonly providerId: import("valibot").StringSchema<undefined>;
229
+ readonly providerName: import("valibot").StringSchema<undefined>;
230
+ readonly tier: import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>;
231
+ readonly unlockable: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
232
+ }, undefined>;
233
+ /** Routes tried and failed before it, oldest first. */
234
+ readonly attempts: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
235
+ readonly providerId: import("valibot").StringSchema<undefined>;
236
+ readonly model: import("valibot").StringSchema<undefined>;
237
+ /** The vendor or transport failure, verbatim. Secrets are stripped first. */
238
+ readonly failure: import("valibot").StringSchema<undefined>;
239
+ /** Whether the failure was one the next route could plausibly do better on. */
240
+ readonly retryable: import("valibot").BooleanSchema<undefined>;
241
+ }, undefined>, undefined>;
242
+ /** Routes never tried, and why. */
243
+ readonly excluded: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
244
+ readonly model: import("valibot").StringSchema<undefined>;
245
+ readonly providerId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
246
+ readonly tier: import("valibot").OptionalSchema<import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>, undefined>;
247
+ readonly reason: import("valibot").PicklistSchema<readonly ["model_not_served", "provider_disabled", "credential_missing", "subscription_locked", "subscription_not_owned", "subscription_required", "pinned_provider_unavailable", "model_no_image_input", "unknown_model_image_input", "structured_output_unsupported", "attempt_budget_exhausted"], undefined>;
248
+ readonly detail: import("valibot").StringSchema<undefined>;
249
+ }, undefined>, undefined>;
250
+ }, undefined>, undefined>;
251
+ /** Wall-clock time of the call that answered, in milliseconds. */
252
+ latencyMs: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
253
+ }, undefined>;
254
+ export type GenerateTextResponse = InferOutput<typeof GenerateTextResponseSchema>;
255
+ /**
256
+ * A structured answer.
257
+ *
258
+ * `object` is typed `any` on the wire because its real shape is whichever
259
+ * registered schema the request named, and a contract cannot know that at
260
+ * definition time. Callers narrow it by parsing against the same `schemaId`
261
+ * they asked for, whose JSON Schema this service publishes.
262
+ */
263
+ export declare const GenerateObjectResponseSchema: import("valibot").ObjectSchema<{
264
+ readonly success: import("valibot").BooleanSchema<undefined>;
265
+ readonly error: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
266
+ } & {
267
+ object: import("valibot").OptionalSchema<import("valibot").AnySchema, undefined>;
268
+ schemaId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
269
+ finishReason: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
270
+ usage: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
271
+ /** Fresh input tokens, exclusive of anything served from a prompt cache. */
272
+ readonly inputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
273
+ readonly outputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
274
+ /** Cached input tokens read, where the provider reports them separately. */
275
+ readonly cachedInputTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
276
+ readonly totalTokens: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
277
+ }, undefined>, undefined>;
278
+ route: import("valibot").OptionalSchema<import("valibot").ObjectSchema<{
279
+ /** The route that answered. */
280
+ readonly served: import("valibot").ObjectSchema<{
281
+ readonly order: import("valibot").SchemaWithPipe<readonly [import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
282
+ readonly model: import("valibot").StringSchema<undefined>;
283
+ readonly providerModelId: import("valibot").StringSchema<undefined>;
284
+ readonly providerId: import("valibot").StringSchema<undefined>;
285
+ readonly providerName: import("valibot").StringSchema<undefined>;
286
+ readonly tier: import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>;
287
+ readonly unlockable: import("valibot").OptionalSchema<import("valibot").BooleanSchema<undefined>, undefined>;
288
+ }, undefined>;
289
+ /** Routes tried and failed before it, oldest first. */
290
+ readonly attempts: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
291
+ readonly providerId: import("valibot").StringSchema<undefined>;
292
+ readonly model: import("valibot").StringSchema<undefined>;
293
+ /** The vendor or transport failure, verbatim. Secrets are stripped first. */
294
+ readonly failure: import("valibot").StringSchema<undefined>;
295
+ /** Whether the failure was one the next route could plausibly do better on. */
296
+ readonly retryable: import("valibot").BooleanSchema<undefined>;
297
+ }, undefined>, undefined>;
298
+ /** Routes never tried, and why. */
299
+ readonly excluded: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
300
+ readonly model: import("valibot").StringSchema<undefined>;
301
+ readonly providerId: import("valibot").OptionalSchema<import("valibot").StringSchema<undefined>, undefined>;
302
+ readonly tier: import("valibot").OptionalSchema<import("valibot").PicklistSchema<readonly ["subscription", "direct", "local", "umbrella"], undefined>, undefined>;
303
+ readonly reason: import("valibot").PicklistSchema<readonly ["model_not_served", "provider_disabled", "credential_missing", "subscription_locked", "subscription_not_owned", "subscription_required", "pinned_provider_unavailable", "model_no_image_input", "unknown_model_image_input", "structured_output_unsupported", "attempt_budget_exhausted"], undefined>;
304
+ readonly detail: import("valibot").StringSchema<undefined>;
305
+ }, undefined>, undefined>;
306
+ }, undefined>, undefined>;
307
+ latencyMs: import("valibot").OptionalSchema<import("valibot").NumberSchema<undefined>, undefined>;
308
+ }, undefined>;
309
+ export type GenerateObjectResponse = InferOutput<typeof GenerateObjectResponseSchema>;
310
+ /**
311
+ * The events a streamed completion emits, as SSE `event:` names.
312
+ *
313
+ * `route` arrives first and only once, naming the provider that got the
314
+ * request. It is sent before the first token because that is the last moment at
315
+ * which the answer is still honest: fallback is possible only until bytes have
316
+ * been written, so a stream that failed over would have to retract a route it
317
+ * had already claimed. After the first `delta`, a failure ends the stream with
318
+ * `error` and nothing is retried.
319
+ */
320
+ export declare const STREAM_EVENTS: readonly ["route", "delta", "done", "error"];
321
+ export declare const StreamEventSchema: import("valibot").PicklistSchema<readonly ["route", "delta", "done", "error"], undefined>;
322
+ export type StreamEvent = InferOutput<typeof StreamEventSchema>;
323
+ //# sourceMappingURL=inference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.d.ts","sourceRoot":"","sources":["../src/inference.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,162 @@
1
+ import { createSuccessResponseSchema } from "@game-infra/api-schemas-core";
2
+ import { any, array, boolean, integer, maxLength, maxValue, minLength, minValue, number, object, optional, picklist, pipe, string, union, } from "valibot";
3
+ import { PresetSlugSchema, RouteCandidateSchema, RouteExclusionSchema } from "./preset.js";
4
+ import { ProviderIdSchema } from "./provider.js";
5
+ /**
6
+ * The inference surface.
7
+ *
8
+ * ai-service defines no prompts. Every word a model sees comes from the caller,
9
+ * which is what keeps this a routing and credential service rather than a
10
+ * second place where a game's voice is decided. What it does own is the part no
11
+ * caller should have to: which provider serves the request, what to do when
12
+ * that provider is down, and what a structured response is allowed to look
13
+ * like.
14
+ */
15
+ /** Who a message is from. */
16
+ export const MESSAGE_ROLES = ["system", "user", "assistant"];
17
+ export const MessageRoleSchema = picklist(MESSAGE_ROLES);
18
+ /** A piece of an image, given as a URL or as base64 bytes with their media type. */
19
+ export const ImagePartSchema = object({
20
+ type: picklist(["image"]),
21
+ /** `https:` or `data:` URL, or bare base64 when {@link mediaType} is set. */
22
+ image: pipe(string(), minLength(1), maxLength(20_000_000)),
23
+ /** `image/png`, `image/jpeg`, … Required when `image` is bare base64. */
24
+ mediaType: optional(pipe(string(), maxLength(120))),
25
+ });
26
+ /** A piece of text. */
27
+ export const TextPartSchema = object({
28
+ type: picklist(["text"]),
29
+ text: pipe(string(), maxLength(2_000_000)),
30
+ });
31
+ /**
32
+ * One message.
33
+ *
34
+ * `content` is a plain string or a list of parts. The string form is what
35
+ * almost every caller wants and is not sugar over the other: a text-only
36
+ * request must be able to route to a model nobody has declared image support
37
+ * for, and that is decidable only if "no parts" and "parts that happen to be
38
+ * text" stay distinguishable.
39
+ */
40
+ export const MessageSchema = object({
41
+ role: MessageRoleSchema,
42
+ content: union([
43
+ pipe(string(), maxLength(2_000_000)),
44
+ array(union([TextPartSchema, ImagePartSchema])),
45
+ ]),
46
+ });
47
+ /**
48
+ * What every inference request carries, whatever it asks the model to produce.
49
+ *
50
+ * Exactly one of `preset` or `model` names the work's destination. A preset is
51
+ * the normal form and is what gives a caller fallback; a bare model is the
52
+ * escape hatch for a caller that knows precisely what it wants, and it routes
53
+ * through the same tier preference with no model-level fallback.
54
+ */
55
+ const InferenceRequestFieldsSchema = object({
56
+ /** Preset slug. Unknown or disabled slugs are refused rather than defaulted. */
57
+ preset: optional(PresetSlugSchema),
58
+ /** Canonical model id, when the caller is naming one directly. */
59
+ model: optional(pipe(string(), minLength(1), maxLength(160))),
60
+ /** Force one provider. Same meaning as a preset entry's pin: no fallback. */
61
+ provider: optional(ProviderIdSchema),
62
+ /** The conversation. At least one message; the service adds none of its own. */
63
+ messages: pipe(array(MessageSchema), minLength(1)),
64
+ /** Overrides the preset's temperature. */
65
+ temperature: optional(pipe(number(), minValue(0), maxValue(2))),
66
+ /** Overrides the preset's output-token cap. */
67
+ maxOutputTokens: optional(pipe(number(), integer(), minValue(1), maxValue(200_000))),
68
+ /**
69
+ * Opaque label recorded with the call, so spend can be read back per caller.
70
+ * A service name or a job kind, never anything derived from a player.
71
+ */
72
+ callLabel: optional(pipe(string(), maxLength(120))),
73
+ });
74
+ /** A free-text completion. */
75
+ export const GenerateTextRequestSchema = object({ ...InferenceRequestFieldsSchema.entries });
76
+ /**
77
+ * A completion shaped by one of this service's registered schemas.
78
+ *
79
+ * The schema is named, never sent. A caller that could post its own schema
80
+ * would be deciding, per call, what this deployment is willing to ask a model
81
+ * for, and the shapes would drift between the callers that share them. So the
82
+ * schemas live here, `schemaId` selects one, and an id this service does not
83
+ * know is an error rather than a fall back to free text.
84
+ */
85
+ export const GenerateObjectRequestSchema = object({
86
+ ...InferenceRequestFieldsSchema.entries,
87
+ schemaId: pipe(string(), minLength(1), maxLength(120)),
88
+ });
89
+ /** Tokens spent on one call, as the provider reported them. */
90
+ export const UsageSchema = object({
91
+ /** Fresh input tokens, exclusive of anything served from a prompt cache. */
92
+ inputTokens: optional(number()),
93
+ outputTokens: optional(number()),
94
+ /** Cached input tokens read, where the provider reports them separately. */
95
+ cachedInputTokens: optional(number()),
96
+ totalTokens: optional(number()),
97
+ });
98
+ /** Why one attempted route did not produce the answer. */
99
+ export const AttemptFailureSchema = object({
100
+ providerId: string(),
101
+ model: string(),
102
+ /** The vendor or transport failure, verbatim. Secrets are stripped first. */
103
+ failure: string(),
104
+ /** Whether the failure was one the next route could plausibly do better on. */
105
+ retryable: boolean(),
106
+ });
107
+ /**
108
+ * What actually happened, reported on every answer.
109
+ *
110
+ * A response that said only what the model produced would hide the two facts a
111
+ * caller most needs when a preset is not behaving: which route served it, and
112
+ * which routes were skipped or failed on the way there. Both are here on
113
+ * success as well as on failure, because a preset degrading quietly to its last
114
+ * fallback looks exactly like one working.
115
+ */
116
+ export const RouteOutcomeSchema = object({
117
+ /** The route that answered. */
118
+ served: RouteCandidateSchema,
119
+ /** Routes tried and failed before it, oldest first. */
120
+ attempts: array(AttemptFailureSchema),
121
+ /** Routes never tried, and why. */
122
+ excluded: array(RouteExclusionSchema),
123
+ });
124
+ /** A free-text answer. */
125
+ export const GenerateTextResponseSchema = createSuccessResponseSchema({
126
+ text: optional(string()),
127
+ /** `stop`, `length`, `content-filter`, … as the provider reported it. */
128
+ finishReason: optional(string()),
129
+ usage: optional(UsageSchema),
130
+ route: optional(RouteOutcomeSchema),
131
+ /** Wall-clock time of the call that answered, in milliseconds. */
132
+ latencyMs: optional(number()),
133
+ });
134
+ /**
135
+ * A structured answer.
136
+ *
137
+ * `object` is typed `any` on the wire because its real shape is whichever
138
+ * registered schema the request named, and a contract cannot know that at
139
+ * definition time. Callers narrow it by parsing against the same `schemaId`
140
+ * they asked for, whose JSON Schema this service publishes.
141
+ */
142
+ export const GenerateObjectResponseSchema = createSuccessResponseSchema({
143
+ object: optional(any()),
144
+ schemaId: optional(string()),
145
+ finishReason: optional(string()),
146
+ usage: optional(UsageSchema),
147
+ route: optional(RouteOutcomeSchema),
148
+ latencyMs: optional(number()),
149
+ });
150
+ /**
151
+ * The events a streamed completion emits, as SSE `event:` names.
152
+ *
153
+ * `route` arrives first and only once, naming the provider that got the
154
+ * request. It is sent before the first token because that is the last moment at
155
+ * which the answer is still honest: fallback is possible only until bytes have
156
+ * been written, so a stream that failed over would have to retract a route it
157
+ * had already claimed. After the first `delta`, a failure ends the stream with
158
+ * `error` and nothing is retried.
159
+ */
160
+ export const STREAM_EVENTS = ["route", "delta", "done", "error"];
161
+ export const StreamEventSchema = picklist(STREAM_EVENTS);
162
+ //# sourceMappingURL=inference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inference.js","sourceRoot":"","sources":["../src/inference.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { type ProviderTier } from "./provider.js";
2
+ /**
3
+ * The two folds that turn a stored preference into the order a request is
4
+ * actually tried in.
5
+ *
6
+ * They live in this package rather than in the service because the console
7
+ * renders the same fold: the preset editor shows the resulting order as the
8
+ * operator drags rows, and a second copy of the rule in Vue is a copy that
9
+ * eventually disagrees with the one the request takes. Getting an order the
10
+ * editor never showed is the worst way to learn a preference was misread.
11
+ */
12
+ /**
13
+ * A preference REORDERS the tiers; it never filters them.
14
+ *
15
+ * The tiers named come first, in the order given; every other tier follows in
16
+ * the built-in order. That total is deliberate. A preference is a stored
17
+ * document, so one written before a tier existed would otherwise make that tier
18
+ * permanently unreachable for the preset that holds it, with nothing on screen
19
+ * saying so; and an operator dragging a tier off a list means "last", not
20
+ * "never" (a tier they actually want off is switched off at the provider,
21
+ * where the effect is visible).
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import { orderedTierPreference } from '@game-infra/ai-schemas'
26
+ *
27
+ * orderedTierPreference(['umbrella'])
28
+ * // ['umbrella', 'subscription', 'direct', 'local']
29
+ * ```
30
+ */
31
+ export declare function orderedTierPreference(preference: readonly ProviderTier[] | undefined): ProviderTier[];
32
+ /**
33
+ * Rank providers inside one tier.
34
+ *
35
+ * Named providers come first in the order given. The rest follow sorted by
36
+ * their own id, which matters more than it looks: the alternative is database
37
+ * order, so two deployments configured with the same providers in a different
38
+ * sequence would route differently while both presets read identically.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import { orderedProviderPreference } from '@game-infra/ai-schemas'
43
+ *
44
+ * orderedProviderPreference(['openrouter'], ['workers-ai', 'bifrost', 'openrouter'])
45
+ * // ['openrouter', 'bifrost', 'workers-ai']
46
+ * ```
47
+ */
48
+ export declare function orderedProviderPreference(preference: readonly string[] | undefined, available: readonly string[]): string[];
49
+ //# sourceMappingURL=preference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference.d.ts","sourceRoot":"","sources":["../src/preference.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3F;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,GAC9C,YAAY,EAAE,CAehB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACzC,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,EAAE,CAOV"}