@kaana.ai/contracts 8.2.0 → 8.3.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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/internal/catalogue.d.ts +1 -1
- package/dist/internal/realtime.d.ts +2 -2
- package/dist/internal/request.d.ts +2 -2
- package/dist/public/anthropicMessages.d.ts +284 -0
- package/dist/public/anthropicMessages.js +274 -0
- package/dist/public/chatCompletions.d.ts +2 -2
- package/dist/public/messages.d.ts +2 -2
- package/dist/public/messages.js +1 -1
- package/dist/public/realtime.d.ts +7 -7
- package/dist/public/responses.d.ts +2 -2
- package/dist/public/version.d.ts +7 -1
- package/dist/public/version.js +7 -1
- package/openapi.json +1274 -140
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* Accounts, applications, `oxy_sk_…` keys, limits and billing are managed in
|
|
11
11
|
* Oxy Console (`https://console.oxy.so`), never here.
|
|
12
12
|
*/
|
|
13
|
+
export * from './public/anthropicMessages.js';
|
|
13
14
|
export * from './public/audio.js';
|
|
14
15
|
export * from './public/audioFormats.js';
|
|
15
16
|
export * from './public/catalogue.js';
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* Accounts, applications, `oxy_sk_…` keys, limits and billing are managed in
|
|
11
11
|
* Oxy Console (`https://console.oxy.so`), never here.
|
|
12
12
|
*/
|
|
13
|
+
export * from './public/anthropicMessages.js';
|
|
13
14
|
export * from './public/audio.js';
|
|
14
15
|
export * from './public/audioFormats.js';
|
|
15
16
|
export * from './public/catalogue.js';
|
|
@@ -254,8 +254,8 @@ export declare const modelDeploymentSchema: z.ZodObject<{
|
|
|
254
254
|
status: z.ZodEnum<{
|
|
255
255
|
active: "active";
|
|
256
256
|
retired: "retired";
|
|
257
|
-
degraded: "degraded";
|
|
258
257
|
disabled: "disabled";
|
|
258
|
+
degraded: "degraded";
|
|
259
259
|
}>;
|
|
260
260
|
dedicatedCapacity: z.ZodBoolean;
|
|
261
261
|
priceVersionId: z.ZodOptional<z.ZodString>;
|
|
@@ -631,8 +631,8 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
631
631
|
type: z.ZodLiteral<"message">;
|
|
632
632
|
itemId: z.ZodOptional<z.ZodString>;
|
|
633
633
|
role: z.ZodEnum<{
|
|
634
|
-
user: "user";
|
|
635
634
|
system: "system";
|
|
635
|
+
user: "user";
|
|
636
636
|
assistant: "assistant";
|
|
637
637
|
}>;
|
|
638
638
|
content: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -682,8 +682,8 @@ export declare const realtimeServerEventSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
682
682
|
type: z.ZodLiteral<"message">;
|
|
683
683
|
itemId: z.ZodOptional<z.ZodString>;
|
|
684
684
|
role: z.ZodEnum<{
|
|
685
|
-
user: "user";
|
|
686
685
|
system: "system";
|
|
686
|
+
user: "user";
|
|
687
687
|
assistant: "assistant";
|
|
688
688
|
}>;
|
|
689
689
|
content: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -47,9 +47,9 @@ export declare const inferenceInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
47
47
|
format: z.ZodLiteral<"messages">;
|
|
48
48
|
messages: z.ZodArray<z.ZodObject<{
|
|
49
49
|
role: z.ZodEnum<{
|
|
50
|
-
user: "user";
|
|
51
50
|
system: "system";
|
|
52
51
|
developer: "developer";
|
|
52
|
+
user: "user";
|
|
53
53
|
assistant: "assistant";
|
|
54
54
|
tool: "tool";
|
|
55
55
|
}>;
|
|
@@ -231,9 +231,9 @@ export declare const inferenceRequestSchema: z.ZodObject<{
|
|
|
231
231
|
format: z.ZodLiteral<"messages">;
|
|
232
232
|
messages: z.ZodArray<z.ZodObject<{
|
|
233
233
|
role: z.ZodEnum<{
|
|
234
|
-
user: "user";
|
|
235
234
|
system: "system";
|
|
236
235
|
developer: "developer";
|
|
236
|
+
user: "user";
|
|
237
237
|
assistant: "assistant";
|
|
238
238
|
tool: "tool";
|
|
239
239
|
}>;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `POST /v1/messages` — the Anthropic-Messages-compatible surface.
|
|
3
|
+
*
|
|
4
|
+
* It speaks the flat Anthropic request, response and stream shapes so an
|
|
5
|
+
* unmodified Anthropic SDK or Claude Code works with
|
|
6
|
+
* `ANTHROPIC_BASE_URL=https://kaana.ai` and an `oxy_sk_…` key (sent as
|
|
7
|
+
* `x-api-key` or as `Authorization: Bearer`). Like `/v1/chat/completions` it
|
|
8
|
+
* gains NO Kaana-specific request field, and it is `.strict()` everywhere: a
|
|
9
|
+
* stock SDK sending a parameter Kaana does not implement is told so rather than
|
|
10
|
+
* having it silently dropped.
|
|
11
|
+
*
|
|
12
|
+
* ## What is refused, and why
|
|
13
|
+
*
|
|
14
|
+
* - **`cache_control`, anywhere** (on a block, a tool, `system` or the
|
|
15
|
+
* request). Kaana's usage units have no unit for a cache WRITE (see the
|
|
16
|
+
* Anthropic adapter's usage meter): a cache write is billed at a premium
|
|
17
|
+
* over input, so honouring the marker while folding the write into
|
|
18
|
+
* `input_tokens` would report less than the request cost. The marker is
|
|
19
|
+
* refused, by name and path, instead of being dropped.
|
|
20
|
+
* - **`thinking` other than `{ type: 'disabled' }`.** The contract's reasoning
|
|
21
|
+
* control is an effort (`low`, `medium`, `high`), not a token budget, and a
|
|
22
|
+
* thinking block has no part in a message: reasoning is private and is never
|
|
23
|
+
* returned. Reasoning effort is asked with `output_config.effort`, which
|
|
24
|
+
* maps one to one. A `thinking` or `redacted_thinking` block in a message is
|
|
25
|
+
* refused for the same reason.
|
|
26
|
+
* - **Server tools** (`web_search`, `bash`, `text_editor`, …), `mcp_servers`,
|
|
27
|
+
* `container`, `service_tier`, `disable_parallel_tool_use`, `document`
|
|
28
|
+
* blocks and any other member this file does not name.
|
|
29
|
+
* - **An image `url` source**: nothing fetches an image URL (ADR 0007); a
|
|
30
|
+
* `base64` source is carried inline under the image rules.
|
|
31
|
+
*
|
|
32
|
+
* `stop_reason: 'stop_sequence'` is never produced: the finish reason Kaana
|
|
33
|
+
* measures does not say WHICH stop sequence ended the turn, and `stop_sequence`
|
|
34
|
+
* would then have to name one. A turn that ended on a stop sequence reports
|
|
35
|
+
* `end_turn`.
|
|
36
|
+
*
|
|
37
|
+
* `metadata.user_id` is accepted and neither forwarded nor stored: it is an
|
|
38
|
+
* end-user identifier, and Kaana persists none.
|
|
39
|
+
*
|
|
40
|
+
* `usage` is derived from the measured units: `input_tokens`, `output_tokens`
|
|
41
|
+
* (reasoning included, as Anthropic counts it) and, only when the route
|
|
42
|
+
* measured it, `cache_read_input_tokens`. There is no `cache_creation_*`.
|
|
43
|
+
*/
|
|
44
|
+
import { z } from 'zod';
|
|
45
|
+
export declare const anthropicMessagesRequestSchema: z.ZodObject<{
|
|
46
|
+
model: z.ZodUnion<readonly [z.ZodString, z.ZodEnum<{
|
|
47
|
+
medium: "medium";
|
|
48
|
+
high: "high";
|
|
49
|
+
auto: "auto";
|
|
50
|
+
instant: "instant";
|
|
51
|
+
xhigh: "xhigh";
|
|
52
|
+
pro: "pro";
|
|
53
|
+
ultra: "ultra";
|
|
54
|
+
}>]>;
|
|
55
|
+
max_tokens: z.ZodNumber;
|
|
56
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
57
|
+
role: z.ZodEnum<{
|
|
58
|
+
user: "user";
|
|
59
|
+
assistant: "assistant";
|
|
60
|
+
}>;
|
|
61
|
+
content: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
62
|
+
type: z.ZodLiteral<"text">;
|
|
63
|
+
text: z.ZodString;
|
|
64
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
65
|
+
type: z.ZodLiteral<"image">;
|
|
66
|
+
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
67
|
+
type: z.ZodLiteral<"base64">;
|
|
68
|
+
media_type: z.ZodString;
|
|
69
|
+
data: z.ZodString;
|
|
70
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
71
|
+
type: z.ZodLiteral<"url">;
|
|
72
|
+
url: z.ZodString;
|
|
73
|
+
}, z.core.$strict>], "type">;
|
|
74
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
75
|
+
type: z.ZodLiteral<"tool_use">;
|
|
76
|
+
id: z.ZodString;
|
|
77
|
+
name: z.ZodString;
|
|
78
|
+
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
79
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
80
|
+
type: z.ZodLiteral<"tool_result">;
|
|
81
|
+
tool_use_id: z.ZodString;
|
|
82
|
+
content: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
83
|
+
type: z.ZodLiteral<"text">;
|
|
84
|
+
text: z.ZodString;
|
|
85
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
86
|
+
type: z.ZodLiteral<"image">;
|
|
87
|
+
source: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
88
|
+
type: z.ZodLiteral<"base64">;
|
|
89
|
+
media_type: z.ZodString;
|
|
90
|
+
data: z.ZodString;
|
|
91
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
92
|
+
type: z.ZodLiteral<"url">;
|
|
93
|
+
url: z.ZodString;
|
|
94
|
+
}, z.core.$strict>], "type">;
|
|
95
|
+
}, z.core.$strict>]>>]>>;
|
|
96
|
+
is_error: z.ZodOptional<z.ZodBoolean>;
|
|
97
|
+
}, z.core.$strict>]>>]>;
|
|
98
|
+
}, z.core.$strict>>;
|
|
99
|
+
system: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodObject<{
|
|
100
|
+
type: z.ZodLiteral<"text">;
|
|
101
|
+
text: z.ZodString;
|
|
102
|
+
}, z.core.$strict>>]>>;
|
|
103
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
104
|
+
top_p: z.ZodOptional<z.ZodNumber>;
|
|
105
|
+
top_k: z.ZodOptional<z.ZodNumber>;
|
|
106
|
+
stop_sequences: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
107
|
+
stream: z.ZodOptional<z.ZodBoolean>;
|
|
108
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
109
|
+
type: z.ZodOptional<z.ZodLiteral<"custom">>;
|
|
110
|
+
name: z.ZodString;
|
|
111
|
+
description: z.ZodOptional<z.ZodString>;
|
|
112
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
113
|
+
strict: z.ZodOptional<z.ZodBoolean>;
|
|
114
|
+
}, z.core.$strict>>>;
|
|
115
|
+
tool_choice: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
116
|
+
type: z.ZodLiteral<"auto">;
|
|
117
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
118
|
+
type: z.ZodLiteral<"any">;
|
|
119
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
120
|
+
type: z.ZodLiteral<"none">;
|
|
121
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
122
|
+
type: z.ZodLiteral<"tool">;
|
|
123
|
+
name: z.ZodString;
|
|
124
|
+
}, z.core.$strict>], "type">>;
|
|
125
|
+
thinking: z.ZodOptional<z.ZodObject<{
|
|
126
|
+
type: z.ZodLiteral<"disabled">;
|
|
127
|
+
}, z.core.$strict>>;
|
|
128
|
+
output_config: z.ZodOptional<z.ZodObject<{
|
|
129
|
+
effort: z.ZodOptional<z.ZodEnum<{
|
|
130
|
+
low: "low";
|
|
131
|
+
medium: "medium";
|
|
132
|
+
high: "high";
|
|
133
|
+
}>>;
|
|
134
|
+
}, z.core.$strict>>;
|
|
135
|
+
metadata: z.ZodOptional<z.ZodObject<{
|
|
136
|
+
user_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
137
|
+
}, z.core.$strict>>;
|
|
138
|
+
}, z.core.$strict>;
|
|
139
|
+
/** The non-streaming body. The request id rides in `Kaana-Request-Id` and `Request-Id`. */
|
|
140
|
+
export declare const anthropicMessageSchema: z.ZodObject<{
|
|
141
|
+
id: z.ZodString;
|
|
142
|
+
type: z.ZodLiteral<"message">;
|
|
143
|
+
role: z.ZodLiteral<"assistant">;
|
|
144
|
+
model: z.ZodString;
|
|
145
|
+
content: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
146
|
+
type: z.ZodLiteral<"text">;
|
|
147
|
+
text: z.ZodString;
|
|
148
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
149
|
+
type: z.ZodLiteral<"tool_use">;
|
|
150
|
+
id: z.ZodString;
|
|
151
|
+
name: z.ZodString;
|
|
152
|
+
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
153
|
+
}, z.core.$strict>], "type">>;
|
|
154
|
+
stop_reason: z.ZodEnum<{
|
|
155
|
+
refusal: "refusal";
|
|
156
|
+
tool_use: "tool_use";
|
|
157
|
+
max_tokens: "max_tokens";
|
|
158
|
+
end_turn: "end_turn";
|
|
159
|
+
}>;
|
|
160
|
+
stop_sequence: z.ZodLiteral<null>;
|
|
161
|
+
usage: z.ZodObject<{
|
|
162
|
+
input_tokens: z.ZodNumber;
|
|
163
|
+
output_tokens: z.ZodNumber;
|
|
164
|
+
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
165
|
+
}, z.core.$strict>;
|
|
166
|
+
}, z.core.$strict>;
|
|
167
|
+
/** The error body, and the data of a stream's `event: error` frame. */
|
|
168
|
+
export declare const anthropicErrorSchema: z.ZodObject<{
|
|
169
|
+
type: z.ZodLiteral<"error">;
|
|
170
|
+
error: z.ZodObject<{
|
|
171
|
+
type: z.ZodEnum<{
|
|
172
|
+
request_too_large: "request_too_large";
|
|
173
|
+
invalid_request_error: "invalid_request_error";
|
|
174
|
+
authentication_error: "authentication_error";
|
|
175
|
+
billing_error: "billing_error";
|
|
176
|
+
permission_error: "permission_error";
|
|
177
|
+
not_found_error: "not_found_error";
|
|
178
|
+
rate_limit_error: "rate_limit_error";
|
|
179
|
+
timeout_error: "timeout_error";
|
|
180
|
+
overloaded_error: "overloaded_error";
|
|
181
|
+
api_error: "api_error";
|
|
182
|
+
}>;
|
|
183
|
+
message: z.ZodString;
|
|
184
|
+
}, z.core.$strict>;
|
|
185
|
+
request_id: z.ZodOptional<z.ZodString>;
|
|
186
|
+
}, z.core.$strict>;
|
|
187
|
+
/**
|
|
188
|
+
* One frame of a streamed message: `event: <type>` and this as its data. The
|
|
189
|
+
* input tokens are known only when the route reports usage, so `message_start`
|
|
190
|
+
* carries zeros and the final `message_delta` the measured totals. A stream that
|
|
191
|
+
* fails after its first frame ends with an `error` frame and no `message_stop`.
|
|
192
|
+
*/
|
|
193
|
+
export declare const anthropicStreamEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
194
|
+
type: z.ZodLiteral<"message_start">;
|
|
195
|
+
message: z.ZodObject<{
|
|
196
|
+
id: z.ZodString;
|
|
197
|
+
type: z.ZodLiteral<"message">;
|
|
198
|
+
role: z.ZodLiteral<"assistant">;
|
|
199
|
+
model: z.ZodString;
|
|
200
|
+
content: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
201
|
+
type: z.ZodLiteral<"text">;
|
|
202
|
+
text: z.ZodString;
|
|
203
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
204
|
+
type: z.ZodLiteral<"tool_use">;
|
|
205
|
+
id: z.ZodString;
|
|
206
|
+
name: z.ZodString;
|
|
207
|
+
input: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
208
|
+
}, z.core.$strict>], "type">>;
|
|
209
|
+
stop_reason: z.ZodLiteral<null>;
|
|
210
|
+
stop_sequence: z.ZodLiteral<null>;
|
|
211
|
+
usage: z.ZodObject<{
|
|
212
|
+
input_tokens: z.ZodNumber;
|
|
213
|
+
output_tokens: z.ZodNumber;
|
|
214
|
+
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
215
|
+
}, z.core.$strict>;
|
|
216
|
+
}, z.core.$strict>;
|
|
217
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
218
|
+
type: z.ZodLiteral<"content_block_start">;
|
|
219
|
+
index: z.ZodNumber;
|
|
220
|
+
content_block: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
221
|
+
type: z.ZodLiteral<"text">;
|
|
222
|
+
text: z.ZodLiteral<"">;
|
|
223
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
224
|
+
type: z.ZodLiteral<"tool_use">;
|
|
225
|
+
id: z.ZodString;
|
|
226
|
+
name: z.ZodString;
|
|
227
|
+
input: z.ZodObject<{}, z.core.$strict>;
|
|
228
|
+
}, z.core.$strict>], "type">;
|
|
229
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
230
|
+
type: z.ZodLiteral<"content_block_delta">;
|
|
231
|
+
index: z.ZodNumber;
|
|
232
|
+
delta: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
233
|
+
type: z.ZodLiteral<"text_delta">;
|
|
234
|
+
text: z.ZodString;
|
|
235
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
236
|
+
type: z.ZodLiteral<"input_json_delta">;
|
|
237
|
+
partial_json: z.ZodString;
|
|
238
|
+
}, z.core.$strict>], "type">;
|
|
239
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
240
|
+
type: z.ZodLiteral<"content_block_stop">;
|
|
241
|
+
index: z.ZodNumber;
|
|
242
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
243
|
+
type: z.ZodLiteral<"message_delta">;
|
|
244
|
+
delta: z.ZodObject<{
|
|
245
|
+
stop_reason: z.ZodEnum<{
|
|
246
|
+
refusal: "refusal";
|
|
247
|
+
tool_use: "tool_use";
|
|
248
|
+
max_tokens: "max_tokens";
|
|
249
|
+
end_turn: "end_turn";
|
|
250
|
+
}>;
|
|
251
|
+
stop_sequence: z.ZodLiteral<null>;
|
|
252
|
+
}, z.core.$strict>;
|
|
253
|
+
usage: z.ZodObject<{
|
|
254
|
+
input_tokens: z.ZodNumber;
|
|
255
|
+
output_tokens: z.ZodNumber;
|
|
256
|
+
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
257
|
+
}, z.core.$strict>;
|
|
258
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
259
|
+
type: z.ZodLiteral<"message_stop">;
|
|
260
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
261
|
+
type: z.ZodLiteral<"ping">;
|
|
262
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
263
|
+
type: z.ZodLiteral<"error">;
|
|
264
|
+
error: z.ZodObject<{
|
|
265
|
+
type: z.ZodEnum<{
|
|
266
|
+
request_too_large: "request_too_large";
|
|
267
|
+
invalid_request_error: "invalid_request_error";
|
|
268
|
+
authentication_error: "authentication_error";
|
|
269
|
+
billing_error: "billing_error";
|
|
270
|
+
permission_error: "permission_error";
|
|
271
|
+
not_found_error: "not_found_error";
|
|
272
|
+
rate_limit_error: "rate_limit_error";
|
|
273
|
+
timeout_error: "timeout_error";
|
|
274
|
+
overloaded_error: "overloaded_error";
|
|
275
|
+
api_error: "api_error";
|
|
276
|
+
}>;
|
|
277
|
+
message: z.ZodString;
|
|
278
|
+
}, z.core.$strict>;
|
|
279
|
+
request_id: z.ZodOptional<z.ZodString>;
|
|
280
|
+
}, z.core.$strict>], "type">;
|
|
281
|
+
export type AnthropicMessagesRequest = z.infer<typeof anthropicMessagesRequestSchema>;
|
|
282
|
+
export type AnthropicMessage = z.infer<typeof anthropicMessageSchema>;
|
|
283
|
+
export type AnthropicError = z.infer<typeof anthropicErrorSchema>;
|
|
284
|
+
export type AnthropicStreamEvent = z.infer<typeof anthropicStreamEventSchema>;
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `POST /v1/messages` — the Anthropic-Messages-compatible surface.
|
|
3
|
+
*
|
|
4
|
+
* It speaks the flat Anthropic request, response and stream shapes so an
|
|
5
|
+
* unmodified Anthropic SDK or Claude Code works with
|
|
6
|
+
* `ANTHROPIC_BASE_URL=https://kaana.ai` and an `oxy_sk_…` key (sent as
|
|
7
|
+
* `x-api-key` or as `Authorization: Bearer`). Like `/v1/chat/completions` it
|
|
8
|
+
* gains NO Kaana-specific request field, and it is `.strict()` everywhere: a
|
|
9
|
+
* stock SDK sending a parameter Kaana does not implement is told so rather than
|
|
10
|
+
* having it silently dropped.
|
|
11
|
+
*
|
|
12
|
+
* ## What is refused, and why
|
|
13
|
+
*
|
|
14
|
+
* - **`cache_control`, anywhere** (on a block, a tool, `system` or the
|
|
15
|
+
* request). Kaana's usage units have no unit for a cache WRITE (see the
|
|
16
|
+
* Anthropic adapter's usage meter): a cache write is billed at a premium
|
|
17
|
+
* over input, so honouring the marker while folding the write into
|
|
18
|
+
* `input_tokens` would report less than the request cost. The marker is
|
|
19
|
+
* refused, by name and path, instead of being dropped.
|
|
20
|
+
* - **`thinking` other than `{ type: 'disabled' }`.** The contract's reasoning
|
|
21
|
+
* control is an effort (`low`, `medium`, `high`), not a token budget, and a
|
|
22
|
+
* thinking block has no part in a message: reasoning is private and is never
|
|
23
|
+
* returned. Reasoning effort is asked with `output_config.effort`, which
|
|
24
|
+
* maps one to one. A `thinking` or `redacted_thinking` block in a message is
|
|
25
|
+
* refused for the same reason.
|
|
26
|
+
* - **Server tools** (`web_search`, `bash`, `text_editor`, …), `mcp_servers`,
|
|
27
|
+
* `container`, `service_tier`, `disable_parallel_tool_use`, `document`
|
|
28
|
+
* blocks and any other member this file does not name.
|
|
29
|
+
* - **An image `url` source**: nothing fetches an image URL (ADR 0007); a
|
|
30
|
+
* `base64` source is carried inline under the image rules.
|
|
31
|
+
*
|
|
32
|
+
* `stop_reason: 'stop_sequence'` is never produced: the finish reason Kaana
|
|
33
|
+
* measures does not say WHICH stop sequence ended the turn, and `stop_sequence`
|
|
34
|
+
* would then have to name one. A turn that ended on a stop sequence reports
|
|
35
|
+
* `end_turn`.
|
|
36
|
+
*
|
|
37
|
+
* `metadata.user_id` is accepted and neither forwarded nor stored: it is an
|
|
38
|
+
* end-user identifier, and Kaana persists none.
|
|
39
|
+
*
|
|
40
|
+
* `usage` is derived from the measured units: `input_tokens`, `output_tokens`
|
|
41
|
+
* (reasoning included, as Anthropic counts it) and, only when the route
|
|
42
|
+
* measured it, `cache_read_input_tokens`. There is no `cache_creation_*`.
|
|
43
|
+
*/
|
|
44
|
+
import { z } from 'zod';
|
|
45
|
+
import { maxUtf16Length, minUtf16Length } from '../stringBounds.js';
|
|
46
|
+
import { reasoningEffortSchema } from './catalogue.js';
|
|
47
|
+
import { modelTargetSchema } from './responses.js';
|
|
48
|
+
const nonEmpty = (max) => z.string().check(minUtf16Length(1)).check(maxUtf16Length(max));
|
|
49
|
+
const textBlockSchema = z.object({ type: z.literal('text'), text: z.string() }).strict();
|
|
50
|
+
const imageBlockSchema = z
|
|
51
|
+
.object({
|
|
52
|
+
type: z.literal('image'),
|
|
53
|
+
source: z.discriminatedUnion('type', [
|
|
54
|
+
z
|
|
55
|
+
.object({
|
|
56
|
+
type: z.literal('base64'),
|
|
57
|
+
media_type: nonEmpty(255),
|
|
58
|
+
data: z.string().check(minUtf16Length(1)),
|
|
59
|
+
})
|
|
60
|
+
.strict(),
|
|
61
|
+
/** Parses so the refusal can name it; Kaana fetches no image URL. */
|
|
62
|
+
z.object({ type: z.literal('url'), url: nonEmpty(4096) }).strict(),
|
|
63
|
+
]),
|
|
64
|
+
})
|
|
65
|
+
.strict();
|
|
66
|
+
const toolUseBlockSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
type: z.literal('tool_use'),
|
|
69
|
+
id: nonEmpty(128),
|
|
70
|
+
name: nonEmpty(128),
|
|
71
|
+
input: z.record(z.string(), z.unknown()),
|
|
72
|
+
})
|
|
73
|
+
.strict();
|
|
74
|
+
const toolResultBlockSchema = z
|
|
75
|
+
.object({
|
|
76
|
+
type: z.literal('tool_result'),
|
|
77
|
+
tool_use_id: nonEmpty(128),
|
|
78
|
+
content: z
|
|
79
|
+
.union([z.string(), z.array(z.union([textBlockSchema, imageBlockSchema]))])
|
|
80
|
+
.optional(),
|
|
81
|
+
/**
|
|
82
|
+
* Accepted. The contract's tool message has no error flag, so the result's
|
|
83
|
+
* own content is what the model reads; the flag is not forwarded.
|
|
84
|
+
*/
|
|
85
|
+
is_error: z.boolean().optional(),
|
|
86
|
+
})
|
|
87
|
+
.strict();
|
|
88
|
+
const messageSchema = z
|
|
89
|
+
.object({
|
|
90
|
+
role: z.enum(['user', 'assistant']),
|
|
91
|
+
content: z.union([
|
|
92
|
+
z.string(),
|
|
93
|
+
z
|
|
94
|
+
.array(z.union([textBlockSchema, imageBlockSchema, toolUseBlockSchema, toolResultBlockSchema]))
|
|
95
|
+
.min(1),
|
|
96
|
+
]),
|
|
97
|
+
})
|
|
98
|
+
.strict()
|
|
99
|
+
.superRefine((message, ctx) => {
|
|
100
|
+
if (typeof message.content === 'string')
|
|
101
|
+
return;
|
|
102
|
+
for (const [index, block] of message.content.entries()) {
|
|
103
|
+
const allowed = message.role === 'assistant'
|
|
104
|
+
? block.type === 'text' || block.type === 'tool_use'
|
|
105
|
+
: block.type !== 'tool_use';
|
|
106
|
+
if (!allowed) {
|
|
107
|
+
ctx.addIssue({
|
|
108
|
+
code: 'custom',
|
|
109
|
+
path: ['content', index, 'type'],
|
|
110
|
+
message: `a ${message.role} message does not carry a ${block.type} block`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const toolSchema = z
|
|
116
|
+
.object({
|
|
117
|
+
type: z.literal('custom').optional(),
|
|
118
|
+
name: nonEmpty(128),
|
|
119
|
+
description: z.string().check(maxUtf16Length(32768)).optional(),
|
|
120
|
+
input_schema: z.record(z.string(), z.unknown()),
|
|
121
|
+
strict: z.boolean().optional(),
|
|
122
|
+
})
|
|
123
|
+
.strict();
|
|
124
|
+
const toolChoiceSchema = z.discriminatedUnion('type', [
|
|
125
|
+
z.object({ type: z.literal('auto') }).strict(),
|
|
126
|
+
z.object({ type: z.literal('any') }).strict(),
|
|
127
|
+
z.object({ type: z.literal('none') }).strict(),
|
|
128
|
+
z.object({ type: z.literal('tool'), name: nonEmpty(128) }).strict(),
|
|
129
|
+
]);
|
|
130
|
+
export const anthropicMessagesRequestSchema = z
|
|
131
|
+
.object({
|
|
132
|
+
/** A model reference (`publisher/model[@revision]`) or a power level. */
|
|
133
|
+
model: modelTargetSchema,
|
|
134
|
+
/** Required, as Anthropic requires it. */
|
|
135
|
+
max_tokens: z.number().int().positive().safe(),
|
|
136
|
+
messages: z.array(messageSchema).min(1),
|
|
137
|
+
system: z.union([z.string(), z.array(textBlockSchema)]).optional(),
|
|
138
|
+
temperature: z.number().min(0).max(1).optional(),
|
|
139
|
+
top_p: z.number().min(0).max(1).optional(),
|
|
140
|
+
top_k: z.number().int().positive().safe().optional(),
|
|
141
|
+
stop_sequences: z.array(nonEmpty(256)).max(8).optional(),
|
|
142
|
+
stream: z.boolean().optional(),
|
|
143
|
+
tools: z.array(toolSchema).max(128).optional(),
|
|
144
|
+
tool_choice: toolChoiceSchema.optional(),
|
|
145
|
+
/** Only "off" is accepted: see the file comment. */
|
|
146
|
+
thinking: z
|
|
147
|
+
.object({ type: z.literal('disabled') })
|
|
148
|
+
.strict()
|
|
149
|
+
.optional(),
|
|
150
|
+
/** `effort` is the contract's reasoning effort; no other member is carried. */
|
|
151
|
+
output_config: z.object({ effort: reasoningEffortSchema.optional() }).strict().optional(),
|
|
152
|
+
/** Accepted and not forwarded or stored. */
|
|
153
|
+
metadata: z
|
|
154
|
+
.object({ user_id: z.string().check(maxUtf16Length(512)).nullable().optional() })
|
|
155
|
+
.strict()
|
|
156
|
+
.optional(),
|
|
157
|
+
})
|
|
158
|
+
.strict()
|
|
159
|
+
.superRefine((request, ctx) => {
|
|
160
|
+
if (request.tool_choice !== undefined && (request.tools ?? []).length === 0) {
|
|
161
|
+
ctx.addIssue({
|
|
162
|
+
code: 'custom',
|
|
163
|
+
path: ['tool_choice'],
|
|
164
|
+
message: 'a tool choice requires at least one tool definition',
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
const usageSchema = z
|
|
169
|
+
.object({
|
|
170
|
+
input_tokens: z.number().int().nonnegative(),
|
|
171
|
+
output_tokens: z.number().int().nonnegative(),
|
|
172
|
+
/** Present only when the route measured a cache read. */
|
|
173
|
+
cache_read_input_tokens: z.number().int().nonnegative().optional(),
|
|
174
|
+
})
|
|
175
|
+
.strict();
|
|
176
|
+
const stopReasonSchema = z.enum(['end_turn', 'max_tokens', 'tool_use', 'refusal']);
|
|
177
|
+
const outputBlockSchema = z.discriminatedUnion('type', [
|
|
178
|
+
textBlockSchema,
|
|
179
|
+
toolUseBlockSchema.extend({ input: z.record(z.string(), z.unknown()) }),
|
|
180
|
+
]);
|
|
181
|
+
const messageBodySchema = z.object({
|
|
182
|
+
id: nonEmpty(256),
|
|
183
|
+
type: z.literal('message'),
|
|
184
|
+
role: z.literal('assistant'),
|
|
185
|
+
/** The revision that served the request. */
|
|
186
|
+
model: nonEmpty(256),
|
|
187
|
+
});
|
|
188
|
+
/** The non-streaming body. The request id rides in `Kaana-Request-Id` and `Request-Id`. */
|
|
189
|
+
export const anthropicMessageSchema = messageBodySchema
|
|
190
|
+
.extend({
|
|
191
|
+
content: z.array(outputBlockSchema),
|
|
192
|
+
stop_reason: stopReasonSchema,
|
|
193
|
+
stop_sequence: z.literal(null),
|
|
194
|
+
usage: usageSchema,
|
|
195
|
+
})
|
|
196
|
+
.strict();
|
|
197
|
+
/** The error body, and the data of a stream's `event: error` frame. */
|
|
198
|
+
export const anthropicErrorSchema = z
|
|
199
|
+
.object({
|
|
200
|
+
type: z.literal('error'),
|
|
201
|
+
error: z
|
|
202
|
+
.object({
|
|
203
|
+
type: z.enum([
|
|
204
|
+
'invalid_request_error',
|
|
205
|
+
'authentication_error',
|
|
206
|
+
'billing_error',
|
|
207
|
+
'permission_error',
|
|
208
|
+
'not_found_error',
|
|
209
|
+
'request_too_large',
|
|
210
|
+
'rate_limit_error',
|
|
211
|
+
'timeout_error',
|
|
212
|
+
'overloaded_error',
|
|
213
|
+
'api_error',
|
|
214
|
+
]),
|
|
215
|
+
message: nonEmpty(4096),
|
|
216
|
+
})
|
|
217
|
+
.strict(),
|
|
218
|
+
request_id: nonEmpty(256).optional(),
|
|
219
|
+
})
|
|
220
|
+
.strict();
|
|
221
|
+
/**
|
|
222
|
+
* One frame of a streamed message: `event: <type>` and this as its data. The
|
|
223
|
+
* input tokens are known only when the route reports usage, so `message_start`
|
|
224
|
+
* carries zeros and the final `message_delta` the measured totals. A stream that
|
|
225
|
+
* fails after its first frame ends with an `error` frame and no `message_stop`.
|
|
226
|
+
*/
|
|
227
|
+
export const anthropicStreamEventSchema = z.discriminatedUnion('type', [
|
|
228
|
+
z
|
|
229
|
+
.object({
|
|
230
|
+
type: z.literal('message_start'),
|
|
231
|
+
message: messageBodySchema
|
|
232
|
+
.extend({
|
|
233
|
+
content: z.array(outputBlockSchema).length(0),
|
|
234
|
+
stop_reason: z.literal(null),
|
|
235
|
+
stop_sequence: z.literal(null),
|
|
236
|
+
usage: usageSchema,
|
|
237
|
+
})
|
|
238
|
+
.strict(),
|
|
239
|
+
})
|
|
240
|
+
.strict(),
|
|
241
|
+
z
|
|
242
|
+
.object({
|
|
243
|
+
type: z.literal('content_block_start'),
|
|
244
|
+
index: z.number().int().nonnegative(),
|
|
245
|
+
content_block: z.discriminatedUnion('type', [
|
|
246
|
+
z.object({ type: z.literal('text'), text: z.literal('') }).strict(),
|
|
247
|
+
toolUseBlockSchema.extend({ input: z.object({}).strict() }),
|
|
248
|
+
]),
|
|
249
|
+
})
|
|
250
|
+
.strict(),
|
|
251
|
+
z
|
|
252
|
+
.object({
|
|
253
|
+
type: z.literal('content_block_delta'),
|
|
254
|
+
index: z.number().int().nonnegative(),
|
|
255
|
+
delta: z.discriminatedUnion('type', [
|
|
256
|
+
z.object({ type: z.literal('text_delta'), text: z.string() }).strict(),
|
|
257
|
+
z.object({ type: z.literal('input_json_delta'), partial_json: z.string() }).strict(),
|
|
258
|
+
]),
|
|
259
|
+
})
|
|
260
|
+
.strict(),
|
|
261
|
+
z
|
|
262
|
+
.object({ type: z.literal('content_block_stop'), index: z.number().int().nonnegative() })
|
|
263
|
+
.strict(),
|
|
264
|
+
z
|
|
265
|
+
.object({
|
|
266
|
+
type: z.literal('message_delta'),
|
|
267
|
+
delta: z.object({ stop_reason: stopReasonSchema, stop_sequence: z.literal(null) }).strict(),
|
|
268
|
+
usage: usageSchema,
|
|
269
|
+
})
|
|
270
|
+
.strict(),
|
|
271
|
+
z.object({ type: z.literal('message_stop') }).strict(),
|
|
272
|
+
z.object({ type: z.literal('ping') }).strict(),
|
|
273
|
+
anthropicErrorSchema,
|
|
274
|
+
]);
|
|
@@ -21,9 +21,9 @@ import { z } from 'zod';
|
|
|
21
21
|
*/
|
|
22
22
|
export declare const chatCompletionMessageSchema: z.ZodObject<{
|
|
23
23
|
role: z.ZodEnum<{
|
|
24
|
-
user: "user";
|
|
25
24
|
system: "system";
|
|
26
25
|
developer: "developer";
|
|
26
|
+
user: "user";
|
|
27
27
|
assistant: "assistant";
|
|
28
28
|
tool: "tool";
|
|
29
29
|
}>;
|
|
@@ -93,9 +93,9 @@ export declare const chatCompletionsRequestSchema: z.ZodObject<{
|
|
|
93
93
|
}>]>;
|
|
94
94
|
messages: z.ZodArray<z.ZodObject<{
|
|
95
95
|
role: z.ZodEnum<{
|
|
96
|
-
user: "user";
|
|
97
96
|
system: "system";
|
|
98
97
|
developer: "developer";
|
|
98
|
+
user: "user";
|
|
99
99
|
assistant: "assistant";
|
|
100
100
|
tool: "tool";
|
|
101
101
|
}>;
|
|
@@ -163,9 +163,9 @@ export declare const inferenceToolCallSchema: z.ZodObject<{
|
|
|
163
163
|
arguments: z.ZodString;
|
|
164
164
|
}, z.core.$strict>;
|
|
165
165
|
export declare const inferenceMessageRoleSchema: z.ZodEnum<{
|
|
166
|
-
user: "user";
|
|
167
166
|
system: "system";
|
|
168
167
|
developer: "developer";
|
|
168
|
+
user: "user";
|
|
169
169
|
assistant: "assistant";
|
|
170
170
|
tool: "tool";
|
|
171
171
|
}>;
|
|
@@ -179,9 +179,9 @@ export declare const inferenceMessageRoleSchema: z.ZodEnum<{
|
|
|
179
179
|
*/
|
|
180
180
|
export declare const inferenceMessageSchema: z.ZodObject<{
|
|
181
181
|
role: z.ZodEnum<{
|
|
182
|
-
user: "user";
|
|
183
182
|
system: "system";
|
|
184
183
|
developer: "developer";
|
|
184
|
+
user: "user";
|
|
185
185
|
assistant: "assistant";
|
|
186
186
|
tool: "tool";
|
|
187
187
|
}>;
|
package/dist/public/messages.js
CHANGED
|
@@ -296,7 +296,7 @@ export const toolDefinitionSchema = z
|
|
|
296
296
|
.object({
|
|
297
297
|
type: z.literal('function'),
|
|
298
298
|
name: z.string().check(minUtf16Length(1)).check(maxUtf16Length(128)),
|
|
299
|
-
description: z.string().check(maxUtf16Length(
|
|
299
|
+
description: z.string().check(maxUtf16Length(32768)).optional(),
|
|
300
300
|
parameters: z.record(z.string(), z.unknown()),
|
|
301
301
|
/** Ask the provider to enforce the schema, where it supports enforcement. */
|
|
302
302
|
strict: z.boolean().optional(),
|