@osovv/vv-opencode 0.16.0 → 0.17.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 +106 -9
- package/dist/cli.js +5 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/agent.js +37 -72
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/completion.js +32 -16
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/preset.d.ts +45 -0
- package/dist/commands/preset.js +214 -0
- package/dist/commands/preset.js.map +1 -0
- package/dist/lib/agent-models.d.ts +21 -0
- package/dist/lib/agent-models.js +106 -0
- package/dist/lib/agent-models.js.map +1 -0
- package/dist/lib/opencode.d.ts +6 -0
- package/dist/lib/opencode.js +73 -23
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/vvoc-config.d.ts +169 -124
- package/dist/lib/vvoc-config.js +303 -101
- package/dist/lib/vvoc-config.js.map +1 -1
- package/package.json +1 -1
- package/schemas/vvoc/v2.json +124 -0
package/dist/lib/vvoc-config.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// FILE: src/lib/vvoc-config.ts
|
|
2
|
-
// VERSION:
|
|
2
|
+
// VERSION: 2.0.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
|
-
// PURPOSE: Define the canonical vvoc.json document shape,
|
|
5
|
-
// SCOPE: Versioned schema constants, default
|
|
6
|
-
// DEPENDS: [ajv/dist/2020, src/lib/package.ts]
|
|
7
|
-
// LINKS: [M-CLI-CONFIG, M-CLI-CONFIG-VALIDATE, M-PLUGIN-GUARDIAN, M-PLUGIN-MEMORY-STORE, M-PLUGIN-SECRETS-REDACTION-INTERNAL-CONFIG]
|
|
4
|
+
// PURPOSE: Define the canonical vvoc.json document shape, schema versions, normalization rules, and validation helpers.
|
|
5
|
+
// SCOPE: Versioned schema constants, preset-aware default config generation, strict and lenient config parsing, section rendering/parsing helpers, and schema plus semantic validation for vvoc-owned configuration.
|
|
6
|
+
// DEPENDS: [ajv/dist/2020, src/lib/agent-models.ts, src/lib/package.ts]
|
|
7
|
+
// LINKS: [M-CLI-CONFIG, M-CLI-CONFIG-VALIDATE, M-CLI-PRESET, M-PLUGIN-GUARDIAN, M-PLUGIN-MEMORY-STORE, M-PLUGIN-SECRETS-REDACTION-INTERNAL-CONFIG]
|
|
8
8
|
// ROLE: RUNTIME
|
|
9
9
|
// MAP_MODE: EXPORTS
|
|
10
10
|
// END_MODULE_CONTRACT
|
|
@@ -13,20 +13,26 @@
|
|
|
13
13
|
// VVOC_CONFIG_VERSION - Canonical vvoc config document version.
|
|
14
14
|
// VVOC_CONFIG_SCHEMA_URL - Hosted JSON Schema URL for the canonical vvoc config.
|
|
15
15
|
// VVOC_CONFIG_SCHEMA - JSON Schema document for vvoc.json.
|
|
16
|
+
// VvocPresetAgents - Partial per-target model override map for a named preset.
|
|
17
|
+
// VvocPreset - Declarative preset shape stored in vvoc.json.
|
|
18
|
+
// VvocPresets - Top-level preset map stored in vvoc.json.
|
|
16
19
|
// GuardianConfig - Fully seeded guardian section shape.
|
|
17
20
|
// GuardianConfigOverrides - Partial guardian section override shape.
|
|
18
21
|
// MemoryConfig - Fully seeded memory section shape.
|
|
19
22
|
// MemoryConfigOverrides - Partial memory section override shape.
|
|
20
23
|
// SecretsRedactionConfig - Fully seeded secrets-redaction section shape.
|
|
21
24
|
// VvocConfig - Fully seeded canonical vvoc config document shape.
|
|
25
|
+
// ParsedVvocConfig - Parsed vvoc config plus the document schema/version found on disk.
|
|
22
26
|
// createGuardianConfig - Builds a fully seeded guardian section from optional overrides.
|
|
23
27
|
// createMemoryConfig - Builds a fully seeded memory section from optional overrides.
|
|
24
28
|
// createDefaultSecretsRedactionConfig - Builds the seeded secrets-redaction section.
|
|
29
|
+
// createDefaultVvocPresets - Builds the seeded named preset map.
|
|
25
30
|
// createDefaultVvocConfig - Builds the fully seeded canonical vvoc config document.
|
|
26
31
|
// parseGuardianConfigText - Strictly parses a guardian section JSON snippet.
|
|
27
32
|
// renderGuardianConfig - Renders a guardian section JSON snippet.
|
|
28
33
|
// parseMemoryConfigText - Strictly parses a memory section JSON snippet.
|
|
29
34
|
// renderMemoryConfig - Renders a memory section JSON snippet.
|
|
35
|
+
// parseVersionedVvocConfigText - Strictly parses vvoc.json and returns the source version plus normalized config.
|
|
30
36
|
// parseVvocConfigText - Strictly parses the canonical vvoc config document.
|
|
31
37
|
// loadLenientVvocConfigText - Parses vvoc.json leniently for runtime fallback with warnings.
|
|
32
38
|
// renderVvocConfig - Renders canonical vvoc.json.
|
|
@@ -34,17 +40,19 @@
|
|
|
34
40
|
// END_MODULE_MAP
|
|
35
41
|
//
|
|
36
42
|
// START_CHANGE_SUMMARY
|
|
37
|
-
// LAST_CHANGE: [
|
|
43
|
+
// LAST_CHANGE: [v2.0.0 - Added vvoc.json schema v2 with declarative named presets and version-aware v1 normalization.]
|
|
38
44
|
// END_CHANGE_SUMMARY
|
|
39
45
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
46
|
+
import { SUPPORTED_MODEL_TARGET_NAMES, normalizeModelTargetOverride, } from "./agent-models.js";
|
|
40
47
|
import { PACKAGE_NAME, PACKAGE_VERSION } from "./package.js";
|
|
41
48
|
const DEFAULT_GUARDIAN_TIMEOUT_MS = 90_000;
|
|
42
49
|
const DEFAULT_GUARDIAN_APPROVAL_RISK_THRESHOLD = 80;
|
|
43
50
|
const DEFAULT_MEMORY_SEARCH_LIMIT = 8;
|
|
44
51
|
const DEFAULT_SECRETS_REDACTION_TTL_MS = 3_600_000;
|
|
45
52
|
const DEFAULT_SECRETS_REDACTION_MAX_MAPPINGS = 10_000;
|
|
46
|
-
|
|
47
|
-
export const
|
|
53
|
+
const VVOC_CONFIG_V1_SCHEMA_URL = `https://cdn.jsdelivr.net/npm/${PACKAGE_NAME}@${PACKAGE_VERSION}/schemas/vvoc/v1.json`;
|
|
54
|
+
export const VVOC_CONFIG_VERSION = 2;
|
|
55
|
+
export const VVOC_CONFIG_SCHEMA_URL = `https://cdn.jsdelivr.net/npm/${PACKAGE_NAME}@${PACKAGE_VERSION}/schemas/vvoc/v2.json`;
|
|
48
56
|
const JSON_SCHEMA_DRAFT_2020_12 = "https://json-schema.org/draft/2020-12/schema";
|
|
49
57
|
const BUILTIN_SECRETS_REDACTION_PATTERNS = [
|
|
50
58
|
"email",
|
|
@@ -61,6 +69,118 @@ const BUILTIN_SECRETS_REDACTION_PATTERNS = [
|
|
|
61
69
|
"syn_key",
|
|
62
70
|
"hex_token",
|
|
63
71
|
];
|
|
72
|
+
const GUARDIAN_CONFIG_SCHEMA = {
|
|
73
|
+
type: "object",
|
|
74
|
+
additionalProperties: false,
|
|
75
|
+
required: ["timeoutMs", "approvalRiskThreshold", "reviewToastDurationMs"],
|
|
76
|
+
properties: {
|
|
77
|
+
model: { type: "string", minLength: 1 },
|
|
78
|
+
variant: { type: "string", minLength: 1 },
|
|
79
|
+
timeoutMs: { type: "integer", minimum: 1 },
|
|
80
|
+
approvalRiskThreshold: { type: "integer", minimum: 0, maximum: 100 },
|
|
81
|
+
reviewToastDurationMs: { type: "integer", minimum: 1 },
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
const MEMORY_CONFIG_SCHEMA = {
|
|
85
|
+
type: "object",
|
|
86
|
+
additionalProperties: false,
|
|
87
|
+
required: ["enabled", "defaultSearchLimit"],
|
|
88
|
+
properties: {
|
|
89
|
+
enabled: { type: "boolean" },
|
|
90
|
+
defaultSearchLimit: { type: "integer", minimum: 1 },
|
|
91
|
+
reviewerModel: { type: "string", minLength: 1 },
|
|
92
|
+
reviewerVariant: { type: "string", minLength: 1 },
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const SECRETS_REDACTION_CONFIG_SCHEMA = {
|
|
96
|
+
type: "object",
|
|
97
|
+
additionalProperties: false,
|
|
98
|
+
required: ["enabled", "secret", "ttlMs", "maxMappings", "patterns", "debug"],
|
|
99
|
+
properties: {
|
|
100
|
+
enabled: { type: "boolean" },
|
|
101
|
+
secret: { type: "string", minLength: 1 },
|
|
102
|
+
ttlMs: { type: "integer", minimum: 0 },
|
|
103
|
+
maxMappings: { type: "integer", minimum: 1 },
|
|
104
|
+
debug: { type: "boolean" },
|
|
105
|
+
patterns: {
|
|
106
|
+
type: "object",
|
|
107
|
+
additionalProperties: false,
|
|
108
|
+
required: ["keywords", "regex", "builtin", "exclude"],
|
|
109
|
+
properties: {
|
|
110
|
+
keywords: {
|
|
111
|
+
type: "array",
|
|
112
|
+
items: {
|
|
113
|
+
type: "object",
|
|
114
|
+
additionalProperties: false,
|
|
115
|
+
required: ["value"],
|
|
116
|
+
properties: {
|
|
117
|
+
value: { type: "string", minLength: 1 },
|
|
118
|
+
category: { type: "string", minLength: 1 },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
regex: {
|
|
123
|
+
type: "array",
|
|
124
|
+
items: {
|
|
125
|
+
type: "object",
|
|
126
|
+
additionalProperties: false,
|
|
127
|
+
required: ["pattern", "category"],
|
|
128
|
+
properties: {
|
|
129
|
+
pattern: { type: "string", minLength: 1 },
|
|
130
|
+
category: { type: "string", minLength: 1 },
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
builtin: {
|
|
135
|
+
type: "array",
|
|
136
|
+
items: { type: "string", minLength: 1 },
|
|
137
|
+
},
|
|
138
|
+
exclude: {
|
|
139
|
+
type: "array",
|
|
140
|
+
items: { type: "string", minLength: 1 },
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
const VVOC_PRESET_AGENTS_SCHEMA = {
|
|
147
|
+
type: "object",
|
|
148
|
+
additionalProperties: false,
|
|
149
|
+
minProperties: 1,
|
|
150
|
+
properties: Object.fromEntries(SUPPORTED_MODEL_TARGET_NAMES.map((agentName) => [agentName, { type: "string", minLength: 1 }])),
|
|
151
|
+
};
|
|
152
|
+
const VVOC_PRESET_SCHEMA = {
|
|
153
|
+
type: "object",
|
|
154
|
+
additionalProperties: false,
|
|
155
|
+
required: ["agents"],
|
|
156
|
+
properties: {
|
|
157
|
+
description: { type: "string", minLength: 1 },
|
|
158
|
+
agents: VVOC_PRESET_AGENTS_SCHEMA,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
const VVOC_CONFIG_V1_SCHEMA = {
|
|
162
|
+
$schema: JSON_SCHEMA_DRAFT_2020_12,
|
|
163
|
+
$id: VVOC_CONFIG_V1_SCHEMA_URL,
|
|
164
|
+
title: "vvoc config",
|
|
165
|
+
description: "Canonical vvoc configuration document (v1).",
|
|
166
|
+
type: "object",
|
|
167
|
+
additionalProperties: false,
|
|
168
|
+
required: ["$schema", "version", "guardian", "memory", "secretsRedaction"],
|
|
169
|
+
properties: {
|
|
170
|
+
$schema: {
|
|
171
|
+
type: "string",
|
|
172
|
+
minLength: 1,
|
|
173
|
+
description: "Hosted JSON Schema URL for vvoc.json.",
|
|
174
|
+
},
|
|
175
|
+
version: {
|
|
176
|
+
type: "integer",
|
|
177
|
+
const: 1,
|
|
178
|
+
},
|
|
179
|
+
guardian: GUARDIAN_CONFIG_SCHEMA,
|
|
180
|
+
memory: MEMORY_CONFIG_SCHEMA,
|
|
181
|
+
secretsRedaction: SECRETS_REDACTION_CONFIG_SCHEMA,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
64
184
|
export const VVOC_CONFIG_SCHEMA = {
|
|
65
185
|
$schema: JSON_SCHEMA_DRAFT_2020_12,
|
|
66
186
|
$id: VVOC_CONFIG_SCHEMA_URL,
|
|
@@ -68,7 +188,7 @@ export const VVOC_CONFIG_SCHEMA = {
|
|
|
68
188
|
description: "Canonical vvoc configuration document.",
|
|
69
189
|
type: "object",
|
|
70
190
|
additionalProperties: false,
|
|
71
|
-
required: ["$schema", "version", "guardian", "memory", "secretsRedaction"],
|
|
191
|
+
required: ["$schema", "version", "guardian", "memory", "secretsRedaction", "presets"],
|
|
72
192
|
properties: {
|
|
73
193
|
$schema: {
|
|
74
194
|
type: "string",
|
|
@@ -79,83 +199,18 @@ export const VVOC_CONFIG_SCHEMA = {
|
|
|
79
199
|
type: "integer",
|
|
80
200
|
const: VVOC_CONFIG_VERSION,
|
|
81
201
|
},
|
|
82
|
-
guardian:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
properties: {
|
|
87
|
-
model: { type: "string", minLength: 1 },
|
|
88
|
-
variant: { type: "string", minLength: 1 },
|
|
89
|
-
timeoutMs: { type: "integer", minimum: 1 },
|
|
90
|
-
approvalRiskThreshold: { type: "integer", minimum: 0, maximum: 100 },
|
|
91
|
-
reviewToastDurationMs: { type: "integer", minimum: 1 },
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
memory: {
|
|
202
|
+
guardian: GUARDIAN_CONFIG_SCHEMA,
|
|
203
|
+
memory: MEMORY_CONFIG_SCHEMA,
|
|
204
|
+
secretsRedaction: SECRETS_REDACTION_CONFIG_SCHEMA,
|
|
205
|
+
presets: {
|
|
95
206
|
type: "object",
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
properties: {
|
|
99
|
-
enabled: { type: "boolean" },
|
|
100
|
-
defaultSearchLimit: { type: "integer", minimum: 1 },
|
|
101
|
-
reviewerModel: { type: "string", minLength: 1 },
|
|
102
|
-
reviewerVariant: { type: "string", minLength: 1 },
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
secretsRedaction: {
|
|
106
|
-
type: "object",
|
|
107
|
-
additionalProperties: false,
|
|
108
|
-
required: ["enabled", "secret", "ttlMs", "maxMappings", "patterns", "debug"],
|
|
109
|
-
properties: {
|
|
110
|
-
enabled: { type: "boolean" },
|
|
111
|
-
secret: { type: "string", minLength: 1 },
|
|
112
|
-
ttlMs: { type: "integer", minimum: 0 },
|
|
113
|
-
maxMappings: { type: "integer", minimum: 1 },
|
|
114
|
-
debug: { type: "boolean" },
|
|
115
|
-
patterns: {
|
|
116
|
-
type: "object",
|
|
117
|
-
additionalProperties: false,
|
|
118
|
-
required: ["keywords", "regex", "builtin", "exclude"],
|
|
119
|
-
properties: {
|
|
120
|
-
keywords: {
|
|
121
|
-
type: "array",
|
|
122
|
-
items: {
|
|
123
|
-
type: "object",
|
|
124
|
-
additionalProperties: false,
|
|
125
|
-
required: ["value"],
|
|
126
|
-
properties: {
|
|
127
|
-
value: { type: "string", minLength: 1 },
|
|
128
|
-
category: { type: "string", minLength: 1 },
|
|
129
|
-
},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
regex: {
|
|
133
|
-
type: "array",
|
|
134
|
-
items: {
|
|
135
|
-
type: "object",
|
|
136
|
-
additionalProperties: false,
|
|
137
|
-
required: ["pattern", "category"],
|
|
138
|
-
properties: {
|
|
139
|
-
pattern: { type: "string", minLength: 1 },
|
|
140
|
-
category: { type: "string", minLength: 1 },
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
builtin: {
|
|
145
|
-
type: "array",
|
|
146
|
-
items: { type: "string", minLength: 1 },
|
|
147
|
-
},
|
|
148
|
-
exclude: {
|
|
149
|
-
type: "array",
|
|
150
|
-
items: { type: "string", minLength: 1 },
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
},
|
|
207
|
+
propertyNames: { minLength: 1 },
|
|
208
|
+
additionalProperties: VVOC_PRESET_SCHEMA,
|
|
155
209
|
},
|
|
156
210
|
},
|
|
157
211
|
};
|
|
158
212
|
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
213
|
+
const validateWithV1Schema = ajv.compile(VVOC_CONFIG_V1_SCHEMA);
|
|
159
214
|
const validateWithSchema = ajv.compile(VVOC_CONFIG_SCHEMA);
|
|
160
215
|
// START_BLOCK_DEFAULT_CONFIG_BUILDERS
|
|
161
216
|
export function createGuardianConfig(overrides = {}) {
|
|
@@ -191,6 +246,37 @@ export function createDefaultSecretsRedactionConfig() {
|
|
|
191
246
|
debug: false,
|
|
192
247
|
};
|
|
193
248
|
}
|
|
249
|
+
export function createDefaultVvocPresets() {
|
|
250
|
+
return createVvocPresets({
|
|
251
|
+
openai: {
|
|
252
|
+
description: "Starter OpenAI overrides for common vvoc model targets.",
|
|
253
|
+
agents: {
|
|
254
|
+
default: "openai/gpt-5.4:xhigh",
|
|
255
|
+
"small-model": "openai/gpt-5.4-mini",
|
|
256
|
+
guardian: "openaig/gpt-5.4-mini",
|
|
257
|
+
explore: "openai/gpt-5.4-mini",
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
zai: {
|
|
261
|
+
description: "Starter ZAI overrides for common vvoc model targets.",
|
|
262
|
+
agents: {
|
|
263
|
+
default: "zai-coding-plan/glm-5.1",
|
|
264
|
+
"small-model": "zai-coding-plan/glm-4.7-flashx",
|
|
265
|
+
guardian: "zai-coding-plan/glm-4.7-flash-x",
|
|
266
|
+
explore: "zai-coding-plan/glm-4.7-flashx",
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
minimax: {
|
|
270
|
+
description: "Starter MiniMax overrides for common vvoc model targets.",
|
|
271
|
+
agents: {
|
|
272
|
+
default: "minimax-coding-plan/minimax-m2.7",
|
|
273
|
+
"small-model": "minimax-coding-plan/minimax-m2.1",
|
|
274
|
+
guardian: "minimax-coding-plan/minimax-m2.1",
|
|
275
|
+
explore: "minimax-coding-plan/minimax-m2.1",
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
194
280
|
export function createDefaultVvocConfig() {
|
|
195
281
|
return {
|
|
196
282
|
$schema: VVOC_CONFIG_SCHEMA_URL,
|
|
@@ -198,6 +284,7 @@ export function createDefaultVvocConfig() {
|
|
|
198
284
|
guardian: createGuardianConfig(),
|
|
199
285
|
memory: createMemoryConfig(),
|
|
200
286
|
secretsRedaction: createDefaultSecretsRedactionConfig(),
|
|
287
|
+
presets: createDefaultVvocPresets(),
|
|
201
288
|
};
|
|
202
289
|
}
|
|
203
290
|
// END_BLOCK_DEFAULT_CONFIG_BUILDERS
|
|
@@ -258,7 +345,7 @@ export function renderMemoryConfig(overrides = {}) {
|
|
|
258
345
|
}
|
|
259
346
|
// END_BLOCK_SECTION_PARSE_AND_RENDER
|
|
260
347
|
// START_BLOCK_CANONICAL_CONFIG_PARSE_RENDER
|
|
261
|
-
export function
|
|
348
|
+
export function parseVersionedVvocConfigText(text, label) {
|
|
262
349
|
const value = parseStrictJson(text, label);
|
|
263
350
|
const errors = validateVvocConfigDocument(value);
|
|
264
351
|
if (errors.length > 0) {
|
|
@@ -266,6 +353,9 @@ export function parseVvocConfigText(text, label) {
|
|
|
266
353
|
}
|
|
267
354
|
return normalizeStrictVvocConfig(value);
|
|
268
355
|
}
|
|
356
|
+
export function parseVvocConfigText(text, label) {
|
|
357
|
+
return parseVersionedVvocConfigText(text, label).config;
|
|
358
|
+
}
|
|
269
359
|
export function loadLenientVvocConfigText(text, label, warnings) {
|
|
270
360
|
let value;
|
|
271
361
|
try {
|
|
@@ -279,12 +369,16 @@ export function loadLenientVvocConfigText(text, label, warnings) {
|
|
|
279
369
|
warnings.push(`${label}: expected a top-level object`);
|
|
280
370
|
return createDefaultVvocConfig();
|
|
281
371
|
}
|
|
372
|
+
const sourceVersion = readLenientSupportedVersion(value.version, `${label}: version`, warnings);
|
|
282
373
|
return {
|
|
283
|
-
$schema:
|
|
284
|
-
version:
|
|
374
|
+
$schema: VVOC_CONFIG_SCHEMA_URL,
|
|
375
|
+
version: VVOC_CONFIG_VERSION,
|
|
285
376
|
guardian: loadLenientGuardianConfig(value.guardian, `${label}: guardian`, warnings),
|
|
286
377
|
memory: loadLenientMemoryConfig(value.memory, `${label}: memory`, warnings),
|
|
287
378
|
secretsRedaction: loadLenientSecretsRedactionConfig(value.secretsRedaction, `${label}: secretsRedaction`, warnings),
|
|
379
|
+
presets: sourceVersion === 2
|
|
380
|
+
? loadLenientVvocPresets(value.presets, `${label}: presets`, warnings)
|
|
381
|
+
: createDefaultVvocPresets(),
|
|
288
382
|
};
|
|
289
383
|
}
|
|
290
384
|
export function renderVvocConfig(config = createDefaultVvocConfig()) {
|
|
@@ -294,25 +388,44 @@ export function renderVvocConfig(config = createDefaultVvocConfig()) {
|
|
|
294
388
|
guardian: createGuardianConfig(config.guardian),
|
|
295
389
|
memory: createMemoryConfig(config.memory),
|
|
296
390
|
secretsRedaction: createSecretsRedactionConfig(config.secretsRedaction),
|
|
391
|
+
presets: createVvocPresets(config.presets),
|
|
297
392
|
});
|
|
298
393
|
}
|
|
299
394
|
// END_BLOCK_CANONICAL_CONFIG_PARSE_RENDER
|
|
300
395
|
// START_BLOCK_SCHEMA_VALIDATION
|
|
301
396
|
export function validateVvocConfigDocument(document) {
|
|
302
|
-
|
|
303
|
-
|
|
397
|
+
const validator = isPlainObject(document) && document.version === 1 ? validateWithV1Schema : validateWithSchema;
|
|
398
|
+
if (!validator(document)) {
|
|
399
|
+
return (validator.errors ?? []).map(formatSchemaError);
|
|
304
400
|
}
|
|
305
|
-
|
|
401
|
+
if (isPlainObject(document) && document.version === VVOC_CONFIG_VERSION) {
|
|
402
|
+
return validatePresetSemantics(document);
|
|
403
|
+
}
|
|
404
|
+
return [];
|
|
306
405
|
}
|
|
307
406
|
// END_BLOCK_SCHEMA_VALIDATION
|
|
308
407
|
function normalizeStrictVvocConfig(value) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
408
|
+
const sourceVersion = readSupportedVersion(value.version, "version");
|
|
409
|
+
const baseConfig = {
|
|
410
|
+
$schema: VVOC_CONFIG_SCHEMA_URL,
|
|
411
|
+
version: VVOC_CONFIG_VERSION,
|
|
312
412
|
guardian: createGuardianConfig(value.guardian),
|
|
313
413
|
memory: createMemoryConfig(value.memory),
|
|
314
414
|
secretsRedaction: createSecretsRedactionConfig(value.secretsRedaction),
|
|
315
415
|
};
|
|
416
|
+
return {
|
|
417
|
+
sourceSchema: readNonEmptyString(value.$schema, "$schema"),
|
|
418
|
+
sourceVersion,
|
|
419
|
+
config: sourceVersion === 1
|
|
420
|
+
? {
|
|
421
|
+
...baseConfig,
|
|
422
|
+
presets: createDefaultVvocPresets(),
|
|
423
|
+
}
|
|
424
|
+
: {
|
|
425
|
+
...baseConfig,
|
|
426
|
+
presets: createVvocPresets(value.presets),
|
|
427
|
+
},
|
|
428
|
+
};
|
|
316
429
|
}
|
|
317
430
|
function createSecretsRedactionConfig(overrides = {}) {
|
|
318
431
|
const defaults = createDefaultSecretsRedactionConfig();
|
|
@@ -331,6 +444,30 @@ function createSecretsRedactionConfig(overrides = {}) {
|
|
|
331
444
|
debug: overrides.debug ?? defaults.debug,
|
|
332
445
|
};
|
|
333
446
|
}
|
|
447
|
+
function createVvocPresets(overrides = {}) {
|
|
448
|
+
const presets = {};
|
|
449
|
+
for (const [presetName, preset] of Object.entries(overrides)) {
|
|
450
|
+
presets[presetName] = createVvocPreset(preset);
|
|
451
|
+
}
|
|
452
|
+
return presets;
|
|
453
|
+
}
|
|
454
|
+
function createVvocPreset(overrides = {}) {
|
|
455
|
+
return compactObject({
|
|
456
|
+
description: normalizeOptionalString(overrides.description),
|
|
457
|
+
agents: createVvocPresetAgents(overrides.agents),
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
function createVvocPresetAgents(overrides = {}) {
|
|
461
|
+
const agents = {};
|
|
462
|
+
for (const agentName of SUPPORTED_MODEL_TARGET_NAMES) {
|
|
463
|
+
const value = overrides[agentName];
|
|
464
|
+
if (value === undefined) {
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
agents[agentName] = normalizeModelTargetOverride(agentName, value, `preset ${agentName}`);
|
|
468
|
+
}
|
|
469
|
+
return agents;
|
|
470
|
+
}
|
|
334
471
|
function cloneKeywordRules(rules) {
|
|
335
472
|
return rules.map((rule) => compactObject({ value: rule.value, category: rule.category }));
|
|
336
473
|
}
|
|
@@ -534,18 +671,61 @@ function loadLenientStringArray(value, label, warnings, fallback) {
|
|
|
534
671
|
.filter(Boolean);
|
|
535
672
|
return entries;
|
|
536
673
|
}
|
|
537
|
-
function
|
|
538
|
-
|
|
539
|
-
|
|
674
|
+
function loadLenientVvocPresets(value, label, warnings) {
|
|
675
|
+
if (!isPlainObject(value)) {
|
|
676
|
+
warnings.push(`${label}: expected an object`);
|
|
677
|
+
return createDefaultVvocPresets();
|
|
678
|
+
}
|
|
679
|
+
const presets = {};
|
|
680
|
+
for (const [presetName, presetValue] of Object.entries(value)) {
|
|
681
|
+
if (!presetName.trim()) {
|
|
682
|
+
warnings.push(`${label}: preset names must be non-empty strings`);
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
if (!isPlainObject(presetValue)) {
|
|
686
|
+
warnings.push(`${label}.${presetName}: expected an object`);
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
const description = Object.hasOwn(presetValue, "description")
|
|
690
|
+
? readLenientOptionalString(presetValue.description, `${label}.${presetName}.description`, warnings)
|
|
691
|
+
: undefined;
|
|
692
|
+
const agents = loadLenientVvocPresetAgents(presetValue.agents, `${label}.${presetName}.agents`, warnings);
|
|
693
|
+
if (Object.keys(agents).length === 0) {
|
|
694
|
+
warnings.push(`${label}.${presetName}.agents: expected at least one supported target`);
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
presets[presetName] = createVvocPreset({ description, agents });
|
|
698
|
+
}
|
|
699
|
+
return Object.keys(presets).length > 0 ? presets : createDefaultVvocPresets();
|
|
540
700
|
}
|
|
541
|
-
function
|
|
701
|
+
function loadLenientVvocPresetAgents(value, label, warnings) {
|
|
702
|
+
if (!isPlainObject(value)) {
|
|
703
|
+
warnings.push(`${label}: expected an object`);
|
|
704
|
+
return {};
|
|
705
|
+
}
|
|
706
|
+
const agents = {};
|
|
707
|
+
for (const [agentName, modelValue] of Object.entries(value)) {
|
|
708
|
+
if (!SUPPORTED_MODEL_TARGET_NAMES.includes(agentName)) {
|
|
709
|
+
warnings.push(`${label}: unsupported target "${agentName}"`);
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
try {
|
|
713
|
+
agents[agentName] = normalizeModelTargetOverride(agentName, modelValue, `${label}.${agentName}`);
|
|
714
|
+
}
|
|
715
|
+
catch (error) {
|
|
716
|
+
warnings.push(`${label}.${agentName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return agents;
|
|
720
|
+
}
|
|
721
|
+
function readLenientSupportedVersion(value, label, warnings) {
|
|
542
722
|
if (value === undefined) {
|
|
543
723
|
return VVOC_CONFIG_VERSION;
|
|
544
724
|
}
|
|
545
|
-
if (value === VVOC_CONFIG_VERSION) {
|
|
546
|
-
return
|
|
725
|
+
if (value === 1 || value === VVOC_CONFIG_VERSION) {
|
|
726
|
+
return value;
|
|
547
727
|
}
|
|
548
|
-
warnings.push(`${label}: expected ${VVOC_CONFIG_VERSION}`);
|
|
728
|
+
warnings.push(`${label}: expected 1 or ${VVOC_CONFIG_VERSION}`);
|
|
549
729
|
return VVOC_CONFIG_VERSION;
|
|
550
730
|
}
|
|
551
731
|
function readLenientOptionalString(value, label, warnings) {
|
|
@@ -580,11 +760,11 @@ function parseStrictJson(text, label) {
|
|
|
580
760
|
throw new Error(`${label}: failed to parse JSON (${error instanceof Error ? error.message : String(error)})`);
|
|
581
761
|
}
|
|
582
762
|
}
|
|
583
|
-
function
|
|
584
|
-
if (value
|
|
585
|
-
|
|
763
|
+
function readSupportedVersion(value, label) {
|
|
764
|
+
if (value === 1 || value === VVOC_CONFIG_VERSION) {
|
|
765
|
+
return value;
|
|
586
766
|
}
|
|
587
|
-
|
|
767
|
+
throw new Error(`${label}: expected 1 or ${VVOC_CONFIG_VERSION}`);
|
|
588
768
|
}
|
|
589
769
|
function readNonEmptyString(value, label) {
|
|
590
770
|
if (typeof value !== "string" || !value.trim()) {
|
|
@@ -629,6 +809,28 @@ function compactObject(value) {
|
|
|
629
809
|
function renderJson(value) {
|
|
630
810
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
631
811
|
}
|
|
812
|
+
function validatePresetSemantics(document) {
|
|
813
|
+
const presetsValue = document.presets;
|
|
814
|
+
if (!isPlainObject(presetsValue)) {
|
|
815
|
+
return [];
|
|
816
|
+
}
|
|
817
|
+
const errors = [];
|
|
818
|
+
for (const [presetName, presetValue] of Object.entries(presetsValue)) {
|
|
819
|
+
if (!isPlainObject(presetValue) || !isPlainObject(presetValue.agents)) {
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
for (const [agentName, modelValue] of Object.entries(presetValue.agents)) {
|
|
823
|
+
const location = `/presets/${presetName}/agents/${agentName}`;
|
|
824
|
+
try {
|
|
825
|
+
normalizeModelTargetOverride(agentName, modelValue, location);
|
|
826
|
+
}
|
|
827
|
+
catch (error) {
|
|
828
|
+
errors.push(`${location} ${error instanceof Error ? error.message : String(error)}`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return errors;
|
|
833
|
+
}
|
|
632
834
|
function formatSchemaError(error) {
|
|
633
835
|
const path = error.instancePath || "/";
|
|
634
836
|
if (error.keyword === "required") {
|