mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-01-10 23:38:08 -05:00
Fix status indicator and chat input synchronization issue (#10914)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
209
frontend/src/utils/__tests__/status.test.ts
Normal file
209
frontend/src/utils/__tests__/status.test.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { getStatusCode, getIndicatorColor, IndicatorColor } from "../status";
|
||||
import { AgentState } from "#/types/agent-state";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
|
||||
describe("getStatusCode", () => {
|
||||
it("should prioritize agent readiness over stale runtime status", () => {
|
||||
// Test case: Agent is ready (AWAITING_USER_INPUT) but runtime status is still starting
|
||||
const result = getStatusCode(
|
||||
{ id: "", message: "", type: "info", status_update: true }, // statusMessage
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.AWAITING_USER_INPUT, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return agent state message, not runtime status
|
||||
expect(result).toBe(I18nKey.AGENT_STATUS$WAITING_FOR_TASK);
|
||||
});
|
||||
|
||||
it("should show runtime status when agent is not ready", () => {
|
||||
// Test case: Agent is loading and runtime is starting
|
||||
const result = getStatusCode(
|
||||
{ id: "", message: "", type: "info", status_update: true }, // statusMessage
|
||||
"CONNECTED", // webSocketStatus
|
||||
"STARTING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus
|
||||
AgentState.LOADING, // agentState (not ready)
|
||||
);
|
||||
|
||||
// Should return runtime status since agent is not ready
|
||||
expect(result).toBe("STATUS$STARTING_RUNTIME");
|
||||
});
|
||||
|
||||
it("should handle agent running state with stale runtime status", () => {
|
||||
// Test case: Agent is running but runtime status is stale
|
||||
const result = getStatusCode(
|
||||
{ id: "", message: "", type: "info", status_update: true }, // statusMessage
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$BUILDING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.RUNNING, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return agent state message, not runtime status
|
||||
expect(result).toBe(I18nKey.AGENT_STATUS$RUNNING_TASK);
|
||||
});
|
||||
|
||||
it("should handle agent finished state with stale runtime status", () => {
|
||||
// Test case: Agent is finished but runtime status is stale
|
||||
const result = getStatusCode(
|
||||
{ id: "", message: "", type: "info", status_update: true }, // statusMessage
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$SETTING_UP_WORKSPACE", // runtimeStatus (stale)
|
||||
AgentState.FINISHED, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return agent state message, not runtime status
|
||||
expect(result).toBe(I18nKey.AGENT_STATUS$WAITING_FOR_TASK);
|
||||
});
|
||||
|
||||
it("should still respect stopped states", () => {
|
||||
// Test case: Runtime is stopped - should always show stopped
|
||||
const result = getStatusCode(
|
||||
{ id: "", message: "", type: "info", status_update: true }, // statusMessage
|
||||
"CONNECTED", // webSocketStatus
|
||||
"STOPPED", // conversationStatus
|
||||
"STATUS$STOPPED", // runtimeStatus
|
||||
AgentState.RUNNING, // agentState
|
||||
);
|
||||
|
||||
// Should return stopped status regardless of agent state
|
||||
expect(result).toBe(I18nKey.CHAT_INTERFACE$STOPPED);
|
||||
});
|
||||
|
||||
it("should handle null agent state with runtime status", () => {
|
||||
// Test case: No agent state, runtime is starting
|
||||
const result = getStatusCode(
|
||||
{ id: "", message: "", type: "info", status_update: true }, // statusMessage
|
||||
"CONNECTED", // webSocketStatus
|
||||
"STARTING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus
|
||||
null, // agentState
|
||||
);
|
||||
|
||||
// Should return runtime status since no agent state
|
||||
expect(result).toBe("STATUS$STARTING_RUNTIME");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getIndicatorColor", () => {
|
||||
it("should prioritize agent readiness over stale runtime status for AWAITING_USER_INPUT", () => {
|
||||
// Test case: Agent is ready (AWAITING_USER_INPUT) but runtime status is still starting
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.AWAITING_USER_INPUT, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return blue for AWAITING_USER_INPUT, not yellow for stale runtime
|
||||
expect(result).toBe(IndicatorColor.BLUE);
|
||||
});
|
||||
|
||||
it("should prioritize agent readiness over stale runtime status for RUNNING", () => {
|
||||
// Test case: Agent is running but runtime status is stale
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$BUILDING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.RUNNING, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return green for RUNNING, not yellow for stale runtime
|
||||
expect(result).toBe(IndicatorColor.GREEN);
|
||||
});
|
||||
|
||||
it("should prioritize agent readiness over stale runtime status for FINISHED", () => {
|
||||
// Test case: Agent is finished but runtime status is stale
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$SETTING_UP_WORKSPACE", // runtimeStatus (stale)
|
||||
AgentState.FINISHED, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return green for FINISHED, not yellow for stale runtime
|
||||
expect(result).toBe(IndicatorColor.GREEN);
|
||||
});
|
||||
|
||||
it("should show yellow when agent is not ready and runtime is starting", () => {
|
||||
// Test case: Agent is loading and runtime is starting
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"STARTING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus
|
||||
AgentState.LOADING, // agentState (not ready)
|
||||
);
|
||||
|
||||
// Should return yellow since agent is not ready
|
||||
expect(result).toBe(IndicatorColor.YELLOW);
|
||||
});
|
||||
|
||||
it("should show orange for AWAITING_USER_CONFIRMATION even with stale runtime", () => {
|
||||
// Test case: Agent is awaiting confirmation but runtime status is stale
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.AWAITING_USER_CONFIRMATION, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return orange for AWAITING_USER_CONFIRMATION, not yellow for stale runtime
|
||||
expect(result).toBe(IndicatorColor.ORANGE);
|
||||
});
|
||||
|
||||
it("should still respect stopped states", () => {
|
||||
// Test case: Runtime is stopped - should always show red
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"STOPPED", // conversationStatus
|
||||
"STATUS$STOPPED", // runtimeStatus
|
||||
AgentState.RUNNING, // agentState
|
||||
);
|
||||
|
||||
// Should return red for stopped status regardless of agent state
|
||||
expect(result).toBe(IndicatorColor.RED);
|
||||
});
|
||||
|
||||
it("should handle null agent state with runtime status", () => {
|
||||
// Test case: No agent state, runtime is starting
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"STARTING", // conversationStatus
|
||||
"STATUS$STARTING_RUNTIME", // runtimeStatus
|
||||
null, // agentState
|
||||
);
|
||||
|
||||
// Should return yellow since no agent state and runtime is starting
|
||||
expect(result).toBe(IndicatorColor.YELLOW);
|
||||
});
|
||||
|
||||
it("should handle USER_CONFIRMED state with stale runtime status", () => {
|
||||
// Test case: Agent is in USER_CONFIRMED state but runtime status is stale
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$BUILDING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.USER_CONFIRMED, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return green for USER_CONFIRMED, not yellow for stale runtime
|
||||
expect(result).toBe(IndicatorColor.GREEN);
|
||||
});
|
||||
|
||||
it("should handle USER_REJECTED state with stale runtime status", () => {
|
||||
// Test case: Agent is in USER_REJECTED state but runtime status is stale
|
||||
const result = getIndicatorColor(
|
||||
"CONNECTED", // webSocketStatus
|
||||
"RUNNING", // conversationStatus
|
||||
"STATUS$BUILDING_RUNTIME", // runtimeStatus (stale)
|
||||
AgentState.USER_REJECTED, // agentState (ready)
|
||||
);
|
||||
|
||||
// Should return green for USER_REJECTED, not yellow for stale runtime
|
||||
expect(result).toBe(IndicatorColor.GREEN);
|
||||
});
|
||||
});
|
||||
@@ -57,10 +57,23 @@ export function getIndicatorColor(
|
||||
) {
|
||||
return IndicatorColor.RED;
|
||||
}
|
||||
|
||||
// Prioritize agent state when it indicates readiness, even if runtime status is stale
|
||||
const agentIsReady =
|
||||
agentState &&
|
||||
[
|
||||
AgentState.AWAITING_USER_INPUT,
|
||||
AgentState.RUNNING,
|
||||
AgentState.FINISHED,
|
||||
AgentState.AWAITING_USER_CONFIRMATION,
|
||||
AgentState.USER_CONFIRMED,
|
||||
AgentState.USER_REJECTED,
|
||||
].includes(agentState);
|
||||
|
||||
// Display a yellow working icon while the runtime is starting
|
||||
if (
|
||||
conversationStatus === "STARTING" ||
|
||||
!["STATUS$READY", null].includes(runtimeStatus) ||
|
||||
(!["STATUS$READY", null].includes(runtimeStatus) && !agentIsReady) ||
|
||||
(agentState != null &&
|
||||
[
|
||||
AgentState.LOADING,
|
||||
@@ -96,10 +109,23 @@ export function getStatusCode(
|
||||
return I18nKey.CHAT_INTERFACE$STOPPED;
|
||||
}
|
||||
|
||||
// Handle runtime status messages
|
||||
// Prioritize agent state when it indicates readiness, even if runtime status is stale
|
||||
const agentIsReady =
|
||||
agentState &&
|
||||
[
|
||||
AgentState.AWAITING_USER_INPUT,
|
||||
AgentState.RUNNING,
|
||||
AgentState.FINISHED,
|
||||
AgentState.PAUSED,
|
||||
AgentState.AWAITING_USER_CONFIRMATION,
|
||||
AgentState.USER_CONFIRMED,
|
||||
AgentState.USER_REJECTED,
|
||||
].includes(agentState);
|
||||
|
||||
if (
|
||||
runtimeStatus &&
|
||||
!["STATUS$READY", "STATUS$RUNTIME_STARTED"].includes(runtimeStatus)
|
||||
!["STATUS$READY", "STATUS$RUNTIME_STARTED"].includes(runtimeStatus) &&
|
||||
!agentIsReady // Skip runtime status check if agent is ready
|
||||
) {
|
||||
const result = (I18nKey as { [key: string]: string })[runtimeStatus];
|
||||
if (result) {
|
||||
|
||||
Reference in New Issue
Block a user