@kaana.ai/contracts 0.0.0-stage → 4.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 (79) hide show
  1. package/LICENSE +673 -0
  2. package/NOTICE +21 -0
  3. package/dist/index.d.ts +29 -0
  4. package/dist/index.js +29 -0
  5. package/dist/internal/attribution.d.ts +116 -0
  6. package/dist/internal/attribution.js +82 -0
  7. package/dist/internal/canonical.d.ts +31 -0
  8. package/dist/internal/canonical.js +57 -0
  9. package/dist/internal/catalogue.d.ts +1030 -0
  10. package/dist/internal/catalogue.js +349 -0
  11. package/dist/internal/credentialControl.d.ts +329 -0
  12. package/dist/internal/credentialControl.js +256 -0
  13. package/dist/internal/decisions.d.ts +245 -0
  14. package/dist/internal/decisions.js +69 -0
  15. package/dist/internal/economics.d.ts +27 -0
  16. package/dist/internal/economics.js +26 -0
  17. package/dist/internal/embeddings.d.ts +164 -0
  18. package/dist/internal/embeddings.js +59 -0
  19. package/dist/internal/errors.d.ts +185 -0
  20. package/dist/internal/errors.js +211 -0
  21. package/dist/internal/grant.d.ts +696 -0
  22. package/dist/internal/grant.js +437 -0
  23. package/dist/internal/identifiers.d.ts +63 -0
  24. package/dist/internal/identifiers.js +65 -0
  25. package/dist/internal/privateAutoExecution.d.ts +158 -0
  26. package/dist/internal/privateAutoExecution.js +188 -0
  27. package/dist/internal/realtime.d.ts +1005 -0
  28. package/dist/internal/realtime.js +187 -0
  29. package/dist/internal/request.d.ts +1079 -0
  30. package/dist/internal/request.js +404 -0
  31. package/dist/internal/routing.d.ts +90 -0
  32. package/dist/internal/routing.js +139 -0
  33. package/dist/internal/scopedExecution.d.ts +74 -0
  34. package/dist/internal/scopedExecution.js +61 -0
  35. package/dist/internal/settlement.d.ts +205 -0
  36. package/dist/internal/settlement.js +71 -0
  37. package/dist/internal/streamEvents.d.ts +422 -0
  38. package/dist/internal/streamEvents.js +171 -0
  39. package/dist/internal/usage.d.ts +127 -0
  40. package/dist/internal/usage.js +109 -0
  41. package/dist/internal.d.ts +30 -0
  42. package/dist/internal.js +30 -0
  43. package/dist/public/audio.d.ts +347 -0
  44. package/dist/public/audio.js +236 -0
  45. package/dist/public/audioFormats.d.ts +64 -0
  46. package/dist/public/audioFormats.js +60 -0
  47. package/dist/public/catalogue.d.ts +914 -0
  48. package/dist/public/catalogue.js +516 -0
  49. package/dist/public/chatCompletions.d.ts +381 -0
  50. package/dist/public/chatCompletions.js +321 -0
  51. package/dist/public/decisions.d.ts +182 -0
  52. package/dist/public/decisions.js +257 -0
  53. package/dist/public/embeddings.d.ts +34 -0
  54. package/dist/public/embeddings.js +66 -0
  55. package/dist/public/errors.d.ts +195 -0
  56. package/dist/public/errors.js +274 -0
  57. package/dist/public/generations.d.ts +330 -0
  58. package/dist/public/generations.js +121 -0
  59. package/dist/public/identifiers.d.ts +139 -0
  60. package/dist/public/identifiers.js +160 -0
  61. package/dist/public/images.d.ts +36 -0
  62. package/dist/public/images.js +36 -0
  63. package/dist/public/messages.d.ts +297 -0
  64. package/dist/public/messages.js +251 -0
  65. package/dist/public/money.d.ts +308 -0
  66. package/dist/public/money.js +237 -0
  67. package/dist/public/policy.d.ts +19 -0
  68. package/dist/public/policy.js +20 -0
  69. package/dist/public/realtime.d.ts +2006 -0
  70. package/dist/public/realtime.js +797 -0
  71. package/dist/public/responses.d.ts +253 -0
  72. package/dist/public/responses.js +95 -0
  73. package/dist/public/streamEvents.d.ts +372 -0
  74. package/dist/public/streamEvents.js +157 -0
  75. package/dist/public/version.d.ts +177 -0
  76. package/dist/public/version.js +177 -0
  77. package/openapi.json +6967 -0
  78. package/package.json +44 -4
  79. package/README.md +0 -3
@@ -0,0 +1,381 @@
1
+ /**
2
+ * `POST /v1/chat/completions` — the OpenAI-compatible surface.
3
+ *
4
+ * It speaks the flat OpenAI request and response shapes so an unmodified OpenAI
5
+ * SDK works against `baseURL: 'https://kaana.ai/v1'` with an `oxy_sk_…` key, and
6
+ * it gains NO Kaana-specific request field: a capability with no OpenAI
7
+ * representation lives on `/v1/responses`. `.strict()` everywhere: a stock SDK
8
+ * sending a parameter Kaana does not implement is told so rather than having it
9
+ * silently dropped.
10
+ *
11
+ * Moved from the Oxy edge (`packages/api/src/schemas/inferenceEdge.schemas.ts`)
12
+ * by Kaana ADR 0002. `model` names a model reference or a power level. The
13
+ * stream chunk and the error body are written down here for the first time;
14
+ * the Oxy edge rendered them in code only.
15
+ */
16
+ import { z } from 'zod';
17
+ /**
18
+ * One OpenAI message. `content` accepts both the string form and the parts
19
+ * array, because both are in wide use and rejecting the string form would fail
20
+ * the stock SDK on its most common call.
21
+ */
22
+ export declare const chatCompletionMessageSchema: z.ZodObject<{
23
+ role: z.ZodEnum<{
24
+ user: "user";
25
+ system: "system";
26
+ developer: "developer";
27
+ assistant: "assistant";
28
+ tool: "tool";
29
+ }>;
30
+ content: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
31
+ type: z.ZodLiteral<"text">;
32
+ text: z.ZodString;
33
+ }, z.core.$strict>, z.ZodObject<{
34
+ type: z.ZodLiteral<"image">;
35
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
36
+ kind: z.ZodLiteral<"url">;
37
+ url: z.ZodString;
38
+ }, z.core.$strict>, z.ZodObject<{
39
+ kind: z.ZodLiteral<"inline">;
40
+ mediaType: z.ZodString;
41
+ data: z.ZodString;
42
+ }, z.core.$strict>], "kind">;
43
+ detail: z.ZodOptional<z.ZodEnum<{
44
+ low: "low";
45
+ high: "high";
46
+ auto: "auto";
47
+ }>>;
48
+ }, z.core.$strict>, z.ZodObject<{
49
+ type: z.ZodLiteral<"audio">;
50
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
51
+ kind: z.ZodLiteral<"url">;
52
+ url: z.ZodString;
53
+ }, z.core.$strict>, z.ZodObject<{
54
+ kind: z.ZodLiteral<"inline">;
55
+ mediaType: z.ZodString;
56
+ data: z.ZodString;
57
+ }, z.core.$strict>], "kind">;
58
+ }, z.core.$strict>, z.ZodObject<{
59
+ type: z.ZodLiteral<"file">;
60
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
61
+ kind: z.ZodLiteral<"url">;
62
+ url: z.ZodString;
63
+ }, z.core.$strict>, z.ZodObject<{
64
+ kind: z.ZodLiteral<"inline">;
65
+ mediaType: z.ZodString;
66
+ data: z.ZodString;
67
+ }, z.core.$strict>], "kind">;
68
+ filename: z.ZodOptional<z.ZodString>;
69
+ }, z.core.$strict>, z.ZodObject<{
70
+ type: z.ZodLiteral<"refusal">;
71
+ text: z.ZodString;
72
+ }, z.core.$strict>], "type">>]>>>;
73
+ name: z.ZodOptional<z.ZodString>;
74
+ tool_call_id: z.ZodOptional<z.ZodString>;
75
+ tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
76
+ id: z.ZodString;
77
+ type: z.ZodLiteral<"function">;
78
+ function: z.ZodObject<{
79
+ name: z.ZodString;
80
+ arguments: z.ZodString;
81
+ }, z.core.$strict>;
82
+ }, z.core.$strict>>>;
83
+ }, z.core.$strict>;
84
+ export declare const chatCompletionsRequestSchema: z.ZodObject<{
85
+ model: z.ZodUnion<readonly [z.ZodString, z.ZodEnum<{
86
+ medium: "medium";
87
+ high: "high";
88
+ auto: "auto";
89
+ instant: "instant";
90
+ xhigh: "xhigh";
91
+ pro: "pro";
92
+ ultra: "ultra";
93
+ }>]>;
94
+ messages: z.ZodArray<z.ZodObject<{
95
+ role: z.ZodEnum<{
96
+ user: "user";
97
+ system: "system";
98
+ developer: "developer";
99
+ assistant: "assistant";
100
+ tool: "tool";
101
+ }>;
102
+ content: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
103
+ type: z.ZodLiteral<"text">;
104
+ text: z.ZodString;
105
+ }, z.core.$strict>, z.ZodObject<{
106
+ type: z.ZodLiteral<"image">;
107
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
108
+ kind: z.ZodLiteral<"url">;
109
+ url: z.ZodString;
110
+ }, z.core.$strict>, z.ZodObject<{
111
+ kind: z.ZodLiteral<"inline">;
112
+ mediaType: z.ZodString;
113
+ data: z.ZodString;
114
+ }, z.core.$strict>], "kind">;
115
+ detail: z.ZodOptional<z.ZodEnum<{
116
+ low: "low";
117
+ high: "high";
118
+ auto: "auto";
119
+ }>>;
120
+ }, z.core.$strict>, z.ZodObject<{
121
+ type: z.ZodLiteral<"audio">;
122
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
123
+ kind: z.ZodLiteral<"url">;
124
+ url: z.ZodString;
125
+ }, z.core.$strict>, z.ZodObject<{
126
+ kind: z.ZodLiteral<"inline">;
127
+ mediaType: z.ZodString;
128
+ data: z.ZodString;
129
+ }, z.core.$strict>], "kind">;
130
+ }, z.core.$strict>, z.ZodObject<{
131
+ type: z.ZodLiteral<"file">;
132
+ source: z.ZodDiscriminatedUnion<[z.ZodObject<{
133
+ kind: z.ZodLiteral<"url">;
134
+ url: z.ZodString;
135
+ }, z.core.$strict>, z.ZodObject<{
136
+ kind: z.ZodLiteral<"inline">;
137
+ mediaType: z.ZodString;
138
+ data: z.ZodString;
139
+ }, z.core.$strict>], "kind">;
140
+ filename: z.ZodOptional<z.ZodString>;
141
+ }, z.core.$strict>, z.ZodObject<{
142
+ type: z.ZodLiteral<"refusal">;
143
+ text: z.ZodString;
144
+ }, z.core.$strict>], "type">>]>>>;
145
+ name: z.ZodOptional<z.ZodString>;
146
+ tool_call_id: z.ZodOptional<z.ZodString>;
147
+ tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
148
+ id: z.ZodString;
149
+ type: z.ZodLiteral<"function">;
150
+ function: z.ZodObject<{
151
+ name: z.ZodString;
152
+ arguments: z.ZodString;
153
+ }, z.core.$strict>;
154
+ }, z.core.$strict>>>;
155
+ }, z.core.$strict>>;
156
+ max_tokens: z.ZodOptional<z.ZodNumber>;
157
+ max_completion_tokens: z.ZodOptional<z.ZodNumber>;
158
+ temperature: z.ZodOptional<z.ZodNumber>;
159
+ top_p: z.ZodOptional<z.ZodNumber>;
160
+ frequency_penalty: z.ZodOptional<z.ZodNumber>;
161
+ presence_penalty: z.ZodOptional<z.ZodNumber>;
162
+ seed: z.ZodOptional<z.ZodNumber>;
163
+ stop: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
164
+ stream: z.ZodOptional<z.ZodBoolean>;
165
+ tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
166
+ type: z.ZodLiteral<"function">;
167
+ function: z.ZodObject<{
168
+ name: z.ZodString;
169
+ description: z.ZodOptional<z.ZodString>;
170
+ parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
171
+ strict: z.ZodOptional<z.ZodBoolean>;
172
+ }, z.core.$strict>;
173
+ }, z.core.$strict>>>;
174
+ tool_choice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
175
+ auto: "auto";
176
+ none: "none";
177
+ required: "required";
178
+ }>, z.ZodObject<{
179
+ type: z.ZodLiteral<"function">;
180
+ function: z.ZodObject<{
181
+ name: z.ZodString;
182
+ }, z.core.$strict>;
183
+ }, z.core.$strict>]>>;
184
+ response_format: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
185
+ type: z.ZodEnum<{
186
+ text: "text";
187
+ json_object: "json_object";
188
+ }>;
189
+ }, z.core.$strict>, z.ZodObject<{
190
+ type: z.ZodLiteral<"json_schema">;
191
+ json_schema: z.ZodObject<{
192
+ name: z.ZodString;
193
+ schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
194
+ strict: z.ZodOptional<z.ZodBoolean>;
195
+ }, z.core.$strict>;
196
+ }, z.core.$strict>]>>;
197
+ reasoning_effort: z.ZodOptional<z.ZodEnum<{
198
+ low: "low";
199
+ medium: "medium";
200
+ high: "high";
201
+ }>>;
202
+ modalities: z.ZodOptional<z.ZodArray<z.ZodEnum<{
203
+ text: "text";
204
+ audio: "audio";
205
+ }>>>;
206
+ audio: z.ZodOptional<z.ZodObject<{
207
+ voice: z.ZodString;
208
+ format: z.ZodEnum<{
209
+ mp3: "mp3";
210
+ opus: "opus";
211
+ flac: "flac";
212
+ wav: "wav";
213
+ pcm16: "pcm16";
214
+ }>;
215
+ }, z.core.$strict>>;
216
+ user: z.ZodOptional<z.ZodString>;
217
+ }, z.core.$strict>;
218
+ /** OpenAI's usage block, with the audio members only when audio tokens were metered. */
219
+ export declare const chatCompletionUsageSchema: z.ZodObject<{
220
+ prompt_tokens: z.ZodNumber;
221
+ completion_tokens: z.ZodNumber;
222
+ total_tokens: z.ZodNumber;
223
+ prompt_tokens_details: z.ZodObject<{
224
+ cached_tokens: z.ZodNumber;
225
+ audio_tokens: z.ZodOptional<z.ZodNumber>;
226
+ cached_tokens_details: z.ZodOptional<z.ZodObject<{
227
+ audio_tokens: z.ZodNumber;
228
+ }, z.core.$strict>>;
229
+ }, z.core.$strict>;
230
+ completion_tokens_details: z.ZodObject<{
231
+ reasoning_tokens: z.ZodNumber;
232
+ audio_tokens: z.ZodOptional<z.ZodNumber>;
233
+ }, z.core.$strict>;
234
+ }, z.core.$strict>;
235
+ /**
236
+ * The non-streaming body. Every field is one a stock OpenAI client reads,
237
+ * spelled the way it spells it; the request id rides in `Kaana-Request-Id`.
238
+ */
239
+ export declare const chatCompletionSchema: z.ZodObject<{
240
+ id: z.ZodString;
241
+ object: z.ZodLiteral<"chat.completion">;
242
+ created: z.ZodNumber;
243
+ model: z.ZodString;
244
+ choices: z.ZodArray<z.ZodObject<{
245
+ index: z.ZodNumber;
246
+ message: z.ZodObject<{
247
+ role: z.ZodLiteral<"assistant">;
248
+ content: z.ZodNullable<z.ZodString>;
249
+ audio: z.ZodOptional<z.ZodObject<{
250
+ id: z.ZodString;
251
+ data: z.ZodString;
252
+ transcript: z.ZodString;
253
+ expires_at: z.ZodNumber;
254
+ }, z.core.$strict>>;
255
+ tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
256
+ id: z.ZodString;
257
+ type: z.ZodLiteral<"function">;
258
+ function: z.ZodObject<{
259
+ name: z.ZodString;
260
+ arguments: z.ZodString;
261
+ }, z.core.$strict>;
262
+ }, z.core.$strict>>>;
263
+ }, z.core.$strict>;
264
+ finish_reason: z.ZodString;
265
+ }, z.core.$strict>>;
266
+ usage: z.ZodObject<{
267
+ prompt_tokens: z.ZodNumber;
268
+ completion_tokens: z.ZodNumber;
269
+ total_tokens: z.ZodNumber;
270
+ prompt_tokens_details: z.ZodObject<{
271
+ cached_tokens: z.ZodNumber;
272
+ audio_tokens: z.ZodOptional<z.ZodNumber>;
273
+ cached_tokens_details: z.ZodOptional<z.ZodObject<{
274
+ audio_tokens: z.ZodNumber;
275
+ }, z.core.$strict>>;
276
+ }, z.core.$strict>;
277
+ completion_tokens_details: z.ZodObject<{
278
+ reasoning_tokens: z.ZodNumber;
279
+ audio_tokens: z.ZodOptional<z.ZodNumber>;
280
+ }, z.core.$strict>;
281
+ }, z.core.$strict>;
282
+ }, z.core.$strict>;
283
+ /**
284
+ * One `data:` frame of a streamed completion, terminated by `data: [DONE]`.
285
+ *
286
+ * Reasoning deltas are not carried (the chunk has no field for them and
287
+ * `delta.content` would render private reasoning as the answer), and neither
288
+ * is any route information: a public stream names no provider. Usage rides on
289
+ * a chunk with `choices: []`, which a stock client skips.
290
+ */
291
+ export declare const chatCompletionChunkSchema: z.ZodObject<{
292
+ id: z.ZodString;
293
+ object: z.ZodLiteral<"chat.completion.chunk">;
294
+ created: z.ZodNumber;
295
+ model: z.ZodString;
296
+ choices: z.ZodArray<z.ZodObject<{
297
+ index: z.ZodNumber;
298
+ delta: z.ZodObject<{
299
+ role: z.ZodOptional<z.ZodLiteral<"assistant">>;
300
+ content: z.ZodOptional<z.ZodString>;
301
+ refusal: z.ZodOptional<z.ZodString>;
302
+ audio: z.ZodOptional<z.ZodObject<{
303
+ id: z.ZodString;
304
+ data: z.ZodOptional<z.ZodString>;
305
+ transcript: z.ZodOptional<z.ZodString>;
306
+ expires_at: z.ZodOptional<z.ZodNumber>;
307
+ }, z.core.$strict>>;
308
+ tool_calls: z.ZodOptional<z.ZodArray<z.ZodObject<{
309
+ index: z.ZodNumber;
310
+ id: z.ZodOptional<z.ZodString>;
311
+ type: z.ZodOptional<z.ZodLiteral<"function">>;
312
+ function: z.ZodObject<{
313
+ name: z.ZodOptional<z.ZodString>;
314
+ arguments: z.ZodOptional<z.ZodString>;
315
+ }, z.core.$strict>;
316
+ }, z.core.$strict>>>;
317
+ }, z.core.$strict>;
318
+ finish_reason: z.ZodNullable<z.ZodString>;
319
+ }, z.core.$strict>>;
320
+ usage: z.ZodOptional<z.ZodObject<{
321
+ prompt_tokens: z.ZodNumber;
322
+ completion_tokens: z.ZodNumber;
323
+ total_tokens: z.ZodNumber;
324
+ prompt_tokens_details: z.ZodObject<{
325
+ cached_tokens: z.ZodNumber;
326
+ audio_tokens: z.ZodOptional<z.ZodNumber>;
327
+ cached_tokens_details: z.ZodOptional<z.ZodObject<{
328
+ audio_tokens: z.ZodNumber;
329
+ }, z.core.$strict>>;
330
+ }, z.core.$strict>;
331
+ completion_tokens_details: z.ZodObject<{
332
+ reasoning_tokens: z.ZodNumber;
333
+ audio_tokens: z.ZodOptional<z.ZodNumber>;
334
+ }, z.core.$strict>;
335
+ }, z.core.$strict>>;
336
+ }, z.core.$strict>;
337
+ /**
338
+ * The error body in the OpenAI idiom: the body of a refusal before the first
339
+ * byte, and a `data:` frame when a stream fails after it. `code` is the public
340
+ * vocabulary.
341
+ */
342
+ export declare const chatCompletionErrorSchema: z.ZodObject<{
343
+ error: z.ZodObject<{
344
+ message: z.ZodString;
345
+ type: z.ZodString;
346
+ param: z.ZodNullable<z.ZodString>;
347
+ code: z.ZodEnum<{
348
+ invalid_request: "invalid_request";
349
+ authentication_failed: "authentication_failed";
350
+ permission_denied: "permission_denied";
351
+ insufficient_scope: "insufficient_scope";
352
+ model_not_found: "model_not_found";
353
+ unsupported_modality: "unsupported_modality";
354
+ context_length_exceeded: "context_length_exceeded";
355
+ request_too_large: "request_too_large";
356
+ output_limit_exceeded: "output_limit_exceeded";
357
+ idempotency_conflict: "idempotency_conflict";
358
+ insufficient_balance: "insufficient_balance";
359
+ spending_limit_exceeded: "spending_limit_exceeded";
360
+ quota_exceeded: "quota_exceeded";
361
+ byok_credential_invalid: "byok_credential_invalid";
362
+ policy_violation: "policy_violation";
363
+ commercial_permission_denied: "commercial_permission_denied";
364
+ no_route_available: "no_route_available";
365
+ upstream_content_filtered: "upstream_content_filtered";
366
+ cancelled: "cancelled";
367
+ rate_limited: "rate_limited";
368
+ provider_error: "provider_error";
369
+ provider_timeout: "provider_timeout";
370
+ provider_overloaded: "provider_overloaded";
371
+ service_unavailable: "service_unavailable";
372
+ internal_error: "internal_error";
373
+ }>;
374
+ }, z.core.$strict>;
375
+ }, z.core.$strict>;
376
+ export type ChatCompletionMessage = z.infer<typeof chatCompletionMessageSchema>;
377
+ export type ChatCompletionsRequest = z.infer<typeof chatCompletionsRequestSchema>;
378
+ export type ChatCompletionUsage = z.infer<typeof chatCompletionUsageSchema>;
379
+ export type ChatCompletion = z.infer<typeof chatCompletionSchema>;
380
+ export type ChatCompletionChunk = z.infer<typeof chatCompletionChunkSchema>;
381
+ export type ChatCompletionError = z.infer<typeof chatCompletionErrorSchema>;
@@ -0,0 +1,321 @@
1
+ /**
2
+ * `POST /v1/chat/completions` — the OpenAI-compatible surface.
3
+ *
4
+ * It speaks the flat OpenAI request and response shapes so an unmodified OpenAI
5
+ * SDK works against `baseURL: 'https://kaana.ai/v1'` with an `oxy_sk_…` key, and
6
+ * it gains NO Kaana-specific request field: a capability with no OpenAI
7
+ * representation lives on `/v1/responses`. `.strict()` everywhere: a stock SDK
8
+ * sending a parameter Kaana does not implement is told so rather than having it
9
+ * silently dropped.
10
+ *
11
+ * Moved from the Oxy edge (`packages/api/src/schemas/inferenceEdge.schemas.ts`)
12
+ * by Kaana ADR 0002. `model` names a model reference or a power level. The
13
+ * stream chunk and the error body are written down here for the first time;
14
+ * the Oxy edge rendered them in code only.
15
+ */
16
+ import { z } from 'zod';
17
+ import { reasoningEffortSchema } from './catalogue.js';
18
+ import { publicErrorCodeSchema } from './errors.js';
19
+ import { inferenceContentPartSchema } from './messages.js';
20
+ import { modelTargetSchema } from './responses.js';
21
+ /** `stop` in the OpenAI dialect: one sequence or a list of them. */
22
+ const openAiStopSchema = z.union([
23
+ z.string().min(1).max(256),
24
+ z.array(z.string().min(1).max(256)).max(8),
25
+ ]);
26
+ const openAiToolCallSchema = z
27
+ .object({
28
+ id: z.string().min(1).max(128),
29
+ type: z.literal('function'),
30
+ function: z
31
+ .object({
32
+ name: z.string().min(1).max(128),
33
+ arguments: z.string(),
34
+ })
35
+ .strict(),
36
+ })
37
+ .strict();
38
+ /**
39
+ * One OpenAI message. `content` accepts both the string form and the parts
40
+ * array, because both are in wide use and rejecting the string form would fail
41
+ * the stock SDK on its most common call.
42
+ */
43
+ export const chatCompletionMessageSchema = z
44
+ .object({
45
+ role: z.enum(['system', 'developer', 'user', 'assistant', 'tool']),
46
+ content: z
47
+ .union([z.string(), z.array(inferenceContentPartSchema)])
48
+ .nullable()
49
+ .optional(),
50
+ name: z.string().max(128).optional(),
51
+ tool_call_id: z.string().min(1).max(128).optional(),
52
+ tool_calls: z.array(openAiToolCallSchema).optional(),
53
+ })
54
+ .strict();
55
+ const openAiToolSchema = z
56
+ .object({
57
+ type: z.literal('function'),
58
+ function: z
59
+ .object({
60
+ name: z.string().min(1).max(128),
61
+ description: z.string().max(2000).optional(),
62
+ parameters: z.record(z.string(), z.unknown()),
63
+ strict: z.boolean().optional(),
64
+ })
65
+ .strict(),
66
+ })
67
+ .strict();
68
+ const openAiToolChoiceSchema = z.union([
69
+ z.enum(['auto', 'none', 'required']),
70
+ z
71
+ .object({
72
+ type: z.literal('function'),
73
+ function: z.object({ name: z.string().min(1).max(128) }).strict(),
74
+ })
75
+ .strict(),
76
+ ]);
77
+ /**
78
+ * OpenAI's `audio` output parameter for its audio chat models. `aac` is
79
+ * refused (no route could be held to it); `pcm16` is OpenAI's spelling of the
80
+ * contract's `pcm`.
81
+ */
82
+ const openAiAudioOutputSchema = z
83
+ .object({
84
+ voice: z.string().min(1).max(64),
85
+ format: z.enum(['wav', 'mp3', 'flac', 'opus', 'pcm16']),
86
+ })
87
+ .strict();
88
+ const openAiResponseFormatSchema = z.union([
89
+ z.object({ type: z.enum(['text', 'json_object']) }).strict(),
90
+ z
91
+ .object({
92
+ type: z.literal('json_schema'),
93
+ json_schema: z
94
+ .object({
95
+ name: z.string().min(1).max(128),
96
+ schema: z.record(z.string(), z.unknown()),
97
+ strict: z.boolean().optional(),
98
+ })
99
+ .strict(),
100
+ })
101
+ .strict(),
102
+ ]);
103
+ export const chatCompletionsRequestSchema = z
104
+ .object({
105
+ /**
106
+ * A model reference (`publisher/model[@revision]`) or a power level. An
107
+ * OpenAI vendor model name (`gpt-4o`) is neither and does not resolve: it is
108
+ * refused as unknown, never mapped to a publisher.
109
+ */
110
+ model: modelTargetSchema,
111
+ messages: z.array(chatCompletionMessageSchema).min(1),
112
+ max_tokens: z.number().int().positive().safe().optional(),
113
+ max_completion_tokens: z.number().int().positive().safe().optional(),
114
+ temperature: z.number().min(0).max(2).optional(),
115
+ top_p: z.number().min(0).max(1).optional(),
116
+ frequency_penalty: z.number().min(-2).max(2).optional(),
117
+ presence_penalty: z.number().min(-2).max(2).optional(),
118
+ seed: z.number().int().safe().optional(),
119
+ stop: openAiStopSchema.optional(),
120
+ stream: z.boolean().optional(),
121
+ tools: z.array(openAiToolSchema).max(128).optional(),
122
+ tool_choice: openAiToolChoiceSchema.optional(),
123
+ response_format: openAiResponseFormatSchema.optional(),
124
+ /** Refused when the resolved model does not advertise the effort. */
125
+ reasoning_effort: reasoningEffortSchema.optional(),
126
+ /** `["text", "audio"]` asks an audio chat model to answer in speech and its transcript. */
127
+ modalities: z
128
+ .array(z.enum(['text', 'audio']))
129
+ .min(1)
130
+ .max(2)
131
+ .optional(),
132
+ /** The voice and format of spoken output. Requires `modalities` to include `audio`. */
133
+ audio: openAiAudioOutputSchema.optional(),
134
+ /**
135
+ * OpenAI's end-user attribution field: the DELEGATED user id, attribution
136
+ * only. `X-Oxy-User-Id` wins when both are present.
137
+ */
138
+ user: z.string().min(1).max(64).optional(),
139
+ })
140
+ .strict()
141
+ .superRefine((request, ctx) => {
142
+ if (request.max_tokens !== undefined && request.max_completion_tokens !== undefined) {
143
+ ctx.addIssue({
144
+ code: 'custom',
145
+ path: ['max_completion_tokens'],
146
+ message: 'send max_tokens or max_completion_tokens, not both',
147
+ });
148
+ }
149
+ const modalities = request.modalities ?? ['text'];
150
+ if (new Set(modalities).size !== modalities.length) {
151
+ ctx.addIssue({
152
+ code: 'custom',
153
+ path: ['modalities'],
154
+ message: 'each modality is named at most once',
155
+ });
156
+ }
157
+ if (!modalities.includes('text')) {
158
+ ctx.addIssue({
159
+ code: 'custom',
160
+ path: ['modalities'],
161
+ message: 'modalities must include text; spoken output always carries its transcript',
162
+ });
163
+ }
164
+ const spoken = modalities.includes('audio');
165
+ if (spoken && request.audio === undefined) {
166
+ ctx.addIssue({
167
+ code: 'custom',
168
+ path: ['audio'],
169
+ message: 'modalities including audio require the audio parameter (voice and format)',
170
+ });
171
+ }
172
+ if (!spoken && request.audio !== undefined) {
173
+ ctx.addIssue({
174
+ code: 'custom',
175
+ path: ['modalities'],
176
+ message: 'the audio parameter requires modalities to include audio',
177
+ });
178
+ }
179
+ if (spoken && request.stream === true && request.audio?.format !== 'pcm16') {
180
+ ctx.addIssue({
181
+ code: 'custom',
182
+ path: ['audio', 'format'],
183
+ message: 'streamed audio output is pcm16; the other formats exist only whole',
184
+ });
185
+ }
186
+ });
187
+ /** OpenAI's usage block, with the audio members only when audio tokens were metered. */
188
+ export const chatCompletionUsageSchema = z
189
+ .object({
190
+ prompt_tokens: z.number().int().nonnegative(),
191
+ completion_tokens: z.number().int().nonnegative(),
192
+ total_tokens: z.number().int().nonnegative(),
193
+ prompt_tokens_details: z
194
+ .object({
195
+ cached_tokens: z.number().int().nonnegative(),
196
+ audio_tokens: z.number().int().nonnegative().optional(),
197
+ cached_tokens_details: z
198
+ .object({ audio_tokens: z.number().int().nonnegative() })
199
+ .strict()
200
+ .optional(),
201
+ })
202
+ .strict(),
203
+ completion_tokens_details: z
204
+ .object({
205
+ reasoning_tokens: z.number().int().nonnegative(),
206
+ audio_tokens: z.number().int().nonnegative().optional(),
207
+ })
208
+ .strict(),
209
+ })
210
+ .strict();
211
+ /**
212
+ * The non-streaming body. Every field is one a stock OpenAI client reads,
213
+ * spelled the way it spells it; the request id rides in `Kaana-Request-Id`.
214
+ */
215
+ export const chatCompletionSchema = z
216
+ .object({
217
+ id: z.string().min(1),
218
+ object: z.literal('chat.completion'),
219
+ /** Unix seconds, as OpenAI's own field is. */
220
+ created: z.number().int().nonnegative(),
221
+ /** The revision that served the request. */
222
+ model: z.string().min(1),
223
+ choices: z.array(z
224
+ .object({
225
+ index: z.number().int().nonnegative(),
226
+ message: z
227
+ .object({
228
+ role: z.literal('assistant'),
229
+ /** `null` when the answer is spoken: the words are in `audio.transcript`. */
230
+ content: z.string().nullable(),
231
+ /** Spoken output. `expires_at` is `created`: Kaana retains no audio. */
232
+ audio: z
233
+ .object({
234
+ id: z.string().min(1),
235
+ data: z.string(),
236
+ transcript: z.string(),
237
+ expires_at: z.number().int().nonnegative(),
238
+ })
239
+ .strict()
240
+ .optional(),
241
+ tool_calls: z.array(openAiToolCallSchema).optional(),
242
+ })
243
+ .strict(),
244
+ /**
245
+ * OpenAI's vocabulary, which has neither `cancelled` nor `refusal`:
246
+ * both are reported as `stop` here.
247
+ */
248
+ finish_reason: z.string().min(1),
249
+ })
250
+ .strict()),
251
+ usage: chatCompletionUsageSchema,
252
+ })
253
+ .strict();
254
+ /**
255
+ * One `data:` frame of a streamed completion, terminated by `data: [DONE]`.
256
+ *
257
+ * Reasoning deltas are not carried (the chunk has no field for them and
258
+ * `delta.content` would render private reasoning as the answer), and neither
259
+ * is any route information: a public stream names no provider. Usage rides on
260
+ * a chunk with `choices: []`, which a stock client skips.
261
+ */
262
+ export const chatCompletionChunkSchema = z
263
+ .object({
264
+ id: z.string().min(1),
265
+ object: z.literal('chat.completion.chunk'),
266
+ created: z.number().int().nonnegative(),
267
+ model: z.string().min(1),
268
+ choices: z.array(z
269
+ .object({
270
+ index: z.number().int().nonnegative(),
271
+ delta: z
272
+ .object({
273
+ role: z.literal('assistant').optional(),
274
+ content: z.string().optional(),
275
+ refusal: z.string().optional(),
276
+ audio: z
277
+ .object({
278
+ id: z.string().min(1),
279
+ data: z.string().optional(),
280
+ transcript: z.string().optional(),
281
+ expires_at: z.number().int().nonnegative().optional(),
282
+ })
283
+ .strict()
284
+ .optional(),
285
+ tool_calls: z
286
+ .array(z
287
+ .object({
288
+ index: z.number().int().nonnegative(),
289
+ id: z.string().min(1).optional(),
290
+ type: z.literal('function').optional(),
291
+ function: z
292
+ .object({ name: z.string().optional(), arguments: z.string().optional() })
293
+ .strict(),
294
+ })
295
+ .strict())
296
+ .optional(),
297
+ })
298
+ .strict(),
299
+ finish_reason: z.string().min(1).nullable(),
300
+ })
301
+ .strict()),
302
+ usage: chatCompletionUsageSchema.optional(),
303
+ })
304
+ .strict();
305
+ /**
306
+ * The error body in the OpenAI idiom: the body of a refusal before the first
307
+ * byte, and a `data:` frame when a stream fails after it. `code` is the public
308
+ * vocabulary.
309
+ */
310
+ export const chatCompletionErrorSchema = z
311
+ .object({
312
+ error: z
313
+ .object({
314
+ message: z.string().min(1),
315
+ type: z.string().min(1),
316
+ param: z.string().nullable(),
317
+ code: publicErrorCodeSchema,
318
+ })
319
+ .strict(),
320
+ })
321
+ .strict();