4 ready-to-build workflows

AI agent workflows for EV charging networks

Triage charge-point downtime, classify failed sessions into refund proposals and answer drivers in their own language — with every dispatch, refund and offline decision human-approved.

Each recipe below is expressed only in VegaDūta's real workflow building blocks — Trigger, Agent, Knowledge, Condition, Approval, Output, Tool (MCP), Voice, Device, Loop, Code and Parallel — so it maps 1:1 to something you can assemble in the Workflow designer. Consequential actions always pass a human Approval step.

1. Charge-point downtime triage (map-reduce, 2 agents)

Today: the CPMS dashboard is open on a second monitor all day, and the network ops engineer scrolls a wall of OCPP alarms — Faulted, comms lost, ground-fault trip, connector-lock failure — most of which clear themselves. Anything that looks real gets typed into a shared Google Sheet called 'Downtime Tracker', colour-coded by whoever is on shift, and the field team is told in a WhatsApp group ('Sec 62 DC-2 down again, anyone nearby?'). Whether a charger actually got reset is remembered, not recorded. In practice the genuinely dead ones are found by a driver at 9pm, not by the wall.

Trigger: Webhook (CPMS alarm stream / scheduled open-alarm pull)

How the workflow runs

  1. Trigger

    Alarm batch arrives. A Webhook trigger receives the alarm batch pushed by the OCPP charge-point management system, or fires on a schedule and pulls the open-alarm list. The CPMS has no first-party connector — it is reached inbound via Webhook and read back via a Tool (MCP) node.

  2. Loop

    Map: iterate every alarm. A Loop node fans a cheap triage agent across each alarm — one focused pass per record, isolated context — so a 400-alarm morning is handled exactly like a 4-alarm one.

  3. Agent

    Triager classifies + proposes. The triage agent returns strict JSON per alarm (fault family, station/EVSE id, whether it is self-clearing noise, and a proposed action: WATCH / REMOTE_RESET / DISPATCH / TAKE_OFFLINE) grounded in the fault-code playbook in Knowledge. It proposes only — it never resets or dispatches.

  4. Tool (MCP)

    Enrich with utilisation + site context. A Tool (MCP) node pulls the last 7 days of sessions and uptime for each flagged station from the CPMS, and any site-level power event from the energy/DISCOM meter feed — so a whole site down on an upstream trip is not triaged as twelve independent charger faults.

  5. Code

    Band the priority with the operator's own rule. A Code node calls the tenant's user-defined SpEL tool to turn severity plus recent usage into a P1/P2/P3 band. The threshold lives in the tool, so ops can retune what counts as P1 without a developer or a redeploy.

  6. Agent

    Reduce: build the shift picture. A reducer agent aggregates the validated items into one shift briefing: repeat offenders, sites sharing a common upstream cause, the reset candidates and the dispatch candidates ranked by driver impact.

  7. Approval

    Ops approves resets, dispatches and offlines. An Approval node holds every proposed remote reset, engineer dispatch and take-offline decision. Taking a charger offline strands drivers and a dispatch spends a field slot — a human owns both.

  8. Device

    Execute the approved remote resets. For approved items only, a Device (Device Control) node issues the remote reset to the charge point — the platform's real device-control path, still gated behind the Approval above.

  9. Output

    Post the briefing + open the tickets. A Tool (MCP) node raises work orders in the field-service tool for approved dispatches and marks approved stations unavailable in the CPMS; an Output node posts the shift briefing to Slack and Email. Unapproved items stay a watch-list — visible, not lost.

Channels & connectors

  • Webhook
  • Tool (MCP → CPMS / OCPP)
  • Tool (MCP → field-service dispatch)
  • Device Control
  • Approval / HITL
  • Slack
  • Email

Outcome

The whole alarm wall is triaged into a ranked shift briefing every run, with self-clearing noise separated from genuinely dead chargers, a written record of what was reset, and a human owning every reset, dispatch and offline.

Why it helps

Map-reduce turns an unbounded manual scroll into cheap per-alarm passes plus one synthesis, and the shift briefing replaces the colour-coded sheet and the WhatsApp group as the record of what was actually done. The engineer's attention moves from sorting alarms to approving the handful of actions that cost money or strand a driver.

Build spec

2 agents1 triage agent (runs once per alarm via the Loop node) + 1 reducer (runs once). Loop, Code, Approval and Device Control are workflow nodes, not agents. · Pattern: Map-reduce: Loop (map) → reducer (reduce) → human approves resets/dispatches → Device Control executes

System prompt (paste-ready)

(Triager) Triage ONE charge-point alarm. Return strict JSON {fault_family (COMMS_LOST|GROUND_FAULT|CONNECTOR_LOCK|OVER_TEMP|EVSE_FAULTED|UNKNOWN), station_id, evse_id, self_clearing (true|false), severity (LOW|MED|HIGH), proposed_action (WATCH|REMOTE_RESET|DISPATCH|TAKE_OFFLINE), reason}. Judge only from the alarm's own fields and the fault-code playbook in the ops Knowledge collection — never invent a fault code, a station id or a repair. A proposed REMOTE_RESET or DISPATCH is a RECOMMENDATION only; you never execute either. If the record is malformed or the code is unknown, set proposed_action=WATCH with reason='needs verification'.

Agent roles & model tiers

  • Alarm triager (per alarm) Economy tier, with a fallback model configured — it runs N times per batch so its model choice dominates total cost, and a provider outage must degrade the triage, never stall the shift

    Classify ONE OCPP alarm into schema-valid JSON with a proposed action. Null for missing fields, zero invented fault codes or station ids, and REMOTE_RESET/DISPATCH/TAKE_OFFLINE are only ever recommendations.
  • Shift reducer (once) Standard tier — reasoning over the whole batch, one call per shift

    Aggregate the validated per-alarm results into one shift briefing: repeat-offender stations, sites sharing an upstream power cause, the reset candidates and the dispatch candidates ranked by driver impact. Use only the provided items and the enrichment data — cite real session counts, never estimate uptime.

MCP connectors

  • OCPP charge-point management (CPMS) — via Tool (MCP): pull the open-alarm list, fetch connector status and 7-day session/uptime history per station, and write the availability state for approved offlines. Inbound alarms arrive by Webhook. No first-party connector.
  • Field-service dispatch / work-order tool — via Tool (MCP): create a work order for an approved dispatch with the station id, fault family and site access notes, and read back its status. No first-party connector.
  • Energy / DISCOM meter feed — via Tool (MCP): fetch site-level power events in the alarm window, so an upstream trip is identified as one cause rather than twelve faults. No first-party connector.
  • Slack + Email — first-party channels for the shift briefing.

Built-in tools

  • knowledge_search (scoped to the OCPP fault-code playbook + per-site runbooks collection)
  • http_request (pull alarms and session history, write availability, open work orders)
  • user-defined tool `alarm_priority_band` (SpEL): input.severity == 'HIGH' && input.sessionsLast7d > 40 ? 'P1' : (input.severity == 'HIGH' || input.sessionsLast7d > 40 ? 'P2' : 'P3') — a pure formula over the tool's JSON input, no API calls, no loops. It matters because 'what counts as P1' is an operator-specific judgement about traffic and SLA, and encoding it in a tenant-authored expression means ops can retune the thresholds themselves without a developer or a new deployment.

Guardrails

  • The agents only propose — every remote reset, engineer dispatch and take-offline passes the Approval node before the Device Control node or the CPMS is touched
  • Schema validation on each triage output — a malformed or unknown-code alarm is dropped to WATCH, never auto-reset and never silently dispatched
  • Idempotent per alarm id and per station, so a replayed alarm batch cannot double-dispatch an engineer or reset a charger twice
  • Remote reset is only ever offered for fault families the playbook lists as reset-safe; anything with a ground-fault or over-temp signature is forced down the DISPATCH path for a human, never reset remotely
  • Unapproved items become a persisted watch-list rather than disappearing — the failure mode of the old spreadsheet was silent loss, not wrong decisions

Cost strategy

Cost is linear and predictable: N × (economy-tier, hard-capped triager) + ONE standard-tier reduce. Because the triager runs across the entire alarm stream — the highest-volume step by far — it MUST sit on the economy tier; that single choice is the dominant cost lever. Configure a fallback model on it so a provider outage degrades the triage instead of stalling the shift. The reducer's one call per shift is where the reasoning budget belongs. Run the map in Parallel batches for wall-clock speed without changing per-item cost.

Output & delivery

Loop maps the cheap triager over every alarm → a Tool (MCP) node enriches the flagged stations with session history and site power events → the Code node bands priority with the operator's own SpEL rule → the reducer synthesizes one shift briefing → ops approves at the Approval node → a Device Control node fires only the approved remote resets, a Tool (MCP) node opens the approved work orders and sets approved stations unavailable in the CPMS, and an Output node posts the briefing to Slack and Email.

2. Failed charging session → grounded refund proposal (2 agents)

Today: a driver pays, plugs in, gets 0.4 kWh, and the session dies. They message the support number on the charger. The support executive opens four things — the CPMS session view for the meter start/stop, the alarm history for that connector around that timestamp, the payment gateway dashboard for the capture, and a Google Sheet where refunds are logged before someone in finance actions them in a batch on Friday. Deciding one ₹280 refund takes fifteen minutes of tab-switching, so the queue is triaged by who complained loudest, and a good share end up as bank disputes instead.

Trigger: Webhook (session-ended event) / WhatsApp (driver complaint)

How the workflow runs

  1. Trigger

    Failed session detected or reported. A Webhook from the CPMS fires on a session that ended abnormally (zero/near-zero energy, error stop reason), or a WhatsApp/SMS message from the driver starts the same flow — so the network finds these before the driver does.

  2. Tool (MCP)

    Assemble the evidence in one pass. Tool (MCP) nodes pull the session record and meter start/stop values from the CPMS, the connector's alarm history in a ±15-minute window, and the payment capture and settlement state from the payment ledger. This is the four-tabs step, done once, deterministically.

  3. Agent

    Fault-attribution agent. An Agent node classifies the session against the refund policy in a scoped Knowledge collection: network fault (charger faulted, comms lost, mid-session abort), vehicle-side stop, or driver-initiated stop — citing the exact fields it used, with an explicit UNCLEAR verdict when the evidence does not decide it.

  4. Condition

    Evidence sufficient?. A Condition node branches: a clean, evidenced verdict flows to the refund proposal; UNCLEAR or missing meter values route straight to a human queue rather than being guessed into a decision.

  5. Code

    Band the remedy with the operator's own formula. A Code node calls the tenant's user-defined SpEL tool to turn energy-delivered-vs-promised into a refund band. The operator's own commercial policy lives in that expression, not in a prompt — so it is auditable and identical on every single session.

  6. Agent

    Resolution drafter. A second agent drafts the proposed remedy — full refund, partial (energy actually delivered vs charged, shown arithmetically), or no refund with a plain-language reason — plus the driver-facing message in the driver's own language via Sarvam.

  7. Approval

    Support lead approves the refund. An Approval node holds the refund amount and the outgoing message. A refund moves real money and a 'no refund' reply is a customer commitment — both are human decisions, never agent-executed.

  8. Output

    Issue + reply. On approval, the refund is issued through Razorpay (UPI) for the approved amount, a Tool (MCP) node stamps the resolution on the session record, and an Output node replies to the driver on WhatsApp/SMS in their language.

Channels & connectors

  • Webhook
  • WhatsApp
  • SMS
  • Razorpay (UPI)
  • Sarvam (Indian languages)
  • Tool (MCP → CPMS)
  • Tool (MCP → payment ledger)
  • Approval / HITL

Outcome

Every failed session arrives at the support lead as an evidenced verdict with a banded amount and a ready-to-send reply in the driver's language — decided in one place instead of four browser tabs and a Friday spreadsheet.

Why it helps

The slow part of a refund was never the decision, it was assembling meter values, alarm history and the payment record by hand. Automating the assembly, banding the amount with the operator's own formula, and keeping the money movement human-approved is what turns a Friday batch into a same-day answer — the lead still owns every rupee that moves.

Build spec

2 agents1 fault-attribution agent + 1 resolution drafter. The evidence pull, the sufficiency branch, the refund banding (Code + SpEL tool), the approval and the refund execution are workflow nodes. · Pattern: Evidence assembly → attribution agent → Condition gate → operator formula → drafter → human approves the money

System prompt (paste-ready)

(Fault attribution) You classify ONE failed EV charging session. Inputs: session record {start, stop, stop_reason, meter_start, meter_stop, energy_kwh, amount_charged}, the connector's alarm history in a ±15-minute window, and the payment capture record. Return strict JSON {verdict (NETWORK_FAULT|VEHICLE_SIDE|DRIVER_STOPPED|UNCLEAR), evidence[] (the exact fields/alarms you relied on), energy_delivered_kwh, amount_charged}. Apply ONLY the refund policy in the Knowledge collection you are scoped to. Never infer a meter value that is absent — if meter values are missing or the alarms do not decide it, return UNCLEAR and stop. You do not decide, band or issue a refund; you produce the evidenced verdict a human will act on.

Agent roles & model tiers

  • Fault attribution (per session) Economy tier with a fallback model — this is the high-volume step (every abnormal session runs it) and it reads structured fields, not prose, so a small model genuinely suffices

    Classify one failed session into NETWORK_FAULT / VEHICLE_SIDE / DRIVER_STOPPED / UNCLEAR, citing the exact evidence fields. Missing meter values ⇒ UNCLEAR, never a guessed verdict.
  • Resolution drafter (decided verdicts only) Standard tier — policy reasoning plus customer-facing writing, Sarvam-backed for Indian languages; it never sees the UNCLEAR cases, which is the second cost lever

    Given a decided verdict and the refund band from the operator's own SpEL tool, draft the remedy — showing the partial-refund arithmetic (energy delivered vs amount charged) — and the driver message in their language. Present it as a proposal for approval; never say the refund has been issued.

MCP connectors

  • OCPP CPMS — via Tool (MCP): fetch the session record with meter start/stop, pull the connector's alarm history for a ±15-minute window around the failure, and stamp the approved resolution back onto the session. Inbound session-ended events arrive by Webhook. No first-party connector.
  • Payment settlement / reconciliation ledger — via Tool (MCP): look up the capture and settlement state for the session's payment reference, so a refund is never proposed against an uncaptured or already-refunded charge. No first-party connector.
  • Razorpay (UPI) — real first-party connector: issues ONLY the approved refund amount, after the Approval node.
  • WhatsApp / SMS — first-party driver channels for the complaint and the reply.
  • Sarvam — first-party Indian-language drafting for the driver reply.

Built-in tools

  • knowledge_search (scoped to the refund + fault-attribution policy collection)
  • http_request (pull session, meter, alarm and payment records; stamp the resolution)
  • user-defined tool `session_refund_band` (SpEL): input.kwhDelivered == 0 ? 'FULL_REFUND' : (input.kwhDelivered < input.kwhPromised * 0.5 ? 'PARTIAL' : 'NONE') — a formula over the tool's JSON input only: no API calls, no loops, no code execution. It matters because the refund threshold is a commercial policy the operator owns, not a model judgement; putting it in a tenant-authored expression makes it identical on every session, visible to an auditor, and changeable by the support lead without a developer.
  • user-defined tool `driver_locale` (SpEL): input.preferredLanguage ?: (input.simCircle != null ? input.simCircle : 'en') — an elvis fallback that picks the reply language deterministically instead of asking the model to guess it.

Guardrails

  • No refund is ever issued by an agent — the amount and the outgoing message both pass the Approval node, and only then does the Razorpay UPI refund execute
  • UNCLEAR is a first-class verdict: missing meter values or inconclusive alarms route to a human queue instead of being reasoned into a refund
  • The refund band comes from the tenant's SpEL formula, not from the model — the model explains the number, it does not choose it
  • Partial-refund arithmetic is shown explicitly (energy delivered vs amount charged) so the approver can check the figure rather than trust it
  • Idempotent per session id and per payment reference — a replayed session-ended webhook or a duplicate driver message can never trigger a second refund
  • The agent may never state or imply to a driver that a refund has been issued; only the post-approval Output node says that

Cost strategy

Tier by volume: the attribution agent runs on EVERY abnormal session, so it sits on the economy tier with a hard token cap and a fallback model for provider outages. The drafter runs only on sessions that reached a decided verdict, so the standard tier is bought for a fraction of the traffic — and UNCLEAR cases never reach it at all. The refund amount itself costs nothing to compute, because it is a SpEL formula rather than an inference call; that is deliberate, since a policy threshold should be deterministic and auditable, not sampled.

Output & delivery

The Tool (MCP) nodes assemble session, alarm and payment evidence in one pass → the economy-tier agent produces an evidenced verdict → the Condition node routes UNCLEAR to humans → the Code node bands the remedy with the operator's own SpEL formula → the standard-tier drafter proposes the amount and the driver message → the support lead approves at the Approval node → Razorpay issues the approved refund, a Tool (MCP) node stamps the session record, and an Output node replies on WhatsApp/SMS in the driver's language.

3. RFID / app authorisation failures — first-line driver support in their language

Today: a driver taps their RFID card at 10pm and the screen says 'Authorization failed'. They call the helpline printed on the unit. It rings into a shared mobile handled by whoever is free, usually in English or Hindi only, and that person has no idea which of five different things went wrong — expired tag, tag never assigned to the account, a roaming/eMSP token the network rejected, a failed pre-auth on the card, or the charger itself being offline — because checking means logging into the CPMS on a laptop they are not sitting at. So the answer is 'sir, please try another charger', and the driver is standing at a kerb in the dark deciding whether to trust this network again.

Trigger: WhatsApp / Voice call / SMS (driver stuck at a charger)

How the workflow runs

  1. Trigger

    Driver reaches out. A WhatsApp, SMS or inbound Voice/Call trigger starts the session — the driver typically reads out the station id printed on the unit, or shares their location.

  2. Voice

    Voice handling in the driver's language. On the call path, a Voice node handles the conversation with ElevenLabs for natural speech and Sarvam for Indian-language understanding, so a driver in Coimbatore or Nagpur is not forced into English at a kerbside at night.

  3. Tool (MCP)

    Look up the real reason. Tool (MCP) nodes query the CPMS for that station's live connector status and its last authorisation attempts, and the token/account registry for the tag or app-account state — the laptop step, done in two seconds inside the conversation.

  4. Agent

    Diagnose + guide. An Agent node maps the evidence to a documented cause in a scoped Knowledge collection (expired tag, unassigned tag, roaming token rejected, pre-auth failed, charger offline) and gives the driver the specific next step — including whether another connector at the same site is genuinely free right now.

  5. Condition

    Self-serve or escalate?. A Condition node branches: causes with a documented driver-side fix are handled in the conversation; anything needing a network-side change (re-issuing a tag, releasing a stuck pre-auth, marking the charger down) routes onward.

  6. Approval

    Human owns any account or network change. An Approval node holds every network-side action — re-issuing or re-binding an RFID tag, releasing a held pre-auth, flagging the station as down. These touch a driver's account, their money, or the network's availability state.

  7. Output

    Resolve or hand over. An Output node confirms the outcome and, when the fix needs a human, hands the full diagnosis and transcript to the support queue — so the driver never re-explains it to a second person.

Channels & connectors

  • WhatsApp
  • SMS
  • Voice / Call
  • ElevenLabs (voice)
  • Sarvam (Indian languages)
  • Tool (MCP → CPMS)
  • Tool (MCP → token / account registry)
  • Approval / HITL

Outcome

A stuck driver gets the actual reason and one concrete next step in their own language within the first exchange, at any hour — and anything that touches their account or the network's state reaches a human with the diagnosis already done.

Why it helps

The failure mode here is information, not effort: 'Authorization failed' hides five causes that need five different actions, and the person answering the shared mobile cannot see any of them. Grounding the answer in the live station and token state, spoken in the driver's own language, is what turns 'try another charger' into a first-exchange resolution.

Build spec

1 agent1 diagnosis agent. The voice handling, the self-serve/escalate branch, the account-change approval and the queue handover are workflow nodes.

System prompt (paste-ready)

You are first-line support for {{network}}'s EV charging drivers. A driver is standing at a charge point and authorisation failed. Using ONLY the live station status, the last authorisation attempts and the token/account state provided to you, identify the cause from the documented list in your Knowledge collection (TAG_EXPIRED | TAG_UNASSIGNED | ROAMING_TOKEN_REJECTED | PREAUTH_FAILED | CHARGER_OFFLINE | UNKNOWN) and give ONE clear next step. Reply in the driver's language. Never invent a station id, a tariff, a tag number or an availability claim; if the lookup did not return it, say you are checking and hand over. You may NOT re-issue a tag, release a pre-auth, refund anything or change a station's state — propose it and the workflow routes it to a human. If the cause is UNKNOWN, say so plainly and hand over rather than guessing.

Agent roles & model tiers

  • Driver-support diagnosis agent Standard tier with a fallback model — it is live, in-conversation and multilingual via Sarvam (ElevenLabs handles speech on the call path); a fallback matters more here than anywhere else, because the driver is standing at a kerb and a provider outage cannot mean silence

    Map live station + token evidence to one documented cause, give one concrete next step in the driver's language, and escalate anything requiring a network-side change. Never claim availability, tariffs or account changes that were not returned by the lookup.

MCP connectors

  • OCPP CPMS — via Tool (MCP): fetch live connector status for the station the driver names, list the last authorisation attempts for that connector with their reject reasons, and check sibling connectors at the same site for genuine current availability. No first-party connector.
  • RFID token / driver-account registry — via Tool (MCP): resolve the tag or app account to its state (valid, expired, unassigned, roaming token) and its bound account, read-only from the agent's side. No first-party connector.
  • WhatsApp / SMS / Voice — first-party driver channels.
  • ElevenLabs — first-party voice output on the call path.
  • Sarvam — first-party Indian-language understanding and reply.

Built-in tools

  • knowledge_search (scoped to the authorisation-failure playbook + per-site tariff and access FAQ)
  • http_request (station status, authorisation attempts, token state)
  • user-defined tool `auth_next_step_code` (SpEL): input.tagState == 'EXPIRED' ? 'RENEW_TAG' : (input.tagState == 'UNASSIGNED' ? 'BIND_TAG' : (input.connectorStatus == 'Faulted' || input.connectorStatus == 'Unavailable' ? 'USE_ALT_CONNECTOR' : (input.preauthFailed ? 'RETRY_PAYMENT' : 'ESCALATE'))) — a pure decision formula over the tool's JSON input: no API calls, no loops. It matters because the mapping from state to advice is the operator's own support policy; encoding it as a tenant-authored expression means the same state always yields the same instruction, the agent explains it rather than inventing it, and support can change the policy without touching a prompt or shipping a release.

Guardrails

  • The agent diagnoses and guides only — re-issuing or re-binding a tag, releasing a pre-auth, issuing any credit, or marking a station down all pass the Approval node
  • Every factual claim (station status, free connectors, tariff, tag state) must come from the live lookup; no availability or price is ever asserted from memory
  • The next-step instruction comes from the tenant's SpEL decision tool, so identical states never produce differently-worded advice on different calls
  • UNKNOWN is an allowed answer and triggers a handover with the full transcript — the agent never guesses a cause to close the conversation
  • The escalation handover carries the diagnosis and transcript, so the driver never repeats themselves to the human agent

Cost strategy

This is a live, one-at-a-time conversation rather than a batch, so there is no per-item multiplier — but it IS the driver-facing surface, so the standard tier is the right floor: a cheap model that hallucinates a tariff or a free connector costs far more than the model saving. Keep cost down structurally instead — the Tool (MCP) lookups and the SpEL decision tool do the factual and policy work so the prompt stays short, and documented self-serve causes close in the conversation without ever reaching a human. Configure a fallback model so the helpline degrades gracefully rather than going quiet.

Output & delivery

The Voice/WhatsApp trigger opens the session (ElevenLabs + Sarvam on the call path) → Tool (MCP) nodes fetch live station and token state → the SpEL tool maps that state to the operator's own next step → the agent explains it in the driver's language → the Condition node splits self-serve from network-side → any account or availability change waits at the Approval node → an Output node confirms the resolution or hands the full diagnosis and transcript to the support queue.

4. Tariff change & site-status broadcast, approved before it reaches a single driver

Today: a site goes down for a transformer upgrade on Saturday, or the tariff changes at midnight. Someone in marketing exports a driver list to Excel, tries to filter it down to people who have actually used that site, gives up and sends to everyone. The Hindi and Tamil versions are done by whoever in the office speaks them, pasted into the bulk-SMS tool by hand, and one of them says ₹18/kWh where the record says ₹18.50 — which becomes a pricing argument on Monday that support cannot win, because the message went out over the company's name.

Trigger: Webhook (tariff change / planned outage from the CPMS or ops tool)

How the workflow runs

  1. Trigger

    Change is published. A Webhook fires when a tariff revision or a planned site outage is entered in the CPMS/ops tool, carrying the exact rate, the effective timestamps and the affected site list — one source of truth instead of a forwarded email.

  2. Tool (MCP)

    Build the affected-driver audience. A Tool (MCP) node queries the CPMS/CRM for drivers who actually charged at the affected sites in the recent window, with their preferred language — so the audience is a query result, not an Excel filter someone gave up on.

  3. Agent

    Draft the message per language. An Agent node drafts the notice for each language via Sarvam, restating the exact effective date, the exact new rate or outage window, and the nearest alternative sites — copying every figure verbatim from the change record, never re-deriving it.

  4. Code

    Verify the numbers survived translation. A Code node re-checks each drafted variant against the source record using the operator's own SpEL formatter: the rate, the effective timestamp and the site list must match exactly across every language, or the draft is rejected before a human ever sees it. This is the ₹18-vs-₹18.50 bug, caught by arithmetic instead of by a customer.

  5. Approval

    Ops + comms sign off the broadcast. An Approval node holds the final audience count and every language variant. A tariff notice is a pricing commitment and a bad broadcast cannot be recalled — a human approves the exact text that goes out.

  6. Output

    Send on the driver's channel. An Output node delivers the approved variant on WhatsApp or SMS in each driver's preferred language, with the site name and the effective time.

Channels & connectors

  • Webhook
  • WhatsApp
  • SMS
  • Sarvam (Indian languages)
  • Tool (MCP → CPMS / driver CRM)
  • Approval / HITL

Outcome

Only the drivers who actually use an affected site hear about it, in their own language, with the rate and the window matching the source record exactly — and no notice leaves without a human approving the final text.

Why it helps

Two things go wrong with these broadcasts: the wrong audience and a number that drifted during hand-translation. Deriving the audience from real session history, and machine-checking every figure against the source record before the human sees it, is what turns the sign-off into a quick yes instead of a proofreading job in four languages.

Build spec

1 agent1 drafting agent producing all language variants. The audience build, the numeric verification (Code node + SpEL formatter), the broadcast approval and the send are workflow nodes.

System prompt (paste-ready)

You draft driver notices for {{network}}. Given a change record {type (TARIFF|PLANNED_OUTAGE), sites[], effective_from, effective_to, old_rate, new_rate, reason} and a target language, write a short notice for WhatsApp/SMS. Copy every number, date and site name VERBATIM from the change record — never round, re-derive, convert or restate a rate in your own words. Name alternative sites only from the list provided. No apology boilerplate, no invented compensation, no promise of a credit or discount. Output {language, body, numbers_used[]} so the workflow can verify every figure against the source. This is a draft for human approval; never present it as already sent.

Agent roles & model tiers

  • Multilingual notice drafter Standard tier with a fallback model, Sarvam-backed for Indian languages — it runs once per LANGUAGE variant, not per driver, so its cost never scales with audience size

    Produce one faithful notice per language with every figure copied verbatim from the change record, list the numbers used for verification, and never invent compensation or alternative sites.

MCP connectors

  • OCPP CPMS / ops tool — via Tool (MCP): read the full tariff-revision or planned-outage record (rate, effective window, affected site ids, reason) that the Webhook announced, so the drafter works from the record rather than the notification. No first-party connector.
  • Driver CRM / session history — via Tool (MCP): query drivers with a session at the affected sites inside the recent window and return their contact channel and preferred language, producing the audience as a query result. No first-party connector.
  • WhatsApp / SMS — first-party driver channels for the approved send.
  • Sarvam — first-party Indian-language drafting.

Built-in tools

  • knowledge_search (scoped to the comms policy + approved notice templates collection)
  • http_request (pull the change record and the affected-driver audience)
  • user-defined tool `tariff_line` (SpEL): 'Rate at ' + input.siteName + ': ' + input.newRate + ' per kWh (was ' + input.oldRate + ') from ' + input.effectiveFrom — string concatenation over the tool's JSON input, no method calls and no loops. It matters because this one line is the entire legal substance of the notice: generating it from the record with the operator's own format, and diffing it against what the model wrote in each language, is how a translated draft is proven to still carry the right number.
  • user-defined tool `rate_delta_direction` (SpEL): input.newRate > input.oldRate ? 'INCREASE' : (input.newRate < input.oldRate ? 'DECREASE' : 'UNCHANGED') — so the notice's framing is derived from arithmetic rather than inferred by the model.

Guardrails

  • Nothing sends without the Approval node — the final audience count and every language variant are approved as the exact text that will go out
  • The Code node hard-verifies each variant's rate, effective timestamp and site list against the source record via the SpEL formatter; a mismatch in any language blocks the WHOLE broadcast rather than sending the good ones
  • The audience is derived from real session history at the affected sites — no whole-base blasts, and drivers with no relationship to the site are never messaged
  • The agent may not invent compensation, credits, discounts or alternative sites not present in the source record
  • Idempotent per change-record id, so a resent webhook cannot broadcast the same notice twice

Cost strategy

Cost here scales with LANGUAGES, not with drivers — the agent drafts one variant per language and the Output node fans the approved text to the whole audience with no further model calls, which is the entire cost design and is what keeps a standard-tier model affordable for a large base. The verification is a deterministic SpEL formula plus a Code-node diff and costs nothing; using a model to check the numbers would be both costlier and less trustworthy. A fallback model keeps a time-boxed midnight tariff notice from missing its window on a provider outage.

Output & delivery

The Webhook change record and the Tool (MCP) audience query feed the drafter → one variant per language → the Code node rebuilds the tariff line with the operator's SpEL formatter and blocks the broadcast on any mismatch → ops and comms approve the exact text at the Approval node → an Output node sends on WhatsApp/SMS in each driver's preferred language.

Related industries

Build one of these in minutes

The sandbox gives you a live agent workspace — no account, no card. Or head back to the full catalogue and compare patterns across every industry.

See how VegaDūta compares to n8n, Dify and BotpressWhy VegaDūta's architectureEstimate your WhatsApp API costs