Skip to main content

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:

  1. parse inbound WhatsApp Cloud API or Telegram payloads;
  2. find or create the User, Conversation, and inbound Message;
  3. create an AgentTask;
  4. enqueue a BullMQ job on agent-tasks.

The agent runner worker owns the assistant pipeline:

  1. inject_profile loads namespace system prompt and employee profile context;
  2. rag_search runs OpenAiRagPipeline, or adapter fallback when no RAG dependency is wired;
  3. generate formats the channel reply;
  4. confidence_check handles injection routing, persona escalation triggers, intent classification, confidence fallback, and trust-matrix bypass;
  5. 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.
  • AgentTask rows 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.