Files

5.4 KiB
Raw Permalink Blame History

Roadmap

Not a generic TODO list — this captures the intended architecture progression and why each phase is sequenced that way.

Phase 1 — Telegram AI Foundation (current)

TypeScript + grammY, Docker dev mode with hot reload, webhook + long-polling, /start /help, normalized message contract, LLM via LiteLLM, conversation persistence in Postgres, one controlled n8n path, tests + docs.

Why this order: prove the transport (Telegram webhook) and the AI loop end-to-end before investing in durable context, RAG, or a second channel.

Phase 2 — Durable Context + Business Tools

Progress (2026-08-30):

  • Product catalog awarenessCatalogRetriever (src/ai/retrieval/catalog.ts) replaces NoopRetriever: SKU-token + name/category keyword lookup over the generated src/data/catalog.ts (259 entries, built by gen_catalog.py from catalog_sku.csv; no prices, no storage paths). Hits are injected into the prompt as "Product facts" with product-page links (https://www.digikedai.com/products/<sku>/); free items (SKU prefix FREE — FREECXM04 = FREE + original paid SKU CXM04, the trial twin) are flagged and routed to /free/. Keyword search chosen over pgvector at this scale (eval criteria below).
  • Passive human-handoff in system.ts — admin contact (Telegram @MrFullStackDev only, no WhatsApp/phone) is offered only when the customer asks for a human or the bot cannot solve the issue; repeat questions are re-answered with one ask-line (deterministic isRepeatQuery on top of memory last_queries); URLs must stand alone on their own line; reply language mirrors the customer (language_code mapped to friendly names).
  • Purchase flow: multi-way state machine + inline buttons (第13批, 2026-08-31) — deterministic pendingPurchase state machine (mirrors the free-trial pendingTrials pattern) replaces the single admin deep link. Purchase intent is intercepted in message:text via PURCHASE_INTENT_RE (zh/en/ms, SKU-aware; FREE-prefixed trial SKUs are never intercepted) → a two-row inline keyboard: ① 网店下单 (online store / marketplace — neutral words, preferred, row on top) → neutral guidance + 联系 admin / 返回 buttons; ② 找 admin 购买 → admin deep link issued DIRECTLY (fallback, fast). 「返回」re-shows the menu; every callback branch ends with answerCallbackQuery() (Telegram retry idempotency). Deep-link prefill is a free-text sentence in the customer's language built by buildAdminPurchaseLink({sku?, paymentPreference?, username?, lang?}) — whatever was collected (SKU / payment preference / labelled username), nothing forced; no SKU → generic product message. The URL is encodeURIComponent'd exactly ONCE in code; the prompt carries two static pre-encoded samples (with/without username) and the model only swaps alphanumeric SKU/username — this killed the double-nesting bug (第1批 f27bbb4). 中性词纪律: no Shopee/Lazada/Add-On/TnG/bank-in anywhere in bot copy until the marketplace is live (test-asserted). Full plan: docs/PURCHASE_FLOW_REDESIGN.md.
  • Free-trial flow button-ified (第3批, 2026-08-31) — startSku / confirmReuse replies now carry inline buttons ( 确认并开通 / ✏️ 提供新 username / ♻️ 加到现有账号) dispatched into the pendingTrials state machine; the legacy text path (同意 / 新账号 xxx / 用户名:…) still works unchanged.

Remaining items:

  • Enrich user profile & conversation memory (src/ai/memory).
  • Explicit tool schemas (product lookup, order lookup, status, free-account) with validation before n8n execution.
  • Admin/user authorization + rate limiting; allowlist enforced in production.
  • Logging, correlation IDs, observability.
  • Formalize Channel/Core contracts so Shopee/Lazada adapters drop in without touching the AI core.

Why now: only once Phase 1 shows what the customers actually ask.

Phase 3 — RAG + Multi-Channel

  • Enable pgvector in the existing pgvector/pgvector:pg17 Postgres (already provisioned) when keyword lookup becomes insufficient.
  • Ingestion pipeline for docs/FAQs/products/policies.
  • Retrieval evaluation + source attribution/citation.
  • Shopee adapter (merchant/chat API), then Lazada adapter.
  • Channel-specific personas/prompts while keeping shared product/customer context.
  • Consider a separate vector DB only if pgvector becomes a real bottleneck.

Why pgvector before Qdrant: vectors live alongside ordinary Postgres data; exact + ANN search; keeps the architecture smaller until scale demands separation.

Criteria for adding new infrastructure

Before introducing any new service, explain operational cost and confirm the existing stack (Postgres, n8n, Traefik, LiteLLM) can't already meet the need. Non-goals to protect: no Qdrant/vector DB without a concrete requirement, no multi-agent swarm, no model fine-tuning, no Dify unless it earns its place.

Risks / open items

  • LiteLLM shared key: bot currently uses the mem0 LiteLLM master key. Phase 2 should mint a dedicated virtual key (rate-limit + revoke isolation). See docs/DECISIONS.md.
  • Webhook auth: TELEGRAM_WEBHOOK_SECRET guards the URL path; keep it strong in production.
  • Free-account workflow: the exact n8n workflow path/schema is still a placeholder — confirm with the actual workflow before wiring it to the LLM as a tool.