Qontak | AI Agent | Knowledge — Phase 1: Conversation History
Conversation History — Phase 1 PRD under the AI Agent: Knowledge ANCHOR. Adds a new dynamic knowledge-source type that lets the AI Agent learn from selected expert agents' resolved conversations (PII-masked, 3-month rolling window, daily sync). Imported from Confluence and reconciled against code (
chatbot,chatbot-fe,qontak-designer).
HEADER BLOCK
| Field | Value |
|---|---|
| PM | Dimas Fauzi Hidayat |
| PRD Version | 1.4 |
| Status | DRAFT |
| PRD Type | PHASE |
| Epic | TBD — Epic not yet created (stories tracked as TEMP placeholders) |
| Squad | BOT (Hadiningbot) |
| Designer | Wulan Febyazzahra Putri (Bulan) |
| PMM | Yosephine Dhisaclara (Ocie) |
| RFC Link | Planned — RFC to be created with engineering and the Data & AI team |
| Figma Master | Figma — AI Agent config (node 18883-4459) · AI Resources (node 10853-57617) |
| Anchor | AI Agent: Knowledge — ANCHOR (Confluence) |
| Labels | epic:qontak-chatbot | module:ai-agent | feature:ai-agent-knowledge |
| Last Updated | 2026-06-30 |
Scope Changes
Backend · Frontend · Data — new conversation_history knowledge type + agent/division config UI (chatbot, chatbot-fe), and the ingestion/PII-masking/daily-sync pipeline (Data).
2. Phase Context
- Anchor PRD: AI Agent: Knowledge — ANCHOR
- Phase Number: Phase 1 of N (phasing by knowledge source; static PDF/URL pre-exist)
- Phase Goal: Let the AI Agent learn from selected expert agents' resolved conversations — a dynamic, PII-masked, self-updating knowledge source — to lower the AI adoption barrier for Qontak360 clients.
- Prior phases: N/A as a phase, but static PDF/Website knowledge already ships and this source plugs into the same Knowledge module and "Training Source" UI.
- This phase: The
conversation_historyknowledge type — division + expert-agent selection, ingestion with quality/PII gates, daily sync over a 3-month rolling window, referencing with room-id source links, and management (status, remove, delete). - Deferred to next: Data-driven agent selection, automated knowledge weighting, multi-media ingestion, real-time sync, cross-division pooling, proactive gap detection (see §16 / ANCHOR future phases).
- Cross-phase deps: Reuses the existing Knowledge Base schema (new
conversation_historytype) and the AI vector DB. The type/index contract here must remain stable for future dynamic sources.
3. One-liner + Problem
One-liner: Enable AI Agents to learn from high-performing human agents' resolved conversations, so they give more "human-like", contextually accurate answers — without manual knowledge-base building.
Problem: Admins struggle to keep AI knowledge updated because official docs (PDFs/websites) miss the edge cases and brand tone agents use daily. That "tribal knowledge" is locked in chat logs and lost to the AI, so agents hit knowledge gaps (slower resolution) and SPVs carry a heavy manual coaching/onboarding burden. For Qontak360 clients, the effort to compile training sources is the real barrier to AI adoption. For full initiative context, see the ANCHOR PRD.
4. Target Users + Persona Context
| Persona | Role | Goal | Pain | Workaround |
|---|---|---|---|---|
| Primary — Agent | Front-line agent handling daily inquiries | Immediate, "proven" Airene Copilot answers based on how the team solved similar issues, without leaving the Inbox | Misinformation / knowledge gaps for specific inquiries → slow resolution | Searches old chats / Slack; waits for an SPV |
| Primary — SPV / Admin | Supervisor / Admin configuring AI knowledge | Set up AI knowledge sources without weeks of manual documentation | Manual onboarding + constant micro-coaching; high effort to compile sources | Manually compiles PDFs/FAQs; coaches 1:1 |
Target profile: Qontak360 AI-Agent users — companies with large agent teams (>100) or high transaction volumes (tax/PPN) needing high accuracy; want AI for daily inquiries but lack resources to build a manual KB from scratch.
5. Non-Goals
- Automated agent selection — the system will not auto-select agents by CSAT/tenure; selection stays a manual Admin task (this phase).
- Real-time knowledge ingestion — knowledge updates daily (once/24h), not as chats happen.
- Multi-media knowledge — text-only; images/files within chats are not indexed.
- Cross-division knowledge sharing — one Division has exactly one Conversation History source; no sharing across divisions.
- Performance reporting overhaul — no new reporting dashboards (handled by a separate initiative).
6. Constraints
- Platform: Web only (AI Agent configuration + AI Resources). Copilot suggestions surface in the Inbox.
- Performance: Initial training completes within ~1 hour for 15 agents. Conversation training runs in a dedicated/isolated service to avoid "noisy neighbor" effects on the main app.
- Tier (plan scope): Qontak360 only — Service Suite and Pro-above. Not on lower tiers.
- Feature flag: TBD (align with engineering) | default: OFF.
- Read/write: Admin / Super Admin can configure, save, remove, and delete the source. Agents consume Copilot suggestions; reference-link access is permission-scoped by room.
- Data limits: Max 15 agents per division-source. 3-month (90-day) rolling lookback. Text-only messages. Excludes internal notes/whispers. Rooms with < 5 bubble messages ignored. One Division = one Conversation History source.
- Quota: Usage governed by a monthly Copilot quota (e.g., 15 quota/seat for Service Suite).
6.1 Data Lifecycle
| Artifact Type | Retention | Cleanup Trigger | User-Visible Effect |
|---|---|---|---|
| Indexed conversation vectors (per division-source) | Rolling 90 days | Daily sync purges data older than 90 days | Knowledge stays "fresh"; "Last Updated" timestamp advances |
| Indexed vectors on source removal | Until source deleted | Hard delete of all associated vectors for that division when the source is deleted | Source disappears from Knowledge Index / AI Resources |
| Transient ingestion payload (raw chat pre-masking) | Not persisted post-processing | Discarded after PII masking + indexing | None |
7. Feature Changes
CHG-001 — "Conversation History" option in Add Knowledge + status in Knowledge Index
- Change Type: Modified flow + modified component (Knowledge module).
- Page: AI Agent → Knowledge Section → "Add Knowledge" (existing agent detail
[id].vue); Create AI Agent (create/index.vue) → "What sources does your agent learn from?"; AI Agent detail[id].vue→ Capabilities tab (per-capability Sources section); and the Knowledge Index page; and the AI Resources page. - Before: "Add Knowledge" offers static sources only (PDF, Website/URL). Knowledge Index lists static sources with no per-source training state for dynamic data.
- After: "Add Knowledge" shows a new "Conversation History" option (Qontak360 only). The Knowledge Index / AI Resources shows a per-source training status ("Training in Progress" / "Active" / "Error") and a "Last Updated" timestamp.
| Element | Before | After |
|---|---|---|
| Add Knowledge modal | PDF / Website only | + "Conversation History" (Qontak360) |
| Knowledge Index row | Static source, no live state | Training status + "Last Updated" timestamp |
Figma: AI Agent config — node 18883-4459.
8. New Features
Design status: IMPLEMENTED on
feat/resources-conv-history(branch:qontak-designer). The prototype is updated and covers most UI/UX requirements. Two gaps remain open for designer/engineer follow-up.Prototype components + Figma nodes:
- Add-source flow + "Conversation history" option —
app/components/bot-automation/sources/AddKnowledgeDrawer.vue· FigmaLJ6ePL0PjxKbHYZZdNK4LX(✨ Bot - AI) nodes20840-30474/20840-32079/20839-31336
- "Add source" sub-drawer lists all 4 source types incl. Conversation history
showAddConvHistoryModal— agent+division picker modal with division-level checkbox select (addConvToggleDivision) and individual agent toggle (addConvToggleAgent)showConvHistoryDrawer— "Conversation history" drawer (when source already exists) withMpToggle "Use as source"for unlink flow + Agent/Division read-only table- Source detail with Agent·Division table —
app/components/bot-automation/sources/SourceDetailDrawer.vue· Figma4eR76oEuKnaW2t40z4dfEa(✨ AI Resources) node10859:83239
- Shows source info + Agent/Division table for conversation-history type; footer "Delete" (danger link) for deletion
- AI Resources list (Status, Last updated, delete) —
app/pages/bot-automation/resources/index.vue· FigmaLJ6ePL0PjxKbHYZZdNK4LXnode20671:248358
- Status column: "Active" / "Processing" (= Training in Progress) / "Inactive"; "Last updated" timestamp column
Remaining gaps (designer/engineer to address before build):
- 15-agent cap + validation message — PRD CONVHIST-S04.
addConvSelectedAgentIdsinAddKnowledgeDrawer.vuehas no cap, no live "N/15" counter, and no "Please limit selection to your top 15 experts" validation. Must be added.- "Select agents with proven expertise" guidance tooltip — PRD §8 / CONVHIST-S01/AC-3. The modal body has descriptive copy but no tooltip component on the agent picker. Must be added.
Division-first multi-select— Resolved.addConvToggleDivision()implements division-level select; individual agents can be deselected (CONVHIST-S05 covered).Training-status lifecycle— Partially resolved. Resources list now shows "Active"/"Processing"; "Error" / "Last Successful Sync" state still absent.
Feature: Conversation History knowledge source
- Entry points:
- (a) Existing AI Agent —
[id].vue→ Knowledge Section → Add Knowledge → "Conversation History" - (b) AI Resources page —
/bot-automation/resources→ Add source → "Conversation History" - (c) Create AI Agent —
create/index.vue→ "What sources does your agent learn from?" → Conversation history row →+button (or "N selected" if already added) - (d) AI Agent detail — Capabilities tab —
[id].vue→ Capabilities tab → per-capability "Add source" (from capability edit drawer, or inline from the capability card body)
- (a) Existing AI Agent —
- Access: Admin / Super Admin on Qontak360 (Service Suite / Pro-above).
Config flow:
- Select a Division (one Division = one Conversation History source).
- Select up to 15 Agents/SPVs within that division (or "select division" to mark all agents under it, still capped at 15) — guidance tooltip: "Select agents with high domain expertise for better reference quality."
- Save → ingestion begins for the last 3 months of resolved chats → status "Training in Progress" → "Active" (~1 hour) with a "Last Updated" timestamp.
Component Tree:
-
CreateAIAgentPage(/bot-automation/ai-agents/create) — entry point (c)KnowledgeSourcesSection— "What sources does your agent learn from?" — purpose: source selection during creationConversationHistoryRow— purpose: dedicated row with+/ "N selected" button;selectedCountFor()shows agent countAddKnowledgeDrawer(:direct-sub-flow="'conversation-history'") — purpose: skips main list, opens directly in conv-history sub-flow- → branches to
showAddConvHistoryModalorshowConvHistoryDrawerdepending onhasConvHistory
- → branches to
-
AIAgentDetailPage(/bot-automation/ai-agents/[id]) — entry points (a) and (d)ProfileTab— entry point (a)KnowledgeSection→AddKnowledgeButton→AddKnowledgeDrawer(id="add-source-drawer") — purpose: agent-level source management
CapabilitiesTab— entry point (d)CapabilityCard(per capability)SourcePills— purpose: shows conv-history as a chip withTrainingStatusBadge("Training" warning / "Failed" critical)InlineAddSourceLink→AddKnowledgeDrawer(id="inline-cap-source-drawer") — purpose: add source without opening edit drawerCapabilityEditDrawer→SourcesSection(collapsible)StatusBanner— purpose: "N sources in training, M failed" warningSourceRow(per source) + remove button — purpose: list + remove capability-scoped sourcesAddSourceButton→AddKnowledgeDrawer(addKnowledgeSubDrawerOpen) — purpose: add source scoped to this capability
- On save: cap-level + agent-level source IDs are merged and deduped via
registerAgentSources()
-
ResourcesPage(/bot-automation/resources) — entry point (b)AddKnowledgeButton→AddKnowledgeDrawer(source-type picker) — purpose: choose source typeSourceTypeOption: "Conversation history"— purpose: entry to this feature (Qontak360 only)ConversationHistoryModal(showAddConvHistoryModal) — purpose: configure new sourceDivisionSelect— purpose: pick the one division (one division = one source)AgentMultiSelect(cap 15) — purpose: pick expert agents; shows15-cap counter+ validationExpertiseTooltip— purpose: guidance ("select agents with proven expertise")SaveButton— purpose: trigger ingestion (disabled until valid)
ConversationHistoryDrawer(showConvHistoryDrawer) — purpose: view/unlink existing sourceMpToggle "Use as source"— purpose: toggle unlinks without deletingAgentsTable(read-only) — purpose: show selected agents
KnowledgeIndexTable/SourceRow— purpose: list sourcesTrainingStatusBadge(Processing / Active / Inactive) — purpose: ingestion stateLastUpdatedCell— purpose: freshness signalRowActions(Delete) — purpose: hard-delete
SourceDetailDrawer— purpose: view a sourceAgentsTable(Agent · Division) — purpose: show which agents feed the sourceDeleteButton(danger link) — purpose: delete the source
UI States:
- Empty: no Conversation History source yet; primary action = Add Knowledge → Conversation History.
- Loading: "Training in Progress" while ingestion runs.
- Error: "Error" / "Last Successful Sync" state if masking/indexing fails, with Admin notification.
- Success: "Active" with "Last Updated" timestamp; source usable by the AI Agent.
📊 UI State Diagram — Conversation History source lifecycle
stateDiagram-v2
[*] --> Configuring: Add Knowledge → Conversation History
Configuring --> Configuring: select division + agents (≤15)
Configuring --> TrainingInProgress: Save (valid)
Configuring --> [*]: Cancel
TrainingInProgress --> Active: ingestion + masking + indexing OK (~1h)
TrainingInProgress --> Error: masking/indexing fails
Error --> TrainingInProgress: retry / next daily sync
Active --> Active: daily sync (ingest new, purge >90d, Last Updated advances)
Active --> Removed: Remove (−) from agent / Delete source
Error --> Removed: Delete source
Removed --> [*]
Figma: AI Resources — node 10853-57617. Implemented prototype + precise nodes: see the Design status callout at the top of this section.
9. API & Webhook Behavior
Technical fields (HTTP methods, JSON schemas, error codes) resolved during RFC. Provided by the Qontak backend + the Data & AI team.
| # | Behavior | Entity Affected | Triggered By | Expected Behavior | Failure Behavior |
|---|---|---|---|---|---|
| 1 | Fetch divisions + agents | Read division/agent directory | Opening the config modal | Returns divisions and the agents within each, to populate selection | Directory unavailable → modal shows load error + retry |
| 2 | Create Conversation History source | New conversation_history knowledge record | Admin clicks Save | Persists division + selected agent IDs (≤15); triggers ingestion of last-3-month resolved rooms for those agents; status → "Training in Progress" | >15 agents → validation error, Save disabled. Save fails → error surfaced |
| 3 | Training-status webhook | Knowledge record status | Data & AI team training pipeline | Updates Qontak backend: in_progress / completed / failed; on completed sets "Last Updated" | On failed/masking error → status "Error"/"Last Successful Sync" + Admin notification |
| 4 | Daily sync (cron, ~24h @ 01:00) | Indexed vectors | Scheduled job | Ingests previous day's resolved rooms for selected agents; purges data > 90 days; updates "Last Updated" | Job failure logged + alerted; previous index retained |
| 5 | Reference link to source room | Read room by room_id | AI answer cites a source | Returns a link to the original room only if the requesting user has permission to view it | Unauthorized (e.g., different division) → access denied / permission error |
Ingestion pipeline (Data & AI team): PII masking (NLP redaction → generic tags), quality gate (
status: resolved, ≥5 bubble messages), role filter (customer-facing only; exclude internal notes/whispers), recency prioritization on conflicts.
10. System Flow + User Stories + ACs
10.1 System Flow
Flow: Configure & ingest a Conversation History knowledge source
Type: User Journey + API Sequence
- Admin opens AI Agent → Knowledge Section (or AI Resources) → clicks "Add Knowledge".
- Selects "Conversation History" (Qontak360 only). Branch: if the account is not Qontak360 → option not shown (NEG-1).
- Selects one Division (one Division = one source). Branch: if the division already has a source → blocked (NEG-3).
- Selects up to 15 Agents/SPVs (or selects the division to include all, capped at 15); tooltip guides expert selection. Branch: 16th selection → validation message, Save disabled (S04).
- Clicks Save → backend creates the source (
POSTcreate, §9 #2) and triggers ingestion of the last 3 months of resolved rooms for those agents → status "Training in Progress". - Quality gate: only
resolvedrooms with ≥5 bubble messages; text-only; exclude internal whispers. Branch: a selected agent with zero qualifying rooms → ignored, others proceed (NEG-2). - PII masking redacts emails/phones/addresses/financial/identity → generic tags, then indexes to the vector DB. Failure branch: masking/indexing fails → room skipped, source status → "Error"/"Last Successful Sync", Admin notified (S06/ERR-1).
- Training-status webhook (§9 #3) flips status "Training in Progress" → "Active" (~1h) and sets a "Last Updated" timestamp.
- End-user asks the AI Agent a question → AI searches the indexed history → returns an answer from a past successful resolution. Branch: conflicting resolutions → prioritize the most recent (S09).
- AI answer may include a reference link to the source
room_id. Branch: requester lacks room permission → access denied (S11/ERR-1). - Daily (24h) sync (§9 #4) ingests the prior day's resolutions and purges data older than 90 days. Failure branch: sync job fails → previous index retained, alert raised (S10/ERR-1).
📊 System Flow — configure & ingest
graph TD
A[Admin: Add Knowledge] --> B{Qontak360?}
B -- No --> B0[Option hidden NEG-1]
B -- Yes --> C[Select Conversation history]
C --> D{Division has a source?}
D -- Yes --> D0[Blocked: one division = one source NEG-3]
D -- No --> E[Select agents]
E --> F{More than 15?}
F -- Yes --> F0[Validation; Save disabled S04]
F -- No --> G[Save → create source + trigger ingestion]
G --> H[Quality gate: resolved, >=5 msgs, text-only, no whispers]
H --> I[PII masking → index vectors]
I -- masking/index fails --> X[Status: Error + notify admin S06]
I -- ok --> J[Webhook: Training in Progress → Active + Last Updated]
J --> K[AI answers from history]
K --> L{Conflicting resolutions?}
L -- Yes --> M[Prioritize most recent S09]
L -- No --> N[Return answer + optional room-id reference]
N --> O{Requester has room permission?}
O -- No --> O0[Access denied S11]
O -- Yes --> P[Open source room]
J --> Q[Daily 24h sync: ingest new, purge >90d]
Q -- sync fails --> R[Retain prior index + alert S10]
10.2 User Stories
All stories carry their original TEMP ticket placeholders from the Confluence draft (real Jira epic/keys TBD — §17 Open Question #2). Priority preserved from the source.
CONVHIST-S01 — Source configuration | Must Have
Story: As an Admin, I want to select "Conversation History" as a knowledge source, so that the AI can learn from agent expertise. (TEMP-15afd22e)
Before: Add Knowledge offers static sources (PDF/Website) only. After: Add Knowledge offers a "Conversation History" option (Qontak360) configurable from both AI Agent config and AI Resources.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| division_id | uuid | Yes | User selection |
| agent_ids | array (≤15) | Yes | User selection |
| source_type | enum (conversation_history) | Yes | System |
Happy Path:
- AC-1: Given I am in the Knowledge Section of a Qontak360 AI Agent, when I select "Conversation History", choose a Division and pick agents, then the system initiates ingestion and shows "Training in Progress".
- AC-2: Given I go to the AI Resources menu, when I click "Add source", then a "Conversation History" option is shown and I can choose a Division or pick agents.
- AC-3: Given I save a valid source, when creation succeeds, then a new row appears in the Knowledge Index with status "Training in Progress" and a guidance tooltip ("Select agents with proven expertise") was shown during selection.
- AC-4: Given I am creating a new AI Agent, when I reach "What sources does your agent learn from?", then a "Conversation history" row is shown; clicking
+opens the division+agent picker (bypassing the main source list); after saving, the button updates to "N selected" showing the agent count. - AC-5: Given I am in the Capabilities tab of an existing AI Agent (
[id].vue), when I click "Add source" in a capability edit drawer or inline from the capability card, then "Conversation history" is available; the added source appears as a pill with a "Training" badge; the capability edit drawer shows a status banner for in-progress or failed sources.
Error Path:
- ERR-1: Given the division/agent directory fails to load, when the modal opens, then a load error with Retry is shown and Save is disabled.
Permission Model: CAN: Admin/Super Admin (Qontak360). CANNOT: Agents, lower tiers. Unauthorized: option not rendered for ineligible roles/plans.
UI States: Loading (directory fetch), Empty (no source yet), Error (load failed + Retry), Success ("Training in Progress" entry created).
Figma: node 18883-4459 / 10853-57617. Dependencies: None.
Prototype (
feat/resources-conv-history):
AddKnowledgeDrawer.vue— "Add source" sub-drawer lists Conversation History, callinghandleNewSourceSelect()(AC-1/2 entry).showAddConvHistoryModal— division+agent picker modal withaddConvFilteredDivisions+ per-division agent checkboxes.resources/index.vue— source row appears with "Processing" status after save (AC-3).create/index.vue(AC-4) —knowledgeSourcesarray (line 1064–1069) includes the "Conversation history" row.AddKnowledgeDrawerbound with:direct-sub-flow="'conversation-history'"(line 398–411) bypasses the main list and jumps to the conv-history sub-flow.selectedCountFor("conversation-history")(line 1278–1285) returnsagentIds.lengthoragentCountfor the "N selected" label. Present in both Guided form and Write prompt tab sections.[id].vue(AC-5) — threeAddKnowledgeDrawerusages: capability edit drawer (line 3521), global agent-level Sources (line 3537), inline from capability card body (line 3546). Capability card body (line 1055–1092) renders conv-history as a source pill with "Training" (warning) / "Failed" (critical)TrainingStatusBadge. Capability edit drawer (line 2362–2432) shows a status banner with counts of in-progress and failed sources.- ERR-1 (directory load error) not in prototype.
CONVHIST-S02 — Remove Conversation History from an AI Agent | Must Have
Story: As a user, I want to remove the Conversation History knowledge from my AI Agent. (TEMP-3452f2e4)
Before: No way to unlink a conversation-history source from an agent. After: A minus (−) control unlinks the source from the agent without deleting the underlying knowledge.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| ai_agent_id | uuid | Yes | Route |
| knowledge_source_id | uuid | Yes | Selected row |
Happy Path:
- AC-1: Given I edit an AI Agent and go to the Knowledge section, when I click the − button beside the Conversation History knowledge, then it is unlinked from this agent.
- AC-2: Given I unlink the source, when the action completes, then the underlying Conversation History knowledge is not deleted (it remains available in AI Resources).
- AC-3: Given the source is unlinked, when the agent next answers, then it no longer references that conversation history.
Error Path:
- ERR-1: Given the unlink request fails, when I click −, then the source stays linked and an error is shown.
Permission Model: CAN: Admin/Super Admin. CANNOT: Agents.
UI States: Loading (removing), Empty (no sources linked), Error (failed), Success (source removed from list).
Dependencies: CONVHIST-S01.
Prototype (
feat/resources-conv-history):
AddKnowledgeDrawer.vue→showConvHistoryDrawer— "Conversation history" drawer withMpToggle id="conv-history-toggle" v-model:is-checked="convHistoryEnabled"implements the unlink toggle (AC-1/2); toggling off unlinks without deleting the underlying source.[id].vue(capability-level removal) —removeKnowledge(index)called from theminus-circularbutton in the capability edit drawer Sources section (line 2433–2468) removes conv-history from an individual capability without deleting the underlying source (AC-1/2).- ERR-1 (unlink failure) not in prototype.
CONVHIST-S03 — Delete Conversation History knowledge | Must Have
Story: As a user, I want to delete the Conversation History knowledge for my AI Agent. (TEMP-2bcdd6e5)
Before: No delete path with usage protection. After: Delete from AI Resources, guarded by an "in use" check; deletion hard-deletes the indexed vectors.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| knowledge_source_id | uuid | Yes | Selected row |
| in_use | boolean | Yes | System (computed) |
Happy Path:
- AC-1: Given I am in the AI Resources menu viewing a Conversation History knowledge, when I click Delete and no AI Agent uses it, then the system shows a confirmation prompt.
- AC-2: Given I confirm deletion of an unused source, when deletion proceeds, then all associated indexed vectors for that division are hard-deleted and the row is removed.
- AC-3: Given a source has been deleted, when I want it back, then it cannot be restored — I must create a new source to re-index (no undo).
Error Path:
- ERR-1: Given the knowledge is used by one or more active AI Agents, when I click Delete, then the system blocks deletion and shows an error: I must remove it from those AI Agents first.
Permission Model: CAN: Admin/Super Admin. CANNOT: Agents. CANNOT: a deleted source cannot be restored (re-create to re-index).
UI States: Loading (deleting), Empty (N/A), Error (in-use block), Success (knowledge removed).
Dependencies: CONVHIST-S02.
Prototype (
feat/resources-conv-history):SourceDetailDrawer.vue— footer renders a "Delete" danger text-link (deleteLinkClass) for conversation-history type (AC-1/2).resources/index.vue— row delete action available. AC-3 (no restore) and ERR-1 (in-use block) are backend behaviors not in prototype.
CONVHIST-S04 — Agent selection cap (15) | Must Have
Story: As QA, I want the system to limit agent selection to 15, so that processing performance and quality are maintained. (TEMP-12664d21)
Before: No cap on selectable agents. After: Selection is capped at 15 with a live counter and validation.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| agent_ids | array | Yes | User selection |
| max_agents | int (15) | Yes | System constant |
Happy Path:
- AC-1: Given I am selecting agents, when I select up to 15, then selection is allowed and Save is enabled.
- AC-2: Given I am selecting agents, when the count changes, then a live counter shows "N/15 selected".
- AC-3: Given I am at 16 and over the cap, when I deselect back to ≤15, then the validation message clears and Save re-enables.
Error Path:
- ERR-1: Given I have selected 15 agents, when I attempt to select the 16th, then a validation message appears ("Please limit selection to your top 15 experts") and Save is disabled.
Permission Model: CAN: Admin/Super Admin.
UI States: Loading (N/A), Empty (none selected → Save disabled), Error (cap exceeded message), Success (≤15 selected → Save enabled).
Dependencies: CONVHIST-S01.
⚠️ Prototype (
feat/resources-conv-history): Not implemented.addConvSelectedAgentIdsinAddKnowledgeDrawer.vuehas no 15-agent cap, no live "N/15" counter, and no validation message. Must be implemented before build.
CONVHIST-S05 — Select a whole division | Must Have
Story: As an Admin, I want to quickly add a selected division as a Conversation History source, so that all agents under that division become a knowledge source. (TEMP-77aff3c9)
Before: Agents must be picked individually. After: Selecting a division marks its agents as selected (still capped at 15); individuals can be deselected.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| division_id | uuid | Yes | User selection |
| included_agent_ids | array (≤15) | Yes | System (derived) + user edits |
Happy Path:
- AC-1: Given I am in the Knowledge Section, when I open the selector, then the system shows all divisions including the agents under each.
- AC-2: Given I select a division, when I confirm, then all agents under it are marked as selected (capped at 15) and I can click Save.
- AC-3: Given a division is selected, when I deselect specific agents, then those are excluded while the rest remain selected.
Error Path:
- ERR-1: Given a division has more than 15 agents, when I select it, then the cap rule (S04) applies — I must narrow to 15 before Save.
Permission Model: CAN: Admin/Super Admin.
UI States: Loading (division/agent fetch), Empty (no divisions), Error (cap exceeded), Success (division's agents selected).
Dependencies: CONVHIST-S04.
Prototype (
feat/resources-conv-history):AddKnowledgeDrawer.vue—addConvToggleDivision(divId)implements division-level checkbox select (AC-2);addConvIsDivisionAll(divId)/addConvIsDivisionPartial(divId)drive the full/indeterminate checkbox state;addConvToggleAgent()deselects individual agents within a division (AC-3). ERR-1 (cap triggered on division select) is blocked by the S04 gap — cap not yet enforced.
CONVHIST-S06 — PII data masking | Must Have
Story: As a Compliance Officer, I want PII redacted, so that sensitive customer data is not leaked into AI responses. (TEMP-abb97fb2 — Data & AI team)
Before: Raw chat data would carry PII into the vector DB. After: A mandatory masking service redacts PII to generic tags before indexing.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| raw_message | text | Yes | Chat ingestion |
| masked_message | text | Yes | Masking engine |
| entity_tags | array (e.g. [EMAIL], [PHONE_NUMBER]) | Yes | Masking engine |
Happy Path:
- AC-1: Given a chat contains an email ("customer@email.com") and a phone ("0812345678"), when the ingestion engine processes the room, then the indexed data replaces them with
[EMAIL]and[PHONE_NUMBER]tags. - AC-2: Given a chat contains an address, credit-card/bank, or national-ID, when ingested, then those entities are redacted to generic tags.
- AC-3: Given redaction occurs, when the message is indexed, then conversation structure is preserved (the AI sees
[PHONE_NUMBER], not the digits).
Error Path:
- ERR-1: Given the masking service fails for a room, when ingestion runs, then that room is not indexed and the source status reflects "Error"/"Last Successful Sync" with an Admin notification.
Permission Model: System rule (Data & AI pipeline).
UI States: N/A (backend) — surfaced via source status.
Dependencies: CONVHIST-S01.
CONVHIST-S07 — Quality gate (noise filter) | Should Have
Story: As a PM, I want to exclude short/junk chats, so that the AI doesn't learn from "empty" interactions. (TEMP-383496c3)
Before: All resolved rooms would be eligible. After: Rooms with fewer than 5 bubble messages are skipped.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| room_id | uuid | Yes | Chat service |
| message_count | int | Yes | System (customer-facing only) |
| min_messages | int (5) | Yes | System constant |
Happy Path:
- AC-1: Given a resolved room has only 3 messages, when the daily sync / ingestion runs, then the system skips the room and does not index it.
- AC-2: Given a resolved room has ≥5 customer-facing messages, when ingestion runs, then it is eligible for indexing.
- AC-3: Given a room has ≥5 messages but only 4 are customer-facing after whisper exclusion (S08), when counted, then it is treated as <5 and skipped.
Error Path:
- ERR-1: Given a room has ≥5 messages but they are all non-text, when filtered, then it yields no indexable content and is skipped (see S13).
Permission Model: System rule.
UI States: N/A (backend).
Dependencies: CONVHIST-S06.
CONVHIST-S08 — Internal privacy (exclude whispers) | Must Have
Story: As an Agent, I want my internal notes/whispers excluded, so that they aren't exposed to customers by the AI. (TEMP-1cef587e)
Before: Ingestion could pick up internal-only messages. After: Only customer-facing bubbles are indexed; internal notes/whispers excluded.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| message_type | enum (customer_facing / internal_note) | Yes | Chat service |
| is_indexable | boolean | Yes | System (derived) |
Happy Path:
- AC-1: Given a room has 10 customer-facing bubbles and 2 "Internal Whispers", when the system ingests the room, then only the 10 customer-facing bubbles are indexed.
- AC-2: Given an internal whisper contains PII, when ingestion runs, then it is excluded entirely (independent of masking).
- AC-3: Given a room mixes customer bubbles and system/bot internal events, when ingested, then only customer-facing agent/customer bubbles are indexed.
Error Path:
- ERR-1: Given a room contains only internal whispers, when ingestion runs, then nothing is indexed for that room.
Permission Model: System rule.
UI States: N/A (backend).
Dependencies: CONVHIST-S06.
CONVHIST-S09 — Recency prioritization | Should Have
Story: As an AI Agent, I want to prioritize the most recent resolutions when conflicts occur, so that I follow the latest SOP. (TEMP-00bf245c)
Before: No conflict-resolution rule between differing historical answers. After: On conflict, the most recent resolved room wins.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| resolution_date | datetime | Yes | Chat service |
| query_type | string | Yes | System (matched intent) |
Happy Path:
- AC-1: Given Agent A solved a "Tax" query in January and Agent B solved it differently in March, when a user asks that Tax query, then the AI generates a response based on the March resolution.
- AC-2: Given several recent resolutions match the same query, when ranked, then the single most-recent resolution is used as the primary reference.
- AC-3: Given two conflicting resolutions share the same resolution date, when ranked, then a deterministic tie-break applies (e.g., most recent
room_id) so output is stable.
Error Path:
- ERR-1: Given recency metadata is missing for a room, when ranking runs, then that room is de-prioritized rather than crashing the ranking.
Permission Model: System rule.
UI States: N/A (backend).
Dependencies: CONVHIST-S06.
CONVHIST-S10 — Daily maintenance sync (rolling 90 days) | Must Have
Story: As an Admin, I want the knowledge to stay fresh via a rolling 90-day window. (TEMP-0d9af881 — Data & AI team)
Before: No automated freshness; knowledge would go stale. After: A 24-hour cron ingests new resolutions and purges data past 90 days.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| sync_run_id | uuid | Yes | System |
| new_messages_ingested | int | Yes | System |
| purged_messages_count | int | Yes | System |
| last_updated | datetime | Yes | System |
Happy Path:
- AC-1: Given the 24-hour cron runs, when data reaches 91 days old, then the system purges the 91st-day data and ingests the last 24 hours' resolutions.
- AC-2: Given a successful sync, when it completes, then the source "Last Updated" timestamp advances.
- AC-3: Given there were no new resolutions in the last 24 hours, when the sync runs, then it still purges aged data and updates "Last Updated".
Error Path:
- ERR-1: Given the sync job fails, when it errors, then the previous index is retained, the failure is alerted, and status reflects "Last Successful Sync".
Permission Model: System rule (scheduled job).
UI States: Success ("Last Updated" advances) / Error (status reflects last successful sync).
Dependencies: CONVHIST-S06.
CONVHIST-S11 — Reference auditing (room-id source link) | Could Have
Story: As an Admin, I want to see the source Room ID for AI answers, so that I can verify accuracy. (TEMP-699b67cf)
Before: AI answers have no traceable source. After: Answers can include a permission-scoped link to the source room.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| room_id | uuid | Yes | Index reference |
| requesting_user_permissions | scope | Yes | Auth session |
Happy Path:
- AC-1: Given the AI provides an answer derived from history, when an authorized Admin views it, then a reference link to the source Room ID is available and opens the room.
- AC-2: Given an answer drew on multiple rooms, when references render, then the primary (most recent) source room is shown.
- AC-3: Given an answer used no conversation-history source, when it renders, then no room-id reference is shown.
Error Path:
- ERR-1: Given the AI answer includes a Room ID link, when a user from a different division clicks it, then access is denied with a permission error.
Permission Model: CAN: users with view permission for that room. CANNOT: users outside the room's division.
UI States: Success (link opens room), Error (permission denied).
Dependencies: CONVHIST-S06.
CONVHIST-S12 — Agent deactivation | Should Have
Story: As QA, I want a departed agent's vetted knowledge to remain useful for a period. (TEMP-76324b9b)
Before: Unclear what happens to a selected agent's history when they leave. After: A deactivated agent's history remains until it ages out of the 90-day window; no new ingestion for them.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| agent_id | uuid | Yes | Source config |
| agent_status | enum (active / deactivated) | Yes | Mekari directory |
| resolution_date | datetime | Yes | Chat service |
Happy Path:
- AC-1: Given Agent C has been deactivated in Mekari, when the knowledge base is queried, then Agent C's historical data remains usable until it naturally ages out of the 3-month window.
- AC-2: Given Agent C is deactivated, when the daily sync runs, then no new conversations are ingested for Agent C going forward.
- AC-3: Given Agent C's data has aged past 90 days, when the daily sync runs, then it is purged like any other expired data.
Error Path:
- ERR-1: Given Agent C is reactivated within the window, when the next sync runs, then ingestion resumes for new resolutions without duplicating existing indexed data.
Permission Model: System rule.
UI States: N/A (backend).
Dependencies: CONVHIST-S10.
CONVHIST-S13 — Multi-media exclusion (text-only) | Must Have
Story: As a Developer, I want only text processed, so that unsupported formats don't crash ingestion. (TEMP-b54d68cf)
Before: Mixed-content rooms could break ingestion. After: Only text content is indexed; images/attachments/voice are ignored.
Data Fields:
| Field | Type | Required | Source |
|---|---|---|---|
| message_content_type | enum (text / image / file / voice) | Yes | Chat service |
| is_indexable | boolean | Yes | System (derived) |
Happy Path:
- AC-1: Given a resolved room contains text and one PDF/image attachment, when ingestion occurs, then the system indexes the text content and ignores/excludes the attachment.
- AC-2: Given a message is an image with a text caption, when ingested, then the caption text is indexed and the image is excluded.
- AC-3: Given a message is a voice note, when ingested, then it is excluded and no transcript is generated (out of scope this phase).
Error Path:
- ERR-1: Given a room contains only non-text content, when ingestion runs, then nothing is indexed for that room and it does not error the batch.
Permission Model: System rule.
UI States: N/A (backend).
Dependencies: CONVHIST-S07.
Negative Scenarios
- NEG-1: Given a non-Qontak360 account, when an Admin opens Add Knowledge, then "Conversation History" is not offered.
- NEG-2: Given a selected agent has zero resolved chats in the last 3 months, when ingestion runs, then that agent is ignored and the others proceed.
- NEG-3: Given an Admin tries to add a second Conversation History source to a division that already has one, when they attempt it, then the system blocks it (one Division = one source).
- NEG-4: Given an internal whisper contains PII, when ingestion runs, then it is excluded entirely (internal-only), independent of masking.
11. Rollout
- Feature flag: TBD (align with engineering) | default: OFF. Enabled per account on Qontak360.
- Stage 1: Internal Alpha — Mekari internal CS/Support team.
- Stage 2: Closed Beta — 5–10 selected Qontak360 early adopters.
- Stage 3: Open Beta / Limited GA — all Service Suite and Pro-above clients.
- GA: All eligible Qontak360 accounts with full GTM.
- Backward compat: Yes — additive; static PDF/URL sources unaffected.
- Migration: None — new
conversation_historyknowledge type; no backfill.
12. Observability
| Event Name | Trigger | Properties |
|---|---|---|
knowledge_source_add_click | Admin clicks "Add Knowledge" | source_type: conversation_history |
conv_history_config_save | Admin clicks Save after selecting agents | division_id, agent_count (1–15), source_id |
conv_history_training_status | Training state changes | status (success/failed/in_progress), duration_seconds, error_message (if failed) |
conv_history_daily_sync | 24-hour background job completes | new_messages_ingested, purged_messages_count, sync_status |
Dashboard owner: BOT squad (Hadiningbot).
Alerts:
conv_history_training_status= failed (3 consecutive for one source) → Slack: BOT squad alert channel.conv_history_daily_sync= failed → Slack alert + escalation to the Data & AI team.
Post-Launch Monitoring Cadence: Weekly for the first 4 weeks post-GA, then monthly. Owner: Dimas (BOT squad PM). Triggers: training failure rate spikes or daily sync failures → investigate within 48h. Rollback: if masking/indexing failures are widespread and unresolved within the SLA, PM disables the flag for affected accounts pending fix.
13. Success Metrics
⭐ Primary KPI: Feature adoption
- Definition: % of active Qontak360 companies that configured ≥1 "Conversation History" training source
- Baseline: N/A — new feature
- Target: ≥ 30% of AI-Agent-active Qontak360 companies within 90 days of GA
Adoption: Knowledge contribution ratio
- Definition: % of an AI Agent's total "Reference Hits" that come from Conversation History vs PDF/Website sources
- Baseline: N/A
- Target: Established during beta
Quality: AI resolution rate uplift + Feature CSAT
- Definition: Reduction in "Unanswered Question" count after adding Conversation History; SPV/Admin CSAT on ease of training the AI from agent data
- Baseline: N/A — measured pre/post per client
- Target: Measurable reduction within 60 days; CSAT target set in beta
Efficiency: Onboarding speed + knowledge freshness
- Definition: Reduction in new-agent time-to-productivity in active divisions; daily sync success (rolling 3-month window maintained)
- Baseline: N/A
- Target: Sync success ≥ 99%; onboarding-speed target set in beta
14. Launch Plan & Stage Gates
| Stage | Audience | Duration | Success Gate | Owner |
|---|---|---|---|---|
| Internal Alpha | Mekari internal CS/Support | 2 weeks | 100% masking of standard phone/email formats; <1h training for 15 agents | PM + QA |
| Closed Beta | 5–10 selected Qontak360 early adopters | 3 weeks | >70% of AI suggestions accepted ("Add to Compose") by human agents | PM + CSM |
| Open Beta / Limited GA | All Service Suite + Pro-above | 3 weeks | No significant performance degradation during the 24-hour sync window | Eng Lead |
| GA | All eligible Qontak360 accounts | Ongoing | KPIs sustained at scale; GTM/localized marketing in motion | PM + PMM |
15. Dependencies
| Dependency | Owning Team | Deliverable Needed | Blocking? |
|---|---|---|---|
| PII masking engine | Data & AI team | NLP redaction of emails/phones/addresses/financial/identity → generic tags, before indexing | YES |
| Conversation training service | Data & AI team | Isolated service to process heavy conversation data + vector indexing | YES |
| Training-status webhook | Data & AI team | Webhook to update Qontak on in_progress/completed/failed | YES |
| Agent–Division mapping API | BOT (chatbot) | Endpoint to list divisions + agents for the config modal | YES |
| Daily sync cron | BOT (chatbot) | Scheduled 24h job: ingest prior day, purge >90 days | YES |
| Resolved-room fetch (Inbox/Chat) | Inbox / Platform | Fetch resolved rooms by agent over a 90-day window | YES |
| Onboarding consent form | Legal / Ops | Existing consent covering use of agent–customer interactions for internal AI training | NO — reuse existing |
16. Key Decisions + Alternatives Rejected
Initiative-level decisions live in the ANCHOR PRD §5. Below are phase-specific decisions.
16a — Decisions Made
| Date | Decision | Rationale |
|---|---|---|
| 2026-04-13 | Max 15 agents per division-source | Balances quality (curated experts) with processing speed; avoids noise |
| 2026-04-13 | 3-month rolling window + daily sync | Keeps knowledge aligned to current SOPs without manual upkeep |
| 2026-04-13 | Recency rule for conflicting resolutions | L/E processes evolve; the latest resolution most likely follows current SOP |
| 2026-04-13 | One Division = one Conversation History source | Prevents conflicting domain knowledge |
| 2026-04-13 | Reuse existing "Training Source" UI | Faster delivery + UI consistency |
16b — Alternatives Rejected
| Alternative | Why Rejected | Date |
|---|---|---|
| Full company-wide history ingestion | High noise/risk — low-performer and junk data degrade accuracy | 2026-04-13 |
| Manual QA export + re-upload as PDF/Excel | High friction; defeats the automation value prop | 2026-04-13 |
| Division-wide auto-inclusion without agent selection | No control to prioritize senior experts over new joiners | 2026-04-13 |
| Real-time ingestion (MVP) | Complexity/cost; daily sync is sufficient for the first release (deferred) | 2026-04-13 |
| Multi-media ingestion (MVP) | Scope/complexity; text-only first (deferred) | 2026-04-13 |
17. Open Questions
| # | Type | Question | Owner | Deadline |
|---|---|---|---|---|
| 1 | Risk | PII masking must redact all listed entities before indexing. Mitigation: mandatory NLP masking → generic tags; Internal Alpha gate requires 100% masking of standard phone/email formats before GA. | Data & AI team | 2026-07-15 |
| 2 | Open Question | Jira epic + keys not yet created — stories are TEMP placeholders; delivery timeline (week-based in the draft) needs absolute dates. | Dimas (PM) | 2026-07-01 |
| 3 | Open Question | Copilot quota model for this source (e.g., 15 quota/seat Service Suite) — confirm metering and limits. | Dimas (PM) | 2026-07-15 |
| 4 | Open Question | Training-status webhook contract (states, payload, retry/error semantics) from the Data & AI team. | Data & AI team | 2026-07-15 |
| 5 | Risk | Reference-link permission scoping must deny cross-division access. Mitigation: validate requesting user's room-view permission on every reference open (S11/ERR-1). | BOT (chatbot) | 2026-07-15 |
| 6 | Assumption | "Resolved" status + ≥5 bubble messages is a sufficient proxy for a "complete, useful" resolution. | Dimas (PM) | 2026-07-15 |
| 7 | Risk | Design coverage: feat/resources-conv-history implements the core add/unlink/delete flows and division-first multi-select (CONVHIST-S05 resolved), but the 15-agent cap/validation (S04) and expertise tooltip (S01/AC-3) are absent, and the "Error" training-status state is not covered. Mitigation: §8 updated to IMPLEMENTED with remaining gaps documented; engineering and designer (Wulan) to add S04 cap + tooltip before build. | Wulan (Design) | 2026-07-15 |
PRD CHANGELOG
| Version | Date | By | Section | Type | Summary |
|---|---|---|---|---|---|
| 1.0 | 2026-06-18 | Claude | All | CREATED | Phase 1 PRD authored in the documents-repo template under the new AI Agent: Knowledge ANCHOR. Reformatted from the Confluence "AI Agent Knowledge: Conversation History" draft: 13 stories converted to native blocks with composite AC ids (CONVHIST-S01…S13, TEMP tickets preserved); added Phase Context, structured Constraints (+ data lifecycle), Feature Changes, New Features, API table, System Flow, Rollout, Dependencies, and Open Questions (PII/webhook/quota/permission flagged). |
| 1.1 | 2026-06-18 | Claude | S8, S17 | MODIFIED | Located the existing design in qontak-designer (AddKnowledgeDrawer / SourceDetailDrawer / resources page + Figma nodes) and cited it in §8. Marked §8 Design status as DRAFT and added Open Question #7 (Risk) flagging the prototype gaps for the designer to revisit: 15-agent cap/validation, expertise tooltip, division-first multi-select, training-status states. |
| 1.2 | 2026-06-18 | Claude | S8, S10 | MODIFIED | Applied score-prd improvements: added a Flow:/Type: declaration + explicit failure branches and a mermaid System Flow diagram (§10.1); added a hierarchical component tree + a mermaid UI-state diagram (§8); lifted every story to ≥3 happy-path ACs and converted all Data Fields to type/required/source tables (§10.2). |
| 1.3 | 2026-06-30 | Claude | §8, S01–S05, §17 | MODIFIED | Attached feat/resources-conv-history prototype implementation to the PRD. §8 Design status updated from DRAFT to IMPLEMENTED; gap list revised: gaps #3 (division-first multi-select) and #4 (training-status) marked resolved/partially resolved; gaps #1 (15-agent cap) and #2 (expertise tooltip) remain open. Prototype notes added to S01–S05 mapping each story's ACs to implementing components (AddKnowledgeDrawer.vue, SourceDetailDrawer.vue, resources/index.vue). S04 flagged ⚠️ not implemented. Open Question #7 updated to reflect current branch state. |
| 1.4 | 2026-06-30 | Claude | §7, §8, S01, S02 | MODIFIED | Added two missing AI Agent entry points: (c) Create AI Agent (create/index.vue) — "What sources does your agent learn from?" conv-history row with directSubFlow drawer; (d) AI Agent detail [id].vue — Capabilities tab per-capability "Add source" (edit drawer, inline). §8 Component Tree expanded to cover all four entry points. S01 AC-4 and AC-5 added for create and capability flows. S01 prototype note updated to reference create/index.vue (lines 398–411, 1064–1069, 1278–1285) and [id].vue (three AddKnowledgeDrawer usages, source pills, status banners). S02 prototype note updated to add capability-level removal via removeKnowledge() in [id].vue. |