@kaana.ai/contracts 0.0.0-stage → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +673 -0
  2. package/NOTICE +21 -0
  3. package/dist/index.d.ts +29 -0
  4. package/dist/index.js +29 -0
  5. package/dist/internal/attribution.d.ts +116 -0
  6. package/dist/internal/attribution.js +82 -0
  7. package/dist/internal/canonical.d.ts +31 -0
  8. package/dist/internal/canonical.js +57 -0
  9. package/dist/internal/catalogue.d.ts +1059 -0
  10. package/dist/internal/catalogue.js +389 -0
  11. package/dist/internal/credentialControl.d.ts +329 -0
  12. package/dist/internal/credentialControl.js +256 -0
  13. package/dist/internal/decisions.d.ts +245 -0
  14. package/dist/internal/decisions.js +69 -0
  15. package/dist/internal/economics.d.ts +27 -0
  16. package/dist/internal/economics.js +26 -0
  17. package/dist/internal/embeddings.d.ts +164 -0
  18. package/dist/internal/embeddings.js +59 -0
  19. package/dist/internal/errors.d.ts +185 -0
  20. package/dist/internal/errors.js +211 -0
  21. package/dist/internal/grant.d.ts +699 -0
  22. package/dist/internal/grant.js +445 -0
  23. package/dist/internal/identifiers.d.ts +63 -0
  24. package/dist/internal/identifiers.js +65 -0
  25. package/dist/internal/privateAutoExecution.d.ts +158 -0
  26. package/dist/internal/privateAutoExecution.js +188 -0
  27. package/dist/internal/realtime.d.ts +1005 -0
  28. package/dist/internal/realtime.js +187 -0
  29. package/dist/internal/request.d.ts +1079 -0
  30. package/dist/internal/request.js +404 -0
  31. package/dist/internal/routing.d.ts +90 -0
  32. package/dist/internal/routing.js +139 -0
  33. package/dist/internal/scopedExecution.d.ts +74 -0
  34. package/dist/internal/scopedExecution.js +61 -0
  35. package/dist/internal/settlement.d.ts +205 -0
  36. package/dist/internal/settlement.js +71 -0
  37. package/dist/internal/streamEvents.d.ts +422 -0
  38. package/dist/internal/streamEvents.js +171 -0
  39. package/dist/internal/usage.d.ts +127 -0
  40. package/dist/internal/usage.js +109 -0
  41. package/dist/internal.d.ts +30 -0
  42. package/dist/internal.js +30 -0
  43. package/dist/public/audio.d.ts +347 -0
  44. package/dist/public/audio.js +236 -0
  45. package/dist/public/audioFormats.d.ts +64 -0
  46. package/dist/public/audioFormats.js +60 -0
  47. package/dist/public/catalogue.d.ts +914 -0
  48. package/dist/public/catalogue.js +516 -0
  49. package/dist/public/chatCompletions.d.ts +381 -0
  50. package/dist/public/chatCompletions.js +321 -0
  51. package/dist/public/decisions.d.ts +182 -0
  52. package/dist/public/decisions.js +257 -0
  53. package/dist/public/embeddings.d.ts +34 -0
  54. package/dist/public/embeddings.js +66 -0
  55. package/dist/public/errors.d.ts +195 -0
  56. package/dist/public/errors.js +274 -0
  57. package/dist/public/generations.d.ts +330 -0
  58. package/dist/public/generations.js +121 -0
  59. package/dist/public/identifiers.d.ts +139 -0
  60. package/dist/public/identifiers.js +160 -0
  61. package/dist/public/images.d.ts +36 -0
  62. package/dist/public/images.js +36 -0
  63. package/dist/public/messages.d.ts +297 -0
  64. package/dist/public/messages.js +251 -0
  65. package/dist/public/money.d.ts +308 -0
  66. package/dist/public/money.js +237 -0
  67. package/dist/public/policy.d.ts +19 -0
  68. package/dist/public/policy.js +20 -0
  69. package/dist/public/realtime.d.ts +2006 -0
  70. package/dist/public/realtime.js +797 -0
  71. package/dist/public/responses.d.ts +253 -0
  72. package/dist/public/responses.js +95 -0
  73. package/dist/public/streamEvents.d.ts +372 -0
  74. package/dist/public/streamEvents.js +157 -0
  75. package/dist/public/version.d.ts +184 -0
  76. package/dist/public/version.js +184 -0
  77. package/openapi.json +6967 -0
  78. package/package.json +44 -4
  79. package/README.md +0 -3
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Structured decisions (`POST /v1/decisions`).
3
+ *
4
+ * Moved from `@oxy.so/contracts` 4.12.0 (`src/inference/decisions.ts`) by Kaana ADR 0002.
5
+ */
6
+ import { z } from 'zod';
7
+ export declare const decisionEffortSchema: z.ZodEnum<{
8
+ low: "low";
9
+ medium: "medium";
10
+ high: "high";
11
+ instant: "instant";
12
+ xhigh: "xhigh";
13
+ }>;
14
+ export declare const decisionQuestionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
15
+ kind: z.ZodLiteral<"choice">;
16
+ options: z.ZodArray<z.ZodString>;
17
+ id: z.ZodString;
18
+ question: z.ZodString;
19
+ criteria: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strict>, z.ZodObject<{
21
+ kind: z.ZodLiteral<"score">;
22
+ levels: z.ZodArray<z.ZodString>;
23
+ id: z.ZodString;
24
+ question: z.ZodString;
25
+ criteria: z.ZodOptional<z.ZodString>;
26
+ }, z.core.$strict>, z.ZodObject<{
27
+ kind: z.ZodLiteral<"noul">;
28
+ id: z.ZodString;
29
+ question: z.ZodString;
30
+ criteria: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strict>], "kind">;
32
+ /**
33
+ * Conservative serialized input accounting, including escaping and structure.
34
+ * Measures both the normalized payload and the provider's structured-question
35
+ * representation. Common instructions repeat per question there. A 255-byte
36
+ * model identity and 4096-byte gateway-policy allowance bound adapter metadata.
37
+ * Kaana must also check its final serialized body before sending it.
38
+ */
39
+ export declare function decisionInputBudget(payload: DecisionInput): {
40
+ total: number;
41
+ context: number;
42
+ gateway: number;
43
+ };
44
+ /** OpenRouter's TOTAL limit is separate from direct state-plus-longest context. */
45
+ export declare function decisionFitsGateway(payload: DecisionInput): boolean;
46
+ export declare const decisionInputSchema: z.ZodObject<{
47
+ state: z.ZodString;
48
+ instructions: z.ZodOptional<z.ZodString>;
49
+ questions: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
50
+ kind: z.ZodLiteral<"choice">;
51
+ options: z.ZodArray<z.ZodString>;
52
+ id: z.ZodString;
53
+ question: z.ZodString;
54
+ criteria: z.ZodOptional<z.ZodString>;
55
+ }, z.core.$strict>, z.ZodObject<{
56
+ kind: z.ZodLiteral<"score">;
57
+ levels: z.ZodArray<z.ZodString>;
58
+ id: z.ZodString;
59
+ question: z.ZodString;
60
+ criteria: z.ZodOptional<z.ZodString>;
61
+ }, z.core.$strict>, z.ZodObject<{
62
+ kind: z.ZodLiteral<"noul">;
63
+ id: z.ZodString;
64
+ question: z.ZodString;
65
+ criteria: z.ZodOptional<z.ZodString>;
66
+ }, z.core.$strict>], "kind">>;
67
+ effort: z.ZodOptional<z.ZodEnum<{
68
+ low: "low";
69
+ medium: "medium";
70
+ high: "high";
71
+ instant: "instant";
72
+ xhigh: "xhigh";
73
+ }>>;
74
+ }, z.core.$strict>;
75
+ export declare const decisionRequestSchema: z.ZodObject<{
76
+ state: z.ZodString;
77
+ instructions: z.ZodOptional<z.ZodString>;
78
+ questions: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
79
+ kind: z.ZodLiteral<"choice">;
80
+ options: z.ZodArray<z.ZodString>;
81
+ id: z.ZodString;
82
+ question: z.ZodString;
83
+ criteria: z.ZodOptional<z.ZodString>;
84
+ }, z.core.$strict>, z.ZodObject<{
85
+ kind: z.ZodLiteral<"score">;
86
+ levels: z.ZodArray<z.ZodString>;
87
+ id: z.ZodString;
88
+ question: z.ZodString;
89
+ criteria: z.ZodOptional<z.ZodString>;
90
+ }, z.core.$strict>, z.ZodObject<{
91
+ kind: z.ZodLiteral<"noul">;
92
+ id: z.ZodString;
93
+ question: z.ZodString;
94
+ criteria: z.ZodOptional<z.ZodString>;
95
+ }, z.core.$strict>], "kind">>;
96
+ effort: z.ZodOptional<z.ZodEnum<{
97
+ low: "low";
98
+ medium: "medium";
99
+ high: "high";
100
+ instant: "instant";
101
+ xhigh: "xhigh";
102
+ }>>;
103
+ model: z.ZodString;
104
+ }, z.core.$strict>;
105
+ export declare const decisionAnswerSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
106
+ id: z.ZodString;
107
+ kind: z.ZodLiteral<"choice">;
108
+ reply: z.ZodString;
109
+ confidence: z.ZodNumber;
110
+ probabilities: z.ZodArray<z.ZodNumber>;
111
+ }, z.core.$strict>, z.ZodObject<{
112
+ id: z.ZodString;
113
+ kind: z.ZodLiteral<"score">;
114
+ reply: z.ZodNumber;
115
+ confidence: z.ZodNumber;
116
+ mean: z.ZodNumber;
117
+ distribution: z.ZodArray<z.ZodNumber>;
118
+ }, z.core.$strict>, z.ZodObject<{
119
+ id: z.ZodString;
120
+ kind: z.ZodLiteral<"noul">;
121
+ probability: z.ZodNumber;
122
+ }, z.core.$strict>], "kind">;
123
+ export declare const decisionSuccessSchema: z.ZodObject<{
124
+ usage: z.ZodArray<z.ZodObject<{
125
+ unit: z.ZodEnum<{
126
+ input_tokens: "input_tokens";
127
+ cached_input_tokens: "cached_input_tokens";
128
+ output_tokens: "output_tokens";
129
+ reasoning_tokens: "reasoning_tokens";
130
+ requests: "requests";
131
+ images: "images";
132
+ audio_input_milliseconds: "audio_input_milliseconds";
133
+ audio_output_milliseconds: "audio_output_milliseconds";
134
+ video_milliseconds: "video_milliseconds";
135
+ characters: "characters";
136
+ embeddings: "embeddings";
137
+ audio_input_tokens: "audio_input_tokens";
138
+ cached_audio_input_tokens: "cached_audio_input_tokens";
139
+ audio_output_tokens: "audio_output_tokens";
140
+ session_milliseconds: "session_milliseconds";
141
+ input_transcription_milliseconds: "input_transcription_milliseconds";
142
+ }>;
143
+ quantity: z.ZodNumber;
144
+ }, z.core.$strict>>;
145
+ routingPolicy: z.ZodObject<{
146
+ routingPolicyId: z.ZodString;
147
+ policyVersion: z.ZodNumber;
148
+ }, z.core.$strict>;
149
+ schemaVersion: z.ZodLiteral<1>;
150
+ requestId: z.ZodString;
151
+ model: z.ZodString;
152
+ data: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
153
+ id: z.ZodString;
154
+ kind: z.ZodLiteral<"choice">;
155
+ reply: z.ZodString;
156
+ confidence: z.ZodNumber;
157
+ probabilities: z.ZodArray<z.ZodNumber>;
158
+ }, z.core.$strict>, z.ZodObject<{
159
+ id: z.ZodString;
160
+ kind: z.ZodLiteral<"score">;
161
+ reply: z.ZodNumber;
162
+ confidence: z.ZodNumber;
163
+ mean: z.ZodNumber;
164
+ distribution: z.ZodArray<z.ZodNumber>;
165
+ }, z.core.$strict>, z.ZodObject<{
166
+ id: z.ZodString;
167
+ kind: z.ZodLiteral<"noul">;
168
+ probability: z.ZodNumber;
169
+ }, z.core.$strict>], "kind">>;
170
+ }, z.core.$strict>;
171
+ /** Bind output to the exact request. Provider order is not semantic. */
172
+ export declare function decisionAnswersMatch(input: DecisionInput, answers: readonly DecisionAnswer[]): boolean;
173
+ export type DecisionQuestion = z.infer<typeof decisionQuestionSchema>;
174
+ export type DecisionInput = {
175
+ state: string;
176
+ instructions?: string;
177
+ questions: DecisionQuestion[];
178
+ effort?: z.infer<typeof decisionEffortSchema>;
179
+ };
180
+ export type DecisionRequest = z.infer<typeof decisionRequestSchema>;
181
+ export type DecisionAnswer = z.infer<typeof decisionAnswerSchema>;
182
+ export type DecisionSuccess = z.infer<typeof decisionSuccessSchema>;
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Structured decisions (`POST /v1/decisions`).
3
+ *
4
+ * Moved from `@oxy.so/contracts` 4.12.0 (`src/inference/decisions.ts`) by Kaana ADR 0002.
5
+ */
6
+ import { z } from 'zod';
7
+ import { modelReferenceSchema, requestIdSchema } from './identifiers.js';
8
+ import { usageQuantitySchema } from './money.js';
9
+ import { routingPolicyReferenceSchema } from './policy.js';
10
+ const probability = z.number().finite().min(0).max(1);
11
+ const text = z.string().min(1).max(65536);
12
+ const id = z.string().min(1).max(128);
13
+ const tolerance = 1e-6;
14
+ export const decisionEffortSchema = z.enum(['instant', 'low', 'medium', 'high', 'xhigh']);
15
+ const common = { id, question: text, criteria: text.optional() };
16
+ export const decisionQuestionSchema = z.discriminatedUnion('kind', [
17
+ z
18
+ .object({
19
+ ...common,
20
+ kind: z.literal('choice'),
21
+ options: z.array(text).min(2).max(255),
22
+ })
23
+ .strict(),
24
+ z
25
+ .object({
26
+ ...common,
27
+ kind: z.literal('score'),
28
+ levels: z.array(text).min(2).max(10),
29
+ })
30
+ .strict(),
31
+ z.object({ ...common, kind: z.literal('noul') }).strict(),
32
+ ]);
33
+ const payloadFields = {
34
+ state: z.string().max(65536),
35
+ instructions: text.optional(),
36
+ questions: z.array(decisionQuestionSchema).min(1).max(255),
37
+ effort: decisionEffortSchema.optional(),
38
+ };
39
+ /**
40
+ * Conservative serialized input accounting, including escaping and structure.
41
+ * Measures both the normalized payload and the provider's structured-question
42
+ * representation. Common instructions repeat per question there. A 255-byte
43
+ * model identity and 4096-byte gateway-policy allowance bound adapter metadata.
44
+ * Kaana must also check its final serialized body before sending it.
45
+ */
46
+ export function decisionInputBudget(payload) {
47
+ const bytes = (value) => new TextEncoder().encode(JSON.stringify(value).replace(/[<>&\u2028\u2029]/g, (char) => `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`)).length;
48
+ const model = 'x'.repeat(255);
49
+ const measure = (questions) => {
50
+ const wireQuestions = Object.fromEntries(questions.map((q) => [
51
+ q.id,
52
+ {
53
+ type: q.kind,
54
+ instructions: {
55
+ question: q.question,
56
+ ...(payload.instructions === undefined ? {} : { instructions: payload.instructions }),
57
+ ...(q.criteria === undefined ? {} : { criteria: q.criteria }),
58
+ },
59
+ ...(q.kind === 'choice'
60
+ ? { criteria: Object.fromEntries(q.options.map((label) => [label, null])) }
61
+ : q.kind === 'score'
62
+ ? { criteria: q.levels }
63
+ : {}),
64
+ },
65
+ ]));
66
+ return Math.max(bytes({ ...payload, model, questions }), bytes({
67
+ model,
68
+ state: payload.state,
69
+ questions: wireQuestions,
70
+ ...(payload.effort === undefined ? {} : { effort: payload.effort }),
71
+ }));
72
+ };
73
+ const total = measure(payload.questions);
74
+ return {
75
+ total,
76
+ context: Math.max(...payload.questions.map((q) => measure([q]))),
77
+ gateway: total + 4096,
78
+ };
79
+ }
80
+ /** OpenRouter's TOTAL limit is separate from direct state-plus-longest context. */
81
+ export function decisionFitsGateway(payload) {
82
+ return decisionInputBudget(payload).gateway <= 32000;
83
+ }
84
+ /** JSON permits escaped lone UTF-16 units; Go replaces them after decoding. */
85
+ function hasUnpairedSurrogate(value) {
86
+ for (let i = 0; i < value.length; i++) {
87
+ const unit = value.charCodeAt(i);
88
+ if (unit >= 0xd800 && unit <= 0xdbff) {
89
+ const next = value.charCodeAt(i + 1);
90
+ if (!(next >= 0xdc00 && next <= 0xdfff))
91
+ return true;
92
+ i++;
93
+ }
94
+ else if (unit >= 0xdc00 && unit <= 0xdfff)
95
+ return true;
96
+ }
97
+ return false;
98
+ }
99
+ function validateInput(payload, ctx) {
100
+ const fields = [
101
+ { value: payload.state, path: ['state'] },
102
+ { value: payload.instructions, path: ['instructions'] },
103
+ ];
104
+ for (const [index, question] of payload.questions.entries()) {
105
+ for (const field of ['id', 'question', 'criteria']) {
106
+ fields.push({ value: question[field], path: ['questions', index, field] });
107
+ }
108
+ if (question.kind === 'choice' || question.kind === 'score') {
109
+ const field = question.kind === 'choice' ? 'options' : 'levels';
110
+ const labels = question.kind === 'choice' ? question.options : question.levels;
111
+ for (const [labelIndex, value] of labels.entries()) {
112
+ fields.push({ value, path: ['questions', index, field, labelIndex] });
113
+ }
114
+ }
115
+ }
116
+ let invalidUnicode = false;
117
+ for (const { value, path } of fields) {
118
+ if (value !== undefined && hasUnpairedSurrogate(value)) {
119
+ invalidUnicode = true;
120
+ ctx.addIssue({
121
+ code: 'custom',
122
+ path,
123
+ message: 'Decisions require paired UTF-16 surrogates.',
124
+ });
125
+ }
126
+ }
127
+ // Reject before measuring/reserving text that the execution runtime would change.
128
+ if (invalidUnicode)
129
+ return;
130
+ if (new Set(payload.questions.map((q) => q.id)).size !== payload.questions.length)
131
+ ctx.addIssue({
132
+ code: 'custom',
133
+ path: ['questions'],
134
+ message: 'Question IDs must be unique.',
135
+ });
136
+ for (const [index, question] of payload.questions.entries()) {
137
+ const labels = question.kind === 'choice'
138
+ ? question.options
139
+ : question.kind === 'score'
140
+ ? question.levels
141
+ : [];
142
+ if (new Set(labels).size !== labels.length)
143
+ ctx.addIssue({
144
+ code: 'custom',
145
+ path: ['questions', index],
146
+ message: 'Options and levels must be unique.',
147
+ });
148
+ }
149
+ const budget = decisionInputBudget(payload);
150
+ if (budget.total > 64000 || budget.context > 32000)
151
+ ctx.addIssue({
152
+ code: 'custom',
153
+ path: ['state'],
154
+ message: 'Decisions exceed the serialized 64000-byte total or 32000-byte per-question context budget.',
155
+ });
156
+ }
157
+ export const decisionInputSchema = z.object(payloadFields).strict().superRefine(validateInput);
158
+ export const decisionRequestSchema = z
159
+ .object({
160
+ model: modelReferenceSchema.refine((model) => model.includes('@'), 'Decisions require a revision-pinned model.'),
161
+ ...payloadFields,
162
+ })
163
+ .strict()
164
+ .superRefine(validateInput);
165
+ export const decisionAnswerSchema = z
166
+ .discriminatedUnion('kind', [
167
+ z
168
+ .object({
169
+ id,
170
+ kind: z.literal('choice'),
171
+ /** Actual provider-selected option. Never reconstructed from probabilities. */
172
+ reply: text,
173
+ /** Provider-returned confidence, not a correctness probability. */
174
+ confidence: probability,
175
+ probabilities: z.array(probability).min(2).max(255),
176
+ })
177
+ .strict(),
178
+ z
179
+ .object({
180
+ id,
181
+ kind: z.literal('score'),
182
+ /** Actual provider score. Kept separate from the validated expected index. */
183
+ reply: z.number().finite().min(0).max(9),
184
+ confidence: probability,
185
+ mean: z.number().finite().min(0).max(9),
186
+ distribution: z.array(probability).min(2).max(10),
187
+ })
188
+ .strict(),
189
+ z.object({ id, kind: z.literal('noul'), probability }).strict(),
190
+ ])
191
+ .superRefine((answer, ctx) => {
192
+ if (answer.kind === 'noul')
193
+ return;
194
+ if (answer.kind === 'score' && Math.abs(answer.reply - answer.mean) > tolerance) {
195
+ ctx.addIssue({
196
+ code: 'custom',
197
+ path: ['reply'],
198
+ message: 'Provider score must match the expected level index.',
199
+ });
200
+ }
201
+ const distribution = answer.kind === 'choice' ? answer.probabilities : answer.distribution;
202
+ if (Math.abs(distribution.reduce((sum, value) => sum + value, 0) - 1) > tolerance)
203
+ ctx.addIssue({
204
+ code: 'custom',
205
+ message: 'Probabilities must sum to one.',
206
+ });
207
+ if (answer.kind === 'score' &&
208
+ Math.abs(distribution.reduce((sum, value, index) => sum + index * value, 0) - answer.mean) >
209
+ tolerance)
210
+ ctx.addIssue({
211
+ code: 'custom',
212
+ path: ['mean'],
213
+ message: 'Mean must equal the expected zero-based level index.',
214
+ });
215
+ });
216
+ const resultFields = {
217
+ schemaVersion: z.literal(1),
218
+ requestId: requestIdSchema,
219
+ model: modelReferenceSchema.refine((model) => model.includes('@'), 'Decisions require an immutable model revision.'),
220
+ data: z.array(decisionAnswerSchema).min(1).max(255),
221
+ };
222
+ function uniqueAnswers(result, ctx) {
223
+ if (new Set(result.data.map((answer) => answer.id)).size !== result.data.length)
224
+ ctx.addIssue({
225
+ code: 'custom',
226
+ path: ['data'],
227
+ message: 'Answer IDs must be unique.',
228
+ });
229
+ }
230
+ export const decisionSuccessSchema = z
231
+ .object({
232
+ ...resultFields,
233
+ usage: z.array(usageQuantitySchema),
234
+ routingPolicy: routingPolicyReferenceSchema,
235
+ })
236
+ .strict()
237
+ .superRefine(uniqueAnswers);
238
+ /** Bind output to the exact request. Provider order is not semantic. */
239
+ export function decisionAnswersMatch(input, answers) {
240
+ if (answers.length !== input.questions.length ||
241
+ new Set(answers.map((a) => a.id)).size !== answers.length)
242
+ return false;
243
+ return input.questions.every((question) => {
244
+ const answer = answers.find((candidate) => candidate.id === question.id);
245
+ if (!answer || !decisionAnswerSchema.safeParse(answer).success || answer.kind !== question.kind)
246
+ return false;
247
+ if (question.kind === 'choice' && answer.kind === 'choice') {
248
+ const index = question.options.indexOf(answer.reply);
249
+ return (question.options.length === answer.probabilities.length &&
250
+ index >= 0 &&
251
+ answer.probabilities[index] + tolerance >= Math.max(...answer.probabilities));
252
+ }
253
+ if (question.kind === 'score' && answer.kind === 'score')
254
+ return question.levels.length === answer.distribution.length;
255
+ return question.kind === 'noul';
256
+ });
257
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `POST /v1/embeddings` — OpenAI-compatible, so a stock OpenAI client works
3
+ * against `https://kaana.ai/v1`.
4
+ *
5
+ * New in contract set 4.0.0 (Kaana ADR 0002, decision 7). The signed-lane
6
+ * result Kaana already produced (`embeddingSuccessSchema` in `/internal`)
7
+ * bounds what this surface can promise: at most 2048 inputs per request and
8
+ * vectors of at most 1024 dimensions.
9
+ */
10
+ import { z } from 'zod';
11
+ /** The most inputs one request may embed. */
12
+ export declare const MAX_EMBEDDING_INPUTS = 2048;
13
+ export declare const embeddingsRequestSchema: z.ZodObject<{
14
+ model: z.ZodString;
15
+ input: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>;
16
+ encoding_format: z.ZodOptional<z.ZodLiteral<"float">>;
17
+ dimensions: z.ZodOptional<z.ZodNumber>;
18
+ user: z.ZodOptional<z.ZodString>;
19
+ }, z.core.$strict>;
20
+ export declare const embeddingsResponseSchema: z.ZodObject<{
21
+ object: z.ZodLiteral<"list">;
22
+ data: z.ZodArray<z.ZodObject<{
23
+ object: z.ZodLiteral<"embedding">;
24
+ index: z.ZodNumber;
25
+ embedding: z.ZodArray<z.ZodNumber>;
26
+ }, z.core.$strict>>;
27
+ model: z.ZodString;
28
+ usage: z.ZodObject<{
29
+ prompt_tokens: z.ZodNumber;
30
+ total_tokens: z.ZodNumber;
31
+ }, z.core.$strict>;
32
+ }, z.core.$strict>;
33
+ export type EmbeddingsRequest = z.infer<typeof embeddingsRequestSchema>;
34
+ export type EmbeddingsResponse = z.infer<typeof embeddingsResponseSchema>;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * `POST /v1/embeddings` — OpenAI-compatible, so a stock OpenAI client works
3
+ * against `https://kaana.ai/v1`.
4
+ *
5
+ * New in contract set 4.0.0 (Kaana ADR 0002, decision 7). The signed-lane
6
+ * result Kaana already produced (`embeddingSuccessSchema` in `/internal`)
7
+ * bounds what this surface can promise: at most 2048 inputs per request and
8
+ * vectors of at most 1024 dimensions.
9
+ */
10
+ import { z } from 'zod';
11
+ import { modelReferenceSchema } from './identifiers.js';
12
+ /** The most inputs one request may embed. */
13
+ export const MAX_EMBEDDING_INPUTS = 2048;
14
+ export const embeddingsRequestSchema = z
15
+ .object({
16
+ /** A concrete model: an embedding space is a property of exact weights. */
17
+ model: modelReferenceSchema,
18
+ input: z.union([
19
+ z.string().min(1),
20
+ z.array(z.string().min(1)).min(1).max(MAX_EMBEDDING_INPUTS),
21
+ ]),
22
+ /** Only `float`: base64 vectors are an encoding the contract does not carry. */
23
+ encoding_format: z.literal('float').optional(),
24
+ /** Requested output dimension, for models that can shorten their vectors. */
25
+ dimensions: z.number().int().positive().max(1024).optional(),
26
+ /** OpenAI's end-user attribution field: the delegated user id, attribution only. */
27
+ user: z.string().min(1).max(64).optional(),
28
+ })
29
+ .strict();
30
+ export const embeddingsResponseSchema = z
31
+ .object({
32
+ object: z.literal('list'),
33
+ data: z
34
+ .array(z
35
+ .object({
36
+ object: z.literal('embedding'),
37
+ index: z.number().int().nonnegative(),
38
+ embedding: z.array(z.number()).min(1).max(1024),
39
+ })
40
+ .strict())
41
+ .min(1)
42
+ .max(MAX_EMBEDDING_INPUTS),
43
+ /** The revision that produced the vectors. */
44
+ model: modelReferenceSchema,
45
+ usage: z
46
+ .object({
47
+ prompt_tokens: z.number().int().nonnegative(),
48
+ total_tokens: z.number().int().nonnegative(),
49
+ })
50
+ .strict(),
51
+ })
52
+ .strict()
53
+ .superRefine((response, ctx) => {
54
+ const indexes = response.data.map((vector) => vector.index);
55
+ if (new Set(indexes).size !== indexes.length) {
56
+ ctx.addIssue({ code: 'custom', path: ['data'], message: 'embedding indexes must be unique' });
57
+ }
58
+ const dimensions = new Set(response.data.map((vector) => vector.embedding.length));
59
+ if (dimensions.size > 1) {
60
+ ctx.addIssue({
61
+ code: 'custom',
62
+ path: ['data'],
63
+ message: 'every vector of one response has the same dimension',
64
+ });
65
+ }
66
+ });