@cloudpeers-jkl/model-router 0.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.
- package/README.md +74 -0
- package/dist/adapters/anthropic.d.ts +7 -0
- package/dist/adapters/anthropic.js +121 -0
- package/dist/adapters/gemini.d.ts +40 -0
- package/dist/adapters/gemini.js +151 -0
- package/dist/adapters/selfhosted.d.ts +14 -0
- package/dist/adapters/selfhosted.js +96 -0
- package/dist/capabilities.d.ts +18 -0
- package/dist/capabilities.js +14 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.js +32 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +22 -0
- package/dist/policy.d.ts +35 -0
- package/dist/policy.js +48 -0
- package/dist/router.d.ts +36 -0
- package/dist/router.js +328 -0
- package/dist/schema.d.ts +335 -0
- package/dist/schema.js +68 -0
- package/dist/types.d.ts +256 -0
- package/dist/types.js +16 -0
- package/package.json +33 -0
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §4 — Zod schema for the router entry point: Anthropic Messages request
|
|
3
|
+
* shape + the `cloudpeers` extension envelope. Validated on every
|
|
4
|
+
* routeMessages/routeMessagesStream call; shape errors are 400
|
|
5
|
+
* (RouterValidationError), per §7.1 #1.
|
|
6
|
+
*
|
|
7
|
+
* The envelope is strict (unknown keys rejected) — a typo'd
|
|
8
|
+
* `sovereignty_class` must fail loudly, never default. The Anthropic layer
|
|
9
|
+
* is permissive on content-block internals so provider-shape evolution
|
|
10
|
+
* doesn't require lockstep schema bumps.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import type { RouterMessagesRequest } from './types.js';
|
|
14
|
+
export declare const cloudpeersEnvelopeSchema: z.ZodObject<{
|
|
15
|
+
v: z.ZodOptional<z.ZodLiteral<1>>;
|
|
16
|
+
sovereignty_class: z.ZodEnum<["local_only", "aggregate_only", "externalizable"]>;
|
|
17
|
+
task_class: z.ZodEnum<["extraction", "classification", "coaching", "reasoning", "synthesis"]>;
|
|
18
|
+
mandate_id: z.ZodOptional<z.ZodString>;
|
|
19
|
+
policy_id: z.ZodOptional<z.ZodString>;
|
|
20
|
+
attribution_chain: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
21
|
+
trust_level: z.ZodOptional<z.ZodEnum<["L0", "L1", "L2", "L3", "L4", "L5"]>>;
|
|
22
|
+
backend_hint: z.ZodOptional<z.ZodEnum<["selfhosted", "gemini", "anthropic"]>>;
|
|
23
|
+
tool_use_strict: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
byok: z.ZodOptional<z.ZodObject<{
|
|
25
|
+
provider: z.ZodString;
|
|
26
|
+
key_ref: z.ZodString;
|
|
27
|
+
}, "strip", z.ZodTypeAny, {
|
|
28
|
+
provider: string;
|
|
29
|
+
key_ref: string;
|
|
30
|
+
}, {
|
|
31
|
+
provider: string;
|
|
32
|
+
key_ref: string;
|
|
33
|
+
}>>;
|
|
34
|
+
}, "strict", z.ZodTypeAny, {
|
|
35
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
36
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
37
|
+
v?: 1 | undefined;
|
|
38
|
+
mandate_id?: string | undefined;
|
|
39
|
+
policy_id?: string | undefined;
|
|
40
|
+
attribution_chain?: string[] | undefined;
|
|
41
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
42
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
43
|
+
tool_use_strict?: boolean | undefined;
|
|
44
|
+
byok?: {
|
|
45
|
+
provider: string;
|
|
46
|
+
key_ref: string;
|
|
47
|
+
} | undefined;
|
|
48
|
+
}, {
|
|
49
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
50
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
51
|
+
v?: 1 | undefined;
|
|
52
|
+
mandate_id?: string | undefined;
|
|
53
|
+
policy_id?: string | undefined;
|
|
54
|
+
attribution_chain?: string[] | undefined;
|
|
55
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
56
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
57
|
+
tool_use_strict?: boolean | undefined;
|
|
58
|
+
byok?: {
|
|
59
|
+
provider: string;
|
|
60
|
+
key_ref: string;
|
|
61
|
+
} | undefined;
|
|
62
|
+
}>;
|
|
63
|
+
export declare const routerMessagesRequestSchema: z.ZodObject<{
|
|
64
|
+
model: z.ZodOptional<z.ZodString>;
|
|
65
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
66
|
+
role: z.ZodEnum<["user", "assistant"]>;
|
|
67
|
+
content: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodObject<{
|
|
68
|
+
type: z.ZodString;
|
|
69
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
70
|
+
type: z.ZodString;
|
|
71
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
72
|
+
type: z.ZodString;
|
|
73
|
+
}, z.ZodTypeAny, "passthrough">>, "many">]>;
|
|
74
|
+
}, "strip", z.ZodTypeAny, {
|
|
75
|
+
role: "user" | "assistant";
|
|
76
|
+
content: string | z.objectOutputType<{
|
|
77
|
+
type: z.ZodString;
|
|
78
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
79
|
+
}, {
|
|
80
|
+
role: "user" | "assistant";
|
|
81
|
+
content: string | z.objectInputType<{
|
|
82
|
+
type: z.ZodString;
|
|
83
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
84
|
+
}>, "many">;
|
|
85
|
+
system: z.ZodOptional<z.ZodString>;
|
|
86
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
88
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
89
|
+
name: z.ZodString;
|
|
90
|
+
description: z.ZodOptional<z.ZodString>;
|
|
91
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
92
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
93
|
+
name: z.ZodString;
|
|
94
|
+
description: z.ZodOptional<z.ZodString>;
|
|
95
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
96
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
97
|
+
name: z.ZodString;
|
|
98
|
+
description: z.ZodOptional<z.ZodString>;
|
|
99
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
100
|
+
}, z.ZodTypeAny, "passthrough">>, "many">>;
|
|
101
|
+
tool_choice: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
102
|
+
stream: z.ZodOptional<z.ZodBoolean>;
|
|
103
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
104
|
+
cloudpeers: z.ZodObject<{
|
|
105
|
+
v: z.ZodOptional<z.ZodLiteral<1>>;
|
|
106
|
+
sovereignty_class: z.ZodEnum<["local_only", "aggregate_only", "externalizable"]>;
|
|
107
|
+
task_class: z.ZodEnum<["extraction", "classification", "coaching", "reasoning", "synthesis"]>;
|
|
108
|
+
mandate_id: z.ZodOptional<z.ZodString>;
|
|
109
|
+
policy_id: z.ZodOptional<z.ZodString>;
|
|
110
|
+
attribution_chain: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
111
|
+
trust_level: z.ZodOptional<z.ZodEnum<["L0", "L1", "L2", "L3", "L4", "L5"]>>;
|
|
112
|
+
backend_hint: z.ZodOptional<z.ZodEnum<["selfhosted", "gemini", "anthropic"]>>;
|
|
113
|
+
tool_use_strict: z.ZodOptional<z.ZodBoolean>;
|
|
114
|
+
byok: z.ZodOptional<z.ZodObject<{
|
|
115
|
+
provider: z.ZodString;
|
|
116
|
+
key_ref: z.ZodString;
|
|
117
|
+
}, "strip", z.ZodTypeAny, {
|
|
118
|
+
provider: string;
|
|
119
|
+
key_ref: string;
|
|
120
|
+
}, {
|
|
121
|
+
provider: string;
|
|
122
|
+
key_ref: string;
|
|
123
|
+
}>>;
|
|
124
|
+
}, "strict", z.ZodTypeAny, {
|
|
125
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
126
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
127
|
+
v?: 1 | undefined;
|
|
128
|
+
mandate_id?: string | undefined;
|
|
129
|
+
policy_id?: string | undefined;
|
|
130
|
+
attribution_chain?: string[] | undefined;
|
|
131
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
132
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
133
|
+
tool_use_strict?: boolean | undefined;
|
|
134
|
+
byok?: {
|
|
135
|
+
provider: string;
|
|
136
|
+
key_ref: string;
|
|
137
|
+
} | undefined;
|
|
138
|
+
}, {
|
|
139
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
140
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
141
|
+
v?: 1 | undefined;
|
|
142
|
+
mandate_id?: string | undefined;
|
|
143
|
+
policy_id?: string | undefined;
|
|
144
|
+
attribution_chain?: string[] | undefined;
|
|
145
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
146
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
147
|
+
tool_use_strict?: boolean | undefined;
|
|
148
|
+
byok?: {
|
|
149
|
+
provider: string;
|
|
150
|
+
key_ref: string;
|
|
151
|
+
} | undefined;
|
|
152
|
+
}>;
|
|
153
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
154
|
+
model: z.ZodOptional<z.ZodString>;
|
|
155
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
156
|
+
role: z.ZodEnum<["user", "assistant"]>;
|
|
157
|
+
content: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodObject<{
|
|
158
|
+
type: z.ZodString;
|
|
159
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
160
|
+
type: z.ZodString;
|
|
161
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
162
|
+
type: z.ZodString;
|
|
163
|
+
}, z.ZodTypeAny, "passthrough">>, "many">]>;
|
|
164
|
+
}, "strip", z.ZodTypeAny, {
|
|
165
|
+
role: "user" | "assistant";
|
|
166
|
+
content: string | z.objectOutputType<{
|
|
167
|
+
type: z.ZodString;
|
|
168
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
169
|
+
}, {
|
|
170
|
+
role: "user" | "assistant";
|
|
171
|
+
content: string | z.objectInputType<{
|
|
172
|
+
type: z.ZodString;
|
|
173
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
174
|
+
}>, "many">;
|
|
175
|
+
system: z.ZodOptional<z.ZodString>;
|
|
176
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
177
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
178
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
179
|
+
name: z.ZodString;
|
|
180
|
+
description: z.ZodOptional<z.ZodString>;
|
|
181
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
182
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
183
|
+
name: z.ZodString;
|
|
184
|
+
description: z.ZodOptional<z.ZodString>;
|
|
185
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
186
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
187
|
+
name: z.ZodString;
|
|
188
|
+
description: z.ZodOptional<z.ZodString>;
|
|
189
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
190
|
+
}, z.ZodTypeAny, "passthrough">>, "many">>;
|
|
191
|
+
tool_choice: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
192
|
+
stream: z.ZodOptional<z.ZodBoolean>;
|
|
193
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
194
|
+
cloudpeers: z.ZodObject<{
|
|
195
|
+
v: z.ZodOptional<z.ZodLiteral<1>>;
|
|
196
|
+
sovereignty_class: z.ZodEnum<["local_only", "aggregate_only", "externalizable"]>;
|
|
197
|
+
task_class: z.ZodEnum<["extraction", "classification", "coaching", "reasoning", "synthesis"]>;
|
|
198
|
+
mandate_id: z.ZodOptional<z.ZodString>;
|
|
199
|
+
policy_id: z.ZodOptional<z.ZodString>;
|
|
200
|
+
attribution_chain: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
201
|
+
trust_level: z.ZodOptional<z.ZodEnum<["L0", "L1", "L2", "L3", "L4", "L5"]>>;
|
|
202
|
+
backend_hint: z.ZodOptional<z.ZodEnum<["selfhosted", "gemini", "anthropic"]>>;
|
|
203
|
+
tool_use_strict: z.ZodOptional<z.ZodBoolean>;
|
|
204
|
+
byok: z.ZodOptional<z.ZodObject<{
|
|
205
|
+
provider: z.ZodString;
|
|
206
|
+
key_ref: z.ZodString;
|
|
207
|
+
}, "strip", z.ZodTypeAny, {
|
|
208
|
+
provider: string;
|
|
209
|
+
key_ref: string;
|
|
210
|
+
}, {
|
|
211
|
+
provider: string;
|
|
212
|
+
key_ref: string;
|
|
213
|
+
}>>;
|
|
214
|
+
}, "strict", z.ZodTypeAny, {
|
|
215
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
216
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
217
|
+
v?: 1 | undefined;
|
|
218
|
+
mandate_id?: string | undefined;
|
|
219
|
+
policy_id?: string | undefined;
|
|
220
|
+
attribution_chain?: string[] | undefined;
|
|
221
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
222
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
223
|
+
tool_use_strict?: boolean | undefined;
|
|
224
|
+
byok?: {
|
|
225
|
+
provider: string;
|
|
226
|
+
key_ref: string;
|
|
227
|
+
} | undefined;
|
|
228
|
+
}, {
|
|
229
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
230
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
231
|
+
v?: 1 | undefined;
|
|
232
|
+
mandate_id?: string | undefined;
|
|
233
|
+
policy_id?: string | undefined;
|
|
234
|
+
attribution_chain?: string[] | undefined;
|
|
235
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
236
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
237
|
+
tool_use_strict?: boolean | undefined;
|
|
238
|
+
byok?: {
|
|
239
|
+
provider: string;
|
|
240
|
+
key_ref: string;
|
|
241
|
+
} | undefined;
|
|
242
|
+
}>;
|
|
243
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
244
|
+
model: z.ZodOptional<z.ZodString>;
|
|
245
|
+
messages: z.ZodArray<z.ZodObject<{
|
|
246
|
+
role: z.ZodEnum<["user", "assistant"]>;
|
|
247
|
+
content: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodObject<{
|
|
248
|
+
type: z.ZodString;
|
|
249
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
250
|
+
type: z.ZodString;
|
|
251
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
252
|
+
type: z.ZodString;
|
|
253
|
+
}, z.ZodTypeAny, "passthrough">>, "many">]>;
|
|
254
|
+
}, "strip", z.ZodTypeAny, {
|
|
255
|
+
role: "user" | "assistant";
|
|
256
|
+
content: string | z.objectOutputType<{
|
|
257
|
+
type: z.ZodString;
|
|
258
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
259
|
+
}, {
|
|
260
|
+
role: "user" | "assistant";
|
|
261
|
+
content: string | z.objectInputType<{
|
|
262
|
+
type: z.ZodString;
|
|
263
|
+
}, z.ZodTypeAny, "passthrough">[];
|
|
264
|
+
}>, "many">;
|
|
265
|
+
system: z.ZodOptional<z.ZodString>;
|
|
266
|
+
max_tokens: z.ZodOptional<z.ZodNumber>;
|
|
267
|
+
temperature: z.ZodOptional<z.ZodNumber>;
|
|
268
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
269
|
+
name: z.ZodString;
|
|
270
|
+
description: z.ZodOptional<z.ZodString>;
|
|
271
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
272
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
273
|
+
name: z.ZodString;
|
|
274
|
+
description: z.ZodOptional<z.ZodString>;
|
|
275
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
276
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
277
|
+
name: z.ZodString;
|
|
278
|
+
description: z.ZodOptional<z.ZodString>;
|
|
279
|
+
input_schema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
280
|
+
}, z.ZodTypeAny, "passthrough">>, "many">>;
|
|
281
|
+
tool_choice: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
282
|
+
stream: z.ZodOptional<z.ZodBoolean>;
|
|
283
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
284
|
+
cloudpeers: z.ZodObject<{
|
|
285
|
+
v: z.ZodOptional<z.ZodLiteral<1>>;
|
|
286
|
+
sovereignty_class: z.ZodEnum<["local_only", "aggregate_only", "externalizable"]>;
|
|
287
|
+
task_class: z.ZodEnum<["extraction", "classification", "coaching", "reasoning", "synthesis"]>;
|
|
288
|
+
mandate_id: z.ZodOptional<z.ZodString>;
|
|
289
|
+
policy_id: z.ZodOptional<z.ZodString>;
|
|
290
|
+
attribution_chain: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
291
|
+
trust_level: z.ZodOptional<z.ZodEnum<["L0", "L1", "L2", "L3", "L4", "L5"]>>;
|
|
292
|
+
backend_hint: z.ZodOptional<z.ZodEnum<["selfhosted", "gemini", "anthropic"]>>;
|
|
293
|
+
tool_use_strict: z.ZodOptional<z.ZodBoolean>;
|
|
294
|
+
byok: z.ZodOptional<z.ZodObject<{
|
|
295
|
+
provider: z.ZodString;
|
|
296
|
+
key_ref: z.ZodString;
|
|
297
|
+
}, "strip", z.ZodTypeAny, {
|
|
298
|
+
provider: string;
|
|
299
|
+
key_ref: string;
|
|
300
|
+
}, {
|
|
301
|
+
provider: string;
|
|
302
|
+
key_ref: string;
|
|
303
|
+
}>>;
|
|
304
|
+
}, "strict", z.ZodTypeAny, {
|
|
305
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
306
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
307
|
+
v?: 1 | undefined;
|
|
308
|
+
mandate_id?: string | undefined;
|
|
309
|
+
policy_id?: string | undefined;
|
|
310
|
+
attribution_chain?: string[] | undefined;
|
|
311
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
312
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
313
|
+
tool_use_strict?: boolean | undefined;
|
|
314
|
+
byok?: {
|
|
315
|
+
provider: string;
|
|
316
|
+
key_ref: string;
|
|
317
|
+
} | undefined;
|
|
318
|
+
}, {
|
|
319
|
+
sovereignty_class: "local_only" | "aggregate_only" | "externalizable";
|
|
320
|
+
task_class: "extraction" | "classification" | "coaching" | "reasoning" | "synthesis";
|
|
321
|
+
v?: 1 | undefined;
|
|
322
|
+
mandate_id?: string | undefined;
|
|
323
|
+
policy_id?: string | undefined;
|
|
324
|
+
attribution_chain?: string[] | undefined;
|
|
325
|
+
trust_level?: "L0" | "L1" | "L2" | "L3" | "L4" | "L5" | undefined;
|
|
326
|
+
backend_hint?: "selfhosted" | "gemini" | "anthropic" | undefined;
|
|
327
|
+
tool_use_strict?: boolean | undefined;
|
|
328
|
+
byok?: {
|
|
329
|
+
provider: string;
|
|
330
|
+
key_ref: string;
|
|
331
|
+
} | undefined;
|
|
332
|
+
}>;
|
|
333
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
334
|
+
/** Parse + narrow. Throws RouterValidationError (statusCode 400) on shape errors. */
|
|
335
|
+
export declare function parseRouterRequest(input: unknown): RouterMessagesRequest;
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* §4 — Zod schema for the router entry point: Anthropic Messages request
|
|
3
|
+
* shape + the `cloudpeers` extension envelope. Validated on every
|
|
4
|
+
* routeMessages/routeMessagesStream call; shape errors are 400
|
|
5
|
+
* (RouterValidationError), per §7.1 #1.
|
|
6
|
+
*
|
|
7
|
+
* The envelope is strict (unknown keys rejected) — a typo'd
|
|
8
|
+
* `sovereignty_class` must fail loudly, never default. The Anthropic layer
|
|
9
|
+
* is permissive on content-block internals so provider-shape evolution
|
|
10
|
+
* doesn't require lockstep schema bumps.
|
|
11
|
+
*/
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import { RouterValidationError } from './errors.js';
|
|
14
|
+
const contentBlockSchema = z
|
|
15
|
+
.object({ type: z.string() })
|
|
16
|
+
.passthrough();
|
|
17
|
+
const messageSchema = z.object({
|
|
18
|
+
role: z.enum(['user', 'assistant']),
|
|
19
|
+
content: z.union([z.string().min(1), z.array(contentBlockSchema).min(1)]),
|
|
20
|
+
});
|
|
21
|
+
const toolSchema = z
|
|
22
|
+
.object({
|
|
23
|
+
name: z.string().min(1),
|
|
24
|
+
description: z.string().optional(),
|
|
25
|
+
input_schema: z.record(z.unknown()),
|
|
26
|
+
})
|
|
27
|
+
.passthrough();
|
|
28
|
+
export const cloudpeersEnvelopeSchema = z
|
|
29
|
+
.object({
|
|
30
|
+
v: z.literal(1).optional(),
|
|
31
|
+
sovereignty_class: z.enum(['local_only', 'aggregate_only', 'externalizable']),
|
|
32
|
+
task_class: z.enum(['extraction', 'classification', 'coaching', 'reasoning', 'synthesis']),
|
|
33
|
+
mandate_id: z.string().min(1).optional(),
|
|
34
|
+
policy_id: z.string().min(1).optional(),
|
|
35
|
+
attribution_chain: z.array(z.string()).optional(),
|
|
36
|
+
trust_level: z.enum(['L0', 'L1', 'L2', 'L3', 'L4', 'L5']).optional(),
|
|
37
|
+
backend_hint: z.enum(['selfhosted', 'gemini', 'anthropic']).optional(),
|
|
38
|
+
tool_use_strict: z.boolean().optional(),
|
|
39
|
+
byok: z
|
|
40
|
+
.object({ provider: z.string().min(1), key_ref: z.string().min(1) })
|
|
41
|
+
.optional(),
|
|
42
|
+
})
|
|
43
|
+
.strict();
|
|
44
|
+
export const routerMessagesRequestSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
model: z.string().optional(),
|
|
47
|
+
messages: z.array(messageSchema).min(1),
|
|
48
|
+
system: z.string().optional(),
|
|
49
|
+
max_tokens: z.number().int().positive().optional(),
|
|
50
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
51
|
+
tools: z.array(toolSchema).optional(),
|
|
52
|
+
tool_choice: z.record(z.unknown()).optional(),
|
|
53
|
+
stream: z.boolean().optional(),
|
|
54
|
+
metadata: z.record(z.unknown()).optional(),
|
|
55
|
+
cloudpeers: cloudpeersEnvelopeSchema,
|
|
56
|
+
})
|
|
57
|
+
.passthrough();
|
|
58
|
+
/** Parse + narrow. Throws RouterValidationError (statusCode 400) on shape errors. */
|
|
59
|
+
export function parseRouterRequest(input) {
|
|
60
|
+
const parsed = routerMessagesRequestSchema.safeParse(input);
|
|
61
|
+
if (!parsed.success) {
|
|
62
|
+
const detail = parsed.error.issues
|
|
63
|
+
.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`)
|
|
64
|
+
.join('; ');
|
|
65
|
+
throw new RouterValidationError(`Invalid router request: ${detail}`);
|
|
66
|
+
}
|
|
67
|
+
return parsed.data;
|
|
68
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloudpeers-jkl/model-router — types.
|
|
3
|
+
*
|
|
4
|
+
* Two API layers, one core:
|
|
5
|
+
* - v1 convenience API (`routeModel`): prompt-in/text-out, kept for the
|
|
6
|
+
* call sites migrated before extraction (behavior-identical).
|
|
7
|
+
* - Spec API (`routeMessages`): Anthropic Messages lingua franca +
|
|
8
|
+
* `cloudpeers` envelope, per INFERENCE_ROUTER_SPEC.md §4/§5 (canonical
|
|
9
|
+
* copy in cloudpeers-github/docs/architecture/, Amendment A1 applies).
|
|
10
|
+
*
|
|
11
|
+
* Decisions encoded: embedded library, no central data plane (2026-07-09);
|
|
12
|
+
* Tier 0 = self-hosted in-boundary; privacy gate stages (MONITOR default);
|
|
13
|
+
* approved providers ONLY: anthropic, gemini, selfhosted. OpenAI excluded
|
|
14
|
+
* by directive. BYOK deferred (A1.2).
|
|
15
|
+
*/
|
|
16
|
+
export type SovereigntyClass = 'local_only' | 'aggregate_only' | 'externalizable';
|
|
17
|
+
/** Static task classes (confidence v1 — no learned complexity classifier). */
|
|
18
|
+
export type TaskClass = 'extraction' | 'classification' | 'coaching' | 'reasoning' | 'synthesis';
|
|
19
|
+
export type Provider = 'selfhosted' | 'gemini' | 'anthropic';
|
|
20
|
+
export type BackendSurface = 'cloud' | 'self_hosted' | 'edge';
|
|
21
|
+
export type GateOutcome = 'allowed' | 'would_block' | 'blocked';
|
|
22
|
+
export interface TextBlock {
|
|
23
|
+
type: 'text';
|
|
24
|
+
text: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ToolUseBlock {
|
|
27
|
+
type: 'tool_use';
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
input: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export interface ToolResultBlock {
|
|
33
|
+
type: 'tool_result';
|
|
34
|
+
tool_use_id: string;
|
|
35
|
+
content: string | ContentBlock[];
|
|
36
|
+
is_error?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock;
|
|
39
|
+
export interface AnthropicMessage {
|
|
40
|
+
role: 'user' | 'assistant';
|
|
41
|
+
content: string | ContentBlock[];
|
|
42
|
+
}
|
|
43
|
+
export interface ToolDefinition {
|
|
44
|
+
name: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
input_schema: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
/** The `cloudpeers` extension envelope (§4). Stripped before any provider call. */
|
|
49
|
+
export interface CloudpeersEnvelope {
|
|
50
|
+
v?: 1;
|
|
51
|
+
sovereignty_class: SovereigntyClass;
|
|
52
|
+
/** v1 embedded routing key (static task-class tier chains, 2026-07-09 resolution 3). */
|
|
53
|
+
task_class: TaskClass;
|
|
54
|
+
/** AP2 mandate the inference is bound to (§7.1 #2). */
|
|
55
|
+
mandate_id?: string;
|
|
56
|
+
/** NemoClaw policy to enforce pre/post call (§7.1 #4). */
|
|
57
|
+
policy_id?: string;
|
|
58
|
+
/** ERC-8183 upstream hop IDs (§7.2 #2). */
|
|
59
|
+
attribution_chain?: string[];
|
|
60
|
+
/** Lab Zero delegation grant. */
|
|
61
|
+
trust_level?: 'L0' | 'L1' | 'L2' | 'L3' | 'L4' | 'L5';
|
|
62
|
+
/** Advisory backend selector — reorders the tier chain, never bypasses the gate. */
|
|
63
|
+
backend_hint?: Provider;
|
|
64
|
+
/** §8.2 — reject 422 instead of degrading when tool-use support is missing. */
|
|
65
|
+
tool_use_strict?: boolean;
|
|
66
|
+
/** §10.2 — accepted by the schema, REJECTED by the router (deferred per A1.2). */
|
|
67
|
+
byok?: {
|
|
68
|
+
provider: string;
|
|
69
|
+
key_ref: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export interface AnthropicMessagesRequest {
|
|
73
|
+
model?: string;
|
|
74
|
+
messages: AnthropicMessage[];
|
|
75
|
+
system?: string;
|
|
76
|
+
max_tokens?: number;
|
|
77
|
+
temperature?: number;
|
|
78
|
+
tools?: ToolDefinition[];
|
|
79
|
+
tool_choice?: Record<string, unknown>;
|
|
80
|
+
stream?: boolean;
|
|
81
|
+
metadata?: Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
export type RouterMessagesRequest = AnthropicMessagesRequest & {
|
|
84
|
+
cloudpeers: CloudpeersEnvelope;
|
|
85
|
+
};
|
|
86
|
+
export interface AnthropicUsage {
|
|
87
|
+
input_tokens: number;
|
|
88
|
+
output_tokens: number;
|
|
89
|
+
}
|
|
90
|
+
export interface AnthropicMessagesResponse {
|
|
91
|
+
id: string;
|
|
92
|
+
type: 'message';
|
|
93
|
+
role: 'assistant';
|
|
94
|
+
content: ContentBlock[];
|
|
95
|
+
model: string;
|
|
96
|
+
stop_reason: string | null;
|
|
97
|
+
usage: AnthropicUsage;
|
|
98
|
+
}
|
|
99
|
+
/** SSE event in Anthropic streaming shape (message_start, content_block_delta, …). */
|
|
100
|
+
export interface AnthropicSSEEvent {
|
|
101
|
+
type: string;
|
|
102
|
+
[key: string]: unknown;
|
|
103
|
+
}
|
|
104
|
+
export interface ToolUseCapability {
|
|
105
|
+
supports_tool_use: boolean;
|
|
106
|
+
supports_parallel_tool_use: boolean;
|
|
107
|
+
preserves_block_position: boolean;
|
|
108
|
+
supports_streaming_tool_use: boolean;
|
|
109
|
+
max_tools_per_request: number | null;
|
|
110
|
+
}
|
|
111
|
+
export type EligibilityResult = {
|
|
112
|
+
eligible: true;
|
|
113
|
+
estimated_latency_ms: number;
|
|
114
|
+
estimated_cost_cents: number;
|
|
115
|
+
} | {
|
|
116
|
+
eligible: false;
|
|
117
|
+
reason: string;
|
|
118
|
+
};
|
|
119
|
+
export interface UsageEvent {
|
|
120
|
+
backend_id: string;
|
|
121
|
+
tokens_in: number;
|
|
122
|
+
tokens_out: number;
|
|
123
|
+
latency_ms: number;
|
|
124
|
+
cost_cents: number;
|
|
125
|
+
cache_hit: boolean;
|
|
126
|
+
cache_unsupported?: true;
|
|
127
|
+
sovereignty_class: SovereigntyClass;
|
|
128
|
+
}
|
|
129
|
+
export interface SelectionContext {
|
|
130
|
+
sovereignty_class: SovereigntyClass;
|
|
131
|
+
tier: number;
|
|
132
|
+
gate: GateOutcome;
|
|
133
|
+
}
|
|
134
|
+
export interface InvocationContext {
|
|
135
|
+
userId: string;
|
|
136
|
+
serviceId: string;
|
|
137
|
+
operation: string;
|
|
138
|
+
signal?: AbortSignal;
|
|
139
|
+
}
|
|
140
|
+
export interface BackendAdapter {
|
|
141
|
+
id: Provider;
|
|
142
|
+
display_name: string;
|
|
143
|
+
surface: BackendSurface;
|
|
144
|
+
supports_streaming: boolean;
|
|
145
|
+
supports_tool_use: boolean;
|
|
146
|
+
supports_prompt_caching: boolean;
|
|
147
|
+
tool_use: ToolUseCapability;
|
|
148
|
+
/** Deploy-time availability (key/endpoint configured). */
|
|
149
|
+
available(): boolean;
|
|
150
|
+
/** Called by the selector before invocation (§3.3). */
|
|
151
|
+
isEligible(req: AnthropicMessagesRequest, ctx: SelectionContext): Promise<EligibilityResult>;
|
|
152
|
+
/** The envelope is stripped by the router before invoke sees the request. */
|
|
153
|
+
invoke(req: AnthropicMessagesRequest, ctx: InvocationContext): Promise<AnthropicMessagesResponse>;
|
|
154
|
+
invokeStream(req: AnthropicMessagesRequest, ctx: InvocationContext): AsyncIterable<AnthropicSSEEvent>;
|
|
155
|
+
/** §10 symmetric observability. latency_ms/sovereignty_class overwritten by the router. */
|
|
156
|
+
reportUsage(req: AnthropicMessagesRequest, res: AnthropicMessagesResponse): UsageEvent;
|
|
157
|
+
}
|
|
158
|
+
export interface MeterEvent {
|
|
159
|
+
userId: string;
|
|
160
|
+
serviceId: string;
|
|
161
|
+
model: string;
|
|
162
|
+
operation: string;
|
|
163
|
+
promptTokens: number;
|
|
164
|
+
completionTokens: number;
|
|
165
|
+
metadata?: Record<string, unknown>;
|
|
166
|
+
}
|
|
167
|
+
export type Meter = (event: MeterEvent) => Promise<unknown>;
|
|
168
|
+
export type QuotaFn = (userId: string, estimatedTokens: number) => Promise<{
|
|
169
|
+
allowed: boolean;
|
|
170
|
+
remainingTokens?: number;
|
|
171
|
+
quotaResetAt?: unknown;
|
|
172
|
+
message?: string;
|
|
173
|
+
}>;
|
|
174
|
+
export interface MandateVerdict {
|
|
175
|
+
valid: boolean;
|
|
176
|
+
/** Required when valid=false: 'expired' → 410, 'revoked' → 409, else 412. */
|
|
177
|
+
reason?: 'expired' | 'revoked' | string;
|
|
178
|
+
}
|
|
179
|
+
export interface PolicyVerdict {
|
|
180
|
+
allowed: boolean;
|
|
181
|
+
reason?: string;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* §7 enforcement hooks. Fail-closed contract: if the request names a
|
|
185
|
+
* mandate_id or policy_id and the corresponding hook is not wired, the
|
|
186
|
+
* router blocks — an enforcement instrument the caller bound to must never
|
|
187
|
+
* be silently skipped. Post-call hooks are observation-only in v1 (§7.2).
|
|
188
|
+
*/
|
|
189
|
+
export interface RouterHooks {
|
|
190
|
+
verifyMandate?: (mandateId: string) => Promise<MandateVerdict>;
|
|
191
|
+
applyPolicy?: (policyId: string, call: {
|
|
192
|
+
backend_id: Provider;
|
|
193
|
+
model: string;
|
|
194
|
+
tier: number;
|
|
195
|
+
}) => Promise<PolicyVerdict>;
|
|
196
|
+
/** §7.2 #1 — Guardian outcome verification. Result recorded, never gating (v1). */
|
|
197
|
+
verifyOutcome?: (mandateId: string, response: AnthropicMessagesResponse) => Promise<{
|
|
198
|
+
outcome_matches_mandate: boolean;
|
|
199
|
+
}>;
|
|
200
|
+
/** §7.2 #2 — append this router hop to the attribution chain and persist. */
|
|
201
|
+
writeAttribution?: (chain: string[], usage: UsageEvent) => Promise<void>;
|
|
202
|
+
}
|
|
203
|
+
export interface RouterDeps {
|
|
204
|
+
adapters: Partial<Record<Provider, BackendAdapter>>;
|
|
205
|
+
meter: Meter;
|
|
206
|
+
quota: QuotaFn;
|
|
207
|
+
hooks?: RouterHooks;
|
|
208
|
+
}
|
|
209
|
+
export interface RouterRequest {
|
|
210
|
+
taskClass: TaskClass;
|
|
211
|
+
prompt: string;
|
|
212
|
+
system?: string;
|
|
213
|
+
/** REQUIRED — the caller declares the data class of the request context.
|
|
214
|
+
* Entity-level tagging per the 2026-07-09 resolutions (per-token retired). */
|
|
215
|
+
sovereigntyClass: SovereigntyClass;
|
|
216
|
+
/** Metering label (token-tracker `operation`). */
|
|
217
|
+
operation: string;
|
|
218
|
+
userId: string;
|
|
219
|
+
serviceId: string;
|
|
220
|
+
temperature?: number;
|
|
221
|
+
maxTokens?: number;
|
|
222
|
+
/** Confidence v1: validate the response shape; failure escalates a tier. */
|
|
223
|
+
validate?: (text: string) => boolean;
|
|
224
|
+
metadata?: Record<string, unknown>;
|
|
225
|
+
}
|
|
226
|
+
export interface RouterResult {
|
|
227
|
+
text: string;
|
|
228
|
+
provider: Provider;
|
|
229
|
+
model: string;
|
|
230
|
+
tier: number;
|
|
231
|
+
escalations: number;
|
|
232
|
+
/** True when every tier failed validation and this is best-effort output. */
|
|
233
|
+
degraded: boolean;
|
|
234
|
+
gate: GateOutcome;
|
|
235
|
+
promptTokens: number;
|
|
236
|
+
completionTokens: number;
|
|
237
|
+
totalTokens: number;
|
|
238
|
+
}
|
|
239
|
+
/** Spec-API result: full Anthropic response + the routing telemetry. */
|
|
240
|
+
export interface MessagesRouteResult {
|
|
241
|
+
response: AnthropicMessagesResponse;
|
|
242
|
+
provider: Provider;
|
|
243
|
+
model: string;
|
|
244
|
+
tier: number;
|
|
245
|
+
escalations: number;
|
|
246
|
+
degraded: boolean;
|
|
247
|
+
gate: GateOutcome;
|
|
248
|
+
usage: UsageEvent;
|
|
249
|
+
}
|
|
250
|
+
export interface TierDef {
|
|
251
|
+
tier: number;
|
|
252
|
+
provider: Provider;
|
|
253
|
+
model: string;
|
|
254
|
+
/** Cloud tiers are subject to the local_only privacy gate. */
|
|
255
|
+
cloud: boolean;
|
|
256
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloudpeers-jkl/model-router — types.
|
|
3
|
+
*
|
|
4
|
+
* Two API layers, one core:
|
|
5
|
+
* - v1 convenience API (`routeModel`): prompt-in/text-out, kept for the
|
|
6
|
+
* call sites migrated before extraction (behavior-identical).
|
|
7
|
+
* - Spec API (`routeMessages`): Anthropic Messages lingua franca +
|
|
8
|
+
* `cloudpeers` envelope, per INFERENCE_ROUTER_SPEC.md §4/§5 (canonical
|
|
9
|
+
* copy in cloudpeers-github/docs/architecture/, Amendment A1 applies).
|
|
10
|
+
*
|
|
11
|
+
* Decisions encoded: embedded library, no central data plane (2026-07-09);
|
|
12
|
+
* Tier 0 = self-hosted in-boundary; privacy gate stages (MONITOR default);
|
|
13
|
+
* approved providers ONLY: anthropic, gemini, selfhosted. OpenAI excluded
|
|
14
|
+
* by directive. BYOK deferred (A1.2).
|
|
15
|
+
*/
|
|
16
|
+
export {};
|