@kaana.ai/contracts 8.0.0 → 8.0.1

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,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 { maxUtf16Length, minUtf16Length } from '../stringBounds.js';
7
8
  import { realtimeAudioFormatSchema, realtimeOutputModalitySchema } from './audioFormats.js';
8
9
  import { realtimeSessionKindSchema, realtimeSessionTransportSchema, } from './catalogue.js';
9
10
  import { inferenceTimestampSchema, modelReferenceSchema, PADDED_BASE64_PATTERN, requestIdSchema, } from './identifiers.js';
@@ -36,15 +37,21 @@ export const MAX_REALTIME_RESUME_WINDOW_MS = 60_000;
36
37
  */
37
38
  export const MAX_REALTIME_ITEM_TEXT_CHARS = 1_048_576;
38
39
  /** A client-chosen command identity, unique within one session. */
39
- export const realtimeCommandIdSchema = z.string().min(1).max(128);
40
+ export const realtimeCommandIdSchema = z
41
+ .string()
42
+ .check(minUtf16Length(1))
43
+ .check(maxUtf16Length(128));
40
44
  /** A conversation item's identity within one session. */
41
- export const realtimeItemIdSchema = z.string().min(1).max(128);
45
+ export const realtimeItemIdSchema = z.string().check(minUtf16Length(1)).check(maxUtf16Length(128));
42
46
  /** A response's identity within one session. */
43
- export const realtimeResponseIdSchema = z.string().min(1).max(128);
47
+ export const realtimeResponseIdSchema = z
48
+ .string()
49
+ .check(minUtf16Length(1))
50
+ .check(maxUtf16Length(128));
44
51
  const audioFrameSchema = z
45
52
  .string()
46
- .min(4)
47
- .max(MAX_REALTIME_AUDIO_FRAME_BASE64_LENGTH)
53
+ .check(minUtf16Length(4))
54
+ .check(maxUtf16Length(MAX_REALTIME_AUDIO_FRAME_BASE64_LENGTH))
48
55
  .regex(PADDED_BASE64_PATTERN);
49
56
  const sequenceSchema = z.number().int().nonnegative().safe();
50
57
  const milliseconds = z.number().int().nonnegative().safe();
@@ -106,16 +113,16 @@ export const realtimeInputTranscriptionSchema = z
106
113
  * the provider its spelling of that language, or none for the model to
107
114
  * detect; it is never refused.
108
115
  */
109
- language: z.string().min(2).max(35).optional(),
116
+ language: z.string().check(minUtf16Length(2)).check(maxUtf16Length(35)).optional(),
110
117
  /** A hint — vocabulary or context — used where the model takes one. */
111
- prompt: z.string().max(4_096).optional(),
118
+ prompt: z.string().check(maxUtf16Length(4_096)).optional(),
112
119
  })
113
120
  .strict();
114
121
  /** The target of a `translation` session. */
115
122
  export const realtimeTranslationSchema = z
116
123
  .object({
117
124
  /** A BCP 47 tag. */
118
- targetLanguage: z.string().min(2).max(35),
125
+ targetLanguage: z.string().check(minUtf16Length(2)).check(maxUtf16Length(35)),
119
126
  })
120
127
  .strict();
121
128
  /**
@@ -134,9 +141,9 @@ export const realtimeToolDefinitionSchema = toolDefinitionSchema.omit({ strict:
134
141
  */
135
142
  export const realtimeSessionConfigSchema = z
136
143
  .object({
137
- instructions: z.string().max(32_768).optional(),
144
+ instructions: z.string().check(maxUtf16Length(32_768)).optional(),
138
145
  outputModalities: z.array(realtimeOutputModalitySchema).min(1).max(2).optional(),
139
- voice: z.string().min(1).max(64).optional(),
146
+ voice: z.string().check(minUtf16Length(1)).check(maxUtf16Length(64)).optional(),
140
147
  inputAudioFormat: realtimeAudioFormatSchema,
141
148
  outputAudioFormat: realtimeAudioFormatSchema.optional(),
142
149
  turnDetection: realtimeTurnDetectionSchema,
@@ -158,7 +165,7 @@ export const realtimeSessionConfigSchema = z
158
165
  */
159
166
  export const realtimeSessionConfigUpdateSchema = z
160
167
  .object({
161
- instructions: z.string().max(32_768).optional(),
168
+ instructions: z.string().check(maxUtf16Length(32_768)).optional(),
162
169
  outputModalities: z.array(realtimeOutputModalitySchema).min(1).max(2).optional(),
163
170
  turnDetection: realtimeTurnDetectionSchema.optional(),
164
171
  inputAudioTranscription: realtimeInputTranscriptionSchema.optional(),
@@ -199,7 +206,10 @@ export const realtimeSessionLimitsSchema = z
199
206
  */
200
207
  export const realtimeContentPartSchema = z.discriminatedUnion('type', [
201
208
  z
202
- .object({ type: z.literal('input_text'), text: z.string().max(MAX_REALTIME_ITEM_TEXT_CHARS) })
209
+ .object({
210
+ type: z.literal('input_text'),
211
+ text: z.string().check(maxUtf16Length(MAX_REALTIME_ITEM_TEXT_CHARS)),
212
+ })
203
213
  .strict(),
204
214
  z
205
215
  .object({
@@ -239,8 +249,8 @@ export const realtimeConversationItemSchema = z
239
249
  .object({
240
250
  type: z.literal('function_call'),
241
251
  itemId: realtimeItemIdSchema.optional(),
242
- callId: z.string().min(1).max(128),
243
- name: z.string().min(1).max(128),
252
+ callId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)),
253
+ name: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)),
244
254
  arguments: z.string(),
245
255
  })
246
256
  .strict(),
@@ -248,8 +258,8 @@ export const realtimeConversationItemSchema = z
248
258
  .object({
249
259
  type: z.literal('function_call_output'),
250
260
  itemId: realtimeItemIdSchema.optional(),
251
- callId: z.string().min(1).max(128),
252
- output: z.string().max(MAX_REALTIME_ITEM_TEXT_CHARS),
261
+ callId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)),
262
+ output: z.string().check(maxUtf16Length(MAX_REALTIME_ITEM_TEXT_CHARS)),
253
263
  })
254
264
  .strict(),
255
265
  ])
@@ -279,7 +289,7 @@ export const realtimeConversationItemSchema = z
279
289
  /** Per-response overrides for `response.create`. Absent fields keep the session's. */
280
290
  export const realtimeResponseParametersSchema = z
281
291
  .object({
282
- instructions: z.string().max(32_768).optional(),
292
+ instructions: z.string().check(maxUtf16Length(32_768)).optional(),
283
293
  outputModalities: z.array(realtimeOutputModalitySchema).min(1).max(2).optional(),
284
294
  maxOutputTokens: z.number().int().positive().safe().optional(),
285
295
  toolChoice: toolChoiceSchema.optional(),
@@ -511,8 +521,8 @@ export const realtimeToolCallEventSchema = z.object({
511
521
  type: z.literal('tool_call'),
512
522
  responseId: realtimeResponseIdSchema,
513
523
  itemId: realtimeItemIdSchema,
514
- toolCallId: z.string().min(1).max(128),
515
- name: z.string().min(1).max(128).optional(),
524
+ toolCallId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)),
525
+ name: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)).optional(),
516
526
  argumentsDelta: z.string().optional(),
517
527
  complete: z.boolean(),
518
528
  });
@@ -644,7 +654,7 @@ export const realtimeSessionOpenSchema = z
644
654
  config: realtimeSessionConfigSchema,
645
655
  limits: realtimeOpenLimitsSchema.optional(),
646
656
  /** The caller's own correlation id. */
647
- clientSessionId: z.string().min(1).max(128).optional(),
657
+ clientSessionId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)).optional(),
648
658
  labels: requestLabelsSchema.optional(),
649
659
  })
650
660
  .strict()
@@ -8,6 +8,7 @@
8
8
  * catalogue identities), and the response names no serving provider.
9
9
  */
10
10
  import { z } from 'zod';
11
+ import { maxUtf16Length, minUtf16Length } from '../stringBounds.js';
11
12
  import { powerLevelSchema } from './catalogue.js';
12
13
  import { generationIdSchema, modelReferenceSchema, requestIdSchema } from './identifiers.js';
13
14
  import { inferenceMessageSchema, inferenceReasoningSchema, requestLabelsSchema, responseFormatSchema, toolChoiceSchema, toolDefinitionSchema, } from './messages.js';
@@ -22,7 +23,10 @@ import { inferenceFinishReasonSchema } from './streamEvents.js';
22
23
  */
23
24
  export const modelTargetSchema = z.union([modelReferenceSchema, powerLevelSchema]);
24
25
  /** The message-or-text input `/v1/responses` accepts. */
25
- const responsesInputSchema = z.union([z.string().min(1), z.array(inferenceMessageSchema).min(1)]);
26
+ const responsesInputSchema = z.union([
27
+ z.string().check(minUtf16Length(1)),
28
+ z.array(inferenceMessageSchema).min(1),
29
+ ]);
26
30
  /**
27
31
  * The request. `model` may be absent: the application's routing policy in Oxy
28
32
  * Console may name a default target, and the request is refused only when it
@@ -44,7 +48,10 @@ export const responsesRequestSchema = z
44
48
  frequencyPenalty: z.number().min(-2).max(2).optional(),
45
49
  presencePenalty: z.number().min(-2).max(2).optional(),
46
50
  seed: z.number().int().safe().optional(),
47
- stopSequences: z.array(z.string().min(1).max(256)).max(8).optional(),
51
+ stopSequences: z
52
+ .array(z.string().check(minUtf16Length(1)).check(maxUtf16Length(256)))
53
+ .max(8)
54
+ .optional(),
48
55
  tools: z.array(toolDefinitionSchema).max(128).optional(),
49
56
  toolChoice: toolChoiceSchema.optional(),
50
57
  responseFormat: responseFormatSchema.optional(),
@@ -52,7 +59,7 @@ export const responsesRequestSchema = z
52
59
  reasoning: inferenceReasoningSchema.optional(),
53
60
  labels: requestLabelsSchema.optional(),
54
61
  /** The caller's own correlation id, echoed on the response. */
55
- clientRequestId: z.string().min(1).max(128).optional(),
62
+ clientRequestId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)).optional(),
56
63
  })
57
64
  .strict()
58
65
  .superRefine((request, ctx) => {
@@ -5,6 +5,7 @@
5
5
  * Moved from `@oxy.so/contracts` 4.12.0 (`src/inference/streamEvents.ts`) by Kaana ADR 0002.
6
6
  */
7
7
  import { z } from 'zod';
8
+ import { maxUtf16Length, minUtf16Length } from '../stringBounds.js';
8
9
  import { generationIdSchema, inferenceTimestampSchema, modelReferenceSchema, PADDED_BASE64_PATTERN, requestIdSchema, } from './identifiers.js';
9
10
  import { publicErrorSchema } from './errors.js';
10
11
  import { usageQuantitySchema, usageSourceSchema } from './money.js';
@@ -51,7 +52,11 @@ export const inferenceStreamAudioEventSchema = z.object({
51
52
  sequence: z.number().int().nonnegative().safe(),
52
53
  outputIndex: z.number().int().nonnegative().safe(),
53
54
  mediaType: inferenceAudioMediaTypeSchema,
54
- data: z.string().min(4).max(65536).regex(PADDED_BASE64_PATTERN),
55
+ data: z
56
+ .string()
57
+ .check(minUtf16Length(4))
58
+ .check(maxUtf16Length(65536))
59
+ .regex(PADDED_BASE64_PATTERN),
55
60
  });
56
61
  /**
57
62
  * A tool call being streamed.
@@ -65,9 +70,9 @@ export const inferenceStreamToolCallEventSchema = z.object({
65
70
  type: z.literal('tool_call'),
66
71
  requestId: requestIdSchema,
67
72
  sequence: z.number().int().nonnegative().safe(),
68
- toolCallId: z.string().min(1).max(128),
73
+ toolCallId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)),
69
74
  /** Present on the first event of a call. */
70
- name: z.string().min(1).max(128).optional(),
75
+ name: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)).optional(),
71
76
  argumentsDelta: z.string().optional(),
72
77
  complete: z.boolean(),
73
78
  });
@@ -103,7 +108,7 @@ export const inferenceStreamDoneEventSchema = z.object({
103
108
  sequence: z.number().int().nonnegative().safe(),
104
109
  generationId: generationIdSchema.optional(),
105
110
  finishReason: inferenceFinishReasonSchema,
106
- receiptId: z.string().min(1).max(128).optional(),
111
+ receiptId: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)).optional(),
107
112
  completedAt: inferenceTimestampSchema,
108
113
  });
109
114
  /* -------------------------------------------------------------------------- */
@@ -0,0 +1,11 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Kaana's frozen wire contract measures strings in UTF-16 code units, as Go's
4
+ * utf16Length does. Zod >=4.5 measures its built-in string bounds in code points.
5
+ * These per-schema checks retain the standard bound metadata used by the Go
6
+ * descriptor and JSON Schema generators, with the contract's explicit measure.
7
+ * No Zod constructor, prototype, shared check or array validation is changed.
8
+ */
9
+ export declare function minUtf16Length(minimum: number): z.core.$ZodCheck<string>;
10
+ export declare function maxUtf16Length(maximum: number): z.core.$ZodCheck<string>;
11
+ export declare function utf16Length(length: number): z.core.$ZodCheck<string>;
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Kaana's frozen wire contract measures strings in UTF-16 code units, as Go's
4
+ * utf16Length does. Zod >=4.5 measures its built-in string bounds in code points.
5
+ * These per-schema checks retain the standard bound metadata used by the Go
6
+ * descriptor and JSON Schema generators, with the contract's explicit measure.
7
+ * No Zod constructor, prototype, shared check or array validation is changed.
8
+ */
9
+ export function minUtf16Length(minimum) {
10
+ const check = z.minLength(minimum);
11
+ check._zod.check = (payload) => {
12
+ if (payload.value.length >= minimum)
13
+ return;
14
+ payload.issues.push({
15
+ origin: 'string',
16
+ code: 'too_small',
17
+ minimum,
18
+ inclusive: true,
19
+ input: payload.value,
20
+ inst: check,
21
+ continue: true,
22
+ });
23
+ };
24
+ return check;
25
+ }
26
+ export function maxUtf16Length(maximum) {
27
+ const check = z.maxLength(maximum);
28
+ check._zod.check = (payload) => {
29
+ if (payload.value.length <= maximum)
30
+ return;
31
+ payload.issues.push({
32
+ origin: 'string',
33
+ code: 'too_big',
34
+ maximum,
35
+ inclusive: true,
36
+ input: payload.value,
37
+ inst: check,
38
+ continue: true,
39
+ });
40
+ };
41
+ return check;
42
+ }
43
+ export function utf16Length(length) {
44
+ const check = z.length(length);
45
+ check._zod.check = (payload) => {
46
+ if (payload.value.length === length)
47
+ return;
48
+ payload.issues.push({
49
+ origin: 'string',
50
+ ...(payload.value.length > length
51
+ ? { code: 'too_big', maximum: length }
52
+ : { code: 'too_small', minimum: length }),
53
+ inclusive: true,
54
+ exact: true,
55
+ input: payload.value,
56
+ inst: check,
57
+ continue: true,
58
+ });
59
+ };
60
+ return check;
61
+ }
@@ -0,0 +1,3 @@
1
+ import { z } from 'zod';
2
+ /** Preserve the existing UTC wire spelling, including minute precision. */
3
+ export declare function utcTimestampCheck(): z.core.$ZodCheck<string>;
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ /** Preserve the existing UTC wire spelling, including minute precision. */
3
+ export function utcTimestampCheck() {
4
+ // Zod >=4.6 requires seconds on a qualified datetime. Compose its calendar
5
+ // and time validators explicitly to retain the contract's previous grammar,
6
+ // without accepting offsets, local datetimes or invalid calendar dates.
7
+ const date = z.regexes.date.source.slice(1, -1);
8
+ const time = z.regexes.time({}).source.slice(1, -1);
9
+ return new z.core.$ZodISODateTime({
10
+ type: 'string',
11
+ format: 'datetime',
12
+ check: 'string_format',
13
+ offset: false,
14
+ local: false,
15
+ precision: null,
16
+ pattern: new RegExp(`^${date}T(?:${time}(?:Z))$`),
17
+ });
18
+ }
package/openapi.json CHANGED
@@ -1388,13 +1388,9 @@
1388
1388
  "minLength": 1
1389
1389
  },
1390
1390
  "param": {
1391
- "anyOf": [
1392
- {
1393
- "type": "string"
1394
- },
1395
- {
1396
- "type": "null"
1397
- }
1391
+ "type": [
1392
+ "string",
1393
+ "null"
1398
1394
  ]
1399
1395
  },
1400
1396
  "code": {
@@ -1542,13 +1538,9 @@
1542
1538
  "const": "assistant"
1543
1539
  },
1544
1540
  "content": {
1545
- "anyOf": [
1546
- {
1547
- "type": "string"
1548
- },
1549
- {
1550
- "type": "null"
1551
- }
1541
+ "type": [
1542
+ "string",
1543
+ "null"
1552
1544
  ]
1553
1545
  },
1554
1546
  "audio": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaana.ai/contracts",
3
- "version": "8.0.0",
3
+ "version": "8.0.1",
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,
@@ -38,10 +38,9 @@
38
38
  "scripts": {
39
39
  "build": "rm -rf dist && tsc -p tsconfig.build.json",
40
40
  "typecheck": "tsc -p tsconfig.json --noEmit",
41
- "test": "bun test src",
42
- "prepublishOnly": "bun run typecheck && bun run test && bun run build && make -C ../.. contract-generate"
41
+ "test": "bun test src"
43
42
  },
44
43
  "dependencies": {
45
- "zod": ">=4.4.3 <4.5.0"
44
+ "zod": ">=4.6.7 <5.0.0"
46
45
  }
47
46
  }