@huyooo/ai-chat-bridge-electron 0.2.21 → 0.2.23

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,4 +1,4 @@
1
- import { AgentConfig, ToolConfigItem, HybridAgent } from '@huyooo/ai-chat-core';
1
+ import { AgentConfig, ToolConfigItem, ChatOptions, HybridAgent } from '@huyooo/ai-chat-core';
2
2
  export { AgentConfig, ChatEvent, ChatMode, ChatOptions, MODELS, ProviderType } from '@huyooo/ai-chat-core';
3
3
  import { StorageContext, StorageAdapter } from '@huyooo/ai-chat-storage';
4
4
  export { MessageRecord, SessionRecord, StorageAdapter, StorageContext } from '@huyooo/ai-chat-storage';
@@ -191,6 +191,11 @@ interface ElectronBridgeOptions extends Omit<AgentConfig, 'tools'> {
191
191
  * 支持:ToolPlugin、Promise<ToolPlugin>
192
192
  */
193
193
  tools?: ToolConfigItem[];
194
+ /**
195
+ * 发送消息前的钩子(可注入额外 options,如本地 Skills 内容)
196
+ * 返回修改后的 options,或 undefined 保持不变
197
+ */
198
+ beforeChat?: (options: ChatOptions) => ChatOptions | Promise<ChatOptions>;
194
199
  }
195
200
  /**
196
201
  * 创建 Electron IPC 桥接
@@ -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}from"@huyooo/ai-chat-core";import{createSearchElectronBridge as c}from"@huyooo/ai-search/bridge/electron";import{createStorage as i}from"@huyooo/ai-chat-storage";import*as l from"zlib";var d=1,u=2,h=9,g=15,f=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:f,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,f=o;!(1&~c)&&e.length>=f+4&&(u=e.readUInt32BE(f),f+=4);const y=!(2&~c);if(a===g){const s=e.readUInt32BE(f);f+=4;const t=e.readUInt32BE(f);return f+=4,{type:"error",sequence:u,isLast:!0,data:{code:s,message:e.slice(f,f+t).toString("utf-8")}}}if(a===h){const s=e.readUInt32BE(f);if(f+=4,0===s)return{type:"result",sequence:u,isLast:y,data:{}};let t,n=e.slice(f,f+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,f,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={},...g}=l,f=n.join(u,"db.sqlite");c({ipcMain:e,channelPrefix:d}).init();const y=new Map,p=await i({type:"sqlite",sqlitePath:f}),m=()=>h,w=new r({...g,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){return{success:!1,result:"",error:e instanceof Error?e.message:String(e)}}}),e.handle(`${d}:send`,async(e,s)=>{const t=e.sender,{message:n,images:r,options:o={},sessionId:a}=s;global.currentWebContents=t;try{for await(const e of w.chat(n,o,r))t.isDestroyed()||t.send(`${d}:progress`,{...e,sessionId:a})}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:a})}}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};
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}from"@huyooo/ai-chat-core";import{createSearchElectronBridge as i}from"@huyooo/ai-search/bridge/electron";import{createStorage as c}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,i=15&t,c=n>>4&15,d=15&n;if(1!==r)throw new Error(`Unsupported protocol version: ${r}`);let u,g=o;!(1&~i)&&e.length>=g+4&&(u=e.readUInt32BE(g),g+=4);const y=!(2&~i);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(c===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");i({ipcMain:e,channelPrefix:d}).init();const y=new Map,p=await c({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){return{success:!1,result:"",error:e instanceof Error?e.message:String(e)}}}),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};
@@ -1 +1 @@
1
- function e(){try{return"undefined"!=typeof localStorage&&"true"===localStorage.getItem("AI_CHAT_DEBUG")}catch{return!1}}function s(s){return{debug:(...s)=>{e()},info:(...s)=>{e()},warn:(...e)=>{},error:(...e)=>{}}}export*from"@huyooo/ai-chat-types";var t=s();function n(e={}){const{bridgeName:s="aiChatBridge"}=e,t=()=>{const e=window[s];if(!e)throw new Error("AI Chat Bridge not found. Make sure to call exposeElectronBridge() in preload.");return e};return{getModels:async()=>t().getModels(),async getAllTools(){const e=t();return"function"==typeof e.getAllTools?e.getAllTools():[]},async*sendMessage(e,s,n,r){const a=t(),o=[];let c=null,i=!1;const l=a.onProgress(e=>{const s=e;r&&s.sessionId&&s.sessionId!==r||(o.push(e),c?.(),"done"!==e.type&&"error"!==e.type||(i=!0))});a.send({message:e,images:n,options:s,sessionId:r});try{for(;!i||o.length>0;){for(;0===o.length&&!i;)await new Promise(e=>c=e);if(o.length>0){const e=o.shift();if(yield e,"done"===e.type||"error"===e.type)break}}}finally{l()}},cancel(){t().cancel()},setCwd(e){t().setCwd(e)},getSessions:async()=>t().getSessions(),getSession:async e=>t().getSession(e),createSession:async e=>t().createSession(e),updateSession:async(e,s)=>t().updateSession(e,s),async deleteSession(e){await t().deleteSession(e)},getMessages:async e=>t().getMessages(e),saveMessage:async e=>t().saveMessage(e),async updateMessage(e){await t().updateMessage(e)},async deleteMessagesAfter(e,s){await t().deleteMessagesAfter(e,s)},async deleteMessagesAfterMessageId(e,s){await t().deleteMessagesAfterMessageId(e,s)},getOperations:async e=>t().getOperations(e),getTrashItems:async()=>t().getTrashItems(),restoreFromTrash:async e=>t().restoreFromTrash(e),listDir:async e=>t().listDir(e),exists:async e=>t().exists(e),stat:async e=>t().stat(e),readFile:async e=>t().readFile(e),readFileBase64:async e=>t().readFileBase64(e),homeDir:async()=>t().homeDir(),resolvePath:async e=>t().resolvePath(e),parentDir:async e=>t().parentDir(e),watchDir:async e=>t().watchDir(e),unwatchDir:async e=>t().unwatchDir(e),onDirChange:e=>t().onDirChange(e),async getSetting(e){const s=t();return s.getSetting?s.getSetting(e):null},async setSetting(e,s){const n=t();n.setSetting&&await n.setSetting(e,s)},async getAllSettings(){const e=t();return e.getAllSettings?e.getAllSettings():{}},async deleteSetting(e){const s=t();s.deleteSetting&&await s.deleteSetting(e)},async getIndexStats(){const e=t();return e.getIndexStats?e.getIndexStats():{totalDocuments:0,indexSize:0,lastUpdated:null}},async getIndexStatus(){const e=t();return e.getIndexStatus?e.getIndexStatus():{isIndexing:!1,lastProgress:null}},async syncIndex(){const e=t();return e.syncIndex?e.syncIndex():{success:!1}},async cancelIndex(){const e=t();return e.cancelIndex?e.cancelIndex():{success:!1}},async deleteIndex(){const e=t();return e.deleteIndex?e.deleteIndex():{success:!1}},async registerIndexListener(){const e=t();return e.registerIndexListener?e.registerIndexListener():{success:!1}},async unregisterIndexListener(){const e=t();return e.unregisterIndexListener?e.unregisterIndexListener():{success:!1}},onIndexProgress(e){const s=t();return s.onIndexProgress?s.onIndexProgress(e):()=>{}},onToolApprovalRequest(e){const s=t();return s.onToolApprovalRequest?s.onToolApprovalRequest(e):()=>{}},async respondToolApproval(e,s){const n=t();if(n.respondToolApproval)return n.respondToolApproval(e,s)},async asrStart(e){const s=t();return s.asrStart?s.asrStart(e):{success:!1,error:"ASR not supported"}},async asrSendAudio(e){const s=t();return s.asrSendAudio?s.asrSendAudio(e):{success:!1,error:"ASR not supported"}},async asrFinish(){const e=t();return e.asrFinish?e.asrFinish():{success:!1,error:"ASR not supported"}},async asrStop(){const e=t();return e.asrStop?e.asrStop():{success:!0}},async asrStatus(){const e=t();return e.asrStatus?e.asrStatus():{connected:!1}},async asrWarmup(e){const s=t();return s.asrWarmup?s.asrWarmup(e):{success:!1,error:"ASR not supported"}},onAsrConnected(e){const s=t();return s.onAsrConnected?s.onAsrConnected(e):()=>{}},onAsrResult(e){const s=t();return s.onAsrResult?s.onAsrResult(e):()=>{}},onAsrError(e){const s=t();return s.onAsrError?s.onAsrError(e):()=>{}},onAsrClosed(e){const s=t();return s.onAsrClosed?s.onAsrClosed(e):()=>{}},async openExternal(e){const s=t();if(s.openExternal)return s.openExternal(e)}}}function r(e){const{bridgeName:s="aiChatBridge",remote:n}=e,{baseURL:r,getToken:a,getAppId:o}=n,c=()=>{const e=window[s];if(!e)throw new Error("AI Chat Bridge not found. Make sure to call exposeElectronBridge() in preload.");return e};async function i(){const e=await a(),s=o?await o():null,t={};return e&&(t.Authorization=`Bearer ${e}`),s&&(t["app-id"]=s),t}async function l(e,s={}){const t=await i(),n=s.method?.toUpperCase()||"GET";["POST","PUT","PATCH"].includes(n)&&(t["Content-Type"]="application/json");const a=await fetch(`${r}${e}`,{...s,headers:{...t,...s.headers||{}}});if(!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);return a.json()}function d(e){try{return JSON.parse(e)}catch{return null}}let u=null;return{getModels:async()=>(await l("/chat/models")).models||[],async getAllTools(){const e=c();return"function"==typeof e.getAllTools?e.getAllTools():[]},async*sendMessage(e,s,n,a){u&&u.abort(),u=new AbortController;const{signal:o}=u;try{const l=c(),u="function"==typeof l.getToolDefinitions?await l.getToolDefinitions():[];let g=e,y=s,p=n;for(let e=0;e<10;e++){const e=await i(),s=await fetch(`${r}/chat/stream`,{method:"POST",headers:{...e,"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify({message:g,options:y,images:p,sessionId:a,tools:u,skillContents:y?.skillContents}),signal:o});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);const n=s.body?.getReader();if(!n)throw new Error("Response body is not readable");const c=new TextDecoder;let S="",h=[],A="",f=!1;for(;;){const{done:e,value:s}=await n.read();if(e)break;S+=c.decode(s,{stream:!0});const r=S.split("\n");S=r.pop()||"";for(const e of r)if(e.startsWith("data: ")){const s=e.slice(6).trim();if("[DONE]"===s)break;const n=d(s);if(n)if("text_delta"===n.type&&(A+=n.data.content||""),"tool_call_request"===n.type){const{id:e,name:s,args:r}=n.data;t.debug("收到 tool_call_request:",s,"args:",JSON.stringify(r).slice(0,500)),h.push({id:e,name:s,args:r}),yield{type:"tool_call_start",data:{id:e,name:s,args:r,startedAt:Date.now()}}}else if("done"===n.type)h.length>0?f=!0:yield n;else if(yield n,"error"===n.type)return}}if(S.startsWith("data: ")){const e=S.slice(6).trim();if(e&&"[DONE]"!==e){const s=d(e);s&&"tool_call_request"!==s.type&&("done"===s.type&&h.length>0?f=!0:yield s)}}if(!(h.length>0&&f))break;{t.debug("执行工具:",h.map(e=>e.name).join(", "));const e=[];for(const s of h){const n=Date.now();t.debug(`executeTool(${s.name}) args:`,JSON.stringify(s.args).slice(0,500));const r=await l.executeTool(s.name,s.args);t.debug(`executeTool(${s.name}) result:`,JSON.stringify(r).slice(0,500)),yield{type:"tool_call_result",data:{id:s.id,name:s.name,result:r.result,success:r.success,error:r.error,resultType:r.resultType,endedAt:Date.now(),duration:Date.now()-n}},e.push({role:"tool",content:r.result,tool_call_id:s.id})}const s=h.map(e=>({id:e.id,type:"function",function:{name:e.name,arguments:JSON.stringify(e.args)}})),n=[...y?.history||[],...g?[{role:"user",content:g}]:[],{role:"assistant",content:A,tool_calls:s},...e];t.debug("继续对话,新 history 长度:",n.length),g="",y={...y,history:n},p=void 0,A=""}}}finally{u=null}},cancel(){u&&(u.abort(),u=null)},setCwd(e){c().setCwd(e)},getSessions:async()=>c().getSessions(),getSession:async e=>c().getSession(e),createSession:async e=>c().createSession(e),updateSession:async(e,s)=>c().updateSession(e,s),async deleteSession(e){await c().deleteSession(e)},getMessages:async e=>c().getMessages(e),saveMessage:async e=>c().saveMessage(e),async updateMessage(e){await c().updateMessage(e)},async deleteMessagesAfter(e,s){await c().deleteMessagesAfter(e,s)},async deleteMessagesAfterMessageId(e,s){await c().deleteMessagesAfterMessageId(e,s)},getOperations:async e=>c().getOperations(e),getTrashItems:async()=>c().getTrashItems(),restoreFromTrash:async e=>c().restoreFromTrash(e),getSkills:async()=>(await l("/skills/list",{method:"POST",body:JSON.stringify({})})).skills||[],createSkill:async e=>l("/skills/create",{method:"POST",body:JSON.stringify(e)}),async updateSkill(e,s){await l("/skills/update",{method:"POST",body:JSON.stringify({id:e,...s})})},async deleteSkill(e){await l("/skills/delete",{method:"POST",body:JSON.stringify({id:e})})},toggleSkill:async e=>l("/skills/toggle",{method:"POST",body:JSON.stringify({id:e})}),listDir:async e=>c().listDir(e),exists:async e=>c().exists(e),stat:async e=>c().stat(e),readFile:async e=>c().readFile(e),readFileBase64:async e=>c().readFileBase64(e),homeDir:async()=>c().homeDir(),resolvePath:async e=>c().resolvePath(e),parentDir:async e=>c().parentDir(e),watchDir:async e=>c().watchDir(e),unwatchDir:async e=>c().unwatchDir(e),onDirChange:e=>c().onDirChange(e),async getSetting(e){const s=c();return s.getSetting?s.getSetting(e):null},async setSetting(e,s){const t=c();t.setSetting&&await t.setSetting(e,s)},async getAllSettings(){const e=c();return e.getAllSettings?e.getAllSettings():{}},async deleteSetting(e){const s=c();s.deleteSetting&&await s.deleteSetting(e)},async getIndexStats(){const e=c();return e.getIndexStats?e.getIndexStats():{totalDocuments:0,indexSize:0,lastUpdated:null}},async getIndexStatus(){const e=c();return e.getIndexStatus?e.getIndexStatus():{isIndexing:!1,lastProgress:null}},async syncIndex(){const e=c();return e.syncIndex?e.syncIndex():{success:!1}},async cancelIndex(){const e=c();return e.cancelIndex?e.cancelIndex():{success:!1}},async deleteIndex(){const e=c();return e.deleteIndex?e.deleteIndex():{success:!1}},async registerIndexListener(){const e=c();return e.registerIndexListener?e.registerIndexListener():{success:!1}},async unregisterIndexListener(){const e=c();return e.unregisterIndexListener?e.unregisterIndexListener():{success:!1}},onIndexProgress(e){const s=c();return s.onIndexProgress?s.onIndexProgress(e):()=>{}},onToolApprovalRequest:e=>()=>{},async respondToolApproval(e,s){},async asrStart(e){const s=c();return s.asrStart?s.asrStart(e):{success:!1,error:"ASR not supported"}},async asrSendAudio(e){const s=c();return s.asrSendAudio?s.asrSendAudio(e):{success:!1,error:"ASR not supported"}},async asrFinish(){const e=c();return e.asrFinish?e.asrFinish():{success:!1,error:"ASR not supported"}},async asrStop(){const e=c();return e.asrStop?e.asrStop():{success:!0}},async asrStatus(){const e=c();return e.asrStatus?e.asrStatus():{connected:!1}},async asrWarmup(e){const s=c();return s.asrWarmup?s.asrWarmup(e):{success:!1,error:"ASR not supported"}},onAsrConnected(e){const s=c();return s.onAsrConnected?s.onAsrConnected(e):()=>{}},onAsrResult(e){const s=c();return s.onAsrResult?s.onAsrResult(e):()=>{}},onAsrError(e){const s=c();return s.onAsrError?s.onAsrError(e):()=>{}},onAsrClosed(e){const s=c();return s.onAsrClosed?s.onAsrClosed(e):()=>{}},async openExternal(e){const s=c();if(s.openExternal)return s.openExternal(e)}}}export{n as createElectronAdapter,r as createHybridAdapter,s as createLogger};
1
+ function e(){try{return"undefined"!=typeof localStorage&&"true"===localStorage.getItem("AI_CHAT_DEBUG")}catch{return!1}}function s(s){return{debug:(...s)=>{e()},info:(...s)=>{e()},warn:(...e)=>{},error:(...e)=>{}}}export*from"@huyooo/ai-chat-types";var t=s();function n(e={}){const{bridgeName:s="aiChatBridge"}=e,t=()=>{const e=window[s];if(!e)throw new Error("AI Chat Bridge not found. Make sure to call exposeElectronBridge() in preload.");return e};return{getModels:async()=>t().getModels(),async getAllTools(){const e=t();return"function"==typeof e.getAllTools?e.getAllTools():[]},async*sendMessage(e,s,n,r){const a=t(),o=[];let c=null,i=!1;const l=a.onProgress(e=>{const s=e;r&&s.sessionId&&s.sessionId!==r||(o.push(e),c?.(),"done"!==e.type&&"error"!==e.type||(i=!0))});a.send({message:e,images:n,options:s,sessionId:r});try{for(;!i||o.length>0;){for(;0===o.length&&!i;)await new Promise(e=>c=e);if(o.length>0){const e=o.shift();if(yield e,"done"===e.type||"error"===e.type)break}}}finally{l()}},cancel(){t().cancel()},setCwd(e){t().setCwd(e)},getSessions:async()=>t().getSessions(),getSession:async e=>t().getSession(e),createSession:async e=>t().createSession(e),updateSession:async(e,s)=>t().updateSession(e,s),async deleteSession(e){await t().deleteSession(e)},getMessages:async e=>t().getMessages(e),saveMessage:async e=>t().saveMessage(e),async updateMessage(e){await t().updateMessage(e)},async deleteMessagesAfter(e,s){await t().deleteMessagesAfter(e,s)},async deleteMessagesAfterMessageId(e,s){await t().deleteMessagesAfterMessageId(e,s)},getOperations:async e=>t().getOperations(e),getTrashItems:async()=>t().getTrashItems(),restoreFromTrash:async e=>t().restoreFromTrash(e),listDir:async e=>t().listDir(e),exists:async e=>t().exists(e),stat:async e=>t().stat(e),readFile:async e=>t().readFile(e),readFileBase64:async e=>t().readFileBase64(e),homeDir:async()=>t().homeDir(),resolvePath:async e=>t().resolvePath(e),parentDir:async e=>t().parentDir(e),watchDir:async e=>t().watchDir(e),unwatchDir:async e=>t().unwatchDir(e),onDirChange:e=>t().onDirChange(e),async getSetting(e){const s=t();return s.getSetting?s.getSetting(e):null},async setSetting(e,s){const n=t();n.setSetting&&await n.setSetting(e,s)},async getAllSettings(){const e=t();return e.getAllSettings?e.getAllSettings():{}},async deleteSetting(e){const s=t();s.deleteSetting&&await s.deleteSetting(e)},async getIndexStats(){const e=t();return e.getIndexStats?e.getIndexStats():{totalDocuments:0,indexSize:0,lastUpdated:null}},async getIndexStatus(){const e=t();return e.getIndexStatus?e.getIndexStatus():{isIndexing:!1,lastProgress:null}},async syncIndex(){const e=t();return e.syncIndex?e.syncIndex():{success:!1}},async cancelIndex(){const e=t();return e.cancelIndex?e.cancelIndex():{success:!1}},async deleteIndex(){const e=t();return e.deleteIndex?e.deleteIndex():{success:!1}},async registerIndexListener(){const e=t();return e.registerIndexListener?e.registerIndexListener():{success:!1}},async unregisterIndexListener(){const e=t();return e.unregisterIndexListener?e.unregisterIndexListener():{success:!1}},onIndexProgress(e){const s=t();return s.onIndexProgress?s.onIndexProgress(e):()=>{}},onToolApprovalRequest(e){const s=t();return s.onToolApprovalRequest?s.onToolApprovalRequest(e):()=>{}},async respondToolApproval(e,s){const n=t();if(n.respondToolApproval)return n.respondToolApproval(e,s)},async asrStart(e){const s=t();return s.asrStart?s.asrStart(e):{success:!1,error:"ASR not supported"}},async asrSendAudio(e){const s=t();return s.asrSendAudio?s.asrSendAudio(e):{success:!1,error:"ASR not supported"}},async asrFinish(){const e=t();return e.asrFinish?e.asrFinish():{success:!1,error:"ASR not supported"}},async asrStop(){const e=t();return e.asrStop?e.asrStop():{success:!0}},async asrStatus(){const e=t();return e.asrStatus?e.asrStatus():{connected:!1}},async asrWarmup(e){const s=t();return s.asrWarmup?s.asrWarmup(e):{success:!1,error:"ASR not supported"}},onAsrConnected(e){const s=t();return s.onAsrConnected?s.onAsrConnected(e):()=>{}},onAsrResult(e){const s=t();return s.onAsrResult?s.onAsrResult(e):()=>{}},onAsrError(e){const s=t();return s.onAsrError?s.onAsrError(e):()=>{}},onAsrClosed(e){const s=t();return s.onAsrClosed?s.onAsrClosed(e):()=>{}},async openExternal(e){const s=t();if(s.openExternal)return s.openExternal(e)}}}function r(e){const{bridgeName:s="aiChatBridge",remote:n}=e,{baseURL:r,getToken:a,getAppId:o}=n,c=()=>{const e=window[s];if(!e)throw new Error("AI Chat Bridge not found. Make sure to call exposeElectronBridge() in preload.");return e};async function i(){const e=await a(),s=o?await o():null,t={};return e&&(t.Authorization=`Bearer ${e}`),s&&(t["app-id"]=s),t}function l(e){try{return JSON.parse(e)}catch{return null}}let d=null;return{getModels:async()=>(await async function(e,s={}){const t=await i(),n=s.method?.toUpperCase()||"GET";["POST","PUT","PATCH"].includes(n)&&(t["Content-Type"]="application/json");const a=await fetch(`${r}${e}`,{...s,headers:{...t,...s.headers||{}}});if(!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);return a.json()}("/chat/models")).models||[],async getAllTools(){const e=c();return"function"==typeof e.getAllTools?e.getAllTools():[]},async*sendMessage(e,s,n,a){d&&d.abort(),d=new AbortController;const{signal:o}=d;try{const d=c(),u="function"==typeof d.getToolDefinitions?await d.getToolDefinitions():[];let g=e,y=s,p=n;for(let e=0;e<10;e++){const e=await i(),s=await fetch(`${r}/chat/stream`,{method:"POST",headers:{...e,"Content-Type":"application/json",Accept:"text/event-stream"},body:JSON.stringify({message:g,options:y,images:p,sessionId:a,tools:u}),signal:o});if(!s.ok)throw new Error(`HTTP ${s.status}: ${s.statusText}`);const n=s.body?.getReader();if(!n)throw new Error("Response body is not readable");const c=new TextDecoder;let S="",A=[],x="",h=!1;for(;;){const{done:e,value:s}=await n.read();if(e)break;S+=c.decode(s,{stream:!0});const r=S.split("\n");S=r.pop()||"";for(const e of r)if(e.startsWith("data: ")){const s=e.slice(6).trim();if("[DONE]"===s)break;const n=l(s);if(n)if("text_delta"===n.type&&(x+=n.data.content||""),"tool_call_request"===n.type){const{id:e,name:s,args:r}=n.data;t.debug("收到 tool_call_request:",s,"args:",JSON.stringify(r).slice(0,500)),A.push({id:e,name:s,args:r}),yield{type:"tool_call_start",data:{id:e,name:s,args:r,startedAt:Date.now()}}}else if("done"===n.type)A.length>0?h=!0:yield n;else if(yield n,"error"===n.type)return}}if(S.startsWith("data: ")){const e=S.slice(6).trim();if(e&&"[DONE]"!==e){const s=l(e);s&&"tool_call_request"!==s.type&&("done"===s.type&&A.length>0?h=!0:yield s)}}if(!(A.length>0&&h))break;{t.debug("执行工具:",A.map(e=>e.name).join(", "));const e=[];for(const s of A){const n=Date.now();t.debug(`executeTool(${s.name}) args:`,JSON.stringify(s.args).slice(0,500));const r=await d.executeTool(s.name,s.args);t.debug(`executeTool(${s.name}) result:`,JSON.stringify(r).slice(0,500)),yield{type:"tool_call_result",data:{id:s.id,name:s.name,result:r.result,success:r.success,error:r.error,resultType:r.resultType,endedAt:Date.now(),duration:Date.now()-n}},e.push({role:"tool",content:r.result,tool_call_id:s.id})}const s=A.map(e=>({id:e.id,type:"function",function:{name:e.name,arguments:JSON.stringify(e.args)}})),n=[...y?.history||[],...g?[{role:"user",content:g}]:[],{role:"assistant",content:x,tool_calls:s},...e];t.debug("继续对话,新 history 长度:",n.length),g="",y={...y,history:n},p=void 0,x=""}}}finally{d=null}},cancel(){d&&(d.abort(),d=null)},setCwd(e){c().setCwd(e)},getSessions:async()=>c().getSessions(),getSession:async e=>c().getSession(e),createSession:async e=>c().createSession(e),updateSession:async(e,s)=>c().updateSession(e,s),async deleteSession(e){await c().deleteSession(e)},getMessages:async e=>c().getMessages(e),saveMessage:async e=>c().saveMessage(e),async updateMessage(e){await c().updateMessage(e)},async deleteMessagesAfter(e,s){await c().deleteMessagesAfter(e,s)},async deleteMessagesAfterMessageId(e,s){await c().deleteMessagesAfterMessageId(e,s)},getOperations:async e=>c().getOperations(e),getTrashItems:async()=>c().getTrashItems(),restoreFromTrash:async e=>c().restoreFromTrash(e),listDir:async e=>c().listDir(e),exists:async e=>c().exists(e),stat:async e=>c().stat(e),readFile:async e=>c().readFile(e),readFileBase64:async e=>c().readFileBase64(e),homeDir:async()=>c().homeDir(),resolvePath:async e=>c().resolvePath(e),parentDir:async e=>c().parentDir(e),watchDir:async e=>c().watchDir(e),unwatchDir:async e=>c().unwatchDir(e),onDirChange:e=>c().onDirChange(e),async getSetting(e){const s=c();return s.getSetting?s.getSetting(e):null},async setSetting(e,s){const t=c();t.setSetting&&await t.setSetting(e,s)},async getAllSettings(){const e=c();return e.getAllSettings?e.getAllSettings():{}},async deleteSetting(e){const s=c();s.deleteSetting&&await s.deleteSetting(e)},async getIndexStats(){const e=c();return e.getIndexStats?e.getIndexStats():{totalDocuments:0,indexSize:0,lastUpdated:null}},async getIndexStatus(){const e=c();return e.getIndexStatus?e.getIndexStatus():{isIndexing:!1,lastProgress:null}},async syncIndex(){const e=c();return e.syncIndex?e.syncIndex():{success:!1}},async cancelIndex(){const e=c();return e.cancelIndex?e.cancelIndex():{success:!1}},async deleteIndex(){const e=c();return e.deleteIndex?e.deleteIndex():{success:!1}},async registerIndexListener(){const e=c();return e.registerIndexListener?e.registerIndexListener():{success:!1}},async unregisterIndexListener(){const e=c();return e.unregisterIndexListener?e.unregisterIndexListener():{success:!1}},onIndexProgress(e){const s=c();return s.onIndexProgress?s.onIndexProgress(e):()=>{}},onToolApprovalRequest:e=>()=>{},async respondToolApproval(e,s){},async asrStart(e){const s=c();return s.asrStart?s.asrStart(e):{success:!1,error:"ASR not supported"}},async asrSendAudio(e){const s=c();return s.asrSendAudio?s.asrSendAudio(e):{success:!1,error:"ASR not supported"}},async asrFinish(){const e=c();return e.asrFinish?e.asrFinish():{success:!1,error:"ASR not supported"}},async asrStop(){const e=c();return e.asrStop?e.asrStop():{success:!0}},async asrStatus(){const e=c();return e.asrStatus?e.asrStatus():{connected:!1}},async asrWarmup(e){const s=c();return s.asrWarmup?s.asrWarmup(e):{success:!1,error:"ASR not supported"}},onAsrConnected(e){const s=c();return s.onAsrConnected?s.onAsrConnected(e):()=>{}},onAsrResult(e){const s=c();return s.onAsrResult?s.onAsrResult(e):()=>{}},onAsrError(e){const s=c();return s.onAsrError?s.onAsrError(e):()=>{}},onAsrClosed(e){const s=c();return s.onAsrClosed?s.onAsrClosed(e):()=>{}},async openExternal(e){const s=c();if(s.openExternal)return s.openExternal(e)}}}export{n as createElectronAdapter,r as createHybridAdapter,s as createLogger};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huyooo/ai-chat-bridge-electron",
3
- "version": "0.2.21",
3
+ "version": "0.2.23",
4
4
  "description": "AI Chat Electron Bridge - IPC integration for Electron apps",
5
5
  "type": "module",
6
6
  "main": "./dist/main/index.js",
@@ -33,10 +33,10 @@
33
33
  "clean": "rm -rf dist"
34
34
  },
35
35
  "dependencies": {
36
- "@huyooo/ai-chat-types": "*",
37
- "@huyooo/ai-chat-core": "^0.2.21",
38
- "@huyooo/ai-chat-storage": "^0.2.21",
39
- "@huyooo/ai-search": "^0.2.21",
36
+ "@huyooo/ai-chat-types": "^0.2.23",
37
+ "@huyooo/ai-chat-core": "^0.2.23",
38
+ "@huyooo/ai-chat-storage": "^0.2.23",
39
+ "@huyooo/ai-search": "^0.2.23",
40
40
  "uuid": "^11.1.0",
41
41
  "ws": "^8.18.3"
42
42
  },