diff --git a/js/ai/src/prompt.ts b/js/ai/src/prompt.ts index c649198f3..bdbe20ba2 100644 --- a/js/ai/src/prompt.ts +++ b/js/ai/src/prompt.ts @@ -736,6 +736,12 @@ function loadPrompt( if (variant) { promptMetadata.variant = variant; } + + // dotprompt can set null description on the schema, which can confuse downstream schema consumers + if (promptMetadata.output?.schema?.description === null) { + delete promptMetadata.output?.schema?.description; + } + return { name: registryDefinitionKey(name, variant ?? undefined, ns), model: promptMetadata.model, diff --git a/js/core/tests/schema_test.ts b/js/core/tests/schema_test.ts index faba9627b..c76abd7bb 100644 --- a/js/core/tests/schema_test.ts +++ b/js/core/tests/schema_test.ts @@ -20,6 +20,7 @@ import { describe, it } from 'node:test'; import { ValidationError, parseSchema, + toJsonSchema, validateSchema, z, } from '../src/schema.js'; @@ -138,3 +139,26 @@ describe('parse()', () => { ); }); }); + +describe('toJsonSchema', () => { + it('converts zod to JSON schema', async () => { + assert.deepStrictEqual( + toJsonSchema({ + schema: z.object({ + output: z.string(), + }), + }), + { + $schema: 'http://json-schema.org/draft-07/schema#', + additionalProperties: true, + properties: { + output: { + type: 'string', + }, + }, + required: ['output'], + type: 'object', + } + ); + }); +}); diff --git a/js/genkit/tests/prompts/schemaRef.prompt b/js/genkit/tests/prompts/schemaRef.prompt new file mode 100644 index 000000000..3c4d37f6b --- /dev/null +++ b/js/genkit/tests/prompts/schemaRef.prompt @@ -0,0 +1,9 @@ +--- +model: googleai/gemini-1.5-flash +input: + schema: myInputSchema +output: + schema: myOutputSchema +--- + +Write a poem about {{foo}}. \ No newline at end of file diff --git a/js/genkit/tests/prompts_test.ts b/js/genkit/tests/prompts_test.ts index 6a19d7f99..816d4e738 100644 --- a/js/genkit/tests/prompts_test.ts +++ b/js/genkit/tests/prompts_test.ts @@ -900,6 +900,8 @@ describe.only('prompt', () => { }); defineEchoModel(ai); pm = defineProgrammableModel(ai); + ai.defineSchema('myInputSchema', z.object({ foo: z.string() })); + ai.defineSchema('myOutputSchema', z.object({ output: z.string() })); }); it('loads from from the folder', async () => { @@ -1014,6 +1016,23 @@ describe.only('prompt', () => { }); }); + it('resolved schema refs', async () => { + const prompt = ai.prompt('schemaRef'); + + const rendered = await prompt.render({ foo: 'bar' }); + assert.deepStrictEqual(rendered.output?.jsonSchema, { + $schema: 'http://json-schema.org/draft-07/schema#', + additionalProperties: true, + properties: { + output: { + type: 'string', + }, + }, + required: ['output'], + type: 'object', + }); + }); + it('loads a varaint from from the folder', async () => { const testPrompt = ai.prompt('test', { variant: 'variant' }); // see tests/prompts folder