@huyooo/ai-chat-bridge-electron 0.2.36 → 0.2.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{ipcMain as e,shell as s}from"electron";import*as t from"fs";import*as n from"path";import{HybridAgent as r,MODELS as o,DEFAULT_MODEL as a,isThrowableToolError as i}from"@huyooo/ai-chat-core";import{createSearchElectronBridge as c}from"@huyooo/ai-search/bridge/electron";import{createStorage as l}from"@huyooo/ai-chat-storage";import*as d from"zlib";var u=1,h=2,f=9,g=15,y=0,p=2,m=0,w=1,$=0,b=1;function S(e,s,t,n){return[17,e<<4|s,t<<4|n,0]}function E(e,s=!1,t=!0){const n=S(h,s?p:y,m,t?b:$),r=t?d.gzipSync(e):e,o=Buffer.alloc(4);return o.writeUInt32BE(r.length,0),Buffer.concat([Buffer.from(n),o,r])}import C from"ws";import{v4 as I}from"uuid";var A=class{config;ws=null;callbacks={};connectId="";isConnected=!1;sessionConfig={};constructor(e){this.config=e}getWsUrl(){return!1!==this.config.useAsyncMode?"wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async":"wss://openspeech.bytedance.com/api/v3/sauc/bigmodel"}getResourceId(){return this.config.resourceId||"volc.bigasr.sauc.duration"}connect(e,s={}){return new Promise((t,n)=>{this.callbacks=e,this.sessionConfig=s,this.connectId=I();const r=this.getWsUrl();this.ws=new C(r,{headers:{"X-Api-App-Key":this.config.appId,"X-Api-Access-Key":this.config.accessKey,"X-Api-Resource-Id":this.getResourceId(),"X-Api-Connect-Id":this.connectId}}),this.ws.on("open",()=>{this.isConnected=!0,this.sendFullClientRequest(),this.callbacks.onConnected?.(),t()}),this.ws.on("message",e=>{try{const s=function(e){if(e.length<4)throw new Error("Invalid response: too short");const s=e[0],t=e[1],n=e[2],r=s>>4&15,o=4*(15&s),a=t>>4&15,i=15&t,c=n>>4&15,l=15&n;if(1!==r)throw new Error(`Unsupported protocol version: ${r}`);let u,h=o;!(1&~i)&&e.length>=h+4&&(u=e.readUInt32BE(h),h+=4);const y=!(2&~i);if(a===g){const s=e.readUInt32BE(h);h+=4;const t=e.readUInt32BE(h);return h+=4,{type:"error",sequence:u,isLast:!0,data:{code:s,message:e.slice(h,h+t).toString("utf-8")}}}if(a===f){const s=e.readUInt32BE(h);if(h+=4,0===s)return{type:"result",sequence:u,isLast:y,data:{}};let t,n=e.slice(h,h+s);if(l===b)try{n=d.gunzipSync(n)}catch(e){throw e}if(c===w){const e=n.toString("utf-8");try{t=JSON.parse(e)}catch(e){throw e}}else t={};return{type:"result",sequence:u,isLast:y,data:t}}throw new Error(`Unknown message type: ${a}`)}(e);if("error"===s.type){const e=s.data;this.callbacks.onError?.(new Error(`ASR Error ${e.code}: ${e.message}`))}else{const e=s.data;this.callbacks.onResult?.(e,s.isLast),s.isLast}}catch(e){this.callbacks.onError?.(e instanceof Error?e:new Error(String(e)))}}),this.ws.on("error",e=>{this.callbacks.onError?.(e),n(e)}),this.ws.on("close",()=>{this.isConnected=!1,this.ws=null,this.callbacks.onClose?.()})})}sendFullClientRequest(){if(!this.ws||this.ws.readyState!==C.OPEN)return;const e=function(e,s=!0){const t=S(u,y,w,s?b:$),n=JSON.stringify(e),r=Buffer.from(n,"utf-8"),o=s?d.gzipSync(r):r,a=Buffer.alloc(4);return a.writeUInt32BE(o.length,0),Buffer.concat([Buffer.from(t),a,o])}({user:{uid:"ai-chat-user"},audio:{format:this.sessionConfig.format||"pcm",rate:this.sessionConfig.sampleRate||16e3,bits:16,channel:1},request:{model_name:"bigmodel",enable_itn:this.sessionConfig.enableItn??!0,enable_punc:this.sessionConfig.enablePunc??!0,enable_ddc:this.sessionConfig.enableDdc??!1,show_utterances:this.sessionConfig.showUtterances??!0,result_type:"full"}});this.ws.send(e)}sendAudio(e){if(!this.ws||this.ws.readyState!==C.OPEN)return;const s=E(e,!1);this.ws.send(s)}finish(){if(!this.ws||this.ws.readyState!==C.OPEN)return;const e=E(Buffer.alloc(0),!0);this.ws.send(e)}disconnect(){this.ws&&(this.ws.close(),this.ws=null),this.isConnected=!1}get connected(){return this.isConnected&&this.ws?.readyState===C.OPEN}};import{ipcMain as D}from"electron";function v(e){const{channelPrefix:s="ai-chat",appId:t,accessKey:n,resourceId:r}=e,o=new Map;function a(e,s){let a=o.get(e);if(!a){a={client:new A({appId:t,accessKey:n,resourceId:r,useAsyncMode:!0}),webContents:s},o.set(e,a),s.on("destroyed",()=>{const s=o.get(e);s&&(s.client.disconnect(),o.delete(e))})}return a}return D.handle(`${s}:asr:start`,async(e,t)=>{const n=e.sender,r=a(n.id,n);r.client.connected&&r.client.disconnect();try{return await r.client.connect({onConnected:()=>{n.isDestroyed()||n.send(`${s}:asr:connected`)},onResult:(e,t)=>{n.isDestroyed()||n.send(`${s}:asr:result`,{result:e,isLast:t})},onError:e=>{n.isDestroyed()||n.send(`${s}:asr:error`,{message:e.message})},onClose:()=>{n.isDestroyed()||n.send(`${s}:asr:closed`)}},t),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),D.handle(`${s}:asr:sendAudio`,async(e,s)=>{const t=e.sender.id,n=o.get(t);if(!n||!n.client.connected)return{success:!1,error:"ASR 会话未启动"};try{const e=s instanceof ArrayBuffer?Buffer.from(s):Buffer.from(new Uint8Array(s));return n.client.sendAudio(e),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),D.handle(`${s}:asr:finish`,async e=>{const s=e.sender.id,t=o.get(s);if(!t||!t.client.connected)return{success:!1,error:"ASR 会话未启动"};try{return t.client.finish(),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),D.handle(`${s}:asr:stop`,async e=>{const s=e.sender.id,t=o.get(s);return t&&t.client.disconnect(),{success:!0}}),D.handle(`${s}:asr:status`,async e=>{const s=e.sender.id,t=o.get(s);return{connected:t?.client.connected??!1}}),D.handle(`${s}:asr:warmup`,async(e,s)=>{const t=e.sender,n=a(t.id,t);if(n.client.connected)return{success:!0};try{return await n.client.connect({onConnected:()=>{},onResult:()=>{},onError:()=>{},onClose:()=>{}},s),n.client.disconnect(),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),{cleanup:()=>{for(const e of o.values())e.client.disconnect();o.clear()}}}async function U(d){const{channelPrefix:u="ai-chat",dataDir:h,defaultContext:f={},...g}=d,y=n.join(h,"db.sqlite");c({ipcMain:e,channelPrefix:u}).init();const p=new Map,m=await l({type:"sqlite",sqlitePath:y}),w=()=>f,$=new r({...g,tools:d.tools,onToolApprovalRequest:async e=>{const s=global.currentWebContents;return!s||new Promise((t,n)=>{p.set(e.id,{resolve:t,reject:n,webContents:s}),s.send(`${u}:toolApprovalRequest`,{id:e.id,name:e.name,args:e.args})})},getAutoRunConfig:async()=>{try{const e=await m.getUserSetting("autoRunConfig",w());if(e)return JSON.parse(e)}catch(e){}}});e.handle(`${u}:models`,()=>o),e.handle(`${u}:getAllTools`,async()=>{0===$.tools.size&&$.toolConfig?await $.asyncInit():$.toolConfig;return $.getAllTools()}),e.handle(`${u}:getToolDefinitions`,async()=>{0===$.tools.size&&$.toolConfig&&await $.asyncInit();return Array.from($.tools.values()).map(e=>({name:e.name,description:e.description,parameters:{type:"object",properties:e.parameters?.properties||{},required:e.parameters?.required||[]}}))}),e.handle(`${u}:executeTool`,async(e,s)=>{const{name:t,args:n}=s;0===$.tools.size&&$.toolConfig&&await $.asyncInit();try{const e=await $.executeTool(t,n),s="string"==typeof e?e:e&&"object"==typeof e&&"result"in e?e.result:JSON.stringify(e),r=$.tools.get(t),o=r?.resultType;return{success:!0,result:s,resultType:o}}catch(e){const s={success:!1,result:"",error:e instanceof Error?e.message:String(e)},t=i(e)?e.toolError:void 0;return t?{...s,toolError:t}:s}}),e.handle(`${u}:send`,async(e,s)=>{const t=e.sender,{message:n,images:r,sessionId:o}=s;let a=s.options||{};d.beforeChat&&(a=await d.beforeChat(a)||a),global.currentWebContents=t;try{for await(const e of $.chat(n,a,r))t.isDestroyed()||t.send(`${u}:progress`,{...e,sessionId:o})}catch(e){if(Error,!t.isDestroyed()){const s=e instanceof Error?{category:"api",message:e.message||String(e),cause:e.stack}:{category:"api",message:String(e)};t.send(`${u}:progress`,{type:"error",data:s,sessionId:o})}}finally{delete global.currentWebContents}}),e.handle(`${u}:toolApprovalResponse`,(e,s)=>{const{id:t,approved:n}=s,r=p.get(t);r&&(p.delete(t),r.resolve(n))}),e.handle(`${u}:cancel`,()=>{$.abort()}),e.handle(`${u}:settings:get`,async(e,s)=>m.getUserSetting(s,w())),e.handle(`${u}:settings:set`,async(e,s,t)=>(await m.setUserSetting(s,t,w()),{success:!0})),e.handle(`${u}:settings:getAll`,async()=>m.getUserSettings(w())),e.handle(`${u}:settings:delete`,async(e,s)=>(await m.deleteUserSetting(s,w()),{success:!0})),e.handle(`${u}:setCwd`,(e,s)=>{$.setCwd(s)}),e.handle(`${u}:config`,()=>$.getConfig()),e.handle(`${u}:sessions:list`,async()=>m.getSessions(w())),e.handle(`${u}:sessions:get`,async(e,s)=>m.getSession(s,w())),e.handle(`${u}:sessions:create`,async(e,s)=>{const t={id:s.id||crypto.randomUUID(),title:s.title||"新对话",model:s.model||a,mode:s.mode||"agent",webSearchEnabled:s.webSearchEnabled??!0,thinkingEnabled:s.thinkingEnabled??!0,hidden:s.hidden??!1};return m.createSession(t,w())}),e.handle(`${u}:sessions:update`,async(e,s,t)=>(await m.updateSession(s,t,w()),m.getSession(s,w()))),e.handle(`${u}:sessions:delete`,async(e,s)=>(await m.deleteSession(s,w()),{success:!0})),e.handle(`${u}:messages:list`,async(e,s)=>m.getMessages(s,w())),e.handle(`${u}:messages:save`,async(e,s)=>{const t=s.id||crypto.randomUUID(),n={id:t,clientId:t,sessionId:s.sessionId,role:s.role,content:s.content,images:s.images||[],model:s.model||null,mode:s.mode||null,webSearchEnabled:s.webSearchEnabled??null,thinkingEnabled:s.thinkingEnabled??null,steps:s.steps||null,operationIds:s.operationIds||null};return m.saveMessage(n,w())}),e.handle(`${u}:messages:update`,async(e,s)=>(await m.updateMessage(s.id,{content:s.content,steps:s.steps,usage:s.usage,duration:s.duration},w()),{success:!0})),e.handle(`${u}:messages:deleteAfter`,async(e,s,t)=>(await m.deleteMessagesAfter(s,new Date(t),w()),{success:!0})),e.handle(`${u}:messages:deleteAfterMessageId`,async(e,s,t)=>(await m.deleteMessagesAfterMessageId(s,t,w()),{success:!0})),e.handle(`${u}:operations:list`,async(e,s)=>m.getOperations(s,w())),e.handle(`${u}:trash:list`,async()=>m.getTrashItems?.(w())||[]),e.handle(`${u}:trash:restore`,async(e,s)=>m.restoreFromTrash?.(s,w())),e.handle(`${u}:openExternal`,async(e,t)=>s.openExternal(t)),e.handle(`${u}:fs:listDir`,async(e,s)=>{try{const e=t.readdirSync(s,{withFileTypes:!0}),r=[];for(const o of e){if(o.name.startsWith("."))continue;const e=n.join(s,o.name);try{const s=t.statSync(e);r.push({name:o.name,path:e,isDirectory:o.isDirectory(),size:s.size,modifiedAt:s.mtime,extension:o.isDirectory()?"":n.extname(o.name).toLowerCase()})}catch{}}return r.sort((e,s)=>e.isDirectory&&!s.isDirectory?-1:!e.isDirectory&&s.isDirectory?1:e.name.localeCompare(s.name))}catch(e){return[]}}),e.handle(`${u}:fs:exists`,async(e,s)=>t.existsSync(s)),e.handle(`${u}:fs:stat`,async(e,s)=>{try{const e=t.statSync(s);return{name:n.basename(s),path:s,isDirectory:e.isDirectory(),size:e.size,modifiedAt:e.mtime,extension:e.isDirectory()?"":n.extname(s).toLowerCase()}}catch{return null}}),e.handle(`${u}:fs:readFile`,async(e,s)=>{try{return t.readFileSync(s,"utf-8")}catch{return null}}),e.handle(`${u}:fs:readFileBase64`,async(e,s)=>{try{return t.readFileSync(s).toString("base64")}catch{return null}}),e.handle(`${u}:fs:homeDir`,async()=>process.env.HOME||process.env.USERPROFILE||"/"),e.handle(`${u}:fs:resolvePath`,async(e,s)=>{if(s.startsWith("~")){const e=process.env.HOME||process.env.USERPROFILE||"/";return n.join(e,s.slice(1))}return n.resolve(s)}),e.handle(`${u}:fs:parentDir`,async(e,s)=>n.dirname(s));const b=new Map;return e.handle(`${u}:fs:watchDir`,async(e,s)=>{const n=e.sender;b.has(s)&&(b.get(s)?.close(),b.delete(s));try{const e=t.watch(s,{persistent:!1},(e,t)=>{n.isDestroyed()||n.send(`${u}:fs:dirChange`,{dirPath:s,eventType:e,filename:t})});return e.on("error",e=>{b.delete(s)}),b.set(s,e),!0}catch(e){return!1}}),e.handle(`${u}:fs:unwatchDir`,async(e,s)=>{const t=b.get(s);t&&(t.close(),b.delete(s))}),{agent:$,storage:m}}export{o as MODELS,v as createAsrBridge,U as createElectronBridge};
1
+ import{ipcMain as e,shell as s}from"electron";import*as t from"fs";import*as n from"path";import{HybridAgent as r,MODELS as o,DEFAULT_MODEL as a,isThrowableToolError as c}from"@huyooo/ai-chat-core";import{createStorage as i}from"@huyooo/ai-chat-storage";import*as l from"zlib";var d=1,u=2,h=9,f=15,g=0,y=2,p=0,m=1,w=0,$=1;function b(e,s,t,n){return[17,e<<4|s,t<<4|n,0]}function S(e,s=!1,t=!0){const n=b(u,s?y:g,p,t?$:w),r=t?l.gzipSync(e):e,o=Buffer.alloc(4);return o.writeUInt32BE(r.length,0),Buffer.concat([Buffer.from(n),o,r])}import E from"ws";import{v4 as C}from"uuid";var I=class{config;ws=null;callbacks={};connectId="";isConnected=!1;sessionConfig={};constructor(e){this.config=e}getWsUrl(){return!1!==this.config.useAsyncMode?"wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async":"wss://openspeech.bytedance.com/api/v3/sauc/bigmodel"}getResourceId(){return this.config.resourceId||"volc.bigasr.sauc.duration"}connect(e,s={}){return new Promise((t,n)=>{this.callbacks=e,this.sessionConfig=s,this.connectId=C();const r=this.getWsUrl();this.ws=new E(r,{headers:{"X-Api-App-Key":this.config.appId,"X-Api-Access-Key":this.config.accessKey,"X-Api-Resource-Id":this.getResourceId(),"X-Api-Connect-Id":this.connectId}}),this.ws.on("open",()=>{this.isConnected=!0,this.sendFullClientRequest(),this.callbacks.onConnected?.(),t()}),this.ws.on("message",e=>{try{const s=function(e){if(e.length<4)throw new Error("Invalid response: too short");const s=e[0],t=e[1],n=e[2],r=s>>4&15,o=4*(15&s),a=t>>4&15,c=15&t,i=n>>4&15,d=15&n;if(1!==r)throw new Error(`Unsupported protocol version: ${r}`);let u,g=o;!(1&~c)&&e.length>=g+4&&(u=e.readUInt32BE(g),g+=4);const y=!(2&~c);if(a===f){const s=e.readUInt32BE(g);g+=4;const t=e.readUInt32BE(g);return g+=4,{type:"error",sequence:u,isLast:!0,data:{code:s,message:e.slice(g,g+t).toString("utf-8")}}}if(a===h){const s=e.readUInt32BE(g);if(g+=4,0===s)return{type:"result",sequence:u,isLast:y,data:{}};let t,n=e.slice(g,g+s);if(d===$)try{n=l.gunzipSync(n)}catch(e){throw e}if(i===m){const e=n.toString("utf-8");try{t=JSON.parse(e)}catch(e){throw e}}else t={};return{type:"result",sequence:u,isLast:y,data:t}}throw new Error(`Unknown message type: ${a}`)}(e);if("error"===s.type){const e=s.data;this.callbacks.onError?.(new Error(`ASR Error ${e.code}: ${e.message}`))}else{const e=s.data;this.callbacks.onResult?.(e,s.isLast),s.isLast}}catch(e){this.callbacks.onError?.(e instanceof Error?e:new Error(String(e)))}}),this.ws.on("error",e=>{this.callbacks.onError?.(e),n(e)}),this.ws.on("close",()=>{this.isConnected=!1,this.ws=null,this.callbacks.onClose?.()})})}sendFullClientRequest(){if(!this.ws||this.ws.readyState!==E.OPEN)return;const e=function(e,s=!0){const t=b(d,g,m,s?$:w),n=JSON.stringify(e),r=Buffer.from(n,"utf-8"),o=s?l.gzipSync(r):r,a=Buffer.alloc(4);return a.writeUInt32BE(o.length,0),Buffer.concat([Buffer.from(t),a,o])}({user:{uid:"ai-chat-user"},audio:{format:this.sessionConfig.format||"pcm",rate:this.sessionConfig.sampleRate||16e3,bits:16,channel:1},request:{model_name:"bigmodel",enable_itn:this.sessionConfig.enableItn??!0,enable_punc:this.sessionConfig.enablePunc??!0,enable_ddc:this.sessionConfig.enableDdc??!1,show_utterances:this.sessionConfig.showUtterances??!0,result_type:"full"}});this.ws.send(e)}sendAudio(e){if(!this.ws||this.ws.readyState!==E.OPEN)return;const s=S(e,!1);this.ws.send(s)}finish(){if(!this.ws||this.ws.readyState!==E.OPEN)return;const e=S(Buffer.alloc(0),!0);this.ws.send(e)}disconnect(){this.ws&&(this.ws.close(),this.ws=null),this.isConnected=!1}get connected(){return this.isConnected&&this.ws?.readyState===E.OPEN}};import{ipcMain as A}from"electron";function D(e){const{channelPrefix:s="ai-chat",appId:t,accessKey:n,resourceId:r}=e,o=new Map;function a(e,s){let a=o.get(e);if(!a){a={client:new I({appId:t,accessKey:n,resourceId:r,useAsyncMode:!0}),webContents:s},o.set(e,a),s.on("destroyed",()=>{const s=o.get(e);s&&(s.client.disconnect(),o.delete(e))})}return a}return A.handle(`${s}:asr:start`,async(e,t)=>{const n=e.sender,r=a(n.id,n);r.client.connected&&r.client.disconnect();try{return await r.client.connect({onConnected:()=>{n.isDestroyed()||n.send(`${s}:asr:connected`)},onResult:(e,t)=>{n.isDestroyed()||n.send(`${s}:asr:result`,{result:e,isLast:t})},onError:e=>{n.isDestroyed()||n.send(`${s}:asr:error`,{message:e.message})},onClose:()=>{n.isDestroyed()||n.send(`${s}:asr:closed`)}},t),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),A.handle(`${s}:asr:sendAudio`,async(e,s)=>{const t=e.sender.id,n=o.get(t);if(!n||!n.client.connected)return{success:!1,error:"ASR 会话未启动"};try{const e=s instanceof ArrayBuffer?Buffer.from(s):Buffer.from(new Uint8Array(s));return n.client.sendAudio(e),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),A.handle(`${s}:asr:finish`,async e=>{const s=e.sender.id,t=o.get(s);if(!t||!t.client.connected)return{success:!1,error:"ASR 会话未启动"};try{return t.client.finish(),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),A.handle(`${s}:asr:stop`,async e=>{const s=e.sender.id,t=o.get(s);return t&&t.client.disconnect(),{success:!0}}),A.handle(`${s}:asr:status`,async e=>{const s=e.sender.id,t=o.get(s);return{connected:t?.client.connected??!1}}),A.handle(`${s}:asr:warmup`,async(e,s)=>{const t=e.sender,n=a(t.id,t);if(n.client.connected)return{success:!0};try{return await n.client.connect({onConnected:()=>{},onResult:()=>{},onError:()=>{},onClose:()=>{}},s),n.client.disconnect(),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),{cleanup:()=>{for(const e of o.values())e.client.disconnect();o.clear()}}}async function v(l){const{channelPrefix:d="ai-chat",dataDir:u,defaultContext:h={},...f}=l,g=n.join(u,"db.sqlite"),y=new Map,p=await i({type:"sqlite",sqlitePath:g}),m=()=>h,w=new r({...f,tools:l.tools,onToolApprovalRequest:async e=>{const s=global.currentWebContents;return!s||new Promise((t,n)=>{y.set(e.id,{resolve:t,reject:n,webContents:s}),s.send(`${d}:toolApprovalRequest`,{id:e.id,name:e.name,args:e.args})})},getAutoRunConfig:async()=>{try{const e=await p.getUserSetting("autoRunConfig",m());if(e)return JSON.parse(e)}catch(e){}}});e.handle(`${d}:models`,()=>o),e.handle(`${d}:getAllTools`,async()=>{0===w.tools.size&&w.toolConfig?await w.asyncInit():w.toolConfig;return w.getAllTools()}),e.handle(`${d}:getToolDefinitions`,async()=>{0===w.tools.size&&w.toolConfig&&await w.asyncInit();return Array.from(w.tools.values()).map(e=>({name:e.name,description:e.description,parameters:{type:"object",properties:e.parameters?.properties||{},required:e.parameters?.required||[]}}))}),e.handle(`${d}:executeTool`,async(e,s)=>{const{name:t,args:n}=s;0===w.tools.size&&w.toolConfig&&await w.asyncInit();try{const e=await w.executeTool(t,n),s="string"==typeof e?e:e&&"object"==typeof e&&"result"in e?e.result:JSON.stringify(e),r=w.tools.get(t),o=r?.resultType;return{success:!0,result:s,resultType:o}}catch(e){const s={success:!1,result:"",error:e instanceof Error?e.message:String(e)},t=c(e)?e.toolError:void 0;return t?{...s,toolError:t}:s}}),e.handle(`${d}:send`,async(e,s)=>{const t=e.sender,{message:n,images:r,sessionId:o}=s;let a=s.options||{};l.beforeChat&&(a=await l.beforeChat(a)||a),global.currentWebContents=t;try{for await(const e of w.chat(n,a,r))t.isDestroyed()||t.send(`${d}:progress`,{...e,sessionId:o})}catch(e){if(Error,!t.isDestroyed()){const s=e instanceof Error?{category:"api",message:e.message||String(e),cause:e.stack}:{category:"api",message:String(e)};t.send(`${d}:progress`,{type:"error",data:s,sessionId:o})}}finally{delete global.currentWebContents}}),e.handle(`${d}:toolApprovalResponse`,(e,s)=>{const{id:t,approved:n}=s,r=y.get(t);r&&(y.delete(t),r.resolve(n))}),e.handle(`${d}:cancel`,()=>{w.abort()}),e.handle(`${d}:settings:get`,async(e,s)=>p.getUserSetting(s,m())),e.handle(`${d}:settings:set`,async(e,s,t)=>(await p.setUserSetting(s,t,m()),{success:!0})),e.handle(`${d}:settings:getAll`,async()=>p.getUserSettings(m())),e.handle(`${d}:settings:delete`,async(e,s)=>(await p.deleteUserSetting(s,m()),{success:!0})),e.handle(`${d}:setCwd`,(e,s)=>{w.setCwd(s)}),e.handle(`${d}:config`,()=>w.getConfig()),e.handle(`${d}:sessions:list`,async()=>p.getSessions(m())),e.handle(`${d}:sessions:get`,async(e,s)=>p.getSession(s,m())),e.handle(`${d}:sessions:create`,async(e,s)=>{const t={id:s.id||crypto.randomUUID(),title:s.title||"新对话",model:s.model||a,mode:s.mode||"agent",webSearchEnabled:s.webSearchEnabled??!0,thinkingEnabled:s.thinkingEnabled??!0,hidden:s.hidden??!1};return p.createSession(t,m())}),e.handle(`${d}:sessions:update`,async(e,s,t)=>(await p.updateSession(s,t,m()),p.getSession(s,m()))),e.handle(`${d}:sessions:delete`,async(e,s)=>(await p.deleteSession(s,m()),{success:!0})),e.handle(`${d}:messages:list`,async(e,s)=>p.getMessages(s,m())),e.handle(`${d}:messages:save`,async(e,s)=>{const t=s.id||crypto.randomUUID(),n={id:t,clientId:t,sessionId:s.sessionId,role:s.role,content:s.content,images:s.images||[],model:s.model||null,mode:s.mode||null,webSearchEnabled:s.webSearchEnabled??null,thinkingEnabled:s.thinkingEnabled??null,steps:s.steps||null,operationIds:s.operationIds||null};return p.saveMessage(n,m())}),e.handle(`${d}:messages:update`,async(e,s)=>(await p.updateMessage(s.id,{content:s.content,steps:s.steps,usage:s.usage,duration:s.duration},m()),{success:!0})),e.handle(`${d}:messages:deleteAfter`,async(e,s,t)=>(await p.deleteMessagesAfter(s,new Date(t),m()),{success:!0})),e.handle(`${d}:messages:deleteAfterMessageId`,async(e,s,t)=>(await p.deleteMessagesAfterMessageId(s,t,m()),{success:!0})),e.handle(`${d}:operations:list`,async(e,s)=>p.getOperations(s,m())),e.handle(`${d}:trash:list`,async()=>p.getTrashItems?.(m())||[]),e.handle(`${d}:trash:restore`,async(e,s)=>p.restoreFromTrash?.(s,m())),e.handle(`${d}:openExternal`,async(e,t)=>s.openExternal(t)),e.handle(`${d}:fs:listDir`,async(e,s)=>{try{const e=t.readdirSync(s,{withFileTypes:!0}),r=[];for(const o of e){if(o.name.startsWith("."))continue;const e=n.join(s,o.name);try{const s=t.statSync(e);r.push({name:o.name,path:e,isDirectory:o.isDirectory(),size:s.size,modifiedAt:s.mtime,extension:o.isDirectory()?"":n.extname(o.name).toLowerCase()})}catch{}}return r.sort((e,s)=>e.isDirectory&&!s.isDirectory?-1:!e.isDirectory&&s.isDirectory?1:e.name.localeCompare(s.name))}catch(e){return[]}}),e.handle(`${d}:fs:exists`,async(e,s)=>t.existsSync(s)),e.handle(`${d}:fs:stat`,async(e,s)=>{try{const e=t.statSync(s);return{name:n.basename(s),path:s,isDirectory:e.isDirectory(),size:e.size,modifiedAt:e.mtime,extension:e.isDirectory()?"":n.extname(s).toLowerCase()}}catch{return null}}),e.handle(`${d}:fs:readFile`,async(e,s)=>{try{return t.readFileSync(s,"utf-8")}catch{return null}}),e.handle(`${d}:fs:readFileBase64`,async(e,s)=>{try{return t.readFileSync(s).toString("base64")}catch{return null}}),e.handle(`${d}:fs:homeDir`,async()=>process.env.HOME||process.env.USERPROFILE||"/"),e.handle(`${d}:fs:resolvePath`,async(e,s)=>{if(s.startsWith("~")){const e=process.env.HOME||process.env.USERPROFILE||"/";return n.join(e,s.slice(1))}return n.resolve(s)}),e.handle(`${d}:fs:parentDir`,async(e,s)=>n.dirname(s));const $=new Map;return e.handle(`${d}:fs:watchDir`,async(e,s)=>{const n=e.sender;$.has(s)&&($.get(s)?.close(),$.delete(s));try{const e=t.watch(s,{persistent:!1},(e,t)=>{n.isDestroyed()||n.send(`${d}:fs:dirChange`,{dirPath:s,eventType:e,filename:t})});return e.on("error",e=>{$.delete(s)}),$.set(s,e),!0}catch(e){return!1}}),e.handle(`${d}:fs:unwatchDir`,async(e,s)=>{const t=$.get(s);t&&(t.close(),$.delete(s))}),{agent:w,storage:p}}export{o as MODELS,D as createAsrBridge,v as createElectronBridge};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huyooo/ai-chat-bridge-electron",
3
- "version": "0.2.36",
3
+ "version": "0.2.40",
4
4
  "description": "AI Chat Electron Bridge - IPC integration for Electron apps",
5
5
  "type": "module",
6
6
  "main": "./dist/main/index.js",
@@ -30,10 +30,9 @@
30
30
  "clean": "rm -rf dist"
31
31
  },
32
32
  "dependencies": {
33
- "@huyooo/ai-chat-types": "^0.2.36",
34
- "@huyooo/ai-chat-core": "^0.2.36",
35
- "@huyooo/ai-chat-storage": "^0.2.36",
36
- "@huyooo/ai-search": "^0.2.36",
33
+ "@huyooo/ai-chat-core": "^0.2.40",
34
+ "@huyooo/ai-chat-storage": "^0.2.40",
35
+ "@huyooo/ai-chat-types": "^0.2.40",
37
36
  "uuid": "^11.1.0",
38
37
  "ws": "^8.18.3"
39
38
  },