From ddb0939b4a23ca0c4254a95abef12c1fe2029b44 Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Wed, 4 Jun 2025 10:59:56 +0200 Subject: [PATCH] breaking: remove old action format design Signed-off-by: benjdlambert --- plugins/scaffolder-node/report.api.md | 210 ++++++++---------- .../src/actions/createTemplateAction.test.ts | 127 +++++------ .../src/actions/createTemplateAction.ts | 161 ++++++-------- plugins/scaffolder-node/src/actions/types.ts | 184 +++++---------- plugins/scaffolder-node/src/actions/util.ts | 40 ++-- 5 files changed, 284 insertions(+), 438 deletions(-) diff --git a/plugins/scaffolder-node/report.api.md b/plugins/scaffolder-node/report.api.md index 08fc2ddb12..a23a9137b1 100644 --- a/plugins/scaffolder-node/report.api.md +++ b/plugins/scaffolder-node/report.api.md @@ -7,7 +7,6 @@ import { BackstageCredentials } from '@backstage/backend-plugin-api'; import { Expand } from '@backstage/types'; import { JsonObject } from '@backstage/types'; import { JsonValue } from '@backstage/types'; -import { Logger } from 'winston'; import { LoggerService } from '@backstage/backend-plugin-api'; import { Observable } from '@backstage/types'; import { Schema } from 'jsonschema'; @@ -25,63 +24,34 @@ import { z } from 'zod'; export type ActionContext< TActionInput extends JsonObject, TActionOutput extends JsonObject = JsonObject, - TSchemaType extends 'v1' | 'v2' = 'v1', -> = TSchemaType extends 'v2' - ? { - logger: LoggerService; - secrets?: TaskSecrets; - workspacePath: string; - input: TActionInput; - checkpoint(opts: { - key: string; - fn: () => Promise | T; - }): Promise; - output( - name: keyof TActionOutput, - value: TActionOutput[keyof TActionOutput], - ): void; - createTemporaryDirectory(): Promise; - getInitiatorCredentials(): Promise; - task: { - id: string; - }; - templateInfo?: TemplateInfo; - isDryRun?: boolean; - user?: { - entity?: UserEntity; - ref?: string; - }; - signal?: AbortSignal; - each?: JsonObject; - } - : { - logger: Logger; - logStream: Writable; - secrets?: TaskSecrets; - workspacePath: string; - input: TActionInput; - checkpoint(opts: { - key: string; - fn: () => Promise | T; - }): Promise; - output( - name: keyof TActionOutput, - value: TActionOutput[keyof TActionOutput], - ): void; - createTemporaryDirectory(): Promise; - getInitiatorCredentials(): Promise; - task: { - id: string; - }; - templateInfo?: TemplateInfo; - isDryRun?: boolean; - user?: { - entity?: UserEntity; - ref?: string; - }; - signal?: AbortSignal; - each?: JsonObject; - }; + _TSchemaType extends 'v2' = 'v2', +> = { + logger: LoggerService; + secrets?: TaskSecrets; + workspacePath: string; + input: TActionInput; + checkpoint(opts: { + key: string; + fn: () => Promise | T; + }): Promise; + output( + name: keyof TActionOutput, + value: TActionOutput[keyof TActionOutput], + ): void; + createTemporaryDirectory(): Promise; + getInitiatorCredentials(): Promise; + task: { + id: string; + }; + templateInfo?: TemplateInfo; + isDryRun?: boolean; + user?: { + entity?: UserEntity; + ref?: string; + }; + signal?: AbortSignal; + each?: JsonObject; +}; // @public (undocumented) export function addFiles(options: { @@ -180,69 +150,67 @@ export function createBranch(options: { logger?: LoggerService | undefined; }): Promise; -// @public @deprecated (undocumented) -export function createTemplateAction< - TInputParams extends JsonObject = JsonObject, - TOutputParams extends JsonObject = JsonObject, - TInputSchema extends JsonObject = JsonObject, - TOutputSchema extends JsonObject = JsonObject, - TActionInput extends JsonObject = TInputParams, - TActionOutput extends JsonObject = TOutputParams, ->( - action: TemplateActionOptions< - TActionInput, - TActionOutput, - TInputSchema, - TOutputSchema, - 'v1' - >, -): TemplateAction; - -// @public @deprecated (undocumented) -export function createTemplateAction< - TInputParams extends JsonObject = JsonObject, - TOutputParams extends JsonObject = JsonObject, - TInputSchema extends z.ZodType = z.ZodType, - TOutputSchema extends z.ZodType = z.ZodType, - TActionInput extends JsonObject = z.infer, - TActionOutput extends JsonObject = z.infer, ->( - action: TemplateActionOptions< - TActionInput, - TActionOutput, - TInputSchema, - TOutputSchema, - 'v1' - >, -): TemplateAction; - // @public export function createTemplateAction< - TInputSchema extends { - [key in string]: (zImpl: typeof z) => z.ZodType; - }, - TOutputSchema extends { - [key in string]: (zImpl: typeof z) => z.ZodType; - }, + TInputSchema extends + | { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + | ((zImpl: typeof z) => z.ZodType), + TOutputSchema extends + | { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + | ((zImpl: typeof z) => z.ZodType), >( action: TemplateActionOptions< - { - [key in keyof TInputSchema]: z.infer>; - }, - { - [key in keyof TOutputSchema]: z.infer>; - }, + TInputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + ? { + [key in keyof TInputSchema]: z.infer>; + } + : TInputSchema extends (zImpl: typeof z) => z.ZodType + ? z.infer> + : never, + TOutputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + ? { + [key in keyof TOutputSchema]: z.infer>; + } + : TOutputSchema extends (zImpl: typeof z) => z.ZodType + ? z.infer> + : never, TInputSchema, TOutputSchema, 'v2' >, ): TemplateAction< - FlattenOptionalProperties<{ - [key in keyof TInputSchema]: z.output>; - }>, - FlattenOptionalProperties<{ - [key in keyof TOutputSchema]: z.output>; - }>, + FlattenOptionalProperties< + TInputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + ? { + [key in keyof TInputSchema]: z.output>; + } + : TInputSchema extends (zImpl: typeof z) => z.ZodType + ? z.output> + : never + >, + FlattenOptionalProperties< + TOutputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + ? { + [key in keyof TOutputSchema]: z.output< + ReturnType + >; + } + : TOutputSchema extends (zImpl: typeof z) => z.ZodType + ? z.output> + : never + >, 'v2' >; @@ -513,7 +481,7 @@ export type TaskStatus = export type TemplateAction< TActionInput extends JsonObject = JsonObject, TActionOutput extends JsonObject = JsonObject, - TSchemaType extends 'v1' | 'v2' = 'v1', + TSchemaType extends 'v2' = 'v2', > = { id: string; description?: string; @@ -536,18 +504,20 @@ export type TemplateActionOptions< TActionInput extends JsonObject = {}, TActionOutput extends JsonObject = {}, TInputSchema extends - | JsonObject - | z.ZodType | { [key in string]: (zImpl: typeof z) => z.ZodType; - } = JsonObject, + } + | ((zImpl: typeof z) => z.ZodType) = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, TOutputSchema extends - | JsonObject - | z.ZodType | { [key in string]: (zImpl: typeof z) => z.ZodType; - } = JsonObject, - TSchemaType extends 'v1' | 'v2' = 'v1' | 'v2', + } + | ((zImpl: typeof z) => z.ZodType) = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TSchemaType extends 'v2' = 'v2', > = { id: string; description?: string; diff --git a/plugins/scaffolder-node/src/actions/createTemplateAction.test.ts b/plugins/scaffolder-node/src/actions/createTemplateAction.test.ts index 43d5d2f660..c813d560cb 100644 --- a/plugins/scaffolder-node/src/actions/createTemplateAction.test.ts +++ b/plugins/scaffolder-node/src/actions/createTemplateAction.test.ts @@ -14,85 +14,8 @@ * limitations under the License. */ import { createTemplateAction } from './createTemplateAction'; -import { z } from 'zod'; describe('createTemplateAction', () => { - it('should allow creating with jsonschema and use the old deprecated types', () => { - const action = createTemplateAction<{ repoUrl: string }, { test: string }>({ - id: 'test', - schema: { - input: { - type: 'object', - required: ['repoUrl'], - properties: { - repoUrl: { type: 'string' }, - }, - }, - output: { - type: 'object', - required: ['test'], - properties: { - test: { type: 'string' }, - }, - }, - }, - handler: async ctx => { - // @ts-expect-error - repoUrl is string - const a: number = ctx.input.repoUrl; - - const b: string = ctx.input.repoUrl; - expect(b).toBeDefined(); - - const stream = ctx.logStream; - expect(stream).toBeDefined(); - - ctx.output('test', 'value'); - - // @ts-expect-error - not valid output type - ctx.output('test', 4); - - // @ts-expect-error - not valid output name - ctx.output('test2', 'value'); - }, - }); - - expect(action).toBeDefined(); - }); - - it('should allow creating with zod and use the old deprecated types', () => { - const action = createTemplateAction({ - id: 'test', - schema: { - input: z.object({ - repoUrl: z.string(), - }), - output: z.object({ - test: z.string(), - }), - }, - handler: async ctx => { - // @ts-expect-error - repoUrl is string - const a: number = ctx.input.repoUrl; - - const b: string = ctx.input.repoUrl; - expect(b).toBeDefined(); - - const stream = ctx.logStream; - expect(stream).toBeDefined(); - - ctx.output('test', 'value'); - - // @ts-expect-error - not valid output type - ctx.output('test', 4); - - // @ts-expect-error - not valid output name - ctx.output('test2', 'value'); - }, - }); - - expect(action).toBeDefined(); - }); - it('should allow creating with new first class zod support', () => { const action = createTemplateAction({ id: 'test', @@ -128,4 +51,54 @@ describe('createTemplateAction', () => { expect(action).toBeDefined(); }); + + it('should allow creating with a function for input and output schema for more complex types', () => { + const action = createTemplateAction({ + id: 'test', + schema: { + input: z => + z.union([ + z.object({ + repoUrl: z.string(), + }), + z.object({ + numberThing: z.number(), + }), + ]), + output: z => + z.object({ + test: z.string(), + }), + }, + handler: async ctx => { + ctx.output('test', 'value'); + + // @ts-expect-error - not valid output type + ctx.output('test', 4); + + // @ts-expect-error - not valid output name + ctx.output('test2', 'value'); + + if ('repoUrl' in ctx.input) { + // @ts-expect-error - not valid input type + const a: number = ctx.input.repoUrl; + + const b: string = ctx.input.repoUrl; + // eslint-disable-next-line jest/no-conditional-expect + expect(b).toBeDefined(); + } + + if ('numberThing' in ctx.input) { + const a: number = ctx.input.numberThing; + // eslint-disable-next-line jest/no-conditional-expect + expect(a).toBeDefined(); + + // @ts-expect-error - not valid input type + const b: string = ctx.input.numberThing; + } + }, + }); + + expect(action).toBeDefined(); + }); }); diff --git a/plugins/scaffolder-node/src/actions/createTemplateAction.ts b/plugins/scaffolder-node/src/actions/createTemplateAction.ts index ce38f3b4e1..edf3e203b9 100644 --- a/plugins/scaffolder-node/src/actions/createTemplateAction.ts +++ b/plugins/scaffolder-node/src/actions/createTemplateAction.ts @@ -30,14 +30,18 @@ export type TemplateActionOptions< TActionInput extends JsonObject = {}, TActionOutput extends JsonObject = {}, TInputSchema extends - | JsonObject - | z.ZodType - | { [key in string]: (zImpl: typeof z) => z.ZodType } = JsonObject, + | { [key in string]: (zImpl: typeof z) => z.ZodType } + | ((zImpl: typeof z) => z.ZodType) = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, TOutputSchema extends - | JsonObject - | z.ZodType - | { [key in string]: (zImpl: typeof z) => z.ZodType } = JsonObject, - TSchemaType extends 'v1' | 'v2' = 'v1' | 'v2', + | { + [key in string]: (zImpl: typeof z) => z.ZodType; + } + | ((zImpl: typeof z) => z.ZodType) = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TSchemaType extends 'v2' = 'v2', > = { id: string; description?: string; @@ -62,109 +66,82 @@ type FlattenOptionalProperties = Expand< [K in keyof T as undefined extends T[K] ? K : never]?: T[K]; } >; - -/** - * @public - * @deprecated migrate to using the new built in zod schema definitions for schemas - */ -export function createTemplateAction< - TInputParams extends JsonObject = JsonObject, - TOutputParams extends JsonObject = JsonObject, - TInputSchema extends JsonObject = JsonObject, - TOutputSchema extends JsonObject = JsonObject, - TActionInput extends JsonObject = TInputParams, - TActionOutput extends JsonObject = TOutputParams, ->( - action: TemplateActionOptions< - TActionInput, - TActionOutput, - TInputSchema, - TOutputSchema, - 'v1' - >, -): TemplateAction; -/** - * @public - * @deprecated migrate to using the new built in zod schema definitions for schemas - */ -export function createTemplateAction< - TInputParams extends JsonObject = JsonObject, - TOutputParams extends JsonObject = JsonObject, - TInputSchema extends z.ZodType = z.ZodType, - TOutputSchema extends z.ZodType = z.ZodType, - TActionInput extends JsonObject = z.infer, - TActionOutput extends JsonObject = z.infer, ->( - action: TemplateActionOptions< - TActionInput, - TActionOutput, - TInputSchema, - TOutputSchema, - 'v1' - >, -): TemplateAction; /** * This function is used to create new template actions to get type safety. * Will convert zod schemas to json schemas for use throughout the system. * @public */ export function createTemplateAction< - TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType }, - TOutputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType }, + TInputSchema extends + | { [key in string]: (zImpl: typeof z) => z.ZodType } + | ((zImpl: typeof z) => z.ZodType), + TOutputSchema extends + | { [key in string]: (zImpl: typeof z) => z.ZodType } + | ((zImpl: typeof z) => z.ZodType), >( action: TemplateActionOptions< - { - [key in keyof TInputSchema]: z.infer>; - }, - { - [key in keyof TOutputSchema]: z.infer>; - }, + TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } + ? { + [key in keyof TInputSchema]: z.infer>; + } + : TInputSchema extends (zImpl: typeof z) => z.ZodType + ? z.infer> + : never, + TOutputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } + ? { + [key in keyof TOutputSchema]: z.infer>; + } + : TOutputSchema extends (zImpl: typeof z) => z.ZodType + ? z.infer> + : never, TInputSchema, TOutputSchema, 'v2' >, ): TemplateAction< - FlattenOptionalProperties<{ - [key in keyof TInputSchema]: z.output>; - }>, - FlattenOptionalProperties<{ - [key in keyof TOutputSchema]: z.output>; - }>, + FlattenOptionalProperties< + TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } + ? { + [key in keyof TInputSchema]: z.output>; + } + : TInputSchema extends (zImpl: typeof z) => z.ZodType + ? z.output> + : never + >, + FlattenOptionalProperties< + TOutputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } + ? { + [key in keyof TOutputSchema]: z.output< + ReturnType + >; + } + : TOutputSchema extends (zImpl: typeof z) => z.ZodType + ? z.output> + : never + >, 'v2' >; export function createTemplateAction< - TInputParams extends JsonObject = JsonObject, - TOutputParams extends JsonObject = JsonObject, - TInputSchema extends - | JsonObject - | z.ZodType - | { [key in string]: (zImpl: typeof z) => z.ZodType } = JsonObject, - TOutputSchema extends - | JsonObject - | z.ZodType - | { [key in string]: (zImpl: typeof z) => z.ZodType } = JsonObject, - TActionInput extends JsonObject = TInputSchema extends z.ZodType< - any, - any, - infer IReturn - > - ? IReturn - : TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } + TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TOutputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TActionInput extends JsonObject = TInputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } ? Expand<{ [key in keyof TInputSchema]: z.infer>; }> - : TInputParams, - TActionOutput extends JsonObject = TOutputSchema extends z.ZodType< - any, - any, - infer IReturn - > - ? IReturn - : TOutputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } + : never, + TActionOutput extends JsonObject = TOutputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } ? Expand<{ [key in keyof TOutputSchema]: z.infer>; }> - : TOutputParams, + : never, >( action: TemplateActionOptions< TActionInput, @@ -172,13 +149,7 @@ export function createTemplateAction< TInputSchema, TOutputSchema >, -): TemplateAction< - TActionInput, - TActionOutput, - TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } - ? 'v2' - : 'v1' -> { +): TemplateAction { const { inputSchema, outputSchema } = parseSchemas( action as TemplateActionOptions, ); diff --git a/plugins/scaffolder-node/src/actions/types.ts b/plugins/scaffolder-node/src/actions/types.ts index 92a2c7464a..f13d256332 100644 --- a/plugins/scaffolder-node/src/actions/types.ts +++ b/plugins/scaffolder-node/src/actions/types.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import { Logger } from 'winston'; -import { Writable } from 'stream'; import { JsonObject, JsonValue } from '@backstage/types'; import { TaskSecrets } from '../tasks'; import { TemplateInfo } from '@backstage/plugin-scaffolder-common'; @@ -32,143 +30,75 @@ import { export type ActionContext< TActionInput extends JsonObject, TActionOutput extends JsonObject = JsonObject, - TSchemaType extends 'v1' | 'v2' = 'v1', -> = TSchemaType extends 'v2' - ? { - logger: LoggerService; - secrets?: TaskSecrets; - workspacePath: string; - input: TActionInput; - checkpoint(opts: { - key: string; - fn: () => Promise | T; - }): Promise; - output( - name: keyof TActionOutput, - value: TActionOutput[keyof TActionOutput], - ): void; - /** - * Creates a temporary directory for use by the action, which is then cleaned up automatically. - */ - createTemporaryDirectory(): Promise; + _TSchemaType extends 'v2' = 'v2', +> = { + logger: LoggerService; + secrets?: TaskSecrets; + workspacePath: string; + input: TActionInput; + checkpoint(opts: { + key: string; + fn: () => Promise | T; + }): Promise; + output( + name: keyof TActionOutput, + value: TActionOutput[keyof TActionOutput], + ): void; + /** + * Creates a temporary directory for use by the action, which is then cleaned up automatically. + */ + createTemporaryDirectory(): Promise; - /** - * Get the credentials for the current request - */ - getInitiatorCredentials(): Promise; + /** + * Get the credentials for the current request + */ + getInitiatorCredentials(): Promise; - /** - * Task information - */ - task: { - id: string; - }; + /** + * Task information + */ + task: { + id: string; + }; - templateInfo?: TemplateInfo; + templateInfo?: TemplateInfo; - /** - * Whether this action invocation is a dry-run or not. - * This will only ever be true if the actions as marked as supporting dry-runs. - */ - isDryRun?: boolean; + /** + * Whether this action invocation is a dry-run or not. + * This will only ever be true if the actions as marked as supporting dry-runs. + */ + isDryRun?: boolean; - /** - * The user which triggered the action. - */ - user?: { - /** - * The decorated entity from the Catalog - */ - entity?: UserEntity; - /** - * An entity ref for the author of the task - */ - ref?: string; - }; + /** + * The user which triggered the action. + */ + user?: { + /** + * The decorated entity from the Catalog + */ + entity?: UserEntity; + /** + * An entity ref for the author of the task + */ + ref?: string; + }; - /** - * Implement the signal to make your custom step abortable https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal - */ - signal?: AbortSignal; + /** + * Implement the signal to make your custom step abortable https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal + */ + signal?: AbortSignal; - /** - * Optional value of each invocation - */ - each?: JsonObject; - } - : /** @deprecated **/ - { - // TODO(blam): move this to LoggerService - logger: Logger; - /** @deprecated - use `ctx.logger` instead */ - logStream: Writable; - secrets?: TaskSecrets; - workspacePath: string; - input: TActionInput; - checkpoint(opts: { - key: string; - fn: () => Promise | T; - }): Promise; - output( - name: keyof TActionOutput, - value: TActionOutput[keyof TActionOutput], - ): void; - - /** - * Creates a temporary directory for use by the action, which is then cleaned up automatically. - */ - createTemporaryDirectory(): Promise; - - /** - * Get the credentials for the current request - */ - getInitiatorCredentials(): Promise; - - /** - * Task information - */ - task: { - id: string; - }; - - templateInfo?: TemplateInfo; - - /** - * Whether this action invocation is a dry-run or not. - * This will only ever be true if the actions as marked as supporting dry-runs. - */ - isDryRun?: boolean; - - /** - * The user which triggered the action. - */ - user?: { - /** - * The decorated entity from the Catalog - */ - entity?: UserEntity; - /** - * An entity ref for the author of the task - */ - ref?: string; - }; - - /** - * Implement the signal to make your custom step abortable https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal - */ - signal?: AbortSignal; - - /** - * Optional value of each invocation - */ - each?: JsonObject; - }; + /** + * Optional value of each invocation + */ + each?: JsonObject; +}; /** @public */ export type TemplateAction< TActionInput extends JsonObject = JsonObject, TActionOutput extends JsonObject = JsonObject, - TSchemaType extends 'v1' | 'v2' = 'v1', + TSchemaType extends 'v2' = 'v2', > = { id: string; description?: string; diff --git a/plugins/scaffolder-node/src/actions/util.ts b/plugins/scaffolder-node/src/actions/util.ts index 57141e9c24..34cc74c811 100644 --- a/plugins/scaffolder-node/src/actions/util.ts +++ b/plugins/scaffolder-node/src/actions/util.ts @@ -130,11 +130,7 @@ function checkRequiredParams(repoUrl: URL, ...params: string[]) { } } -const isZodSchema = (schema: unknown): schema is z.ZodType => { - return typeof schema === 'object' && !!schema && 'safeParseAsync' in schema; -}; - -const isNativeZodSchema = ( +const isKeyValueZodCallback = ( schema: unknown, ): schema is { [key in string]: (zImpl: typeof z) => z.ZodType } => { return ( @@ -144,23 +140,20 @@ const isNativeZodSchema = ( ); }; +const isZodFunctionDefinition = ( + schema: unknown, +): schema is (zImpl: typeof z) => z.ZodType => { + return typeof schema === 'function'; +}; + export const parseSchemas = ( - action: TemplateActionOptions, + action: TemplateActionOptions, ): { inputSchema?: Schema; outputSchema?: Schema } => { if (!action.schema) { return { inputSchema: undefined, outputSchema: undefined }; } - if (isZodSchema(action.schema.input)) { - return { - inputSchema: zodToJsonSchema(action.schema.input) as Schema, - outputSchema: isZodSchema(action.schema.output) - ? (zodToJsonSchema(action.schema.output) as Schema) - : undefined, - }; - } - - if (isNativeZodSchema(action.schema.input)) { + if (isKeyValueZodCallback(action.schema.input)) { const input = z.object( Object.fromEntries( Object.entries(action.schema.input).map(([k, v]) => [k, v(z)]), @@ -169,7 +162,7 @@ export const parseSchemas = ( return { inputSchema: zodToJsonSchema(input) as Schema, - outputSchema: isNativeZodSchema(action.schema.output) + outputSchema: isKeyValueZodCallback(action.schema.output) ? (zodToJsonSchema( z.object( Object.fromEntries( @@ -181,9 +174,18 @@ export const parseSchemas = ( }; } + if (isZodFunctionDefinition(action.schema.input)) { + return { + inputSchema: zodToJsonSchema(action.schema.input(z)) as Schema, + outputSchema: isZodFunctionDefinition(action.schema.output) + ? (zodToJsonSchema(action.schema.output(z)) as Schema) + : undefined, + }; + } + return { - inputSchema: action.schema.input, - outputSchema: action.schema.output, + inputSchema: undefined, + outputSchema: undefined, }; };