Skip to content
reaatech

Files · Auto-Takeoff Agent for Small GC Bid Prep

84 (1 binary, 680.5 kB total)attempt 1

README.md·5306 B·markdown
markdown
# Auto-Takeoff Agent for Small GC Bid Prep
 
> Convert plan sets to BOM + sub RFPs in minutes, not days.
 
A General Contractor estimator spends days manually measuring plan sets and spec docs to produce a bill of materials and subcontractor RFPs. Errors in takeoff lead to underbid losses or overbid rejections. This recipe automates extraction of quantities, materials, and specs from PDFs and images, then generates structured RFPs for subs.
 
**Target provider:** agnostic (Vercel AI SDK)  
**Archetype:** document-pipeline  
**Vertical:** construction-trades  
**Stack:** Next.js 16 App Router + Fastify standalone server
 
## Architecture
 
The pipeline processes plan sets in 7 stages:
 
1. **Load** — Accept plan set documents via `POST /api/takeoff`
2. **OCR** — Extract text from each document using `@reaatech/media-pipeline-mcp-doc-extraction`
3. **Tables** — Extract structured tables (schedules, material lists)
4. **Fields** — Extract typed fields (material names, quantities, specs)
5. **Interpret** — Vercel AI SDK (`ai` + `@ai-sdk/openai`) converts extracted data into structured material line items
6. **BOM** — Generate a validated Bill of Materials
7. **Persist** — Store the job result via `@reaatech/a2a-reference-persistence`
 
After takeoff, `POST /api/rfp` generates one subcontractor RFP per trade, each containing a natural-language scope of work written by the LLM.
 
## REAA Packages
 
| Package | Version | Role |
|---------|---------|------|
| [`@reaatech/media-pipeline-mcp-doc-extraction`](https://www.npmjs.com/package/@reaatech/media-pipeline-mcp-doc-extraction) | 0.3.0 | Document OCR, table extraction, field extraction, summarization |
| [`@reaatech/agent-mesh`](https://www.npmjs.com/package/@reaatech/agent-mesh) | 1.0.0 | Request/response schemas and type validation |
| [`@reaatech/llm-cache`](https://www.npmjs.com/package/@reaatech/llm-cache) | 0.1.0 | Semantic + exact-match caching for LLM calls |
| [`@reaatech/agent-budget-engine`](https://www.npmjs.com/package/@reaatech/agent-budget-engine) | 0.1.1 | Per-scope budget enforcement with state machine |
| [`@reaatech/a2a-reference-persistence`](https://www.npmjs.com/package/@reaatech/a2a-reference-persistence) | 0.2.0 | In-memory and filesystem task stores |
| [`@reaatech/agents-markdown`](https://www.npmjs.com/package/@reaatech/agents-markdown) | 1.0.1 | Validation result types and utilities |
 
## Third-Party Packages
 
- `ai@6.0.202` — Vercel AI SDK (`generateText`, `Output`)
- `@ai-sdk/openai@3.0.70` — OpenAI provider
- `zod@4.4.3` — Schema validation
- `langfuse@3.38.20` — LLM tracing (optional)
- `fastify@5.2.2` — Standalone HTTP server
 
## Environment Variables
 
| Variable | Description |
|----------|-------------|
| `OPENAI_API_KEY` | OpenAI API key for LLM calls |
| `LANGFUSE_PUBLIC_KEY` | Langfuse public key (optional) |
| `LANGFUSE_SECRET_KEY` | Langfuse secret key (optional) |
| `LANGFUSE_HOST` | Langfuse host URL (optional) |
| `FASTIFY_PORT` | Fastify server port (default: 3001) |
| `MODEL_ID` | LLM model identifier (optional — defaults to gpt-5.2) |
 
## API Reference
 
### `POST /api/takeoff`
Submit a plan set for automated takeoff. Returns a job result with BOM.
 
### `GET /api/takeoff/:id`
Get the status and result of a takeoff job.
 
### `DELETE /api/takeoff/:id`
Cancel and remove a takeoff job.
 
### `POST /api/rfp`
Generate subcontractor RFPs from a Bill of Materials.
 
### `GET /api/rfp/:id`
Retrieve a generated RFP document.
 
### `GET /api/budget`
View current budget status for all scopes.
 
### `GET /api/health`
Health check — returns `{ "status": "ok", "version": "0.1.0" }`.
 
## Getting Started
 
```bash
pnpm install
cp .env.example .env.local
# Edit .env.local with your OPENAI_API_KEY
pnpm dev            # Next.js dev server on port 3000
```
 
To start the standalone Fastify server:
```bash
pnpm tsx src/server.ts
```
 
## Testing
 
```bash
pnpm test           # vitest run with coverage
pnpm typecheck      # tsc --noEmit
pnpm lint           # eslint .
```
 
Tests mock all external dependencies (`vi.mock` for LLM calls, package adapters). No live HTTP calls are made during test execution.
 
## Project Layout
 
```
app/                  Next.js App Router pages + API routes
  api/
    takeoff/          POST / (create), GET /[id] (status), DELETE /[id] (cancel)
    rfp/              POST / (generate), GET /[id] (fetch)
    budget/           GET / (budget status)
    health/           GET / (health check)
src/
  types/              Zod schemas and TypeScript interfaces
  services/
    document-extraction.ts    Wraps @reaatech/media-pipeline-mcp-doc-extraction
    cache-manager.ts          Wraps @reaatech/llm-cache
    budget-manager.ts         Wraps @reaatech/agent-budget-engine
    task-persistence.ts       Wraps @reaatech/a2a-reference-persistence
    llm-processor.ts          Vercel AI SDK LLM integration
    takeoff-engine.ts         Pipeline orchestrator
    rfp-generator.ts          RFP generation from BOM
  server.ts           Standalone Fastify server entrypoint
  index.ts            Public API barrel exports
tests/                Vitest suite mirroring src/
packages/             API references for every dependency
DEV_PLAN.md           Build plan for this recipe
```
 
## License
 
MIT — see [LICENSE](./LICENSE).