hermes - 💡(How to fix) Fix Feature: Frustration detection and /progress-report command — non-interrupting task status checks [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#18419Fetched 2026-05-02 05:48:45
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
labeled ×3cross-referenced ×1

Error Message

ROLE: Stall Diagnostician MODEL: aux (flash-tier) TIMEOUT: 30 seconds TOOLSETS: [terminal]

TASK:

  1. Check if the process is still alive: ps aux | grep {pid}
  2. Check last 50 lines of output: process log
  3. Check for common failure modes: a. API rate limit: grep for "rate limit", "429", "quota" b. Network timeout: grep for "timeout", "ETIMEDOUT", "ECONNREFUSED" c. Model error: grep for "error", "failed", "exception", "Traceback" d. Authentication: grep for "unauthorized", "401", "403" e. Disk space: df -h (running out of space causes silent hangs) f. Memory pressure: free -h (OOM kills don't always produce output) g. DNS issues: check if the machine can resolve hosts
  4. Check system resources: top -bn1 | head -20
  5. Return structured diagnosis

OUTPUT: { "stall_cause": "api_rate_limit", "confidence": 0.85, "evidence": "GitHub API returned 403 with 'rate limit exceeded' at 17:23:41", "suggestion": "Wait for rate limit window to reset (~15 min) or reduce API calls", "auto_recovery_possible": true, "auto_recovery_action": "wait_and_retry" }

Root Cause

  1. Eliminates the #1 source of user frustration with AI agents — "what is it doing??" — without requiring any architecture changes to the agent itself
  2. Side-channel design — progress checks don't pollute context, don't interrupt tasks, don't waste tokens
  3. Proactive, not reactive — stall detection notifies the user BEFORE they get frustrated
  4. Frustration patterns are universal — every Telegram/Discord/WhatsApp user types "hey" and "???" when waiting. This is platform-agnostic human behavior, not a niche feature
  5. Auto-recovery — many stalls are transient (rate limits, network blips). The system handles them automatically instead of requiring manual intervention

Code Example

CATEGORY: presence_probe
  - "are you there", "you there", "you alive", "still there"
  - "anyone", "hello", "hey", "yo", "hi"
  - "ping", "beep", "boop"
  - Repeated single messages in quick succession (2+ identical messages within 60s)

CATEGORY: status_request
  - "what's going on", "whats going on", "what's happening"
  - "status", "progress", "report"
  - "how's it going", "how is it going"
  - "any update", "updates", "progress report"
  - "report back", "give me a status"
  - "where are we", "where are we at"

CATEGORY: impatience_indicator
  - "hello??", "hey???", "???", "..."
  - "hello" followed by another "hello" within 120s
  - "are you there" sent after a long silence (>2 min with no output)
  - ALL CAPS messages: "HEY", "STATUS", "REPORT"

CATEGORY: concern_probe
  - "did it crash", "is it stuck", "did it fail"
  - "is this done yet", "how much longer"
  - "why is this taking so long"
  - "timeout", "timed out", "error"

CATEGORY: gentle_nudge
  - "sup", "what's up", "whatsup", "whatup"
  - "how's it looking", "anything new"
  - "finished?", "done yet"

---

def classify_message(text, context):
    """
    Returns: 'frustration_probe' | 'steer_request' | 'normal_message'
    """
    text_lower = text.strip().lower()
    
    # Quick rejection: if the message is long (>50 chars) or contains
    # specific action verbs, it's probably a real steer request
    if len(text_lower) > 50 and not any(p in text_lower for p in SHORT_PROBES):
        return 'normal_message'
    
    # If there's an active long-running task, these are progress probes
    if active_task_exists():
        for pattern_set in FRUSTRATION_PATTERNS:
            if any(p in text_lower for p in pattern_set):
                return 'frustration_probe'
    
    # Without an active task, short messages are just greetings
    return 'normal_message'

---

"hey, stop the build"steer_request (has an action verb + target)
"are you there? cancel it"steer_request (frustration opener but real command)
"what's going on with X?"steer_request (asking about a topic, not progress)
"status of the deploy"steer_request (asking about a specific task, not current task)

---

/progress-report
/progressreport
/whatsgoingon
/whats-up
/whatsup
/status
/report

---

def get_progress_report():
    report = {}
    
    # 1. Active process check
    if terminal_process_running():
        proc = get_active_process()
        report["status"] = "running"
        report["command"] = proc.command  # truncated
        report["started_at"] = proc.started_at
        report["elapsed"] = now() - proc.started_at
        report["last_output"] = proc.last_output_line
        report["last_output_at"] = proc.last_output_timestamp
        report["cpu_usage"] = proc.cpu_percent
        report["memory_usage"] = proc.memory_mb
        
        # Detect stall: no output for >2 minutes on a process that was producing output
        if proc.was_producing_output and (now() - proc.last_output_timestamp > 120):
            report["stall_detected"] = True
            report["stall_duration"] = now() - proc.last_output_timestamp
            report["stall_context"] = proc.last_output_lines(20)
    
    # 2. Cron job check
    active_crons = get_running_cron_jobs()
    if active_crons:
        for job in active_crons:
            report["cron_jobs"].append({
                "name": job.name,
                "job_id": job.job_id,
                "started_at": job.started_at,
                "elapsed": now() - job.started_at,
                "model": job.model,
                "tools_used": job.tools_accessed,
                "last_status": job.last_status_update
            })
    
    # 3. Delegated agent check
    if delegated_agent_active():
        agent = get_active_delegated_agent()
        report["delegated_agent"] = {
            "goal": agent.goal_summary,
            "started_at": agent.started_at,
            "elapsed": now() - agent.started_at,
            "current_step": agent.current_step,
            "tools_called": agent.tools_call_count
        }
    
    # 4. Queue check
    pending_messages = get_pending_messages()
    if pending_messages:
        report["queued_messages"] = len(pending_messages)
        report["oldest_pending"] = pending_messages[0].received_at
    
    return report

---

**Still working on it**

🔍 **GitHub Issue Monitor** (cron job)
Running for 4m 23s
🔧 Tools called: 12 (terminal, web_search, gh api)
📊 Last activity: 8s ago — fetching comments on hermes-agent#18289

Estimate: based on tool call rate, ~3-5 minutes remaining.

---

⚠️ **Task may be stuck**

🔍 **GitHub Issue Monitor** (cron job)
Running for 12m 05s
🔧 Tools called: 8 (last one 8m ago)
📊 Last output: "Checking comments on OmniRoute#1814..."

📋 **Possible causes:**
API rate limit hit (GitHub 5000/hr, 8 calls so far — unlikely)
Model timeout waiting for response
Process hung on network call

🔧 **Auto-action:** Spawning diagnostic check...
[diagnostic results follow in next message]

---

**Task finished** — response wasn't delivered

The GitHub Issue Monitor completed 3m ago but the result wasn't sent.
Re-delivering now:

📊 **GitHub Issue Activity** (last 8h)
[...full result...]

---

😴 **Nothing running**

No active tasks, cron jobs, or agents. Last activity:
GitHub Issue Monitor — completed 2h ago ✅
Software Cache Refresh — scheduled in 5 days

Queued messages: 0

All clear. Need something?

---

ROLE: Stall Diagnostician
MODEL: aux (flash-tier)
TIMEOUT: 30 seconds
TOOLSETS: [terminal]

TASK:
1. Check if the process is still alive: ps aux | grep {pid}
2. Check last 50 lines of output: process log
3. Check for common failure modes:
   a. API rate limit: grep for "rate limit", "429", "quota"
   b. Network timeout: grep for "timeout", "ETIMEDOUT", "ECONNREFUSED"
   c. Model error: grep for "error", "failed", "exception", "Traceback"
   d. Authentication: grep for "unauthorized", "401", "403"
   e. Disk space: df -h (running out of space causes silent hangs)
   f. Memory pressure: free -h (OOM kills don't always produce output)
   g. DNS issues: check if the machine can resolve hosts
4. Check system resources: top -bn1 | head -20
5. Return structured diagnosis

OUTPUT:
{
  "stall_cause": "api_rate_limit",
  "confidence": 0.85,
  "evidence": "GitHub API returned 403 with 'rate limit exceeded' at 17:23:41",
  "suggestion": "Wait for rate limit window to reset (~15 min) or reduce API calls",
  "auto_recovery_possible": true,
  "auto_recovery_action": "wait_and_retry"
}

---

⚠️ **Heads up**GitHub Issue Monitor seems stuck

Been running for 15m with no activity in the last 8 minutes.
Likely cause: GitHub API rate limit hit.

I'll retry automatically when the window resets (~22:45).

React 👍 to acknowledge, or 🛑 to cancel the job.

---

User message arrives
┌─────────────────────┐
Pattern Classifier  (regex, <50 chars,│   active task check)└─────────┬───────────┘
          ├── "frustration_probe" ──► Progress Reporter (non-interrupting)
          │                                    │
          │                                    ├── Report from internal state
          │                                    ├── Spawn diagnostic if stalled
          │                                    └── Send response immediately
          ├── "/progress-report" ──► Same Progress Reporter
          └── "normal_message" ──► Standard agent queue

---

agent:
  frustration_detection:
    enabled: true  # on by defaultthis should just work
    
    # Pattern sensitivity
    detect_short_probes: true     # "hey", "ping", "???"
    detect_repeated_messages: true # same message 2+ times in 60s
    detect_all_caps: true         # "STATUS", "REPORT"
    
    # Don't classify as frustration if message contains these
    action_verbs: ["stop", "cancel", "abort", "kill", "skip", "change", "switch", "do", "run", "make", "create", "fix", "update"]
    
    # Response style
    response_includes_estimate: true   # rough time remaining
    response_includes_tools_used: true # what tools have been called
    response_includes_next_step: true  # what the agent is about to do
    
  progress_report:
    command_aliases:
      - /progress-report
      - /progressreport
      - /whatsgoingon
      - /whats-up
      - /whatsup
      - /status
      - /report
    
  stall_detection:
    enabled: true
    check_interval_seconds: 30
    
    # Stall thresholds
    no_output_threshold_seconds: 120
    no_tool_calls_threshold_seconds: 300
    no_status_update_threshold_seconds: 600
    cpu_zero_threshold_seconds: 60
    repeated_output_threshold: 3
    
    # Auto-diagnosis
    auto_diagnose: true
    diagnostic_model: "aux"  # use cheapest available
    
    # Auto-recovery
    auto_recovery: true
    auto_recovery_actions:
      rate_limit: "wait_and_retry"
      network_timeout: "retry_with_backoff"
      model_timeout: "fallback_to_aux"
    
    # Proactive notification
    notify_on_stall: true
    stall_notify_after_seconds: 300  # 5 min of no activity
    
    # Emoji acknowledgment of proactive notifications
    ack_emoji: "👍"   # user reacts 👍 to acknowledge
    cancel_emoji: "🛑" # user reacts 🛑 to cancel stalled job
RAW_BUFFERClick to expand / collapse

Problem

When a long-running agent task is in progress (cron job, delegated agent, multi-step build, etc.), the user has zero visibility into what's happening. The natural response is to send messages like:

  • "are you there"
  • "what's going on"
  • "hey"
  • "report back"
  • "hello??"
  • "what's up"
  • "status?"

These are not requests to change course — they're steer requests for a progress report. But currently, each of these messages either:

  1. Interrupts the running task — the agent stops what it's doing, processes the new message, and may lose context or abort the long-running operation
  2. Gets queued and ignored — the message sits in a queue and the user gets no feedback, making them more frustrated
  3. Gets a generic "I'm working on it" — unhelpful and doesn't actually report progress

The user isn't trying to steer the task. They want to know: Is it still running? What's it doing? Is it stuck?

Proposed Solution

Part A: Frustration Pattern Detection

A lightweight pattern-matching layer that intercepts messages matching known "frustration/probe" patterns and routes them to a progress-report handler instead of the main agent loop.

1.1 Pattern Taxonomy

CATEGORY: presence_probe
  - "are you there", "you there", "you alive", "still there"
  - "anyone", "hello", "hey", "yo", "hi"
  - "ping", "beep", "boop"
  - Repeated single messages in quick succession (2+ identical messages within 60s)

CATEGORY: status_request
  - "what's going on", "whats going on", "what's happening"
  - "status", "progress", "report"
  - "how's it going", "how is it going"
  - "any update", "updates", "progress report"
  - "report back", "give me a status"
  - "where are we", "where are we at"

CATEGORY: impatience_indicator
  - "hello??", "hey???", "???", "..."
  - "hello" followed by another "hello" within 120s
  - "are you there" sent after a long silence (>2 min with no output)
  - ALL CAPS messages: "HEY", "STATUS", "REPORT"

CATEGORY: concern_probe
  - "did it crash", "is it stuck", "did it fail"
  - "is this done yet", "how much longer"
  - "why is this taking so long"
  - "timeout", "timed out", "error"

CATEGORY: gentle_nudge
  - "sup", "what's up", "whatsup", "whatup"
  - "how's it looking", "anything new"
  - "finished?", "done yet"

1.2 Detection Logic

def classify_message(text, context):
    """
    Returns: 'frustration_probe' | 'steer_request' | 'normal_message'
    """
    text_lower = text.strip().lower()
    
    # Quick rejection: if the message is long (>50 chars) or contains
    # specific action verbs, it's probably a real steer request
    if len(text_lower) > 50 and not any(p in text_lower for p in SHORT_PROBES):
        return 'normal_message'
    
    # If there's an active long-running task, these are progress probes
    if active_task_exists():
        for pattern_set in FRUSTRATION_PATTERNS:
            if any(p in text_lower for p in pattern_set):
                return 'frustration_probe'
    
    # Without an active task, short messages are just greetings
    return 'normal_message'

Key principle: Only classify as frustration probe when there IS an active task. Without context, "hey" is just a greeting.

1.3 Anti-Pattern: Don't Misclassify Real Steer Requests

"hey, stop the build"        → steer_request (has an action verb + target)
"are you there? cancel it"   → steer_request (frustration opener but real command)
"what's going on with X?"    → steer_request (asking about a topic, not progress)
"status of the deploy"       → steer_request (asking about a specific task, not current task)

The classifier should check for the presence of action verbs, specific entity references, or task identifiers. If found, route as a normal steer request even if it starts with a frustration pattern.


Part B: /progress-report Command (and aliases)

A dedicated slash command for explicit progress checks.

2.1 Command Aliases

/progress-report
/progressreport
/whatsgoingon
/whats-up
/whatsup
/status
/report

All resolve to the same handler. The aliases exist because users will type whatever feels natural when frustrated.

2.2 Behavior

The /progress-report command is a non-interrupting steer subtype. It does NOT:

  • Stop the running task
  • Inject a new message into the agent's context window
  • Modify the agent's plan or prompt
  • Queue a message that will be processed after the task completes

Instead, it:

  1. Reports immediately from the task runner's internal state
  2. If the task is actively running, reports what step it's on and how long it's been running
  3. If the task appears stalled, spawns a delegated check agent to diagnose why
  4. If the task completed but the response wasn't delivered, re-delivers the result
  5. If no task is running, says so

2.3 Progress Report Sources

def get_progress_report():
    report = {}
    
    # 1. Active process check
    if terminal_process_running():
        proc = get_active_process()
        report["status"] = "running"
        report["command"] = proc.command  # truncated
        report["started_at"] = proc.started_at
        report["elapsed"] = now() - proc.started_at
        report["last_output"] = proc.last_output_line
        report["last_output_at"] = proc.last_output_timestamp
        report["cpu_usage"] = proc.cpu_percent
        report["memory_usage"] = proc.memory_mb
        
        # Detect stall: no output for >2 minutes on a process that was producing output
        if proc.was_producing_output and (now() - proc.last_output_timestamp > 120):
            report["stall_detected"] = True
            report["stall_duration"] = now() - proc.last_output_timestamp
            report["stall_context"] = proc.last_output_lines(20)
    
    # 2. Cron job check
    active_crons = get_running_cron_jobs()
    if active_crons:
        for job in active_crons:
            report["cron_jobs"].append({
                "name": job.name,
                "job_id": job.job_id,
                "started_at": job.started_at,
                "elapsed": now() - job.started_at,
                "model": job.model,
                "tools_used": job.tools_accessed,
                "last_status": job.last_status_update
            })
    
    # 3. Delegated agent check
    if delegated_agent_active():
        agent = get_active_delegated_agent()
        report["delegated_agent"] = {
            "goal": agent.goal_summary,
            "started_at": agent.started_at,
            "elapsed": now() - agent.started_at,
            "current_step": agent.current_step,
            "tools_called": agent.tools_call_count
        }
    
    # 4. Queue check
    pending_messages = get_pending_messages()
    if pending_messages:
        report["queued_messages"] = len(pending_messages)
        report["oldest_pending"] = pending_messages[0].received_at
    
    return report

2.4 Output Format (Telegram)

When task is running normally:

⏳ **Still working on it**

🔍 **GitHub Issue Monitor** (cron job)
⏱ Running for 4m 23s
🔧 Tools called: 12 (terminal, web_search, gh api)
📊 Last activity: 8s ago — fetching comments on hermes-agent#18289

Estimate: based on tool call rate, ~3-5 minutes remaining.

When task appears stalled:

⚠️ **Task may be stuck**

🔍 **GitHub Issue Monitor** (cron job)
⏱ Running for 12m 05s
🔧 Tools called: 8 (last one 8m ago)
📊 Last output: "Checking comments on OmniRoute#1814..."

📋 **Possible causes:**
  • API rate limit hit (GitHub 5000/hr, 8 calls so far — unlikely)
  • Model timeout waiting for response
  • Process hung on network call

🔧 **Auto-action:** Spawning diagnostic check...
[diagnostic results follow in next message]

When task completed but response wasn't delivered:

✅ **Task finished** — response wasn't delivered

The GitHub Issue Monitor completed 3m ago but the result wasn't sent.
Re-delivering now:

📊 **GitHub Issue Activity** (last 8h)
[...full result...]

When no task is running:

😴 **Nothing running**

No active tasks, cron jobs, or agents. Last activity:
  • GitHub Issue Monitor — completed 2h ago ✅
  • Software Cache Refresh — scheduled in 5 days

Queued messages: 0

All clear. Need something?

Part C: Stall Detection & Auto-Diagnosis

3.1 Stall Detection Rules

A task is considered "stalled" when:

ConditionThresholdNotes
No terminal output2 minutesOnly if the process was previously producing output
No tool calls5 minutesAgent is thinking but not acting
No status update10 minutesFor cron jobs with tracked progress
CPU at 0%1 minuteProcess exists but doing nothing
Same output line repeated3 timesLikely a retry loop
Process exists but no memory change3 minutesZombie or hung process

3.2 Auto-Diagnosis Agent

When a stall is detected (either by frustration probe or by periodic monitoring), spawn a lightweight diagnostic delegated agent:

ROLE: Stall Diagnostician
MODEL: aux (flash-tier)
TIMEOUT: 30 seconds
TOOLSETS: [terminal]

TASK:
1. Check if the process is still alive: ps aux | grep {pid}
2. Check last 50 lines of output: process log
3. Check for common failure modes:
   a. API rate limit: grep for "rate limit", "429", "quota"
   b. Network timeout: grep for "timeout", "ETIMEDOUT", "ECONNREFUSED"
   c. Model error: grep for "error", "failed", "exception", "Traceback"
   d. Authentication: grep for "unauthorized", "401", "403"
   e. Disk space: df -h (running out of space causes silent hangs)
   f. Memory pressure: free -h (OOM kills don't always produce output)
   g. DNS issues: check if the machine can resolve hosts
4. Check system resources: top -bn1 | head -20
5. Return structured diagnosis

OUTPUT:
{
  "stall_cause": "api_rate_limit",
  "confidence": 0.85,
  "evidence": "GitHub API returned 403 with 'rate limit exceeded' at 17:23:41",
  "suggestion": "Wait for rate limit window to reset (~15 min) or reduce API calls",
  "auto_recovery_possible": true,
  "auto_recovery_action": "wait_and_retry"
}

3.3 Auto-Recovery

For certain stall causes, the system can auto-recover without user intervention:

Stall CauseAuto-Recovery Action
API rate limit (GitHub, OpenAI, etc.)Wait for window reset, then retry
Network timeout (transient)Retry with backoff
Model timeout (provider overloaded)Retry with aux model fallback
Disk space lowAlert user, don't auto-fix
Memory OOMAlert user, don't auto-fix
Process died (signal)Report cause, suggest retry
Infinite loop (same output)Kill process, alert user
Authentication failureAlert user, don't expose credentials

3.4 Proactive Stall Notifications

The system should proactively notify the user when a stall is detected, rather than waiting for a frustration probe:

⚠️ **Heads up** — GitHub Issue Monitor seems stuck

Been running for 15m with no activity in the last 8 minutes.
Likely cause: GitHub API rate limit hit.

I'll retry automatically when the window resets (~22:45).

React 👍 to acknowledge, or 🛑 to cancel the job.

This is the ideal UX — the user gets notified BEFORE they get frustrated.


Part D: Integration Architecture

4.1 Message Flow

User message arrives
┌─────────────────────┐
│  Pattern Classifier │
│  (regex, <50 chars,  │
│   active task check) │
└─────────┬───────────┘
          ├── "frustration_probe" ──► Progress Reporter (non-interrupting)
          │                                    │
          │                                    ├── Report from internal state
          │                                    ├── Spawn diagnostic if stalled
          │                                    └── Send response immediately
          ├── "/progress-report" ──► Same Progress Reporter
          └── "normal_message" ──► Standard agent queue

4.2 Key Design Decisions

  1. Progress reports are side-channel — they never enter the agent's conversation context. The running task is completely unaware that a progress check happened.

  2. Frustration probes are ephemeral — they are NOT logged in conversation history. They don't pollute the context window and don't affect the agent's future behavior.

  3. Progress data comes from the task runner, not the LLM — the progress handler reads process state, tool call logs, and system metrics directly. It doesn't need to ask the agent "what are you doing?" — it can see for itself.

  4. Stall detection is continuous — a background monitor checks task health periodically (every 30-60 seconds), not just when the user asks. This enables proactive notifications.


Part E: Configuration

agent:
  frustration_detection:
    enabled: true  # on by default — this should just work
    
    # Pattern sensitivity
    detect_short_probes: true     # "hey", "ping", "???"
    detect_repeated_messages: true # same message 2+ times in 60s
    detect_all_caps: true         # "STATUS", "REPORT"
    
    # Don't classify as frustration if message contains these
    action_verbs: ["stop", "cancel", "abort", "kill", "skip", "change", "switch", "do", "run", "make", "create", "fix", "update"]
    
    # Response style
    response_includes_estimate: true   # rough time remaining
    response_includes_tools_used: true # what tools have been called
    response_includes_next_step: true  # what the agent is about to do
    
  progress_report:
    command_aliases:
      - /progress-report
      - /progressreport
      - /whatsgoingon
      - /whats-up
      - /whatsup
      - /status
      - /report
    
  stall_detection:
    enabled: true
    check_interval_seconds: 30
    
    # Stall thresholds
    no_output_threshold_seconds: 120
    no_tool_calls_threshold_seconds: 300
    no_status_update_threshold_seconds: 600
    cpu_zero_threshold_seconds: 60
    repeated_output_threshold: 3
    
    # Auto-diagnosis
    auto_diagnose: true
    diagnostic_model: "aux"  # use cheapest available
    
    # Auto-recovery
    auto_recovery: true
    auto_recovery_actions:
      rate_limit: "wait_and_retry"
      network_timeout: "retry_with_backoff"
      model_timeout: "fallback_to_aux"
    
    # Proactive notification
    notify_on_stall: true
    stall_notify_after_seconds: 300  # 5 min of no activity
    
    # Emoji acknowledgment of proactive notifications
    ack_emoji: "👍"   # user reacts 👍 to acknowledge
    cancel_emoji: "🛑" # user reacts 🛑 to cancel stalled job

Part F: Examples

Scenario 1: User sends "hey" during a long build

User: hey

Agent: ⏳ Still working on it 🔨 Building hermes-agent from source ⏱ Running for 7m 12s 📊 Step 3/5: Running test suite (312/547 tests passed)

The running task is completely unaffected.

Scenario 2: User sends "are you there" twice in 1 minute

User: are you there (1 minute passes, no response to first message because task is running) User: are you there

Agent: ⏳ Yes, still here. GitHub Issue Monitor is running. ⏱ 8m 34s elapsed, 23 API calls made 📊 Currently checking: OmniRoute#1814 comments

(The double-probe triggers a more detailed response)

Scenario 3: User sends /status on a stalled task

User: /status

Agent: ⚠️ Task may be stuck

🔍 GitHub Issue Monitor (cron job) ⏱ Running for 14m 02s 📊 Last activity: 9m ago — no output since

🔧 Diagnosing...

✅ Diagnosis: GitHub API rate limit hit 📋 "API rate limit exceeded for user apoapostolov" 💡 Rate window resets at 18:00 (in ~12 minutes) 🔄 Will auto-retry when window opens.

React 🛑 to cancel, or I'll resume automatically.

Scenario 4: Proactive stall notification (no user message)

Agent: ⚠️ Heads up — Software Cache Refresh seems stuck

Been running for 18m with no output in the last 12 minutes. Diagnosis: pip list command hanging (possible network issue).

I'll retry once more. If it fails again, I'll abort and report.

React 👍 to acknowledge or 🛑 to cancel.


Why This Matters

  1. Eliminates the #1 source of user frustration with AI agents — "what is it doing??" — without requiring any architecture changes to the agent itself
  2. Side-channel design — progress checks don't pollute context, don't interrupt tasks, don't waste tokens
  3. Proactive, not reactive — stall detection notifies the user BEFORE they get frustrated
  4. Frustration patterns are universal — every Telegram/Discord/WhatsApp user types "hey" and "???" when waiting. This is platform-agnostic human behavior, not a niche feature
  5. Auto-recovery — many stalls are transient (rate limits, network blips). The system handles them automatically instead of requiring manual intervention

Open Questions

  • Should frustration probes from group chats behave differently? (Probably ignore them — only respond to the configured user's probes in DMs)
  • Should the progress reporter show the actual terminal output, or a summary? (Summary for Telegram, full output available on request)
  • How to handle overlapping long-running tasks? (Show all of them, ordered by start time)
  • Should there be a "verbose mode" progress report that shows more detail?

extent analysis

TL;DR

Implement a pattern-matching layer to detect frustration probes and route them to a progress-report handler, providing users with immediate feedback on long-running tasks without interrupting the task itself.

Guidance

  1. Implement the pattern classifier: Use the provided taxonomy to identify frustration patterns and route them to the progress-report handler.
  2. Develop the progress-report handler: Create a non-interrupting steer subtype that reports task progress, including what step it's on, how long it's been running, and any relevant tool calls or system metrics.
  3. Integrate stall detection and auto-diagnosis: Implement periodic monitoring to detect stalls and spawn a diagnostic delegated agent to diagnose the cause.
  4. Configure the system: Use the provided YAML configuration to enable frustration detection, progress reporting, and stall detection, and adjust thresholds and settings as needed.

Example

def classify_message(text, context):
    # Quick rejection: if the message is long (>50 chars) or contains specific action verbs, it's probably a real steer request
    if len(text.strip().lower()) > 50 and not any(p in text.strip().lower() for p in SHORT_PROBES):
        return 'normal_message'
    
    # If there's an active long-running task, these are progress probes
    if active_task_exists():
        for pattern_set in FRUSTRATION_PATTERNS:
            if any(p in text.strip().lower() for p in pattern_set):
                return 'frustration_probe'
    
    # Without an active task, short messages are just greetings
    return 'normal_message'

Notes

The implementation should consider the specific requirements and constraints of the system, including the type of tasks being run, the user interface, and the available system metrics. The provided code snippets and configuration examples should be adapted to fit the specific use case.

Recommendation

Apply the workaround by implementing the pattern-matching layer and progress-report handler

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix Feature: Frustration detection and /progress-report command — non-interrupting task status checks [1 participants]