-
Notifications
You must be signed in to change notification settings - Fork 10
fix(workflow-executor): preserve AI suggestion in pending data #1586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Tonours
wants to merge
5
commits into
feat/prd-214-server-step-mapper
Choose a base branch
from
fix/workflow-executor-preserve-ai-suggestion-in-pending-data
base: feat/prd-214-server-step-mapper
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
d58877a
fix(workflow-executor): preserve AI suggestion in pending data
Tonours 270ecf0
refactor(workflow-executor): type userConfirmation precisely per step…
df8e7a9
fix(workflow-executor): reject name override without selectedRecordId…
86d20c8
style(workflow-executor): fix prettier formatting in step-execution-d…
96808c0
fix(workflow-executor): reject empty string name and fix refine condi…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
109 changes: 64 additions & 45 deletions
109
packages/workflow-executor/src/http/pending-data-validators.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,53 +1,72 @@ | ||
| import type { StepExecutionData } from '../types/step-execution-data'; | ||
|
|
||
| import { z } from 'zod'; | ||
|
|
||
| // Per-step-type schemas for the `pendingData` payload sent by the front via | ||
| // POST /runs/:runId/trigger. Consumed by step executors to validate `incomingPendingData` | ||
| // before applying user confirmation or override. Schemas use .strict() to reject unknown fields. | ||
| const patchBodySchemas: Partial<Record<StepExecutionData['type'], z.ZodTypeAny>> = { | ||
| 'update-record': z | ||
| .object({ | ||
| userConfirmed: z.boolean(), | ||
| value: z.string().optional(), // user may override the AI-proposed value | ||
| }) | ||
| .strict(), | ||
|
|
||
| 'trigger-action': z | ||
| .object({ | ||
| userConfirmed: z.boolean(), | ||
| // Opaque action result from the frontend. Required when userConfirmed=true; the | ||
| // presence check lives in the step-executor so a descriptive StepStateError can | ||
| // name the runId/stepIndex — not achievable from inside a zod schema. | ||
| actionResult: z.unknown().optional(), | ||
| }) | ||
| .strict(), | ||
|
|
||
| mcp: z.object({ userConfirmed: z.boolean() }).strict(), | ||
|
|
||
| 'load-related-record': z | ||
| .object({ | ||
| userConfirmed: z.boolean(), | ||
| // User may intentionally switch to a different relation than the one the AI selected. | ||
| // The executor re-derives relatedCollectionName from FieldSchema when processing the confirmation. | ||
| name: z.string().optional(), | ||
| displayName: z.string().optional(), | ||
| // User may override the AI-selected record; must be non-empty when provided. | ||
| selectedRecordId: z | ||
| .array(z.union([z.string(), z.number()])) | ||
| .min(1) | ||
| .optional(), | ||
| }) | ||
| .strict(), | ||
| // relatedCollectionName and suggestedFields are NOT accepted — internal executor data. | ||
|
|
||
| guidance: z | ||
| .object({ | ||
| userInput: z.string().optional(), | ||
| }) | ||
| .strict(), | ||
|
|
||
| condition: z.object({ selectedOption: z.string() }).strict(), | ||
|
|
||
| const updateRecordPatchSchema = z | ||
| .object({ | ||
| userConfirmed: z.boolean(), | ||
| value: z.string().optional(), // user may override the AI-proposed value | ||
| }) | ||
| .strict(); | ||
|
|
||
| const triggerActionPatchSchema = z | ||
| .object({ | ||
| userConfirmed: z.boolean(), | ||
| // Opaque action result from the frontend. Required when userConfirmed=true; the | ||
| // presence check lives in the step-executor so a descriptive StepStateError can | ||
| // name the runId/stepIndex — not achievable from inside a zod schema. | ||
| actionResult: z.unknown().optional(), | ||
| }) | ||
| .strict(); | ||
|
|
||
| const mcpPatchSchema = z.object({ userConfirmed: z.boolean() }).strict(); | ||
|
|
||
| const loadRelatedRecordPatchSchema = z | ||
| .object({ | ||
| userConfirmed: z.boolean(), | ||
| // User may intentionally switch to a different relation than the one the AI selected. | ||
| // The executor re-derives relatedCollectionName and displayName from FieldSchema when | ||
| // processing the confirmation. | ||
| name: z.string().min(1).optional(), | ||
| // User may override the AI-selected record; must be non-empty when provided. | ||
| // Required when overriding the relation name — the original record ID belongs to a | ||
| // different collection and cannot be reused for the new relation. | ||
| selectedRecordId: z | ||
| .array(z.union([z.string(), z.number()])) | ||
| .min(1) | ||
| .optional(), | ||
| }) | ||
| .strict() | ||
| .refine(data => data.name === undefined || data.selectedRecordId !== undefined, { | ||
| message: 'selectedRecordId is required when overriding the relation name', | ||
| }); | ||
| // relatedCollectionName, displayName and suggestedFields are NOT accepted — internal executor data. | ||
|
|
||
| const guidancePatchSchema = z | ||
| .object({ | ||
| userInput: z.string().optional(), | ||
| }) | ||
| .strict(); | ||
|
|
||
| const conditionPatchSchema = z.object({ selectedOption: z.string() }).strict(); | ||
|
|
||
| // Inferred types — consumed by step-execution-data.ts to type `userConfirmation` precisely, | ||
| // removing the need for runtime type guards in executors. | ||
| export type UpdateRecordConfirmation = z.infer<typeof updateRecordPatchSchema>; | ||
| export type TriggerActionConfirmation = z.infer<typeof triggerActionPatchSchema>; | ||
| export type McpConfirmation = z.infer<typeof mcpPatchSchema>; | ||
| export type LoadRelatedRecordConfirmation = z.infer<typeof loadRelatedRecordPatchSchema>; | ||
| export type GuidanceConfirmation = z.infer<typeof guidancePatchSchema>; | ||
|
|
||
| const patchBodySchemas: Partial<Record<string, z.ZodTypeAny>> = { | ||
| 'update-record': updateRecordPatchSchema, | ||
| 'trigger-action': triggerActionPatchSchema, | ||
| mcp: mcpPatchSchema, | ||
| 'load-related-record': loadRelatedRecordPatchSchema, | ||
| guidance: guidancePatchSchema, | ||
| condition: conditionPatchSchema, | ||
| }; | ||
|
|
||
| export default patchBodySchemas; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.