{ "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 retry counter in workflow data\nreturn {\n retry_count: 0,\n max_retries: 15,\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": "// Get retry count from input or default to 0\nconst currentRetries = $input.item.json.retry_count || 0;\nconst maxRetries = 15; // 15 * 15s = ~4 minutes\n\nif (currentRetries >= maxRetries) {\n throw new Error('Timeout: Agent did not start within 4 minutes');\n}\n\nconst convId = $('1. Create Conversation').item.json.conversation_id;\n\nreturn {\n conversation_id: convId,\n retry_count: currentRetries + 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" }