Compare commits

...

1 Commits

5 changed files with 86 additions and 1 deletions

View File

@@ -0,0 +1,65 @@
import { renderHook } from "@testing-library/react";
import { useWSStatusChange } from "#/routes/_oh.app/hooks/use-ws-status-change";
import { WsClientProviderStatus } from "#/context/ws-client-provider";
import { AgentState } from "#/types/agent-state";
import { setCurrentAgentState } from "#/state/agent-slice";
import { vi, describe, it, expect, beforeEach, afterEach } from "vitest";
import * as wsClientProvider from "#/context/ws-client-provider";
import * as authContext from "#/context/auth-context";
import * as reactRedux from "react-redux";
// Mock the dependencies
vi.mock("#/context/ws-client-provider");
vi.mock("#/context/auth-context");
vi.mock("react-redux");
describe("useWSStatusChange", () => {
const mockDispatch = vi.fn();
const mockUseWsClient = vi.fn();
const mockUseSelector = vi.fn();
beforeEach(() => {
vi.spyOn(reactRedux, "useDispatch").mockReturnValue(mockDispatch);
vi.spyOn(wsClientProvider, "useWsClient").mockReturnValue({
status: WsClientProviderStatus.CONNECTED,
send: vi.fn(),
});
vi.spyOn(authContext, "useAuth").mockReturnValue({
gitHubToken: null,
});
vi.spyOn(reactRedux, "useSelector").mockImplementation((selector) => {
if (selector.name === "selectedRepository") {
return { selectedRepository: null };
}
return {
curAgentState: AgentState.RUNNING,
files: [],
importedProjectZip: null,
initialQuery: "",
};
});
});
afterEach(() => {
vi.clearAllMocks();
});
it("should set agent state to DISCONNECTED when websocket disconnects", () => {
// Initial render with connected status
const { rerender } = renderHook(() => useWSStatusChange());
// Update websocket status to disconnected
vi.spyOn(wsClientProvider, "useWsClient").mockReturnValue({
status: WsClientProviderStatus.DISCONNECTED,
send: vi.fn(),
});
// Rerender the hook with new status
rerender();
// Verify that the agent state was set to DISCONNECTED
expect(mockDispatch).toHaveBeenCalledWith(
setCurrentAgentState(AgentState.DISCONNECTED),
);
});
});

View File

@@ -49,6 +49,10 @@ export const AGENT_STATUS_MAP: {
message: I18nKey.CHAT_INTERFACE$AGENT_ERROR_MESSAGE,
indicator: IndicatorColor.RED,
},
[AgentState.DISCONNECTED]: {
message: I18nKey.CHAT_INTERFACE$AGENT_DISCONNECTED_MESSAGE,
indicator: IndicatorColor.ORANGE,
},
[AgentState.AWAITING_USER_CONFIRMATION]: {
message: I18nKey.CHAT_INTERFACE$AGENT_AWAITING_USER_CONFIRMATION_MESSAGE,
indicator: IndicatorColor.ORANGE,

View File

@@ -1224,6 +1224,20 @@
"fr": "L'agent s'est arrêté.",
"tr": "Ajan durdu."
},
"CHAT_INTERFACE$AGENT_DISCONNECTED_MESSAGE": {
"en": "Disconnected, trying to reconnect...",
"de": "Verbindung getrennt, versuche neu zu verbinden...",
"zh-CN": "已断开连接,正在尝试重新连接...",
"zh-TW": "已斷開連接,正在嘗試重新連接...",
"ko-KR": "연결이 끊어졌습니다. 재연결을 시도하는 중...",
"no": "Frakoblet, prøver å koble til på nytt...",
"it": "Disconnesso, tentativo di riconnessione in corso...",
"pt": "Desconectado, tentando reconectar...",
"es": "Desconectado, intentando reconectar...",
"ar": "تم قطع الاتصال، جاري محاولة إعادة الاتصال...",
"fr": "Déconnecté, tentative de reconnexion...",
"tr": "Bağlantı kesildi, yeniden bağlanmaya çalışılıyor..."
},
"CHAT_INTERFACE$AGENT_FINISHED_MESSAGE": {
"en": "Agent has finished the task.",
"de": "Agent hat die Aufgabe erledigt.",

View File

@@ -83,7 +83,7 @@ export const useWSStatusChange = () => {
}
if (status === WsClientProviderStatus.DISCONNECTED) {
dispatch(setCurrentAgentState(AgentState.STOPPED));
dispatch(setCurrentAgentState(AgentState.DISCONNECTED));
}
}, [status]);
};

View File

@@ -11,10 +11,12 @@ export enum AgentState {
AWAITING_USER_CONFIRMATION = "awaiting_user_confirmation",
USER_CONFIRMED = "user_confirmed",
USER_REJECTED = "user_rejected",
DISCONNECTED = "disconnected",
}
export const RUNTIME_INACTIVE_STATES = [
AgentState.LOADING,
AgentState.STOPPED,
AgentState.ERROR,
AgentState.DISCONNECTED,
];