@omercnet/paseo-omp 0.3.0-next.105.1 → 0.3.0-next.106.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.
- package/client/omp-config-surface.tsx +80 -10
- package/client/omp-model-picker-state.ts +145 -0
- package/client/omp-model-picker.tsx +282 -0
- package/client/omp-routing-editor.tsx +307 -0
- package/docs/configuration.md +1 -1
- package/docs/images/model-role-picker-compact.webp +0 -0
- package/docs/images/model-role-picker-desktop.webp +0 -0
- package/index.server.ts +3 -0
- package/package.json +1 -1
- package/server/omp-models.ts +59 -0
- package/server/omp-settings.ts +30 -20
- package/shared/omp-models.ts +49 -0
- package/shared/omp-settings.ts +227 -3
package/shared/omp-settings.ts
CHANGED
|
@@ -17,6 +17,163 @@ export type OmpSettingType = z.infer<typeof OmpSettingTypeSchema>;
|
|
|
17
17
|
export const OmpScalarValueSchema = z.union([z.boolean(), z.number(), z.string()]);
|
|
18
18
|
export type OmpScalarValue = z.infer<typeof OmpScalarValueSchema>;
|
|
19
19
|
|
|
20
|
+
const MAX_ROUTING_ENTRIES = 64;
|
|
21
|
+
const MAX_FALLBACK_CHAIN_LENGTH = 16;
|
|
22
|
+
const MAX_AGENT_MODEL_CHOICES = 8;
|
|
23
|
+
const MAX_MODEL_SELECTOR_LENGTH = 513;
|
|
24
|
+
|
|
25
|
+
function containsControlCharacter(value: string): boolean {
|
|
26
|
+
for (const character of value) {
|
|
27
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
28
|
+
if (codePoint < 32 || codePoint === 127) return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function utf8ByteLength(value: string): number {
|
|
34
|
+
let bytes = 0;
|
|
35
|
+
for (const character of value) {
|
|
36
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
37
|
+
bytes += codePoint <= 0x7f ? 1 : codePoint <= 0x7ff ? 2 : codePoint <= 0xffff ? 3 : 4;
|
|
38
|
+
}
|
|
39
|
+
return bytes;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const OmpRoleNameSchema = z
|
|
43
|
+
.string()
|
|
44
|
+
.min(1)
|
|
45
|
+
.max(64)
|
|
46
|
+
.regex(
|
|
47
|
+
/^[A-Za-z][A-Za-z0-9_-]*$/,
|
|
48
|
+
"Role names must start with a letter and use only letters, digits, _ or -.",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export const OmpModelSelectorSchema = z
|
|
52
|
+
.string()
|
|
53
|
+
.min(1)
|
|
54
|
+
.max(MAX_MODEL_SELECTOR_LENGTH)
|
|
55
|
+
.refine(
|
|
56
|
+
(value) => utf8ByteLength(value) <= MAX_MODEL_SELECTOR_LENGTH,
|
|
57
|
+
`Model selectors must not exceed ${MAX_MODEL_SELECTOR_LENGTH} UTF-8 bytes.`,
|
|
58
|
+
)
|
|
59
|
+
.refine(
|
|
60
|
+
(value) => value === value.trim() && !/\s/u.test(value) && !containsControlCharacter(value),
|
|
61
|
+
{
|
|
62
|
+
message: "Model selectors must be a single printable token.",
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export function isValidOmpModelSelector(value: string): boolean {
|
|
67
|
+
return OmpModelSelectorSchema.safeParse(value).success;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const OmpAgentNameSchema = z
|
|
71
|
+
.string()
|
|
72
|
+
.min(1)
|
|
73
|
+
.max(128)
|
|
74
|
+
.refine((value) => value === value.trim() && !containsControlCharacter(value), {
|
|
75
|
+
message: "Agent names cannot have surrounding whitespace or control characters.",
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const OmpModelRolesSchema = z
|
|
79
|
+
.record(OmpRoleNameSchema, OmpModelSelectorSchema)
|
|
80
|
+
.refine((value) => Object.keys(value).length <= MAX_ROUTING_ENTRIES, "Too many model roles.");
|
|
81
|
+
|
|
82
|
+
const OmpFallbackKeySchema = z.string().superRefine((value, context) => {
|
|
83
|
+
const schema = value.includes("/") ? OmpModelSelectorSchema : OmpRoleNameSchema;
|
|
84
|
+
const result = schema.safeParse(value);
|
|
85
|
+
if (!result.success) {
|
|
86
|
+
context.addIssue({
|
|
87
|
+
code: "custom",
|
|
88
|
+
message: result.error.issues[0]?.message ?? "Invalid fallback chain key.",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
export const OmpFallbackChainsSchema = z
|
|
94
|
+
.record(OmpFallbackKeySchema, z.array(OmpModelSelectorSchema).max(MAX_FALLBACK_CHAIN_LENGTH))
|
|
95
|
+
.refine((value) => Object.keys(value).length <= MAX_ROUTING_ENTRIES, "Too many fallback chains.");
|
|
96
|
+
|
|
97
|
+
export const OmpCycleOrderSchema = z
|
|
98
|
+
.array(OmpRoleNameSchema)
|
|
99
|
+
.max(MAX_ROUTING_ENTRIES)
|
|
100
|
+
.refine((value) => new Set(value).size === value.length, "Cycle roles must be unique.");
|
|
101
|
+
|
|
102
|
+
export const OmpAgentModelOverridesSchema = z
|
|
103
|
+
.record(
|
|
104
|
+
OmpAgentNameSchema,
|
|
105
|
+
z.union([
|
|
106
|
+
OmpModelSelectorSchema,
|
|
107
|
+
z.array(OmpModelSelectorSchema).min(1).max(MAX_AGENT_MODEL_CHOICES),
|
|
108
|
+
]),
|
|
109
|
+
)
|
|
110
|
+
.refine(
|
|
111
|
+
(value) => Object.keys(value).length <= MAX_ROUTING_ENTRIES,
|
|
112
|
+
"Too many agent model overrides.",
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
export const OmpAgentServiceTierOverridesSchema = z
|
|
116
|
+
.record(
|
|
117
|
+
OmpAgentNameSchema,
|
|
118
|
+
z.enum(["inherit", "none", "auto", "default", "flex", "scale", "priority"]),
|
|
119
|
+
)
|
|
120
|
+
.refine(
|
|
121
|
+
(value) => Object.keys(value).length <= MAX_ROUTING_ENTRIES,
|
|
122
|
+
"Too many agent service tier overrides.",
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const OmpAgentToggleOrSelectorSchema = z.union([z.enum(["on", "off"]), OmpModelSelectorSchema]);
|
|
126
|
+
|
|
127
|
+
export const OmpAgentPrewalkSchema = z
|
|
128
|
+
.record(OmpAgentNameSchema, OmpAgentToggleOrSelectorSchema)
|
|
129
|
+
.refine(
|
|
130
|
+
(value) => Object.keys(value).length <= MAX_ROUTING_ENTRIES,
|
|
131
|
+
"Too many agent prewalk overrides.",
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
export const OmpAgentAdvisorSchema = z
|
|
135
|
+
.record(OmpAgentNameSchema, OmpAgentToggleOrSelectorSchema)
|
|
136
|
+
.refine(
|
|
137
|
+
(value) => Object.keys(value).length <= MAX_ROUTING_ENTRIES,
|
|
138
|
+
"Too many agent advisor overrides.",
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
export const OMP_STRUCTURED_SETTING_PATHS = [
|
|
142
|
+
"modelRoles",
|
|
143
|
+
"retry.fallbackChains",
|
|
144
|
+
"cycleOrder",
|
|
145
|
+
"task.agentModelOverrides",
|
|
146
|
+
"task.agentServiceTierOverrides",
|
|
147
|
+
"task.agentPrewalk",
|
|
148
|
+
"task.agentAdvisor",
|
|
149
|
+
] as const;
|
|
150
|
+
export type OmpStructuredSettingPath = (typeof OMP_STRUCTURED_SETTING_PATHS)[number];
|
|
151
|
+
|
|
152
|
+
export function parseOmpStructuredSettingValue(path: string, value: unknown): unknown | undefined {
|
|
153
|
+
switch (path) {
|
|
154
|
+
case "modelRoles":
|
|
155
|
+
return OmpModelRolesSchema.safeParse(value).data;
|
|
156
|
+
case "retry.fallbackChains":
|
|
157
|
+
return OmpFallbackChainsSchema.safeParse(value).data;
|
|
158
|
+
case "cycleOrder":
|
|
159
|
+
return OmpCycleOrderSchema.safeParse(value).data;
|
|
160
|
+
case "task.agentModelOverrides":
|
|
161
|
+
return OmpAgentModelOverridesSchema.safeParse(value).data;
|
|
162
|
+
case "task.agentServiceTierOverrides":
|
|
163
|
+
return OmpAgentServiceTierOverridesSchema.safeParse(value).data;
|
|
164
|
+
case "task.agentPrewalk":
|
|
165
|
+
return OmpAgentPrewalkSchema.safeParse(value).data;
|
|
166
|
+
case "task.agentAdvisor":
|
|
167
|
+
return OmpAgentAdvisorSchema.safeParse(value).data;
|
|
168
|
+
default:
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function isOmpStructuredSettingPath(path: string): path is OmpStructuredSettingPath {
|
|
174
|
+
return (OMP_STRUCTURED_SETTING_PATHS as readonly string[]).includes(path);
|
|
175
|
+
}
|
|
176
|
+
|
|
20
177
|
export const OmpSettingSchema = z
|
|
21
178
|
.object({
|
|
22
179
|
path: z.string(),
|
|
@@ -184,9 +341,76 @@ export const listOmpSettings = defineRpc({
|
|
|
184
341
|
}),
|
|
185
342
|
});
|
|
186
343
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
344
|
+
const OmpScalarSettingPathSchema = z
|
|
345
|
+
.string()
|
|
346
|
+
.min(1)
|
|
347
|
+
.refine(
|
|
348
|
+
(path) => !isOmpStructuredSettingPath(path),
|
|
349
|
+
"Structured routing settings require typed values.",
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
const OmpStructuredSettingChangeSchema = z.discriminatedUnion("path", [
|
|
353
|
+
z
|
|
354
|
+
.object({
|
|
355
|
+
operation: z.literal("set"),
|
|
356
|
+
path: z.literal("modelRoles"),
|
|
357
|
+
value: OmpModelRolesSchema,
|
|
358
|
+
})
|
|
359
|
+
.strict(),
|
|
360
|
+
z
|
|
361
|
+
.object({
|
|
362
|
+
operation: z.literal("set"),
|
|
363
|
+
path: z.literal("retry.fallbackChains"),
|
|
364
|
+
value: OmpFallbackChainsSchema,
|
|
365
|
+
})
|
|
366
|
+
.strict(),
|
|
367
|
+
z
|
|
368
|
+
.object({
|
|
369
|
+
operation: z.literal("set"),
|
|
370
|
+
path: z.literal("cycleOrder"),
|
|
371
|
+
value: OmpCycleOrderSchema,
|
|
372
|
+
})
|
|
373
|
+
.strict(),
|
|
374
|
+
z
|
|
375
|
+
.object({
|
|
376
|
+
operation: z.literal("set"),
|
|
377
|
+
path: z.literal("task.agentModelOverrides"),
|
|
378
|
+
value: OmpAgentModelOverridesSchema,
|
|
379
|
+
})
|
|
380
|
+
.strict(),
|
|
381
|
+
z
|
|
382
|
+
.object({
|
|
383
|
+
operation: z.literal("set"),
|
|
384
|
+
path: z.literal("task.agentServiceTierOverrides"),
|
|
385
|
+
value: OmpAgentServiceTierOverridesSchema,
|
|
386
|
+
})
|
|
387
|
+
.strict(),
|
|
388
|
+
z
|
|
389
|
+
.object({
|
|
390
|
+
operation: z.literal("set"),
|
|
391
|
+
path: z.literal("task.agentPrewalk"),
|
|
392
|
+
value: OmpAgentPrewalkSchema,
|
|
393
|
+
})
|
|
394
|
+
.strict(),
|
|
395
|
+
z
|
|
396
|
+
.object({
|
|
397
|
+
operation: z.literal("set"),
|
|
398
|
+
path: z.literal("task.agentAdvisor"),
|
|
399
|
+
value: OmpAgentAdvisorSchema,
|
|
400
|
+
})
|
|
401
|
+
.strict(),
|
|
402
|
+
]);
|
|
403
|
+
|
|
404
|
+
const OmpSettingChangeSchema = z.union([
|
|
405
|
+
z
|
|
406
|
+
.object({
|
|
407
|
+
operation: z.literal("set"),
|
|
408
|
+
path: OmpScalarSettingPathSchema,
|
|
409
|
+
value: OmpScalarValueSchema,
|
|
410
|
+
})
|
|
411
|
+
.strict(),
|
|
412
|
+
OmpStructuredSettingChangeSchema,
|
|
413
|
+
z.object({ operation: z.literal("reset"), path: z.string().min(1) }).strict(),
|
|
190
414
|
]);
|
|
191
415
|
|
|
192
416
|
export const updateOmpSettings = defineRpc({
|