From 67b841e646e6a97d269d5aee55dd16fee1c93f9d Mon Sep 17 00:00:00 2001 From: aboutphilippe Date: Fri, 28 Mar 2025 13:35:36 +0530 Subject: [PATCH 1/7] lint --- .../apps/backend/src/agents/chat.ts | 4 +- .../apps/backend/src/functions/llmChat.ts | 53 ++++++------ .../apps/backend/src/functions/stream.ts | 80 ------------------- .../apps/frontend/app/api/chat/route.ts | 42 ++-------- .../frontend/components/agent-builder.tsx | 1 - .../apps/frontend/components/agent-chat.tsx | 24 +++--- .../frontend/components/flow/baseEdge.tsx | 2 +- .../frontend/components/flow/defaultNode.tsx | 4 +- .../frontend/components/flow/nodeHeader.tsx | 5 +- .../frontend/components/flow/workflowEdge.tsx | 27 +------ .../frontend/components/workflow-selector.tsx | 2 +- 11 files changed, 56 insertions(+), 188 deletions(-) delete mode 100644 agent-reactflow/apps/backend/src/functions/stream.ts diff --git a/agent-reactflow/apps/backend/src/agents/chat.ts b/agent-reactflow/apps/backend/src/agents/chat.ts index 2b8f60e..1d2d39e 100644 --- a/agent-reactflow/apps/backend/src/agents/chat.ts +++ b/agent-reactflow/apps/backend/src/agents/chat.ts @@ -4,7 +4,6 @@ import { condition, log, step, - sleep, } from "@restackio/ai/agent"; import * as functions from "../functions"; @@ -19,9 +18,10 @@ export async function agentChat(): Promise { let endReceived = false; let messages: functions.Message[] = []; - onEvent(messagesEvent, async ({ messages, stream = true }: { messages: functions.Message[], stream?: boolean }) => { + onEvent(messagesEvent, async ({ messages, tools, stream = true }: { messages: functions.Message[], tools: any, stream?: boolean }) => { const result = await step({}).llmChat({ messages, + tools, stream }); messages.push(result); diff --git a/agent-reactflow/apps/backend/src/functions/llmChat.ts b/agent-reactflow/apps/backend/src/functions/llmChat.ts index e31e3f8..2afbe2b 100644 --- a/agent-reactflow/apps/backend/src/functions/llmChat.ts +++ b/agent-reactflow/apps/backend/src/functions/llmChat.ts @@ -1,10 +1,8 @@ -import { FunctionFailure, log } from "@restackio/ai/function"; -import { ChatCompletionCreateParamsNonStreaming, ChatCompletionCreateParamsStreaming, ChatCompletionTool } from "openai/resources/chat/completions"; +import { FunctionFailure, log, streamToWebsocket } from "@restackio/ai/function"; +import { ChatCompletionCreateParamsNonStreaming, ChatCompletionCreateParamsStreaming } from "openai/resources/chat/completions"; import { openaiClient } from "../utils/client"; import { apiAddress } from "../client"; -import { streamToWebsocket } from "./stream"; -import z from "zod"; export type Message = { role: "system" | "user" | "assistant"; @@ -16,6 +14,7 @@ export type OpenAIChatInput = { model?: string; messages: Message[]; stream?: boolean; + tools?: any; }; export const llmChat = async ({ @@ -23,6 +22,7 @@ export const llmChat = async ({ model = "gpt-4o-mini", messages, stream = true, + tools, }: OpenAIChatInput): Promise => { try { const openai = openaiClient({}); @@ -36,28 +36,29 @@ export const llmChat = async ({ : []), ...(messages ?? []), ], - tools: [ - { - type: "function", - function: { - name: "reactflow", - description: "Update flow", - parameters: { - type: "object", - properties: { - flow: { - type: "object", - description: "The json object of the flow to update" - } - }, - required: [ - "flow" - ], - additionalProperties: false, - }, - }, - }, - ], + tools, + // tools: [ + // { + // type: "function", + // function: { + // name: "reactflow", + // description: "Update flow", + // parameters: { + // type: "object", + // properties: { + // flow: { + // type: "object", + // description: "The json object of the flow to update" + // } + // }, + // required: [ + // "flow" + // ], + // additionalProperties: false, + // }, + // }, + // }, + // ], model, stream, }; diff --git a/agent-reactflow/apps/backend/src/functions/stream.ts b/agent-reactflow/apps/backend/src/functions/stream.ts deleted file mode 100644 index 5f25656..0000000 --- a/agent-reactflow/apps/backend/src/functions/stream.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { FunctionFailure, log, functionInfo, heartbeat } from "@restackio/ai/function"; -import WebSocket from "ws"; - -export async function streamToWebsocket({ - apiAddress = "localhost:9233", - data, -}: { - apiAddress?: string; - data: any; -}): Promise { - // Get workflow info from the current context - - const infoObj = { - activityId: functionInfo().activityId, - workflowId: functionInfo().workflowExecution.workflowId, - runId: functionInfo().workflowExecution.runId, - activityType: functionInfo().activityType, - taskQueue: functionInfo().taskQueue, - }; - - // Determine the protocol based on the provided API address - const protocol = apiAddress?.startsWith("localhost") ? "ws" : "wss"; - const websocketUrl = `${protocol}://${apiAddress}/stream/ws/agent?agentId=${functionInfo().workflowExecution.workflowId}&runId=${functionInfo().workflowExecution.runId}`; - - let ws: WebSocket | null = null; - let collectedMessages = ""; - - log.debug("Stream to websocket", { websocketUrl }); - - try { - // Open the WebSocket connection - try { - ws = new WebSocket(websocketUrl); - } catch (error: any) { - throw FunctionFailure.nonRetryable("Error restack stream websocket connection:", error?.message || error); - } - await new Promise((resolve, reject) => { - ws!.onopen = () => resolve(); - ws!.onerror = (err: any) => reject(err); - }); - - heartbeat(infoObj); - - log.info("data", data); - - // For asynchronous iteration - for await (const chunk of data) { - log.debug("Stream chunk", { chunk }); - const rawChunkJson = JSON.stringify(chunk); - heartbeat(rawChunkJson); - ws.send(rawChunkJson); - // Attempt to extract content from the chunk if using OpenAI-like stream responses - if ( - chunk && - Array.isArray(chunk.choices) && - chunk.choices.length > 0 && - chunk.choices[0].delta && - typeof chunk.choices[0].delta.content === "string" - ) { - collectedMessages += chunk.choices[0].delta.content; - } - } - - return collectedMessages; - } catch (error: any) { - const errorMessage = `Error with restack stream to websocket: ${error?.message || error}`; - log.error(errorMessage, { error }); - throw new FunctionFailure(errorMessage); - } finally { - // Ensure the WebSocket connection is closed properly - if (ws && ws.readyState === WebSocket.OPEN) { - try { - ws.send("[DONE]"); - ws.close(); - } catch (closeError) { - log.error("Error while closing websocket", { error: closeError }); - } - } - } -} \ No newline at end of file diff --git a/agent-reactflow/apps/frontend/app/api/chat/route.ts b/agent-reactflow/apps/frontend/app/api/chat/route.ts index d26577d..9e16bdd 100644 --- a/agent-reactflow/apps/frontend/app/api/chat/route.ts +++ b/agent-reactflow/apps/frontend/app/api/chat/route.ts @@ -1,4 +1,4 @@ -import { createOpenAI, openai } from '@ai-sdk/openai'; +import { createOpenAI } from '@ai-sdk/openai'; import { streamText, tool } from 'ai'; import { z } from 'zod'; @@ -8,42 +8,13 @@ export async function POST(req: Request) { const { messages, agentId, runId } = await req.json(); try { - // TODO: use restack agent chat - // const openaiClient = createOpenAI({ - // apiKey: 'next-flow-frontend', - // baseURL: `http://localhost:9233/stream/agents/agentChat/${agentId}/${runId}`, - // }) - - // const zodObject = z.object({ - // nodes: z.array(z.object({ - // id: z.string(), - // type: z.string(), - // position: z.object({ - // x: z.number(), - // y: z.number(), - // }), - // data: z.object({ - // label: z.string(), - // description: z.string(), - // // icon: z.any(), - // handles: z.array(z.object({ - // id: z.string(), - // type: z.string(), - // position: z.string(), - // })), - // status: z.string(), - // }), - // })), - // edges: z.array(z.object({ - // id: z.string(), - // source: z.string(), - // target: z.string(), - // sourceHandle: z.string(), - // })), - // }); + const openaiClient = createOpenAI({ + apiKey: 'next-flow-frontend', + baseURL: `http://localhost:9233/stream/agents/agentChat/${agentId}/${runId}`, + }) const result = streamText({ - model: openai('gpt-4o'), + model: openaiClient('gpt-4o'), messages, tools: { updateFlow: tool({ @@ -52,7 +23,6 @@ export async function POST(req: Request) { flow: z.any() }), execute: async ({ flow }) => { - console.log("updated flow", flow); return { flow, }; diff --git a/agent-reactflow/apps/frontend/components/agent-builder.tsx b/agent-reactflow/apps/frontend/components/agent-builder.tsx index a259d16..e18b272 100644 --- a/agent-reactflow/apps/frontend/components/agent-builder.tsx +++ b/agent-reactflow/apps/frontend/components/agent-builder.tsx @@ -12,7 +12,6 @@ import { ReactFlow, type Connection, type Edge, NodeTypes, - Panel, } from "@xyflow/react" import "@xyflow/react/dist/style.css" import { Button } from "./ui/button" diff --git a/agent-reactflow/apps/frontend/components/agent-chat.tsx b/agent-reactflow/apps/frontend/components/agent-chat.tsx index 6b63c21..b4c61a7 100644 --- a/agent-reactflow/apps/frontend/components/agent-chat.tsx +++ b/agent-reactflow/apps/frontend/components/agent-chat.tsx @@ -10,7 +10,7 @@ import { ScrollArea } from "./ui/scroll-area" import { useChat } from '@ai-sdk/react' import { Node, Edge, ReactFlowInstance } from "@xyflow/react" import { workflowData } from "../lib/workflowData" -// import { runAgent } from "../app/actions/agent" +import { runAgent } from "../app/actions/agent" interface AgentChatProps { onClose: () => void @@ -168,17 +168,17 @@ export default function AgentChat({ onClose, reactFlowInstance, setNodes, setEdg const [agentId, setAgentId] = useState(""); const [runId, setRunId] = useState(""); - // useEffect(() => { - // const createAgentChat = async () => { - // const { agentId, runId } = await runAgent({ - // agentName: "agentChat", - // input: { }, - // }) - // setAgentId(agentId); - // setRunId(runId); - // } - // createAgentChat(); - // }, []); + useEffect(() => { + const createAgentChat = async () => { + const { agentId, runId } = await runAgent({ + agentName: "agentChat", + input: { }, + }) + setAgentId(agentId); + setRunId(runId); + } + createAgentChat(); + }, []); const currentFlow = reactFlowInstance?.toObject(); diff --git a/agent-reactflow/apps/frontend/components/flow/baseEdge.tsx b/agent-reactflow/apps/frontend/components/flow/baseEdge.tsx index 4984e51..e11cfbb 100644 --- a/agent-reactflow/apps/frontend/components/flow/baseEdge.tsx +++ b/agent-reactflow/apps/frontend/components/flow/baseEdge.tsx @@ -1,7 +1,7 @@ "use client" import { memo } from "react" -import { BaseEdge, EdgeLabelRenderer, type EdgeProps, getBezierPath, getSmoothStepPath, getStraightPath } from "@xyflow/react" +import { BaseEdge, EdgeLabelRenderer, type EdgeProps, getSmoothStepPath } from "@xyflow/react" const WorkflowEdge = memo( ({ diff --git a/agent-reactflow/apps/frontend/components/flow/defaultNode.tsx b/agent-reactflow/apps/frontend/components/flow/defaultNode.tsx index 215b724..27c382a 100644 --- a/agent-reactflow/apps/frontend/components/flow/defaultNode.tsx +++ b/agent-reactflow/apps/frontend/components/flow/defaultNode.tsx @@ -19,8 +19,8 @@ export type NodeData = { handles: Handle[]; } -const DefaultNode = memo(({ id, type, data, isConnectable, selected, zIndex, positionAbsoluteX, positionAbsoluteY, dragging, dragHandle }: NodeProps) => { - const { label, description, icon } = data as NodeData; +const DefaultNode = memo(({ data, isConnectable, selected }: NodeProps) => { + const { label, icon } = data as NodeData; // Use the provided icon or a default icon const nodeIcon = typeof icon === 'string' && Icons[icon] ? React.createElement(Icons[icon], { className: "h-4 w-4" }) : ; diff --git a/agent-reactflow/apps/frontend/components/flow/nodeHeader.tsx b/agent-reactflow/apps/frontend/components/flow/nodeHeader.tsx index 4a179e4..c67fbd2 100644 --- a/agent-reactflow/apps/frontend/components/flow/nodeHeader.tsx +++ b/agent-reactflow/apps/frontend/components/flow/nodeHeader.tsx @@ -1,6 +1,5 @@ -import { forwardRef, useCallback, HTMLAttributes, ReactNode } from "react"; -import { useNodeId, useReactFlow } from "@xyflow/react"; -import { EllipsisVertical, Trash } from "lucide-react"; +import { forwardRef, HTMLAttributes, ReactNode } from "react"; +import { EllipsisVertical } from "lucide-react"; import { cn } from "../../lib/utils"; import { Slot } from "@radix-ui/react-slot"; diff --git a/agent-reactflow/apps/frontend/components/flow/workflowEdge.tsx b/agent-reactflow/apps/frontend/components/flow/workflowEdge.tsx index b38c757..322297a 100644 --- a/agent-reactflow/apps/frontend/components/flow/workflowEdge.tsx +++ b/agent-reactflow/apps/frontend/components/flow/workflowEdge.tsx @@ -43,7 +43,7 @@ export const workflowEdge = memo(function WorkflowEdge({ targetPosition, targetX, targetY, - sourceHandle, + sourceHandleId }: EdgeProps) { const nodeData = useStore((state) => state.nodeLookup.get(source)?.data); const [edgePath, labelX, labelY] = getPath({ @@ -55,40 +55,19 @@ export const workflowEdge = memo(function WorkflowEdge({ targetY, targetPosition, }); - - console.log("sourceHandle", sourceHandle); - console.log("sourceHandle", sourceHandle); - - // const label = useMemo(() => { - // if (data.key && nodeData) { - // const value = nodeData[data.key]; - - // switch (typeof value) { - // case "string": - // case "number": - // return value; - - // case "object": - // return JSON.stringify(value); - - // default: - // return ""; - // } - // } - // }, [data, nodeData]); const transform = `translate(${labelX}px,${labelY}px) translate(-50%, -50%)`; return ( <> - {sourceHandle && ( + {sourceHandleId && (
-
{sourceHandle}
+
{sourceHandleId}
)} diff --git a/agent-reactflow/apps/frontend/components/workflow-selector.tsx b/agent-reactflow/apps/frontend/components/workflow-selector.tsx index e3ddc29..ec2e7bb 100644 --- a/agent-reactflow/apps/frontend/components/workflow-selector.tsx +++ b/agent-reactflow/apps/frontend/components/workflow-selector.tsx @@ -3,7 +3,7 @@ import React from "react" import { useState } from "react" -import { X, Search, Workflow } from "lucide-react" +import { X, Search, Workflow, StepForward } from "lucide-react" import { Input } from "./ui/input" import { Button } from "./ui/button" import { ScrollArea } from "./ui/scroll-area" From c3683b076fd0b03f44d8c3996fc0d12a8d0f5b0d Mon Sep 17 00:00:00 2001 From: aboutphilippe Date: Fri, 28 Mar 2025 13:44:03 +0530 Subject: [PATCH 2/7] lint backend --- agent-reactflow/apps/backend/.gitignore | 3 ++- agent-reactflow/apps/backend/eslint.config.mjs | 4 ++++ agent-reactflow/apps/backend/package.json | 4 ++-- agent-reactflow/apps/backend/src/agents/chat.ts | 2 +- agent-reactflow/apps/backend/src/agents/flow.ts | 2 +- .../apps/backend/src/workflows/endFlow.ts | 14 +++++++++++--- agent-reactflow/apps/frontend/eslint.config.js | 4 ---- 7 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 agent-reactflow/apps/backend/eslint.config.mjs delete mode 100644 agent-reactflow/apps/frontend/eslint.config.js diff --git a/agent-reactflow/apps/backend/.gitignore b/agent-reactflow/apps/backend/.gitignore index 65e7c43..c437f27 100644 --- a/agent-reactflow/apps/backend/.gitignore +++ b/agent-reactflow/apps/backend/.gitignore @@ -1,4 +1,5 @@ .env node_modules media -dist \ No newline at end of file +dist +.eslintcache \ No newline at end of file diff --git a/agent-reactflow/apps/backend/eslint.config.mjs b/agent-reactflow/apps/backend/eslint.config.mjs new file mode 100644 index 0000000..cb5569a --- /dev/null +++ b/agent-reactflow/apps/backend/eslint.config.mjs @@ -0,0 +1,4 @@ +import { config } from "@agent-reactflow/eslint-config/base"; + +/** @type {import("eslint").Linter.Config} */ +export default config; diff --git a/agent-reactflow/apps/backend/package.json b/agent-reactflow/apps/backend/package.json index 84e19ea..1550800 100644 --- a/agent-reactflow/apps/backend/package.json +++ b/agent-reactflow/apps/backend/package.json @@ -7,11 +7,11 @@ "start": "tsx src/services.ts", "start.watch": "nodemon src/services.ts", "dev": "open-cli http://localhost:5233 && tsx watch --include src src/services.ts", + "lint": "eslint src --fix --max-warnings 0 --cache", "build": "tsc --build", "clean": "rm -rf node_modules", "workflow": "tsx ./scheduleWorkflow.ts", - "event": "tsx ./eventAgent.ts", - "restack-up": "node restack_up.mjs" + "event": "tsx ./eventAgent.ts" }, "dependencies": { "@restackio/ai": "^0.0.119", diff --git a/agent-reactflow/apps/backend/src/agents/chat.ts b/agent-reactflow/apps/backend/src/agents/chat.ts index 1d2d39e..9bc3017 100644 --- a/agent-reactflow/apps/backend/src/agents/chat.ts +++ b/agent-reactflow/apps/backend/src/agents/chat.ts @@ -16,7 +16,7 @@ type AgentChatOutput = { export async function agentChat(): Promise { let endReceived = false; - let messages: functions.Message[] = []; + const messages: functions.Message[] = []; onEvent(messagesEvent, async ({ messages, tools, stream = true }: { messages: functions.Message[], tools: any, stream?: boolean }) => { const result = await step({}).llmChat({ diff --git a/agent-reactflow/apps/backend/src/agents/flow.ts b/agent-reactflow/apps/backend/src/agents/flow.ts index c22c49d..e48f303 100644 --- a/agent-reactflow/apps/backend/src/agents/flow.ts +++ b/agent-reactflow/apps/backend/src/agents/flow.ts @@ -44,7 +44,7 @@ export type AgentFlowOutput = { } export async function agentFlow({flowJson}: AgentFlowInput): Promise { let endReceived = false; - let eventResults: AgentFlowOutput['results'] = [] + const eventResults: AgentFlowOutput['results'] = [] try { diff --git a/agent-reactflow/apps/backend/src/workflows/endFlow.ts b/agent-reactflow/apps/backend/src/workflows/endFlow.ts index 8b5e3c2..4005b09 100644 --- a/agent-reactflow/apps/backend/src/workflows/endFlow.ts +++ b/agent-reactflow/apps/backend/src/workflows/endFlow.ts @@ -10,16 +10,24 @@ export type EndFlowInput = { export type EndFlowOutput = { response: "success" | "failure"; - rawResponse: {}; + rawResponse: any; }; export async function endFlow(input: EndFlowInput): Promise { + + const agentId = workflowInfo().parent?.workflowId; + const runId = workflowInfo().parent?.runId; + + if (!agentId || !runId) { + throw new Error("Workflow ID or run ID is not available"); + } + await step({}).sendAgentEvent({ eventName: 'end', eventInput: {}, - agentId: workflowInfo().parent?.workflowId!, - runId: workflowInfo().parent?.runId!, + agentId, + runId, }); if (input.eventData.response === "success") { diff --git a/agent-reactflow/apps/frontend/eslint.config.js b/agent-reactflow/apps/frontend/eslint.config.js deleted file mode 100644 index 610d94b..0000000 --- a/agent-reactflow/apps/frontend/eslint.config.js +++ /dev/null @@ -1,4 +0,0 @@ -import { nextJsConfig } from "@agent-reactflow/eslint-config/next-js"; - -/** @type {import("eslint").Linter.Config} */ -export default nextJsConfig; From 60fe28c3b780e540244217f307e0d8e4bc7b3c96 Mon Sep 17 00:00:00 2001 From: aboutphilippe Date: Fri, 28 Mar 2025 14:18:16 +0530 Subject: [PATCH 3/7] tool prompt description --- agent-reactflow/apps/frontend/app/api/chat/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent-reactflow/apps/frontend/app/api/chat/route.ts b/agent-reactflow/apps/frontend/app/api/chat/route.ts index 9e16bdd..8e7e121 100644 --- a/agent-reactflow/apps/frontend/app/api/chat/route.ts +++ b/agent-reactflow/apps/frontend/app/api/chat/route.ts @@ -18,7 +18,7 @@ export async function POST(req: Request) { messages, tools: { updateFlow: tool({ - description: 'Update flow', + description: 'Create or update flow', parameters: z.object({ flow: z.any() }), From bba9598821397b4de4b2f7d3361af9a25293f954 Mon Sep 17 00:00:00 2001 From: aboutphilippe Date: Fri, 28 Mar 2025 14:28:13 +0530 Subject: [PATCH 4/7] add debug info --- .../apps/backend/src/functions/llmChat.ts | 24 +------------------ .../apps/frontend/components/agent-chat.tsx | 8 ++++++- .../apps/frontend/components/agent-test.tsx | 16 ++++++------- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/agent-reactflow/apps/backend/src/functions/llmChat.ts b/agent-reactflow/apps/backend/src/functions/llmChat.ts index 2afbe2b..0cc4666 100644 --- a/agent-reactflow/apps/backend/src/functions/llmChat.ts +++ b/agent-reactflow/apps/backend/src/functions/llmChat.ts @@ -19,7 +19,7 @@ export type OpenAIChatInput = { export const llmChat = async ({ systemContent = "", - model = "gpt-4o-mini", + model = "gpt-4o", messages, stream = true, tools, @@ -37,28 +37,6 @@ export const llmChat = async ({ ...(messages ?? []), ], tools, - // tools: [ - // { - // type: "function", - // function: { - // name: "reactflow", - // description: "Update flow", - // parameters: { - // type: "object", - // properties: { - // flow: { - // type: "object", - // description: "The json object of the flow to update" - // } - // }, - // required: [ - // "flow" - // ], - // additionalProperties: false, - // }, - // }, - // }, - // ], model, stream, }; diff --git a/agent-reactflow/apps/frontend/components/agent-chat.tsx b/agent-reactflow/apps/frontend/components/agent-chat.tsx index b4c61a7..b46cb5f 100644 --- a/agent-reactflow/apps/frontend/components/agent-chat.tsx +++ b/agent-reactflow/apps/frontend/components/agent-chat.tsx @@ -11,6 +11,7 @@ import { useChat } from '@ai-sdk/react' import { Node, Edge, ReactFlowInstance } from "@xyflow/react" import { workflowData } from "../lib/workflowData" import { runAgent } from "../app/actions/agent" +import Link from "next/link" interface AgentChatProps { onClose: () => void @@ -194,8 +195,13 @@ export default function AgentChat({ onClose, reactFlowInstance, setNodes, setEdg - {runId &&
+ {runId &&
+
+

Dev debug info

+ Open on Restack +
{JSON.stringify({agentId, runId}, null, 2)}
+
}
diff --git a/agent-reactflow/apps/frontend/components/agent-test.tsx b/agent-reactflow/apps/frontend/components/agent-test.tsx index d68ba13..61f5f20 100644 --- a/agent-reactflow/apps/frontend/components/agent-test.tsx +++ b/agent-reactflow/apps/frontend/components/agent-test.tsx @@ -5,6 +5,7 @@ import { X, CheckCircle, AlertCircle, Clock } from "lucide-react" import { Button } from "./ui/button" import { runAgent, sendAgentEvent, getAgentResult } from "../app/actions/agent" import { ReactFlowInstance, Node } from "@xyflow/react" +import Link from "next/link" interface AgentTestPanelProps { onClose: () => void @@ -215,14 +216,13 @@ export default function AgentTestPanel({ onClose, workflowData, reactFlowInstanc {isRunning ? "Running..." : "Run agent"} - {/* {runId && ( -