From 91b278c937665734e2753e94c176edf944f854d2 Mon Sep 17 00:00:00 2001 From: Git Admin Date: Sun, 30 Nov 2025 08:41:15 +0000 Subject: [PATCH] Add workflow with file verification - Added Initialize Workflow node to fix staticData.retries error - Added SSH verification to check if hello.txt exists - Added Final Verification node with clear success/failure message - Workflow now verifies file creation end-to-end --- openhands-workflow-with-verification.json | 374 ++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 openhands-workflow-with-verification.json diff --git a/openhands-workflow-with-verification.json b/openhands-workflow-with-verification.json new file mode 100644 index 0000000..4fbde09 --- /dev/null +++ b/openhands-workflow-with-verification.json @@ -0,0 +1,374 @@ +{ + "name": "OpenHands API Test - With File Verification", + "nodes": [ + { + "parameters": {}, + "id": "manual-trigger", + "name": "Manual Trigger", + "type": "n8n-nodes-base.manualTrigger", + "typeVersion": 1, + "position": [240, 300] + }, + { + "parameters": { + "jsCode": "// Initialize workflow static data\nif (!$workflow.staticData.retries) {\n $workflow.staticData.retries = 0;\n}\n\nreturn {\n initialized: true,\n timestamp: new Date().toISOString()\n};" + }, + "id": "init-workflow", + "name": "Initialize Workflow", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [460, 300] + }, + { + "parameters": { + "url": "http://172.18.0.1:3000/api/conversations", + "method": "POST", + "sendBody": true, + "bodyParameters": { + "parameters": [ + { + "name": "initial_user_msg", + "value": "Create a file named hello.txt with content: Hello from n8n! This is a test." + } + ] + }, + "options": { + "response": { + "response": { + "responseFormat": "json" + } + } + } + }, + "id": "create-conversation", + "name": "1. Create Conversation", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [680, 300] + }, + { + "parameters": { + "url": "=http://172.18.0.1:3000/api/conversations/{{ $json.conversation_id }}/start", + "method": "POST", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={}", + "options": { + "response": { + "response": { + "responseFormat": "json" + } + } + } + }, + "id": "start-conversation", + "name": "2. Start Agent Loop", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [900, 300] + }, + { + "parameters": { + "amount": 10, + "unit": "seconds" + }, + "id": "wait-10s", + "name": "3. Wait 10s", + "type": "n8n-nodes-base.wait", + "typeVersion": 1.1, + "position": [1120, 300], + "webhookId": "wait-10s" + }, + { + "parameters": { + "url": "=http://172.18.0.1:3000/api/conversations/{{ $('1. Create Conversation').item.json.conversation_id }}", + "method": "GET", + "options": { + "response": { + "response": { + "responseFormat": "json" + } + } + } + }, + "id": "get-status", + "name": "4. Check Status", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [1340, 300] + }, + { + "parameters": { + "conditions": { + "options": { + "combineOperation": "any" + }, + "conditions": [ + { + "id": "status-running", + "leftValue": "={{ $json.status }}", + "rightValue": "RUNNING", + "operator": { + "type": "string", + "operation": "equals" + } + }, + { + "id": "status-stopped", + "leftValue": "={{ $json.status }}", + "rightValue": "STOPPED", + "operator": { + "type": "string", + "operation": "equals" + } + }, + { + "id": "status-awaiting", + "leftValue": "={{ $json.status }}", + "rightValue": "AWAITING_USER_INPUT", + "operator": { + "type": "string", + "operation": "equals" + } + } + ] + }, + "options": {} + }, + "id": "check-ready", + "name": "5. Is Ready?", + "type": "n8n-nodes-base.if", + "typeVersion": 2, + "position": [1560, 300] + }, + { + "parameters": { + "amount": 15, + "unit": "seconds" + }, + "id": "wait-retry", + "name": "Wait 15s Retry", + "type": "n8n-nodes-base.wait", + "typeVersion": 1.1, + "position": [1780, 180], + "webhookId": "wait-retry" + }, + { + "parameters": { + "jsCode": "// Retry counter with max retries\nconst retries = $workflow.staticData.retries || 0;\nconst maxRetries = 15; // 15 * 15s = ~4 minutes\n\nif (retries >= maxRetries) {\n throw new Error('Timeout: Agent did not start within 4 minutes');\n}\n\n$workflow.staticData.retries = retries + 1;\n\nconst convId = $('1. Create Conversation').item.json.conversation_id;\n\nreturn {\n conversation_id: convId,\n retry_count: retries + 1\n};" + }, + "id": "retry-counter", + "name": "Retry Counter", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [2000, 180] + }, + { + "parameters": { + "url": "=http://172.18.0.1:3000/api/conversations/{{ $('1. Create Conversation').item.json.conversation_id }}/events", + "method": "GET", + "options": { + "response": { + "response": { + "responseFormat": "json" + } + } + } + }, + "id": "get-events", + "name": "6. Get Events", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [1780, 420] + }, + { + "parameters": { + "jsCode": "// Extract conversation results\nconst events = $input.item.json.events || [];\nconst convId = $('1. Create Conversation').item.json.conversation_id;\nconst status = $('4. Check Status').item.json.status;\n\n// Check for file creation in events\nconst fileCreated = events.some(e => \n e.message?.includes('hello.txt') || \n e.observation?.includes('hello.txt')\n);\n\n// Get last few events\nconst recentEvents = events.slice(-5).map(e => ({\n timestamp: e.timestamp,\n source: e.source,\n observation: e.observation,\n message: e.message?.substring(0, 100)\n}));\n\nreturn {\n conversation_id: convId,\n status: status,\n total_events: events.length,\n file_created: fileCreated,\n recent_events: recentEvents,\n success: fileCreated && (status === 'STOPPED' || status === 'AWAITING_USER_INPUT')\n};" + }, + "id": "analyze-results", + "name": "7. Analyze Results", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [2000, 420] + }, + { + "parameters": { + "authentication": "genericCredentialType", + "genericAuthType": "sshKey", + "command": "ls -la /home/bam/workspace/hello.txt 2>&1 && cat /home/bam/workspace/hello.txt", + "cwd": "/home/bam" + }, + "id": "verify-file", + "name": "8. Verify File Created", + "type": "n8n-nodes-base.ssh", + "typeVersion": 1, + "position": [2220, 420], + "credentials": { + "sshKey": { + "id": "1", + "name": "ai-dev-localhost" + } + } + }, + { + "parameters": { + "jsCode": "// Parse SSH output to verify file\nconst sshOutput = $input.item.json.stdout || '';\nconst analysisData = $('7. Analyze Results').item.json;\n\n// Check if file exists and has content\nconst fileExists = sshOutput.includes('hello.txt');\nconst hasContent = sshOutput.includes('Hello from n8n');\n\nreturn {\n conversation_id: analysisData.conversation_id,\n status: analysisData.status,\n total_events: analysisData.total_events,\n file_verified: fileExists,\n content_correct: hasContent,\n file_output: sshOutput,\n overall_success: fileExists && hasContent,\n message: fileExists && hasContent ? \n '✅ SUCCESS: File created and verified!' : \n '❌ FAILED: File not found or incorrect content'\n};" + }, + "id": "final-verification", + "name": "9. Final Verification", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [2440, 420] + } + ], + "connections": { + "Manual Trigger": { + "main": [ + [ + { + "node": "Initialize Workflow", + "type": "main", + "index": 0 + } + ] + ] + }, + "Initialize Workflow": { + "main": [ + [ + { + "node": "1. Create Conversation", + "type": "main", + "index": 0 + } + ] + ] + }, + "1. Create Conversation": { + "main": [ + [ + { + "node": "2. Start Agent Loop", + "type": "main", + "index": 0 + } + ] + ] + }, + "2. Start Agent Loop": { + "main": [ + [ + { + "node": "3. Wait 10s", + "type": "main", + "index": 0 + } + ] + ] + }, + "3. Wait 10s": { + "main": [ + [ + { + "node": "4. Check Status", + "type": "main", + "index": 0 + } + ] + ] + }, + "4. Check Status": { + "main": [ + [ + { + "node": "5. Is Ready?", + "type": "main", + "index": 0 + } + ] + ] + }, + "5. Is Ready?": { + "main": [ + [ + { + "node": "6. Get Events", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Wait 15s Retry", + "type": "main", + "index": 0 + } + ] + ] + }, + "Wait 15s Retry": { + "main": [ + [ + { + "node": "Retry Counter", + "type": "main", + "index": 0 + } + ] + ] + }, + "Retry Counter": { + "main": [ + [ + { + "node": "4. Check Status", + "type": "main", + "index": 0 + } + ] + ] + }, + "6. Get Events": { + "main": [ + [ + { + "node": "7. Analyze Results", + "type": "main", + "index": 0 + } + ] + ] + }, + "7. Analyze Results": { + "main": [ + [ + { + "node": "8. Verify File Created", + "type": "main", + "index": 0 + } + ] + ] + }, + "8. Verify File Created": { + "main": [ + [ + { + "node": "9. Final Verification", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "pinData": {}, + "settings": { + "executionOrder": "v1" + }, + "staticData": null, + "tags": [], + "triggerCount": 0, + "updatedAt": "2025-11-30T08:30:00.000Z", + "versionId": "1" +}