Files · Vertex AI Multi-Agent Handoff for ServiceTitan Dispatch Automation
69 (1 binary, 691.5 kB total)attempt 2
README.md·4512 B·markdown
markdown
# Vertex AI Multi-Agent Handoff for ServiceTitan Dispatch Automation
> An AI dispatch mesh that runs `classify → confidence gate → route → dispatch` to triage field service requests, schedule appointments, and assign technicians in ServiceTitan via REST, reducing manual coordination.
A tutorialized reference solution from [reaatech.com](https://reaatech.com), demonstrating how to build production-grade AI systems with the `@reaatech/*` package family.
## Architecture
```
Webhook → Intake Agent (classify) → Confidence Gate → Dispatch Agent → ServiceTitan API
```
The multi-agent mesh uses **Vertex AI** (Gemini) for natural language understanding to classify incoming service requests via `@reaatech/agent-mesh-classifier`. Classified requests are routed through a **confidence gate** (`@reaatech/agent-mesh-confidence`) that decides whether to route directly to the dispatch agent, ask for clarification, or fall back to a default handler. Stateful transfers between agents are managed by `@reaatech/agent-handoff-routing`. The dispatch agent reads/writes job data through ServiceTitan's REST API (OAuth2).
## Prerequisites
- **Node.js** >= 22
- **pnpm** 10.x
- **Google Cloud** project with Vertex AI API enabled
- **ServiceTitan** tenant with API credentials (OAuth2 client_credentials)
## Quick start
```bash
pnpm install
cp .env.example .env # fill in your GCP + ServiceTitan + Langfuse credentials
pnpm dev # starts Next.js dev server
```
## API endpoints
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/webhook` | Accepts a service request JSON body (`{ raw_input: string }`), classifies it, optionally dispatches a technician, returns a decision |
| `GET` | `/api/dispatch` | Returns dispatch job status given `?jobId=<id>` |
## Agent mesh flow
1. **Intake classification** — `@reaatech/agent-mesh-classifier` classifies raw input against an agent registry (intake, dispatch)
2. **Confidence gating** — `evaluateConfidenceGate` applies a 6-rule decision tree: unknown agent → default, default agent → route, session bypass → route, sufficient confidence → route, clarification enabled → clarify, otherwise → fallback
3. **Handoff routing** — `@reaatech/agent-handoff-routing` selects the optimal agent using weighted scoring (skill match 40%, domain match 30%, load factor 20%, language match 10%)
4. **Dispatch execution** — The dispatch agent queries ServiceTitan for available technicians, validates scheduling constraints, and creates a job
## Environment variables
| Variable | Description |
|---|---|
| `GOOGLE_CLOUD_PROJECT` | GCP project ID for Vertex AI |
| `GOOGLE_CLOUD_LOCATION` | GCP region for Vertex AI (e.g., us-central1) |
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to GCP service account JSON |
| `SERVICETITAN_CLIENT_ID` | ServiceTitan OAuth2 client ID |
| `SERVICETITAN_CLIENT_SECRET` | ServiceTitan OAuth2 client secret |
| `SERVICETITAN_TENANT_ID` | ServiceTitan tenant identifier |
| `SERVICETITAN_API_BASE_URL` | ServiceTitan API base URL |
| `LANGFUSE_PUBLIC_KEY` | Langfuse public key for tracing |
| `LANGFUSE_SECRET_KEY` | Langfuse secret key for tracing |
| `LANGFUSE_BASE_URL` | Langfuse host URL |
## Testing
```bash
pnpm test # vitest run with coverage
pnpm typecheck # tsc --noEmit
pnpm lint # eslint .
```
All tests mock externals via `msw` (HTTP) and `vi.mock` (package-level). No live API calls during tests.
## Project layout
```
app/ Next.js App Router pages + API routes
src/
├── agents/ Intake and dispatch agents
├── integration/ ServiceTitan REST client
├── lib/ LLM adapter, env config
├── mesh.ts Orchestrator
├── observability.ts Langfuse tracing
└── types/ Shared types and schemas
tests/ vitest suite (mirrors src/)
├── setup.ts MSW server + global mocks
├── types.test.ts
├── env.test.ts
├── llm.test.ts
├── servicetitan.test.ts
├── intake.test.ts
├── dispatch.test.ts
├── mesh.test.ts
├── handoff-routing.test.ts
├── webhook.test.ts
├── dispatch-api.test.ts
├── observability.test.ts
└── index.test.ts
packages/ API references for every dependency (read these first)
DEV_PLAN.md build plan for this recipe
```
## License
MIT — see [LICENSE](./LICENSE).