{
 "name": "[노드 한 장] Custom Code Tool · 샘플 할인 합계는 고정 JS로",
 "nodes": [
  {
   "id": "manual",
   "name": "Run manually",
   "type": "n8n-nodes-base.manualTrigger",
   "typeVersion": 1,
   "position": [
    0,
    0
   ],
   "parameters": {}
  },
  {
   "id": "agent",
   "name": "AI Agent",
   "type": "@n8n/n8n-nodes-langchain.agent",
   "typeVersion": 3.1,
   "position": [
    260,
    0
   ],
   "parameters": {
    "promptType": "define",
    "text": "직접 작성한 가상 샘플입니다. 단가 50000원, 수량 3개, 할인 10%의 합계를 calculate_discount_total 도구로 정확히 한 번 계산하세요. 도구 입력 query는 {\"unitPrice\":50000,\"quantity\":3,\"discountPercent\":10} JSON 문자열이어야 합니다. 배송비와 추가 세금은 없다고 가정합니다. 도구 결과를 받은 뒤 숫자와 원만 포함한 최종 답을 하세요. 스스로 계산한 값을 도구 결과 대신 사용하지 마세요.",
    "options": {
     "systemMessage": "당신은 샘플 계산을 도구에 맡기는 실습 Agent입니다. 사용 가능한 도구는 calculate_discount_total입니다. 지시된 JSON 문자열을 도구에 보내고 관측한 도구 반환값만 최종 답에 사용하세요. 내부 사고 과정은 출력하지 마세요.",
     "maxIterations": 3,
     "returnIntermediateSteps": false,
     "enableStreaming": false,
     "forceToolCallOnFirstIteration": true
    }
   }
  },
  {
   "id": "model",
   "name": "OpenAI Chat Model",
   "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
   "typeVersion": 1.2,
   "position": [
    160,
    240
   ],
   "parameters": {
    "model": {
     "__rl": true,
     "mode": "list",
     "value": "gpt-4.1-mini",
     "cachedResultName": "gpt-4.1-mini"
    },
    "options": {
     "temperature": 0,
     "maxTokens": 200,
     "maxRetries": 0
    }
   }
  },
  {
   "id": "tool",
   "name": "calculate_discount_total",
   "type": "@n8n/n8n-nodes-langchain.toolCode",
   "typeVersion": 1.3,
   "position": [
    440,
    240
   ],
   "parameters": {
    "description": "샘플 할인 합계를 고정 JavaScript 산술로 계산합니다. query는 unitPrice, quantity, discountPercent 숫자를 담은 JSON 문자열이어야 합니다. 예: {\"unitPrice\":50000,\"quantity\":3,\"discountPercent\":10}. 반환값은 합계 숫자의 문자열입니다. 배송비와 추가 세금은 포함하지 않습니다.",
    "language": "javaScript",
    "jsCode": "// 직접 작성한 가상 샘플. JSON 숫자를 검증하고 고정 산술만 수행합니다.\nconst p = JSON.parse(query);\nconst unitPrice = Number(p.unitPrice);\nconst quantity = Number(p.quantity);\nconst discountPercent = Number(p.discountPercent);\nif (!Number.isFinite(unitPrice) || unitPrice <= 0 || !Number.isInteger(quantity) || quantity <= 0 || !Number.isFinite(discountPercent) || discountPercent < 0 || discountPercent > 100) {\n  throw new Error('Invalid numeric inputs');\n}\nconst total = unitPrice * quantity * (1 - discountPercent / 100);\nif (!Number.isFinite(total)) throw new Error('Invalid total');\nreturn String(total);",
    "specifyInputSchema": false
   }
  }
 ],
 "connections": {
  "Run manually": {
   "main": [
    [
     {
      "node": "AI Agent",
      "type": "main",
      "index": 0
     }
    ]
   ]
  },
  "OpenAI Chat Model": {
   "ai_languageModel": [
    [
     {
      "node": "AI Agent",
      "type": "ai_languageModel",
      "index": 0
     }
    ]
   ]
  },
  "calculate_discount_total": {
   "ai_tool": [
    [
     {
      "node": "AI Agent",
      "type": "ai_tool",
      "index": 0
     }
    ]
   ]
  }
 },
 "settings": {
  "executionOrder": "v1",
  "timezone": "Asia/Seoul"
 },
 "meta": {
  "templateCredsSetupCompleted": false,
  "source": "datapopcorn.ai/workflow/nodes"
 }
}