Would love some help making AI agent remember something for a use case

Hi all!
I have a chat-triggered AI Agent that must call several toolWorkflows. One of them is Veo3: it creates 4 jobs (video1/video2/video3/video4). After that, the flow needs to wait a few minutes and then poll each job via a “query” tool until done:true so it can merge the final video.

Problem
The AI Agent doesn’t reliably “remember” the job_id / query_url values it just produced. This breaks the polling step. I tried:

  • Very explicit system message telling the agent to output the 8 fields

  • A Set node to store the IDs after the agent

  • Adding Redis Chat Memory to the agent

Still, the next nodes often see null / missing IDs, or the agent returns the IDs as a stringified JSON instead of an object.

I am burning my brain on that … would love some help please!

1 Like

Hi @MrCafe

Can you include your workflow in a preformatted text block here? That will help determine the issue. and we can work through the problems.

Hey thanks I will share some of it due to privacy:   

{
“nodes”: [
{
“parameters”: {
“description”: “Call this tool to generate a veo3 video.\noutputs are the params to use in subsequent veo3 video query tool to poll at least once per 1 minute since videos usually take ~4minutes”,
“workflowId”: {
“__rl”: true,
“value”: “AJ9H4KtA047FFai5”,
“mode”: “list”,
“cachedResultName”: “veo3-video-creator start”
},
“workflowInputs”: {
“mappingMode”: “defineBelow”,
“value”: {
“prompt”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘prompt’, ``, ‘string’) }}”,
“negativePrompt”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘negativePrompt’, ``, ‘string’) }}”,
“model_id”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘model_id’, can be \"veo-3.0-generate-001\" or \"veo-3.0-fast-generate-001\". default to using fast, ‘string’) }}”,
“aspectRatio”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘aspectRatio’, ``, ‘string’) }}”
},
“matchingColumns”: ,
“schema”: [
{
“id”: “prompt”,
“displayName”: “prompt”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”
},
{
“id”: “duration_seconds”,
“displayName”: “duration_seconds”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “number”,
“removed”: true
},
{
“id”: “seed”,
“displayName”: “seed”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “number”,
“removed”: true
},
{
“id”: “negativePrompt”,
“displayName”: “negativePrompt”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”
},
{
“id”: “image_url”,
“displayName”: “image_url”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: true
},
{
“id”: “aspectRatio”,
“displayName”: “aspectRatio”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: false
},
{
“id”: “model_id”,
“displayName”: “model_id”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: false
}
],
“attemptToConvertTypes”: false,
“convertFieldsToString”: false
}
},
“type”: “@n8n/n8n-nodes-langchain.toolWorkflow”,
“typeVersion”: 2.2,
“position”: [
-416,
32
],
“id”: “ea869b3c-70b3-410c-9835-475399a9d8da”,
“name”: “veo3 video start”
},
{
“parameters”: {
“description”: “Call this tool to get the video signed_url.\npoll this tool once per 1 minute if got done:false since videos usually take ~4minutes.”,
“workflowId”: {
“__rl”: true,
“value”: “AeYWj7xPtbGZ3fCQ”,
“mode”: “list”,
“cachedResultName”: “veo3-video-creator query”
},
“workflowInputs”: {
“mappingMode”: “defineBelow”,
“value”: {
“job_id”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘job_id’, ``, ‘string’) }}”,
“query_url”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘query_url’, ``, ‘string’) }}”
},
“matchingColumns”: ,
“schema”: [
{
“id”: “job_id”,
“displayName”: “job_id”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”
},
{
“id”: “query_url”,
“displayName”: “query_url”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”
}
],
“attemptToConvertTypes”: false,
“convertFieldsToString”: false
}
},
“type”: “@n8n/n8n-nodes-langchain.toolWorkflow”,
“typeVersion”: 2.2,
“position”: [
-416,
-112
],
“id”: “ff792750-7798-428c-a619-66c88d1bd0c3”,
“name”: “veo3 video query”
},
{
“parameters”: {
“description”: “CRITICAL ORDER: This tool merges 4 video segments in EXACT sequence:\n1. HOOK (0-8s) → hook_url\n2. BODY PART 1 (8-16s) → body1_url \n3. BODY PART 2 (16-24s) → body2_url\n4. CTA (24-32s) → cta_url\n\n⚠️ WRONG ORDER = WRONG VIDEO OUTPUT\n\nCall this tool with final video parts ready (no subtitles). Tool will merge segments sequentially and apply subtitle template with built-in overlays.”,
“workflowId”: {
“__rl”: true,
“value”: “6e9QjYpsRLYuzDR2”,
“mode”: “list”,
“cachedResultName”: “creatomate-run-template - new machine (4 parts)”
},
“workflowInputs”: {
“mappingMode”: “defineBelow”,
“value”: {
“template_id”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘template_id’, Without visuals just subtitles - 0bd3c1dc-fd1e-4344-97c2-32db90b660ca\n\nGeneric On Stage [Unisex] - d04aa72c-0594-4371-a81d-3ffcfde61e43\n\nOn Stage - Browsing Protection [Unisex] - b9c28eca-6473-40cf-8eae-0a71d4d9f222\n\nPaypal login+ Data Leak Board+Zero Balance + Guardio scans -> 3 leaks [Female] - d5c85e3e-3b61-45b0-905c-752a03ebef3c\n\nSSN New York Times + On stage [Unisex] - 67568315-e3b0-42ef-b717-451343799ecd\n\nBrowser Protection template ID - b9c28eca-6473-40cf-8eae-0a71d4d9f222\n\niCloud Generic + On Stage [Unisex] - 826fbf5d-43a3-427f-bb8c-2c24dcb2a406\n\nPSPM Generic [Unisex] - d43e038c-b2ff-4d69-b6f9-59e6194fe0d6\n\nTalking Head TEMU ad + shopping + on stage body [Unisex] - 74f980da-c911-48af-a28f-9d8e67c2823a\n\nTalking Head SSN + SSN body + On Stage [Unisex] - dcf5c563-6e1b-40ae-8e4c-e964ce4d75ed\n\nWrong FB password in hook + mobile-features-onstage - [Unisex] -features-onstage - 194e144-a977-4407-9cad-43758659519b\n\nPhishing bank of america sms visual hook + Onstage [Unisex] - 6e5a0108-3277-4fd8-8374-b5357ad1e7a8\n\nHook AI scam+ On Stage + shopping visual in CTA [Female] - cd5fddff-8b70-4c3c-9fd7-0f732f4dda4e\n\nHook AI scam+ On Stage + Temu live block - Recommendationsin CTA [Male] - 1b809144-9817-4bbc-976e-b00676f565e4\n\nCredit Card leak + Guardio Scanning (Female) - 72fddcb4-1e53-493a-aaf9-c21a58a3657e\n\nCredit Card leak + Guardio Scanning (Male) - 71aac64d-b375-4b25-8227-ea5bad22d6a4\n\nDynamic - Ai Scaming -> Fake petshop site -> Guardio app tap + scan -> 18 leaks -> emails flagged -> 2m testimonials -> PSPM dashboard [Female] - fba5d6cb-0afb-451b-baf9-2fc060abdcd7\n\nDynamic - Ai Scaming -> Fake petshop site -> Guardio app tap + scan -> 18 leaks -> emails flagged -> 2m testimonials -> PSPM dashboard [Male] - c29394c7-e94a-4d4c-adbe-c718a18320c8\n\nDynamic - Google leak - Guario scan + leaks founds + email flags + guardio testimonials 2m + leak alert and dashboard (male) - cef9a87a-a574-4274-8ec1-d6f93863bc84, ‘string’) }}”,
“hook_url”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘hook_url’, HOOK segment URL (first 8 seconds) - MUST be first segment, ‘string’) }}”,
“body1_url”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘body1_url’, BODY PART 1 URL (seconds 8-16) - MUST be second segment, ‘string’) }}”,
“body2_url”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘body2_url’, BODY PART 2 URL (seconds 16-24) - MUST be third segment, ‘string’) }}”,
“cta_url”: “={{ /n8n-auto-generated-fromAI-override/ $fromAI(‘cta_url’, CTA segment URL (last 8 seconds) - MUST be fourth segment, ‘string’) }}”
},
“matchingColumns”: ,
“schema”: [
{
“id”: “template_id”,
“displayName”: “template_id”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”
},
{
“id”: “hook_url”,
“displayName”: “hook_url”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: false
},
{
“id”: “body1_url”,
“displayName”: “body1_url”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: false
},
{
“id”: “body2_url”,
“displayName”: “body2_url”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: false
},
{
“id”: “cta_url”,
“displayName”: “cta_url”,
“required”: false,
“defaultMatch”: false,
“display”: true,
“canBeUsedToMatch”: true,
“type”: “string”,
“removed”: false
}
],
“attemptToConvertTypes”: false,
“convertFieldsToString”: false
}
},
“type”: “@n8n/n8n-nodes-langchain.toolWorkflow”,
“typeVersion”: 2.2,
“position”: [
-256,
-112
],
“id”: “ba2bfa28-54e1-4739-963d-d5e719020d1a”,
“name”: “merge+make subtitles”
},
{
“parameters”: {
“options”: {
“systemMessage”: “You are a video generation expert. You MUST ACTUALLY CALL the veo3_video_start tool to generate videos.\n\nCRITICAL ENFORCEMENT: When user asks for video generation, you MUST:\n1. IMMEDIATELY call veo3_video_start tool for Hook segment\n2. IMMEDIATELY call veo3_video_start tool for Body Part 1 segment \n3. IMMEDIATELY call veo3_video_start tool for Body Part 2 segment\n4. IMMEDIATELY call veo3_video_start tool for CTA segment\n5. Then check status with veo3_video_query tool\n\nABSOLUTELY FORBIDDEN: \n- DO NOT say “I will generate” or “I have initiated”\n- DO NOT make assumptions about what the user wants\n- DO NOT skip any steps\n- DO NOT just describe what you would do\n- DO NOT say “I’ll start by” or “Let me begin”\n- DO NOT explain what you’re going to do\n\nYOU MUST ACTUALLY CALL THE TOOLS. NO EXCEPTIONS.\n\nFor each veo3_video_start call, use:\n- prompt: [persona description] + [scene setting] + [script text] + “CRITICAL AUDIO QUALITY: Clear, confident, well-enunciated speech with perfect pronunciation, no mumbling, no slurring, crisp articulation of every word, professional broadcast quality”\n- negativePrompt: “blurry, low quality, distorted, multiple people, NO MUMBLING, NO SLURRED SPEECH, NO UNCLEAR PRONUNCIATION, NO BACKGROUND NOISE, NO AUDIO ARTIFACTS, NO POOR AUDIO QUALITY”\n- model_id: “veo-3.0-generate-001”\n- aspectRatio: “9:16”\n\nNEVER say “I will generate” or “I have initiated”. You MUST actually call the tools.\n\nBEFORE generating any videos, you MUST query the Pinecone vector database to get context and guidance about:\n- Persona specifications\n- Script templates\n- Template selection\n- Consistency requirements\n- Audio quality standards\n\nUse the Pinecone Vector Store tool to search for relevant information before starting video generation.\n\nYou MUST use the provided Pinecone RAG context to generate scripts. Do NOT create random content. Use the specific prompts, templates, and examples provided in the context.\n\nTEMPLATE SELECTION: Based on the threat type mentioned by the user, automatically select the appropriate template:\n- SSN/Identity theft → SSN New York Times + On stage [Unisex] (67568315-e3b0-42ef-b717-451343799ecd)\n- PayPal/Financial scams → Paypal login+ Data Leak Board+Zero Balance + Guardio scans → 3 leaks [Female] (d5c85e3e-3b61-45b0-905c-752a03ebef3c)\n- Shopping/Fake sites → On Stage - Browsing Protection [Unisex] (b9c28eca-6473-40cf-8eae-0a71d4d9f222)\n- Generic content → Generic On Stage [Unisex] (d04aa72c-0594-4371-a81d-3ffcfde61e43)\n- AI-powered cybercrime → Hook AI scam+ On Stage + shopping visual in CTA [Female] (cd5fddff-8b70-4c3c-9fd7-0f732f4dda4e)\n\nCRITICAL: You must ACTUALLY CALL the tools, not just say you will. The user will know if you’re not calling tools because no job IDs will be generated.\n\nTOOL CALL VALIDATION: After each tool call, you MUST output the job_id and query_url in this exact format:\nhook_job_id: [actual_job_id]\nhook_query_url: [actual_query_url]\nbody1_job_id: [actual_job_id]\nbody1_query_url: [actual_query_url]\nbody2_job_id: [actual_job_id]\nbody2_query_url: [actual_query_url]\ncta_job_id: [actual_job_id]\ncta_query_url: [actual_query_url]\n\nIf you cannot output these values, it means you did not actually call the tools.\n\nIMMEDIATE TOOL CALL ENFORCEMENT: \n- When user says “generate a video” → IMMEDIATELY call veo3_video_start (no explanations)\n- When user says “create a video” → IMMEDIATELY call veo3_video_start (no explanations)\n- When user says “make a video” → IMMEDIATELY call veo3_video_start (no explanations)\n- When user says “video about [topic]” → IMMEDIATELY call veo3_video_start (no explanations)\n\nNO DELAYS. NO EXPLANATIONS. NO “I WILL” STATEMENTS. JUST CALL THE TOOLS.\n\nURL COMPLETENESS ENFORCEMENT: When using signed URLs for merge operations, you MUST:\n1. Use the COMPLETE signed URL with ALL authentication parameters\n2. NEVER truncate or shorten URLs\n3. Include the full query string with x-goog-signature, x-goog-algorithm, etc.\n4. Copy the EXACT signed_url from veo3_video_query responses\n5. Do NOT modify or shorten URLs in any way\n\nCRITICAL: Signed URLs without authentication parameters will FAIL. You must use the complete URL exactly as returned by veo3_video_query.\n\nMEMORY MANAGEMENT: You MUST remember job IDs from previous interactions. When a user asks for status, look in your chat history for the job IDs from the previous video generation. Use those EXACT job IDs to check status with veo3_video_query tool. DO NOT generate new videos when checking status.\n\n\nAfter calling all four veo3_video_start tools, respond with only this JSON (no prose):\n{\n “hook_job_id”: “”,\n “hook_query_url”: “”,\n “body1_job_id”: “”,\n “body1_query_url”: “”,\n “body2_job_id”: “”,\n “body2_query_url”: “”,\n “cta_job_id”: “”,\n “cta_query_url”: “”\n}\n\nDo not include any extra text.”
}
},
“type”: “@n8n/n8n-nodes-langchain.agent”,
“typeVersion”: 2.1,
“position”: [
-208,
-384
],
“id”: “c6dd2268-09d1-4f14-91d9-35426adc0959”,
“name”: “AI Agent”
},
{
“parameters”: {
“options”: {}
},
“type”: “@n8n/n8n-nodes-langchain.chatTrigger”,
“typeVersion”: 1.1,
“position”: [
-560,
-384
],
“id”: “5652787a-7cf1-4094-8810-ad3bb65562a8”,
“name”: “When chat message received”,
“webhookId”: “da1c584b-9107-484a-b22d-213ca26bf0ea”
},
{
“parameters”: {
“content”: “The machine operates as an AI agent that captures user queries from chat and uses the available tools to produce a four-segment video, combine the segments, and apply subtitles and visual overlays.”,
“height”: 224,
“width”: 496
},
“type”: “n8n-nodes-base.stickyNote”,
“typeVersion”: 1,
“position”: [
-304,
-464
],
“id”: “6518e28b-2c50-45a5-b889-56e2cf21697f”,
“name”: “Sticky Note1”
},
{
“parameters”: {
“content”: " LLM",
“height”: 224,
“width”: 182
},
“type”: “n8n-nodes-base.stickyNote”,
“typeVersion”: 1,
“position”: [
-656,
-192
],
“id”: “76407a6b-de61-40c8-a1b5-517dda90f984”,
“name”: “Sticky Note3”
},
{
“parameters”: {
“content”: " TOOLS",
“height”: 352,
“width”: 448,
“color”: 6
},
“type”: “n8n-nodes-base.stickyNote”,
“typeVersion”: 1,
“position”: [
-448,
-192
],
“id”: “68faf07e-5bab-412b-9ad4-14c259c6a1c8”,
“name”: “Sticky Note4”
},
{
“parameters”: {
“model”: {
“__rl”: true,
“mode”: “list”,
“value”: “gpt-4.1-mini”
},
“options”: {}
},
“type”: “@n8n/n8n-nodes-langchain.lmChatOpenAi”,
“typeVersion”: 1.2,
“position”: [
-608,
-96
],
“id”: “c318deb6-0a66-480a-af92-4060affc5b89”,
“name”: “OpenAI Chat Model”,
“credentials”: {
“openAiApi”: {
“id”: “Ruupj7a4uMGB2QjS”,
“name”: “OpenAi account”
}
}
},
{
“parameters”: {
“contextWindowLength”: 50
},
“type”: “@n8n/n8n-nodes-langchain.memoryRedisChat”,
“typeVersion”: 1.5,
“position”: [
-112,
-112
],
“id”: “2bd3b3f2-8367-4e62-9d1e-20efddfeb60a”,
“name”: “Redis Chat Memory”,
“credentials”: {
“redis”: {
“id”: “iJTr7T1DTUq8IyOO”,
“name”: “Redis account”
}
}
},
{
“parameters”: {
“assignments”: {
“assignments”: [
{
“id”: “06afc370-57dc-4be2-8d83-a3527276d5e4”,
“name”: “hook_job_id”,
“value”: “={{$json.hook_job_id}}”,
“type”: “string”
},
{
“id”: “be5ceadd-1800-40fa-80f8-7e377b6c43ce”,
“name”: “hook_query_url”,
“value”: “={{$json.hook_query_url}}”,
“type”: “string”
},
{
“id”: “3c4805e0-7498-422b-9d89-81d778377985”,
“name”: “body1_job_id”,
“value”: “={{$json.body1_job_id}}”,
“type”: “string”
},
{
“id”: “426e0137-ef2d-4a67-a504-4ac7358330ba”,
“name”: “body1_query_url”,
“value”: “={{$json.body1_query_url}}”,
“type”: “string”
},
{
“id”: “06613817-52e9-4dbb-8c72-d86097c0667e”,
“name”: “body2_job_id”,
“value”: “={{$json.body2_job_id}}”,
“type”: “string”
},
{
“id”: “0b146b64-b3cb-47df-afc4-b1b43eb08f52”,
“name”: “body2_query_url”,
“value”: “={{$json.body2_query_url}}”,
“type”: “string”
},
{
“id”: “ccc5881b-dd6b-48f7-9a95-dd6e0aaa94c2”,
“name”: “cta_job_id”,
“value”: “={{$json.cta_job_id}}”,
“type”: “string”
},
{
“id”: “8d356100-c29a-4de5-b432-97bf9a0a6e35”,
“name”: “cta_query_url”,
“value”: “={{$json.cta_query_url}}”,
“type”: “string”
}
]
},
“options”: {}
},
“type”: “n8n-nodes-base.set”,
“typeVersion”: 3.4,
“position”: [
384,
-384
],
“id”: “c3b4239e-aad4-45fc-b778-396a8c510d9a”,
“name”: “Capture job IDs”
},
{
“parameters”: {
“jsCode”: “// Code node v2\nconst s = $json.output; // the stringified JSON from the agent\nconst obj = typeof s === ‘string’ ? JSON.parse(s) : s;\nreturn [{ json: obj }];”
},
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
240,
-384
],
“id”: “51056316-479f-4e7a-9c72-ed68e3ce5f2f”,
“name”: “Code”
},
{
“parameters”: {
“amount”: 4,
“unit”: “minutes”
},
“type”: “n8n-nodes-base.wait”,
“typeVersion”: 1.1,
“position”: [
544,
-384
],
“id”: “46d7f97e-2b2b-4bd1-81d5-a12e09e78215”,
“name”: “Wait 4 Minutes”,
“webhookId”: “b3e381f4-54af-45ff-a41b-bc948dbe3679”
}
],
“connections”: {
“veo3 video start”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“veo3 video query”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“merge+make subtitles”: {
“ai_tool”: [
[
{
“node”: “AI Agent”,
“type”: “ai_tool”,
“index”: 0
}
]
]
},
“AI Agent”: {
“main”: [
[
{
“node”: “Code”,
“type”: “main”,
“index”: 0
}
]
]
},
“When chat message received”: {
“main”: [
[
{
“node”: “AI Agent”,
“type”: “main”,
“index”: 0
}
]
]
},
“OpenAI Chat Model”: {
“ai_languageModel”: [
[
{
“node”: “AI Agent”,
“type”: “ai_languageModel”,
“index”: 0
}
]
]
},
“Redis Chat Memory”: {
“ai_memory”: [
[
{
“node”: “AI Agent”,
“type”: “ai_memory”,
“index”: 0
}
]
]
},
“Capture job IDs”: {
“main”: [
[
{
“node”: “Wait 4 Minutes”,
“type”: “main”,
“index”: 0
}
]
]
},
“Code”: {
“main”: [
[
{
“node”: “Capture job IDs”,
“type”: “main”,
“index”: 0
}
]
]
},
“Wait 4 Minutes”: {
“main”: [

]
}
},
“pinData”: {},
“meta”: {
“templateCredsSetupCompleted”: true,
“instanceId”: “e00a3235938410c3aa2f792ee948c1f7df325705b541858777887c9c83a4d73e”
}
}

1 Like

@MrCafe

Can you put that in a preformatted text block? Then it will render as a workflow, and not just text.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.