fix: use valid Zen summaries for notes

This commit is contained in:
Bohdan Triapitsyn
2026-04-30 13:07:37 +03:00
parent fa71954ef1
commit bbd83d60c6
16 changed files with 430 additions and 62 deletions
@@ -507,13 +507,20 @@ export const TextSelectionMenu: React.FC<TextSelectionMenuProps> = ({ containerR
try {
setIsAddingToNotes(true);
const distilledInsight = await summarizeText(selectedText, {
threshold: 0,
maxLength: 100,
mode: 'note',
});
let noteText = selectedText;
let usedSummaryFallback = false;
try {
noteText = await summarizeText(selectedText, {
threshold: 0,
maxLength: 100,
mode: 'note',
});
} catch (summaryError) {
usedSummaryFallback = true;
console.warn('[AddToNotes] Summary failed, saving selected text:', summaryError);
}
const projectData = await getProjectNotesAndTodos(currentProjectRef);
const nextNotes = appendDistilledInsightToNotes(projectData.notes, distilledInsight);
const nextNotes = appendDistilledInsightToNotes(projectData.notes, noteText);
const saved = await saveProjectNotesAndTodos(currentProjectRef, {
notes: nextNotes,
todos: projectData.todos,
@@ -525,7 +532,11 @@ export const TextSelectionMenu: React.FC<TextSelectionMenuProps> = ({ containerR
window.dispatchEvent(new CustomEvent('openchamber:project-notes-updated', {
detail: { projectId: currentProjectRef.id },
}));
toast.success(t('chat.textSelection.toast.addToNotesSuccess'));
if (usedSummaryFallback) {
toast.warning(t('chat.textSelection.toast.addToNotesSummaryFailed'));
} else {
toast.success(t('chat.textSelection.toast.addToNotesSuccess'));
}
hideMenu();
window.getSelection()?.removeAllRanges();
} catch (error) {
@@ -42,7 +42,6 @@ const TEMPLATE_EVENT_LABEL_KEYS = {
question: 'settings.notifications.page.template.event.question',
} as const satisfies Record<NotificationTemplateEvent, string>;
const UTILITY_PROVIDER_ID = 'zen';
const UTILITY_PREFERRED_MODEL_ID = 'big-pickle';
const UTILITY_NOT_SELECTED_VALUE = '__not_selected__';
@@ -78,7 +77,6 @@ export const NotificationSettings: React.FC = () => {
const setSummaryLength = useUIStore(state => state.setSummaryLength);
const maxLastMessageLength = useUIStore(state => state.maxLastMessageLength);
const setMaxLastMessageLength = useUIStore(state => state.setMaxLastMessageLength);
const providers = useConfigStore((state) => state.providers);
const settingsZenModel = useConfigStore((state) => state.settingsZenModel);
const setSettingsZenModel = useConfigStore((state) => state.setSettingsZenModel);
@@ -88,27 +86,7 @@ export const NotificationSettings: React.FC = () => {
const [pushBusy, setPushBusy] = React.useState(false);
const [fetchedZenModels, setFetchedZenModels] = React.useState<Array<{ id: string; name: string }>>([]);
const providerZenModels = React.useMemo(() => {
const zenProvider = providers.find((provider) => provider.id === UTILITY_PROVIDER_ID);
const models = Array.isArray(zenProvider?.models) ? zenProvider.models : [];
return models
.map((model: Record<string, unknown>) => {
const id = typeof model.id === 'string' ? model.id.trim() : '';
if (!id) {
return null;
}
const name = typeof model.name === 'string' && model.name.trim().length > 0 ? model.name.trim() : id;
return { id, name };
})
.filter((model): model is { id: string; name: string } => model !== null);
}, [providers]);
React.useEffect(() => {
if (providerZenModels.length > 0) {
setFetchedZenModels([]);
return;
}
const controller = new AbortController();
void fetch('/api/zen/models', {
method: 'GET',
@@ -145,11 +123,11 @@ export const NotificationSettings: React.FC = () => {
return () => {
controller.abort();
};
}, [providerZenModels]);
}, []);
const utilityModelOptions = React.useMemo(() => {
return providerZenModels.length > 0 ? providerZenModels : fetchedZenModels;
}, [fetchedZenModels, providerZenModels]);
return fetchedZenModels;
}, [fetchedZenModels]);
const utilitySelectedModelId = React.useMemo(() => {
if (settingsZenModel && utilityModelOptions.some((model) => model.id === settingsZenModel)) {
+1
View File
@@ -1366,6 +1366,7 @@ export const dict = {
'chat.textSelection.toast.noProject': 'No project found for this session',
'chat.textSelection.toast.addToNotesFailed': 'Failed to add to notes',
'chat.textSelection.toast.addToNotesSuccess': 'Added distilled insight to notes',
'chat.textSelection.toast.addToNotesSummaryFailed': 'Could not summarize selection, added selected text to notes',
'chat.textSelection.actions.addToChat': 'Add to chat',
'chat.textSelection.actions.newSession': 'New session',
'chat.textSelection.actions.copy': 'Copy',
+1
View File
@@ -1332,6 +1332,7 @@ export const dict: Record<I18nKey, string> = {
"chat.textSelection.toast.noProject": "No se encontró proyecto para esta sesión",
"chat.textSelection.toast.addToNotesFailed": "No se pudo añadir a las notas",
"chat.textSelection.toast.addToNotesSuccess": "Se añadió la información destilada a notas",
"chat.textSelection.toast.addToNotesSummaryFailed": "No se pudo resumir la selección; se añadió el texto seleccionado a las notas",
"chat.textSelection.actions.addToChat": "Añadir al chat",
"chat.textSelection.actions.newSession": "Nueva sesión",
"chat.textSelection.actions.copy": "Copiar",
+1
View File
@@ -1368,6 +1368,7 @@ export const dict: Record<I18nKey, string> = {
'chat.textSelection.toast.noProject': '이 세션의 프로젝트를 찾을 수 없음',
'chat.textSelection.toast.addToNotesFailed': '메모 추가 실패',
'chat.textSelection.toast.addToNotesSuccess': '정리된 인사이트를 메모에 추가함',
'chat.textSelection.toast.addToNotesSummaryFailed': '선택 영역을 요약할 수 없어 선택한 텍스트를 메모에 추가함',
'chat.textSelection.actions.addToChat': '채팅에 추가',
'chat.textSelection.actions.newSession': '새 세션',
'chat.textSelection.actions.copy': '복사',
@@ -1332,6 +1332,7 @@ export const dict: Record<I18nKey, string> = {
"chat.textSelection.toast.noProject": "Não foi encontrado projeto para esta sessão",
"chat.textSelection.toast.addToNotesFailed": "Não foi possível adicionar às notas",
"chat.textSelection.toast.addToNotesSuccess": "Informação destilada adicionada às notas",
"chat.textSelection.toast.addToNotesSummaryFailed": "Não foi possível resumir a seleção; o texto selecionado foi adicionado às notas",
"chat.textSelection.actions.addToChat": "Adicionar ao chat",
"chat.textSelection.actions.newSession": "Nova sessão",
"chat.textSelection.actions.copy": "Copiar",
+1
View File
@@ -1332,6 +1332,7 @@ export const dict: Record<I18nKey, string> = {
"chat.textSelection.toast.noProject": "Для цієї сесії не знайдено жодного проєкту",
"chat.textSelection.toast.addToNotesFailed": "Не вдалося додати до нотаток",
"chat.textSelection.toast.addToNotesSuccess": "Інсайт додано до нотаток",
"chat.textSelection.toast.addToNotesSummaryFailed": "Не вдалося підсумувати виділення, виділений текст додано до нотаток",
"chat.textSelection.actions.addToChat": "Додати в чат",
"chat.textSelection.actions.newSession": "Нова сесія",
"chat.textSelection.actions.copy": "Копіювати",
@@ -1332,6 +1332,7 @@ export const dict: Record<I18nKey, string> = {
'chat.textSelection.toast.noProject': '未找到此会话对应的项目',
'chat.textSelection.toast.addToNotesFailed': '添加到笔记失败',
'chat.textSelection.toast.addToNotesSuccess': '已将洞察添加到笔记',
'chat.textSelection.toast.addToNotesSummaryFailed': '无法总结所选内容,已将所选文本添加到笔记',
'chat.textSelection.actions.addToChat': '添加到聊天',
'chat.textSelection.actions.newSession': '新建会话',
'chat.textSelection.actions.copy': '复制',
+1 -2
View File
@@ -52,13 +52,12 @@ export async function summarizeText(
}
try {
const zenModel = store.settingsZenModel;
const response = await fetch(resolveSummarizeUrl(), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text, threshold, maxLength, mode, ...(zenModel ? { zenModel } : {}) }),
body: JSON.stringify({ text, threshold, maxLength, mode }),
});
if (!response.ok) {