[{"parameters":{"httpMethod":"POST","path":"chat","responseMode":"responseNode","options":{"allowedOrigins":"*"}},"id":"aa000000-0000-4000-8000-000000000001","name":"Webhook","type":"n8n-nodes-base.webhook","typeVersion":2,"position":[-460,0],"webhookId":"aa000000-0000-4000-8000-0000000000f1"},{"parameters":{"jsCode":"// Susun payload untuk Command Code Provider API (format OpenAI Chat Completions)\nconst input = $input.first().json;\nconst body = input.body ?? {};\nconst query = input.query ?? {};\n\nconst sessionId = String(body.sessionId ?? query.sessionId ?? 'default');\nconst userMessage = String(body.message ?? query.message ?? '').trim();\n\nif (!userMessage) {\n  throw new Error('Field \"message\" wajib diisi.');\n}\n\nconst model = body.model ?? $env.CHAT_MODEL ?? 'deepseek/deepseek-v4-flash';\nconst systemPrompt = body.system ?? $env.SYSTEM_PROMPT ?? 'Kamu adalah asisten AI yang membantu.';\n\n// Memori percakapan per-session. Persisten hanya pada eksekusi produksi\n// (webhook production), tidak tersimpan saat klik 'Test workflow'.\nconst staticData = $getWorkflowStaticData('global');\nstaticData.memory = staticData.memory || {};\nconst stored = staticData.memory[sessionId] || [];\n\nconst history = Array.isArray(body.history)\n  ? body.history\n  : stored.slice(-10);\n\nconst messages = [\n  { role: 'system', content: systemPrompt },\n  ...history,\n  { role: 'user', content: userMessage },\n];\n\nreturn [{ json: { sessionId, model, messages, userMessage } }];"},"id":"aa000000-0000-4000-8000-000000000002","name":"Build Request","type":"n8n-nodes-base.code","typeVersion":2,"position":[-240,0]},{"parameters":{"method":"POST","url":"={{ $env.CMD_API_BASE + '/chat/completions' }}","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","sendBody":true,"specifyBody":"json","jsonBody":"={{ JSON.stringify({ model: $json.model, messages: $json.messages, stream: false }) }}","options":{"timeout":120000,"response":{"response":{"neverError":false}}}},"id":"aa000000-0000-4000-8000-000000000003","name":"Command Code API","type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[0,0],"retryOnFail":true,"maxTries":3,"waitBetweenTries":3000,"onError":"continueRegularOutput"},{"parameters":{"jsCode":"// Ambil jawaban model, simpan ke memori, siapkan respons HTTP.\nconst staticData = $getWorkflowStaticData('global');\nstaticData.memory = staticData.memory || {};\n\nconst req = $('Build Request').item.json;\nconst res = $input.first().json;\n\nconst upstreamError = res.error;\nconst reply = upstreamError\n  ? `[error] ${upstreamError.message ?? JSON.stringify(upstreamError)}`\n  : (res.choices?.[0]?.message?.content ?? '').trim();\n\nif (!upstreamError && reply) {\n  const history = staticData.memory[req.sessionId] || [];\n  history.push({ role: 'user', content: req.userMessage });\n  history.push({ role: 'assistant', content: reply });\n  staticData.memory[req.sessionId] = history.slice(-20);\n}\n\nreturn [{\n  json: {\n    sessionId: req.sessionId,\n    model: req.model,\n    reply,\n    error: upstreamError ? true : false,\n    usage: res.usage ?? null,\n  },\n}];"},"id":"aa000000-0000-4000-8000-000000000004","name":"Extract Reply","type":"n8n-nodes-base.code","typeVersion":2,"position":[220,0]},{"parameters":{"respondWith":"json","responseBody":"={{ JSON.stringify({ sessionId: $json.sessionId, reply: $json.reply, error: $json.error, usage: $json.usage }) }}","options":{"responseCode":"={{ $json.error ? 502 : 200 }}"}},"id":"aa000000-0000-4000-8000-000000000005","name":"Respond to Webhook","type":"n8n-nodes-base.respondToWebhook","typeVersion":1.1,"position":[440,0]}]
