# Plan — Native Agentic Chatbot (retires the step-graph Flows)

> Design + phased build for the conversational AI agent that replaces the
> deterministic-flow approach — both the legacy n8n Gen-2 workflows and the
> native step-graph questionnaire engine (being retired). **Net-new: the
> platform has no LLM integration today.** Architecture is research-backed
> (single agent + deterministic rails + gated RAG — see "Architecture").

## Goal

Replace the form-like flow with one Claude agent that holds a natural,
progressive conversation, lets contacts pivot intents mid-chat, and routes the
captured data to the right destination. Categories are pluggable:

- **Leads → LeadRat** (native `LeadRatService`). It's a multi-**service**
  business — 10 lines (real-estate investment, Golden Visa, mortgage, company
  setup, banking, tax, property maintenance, pool, landscaping, waterproofing),
  all qualified as LeadRat leads.
- **Job seekers → email** (`careers@silveroakglobal.ae`).

v1 = conversational intake. Knowledge RAG (property/area/process Q&A) = phase 2.

## Architecture (research-backed)

A **single** Claude agent with **implicit in-prompt routing** (so pivots are
seamless and lossless) wrapped in **deterministic compliance rails** and
**scoped tools**. Not router→specialist (routing only works when classification
is accurate — mid-conversation pivots break it) and not multi-agent (its wins
are parallel research, ~15× tokens, not single-user chat).

- Native NestJS module `apps/api/src/agent/` driving a thin
  **provider-agnostic LLM client** in `packages/shared` — plain `fetch` +
  injectable `fetchFn`, mirroring the Meta/n8n clients, **no SDK dependency** —
  that targets DeepSeek's OpenAI/Anthropic-compatible endpoint **or** Claude,
  selected by the `connections` store.
- **Model (decided):** **start on Claude Haiku** (available now, strong Arabic)
  while DeepSeek-V4 credit approval is pending — then flip the default to
  **DeepSeek V4 Flash** (Pro/thinking for hard turns) once approved. Because the
  client is provider-agnostic this is a **config swap, zero architecture cost**.
  Claude stays as the configurable fallback (availability + Arabic safety net).
  Model + endpoint + key come from the `connections` store (`anthropic` exists;
  add a `deepseek` provider).
- **Cost levers:** on Claude, Anthropic **prompt caching** (`cache_control` on
  system + tools + history); on DeepSeek, **context caching is automatic + on by
  default** (cache hits ~98% cheaper). Plus **gated RAG** (retrieval only on
  knowledge turns), rolling **summarisation/compaction** as a chat grows, and
  cheap-vs-strong model routing.

## Tools (wrap existing native services — no new integrations)

| Tool | Backed by | Notes |
|---|---|---|
| `crm_lead` | `LeadRatService` create/update/appendNote | map to real LeadRat fields where they exist, not notes-soup |
| `send_whatsapp` | `MessageService.send` | consent + 24h window already enforced; on `window_closed` the agent sends an approved template |
| `record_consent` | `ConsentService` | also a deterministic pre-agent PDPL gate |
| `validate_phone` | existing `manychat-check-phone-number` webhook | port native later if desired |
| `send_email` | `EmailService` (+ CV pipeline) | job-seeker → careers@; CV handling: keep the n8n `Recruitment CV Receiver` side-effect, or port native (decide at P2) |
| `kb_search` *(phase 2)* | pgvector hybrid retrieval | tool-gated |

## Memory / state

- **History:** existing `messages` rows per contact.
- **Running summary + thread status:** additive **`agent_sessions`** table
  (`contactId` unique, `summary`, `status`, `model`, `tokensIn/Out`,
  `lastModelAt`).
- **Segment facts** (budget / area / service / buyer-type / consent / crmId):
  `Contact.attributes` JSON (already used for flow variables).
- **Out-of-band awareness:** read recent outbound template/campaign rows from
  `messages` so the agent knows what was broadcast to this contact.

## Inbound wiring

`BasicFlowEngine.dispatch()` gains an **exclusive agent path**: when the agent
is enabled (active `anthropic` connection + a setting flag), a conversational
inbound (i.e. not an opt-keyword — those stay terminal and ahead of the agent)
is handed to `AgentService.handle(incoming)`, which returns `{ handled: true }`
so the questionnaire engine and n8n dispatch are suppressed. This replaces the
`start_questionnaire` path as the conversational handler. **Feature-flagged and
test-number-gated** so it is inert until cutover.

## Data model

Additive migration only: new `agent_sessions` table. No destructive changes
(`Contact.attributes` already exists). Migrations are additive + applied with
`prisma migrate deploy` per CLAUDE.md.

## Phased build (TDD; commit + push per verified slice)

- **P0 — Scaffold.** Add `@anthropic-ai/sdk`; an Anthropic client in
  `packages/shared` (mirrors the Meta/n8n clients); `AgentModule` skeleton;
  read the `anthropic` connection; boot + `/health`.
- **P1 — Single-turn loop.** Build messages from history + a system prompt (the
  10 services, tone/buyer-type adaptation, progressive-profiling rules), call
  Claude, persist the reply via `MessageService`. No tools yet. Tests.
- **P2 — Tools + tool-use loop.** `crm_lead`, `send_whatsapp`, `record_consent`,
  `validate_phone`; loop until a final reply. Tests with stubbed services.
- **P3 — Memory + cost.** `agent_sessions` summary, `Contact.attributes` facts,
  prompt caching, compaction / tool-result clearing. Tests.
- **P4 — Inbound wiring + rails.** Deterministic PDPL gate; the agent path in
  `BasicFlowEngine` behind the flag; pivot handling; returning-lead recall.
  Tests.
- **P5 — Verify + cutover.** Test-/fresh-number end-to-end (lead, job-seeker,
  mid-chat pivot, consent); cut inbound from the questionnaire engine to the
  agent; **then** retire the step-graph engine + builder.
- **Phase 2 (later).** pgvector hybrid (Postgres FTS + vector) RAG + Cohere
  reranker + `kb_search`; promote the knowledge features (project search, area
  guides, mortgage/cost/visa explainers).

## Cutover & safety

`New Leads` and `Recruitment` run **live on the step-graph engine today**. Build
the agent behind a flag, verify on the test/fresh number, flip inbound, **then**
retire the step-graph — never delete-first, so live intake never goes dark.

## Open decisions (operator)

1. **Validate during build (not blocking):** DeepSeek's **Arabic** quality (its
   documented strength is Chinese; no Arabic benchmark found) — test early on the
   test number; and **API availability** (flagged less reliable than Anthropic)
   — covered by the Claude fallback. Confirm a monthly token-cost ceiling.
2. Job-seeker CV: keep delegating to the n8n `Recruitment CV Receiver`
   side-effect, or port it native? (decided at P2)
3. Phase-2 embeddings provider (Anthropic has none): OpenAI vs a local model on
   the VPS (mind the ~1k-PID cap).

## Testing (per CLAUDE.md)

TDD throughout. Per-package `npx vitest run --pool=forks
--poolOptions.forks.maxForks=2`; `pnpm --filter @whatapp/api build`; pm2 restart
+ `/health` (operator step for live). Never bare `pnpm test` (PID cap).

## Execution model — hybrid (local dev + VPS deploy/verify)

Matches this repo's proven loop and respects the ~1k-PID VPS cap:

- **Local (Windows clone):** all development — code, TDD (per-package
  `vitest --pool=forks` capped), typecheck, `pnpm build`, commit + push. P0–P4
  dev needs no live infra (unit tests stub the services).
- **VPS (live only):** `git pull`, additive `prisma migrate deploy`, build +
  `pm2 restart`, `/health`, and live test-number verification. Required for P3's
  migration and P5's end-to-end. **Never run tests / heavy builds on the VPS**
  (PID cap → false failures + competes with the live service).
- **Continuity:** git (push ↔ pull) + `HANDOFF.md` + operator-action-items —
  the same hand-off the repo already uses. Sequential per verified slice
  (dev → push → pull → deploy → verify), not parallel, to avoid drift.
- **Open:** drive the VPS steps via SSH (needs host + key) or hand them to the
  operator as today. P0–P2 + most of P3–P4 are fully local, so this is not
  needed until the first migration / live verify.
