Skip to content

[Bug] Agent stuck in 'still running' state after interrupt() when reactive stream is frozen #679

@richuV

Description

@richuV

Description

When a reactive stream is stuck (e.g., LLM timeout, network issue), calling interrupt() does not reset the running state, causing the Agent to be permanently stuck in "Agent is still running" state.

Root Cause

In AgentBase.java:

  1. The running AtomicBoolean is set to true at the start of call() (line 163)
  2. It's only reset to false in doFinally() (line 180)
  3. When the reactive stream freezes (e.g., waiting for LLM response that never comes), doFinally() is never called
  4. interrupt() only sets interruptFlag, it does NOT reset running
// Line 163: Set running to true
if (!running.compareAndSet(false, true) && checkRunning) {
    return Mono.error(new IllegalStateException("Agent is still running..."));
}

// Line 180: Only reset in doFinally - never called if stream is frozen
.doFinally(signalType -> running.set(false));

// Line 297-299: interrupt() only sets flag, doesn't reset running
public void interrupt() {
    interruptFlag.set(true);
}

Steps to Reproduce

  1. Start an agent request
  2. Let it get stuck waiting for LLM response (simulate with a very slow/unresponsive API)
  3. Call agent.interrupt() to cancel
  4. Try to send a new request
  5. Result: Error "Agent is still running, please wait for it to finish"
  6. Expected: Agent should be ready to accept new requests

Suggested Fix

Add a public method to force reset the running state:

/**
 * Force reset the running state.
 * Use when the reactive stream is stuck and doFinally() won't be called.
 */
public void forceResetRunningState() {
    running.set(false);
    resetInterruptFlag();
}

Or alternatively, add an option to interrupt() to also reset running state:

public void interrupt(boolean forceReset) {
    interruptFlag.set(true);
    if (forceReset) {
        running.set(false);
    }
}

Workaround

Currently using reflection to reset the running state:

private void forceResetAgentRunningState(ReActAgent agent) {
    try {
        Class<?> agentBaseClass = agent.getClass();
        while (agentBaseClass != null && !agentBaseClass.getName().endsWith("AgentBase")) {
            agentBaseClass = agentBaseClass.getSuperclass();
        }
        if (agentBaseClass != null) {
            Field runningField = agentBaseClass.getDeclaredField("running");
            runningField.setAccessible(true);
            AtomicBoolean running = (AtomicBoolean) runningField.get(agent);
            running.set(false);
        }
    } catch (Exception e) {
        // Handle error
    }
}

Environment

  • agentscope-java version: latest main branch
  • Java version: 21

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions