Files · xAI Grok Knowledge Agent for Buildium Property Management Queries
82 (1 binary, 617.0 kB total)attempt 1
README.md·11020 B·markdown
markdown
# xAI Grok Knowledge Agent for Buildium Property Management Queries
> Answer tenant and property manager questions about leases, payments, and maintenance schedules using an AI agent connected to Buildium data.
A tutorialized reference solution from [reaatech.com](https://reaatech.com), demonstrating how to build production-grade AI systems with the `@reaatech/*` package family.
## Architecture
```
Buildium API ──► BuildiumSyncService ──► VoyageEmbeddingService ──► pgvector (PostgreSQL)
│ │
│ @reaatech/hybrid-rag-ingestion │
│ (chunks via chunkDocument / ChunkingStrategy.RECURSIVE) │
│ │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
@reaatech/hybrid-rag
(RAG types + retrieval)
│
▼
@reaatech/llm-router-core
(model routing + budget check)
│
▼
@ai-sdk/xai + ai (Vercel AI SDK)
(xAI Grok via generateText)
│
▼
@reaatech/session-continuity
(multi-turn conversation state)
│
▼
@reaatech/llm-cost-telemetry
(per-call cost tracking)
│
▼
@reaatech/agent-mesh
(IncomingRequest / AgentResponse schemas)
│
▼
Next.js API route (app/api/chat/route.ts)
──► JSON response
```
**Data flow:**
1. **Buildium API** — raw property management data (leases, tenants, work orders, properties) fetched via OAuth2-authenticated REST calls.
2. **BuildiumSyncService** — fetches all entity types, transforms each into `Document` objects (from `@reaatech/hybrid-rag`), validates and preprocesses content with `TextPreprocessor` / `DocumentValidator`, then chunks via `chunkDocument` (`@reaatech/hybrid-rag-ingestion`) using `ChunkingStrategy.RECURSIVE`.
3. **VoyageEmbeddingService** (`voyageai`) — embeds chunked text into 1024-dimensional vectors via the `voyage-3` model.
4. **pgvector** (`pgvector` + `postgres`) — stores embeddings in a `document_chunks` table with an HNSW index for fast cosine-distance search.
5. **RagRetrievalService** — on query, embeds the input and runs `<=>` (cosine distance) against the vector index, returning ranked `RetrievalResult[]`.
6. **LlmRouterService** (`@reaatech/llm-router-core`) — receives the retrieved context and session history, checks the daily budget via `CostTelemetryService` (`@reaatech/llm-cost-telemetry`), then calls `generateText` from `ai` + `@ai-sdk/xai` targeting the xAI Grok model.
7. **SessionManager** (`@reaatech/session-continuity`) — persists conversation turns to `sessions`/`messages` tables, enforces token budgets, and supports sliding-window compression for long conversations.
8. **KnowledgeAgentOrchestrator** — wires retrieval, session, routing, and cost tracking together using typed schemas from `@reaatech/agent-mesh` (`IncomingRequestSchema`, `AgentResponseSchema`).
9. **Next.js API route** — `POST /api/chat` accepts JSON, delegates to the orchestrator, returns `{ content, sessionId, sources }`.
**Key packages:**
| Package | Role |
|---|---|
| `@reaatech/hybrid-rag-ingestion` | Document chunking (`chunkDocument`, `ChunkingStrategy`) |
| `voyageai` | Embedding generation (Voyage AI API) |
| `pgvector` / `postgres` | Vector storage and similarity search |
| `@reaatech/hybrid-rag` | Document and retrieval types (`Document`, `RetrievalResult`) |
| `@reaatech/llm-router-core` | Model routing, budget checking |
| `@ai-sdk/xai` / `ai` | xAI Grok LLM access via Vercel AI SDK |
| `@reaatech/session-continuity` | Multi-turn conversation management |
| `@reaatech/llm-cost-telemetry` | Per-call cost tracking and daily budget enforcement |
| `@reaatech/agent-mesh` | Request/response schemas (`IncomingRequest`, `AgentResponse`) |
## Setup
### Prerequisites
- Node.js >= 22
- pnpm >= 10
- PostgreSQL 15+ with `pgvector` extension
### Environment variables
Copy `.env.example` to `.env.local` and fill in your credentials:
```bash
cp .env.example .env.local
```
Key variables (see `.env.example` for all):
| Variable | Description |
|---|---|
| `DATABASE_URL` | PostgreSQL connection string |
| `XAI_API_KEY` | xAI API key for Grok access |
| `VOYAGE_API_KEY` | Voyage AI API key for embeddings |
| `BUILDIUM_CLIENT_ID` / `BUILDIUM_CLIENT_SECRET` | Buildium OAuth2 credentials |
| `BUILDIUM_SYNC_INTERVAL_MINUTES` | How often to auto-sync Buildium data (default 60) |
| `VECTOR_DIMENSION` | Embedding dimension (1024 for voyage-3) |
| `SESSION_MAX_TOKENS` | Max tokens per conversation session (default 4096) |
### Database
Connect to your PostgreSQL instance and enable the vector extension:
```sql
CREATE EXTENSION IF NOT EXISTS vector;
```
Then run migrations (they execute automatically when the server starts in Node.js runtime):
```bash
pnpm dev
```
Migrations create the following tables: `documents`, `document_chunks` (with `vector(1024)` embedding column and HNSW index), `sync_metadata`, `sessions`, `messages`, and `cost_spans`.
### Install dependencies
```bash
pnpm install
```
## API
### POST /api/chat
Submit a property management query.
**Request body:**
```json
{
"request_id": "req-abc123",
"input": "When is my rent due?",
"user_id": "user-42",
"session_id": "sess-existing"
}
```
| Field | Type | Required | Description |
|---|---|---|---|
| `request_id` | `string` | yes | Client-generated request identifier |
| `input` | `string` | yes | The user's natural-language query |
| `user_id` | `string` | no | User identifier (defaults to `"anonymous"`) |
| `session_id` | `string` | no | Resume an existing conversation session |
**Response:**
```json
{
"content": "Your rent of $2,000 is due on the 1st of each month.",
"sessionId": "sess-abc123",
"sources": ["buildium/leases", "buildium/tenants"]
}
```
| Field | Type | Description |
|---|---|---|
| `content` | `string` | The Grok-generated answer |
| `sessionId` | `string` | Session ID for follow-up turns |
| `sources` | `string[]` | Deduplicated source entity types used in the answer |
**Example:**
```bash
curl -X POST http://localhost:3000/api/chat \
-H "Content-Type: application/json" \
-d '{"request_id":"req-1","input":"What is my rent?","user_id":"user-42"}'
```
**Error responses:**
- `400` — Invalid request body or missing required fields (details in `error` / `details`)
- `500` — Internal error (check server logs)
### GET /api/chat
Health check:
```bash
curl http://localhost:3000/api/chat
# → { "status": "ok" }
```
## Sync
Manually trigger a full Buildium data sync:
```bash
pnpm exec tsx -e "
import { BuildiumSyncService } from './src/lib/buildium-sync.js';
new BuildiumSyncService().syncAll().then(console.log);
"
```
Or set `BUILDIUM_SYNC_INTERVAL_MINUTES` in your environment to enable automatic scheduled sync (the instrumentation hook registers an interval at server start).
Sync fetches all leases, tenants, work orders, and properties from the Buildium API, chunks them, generates embeddings, and upserts them into the vector database. Errors are isolated per entity type — one failure doesn't block the others.
## Dev commands
| Command | Description |
|---|---|
| `pnpm dev` | Start Next.js development server |
| `pnpm test` | Run Vitest with coverage |
| `pnpm typecheck` | TypeScript type checking (`tsc --noEmit`) |
| `pnpm lint` | ESLint on all files |
## Project structure
```
xai-grok-knowledge-agent-for-buildium-property-management-queries/
├── app/
│ ├── api/chat/route.ts POST/GET chat endpoint
│ ├── layout.tsx App Router layout
│ └── page.tsx Landing page
├── src/
│ ├── db/
│ │ └── migrations/ PostgreSQL migrations (001–008)
│ ├── lib/
│ │ ├── agent-orchestrator.ts Wires retrieval/session/routing
│ │ ├── buildium-sync.ts Buildium data sync service
│ │ ├── buildium/ Buildium REST client (OAuth2)
│ │ ├── cost-telemetry.ts LLM cost recording & budgets
│ │ ├── db.ts postgres connection singleton
│ │ ├── embeddings.ts Voyage AI embedding service
│ │ ├── llm-router.ts Model routing to xAI Grok
│ │ ├── pgvector.ts pgvector SQL helper re-exports
│ │ ├── rag-retrieval.ts Vector similarity search
│ │ └── session-service.ts Multi-turn session management
│ ├── index.ts Barrel exports
│ └── instrumentation.ts Server init (migrations, sync)
├── tests/ Vitest test suite (mirrors src/)
├── packages/ API reference docs for deps
├── .env.example Environment variable template
├── DEV_PLAN.md Build plan for this recipe
└── package.json
```
## License
MIT — see [LICENSE](./LICENSE).