Inspiration
Indonesia's 65 million SMEs lose deals daily to one boring failure: sales follow-up. The owner is doing five jobs at once, leads sit cold for a week, and the prospect quietly buys from someone else. Existing "AI sales tools" stop at "draft an email" — but the actual money only moves when payment lands.
Niaga is built for that gap: a seven-agent team that does not just send email. It argues with itself about each lead, writes in real business Indonesian, classifies replies, and closes the loop by sending a DOKU payment link. The owner defines the offer once; the agents do the rest.
What it does
Define one Indonesian Ideal Customer Profile and one offer. Niaga then runs a continuous autonomous loop:
| # | Agent | Role |
|---|---|---|
| 1 | Prospector | Enriches each lead with web data |
| 2 | Bull | Argues for pursuing the lead |
| 3 | Bear | Argues against — surfaces real risks |
| 4 | Judge | Renders an explainable verdict |
| 5 | Outreach | Drafts and sends Bahasa Indonesia email |
| 6 | Reply | Classifies the prospect's response by intent |
| 7 | Closer | Decides if and when to fire a DOKU payment link |
Plus an AfterCare agent triggered by the DOKU webhook on payment receipt, and a deterministic Orchestrator that strings them together with no human clicks between "lead in" and "money in."
Everything streams to a live agent feed UI so the operator can watch the agents think, debate, and act in real time.
How we built it
- LLM: Google Gemini via Vertex AI.
gemini-2.5-profor reasoning agents (Judge, Outreach, Closer),gemini-2.5-flashfor fast classifiers (Prospector, Bull, Bear, Reply, AfterCare). - Backend: FastAPI + SQLAlchemy + WebSockets for the agent feed, deployed to Google Cloud Run.
- Frontend: React + Vite + TypeScript + Tailwind, with id/en i18n.
- Email: Gmail SMTP for send, IMAP for receive, with quoted-reply stripping so we hand the LLM clean text.
- Payment: DOKU Checkout v1 API in sandbox, fully wired through the HMAC signing scheme and webhook verification.
- Infra: Cloud Run with
min-instances=1so the IMAP poller is always alive — judges do not need to click anything for the system to react to a reply.
Challenges we ran into
- DOKU's HMAC signature is not what the stub assumed. The first sandbox call returned
invalid_signature. The spec requires newline-separatedClient-Id / Request-Id / Request-Timestamp / Request-Target / Digestwith base64-encoded SHA-256 digest and anHMACSHA256=header prefix. Fixed, and now generates realstaging.doku.com/checkout-link-v2/...links end-to-end. - A live personal Gmail with 10,000+ unread emails drowns a naive
SEARCH UNSEENpoller. We narrowed toUNSEEN SINCE <today-2d>with a hard cap so the poll always completes within a run's lifetime. - The original
inbox_loopwas tied to a specificAgentRunand died when the run completed — meaning the judge would have had to manually start a run for every reply to be detected. Refactored into a single always-onglobal_inbox_loopstarted by the FastAPI lifespan, paired with--min-instances=1so the container never scales to zero.
Accomplishments we are proud of
- A real autonomous loop: in the live demo, you reply to the outreach email and within ~15 seconds the system has classified your intent, decided whether to send a payment link, and (if you said "kirim payment link") dropped a real DOKU sandbox checkout URL into the thread — without any operator click.
- Adversarial qualification with explainable verdicts: every lead carries a permanent record of why the Bull pushed for it, why the Bear pushed back, and how the Judge resolved it.
- True Bahasa Indonesia outreach, not English-with-translate. Business-formal register by default, switchable via the Sales Voice setting.
What we learned
- LLMs are unreliable JSON producers; every agent boundary needs a
_parse_errorfallback that gracefully degrades the lead's status instead of crashing the run. - "Always-on" is harder than it sounds on Cloud Run: you need lifespan hooks,
min-instances >= 1, and an external state store (not ephemeral SQLite) before the demo is truly production-shaped. - Adversarial multi-agent design (Bull/Bear/Judge) catches more bad leads than a single classifier — the Bear keeps the Bull honest in a way that a higher temperature alone cannot.
What is next for Niaga
- Switch SQLite → managed Postgres (Neon / Cloud SQL) so the campaign survives a deploy.
- Wire DOKU's webhook URL per payment method so the AfterCare agent fires reliably on every paid transaction.
- Indonesian-specific lead finding via Google Maps Places + LinkedIn enrichment.
- A quota / cost cap dashboard so SME owners can confidently leave the agents running overnight.
Built With
- bahasa-indonesia
- doku
- fastapi
- gmail
- google-cloud
- google-gemini
- multi-agent
- python
- react
- sqlalchemy
- tailwindcss
- typescript
- vite
- websockets
Log in or sign up for Devpost to join the conversation.