@@ -14,6 +14,7 @@ import { LocalDurationRecommender } from './LocalFallback';
1414import { AIError } from './ai-errors' ;
1515import { ensureOnline , ensureMinLength } from './aiGuards' ;
1616import { getAIPlugin , getRemotePlugin , getElectronPlugin } from './aiPluginProvider' ;
17+ import { offlineAIQueue } from './offlineAIQueue' ;
1718import type { AIPlugin , DurationHistoryData , DurationOptions , DurationResult ,
1819 SummarizeResult , FlashcardResult , EvaluateResult ,
1920 SummarizeOptions , FlashcardOptions , EvaluateOptions ,
@@ -41,12 +42,23 @@ class AIPluginLoader {
4142 /**
4243 * 统一非流式调用包装:守卫 → 取插件 → 能力检查 → 调用
4344 * invoke 返回 undefined 表示当前插件未实现该可选能力
45+ * @ai -context P2-11:opts.offline 提供离线入队描述(feature/endpoint/payload)时,
46+ * 离线不再单纯报错,而是 fire-and-forget 入队(联网后自动重放)后再抛 offline 提示。
4447 */
4548 private async call < T > (
4649 invoke : ( plugin : AIPlugin ) => Promise < T > | undefined ,
47- opts : { contentCheck ?: string ; unsupportedMsg : string } ,
50+ opts : { contentCheck ?: string ; unsupportedMsg : string ; offline ?: { feature : string ; endpoint : string ; payload : unknown } } ,
4851 ) : Promise < T > {
49- ensureOnline ( ) ;
52+ try {
53+ ensureOnline ( ) ;
54+ } catch ( err ) {
55+ if ( opts . offline && err instanceof AIError && err . code === 'offline' ) {
56+ // 离线入队(不阻塞、不报错,联网后自动重放;测试环境无 indexedDB 时静默失败)
57+ offlineAIQueue . enqueue ( opts . offline . feature , opts . offline . endpoint , opts . offline . payload ) . catch ( ( ) => { } ) ;
58+ throw new AIError ( '当前处于离线状态,请求已加入队列,联网后自动完成' , 'offline' , false ) ;
59+ }
60+ throw err ;
61+ }
5062 ensureMinLength ( opts . contentCheck ) ;
5163 const plugin = await getAIPlugin ( ) ;
5264 const result = invoke ( plugin ) ;
@@ -75,10 +87,15 @@ class AIPluginLoader {
7587
7688 // ── 非流式功能 ─────────────────────────────────────────
7789
78- /** 摘要功能 */
90+ /** 摘要功能(P2-11:离线入队,联网后自动重放) */
7991 async summarizeNote ( content : string , options ?: SummarizeOptions ) : Promise < SummarizeResult > {
8092 return this . call ( p => p . summarizeNote ( content , options ) ,
81- { contentCheck : content , unsupportedMsg : '当前 AI 插件不支持摘要' } ) ;
93+ { contentCheck : content , unsupportedMsg : '当前 AI 插件不支持摘要' ,
94+ offline : {
95+ feature : 'summarize' ,
96+ endpoint : '/api/v1/ai/summarize' ,
97+ payload : { text : content , options : { max_length : options ?. maxLength , style : options ?. style , language : options ?. language } } ,
98+ } } ) ;
8299 }
83100
84101 /** 闪卡生成 */
0 commit comments