Skip to content
reaatechREAATECH

Files · Ollama Agent Mesh for Small Business Workflow Automation

87 (1 binary, 808.2 kB total)attempt 2

README.md·9361 B·markdown
markdown
# Ollama Agent Mesh for Small Business Workflow Automation
 
> Orchestrate a fleet of local LLM specialists — email triage, CRM updates,
> report generation — without sending data to the cloud.
 
A privacy-preserving automation layer for SMBs. An Express server exposes
`POST /execute-task` and routes each request through a mesh of specialist agents
powered by local [Ollama](https://ollama.com) models. The mesh uses
`@reaatech/*` packages for routing, confidence scoring, session continuity,
agent handoff, and model selection.
 
---
 
## Overview
 
Every SMB handles the same repetitive workflows: sorting incoming email,
keeping CRM records current, and generating weekly reports. Off-the-shelf
solutions either cost too much or require shipping customer data to a third
party.
 
This project runs **entirely offline** using Ollama on your own hardware. An
Express server accepts task requests, classifies the intent, routes to the
right specialist agent via a confidence-scored mesh, and returns results — no
data ever leaves your network.
 
### What you can do with it
 
- **Email triage** — Classify inbound messages as support-request,
  sales-inquiry, billing-issue, or spam; extract action items; draft replies.
- **CRM updates** — Extract structured contact and deal records from
  conversation or email text.
- **Report generation** — Produce structured row data ready for spreadsheet
  export (`.xlsx` via the `xlsx` package).
 
---
 
## Architecture
 
```
┌──────────────┐
│   Express     │  POST /execute-task { input, employee_id? }
│   Server      │  GET  /health
└──────┬───────┘


┌──────────────────┐
│  Intent           │  Classifies raw input → agent route
│  Classifier       │
└──────┬───────────┘


┌──────────────────┐
│  Confidence       │  Routes above threshold → specialist
│  Router           │  Falls back below threshold → handoff
│  (@reaatech/      │
│   confidence-     │
│   router)         │
└──────┬───────────┘


┌──────────────────┐
│  Specialist       │  email-triage  │  crm-update  │  report
│  Agents           │  (Mastra Agent + @ai-sdk/openai-compatible)
└──────┬───────────┘


┌──────────────────┐
│  Ollama           │  llama3.1, qwen3:1.8b (or any local model)
│  (localhost:      │
│   11434)          │
└──────────────────┘
```
 
### REAA packages powering the mesh
 
| Package | Role |
|---|---|
| `@reaatech/agent-mesh-router` | Dispatch requests to the correct agent in the mesh |
| `@reaatech/confidence-router` | Score routing confidence; fallback below threshold |
| `@reaatech/session-continuity` | Maintain conversation state across turns |
| `@reaatech/agent-handoff` | Graceful handoff when confidence is low |
| `@reaatech/llm-router-core` | Cost-optimised model selection |
 
---
 
## Prerequisites
 
- **Ollama** running locally with at least one pulled model:
 
  ```bash
  ollama pull llama3.1
  ollama pull qwen3:1.8b    # lighter model for analysis tasks
  ```
 
- **Node.js** >= 22
- **pnpm** 10
 
  ```bash
  corepack enable && corepack prepare pnpm@10 --activate
  ```
 
---
 
## Quick Start
 
```bash
# 1. Install dependencies
pnpm install
 
# 2. Copy environment file and customise
cp .env.example .env
# Edit .env — at minimum set OLLAMA_HOST if your instance isn't at
# http://127.0.0.1:11434
 
# 3. Confirm Ollama is reachable
curl http://localhost:11434/api/tags
 
# 4. Start the mesh server
pnpm exec tsx src/server.ts
# → Mesh server listening on port 3001
```
 
Verify the server is alive:
 
```bash
curl http://localhost:3001/health
# → {"status":"ok","uptime_ms":1234}
```
 
Try a task:
 
```bash
curl -X POST http://localhost:3001/execute-task \
  -H 'Content-Type: application/json' \
  -d '{"input":"Can you sort these emails for me? We got a complaint from Acme Corp"}'
```
 
---
 
## API Reference
 
### `POST /execute-task`
 
The primary endpoint. Accepts a natural-language task description and optional
employee identifier, routes through the agent mesh, and returns the result.
 
**Request body**
 
| Field | Type | Required | Description |
|---|---|---|---|
| `input` | `string` | yes | Natural-language task or message |
| `employee_id` | `string` | no | Employee identifier for context/tracking |
 
**Response**
 
| Field | Type | Description |
|---|---|---|
| `content` | `string` | The agent's output (reply, extracted data, report) |
| `workflow_complete` | `boolean` | Whether the workflow reached a terminal state |
| `workflow_state` | `object` | Session state for follow-up turns |
 
**Example**
 
```bash
curl -X POST http://localhost:3001/execute-task \
  -H 'Content-Type: application/json' \
  -d '{"input":"Create a weekly report for Q1 deals","employee_id":"emp_42"}'
```
 
```json
{
  "content": "[{\"quarter\":\"Q1\",\"deals\":5,\"value\":125000,\"stage\":\"closed-won\"},...]",
  "workflow_complete": true,
  "workflow_state": { "turn": 2, "agent": "report", "summary": "..." }
}
```
 
### `GET /health`
 
Returns server health information.
 
```json
{
  "status": "ok",
  "uptime_ms": 12345
}
```
 
---
 
## Configuration
 
The mesh is configured entirely through `mesh-config.yaml` in the project root.
 
```yaml
confidence:
  routeThreshold: 0.8       # minimum score to route directly
  fallbackThreshold: 0.3    # below this → handoff to human
 
llm:
  defaultStrategy: cost-optimized
  models:
    - id: llama3.1
      capabilities: [general, code, reasoning]
      costPerMillionInput: 0
      costPerMillionOutput: 0
      maxTokens: 8192
    - id: qwen3:1.8b
      capabilities: [general, analysis]
      costPerMillionInput: 0
      costPerMillionOutput: 0
      maxTokens: 32768
 
agents:
  - id: email-triage
    displayName: Email Triage Specialist
    model: qwen3:1.8b
    instructions: >
      You are an email triage specialist for a small business. Categorize each
      email as: support-request, sales-inquiry, billing-issue, or spam. Extract
      sender name, email, and key action items. Draft a reply when possible.
 
  - id: crm-update
    displayName: CRM Update Specialist
    model: llama3.1
    instructions: >
      You extract structured CRM records from conversation. Output a JSON array
      of records with fields: company, contact_name, email, phone, deal_stage,
      notes, next_step. Only include verified facts, mark uncertain data with
      confidence.
 
  - id: report
    displayName: Report Generation Specialist
    model: llama3.1
    instructions: >
      You generate structured report data. For each report request, produce a
      JSON array of row objects with consistent keys. Include summary statistics
      when relevant. Output should be ready for spreadsheet conversion.
 
session:
  maxTokens: 4096
  reserveTokens: 500
  overflowStrategy: compress
```
 
---
 
## Environment Variables
 
| Variable | Default | Required | Description |
|---|---|---|---|
| `NODE_ENV` | `development` | — | Runtime environment |
| `PORT` | `3001` | — | Express server port |
| `OLLAMA_HOST` | `http://127.0.0.1:11434` | — | Ollama API base URL |
| `OLLAMA_DEFAULT_MODEL` | `llama3.1` | — | Fallback model for unclassified tasks |
| `FIRECRAWL_API_KEY` | — | no | API key for web research (Firecrawl) |
| `GOOGLE_APPLICATION_CREDENTIALS` | — | no | Path to GCP service-account JSON for Sheets/Gmail |
| `LANGFUSE_PUBLIC_KEY` | — | no | Langfuse trace observability public key |
| `LANGFUSE_SECRET_KEY` | — | no | Langfuse trace observability secret key |
| `LANGFUSE_BASE_URL` | — | no | Langfuse instance base URL |
 
---
 
## Adding a Specialist Agent
 
Add a new agent in three steps:
 
### 1. Register in `mesh-config.yaml`
 
Add a new entry under the `agents` list:
 
```yaml
agents:
  - id: compliance-check
    displayName: Compliance Check Specialist
    model: llama3.1
    instructions: >
      You review text for regulatory compliance. Flag any language that violates
      GDPR, HIPAA, or SOC2 requirements. Output a JSON array of findings with
      fields: clause, regulation, risk_level, recommendation.
```
 
### 2. (Optional) Create a dedicated agent file
 
If the agent needs custom logic beyond the generic `specialist-agent.ts`,
create `src/agents/compliance-check-agent.ts`:
 
```ts
import { Agent } from '@mastra/core/agent';
import { createOllamaProvider } from './specialist-agent.js';
 
const provider = createOllamaProvider();
 
export const complianceCheckAgent = new Agent({
  id: 'compliance-check',
  name: 'Compliance Check Specialist',
  instructions: `You review text for regulatory compliance...`,
  model: provider.chatModel('llama3.1'),
});
```
 
### 3. Register in the loader
 
If you created a custom file, wire it in `src/config/config-loader.ts` or your
registry. For agents that only need a config entry (no custom logic), the
generic `AgentRegistry.initFromConfig()` already picks them up from
`mesh-config.yaml`.
 
---
 
## License
 
MIT — see [LICENSE](./LICENSE).