Commit Graph

21 Commits

Author SHA1 Message Date
Carlos Garcia
590f1b7ee2 fix: make Odoo login configurable via ODOO_USER (default __system__)
Some Odoo instances require the user's actual login/email for API key
auth rather than the __system__ special login. ODOO_USER defaults to
__system__ for standard Odoo 16+ installs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 19:15:06 -04:00
Carlos Garcia
65e471b6ce fix: MemoryManager kwarg 'llm' -> 'llm_router'; fix alembic script_location
- main.py: MemoryManager(pool=pool, llm=...) -> llm_router=...
  Class signature is __init__(self, pool, llm_router=None).

- alembic.ini: script_location = migrations -> agent_service/migrations
  When alembic runs from WORKDIR /app inside the container, 'migrations'
  resolves to /app/migrations (missing). Correct path is
  /app/agent_service/migrations where versions/ actually lives.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:43:03 -04:00
Carlos Garcia
6d15859779 fix(setup.sh): detect stale DB volume, run Alembic migrations on startup
- Before bringing up the stack, check if the agent-db volume exists but
  is missing the expected database (left from a previous broken run with
  wrong POSTGRES_DB). Offer to wipe and re-init automatically.
- After docker compose up, wait for pg_isready then run
  `alembic upgrade head` inside the agent container so tables are created
  before the agent attempts to use them.
- Restart agent-service after migrations so it connects to a fully
  initialized database on its first attempt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:39:51 -04:00
Carlos Garcia
7765824c70 feat: add setup.sh — zero-config interactive installer
Replaces manual .env editing with a guided setup script.

Auto-discovers:
- Odoo container name and database (via `docker ps` + odoo.conf inspection)
- Ollama endpoint (scans 192.168.2.10/9, 192.168.2.1, localhost on port 11434)
- Ollama model list (lets user pick from available, auto-selects if only one)

Auto-generates (idempotent — preserves on re-run):
- POSTGRES_PASSWORD (openssl rand -hex 24)
- AGENT_API_KEY     (openssl rand -hex 32)
- WEBHOOK_SECRET    (openssl rand -hex 32)

Postgres constants always written correctly:
- POSTGRES_HOST=agent-db, POSTGRES_DB=activeblue_ai, POSTGRES_USER=activeblue
  (fixes previous issue where these were blank or wrong in .env)

Odoo API key:
- Attempts auto-creation via Odoo HTTP session + res.users.apikeys.description
  wizard (works on Odoo 16/17/18 with valid admin credentials)
- Falls back to clear manual instructions + paste prompt on failure

Writes .env with chmod 600. Offers to `docker compose up -d` when done.

Usage:
  cd /root/odoo/odoo-ai
  bash setup.sh

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:35:23 -04:00
Carlos Garcia
a3fbc9746f fix: remove stale port binding and deprecated version key from compose
- Remove ports: mapping (192.168.2.47:8001:8001 — stale IP from prior host,
  caused 'cannot assign requested address' bind failure). Agent is only
  reachable via activeblue-net; no host exposure needed.
- Remove top-level version: key (obsolete, triggers deprecation warning).

These fixes were applied manually on the miaai host but never committed,
causing git pull to conflict and the Python fixes to silently not apply.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:53:54 -04:00
Carlos Garcia
c769fca79f fix: resolve all 5 startup constructor errors + add DB retry
Fixes all errors reported in docker compose logs agent-service:

1. config.py: add ollama_max_concurrent, claude_timeout, claude_max_concurrent
   fields so LLMRouter(config=settings) can read them without AttributeError.

2. main.py - LLM router: drop manual OllamaBackend/ClaudeBackend construction;
   call LLMRouter(config=settings, pg_pool=pool) to match class signature.
   Fixes: OllamaBackend.__init__() unexpected kwarg 'base_url'.

3. main.py - DB: add 5-attempt retry with 2s backoff and redacted DSN logging.
   Fixes: connection refused race on startup before Postgres accepts connections.

4. main.py - AgentRegistry: call AgentRegistry() with no args (class takes none),
   then await agent_registry.load_from_odoo(odoo) to populate active agents.
   Fixes: AgentRegistry.__init__() unexpected kwarg 'odoo'.

5. main.py - PeerBus: pass registry=agent_registry at construction; register
   specialist agents on agent_registry (not peer_bus, which has no register()).
   peer_bus.py: make directive_id optional (default None) — bus is a singleton
   at startup; directive_id is only needed per-request.
   Fixes: PeerBus.__init__() missing positional args 'registry' and 'directive_id'.

6. main.py - MasterAgent: drop unexpected peer_bus= kwarg from constructor call.
   Fixes: MasterAgent.__init__() unexpected kwarg 'peer_bus'.

7. mcp_router.py: pass NotificationOptions() instance instead of None.
   Fixes: AttributeError 'NoneType' has no attribute 'tools_changed' (was applied
   in running container but not committed; now committed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:48:23 -04:00
ActiveBlue Build
66b114cdcf feat(mcp): add MCP gateway — 14 tools over SSE, all agent calls forced local
Architecture:
- agent_service/mcp/tools.py: 14 Tool definitions with JSON schemas
    dispatch, finance_query, accounting_query, crm_query, sales_query,
    project_query, elearning_query, expenses_query, employees_query,
    get_health, list_agents, trigger_sweep, get_pending_approvals, approve_directive
- agent_service/mcp/server.py: mcp.Server with list_tools + call_tool handlers
- agent_service/routers/mcp_router.py: Starlette routes at /mcp/sse + /mcp/messages
- main.py: mounts MCP routes alongside existing FastAPI routers (graceful fallback if mcp not installed)

Privacy guarantee (enforced in server.py, not by convention):
- _force_local_context() sets llm_router._privacy_mode = 'local' before EVERY agent call
- _restore_mode() restores original mode after the tool returns
- HIPAA agents (finance, accounting, expenses, employees) were already Ollama-only;
  MCP adds a second enforcement layer for all 8 agents
- MCP client (e.g. Claude Code CLI) receives only tool results — no LLM completions cross the boundary

Usage (Claude Code CLI):
  claude mcp add --transport sse http://192.168.2.47:8001/mcp/sse
  or copy claude_mcp_config.json to ~/.claude/mcp_servers.json

requirements.txt: added mcp==1.3.0
tests/test_mcp_server.py: 13 tests covering tool count, schemas, HIPAA labelling, privacy override

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 16:45:49 -04:00
ActiveBlue Build
fb4bf56816 feat(packaging): add Debian packaging and APT repository scripts
debian/DEBIAN/control: package metadata, depends on python3.11+, postgresql-client
debian/DEBIAN/postinst: creates activeblue-ai system user, installs venv, enables service
debian/DEBIAN/prerm: stops and disables service before removal
debian/DEBIAN/postrm: purge removes config, logs, venv, and system user
debian/lib/systemd/system/activeblue-ai.service:
  - Runs as dedicated user with PrivateTmp + ProtectSystem hardening
  - EnvironmentFile=/etc/activeblue-ai/.env
  - Restart=on-failure with 5s backoff
debian/usr/bin/activeblue-ai: CLI with start/stop/restart/status/logs/migrate/health/sweep/privacy/version
build_deb.sh: builds activeblue-ai_X.Y.Z_all.deb in dist/
publish_repo.sh: scans packages, generates Release + checksums, optional GPG signing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 18:09:48 -04:00
ActiveBlue Build
7487fc73f9 feat(infra): add sweep coordinator, structured logging, test suite, and README
Sweep coordinator (Step 16):
- SweepCoordinator runs all 8 agents in parallel with 60s per-agent / 300s total timeout
- Aggregates findings, actions, errors into SweepCoordinatorResult
- Registered in FastAPI lifespan; triggered via POST /sweep

Structured logging (Step 18):
- logging_utils/structured.py: JSONFormatter emitting ts/level/logger/msg + custom fields
- log_directive_event() for structured directive lifecycle logging
- push_to_loki() async Loki push (graceful no-op if LOKI_URL unset)
- configure_logging() replaces root handler at startup

Tests (Steps 17+19):
- conftest.py: mock_odoo, mock_pool, mock_llm fixtures
- test_tool_validator.py: 9 tests covering validation, coercion, hallucination stripping
- test_llm_router.py: 6 tests covering local/cloud/hybrid modes and HIPAA enforcement
- test_peer_bus.py: 6 tests covering registration, timeout, depth, circular detection
- test_finance_agent.py: 10 tests covering all 6 steps + sweep + peer request
- test_memory_manager.py: 3 tests covering context build + hard cap enforcement
- test_dispatch_router.py: 3 tests covering dispatch, rate limit, health endpoint
- test_odoo_client.py: 4 tests covering search_read, write result, unlink warning
- test_e2e_dispatch.py: 2 E2E tests - full dispatch cycle + peer bus communication

README (Step 20): architecture diagram, privacy modes, quick start, env vars, structure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 18:08:11 -04:00
ActiveBlue Build
fe47f950e4 feat(agents): add 7 specialist agents with tools and system prompts
Agents (all following 6-step contract: _plan/_gather/_reason/_act/_report):
- AccountingAgent: trial balance, chart of accounts, tax summary (HIPAA-locked)
- CrmAgent: pipeline summary, lead/opportunity management, won/lost analysis
- SalesAgent: sales orders, quotations, revenue by rep, expired quote detection
- ProjectAgent: task tracking, blocked/overdue detection, timesheet logging
- ElearningAgent: course completion, low-engagement flagging, next-course suggestion
- ExpensesAgent: expense sheets, pending approvals, policy violations (HIPAA-locked)
- EmployeesAgent: headcount, contracts, leaves, attendance, expired contract sweep (HIPAA-locked)

Tools (one file per domain):
- accounting_tools.py, crm_tools.py, sales_tools.py, project_tools.py
- elearning_tools.py, expenses_tools.py, employees_tools.py

System prompts: each agent has a domain-specific system.txt with rules and output format

All agents implement handle_peer_request() and sweep() for proactive monitoring
HIPAA-locked agents (accounting, expenses, employees) enforced via LLMRouter

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 18:04:32 -04:00
ActiveBlue Build
29409ed71d feat(odoo): add activeblue_ai Odoo 18 module with OWL2 frontend
Models:
- ab.ai.bot: service URL, webhook secret, privacy mode, ping/dispatch
- ab.ai.directive: full directive lifecycle log with status tracking
- ab.ai.log: activity log with level/agent/record linkage
- ab.ai.agent.registry: agent list synced from agent service

Controllers:
- webhook.py: /ai/webhook/callback handles directive_completed, escalation, sweep_findings
- health_proxy.py: /ai/health proxies agent service detailed health
- approval.py: /ai/chat dispatch, /ai/approval/pending, /ai/approval/respond

Security:
- group_ai_user (chat) + group_ai_manager (configure, approve, logs)
- ir.model.access.csv for all 4 models

Views: list/form for bot, directives, logs, registry; main menu with AI brain icon

OWL2 frontend:
- systray_button.js: brain icon in top bar, status dot, pending approval badge
- ai_panel.js: slide-in chat panel, approval workflow, 30s poll for pending items
- CSS: slide-in animation, message bubbles, loading dots, approval section

Data: 4 cron jobs (ping, registry sync, directive/log cleanup)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 17:59:02 -04:00
ActiveBlue Build
430ab966b2 feat(service): add FastAPI agent service with 5 routers and Docker setup
- config.py: pydantic-settings with all env vars, privacy mode, per-agent overrides
- app_state.py: global singletons (pool, master agent, registry, llm_router, sweep)
- main.py: FastAPI lifespan startup — DB pool, LLM router, Odoo client, agents, master
- routers/dispatch.py: POST /dispatch with rate limiting and webhook secret auth
- routers/approval.py: GET /approval/pending, POST /approval/respond
- routers/registry.py: GET/POST /registry/agents, POST /registry/backend overrides
- routers/sweep.py: POST /sweep trigger, GET /sweep/status
- routers/health.py: GET /health, GET /health/detailed (DB/Odoo/Ollama checks)
- requirements.txt: pinned deps (fastapi, uvicorn, asyncpg, anthropic, alembic)
- Dockerfile: python:3.11-slim, single uvicorn worker
- docker-compose.yml: agent-service + postgres:15, bound to 192.168.2.47:8001

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 17:54:28 -04:00
ActiveBlue Build
dab6354d09 feat(finance): add FinanceAgent with full 6-step contract and FinanceTools
- FinanceAgent implements _plan/_gather/_reason/_act/_report lifecycle
- Proactive sweep flags 30+ day overdue invoices, auto-sends reminders >60d/>$1k
- PeerBus handler exposes overdue_summary, payment_history, financial_summary
- HIPAA-locked: Ollama only, no cloud LLM routing
- FinanceTools wraps OdooClient with 9 read/write methods on account.move
- finance_system.txt prompt enforces no-write-to-invoices rule
- research/finance_research.md documents Odoo 18 account model details

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 17:51:49 -04:00
ActiveBlue Build
4ca62ee54b feat: add Master AI with directive builder and synthesis 2026-04-12 17:17:44 -04:00
ActiveBlue Build
21998f76aa feat: add base agent and peer bus 2026-04-12 16:55:30 -04:00
ActiveBlue Build
9ab1f8bbf8 feat: add 3-tier memory layer 2026-04-12 16:51:39 -04:00
ActiveBlue Build
7d92c2ea6f feat: add LLM abstraction layer (router, Ollama backend, Claude backend) 2026-04-12 16:46:18 -04:00
ActiveBlue Build
0e13b93e3a feat: add Odoo XML-RPC client with connection pool and retry 2026-04-12 16:46:13 -04:00
ActiveBlue Build
34a65a485e chore: add alembic migrations for memory and directive schema 2026-04-12 14:18:07 -04:00
ActiveBlue Build
bea58371c1 chore: add docker and traefik config for ai.activeblue.net 2026-04-12 14:17:32 -04:00
ActiveBlue Build
d1e8847cad chore: initialize repo 2026-04-12 14:12:51 -04:00