@kaana.ai/contracts 4.4.0 → 5.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.
@@ -4,7 +4,9 @@
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 { type ModelAudioCapabilities, type ModelCapabilities, realtimeSessionKindSchema } from './catalogue.js';
7
+ import { realtimeOutputModalitySchema } from './audioFormats.js';
8
+ import { type ModelAudioCapabilities, type ModelCapabilities, type RealtimeParameters, realtimeSessionKindSchema } from './catalogue.js';
9
+ import { toolChoiceSchema } from './messages.js';
8
10
  /**
9
11
  * The most base64 characters one audio frame may carry: 49 152 bytes of audio,
10
12
  * about one second of 24 kHz mono PCM16. Bounded so no frame is large enough to
@@ -28,11 +30,6 @@ export declare const realtimeCommandIdSchema: z.ZodString;
28
30
  export declare const realtimeItemIdSchema: z.ZodString;
29
31
  /** A response's identity within one session. */
30
32
  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
33
  /**
37
34
  * How the end of a user's turn is detected.
38
35
  *
@@ -85,6 +82,16 @@ export declare const realtimeInputTranscriptionSchema: z.ZodObject<{
85
82
  export declare const realtimeTranslationSchema: z.ZodObject<{
86
83
  targetLanguage: z.ZodString;
87
84
  }, z.core.$strict>;
85
+ /**
86
+ * A function tool a session may call: the chat tool without `strict`, which no
87
+ * realtime provider's session schema has (contract set 5.0.0).
88
+ */
89
+ export declare const realtimeToolDefinitionSchema: z.ZodObject<{
90
+ type: z.ZodLiteral<"function">;
91
+ name: z.ZodString;
92
+ parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
93
+ description: z.ZodOptional<z.ZodString>;
94
+ }, z.core.$strict>;
88
95
  /**
89
96
  * A session's full configuration, as signed at open and as echoed back by
90
97
  * `session.created` and `session.updated`.
@@ -141,19 +148,17 @@ export declare const realtimeSessionConfigSchema: z.ZodObject<{
141
148
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
142
149
  type: z.ZodLiteral<"function">;
143
150
  name: z.ZodString;
144
- description: z.ZodOptional<z.ZodString>;
145
151
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
146
- strict: z.ZodOptional<z.ZodBoolean>;
152
+ description: z.ZodOptional<z.ZodString>;
147
153
  }, z.core.$strict>>>;
148
154
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
149
- auto: "auto";
150
155
  none: "none";
156
+ auto: "auto";
151
157
  required: "required";
152
158
  }>, z.ZodObject<{
153
159
  type: z.ZodLiteral<"function">;
154
160
  name: z.ZodString;
155
161
  }, z.core.$strict>]>>;
156
- temperature: z.ZodOptional<z.ZodNumber>;
157
162
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
158
163
  }, z.core.$strict>;
159
164
  /**
@@ -197,19 +202,17 @@ export declare const realtimeSessionConfigUpdateSchema: z.ZodObject<{
197
202
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
198
203
  type: z.ZodLiteral<"function">;
199
204
  name: z.ZodString;
200
- description: z.ZodOptional<z.ZodString>;
201
205
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
202
- strict: z.ZodOptional<z.ZodBoolean>;
206
+ description: z.ZodOptional<z.ZodString>;
203
207
  }, z.core.$strict>>>;
204
208
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
205
- auto: "auto";
206
209
  none: "none";
210
+ auto: "auto";
207
211
  required: "required";
208
212
  }>, z.ZodObject<{
209
213
  type: z.ZodLiteral<"function">;
210
214
  name: z.ZodString;
211
215
  }, z.core.$strict>]>>;
212
- temperature: z.ZodOptional<z.ZodNumber>;
213
216
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
214
217
  }, z.core.$strict>;
215
218
  /**
@@ -315,8 +318,8 @@ export declare const realtimeResponseParametersSchema: z.ZodObject<{
315
318
  }>>>;
316
319
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
317
320
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
318
- auto: "auto";
319
321
  none: "none";
322
+ auto: "auto";
320
323
  required: "required";
321
324
  }>, z.ZodObject<{
322
325
  type: z.ZodLiteral<"function">;
@@ -358,19 +361,17 @@ export declare const realtimeSessionUpdateCommandSchema: z.ZodObject<{
358
361
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
359
362
  type: z.ZodLiteral<"function">;
360
363
  name: z.ZodString;
361
- description: z.ZodOptional<z.ZodString>;
362
364
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
363
- strict: z.ZodOptional<z.ZodBoolean>;
365
+ description: z.ZodOptional<z.ZodString>;
364
366
  }, z.core.$strict>>>;
365
367
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
366
- auto: "auto";
367
368
  none: "none";
369
+ auto: "auto";
368
370
  required: "required";
369
371
  }>, z.ZodObject<{
370
372
  type: z.ZodLiteral<"function">;
371
373
  name: z.ZodString;
372
374
  }, z.core.$strict>]>>;
373
- temperature: z.ZodOptional<z.ZodNumber>;
374
375
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
375
376
  }, z.core.$strict>;
376
377
  schemaVersion: z.ZodLiteral<1>;
@@ -478,8 +479,8 @@ export declare const realtimeResponseCreateCommandSchema: z.ZodObject<{
478
479
  }>>>;
479
480
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
480
481
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
481
- auto: "auto";
482
482
  none: "none";
483
+ auto: "auto";
483
484
  required: "required";
484
485
  }>, z.ZodObject<{
485
486
  type: z.ZodLiteral<"function">;
@@ -550,19 +551,17 @@ export declare const realtimeClientCommandSchema: z.ZodDiscriminatedUnion<[z.Zod
550
551
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
551
552
  type: z.ZodLiteral<"function">;
552
553
  name: z.ZodString;
553
- description: z.ZodOptional<z.ZodString>;
554
554
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
555
- strict: z.ZodOptional<z.ZodBoolean>;
555
+ description: z.ZodOptional<z.ZodString>;
556
556
  }, z.core.$strict>>>;
557
557
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
558
- auto: "auto";
559
558
  none: "none";
559
+ auto: "auto";
560
560
  required: "required";
561
561
  }>, z.ZodObject<{
562
562
  type: z.ZodLiteral<"function">;
563
563
  name: z.ZodString;
564
564
  }, z.core.$strict>]>>;
565
- temperature: z.ZodOptional<z.ZodNumber>;
566
565
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
567
566
  }, z.core.$strict>;
568
567
  schemaVersion: z.ZodLiteral<1>;
@@ -658,8 +657,8 @@ export declare const realtimeClientCommandSchema: z.ZodDiscriminatedUnion<[z.Zod
658
657
  }>>>;
659
658
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
660
659
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
661
- auto: "auto";
662
660
  none: "none";
661
+ auto: "auto";
663
662
  required: "required";
664
663
  }>, z.ZodObject<{
665
664
  type: z.ZodLiteral<"function">;
@@ -736,19 +735,17 @@ export declare const realtimeSessionUpdatedEventSchema: z.ZodObject<{
736
735
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
737
736
  type: z.ZodLiteral<"function">;
738
737
  name: z.ZodString;
739
- description: z.ZodOptional<z.ZodString>;
740
738
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
741
- strict: z.ZodOptional<z.ZodBoolean>;
739
+ description: z.ZodOptional<z.ZodString>;
742
740
  }, z.core.$strict>>>;
743
741
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
744
- auto: "auto";
745
742
  none: "none";
743
+ auto: "auto";
746
744
  required: "required";
747
745
  }>, z.ZodObject<{
748
746
  type: z.ZodLiteral<"function">;
749
747
  name: z.ZodString;
750
748
  }, z.core.$strict>]>>;
751
- temperature: z.ZodOptional<z.ZodNumber>;
752
749
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
753
750
  }, z.core.$strict>;
754
751
  schemaVersion: z.ZodLiteral<1>;
@@ -1065,15 +1062,9 @@ export interface RealtimeConfigIssue {
1065
1062
  * apply the same ones, and a session a client may open is one Kaana may run.
1066
1063
  */
1067
1064
  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
1065
  /**
1074
1066
  * 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`).
1067
+ * Kaana's defaults when omitted, never above them.
1077
1068
  */
1078
1069
  export declare const realtimeOpenLimitsSchema: z.ZodObject<{
1079
1070
  maxDurationMs: z.ZodOptional<z.ZodNumber>;
@@ -1081,8 +1072,13 @@ export declare const realtimeOpenLimitsSchema: z.ZodObject<{
1081
1072
  maxInputAudioBytes: z.ZodOptional<z.ZodNumber>;
1082
1073
  maxOutputAudioBytes: z.ZodOptional<z.ZodNumber>;
1083
1074
  maxResponses: z.ZodOptional<z.ZodNumber>;
1084
- maxTextItems: z.ZodOptional<z.ZodNumber>;
1085
1075
  }, z.core.$strict>;
1076
+ /**
1077
+ * The largest first frame of `GET /v1/realtime`: a `session.open` with its
1078
+ * instructions and up to 128 tool definitions (contract set 5.0.0). A larger
1079
+ * frame closes the connection before it is read.
1080
+ */
1081
+ export declare const MAX_REALTIME_OPEN_FRAME_BYTES: number;
1086
1082
  /**
1087
1083
  * The first frame a client sends on `GET /v1/realtime?model=…` to OPEN a
1088
1084
  * session (a reconnection instead sends `session.resume`). One grant covers the
@@ -1147,19 +1143,17 @@ export declare const realtimeSessionOpenSchema: z.ZodObject<{
1147
1143
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
1148
1144
  type: z.ZodLiteral<"function">;
1149
1145
  name: z.ZodString;
1150
- description: z.ZodOptional<z.ZodString>;
1151
1146
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1152
- strict: z.ZodOptional<z.ZodBoolean>;
1147
+ description: z.ZodOptional<z.ZodString>;
1153
1148
  }, z.core.$strict>>>;
1154
1149
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1155
- auto: "auto";
1156
1150
  none: "none";
1151
+ auto: "auto";
1157
1152
  required: "required";
1158
1153
  }>, z.ZodObject<{
1159
1154
  type: z.ZodLiteral<"function">;
1160
1155
  name: z.ZodString;
1161
1156
  }, z.core.$strict>]>>;
1162
- temperature: z.ZodOptional<z.ZodNumber>;
1163
1157
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1164
1158
  }, z.core.$strict>;
1165
1159
  limits: z.ZodOptional<z.ZodObject<{
@@ -1168,7 +1162,6 @@ export declare const realtimeSessionOpenSchema: z.ZodObject<{
1168
1162
  maxInputAudioBytes: z.ZodOptional<z.ZodNumber>;
1169
1163
  maxOutputAudioBytes: z.ZodOptional<z.ZodNumber>;
1170
1164
  maxResponses: z.ZodOptional<z.ZodNumber>;
1171
- maxTextItems: z.ZodOptional<z.ZodNumber>;
1172
1165
  }, z.core.$strict>>;
1173
1166
  clientSessionId: z.ZodOptional<z.ZodString>;
1174
1167
  labels: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -1199,6 +1192,28 @@ export declare function checkRealtimeSessionOpen(open: z.infer<typeof realtimeSe
1199
1192
  readonly capabilities: ModelCapabilities;
1200
1193
  readonly audio?: ModelAudioCapabilities;
1201
1194
  }): RealtimeOpenIssue[];
1195
+ /**
1196
+ * The part of a session configuration, of a `session.update` or of a
1197
+ * `response.create` that a model's {@link RealtimeParameters} govern.
1198
+ */
1199
+ export interface RealtimeGovernedFields {
1200
+ readonly outputModalities?: readonly RealtimeOutputModality[];
1201
+ readonly turnDetection?: RealtimeTurnDetection;
1202
+ readonly inputAudioTranscription?: {
1203
+ readonly prompt?: string;
1204
+ };
1205
+ readonly toolChoice?: z.infer<typeof toolChoiceSchema>;
1206
+ readonly maxOutputTokens?: number;
1207
+ }
1208
+ /**
1209
+ * Every field that `parameters` do not serve, each with the `param` Kaana's
1210
+ * refusal names (`prefix` is `config` for an open or a `session.update`,
1211
+ * `response` for a `response.create`), in the order Kaana checks them. It is
1212
+ * exactly Kaana's own check (Go's `RealtimeParameters.Issues`, held to the
1213
+ * same vectors), so a client that builds its session from a model's
1214
+ * parameters, or filters models with this, is never refused for one.
1215
+ */
1216
+ export declare function realtimeParameterIssues(prefix: 'config' | 'response', fields: RealtimeGovernedFields, parameters: RealtimeParameters): RealtimeOpenIssue[];
1202
1217
  /**
1203
1218
  * The session opened: the revision-pinned model, fixed for the rest of the
1204
1219
  * session, and the effective configuration and limits. The signed lane's
@@ -1260,19 +1275,17 @@ export declare const realtimePublicSessionCreatedEventSchema: z.ZodObject<{
1260
1275
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
1261
1276
  type: z.ZodLiteral<"function">;
1262
1277
  name: z.ZodString;
1263
- description: z.ZodOptional<z.ZodString>;
1264
1278
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1265
- strict: z.ZodOptional<z.ZodBoolean>;
1279
+ description: z.ZodOptional<z.ZodString>;
1266
1280
  }, z.core.$strict>>>;
1267
1281
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1268
- auto: "auto";
1269
1282
  none: "none";
1283
+ auto: "auto";
1270
1284
  required: "required";
1271
1285
  }>, z.ZodObject<{
1272
1286
  type: z.ZodLiteral<"function">;
1273
1287
  name: z.ZodString;
1274
1288
  }, z.core.$strict>]>>;
1275
- temperature: z.ZodOptional<z.ZodNumber>;
1276
1289
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1277
1290
  }, z.core.$strict>;
1278
1291
  limits: z.ZodObject<{
@@ -1499,19 +1512,17 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1499
1512
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
1500
1513
  type: z.ZodLiteral<"function">;
1501
1514
  name: z.ZodString;
1502
- description: z.ZodOptional<z.ZodString>;
1503
1515
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1504
- strict: z.ZodOptional<z.ZodBoolean>;
1516
+ description: z.ZodOptional<z.ZodString>;
1505
1517
  }, z.core.$strict>>>;
1506
1518
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1507
- auto: "auto";
1508
1519
  none: "none";
1520
+ auto: "auto";
1509
1521
  required: "required";
1510
1522
  }>, z.ZodObject<{
1511
1523
  type: z.ZodLiteral<"function">;
1512
1524
  name: z.ZodString;
1513
1525
  }, z.core.$strict>]>>;
1514
- temperature: z.ZodOptional<z.ZodNumber>;
1515
1526
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1516
1527
  }, z.core.$strict>;
1517
1528
  limits: z.ZodObject<{
@@ -1577,19 +1588,17 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1577
1588
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
1578
1589
  type: z.ZodLiteral<"function">;
1579
1590
  name: z.ZodString;
1580
- description: z.ZodOptional<z.ZodString>;
1581
1591
  parameters: z.ZodRecord<z.ZodString, z.ZodUnknown>;
1582
- strict: z.ZodOptional<z.ZodBoolean>;
1592
+ description: z.ZodOptional<z.ZodString>;
1583
1593
  }, z.core.$strict>>>;
1584
1594
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
1585
- auto: "auto";
1586
1595
  none: "none";
1596
+ auto: "auto";
1587
1597
  required: "required";
1588
1598
  }>, z.ZodObject<{
1589
1599
  type: z.ZodLiteral<"function">;
1590
1600
  name: z.ZodString;
1591
1601
  }, z.core.$strict>]>>;
1592
- temperature: z.ZodOptional<z.ZodNumber>;
1593
1602
  maxOutputTokens: z.ZodOptional<z.ZodNumber>;
1594
1603
  }, z.core.$strict>;
1595
1604
  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)
@@ -102,6 +100,11 @@ export const realtimeTranslationSchema = z
102
100
  targetLanguage: z.string().min(2).max(35),
103
101
  })
104
102
  .strict();
103
+ /**
104
+ * A function tool a session may call: the chat tool without `strict`, which no
105
+ * realtime provider's session schema has (contract set 5.0.0).
106
+ */
107
+ export const realtimeToolDefinitionSchema = toolDefinitionSchema.omit({ strict: true });
105
108
  /**
106
109
  * A session's full configuration, as signed at open and as echoed back by
107
110
  * `session.created` and `session.updated`.
@@ -121,9 +124,8 @@ export const realtimeSessionConfigSchema = z
121
124
  turnDetection: realtimeTurnDetectionSchema,
122
125
  inputAudioTranscription: realtimeInputTranscriptionSchema.optional(),
123
126
  translation: realtimeTranslationSchema.optional(),
124
- tools: z.array(toolDefinitionSchema).max(128).optional(),
127
+ tools: z.array(realtimeToolDefinitionSchema).max(128).optional(),
125
128
  toolChoice: toolChoiceSchema.optional(),
126
- temperature: z.number().min(0).max(2).optional(),
127
129
  /** Per response, not per session: the session's ceiling is `limits`. */
128
130
  maxOutputTokens: z.number().int().positive().safe().optional(),
129
131
  })
@@ -142,9 +144,8 @@ export const realtimeSessionConfigUpdateSchema = z
142
144
  outputModalities: z.array(realtimeOutputModalitySchema).min(1).max(2).optional(),
143
145
  turnDetection: realtimeTurnDetectionSchema.optional(),
144
146
  inputAudioTranscription: realtimeInputTranscriptionSchema.optional(),
145
- tools: z.array(toolDefinitionSchema).max(128).optional(),
147
+ tools: z.array(realtimeToolDefinitionSchema).max(128).optional(),
146
148
  toolChoice: toolChoiceSchema.optional(),
147
- temperature: z.number().min(0).max(2).optional(),
148
149
  maxOutputTokens: z.number().int().positive().safe().optional(),
149
150
  })
150
151
  .strict()
@@ -587,21 +588,16 @@ export function realtimeConfigIssues(kind, config) {
587
588
  /* Opening a session (`GET /v1/realtime`) */
588
589
  /* -------------------------------------------------------------------------- */
589
590
  /**
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.
591
+ * The customer's partial limits request: every signed limit, each filled from
592
+ * Kaana's defaults when omitted, never above them.
592
593
  */
593
- export const MAX_REALTIME_TEXT_ITEMS = 10_000;
594
+ export const realtimeOpenLimitsSchema = realtimeSessionLimitsSchema.partial().strict();
594
595
  /**
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`).
596
+ * The largest first frame of `GET /v1/realtime`: a `session.open` with its
597
+ * instructions and up to 128 tool definitions (contract set 5.0.0). A larger
598
+ * frame closes the connection before it is read.
598
599
  */
599
- export const realtimeOpenLimitsSchema = realtimeSessionLimitsSchema
600
- .partial()
601
- .extend({
602
- maxTextItems: z.number().int().nonnegative().max(MAX_REALTIME_TEXT_ITEMS).optional(),
603
- })
604
- .strict();
600
+ export const MAX_REALTIME_OPEN_FRAME_BYTES = 1024 * 1024;
605
601
  /**
606
602
  * The first frame a client sends on `GET /v1/realtime?model=…` to OPEN a
607
603
  * session (a reconnection instead sends `session.resume`). One grant covers the
@@ -702,9 +698,79 @@ export function checkRealtimeSessionOpen(open, model) {
702
698
  !audio.languages.includes(transcription.language)) {
703
699
  issues.push({
704
700
  param: 'config.inputAudioTranscription.language',
705
- message: `this model does not declare the language ${transcription.language}`,
701
+ message: `this model does not declare the language ${transcription.language}` +
702
+ (audio.detectsLanguage === true ? '; omit it to let the model detect the language' : ''),
706
703
  });
707
704
  }
705
+ if (realtime.parameters !== undefined) {
706
+ issues.push(...realtimeParameterIssues('config', config, realtime.parameters));
707
+ }
708
+ return issues;
709
+ }
710
+ function toolChoiceKind(choice) {
711
+ return typeof choice === 'string' ? choice : 'function';
712
+ }
713
+ function sameModalities(a, b) {
714
+ const left = [...a].sort();
715
+ const right = [...b].sort();
716
+ return left.length === right.length && left.every((value, index) => value === right[index]);
717
+ }
718
+ /**
719
+ * Every field that `parameters` do not serve, each with the `param` Kaana's
720
+ * refusal names (`prefix` is `config` for an open or a `session.update`,
721
+ * `response` for a `response.create`), in the order Kaana checks them. It is
722
+ * exactly Kaana's own check (Go's `RealtimeParameters.Issues`, held to the
723
+ * same vectors), so a client that builds its session from a model's
724
+ * parameters, or filters models with this, is never refused for one.
725
+ */
726
+ export function realtimeParameterIssues(prefix, fields, parameters) {
727
+ const issues = [];
728
+ const issue = (param, message) => issues.push({ param: `${prefix}.${param}`, message });
729
+ if (fields.outputModalities !== undefined &&
730
+ !parameters.outputModalities.some((set) => sameModalities(set, fields.outputModalities ?? []))) {
731
+ issue('outputModalities', `this model produces ${parameters.outputModalities.map((set) => `[${set.join(' ')}]`).join(' or ')} in one response`);
732
+ }
733
+ const detection = fields.turnDetection;
734
+ if (detection !== undefined) {
735
+ const served = parameters.turnDetection.find((candidate) => candidate.type === detection.type);
736
+ if (served === undefined) {
737
+ issue('turnDetection', `this model has no ${detection.type} turn detection`);
738
+ }
739
+ else {
740
+ if (served.fixedResponses && detection.type !== 'none') {
741
+ if (!detection.createResponse) {
742
+ issue('turnDetection.createResponse', `this model's ${detection.type} always answers the turn it detected; createResponse must be true`);
743
+ }
744
+ if (!detection.interruptResponse) {
745
+ issue('turnDetection.interruptResponse', `this model's ${detection.type} lets the caller's speech interrupt an answer; interruptResponse must be true`);
746
+ }
747
+ }
748
+ if (detection.type === 'server_vad') {
749
+ const threshold = served.threshold;
750
+ if (threshold !== undefined &&
751
+ detection.threshold !== undefined &&
752
+ (detection.threshold < threshold.min || detection.threshold > threshold.max)) {
753
+ issue('turnDetection.threshold', `this model's ${detection.type} threshold is ${threshold.min} to ${threshold.max}`);
754
+ }
755
+ }
756
+ }
757
+ }
758
+ if (fields.inputAudioTranscription?.prompt !== undefined &&
759
+ !parameters.inputTranscriptionPrompt) {
760
+ issue('inputAudioTranscription.prompt', "this model's input transcription takes no prompt");
761
+ }
762
+ if (fields.toolChoice !== undefined &&
763
+ !parameters.toolChoice.includes(toolChoiceKind(fields.toolChoice))) {
764
+ issue('toolChoice', `this model serves the tool choices ${parameters.toolChoice.join(', ')}`);
765
+ }
766
+ if (fields.maxOutputTokens !== undefined) {
767
+ if (parameters.maxOutputTokens === undefined) {
768
+ issue('maxOutputTokens', 'this model has no output token cap');
769
+ }
770
+ else if (fields.maxOutputTokens > parameters.maxOutputTokens) {
771
+ issue('maxOutputTokens', `this model caps a response at most at ${parameters.maxOutputTokens} output tokens`);
772
+ }
773
+ }
708
774
  return issues;
709
775
  }
710
776
  /* -------------------------------------------------------------------------- */
@@ -118,8 +118,8 @@ export declare const responsesRequestSchema: z.ZodObject<{
118
118
  strict: z.ZodOptional<z.ZodBoolean>;
119
119
  }, z.core.$strict>>>;
120
120
  toolChoice: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
121
- auto: "auto";
122
121
  none: "none";
122
+ auto: "auto";
123
123
  required: "required";
124
124
  }>, z.ZodObject<{
125
125
  type: z.ZodLiteral<"function">;
@@ -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 = "5.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,38 @@ 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.
138
158
  */
139
159
  /** The public API's one origin and version. */
140
160
  export declare const KAANA_API_BASE_URL = "https://kaana.ai/v1";
141
161
  /** The response header that carries the request id. */
142
162
  export declare const KAANA_REQUEST_ID_HEADER = "Kaana-Request-Id";
143
- /** The response header that carries {@link INFERENCE_CONTRACT_VERSION}. */
163
+ /**
164
+ * The header that carries {@link INFERENCE_CONTRACT_VERSION}: on every
165
+ * response, the set Kaana serves; on a request (`@kaana.ai/sdk` 2.0.0 and
166
+ * later), the set the client parses. The catalogue's leaves are strict, so
167
+ * Kaana renders `GET /v1/models` in the shape of the client's set: a client
168
+ * that states none is served the 4.x shape, without what set 5.0.0 added.
169
+ */
144
170
  export declare const KAANA_CONTRACT_VERSION_HEADER = "Kaana-Contract-Version";
145
171
  /**
146
172
  * 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 = '5.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,38 @@ 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.
138
158
  */
139
159
  /** The public API's one origin and version. */
140
160
  export const KAANA_API_BASE_URL = 'https://kaana.ai/v1';
141
161
  /** The response header that carries the request id. */
142
162
  export const KAANA_REQUEST_ID_HEADER = 'Kaana-Request-Id';
143
- /** The response header that carries {@link INFERENCE_CONTRACT_VERSION}. */
163
+ /**
164
+ * The header that carries {@link INFERENCE_CONTRACT_VERSION}: on every
165
+ * response, the set Kaana serves; on a request (`@kaana.ai/sdk` 2.0.0 and
166
+ * later), the set the client parses. The catalogue's leaves are strict, so
167
+ * Kaana renders `GET /v1/models` in the shape of the client's set: a client
168
+ * that states none is served the 4.x shape, without what set 5.0.0 added.
169
+ */
144
170
  export const KAANA_CONTRACT_VERSION_HEADER = 'Kaana-Contract-Version';
145
171
  /**
146
172
  * The response header that names the revision that actually served a request