ADR-001: Agent-Tasks Message Pipeline
- Status: Accepted
- Date: 2026-04-14
- Author: CTO Agent (KALA-107)
Context
Inbound channel handlers originally owned too much of the assistant workflow. WhatsApp and Telegram handlers normalized transport payloads, looked up conversations, ran prompt-injection checks, classified intent, called RAG, evaluated trust, and routed to HITL or outbound delivery.
That shape made the core assistant behavior hard to observe and hard to reuse:
- each channel could drift from the others;
- long-running LLM and RAG work lived inside channel-specific workers;
- test mode needed real channel dependencies to exercise the pipeline;
- escalation triggers were split between persona config and channel control flow;
- progress visibility was limited to final channel-side outcomes.
Decision
Use agent-tasks as the canonical asynchronous execution boundary for assistant responses.
Channel workers only perform transport-specific work:
- parse inbound WhatsApp Cloud API or Telegram payloads;
- find or create the
User,Conversation, and inboundMessage; - create an
AgentTask; - enqueue a BullMQ job on
agent-tasks.
The agent runner worker owns the assistant pipeline:
inject_profileloads namespace system prompt and employee profile context;rag_searchrunsOpenAiRagPipeline, or adapter fallback when no RAG dependency is wired;generateformats the channel reply;confidence_checkhandles injection routing, persona escalation triggers, intent classification, confidence fallback, and trust-matrix bypass;- the worker routes to outbound delivery, pending approval, or persona escalation.
Every step is persisted as an AgentToolCall so API clients and WebSocket subscribers can observe progress.
Consequences
Positive
- One pipeline controls WhatsApp, Telegram, and future channels.
- Channel adapters stay focused on transport concerns.
- Agent task status and tool-call progress are observable through REST and WebSocket APIs.
- Persona escalation is evaluated in the same place as trust and confidence gates.
- Test mode can use deterministic adapter dependencies without starting real channel bots.
Negative
- The worker needs explicit channel outbound dependencies for each supported channel.
- The fallback adapter path must stay aligned with the full RAG path so tests do not hide production-only behavior.
AgentTaskrows become part of the critical path and need regular retention/cleanup policy work.
Implementation Notes
- Queue name:
agent-tasks. - Worker:
src/agent-runner/worker.ts. - Fastify plugin:
src/plugins/agent-runner.ts. - REST API:
GET /api/v1/agent-tasks,GET /api/v1/agent-tasks/:id,GET /api/v1/agent-tasks/stats. - WebSocket API:
ws://<host>/ws/agent-tasks. - Namespace adapter config:
Namespace.config.agentRunner.activeAdapter.
The old channel-owned RAG path is no longer the primary message pipeline. OpenAiRagPipeline remains the retrieval/generation component, used by the agent runner and by POST /api/v1/rag/draft for manual testing.