diff --git a/src/plugin/normalize-tool-arg-schemas.test.ts b/src/plugin/normalize-tool-arg-schemas.test.ts index 27f148995..8a9247dda 100644 --- a/src/plugin/normalize-tool-arg-schemas.test.ts +++ b/src/plugin/normalize-tool-arg-schemas.test.ts @@ -6,7 +6,7 @@ import { tmpdir } from "node:os" import { dirname, join } from "node:path" import { pathToFileURL } from "node:url" import { tool } from "@opencode-ai/plugin" -import { normalizeToolArgSchemas } from "./normalize-tool-arg-schemas" +import { normalizeToolArgSchemas, sanitizeJsonSchema } from "./normalize-tool-arg-schemas" const tempDirectories: string[] = [] @@ -95,3 +95,36 @@ describe("normalizeToolArgSchemas", () => { expect(afterQuery?.examples).toEqual(["issue 2314"]) }) }) + +describe("sanitizeJsonSchema", () => { + it("rewrites bare $ref values to $defs JSON pointers", () => { + // given + const schema = { + type: "object", + properties: { + new_encoding: { $ref: "Encoding" }, + existing_pointer: { $ref: "#/$defs/AlreadyValid" }, + }, + $defs: { + Encoding: { type: "string" }, + AlreadyValid: { type: "string" }, + }, + } + + // when + const sanitized = sanitizeJsonSchema(schema) + + // then + expect(sanitized).toEqual({ + type: "object", + properties: { + new_encoding: { $ref: "#/$defs/Encoding" }, + existing_pointer: { $ref: "#/$defs/AlreadyValid" }, + }, + $defs: { + Encoding: { type: "string" }, + AlreadyValid: { type: "string" }, + }, + }) + }) +}) diff --git a/src/plugin/normalize-tool-arg-schemas.ts b/src/plugin/normalize-tool-arg-schemas.ts index 0f626b546..52813bc64 100644 --- a/src/plugin/normalize-tool-arg-schemas.ts +++ b/src/plugin/normalize-tool-arg-schemas.ts @@ -47,6 +47,14 @@ function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value) } +function normalizeJsonSchemaRef(value: string): string { + if (value.startsWith("#") || value.includes(":") || value.startsWith("/")) { + return value + } + + return `#/$defs/${value}` +} + export function sanitizeJsonSchema(value: unknown, depth = 0, isPropertyName = false): unknown { if (Array.isArray(value)) { return value.map((item) => sanitizeJsonSchema(item, depth + 1, false)) @@ -67,6 +75,11 @@ export function sanitizeJsonSchema(value: unknown, depth = 0, isPropertyName = f continue } + if (!isPropertyName && key === "$ref" && typeof nestedValue === "string") { + sanitized[key] = normalizeJsonSchemaRef(nestedValue) + continue + } + const childIsPropertyName = key === "properties" && !isPropertyName sanitized[key] = sanitizeJsonSchema(nestedValue, depth + 1, childIsPropertyName) }