diff --git a/core/package-lock.json b/core/package-lock.json index 935b973492..b37d13f843 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -76,7 +76,7 @@ "winston": "^3.17.0", "workerpool": "^9.1.3", "yaml": "^2.4.2", - "zod": "^3.24.2" + "zod": "^3.25.13" }, "devDependencies": { "@babel/preset-env": "^7.24.7", @@ -143,7 +143,8 @@ "dependencies": { "@continuedev/config-types": "^1.0.14", "yaml": "^2.6.1", - "zod": "^3.24.2" + "zod": "^3.25.13", + "zod-validation-error": "^3.4.1" }, "bin": { "config-yaml": "dist/cli.js" @@ -16609,9 +16610,9 @@ } }, "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "version": "3.25.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.13.tgz", + "integrity": "sha512-Q8mvk2iWi7rTDfpQBsu4ziE7A6AxgzJ5hzRyRYQkoV3A3niYsXVwDaP1Kbz3nWav6S+VZ6k2OznFn8ZyDHvIrg==", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/core/package.json b/core/package.json index 5622cc9032..d7bfa6f739 100644 --- a/core/package.json +++ b/core/package.json @@ -111,7 +111,7 @@ "winston": "^3.17.0", "workerpool": "^9.1.3", "yaml": "^2.4.2", - "zod": "^3.24.2" + "zod": "^3.25.13" }, "engine-strict": true, "engines": { diff --git a/extensions/vscode/package-lock.json b/extensions/vscode/package-lock.json index 5634027da7..f726218bcc 100644 --- a/extensions/vscode/package-lock.json +++ b/extensions/vscode/package-lock.json @@ -169,7 +169,7 @@ "winston": "^3.17.0", "workerpool": "^9.1.3", "yaml": "^2.4.2", - "zod": "^3.24.2" + "zod": "^3.25.13" }, "devDependencies": { "@babel/preset-env": "^7.24.7", diff --git a/gui/package-lock.json b/gui/package-lock.json index 8ab34dbe73..73dc69a706 100644 --- a/gui/package-lock.json +++ b/gui/package-lock.json @@ -173,7 +173,7 @@ "winston": "^3.17.0", "workerpool": "^9.1.3", "yaml": "^2.4.2", - "zod": "^3.24.2" + "zod": "^3.25.13" }, "devDependencies": { "@babel/preset-env": "^7.24.7", @@ -216,7 +216,8 @@ "dependencies": { "@continuedev/config-types": "^1.0.14", "yaml": "^2.6.1", - "zod": "^3.24.2" + "zod": "^3.25.13", + "zod-validation-error": "^3.4.1" }, "bin": { "config-yaml": "dist/cli.js" diff --git a/packages/config-yaml/package-lock.json b/packages/config-yaml/package-lock.json index dc3a327ed2..a60d909dad 100644 --- a/packages/config-yaml/package-lock.json +++ b/packages/config-yaml/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "@continuedev/config-types": "^1.0.14", "yaml": "^2.6.1", - "zod": "^3.24.2" + "zod": "^3.25.13", + "zod-validation-error": "^3.4.1" }, "bin": { "config-yaml": "dist/cli.js" @@ -3818,9 +3819,9 @@ } }, "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", + "version": "3.25.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.13.tgz", + "integrity": "sha512-Q8mvk2iWi7rTDfpQBsu4ziE7A6AxgzJ5hzRyRYQkoV3A3niYsXVwDaP1Kbz3nWav6S+VZ6k2OznFn8ZyDHvIrg==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -3834,6 +3835,17 @@ "peerDependencies": { "zod": "^3.24.1" } + }, + "node_modules/zod-validation-error": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.4.1.tgz", + "integrity": "sha512-1KP64yqDPQ3rupxNv7oXhf7KdhHHgaqbKuspVoiN93TT0xrBjql+Svjkdjq/Qh/7GSMmgQs3AfvBT0heE35thw==", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.24.4" + } } } } diff --git a/packages/config-yaml/package.json b/packages/config-yaml/package.json index 5499f7a50b..948a593113 100644 --- a/packages/config-yaml/package.json +++ b/packages/config-yaml/package.json @@ -18,7 +18,8 @@ "dependencies": { "@continuedev/config-types": "^1.0.14", "yaml": "^2.6.1", - "zod": "^3.24.2" + "zod": "^3.25.13", + "zod-validation-error": "^3.4.1" }, "devDependencies": { "@types/jest": "^29.5.14", diff --git a/packages/config-yaml/src/load/unroll.test.ts b/packages/config-yaml/src/load/unroll.test.ts new file mode 100644 index 0000000000..aed83ccc89 --- /dev/null +++ b/packages/config-yaml/src/load/unroll.test.ts @@ -0,0 +1,72 @@ +import { configYamlSchema } from "../schemas/index.js"; +import { parseConfigYaml } from "./unroll.js"; + + + +describe("config.yaml validation", () => { + it("parses valid config YAML", () => { + const yaml = ` +name: Local Assistant +version: 1.0.0 +schema: v1 + +models: + - name: granite3.3:8b + provider: ollama + model: granite3.3:8b + roles: + - autocomplete + - chat + + - name: nomic-embed-text + provider: ollama + model: nomic-embed-text:latest + roles: + - embed + +context: + - provider: code + - provider: docs + - provider: diff + - provider: terminal + - provider: problems + - provider: folder + - provider: codebase + - provider: clipboard + +rules: + - name: Angry Teenager + rule: always respond like an angry teenager + +docs: + - name: Continue docs + startUrl: https://docs.continue.dev/ +`; + const result = parseConfigYaml(yaml); + expect(result).toMatchObject({ name: "Local Assistant", version: "1.0.0" }); + expect(() => configYamlSchema.parse(result)).not.toThrow(); + }); + + it("throws on invalid YAML", () => { + const yaml = ` +name: Local Assistant +version: 1.0.0 +schema: v1 + +models: [] + +context: + - provider: code + - provider: codebase + +data: + - destination: https://docs.continue.dev/ +`; + + const expectedError = `Failed to parse assistant: +Validation error: Required at \"data[0].name\"; Required at \"data[0].schema\", or Required at \"data[0].uses\"`; + + expect(() => parseConfigYaml(yaml)).toThrow(expectedError); + }); + +}); diff --git a/packages/config-yaml/src/load/unroll.ts b/packages/config-yaml/src/load/unroll.ts index 0b5003473b..fa83e65ead 100644 --- a/packages/config-yaml/src/load/unroll.ts +++ b/packages/config-yaml/src/load/unroll.ts @@ -1,4 +1,5 @@ import * as YAML from "yaml"; +import { fromError } from "zod-validation-error"; import { PlatformClient, Registry } from "../interfaces/index.js"; import { encodeSecretLocation } from "../interfaces/SecretResult.js"; import { @@ -30,13 +31,9 @@ export function parseConfigYaml(configYaml: string): ConfigYaml { if (result.success) { return result.data; } - throw new Error( - result.error.errors - .map((e) => `${e.path.join(".")}: ${e.message}`) - .join(""), - ); - } catch (e) { - console.log("Failed to parse rolled assistant:", configYaml); + throw fromError(result.error); + } catch (e : any) { + console.log("Failed to parse rolled assistant:", configYaml, e.message); throw new Error( `Failed to parse assistant:\n${e instanceof Error ? e.message : e}`, );