From 75ed573f11276327c1532b2b4429af125d921969 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sat, 12 Sep 2026 12:20:52 +0200 Subject: [PATCH] fix(app): show actionable chat search failures Keep transport error details in the search model while showing localized retry guidance. Use named client request options for timeline search. --- packages/app/e2e/browser/chat-find.spec.ts | 5 +++++ .../app/src/agent-stream/chat-find/index.web.tsx | 4 ++-- packages/app/src/i18n/resources/ar.ts | 1 + packages/app/src/i18n/resources/en.ts | 1 + packages/app/src/i18n/resources/es.ts | 2 ++ packages/app/src/i18n/resources/fr.ts | 2 ++ packages/app/src/i18n/resources/ja.ts | 2 ++ packages/app/src/i18n/resources/ko.ts | 1 + packages/app/src/i18n/resources/pt-BR.ts | 2 ++ packages/app/src/i18n/resources/ru.ts | 2 ++ packages/app/src/i18n/resources/zh-CN.ts | 1 + packages/client/src/daemon-client.ts | 16 +++++++++++----- 12 files changed, 32 insertions(+), 7 deletions(-) diff --git a/packages/app/e2e/browser/chat-find.spec.ts b/packages/app/e2e/browser/chat-find.spec.ts index 0a01da4a00..5d94b5166a 100644 --- a/packages/app/e2e/browser/chat-find.spec.ts +++ b/packages/app/e2e/browser/chat-find.spec.ts @@ -163,6 +163,11 @@ test("shows a disconnected search failure and recovers with Retry", async ({ pag await expectReconnectingToastVisible(page); await searchChat(page, "hello world"); await expect(status(page)).toHaveText("Failed"); + await expect( + page.getByText("Could not search this chat. Check the host connection and retry.", { + exact: true, + }), + ).toBeVisible(); await expect(page.getByRole("button", { name: "Retry", exact: true })).toBeVisible(); gate.restore(); await expectReconnectingToastGone(page); diff --git a/packages/app/src/agent-stream/chat-find/index.web.tsx b/packages/app/src/agent-stream/chat-find/index.web.tsx index ea971d4cb0..ca9f7537b1 100644 --- a/packages/app/src/agent-stream/chat-find/index.web.tsx +++ b/packages/app/src/agent-stream/chat-find/index.web.tsx @@ -62,7 +62,7 @@ export function ChatFind({ search(query, cursor) { const client = getHostRuntimeStore().getClient(serverId); if (!client) return Promise.reject(new Error("Host disconnected")); - return client.searchAgentTimeline(agentId, query, cursor); + return client.searchAgentTimeline({ agentId, query, cursor }); }, load(targetEpoch, seq) { return getHostRuntimeStore().fetchAgentTimeline( @@ -136,7 +136,7 @@ export function ChatFind({ /> {state.error && ( - {state.error} + {t("paneFind.searchFailed")} diff --git a/packages/app/src/i18n/resources/ar.ts b/packages/app/src/i18n/resources/ar.ts index b40c4ad9a7..e90f4264ef 100644 --- a/packages/app/src/i18n/resources/ar.ts +++ b/packages/app/src/i18n/resources/ar.ts @@ -3,6 +3,7 @@ import { pluginSettings } from "./plugin-settings"; export const ar: TranslationResources = { paneFind: { + searchFailed: "تعذر البحث في هذه المحادثة. تحقق من الاتصال بالمضيف وأعد المحاولة.", searching: "جارٍ البحث…", loading: "جارٍ التحميل…", failed: "فشل", diff --git a/packages/app/src/i18n/resources/en.ts b/packages/app/src/i18n/resources/en.ts index 3488151428..42aee2127e 100644 --- a/packages/app/src/i18n/resources/en.ts +++ b/packages/app/src/i18n/resources/en.ts @@ -1,5 +1,6 @@ export const en = { paneFind: { + searchFailed: "Could not search this chat. Check the host connection and retry.", searching: "Searching…", loading: "Loading…", failed: "Failed", diff --git a/packages/app/src/i18n/resources/es.ts b/packages/app/src/i18n/resources/es.ts index 6f18669c9c..153c0e2340 100644 --- a/packages/app/src/i18n/resources/es.ts +++ b/packages/app/src/i18n/resources/es.ts @@ -3,6 +3,8 @@ import { pluginSettings } from "./plugin-settings"; export const es: TranslationResources = { paneFind: { + searchFailed: + "No se pudo buscar en este chat. Comprueba la conexión con el host y vuelve a intentarlo.", searching: "Buscando…", loading: "Cargando…", failed: "Error", diff --git a/packages/app/src/i18n/resources/fr.ts b/packages/app/src/i18n/resources/fr.ts index d89bc21896..98b25c1a86 100644 --- a/packages/app/src/i18n/resources/fr.ts +++ b/packages/app/src/i18n/resources/fr.ts @@ -3,6 +3,8 @@ import { pluginSettings } from "./plugin-settings"; export const fr: TranslationResources = { paneFind: { + searchFailed: + "Impossible de rechercher dans cette conversation. Vérifiez la connexion à l’hôte et réessayez.", searching: "Recherche…", loading: "Chargement…", failed: "Échec", diff --git a/packages/app/src/i18n/resources/ja.ts b/packages/app/src/i18n/resources/ja.ts index 264a5062ab..39bc61a1bb 100644 --- a/packages/app/src/i18n/resources/ja.ts +++ b/packages/app/src/i18n/resources/ja.ts @@ -3,6 +3,8 @@ import { pluginSettings } from "./plugin-settings"; export const ja: TranslationResources = { paneFind: { + searchFailed: + "このチャットを検索できませんでした。ホストへの接続を確認して再試行してください。", searching: "検索中…", loading: "読み込み中…", failed: "失敗", diff --git a/packages/app/src/i18n/resources/ko.ts b/packages/app/src/i18n/resources/ko.ts index d4dd6ae26f..eeb555b654 100644 --- a/packages/app/src/i18n/resources/ko.ts +++ b/packages/app/src/i18n/resources/ko.ts @@ -3,6 +3,7 @@ import { pluginSettings } from "./plugin-settings"; export const ko: TranslationResources = { paneFind: { + searchFailed: "이 채팅을 검색할 수 없습니다. 호스트 연결을 확인하고 다시 시도하세요.", searching: "검색 중…", loading: "불러오는 중…", failed: "실패", diff --git a/packages/app/src/i18n/resources/pt-BR.ts b/packages/app/src/i18n/resources/pt-BR.ts index 3bdce006a7..84e732668d 100644 --- a/packages/app/src/i18n/resources/pt-BR.ts +++ b/packages/app/src/i18n/resources/pt-BR.ts @@ -3,6 +3,8 @@ import { pluginSettings } from "./plugin-settings"; export const ptBR: TranslationResources = { paneFind: { + searchFailed: + "Não foi possível pesquisar nesta conversa. Verifique a conexão com o host e tente novamente.", searching: "Buscando…", loading: "Carregando…", failed: "Falhou", diff --git a/packages/app/src/i18n/resources/ru.ts b/packages/app/src/i18n/resources/ru.ts index dd68360f89..6e4d385fae 100644 --- a/packages/app/src/i18n/resources/ru.ts +++ b/packages/app/src/i18n/resources/ru.ts @@ -3,6 +3,8 @@ import { pluginSettings } from "./plugin-settings"; export const ru: TranslationResources = { paneFind: { + searchFailed: + "Не удалось выполнить поиск в чате. Проверьте подключение к хосту и повторите попытку.", searching: "Поиск…", loading: "Загрузка…", failed: "Ошибка", diff --git a/packages/app/src/i18n/resources/zh-CN.ts b/packages/app/src/i18n/resources/zh-CN.ts index ef2c9a5c10..1717506d97 100644 --- a/packages/app/src/i18n/resources/zh-CN.ts +++ b/packages/app/src/i18n/resources/zh-CN.ts @@ -3,6 +3,7 @@ import { pluginSettings } from "./plugin-settings"; export const zhCN: TranslationResources = { paneFind: { + searchFailed: "无法搜索此聊天。请检查主机连接后重试。", searching: "搜索中…", loading: "加载中…", failed: "失败", diff --git a/packages/client/src/daemon-client.ts b/packages/client/src/daemon-client.ts index e71951a007..14341f7605 100644 --- a/packages/client/src/daemon-client.ts +++ b/packages/client/src/daemon-client.ts @@ -576,6 +576,12 @@ export interface FetchAgentTimelineOptions { timeout?: number; } +export interface AgentTimelineSearchOptions { + agentId: string; + query: string; + cursor?: number; +} + export type AgentTimelineSearchPayload = Extract< SessionOutboundMessage, { type: "agent.timeline.search.response" } @@ -2973,11 +2979,11 @@ export class DaemonClient { return { seq: payload.seq, epoch: payload.epoch }; } - async searchAgentTimeline( - agentId: string, - query: string, - cursor?: number, - ): Promise { + async searchAgentTimeline({ + agentId, + query, + cursor, + }: AgentTimelineSearchOptions): Promise { const requestId = this.createRequestId(); const payload = await this.sendCorrelatedSessionRequest({ requestId,