Skip to content
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

Execute variables in action input #7715

Merged
merged 5 commits into from
Oct 16, 2024
Merged

Conversation

thomtrp
Copy link
Contributor

@thomtrp thomtrp commented Oct 15, 2024

  • send context from all previous steps rather than unique payload
  • wrap input data in settings into input field
  • add email into send email action settings
  • update output shape
Capture d’écran 2024-10-15 à 15 21 32 Capture d’écran 2024-10-15 à 15 20 09

@thomtrp thomtrp changed the title Use context in workflows rather than payload Execute variables in action input Oct 15, 2024
@thomtrp thomtrp force-pushed the tt-execute-variable-in-workflow branch 2 times, most recently from 48367c5 to 126dcea Compare October 15, 2024 13:28
@thomtrp thomtrp marked this pull request as ready for review October 15, 2024 13:29
Copy link
Contributor

@martmull martmull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, good job, some comments

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

This pull request introduces significant changes to the workflow execution process, focusing on variable handling and input structure for workflow actions. Here's a concise summary of the major changes:

  • Restructured workflow step settings to wrap input data in an 'input' field for both code and email actions
  • Added email field to send email action settings for improved flexibility
  • Implemented variable resolution using Handlebars templating for dynamic content in action inputs
  • Updated workflow execution to use a context object containing data from all previous steps
  • Modified workflow run output structure to track multiple execution attempts per step
  • Introduced a new variable resolver utility for handling different input types and error scenarios

Key points to consider:

  • The changes may require updates to existing code that relies on the previous input structure
  • New error handling for variable evaluation failures has been added
  • The modifications aim to enhance flexibility and tracking in workflow execution

20 file(s) reviewed, 25 comment(s)
Edit PR Review Bot Settings | Greptile

Copy link
Contributor

@Devessier Devessier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, @thomtrp! I left some comments to discuss a few things in your implementation. That looks great! 😉

attemptCount: number;
result: object | undefined;
error: string | undefined;
}[];
};

export type WorkflowRunOutput = {
steps: Record<string, StepRunOutput>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The consequence of storing the output of the steps in an object is that their order is not guaranteed to be preserved. That's not an issue on its own, but the frontend will have to fetch the steps definition to print the output in order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. In V1, the frontend may have to re-order the output if we go with the figma. But most likely, we will end with a drawer and each step will look for its output. That's where a map with the step id as key will be useful!

}: {
step: WorkflowStep;
payload?: object;
context?: Record<string, any>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like to use unknown instead of any when I don't know the data type that will be there. It forces me to type-check it explicitly later.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we might want to create a specific type for the context so we can reuse it easily.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use Record<string, any> in a lot of places actually. This is because we do not know the shape of the objects. And same goes for context, since it could contain anything. Not sure what specific type we would create...

About the unknown you are right, I updated the code 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect for unknown 👌
I wasn't clear, but I meant that we could create a WorkflowStepInputContext type or another name not to repeat Record<string, unknown> many times.

const VARIABLE_PATTERN = RegExp('\\{\\{(.*?)\\}\\}', 'g');

export const resolve = (
unresolvedInput: any,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible for us to predict a more specific type for the unresolvedInput parameter? If it's not, I would use unknown to be forced to explicitly check the type of the arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope as explained above. So using unknown!

Comment on lines +55 to +81
return input.replace(VARIABLE_PATTERN, (matchedToken, _) => {
const processedToken = evalFromContext(matchedToken, context);

return processedToken;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't we redoing the job of Handlebars here? Couldn't we call evalFromContext on the whole input string and let Handlebars replace the variables? i might misunderstand something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to focus on variables only there. Giving the whole string to handlebars can make it translate pretty much anything. See different templates here https://handlebarsjs.com/guide/#nested-input-objects

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Having loops and conditions might be interesting when writing the body of the email, though!

@thomtrp thomtrp force-pushed the tt-execute-variable-in-workflow branch 3 times, most recently from 9dc1752 to 0906d12 Compare October 15, 2024 16:52
Copy link
Contributor

@martmull martmull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small comment about naming and typing but LGTM though. Nice work!

step: WorkflowStep;
payload?: object;
}): Promise<WorkflowActionResult>;
execute(payload: unknown): Promise<WorkflowActionResult>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • we know that payload is at least an object isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot be sure. The step could have an input null. Or the inferred variables could provide anything

step: WorkflowCodeStep;
payload?: object;
}): Promise<WorkflowActionResult> {
async execute(payload: WorkflowCodeStepInput): Promise<WorkflowActionResult> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

payload might not be the proper naming finally. What about workflowStepInput or actionInput or just input?

Copy link
Contributor Author

@thomtrp thomtrp Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will go with workflowStepInput there!

it('should throw an error for invalid expressions', () => {
expect(() => resolveInput('{{invalidFunction()}}', context)).toThrow();
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

@Devessier Devessier self-requested a review October 16, 2024 08:42
Copy link
Contributor

@Devessier Devessier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job, @thomtrp, as usual! We can merge.

Comment on lines +55 to +81
return input.replace(VARIABLE_PATTERN, (matchedToken, _) => {
const processedToken = evalFromContext(matchedToken, context);

return processedToken;
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Having loops and conditions might be interesting when writing the body of the email, though!

@thomtrp thomtrp force-pushed the tt-execute-variable-in-workflow branch from c42303c to a72ebcc Compare October 16, 2024 12:16
@thomtrp thomtrp merged commit e811bae into main Oct 16, 2024
16 checks passed
@thomtrp thomtrp deleted the tt-execute-variable-in-workflow branch October 16, 2024 12:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants