diff --git a/app/src/renderer/Resource/components/TextResource.svelte b/app/src/renderer/Resource/components/TextResource.svelte index ccf1a503e..443e9a433 100644 --- a/app/src/renderer/Resource/components/TextResource.svelte +++ b/app/src/renderer/Resource/components/TextResource.svelte @@ -89,7 +89,6 @@ } from '@deta/services/constants' import type { MentionAction } from '@deta/editor/src/lib/extensions/Mention' import { type AITool, ModelTiers, Provider } from '@deta/types/src/ai.types' - import { Toast, useToasts } from '@deta/ui' import { useConfig } from '@deta/services' import { createWikipediaAPI, WebParser } from '@deta/web-parser' import EmbeddedResource from './EmbeddedResource.svelte' @@ -137,7 +136,6 @@ const log = useLogScope('TextCard') const resourceManager = useResourceManager() const ai = useAI() - const toasts = useToasts() const config = useConfig() const wikipediaAPI = createWikipediaAPI() @@ -717,14 +715,9 @@ } const handleEditorFilePaste = async (e: CustomEvent<{ files: File[]; htmlData?: string }>) => { - let toast: Toast | null = null try { const { files, htmlData } = e.detail - if (toasts) { - toast = toasts.loading('Importing pasted items…') - } - let parsed: any[] = [] // If we have direct files, use them @@ -831,9 +824,6 @@ } } - if (toast) { - toast.success('Items imported!') - } return } } @@ -873,20 +863,12 @@ await processDropResource(position, resource, true, { x: 0, y: 0 }) } - - if (toast) { - toast.success('Items imported!') - } } catch (err) { - if (toast) { - toast.error('Failed to import pasted items!') - } log.error(err) } } const handlePaste = async (e: ClipboardEvent) => { - let toast: Toast | null = null e.preventDefault() try { var parsed = await processPaste(e) @@ -895,8 +877,6 @@ parsed = parsed.filter((e) => e.type === 'file') if (parsed.length <= 0) return - toast = toasts.loading('Importing pasted items…') - const newResources = await createResourcesFromMediaItems(resourceManager, parsed, '', [ ResourceTag.paste(), ResourceTag.silent() @@ -911,17 +891,12 @@ await processDropResource(position, resource, true, { x: 0, y: 0 }) } - - toast.success('Items imported!') } catch (e) { - toast?.error('Failed to import pasted items!') - log.error(e) } } const handleDrop = async (drag) => { - let toast: Toast | null = null try { const editor = editorElem.getEditor() const position = dragPosition ?? editor.view.state.selection.from @@ -932,8 +907,6 @@ if (drag.isNative) { if (drag.dataTransfer?.getData('text/html')?.includes(' { @@ -1375,16 +1338,7 @@ log.debug('autocomplete response', response) if (response.error) { log.error('Error generating AI output', response.error) - let errorMsg = response.error.message - if (response.error.type === PageChatMessageSentEventError.TooManyRequests) { - errorMsg = 'Too many requests, please try again later' - } else if (response.error.type === PageChatMessageSentEventError.BadRequest) { - errorMsg = - 'Sorry your query did not pass our content policy, please try again with a different query.' - } else if (response.error.type === PageChatMessageSentEventError.RAGEmptyContext) { - errorMsg = - 'No relevant context found. Please add more resources or try a different query.' - } + let errorMsg = response.error.message || 'An unknown error occurred' aiGeneration.updateStatus('failed') chatInputComp?.showStatus({ type: 'error', @@ -1472,7 +1426,6 @@ if (type === MentionItemType.BUILT_IN || type === MentionItemType.MODEL) { log.debug('Built-in or model mention clicked, cannot be opened') - toasts.info('This is a built-in mention and cannot be opened') return } @@ -1501,54 +1454,8 @@ log.debug('Cannot open mention', item, action) return } - - if (action === 'overlay') { - if (id === INBOX_MENTION.id) { - openSpaceInStuff('inbox') - } else if (id === EVERYTHING_MENTION.id) { - openSpaceInStuff('all') - } else if (type === MentionItemType.RESOURCE) { - // oasis.openResourceDetailsSidebar(id, { select: true, selectedSpace: 'auto' }) - } else if (type === MentionItemType.CONTEXT) { - openSpaceInStuff(id) - } else { - toasts.info('This is a built-in mention and cannot be opened') - } - } else { - if (type === MentionItemType.BUILT_IN || type === MentionItemType.MODEL) { - toasts.info('This is a built-in mention and cannot be opened') - return - } - - // if (type === MentionItemType.RESOURCE) { - // tabsManager.openResourcFromContextAsPageTab(id, { - // active: action !== 'new-background-tab' - // }) - // return - // } - - // if (action === 'open') { - // tabsManager.changeScope( - // id === INBOX_MENTION.id || id === EVERYTHING_MENTION.id ? null : id, - // ChangeContextEventTrigger.Note - // ) - - // return - // } - - // const space = await oasis.getSpace(id) - // if (!space) { - // log.error('Space not found', id) - // return - // } - - // tabsManager.addSpaceTab(space, { - // active: action === 'new-tab' - // }) - } } catch (e) { log.error('Error handling mention click', e) - toasts.error('Failed to handle mention click') } } @@ -1594,20 +1501,6 @@ if (response.error) { log.error('Error generating AI output', response.error) - if (response.error.type === PageChatMessageSentEventError.TooManyRequests) { - toasts.error('Too many requests, please try again later') - } else if (response.error.type === PageChatMessageSentEventError.RAGEmptyContext) { - toasts.error( - 'No relevant context found. Please add more resources or try a different query.' - ) - } else if (response.error.type === PageChatMessageSentEventError.BadRequest) { - toasts.error( - 'Sorry your query did not pass our content policy, please try again with a different query.' - ) - } else { - toasts.error('Something went wrong generating the AI output. Please try again.') - } - return } @@ -1636,7 +1529,6 @@ showBubbleMenu.set(true) } catch (e) { log.error('Error rewriting', e) - toasts.error('Failed to rewrite') showBubbleMenu.set(false) } } @@ -1715,7 +1607,6 @@ const checkIfAlreadyRunning = (kind: string = 'ai generation') => { if ($isGeneratingAI) { log.debug(`Ignoring ${kind} request - AI generation already in progress`) - toasts.info('AI generation already running, please wait') return true } @@ -1755,7 +1646,6 @@ selectedContext.set(e.detail) } catch (e) { log.error('Error selecting context', e) - toasts.error('Failed to select context') } } @@ -1841,7 +1731,6 @@ } } catch (e) { log.error('Error handling note button click', e) - toasts.error('Failed to handle note button click') } } @@ -2021,7 +1910,6 @@ ) } catch (e) { log.error('Error doing magic', e) - toasts.error('Failed to autocomplete') } } @@ -2058,7 +1946,6 @@ if (!generatedPrompts) { log.error('Failed to generate prompts') - toasts.error('Failed to generate suggestions') generatingPrompts.set(false) return } @@ -2067,7 +1954,6 @@ prompts.set(generatedPrompts) } catch (e) { log.error('Error generating prompts', e) - toasts.error('Failed to generate suggestions') } finally { generatingPrompts.set(false) } @@ -2100,7 +1986,6 @@ ) } catch (e) { log.error('Error doing magic', e) - toasts.error('Failed to generate suggestion') } } @@ -2391,7 +2276,6 @@ log.debug('Inserted onboarding mention into editor', mentionItem) } catch (error) { log.error('Error inserting onboarding mention', error) - toasts.error('Failed to insert mention') } } @@ -2425,7 +2309,6 @@ log.debug('UseAsDefaultBrowser extension inserted successfully at the end of the document') } catch (err) { log.error('Error inserting UseAsDefaultBrowser extension', err) - toasts.error('Failed to insert default browser prompt') } } @@ -2475,7 +2358,6 @@ // editor.commands.focus() } catch (err) { log.error('Error inserting extension', err) - toasts.error('Failed to insert content') } } @@ -2539,7 +2421,6 @@ log.debug('Onboarding footer with links inserted successfully') } catch (err) { log.error('Error inserting onboarding footer', err) - toasts.error('Failed to insert resource links') } } diff --git a/packages/backend/src/ai/llm/client/mod.rs b/packages/backend/src/ai/llm/client/mod.rs index 0118a32fc..c23327edc 100644 --- a/packages/backend/src/ai/llm/client/mod.rs +++ b/packages/backend/src/ai/llm/client/mod.rs @@ -318,13 +318,16 @@ impl Provider { messages: &[Message], response_format: Option<&serde_json::Value>, ) -> BackendResult { - serde_json::to_string(&serde_json::json!({ + let mut json_obj = serde_json::json!({ "model": model, "stream": stream, "messages": messages, - "response_format": response_format - })) - .map_err(|err| { + }); + if let Some(format) = response_format { + json_obj["response_format"] = serde_json::json!(format); + } + + serde_json::to_string(&json_obj).map_err(|err| { BackendError::GenericError(format!( "failed to serialize openai completion request: {err}" )) @@ -691,7 +694,7 @@ impl LLMClient { } // TODO: are there other cases of bad request if status == reqwest::StatusCode::BAD_REQUEST { - return Err(BackendError::LLMClientErrorBadRequest); + return Err(BackendError::LLMClientErrorBadRequest(response.text()?)); } if status == reqwest::StatusCode::UNAUTHORIZED { return Err(BackendError::LLMClientErrorUnauthorized); diff --git a/packages/backend/src/lib.rs b/packages/backend/src/lib.rs index 86b0f56c1..73dbf58c3 100644 --- a/packages/backend/src/lib.rs +++ b/packages/backend/src/lib.rs @@ -24,8 +24,8 @@ pub enum BackendError { LLMClientError { r#type: String, message: String }, #[error("LLM API Key Missing error")] LLMClientErrorAPIKeyMissing, - #[error("LLM Bad Request error")] - LLMClientErrorBadRequest, + #[error("LLM Bad Request error: {0}")] + LLMClientErrorBadRequest(String), #[error("LLM Too Many Requests error")] LLMClientErrorTooManyRequests, #[error("LLM Unauthorized error")] diff --git a/packages/backend/types/index.ts b/packages/backend/types/index.ts index fccb70b12..6e81cc876 100644 --- a/packages/backend/types/index.ts +++ b/packages/backend/types/index.ts @@ -99,8 +99,8 @@ export class APIKeyMissingError extends Error { } export class BadRequestError extends Error { - constructor() { - super('Bad request') + constructor(message?: string) { + super(message || 'Bad request') this.name = 'BadRequestError' // Maintains proper stack trace for where error was thrown (only available on V8) if (Error.captureStackTrace) { diff --git a/packages/services/src/lib/ai/helpers.ts b/packages/services/src/lib/ai/helpers.ts index 0c0e03cc4..1ec389912 100644 --- a/packages/services/src/lib/ai/helpers.ts +++ b/packages/services/src/lib/ai/helpers.ts @@ -288,7 +288,8 @@ export const parseAIError = (e: any) => { content = 'API key is missing. Configure an API key in your Settings to continue.' } else if (e instanceof BadRequestError) { error = PageChatMessageSentEventError.BadRequest - content = 'The AI server sent a bad request error. You can try again with a different query.' + content = + e.message || 'The AI server sent a bad request response, you can try modifying your query' } else if (e instanceof UnauthorizedError) { error = PageChatMessageSentEventError.Unauthorized content = diff --git a/packages/services/src/lib/sffs.ts b/packages/services/src/lib/sffs.ts index 656748dd0..f36a4c947 100644 --- a/packages/services/src/lib/sffs.ts +++ b/packages/services/src/lib/sffs.ts @@ -976,7 +976,7 @@ export class SFFS { typeof error === 'string' ? error : error instanceof Error ? error.message : undefined if (message) { if (message.includes('LLM Bad Request error')) { - throw new BadRequestError() + throw new BadRequestError(message.replace('LLM Bad Request error: ', '')) } if (message.includes('LLM API Key Missing error')) { throw new APIKeyMissingError()