Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "Open session",
"Connected": "Connected",
"OpenAgain": "Open again",
"BackToForm": "Back to form"
"BackToForm": "Back to form",
"StartFaceVerify": "Start verification"
},
"ConnectionGuide": {
"TokenCommand": "Connect command (token)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "Abrir sesión",
"Connected": "Conectado",
"OpenAgain": "Abrir de nuevo",
"BackToForm": "Volver al formulario"
"BackToForm": "Volver al formulario",
"StartFaceVerify": "Iniciar verificación"
},
"ConnectionGuide": {
"TokenCommand": "Comando de conexión (token)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "セッションを開く",
"Connected": "接続完了",
"OpenAgain": "もう一度開く",
"BackToForm": "フォームに戻る"
"BackToForm": "フォームに戻る",
"StartFaceVerify": "認証を開始"
},
"ConnectionGuide": {
"TokenCommand": "接続コマンド(トークン)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "세션 열기",
"Connected": "연결됨",
"OpenAgain": "다시 열기",
"BackToForm": "연결 설정으로 돌아가기"
"BackToForm": "연결 설정으로 돌아가기",
"StartFaceVerify": "인증 시작"
},
"ConnectionGuide": {
"TokenCommand": "연결 명령 (토큰)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/pt_br.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "Abrir sessão",
"Connected": "Conectado",
"OpenAgain": "Abrir novamente",
"BackToForm": "Voltar ao formulário"
"BackToForm": "Voltar ao formulário",
"StartFaceVerify": "Iniciar verificação"
},
"ConnectionGuide": {
"TokenCommand": "Comando de conexão (token)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "Открытие сеанса",
"Connected": "Подключено",
"OpenAgain": "Открыть снова",
"BackToForm": "Вернуться к форме"
"BackToForm": "Вернуться к форме",
"StartFaceVerify": "Начать проверку"
},
"ConnectionGuide": {
"TokenCommand": "Команда подключения (токен)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "Mở phiên",
"Connected": "Đã kết nối",
"OpenAgain": "Mở lại",
"BackToForm": "Quay lại biểu mẫu"
"BackToForm": "Quay lại biểu mẫu",
"StartFaceVerify": "Bắt đầu xác minh"
},
"ConnectionGuide": {
"TokenCommand": "Lệnh kết nối (token)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "建立会话连接",
"Connected": "连接完成",
"OpenAgain": "再次打开",
"BackToForm": "返回修改"
"BackToForm": "返回修改",
"StartFaceVerify": "开始核验"
},
"ConnectionGuide": {
"TokenCommand": "连接命令(使用 Token)",
Expand Down
3 changes: 2 additions & 1 deletion i18n/locales/zh_hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,8 @@
"OpenSession": "建立工作階段連線",
"Connected": "連線完成",
"OpenAgain": "再次開啟",
"BackToForm": "返回修改"
"BackToForm": "返回修改",
"StartFaceVerify": "開始核驗"
},
"ConnectionGuide": {
"TokenCommand": "連線命令(使用 Token)",
Expand Down
37 changes: 31 additions & 6 deletions ui/chen/composables/useChenSession.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ function createSession() {
authenticate: async () => "token",
markConnected: vi.fn(),
markDisconnected: vi.fn(),
markFailed: vi.fn(),
onBeforeReady: async () => {},
onAfterReady: async () => {},
onDisconnected: vi.fn(),
Expand Down Expand Up @@ -49,7 +48,6 @@ describe("chen session dialogs", () => {
authenticate: async () => "token",
markConnected: vi.fn(),
markDisconnected: vi.fn(),
markFailed: vi.fn(),
onBeforeReady: async () => {},
onAfterReady: async () => {},
onDisconnected: vi.fn(),
Expand All @@ -66,7 +64,6 @@ describe("chen session dialogs", () => {

it("marks a ready session as disconnected when its socket closes", async () => {
const markDisconnected = vi.fn();
const markFailed = vi.fn();
const socket = {
readyState: 0,
onopen: null as ((event: Event) => void) | null,
Expand All @@ -80,7 +77,6 @@ describe("chen session dialogs", () => {
authenticate: async () => "token",
markConnected: vi.fn(),
markDisconnected,
markFailed,
onBeforeReady: async () => {},
onAfterReady: async () => {},
onDisconnected: vi.fn(),
Expand All @@ -97,7 +93,37 @@ describe("chen session dialogs", () => {
socket.onclose?.({ code: 1006, reason: "" } as CloseEvent);

expect(markDisconnected).toHaveBeenCalled();
expect(markFailed).not.toHaveBeenCalled();
});

it("marks a session as disconnected when its socket closes before ready", async () => {
const markDisconnected = vi.fn();
const socket = {
readyState: 0,
onopen: null as ((event: Event) => void) | null,
onmessage: null as ((event: MessageEvent) => void) | null,
onerror: null,
onclose: null as ((event: CloseEvent) => void) | null,
send: vi.fn(),
close: vi.fn()
};
const session = useChenSession({
authenticate: async () => "token",
markConnected: vi.fn(),
markDisconnected,
onBeforeReady: async () => {},
onAfterReady: async () => {},
onDisconnected: vi.fn(),
showMessage: vi.fn(),
resolveUrl: () => "ws://chen.test/ws/session",
createSocket: () => socket as unknown as WebSocket
});

await session.bootstrapSession();
socket.readyState = 1;
socket.onopen?.({} as Event);
socket.onclose?.({ code: 1006, reason: "" } as CloseEvent);

expect(markDisconnected).toHaveBeenCalled();
});

it("forwards MCP frames received before the main session is ready", async () => {
Expand All @@ -115,7 +141,6 @@ describe("chen session dialogs", () => {
authenticate: async () => "token",
markConnected: vi.fn(),
markDisconnected: vi.fn(),
markFailed: vi.fn(),
onBeforeReady: async () => {},
onAfterReady: async () => {},
onDisconnected: vi.fn(),
Expand Down
5 changes: 1 addition & 4 deletions ui/chen/composables/useChenSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ interface UseChenSessionOptions {
authenticate: () => Promise<string>;
markConnected: () => void;
markDisconnected: (reason: string) => void;
markFailed: (reason: string) => void;
onBeforeReady: () => Promise<void>;
onAfterReady: () => Promise<void>;
onDisconnected: () => void;
Expand Down Expand Up @@ -71,7 +70,6 @@ export function useChenSession(options: UseChenSessionOptions) {

function handleFatal(cause: unknown, reason = "") {
if (fatalNotified) return;
const wasReady = ready.value;
const message = normalizeError(cause);
fatalNotified = true;
bootstrapGeneration += 1;
Expand All @@ -80,8 +78,7 @@ export function useChenSession(options: UseChenSessionOptions) {
loading.value = false;
error.value = message;
errorReason.value = reason;
if (wasReady) options.markDisconnected(message);
else options.markFailed(message);
options.markDisconnected(message);

// A Chen session owns all of its consoles. Close dependent consoles first
// so their backend close handlers can still resolve the active session.
Expand Down
12 changes: 1 addition & 11 deletions ui/chen/workspaces/DatabaseSessionSurface.vue
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ const { t } = useI18n();
const { openAi } = useAiPanel();
const { addErrorToast } = useErrorToast();
const userInfoStore = useUserInfoStore();
const { markSessionConnected, markSessionDisconnected, markSessionFailed } = useWorkspaceTabs();
const { markSessionConnected, markSessionDisconnected } = useWorkspaceTabs();
const tabRef = toRef(props, "tab");
const endpointUrl = computed(() => {
const explicit = String(props.tab.payload?.endpointUrl || "").trim();
Expand Down Expand Up @@ -360,16 +360,6 @@ const session = useChenSession({
translate: t,
markConnected: () => markSessionConnected(props.tab.id),
markDisconnected: (reason) => markSessionDisconnected(props.tab.id, reason),
markFailed: (reason) =>
markSessionFailed(
{
tabId: props.tab.id,
assetId: props.tab.assetId,
protocol: props.tab.protocol,
account: props.tab.account
},
reason
),
onBeforeReady: async () => {
await auth.loadProfile();
await tree.loadNodeChildren(null);
Expand Down
Loading
Loading