Răsfoiți Sursa

chore(frontend): Remove old session class and some artifacts that are no longer needed (#4310)

sp.wack 1 an în urmă
părinte
comite
70bd710e82

+ 1 - 28
frontend/__tests__/components/chat/ChatInterface.test.tsx

@@ -1,10 +1,8 @@
 import { screen, act } from "@testing-library/react";
-import { afterEach, describe, expect, it, vi } from "vitest";
+import { describe, expect, it, vi } from "vitest";
 import userEvent from "@testing-library/user-event";
 import { renderWithProviders } from "test-utils";
 import { createMemoryRouter, RouterProvider } from "react-router-dom";
-import Session from "#/services/session";
-import ActionType from "#/types/ActionType";
 import { addAssistantMessage } from "#/state/chatSlice";
 import AgentState from "#/types/AgentState";
 import ChatInterface from "#/components/chat/ChatInterface";
@@ -34,9 +32,6 @@ HTMLElement.prototype.scrollTo = vi.fn().mockImplementation(() => {});
 const TEST_TIMESTAMP = new Date().toISOString();
 
 describe.skip("ChatInterface", () => {
-  const sessionSendSpy = vi.spyOn(Session, "send");
-  vi.spyOn(Session, "isConnected").mockReturnValue(true);
-
   // TODO: replace below with e.g. fake timers
   // https://vitest.dev/guide/mocking#timers
   // https://vitest.dev/api/vi.html#vi-usefaketimers
@@ -66,19 +61,6 @@ describe.skip("ChatInterface", () => {
     },
   });
 
-  const userMessageEvent = {
-    action: ActionType.MESSAGE,
-    args: {
-      content: "my message",
-      images_urls: [],
-      timestamp: TEST_TIMESTAMP,
-    },
-  };
-
-  afterEach(() => {
-    sessionSendSpy.mockClear();
-  });
-
   it("should render empty message list and input", () => {
     renderWithProviders(<ChatInterface />);
     expect(screen.queryAllByTestId("article")).toHaveLength(0);
@@ -125,10 +107,6 @@ describe.skip("ChatInterface", () => {
     const input = screen.getByRole("textbox");
     await user.type(input, "my message");
     await user.keyboard("{Enter}");
-
-    expect(sessionSendSpy).toHaveBeenCalledWith(
-      expect.toMatchMessageEvent(JSON.stringify(userMessageEvent)),
-    );
   });
 
   it("should send the user message as an event to the Session when the agent state is AWAITING_USER_INPUT", async () => {
@@ -144,10 +122,6 @@ describe.skip("ChatInterface", () => {
     const input = screen.getByRole("textbox");
     await user.type(input, "my message");
     await user.keyboard("{Enter}");
-
-    expect(sessionSendSpy).toHaveBeenCalledWith(
-      expect.toMatchMessageEvent(JSON.stringify(userMessageEvent)),
-    );
   });
 
   it("should disable the user input if agent is not initialized", async () => {
@@ -168,7 +142,6 @@ describe.skip("ChatInterface", () => {
     );
 
     expect(submitButton).toBeDisabled();
-    expect(sessionSendSpy).not.toHaveBeenCalled();
   });
 
   it.todo("test scroll-related behaviour");

+ 0 - 26
frontend/__tests__/components/chat/ConfirmationButtons.test.tsx

@@ -1,26 +0,0 @@
-import { describe, expect, it, vi } from "vitest";
-import { userEvent } from "@testing-library/user-event";
-import { render, screen } from "@testing-library/react";
-import AgentState from "#/types/AgentState";
-import { changeAgentState } from "#/services/agentStateService";
-import ConfirmationButtons from "#/components/chat/ConfirmationButtons";
-
-describe("ConfirmationButtons", () => {
-  vi.mock("#/services/agentStateService", () => ({
-    changeAgentState: vi.fn(),
-  }));
-
-  it.skip("should change agent state appropriately on button click", async () => {
-    const user = userEvent.setup();
-    render(<ConfirmationButtons />);
-
-    const confirmButton = screen.getByTestId("action-confirm-button");
-    const rejectButton = screen.getByTestId("action-reject-button");
-
-    await user.click(confirmButton);
-    expect(changeAgentState).toHaveBeenCalledWith(AgentState.USER_CONFIRMED);
-
-    await user.click(rejectButton);
-    expect(changeAgentState).toHaveBeenCalledWith(AgentState.USER_REJECTED);
-  });
-});

+ 0 - 82
frontend/__tests__/components/modals/settings/AutocompleteCombobox.test.tsx

@@ -1,82 +0,0 @@
-import { act, render, screen } from "@testing-library/react";
-import userEvent from "@testing-library/user-event";
-import { describe, expect, it, vi } from "vitest";
-import { AutocompleteCombobox } from "#/components/modals/settings/AutocompleteCombobox";
-
-const onChangeMock = vi.fn();
-
-const renderComponent = () =>
-  render(
-    <AutocompleteCombobox
-      ariaLabel="model"
-      items={[
-        { value: "m1", label: "model1" },
-        { value: "m2", label: "model2" },
-        { value: "m3", label: "model3" },
-      ]}
-      defaultKey="m1"
-      tooltip="tooltip"
-      onChange={onChangeMock}
-    />,
-  );
-
-describe("AutocompleteCombobox", () => {
-  it("should render a combobox with the default value", () => {
-    renderComponent();
-
-    const modelInput = screen.getByRole("combobox", { name: "model" });
-    expect(modelInput).toHaveValue("model1");
-  });
-
-  it("should open a dropdown with the available values", async () => {
-    renderComponent();
-
-    const modelInput = screen.getByRole("combobox", { name: "model" });
-
-    expect(screen.queryByText("model2")).not.toBeInTheDocument();
-    expect(screen.queryByText("model3")).not.toBeInTheDocument();
-
-    await act(async () => {
-      await userEvent.click(modelInput);
-    });
-
-    expect(screen.getByText("model2")).toBeInTheDocument();
-    expect(screen.getByText("model3")).toBeInTheDocument();
-  });
-
-  it("should call the onChange handler when a new value is selected", async () => {
-    renderComponent();
-
-    const modelInput = screen.getByRole("combobox", { name: "model" });
-    expect(modelInput).toHaveValue("model1");
-
-    await act(async () => {
-      await userEvent.click(modelInput);
-    });
-
-    const model2 = screen.getByText("model2");
-    await act(async () => {
-      await userEvent.click(model2);
-    });
-
-    expect(onChangeMock).toHaveBeenCalledWith("model2");
-  });
-
-  it("should set the input value to the default key if the default key is not in the list", () => {
-    render(
-      <AutocompleteCombobox
-        ariaLabel="model"
-        items={[{ value: "m1", label: "model1" }]}
-        defaultKey="m2"
-        tooltip="tooltip"
-        onChange={onChangeMock}
-      />,
-    );
-
-    const modelInput = screen.getByRole("combobox", { name: "model" });
-
-    expect(modelInput).toHaveValue("m2");
-  });
-
-  it.todo("should show a tooltip after 0.5 seconds of focus");
-});

+ 0 - 41
frontend/__tests__/services/session.test.ts

@@ -1,41 +0,0 @@
-import { afterEach, describe, expect, it, vi } from "vitest";
-import ActionType from "#/types/ActionType";
-import { Settings, saveSettings } from "../../src/services/settings";
-import Session from "../../src/services/session";
-
-const sendSpy = vi.spyOn(Session, "send");
-// @ts-expect-error - spying on private function
-const setupSpy = vi.spyOn(Session, "_setupSocket").mockImplementation(() => {
-  // @ts-expect-error - calling a private function
-  Session._initializeAgent();
-});
-
-describe("startNewSession", () => {
-  afterEach(() => {
-    sendSpy.mockClear();
-    setupSpy.mockClear();
-  });
-
-  it("Should start a new session with the current settings", () => {
-    const settings: Settings = {
-      LLM_MODEL: "llm_value",
-      LLM_BASE_URL: "base_url",
-      AGENT: "agent_value",
-      LANGUAGE: "language_value",
-      LLM_API_KEY: "sk-...",
-      CONFIRMATION_MODE: true,
-      SECURITY_ANALYZER: "analyzer",
-    };
-
-    const event = {
-      action: ActionType.INIT,
-      args: settings,
-    };
-
-    saveSettings(settings);
-    Session.startNewSession();
-
-    expect(setupSpy).toHaveBeenCalledTimes(1);
-    expect(sendSpy).toHaveBeenCalledWith(JSON.stringify(event));
-  });
-});

+ 0 - 81
frontend/src/components/modals/settings/AutocompleteCombobox.tsx

@@ -1,81 +0,0 @@
-import { Autocomplete, AutocompleteItem, Tooltip } from "@nextui-org/react";
-import React from "react";
-import { useTranslation } from "react-i18next";
-import { I18nKey } from "#/i18n/declaration";
-
-type Label = "model" | "agent" | "language" | "securityanalyzer";
-
-const LABELS: Record<Label, I18nKey> = {
-  model: I18nKey.CONFIGURATION$MODEL_SELECT_LABEL,
-  agent: I18nKey.CONFIGURATION$AGENT_SELECT_LABEL,
-  language: I18nKey.CONFIGURATION$LANGUAGE_SELECT_LABEL,
-  securityanalyzer: I18nKey.CONFIGURATION$SECURITY_SELECT_LABEL,
-};
-
-const PLACEHOLDERS: Record<Label, I18nKey> = {
-  model: I18nKey.CONFIGURATION$MODEL_SELECT_PLACEHOLDER,
-  agent: I18nKey.CONFIGURATION$AGENT_SELECT_PLACEHOLDER,
-  language: I18nKey.CONFIGURATION$LANGUAGE_SELECT_PLACEHOLDER,
-  securityanalyzer: I18nKey.CONFIGURATION$SECURITY_SELECT_PLACEHOLDER,
-};
-
-type AutocompleteItemType = {
-  value: string;
-  label: string;
-};
-
-interface AutocompleteComboboxProps {
-  ariaLabel: Label;
-  items: AutocompleteItemType[];
-  defaultKey: string;
-  onChange: (key: string) => void;
-  tooltip: string;
-  allowCustomValue?: boolean;
-  disabled?: boolean;
-}
-
-export function AutocompleteCombobox({
-  ariaLabel,
-  items,
-  defaultKey,
-  onChange,
-  tooltip,
-  allowCustomValue = false,
-  disabled = false,
-}: AutocompleteComboboxProps) {
-  const { t } = useTranslation();
-
-  return (
-    <Tooltip
-      content={
-        disabled
-          ? `${tooltip} ${t(I18nKey.SETTINGS$DISABLED_RUNNING)}`
-          : tooltip
-      }
-      closeDelay={100}
-      delay={500}
-    >
-      <Autocomplete
-        aria-label={ariaLabel}
-        label={t(LABELS[ariaLabel])}
-        placeholder={t(PLACEHOLDERS[ariaLabel])}
-        defaultItems={items}
-        defaultSelectedKey={defaultKey}
-        inputValue={
-          // Find the label for the default key, otherwise use the default key itself
-          // This is useful when the default key is not in the list of items, in the case of a custom LLM model
-          items.find((item) => item.value === defaultKey)?.label || defaultKey
-        }
-        onInputChange={(val) => {
-          onChange(val);
-        }}
-        isDisabled={disabled}
-        allowsCustomValue={allowCustomValue}
-      >
-        {(item) => (
-          <AutocompleteItem key={item.value}>{item.label}</AutocompleteItem>
-        )}
-      </Autocomplete>
-    </Tooltip>
-  );
-}

+ 0 - 184
frontend/src/components/modals/settings/SettingsForm.tsx

@@ -1,184 +0,0 @@
-import { Input, Switch, Tooltip, useDisclosure } from "@nextui-org/react";
-import React from "react";
-import { useTranslation } from "react-i18next";
-import { FaEye, FaEyeSlash } from "react-icons/fa";
-import { AvailableLanguages } from "../../../i18n";
-import { I18nKey } from "../../../i18n/declaration";
-import { AutocompleteCombobox } from "./AutocompleteCombobox";
-import { Settings } from "#/services/settings";
-import { organizeModelsAndProviders } from "#/utils/organizeModelsAndProviders";
-import { extractModelAndProvider } from "#/utils/extractModelAndProvider";
-import { ModelSelector } from "./ModelSelector";
-
-interface SettingsFormProps {
-  settings: Settings;
-  models: string[];
-  agents: string[];
-  securityAnalyzers: string[];
-  disabled: boolean;
-
-  onModelChange: (model: string) => void;
-  onBaseURLChange: (baseURL: string) => void;
-  onAPIKeyChange: (apiKey: string) => void;
-  onAgentChange: (agent: string) => void;
-  onLanguageChange: (language: string) => void;
-  onConfirmationModeChange: (confirmationMode: boolean) => void;
-  onSecurityAnalyzerChange: (securityAnalyzer: string) => void;
-}
-
-function SettingsForm({
-  settings,
-  models,
-  agents,
-  securityAnalyzers,
-  disabled,
-  onModelChange,
-  onBaseURLChange,
-  onAPIKeyChange,
-  onAgentChange,
-  onLanguageChange,
-  onConfirmationModeChange,
-  onSecurityAnalyzerChange,
-}: SettingsFormProps) {
-  const { t } = useTranslation();
-  const { isOpen: isVisible, onOpenChange: onVisibleChange } = useDisclosure();
-  const advancedAlreadyInUse = React.useMemo(() => {
-    const organizedModels = organizeModelsAndProviders(models);
-    const { provider, model } = extractModelAndProvider(
-      settings.LLM_MODEL || "",
-    );
-    const isKnownModel =
-      provider in organizedModels &&
-      organizedModels[provider].models.includes(model);
-
-    return (
-      !!settings.SECURITY_ANALYZER ||
-      !!settings.CONFIRMATION_MODE ||
-      !!settings.LLM_BASE_URL ||
-      (!!settings.LLM_MODEL && !isKnownModel)
-    );
-  }, [settings, models]);
-  const [enableAdvanced, setEnableAdvanced] =
-    React.useState(advancedAlreadyInUse);
-
-  React.useEffect(() => {
-    setEnableAdvanced(advancedAlreadyInUse);
-  }, [advancedAlreadyInUse]);
-
-  const handleAdvancedChange = (value: boolean) => {
-    setEnableAdvanced(value);
-  };
-
-  return (
-    <>
-      <Switch
-        data-testid="advanced-options-toggle"
-        aria-checked={enableAdvanced}
-        isSelected={enableAdvanced}
-        onValueChange={handleAdvancedChange}
-      >
-        Advanced Options
-      </Switch>
-      {enableAdvanced && (
-        <>
-          <Input
-            data-testid="custom-model-input"
-            label="Custom Model"
-            onValueChange={onModelChange}
-            defaultValue={settings.LLM_MODEL}
-          />
-          <Input
-            data-testid="base-url-input"
-            label="Base URL"
-            onValueChange={onBaseURLChange}
-            defaultValue={settings.LLM_BASE_URL}
-          />
-        </>
-      )}
-      {!enableAdvanced && (
-        <ModelSelector
-          isDisabled={disabled}
-          models={organizeModelsAndProviders(models)}
-          currentModel={settings.LLM_MODEL}
-        />
-      )}
-      <Input
-        label="API Key"
-        isDisabled={disabled}
-        aria-label="apikey"
-        data-testid="apikey"
-        placeholder={t(I18nKey.SETTINGS$API_KEY_PLACEHOLDER)}
-        type={isVisible ? "text" : "password"}
-        value={settings.LLM_API_KEY || ""}
-        onChange={(e) => {
-          onAPIKeyChange(e.target.value);
-        }}
-        endContent={
-          <button
-            className="focus:outline-none"
-            type="button"
-            onClick={onVisibleChange}
-          >
-            {isVisible ? (
-              <FaEye className="text-2xl text-default-400 pointer-events-none" />
-            ) : (
-              <FaEyeSlash className="text-2xl text-default-400 pointer-events-none" />
-            )}
-          </button>
-        }
-      />
-      <AutocompleteCombobox
-        ariaLabel="language"
-        items={AvailableLanguages}
-        defaultKey={settings.LANGUAGE}
-        onChange={onLanguageChange}
-        tooltip={t(I18nKey.SETTINGS$LANGUAGE_TOOLTIP)}
-        disabled={disabled}
-      />
-      {enableAdvanced && (
-        <AutocompleteCombobox
-          ariaLabel="agent"
-          items={agents.map((agent) => ({ value: agent, label: agent }))}
-          defaultKey={settings.AGENT}
-          onChange={onAgentChange}
-          tooltip={t(I18nKey.SETTINGS$AGENT_TOOLTIP)}
-        />
-      )}
-      {enableAdvanced && (
-        <AutocompleteCombobox
-          ariaLabel="securityanalyzer"
-          items={securityAnalyzers.map((securityAnalyzer) => ({
-            value: securityAnalyzer,
-            label: securityAnalyzer,
-          }))}
-          defaultKey={settings.SECURITY_ANALYZER}
-          onChange={onSecurityAnalyzerChange}
-          tooltip={t(I18nKey.SETTINGS$SECURITY_ANALYZER)}
-          disabled={disabled}
-        />
-      )}
-      {enableAdvanced && (
-        <Switch
-          aria-label="confirmationmode"
-          data-testid="confirmationmode"
-          defaultSelected={
-            settings.CONFIRMATION_MODE || !!settings.SECURITY_ANALYZER
-          }
-          onValueChange={onConfirmationModeChange}
-          isDisabled={disabled || !!settings.SECURITY_ANALYZER}
-          isSelected={settings.CONFIRMATION_MODE}
-        >
-          <Tooltip
-            content={t(I18nKey.SETTINGS$CONFIRMATION_MODE_TOOLTIP)}
-            closeDelay={100}
-            delay={500}
-          >
-            {t(I18nKey.SETTINGS$CONFIRMATION_MODE)}
-          </Tooltip>
-        </Switch>
-      )}
-    </>
-  );
-}
-
-export default SettingsForm;

+ 0 - 202
frontend/src/components/modals/settings/SettingsModal.tsx

@@ -1,202 +0,0 @@
-import { Spinner } from "@nextui-org/react";
-import i18next from "i18next";
-import React, { useEffect } from "react";
-import { useTranslation } from "react-i18next";
-import { useSelector } from "react-redux";
-import { fetchSecurityAnalyzers } from "#/services/options";
-import { AvailableLanguages } from "#/i18n";
-import { I18nKey } from "#/i18n/declaration";
-import Session from "#/services/session";
-import { RootState } from "../../../store";
-import AgentState from "../../../types/AgentState";
-import {
-  Settings,
-  getSettings,
-  getDefaultSettings,
-  settingsAreUpToDate,
-  maybeMigrateSettings,
-  saveSettings,
-} from "#/services/settings";
-import toast from "#/utils/toast";
-import BaseModal from "../base-modal/BaseModal";
-import SettingsForm from "./SettingsForm";
-
-interface SettingsProps {
-  isOpen: boolean;
-  onOpenChange: (isOpen: boolean) => void;
-  models: string[];
-  agents: string[];
-}
-
-const REQUIRED_SETTINGS = ["LLM_MODEL"];
-
-function SettingsModal({
-  isOpen,
-  onOpenChange,
-  models,
-  agents,
-}: SettingsProps) {
-  const { t } = useTranslation();
-
-  const [securityAnalyzers, setSecurityAnalyzers] = React.useState<string[]>(
-    [],
-  );
-  const [settings, setSettings] = React.useState<Settings>({} as Settings);
-  const [agentIsRunning, setAgentIsRunning] = React.useState<boolean>(false);
-  const [loading, setLoading] = React.useState(true);
-  const { curAgentState } = useSelector((state: RootState) => state.agent);
-
-  useEffect(() => {
-    maybeMigrateSettings();
-    setSettings(getSettings());
-  }, []);
-
-  useEffect(() => {
-    const isRunning =
-      curAgentState === AgentState.RUNNING ||
-      curAgentState === AgentState.PAUSED ||
-      curAgentState === AgentState.AWAITING_USER_INPUT ||
-      curAgentState === AgentState.AWAITING_USER_CONFIRMATION;
-    setAgentIsRunning(isRunning);
-  }, [curAgentState]);
-
-  React.useEffect(() => {
-    (async () => {
-      try {
-        setSecurityAnalyzers(await fetchSecurityAnalyzers());
-      } catch (error) {
-        toast.error("settings", t(I18nKey.CONFIGURATION$ERROR_FETCH_MODELS));
-      } finally {
-        setLoading(false);
-      }
-    })();
-  }, []);
-
-  const handleModelChange = (model: string) => {
-    setSettings((prev) => ({
-      ...prev,
-      LLM_MODEL: model,
-    }));
-  };
-
-  const handleBaseURLChange = (baseURL: string) => {
-    setSettings((prev) => ({
-      ...prev,
-      LLM_BASE_URL: baseURL,
-    }));
-  };
-
-  const handleAgentChange = (agent: string) => {
-    setSettings((prev) => ({ ...prev, AGENT: agent }));
-  };
-
-  const handleLanguageChange = (language: string) => {
-    const key =
-      AvailableLanguages.find((lang) => lang.label === language)?.value ||
-      language;
-    // The appropriate key is assigned when the user selects a language.
-    // Otherwise, their input is reflected in the inputValue field of the Autocomplete component.
-    setSettings((prev) => ({ ...prev, LANGUAGE: key }));
-  };
-
-  const handleAPIKeyChange = (key: string) => {
-    setSettings((prev) => ({ ...prev, LLM_API_KEY: key }));
-  };
-
-  const handleConfirmationModeChange = (confirmationMode: boolean) => {
-    setSettings((prev) => ({ ...prev, CONFIRMATION_MODE: confirmationMode }));
-  };
-
-  const handleSecurityAnalyzerChange = (securityAnalyzer: string) => {
-    setSettings((prev) => ({
-      ...prev,
-      CONFIRMATION_MODE: true,
-      SECURITY_ANALYZER: securityAnalyzer,
-    }));
-  };
-
-  const handleResetSettings = () => {
-    setSettings(getDefaultSettings);
-  };
-
-  const handleSaveSettings = () => {
-    saveSettings(settings);
-    i18next.changeLanguage(settings.LANGUAGE);
-    Session.startNewSession();
-
-    localStorage.setItem(
-      `API_KEY_${settings.LLM_MODEL || models[0]}`,
-      settings.LLM_API_KEY,
-    );
-  };
-
-  let subtitle = "";
-  if (loading) {
-    subtitle = t(I18nKey.CONFIGURATION$AGENT_LOADING);
-  } else if (agentIsRunning) {
-    subtitle = t(I18nKey.CONFIGURATION$AGENT_RUNNING);
-  } else if (!settingsAreUpToDate()) {
-    subtitle = t(I18nKey.CONFIGURATION$SETTINGS_NEED_UPDATE_MESSAGE);
-  }
-  const saveIsDisabled = REQUIRED_SETTINGS.some(
-    (key) => !settings[key as keyof Settings],
-  );
-
-  return (
-    <BaseModal
-      isOpen={isOpen}
-      onOpenChange={onOpenChange}
-      title={t(I18nKey.CONFIGURATION$MODAL_TITLE)}
-      isDismissable={settingsAreUpToDate()}
-      subtitle={subtitle}
-      actions={
-        loading
-          ? []
-          : [
-              {
-                label: t(I18nKey.CONFIGURATION$MODAL_SAVE_BUTTON_LABEL),
-                action: handleSaveSettings,
-                isDisabled: saveIsDisabled,
-                closeAfterAction: true,
-                className: "bg-primary rounded-lg",
-              },
-              {
-                label: t(I18nKey.CONFIGURATION$MODAL_RESET_BUTTON_LABEL),
-                action: handleResetSettings,
-                closeAfterAction: false,
-                className: "bg-neutral-500 rounded-lg",
-              },
-              {
-                label: t(I18nKey.CONFIGURATION$MODAL_CLOSE_BUTTON_LABEL),
-                action: () => {
-                  setSettings(getSettings()); // reset settings from any changes
-                },
-                isDisabled: !settingsAreUpToDate(),
-                closeAfterAction: true,
-                className: "bg-rose-600 rounded-lg",
-              },
-            ]
-      }
-    >
-      {loading && <Spinner />}
-      {!loading && (
-        <SettingsForm
-          disabled={agentIsRunning}
-          settings={settings}
-          models={models}
-          agents={agents}
-          securityAnalyzers={securityAnalyzers}
-          onModelChange={handleModelChange}
-          onBaseURLChange={handleBaseURLChange}
-          onAgentChange={handleAgentChange}
-          onLanguageChange={handleLanguageChange}
-          onAPIKeyChange={handleAPIKeyChange}
-          onConfirmationModeChange={handleConfirmationModeChange}
-          onSecurityAnalyzerChange={handleSecurityAnalyzerChange}
-        />
-      )}
-    </BaseModal>
-  );
-}
-
-export default SettingsModal;

+ 0 - 13
frontend/src/services/agentStateService.ts

@@ -1,21 +1,8 @@
 import ActionType from "#/types/ActionType";
 import AgentState from "#/types/AgentState";
-import Session from "./session";
-
-const INIT_DELAY = 1000;
 
 export const generateAgentStateChangeEvent = (state: AgentState) =>
   JSON.stringify({
     action: ActionType.CHANGE_AGENT_STATE,
     args: { agent_state: state },
   });
-
-export function changeAgentState(state: AgentState): void {
-  const eventString = generateAgentStateChangeEvent(state);
-  Session.send(eventString);
-  if (state === AgentState.STOPPED) {
-    setTimeout(() => {
-      Session.startNewSession();
-    }, INIT_DELAY);
-  }
-}

+ 0 - 221
frontend/src/services/session.ts

@@ -1,221 +0,0 @@
-import i18next from "i18next";
-import toast from "#/utils/toast";
-import { handleAssistantMessage } from "./actions";
-import { getToken, setToken, clearToken } from "./auth";
-import ActionType from "#/types/ActionType";
-import { getSettings } from "./settings";
-import { I18nKey } from "#/i18n/declaration";
-
-const translate = (key: I18nKey) => i18next.t(key);
-
-// Define a type for the messages
-type Message = {
-  action: ActionType;
-  args: Record<string, unknown>;
-};
-
-class Session {
-  private static _socket: WebSocket | null = null;
-
-  private static _latest_event_id: number = -1;
-
-  private static _messageQueue: Message[] = [];
-
-  public static _history: Record<string, unknown>[] = [];
-
-  // callbacks contain a list of callable functions
-  // event: function, like:
-  // open: [function1, function2]
-  // message: [function1, function2]
-  private static callbacks: {
-    [K in keyof WebSocketEventMap]: ((data: WebSocketEventMap[K]) => void)[];
-  } = {
-    open: [],
-    message: [],
-    error: [],
-    close: [],
-  };
-
-  private static _connecting = false;
-
-  private static _disconnecting = false;
-
-  public static restoreOrStartNewSession() {
-    if (Session.isConnected()) {
-      Session.disconnect();
-    }
-    Session._connect();
-  }
-
-  public static startNewSession() {
-    clearToken();
-    Session.restoreOrStartNewSession();
-  }
-
-  private static _initializeAgent = () => {
-    const settings = getSettings();
-    const event = {
-      action: ActionType.INIT,
-      args: {
-        ...settings,
-      },
-    };
-    const eventString = JSON.stringify(event);
-    Session.send(eventString);
-  };
-
-  private static _connect(): void {
-    if (Session.isConnected()) return;
-    Session._connecting = true;
-
-    const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
-    let wsURL = `${protocol}//${window.location.host}/ws`;
-    const token = getToken();
-    if (token) {
-      wsURL += `?token=${token}`;
-      if (Session._latest_event_id !== -1) {
-        wsURL += `&latest_event_id=${Session._latest_event_id}`;
-      }
-    }
-    Session._socket = new WebSocket(wsURL);
-    Session._setupSocket();
-  }
-
-  private static _setupSocket(): void {
-    if (!Session._socket) {
-      throw new Error(
-        translate(I18nKey.SESSION$SOCKET_NOT_INITIALIZED_ERROR_MESSAGE),
-      );
-    }
-    Session._socket.onopen = (e) => {
-      toast.success("ws", translate(I18nKey.SESSION$SERVER_CONNECTED_MESSAGE));
-      Session._connecting = false;
-      Session._initializeAgent();
-      Session._flushQueue();
-      Session.callbacks.open?.forEach((callback) => {
-        callback(e);
-      });
-    };
-
-    Session._socket.onmessage = (e) => {
-      let data = null;
-      try {
-        data = JSON.parse(e.data);
-        Session._history.push(data);
-      } catch (err) {
-        toast.error(
-          "ws",
-          translate(I18nKey.SESSION$SESSION_HANDLING_ERROR_MESSAGE),
-        );
-        return;
-      }
-      if (data.error && data.error_code === 401) {
-        Session._latest_event_id = -1;
-        clearToken();
-      } else if (data.token) {
-        setToken(data.token);
-      } else {
-        if (data.id !== undefined) {
-          Session._latest_event_id = data.id;
-        }
-        handleAssistantMessage(data);
-      }
-    };
-
-    Session._socket.onerror = () => {
-      // TODO report error
-      toast.error(
-        "ws",
-        translate(I18nKey.SESSION$SESSION_CONNECTION_ERROR_MESSAGE),
-      );
-    };
-
-    Session._socket.onclose = () => {
-      if (!Session._disconnecting) {
-        setTimeout(() => {
-          Session.restoreOrStartNewSession();
-        }, 3000); // Reconnect after 3 seconds
-      }
-      Session._disconnecting = false;
-    };
-  }
-
-  static isConnected(): boolean {
-    return (
-      Session._socket !== null && Session._socket.readyState === WebSocket.OPEN
-    );
-  }
-
-  static disconnect(): void {
-    Session._disconnecting = true;
-    if (Session._socket) {
-      Session._socket.close();
-    }
-    Session._socket = null;
-  }
-
-  private static _flushQueue(): void {
-    while (Session._messageQueue.length > 0) {
-      const message = Session._messageQueue.shift();
-      if (message) {
-        setTimeout(() => Session.send(JSON.stringify(message)), 1000);
-      }
-    }
-  }
-
-  static send(message: string): void {
-    const messageObject: Message = JSON.parse(message);
-
-    if (Session._connecting) {
-      Session._messageQueue.push(messageObject);
-      return;
-    }
-    if (!Session.isConnected()) {
-      throw new Error(
-        translate(I18nKey.SESSION$SESSION_CONNECTION_ERROR_MESSAGE),
-      );
-    }
-
-    if (Session.isConnected()) {
-      Session._socket?.send(message);
-      Session._history.push(JSON.parse(message));
-    } else {
-      toast.error(
-        "ws",
-        translate(I18nKey.SESSION$SESSION_CONNECTION_ERROR_MESSAGE),
-      );
-    }
-  }
-
-  static addEventListener(
-    event: string,
-    callback: (e: MessageEvent) => void,
-  ): void {
-    Session._socket?.addEventListener(
-      event as keyof WebSocketEventMap,
-      callback as (
-        this: WebSocket,
-        ev: WebSocketEventMap[keyof WebSocketEventMap],
-      ) => never,
-    );
-  }
-
-  static removeEventListener(
-    event: string,
-    listener: (e: Event) => void,
-  ): void {
-    Session._socket?.removeEventListener(event, listener);
-  }
-
-  static registerCallback<K extends keyof WebSocketEventMap>(
-    event: K,
-    callbacks: ((data: WebSocketEventMap[K]) => void)[],
-  ): void {
-    if (Session.callbacks[event] === undefined) {
-      return;
-    }
-    Session.callbacks[event].push(...callbacks);
-  }
-}
-
-export default Session;