Skip to content

Commit 22678e1

Browse files
authored
fix: bubble up bad request error message to user & skip response format in completion request if not provided (#41)
1 parent c2731a1 commit 22678e1

File tree

6 files changed

+16
-131
lines changed

6 files changed

+16
-131
lines changed

app/src/renderer/Resource/components/TextResource.svelte

Lines changed: 1 addition & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
} from '@deta/services/constants'
9090
import type { MentionAction } from '@deta/editor/src/lib/extensions/Mention'
9191
import { type AITool, ModelTiers, Provider } from '@deta/types/src/ai.types'
92-
import { Toast, useToasts } from '@deta/ui'
9392
import { useConfig } from '@deta/services'
9493
import { createWikipediaAPI, WebParser } from '@deta/web-parser'
9594
import EmbeddedResource from './EmbeddedResource.svelte'
@@ -137,7 +136,6 @@
137136
const log = useLogScope('TextCard')
138137
const resourceManager = useResourceManager()
139138
const ai = useAI()
140-
const toasts = useToasts()
141139
const config = useConfig()
142140
const wikipediaAPI = createWikipediaAPI()
143141
@@ -717,14 +715,9 @@
717715
}
718716
719717
const handleEditorFilePaste = async (e: CustomEvent<{ files: File[]; htmlData?: string }>) => {
720-
let toast: Toast | null = null
721718
try {
722719
const { files, htmlData } = e.detail
723720
724-
if (toasts) {
725-
toast = toasts.loading('Importing pasted items…')
726-
}
727-
728721
let parsed: any[] = []
729722
730723
// If we have direct files, use them
@@ -831,9 +824,6 @@
831824
}
832825
}
833826
834-
if (toast) {
835-
toast.success('Items imported!')
836-
}
837827
return
838828
}
839829
}
@@ -873,20 +863,12 @@
873863
874864
await processDropResource(position, resource, true, { x: 0, y: 0 })
875865
}
876-
877-
if (toast) {
878-
toast.success('Items imported!')
879-
}
880866
} catch (err) {
881-
if (toast) {
882-
toast.error('Failed to import pasted items!')
883-
}
884867
log.error(err)
885868
}
886869
}
887870
888871
const handlePaste = async (e: ClipboardEvent) => {
889-
let toast: Toast | null = null
890872
e.preventDefault()
891873
try {
892874
var parsed = await processPaste(e)
@@ -895,8 +877,6 @@
895877
parsed = parsed.filter((e) => e.type === 'file')
896878
if (parsed.length <= 0) return
897879
898-
toast = toasts.loading('Importing pasted items…')
899-
900880
const newResources = await createResourcesFromMediaItems(resourceManager, parsed, '', [
901881
ResourceTag.paste(),
902882
ResourceTag.silent()
@@ -911,17 +891,12 @@
911891
912892
await processDropResource(position, resource, true, { x: 0, y: 0 })
913893
}
914-
915-
toast.success('Items imported!')
916894
} catch (e) {
917-
toast?.error('Failed to import pasted items!')
918-
919895
log.error(e)
920896
}
921897
}
922898
923899
const handleDrop = async (drag) => {
924-
let toast: Toast | null = null
925900
try {
926901
const editor = editorElem.getEditor()
927902
const position = dragPosition ?? editor.view.state.selection.from
@@ -932,8 +907,6 @@
932907
933908
if (drag.isNative) {
934909
if (drag.dataTransfer?.getData('text/html')?.includes('<img ')) {
935-
toast = toasts.loading('Embedding image…')
936-
937910
try {
938911
let srcUrl = drag.dataTransfer?.getData('text/html').split('<img ')[1].split('src="')[1]
939912
srcUrl = srcUrl.slice(0, srcUrl.indexOf('"'))
@@ -965,12 +938,10 @@
965938
await processDropResource(position, resource, isBlock)
966939
} catch (error) {
967940
log.error('Failed to embedd image: ', error)
968-
toast.error('Failed to embedd image!')
969941
drag.abort()
970942
return
971943
}
972944
973-
toast.success('Image embedded!')
974945
drag.continue()
975946
return
976947
}
@@ -1004,7 +975,6 @@
1004975
// }
1005976
// } else {
1006977
// log.debug('Creating resource from tab', tab)
1007-
// toast = toasts.loading('Processing Tab…')
1008978
// const { resource } = await tabsManager.createResourceFromTab(tab, { silent: true })
1009979
// if (resource) {
1010980
// log.debug('Created resource from tab', resource)
@@ -1017,7 +987,6 @@
1017987
// y: drag.event.clientY
1018988
// }
1019989
// )
1020-
// toast.success(isBlock ? 'Tab Embedded!' : 'Tab Linked!')
1021990
// drag.continue()
1022991
// return
1023992
// }
@@ -1071,11 +1040,6 @@
10711040
}
10721041
} catch (e) {
10731042
log.error('Error handling drop', e)
1074-
if (toast) {
1075-
toast.error('Failed to handle drop')
1076-
} else {
1077-
toasts.error('Failed to handle drop')
1078-
}
10791043
drag.abort()
10801044
}
10811045
}
@@ -1147,7 +1111,6 @@
11471111
true
11481112
)
11491113
// await tabsManager.openResourceAsTab(resource, { active: true })
1150-
toasts.success('Note created!')
11511114
}
11521115
11531116
const getLastNode = (type: string) => {
@@ -1375,16 +1338,7 @@
13751338
log.debug('autocomplete response', response)
13761339
if (response.error) {
13771340
log.error('Error generating AI output', response.error)
1378-
let errorMsg = response.error.message
1379-
if (response.error.type === PageChatMessageSentEventError.TooManyRequests) {
1380-
errorMsg = 'Too many requests, please try again later'
1381-
} else if (response.error.type === PageChatMessageSentEventError.BadRequest) {
1382-
errorMsg =
1383-
'Sorry your query did not pass our content policy, please try again with a different query.'
1384-
} else if (response.error.type === PageChatMessageSentEventError.RAGEmptyContext) {
1385-
errorMsg =
1386-
'No relevant context found. Please add more resources or try a different query.'
1387-
}
1341+
let errorMsg = response.error.message || 'An unknown error occurred'
13881342
aiGeneration.updateStatus('failed')
13891343
chatInputComp?.showStatus({
13901344
type: 'error',
@@ -1472,7 +1426,6 @@
14721426
14731427
if (type === MentionItemType.BUILT_IN || type === MentionItemType.MODEL) {
14741428
log.debug('Built-in or model mention clicked, cannot be opened')
1475-
toasts.info('This is a built-in mention and cannot be opened')
14761429
return
14771430
}
14781431
@@ -1501,54 +1454,8 @@
15011454
log.debug('Cannot open mention', item, action)
15021455
return
15031456
}
1504-
1505-
if (action === 'overlay') {
1506-
if (id === INBOX_MENTION.id) {
1507-
openSpaceInStuff('inbox')
1508-
} else if (id === EVERYTHING_MENTION.id) {
1509-
openSpaceInStuff('all')
1510-
} else if (type === MentionItemType.RESOURCE) {
1511-
// oasis.openResourceDetailsSidebar(id, { select: true, selectedSpace: 'auto' })
1512-
} else if (type === MentionItemType.CONTEXT) {
1513-
openSpaceInStuff(id)
1514-
} else {
1515-
toasts.info('This is a built-in mention and cannot be opened')
1516-
}
1517-
} else {
1518-
if (type === MentionItemType.BUILT_IN || type === MentionItemType.MODEL) {
1519-
toasts.info('This is a built-in mention and cannot be opened')
1520-
return
1521-
}
1522-
1523-
// if (type === MentionItemType.RESOURCE) {
1524-
// tabsManager.openResourcFromContextAsPageTab(id, {
1525-
// active: action !== 'new-background-tab'
1526-
// })
1527-
// return
1528-
// }
1529-
1530-
// if (action === 'open') {
1531-
// tabsManager.changeScope(
1532-
// id === INBOX_MENTION.id || id === EVERYTHING_MENTION.id ? null : id,
1533-
// ChangeContextEventTrigger.Note
1534-
// )
1535-
1536-
// return
1537-
// }
1538-
1539-
// const space = await oasis.getSpace(id)
1540-
// if (!space) {
1541-
// log.error('Space not found', id)
1542-
// return
1543-
// }
1544-
1545-
// tabsManager.addSpaceTab(space, {
1546-
// active: action === 'new-tab'
1547-
// })
1548-
}
15491457
} catch (e) {
15501458
log.error('Error handling mention click', e)
1551-
toasts.error('Failed to handle mention click')
15521459
}
15531460
}
15541461
@@ -1594,20 +1501,6 @@
15941501
if (response.error) {
15951502
log.error('Error generating AI output', response.error)
15961503
1597-
if (response.error.type === PageChatMessageSentEventError.TooManyRequests) {
1598-
toasts.error('Too many requests, please try again later')
1599-
} else if (response.error.type === PageChatMessageSentEventError.RAGEmptyContext) {
1600-
toasts.error(
1601-
'No relevant context found. Please add more resources or try a different query.'
1602-
)
1603-
} else if (response.error.type === PageChatMessageSentEventError.BadRequest) {
1604-
toasts.error(
1605-
'Sorry your query did not pass our content policy, please try again with a different query.'
1606-
)
1607-
} else {
1608-
toasts.error('Something went wrong generating the AI output. Please try again.')
1609-
}
1610-
16111504
return
16121505
}
16131506
@@ -1636,7 +1529,6 @@
16361529
showBubbleMenu.set(true)
16371530
} catch (e) {
16381531
log.error('Error rewriting', e)
1639-
toasts.error('Failed to rewrite')
16401532
showBubbleMenu.set(false)
16411533
}
16421534
}
@@ -1715,7 +1607,6 @@
17151607
const checkIfAlreadyRunning = (kind: string = 'ai generation') => {
17161608
if ($isGeneratingAI) {
17171609
log.debug(`Ignoring ${kind} request - AI generation already in progress`)
1718-
toasts.info('AI generation already running, please wait')
17191610
return true
17201611
}
17211612
@@ -1755,7 +1646,6 @@
17551646
selectedContext.set(e.detail)
17561647
} catch (e) {
17571648
log.error('Error selecting context', e)
1758-
toasts.error('Failed to select context')
17591649
}
17601650
}
17611651
@@ -1841,7 +1731,6 @@
18411731
}
18421732
} catch (e) {
18431733
log.error('Error handling note button click', e)
1844-
toasts.error('Failed to handle note button click')
18451734
}
18461735
}
18471736
@@ -2021,7 +1910,6 @@
20211910
)
20221911
} catch (e) {
20231912
log.error('Error doing magic', e)
2024-
toasts.error('Failed to autocomplete')
20251913
}
20261914
}
20271915
@@ -2058,7 +1946,6 @@
20581946
20591947
if (!generatedPrompts) {
20601948
log.error('Failed to generate prompts')
2061-
toasts.error('Failed to generate suggestions')
20621949
generatingPrompts.set(false)
20631950
return
20641951
}
@@ -2067,7 +1954,6 @@
20671954
prompts.set(generatedPrompts)
20681955
} catch (e) {
20691956
log.error('Error generating prompts', e)
2070-
toasts.error('Failed to generate suggestions')
20711957
} finally {
20721958
generatingPrompts.set(false)
20731959
}
@@ -2100,7 +1986,6 @@
21001986
)
21011987
} catch (e) {
21021988
log.error('Error doing magic', e)
2103-
toasts.error('Failed to generate suggestion')
21041989
}
21051990
}
21061991
@@ -2391,7 +2276,6 @@
23912276
log.debug('Inserted onboarding mention into editor', mentionItem)
23922277
} catch (error) {
23932278
log.error('Error inserting onboarding mention', error)
2394-
toasts.error('Failed to insert mention')
23952279
}
23962280
}
23972281
@@ -2425,7 +2309,6 @@
24252309
log.debug('UseAsDefaultBrowser extension inserted successfully at the end of the document')
24262310
} catch (err) {
24272311
log.error('Error inserting UseAsDefaultBrowser extension', err)
2428-
toasts.error('Failed to insert default browser prompt')
24292312
}
24302313
}
24312314
@@ -2475,7 +2358,6 @@
24752358
// editor.commands.focus()
24762359
} catch (err) {
24772360
log.error('Error inserting extension', err)
2478-
toasts.error('Failed to insert content')
24792361
}
24802362
}
24812363
@@ -2539,7 +2421,6 @@
25392421
log.debug('Onboarding footer with links inserted successfully')
25402422
} catch (err) {
25412423
log.error('Error inserting onboarding footer', err)
2542-
toasts.error('Failed to insert resource links')
25432424
}
25442425
}
25452426

packages/backend/src/ai/llm/client/mod.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,13 +318,16 @@ impl Provider {
318318
messages: &[Message],
319319
response_format: Option<&serde_json::Value>,
320320
) -> BackendResult<String> {
321-
serde_json::to_string(&serde_json::json!({
321+
let mut json_obj = serde_json::json!({
322322
"model": model,
323323
"stream": stream,
324324
"messages": messages,
325-
"response_format": response_format
326-
}))
327-
.map_err(|err| {
325+
});
326+
if let Some(format) = response_format {
327+
json_obj["response_format"] = serde_json::json!(format);
328+
}
329+
330+
serde_json::to_string(&json_obj).map_err(|err| {
328331
BackendError::GenericError(format!(
329332
"failed to serialize openai completion request: {err}"
330333
))
@@ -691,7 +694,7 @@ impl LLMClient {
691694
}
692695
// TODO: are there other cases of bad request
693696
if status == reqwest::StatusCode::BAD_REQUEST {
694-
return Err(BackendError::LLMClientErrorBadRequest);
697+
return Err(BackendError::LLMClientErrorBadRequest(response.text()?));
695698
}
696699
if status == reqwest::StatusCode::UNAUTHORIZED {
697700
return Err(BackendError::LLMClientErrorUnauthorized);

packages/backend/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub enum BackendError {
2424
LLMClientError { r#type: String, message: String },
2525
#[error("LLM API Key Missing error")]
2626
LLMClientErrorAPIKeyMissing,
27-
#[error("LLM Bad Request error")]
28-
LLMClientErrorBadRequest,
27+
#[error("LLM Bad Request error: {0}")]
28+
LLMClientErrorBadRequest(String),
2929
#[error("LLM Too Many Requests error")]
3030
LLMClientErrorTooManyRequests,
3131
#[error("LLM Unauthorized error")]

packages/backend/types/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ export class APIKeyMissingError extends Error {
9999
}
100100

101101
export class BadRequestError extends Error {
102-
constructor() {
103-
super('Bad request')
102+
constructor(message?: string) {
103+
super(message || 'Bad request')
104104
this.name = 'BadRequestError'
105105
// Maintains proper stack trace for where error was thrown (only available on V8)
106106
if (Error.captureStackTrace) {

0 commit comments

Comments
 (0)