"I already built this in Zapier, why would I need an agent?" A year ago the answer was easy. Not anymore — Zapier shipped AI Orchestration in July 2026, Make shipped AI Agents in its canvas earlier the same year. "Does a model decide something" stopped being the dividing line.

This post continues my series on building agents. The previous one covered writing a good agent prompt.

What's actually still different

A trigger-action platform's workflow shape — which apps, roughly what order — is drawn by a human ahead of time in the builder, even when one step now delegates to a model. An agent you build yourself, the way this series has, decides that whole shape at runtime: which tools apply, in what order, for this specific message.

flowchart TD subgraph Fixed automation F0[Any trigger] --> F1[Step A, always] --> F2[Step B, always] end subgraph Agent A0[Any message] --> AD{Model reads it} AD -->|only A applies| A1[Step A] AD -->|only B applies| A2[Step B] AD -->|both apply| A3[Step A and Step B] AD -->|neither applies| A4[No tool, just reply] end

Proving it in code

// agent/fixed-vs-agent.ts import Anthropic from '@anthropic-ai/sdk'; const client = new Anthropic(); const expenses: { item: string; amount: number }[] = []; const log: string[] = []; function addExpense(item: string, amount: number) { expenses.push({ item, amount }); return { ok: true, recorded: expenses.length }; } function getTotal() { return { total: expenses.reduce((sum, e) => sum + e.amount, 0) }; } function notify(message: string) { log.push(message); return { sent: true }; } function runFixedAutomation(item: string, amount: number) { const step1 = addExpense(item, amount); const step2 = notify(`Recorded: ${item} (${amount})`); return { step1, step2 }; } const tools: Anthropic.Tool[] = [ { name: 'add_expense', description: 'Record one expense. Use it whenever the user says they spent money.', input_schema: { type: 'object', properties: { item: { type: 'string' }, amount: { type: 'number' } }, required: ['item', 'amount'], }, }, { name: 'get_total', description: "Return the exact sum of every expense recorded so far. Use this whenever the user asks for a total, a sum, or how much they've spent overall.", input_schema: { type: 'object', properties: {} }, }, { name: 'notify', description: 'Send the user a short notification. Use this only when the user explicitly asks to be notified or reminded.', input_schema: { type: 'object', properties: { message: { type: 'string' } }, required: ['message'], }, }, ]; function execute(name: string, input: Record<string, unknown>): unknown { if (name === 'add_expense') return addExpense(String(input.item), Number(input.amount)); if (name === 'get_total') return getTotal(); if (name === 'notify') return notify(String(input.message)); return { error: 'unknown tool' }; } async function runAgent(userText: string): Promise<string> { const messages: Anthropic.MessageParam[] = [{ role: 'user', content: userText }]; for (let step = 0; step < 4; step++) { const response = await client.messages.create({ model: 'claude-sonnet-5', max_tokens: 300, tools, messages, }); messages.push({ role: 'assistant', content: response.content }); if (response.stop_reason !== 'tool_use') { const block = response.content.find((b): b is Anthropic.TextBlock => b.type === 'text'); return block?.text ?? ''; } const results: Anthropic.ToolResultBlockParam[] = []; for (const block of response.content) { if (block.type === 'tool_use') { results.push({ type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(execute(block.name, block.input as Record<string, unknown>)), }); } } messages.push({ role: 'user', content: results }); } return 'Stopped: step limit reached'; } runAgent('I spent 500 on lunch.').then(console.log); 

runFixedAutomation always runs both steps, regardless of content. runAgent, same three tools, picks a different path for "I spent 500 on lunch" (just add_expense), "what's my total" (just get_total), and "I spent 200 on tea, notify me" (both) — decided by the model each time, not written into the function.

The near-miss writing this

The first draft argued no-code tools can't reason, full stop. Checking current reality before publishing caught that it was already wrong — both platforms shipped real agent features this year. The fix was rebuilding the comparison around what's still true, not whether a model is involved at all.

Common mistakes

  • Assuming "no-code" still means "no reasoning."
  • Treating a platform's AI Agent feature as equivalent to building your own.
  • Writing custom code for a job the platform's library already covers.
  • Forcing a complex, stateful job into a platform's bounded actions.

Read the full version

I write each post in English and Bangla. The full version is on my blog: AI Agent vs Zapier/Make

Where's your line between "use the platform" and "build it yourself"?