The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "AA Factory 02 - Ensure Model Ready",
"nodes": [
{
"parameters": {},
"id": "f3728b44-756e-4127-9686-b39a47b4d5dc",
"name": "Sub-workflow Input",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1,
"position": [
-1936,
-112
]
},
{
"parameters": {
"jsCode": "const input = $json ?? {};\nconst now = new Date().toISOString();\nconst obs = input.observability ?? {};\nconst trace = Array.isArray(obs.trace) ? [...obs.trace] : [];\nconst startedAt = obs.stage_started_at ?? obs.started_at ?? now;\nconst durationMs = Math.max(0, Date.parse(now) - Date.parse(startedAt));\nconst event = {\n timestamp: now,\n correlation_id: obs.correlation_id ?? input.correlation_id ?? null,\n workflow: $workflow.name,\n execution_id: $execution.id,\n stage: 'model-readiness',\n status: 'started',\n duration_ms: durationMs,\n ...({}),\n};\ntrace.push(event);\nconsole.log(JSON.stringify({event:'autonomous_agent_workflow_stage', ...event}));\nreturn [{json:{...input, observability:{...obs, stage_started_at:now, trace}, last_event:event}}];"
},
"id": "0a161206-7d5b-4eeb-a6f8-7f1a925b1254",
"name": "Start Model Readiness Trace",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1744,
-112
]
},
{
"parameters": {
"operation": "get",
"modelName": "={{ $json.blueprint.model_policy.model }}"
},
"id": "5f6b4718-b72e-4a71-8fa0-dcf6c933f06e",
"name": "Inspect Required Model",
"type": "n8n-nodes-autonomous-agent.autonomousAgentLlmModel",
"typeVersion": 1,
"position": [
-1520,
-112
],
"credentials": {
"autonomousAgentApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const rawResponse = $json ?? {};\n\n// Support:\n// 1. Direct array: [{ model, details }]\n// 2. Wrapped array: { data: [{ model, details }] }\n// 3. Direct object: { model, details }\nconst modelRecord = Array.isArray(rawResponse)\n ? rawResponse[0]\n : Array.isArray(rawResponse.data)\n ? rawResponse.data[0]\n : rawResponse;\n\nconst inspectedModel =\n modelRecord &&\n typeof modelRecord === 'object' &&\n modelRecord.model != null &&\n modelRecord.details != null\n ? modelRecord\n : null;\n\nconst pullError =\n rawResponse.error ??\n rawResponse.details?.error ??\n modelRecord?.error ??\n modelRecord?.details?.error ??\n null;\n\nconst pullMessage = String(\n rawResponse.message ??\n rawResponse.detail ??\n pullError?.message ??\n pullError?.detail ??\n ''\n);\n\nconst timeoutObserved =\n /timeout|timed out|30000ms exceeded/i.test(pullMessage);\n\nconst requestedModel =\n $('Start Model Readiness Trace')\n .item\n .json\n .blueprint\n .model_policy\n .model;\n\nreturn [{\n json: {\n model: inspectedModel?.model ?? requestedModel,\n\n // True only when both model and details are present.\n modelInstalled: inspectedModel !== null,\n\n provider: inspectedModel?.provider ?? null,\n modelDetails: inspectedModel?.details ?? null,\n\n pollAttempt: 0,\n maximumPollAttempts: 60,\n pollIntervalSeconds: 15,\n\n pullRequestTimedOut: timeoutObserved,\n pullRequestMessage: pullMessage,\n },\n}];"
},
"id": "2d7d873a-92b1-4acb-abcd-becd691edd5a",
"name": "Normalize Model Inspection",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-1296,
-112
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "1b1e09ab-2783-4e6d-a6bb-8da1385851b3",
"leftValue": "={{ $json.modelInstalled }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "66182bde-0c12-477d-bc32-061a738e1175",
"name": "Model Installed?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
-1088,
-112
]
},
{
"parameters": {
"operation": "pull",
"model": "={{ $json.model }}"
},
"id": "6cd08b57-37c6-489b-adb2-f3ce98e32733",
"name": "Pull Required Model",
"type": "n8n-nodes-autonomous-agent.autonomousAgentLlmModel",
"typeVersion": 1,
"position": [
-864,
16
],
"retryOnFail": false,
"notesInFlow": true,
"credentials": {
"autonomousAgentApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput",
"notes": "A 30-second client timeout does not necessarily mean the Ollama pull stopped. Continue into bounded inspection polling and only fail when the model is still unavailable after the configured polling limit."
},
{
"parameters": {
"jsCode": "const rawResponse = $json ?? {};\n\n// Supports:\n// 1. [{ provider, model, status, result }]\n// 2. { data: [{ provider, model, status, result }] }\n// 3. { provider, model, status, result }\nconst modelRecord = Array.isArray(rawResponse)\n ? rawResponse[0]\n : Array.isArray(rawResponse.data)\n ? rawResponse.data[0]\n : rawResponse;\n\nconst pullError =\n rawResponse.error ??\n rawResponse.details?.error ??\n modelRecord?.error ??\n modelRecord?.details?.error ??\n null;\n\nconst pullMessage = String(\n rawResponse.message ??\n rawResponse.detail ??\n modelRecord?.message ??\n modelRecord?.detail ??\n pullError?.message ??\n pullError?.detail ??\n ''\n);\n\nconst timeoutObserved =\n /timeout|timed out|30000ms exceeded/i.test(pullMessage);\n\nconst requestedModel =\n $('Start Model Readiness Trace')\n .item\n .json\n .blueprint\n .model_policy\n .model;\n\nconst hasModel =\n typeof modelRecord?.model === 'string' &&\n modelRecord.model.trim().length > 0;\n\nconst modelAvailable =\n hasModel &&\n (\n modelRecord.status === 'available' ||\n modelRecord.result?.status === 'success'\n );\n\nreturn [{\n json: {\n model: hasModel\n ? modelRecord.model\n : requestedModel,\n\n provider: modelRecord?.provider ?? null,\n modelStatus: modelRecord?.status ?? null,\n modelAvailable,\n\n usedByPolicies: Array.isArray(modelRecord?.used_by_policies)\n ? modelRecord.used_by_policies\n : [],\n\n nextAction: modelRecord?.next_action ?? null,\n resultStatus: modelRecord?.result?.status ?? null,\n\n pollAttempt: 0,\n maximumPollAttempts: 60,\n pollIntervalSeconds: 15,\n\n pullRequestTimedOut: timeoutObserved,\n pullRequestMessage: pullMessage,\n },\n}];"
},
"id": "04838327-1f3a-4b16-b818-9d1040374320",
"name": "Initialize Model Poll",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-640,
16
]
},
{
"parameters": {
"amount": 15
},
"id": "1336086f-7b1f-401c-9615-6be82b9b5a2a",
"name": "Wait Before Model Recheck",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
-416,
16
]
},
{
"parameters": {
"operation": "get",
"modelName": "={{ $json.model }}"
},
"id": "813d3ec0-ba06-467e-b896-8dab25b452db",
"name": "Inspect Pulled Model",
"type": "n8n-nodes-autonomous-agent.autonomousAgentLlmModel",
"typeVersion": 1,
"position": [
-208,
16
],
"retryOnFail": false,
"credentials": {
"autonomousAgentApi": {
"name": "<your credential>"
}
},
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "const rawResponse = $json ?? {};\nlet previousPoll = {};\ntry { previousPoll = $('Increment Model Poll').item.json; } catch { previousPoll = $('Initialize Model Poll').item.json; }\n\n// Support:\n// 1. Direct array: [{ model, details }]\n// 2. Wrapped array: { data: [{ model, details }] }\n// 3. Direct object: { model, details }\nconst modelRecord = Array.isArray(rawResponse)\n ? rawResponse[0]\n : Array.isArray(rawResponse.data)\n ? rawResponse.data[0]\n : rawResponse;\n\nconst inspectedModel =\n modelRecord &&\n typeof modelRecord === 'object' &&\n modelRecord.model != null &&\n modelRecord.details != null\n ? modelRecord\n : null;\n\nconst pullError =\n rawResponse.error ??\n rawResponse.details?.error ??\n modelRecord?.error ??\n modelRecord?.details?.error ??\n null;\n\nconst pullMessage = String(\n rawResponse.message ??\n rawResponse.detail ??\n pullError?.message ??\n pullError?.detail ??\n ''\n);\n\nconst timeoutObserved =\n /timeout|timed out|30000ms exceeded/i.test(pullMessage);\n\nconst requestedModel =\n $('Start Model Readiness Trace')\n .item\n .json\n .blueprint\n .model_policy\n .model;\n\nreturn [{\n json: {\n model: inspectedModel?.model ?? requestedModel,\n\n // True only when both model and details are present.\n modelInstalled: inspectedModel !== null,\n\n provider: inspectedModel?.provider ?? null,\n modelDetails: inspectedModel?.details ?? null,\n\n pollAttempt: Number(previousPoll.pollAttempt ?? 0),\n maximumPollAttempts: Number(previousPoll.maximumPollAttempts ?? 60),\n pollIntervalSeconds: Number(previousPoll.pollIntervalSeconds ?? 15),\n\n pullRequestTimedOut: timeoutObserved,\n pullRequestMessage: pullMessage,\n },\n}];"
},
"id": "0a49d856-2ea2-4e23-bcc8-e9cfb5a5e52c",
"name": "Normalize Pulled Model Inspection",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
32,
16
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "5d44ceae-aec1-480e-a472-ebd7ef593d72",
"leftValue": "={{ $json.modelInstalled }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "896fedf2-2b0a-4cd9-8dd7-596207c203b2",
"name": "Model Pull Complete?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
240,
16
]
},
{
"parameters": {
"jsCode": "return [{\n json: {\n ...$json,\n pollAttempt: Number($json.pollAttempt ?? 0) + 1,\n maximumPollAttempts: Number($json.maximumPollAttempts ?? 60),\n pollIntervalSeconds: Number($json.pollIntervalSeconds ?? 10),\n },\n}];"
},
"id": "debf7a48-0efa-4e19-81c9-151cfc8b04cf",
"name": "Increment Model Poll",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
464,
128
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "df92feee-63f6-4589-b51c-3d5ce558c691",
"leftValue": "={{ $json.pollAttempt >= $json.maximumPollAttempts }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "498d9d2e-d32b-42f5-b225-09c65cb9ed06",
"name": "Model Poll Limit Reached?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
688,
128
]
},
{
"parameters": {
"jsCode": "throw new Error(\n `Ollama model ${$json.model} was not installed after ` +\n `${$json.pollAttempt} polling attempts`\n);"
},
"id": "3b0e2a9b-9a3c-4f64-a024-529eeef58a4c",
"name": "Model Pull Timed Out",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
912,
128
]
},
{
"parameters": {
"jsCode": "const state=$json; const parent=$('Sub-workflow Input').item.json; const now=new Date().toISOString(); const obs=parent.observability??{}; const trace=Array.isArray(obs.trace)?[...obs.trace]:[]; const startedAt=obs.stage_started_at??obs.started_at??now; const event={timestamp:now,correlation_id:obs.correlation_id,workflow:$workflow.name,execution_id:$execution.id,stage:'model-readiness',status:'completed',duration_ms:Math.max(0,Date.parse(now)-Date.parse(startedAt)),model:state.model??parent.blueprint?.model_policy?.model,poll_attempts:Number(state.pollAttempt??0),pull_timeout_observed:Boolean(state.pullRequestTimedOut)}; trace.push(event); console.log(JSON.stringify({event:'autonomous_agent_workflow_stage',...event})); return [{json:{...parent,model_readiness:state,observability:{...obs,stage_started_at:now,trace},last_event:event}}];"
},
"id": "8c8a2d0f-eb26-4670-84bc-569cbd9fb723",
"name": "Model Ready",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
-144
]
}
],
"connections": {
"Sub-workflow Input": {
"main": [
[
{
"node": "Start Model Readiness Trace",
"type": "main",
"index": 0
}
]
]
},
"Start Model Readiness Trace": {
"main": [
[
{
"node": "Inspect Required Model",
"type": "main",
"index": 0
}
]
]
},
"Inspect Required Model": {
"main": [
[
{
"node": "Normalize Model Inspection",
"type": "main",
"index": 0
}
]
]
},
"Normalize Model Inspection": {
"main": [
[
{
"node": "Model Installed?",
"type": "main",
"index": 0
}
]
]
},
"Model Installed?": {
"main": [
[
{
"node": "Model Ready",
"type": "main",
"index": 0
}
],
[
{
"node": "Pull Required Model",
"type": "main",
"index": 0
}
]
]
},
"Pull Required Model": {
"main": [
[
{
"node": "Initialize Model Poll",
"type": "main",
"index": 0
}
]
]
},
"Initialize Model Poll": {
"main": [
[
{
"node": "Wait Before Model Recheck",
"type": "main",
"index": 0
}
]
]
},
"Wait Before Model Recheck": {
"main": [
[
{
"node": "Inspect Pulled Model",
"type": "main",
"index": 0
}
]
]
},
"Inspect Pulled Model": {
"main": [
[
{
"node": "Normalize Pulled Model Inspection",
"type": "main",
"index": 0
}
]
]
},
"Normalize Pulled Model Inspection": {
"main": [
[
{
"node": "Model Pull Complete?",
"type": "main",
"index": 0
}
]
]
},
"Model Pull Complete?": {
"main": [
[
{
"node": "Model Ready",
"type": "main",
"index": 0
}
],
[
{
"node": "Increment Model Poll",
"type": "main",
"index": 0
}
]
]
},
"Increment Model Poll": {
"main": [
[
{
"node": "Model Poll Limit Reached?",
"type": "main",
"index": 0
}
]
]
},
"Model Poll Limit Reached?": {
"main": [
[
{
"node": "Model Pull Timed Out",
"type": "main",
"index": 0
}
],
[
{
"node": "Wait Before Model Recheck",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"availableInMCP": false
},
"versionId": "b16b796e-f88f-46d4-9648-28b53bea6dde",
"nodeGroups": [],
"id": "TwazUNKFroOI0ENW",
"tags": [
{
"name": "factory",
"id": "RafL6i7R2YphAkeq",
"updatedAt": "2026-07-26T11:35:57.670Z",
"createdAt": "2026-07-26T11:35:57.670Z"
}
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
autonomousAgentApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AA Factory 02 - Ensure Model Ready. Uses executeWorkflowTrigger, n8n-nodes-autonomous-agent. Event-driven trigger; 15 nodes.
Source: https://github.com/MustiSquare/n8n-with-autonomous-agent-platform-demo/blob/main/workflows/00-agent-execution-factory/02-ensure-model-ready.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
AA Factory 03 - Provision Resources. Uses executeWorkflowTrigger, n8n-nodes-autonomous-agent. Event-driven trigger; 9 nodes.
AA Factory 01 - Plan Blueprint. Uses executeWorkflowTrigger, n8n-nodes-autonomous-agent. Event-driven trigger; 5 nodes.
AA Factory 04 - Create Target Execution. Uses executeWorkflowTrigger, n8n-nodes-autonomous-agent. Event-driven trigger; 4 nodes.
Autonomous Agent - Incident Response - Create Capability - incident-root-cause-analysis. Uses executeWorkflowTrigger, n8n-nodes-autonomous-agent. Event-driven trigger; 2 nodes.
Autonomous Agent - Incident Response - Create Capability - production-remediation-plan. Uses executeWorkflowTrigger, n8n-nodes-autonomous-agent. Event-driven trigger; 2 nodes.