Qontak | Chatbot | AI Agent — Idle Action — Adj: Sequential Idle Follow-up
HEADER BLOCK
| Field | Value |
|---|---|
| PM | Dimas Fauzi Hidayat |
| PRD Version | 1.1 |
| Status | DRAFT |
| PRD Type | ADJUSTMENT |
| Epic | BOT-XXXXX — add once Epic is created |
| Squad | BOT — Chatbot Squad |
| RFC Link | N/A — RFC to follow via rfc-starter |
| Figma Master | TBD — designer not yet assigned (step-list builder UI undesigned) |
| Anchor | No — standalone adjustment. Related initiative: Autonomous AI Agent |
| Labels | epic:qontak-chat | module:ai-agent | feature:idle-action |
| Last Updated | 2026-06-25 |
Status values:
DRAFT→READY→BUILD→SHIPPEDREADY gate: Epic cannot move to In Progress in Jira without PRD Link + RFC Link populated.
Table of Contents
- HEADER BLOCK
- 2. CONDITIONAL BLOCK: ADJUSTMENT CONTEXT
- 3. One-liner + Problem
- 4. Target Users + Persona Context
- 5. Non-Goals
- 6. Scope Changes
- 7. Constraints
- 8. Feature Changes
- 9. API & Webhook Behavior
- 10. System Flow + User Stories + ACs
- 11. Rollout
- 12. Observability
- 13. Success Metrics
- 14. Launch Plan & Stage Gates
- 15. Dependencies
- 16. Key Decisions + Alternatives Rejected
- 17. Open Questions
- PRD CHANGELOG
2. CONDITIONAL BLOCK: ADJUSTMENT CONTEXT
| Field | Detail |
|---|---|
| Parent Anchor PRD | N/A — standalone adjustment. The AI Agent v2 idle action ships today but was never captured in a repo PRD; this adjustment documents the existing behavior only insofar as it defines the before→after delta. Related initiative: Autonomous AI Agent. |
| This adjustment covers | Replacing the AI Agent's single idle action (parameters['idle_rule'].action = one of none/follow_up/assign/resolve) with a user-configurable ordered sequence of up to 3 steps, each step carrying its own idle duration + action + message. Adds per-room step-state tracking so an idle window advances the sequence and a customer reply resets it. Removes the AI Agent idle path's reliance on the global channel idle rule. |
| Parent PRD still owns | The AI Agent v2 engine, prompt/knowledge/capability config, routing, and all non-idle advanced settings (category, temperature, reasoning, message_limit, wait_time_seconds) remain unchanged. The legacy channel/bot-response idle rule (channel_integration.default_auto_send_next_intent_*, process_idle_rule_action.rb global path) is untouched and continues to govern non-AI-Agent flows. |
| Reason for adjustment | (1) Containment/deflection gap — today a single idle action can either nudge or resolve, so idle conversations either never auto-close (inflating open-room counts) or close prematurely without a nudge; the only "nudge-then-resolve" path requires chaining to the global channel idle rule, which is confusing to configure and couples the agent to channel settings. (2) Customer/sales request — customers have asked for multi-step idle follow-up before auto-close. |
| Scope boundary | Affects only the AI Agent idle path: the idle_rule shape in ai_agents.parameters, its create/update contract + entity, the FE idle-action form, and the runtime that fires it (send_message_with_resolve.rb detection + process_idle_rule_action.rb execution). No change to start/stop of conversations outside idle, to the global channel idle rule, or to any other advanced setting. Capped at 3 steps. |
3. One-liner + Problem
One-liner: Let Chatbot Specialists configure the AI Agent's idle action as a self-contained sequence of up to 3 steps — nudge, then auto-resolve — without touching channel settings.
Problem:
The AI Agent idle action is single-action today: after one idle timer it does exactly one of nudge / assign / resolve. To "nudge first, then resolve" a PM must enable the global channel idle rule in bot settings and rely on a hardcoded fallback (chatbot BE: process_idle_rule_action.rb:77-83) — a coupling that is non-obvious, easy to misconfigure, and shared across the whole channel rather than owned by the agent. The result: idle conversations either never auto-close (inflating open-room counts and human queue load) or close prematurely with no nudge, and customers have explicitly asked for a configurable multi-step idle follow-up. Full engine context: Autonomous AI Agent.
4. Target Users + Persona Context
Personas inherited from the AI Agent v2 engine (Autonomous AI Agent) — the same people who configure an AI Agent today. This adjustment does not introduce a new persona; it changes the configuration surface they already use.
| Persona | Role | Goal | Pain | Workaround |
|---|---|---|---|---|
| Primary — Chatbot Specialist (Qontak internal) | Qontak team member who sets up and tunes AI Agents on behalf of customers | Make the AI Agent close idle conversations gracefully — nudge the customer, and if still silent, auto-resolve with a closing message — without leaving stale open rooms | The idle action only allows one action per timer; to get nudge→resolve they must turn on the global channel idle rule and understand the implicit chaining, which differs per channel and is easy to get wrong | Configure a follow_up idle action on the agent and separately configure a resolve on the channel's global idle rule, then mentally chain the two timers; or just pick resolve and accept no nudge |
| Secondary — Customer Bot Builder | A Qontak customer's admin who self-serves AI Agent configuration | Set up "remind the customer, then close politely" entirely within the AI Agent settings they own | They don't control or understand channel-level idle settings, so multi-step idle behavior is effectively unavailable to them | Accept single-action behavior (nudge-only or resolve-only), or raise a request to their Chatbot Specialist |
5. Non-Goals
- More than 3 steps. The sequence is hard-capped at 3 steps. Unbounded or N-step idle chains are explicitly out of scope for this adjustment.
- Changing the legacy global channel/bot-response idle rule.
channel_integration.default_auto_send_next_intent_*and the global path inprocess_idle_rule_action.rbremain as-is for non-AI-Agent flows. This adjustment only stops the AI Agent idle path from depending on it. - New idle action types. Steps reuse the existing action vocabulary (
follow_up,assign,resolve). No new action kind (e.g. "send template", "tag", "webhook") is introduced here. - Per-step branching / conditional logic. Steps run in fixed order on a timer; there is no "if customer did X, jump to step 3" branching. The only dynamic behavior is reset-on-reply and advance-on-idle.
- Re-architecting idle detection. This is not a rewrite of how idle is detected or how
ProcessIdleRuleMessageWorkeris scheduled — it extends the existing mechanism, it does not replace it. - Changing other AI Agent advanced settings.
category,temperature,reasoning,message_limit,wait_time_secondsare untouched.
6. Scope Changes
Engineering surfaces this PRD touches (controlled vocab). Kept in sync with the scope_changes frontmatter above.
- Backend —
chatbot: extendai_agents.parameters['idle_rule'](JSONB, no migration — it is a schema-less blob) to carry an orderedstepsarray (max 3); extend theidle_rulecontract inapp/api/frontend_service/v2/ai_agent/ai_agents_controller.rband theIdleRuleentity in.../models/profile.rbto accept/exposesteps; reworkprocess_idle_rule_action.rbto execute the current step and re-arm the next step's timer (instead of falling through to the global channel idle rule), andsend_message_with_resolve.rb#ai_agent_idle_rule?to carry a step pointer; add per-room step-state (advance on idle, reset on customer reply); new feature flagai_agent_sequential_idle. - Frontend —
chatbot-fe: turn the single-action picker inmodules/ai-agent/components/forms/AiAgentIdleActionForm.vueinto an add/remove step-list builder (1–3 steps); extendmodules/ai-agent/utils/idleActionUtils.tstransformToIdleRule/transformFromIdleRuleto (de)serialize thestepsarray; extend theIdleRuleinterface instore/ai-agent/interface.ts. - Design — Figma for the step-list builder UI: add-step, per-step action + duration + message, remove-step, and the 3-step cap state — TBD, designer not yet assigned.
7. Constraints
| Field | Value |
|---|---|
| Platform | Web only (AI Agent configuration is web-app only, same as parent engine). The runtime idle behavior applies to all messaging channels the AI Agent serves. |
| Plan / tier | Inherits the AI Agent (v2) entitlement — available on the same plan tier(s) that already unlock the AI Agent feature; not a separate add-on. No new tier introduced. (Exact plan SKU to confirm with Commercial — tracked in S17 #3.) |
| Performance | No added latency on the live message path — step advancement is driven by the existing async ProcessIdleRuleMessageWorker, not inline with inbound messages. Each step fires within ±1 minute of its configured idle duration (same tolerance as today's single idle action). |
| Backward compat | Required. Existing agents store a single-action idle_rule ({action, follow_up, resolve, assign}). The runtime and the API must treat a legacy single-action idle_rule as an implicit 1-step sequence and keep firing it unchanged. No backfill/migration of stored data is required — the JSONB blob is read leniently. |
| Step cap | Maximum 3 steps. Enforced in the API contract (reject >3), the FE builder (disable "add step" at 3), and defensively at runtime (ignore steps beyond index 2). |
| Step ordering | The final step should be terminal (resolve or assign); a follow_up as the last step ends the sequence with no further action (allowed, but the room stays open). Non-terminal-last is permitted but flagged in the UI. |
| Feature flag | ai_agent_sequential_idle | default: OFF. When OFF, only single-action idle_rule is accepted/rendered (current behavior). When ON, the steps array is accepted, rendered, and executed. |
| Rollout note | Pure additive read of an existing JSONB field — no schema migration, no low-traffic window required. Flag-gated rollout per org/agent. |
8. Feature Changes
This adjustment has three discrete changes: the config data shape (CHG-001), the configuration UI (CHG-002), and the runtime execution + step-state (CHG-003).
Change ID: CHG-001 — Idle rule data shape: single action → ordered steps
| Field | Detail |
|---|---|
| Change Type | Modified behavior (data model — JSONB, no schema migration) |
| Page | Backend — ai_agents.parameters['idle_rule'] |
| Page Intent | Persist how the AI Agent behaves when a conversation goes idle |
| Before | idle_rule is a single object: { action: "none"|"follow_up"|"assign"|"resolve", follow_up: {duration, message}, assign: {duration, type, division, agent, message}, resolve: {duration, message} }. Exactly one action fires, after one timer. |
| After | idle_rule additionally accepts { steps: [ {order, action, duration, message, assign?:{type,division,agent}}, … ] } with 1–3 entries, executed in order. A legacy single-action idle_rule (no steps) is read as an implicit 1-step sequence. duration stays in seconds per step. |
| Element | Before | After |
|---|---|---|
| Action count | 1 action total | 1–3 ordered steps |
| Timer | 1 idle duration | 1 idle duration per step (measured from the previous step firing, or from last customer activity for step 1) |
| Nudge-then-resolve | Only via global channel idle rule chaining | Native: e.g. step 1 follow_up, step 2 resolve |
| Storage | parameters['idle_rule'] single object | Same key, steps array added; no migration |
Figma: N/A — data/contract change, no UI.
Change ID: CHG-002 — Idle action form: single picker → step-list builder
| Field | Detail |
|---|---|
| Change Type | Modified component |
| Page | chatbot-fe — modules/ai-agent/components/forms/AiAgentIdleActionForm.vue (AI Agent → Advanced Settings → Idle action) |
| Page Intent | Configure what the AI Agent does when a conversation goes idle |
| Before | A single segmented picker (none / resolve / assign / follow_up) with one duration field and the action's message/assignment fields. |
| After | A step list (1–3 rows). Each row picks an action (follow_up / assign / resolve), its idle duration (hrs/min), and its message (+ assignment target for assign). "Add step" is disabled at 3 steps. Steps can be removed (min 1). If the last step is a non-terminal follow_up, the UI shows an inline hint ("conversation stays open after the last nudge"). With the flag OFF, the form renders the legacy single picker. |
| Element | Before | After |
|---|---|---|
| Action selector | One segmented control | One per step row, up to 3 rows |
| Add/remove | N/A | "Add step" (≤3), "Remove" per row (≥1) |
| Last-step hint | N/A | Inline warning when final step is follow_up |
Figma: TBD — designer not yet assigned.
Change ID: CHG-003 — Runtime: single fire → step advance/reset, no global-rule fallback
| Field | Detail |
|---|---|
| Change Type | Modified behavior |
| Page | Backend — app/core/use_cases/system/hub/process_idle_rule_action.rb + send_message_with_resolve.rb#ai_agent_idle_rule? |
| Page Intent | Execute the AI Agent idle action when a room goes idle |
| Before | On idle, the configured single action fires once. If the action is follow_up and the channel's global idle rule is configured, the runtime additionally executes the global channel idle rule (process_idle_rule_action.rb:77-83). No per-room idle step state. |
| After | On idle, the runtime fires the current step, then — if more steps remain — re-arms the next step's timer (ProcessIdleRuleMessageWorker scheduled with step_index+1 and that step's duration). A customer reply resets the sequence to step 1. The AI-Agent path no longer falls through to the global channel idle rule; the sequence is self-contained. Per-room step pointer tracks position (advance on idle, reset on reply). Legacy single-action idle_rule behaves exactly as before (a 1-step sequence with no re-arm). |
| Element | Before | After |
|---|---|---|
| After firing an action | Stop (or chain to global rule if follow_up) | Re-arm next step's timer, or stop if last step |
| Customer reply mid-sequence | N/A (single fire) | Reset pointer to step 1; sequence re-arms from the next idle window |
| Global channel idle rule | Used as the implicit "step 2" for follow_up | Not invoked by the AI-Agent idle path |
Figma: N/A — backend behavior.
New Features
N/A — this adjustment modifies existing behavior and configuration only; no new standalone screen or page is introduced (the step list lives inside the existing Idle action form).
9. API & Webhook Behavior
Plain-language behavior; exact endpoint shapes resolved during RFC.
| # | Behavior | Entity Affected | Triggered By | Expected Behavior | Failure Behavior |
|---|---|---|---|---|---|
| 1 | Save sequential idle config | ai_agents.parameters['idle_rule'].steps | Chatbot Specialist / Bot Builder saves AI Agent (create/update AI Agent) with flag ON | Persist the steps array (1–3 entries) to the agent's idle_rule. Each step validated: action ∈ {follow_up, assign, resolve}, duration a positive integer (seconds, ≤ 24h), message present for follow_up/resolve, assignment target present for assign. | Reject the whole save with a field-level error if >3 steps, an unknown action, a non-positive/over-cap duration, or a missing required message/target. No partial write. |
| 2 | Read idle config for the form | idle_rule (entity exposed to FE) | FE loads the AI Agent advanced settings | Return steps if present; otherwise return the legacy single-action object and let the FE render it as a 1-step sequence. | On read error, FE shows the form error state and the existing config is left unchanged. |
| 3 | Fire current idle step | Room / conversation + idle_rule.steps[i] | ProcessIdleRuleMessageWorker fires after step i's idle duration elapses with no customer activity | Execute step i's action: follow_up → send the message; assign → enqueue assignment (round-robin or specific, per existing logic); resolve → resolve the room with the closing message. If i is not the last step, schedule the worker again for step i+1 with step i+1's duration. Do not invoke the global channel idle rule. | If sending/assigning/resolving fails, log the failure with the step index and do not advance the pointer; rely on existing worker retry. A terminal failure leaves the room in its current state (not silently advanced). |
| 4 | Reset sequence on customer activity | Per-room idle step pointer | Inbound customer message while a sequence is mid-flight | Reset the step pointer to step 1 and cancel/ignore any in-flight step timer so the next idle window starts the sequence from step 1. | If the reset can't be recorded, the worst case is the next idle window re-fires from the persisted pointer; never sends a step out of order or double-resolves a room. |
| 5 | Stop at terminal step | Room / conversation | Last step executes (or a resolve step on any index) | After a resolve the room is closed and no further steps fire even if configured (resolve is terminal). After the final configured step (if follow_up), the sequence ends and the room stays open until the next inbound message resets it. | A resolve that fails does not advance past it; the next idle window retries the resolve step. |
[Claude to resolve during RFC: where the per-room step pointer is stored (room/session column vs. cache vs. carried on the scheduled job), exact worker scheduling signature, idempotency key to prevent a step firing twice on retry, and the validation error payload shape.]
10. System Flow + User Stories + ACs
Stories focus on the changed behavior: configuring a sequence, executing it step-by-step, resetting it on reply, and preserving legacy single-action behavior. Unchanged idle detection and the channel global rule are not re-documented.
10.1. System Flow
Flow: Sequential idle follow-up — configure → idle fire → advance → reset/terminate · Type: User Journey + State Lifecycle
- Chatbot Specialist opens AI Agent → Advanced Settings → Idle action (flag
ai_agent_sequential_idleON). - They add up to 3 steps; e.g. Step 1 =
follow_up(10 min, "Are you still there?"), Step 2 =follow_up(10 min, "Last reminder before we close"), Step 3 =resolve(10 min, "Closing for now — reach out anytime"). Save. - Backend validates (≤3 steps, valid action/duration/message) and persists
idle_rule.steps. - A customer conversation handled by this agent goes quiet. After Step 1's duration with no customer activity,
ProcessIdleRuleMessageWorkerfires Step 1 → sends the nudge → schedules itself for Step 2's duration. - Still quiet → Step 2 fires → schedules Step 3.
- Still quiet → Step 3 (
resolve) fires → room is resolved with the closing message → sequence ends. - Reset branch: if at any point the customer replies, the step pointer resets to Step 1; the next idle window starts the sequence over from Step 1.
- Terminal branch: a
resolvestep closes the room; no later step fires. A finalfollow_upstep ends the sequence with the room left open. - Failure branch: if a step's send/assign/resolve fails, the pointer does not advance; the worker retries per existing retry policy.
- Legacy branch: an agent with a single-action
idle_rule(nosteps) fires that one action exactly as today (treated as a 1-step sequence, no re-arm, no global-rule fallback change for non-AI-Agent flows).
📊 System Flow — Sequential Idle Follow-up
stateDiagram-v2
[*] --> Active: Conversation active
Active --> Step1: Idle ≥ step1.duration
Step1 --> Step2: action fired, more steps, idle ≥ step2.duration
Step2 --> Step3: action fired, more steps, idle ≥ step3.duration
Step1 --> Active: Customer replies (reset)
Step2 --> Active: Customer replies (reset)
Step3 --> Active: Customer replies (reset)
Step3 --> Resolved: step is resolve (terminal)
Step2 --> Resolved: step is resolve (terminal)
Step1 --> Resolved: step is resolve (terminal)
Step3 --> Ended: last step is follow_up (room stays open)
Step1 --> FireFailed: send/assign/resolve error
Step2 --> FireFailed: send/assign/resolve error
Step3 --> FireFailed: send/assign/resolve error
FireFailed --> Active: pointer not advanced; worker retries
Resolved --> [*]
Ended --> Active: next inbound resets to Step1
10.2. User Stories
Must Have stories define committed scope. At least 1 Must Have required for READY. Before State + After Delta are mandatory per story.
[IDLE-ADJ-S01] — Configure a multi-step idle sequence
| User Story | As a Chatbot Specialist, I want to configure up to 3 ordered idle steps (each with its own action, timer, and message) on the AI Agent, so that the agent can nudge an idle customer and then auto-resolve without me touching channel settings. |
| Before State | The Idle action form (AiAgentIdleActionForm.vue) offers a single segmented picker (none/resolve/assign/follow_up) with one timer and one message. Only one action can be configured. |
| After Delta | With ai_agent_sequential_idle ON, the form becomes a step list of 1–3 rows; each row has its own action, duration, and message (+ assignment target for assign). "Add step" disables at 3. Saving persists idle_rule.steps. |
| Importance | Must Have |
| Mockup / Technical Notes | Figma: TBD — designer not yet assigned Data Fields: • steps[] (array, required when flag ON, 1–3 items) — User input• steps[].action (string follow_up|assign|resolve, required) — User input• steps[].duration (int seconds, required, >0, ≤86400) — User input (hrs/min in UI)• steps[].message (string, required for follow_up/resolve) — User input• steps[].assign (object, required when action=assign) — User inputTechnical Notes: Extends idleActionUtils.ts transformToIdleRule/transformFromIdleRule and the IdleRule store interface; serializes duration hrs/min → seconds. Per S7 §Step cap (max 3) and §Feature flag (ai_agent_sequential_idle | default: OFF). |
| Acceptance Criteria | — Happy Path — • AC-1: Given the flag is ON and an agent with no idle config, when the Specialist adds 3 steps (follow_up 10m, follow_up 10m, resolve 10m) and saves, then idle_rule.steps persists 3 ordered entries with durations in seconds and the form reloads showing the same 3 steps.• AC-2: Given a step row with action assign, when the Specialist selects an assignment target and saves, then the step persists with its assign target alongside its duration and (optional) message.• AC-3: Given a single configured step, when the Specialist saves, then it persists as a 1-step sequence and behaves identically to the legacy single action. — Error / Unhappy Path — • ERR-1: Given 3 steps already exist, when the Specialist tries to add a 4th, then the "Add step" control is disabled and no 4th row is created. • ERR-2: Given a follow_up/resolve step with an empty message, when the Specialist saves, then the save is rejected with a field-level "message required" error and nothing is persisted.• ERR-3: Given a step with duration 0 or > 24h, when the Specialist saves, then the save is rejected with a duration-range error. — Permission Model — • CAN: Roles that can edit AI Agent config (Chatbot Specialist; customer Bot Builder) with ai_agent_sequential_idle = ON.• CANNOT: Roles without AI Agent edit rights; any role when the flag is OFF (they see the legacy single picker). • Unauthorized: Step builder not rendered; legacy picker shown or form read-only per existing permission behavior. — UI States — • Loading: Form shows skeleton while the agent config loads. • Empty: No steps yet → one empty step row with defaults. • Error: Save failure → inline field errors; unsaved steps retained. • Success: Saved → toast + reloaded step list. — Negative Scenarios — (from Non-Goals) • NEG-1: Given the flag is ON, when the Specialist attempts to configure a 4th step via the API directly, then the API rejects the payload (>3 steps) and persists nothing. • NEG-2: Given a step, when the Specialist looks for a "send template/webhook/tag" action, then only follow_up/assign/resolve are available (no new action types). |
Dependencies: None
[IDLE-ADJ-S02] — Execute the sequence step-by-step at runtime
| User Story | As a Chatbot Specialist, I want each configured step to fire in order on its own idle timer and the next step to be armed only if the customer stays silent, so that an idle customer is nudged and then resolved exactly as I configured, without the global channel idle rule. |
| Before State | On idle, the single configured action fires once; if it is follow_up and the channel global idle rule is set, the runtime also runs the global channel idle rule (process_idle_rule_action.rb:77-83). No per-room idle step state. |
| After Delta | The runtime fires the current step, then re-arms ProcessIdleRuleMessageWorker for the next step's duration if one remains; the AI-Agent idle path no longer invokes the global channel idle rule. A per-room step pointer tracks position. |
| Importance | Must Have |
| Mockup / Technical Notes | Figma: N/A — backend behavior. Data Fields: • idle_rule.steps[] (array) — API response / stored config• step_index (int, 0-based) — per-room state, carried to the worker• room_id, ai_agent_id (refs) — from the idle contextTechnical Notes: send_message_with_resolve.rb#ai_agent_idle_rule? carries step_index; process_idle_rule_action.rb executes steps[step_index] then schedules step_index+1. Per S7 §Step ordering (final step terminal). RFC resolves pointer storage + idempotency key. |
| Acceptance Criteria | — Happy Path — • AC-1: Given an agent configured with [follow_up 10m, follow_up 10m, resolve 10m] and a room idle since the customer's last message, when 10 min elapse with no customer activity, then Step 1's message is sent and the worker is scheduled for Step 2 in 10 min. • AC-2: Given Step 1 has fired and the room stays idle, when Step 2's 10 min elapse, then Step 2's message is sent and the worker is scheduled for Step 3. • AC-3: Given Steps 1–2 have fired and the room stays idle, when Step 3's 10 min elapse, then the room is resolved with Step 3's closing message and no further worker is scheduled. • AC-4: Given a step with action assign, when that step fires, then assignment is enqueued via the existing assign path (round-robin or specific) and, if it is not the last step, the next step is still armed.— Error / Unhappy Path — • ERR-1: Given Step 2 is due, when sending Step 2's message fails, then the step pointer is not advanced, the failure is logged with step_index, and the worker retries per existing policy (Step 3 is not armed until Step 2 succeeds).• ERR-2: Given a resolve step is due, when the resolve operation fails, then the room is not advanced past it and the resolve is retried on the next worker run (no silent skip to "ended").— Permission Model — • CAN: System/worker executes on behalf of the AI Agent. • CANNOT: N/A — no end-user action; execution is system-driven. • Unauthorized: N/A. — UI States — • Loading / Empty / Error / Success: N/A — backend execution; observable via events in §12, not UI. — Negative Scenarios — (from Non-Goals) • NEG-1: Given an AI-Agent idle sequence fires follow_up as Step 1, when Step 1 completes, then the global channel idle rule is NOT invoked (the :77-83 fallback no longer applies to the AI-Agent path).• NEG-2: Given a stored config somehow contains 4+ steps, when the runtime reads it, then it executes at most the first 3 and ignores the rest. |
Dependencies: [IDLE-ADJ-S01] (config must persist steps)
[IDLE-ADJ-S03] — Reset the sequence when the customer replies
| User Story | As a customer in an idle conversation, when I reply mid-sequence, I want the idle sequence to start over, so that I'm not nudged for "still there?" or auto-resolved right after I've just responded. |
| Before State | Single-fire idle action; there is no notion of a sequence to reset. |
| After Delta | An inbound customer message resets the per-room step pointer to Step 1 and cancels/ignores any in-flight step timer; the next idle window restarts from Step 1. |
| Importance | Must Have |
| Mockup / Technical Notes | Figma: N/A — backend behavior. Data Fields: • step_index (int) — reset to 0 on inbound customer message• room_id (ref) — from the inbound message contextTechnical Notes: Hook the reset on the existing inbound-customer-message path that already restarts idle detection. Idempotent: replaying the reset is safe. |
| Acceptance Criteria | — Happy Path — • AC-1: Given a room is at Step 2 of a 3-step sequence, when the customer sends a message, then the step pointer resets to Step 1 and any pending Step 3 timer is cancelled/ignored. • AC-2: Given the pointer has reset to Step 1, when the room goes idle again for Step 1's duration, then Step 1 fires (not Step 2 or 3). • AC-3: Given a room where the customer replies before Step 1 ever fires, when they go idle again, then the timer measures from the new last message and Step 1 fires after its full duration. — Error / Unhappy Path — • ERR-1: Given a customer reply arrives at the same time Step 2 is firing (race), when both are processed, then the room is never both nudged-and-reset inconsistently — at most one of {advance, reset} wins and the resulting pointer is internally consistent (RFC: idempotency/locking). • ERR-2: Given the reset write fails, when the next idle window arrives, then the system fires from the last persisted pointer and never sends a step out of order or double-resolves. — Permission Model — • CAN: Any inbound customer message triggers the reset (system behavior). • CANNOT: N/A. • Unauthorized: N/A. — UI States — • N/A — backend behavior. — Negative Scenarios — (from Non-Goals) • NEG-1: Given the customer replies, when the sequence resets, then it restarts from Step 1 (no conditional "jump to step N" branching — Non-Goal 4). |
Dependencies: [IDLE-ADJ-S02]
[IDLE-ADJ-S04] — Preserve legacy single-action idle behavior (regression)
| User Story | As a Chatbot Specialist with an existing single-action idle config, I want my agent to keep behaving exactly as before, so that enabling this feature for others never changes or breaks agents that were configured the old way. |
| Before State | Agents store idle_rule as {action, follow_up/assign/resolve} (no steps) and fire that one action on idle. |
| After Delta | The runtime and API read a legacy idle_rule (no steps) as an implicit 1-step sequence and fire it identically — no re-arm, and no change to the existing global-channel-idle-rule behavior for non-AI-Agent flows. |
| Importance | Must Have |
| Mockup / Technical Notes | Figma: N/A. Data Fields: • idle_rule.action + sub-object (legacy shape) — stored configTechnical Notes: Lenient read of the JSONB blob — steps absent ⇒ synthesize one step from action. No backfill/migration. Per S7 §Backward compat. |
| Acceptance Criteria | — Happy Path — • AC-1: Given an agent with legacy idle_rule {action: "resolve", resolve:{duration, message}} and the flag OFF, when the room goes idle for the duration, then the room resolves with the message exactly as today.• AC-2: Given a legacy idle_rule {action: "follow_up"} on a channel whose global idle rule is configured (non-AI-Agent flow), when idle fires, then the existing global-rule behavior for that channel flow is unchanged.• AC-3: Given the flag is OFF, when the Specialist opens the form, then they see the legacy single picker (no step builder) and can edit as before. — Error / Unhappy Path — • ERR-1: Given a malformed/empty legacy idle_rule, when idle is evaluated, then the system takes no idle action and logs nothing user-facing (same as today's action: none).— Permission Model — • CAN: Existing roles, unchanged. • CANNOT: Unchanged. • Unauthorized: Unchanged. — UI States — • Legacy single-picker states unchanged. — Negative Scenarios — (from Non-Goals) • NEG-1: Given the flag is OFF, when any agent is saved, then no steps array is written or required (Non-Goal: no forced migration). |
Dependencies: None
11. Rollout
| Field | Detail |
|---|---|
| Rollout type | Controlled rollout with flag (ai_agent_sequential_idle) |
| Feature flag | ai_agent_sequential_idle | default: OFF |
| Rollout | Stage 1 → Internal QA on staging (Qontak-owned test agents) — 1 week Stage 2 → Closed beta: 2–3 design-partner orgs who requested multi-step idle — 2 weeks Stage 3 → GA: flag default flips ON per plan tier |
| Backward compat | Yes — existing single-action idle_rule configs are read as 1-step sequences and fire unchanged; no stored data is migrated. |
| Migration | None — idle_rule is a schema-less JSONB blob; steps is an additive read. |
12. Observability
New or Modified Events:
| Event Name | Trigger | Properties | Change from parent |
|---|---|---|---|
ai_agent_idle_sequence_saved | Specialist saves an idle config with ≥1 step (flag ON) | ai_agent_id, org_id, step_count (1–3), actions (ordered list), has_terminal_step (bool) | New — drives the ⭐ config-adoption KPI |
ai_agent_idle_step_fired | A step executes at runtime | ai_agent_id, room_id, step_index, action, is_last_step (bool) | New — per-step execution telemetry |
ai_agent_idle_sequence_reset | Customer reply resets a mid-flight sequence | ai_agent_id, room_id, from_step_index | New — measures re-engagement |
ai_agent_idle_sequence_resolved | A resolve step closes the room | ai_agent_id, room_id, resolved_at_step_index | New — drives auto-resolution/containment tracking |
ai_agent_idle_step_failed | A step's send/assign/resolve fails | ai_agent_id, room_id, step_index, action, reason | New — alerting |
Dashboard owner: BOT — Chatbot Squad. Surfaced alongside existing AI Agent telemetry (the BI ai_activity_logs Metabase datamart that already consumes per-response AI Agent telemetry).
Post-launch monitoring cadence: Weekly review for the first 4 weeks post-GA. Investigate immediately if ai_agent_idle_step_failed exceeds 2% of ai_agent_idle_step_fired in any rolling 24h window, or if ai_agent_idle_sequence_resolved drops > 20% week-over-week after a steady state is reached.
13. Success Metrics
| Metric | Definition | Baseline | Target |
|---|---|---|---|
| ⭐ Sequential idle config adoption | % of active AI Agents configured with a multi-step (≥2 step) idle sequence, of all agents with any idle action | 0% (capability does not exist) | ≥ 30% of idle-configured agents within 30 days of GA |
| Auto-resolution via sequence | Count / % of idle conversations closed by a resolve step at the end of a sequence (no human) | N/A — not separable today | Established as a baseline in beta; trend up post-GA |
| Re-engagement after nudge | % of sequences that reset because the customer replied after a follow_up step (before resolve) | N/A — not measurable today | Established in beta; reported monthly |
| Idle step failure rate | ai_agent_idle_step_failed ÷ ai_agent_idle_step_fired | N/A | < 2% sustained |
14. Launch Plan & Stage Gates
| Stage | Audience | Duration | Success Gate | Owner |
|---|---|---|---|---|
| Internal QA (staging) | Qontak-owned test AI Agents | 1 week | All S01–S04 ACs pass; a 3-step sequence fires in order, resets on reply, resolves at terminal; legacy single-action regression green; ai_agent_idle_step_failed = 0 across the test matrix | BOT Squad QA |
| Closed beta | 2–3 design-partner orgs who requested multi-step idle | 2 weeks | ≥1 partner runs a live nudge→resolve sequence; step-failure rate < 2%; no P1/P2 idle bugs; positive partner confirmation | DRI |
| GA | All eligible orgs (per plan tier), flag default ON | Ongoing | ⭐ ≥ 30% sequential-config adoption within 30 days; step-failure rate < 2% sustained | DRI |
15. Dependencies
| Dependency | Owning Team | Deliverable Needed | Blocking? |
|---|---|---|---|
| Step-list builder Figma — TBD, designer not yet assigned | Design (qontak-designer) | Assign a designer, then frame-level design for add/remove step, per-step action+duration+message, 3-step cap, last-step-follow_up hint | YES — CHG-002 (FE) cannot be built to spec without it |
| Per-room step-pointer storage decision | BOT Squad (Eng, via RFC) | RFC decision on where the step pointer lives (room/session column vs. cache vs. carried on the scheduled job) + idempotency key | YES — CHG-003 runtime depends on it |
ai_agent_sequential_idle feature flag | BOT Squad | Flag provisioned in the flag system with per-org/agent targeting | YES — gates the whole rollout |
No dependency on the global channel idle rule — this adjustment removes that coupling rather than adding to it.
16. Key Decisions + Alternatives Rejected
8a — Decisions Made
| Date | Decision | Rationale |
|---|---|---|
| 2026-06-25 | Cap the sequence at 3 steps | Covers the requested "nudge → nudge → resolve" pattern; keeps UI and step-state logic simple; avoids unbounded scheduling chains |
| 2026-06-25 | Store steps inside the existing parameters['idle_rule'] JSONB, not a new table | No migration; the blob is already schema-less; legacy single-action configs read leniently as a 1-step sequence |
| 2026-06-25 | Free per-step action (each step picks follow_up/assign/resolve + its own duration/message), last step typically terminal | Most flexible; matches the existing per-action data model; chosen over a fixed nudges→terminal pattern |
| 2026-06-25 | Make the AI-Agent idle path self-contained — stop invoking the global channel idle rule from it | Removes the confusing cross-setting coupling that is the core problem; the global rule stays intact for non-AI-Agent flows |
| 2026-06-25 | Reset on customer reply, advance on idle | Matches user expectation (don't nudge/resolve someone who just replied) and reuses the existing inbound-message idle-restart hook |
8b — Alternatives Rejected
| Alternative | Why Rejected | Date |
|---|---|---|
| Keep relying on the global channel idle rule for "nudge then resolve" | This is the problem — per-channel, non-obvious, not owned by the agent, unavailable to customer Bot Builders | 2026-06-25 |
Fixed pattern: steps 1..N-1 always follow_up, only last terminal | Less flexible; the per-action data model already supports free actions, and Specialists may legitimately want an assign mid-sequence | 2026-06-25 |
| Unbounded / N-step sequences | Scope creep and unbounded scheduling chains for marginal benefit; 3 steps covers the requested use cases | 2026-06-25 |
New ai_agent_idle_steps normalized table | Adds a migration and query complexity for data that is small, agent-scoped, and already lives in the agent's JSONB config | 2026-06-25 |
17. Open Questions
| # | Type | Question | Owner | Deadline |
|---|---|---|---|---|
| 1 | Open Question | Where does the per-room step pointer live — a column on the room/session record, a cache entry, or carried on the scheduled ProcessIdleRuleMessageWorker job? Resolved in the RFC. | BOT Eng | 2026-07-15 |
| 2 | Open Question | What is the idempotency key that prevents a step firing twice on worker retry, and how does it interact with the reset-on-reply race (ERR-1 in S03)? | BOT Eng | 2026-07-15 |
| 3 | Open Question | Which plan tier(s) unlock the AI Agent entitlement this inherits, and do any get ai_agent_sequential_idle ON by default at GA? Confirm with Commercial. | DRI | 2026-08-31 |
| 4 | Assumption | The existing inbound-customer-message path that restarts idle detection can host the sequence reset without a new listener. | BOT Eng | 2026-07-15 |
| 5 | Assumption | A final follow_up step that leaves the room open is acceptable product behavior (vs. forcing the last step to be terminal). | DRI | 2026-08-15 |
| 6 | Risk | Reset-on-reply vs. advance-on-idle race could double-act on a room (nudge after a reply, or advance + reset). Mitigation: RFC defines an idempotency key + locking so at most one of {advance, reset} wins and the pointer stays consistent (S03 ERR-1/ERR-2); covered by a concurrency test in the QA matrix before beta. | BOT Eng | 2026-08-15 |
| 7 | Risk | Removing the global-channel-idle-rule fallback from the AI-Agent path could change behavior for agents that today rely on that implicit chaining. Mitigation: the change is flag-gated (ai_agent_sequential_idle); with the flag OFF the legacy path is untouched, and beta validates affected agents before GA (S04). | DRI | 2026-08-31 |
PRD CHANGELOG
| Version | Date | By | Section | Type | Summary |
|---|---|---|---|---|---|
| 1.0 | 2026-06-25 | Claude | All | CREATED | Adjustment PRD created for sequential idle follow-up — making the AI Agent idle action a self-contained, user-configurable sequence of up to 3 steps, independent of the global channel idle rule. |
| 1.1 | 2026-06-25 | Claude | One-liner, Constraints, Open Questions | MODIFIED | Coaching-pass fixes: tightened one-liner to ≤25 words, named plan/tier (inherits AI Agent entitlement), converted Open Questions deadlines from conditions to dates. |