Skip to content

Commit

Permalink
fix: remove/filter old args before action execution
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgrittner committed Oct 7, 2024
1 parent 46bad23 commit 6437140
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 2 deletions.
4 changes: 4 additions & 0 deletions admyral/action_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def get(cls, type_name: str) -> Action:
raise ValueError(f"Action with type '{type_name}' does not exist")
return cls._actions[type_name]

@classmethod
def get_or_none(cls, type_name: str) -> Action | None:
return cls._actions.get(type_name)

@classmethod
def is_registered(cls, type_name: str) -> bool:
return type_name in cls._actions
Expand Down
8 changes: 8 additions & 0 deletions admyral/workers/python_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ async def execute_python_action(action_type: str, action_args: dict[str, Any]) -
f"Action with type '{action_type}' not found. Did you push your action?"
)

# filter action_args based on action arguments
# Why filter action_args? Because an action might have been updated,
# i.e., an argument might have been removed. This would cause the
# function call to fail. Hence, we filter the arguments to only include
# the ones that are actually defined by the action.
defined_args = set(map(lambda arg: arg.arg_name, python_action.arguments))
action_args = {k: v for k, v in action_args.items() if k in defined_args}

with tempfile.TemporaryDirectory() as job_dir:
logger.info(f"Job directory: {job_dir}")

Expand Down
14 changes: 13 additions & 1 deletion admyral/workers/workflow_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,11 @@ async def _execute_action_node(

action_type = node.type

if action_type not in ActionRegistry.get_action_types():
action = ActionRegistry.get_or_none(action_type)
if not action:
# Custom Python action
# Note: we filter the action_args in execute_python_action
# because first need to fetch the custom action.
return await _execute_activity(
"execute_python_action",
args=[
Expand All @@ -270,6 +273,15 @@ async def _execute_action_node(
{"action_type": action_type, "action_args": action_args},
],
)

# filter action_args based on action arguments
# Why filter action_args? Because an action might have been updated,
# i.e., an argument might have been removed. This would cause the
# function call to fail. Hence, we filter the arguments to only include
# the ones that are actually defined by the action.
defined_args = set(map(lambda arg: arg.arg_name, action.arguments))
action_args = {k: v for k, v in action_args.items() if k in defined_args}

return await _execute_activity(
action_type,
args=[ctx_dict, node.secrets_mapping, action_args],
Expand Down
40 changes: 39 additions & 1 deletion web/src/components/save-workflow-button/save-workflow-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import { useWorkflowStore } from "@/stores/workflow-store";
import { useEffect } from "react";
import { errorToast, infoToast } from "@/lib/toast";
import { AxiosError } from "axios";
import { useEditorActionStore } from "@/stores/editor-action-store";
import { EditorWorkflowNodeType } from "@/types/react-flow";

const SPACE = " ";

export default function SaveWorkflowButton() {
const { getWorkflow, updateWebhookIdAndSecret } = useWorkflowStore();
const { actionsIndex } = useEditorActionStore();
const saveWorkflow = useSaveWorkflowApi();

useEffect(() => {
Expand Down Expand Up @@ -43,6 +46,10 @@ export default function SaveWorkflowButton() {

const handleSaveWorkflow = () => {
const workflow = getWorkflow();
if (Object.keys(actionsIndex).length === 0) {
errorToast("Editor actions must be loaded to save the workflow.");
return;
}
if (workflow.workflowName.length === 0) {
errorToast(
"Workflow name must not be empty. Go to settings to set one.",
Expand All @@ -53,7 +60,38 @@ export default function SaveWorkflowButton() {
errorToast("Workflow name must not contain empty spaces.");
return;
}
saveWorkflow.mutate(workflow);

// Make sure that we only save args which are present in the current
// action definition. If an action is updated and an argument is
// removed, we want to clean it up here.
const nodes = workflow.nodes.map((node) => {
if (node.type === EditorWorkflowNodeType.ACTION) {
const argsFilter = new Set(
actionsIndex[node.actionType].arguments.map(
(arg) => arg.argName,
),
);
const args = Object.keys(node.args)
.filter((argName) => argsFilter.has(argName))
.reduce(
(acc, argName) => {
acc[argName] = node.args[argName];
return acc;
},
{} as Record<string, string>,
);
return {
...node,
args,
};
}
return node;
});

saveWorkflow.mutate({
...workflow,
nodes,
});
};

return (
Expand Down

0 comments on commit 6437140

Please sign in to comment.