Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import {Accordion} from '@/components/ui/accordion';
import {ResizableHandle, ResizablePanel, ResizablePanelGroup} from '@/components/ui/resizable';
import {ScrollArea} from '@/components/ui/scroll-area';
import {useCopilotStore} from '@/shared/components/copilot/stores/useCopilotStore';
import WorkflowExecutionsHeader from '@/shared/components/workflow-executions/WorkflowExecutionsHeader';
import WorkflowExecutionsTabsPanel from '@/shared/components/workflow-executions/WorkflowExecutionsTabsPanel';
import WorkflowExecutionsTaskAccordionItem from '@/shared/components/workflow-executions/WorkflowExecutionsTaskAccordionItem';
import WorkflowExecutionsTriggerAccordionItem from '@/shared/components/workflow-executions/WorkflowExecutionsTriggerAccordionItem';
import {getInitialSelectedItem, getTasksTree} from '@/shared/components/workflow-executions/WorkflowExecutionsUtils';
import {
getErrorItem,
getInitialSelectedItem,
getTasksTree,
} from '@/shared/components/workflow-executions/WorkflowExecutionsUtils';
import {TaskExecution, TriggerExecution} from '@/shared/middleware/platform/workflow/execution';
import {WorkflowTestExecution} from '@/shared/middleware/platform/workflow/test';
import {ChevronDownIcon, RefreshCwIcon, RefreshCwOffIcon} from 'lucide-react';
Expand All @@ -28,6 +33,8 @@ const WorkflowExecutionsTestOutput = ({
getInitialSelectedItem(workflowTestExecution)
);

const setWorkflowExecutionError = useCopilotStore((state) => state.setWorkflowExecutionError);

const job = workflowTestExecution?.job;
const triggerExecution = workflowTestExecution?.triggerExecution;

Expand All @@ -36,6 +43,22 @@ const WorkflowExecutionsTestOutput = ({
setActiveTab('input');
}, [workflowTestExecution]);

// Set workflow execution error in copilot store when an error exists
useEffect(() => {
const errorItem = getErrorItem(workflowTestExecution);

if (errorItem?.error) {
setWorkflowExecutionError({
errorMessage: errorItem.error.message,
stackTrace: errorItem.error.stackTrace,
title: errorItem.title,
});
} else {
// Clear error when workflow succeeds
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nepotreban komentar

setWorkflowExecutionError(undefined);
}
}, [workflowTestExecution, setWorkflowExecutionError]);

const tasksTree = useMemo(() => (job ? getTasksTree(job) : []), [job]);

const onTaskClick = useCallback((taskExecution: TaskExecution | TriggerExecution) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,14 @@ export const useWorkflowLayout = (includeComponents?: string[]) => {
};

const handleCopilotClick = () => {
setContext({mode: MODE.ASK, parameters: {}, source: Source.WORKFLOW_EDITOR});
const currentContext = useCopilotStore.getState().context;

setContext({
...currentContext,
mode: MODE.ASK,
parameters: {},
source: Source.WORKFLOW_EDITOR,
});

if (!copilotPanelOpen) {
setCopilotPanelOpen(!copilotPanelOpen);
Expand Down
9 changes: 8 additions & 1 deletion client/src/shared/components/copilot/CopilotButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ const CopilotButton = ({parameters = {}, source}: CopilotButtonProps) => {
const ff_1570 = useFeatureFlagsStore()('ff-1570');

const handleClick = () => {
setContext({mode: MODE.ASK, parameters, source});
const currentContext = useCopilotStore.getState().context;

setContext({
...currentContext,
mode: MODE.ASK,
parameters,
source,
});

if (!copilotPanelOpen) {
setCopilotPanelOpen(!copilotPanelOpen);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export function CopilotRuntimeProvider({
agent.setState({
...context,
currentSelectedNode: currentComponent?.name,
workflowExecutionError: context.taskExecutionError,
workflowId: workflow.id,
});

Expand Down
27 changes: 27 additions & 0 deletions client/src/shared/components/copilot/stores/useCopilotStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export type ContextType = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
parameters: Record<string, any>;
mode: MODE;
taskExecutionError?: {
errorMessage?: string;
stackTrace?: string[];
title?: string;
};
};

interface CopilotStateI {
Expand All @@ -28,6 +33,15 @@ interface CopilotStateI {

context: ContextType;
setContext: (context: ContextType | undefined) => void;
setWorkflowExecutionError: (
workflowExecutionError:
| {
errorMessage?: string;
stackTrace?: string[];
title?: string;
}
| undefined
) => void;

copilotPanelOpen: boolean;
setCopilotPanelOpen: (showCopilot: boolean) => void;
Expand All @@ -54,7 +68,10 @@ export const useCopilotStore = create<CopilotStateI>()(
},

context: {
source: Source.WORKFLOW_EDITOR,
parameters: {},
mode: MODE.ASK,
workflowExecutionError: undefined,
},
setContext: (context) =>
set((state) => {
Expand All @@ -63,6 +80,16 @@ export const useCopilotStore = create<CopilotStateI>()(
context,
};
}),
setWorkflowExecutionError: (error) =>
set((state) => {
return {
...state,
context: {
...state.context,
taskExecutionError: error,
},
};
}),

copilotPanelOpen: false,
setCopilotPanelOpen: (copilotPanelOpen) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ export const getFilteredOutput = (
return output;
};

export const getErrorItem = (
workflowTestExecution?: WorkflowTestExecution
): TaskExecution | TriggerExecution | undefined => {
if (!workflowTestExecution) return undefined;

if (workflowTestExecution.triggerExecution && workflowTestExecution.triggerExecution.error) {
return workflowTestExecution.triggerExecution;
}

const failedTask = workflowTestExecution.job?.taskExecutions?.find((task) => task.error && 'workflowTask' in task);

if (failedTask) {
return failedTask;
}

return undefined;
};

export const getInitialSelectedItem = (
workflowTestExecution?: WorkflowTestExecution
): TaskExecution | TriggerExecution | undefined => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class WorkflowEditorSpringAIAgent extends SpringAIAgent {
- When operating in ASK mode, the assistant must not modify, propose modifications to, or generate new versions of the workflow definition. The assistant may only describe, clarify, or explain.
- If a current selected node is available, the assistant must prioritize all answers using that node as the primary context.
- If no node is selected, the assistant must use the broader workflow context as the primary basis for responses.
- If state.workflowExecutionError is not empty, there is an error and you must instruct the user on how to fix it. The user can't modify the code, only the input parameters. If it's impossible to fix the error, instruct the user to raise an issue on our GitHub https://github.com/bytechefhq/bytechef/issues.
""";

private final WorkflowService workflowService;
Expand Down
Loading