Skip to content

Commit a849288

Browse files
fix: route function-typed Standard Schemas through elicitation conversion
The schema-detection guard required typeof object, so function-typed Standard Schemas (e.g. ArkType) fell through to the raw branch and the vendor-internal object shipped as requestedSchema with no conversion or flat-primitive gate. Delegate to isStandardSchema, which accepts functions and verifies ~standard.validate — and, matching the precedent in normalizeRawShapeSchema, does not gate on ~standard.jsonSchema so the zod 4.0/4.1 fallback stays reachable. Also fixes the reverse misroute: a plain JSON requestedSchema containing a literal '~standard' key is wire-legal and now stays on the raw branch instead of throwing a vendor error.
1 parent a228f8a commit a849288

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

packages/core-internal/src/shared/elicitation.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ElicitRequestFormParamsSchema } from '../types/schemas';
66
import type { ElicitRequestFormParams } from '../types/types';
77
import { parseSchema } from '../util/schema';
88
import type { StandardSchemaWithJSON } from '../util/standardSchema';
9-
import { standardSchemaToJsonSchema } from '../util/standardSchema';
9+
import { isStandardSchema, standardSchemaToJsonSchema } from '../util/standardSchema';
1010
import type { ElicitInputFormParams } from './protocol';
1111

1212
export type NormalizedElicitInputFormParams = {
@@ -154,7 +154,12 @@ function findStrippedJsonSchemaPaths(original: unknown, parsed: unknown, path =
154154
function isElicitInputSchema(
155155
schema: ElicitRequestFormParams['requestedSchema'] | StandardSchemaWithJSON
156156
): schema is StandardSchemaWithJSON {
157-
return typeof schema === 'object' && schema !== null && '~standard' in schema;
157+
// isStandardSchema, not a plain '~standard' key probe: ArkType schemas are functions
158+
// (a typeof-object check routes them, unconverted, to the raw branch), and a plain JSON
159+
// schema containing a literal '~standard' key — wire-legal via the catchall — must stay
160+
// on the raw branch. Not isStandardSchemaWithJSON: gating on `~standard.jsonSchema` here
161+
// would front-run standardSchemaToJsonSchema's zod 4.0/4.1 fallback (see zodCompat.ts).
162+
return isStandardSchema(schema);
158163
}
159164

160165
function convertStandardElicitationSchema(standardSchema: StandardSchemaWithJSON): Record<string, unknown> {

packages/core-internal/test/shared/elicitation.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,51 @@ function schemaFromJson(jsonSchema: Record<string, unknown>): StandardSchemaWith
1919
} satisfies StandardSchemaWithJSON;
2020
}
2121

22+
describe('normalizeElicitInputFormParams schema detection', () => {
23+
test('converts function-typed Standard Schemas (ArkType-style)', () => {
24+
const jsonSchema = {
25+
type: 'object',
26+
properties: { name: { type: 'string' } },
27+
required: ['name']
28+
};
29+
const functionSchema = Object.assign(() => {}, {
30+
'~standard': {
31+
version: 1 as const,
32+
vendor: 'test',
33+
validate: (value: unknown) => ({ value }),
34+
jsonSchema: {
35+
input: () => jsonSchema,
36+
output: () => ({})
37+
}
38+
}
39+
});
40+
41+
const { params, standardSchema } = normalizeElicitInputFormParams({
42+
message: 'Name?',
43+
requestedSchema: functionSchema as unknown as StandardSchemaWithJSON
44+
});
45+
46+
expect(standardSchema).toBe(functionSchema);
47+
expect(params.requestedSchema).toEqual(jsonSchema);
48+
});
49+
50+
test('routes a plain JSON schema containing a literal "~standard" key to the raw branch', () => {
51+
const rawSchema = {
52+
type: 'object' as const,
53+
properties: { name: { type: 'string' as const } },
54+
'~standard': 'extension-data'
55+
};
56+
57+
const { params, standardSchema } = normalizeElicitInputFormParams({
58+
message: 'Name?',
59+
requestedSchema: rawSchema as never
60+
});
61+
62+
expect(standardSchema).toBeUndefined();
63+
expect(params.requestedSchema).toBe(rawSchema);
64+
});
65+
});
66+
2267
describe('normalizeElicitInputFormParams root keywords', () => {
2368
test('keeps the spec-declared root keys including $schema', () => {
2469
const { params } = normalizeElicitInputFormParams({

0 commit comments

Comments
 (0)