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": "Log Agent Outputs",
"nodes": [
{
"parameters": {
"model": "openai/gpt-4.1-mini",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"typeVersion": 1,
"position": [
40,
240
],
"id": "d94afe23-8e36-4624-9e89-aa152b29f328",
"name": "4.1-mini",
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"sendTo": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('To', ``, 'string') }}",
"subject": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}",
"message": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}",
"options": {
"appendAttribution": true
}
},
"type": "n8n-nodes-base.gmailTool",
"typeVersion": 2.1,
"position": [
220,
240
],
"id": "a7572331-dc94-4b31-9310-03b82e9be783",
"name": "Send Email",
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "search",
"base": {
"__rl": true,
"value": "appK0rbtvf9e7vt6w",
"mode": "list",
"cachedResultName": "Contacts",
"cachedResultUrl": "https://airtable.com/appK0rbtvf9e7vt6w"
},
"table": {
"__rl": true,
"value": "tbl08JGCfUK1RhXsG",
"mode": "list",
"cachedResultName": "Contacts",
"cachedResultUrl": "https://airtable.com/appK0rbtvf9e7vt6w/tbl08JGCfUK1RhXsG"
},
"options": {}
},
"type": "n8n-nodes-base.airtableTool",
"typeVersion": 2.1,
"position": [
320,
240
],
"id": "74f29af7-905a-490c-bb2a-fcc96c2af060",
"name": "Get Contacts",
"credentials": {
"airtableTokenApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "144h5vN3d_SsZMNkZncQAKMrwJ3wkceUEq47dO7FwLyA",
"mode": "list",
"cachedResultName": "Agent Logs",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/144h5vN3d_SsZMNkZncQAKMrwJ3wkceUEq47dO7FwLyA/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/144h5vN3d_SsZMNkZncQAKMrwJ3wkceUEq47dO7FwLyA/edit#gid=0"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Timestamp": "={{ $now.format('D hh:mm a') }}",
"Workflow": "={{ $workflow.name }}",
"Input": "={{ $('Telegram Trigger').item.json.message.text }}",
"Output": "={{ $('AI Agent').item.json.output }}",
"Actions": "={{ JSON.stringify($json.steps, null, 2) }}",
"Tokens": "={{ JSON.stringify($json.tokens, null, 2) }}",
"Total Cost": "={{ $json.total_cost }}"
},
"matchingColumns": [],
"schema": [
{
"id": "Timestamp",
"displayName": "Timestamp",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Workflow",
"displayName": "Workflow",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Input",
"displayName": "Input",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Output",
"displayName": "Output",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Error Message",
"displayName": "Error Message",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "Actions",
"displayName": "Actions",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Tokens",
"displayName": "Tokens",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "Total Cost",
"displayName": "Total Cost",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
760,
-20
],
"id": "e86e0eff-a2aa-45b7-a666-ac4fee4de3e0",
"name": "Log",
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"calendar": {
"__rl": true,
"value": "nateherk88@gmail.com",
"mode": "list",
"cachedResultName": "nateherk88@gmail.com"
},
"start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', ``, 'string') }}",
"end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', ``, 'string') }}",
"additionalFields": {
"summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Summary', ``, 'string') }}"
}
},
"type": "n8n-nodes-base.googleCalendarTool",
"typeVersion": 1.3,
"position": [
420,
240
],
"id": "50448561-db40-43ee-bf28-b6d328ed4cfa",
"name": "Create Event",
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Initialize the output arrays\nconst steps = [];\nconst tokens = [];\nlet totalCost = 0; // Add this to track the total cost\n\n// Process each item in the input\nfor (const item of $input.all()) {\n let data = item.json;\n \n // Check if the data is an array itself (like your example JSON)\n if (Array.isArray(data)) {\n // Process each object in the array\n for (const obj of data) {\n // Extract steps information\n if (obj.intermediateSteps && Array.isArray(obj.intermediateSteps)) {\n for (const step of obj.intermediateSteps) {\n if (step.action) {\n steps.push({\n tool: step.action.tool,\n toolInput: step.action.toolInput,\n observation: step.observation\n });\n }\n }\n }\n \n // Extract token and cost information\n if (obj.intermediateSteps && Array.isArray(obj.intermediateSteps)) {\n for (const step of obj.intermediateSteps) {\n if (step.action && step.action.messageLog && Array.isArray(step.action.messageLog)) {\n for (const message of step.action.messageLog) {\n if (message.kwargs && message.kwargs.response_metadata && message.kwargs.response_metadata.usage) {\n const usage = message.kwargs.response_metadata.usage;\n tokens.push({\n prompt_tokens: usage.prompt_tokens,\n completion_tokens: usage.completion_tokens,\n total_tokens: usage.total_tokens,\n cost: usage.cost,\n model_name: message.kwargs.response_metadata.model_name\n });\n \n // Add the cost to our running total\n if (typeof usage.cost === 'number') {\n totalCost += usage.cost;\n }\n }\n }\n }\n }\n }\n }\n } else {\n // If data is not an array, process it as a single object\n // Extract steps information\n if (data.intermediateSteps && Array.isArray(data.intermediateSteps)) {\n for (const step of data.intermediateSteps) {\n if (step.action) {\n steps.push({\n tool: step.action.tool,\n toolInput: step.action.toolInput,\n observation: step.observation\n });\n }\n }\n }\n \n // Extract token and cost information\n if (data.intermediateSteps && Array.isArray(data.intermediateSteps)) {\n for (const step of data.intermediateSteps) {\n if (step.action && step.action.messageLog && Array.isArray(step.action.messageLog)) {\n for (const message of step.action.messageLog) {\n if (message.kwargs && message.kwargs.response_metadata && message.kwargs.response_metadata.usage) {\n const usage = message.kwargs.response_metadata.usage;\n tokens.push({\n prompt_tokens: usage.prompt_tokens,\n completion_tokens: usage.completion_tokens,\n total_tokens: usage.total_tokens,\n cost: usage.cost,\n model_name: message.kwargs.response_metadata.model_name\n });\n \n // Add the cost to our running total\n if (typeof usage.cost === 'number') {\n totalCost += usage.cost;\n }\n }\n }\n }\n }\n }\n }\n}\n\n// Return the processed data with total_cost included\nreturn [{\n json: {\n steps: steps,\n tokens: tokens,\n total_cost: totalCost\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
620,
-20
],
"id": "00ac40ff-ea45-463f-b5bd-2b337486fba8",
"name": "Clean Up"
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "144h5vN3d_SsZMNkZncQAKMrwJ3wkceUEq47dO7FwLyA",
"mode": "list",
"cachedResultName": "Agent Logs",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/144h5vN3d_SsZMNkZncQAKMrwJ3wkceUEq47dO7FwLyA/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/144h5vN3d_SsZMNkZncQAKMrwJ3wkceUEq47dO7FwLyA/edit#gid=0"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Timestamp": "={{ $now.format('D hh:mm a') }}",
"Workflow": "={{ $workflow.name }}",
"Output": "ERROR",
"Input": "={{ $('Telegram Trigger').item.json.message.text }}",
"Total Cost": "={{ $json.total_cost }}",
"Tokens": "={{ JSON.stringify($json.tokens, null, 2) }}",
"Actions": "={{ JSON.stringify($json.steps, null, 2) }}",
"Error Message": "={{ $('AI Agent').item.json.error }}"
},
"matchingColumns": [],
"schema": [
{
"id": "Timestamp",
"displayName": "Timestamp",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Workflow",
"displayName": "Workflow",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Input",
"displayName": "Input",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Output",
"displayName": "Output",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Error Message",
"displayName": "Error Message",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Actions",
"displayName": "Actions",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Tokens",
"displayName": "Tokens",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
},
{
"id": "Total Cost",
"displayName": "Total Cost",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
760,
240
],
"id": "bbc28e22-4148-476b-9307-2b0f73ea417f",
"name": "Errors",
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"type": "n8n-nodes-base.telegramTrigger",
"typeVersion": 1.2,
"position": [
0,
0
],
"id": "31887bf6-10d1-4d2d-a7a8-127c21e4807c",
"name": "Telegram Trigger",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"chatId": "={{ $('Telegram Trigger').item.json.message.from.id }}",
"text": "=Error: {{ $('AI Agent').item.json.error }}",
"additionalFields": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
980,
240
],
"id": "02bea6a4-6b4f-42b0-971f-112736d8319a",
"name": "Error Response",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"chatId": "={{ $('Telegram Trigger').item.json.message.from.id }}",
"text": "={{ $('AI Agent').item.json.output }}",
"additionalFields": {
"appendAttribution": false
}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
980,
-20
],
"id": "89a37553-39ff-4b72-8de0-4165bce7d0eb",
"name": "Response",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "## Trigger",
"height": 240,
"width": 220,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-60,
-80
],
"id": "d98a8e4b-f93f-4715-a0c1-9ca0ac4aabf1",
"name": "Sticky Note"
},
{
"parameters": {
"content": "## AI Agent\n",
"height": 240,
"width": 340,
"color": 5
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
180,
-80
],
"id": "8383ef01-005e-4d89-9578-2e5ed9cd7fa3",
"name": "Sticky Note1"
},
{
"parameters": {
"content": "## Chat Model",
"height": 200,
"width": 200,
"color": 2
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-20,
180
],
"id": "eac4405a-f4e6-40e1-9871-4c987ef4938e",
"name": "Sticky Note2"
},
{
"parameters": {
"content": "## Tools",
"height": 200,
"width": 320,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
200,
180
],
"id": "8d3a1500-2b1e-4b0e-b849-2324856841c3",
"name": "Sticky Note3"
},
{
"parameters": {
"content": "## Log Actions & Cost",
"height": 240,
"width": 380,
"color": 4
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
540,
-100
],
"id": "e8ed3e1f-b09d-4ad7-8eba-bf3ea2930994",
"name": "Sticky Note4"
},
{
"parameters": {
"content": "## Log Error Actions & Cost",
"height": 240,
"width": 380,
"color": 3
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
540,
160
],
"id": "8a7a07fc-55a2-4794-8196-f88d34f9f72b",
"name": "Sticky Note5"
},
{
"parameters": {
"jsCode": "// Initialize the output arrays\nconst steps = [];\nconst tokens = [];\nlet totalCost = 0; // Add this to track the total cost\n\n// Process each item in the input\nfor (const item of $input.all()) {\n let data = item.json;\n \n // Check if the data is an array itself (like your example JSON)\n if (Array.isArray(data)) {\n // Process each object in the array\n for (const obj of data) {\n // Extract steps information\n if (obj.intermediateSteps && Array.isArray(obj.intermediateSteps)) {\n for (const step of obj.intermediateSteps) {\n if (step.action) {\n steps.push({\n tool: step.action.tool,\n toolInput: step.action.toolInput,\n observation: step.observation\n });\n }\n }\n }\n \n // Extract token and cost information\n if (obj.intermediateSteps && Array.isArray(obj.intermediateSteps)) {\n for (const step of obj.intermediateSteps) {\n if (step.action && step.action.messageLog && Array.isArray(step.action.messageLog)) {\n for (const message of step.action.messageLog) {\n if (message.kwargs && message.kwargs.response_metadata && message.kwargs.response_metadata.usage) {\n const usage = message.kwargs.response_metadata.usage;\n tokens.push({\n prompt_tokens: usage.prompt_tokens,\n completion_tokens: usage.completion_tokens,\n total_tokens: usage.total_tokens,\n cost: usage.cost,\n model_name: message.kwargs.response_metadata.model_name\n });\n \n // Add the cost to our running total\n if (typeof usage.cost === 'number') {\n totalCost += usage.cost;\n }\n }\n }\n }\n }\n }\n }\n } else {\n // If data is not an array, process it as a single object\n // Extract steps information\n if (data.intermediateSteps && Array.isArray(data.intermediateSteps)) {\n for (const step of data.intermediateSteps) {\n if (step.action) {\n steps.push({\n tool: step.action.tool,\n toolInput: step.action.toolInput,\n observation: step.observation\n });\n }\n }\n }\n \n // Extract token and cost information\n if (data.intermediateSteps && Array.isArray(data.intermediateSteps)) {\n for (const step of data.intermediateSteps) {\n if (step.action && step.action.messageLog && Array.isArray(step.action.messageLog)) {\n for (const message of step.action.messageLog) {\n if (message.kwargs && message.kwargs.response_metadata && message.kwargs.response_metadata.usage) {\n const usage = message.kwargs.response_metadata.usage;\n tokens.push({\n prompt_tokens: usage.prompt_tokens,\n completion_tokens: usage.completion_tokens,\n total_tokens: usage.total_tokens,\n cost: usage.cost,\n model_name: message.kwargs.response_metadata.model_name\n });\n \n // Add the cost to our running total\n if (typeof usage.cost === 'number') {\n totalCost += usage.cost;\n }\n }\n }\n }\n }\n }\n }\n}\n\n// Return the processed data with total_cost included\nreturn [{\n json: {\n steps: steps,\n tokens: tokens,\n total_cost: totalCost\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
620,
240
],
"id": "e4300814-01f2-4c98-b1bb-51ddf49b8405",
"name": "Clean_Up"
},
{
"parameters": {
"content": "## Reponse",
"height": 240,
"width": 200,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
940,
-100
],
"id": "6b02e42b-f9e6-4bce-97a3-08a027bf6e58",
"name": "Sticky Note6"
},
{
"parameters": {
"content": "## Reponse",
"height": 240,
"width": 200,
"color": 7
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
940,
160
],
"id": "af52b476-dc6f-44bf-b6a2-e7cf82f0c058",
"name": "Sticky Note7"
},
{
"parameters": {
"promptType": "define",
"text": "={{ $json.message.text }}",
"options": {
"returnIntermediateSteps": true
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 1.9,
"position": [
220,
0
],
"id": "a3d81b58-528b-4bfc-b0f0-416db8303eb8",
"name": "AI Agent",
"onError": "continueErrorOutput"
},
{
"parameters": {
"content": "# \ud83d\udee0\ufe0f Setup Guide \n**Author:** [Nate Herk](https://www.youtube.com/@nateherk)\n\nTo get this workflow up and running, follow these steps:\n\n1. **Connect your [OpenRouter API key](https://openrouter.ai/)** \n Make sure you\u2019ve added it under Credentials in n8n.\n\n2. **Connect your Telegram account** \n Set up your Telegram Bot credentials and ensure it's authorized.\n\n3. **Connect any tool credentials** \n Link the tools you want this workflow to interact with \u2014 this may include CRMs, email platforms, etc.\n\n4. **Connect the Google Sheet template** \n Use [this template](https://docs.google.com/spreadsheets/d/1ImjPm2JF-uhxa9ZZ12yO3Pq7q9PakYobrdAk57c9z8c/edit?usp=sharing) and link it to the Google Sheets node in your workflow.\n\nOnce all connections are set up, you're good to go!\n",
"height": 540,
"width": 520
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-600,
-80
],
"id": "173a7f5e-1dd2-41c8-8d57-1fdf12158d91",
"name": "Sticky Note8"
}
],
"connections": {
"4.1-mini": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Send Email": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get Contacts": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Create Event": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Clean Up": {
"main": [
[
{
"node": "Log",
"type": "main",
"index": 0
}
]
]
},
"Telegram Trigger": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Errors": {
"main": [
[
{
"node": "Error Response",
"type": "main",
"index": 0
}
]
]
},
"Log": {
"main": [
[
{
"node": "Response",
"type": "main",
"index": 0
}
]
]
},
"Clean_Up": {
"main": [
[
{
"node": "Errors",
"type": "main",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Clean Up",
"type": "main",
"index": 0
}
],
[
{
"node": "Clean_Up",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "af9b7b0b-241b-4183-9987-c7ede3190c73",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "iTVv4EMeEzvP6ODO",
"tags": []
}
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.
airtableTokenApigmailOAuth2googleCalendarOAuth2ApigoogleSheetsOAuth2ApiopenRouterApitelegramApi
About this workflow
Log Agent Outputs. Uses lmChatOpenRouter, gmailTool, airtableTool, googleSheets. Event-driven trigger; 21 nodes.
Source: https://github.com/Zie619/n8n-workflows — original creator credit. Request a take-down →