@kaana.ai/contracts 4.4.1 → 6.0.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.
@@ -783,6 +783,10 @@ export declare const declaredModelSchema: z.ZodObject<{
783
783
  currency: z.ZodString;
784
784
  }, z.core.$strict>>;
785
785
  }, z.core.$strict>>;
786
+ pricePerMinute: z.ZodOptional<z.ZodObject<{
787
+ amount: z.core.$ZodBranded<z.ZodString, "ExactDecimal", "out">;
788
+ currency: z.ZodString;
789
+ }, z.core.$strict>>;
786
790
  evaluations: z.ZodDefault<z.ZodArray<z.ZodObject<{
787
791
  suite: z.ZodString;
788
792
  metric: z.ZodString;
@@ -1007,6 +1011,10 @@ export declare const declaredCatalogueSchema: z.ZodObject<{
1007
1011
  currency: z.ZodString;
1008
1012
  }, z.core.$strict>>;
1009
1013
  }, z.core.$strict>>;
1014
+ pricePerMinute: z.ZodOptional<z.ZodObject<{
1015
+ amount: z.core.$ZodBranded<z.ZodString, "ExactDecimal", "out">;
1016
+ currency: z.ZodString;
1017
+ }, z.core.$strict>>;
1010
1018
  evaluations: z.ZodDefault<z.ZodArray<z.ZodObject<{
1011
1019
  suite: z.ZodString;
1012
1020
  metric: z.ZodString;
@@ -104,7 +104,6 @@ export declare const realtimeSessionRequestSchema: z.ZodObject<{
104
104
  name: z.ZodString;
105
105
  description: z.ZodOptional<z.ZodString>;
106
106
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
107
- strict: z.ZodOptional<z.ZodBoolean>;
108
107
  }, z.core.$strict>>>;
109
108
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
110
109
  auto: "auto";
@@ -114,7 +113,6 @@ export declare const realtimeSessionRequestSchema: z.ZodObject<{
114
113
  type: z.ZodLiteral<"function">;
115
114
  name: z.ZodString;
116
115
  }, z.core.$strict>]>>;
117
- temperature: z.ZodOptional<z.ZodNumber>;
118
116
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
119
117
  }, z.core.$strict>;
120
118
  limits: z.ZodObject<{
@@ -246,7 +244,6 @@ export declare const realtimeSessionCreatedEventSchema: z.ZodObject<{
246
244
  name: z.ZodString;
247
245
  description: z.ZodOptional<z.ZodString>;
248
246
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
249
- strict: z.ZodOptional<z.ZodBoolean>;
250
247
  }, z.core.$strict>>>;
251
248
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
252
249
  auto: "auto";
@@ -256,7 +253,6 @@ export declare const realtimeSessionCreatedEventSchema: z.ZodObject<{
256
253
  type: z.ZodLiteral<"function">;
257
254
  name: z.ZodString;
258
255
  }, z.core.$strict>]>>;
259
- temperature: z.ZodOptional<z.ZodNumber>;
260
256
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
261
257
  }, z.core.$strict>;
262
258
  limits: z.ZodObject<{
@@ -505,7 +501,6 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
505
501
  name: z.ZodString;
506
502
  description: z.ZodOptional<z.ZodString>;
507
503
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
508
- strict: z.ZodOptional<z.ZodBoolean>;
509
504
  }, z.core.$strict>>>;
510
505
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
511
506
  auto: "auto";
@@ -515,7 +510,6 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
515
510
  type: z.ZodLiteral<"function">;
516
511
  name: z.ZodString;
517
512
  }, z.core.$strict>]>>;
518
- temperature: z.ZodOptional<z.ZodNumber>;
519
513
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
520
514
  }, z.core.$strict>;
521
515
  limits: z.ZodObject<{
@@ -583,7 +577,6 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
583
577
  name: z.ZodString;
584
578
  description: z.ZodOptional<z.ZodString>;
585
579
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
586
- strict: z.ZodOptional<z.ZodBoolean>;
587
580
  }, z.core.$strict>>>;
588
581
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
589
582
  auto: "auto";
@@ -593,7 +586,6 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
593
586
  type: z.ZodLiteral<"function">;
594
587
  name: z.ZodString;
595
588
  }, z.core.$strict>]>>;
596
- temperature: z.ZodOptional<z.ZodNumber>;
597
589
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
598
590
  }, z.core.$strict>;
599
591
  schemaVersion: z.ZodLiteral<1>;
@@ -344,6 +344,10 @@ export declare const inferenceRequestSchema: z.ZodObject<{
344
344
  }>;
345
345
  speed: z.ZodOptional<z.ZodNumber>;
346
346
  }, z.core.$strict>>;
347
+ transcription: z.ZodOptional<z.ZodObject<{
348
+ language: z.ZodOptional<z.ZodString>;
349
+ prompt: z.ZodOptional<z.ZodString>;
350
+ }, z.core.$strict>>;
347
351
  audioOutput: z.ZodOptional<z.ZodObject<{
348
352
  voice: z.ZodString;
349
353
  format: z.ZodEnum<{
@@ -619,6 +623,10 @@ export declare const scopedInferenceRequestSchema: z.ZodObject<{
619
623
  }>;
620
624
  speed: z.ZodOptional<z.ZodNumber>;
621
625
  }, z.core.$strict>>;
626
+ transcription: z.ZodOptional<z.ZodObject<{
627
+ language: z.ZodOptional<z.ZodString>;
628
+ prompt: z.ZodOptional<z.ZodString>;
629
+ }, z.core.$strict>>;
622
630
  audioOutput: z.ZodOptional<z.ZodObject<{
623
631
  voice: z.ZodString;
624
632
  format: z.ZodEnum<{
@@ -864,6 +872,10 @@ export declare const privateAutoInferenceRequestSchema: z.ZodObject<{
864
872
  high: "high";
865
873
  }>;
866
874
  }, z.core.$strict>>;
875
+ transcription: z.ZodOptional<z.ZodObject<{
876
+ language: z.ZodOptional<z.ZodString>;
877
+ prompt: z.ZodOptional<z.ZodString>;
878
+ }, z.core.$strict>>;
867
879
  tools: z.ZodDefault<z.ZodArray<z.ZodObject<{
868
880
  type: z.ZodLiteral<"function">;
869
881
  name: z.ZodString;
@@ -7,7 +7,7 @@ import { z } from 'zod';
7
7
  import { inferenceApiFormatSchema, inferenceModalitySchema } from '../public/catalogue.js';
8
8
  import { decisionInputSchema } from '../public/decisions.js';
9
9
  import { idempotencyKeySchema, inferenceTimestampSchema } from '../public/identifiers.js';
10
- import { inferenceAudioOutputParametersSchema, inferenceMessageSchema, inferenceReasoningSchema, inferenceSpeechParametersSchema, responseFormatSchema, samplingParametersSchema, toolChoiceSchema, toolDefinitionSchema, } from '../public/messages.js';
10
+ import { inferenceAudioOutputParametersSchema, inferenceMessageSchema, inferenceReasoningSchema, inferenceSpeechParametersSchema, inferenceTranscriptionParametersSchema, responseFormatSchema, samplingParametersSchema, toolChoiceSchema, toolDefinitionSchema, } from '../public/messages.js';
11
11
  import { routingPolicyReferenceSchema } from '../public/policy.js';
12
12
  import { inferenceAttributionSchema } from './attribution.js';
13
13
  import { PRIVATE_AUTO_REQUEST_ENVELOPE_VERSION, privateAutoExecutionSchema, privateAutoInputSchema, } from './privateAutoExecution.js';
@@ -96,6 +96,8 @@ const inferenceRequestObjectSchema = z.object({
96
96
  /** Absent means the route's own default reasoning behaviour. */
97
97
  reasoning: inferenceReasoningSchema.optional(),
98
98
  speech: inferenceSpeechParametersSchema.optional(),
99
+ /** File transcription parameters. Contract set 4.5.0. */
100
+ transcription: inferenceTranscriptionParametersSchema.optional(),
99
101
  /** Spoken output from a conversational model. Contract set 3.2.0. */
100
102
  audioOutput: inferenceAudioOutputParametersSchema.optional(),
101
103
  tools: z.array(toolDefinitionSchema).default([]),
@@ -164,6 +166,7 @@ export const inferenceRequestSchema = inferenceRequestObjectSchema.superRefine((
164
166
  request.responseFormat !== undefined ||
165
167
  request.reasoning !== undefined ||
166
168
  request.speech !== undefined ||
169
+ request.transcription !== undefined ||
167
170
  request.audioOutput !== undefined) {
168
171
  ctx.addIssue({
169
172
  code: 'custom',
@@ -191,6 +194,16 @@ export const inferenceRequestSchema = inferenceRequestObjectSchema.superRefine((
191
194
  message: 'speech parameters require the audio_speech API format',
192
195
  });
193
196
  }
197
+ if (request.transcription !== undefined &&
198
+ (request.client.apiFormat !== 'audio_transcriptions' ||
199
+ request.modality !== 'audio' ||
200
+ request.input.format !== 'messages')) {
201
+ ctx.addIssue({
202
+ code: 'custom',
203
+ path: ['transcription'],
204
+ message: 'transcription parameters require the audio_transcriptions API format with audio messages input',
205
+ });
206
+ }
194
207
  if (request.audioOutput !== undefined) {
195
208
  if (request.client.apiFormat !== 'chat_completions') {
196
209
  ctx.addIssue({
@@ -8,6 +8,7 @@
8
8
  * (decision 9) and transcription are new in contract set 4.0.0.
9
9
  */
10
10
  import { z } from 'zod';
11
+ import { type AudioInputMediaType } from './audioFormats.js';
11
12
  import type { ModelAudioCapabilities } from './catalogue.js';
12
13
  /** The longest text one speech request may carry, before any model's own limit. */
13
14
  export declare const MAX_SPEECH_INPUT_CHARACTERS = 100000;
@@ -248,11 +249,6 @@ export declare const transcriptionRequestSchema: z.ZodObject<{
248
249
  model: z.ZodString;
249
250
  language: z.ZodOptional<z.ZodString>;
250
251
  prompt: z.ZodOptional<z.ZodString>;
251
- timestamps: z.ZodOptional<z.ZodEnum<{
252
- none: "none";
253
- segment: "segment";
254
- word: "word";
255
- }>>;
256
252
  }, z.core.$strict>;
257
253
  /**
258
254
  * The longest audio one transcription request may carry, when its container
@@ -277,11 +273,6 @@ export declare const transcriptionJsonRequestSchema: z.ZodObject<{
277
273
  model: z.ZodString;
278
274
  language: z.ZodOptional<z.ZodString>;
279
275
  prompt: z.ZodOptional<z.ZodString>;
280
- timestamps: z.ZodOptional<z.ZodEnum<{
281
- none: "none";
282
- segment: "segment";
283
- word: "word";
284
- }>>;
285
276
  audio: z.ZodObject<{
286
277
  mediaType: z.ZodEnum<{
287
278
  "audio/mpeg": "audio/mpeg";
@@ -296,7 +287,7 @@ export declare const transcriptionJsonRequestSchema: z.ZodObject<{
296
287
  data: z.ZodString;
297
288
  }, z.core.$strict>;
298
289
  }, z.core.$strict>;
299
- /** The response. Segments or words are present only when the request asked for them. */
290
+ /** The response. */
300
291
  export declare const transcriptionSchema: z.ZodObject<{
301
292
  schemaVersion: z.ZodLiteral<1>;
302
293
  requestId: z.ZodString;
@@ -304,16 +295,6 @@ export declare const transcriptionSchema: z.ZodObject<{
304
295
  text: z.ZodString;
305
296
  language: z.ZodOptional<z.ZodString>;
306
297
  durationMs: z.ZodOptional<z.ZodNumber>;
307
- segments: z.ZodOptional<z.ZodArray<z.ZodObject<{
308
- text: z.ZodString;
309
- startMs: z.ZodNumber;
310
- endMs: z.ZodNumber;
311
- }, z.core.$strict>>>;
312
- words: z.ZodOptional<z.ZodArray<z.ZodObject<{
313
- word: z.ZodString;
314
- startMs: z.ZodNumber;
315
- endMs: z.ZodNumber;
316
- }, z.core.$strict>>>;
317
298
  usage: z.ZodArray<z.ZodObject<{
318
299
  unit: z.ZodEnum<{
319
300
  input_tokens: "input_tokens";
@@ -336,6 +317,22 @@ export declare const transcriptionSchema: z.ZodObject<{
336
317
  quantity: z.ZodNumber;
337
318
  }, z.core.$strict>>;
338
319
  }, z.core.$strict>;
320
+ /** Why a transcription request cannot be served by a model, before anything is held. */
321
+ export interface TranscriptionRequestIssue {
322
+ /** The request's field at fault, as `invalid_request.param` names it. */
323
+ readonly param: 'file';
324
+ readonly message: string;
325
+ }
326
+ /**
327
+ * Check a transcription upload against the model's published `audio` — the
328
+ * transcription counterpart of {@link checkSpeechRequest}. Kaana refuses an
329
+ * upload in a format the model does not read with `invalid_request` and
330
+ * `param: 'file'` BEFORE asking Oxy for a grant. A language or a prompt is
331
+ * never refused: Kaana sends the provider its spelling of the language, or
332
+ * none for the model to detect, and the prompt where it is taken (Kaana ADR
333
+ * 0003). `mediaType` is the upload's.
334
+ */
335
+ export declare function checkTranscriptionRequest(mediaType: AudioInputMediaType, audio: ModelAudioCapabilities): TranscriptionRequestIssue[];
339
336
  export type SpeechStreamFormat = z.infer<typeof speechStreamFormatSchema>;
340
337
  export type SpeechRequest = z.infer<typeof speechRequestSchema>;
341
338
  export type SpeechAudioDeltaEvent = z.infer<typeof speechAudioDeltaEventSchema>;
@@ -160,12 +160,16 @@ export const MAX_TRANSCRIPTION_FILE_BYTES = 20 * 1024 * 1024;
160
160
  export const transcriptionRequestSchema = z
161
161
  .object({
162
162
  model: modelReferenceSchema,
163
- /** The spoken language, when known; validated against the model's `audio.languages`. */
163
+ /**
164
+ * The spoken language, when known, as the client's own BCP 47 tag. Kaana
165
+ * sends the provider its spelling of it, or none for the model to detect.
166
+ */
164
167
  language: languageTagSchema.optional(),
165
- /** Vocabulary or context that helps the model; never an instruction. */
168
+ /**
169
+ * A hint — vocabulary or context that helps the model, never an
170
+ * instruction — used where the model takes one.
171
+ */
166
172
  prompt: z.string().max(4096).optional(),
167
- /** Absent means `none`. */
168
- timestamps: z.enum(['none', 'segment', 'word']).optional(),
169
173
  })
170
174
  .strict();
171
175
  /**
@@ -201,11 +205,7 @@ export const transcriptionJsonRequestSchema = transcriptionRequestSchema
201
205
  .strict(),
202
206
  })
203
207
  .strict();
204
- const timedSpanFields = {
205
- startMs: z.number().int().nonnegative().safe(),
206
- endMs: z.number().int().nonnegative().safe(),
207
- };
208
- /** The response. Segments or words are present only when the request asked for them. */
208
+ /** The response. */
209
209
  export const transcriptionSchema = z
210
210
  .object({
211
211
  schemaVersion: z.literal(1),
@@ -213,24 +213,24 @@ export const transcriptionSchema = z
213
213
  /** The revision that actually served the request. */
214
214
  model: modelReferenceSchema,
215
215
  text: z.string(),
216
- /** The language the model heard, when it reports one. */
216
+ /** The language the model heard, when its provider reports it as a tag. */
217
217
  language: languageTagSchema.optional(),
218
+ /** The audio's duration, measured from its container before the grant. */
218
219
  durationMs: z.number().int().nonnegative().safe().optional(),
219
- segments: z.array(z.object({ ...timedSpanFields, text: z.string() }).strict()).optional(),
220
- words: z.array(z.object({ ...timedSpanFields, word: z.string() }).strict()).optional(),
221
220
  usage: usageSchema,
222
221
  })
223
- .strict()
224
- .superRefine((transcription, ctx) => {
225
- for (const field of ['segments', 'words']) {
226
- for (const [index, span] of (transcription[field] ?? []).entries()) {
227
- if (span.endMs < span.startMs) {
228
- ctx.addIssue({
229
- code: 'custom',
230
- path: [field, index, 'endMs'],
231
- message: 'a span cannot end before it starts',
232
- });
233
- }
234
- }
235
- }
236
- });
222
+ .strict();
223
+ /**
224
+ * Check a transcription upload against the model's published `audio` — the
225
+ * transcription counterpart of {@link checkSpeechRequest}. Kaana refuses an
226
+ * upload in a format the model does not read with `invalid_request` and
227
+ * `param: 'file'` BEFORE asking Oxy for a grant. A language or a prompt is
228
+ * never refused: Kaana sends the provider its spelling of the language, or
229
+ * none for the model to detect, and the prompt where it is taken (Kaana ADR
230
+ * 0003). `mediaType` is the upload's.
231
+ */
232
+ export function checkTranscriptionRequest(mediaType, audio) {
233
+ return audio.audioFormats.input.includes(mediaType)
234
+ ? []
235
+ : [{ param: 'file', message: `this model does not take ${mediaType} audio` }];
236
+ }
@@ -50,6 +50,14 @@ export declare const realtimeAudioFormatSchema: z.ZodEnum<{
50
50
  g711_ulaw: "g711_ulaw";
51
51
  g711_alaw: "g711_alaw";
52
52
  }>;
53
+ /**
54
+ * What a session's responses produce. Declared here, beside the encodings,
55
+ * since contract set 5.0.0.
56
+ */
57
+ export declare const realtimeOutputModalitySchema: z.ZodEnum<{
58
+ text: "text";
59
+ audio: "audio";
60
+ }>;
53
61
  /**
54
62
  * The media type a speech request's `response_format` produces. A client
55
63
  * knows it before the first byte, which is why the speech stream events do
@@ -42,6 +42,11 @@ export const audioInputMediaTypeSchema = z.enum([
42
42
  * catalogue cannot import the realtime module that imports it.
43
43
  */
44
44
  export const realtimeAudioFormatSchema = z.enum(['pcm16_24khz', 'g711_ulaw', 'g711_alaw']);
45
+ /**
46
+ * What a session's responses produce. Declared here, beside the encodings,
47
+ * since contract set 5.0.0.
48
+ */
49
+ export const realtimeOutputModalitySchema = z.enum(['text', 'audio']);
45
50
  const SPEECH_MEDIA_TYPES = {
46
51
  mp3: 'audio/mpeg',
47
52
  opus: 'audio/ogg',
@@ -352,6 +352,12 @@ export declare const voiceSchema: z.ZodObject<{
352
352
  * none; a caller that needs a language then cannot choose the model.
353
353
  * `gender` is published only where it has been reviewed against the
354
354
  * provider's own catalogue; absent is unknown.
355
+ *
356
+ * A model's `languages` describe it; they are not a list a request must pick
357
+ * from. A request names the client's own BCP 47 tag, and Kaana sends the
358
+ * provider its spelling of that language, or none for the model to detect
359
+ * (Kaana ADR 0003). A transcription model's `audioFormats.input` are the
360
+ * uploads it reads.
355
361
  */
356
362
  export declare const modelAudioCapabilitiesSchema: z.ZodObject<{
357
363
  voices: z.ZodArray<z.ZodObject<{
@@ -573,6 +579,10 @@ export declare const modelSchema: z.ZodObject<{
573
579
  currency: z.ZodString;
574
580
  }, z.core.$strict>>;
575
581
  }, z.core.$strict>>;
582
+ pricePerMinute: z.ZodOptional<z.ZodObject<{
583
+ amount: z.core.$ZodBranded<z.ZodString, "ExactDecimal", "out">;
584
+ currency: z.ZodString;
585
+ }, z.core.$strict>>;
576
586
  deprecation: z.ZodObject<{
577
587
  status: z.ZodEnum<{
578
588
  active: "active";
@@ -788,6 +798,10 @@ export declare const modelListSchema: z.ZodObject<{
788
798
  currency: z.ZodString;
789
799
  }, z.core.$strict>>;
790
800
  }, z.core.$strict>>;
801
+ pricePerMinute: z.ZodOptional<z.ZodObject<{
802
+ amount: z.core.$ZodBranded<z.ZodString, "ExactDecimal", "out">;
803
+ currency: z.ZodString;
804
+ }, z.core.$strict>>;
791
805
  deprecation: z.ZodObject<{
792
806
  status: z.ZodEnum<{
793
807
  active: "active";
@@ -6,7 +6,7 @@
6
6
  import { z } from 'zod';
7
7
  import { inferenceDateSchema, inferenceHttpsUrlSchema, inferenceRegionSchema, inferenceTimestampSchema, modelIdSchema, modelReferenceSchema, modelRevisionLabelSchema, publisherSlugSchema, } from './identifiers.js';
8
8
  import { audioInputMediaTypeSchema, languageTagSchema, realtimeAudioFormatSchema, } from './audioFormats.js';
9
- import { priceSnapshotSchema } from './money.js';
9
+ import { moneySchema, priceSnapshotSchema } from './money.js';
10
10
  import { inferenceAudioMediaTypeSchema } from './streamEvents.js';
11
11
  /** Input/request modalities; structured decisions are an output, never an input. */
12
12
  export const inferenceModalitySchema = z.enum(['text', 'image', 'audio', 'video', 'embedding']);
@@ -378,6 +378,12 @@ export const voiceSchema = z
378
378
  * none; a caller that needs a language then cannot choose the model.
379
379
  * `gender` is published only where it has been reviewed against the
380
380
  * provider's own catalogue; absent is unknown.
381
+ *
382
+ * A model's `languages` describe it; they are not a list a request must pick
383
+ * from. A request names the client's own BCP 47 tag, and Kaana sends the
384
+ * provider its spelling of that language, or none for the model to detect
385
+ * (Kaana ADR 0003). A transcription model's `audioFormats.input` are the
386
+ * uploads it reads.
381
387
  */
382
388
  export const modelAudioCapabilitiesSchema = z
383
389
  .object({
@@ -469,6 +475,14 @@ export const modelSchema = z.object({
469
475
  dataPolicy: inferenceDataPolicySchema,
470
476
  /** Oxy's list price. Absent for a model a customer cannot buy per unit (BYOK-only). */
471
477
  pricing: priceSnapshotSchema.optional(),
478
+ /**
479
+ * Kaana's price of one minute of this model's work, whatever units its
480
+ * provider bills (contract set 6.0.0): for a realtime model, a minute of a
481
+ * conversation under `server_vad`, Kaana's default turn detection; for a
482
+ * transcription model, a minute of audio. An estimate to reserve or show
483
+ * with, rounded up; what a request costs is what it measured, in `pricing`.
484
+ */
485
+ pricePerMinute: moneySchema.optional(),
472
486
  deprecation: modelDeprecationSchema,
473
487
  evaluations: z.array(modelEvaluationResultSchema).default([]),
474
488
  safety: modelSafetyMetadataSchema.optional(),
@@ -250,6 +250,17 @@ export declare const inferenceSpeechParametersSchema: z.ZodObject<{
250
250
  }>;
251
251
  speed: z.ZodOptional<z.ZodNumber>;
252
252
  }, z.core.$strict>;
253
+ /**
254
+ * Parameters for a file transcription, preserved in the signed request
255
+ * (contract set 4.5.0). `language` is the caller's statement of what is spoken,
256
+ * in the tag the model's catalogue `audio.languages` declares; absent lets the
257
+ * model detect it. An adapter whose provider takes no language refuses one
258
+ * rather than dropping it.
259
+ */
260
+ export declare const inferenceTranscriptionParametersSchema: z.ZodObject<{
261
+ language: z.ZodOptional<z.ZodString>;
262
+ prompt: z.ZodOptional<z.ZodString>;
263
+ }, z.core.$strict>;
253
264
  /**
254
265
  * Spoken output from a CONVERSATIONAL model (contract set 3.2.0) — an audio chat
255
266
  * model answering in its own voice, as opposed to `speech`, which reads given
@@ -283,6 +294,7 @@ export declare const inferenceAudioOutputParametersSchema: z.ZodObject<{
283
294
  */
284
295
  export declare const requestLabelsSchema: z.ZodRecord<z.ZodString, z.ZodString>;
285
296
  export type InferenceSpeechParameters = z.infer<typeof inferenceSpeechParametersSchema>;
297
+ export type InferenceTranscriptionParameters = z.infer<typeof inferenceTranscriptionParametersSchema>;
286
298
  export type InferenceAudioOutputParameters = z.infer<typeof inferenceAudioOutputParametersSchema>;
287
299
  export type InferenceContentSource = z.infer<typeof inferenceContentSourceSchema>;
288
300
  export type InferenceContentPart = z.infer<typeof inferenceContentPartSchema>;
@@ -5,6 +5,7 @@
5
5
  * Moved from `@oxy.so/contracts` 4.12.0 (`src/inference/request.ts`) by Kaana ADR 0002.
6
6
  */
7
7
  import { z } from 'zod';
8
+ import { languageTagSchema } from './audioFormats.js';
8
9
  import { reasoningEffortSchema } from './catalogue.js';
9
10
  /**
10
11
  * Where binary or remote content comes from.
@@ -219,6 +220,20 @@ export const inferenceSpeechParametersSchema = z
219
220
  speed: z.number().min(0.25).max(4).optional(),
220
221
  })
221
222
  .strict();
223
+ /**
224
+ * Parameters for a file transcription, preserved in the signed request
225
+ * (contract set 4.5.0). `language` is the caller's statement of what is spoken,
226
+ * in the tag the model's catalogue `audio.languages` declares; absent lets the
227
+ * model detect it. An adapter whose provider takes no language refuses one
228
+ * rather than dropping it.
229
+ */
230
+ export const inferenceTranscriptionParametersSchema = z
231
+ .object({
232
+ language: languageTagSchema.optional(),
233
+ /** Vocabulary or context, never an instruction (contract set 5.0.0). */
234
+ prompt: z.string().max(4096).optional(),
235
+ })
236
+ .strict();
222
237
  /**
223
238
  * Spoken output from a CONVERSATIONAL model (contract set 3.2.0) — an audio chat
224
239
  * model answering in its own voice, as opposed to `speech`, which reads given
@@ -4,6 +4,7 @@
4
4
  * Moved from `@oxy.so/contracts` 4.12.0 (`src/inference/realtime.ts`) by Kaana ADR 0002.
5
5
  */
6
6
  import { z } from 'zod';
7
+ import { realtimeOutputModalitySchema } from './audioFormats.js';
7
8
  import { type ModelAudioCapabilities, type ModelCapabilities, realtimeSessionKindSchema } from './catalogue.js';
8
9
  /**
9
10
  * The most base64 characters one audio frame may carry: 49 152 bytes of audio,
@@ -28,11 +29,6 @@ export declare const realtimeCommandIdSchema: z.ZodString;
28
29
  export declare const realtimeItemIdSchema: z.ZodString;
29
30
  /** A response's identity within one session. */
30
31
  export declare const realtimeResponseIdSchema: z.ZodString;
31
- /** What a session's responses produce. */
32
- export declare const realtimeOutputModalitySchema: z.ZodEnum<{
33
- text: "text";
34
- audio: "audio";
35
- }>;
36
32
  /**
37
33
  * How the end of a user's turn is detected.
38
34
  *
@@ -41,6 +37,10 @@ export declare const realtimeOutputModalitySchema: z.ZodEnum<{
41
37
  * them: whether the model answers on its own, and whether new speech cuts it
42
38
  * off, are the two behaviours a caller most needs to have chosen, and a default
43
39
  * would choose them silently — and differently per provider.
40
+ *
41
+ * A `server_vad` that names no `silenceDurationMs` waits Kaana's
42
+ * {@link REALTIME_DEFAULT_SILENCE_DURATION_MS}, on every provider (contract set
43
+ * 6.0.0), never the provider's own default.
44
44
  */
45
45
  export declare const realtimeTurnDetectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
46
46
  type: z.ZodLiteral<"none">;
@@ -69,13 +69,12 @@ export declare const realtimeTurnDetectionSchema: z.ZodDiscriminatedUnion<[z.Zod
69
69
  *
70
70
  * In a `conversation` it is served only by a model whose catalogue entry says
71
71
  * so (`capabilities.realtime.inputAudioTranscription`, contract set 4.1.0),
72
- * and each transcribed turn arrives as `transcript.delta` / `transcript.done`
73
- * with `source: 'input_audio'`. What it costs is settled with the session:
74
- * where the provider bills the transcription apart from the session model, as
75
- * `input_transcription_milliseconds` (see `USAGE_UNITS`); where the session's
76
- * own price includes it, as nothing more.
77
- *
78
- * `language`, when given, is one of the model's published `audio.languages`.
72
+ * and each transcribed turn arrives as deltas that only append and EXACTLY
73
+ * ONE `transcript.done` with `source: 'input_audio'`, the final transcript of
74
+ * that item (contract set 6.0.0), whatever its provider sends. What it costs
75
+ * is settled with the session: where the provider bills the transcription
76
+ * apart from the session model, as `input_transcription_milliseconds` (see
77
+ * `USAGE_UNITS`); where the session's own price includes it, as nothing more.
79
78
  */
80
79
  export declare const realtimeInputTranscriptionSchema: z.ZodObject<{
81
80
  language: z.ZodOptional<z.ZodString>;
@@ -85,6 +84,16 @@ export declare const realtimeInputTranscriptionSchema: z.ZodObject<{
85
84
  export declare const realtimeTranslationSchema: z.ZodObject<{
86
85
  targetLanguage: z.ZodString;
87
86
  }, z.core.$strict>;
87
+ /**
88
+ * A function tool a session may call: the chat tool without `strict`, which no
89
+ * realtime provider's session schema has (contract set 5.0.0).
90
+ */
91
+ export declare const realtimeToolDefinitionSchema: z.ZodObject<{
92
+ type: z.ZodLiteral<"function">;
93
+ name: z.ZodString;
94
+ description: z.ZodOptional<z.ZodString>;
95
+ parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
96
+ }, z.core.$strict>;
88
97
  /**
89
98
  * A session's full configuration, as signed at open and as echoed back by
90
99
  * `session.created` and `session.updated`.
@@ -143,7 +152,6 @@ export declare const realtimeSessionConfigSchema: z.ZodObject<{
143
152
  name: z.ZodString;
144
153
  description: z.ZodOptional<z.ZodString>;
145
154
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
146
- strict: z.ZodOptional<z.ZodBoolean>;
147
155
  }, z.core.$strict>>>;
148
156
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
149
157
  auto: "auto";
@@ -153,7 +161,6 @@ export declare const realtimeSessionConfigSchema: z.ZodObject<{
153
161
  type: z.ZodLiteral<"function">;
154
162
  name: z.ZodString;
155
163
  }, z.core.$strict>]>>;
156
- temperature: z.ZodOptional<z.ZodNumber>;
157
164
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
158
165
  }, z.core.$strict>;
159
166
  /**
@@ -199,7 +206,6 @@ export declare const realtimeSessionConfigUpdateSchema: z.ZodObject<{
199
206
  name: z.ZodString;
200
207
  description: z.ZodOptional<z.ZodString>;
201
208
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
202
- strict: z.ZodOptional<z.ZodBoolean>;
203
209
  }, z.core.$strict>>>;
204
210
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
205
211
  auto: "auto";
@@ -209,7 +215,6 @@ export declare const realtimeSessionConfigUpdateSchema: z.ZodObject<{
209
215
  type: z.ZodLiteral<"function">;
210
216
  name: z.ZodString;
211
217
  }, z.core.$strict>]>>;
212
- temperature: z.ZodOptional<z.ZodNumber>;
213
218
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
214
219
  }, z.core.$strict>;
215
220
  /**
@@ -360,7 +365,6 @@ export declare const realtimeSessionUpdateCommandSchema: z.ZodObject<{
360
365
  name: z.ZodString;
361
366
  description: z.ZodOptional<z.ZodString>;
362
367
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
363
- strict: z.ZodOptional<z.ZodBoolean>;
364
368
  }, z.core.$strict>>>;
365
369
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
366
370
  auto: "auto";
@@ -370,7 +374,6 @@ export declare const realtimeSessionUpdateCommandSchema: z.ZodObject<{
370
374
  type: z.ZodLiteral<"function">;
371
375
  name: z.ZodString;
372
376
  }, z.core.$strict>]>>;
373
- temperature: z.ZodOptional<z.ZodNumber>;
374
377
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
375
378
  }, z.core.$strict>;
376
379
  schemaVersion: z.ZodLiteral<1>;
@@ -552,7 +555,6 @@ export declare const realtimeClientCommandSchema: z.ZodDiscriminatedUnion<[z.Zod
552
555
  name: z.ZodString;
553
556
  description: z.ZodOptional<z.ZodString>;
554
557
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
555
- strict: z.ZodOptional<z.ZodBoolean>;
556
558
  }, z.core.$strict>>>;
557
559
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
558
560
  auto: "auto";
@@ -562,7 +564,6 @@ export declare const realtimeClientCommandSchema: z.ZodDiscriminatedUnion<[z.Zod
562
564
  type: z.ZodLiteral<"function">;
563
565
  name: z.ZodString;
564
566
  }, z.core.$strict>]>>;
565
- temperature: z.ZodOptional<z.ZodNumber>;
566
567
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
567
568
  }, z.core.$strict>;
568
569
  schemaVersion: z.ZodLiteral<1>;
@@ -738,7 +739,6 @@ export declare const realtimeSessionUpdatedEventSchema: z.ZodObject<{
738
739
  name: z.ZodString;
739
740
  description: z.ZodOptional<z.ZodString>;
740
741
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
741
- strict: z.ZodOptional<z.ZodBoolean>;
742
742
  }, z.core.$strict>>>;
743
743
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
744
744
  auto: "auto";
@@ -748,7 +748,6 @@ export declare const realtimeSessionUpdatedEventSchema: z.ZodObject<{
748
748
  type: z.ZodLiteral<"function">;
749
749
  name: z.ZodString;
750
750
  }, z.core.$strict>]>>;
751
- temperature: z.ZodOptional<z.ZodNumber>;
752
751
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
753
752
  }, z.core.$strict>;
754
753
  schemaVersion: z.ZodLiteral<1>;
@@ -1065,15 +1064,9 @@ export interface RealtimeConfigIssue {
1065
1064
  * apply the same ones, and a session a client may open is one Kaana may run.
1066
1065
  */
1067
1066
  export declare function realtimeConfigIssues(kind: z.infer<typeof realtimeSessionKindSchema>, config: z.infer<typeof realtimeSessionConfigSchema>): RealtimeConfigIssue[];
1068
- /**
1069
- * The most text `conversation.item.create` commands a session may be opened
1070
- * for: the bound a duration-priced route's hold is sized from.
1071
- */
1072
- export declare const MAX_REALTIME_TEXT_ITEMS = 10000;
1073
1067
  /**
1074
1068
  * The customer's partial limits request: every signed limit, each filled from
1075
- * Kaana's defaults when omitted, plus `maxTextItems`, the most billable text
1076
- * items the session may send (absent, it defaults to `maxResponses`).
1069
+ * Kaana's defaults when omitted, never above them.
1077
1070
  */
1078
1071
  export declare const realtimeOpenLimitsSchema: z.ZodObject<{
1079
1072
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -1081,8 +1074,23 @@ export declare const realtimeOpenLimitsSchema: z.ZodObject<{
1081
1074
  maxInputAudioBytes: z.ZodOptional<z.ZodNumber>;
1082
1075
  maxOutputAudioBytes: z.ZodOptional<z.ZodNumber>;
1083
1076
  maxResponses: z.ZodOptional<z.ZodNumber>;
1084
- maxTextItems: z.ZodOptional<z.ZodNumber>;
1085
1077
  }, z.core.$strict>;
1078
+ /**
1079
+ * The largest first frame of `GET /v1/realtime`: a `session.open` with its
1080
+ * instructions and up to 128 tool definitions (contract set 5.0.0). A larger
1081
+ * frame closes the connection before it is read.
1082
+ */
1083
+ export declare const MAX_REALTIME_OPEN_FRAME_BYTES: number;
1084
+ /**
1085
+ * The silence, in milliseconds, after which `server_vad` ends a caller's turn
1086
+ * when the session names none (contract set 6.0.0, Kaana ADR 0003). Kaana
1087
+ * sends it to every provider, so a turn ends the same way whichever serves
1088
+ * the session. Measured on x-ai/grok-voice-3.0 (2026-10-16): with xAI's own
1089
+ * default a phrase with pauses of 0.56 s and 0.79 s was cut into three
1090
+ * responses, two cancelled, the model speaking before the phrase ended; at
1091
+ * 500 ms it was one response, answered 490–576 ms after the phrase.
1092
+ */
1093
+ export declare const REALTIME_DEFAULT_SILENCE_DURATION_MS = 500;
1086
1094
  /**
1087
1095
  * The first frame a client sends on `GET /v1/realtime?model=…` to OPEN a
1088
1096
  * session (a reconnection instead sends `session.resume`). One grant covers the
@@ -1149,7 +1157,6 @@ export declare const realtimeSessionOpenSchema: z.ZodObject<{
1149
1157
  name: z.ZodString;
1150
1158
  description: z.ZodOptional<z.ZodString>;
1151
1159
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1152
- strict: z.ZodOptional<z.ZodBoolean>;
1153
1160
  }, z.core.$strict>>>;
1154
1161
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1155
1162
  auto: "auto";
@@ -1159,7 +1166,6 @@ export declare const realtimeSessionOpenSchema: z.ZodObject<{
1159
1166
  type: z.ZodLiteral<"function">;
1160
1167
  name: z.ZodString;
1161
1168
  }, z.core.$strict>]>>;
1162
- temperature: z.ZodOptional<z.ZodNumber>;
1163
1169
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1164
1170
  }, z.core.$strict>;
1165
1171
  limits: z.ZodOptional<z.ZodObject<{
@@ -1168,7 +1174,6 @@ export declare const realtimeSessionOpenSchema: z.ZodObject<{
1168
1174
  maxInputAudioBytes: z.ZodOptional<z.ZodNumber>;
1169
1175
  maxOutputAudioBytes: z.ZodOptional<z.ZodNumber>;
1170
1176
  maxResponses: z.ZodOptional<z.ZodNumber>;
1171
- maxTextItems: z.ZodOptional<z.ZodNumber>;
1172
1177
  }, z.core.$strict>>;
1173
1178
  clientSessionId: z.ZodOptional<z.ZodString>;
1174
1179
  labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -1262,7 +1267,6 @@ export declare const realtimePublicSessionCreatedEventSchema: z.ZodObject<{
1262
1267
  name: z.ZodString;
1263
1268
  description: z.ZodOptional<z.ZodString>;
1264
1269
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1265
- strict: z.ZodOptional<z.ZodBoolean>;
1266
1270
  }, z.core.$strict>>>;
1267
1271
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1268
1272
  auto: "auto";
@@ -1272,7 +1276,6 @@ export declare const realtimePublicSessionCreatedEventSchema: z.ZodObject<{
1272
1276
  type: z.ZodLiteral<"function">;
1273
1277
  name: z.ZodString;
1274
1278
  }, z.core.$strict>]>>;
1275
- temperature: z.ZodOptional<z.ZodNumber>;
1276
1279
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1277
1280
  }, z.core.$strict>;
1278
1281
  limits: z.ZodObject<{
@@ -1501,7 +1504,6 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1501
1504
  name: z.ZodString;
1502
1505
  description: z.ZodOptional<z.ZodString>;
1503
1506
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1504
- strict: z.ZodOptional<z.ZodBoolean>;
1505
1507
  }, z.core.$strict>>>;
1506
1508
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1507
1509
  auto: "auto";
@@ -1511,7 +1513,6 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1511
1513
  type: z.ZodLiteral<"function">;
1512
1514
  name: z.ZodString;
1513
1515
  }, z.core.$strict>]>>;
1514
- temperature: z.ZodOptional<z.ZodNumber>;
1515
1516
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1516
1517
  }, z.core.$strict>;
1517
1518
  limits: z.ZodObject<{
@@ -1579,7 +1580,6 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1579
1580
  name: z.ZodString;
1580
1581
  description: z.ZodOptional<z.ZodString>;
1581
1582
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1582
- strict: z.ZodOptional<z.ZodBoolean>;
1583
1583
  }, z.core.$strict>>>;
1584
1584
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1585
1585
  auto: "auto";
@@ -1589,7 +1589,6 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1589
1589
  type: z.ZodLiteral<"function">;
1590
1590
  name: z.ZodString;
1591
1591
  }, z.core.$strict>]>>;
1592
- temperature: z.ZodOptional<z.ZodNumber>;
1593
1592
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1594
1593
  }, z.core.$strict>;
1595
1594
  schemaVersion: z.ZodLiteral<1>;
@@ -4,7 +4,7 @@
4
4
  * Moved from `@oxy.so/contracts` 4.12.0 (`src/inference/realtime.ts`) by Kaana ADR 0002.
5
5
  */
6
6
  import { z } from 'zod';
7
- import { realtimeAudioFormatSchema } from './audioFormats.js';
7
+ import { realtimeAudioFormatSchema, realtimeOutputModalitySchema } from './audioFormats.js';
8
8
  import { realtimeSessionKindSchema, realtimeSessionTransportSchema, } from './catalogue.js';
9
9
  import { inferenceTimestampSchema, modelReferenceSchema, PADDED_BASE64_PATTERN, requestIdSchema, } from './identifiers.js';
10
10
  import { publicErrorSchema } from './errors.js';
@@ -34,8 +34,6 @@ export const realtimeCommandIdSchema = z.string().min(1).max(128);
34
34
  export const realtimeItemIdSchema = z.string().min(1).max(128);
35
35
  /** A response's identity within one session. */
36
36
  export const realtimeResponseIdSchema = z.string().min(1).max(128);
37
- /** What a session's responses produce. */
38
- export const realtimeOutputModalitySchema = z.enum(['text', 'audio']);
39
37
  const audioFrameSchema = z
40
38
  .string()
41
39
  .min(4)
@@ -51,6 +49,10 @@ const milliseconds = z.number().int().nonnegative().safe();
51
49
  * them: whether the model answers on its own, and whether new speech cuts it
52
50
  * off, are the two behaviours a caller most needs to have chosen, and a default
53
51
  * would choose them silently — and differently per provider.
52
+ *
53
+ * A `server_vad` that names no `silenceDurationMs` waits Kaana's
54
+ * {@link REALTIME_DEFAULT_SILENCE_DURATION_MS}, on every provider (contract set
55
+ * 6.0.0), never the provider's own default.
54
56
  */
55
57
  export const realtimeTurnDetectionSchema = z.discriminatedUnion('type', [
56
58
  z.object({ type: z.literal('none') }).strict(),
@@ -80,18 +82,22 @@ export const realtimeTurnDetectionSchema = z.discriminatedUnion('type', [
80
82
  *
81
83
  * In a `conversation` it is served only by a model whose catalogue entry says
82
84
  * so (`capabilities.realtime.inputAudioTranscription`, contract set 4.1.0),
83
- * and each transcribed turn arrives as `transcript.delta` / `transcript.done`
84
- * with `source: 'input_audio'`. What it costs is settled with the session:
85
- * where the provider bills the transcription apart from the session model, as
86
- * `input_transcription_milliseconds` (see `USAGE_UNITS`); where the session's
87
- * own price includes it, as nothing more.
88
- *
89
- * `language`, when given, is one of the model's published `audio.languages`.
85
+ * and each transcribed turn arrives as deltas that only append and EXACTLY
86
+ * ONE `transcript.done` with `source: 'input_audio'`, the final transcript of
87
+ * that item (contract set 6.0.0), whatever its provider sends. What it costs
88
+ * is settled with the session: where the provider bills the transcription
89
+ * apart from the session model, as `input_transcription_milliseconds` (see
90
+ * `USAGE_UNITS`); where the session's own price includes it, as nothing more.
90
91
  */
91
92
  export const realtimeInputTranscriptionSchema = z
92
93
  .object({
93
- /** A BCP 47 tag, when the caller knows the language. */
94
+ /**
95
+ * The client's own BCP 47 tag, when it knows the language. Kaana sends
96
+ * the provider its spelling of that language, or none for the model to
97
+ * detect; it is never refused.
98
+ */
94
99
  language: z.string().min(2).max(35).optional(),
100
+ /** A hint — vocabulary or context — used where the model takes one. */
95
101
  prompt: z.string().max(4_096).optional(),
96
102
  })
97
103
  .strict();
@@ -102,6 +108,11 @@ export const realtimeTranslationSchema = z
102
108
  targetLanguage: z.string().min(2).max(35),
103
109
  })
104
110
  .strict();
111
+ /**
112
+ * A function tool a session may call: the chat tool without `strict`, which no
113
+ * realtime provider's session schema has (contract set 5.0.0).
114
+ */
115
+ export const realtimeToolDefinitionSchema = toolDefinitionSchema.omit({ strict: true });
105
116
  /**
106
117
  * A session's full configuration, as signed at open and as echoed back by
107
118
  * `session.created` and `session.updated`.
@@ -121,9 +132,8 @@ export const realtimeSessionConfigSchema = z
121
132
  turnDetection: realtimeTurnDetectionSchema,
122
133
  inputAudioTranscription: realtimeInputTranscriptionSchema.optional(),
123
134
  translation: realtimeTranslationSchema.optional(),
124
- tools: z.array(toolDefinitionSchema).max(128).optional(),
135
+ tools: z.array(realtimeToolDefinitionSchema).max(128).optional(),
125
136
  toolChoice: toolChoiceSchema.optional(),
126
- temperature: z.number().min(0).max(2).optional(),
127
137
  /** Per response, not per session: the session's ceiling is `limits`. */
128
138
  maxOutputTokens: z.number().int().positive().safe().optional(),
129
139
  })
@@ -142,9 +152,8 @@ export const realtimeSessionConfigUpdateSchema = z
142
152
  outputModalities: z.array(realtimeOutputModalitySchema).min(1).max(2).optional(),
143
153
  turnDetection: realtimeTurnDetectionSchema.optional(),
144
154
  inputAudioTranscription: realtimeInputTranscriptionSchema.optional(),
145
- tools: z.array(toolDefinitionSchema).max(128).optional(),
155
+ tools: z.array(realtimeToolDefinitionSchema).max(128).optional(),
146
156
  toolChoice: toolChoiceSchema.optional(),
147
- temperature: z.number().min(0).max(2).optional(),
148
157
  maxOutputTokens: z.number().int().positive().safe().optional(),
149
158
  })
150
159
  .strict()
@@ -587,21 +596,26 @@ export function realtimeConfigIssues(kind, config) {
587
596
  /* Opening a session (`GET /v1/realtime`) */
588
597
  /* -------------------------------------------------------------------------- */
589
598
  /**
590
- * The most text `conversation.item.create` commands a session may be opened
591
- * for: the bound a duration-priced route's hold is sized from.
599
+ * The customer's partial limits request: every signed limit, each filled from
600
+ * Kaana's defaults when omitted, never above them.
592
601
  */
593
- export const MAX_REALTIME_TEXT_ITEMS = 10_000;
602
+ export const realtimeOpenLimitsSchema = realtimeSessionLimitsSchema.partial().strict();
594
603
  /**
595
- * The customer's partial limits request: every signed limit, each filled from
596
- * Kaana's defaults when omitted, plus `maxTextItems`, the most billable text
597
- * items the session may send (absent, it defaults to `maxResponses`).
604
+ * The largest first frame of `GET /v1/realtime`: a `session.open` with its
605
+ * instructions and up to 128 tool definitions (contract set 5.0.0). A larger
606
+ * frame closes the connection before it is read.
598
607
  */
599
- export const realtimeOpenLimitsSchema = realtimeSessionLimitsSchema
600
- .partial()
601
- .extend({
602
- maxTextItems: z.number().int().nonnegative().max(MAX_REALTIME_TEXT_ITEMS).optional(),
603
- })
604
- .strict();
608
+ export const MAX_REALTIME_OPEN_FRAME_BYTES = 1024 * 1024;
609
+ /**
610
+ * The silence, in milliseconds, after which `server_vad` ends a caller's turn
611
+ * when the session names none (contract set 6.0.0, Kaana ADR 0003). Kaana
612
+ * sends it to every provider, so a turn ends the same way whichever serves
613
+ * the session. Measured on x-ai/grok-voice-3.0 (2026-10-16): with xAI's own
614
+ * default a phrase with pauses of 0.56 s and 0.79 s was cut into three
615
+ * responses, two cancelled, the model speaking before the phrase ended; at
616
+ * 500 ms it was one response, answered 490–576 ms after the phrase.
617
+ */
618
+ export const REALTIME_DEFAULT_SILENCE_DURATION_MS = 500;
605
619
  /**
606
620
  * The first frame a client sends on `GET /v1/realtime?model=…` to OPEN a
607
621
  * session (a reconnection instead sends `session.resume`). One grant covers the
@@ -697,14 +711,6 @@ export function checkRealtimeSessionOpen(open, model) {
697
711
  message: 'this model does not transcribe its input inside a conversation',
698
712
  });
699
713
  }
700
- if (transcription?.language !== undefined &&
701
- audio !== undefined &&
702
- !audio.languages.includes(transcription.language)) {
703
- issues.push({
704
- param: 'config.inputAudioTranscription.language',
705
- message: `this model does not declare the language ${transcription.language}`,
706
- });
707
- }
708
714
  return issues;
709
715
  }
710
716
  /* -------------------------------------------------------------------------- */
@@ -100,7 +100,7 @@
100
100
  * change to, say, the catalogue reject every in-flight inference request; the
101
101
  * per-shape `schemaVersion` is what a message is validated against.
102
102
  */
103
- export declare const INFERENCE_CONTRACT_VERSION = "4.4.0";
103
+ export declare const INFERENCE_CONTRACT_VERSION = "6.0.0";
104
104
  /**
105
105
  * Contract set 4.0.0 (Kaana ADR 0002) is the first published as
106
106
  * `@kaana.ai/contracts`. MAJOR because the set changed hands and split in two:
@@ -135,12 +135,52 @@ export declare const INFERENCE_CONTRACT_VERSION = "4.4.0";
135
135
  * permission, dedicated capacity), and `sameModelFailover` on
136
136
  * `grantStepLimitsSchema` (default `true`: what 4.3.0 did). Nothing in 4.3.0
137
137
  * changes.
138
+ *
139
+ * Contract set 4.5.0 is additive: the signed envelope's optional
140
+ * `transcription` member (`inferenceTranscriptionParametersSchema`), which
141
+ * carries a file transcription's `language` to the model instead of the
142
+ * public API refusing it. Nothing in 4.4.0 changes.
143
+ *
144
+ * Contract set 5.0.0 publishes what each voice model ACCEPTS, so a client
145
+ * builds its request from the catalogue instead of learning the rules from a
146
+ * refusal. Additive: `capabilities.realtime.parameters` (turn detections and
147
+ * their bounds, output modality sets, tool choices, the output token cap, the
148
+ * input transcription prompt, and the units each detection is billed in),
149
+ * `audio.detectsLanguage` and `audio.transcriptionPrompt`,
150
+ * `realtimeParameterIssues` and `checkTranscriptionRequest`, the envelope's
151
+ * `transcription.prompt`, `MAX_REALTIME_OPEN_FRAME_BYTES`. MAJOR because it
152
+ * REMOVES what no server ever served, each of which Kaana already refused:
153
+ * the realtime `temperature`, a realtime tool's `strict`
154
+ * (`realtimeToolDefinitionSchema`), `limits.maxTextItems` and
155
+ * `MAX_REALTIME_TEXT_ITEMS`, and a transcription's `timestamps`, `segments`
156
+ * and `words`. A request that parsed under 4.5.0 and that Kaana served
157
+ * still parses and is served the same.
158
+ *
159
+ * Contract set 6.0.0 (Kaana ADR 0003) is one canonical API: no provider's
160
+ * variant reaches a client. Kaana translates or emulates every value the
161
+ * contract offers on every model, so the catalogue publishes product
162
+ * capabilities only. MAJOR because it REMOVES what 5.0.0 published of each
163
+ * provider's wire: `capabilities.realtime.parameters`
164
+ * (`realtimeParametersSchema`, `realtimeTurnDetectionParametersSchema`,
165
+ * `numberRangeSchema`, `realtimeToolChoiceKindSchema`),
166
+ * `realtimeParameterIssues`, `audio.detectsLanguage` and
167
+ * `audio.transcriptionPrompt`; and `checkTranscriptionRequest` takes the
168
+ * upload's media type alone, since a language or a prompt is never refused.
169
+ * Additive: a model's `pricePerMinute`, exactly one input `transcript.done`
170
+ * per item, and `REALTIME_DEFAULT_SILENCE_DURATION_MS`, the silence a
171
+ * `server_vad` that names none waits on every provider. A client on 5.0.0
172
+ * parses every 6.0.0 response.
138
173
  */
139
174
  /** The public API's one origin and version. */
140
175
  export declare const KAANA_API_BASE_URL = "https://kaana.ai/v1";
141
176
  /** The response header that carries the request id. */
142
177
  export declare const KAANA_REQUEST_ID_HEADER = "Kaana-Request-Id";
143
- /** The response header that carries {@link INFERENCE_CONTRACT_VERSION}. */
178
+ /**
179
+ * The header that carries {@link INFERENCE_CONTRACT_VERSION}: on every
180
+ * response, the set Kaana serves; on a request (`@kaana.ai/sdk` 2.0.0 and
181
+ * later), the set the client parses. Every set since 4.0.0 parses the
182
+ * catalogue Kaana serves.
183
+ */
144
184
  export declare const KAANA_CONTRACT_VERSION_HEADER = "Kaana-Contract-Version";
145
185
  /**
146
186
  * The response header that names the revision that actually served a request
@@ -100,7 +100,7 @@
100
100
  * change to, say, the catalogue reject every in-flight inference request; the
101
101
  * per-shape `schemaVersion` is what a message is validated against.
102
102
  */
103
- export const INFERENCE_CONTRACT_VERSION = '4.4.0';
103
+ export const INFERENCE_CONTRACT_VERSION = '6.0.0';
104
104
  /**
105
105
  * Contract set 4.0.0 (Kaana ADR 0002) is the first published as
106
106
  * `@kaana.ai/contracts`. MAJOR because the set changed hands and split in two:
@@ -135,12 +135,52 @@ export const INFERENCE_CONTRACT_VERSION = '4.4.0';
135
135
  * permission, dedicated capacity), and `sameModelFailover` on
136
136
  * `grantStepLimitsSchema` (default `true`: what 4.3.0 did). Nothing in 4.3.0
137
137
  * changes.
138
+ *
139
+ * Contract set 4.5.0 is additive: the signed envelope's optional
140
+ * `transcription` member (`inferenceTranscriptionParametersSchema`), which
141
+ * carries a file transcription's `language` to the model instead of the
142
+ * public API refusing it. Nothing in 4.4.0 changes.
143
+ *
144
+ * Contract set 5.0.0 publishes what each voice model ACCEPTS, so a client
145
+ * builds its request from the catalogue instead of learning the rules from a
146
+ * refusal. Additive: `capabilities.realtime.parameters` (turn detections and
147
+ * their bounds, output modality sets, tool choices, the output token cap, the
148
+ * input transcription prompt, and the units each detection is billed in),
149
+ * `audio.detectsLanguage` and `audio.transcriptionPrompt`,
150
+ * `realtimeParameterIssues` and `checkTranscriptionRequest`, the envelope's
151
+ * `transcription.prompt`, `MAX_REALTIME_OPEN_FRAME_BYTES`. MAJOR because it
152
+ * REMOVES what no server ever served, each of which Kaana already refused:
153
+ * the realtime `temperature`, a realtime tool's `strict`
154
+ * (`realtimeToolDefinitionSchema`), `limits.maxTextItems` and
155
+ * `MAX_REALTIME_TEXT_ITEMS`, and a transcription's `timestamps`, `segments`
156
+ * and `words`. A request that parsed under 4.5.0 and that Kaana served
157
+ * still parses and is served the same.
158
+ *
159
+ * Contract set 6.0.0 (Kaana ADR 0003) is one canonical API: no provider's
160
+ * variant reaches a client. Kaana translates or emulates every value the
161
+ * contract offers on every model, so the catalogue publishes product
162
+ * capabilities only. MAJOR because it REMOVES what 5.0.0 published of each
163
+ * provider's wire: `capabilities.realtime.parameters`
164
+ * (`realtimeParametersSchema`, `realtimeTurnDetectionParametersSchema`,
165
+ * `numberRangeSchema`, `realtimeToolChoiceKindSchema`),
166
+ * `realtimeParameterIssues`, `audio.detectsLanguage` and
167
+ * `audio.transcriptionPrompt`; and `checkTranscriptionRequest` takes the
168
+ * upload's media type alone, since a language or a prompt is never refused.
169
+ * Additive: a model's `pricePerMinute`, exactly one input `transcript.done`
170
+ * per item, and `REALTIME_DEFAULT_SILENCE_DURATION_MS`, the silence a
171
+ * `server_vad` that names none waits on every provider. A client on 5.0.0
172
+ * parses every 6.0.0 response.
138
173
  */
139
174
  /** The public API's one origin and version. */
140
175
  export const KAANA_API_BASE_URL = 'https://kaana.ai/v1';
141
176
  /** The response header that carries the request id. */
142
177
  export const KAANA_REQUEST_ID_HEADER = 'Kaana-Request-Id';
143
- /** The response header that carries {@link INFERENCE_CONTRACT_VERSION}. */
178
+ /**
179
+ * The header that carries {@link INFERENCE_CONTRACT_VERSION}: on every
180
+ * response, the set Kaana serves; on a request (`@kaana.ai/sdk` 2.0.0 and
181
+ * later), the set the client parses. Every set since 4.0.0 parses the
182
+ * catalogue Kaana serves.
183
+ */
144
184
  export const KAANA_CONTRACT_VERSION_HEADER = 'Kaana-Contract-Version';
145
185
  /**
146
186
  * The response header that names the revision that actually served a request
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Kaana API",
5
- "version": "4.4.0",
5
+ "version": "6.0.0",
6
6
  "description": "Kaana inference API. Generated from @kaana.ai/contracts; the Zod source is the authority. Accounts, applications, oxy_sk_ keys, limits and billing are managed in Oxy Console: https://console.oxy.so"
7
7
  },
8
8
  "servers": [
@@ -3191,6 +3191,19 @@
3191
3191
  ],
3192
3192
  "additionalProperties": false
3193
3193
  },
3194
+ "InferenceTranscriptionParameters": {
3195
+ "type": "object",
3196
+ "properties": {
3197
+ "language": {
3198
+ "$ref": "#/components/schemas/LanguageTag"
3199
+ },
3200
+ "prompt": {
3201
+ "type": "string",
3202
+ "maxLength": 4096
3203
+ }
3204
+ },
3205
+ "additionalProperties": false
3206
+ },
3194
3207
  "LanguageTag": {
3195
3208
  "type": "string",
3196
3209
  "maxLength": 35,
@@ -3807,6 +3820,9 @@
3807
3820
  "pricing": {
3808
3821
  "$ref": "#/components/schemas/PriceSnapshot"
3809
3822
  },
3823
+ "pricePerMinute": {
3824
+ "$ref": "#/components/schemas/Money"
3825
+ },
3810
3826
  "deprecation": {
3811
3827
  "$ref": "#/components/schemas/ModelDeprecation"
3812
3828
  },
@@ -4760,11 +4776,6 @@
4760
4776
  "type": "integer",
4761
4777
  "exclusiveMinimum": 0,
4762
4778
  "maximum": 10000
4763
- },
4764
- "maxTextItems": {
4765
- "type": "integer",
4766
- "minimum": 0,
4767
- "maximum": 10000
4768
4779
  }
4769
4780
  },
4770
4781
  "additionalProperties": false
@@ -5352,17 +5363,12 @@
5352
5363
  "maxItems": 128,
5353
5364
  "type": "array",
5354
5365
  "items": {
5355
- "$ref": "#/components/schemas/ToolDefinition"
5366
+ "$ref": "#/components/schemas/RealtimeToolDefinition"
5356
5367
  }
5357
5368
  },
5358
5369
  "toolChoice": {
5359
5370
  "$ref": "#/components/schemas/ToolChoice"
5360
5371
  },
5361
- "temperature": {
5362
- "type": "number",
5363
- "minimum": 0,
5364
- "maximum": 2
5365
- },
5366
5372
  "maxOutputTokens": {
5367
5373
  "type": "integer",
5368
5374
  "exclusiveMinimum": 0,
@@ -5400,17 +5406,12 @@
5400
5406
  "maxItems": 128,
5401
5407
  "type": "array",
5402
5408
  "items": {
5403
- "$ref": "#/components/schemas/ToolDefinition"
5409
+ "$ref": "#/components/schemas/RealtimeToolDefinition"
5404
5410
  }
5405
5411
  },
5406
5412
  "toolChoice": {
5407
5413
  "$ref": "#/components/schemas/ToolChoice"
5408
5414
  },
5409
- "temperature": {
5410
- "type": "number",
5411
- "minimum": 0,
5412
- "maximum": 2
5413
- },
5414
5415
  "maxOutputTokens": {
5415
5416
  "type": "integer",
5416
5417
  "exclusiveMinimum": 0,
@@ -5820,6 +5821,37 @@
5820
5821
  "complete"
5821
5822
  ]
5822
5823
  },
5824
+ "RealtimeToolDefinition": {
5825
+ "type": "object",
5826
+ "properties": {
5827
+ "type": {
5828
+ "type": "string",
5829
+ "const": "function"
5830
+ },
5831
+ "name": {
5832
+ "type": "string",
5833
+ "minLength": 1,
5834
+ "maxLength": 128
5835
+ },
5836
+ "description": {
5837
+ "type": "string",
5838
+ "maxLength": 2000
5839
+ },
5840
+ "parameters": {
5841
+ "type": "object",
5842
+ "propertyNames": {
5843
+ "type": "string"
5844
+ },
5845
+ "additionalProperties": {}
5846
+ }
5847
+ },
5848
+ "required": [
5849
+ "type",
5850
+ "name",
5851
+ "parameters"
5852
+ ],
5853
+ "additionalProperties": false
5854
+ },
5823
5855
  "RealtimeTranscriptDeltaEvent": {
5824
5856
  "type": "object",
5825
5857
  "properties": {
@@ -6682,14 +6714,6 @@
6682
6714
  "type": "string",
6683
6715
  "maxLength": 4096
6684
6716
  },
6685
- "timestamps": {
6686
- "type": "string",
6687
- "enum": [
6688
- "none",
6689
- "segment",
6690
- "word"
6691
- ]
6692
- },
6693
6717
  "audio": {
6694
6718
  "type": "object",
6695
6719
  "properties": {
@@ -6728,14 +6752,6 @@
6728
6752
  "prompt": {
6729
6753
  "type": "string",
6730
6754
  "maxLength": 4096
6731
- },
6732
- "timestamps": {
6733
- "type": "string",
6734
- "enum": [
6735
- "none",
6736
- "segment",
6737
- "word"
6738
- ]
6739
6755
  }
6740
6756
  },
6741
6757
  "required": [
@@ -6767,60 +6783,6 @@
6767
6783
  "minimum": 0,
6768
6784
  "maximum": 9007199254740991
6769
6785
  },
6770
- "segments": {
6771
- "type": "array",
6772
- "items": {
6773
- "type": "object",
6774
- "properties": {
6775
- "startMs": {
6776
- "type": "integer",
6777
- "minimum": 0,
6778
- "maximum": 9007199254740991
6779
- },
6780
- "endMs": {
6781
- "type": "integer",
6782
- "minimum": 0,
6783
- "maximum": 9007199254740991
6784
- },
6785
- "text": {
6786
- "type": "string"
6787
- }
6788
- },
6789
- "required": [
6790
- "startMs",
6791
- "endMs",
6792
- "text"
6793
- ],
6794
- "additionalProperties": false
6795
- }
6796
- },
6797
- "words": {
6798
- "type": "array",
6799
- "items": {
6800
- "type": "object",
6801
- "properties": {
6802
- "startMs": {
6803
- "type": "integer",
6804
- "minimum": 0,
6805
- "maximum": 9007199254740991
6806
- },
6807
- "endMs": {
6808
- "type": "integer",
6809
- "minimum": 0,
6810
- "maximum": 9007199254740991
6811
- },
6812
- "word": {
6813
- "type": "string"
6814
- }
6815
- },
6816
- "required": [
6817
- "startMs",
6818
- "endMs",
6819
- "word"
6820
- ],
6821
- "additionalProperties": false
6822
- }
6823
- },
6824
6786
  "usage": {
6825
6787
  "$ref": "#/components/schemas/Usage"
6826
6788
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaana.ai/contracts",
3
- "version": "4.4.1",
3
+ "version": "6.0.0",
4
4
  "description": "Kaana inference contract: the Zod schemas of the public API at https://kaana.ai/v1 and, under /internal, of the Oxy-Kaana grant, settlement and signed lane.",
5
5
  "type": "module",
6
6
  "sideEffects": false,