@kaana.ai/contracts 8.0.1 → 8.2.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.
@@ -562,6 +562,26 @@ export declare const modelCatalogueEntrySchema: z.ZodObject<{
562
562
  ultra: "ultra";
563
563
  }>>;
564
564
  }, z.core.$strip>;
565
+ /**
566
+ * What a model line's image input costs at most, as the line's own documented
567
+ * rule states it (contract set 8.2.0, Kaana ADR 0007). Internal: Oxy reads it
568
+ * from the declared catalogue to bound the input of a request carrying images;
569
+ * `GET /v1/models` does not serve it.
570
+ *
571
+ * `maxInputTokensPerImage` is the most input tokens the line's provider bills
572
+ * for ONE image the contract admits (`checkImageInput`), at any `detail` the
573
+ * contract offers, from the publisher's documented resize and tokenization
574
+ * rule. Images are billed as input tokens at the line's `input_tokens` price;
575
+ * this figure only sizes a hold and qualifies a route, the settlement is the
576
+ * provider's own count.
577
+ *
578
+ * ABSENT means undeclared, even on a model whose `inputModalities` lists
579
+ * `image`: nobody has stated what one image costs on it, so no request carrying
580
+ * an image is authorized on it.
581
+ */
582
+ export declare const declaredImageInputSchema: z.ZodObject<{
583
+ maxInputTokensPerImage: z.ZodNumber;
584
+ }, z.core.$strict>;
565
585
  /**
566
586
  * One model as Kaana DECLARES it in `configs/public-catalogue.json` (Kaana ADR
567
587
  * 0002, amendment 2026-10-15): the public `modelSchema` without the three
@@ -791,6 +811,9 @@ export declare const declaredModelSchema: z.ZodObject<{
791
811
  platform_internal: "platform_internal";
792
812
  public: "public";
793
813
  }>;
814
+ imageInput: z.ZodOptional<z.ZodObject<{
815
+ maxInputTokensPerImage: z.ZodNumber;
816
+ }, z.core.$strict>>;
794
817
  }, z.core.$strict>;
795
818
  /**
796
819
  * The declared catalogue: identity, publisher, licence, provenance, data
@@ -1019,9 +1042,13 @@ export declare const declaredCatalogueSchema: z.ZodObject<{
1019
1042
  platform_internal: "platform_internal";
1020
1043
  public: "public";
1021
1044
  }>;
1045
+ imageInput: z.ZodOptional<z.ZodObject<{
1046
+ maxInputTokensPerImage: z.ZodNumber;
1047
+ }, z.core.$strict>>;
1022
1048
  }, z.core.$strict>>;
1023
1049
  }, z.core.$strict>;
1024
1050
  export type DeclaredModel = z.infer<typeof declaredModelSchema>;
1051
+ export type DeclaredImageInput = z.infer<typeof declaredImageInputSchema>;
1025
1052
  export type DeclaredCatalogue = z.infer<typeof declaredCatalogueSchema>;
1026
1053
  export type AvailabilityScope = z.infer<typeof availabilityScopeSchema>;
1027
1054
  export type CommercialPermission = z.infer<typeof commercialPermissionSchema>;
@@ -354,6 +354,28 @@ export const modelCatalogueEntrySchema = z.object({
354
354
  */
355
355
  powerClass: modelPowerClassSchema.optional(),
356
356
  });
357
+ /**
358
+ * What a model line's image input costs at most, as the line's own documented
359
+ * rule states it (contract set 8.2.0, Kaana ADR 0007). Internal: Oxy reads it
360
+ * from the declared catalogue to bound the input of a request carrying images;
361
+ * `GET /v1/models` does not serve it.
362
+ *
363
+ * `maxInputTokensPerImage` is the most input tokens the line's provider bills
364
+ * for ONE image the contract admits (`checkImageInput`), at any `detail` the
365
+ * contract offers, from the publisher's documented resize and tokenization
366
+ * rule. Images are billed as input tokens at the line's `input_tokens` price;
367
+ * this figure only sizes a hold and qualifies a route, the settlement is the
368
+ * provider's own count.
369
+ *
370
+ * ABSENT means undeclared, even on a model whose `inputModalities` lists
371
+ * `image`: nobody has stated what one image costs on it, so no request carrying
372
+ * an image is authorized on it.
373
+ */
374
+ export const declaredImageInputSchema = z
375
+ .object({
376
+ maxInputTokensPerImage: z.number().int().positive().safe(),
377
+ })
378
+ .strict();
357
379
  /**
358
380
  * One model as Kaana DECLARES it in `configs/public-catalogue.json` (Kaana ADR
359
381
  * 0002, amendment 2026-10-15): the public `modelSchema` without the three
@@ -368,8 +390,20 @@ export const modelCatalogueEntrySchema = z.object({
368
390
  */
369
391
  export const declaredModelSchema = modelSchema
370
392
  .omit({ schemaVersion: true, currentRevision: true, availableRevisions: true })
371
- .extend({ audience: z.enum(['public', 'platform_internal']) })
372
- .strict();
393
+ .extend({
394
+ audience: z.enum(['public', 'platform_internal']),
395
+ imageInput: declaredImageInputSchema.optional(),
396
+ })
397
+ .strict()
398
+ .superRefine((model, ctx) => {
399
+ if (model.imageInput !== undefined && !model.capabilities.inputModalities.includes('image')) {
400
+ ctx.addIssue({
401
+ code: 'custom',
402
+ path: ['imageInput'],
403
+ message: 'a model that bounds its image input takes image input',
404
+ });
405
+ }
406
+ });
373
407
  /**
374
408
  * The declared catalogue: identity, publisher, licence, provenance, data
375
409
  * policy, capabilities, voices and the LIST PRICE per unit of every model
@@ -74,6 +74,7 @@ export declare const grantRequestFactsSchema: z.ZodObject<{
74
74
  audioInputMilliseconds: z.ZodOptional<z.ZodNumber>;
75
75
  embeddingInputs: z.ZodOptional<z.ZodNumber>;
76
76
  images: z.ZodOptional<z.ZodNumber>;
77
+ inputImages: z.ZodOptional<z.ZodNumber>;
77
78
  declaredTools: z.ZodNumber;
78
79
  stream: z.ZodBoolean;
79
80
  realtimeSessionKind: z.ZodOptional<z.ZodEnum<{
@@ -125,6 +126,7 @@ export declare const inferenceAuthorizationRequestSchema: z.ZodObject<{
125
126
  audioInputMilliseconds: z.ZodOptional<z.ZodNumber>;
126
127
  embeddingInputs: z.ZodOptional<z.ZodNumber>;
127
128
  images: z.ZodOptional<z.ZodNumber>;
129
+ inputImages: z.ZodOptional<z.ZodNumber>;
128
130
  declaredTools: z.ZodNumber;
129
131
  stream: z.ZodBoolean;
130
132
  realtimeSessionKind: z.ZodOptional<z.ZodEnum<{
@@ -204,6 +206,7 @@ export declare const authorizationRequestSchema: z.ZodDiscriminatedUnion<[z.ZodO
204
206
  audioInputMilliseconds: z.ZodOptional<z.ZodNumber>;
205
207
  embeddingInputs: z.ZodOptional<z.ZodNumber>;
206
208
  images: z.ZodOptional<z.ZodNumber>;
209
+ inputImages: z.ZodOptional<z.ZodNumber>;
207
210
  declaredTools: z.ZodNumber;
208
211
  stream: z.ZodBoolean;
209
212
  realtimeSessionKind: z.ZodOptional<z.ZodEnum<{
@@ -22,7 +22,7 @@ import { maxUtf16Length, minUtf16Length } from '../stringBounds.js';
22
22
  import { powerLevelSchema, realtimeSessionKindSchema } from '../public/catalogue.js';
23
23
  import { generationRecordSchema } from '../public/generations.js';
24
24
  import { delegatedUserIdSchema, generationIdSchema, idempotencyKeySchema, inferenceEnvironmentSchema, inferenceRegionSchema, inferenceTimestampSchema, modelIdSchema, modelRevisionLabelSchema, oxyApplicationIdSchema, oxyCredentialIdSchema, requestIdSchema, } from '../public/identifiers.js';
25
- import { requestLabelsSchema } from '../public/messages.js';
25
+ import { MAX_INPUT_IMAGES, requestLabelsSchema } from '../public/messages.js';
26
26
  import { moneySchema } from '../public/money.js';
27
27
  import { routingPolicyReferenceSchema } from '../public/policy.js';
28
28
  import { inferenceScopeSchema } from './attribution.js';
@@ -107,6 +107,13 @@ export const grantRequestFactsSchema = z
107
107
  /** Embeddings: how many inputs. Images: how many images. */
108
108
  embeddingInputs: z.number().int().positive().max(2048).optional(),
109
109
  images: z.number().int().positive().max(10).optional(),
110
+ /**
111
+ * Completions: how many image parts the input carries (contract set 8.2.0,
112
+ * Kaana ADR 0007), present exactly when it carries one. Their bytes are not
113
+ * in `estimatedInputTokens`: Oxy bounds each image by the line's declared
114
+ * `imageInput.maxInputTokensPerImage` and admits only lines that declare it.
115
+ */
116
+ inputImages: z.number().int().positive().max(MAX_INPUT_IMAGES).optional(),
110
117
  /** How many tools the request declares; their definitions stay in Kaana. */
111
118
  declaredTools: z.number().int().nonnegative().max(128),
112
119
  stream: z.boolean(),
@@ -108,6 +108,7 @@ export declare const realtimeSessionRequestSchema: z.ZodObject<{
108
108
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
109
109
  language: z.ZodOptional<z.ZodString>;
110
110
  prompt: z.ZodOptional<z.ZodString>;
111
+ interimResults: z.ZodOptional<z.ZodBoolean>;
111
112
  }, z.core.$strict>>;
112
113
  translation: z.ZodOptional<z.ZodObject<{
113
114
  targetLanguage: z.ZodString;
@@ -248,6 +249,7 @@ export declare const realtimeSessionCreatedEventSchema: z.ZodObject<{
248
249
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
249
250
  language: z.ZodOptional<z.ZodString>;
250
251
  prompt: z.ZodOptional<z.ZodString>;
252
+ interimResults: z.ZodOptional<z.ZodBoolean>;
251
253
  }, z.core.$strict>>;
252
254
  translation: z.ZodOptional<z.ZodObject<{
253
255
  targetLanguage: z.ZodString;
@@ -505,6 +507,7 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
505
507
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
506
508
  language: z.ZodOptional<z.ZodString>;
507
509
  prompt: z.ZodOptional<z.ZodString>;
510
+ interimResults: z.ZodOptional<z.ZodBoolean>;
508
511
  }, z.core.$strict>>;
509
512
  translation: z.ZodOptional<z.ZodObject<{
510
513
  targetLanguage: z.ZodString;
@@ -581,6 +584,7 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
581
584
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
582
585
  language: z.ZodOptional<z.ZodString>;
583
586
  prompt: z.ZodOptional<z.ZodString>;
587
+ interimResults: z.ZodOptional<z.ZodBoolean>;
584
588
  }, z.core.$strict>>;
585
589
  translation: z.ZodOptional<z.ZodObject<{
586
590
  targetLanguage: z.ZodString;
@@ -827,6 +831,16 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
827
831
  requestId: z.ZodString;
828
832
  sequence: z.ZodNumber;
829
833
  commandId: z.ZodOptional<z.ZodString>;
834
+ }, z.core.$strip>, z.ZodObject<{
835
+ type: z.ZodLiteral<"transcript.interim">;
836
+ source: z.ZodLiteral<"input_audio">;
837
+ itemId: z.ZodString;
838
+ contentIndex: z.ZodNumber;
839
+ text: z.ZodString;
840
+ schemaVersion: z.ZodLiteral<1>;
841
+ requestId: z.ZodString;
842
+ sequence: z.ZodNumber;
843
+ commandId: z.ZodOptional<z.ZodString>;
830
844
  }, z.core.$strip>, z.ZodObject<{
831
845
  type: z.ZodLiteral<"text.delta">;
832
846
  responseId: z.ZodString;
@@ -11,7 +11,7 @@ import { inferenceTimestampSchema, modelReferenceSchema, requestIdSchema, } from
11
11
  import { usageQuantitySchema, usageSourceSchema } from '../public/money.js';
12
12
  import { routingPolicyReferenceSchema } from '../public/policy.js';
13
13
  import { inferenceFinishReasonSchema } from '../public/streamEvents.js';
14
- import { MAX_REALTIME_RESUME_WINDOW_MS, realtimeCommandAcceptedEventSchema, realtimeCommandIdSchema, realtimeConfigIssues, realtimeInputAudioClearedEventSchema, realtimeInputAudioCommittedEventSchema, realtimeItemAddedEventSchema, realtimeItemDeletedEventSchema, realtimeItemDoneEventSchema, realtimeItemTruncatedEventSchema, realtimeOutputAudioDeltaEventSchema, realtimeOutputAudioDoneEventSchema, realtimeResponseCreatedEventSchema, realtimeResponseIdSchema, realtimeResponseStatusSchema, realtimeSessionCloseReasonSchema, realtimeSessionConfigSchema, realtimeSessionLimitsSchema, realtimeSessionResumedEventSchema, realtimeSessionUpdatedEventSchema, realtimeSpeechStartedEventSchema, realtimeSpeechStoppedEventSchema, realtimeTextDeltaEventSchema, realtimeToolCallEventSchema, realtimeTranscriptDeltaEventSchema, realtimeTranscriptDoneEventSchema, } from '../public/realtime.js';
14
+ import { MAX_REALTIME_RESUME_WINDOW_MS, realtimeCommandAcceptedEventSchema, realtimeCommandIdSchema, realtimeConfigIssues, realtimeInputAudioClearedEventSchema, realtimeInputAudioCommittedEventSchema, realtimeItemAddedEventSchema, realtimeItemDeletedEventSchema, realtimeItemDoneEventSchema, realtimeItemTruncatedEventSchema, realtimeOutputAudioDeltaEventSchema, realtimeOutputAudioDoneEventSchema, realtimeResponseCreatedEventSchema, realtimeResponseIdSchema, realtimeResponseStatusSchema, realtimeSessionCloseReasonSchema, realtimeSessionConfigSchema, realtimeSessionLimitsSchema, realtimeSessionResumedEventSchema, realtimeSessionUpdatedEventSchema, realtimeSpeechStartedEventSchema, realtimeSpeechStoppedEventSchema, realtimeTextDeltaEventSchema, realtimeToolCallEventSchema, realtimeTranscriptDeltaEventSchema, realtimeTranscriptDoneEventSchema, realtimeTranscriptInterimEventSchema, } from '../public/realtime.js';
15
15
  import { inferenceAttributionSchema } from './attribution.js';
16
16
  import { inferenceErrorSchema } from './errors.js';
17
17
  import { deploymentIdSchema, inferenceProviderSlugSchema } from './identifiers.js';
@@ -165,6 +165,7 @@ export const realtimeServerEventSchema = z
165
165
  realtimeOutputAudioDoneEventSchema,
166
166
  realtimeTranscriptDeltaEventSchema,
167
167
  realtimeTranscriptDoneEventSchema,
168
+ realtimeTranscriptInterimEventSchema,
168
169
  realtimeTextDeltaEventSchema,
169
170
  realtimeToolCallEventSchema,
170
171
  realtimeResponseDoneEventSchema,
@@ -95,6 +95,61 @@ export declare const inferenceContentPartSchema: z.ZodDiscriminatedUnion<[z.ZodO
95
95
  type: z.ZodLiteral<"refusal">;
96
96
  text: z.ZodString;
97
97
  }, z.core.$strict>], "type">;
98
+ /**
99
+ * The image formats a request may carry. Every provider that serves image input
100
+ * on a Kaana route reads these four: Anthropic (`image/jpeg`, `image/png`,
101
+ * `image/gif`, `image/webp`) and OpenAI (PNG, JPEG, WEBP, non-animated GIF).
102
+ */
103
+ export declare const INPUT_IMAGE_MEDIA_TYPES: readonly ["image/png", "image/jpeg", "image/webp", "image/gif"];
104
+ /**
105
+ * The most image parts one request may carry, across every message. Above 20
106
+ * images Anthropic applies a stricter per-image dimension limit to EVERY image
107
+ * of the request, so 20 is the most a request can carry and keep one rule per
108
+ * image on every route.
109
+ */
110
+ export declare const MAX_INPUT_IMAGES = 20;
111
+ /**
112
+ * The most decoded bytes one image may carry: 3,750,000, whose base64 is
113
+ * 5,000,000 characters, the smallest per-image limit a provider serving these
114
+ * routes documents (Anthropic on Amazon Bedrock: 5 MB base64-encoded).
115
+ */
116
+ export declare const MAX_INPUT_IMAGE_BYTES = 3750000;
117
+ /** Why one image part cannot be carried, before anything is held. Never the image itself. */
118
+ export interface ImageInputIssue {
119
+ /** The message, as its index in the request's message list. */
120
+ readonly messageIndex: number;
121
+ /** The part, as its index in that message's content; absent for the request-wide count. */
122
+ readonly partIndex?: number;
123
+ /** The field at fault, relative to the part. */
124
+ readonly field: 'role' | 'source' | 'source.mediaType' | 'source.data' | 'count';
125
+ readonly message: string;
126
+ }
127
+ /**
128
+ * Check the image parts of a conversation against the contract's image rules
129
+ * (Kaana ADR 0007). Kaana refuses a request with `invalid_request` and the first
130
+ * issue BEFORE it asks Oxy for a grant; Oxy applies the same rules on its own
131
+ * edge; a client may run it first.
132
+ *
133
+ * - an image is `inline`: no component fetches an image URL, and a `url`
134
+ * source is never forwarded to a provider to fetch either;
135
+ * - its media type is one of {@link INPUT_IMAGE_MEDIA_TYPES};
136
+ * - its data is canonical base64 of at most {@link MAX_INPUT_IMAGE_BYTES} bytes;
137
+ * - it rides on a `user` or `tool` message;
138
+ * - the request carries at most {@link MAX_INPUT_IMAGES} of them.
139
+ *
140
+ * Returns the number of image parts and every issue, in message order. An issue
141
+ * names where and why, never the bytes: an image is payload and is never echoed
142
+ * into an error, a log line or a record.
143
+ */
144
+ export declare function checkImageInput(messages: readonly InferenceMessage[]): {
145
+ readonly images: number;
146
+ readonly issues: ImageInputIssue[];
147
+ };
148
+ /**
149
+ * The decoded length of canonical base64 (RFC 4648 section 4, padded, no line
150
+ * breaks), or `undefined` when the text is not that. Counted, never decoded.
151
+ */
152
+ export declare function base64DecodedLength(data: string): number | undefined;
98
153
  /**
99
154
  * A tool call an assistant made, in the normalized form.
100
155
  *
@@ -86,6 +86,113 @@ export const inferenceContentPartSchema = z.discriminatedUnion('type', [
86
86
  */
87
87
  z.object({ type: z.literal('refusal'), text: z.string() }).strict(),
88
88
  ]);
89
+ /* -------------------------------------------------------------------------- */
90
+ /* Image input (contract set 8.2.0, Kaana ADR 0007) */
91
+ /* -------------------------------------------------------------------------- */
92
+ /**
93
+ * The image formats a request may carry. Every provider that serves image input
94
+ * on a Kaana route reads these four: Anthropic (`image/jpeg`, `image/png`,
95
+ * `image/gif`, `image/webp`) and OpenAI (PNG, JPEG, WEBP, non-animated GIF).
96
+ */
97
+ export const INPUT_IMAGE_MEDIA_TYPES = [
98
+ 'image/png',
99
+ 'image/jpeg',
100
+ 'image/webp',
101
+ 'image/gif',
102
+ ];
103
+ /**
104
+ * The most image parts one request may carry, across every message. Above 20
105
+ * images Anthropic applies a stricter per-image dimension limit to EVERY image
106
+ * of the request, so 20 is the most a request can carry and keep one rule per
107
+ * image on every route.
108
+ */
109
+ export const MAX_INPUT_IMAGES = 20;
110
+ /**
111
+ * The most decoded bytes one image may carry: 3,750,000, whose base64 is
112
+ * 5,000,000 characters, the smallest per-image limit a provider serving these
113
+ * routes documents (Anthropic on Amazon Bedrock: 5 MB base64-encoded).
114
+ */
115
+ export const MAX_INPUT_IMAGE_BYTES = 3_750_000;
116
+ /**
117
+ * Check the image parts of a conversation against the contract's image rules
118
+ * (Kaana ADR 0007). Kaana refuses a request with `invalid_request` and the first
119
+ * issue BEFORE it asks Oxy for a grant; Oxy applies the same rules on its own
120
+ * edge; a client may run it first.
121
+ *
122
+ * - an image is `inline`: no component fetches an image URL, and a `url`
123
+ * source is never forwarded to a provider to fetch either;
124
+ * - its media type is one of {@link INPUT_IMAGE_MEDIA_TYPES};
125
+ * - its data is canonical base64 of at most {@link MAX_INPUT_IMAGE_BYTES} bytes;
126
+ * - it rides on a `user` or `tool` message;
127
+ * - the request carries at most {@link MAX_INPUT_IMAGES} of them.
128
+ *
129
+ * Returns the number of image parts and every issue, in message order. An issue
130
+ * names where and why, never the bytes: an image is payload and is never echoed
131
+ * into an error, a log line or a record.
132
+ */
133
+ export function checkImageInput(messages) {
134
+ const issues = [];
135
+ let images = 0;
136
+ for (const [messageIndex, message] of messages.entries()) {
137
+ for (const [partIndex, part] of message.content.entries()) {
138
+ if (part.type !== 'image')
139
+ continue;
140
+ images += 1;
141
+ const at = { messageIndex, partIndex };
142
+ if (message.role !== 'user' && message.role !== 'tool') {
143
+ issues.push({ ...at, field: 'role', message: 'an image rides on a user or tool message' });
144
+ }
145
+ const source = part.source;
146
+ if (source.kind !== 'inline') {
147
+ issues.push({
148
+ ...at,
149
+ field: 'source',
150
+ message: 'an image is sent inline as base64; no image URL is fetched',
151
+ });
152
+ continue;
153
+ }
154
+ if (!INPUT_IMAGE_MEDIA_TYPES.includes(source.mediaType)) {
155
+ issues.push({
156
+ ...at,
157
+ field: 'source.mediaType',
158
+ message: `an image is one of ${INPUT_IMAGE_MEDIA_TYPES.join(', ')}`,
159
+ });
160
+ }
161
+ const bytes = base64DecodedLength(source.data);
162
+ if (bytes === undefined) {
163
+ issues.push({ ...at, field: 'source.data', message: 'image data is canonical base64' });
164
+ }
165
+ else if (bytes > MAX_INPUT_IMAGE_BYTES) {
166
+ issues.push({
167
+ ...at,
168
+ field: 'source.data',
169
+ message: `an image is at most ${MAX_INPUT_IMAGE_BYTES} bytes`,
170
+ });
171
+ }
172
+ }
173
+ }
174
+ if (images > MAX_INPUT_IMAGES) {
175
+ issues.push({
176
+ messageIndex: messages.length - 1,
177
+ field: 'count',
178
+ message: `a request carries at most ${MAX_INPUT_IMAGES} images`,
179
+ });
180
+ }
181
+ return { images, issues };
182
+ }
183
+ const BASE64_BODY = /^[A-Za-z0-9+/]*$/;
184
+ /**
185
+ * The decoded length of canonical base64 (RFC 4648 section 4, padded, no line
186
+ * breaks), or `undefined` when the text is not that. Counted, never decoded.
187
+ */
188
+ export function base64DecodedLength(data) {
189
+ if (data.length === 0 || data.length % 4 !== 0)
190
+ return undefined;
191
+ const padding = data.endsWith('==') ? 2 : data.endsWith('=') ? 1 : 0;
192
+ if (!BASE64_BODY.test(data.slice(0, data.length - padding)))
193
+ return undefined;
194
+ return (data.length / 4) * 3 - padding;
195
+ }
89
196
  /**
90
197
  * A tool call an assistant made, in the normalized form.
91
198
  *
@@ -89,6 +89,7 @@ export declare const realtimeTurnDetectionSchema: z.ZodDiscriminatedUnion<[z.Zod
89
89
  export declare const realtimeInputTranscriptionSchema: z.ZodObject<{
90
90
  language: z.ZodOptional<z.ZodString>;
91
91
  prompt: z.ZodOptional<z.ZodString>;
92
+ interimResults: z.ZodOptional<z.ZodBoolean>;
92
93
  }, z.core.$strict>;
93
94
  /** The target of a `translation` session. */
94
95
  export declare const realtimeTranslationSchema: z.ZodObject<{
@@ -153,6 +154,7 @@ export declare const realtimeSessionConfigSchema: z.ZodObject<{
153
154
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
154
155
  language: z.ZodOptional<z.ZodString>;
155
156
  prompt: z.ZodOptional<z.ZodString>;
157
+ interimResults: z.ZodOptional<z.ZodBoolean>;
156
158
  }, z.core.$strict>>;
157
159
  translation: z.ZodOptional<z.ZodObject<{
158
160
  targetLanguage: z.ZodString;
@@ -210,6 +212,7 @@ export declare const realtimeSessionConfigUpdateSchema: z.ZodObject<{
210
212
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
211
213
  language: z.ZodOptional<z.ZodString>;
212
214
  prompt: z.ZodOptional<z.ZodString>;
215
+ interimResults: z.ZodOptional<z.ZodBoolean>;
213
216
  }, z.core.$strict>>;
214
217
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
215
218
  type: z.ZodLiteral<"function">;
@@ -369,6 +372,7 @@ export declare const realtimeSessionUpdateCommandSchema: z.ZodObject<{
369
372
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
370
373
  language: z.ZodOptional<z.ZodString>;
371
374
  prompt: z.ZodOptional<z.ZodString>;
375
+ interimResults: z.ZodOptional<z.ZodBoolean>;
372
376
  }, z.core.$strict>>;
373
377
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
374
378
  type: z.ZodLiteral<"function">;
@@ -559,6 +563,7 @@ export declare const realtimeClientCommandSchema: z.ZodDiscriminatedUnion<[z.Zod
559
563
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
560
564
  language: z.ZodOptional<z.ZodString>;
561
565
  prompt: z.ZodOptional<z.ZodString>;
566
+ interimResults: z.ZodOptional<z.ZodBoolean>;
562
567
  }, z.core.$strict>>;
563
568
  tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
564
569
  type: z.ZodLiteral<"function">;
@@ -740,6 +745,7 @@ export declare const realtimeSessionUpdatedEventSchema: z.ZodObject<{
740
745
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
741
746
  language: z.ZodOptional<z.ZodString>;
742
747
  prompt: z.ZodOptional<z.ZodString>;
748
+ interimResults: z.ZodOptional<z.ZodBoolean>;
743
749
  }, z.core.$strict>>;
744
750
  translation: z.ZodOptional<z.ZodObject<{
745
751
  targetLanguage: z.ZodString;
@@ -1017,6 +1023,24 @@ export declare const realtimeTranscriptDoneEventSchema: z.ZodObject<{
1017
1023
  sequence: z.ZodNumber;
1018
1024
  commandId: z.ZodOptional<z.ZodString>;
1019
1025
  }, z.core.$strip>;
1026
+ /**
1027
+ * The provisional text of an input item not yet final (contract set 8.1.0,
1028
+ * Kaana ADR 0006): sent only to a `transcription` session that asked for
1029
+ * `interimResults`. Each one REPLACES the item's previous interim text; it is
1030
+ * display state, never settled and never part of the item's transcript, and
1031
+ * the item's next `transcript.delta` or its `transcript.done` supersedes it.
1032
+ */
1033
+ export declare const realtimeTranscriptInterimEventSchema: z.ZodObject<{
1034
+ type: z.ZodLiteral<"transcript.interim">;
1035
+ source: z.ZodLiteral<"input_audio">;
1036
+ itemId: z.ZodString;
1037
+ contentIndex: z.ZodNumber;
1038
+ text: z.ZodString;
1039
+ schemaVersion: z.ZodLiteral<1>;
1040
+ requestId: z.ZodString;
1041
+ sequence: z.ZodNumber;
1042
+ commandId: z.ZodOptional<z.ZodString>;
1043
+ }, z.core.$strip>;
1020
1044
  /** Written output of a response (`outputModalities` including `text`). */
1021
1045
  export declare const realtimeTextDeltaEventSchema: z.ZodObject<{
1022
1046
  type: z.ZodLiteral<"text.delta">;
@@ -1158,6 +1182,7 @@ export declare const realtimeSessionOpenSchema: z.ZodObject<{
1158
1182
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
1159
1183
  language: z.ZodOptional<z.ZodString>;
1160
1184
  prompt: z.ZodOptional<z.ZodString>;
1185
+ interimResults: z.ZodOptional<z.ZodBoolean>;
1161
1186
  }, z.core.$strict>>;
1162
1187
  translation: z.ZodOptional<z.ZodObject<{
1163
1188
  targetLanguage: z.ZodString;
@@ -1268,6 +1293,7 @@ export declare const realtimePublicSessionCreatedEventSchema: z.ZodObject<{
1268
1293
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
1269
1294
  language: z.ZodOptional<z.ZodString>;
1270
1295
  prompt: z.ZodOptional<z.ZodString>;
1296
+ interimResults: z.ZodOptional<z.ZodBoolean>;
1271
1297
  }, z.core.$strict>>;
1272
1298
  translation: z.ZodOptional<z.ZodObject<{
1273
1299
  targetLanguage: z.ZodString;
@@ -1505,6 +1531,7 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1505
1531
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
1506
1532
  language: z.ZodOptional<z.ZodString>;
1507
1533
  prompt: z.ZodOptional<z.ZodString>;
1534
+ interimResults: z.ZodOptional<z.ZodBoolean>;
1508
1535
  }, z.core.$strict>>;
1509
1536
  translation: z.ZodOptional<z.ZodObject<{
1510
1537
  targetLanguage: z.ZodString;
@@ -1581,6 +1608,7 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1581
1608
  inputAudioTranscription: z.ZodOptional<z.ZodObject<{
1582
1609
  language: z.ZodOptional<z.ZodString>;
1583
1610
  prompt: z.ZodOptional<z.ZodString>;
1611
+ interimResults: z.ZodOptional<z.ZodBoolean>;
1584
1612
  }, z.core.$strict>>;
1585
1613
  translation: z.ZodOptional<z.ZodObject<{
1586
1614
  targetLanguage: z.ZodString;
@@ -1827,6 +1855,16 @@ export declare const realtimePublicServerEventSchema: z.ZodDiscriminatedUnion<[z
1827
1855
  requestId: z.ZodString;
1828
1856
  sequence: z.ZodNumber;
1829
1857
  commandId: z.ZodOptional<z.ZodString>;
1858
+ }, z.core.$strip>, z.ZodObject<{
1859
+ type: z.ZodLiteral<"transcript.interim">;
1860
+ source: z.ZodLiteral<"input_audio">;
1861
+ itemId: z.ZodString;
1862
+ contentIndex: z.ZodNumber;
1863
+ text: z.ZodString;
1864
+ schemaVersion: z.ZodLiteral<1>;
1865
+ requestId: z.ZodString;
1866
+ sequence: z.ZodNumber;
1867
+ commandId: z.ZodOptional<z.ZodString>;
1830
1868
  }, z.core.$strip>, z.ZodObject<{
1831
1869
  type: z.ZodLiteral<"text.delta">;
1832
1870
  responseId: z.ZodString;
@@ -116,6 +116,12 @@ export const realtimeInputTranscriptionSchema = z
116
116
  language: z.string().check(minUtf16Length(2)).check(maxUtf16Length(35)).optional(),
117
117
  /** A hint — vocabulary or context — used where the model takes one. */
118
118
  prompt: z.string().check(maxUtf16Length(4_096)).optional(),
119
+ /**
120
+ * Send `transcript.interim`: the model's provisional text of the current
121
+ * item, about every half second, before any of it is final (contract set
122
+ * 8.1.0, Kaana ADR 0006). Only a `transcription` session sends it.
123
+ */
124
+ interimResults: z.boolean().optional(),
119
125
  })
120
126
  .strict();
121
127
  /** The target of a `translation` session. */
@@ -506,6 +512,21 @@ export const realtimeTranscriptDoneEventSchema = z.object({
506
512
  responseId: realtimeResponseIdSchema.optional(),
507
513
  transcript: z.string(),
508
514
  });
515
+ /**
516
+ * The provisional text of an input item not yet final (contract set 8.1.0,
517
+ * Kaana ADR 0006): sent only to a `transcription` session that asked for
518
+ * `interimResults`. Each one REPLACES the item's previous interim text; it is
519
+ * display state, never settled and never part of the item's transcript, and
520
+ * the item's next `transcript.delta` or its `transcript.done` supersedes it.
521
+ */
522
+ export const realtimeTranscriptInterimEventSchema = z.object({
523
+ ...eventBase,
524
+ type: z.literal('transcript.interim'),
525
+ source: z.literal('input_audio'),
526
+ itemId: realtimeItemIdSchema,
527
+ contentIndex: z.number().int().nonnegative().safe(),
528
+ text: z.string(),
529
+ });
509
530
  /** Written output of a response (`outputModalities` including `text`). */
510
531
  export const realtimeTextDeltaEventSchema = z.object({
511
532
  ...eventBase,
@@ -599,6 +620,9 @@ export function realtimeConfigIssues(kind, config) {
599
620
  }
600
621
  break;
601
622
  }
623
+ if (kind !== 'transcription' && config.inputAudioTranscription?.interimResults === true) {
624
+ found(['inputAudioTranscription', 'interimResults'], 'only a transcription session sends interim text');
625
+ }
602
626
  if (config.toolChoice !== undefined && !hasTools) {
603
627
  found(['toolChoice'], 'a tool choice requires at least one tool definition');
604
628
  }
@@ -805,6 +829,7 @@ export const realtimePublicServerEventSchema = z
805
829
  realtimeOutputAudioDoneEventSchema,
806
830
  realtimeTranscriptDeltaEventSchema,
807
831
  realtimeTranscriptDoneEventSchema,
832
+ realtimeTranscriptInterimEventSchema,
808
833
  realtimeTextDeltaEventSchema,
809
834
  realtimeToolCallEventSchema,
810
835
  realtimePublicResponseDoneEventSchema,
@@ -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 = "8.0.0";
103
+ export declare const INFERENCE_CONTRACT_VERSION = "8.2.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:
@@ -181,6 +181,20 @@ export declare const INFERENCE_CONTRACT_VERSION = "8.0.0";
181
181
  * envelopes v3 and v4 (`scopedExecutionSchema`, `privateAutoExecutionSchema`
182
182
  * and every shape under them) and a deployment's `scopedExecution`. A grant
183
183
  * or a request that parsed under 6.0.0 without them still parses the same.
184
+ *
185
+ * Contract set 8.1.0 (Kaana ADR 0006) is additive: a `transcription`
186
+ * session's `inputAudioTranscription.interimResults`, and the
187
+ * `transcript.interim` event it asks for, the provisional text of an input
188
+ * item that the item's deltas and its `transcript.done` supersede. Any other
189
+ * kind asking for interim text is refused. Nothing in 8.0.0 changes.
190
+ *
191
+ * Contract set 8.2.0 (Kaana ADR 0007) is additive: image input. The rules an
192
+ * image part answers to (`checkImageInput`, `INPUT_IMAGE_MEDIA_TYPES`,
193
+ * `MAX_INPUT_IMAGES`, `MAX_INPUT_IMAGE_BYTES`), the internal declared model's
194
+ * `imageInput` (the most input tokens one image costs on the line) and the
195
+ * grant fact `inputImages`. Every 8.1.0 message parses the same; a consumer on
196
+ * 8.1.0 or earlier refuses a declared catalogue or an authorization carrying
197
+ * what is new, so Oxy reads them before Kaana publishes them.
184
198
  */
185
199
  /** The public API's one origin and version. */
186
200
  export declare const KAANA_API_BASE_URL = "https://kaana.ai/v1";
@@ -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 = '8.0.0';
103
+ export const INFERENCE_CONTRACT_VERSION = '8.2.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:
@@ -181,6 +181,20 @@ export const INFERENCE_CONTRACT_VERSION = '8.0.0';
181
181
  * envelopes v3 and v4 (`scopedExecutionSchema`, `privateAutoExecutionSchema`
182
182
  * and every shape under them) and a deployment's `scopedExecution`. A grant
183
183
  * or a request that parsed under 6.0.0 without them still parses the same.
184
+ *
185
+ * Contract set 8.1.0 (Kaana ADR 0006) is additive: a `transcription`
186
+ * session's `inputAudioTranscription.interimResults`, and the
187
+ * `transcript.interim` event it asks for, the provisional text of an input
188
+ * item that the item's deltas and its `transcript.done` supersede. Any other
189
+ * kind asking for interim text is refused. Nothing in 8.0.0 changes.
190
+ *
191
+ * Contract set 8.2.0 (Kaana ADR 0007) is additive: image input. The rules an
192
+ * image part answers to (`checkImageInput`, `INPUT_IMAGE_MEDIA_TYPES`,
193
+ * `MAX_INPUT_IMAGES`, `MAX_INPUT_IMAGE_BYTES`), the internal declared model's
194
+ * `imageInput` (the most input tokens one image costs on the line) and the
195
+ * grant fact `inputImages`. Every 8.1.0 message parses the same; a consumer on
196
+ * 8.1.0 or earlier refuses a declared catalogue or an authorization carrying
197
+ * what is new, so Oxy reads them before Kaana publishes them.
184
198
  */
185
199
  /** The public API's one origin and version. */
186
200
  export const KAANA_API_BASE_URL = 'https://kaana.ai/v1';
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Kaana API",
5
- "version": "8.0.0",
5
+ "version": "8.2.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": [
@@ -4470,6 +4470,9 @@
4470
4470
  "prompt": {
4471
4471
  "type": "string",
4472
4472
  "maxLength": 4096
4473
+ },
4474
+ "interimResults": {
4475
+ "type": "boolean"
4473
4476
  }
4474
4477
  },
4475
4478
  "additionalProperties": false
@@ -5020,6 +5023,9 @@
5020
5023
  {
5021
5024
  "$ref": "#/components/schemas/RealtimeTranscriptDoneEvent"
5022
5025
  },
5026
+ {
5027
+ "$ref": "#/components/schemas/RealtimeTranscriptInterimEvent"
5028
+ },
5023
5029
  {
5024
5030
  "$ref": "#/components/schemas/RealtimeTextDeltaEvent"
5025
5031
  },
@@ -5945,6 +5951,55 @@
5945
5951
  "transcript"
5946
5952
  ]
5947
5953
  },
5954
+ "RealtimeTranscriptInterimEvent": {
5955
+ "type": "object",
5956
+ "properties": {
5957
+ "schemaVersion": {
5958
+ "type": "number",
5959
+ "const": 1
5960
+ },
5961
+ "requestId": {
5962
+ "$ref": "#/components/schemas/RequestId"
5963
+ },
5964
+ "sequence": {
5965
+ "type": "integer",
5966
+ "minimum": 0,
5967
+ "maximum": 9007199254740991
5968
+ },
5969
+ "commandId": {
5970
+ "$ref": "#/components/schemas/RealtimeCommandId"
5971
+ },
5972
+ "type": {
5973
+ "type": "string",
5974
+ "const": "transcript.interim"
5975
+ },
5976
+ "source": {
5977
+ "type": "string",
5978
+ "const": "input_audio"
5979
+ },
5980
+ "itemId": {
5981
+ "$ref": "#/components/schemas/RealtimeItemId"
5982
+ },
5983
+ "contentIndex": {
5984
+ "type": "integer",
5985
+ "minimum": 0,
5986
+ "maximum": 9007199254740991
5987
+ },
5988
+ "text": {
5989
+ "type": "string"
5990
+ }
5991
+ },
5992
+ "required": [
5993
+ "schemaVersion",
5994
+ "requestId",
5995
+ "sequence",
5996
+ "type",
5997
+ "source",
5998
+ "itemId",
5999
+ "contentIndex",
6000
+ "text"
6001
+ ]
6002
+ },
5948
6003
  "RealtimeTranscriptSource": {
5949
6004
  "type": "string",
5950
6005
  "enum": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaana.ai/contracts",
3
- "version": "8.0.1",
3
+ "version": "8.2.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,