fix: preserve schema compatibility on rc.115

This commit is contained in:
Kit Langton
2026-09-20 18:47:56 -07:00
parent cc782a0cc8
commit 63e66ca3e6
4 changed files with 18 additions and 12 deletions
+1 -1
View File
@@ -231,7 +231,7 @@ export const toDefinitions = (tools: Tools): ReadonlyArray<ToolDefinitionClass>
)
const toJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
const document = Schema.toJsonSchemaDocument(schema)
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
if (Object.keys(document.definitions).length === 0) return document.schema
return { ...document.schema, $defs: document.definitions }
}
+13 -7
View File
@@ -1,4 +1,4 @@
import { JsonPointer, Schema } from "effect"
import { JsonPointer, Schema, SchemaAST } from "effect"
import type { Tool, JsonSchema, SchemaType } from "./tool.js"
const isEffectSchema = (schema: SchemaType): schema is Schema.Decoder<unknown> & Schema.Top => Schema.isSchema(schema)
@@ -203,7 +203,7 @@ const renderSchema = (
export const toTypeScript = (schema: Schema.Top, decoded = false, pretty = false): string => {
try {
const visible = decoded ? Schema.toType(schema) : schema
const document = Schema.toJsonSchemaDocument(visible) as {
const document = Schema.toJsonSchemaDocument(visible, { onExcessProperty: "error" }) as {
readonly schema: JsonSchema
readonly definitions?: Readonly<Record<string, JsonSchema>>
}
@@ -230,7 +230,7 @@ export type InputProperty = {
export const inputProperties = <R>(tool: Tool<R>): Array<InputProperty> => {
try {
const document = isEffectSchema(tool.input)
? (Schema.toJsonSchemaDocument(tool.input) as {
? (Schema.toJsonSchemaDocument(tool.input, { onExcessProperty: "error" }) as {
readonly schema: JsonSchema
readonly definitions?: Readonly<Record<string, JsonSchema>>
})
@@ -261,10 +261,16 @@ export const inputProperties = <R>(tool: Tool<R>): Array<InputProperty> => {
export const inputTypeScript = <R>(tool: Tool<R>, pretty = false): string =>
isEffectSchema(tool.input) ? toTypeScript(tool.input, false, pretty) : jsonSchemaToTypeScript(tool.input, pretty)
// Empty object schemas render as `{}` in compact form; anything with properties,
// an index signature, or union members renders differently, so equality is a
// conservative emptiness test for both Effect and JSON Schema inputs.
export const isEmptyInput = <R>(tool: Tool<R>): boolean => inputTypeScript(tool) === "{}"
// Effect 4.0 models an empty Struct as a non-nullish object, so inspect its AST.
// Raw JSON Schema inputs retain the compact `{}` rendering check.
export const isEmptyInput = <R>(tool: Tool<R>): boolean => {
if (!isEffectSchema(tool.input)) return inputTypeScript(tool) === "{}"
return (
SchemaAST.isObjects(tool.input.ast) &&
tool.input.ast.propertySignatures.length === 0 &&
tool.input.ast.indexSignatures.length === 0
)
}
export const outputTypeScript = <R>(tool: Tool<R>, pretty = false): string =>
tool.output === undefined
+1 -1
View File
@@ -170,7 +170,7 @@ const standardJsonSchema = (schema: StandardSchemaV1<any, any>, io: "input" | "o
}
const toJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
const document = Schema.toJsonSchemaDocument(schema)
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
// Effect emits valid JSON Schema that some inference providers handle poorly. Simplify it
// without changing validation: `{ type: "integer", allOf: [{ minimum: 0 }] }` becomes
// `{ type: "integer", minimum: 0 }` only when no keyword would be overwritten. Named schemas
+3 -3
View File
@@ -1638,9 +1638,9 @@ function checksPortable(checks: SchemaAST.Checks | undefined): boolean {
? !check.aborted &&
check.annotations?.representation !== undefined &&
serializable(check.annotations.representation) &&
typeof check.annotations.arbitrary === "object" &&
check.annotations.arbitrary !== null &&
"constraint" in check.annotations.arbitrary
typeof check.annotations.arbitraryConstraint === "object" &&
check.annotations.arbitraryConstraint !== null &&
serializable(check.annotations.arbitraryConstraint)
: checksPortable(check.checks),
)
}