Skip to content
Open
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
2 changes: 2 additions & 0 deletions .claude/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Quick reference for anyone starting with Claude on this project. Updated by the

## Fixes & Gotchas

- **Who persists a chat reply (issue #6034)** — the core writes an unsegmented reply to the conversation store under `agent:<request_id>` **before** it publishes `chat_done` (`web_chat::presentation::deliver_response` → `web_chat::reply_persistence`), and the frontend's `addInferenceResponse` reuses that id so the store's idempotency collapses the two writes onto one row. Before this the frontend was the *only* persister of an interactive reply, so a failed `threads_message_append`, a socket reconnect (which issues a new `client_id`, leaving only the `thread:<id>` room as a route) or a webview reload lost the answer from screen and disk while the agent's session history still held it. Two rules follow: any new `chat_done` append site must pass `deliveredReplyMessageId(event)` or the thread gets two copies of one answer (#5933 again), and a **segmented** delivery is the exception — the client owns one row per segment there, so the core stores nothing and the ids stay generated.
- **`deliver_response` does not segment any more** — `presentation.rs` sets `let segments = [full_response.to_string()]` unconditionally, so the multi-segment branch (and every `chat_segment` event) is dead on the interactive path; the segmentation helpers survive for channel callers and tests. Read that binding before reasoning about `segment_total`, which is never set in practice today.
- **macOS close button does not dismiss window (issue #2049)** — `WebviewWindow::hide()` routes through CEF's `WindowMessage::Hide` → `cef::Window::hide()` which does NOT propagate to the visible NSWindow frame. Fix: use `AppHandle::hide()` which calls `[NSApp hide:]` via `set_application_visibility(false)`. This is macOS-only (`#[cfg(target_os = "macos")]`); the `CloseRequested` handlers are in `app/src-tauri/src/lib.rs` (grep `WindowEvent::CloseRequested` — line numbers drift). PR #2118.
- **ServiceBlockingGate CORS errors** — The gate calls `openhumanServiceStatus()` and `openhumanAgentServerStatus()` at startup. These used `callCoreRpc()` which falls back to raw `fetch()` when socket isn't connected yet, causing CORS errors. Fix: route through `invoke('core_rpc_relay')` instead (Tauri IPC, no CORS).
- **Socket not connected at startup** — `SocketProvider` only connects when a Redux `auth.token` is set. At fresh launch (no token), socket is null, so any `callCoreRpc()` call falls back to `fetch()`. Always use `invoke('core_rpc_relay')` for local sidecar RPC calls.
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/ar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6404,6 +6404,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'النموذج المحلي غير متاح',
'userErrors.localModelUnavailable.body':
'لا يمكن الوصول إلى Ollama على النقطة الطرفية المُهيأة، أو أن النموذج المطلوب غير مثبّت عليها. شغّل Ollama ونزّل النموذج على تلك النقطة الطرفية، أو حوّل هذا العمل إلى مزوّد سحابي.',
'userErrors.replyDeliveryFailed.title': 'تعذّر عرض الرد',
'userErrors.replyDeliveryFailed.body':
'أنهى الوكيل هذه الجولة، لكن تعذّر حفظ ردّه أو قراءته مجددًا. اطلب منه تكرار الرد.',
'userErrors.memoryStoreCorrupt.title': 'تلف فهرس الذاكرة',
'userErrors.memoryStoreCorrupt.body':
'كانت قاعدة بيانات شجرة الذاكرة تالفة. تم الاحتفاظ بالملف التالف بجوار بيانات الذاكرة وأعيد إنشاء فهرس فارغ. أعد مزامنة مصادر الذاكرة لإعادة تعبئته.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/bn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6554,6 +6554,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'লোকাল মডেল অনুপলব্ধ',
'userErrors.localModelUnavailable.body':
'কনফিগার করা এন্ডপয়েন্টে Ollama-তে পৌঁছানো যাচ্ছে না, অথবা সেখানে প্রয়োজনীয় মডেলটি ইনস্টল করা নেই। Ollama চালু করে সেই এন্ডপয়েন্টে মডেলটি পুল করুন, অথবা এই কাজটি কোনো ক্লাউড প্রোভাইডারে সরিয়ে নিন।',
'userErrors.replyDeliveryFailed.title': 'উত্তরটি দেখানো যায়নি',
'userErrors.replyDeliveryFailed.body':
'এজেন্ট এই দফাটি শেষ করেছে, কিন্তু তার উত্তর সংরক্ষণ বা পুনরায় পড়া যায়নি। আবার জিজ্ঞাসা করলে সে উত্তরটি আবার দেবে।',
'userErrors.memoryStoreCorrupt.title': 'মেমোরি ইনডেক্স নষ্ট হয়ে গেছে',
'userErrors.memoryStoreCorrupt.body':
'আপনার মেমোরি ট্রির ডেটাবেস নষ্ট হয়ে গিয়েছিল। নষ্ট ফাইলটি মেমোরি ডেটার পাশে সংরক্ষিত আছে এবং একটি খালি ইনডেক্স নতুন করে তৈরি হয়েছে। আবার পূরণ করতে মেমোরি উৎসগুলি পুনরায় সিঙ্ক করুন।',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6739,6 +6739,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Lokales Modell nicht verfügbar',
'userErrors.localModelUnavailable.body':
'Ollama ist unter dem konfigurierten Endpunkt nicht erreichbar, oder das benötigte Modell ist dort nicht installiert. Starte Ollama und lade das Modell auf diesem Endpunkt, oder verlagere diese Arbeit auf einen Cloud-Anbieter.',
'userErrors.replyDeliveryFailed.title': 'Antwort konnte nicht angezeigt werden',
'userErrors.replyDeliveryFailed.body':
'Der Agent hat diese Runde beendet, seine Antwort ließ sich aber weder speichern noch erneut lesen. Frag noch einmal, damit er sie wiederholt.',
'userErrors.memoryStoreCorrupt.title': 'Gedächtnisindex war beschädigt',
'userErrors.memoryStoreCorrupt.body':
'Die Datenbank des Gedächtnisbaums war beschädigt. Die beschädigte Datei wurde neben deinen Gedächtnisdaten aufbewahrt und ein leerer Index neu aufgebaut. Synchronisiere deine Gedächtnisquellen erneut, um ihn wieder zu füllen.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7069,6 +7069,9 @@ const en: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Local model unavailable',
'userErrors.localModelUnavailable.body':
'Ollama is not reachable at the configured endpoint, or the required model is not installed there. Start Ollama and pull the model at that endpoint, or switch this workload to a cloud provider.',
'userErrors.replyDeliveryFailed.title': 'Reply could not be shown',
'userErrors.replyDeliveryFailed.body':
'The agent finished this turn, but its reply could not be saved or read back. Ask again to have it repeated.',
'userErrors.memoryStoreCorrupt.title': 'Memory index was corrupted',
'userErrors.memoryStoreCorrupt.body':
'The database behind your memory tree was damaged. The damaged file was preserved next to your memory data, and an empty index was rebuilt. Re-sync your memory sources to fill it again.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6698,6 +6698,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Modelo local no disponible',
'userErrors.localModelUnavailable.body':
'No se puede acceder a Ollama en el punto de conexión configurado, o el modelo necesario no está instalado allí. Inicia Ollama y descarga el modelo en ese punto de conexión, o cambia este trabajo a un proveedor en la nube.',
'userErrors.replyDeliveryFailed.title': 'No se pudo mostrar la respuesta',
'userErrors.replyDeliveryFailed.body':
'El agente terminó este turno, pero su respuesta no se pudo guardar ni volver a leer. Vuelve a preguntar para que la repita.',
'userErrors.memoryStoreCorrupt.title': 'El índice de memoria se dañó',
'userErrors.memoryStoreCorrupt.body':
'La base de datos del árbol de memoria estaba dañada. El archivo dañado se conservó junto a tus datos de memoria y se reconstruyó un índice vacío. Vuelve a sincronizar tus fuentes de memoria para rellenarlo.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6726,6 +6726,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.body':
"Ollama n'est pas joignable sur le point de terminaison configuré, ou le modèle requis n'y est pas installé. Lancez Ollama et téléchargez le modèle sur ce point de terminaison, ou basculez cette charge de travail vers un fournisseur cloud.",
'userErrors.scope.chat': 'Chat',
'userErrors.replyDeliveryFailed.title': 'Impossible d’afficher la réponse',
'userErrors.replyDeliveryFailed.body':
'L’agent a terminé ce tour, mais sa réponse n’a pas pu être enregistrée ni récupérée. Redemande-lui de la répéter.',
'userErrors.memoryStoreCorrupt.title': 'L’index mémoire a été corrompu',
'userErrors.memoryStoreCorrupt.body':
'La base de données de l’arbre mémoire était endommagée. Le fichier endommagé a été conservé à côté de vos données mémoire et un index vide a été reconstruit. Resynchronisez vos sources mémoire pour le remplir à nouveau.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/hi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6554,6 +6554,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'लोकल मॉडल उपलब्ध नहीं है',
'userErrors.localModelUnavailable.body':
'कॉन्फ़िगर किए गए एंडपॉइंट पर Ollama तक पहुँच नहीं है, या ज़रूरी मॉडल वहाँ इंस्टॉल नहीं है। Ollama शुरू करके उसी एंडपॉइंट पर मॉडल पुल करें, या इस काम को किसी क्लाउड प्रोवाइडर पर ले जाएँ।',
'userErrors.replyDeliveryFailed.title': 'उत्तर दिखाया नहीं जा सका',
'userErrors.replyDeliveryFailed.body':
'एजेंट ने यह बारी पूरी कर ली, लेकिन उसका उत्तर न सहेजा जा सका और न दोबारा पढ़ा जा सका। दोबारा पूछें ताकि वह उत्तर फिर से दे।',
'userErrors.memoryStoreCorrupt.title': 'मेमोरी इंडेक्स खराब हो गया',
'userErrors.memoryStoreCorrupt.body':
'आपकी मेमोरी ट्री का डेटाबेस खराब हो गया था। खराब फाइल आपके मेमोरी डेटा के पास सुरक्षित रखी गई है, और एक खाली इंडेक्स फिर से बनाया गया है। इसे दोबारा भरने के लिए अपने मेमोरी स्रोतों को फिर से सिंक करें।',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6590,6 +6590,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Model lokal tidak tersedia',
'userErrors.localModelUnavailable.body':
'Ollama tidak dapat dijangkau di endpoint yang dikonfigurasi, atau model yang dibutuhkan belum terpasang di sana. Jalankan Ollama dan unduh modelnya di endpoint tersebut, atau alihkan pekerjaan ini ke penyedia cloud.',
'userErrors.replyDeliveryFailed.title': 'Balasan tidak dapat ditampilkan',
'userErrors.replyDeliveryFailed.body':
'Agen menyelesaikan giliran ini, tetapi balasannya tidak dapat disimpan atau dibaca ulang. Tanyakan lagi agar diulangi.',
'userErrors.memoryStoreCorrupt.title': 'Indeks memori rusak',
'userErrors.memoryStoreCorrupt.body':
'Basis data pohon memori mengalami kerusakan. Berkas yang rusak disimpan di samping data memori Anda, dan indeks kosong telah dibangun ulang. Sinkronkan ulang sumber memori untuk mengisinya kembali.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6680,6 +6680,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.body':
"Ollama non è raggiungibile sull'endpoint configurato, oppure il modello necessario non è installato lì. Avvia Ollama e scarica il modello su quell'endpoint, oppure sposta questo lavoro su un provider cloud.",
'userErrors.scope.chat': 'Chat',
'userErrors.replyDeliveryFailed.title': 'Impossibile mostrare la risposta',
'userErrors.replyDeliveryFailed.body':
'L’agente ha completato questo turno, ma la sua risposta non è stata salvata né riletta. Chiedi di nuovo per fartela ripetere.',
'userErrors.memoryStoreCorrupt.title': 'L’indice della memoria era corrotto',
'userErrors.memoryStoreCorrupt.body':
'Il database dell’albero della memoria era danneggiato. Il file danneggiato è stato conservato accanto ai tuoi dati di memoria ed è stato ricostruito un indice vuoto. Risincronizza le tue fonti di memoria per riempirlo di nuovo.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6480,6 +6480,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': '로컬 모델을 사용할 수 없음',
'userErrors.localModelUnavailable.body':
'구성된 엔드포인트에서 Ollama에 연결할 수 없거나 필요한 모델이 그곳에 설치되어 있지 않습니다. Ollama를 실행하고 해당 엔드포인트에 모델을 내려받거나, 이 작업을 클라우드 제공업체로 전환하세요.',
'userErrors.replyDeliveryFailed.title': '답변을 표시하지 못했습니다',
'userErrors.replyDeliveryFailed.body':
'에이전트가 이 턴을 마쳤지만 답변을 저장하거나 다시 읽어올 수 없었습니다. 다시 물어보면 답변을 되풀이합니다.',
'userErrors.memoryStoreCorrupt.title': '메모리 인덱스가 손상되었습니다',
'userErrors.memoryStoreCorrupt.body':
'메모리 트리의 데이터베이스가 손상되었습니다. 손상된 파일은 메모리 데이터 옆에 보존되었고 빈 인덱스가 다시 생성되었습니다. 메모리 소스를 다시 동기화하여 채워 주세요.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6656,6 +6656,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Model lokalny niedostępny',
'userErrors.localModelUnavailable.body':
'Ollama jest nieosiągalna pod skonfigurowanym punktem końcowym albo wymagany model nie jest tam zainstalowany. Uruchom Ollamę i pobierz model w tym punkcie końcowym lub przenieś tę pracę do dostawcy w chmurze.',
'userErrors.replyDeliveryFailed.title': 'Nie udało się pokazać odpowiedzi',
'userErrors.replyDeliveryFailed.body':
'Agent zakończył tę turę, ale jego odpowiedzi nie udało się zapisać ani odczytać ponownie. Zapytaj jeszcze raz, aby ją powtórzył.',
'userErrors.memoryStoreCorrupt.title': 'Indeks pamięci był uszkodzony',
'userErrors.memoryStoreCorrupt.body':
'Baza danych drzewa pamięci była uszkodzona. Uszkodzony plik zachowano obok danych pamięci i odbudowano pusty indeks. Zsynchronizuj ponownie źródła pamięci, aby go wypełnić.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/pt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6667,6 +6667,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Modelo local indisponível',
'userErrors.localModelUnavailable.body':
'O Ollama não está acessível no endpoint configurado, ou o modelo necessário não está instalado nele. Inicie o Ollama e baixe o modelo nesse endpoint, ou mude este trabalho para um provedor na nuvem.',
'userErrors.replyDeliveryFailed.title': 'Não foi possível mostrar a resposta',
'userErrors.replyDeliveryFailed.body':
'O agente concluiu este turno, mas a resposta dele não pôde ser salva nem lida novamente. Pergunte de novo para que ele repita.',
'userErrors.memoryStoreCorrupt.title': 'O índice de memória foi corrompido',
'userErrors.memoryStoreCorrupt.body':
'O banco de dados da árvore de memória estava danificado. O arquivo danificado foi preservado ao lado dos seus dados de memória e um índice vazio foi reconstruído. Sincronize novamente suas fontes de memória para preenchê-lo.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6629,6 +6629,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': 'Локальная модель недоступна',
'userErrors.localModelUnavailable.body':
'Ollama недоступен по настроенному адресу, либо нужная модель там не установлена. Запустите Ollama и загрузите модель по этому адресу или переведите эту работу на облачного провайдера.',
'userErrors.replyDeliveryFailed.title': 'Не удалось показать ответ',
'userErrors.replyDeliveryFailed.body':
'Агент завершил этот ход, но его ответ не удалось сохранить или прочитать заново. Спросите ещё раз, чтобы он повторил.',
'userErrors.memoryStoreCorrupt.title': 'Индекс памяти был повреждён',
'userErrors.memoryStoreCorrupt.body':
'База данных дерева памяти была повреждена. Повреждённый файл сохранён рядом с данными памяти, а пустой индекс создан заново. Заново синхронизируйте источники памяти, чтобы заполнить его.',
Expand Down
3 changes: 3 additions & 0 deletions app/src/lib/i18n/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6191,6 +6191,9 @@ const messages: TranslationMap = {
'userErrors.localModelUnavailable.title': '本地模型不可用',
'userErrors.localModelUnavailable.body':
'无法在配置的端点连接 Ollama,或所需模型未安装在该端点。请启动 Ollama 并在该端点拉取模型,或将此工作切换到云端提供商。',
'userErrors.replyDeliveryFailed.title': '无法显示回复',
'userErrors.replyDeliveryFailed.body':
'智能体已完成这一轮,但它的回复既没能保存也没能重新读取。再问一次即可让它重复回复。',
'userErrors.memoryStoreCorrupt.title': '记忆索引已损坏',
'userErrors.memoryStoreCorrupt.body':
'记忆树使用的数据库已损坏。受损文件已保留在记忆数据旁边,并已重建一个空索引。请重新同步记忆来源以重新填充。',
Expand Down
24 changes: 24 additions & 0 deletions app/src/lib/userErrors/classify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,30 @@ export function classifyIntegrationError(
};
}

/**
* #6034: a completed reply that reached neither writer, so there is nothing to
* render and nothing to re-read.
*
* The caller already knows this happened — it just failed an append and a
* refetch — so, like the two constructors above, this takes the fact rather
* than sniffing prose. Scoped per thread so two different lost replies are two
* entries, and one thread failing repeatedly is one entry with a count.
*/
export function classifyReplyDeliveryFailure(threadId: string): UserErrorDescriptor | null {
const thread = threadId?.trim();
if (!thread) return null;
return {
id: userErrorId('reply_delivery_failed', 'chat', thread),
kind: 'reply_delivery_failed',
severity: 'error',
scope: 'chat',
sourceDomain: 'chat',
titleKey: 'userErrors.replyDeliveryFailed.title',
bodyKey: 'userErrors.replyDeliveryFailed.body',
action: 'dismiss',
};
}

/** Build the stable dedupe identity for an error. */
export function userErrorId(
kind: UserErrorDescriptor['kind'],
Expand Down
Loading
Loading