ChanlChanl
Agent Architecture

How to rescue a stuck CX agent conversation

Conversations get stuck in four predictable patterns: clarification spirals, topic drift, assumption deadlocks, and initiative mismatches. Here's how to detect each one mid-flight and apply the repair move that actually works.

DGDean GroverCo-founderFollow
June 30, 2026
12 min read
Warm illustration of two figures in conversation, one gesturing toward a branching path ahead

Your customer called to cancel their subscription. Twenty messages later, your agent was working through a shipping address update. Nobody was rude. Nobody was confused. The conversation had just wandered off course, two topics ago, and neither side noticed until the customer gave up and asked for a human.

The agent wasn't broken. It was following the customer's lead, as designed. The customer mentioned they were moving, the agent latched onto the address to be helpful, and somewhere in between, the cancellation got buried. By the time both parties realized they were somewhere neither intended to be, it was easier to escalate than to find their way back.

That's a stuck conversation. And it has a fix.

What conversation repair is

Conversation repair is the set of moves an agent uses to recover a conversation that has gone off course without escalating to a human or starting over. It's distinct from escalation (handing off when the task requires human judgment) and from error handling (recovering when a tool call fails). It's what happens when the mutual understanding between agent and customer has degraded, not through any single wrong turn but through accumulated small deviations that compound into a real problem.

Human conversation partners do this constantly. "I think we got off track there." "Let me make sure I understand what you actually need." "I realize I answered a different question than you asked." These are repair moves. They acknowledge a breakdown, reset shared understanding, and resume toward the goal.

Agents can do this too. But they need to recognize that a repair is needed before they can attempt it. Most agents don't have that recognition layer. They have escalation logic (triggered by frustration signals or specific keywords) and they have normal conversation flow. The space between "slightly off track" and "needs a human" is where most stuck conversations live, and it's mostly unhandled.

The escalation decision is downstream of repair. You escalate when repair has failed. You repair when the conversation can still succeed but has temporarily lost its way.

The four failure modes that need repair

Four patterns break most stuck CX conversations. A clarification spiral happens when the agent keeps requesting the same information the customer has already given in a different form. Topic drift happens when a tangential customer mention redirects the conversation away from the original goal. An assumption deadlock happens when the agent acts on a wrong assumption that the customer keeps trying to correct without success. An initiative mismatch happens when both sides are waiting for the other to move.

Each mode has a specific cause and a specific repair. Applying the wrong repair to the wrong mode makes things worse.

Clarification spiral. The agent needs an order number. The customer says "the one from last Tuesday." The agent asks for the 8-digit order number. The customer says "I got an email about it." The agent asks for the 8-digit order number again. Nobody is being unhelpful. The agent's entity extractor needs a specific format that the customer's natural language doesn't match. Without a repair move, this continues until the customer gives up or repeats themselves loudly enough to trigger an escalation signal.

Topic drift. The customer calls to cancel their subscription and mentions in passing that they're moving. The agent, being helpful, asks about the new address to update the account. The customer answers. The agent asks a follow-up question about the move. Four turns later, the cancellation has never been addressed, the agent is cheerfully updating shipping details, and the customer thinks the agent forgot their actual request. Topic drift is subtle because every individual agent turn looks correct.

Assumption deadlock. The agent makes an inference early in the conversation and acts on it. The customer ordered a blue jacket but received the wrong size. The agent assumes "wrong size" means a return and launches a return flow. The customer actually wants to exchange it. "I want to exchange it." "Of course, your return has been initiated." "No, I want to exchange." "Your refund will be processed to your original payment method." The assumption is locked into the agent's working context and doesn't update when the customer corrects it.

Initiative mismatch. The agent asks an open-ended question. "What can I help you with today?" The customer says "billing." The agent asks another open question: "What's the issue with your billing?" The customer says "I just need to check something." Now both sides are waiting. The agent is waiting for specifics. The customer is waiting for the agent to take a lead. In voice, this is silence. In chat, it's a one-word response to a question that needed three sentences to answer.

Detecting which mode you're in

Each failure mode has a signature in the transcript. Clarification spirals show the same entity request appearing two or more times. Topic drift shows agent actions that don't match the original intent. Assumption deadlocks show customer correction phrases appearing without corresponding agent state changes. Initiative mismatches show very brief customer responses after open-ended agent questions.

ModeTranscript signalDetection rule
Clarification spiralSame entity slot requested 2+ timesCount entity extraction requests per slot; flag at 2
Topic driftAgent action type diverges from original intentCompare current action to captured original intent; flag after 4+ turns of divergence
Assumption deadlockCustomer correction phrases without state updateMatch correction language ("no", "I mean", "actually") against agent state changes
Initiative mismatchCustomer response under 5 words after open agent questionMeasure customer turn length after open-ended agent turns
Yes No Yes No No, 4+ turns Yes Yes No Yes No, 2nd attempt failed New customer turn received Check repair signals Same entityrequested 2+ times? Clarification spiralOffer concrete options Customer correctedagent 2+ times? Assumption deadlockName assumption aloud Current actionmatches original intent? Topic driftName both topics, ask which to return to Brief responseafter open question? Initiative mismatchOffer specific direction Healthy, continue Repair resolved? Escalate with context package
Conversation repair decision flow: detect the failure mode, apply the targeted repair, escalate if repair fails
Conversation analyst reviewing data

Sentiment Analysis

Last 7 days

Positive 68%
Neutral 24%
Negative 8%
Top Topics
Billing342
Support281
Onboarding197
Upgrade156

Here's a TypeScript implementation of a conversation state tracker that detects each mode:

conversation-state-tracker.ts·typescript
type RepairMode =
  | 'clarification_spiral'
  | 'topic_drift'
  | 'assumption_deadlock'
  | 'initiative_mismatch'
  | 'healthy';
 
interface ConversationState {
  originalIntent: string;
  currentIntent: string;
  entityRequests: Record<string, number>;  // entity name -> request count
  correctionCount: number;
  lastAgentQuestionType: 'open' | 'closed' | 'statement' | null;
  turnsSinceIntentMatch: number;
}
 
interface Turn {
  role: 'agent' | 'customer';
  content: string;
  detectedIntent?: string;
  requestedEntity?: string;
}
 
const CORRECTION_PHRASES = [
  /\b(no,?\s*(i|that'?s|it'?s))/i,
  /\bi\s*(meant?|mean|actually|said)/i,
  /\bactually\b/i,
  /\bnot\s+(a\s+)?(return|refund)\b/i,
  /\bexchange\b.*\bnot\b/i,
];
 
export function detectRepairMode(
  state: ConversationState,
  recentTurns: Turn[],
): { mode: RepairMode; confidence: number; signal: string } {
  // Clarification spiral: same entity asked 2+ times
  const spiralEntity = Object.entries(state.entityRequests)
    .find(([, count]) => count >= 2);
  if (spiralEntity) {
    return {
      mode: 'clarification_spiral',
      confidence: 0.92,
      signal: `Entity '${spiralEntity[0]}' requested ${spiralEntity[1]} times`,
    };
  }
 
  // Assumption deadlock: customer correction appearing without state reset
  if (state.correctionCount >= 2) {
    return {
      mode: 'assumption_deadlock',
      confidence: 0.88,
      signal: `Customer correction detected ${state.correctionCount} times without intent update`,
    };
  }
 
  // Topic drift: current intent diverged from original for 4+ turns
  if (
    state.currentIntent !== state.originalIntent &&
    state.turnsSinceIntentMatch >= 4
  ) {
    return {
      mode: 'topic_drift',
      confidence: 0.80,
      signal: `Intent drifted from '${state.originalIntent}' to '${state.currentIntent}' for ${state.turnsSinceIntentMatch} turns`,
    };
  }
 
  // Initiative mismatch: brief customer response after open agent question
  const lastCustomer = [...recentTurns].reverse().find(t => t.role === 'customer');
  const lastAgentQuestion = [...recentTurns]
    .reverse()
    .filter(t => t.role === 'agent')
    .find(t => t.content.trim().endsWith('?'));
 
  if (
    lastCustomer &&
    lastAgentQuestion &&
    lastCustomer.content.split(' ').length <= 4 &&
    state.lastAgentQuestionType === 'open'
  ) {
    return {
      mode: 'initiative_mismatch',
      confidence: 0.75,
      signal: `Customer gave ${lastCustomer.content.split(' ').length}-word response after open question`,
    };
  }
 
  return { mode: 'healthy', confidence: 1.0, signal: 'No repair signal detected' };
}
 
export function updateState(
  state: ConversationState,
  turn: Turn,
): ConversationState {
  const updated = { ...state };
 
  if (turn.role === 'agent') {
    if (turn.requestedEntity) {
      updated.entityRequests[turn.requestedEntity] =
        (state.entityRequests[turn.requestedEntity] ?? 0) + 1;
    }
    updated.lastAgentQuestionType = turn.content.trim().endsWith('?') ? 'open' : 'statement';
  }
 
  if (turn.role === 'customer') {
    if (turn.detectedIntent && turn.detectedIntent !== state.currentIntent) {
      updated.currentIntent = turn.detectedIntent;
      updated.turnsSinceIntentMatch = 0;
    } else {
      updated.turnsSinceIntentMatch += 1;
    }
 
    const isCorrection = CORRECTION_PHRASES.some(p => p.test(turn.content));
    if (isCorrection) {
      updated.correctionCount += 1;
    }
  }
 
  return updated;
}

Repair strategies for each mode

The repair strategy for each mode targets its specific cause. Applying the wrong one makes the conversation worse, not better. A topic drift repair applied to a clarification spiral sounds dismissive. An assumption repair applied to initiative mismatch sounds aggressive.

Repairing a clarification spiral. Stop asking the abstract question. Offer concrete options the customer can confirm or deny.

Instead of: "I need your 8-digit order number."

Try: "I found two recent orders on your account: order KL-8827 for the blue jacket from June 22nd, and order KL-9042 for the running shoes from June 25th. Which one are we looking at?"

If you can't offer options (no recent orders match), narrow the search space: "I'm searching by your account email. If you have the order confirmation email, the number starts with 'KL-' and has 5 digits after that. Does anything like that ring a bell?"

The key is that you're giving the customer something to confirm rather than something to produce. Confirmation is much easier than recall under pressure.

Repairing topic drift. Name both topics explicitly and ask which to continue with.

"Before I finish updating your new address, I want to make sure we got to what you actually called about. You mentioned canceling your subscription at the start. Would you like to handle that first, or are you all set on the cancellation and we should just finish the address update?"

Name the original goal, name the current topic, and ask which to return to. Don't assume. The customer may have changed their mind about the cancellation. But give them the explicit choice rather than guessing.

Repairing an assumption deadlock. Say the assumption out loud and invite correction directly.

"I've been treating this as a return and processing a refund, but I'm hearing you say you want to exchange it for a different size. Let me start over with that. You received the blue jacket in medium, and you want the large instead. Is that right?"

Naming the assumption explicitly breaks the loop. The customer now has something concrete to confirm rather than having to contradict an implicit inference they can't see. This repair works because the customer already knows what they want. The problem is the agent hasn't been updating its model. Saying the assumption out loud forces the model to reset.

Repairing initiative mismatch. Take the lead with a specific suggestion.

"Let me suggest something to move us forward: I'll pull up your most recent invoice and walk through the charges one by one. That's usually the fastest way to sort out a billing question. Does that sound right?"

Offering a specific action removes the ambiguity that's causing the stall. You're not asking what the customer wants (you've already tried that). You're proposing something concrete and giving them one decision: approve or redirect.

When repair should lead to escalation

Escalate if you've attempted one repair move and the conversation still isn't progressing. The signal is a second occurrence of the same failure mode after the repair was applied. At that point the problem is either a task the agent genuinely can't complete or a customer who needs a human for reasons that have nothing to do with conversation structure.

When you escalate after a failed repair, pass the context forward cleanly. The human agent who takes over shouldn't start from scratch. Package what you know:

repair-escalation-handoff.ts·typescript
interface RepairHistory {
  mode: RepairMode;
  attemptedAt: number;  // turn number
  repairMove: string;
  outcome: 'resolved' | 'partial' | 'failed';
}
 
interface EscalationContext {
  originalIntent: string;
  failedRepairs: RepairHistory[];
  currentStuckMode: RepairMode;
  customerFrustrationSignals: string[];
  suggestedPickupPoint: string;
}
 
export function buildRepairHandoff(
  state: ConversationState,
  failedRepairs: RepairHistory[],
  turns: Turn[],
): EscalationContext {
  const frustrationSignals = turns
    .filter(t => t.role === 'customer')
    .filter(t =>
      /\b(frustrated|this is ridiculous|you keep|I already told|why (can't|won't|don't) you)\b/i.test(t.content) ||
      (t.content === t.content.toUpperCase() && t.content.length > 8)
    )
    .map(t => t.content.slice(0, 80));
 
  return {
    originalIntent: state.originalIntent,
    failedRepairs,
    currentStuckMode: detectRepairMode(state, turns).mode,
    customerFrustrationSignals: frustrationSignals,
    suggestedPickupPoint:
      `Customer's original request was: ${state.originalIntent}. ` +
      `The conversation got stuck on ${failedRepairs.at(-1)?.mode ?? 'unknown'}. ` +
      `One repair was attempted (${failedRepairs.at(-1)?.repairMove ?? 'none'}) without success.`,
  };
}

The handoff context package is what makes the transition feel seamless to the customer. They shouldn't have to repeat themselves to the human agent. Everything the agent learned, including the failed repair attempt and the point where it got stuck, should arrive before the first human turn.

Testing repair scenarios before launch

Testing conversation repair means writing multi-turn scenarios that trigger each failure mode, then verifying the agent detects the mode and applies the right repair move. Most teams test escalation paths. Very few test repair paths. The gap means a large class of conversation failure goes undetected until customers start dropping off.

In Chanl's scenarios, you write the customer side of the conversation as a script and evaluate the agent's responses against criteria you define:

text
# Clarification spiral test
Turn 1 (customer): "I want to return the jacket"
Turn 2 (agent): [expects entity request for order ID]
Turn 3 (customer): "The one from last week"
Turn 4 (agent): [expects entity request for order ID again]
Turn 5 (customer): "From my email"
Turn 6 (agent): EVALUATE: must offer specific order options, must NOT ask for order ID a third time

You're checking that the agent detects the spiral after two failed entity requests and switches to the options-based repair, rather than asking for the same information a third time.

Run equivalent tests for each mode. Run them again any time you modify entity extraction configuration, update intent models, or change the agent's question design.

Repair logic is also worth testing after model updates. A model upgrade that makes your agent more confident can increase assumption deadlocks because the agent acts on weaker evidence. A model that's better at following instructions can reduce initiative mismatches but accidentally decrease clarification spiral detection if the new prompts are less explicit about when to offer options.

Monitoring repair frequency as a quality signal

Track repair move frequency by conversation type and agent version. Repair rates are a leading indicator of systemic conversation design problems, and they show up before the customer satisfaction metrics do.

High clarification spiral rate. Your entity extraction schema doesn't match how real customers describe things. The fix is in your slot-filling prompts: make the entity description broader, add example phrasings, or add the options-based fallback earlier in the flow.

High topic drift rate. Your agent is too responsive to tangential customer mentions. Review your intent tracking. Add an explicit topic boundary rule: once an intent is established, don't update it unless the customer uses an explicit topic change phrase ("actually, I also need to..." or "before that...").

High assumption deadlock rate. Your agent is acting on inferences before confirming them. Add a confirmation step before acting on assumptions for high-stakes actions (returns, cancellations, account changes). The extra turn is worth the reduction in deadlocks.

High initiative mismatch rate. Your agent is asking too many open-ended questions. Review your turn design. Prefer closed questions with bounded choices ("would you like a refund or an exchange?") over open questions ("what would you like to do?") for situations where the customer's goal is already partially known.

Chanl's analytics breaks repair move frequency out by conversation type, intent category, and agent version. When a new deployment spikes clarification spirals by 20%, you see it in the repair dashboard before you see it in your escalation rate or your satisfaction scores. Repair frequency is an early warning, not a lagging indicator.

Chanl's monitoring also lets you set alert thresholds: if the clarification spiral rate for a given intent crosses a ceiling, you get a notification before the problem compounds. The threshold you set reflects your risk tolerance. For low-stakes intents (checking a balance), you might allow 12% before alerting. For high-stakes intents (canceling a contract), 5% might be your ceiling.


The gap in most agent deployments is not escalation logic. Teams spend real time on escalation. The gap is the space between "conversation slightly off course" and "customer frustrated enough to ask for a human." That space is where repair lives, and closing it is mostly a matter of naming the failure modes, detecting them early, and having a specific response to each one.

Your customers usually called with a solvable problem. They're stuck because the conversation lost its way, not because the task is too hard. Give your agent a way back, and most of them will find it.

Catch stuck conversations before customers give up

Chanl's analytics surface repair move frequency, escalation rates, and intent drift patterns by conversation type and agent version. Set alert thresholds for the failure modes that matter most to your team.

Try Chanl Free
DG

Co-founder

Building the platform for AI agents at Chanl — tools, testing, and observability for customer experience.

Learn Agentic AI

Weekly. Patterns for shipping agents that work. MCP, scorecards, regression tests, prompts, model comparisons.

500+ builders subscribed

Frequently Asked Questions