Commit Graph

85 Commits

Author SHA1 Message Date
e879d27e55 docs(02-01): complete two-layer memory plan — SUMMARY, STATE, ROADMAP, REQUIREMENTS
- SUMMARY.md: memory system docs (Redis sliding window + pgvector HNSW)
- STATE.md: 67% progress (6/9 plans), 3 key decisions, metrics logged
- ROADMAP.md: Phase 2 plan progress updated (2 summaries complete)
- REQUIREMENTS.md: AGNT-02 (conversational memory), AGNT-03 (cross-session recall) marked complete
2026-03-23 14:47:06 -06:00
45b957377f feat(02-01): wire two-layer memory into orchestrator pipeline
- builder.py: add build_messages_with_memory() — injects pgvector context as
  system message + sliding window history before current user turn
- runner.py: accept optional messages parameter; fallback to simple build for
  backward compat (existing tests unaffected)
- tasks.py: memory pipeline in _process_message — load short-term + retrieve
  long-term before LLM call; append turns to Redis + dispatch embed_and_store
  fire-and-forget after response
- tasks.py: add embed_and_store Celery task (sync def + asyncio.run()) for
  async pgvector backfill — never blocks the LLM response pipeline
- memory/embedder.py: lazy singleton SentenceTransformer (all-MiniLM-L6-v2)
  with embed_text() / embed_texts() helpers
- All 202 tests pass (196 existing + 6 new memory integration tests)
2026-03-23 14:45:21 -06:00
2dc94682ff docs(02-03): complete WhatsApp channel adapter plan
- Create 02-03-SUMMARY.md documenting WhatsApp adapter implementation
- Update STATE.md: advance progress to 56%, add 4 key decisions, record metrics
- Update ROADMAP.md: Phase 2 plan progress updated
- Mark CHAN-03, CHAN-04 requirements complete in REQUIREMENTS.md
2026-03-23 14:44:49 -06:00
6fea34db28 feat(02-03): WhatsApp adapter with business-function scoping and router registration
- Register whatsapp_router in gateway main.py (GET + POST /whatsapp/webhook)
- Implement is_clearly_off_topic() tier 1 keyword scoping gate
- Implement build_off_topic_reply() canned redirect message builder
- Full webhook handler: verify -> normalize -> tenant -> rate limit -> dedup -> scope -> media -> dispatch
- Outbound delivery via send_whatsapp_message() and send_whatsapp_media()
- Media download from Meta API and storage in MinIO with tenant-prefixed keys
- 14 new passing scoping tests
2026-03-23 14:43:04 -06:00
28a5ee996e feat(02-01): add two-layer memory system — Redis sliding window + pgvector long-term
- ConversationEmbedding ORM model with Vector(384) column (pgvector)
- memory_short_key, escalation_status_key, pending_tool_confirm_key in redis_keys.py
- orchestrator/memory/short_term.py: RPUSH/LTRIM sliding window (get_recent_messages, append_message)
- orchestrator/memory/long_term.py: pgvector HNSW cosine search (retrieve_relevant, store_embedding)
- Migration 002: conversation_embeddings table, HNSW index, RLS with FORCE, SELECT/INSERT only
- 10 unit tests (fakeredis), 6 integration tests (pgvector) — all passing
- Auto-fix [Rule 3]: postgres image updated to pgvector/pgvector:pg16 (extension required)
2026-03-23 14:41:57 -06:00
370a860622 feat(02-03): add MediaAttachment model, WhatsApp normalizer, and signature verification
- Add MediaType(StrEnum) and MediaAttachment(BaseModel) to shared/models/message.py
- Add media: list[MediaAttachment] field to MessageContent
- Add whatsapp_app_secret, whatsapp_verify_token, and MinIO settings to shared/config.py
- Add normalize_whatsapp_event() to gateway/normalize.py (text, image, document support)
- Create whatsapp.py adapter with verify_whatsapp_signature() and verify_hub_challenge()
- 30 new passing tests (signature verification + normalizer)
2026-03-23 14:41:48 -06:00
b2e86f1046 fix(02-agent-features): revise plans based on checker feedback 2026-03-23 14:32:20 -06:00
7da5ffb92a docs(02-agent-features): create phase plan 2026-03-23 14:23:11 -06:00
ac54d819f8 docs(02): add research and validation strategy 2026-03-23 14:16:42 -06:00
3fe334b702 docs(02-agent-features): research phase domain 2026-03-23 14:15:40 -06:00
e48fbaa3d4 docs(state): record phase 2 context session 2026-03-23 13:12:16 -06:00
1f070e2a64 docs(02): capture phase context 2026-03-23 13:12:09 -06:00
6f4445f982 docs(phase-1): complete phase execution 2026-03-23 10:39:30 -06:00
44f5b98890 docs(01-03): complete Channel Gateway + Message Router plan 2026-03-23 10:34:50 -06:00
74326dfc3d feat(01-03): integration tests for Slack flow, rate limiting, and agent persona
- tests/unit/test_ratelimit.py: 11 tests for Redis token bucket (CHAN-05)
  - allows requests under limit, rejects 31st request
  - per-tenant isolation, per-channel isolation
  - TTL key expiry and window reset
- tests/integration/test_slack_flow.py: 15 tests for end-to-end Slack flow (CHAN-02)
  - normalization: bot token stripped, channel=slack, thread_id set
  - @mention: placeholder posted in-thread, Celery dispatched with placeholder_ts
  - DM flow: same pipeline triggered for channel_type=im
  - bot messages silently ignored (no infinite loop)
  - unknown workspace_id silently ignored
  - duplicate events (Slack retries) skipped via idempotency
- tests/integration/test_agent_persona.py: 15 tests for persona in prompts (AGNT-01)
  - system prompt contains name, role, persona, AI transparency clause
  - model_preference forwarded to LLM pool
  - full messages array: [system, user] structure verified
- tests/integration/test_ratelimit.py: 4 tests for rate limit integration
  - over-limit -> ephemeral rejection posted
  - over-limit -> Celery NOT dispatched, placeholder NOT posted
  - within-limit -> no rejection
  - ephemeral message includes actionable retry hint
All 45 tests pass
2026-03-23 10:32:48 -06:00
6f30705e1a feat(01-03): Channel Gateway (Slack adapter) and Message Router
- gateway/normalize.py: normalize_slack_event -> KonstructMessage (strips bot mention)
- gateway/channels/slack.py: register_slack_handlers for app_mention + DM events
  - rate limit check -> ephemeral rejection on exceeded
  - idempotency dedup (Slack retry protection)
  - placeholder 'Thinking...' message posted in-thread before Celery dispatch
  - auto-follow engaged threads with 30-minute TTL
  - HTTP 200 returned immediately; all LLM work dispatched to Celery
- gateway/main.py: FastAPI on port 8001, /slack/events + /health
- router/tenant.py: resolve_tenant workspace_id -> tenant_id (RLS-bypass query)
- router/ratelimit.py: check_rate_limit Redis token bucket, RateLimitExceeded exception
- router/idempotency.py: is_duplicate + mark_processed (SET NX, 24h TTL)
- router/context.py: load_agent_for_tenant with RLS ContextVar setup
- orchestrator/tasks.py: handle_message now extracts placeholder_ts/channel_id,
  calls _update_slack_placeholder via chat.update after LLM response
- docker-compose.yml: gateway service on port 8001
- pyproject.toml: added redis, konstruct-router, konstruct-orchestrator deps
2026-03-23 10:27:59 -06:00
dcd89cc8fd docs(01-04): complete portal plan — tenant/agent CRUD and Agent Designer
- Create 01-04-SUMMARY.md documenting FastAPI portal API and Next.js portal
- Update STATE.md: advance plan, record metrics, add decisions
- Update ROADMAP.md: phase 1 plan progress (3/4 summaries)
- Update REQUIREMENTS.md: mark PRTA-01, PRTA-02 complete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 10:22:22 -06:00
cec7180fb0 feat(01-04): Next.js 16 admin portal with Auth.js v5, tenant CRUD, and Agent Designer
- Initialize Next.js 16 project in packages/portal/ with TypeScript, Tailwind 4, shadcn/ui
- Auth.js v5 with Credentials provider calling FastAPI /auth/verify endpoint
- proxy.ts (Next.js 16 replacement for middleware.ts) protects all routes
- Login page with React Hook Form + zod validation (standard-schema resolver for zod v4 compat)
- Agent Designer: prominent dedicated module with Identity, Personality, Configuration,
  Capabilities, Escalation, and Status sections; employee-centric language throughout
- Tenant CRUD: list, create (slug auto-gen), view/edit, delete with confirmation
- TanStack Query hooks for all API operations with proper cache invalidation
- Route group (dashboard) provides shared Nav sidebar + QueryClientProvider
- Update docker-compose.yml to add portal service on port 3000
- Deviations: middleware.ts renamed to proxy.ts in Next.js 16; zodResolver replaced with
  standardSchemaResolver for zod v4 + @hookform/resolvers v5 compatibility
2026-03-23 10:19:40 -06:00
0eae48699f docs(01-02): complete LLM pool and orchestrator plan 2026-03-23 10:08:55 -06:00
8257c554d7 feat(01-02): Celery orchestrator — handle_message task, system prompt builder, LLM pool runner
- Create orchestrator/main.py: Celery app with Redis broker/backend, task_acks_late=True, 10-min timeout
- Create orchestrator/tasks.py: SYNC def handle_message (critical pattern: asyncio.run for async work)
  - Deserializes KonstructMessage, sets RLS context, loads agent from DB, calls run_agent
  - Retries up to 3x on deserialization failure
- Create orchestrator/agents/builder.py: build_system_prompt assembles system_prompt + identity + persona + AI transparency clause
- Create orchestrator/agents/runner.py: run_agent posts to llm-pool /complete via httpx, returns polite fallback on error
- Add Celery[redis] dependency to orchestrator pyproject.toml
- Create tests/integration/test_llm_fallback.py: 7 tests for fallback routing and 503 on total failure (LLM-01)
- Create tests/integration/test_llm_providers.py: 12 tests verifying all three providers configured correctly (LLM-02)
- All 19 integration tests pass
2026-03-23 10:06:44 -06:00
7b348b97e9 feat(01-04): FastAPI portal API endpoints with tenant/agent CRUD and auth
- Add packages/shared/shared/api/portal.py with APIRouter at /api/portal
- POST /auth/verify validates bcrypt credentials against portal_users table
- POST /auth/register creates new portal users with hashed passwords
- Tenant CRUD: GET/POST /tenants, GET/PUT/DELETE /tenants/{id}
- Agent CRUD: full CRUD under /tenants/{tenant_id}/agents/{id}
- Agent endpoints set RLS current_tenant_id context for policy compliance
- Pydantic v2 schemas with slug validation (lowercase, hyphens, 2-50 chars)
- Add bcrypt>=4.0.0 dependency to konstruct-shared
- Integration tests: 38 tests covering all CRUD, validation, and isolation
2026-03-23 10:05:07 -06:00
ee2f88e13b feat(01-02): LLM Backend Pool — LiteLLM Router with Ollama + Anthropic + OpenAI fallback
- Create llm_pool/router.py: LiteLLM Router with fast (Ollama) and quality (Anthropic/OpenAI) model groups
- Configure fallback chain: quality providers fail -> fast group
- Pin LiteLLM to ==1.82.5 (avoid September 2025 OOM regression in later releases)
- Create llm_pool/main.py: FastAPI service on port 8004 with /complete and /health endpoints
- Add providers/__init__.py: reserved for future per-provider customization
- Update docker-compose.yml: add llm-pool and celery-worker service stubs
2026-03-23 10:03:05 -06:00
0054383be0 docs(01-foundation-01): complete monorepo scaffolding and RLS tenant isolation plan 2026-03-23 09:59:55 -06:00
47e78627fd feat(01-foundation-01): Alembic migrations with RLS and tenant isolation tests
- alembic.ini + migrations/env.py: async SQLAlchemy migration setup using asyncpg
- migrations/versions/001_initial_schema.py: creates tenants, agents, channel_connections, portal_users
  - ENABLE + FORCE ROW LEVEL SECURITY on agents and channel_connections
  - RLS policy: tenant_id = current_setting('app.current_tenant', TRUE)::uuid
  - konstruct_app role created with SELECT/INSERT/UPDATE/DELETE on all tables
- packages/shared/shared/rls.py: idempotent configure_rls_hook, UUID-sanitized SET LOCAL
- tests/conftest.py: test_db_name (session-scoped), db_engine + db_session as konstruct_app
- tests/unit/test_normalize.py: 11 tests for KonstructMessage Slack normalization (CHAN-01)
- tests/unit/test_tenant_resolution.py: 7 tests for workspace_id → tenant resolution (TNNT-02)
- tests/unit/test_redis_namespacing.py: 15 tests for Redis key namespace isolation (TNNT-03)
- tests/integration/test_tenant_isolation.py: 7 tests proving RLS tenant isolation (TNNT-01)
  - tenant_b cannot see tenant_a's agents or channel_connections
  - FORCE ROW LEVEL SECURITY verified via pg_class.relforcerowsecurity
2026-03-23 09:57:29 -06:00
5714acf741 feat(01-foundation-01): monorepo scaffolding, Docker Compose, and shared data models
- pyproject.toml: uv workspace with 5 member packages (shared, gateway, router, orchestrator, llm-pool)
- docker-compose.yml: PostgreSQL 16 + Redis 7 + Ollama services on konstruct-net
- .env.example: all required env vars documented, konstruct_app role (not superuser)
- scripts/init-db.sh: creates konstruct_app role at DB init time
- packages/shared/shared/config.py: Pydantic Settings loading all env vars
- packages/shared/shared/models/message.py: KonstructMessage, ChannelType, SenderInfo, MessageContent
- packages/shared/shared/models/tenant.py: Tenant, Agent, ChannelConnection SQLAlchemy 2.0 models
- packages/shared/shared/models/auth.py: PortalUser model for admin portal auth
- packages/shared/shared/db.py: async SQLAlchemy engine, session factory, get_session dependency
- packages/shared/shared/rls.py: current_tenant_id ContextVar and configure_rls_hook with parameterized SET LOCAL
- packages/shared/shared/redis_keys.py: tenant-namespaced key constructors (rate_limit, idempotency, session, engaged_thread)
2026-03-23 09:49:28 -06:00
d611a07cc2 docs(01-foundation): create phase plan 2026-03-23 09:32:44 -06:00
60080980da docs(01): add research and validation strategy 2026-03-23 09:26:15 -06:00
2ab18fde4f docs(01): research phase 1 foundation domain 2026-03-23 09:25:20 -06:00
fe3b36be16 docs(state): record phase 1 context session 2026-03-23 09:20:02 -06:00
d032d81171 docs(01): capture phase context 2026-03-23 09:19:53 -06:00
f39508d297 docs: create roadmap (3 phases) 2026-03-23 09:06:16 -06:00
353f9b3f12 docs: define v1 requirements 2026-03-23 08:53:20 -06:00
376982f16f docs: complete project research 2026-03-22 00:12:58 -06:00
320da9df87 chore: add project config 2026-03-22 00:03:51 -06:00
fa3aea5f29 docs: initialize project 2026-03-22 00:01:49 -06:00