Skip to content

Commit 7217288

Browse files
committed
fix(GmailTools): enhance Gmail compose with retry logic and fallback extraction
1 parent dd59284 commit 7217288

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

entrypoints/content/components/GmailTools/GmailComposeCard.vue

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ import { useLogger } from '@/composables/useLogger'
183183
import { useToast } from '@/composables/useToast'
184184
import { fromError } from '@/utils/error'
185185
import { useI18n } from '@/utils/i18n'
186+
import { extractValueOfKeyByPattern } from '@/utils/json/parser/pattern-extractor'
186187
import type { LanguageCode } from '@/utils/language/detect'
187188
import { getLanguageName, SUPPORTED_LANGUAGES } from '@/utils/language/detect'
188189
import { useOllamaStatusStore } from '@/utils/pinia-store/store'
@@ -459,8 +460,11 @@ const start = async () => {
459460
460461
logger.debug('Gmail compose prompt:', { systemPrompt, userPrompt })
461462
462-
const retry = 0
463+
let retry = 0
464+
let text = ''
463465
do {
466+
text = ''
467+
retry += 1
464468
logger.debug(`Gmail compose attempt #${retry + 1}`)
465469
const iter = streamObjectInBackground({
466470
prompt: userPrompt,
@@ -470,14 +474,26 @@ const start = async () => {
470474
})
471475
472476
for await (const part of iter) {
473-
// Extract the structured result
474477
if (part.type === 'object') {
475478
runningStatus.value = 'streaming'
476479
optimizedSubject.value = part.object.subject || ''
477480
optimizedBody.value = part.object.body || ''
478481
}
482+
else if (part.type === 'text-delta') {
483+
text += part.textDelta
484+
}
479485
}
480-
} while ((!optimizedSubject.value || !optimizedBody.value) && retry < 3)
486+
} while ((!optimizedSubject.value || !optimizedBody.value) && retry < 2)
487+
488+
// Fallback: try to extract from raw text if structured extraction failed
489+
if (!optimizedSubject.value) {
490+
const extractSubjectMatch = extractValueOfKeyByPattern(text, 'subject')
491+
if (extractSubjectMatch) optimizedSubject.value = extractSubjectMatch
492+
}
493+
if (!optimizedBody.value) {
494+
const extractBodyMatch = extractValueOfKeyByPattern(text, 'body')
495+
if (extractBodyMatch) optimizedBody.value = extractBodyMatch
496+
}
481497
482498
logger.debug('Gmail compose structured response:', {
483499
subject: optimizedSubject.value,

entrypoints/content/utils/page-injection/gmail-tools.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n'
33

44
import LogoSvg from '@/assets/icons/logo-custom-color.svg?raw'
55
import { useDocumentLoaded } from '@/composables/useDocumentLoaded'
6-
import { useLogger } from '@/composables/useLogger'
6+
import Logger from '@/utils/logger'
77
import { c2bRpc } from '@/utils/rpc'
88
import { toggleContainer } from '@/utils/rpc/content-main-world-fns'
99
import { sleep } from '@/utils/sleep'
@@ -12,7 +12,7 @@ import { getUserConfig } from '@/utils/user-config'
1212
import { useGmailDetector } from '../../composables/useGmailDetector'
1313
import { EmailExtractor } from '../gmail/email-extractor'
1414

15-
const logger = useLogger()
15+
const logger = Logger.child('gmail-tools')
1616
const NATIVEMIND_GMAIL_SUMMARY_BUTTON_CLASS = 'nativemind-gmail-summary-btn'
1717
const NATIVEMIND_GMAIL_REPLY_BUTTON_CLASS = 'nativemind-gmail-reply-btn'
1818
const NATIVEMIND_GMAIL_COMPOSE_BUTTON_CLASS = 'nativemind-gmail-compose-btn'
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export function extractValueOfKeyByPattern(json: string, key: string): string | null {
2+
const regex = new RegExp(`"${key}"\\s*:\\s*("(.*?)"|\\d+|true|false|null)`, 'is')
3+
4+
const match = json.match(regex)
5+
if (match && match[1]) {
6+
let value = match[1].trim()
7+
if (value.startsWith('"') && value.endsWith('"')) {
8+
value = value.slice(1, -1)
9+
const unescapedValue = value.replace(/\\"/g, '"').replace(/\\\\/g, '\\').replace(/\\n/g, '\n')
10+
return unescapedValue
11+
}
12+
return value
13+
}
14+
return null
15+
}

0 commit comments

Comments
 (0)