@huyooo/ai-chat-bridge-electron 0.2.45 → 0.3.6
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.
- package/dist/main/asr/client.d.ts +112 -0
- package/dist/main/asr/index.d.ts +35 -0
- package/dist/main/asr/protocol.d.ts +135 -0
- package/dist/main/create-electron-chat.d.ts +100 -0
- package/dist/main/index.d.ts +88 -169
- package/dist/main/index.js +1 -1
- package/dist/preload/index.d.ts +47 -28
- package/dist/preload/index.js +1 -1
- package/dist/renderer/index.d.ts +10 -204
- package/dist/renderer/index.js +2 -1
- package/dist/renderer/logger.d.ts +16 -0
- package/package.json +13 -8
- package/dist/main/index.cjs +0 -364
- package/dist/main/index.d.cts +0 -61
- package/dist/main/index.js.map +0 -1
- package/dist/preload/index.cjs +0 -122
- package/dist/preload/index.d.cts +0 -276
- package/dist/preload/index.js.map +0 -1
- package/dist/renderer/index.cjs +0 -199
- package/dist/renderer/index.d.cts +0 -504
- package/dist/renderer/index.js.map +0 -1
package/dist/main/index.js
CHANGED
|
@@ -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 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?.ui;return{success:!0,result:s,ui: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};
|
|
1
|
+
import{ipcMain as e,shell as t}from"electron";import*as n from"fs";import*as r from"path";import{ChatRuntime as i,DEFAULT_MODEL as a,buildModelOptions as o,isToolError as s,normalizeToolResult as c,resolveToolGovernanceSnapshot as l,resolveToolResultUi as u,serializeToolResult as d}from"@huyooo/ai-chat-core";import{assetManager as f,createDefaultToolExecutor as p}from"@huyooo/ai-chat-host-node";import{createStorage as m}from"@huyooo/ai-chat-storage";import*as h from"zlib";import g from"ws";import{v4 as _}from"uuid";const v={FULL_CLIENT_REQUEST:1,AUDIO_ONLY_REQUEST:2,FULL_SERVER_RESPONSE:9,ERROR_RESPONSE:15},y={NONE:0,HAS_SEQUENCE:1,LAST_PACKET:2,LAST_PACKET_WITH_SEQUENCE:3},b={NONE:0,JSON:1},x={NONE:0,GZIP:1};function S(e,t,n,r){return[17,e<<4|t,n<<4|r,0]}function C(e,t=!0){let n=S(v.FULL_CLIENT_REQUEST,y.NONE,b.JSON,t?x.GZIP:x.NONE),r=JSON.stringify(e),i=Buffer.from(r,`utf-8`),a=t?h.gzipSync(i):i,o=Buffer.alloc(4);return o.writeUInt32BE(a.length,0),Buffer.concat([Buffer.from(n),o,a])}function w(e,t=!1,n=!0){let r=S(v.AUDIO_ONLY_REQUEST,t?y.LAST_PACKET:y.NONE,b.NONE,n?x.GZIP:x.NONE),i=n?h.gzipSync(e):e,a=Buffer.alloc(4);return a.writeUInt32BE(i.length,0),Buffer.concat([Buffer.from(r),a,i])}function T(e){if(e.length<4)throw Error(`Invalid response: too short`);let t=e[0],n=e[1],r=e[2],i=t>>4&15,a=(t&15)*4,o=n>>4&15,s=n&15,c=r>>4&15,l=r&15;if(i!==1)throw Error(`Unsupported protocol version: ${i}`);let u=a,d;(s&1)==1&&e.length>=u+4&&(d=e.readUInt32BE(u),u+=4);let f=(s&2)==2;if(o===v.ERROR_RESPONSE){let t=e.readUInt32BE(u);u+=4;let n=e.readUInt32BE(u);u+=4;let r=e.slice(u,u+n).toString(`utf-8`);return{type:`error`,sequence:d,isLast:!0,data:{code:t,message:r}}}if(o===v.FULL_SERVER_RESPONSE){let t=e.readUInt32BE(u);if(u+=4,t===0)return{type:`result`,sequence:d,isLast:f,data:{}};let n=e.slice(u,u+t);if(l===x.GZIP)try{n=h.gunzipSync(n)}catch(e){throw e}let r;if(c===b.JSON){let e=n.toString(`utf-8`);try{r=JSON.parse(e)}catch(e){throw e}}else r={};return{type:`result`,sequence:d,isLast:f,data:r}}throw Error(`Unknown message type: ${o}`)}var E=class{config;ws=null;callbacks={};connectId=``;isConnected=!1;sessionConfig={};constructor(e){this.config=e}getWsUrl(){return this.config.useAsyncMode===!1?`wss://openspeech.bytedance.com/api/v3/sauc/bigmodel`:`wss://openspeech.bytedance.com/api/v3/sauc/bigmodel_async`}getResourceId(){return this.config.resourceId||`volc.bigasr.sauc.duration`}connect(e,t={}){return new Promise((n,r)=>{this.callbacks=e,this.sessionConfig=t,this.connectId=_(),this.ws=new g(this.getWsUrl(),{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?.(),n()}),this.ws.on(`message`,e=>{try{let t=T(e);if(t.type===`error`){let e=t.data;this.callbacks.onError?.(Error(`ASR Error ${e.code}: ${e.message}`))}else{let e=t.data;this.callbacks.onResult?.(e,t.isLast),t.isLast}}catch(e){this.callbacks.onError?.(e instanceof Error?e:Error(String(e)))}}),this.ws.on(`error`,e=>{this.callbacks.onError?.(e),r(e)}),this.ws.on(`close`,()=>{this.isConnected=!1,this.ws=null,this.callbacks.onClose?.()})})}sendFullClientRequest(){if(!this.ws||this.ws.readyState!==g.OPEN)return;let e=C({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!==g.OPEN)return;let t=w(e,!1);this.ws.send(t)}finish(){if(!this.ws||this.ws.readyState!==g.OPEN)return;let e=w(Buffer.alloc(0),!0);this.ws.send(e)}disconnect(){this.ws&&=(this.ws.close(),null),this.isConnected=!1}get connected(){return this.isConnected&&this.ws?.readyState===g.OPEN}};function D(t){let{channelPrefix:n=`ai-chat`,appId:r,accessKey:i,resourceId:a}=t,o=new Map;function s(e,t){let n=o.get(e);return n||(n={client:new E({appId:r,accessKey:i,resourceId:a,useAsyncMode:!0}),webContents:t},o.set(e,n),t.on(`destroyed`,()=>{let t=o.get(e);t&&(t.client.disconnect(),o.delete(e))})),n}return e.handle(`${n}:asr:start`,async(e,t)=>{let r=e.sender,i=r.id,a=s(i,r);a.client.connected&&a.client.disconnect();try{return await a.client.connect({onConnected:()=>{r.isDestroyed()||r.send(`${n}:asr:connected`)},onResult:(e,t)=>{r.isDestroyed()||r.send(`${n}:asr:result`,{result:e,isLast:t})},onError:e=>{r.isDestroyed()||r.send(`${n}:asr:error`,{message:e.message})},onClose:()=>{r.isDestroyed()||r.send(`${n}:asr:closed`)}},t),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),e.handle(`${n}:asr:sendAudio`,async(e,t)=>{let n=e.sender.id,r=o.get(n);if(!r||!r.client.connected)return{success:!1,error:`ASR 会话未启动`};try{let e=t instanceof ArrayBuffer?Buffer.from(t):Buffer.from(new Uint8Array(t));return r.client.sendAudio(e),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),e.handle(`${n}:asr:finish`,async e=>{let t=e.sender.id,n=o.get(t);if(!n||!n.client.connected)return{success:!1,error:`ASR 会话未启动`};try{return n.client.finish(),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),e.handle(`${n}:asr:stop`,async e=>{let t=e.sender.id,n=o.get(t);return n&&n.client.disconnect(),{success:!0}}),e.handle(`${n}:asr:status`,async e=>{let t=e.sender.id;return{connected:o.get(t)?.client.connected??!1}}),e.handle(`${n}:asr:warmup`,async(e,t)=>{let n=e.sender,r=n.id,i=s(r,n);if(i.client.connected)return{success:!0};try{return await i.client.connect({onConnected:()=>{},onResult:()=>{},onError:()=>{},onClose:()=>{}},t),i.client.disconnect(),{success:!0}}catch(e){return{success:!1,error:e instanceof Error?e.message:String(e)}}}),{cleanup:()=>{for(let e of o.values())e.client.disconnect();o.clear()}}}async function O(e){let{dataDir:t,assetsDir:n,metadataStore:r,llm:i,maxIterations:a,maxDurationMs:o,maxToolCalls:s,maxTotalTokens:c,tools:l,preloadTools:u,asr:d,channelPrefix:p,cwd:m,defaultContext:h,sqliteFactory:g,beforeChat:_,dataEngine:v}=e,y=`${t}/data`,b=await f({tools:l,assetsDir:n??`${t}/assets`,metadataStore:r,preloadTools:u}),{agent:x,storage:S}=await P({llmConfig:i,maxIterations:a,maxDurationMs:o,maxToolCalls:s,maxTotalTokens:c,dataDir:y,tools:b.tools,cwd:m,channelPrefix:p,defaultContext:h,sqliteFactory:g,beforeChat:async e=>{let t=b.getEnabledSkillContents(),n=t.length>0?{...e,skillContents:[...t,...e.skillContents??[]]}:e;return _?_(n):n},dataEngine:v});return await b.bind(x),d&&D({...d,channelPrefix:p}),{agent:x,storage:S,assetManager:b}}function k(e,t){return e===`INVALID_PARAMS`?`validation`:e===`PERMISSION_DENIED`||e===`TOOL_NOT_ENABLED`?`permission`:e===`NETWORK_ERROR`?`network`:e===`NOT_FOUND`?`not_found`:e===`TIMEOUT`?`runtime`:t}function A(e){let{message:t,failureReason:n,code:r,category:i,retryable:a,suggestion:o,details:s,cause:c,stack:l}=e,u={...s??{},...c?{cause:c}:{},...l?{stack:l}:{}};return{status:`error`,failureReason:n,error:{message:t,...r?{code:r}:{},...i?{category:i}:{},...a===void 0?{}:{retryable:a},...o?{suggestion:o}:{},...Object.keys(u).length>0?{details:u}:{}}}}function j(e){if(typeof e!=`number`||!Number.isFinite(e))return;let t=Math.trunc(e);return t>0?t:void 0}function M(e){if(e)try{let t=JSON.parse(e);if(!t||typeof t!=`object`)return;let n={maxIterations:j(t.maxIterations),maxDurationMs:j(t.maxDurationMs),maxToolCalls:j(t.maxToolCalls),maxTotalTokens:j(t.maxTotalTokens)};return Object.values(n).some(e=>e!==void 0)?n:void 0}catch{return}}function N(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}async function P(f){let{llmConfig:h,cwd:g=process.cwd(),maxIterations:_,maxDurationMs:v,maxToolCalls:y,maxTotalTokens:b,channelPrefix:x=`ai-chat`,dataDir:S,defaultContext:C={},sqliteFactory:w,tools:T,mcpServers:E,dataEngine:D,resolveAtFileContext:O}=f,j=r.join(S,`db.sqlite`),P=new Map,F=async e=>{let t=global.currentApprovalContext,n=t?.auditContext;f.audit?.recordToolApprovalRequest?.({id:e.id,name:e.name,toolName:e.toolName??null,extensionId:e.extensionId??null,displayName:e.displayName??null,args:e.args,context:n});let r=t?.webContents;return r?new Promise((t,i)=>{P.set(e.id,{resolve:t,reject:i,webContents:r,name:e.name,toolName:e.toolName,extensionId:e.extensionId,displayName:e.displayName,auditContext:n}),r.send(`${x}:toolApprovalRequest`,{id:e.id,name:e.name,args:e.args})}):(f.audit?.recordToolApprovalResponse?.({id:e.id,name:e.name,toolName:e.toolName??null,extensionId:e.extensionId??null,displayName:e.displayName??null,approved:!1,context:n}),!1)},I=await m({type:`sqlite`,sqlitePath:j,sqliteFactory:w}),L=()=>C,R=async()=>{try{let e=await I.getUserSetting(`autoRunConfig`,L());if(e)return JSON.parse(e)}catch{}},z=async()=>{try{return M(await I.getUserSetting(`agentExecutionBudget`,L()))}catch{return}},B=new i({llmConfig:h,cwd:g,maxIterations:_,maxDurationMs:v,maxToolCalls:y,maxTotalTokens:b,tools:T,mcpServers:E,onToolApprovalRequest:F,getAutoRunConfig:R,dataEngine:D,audit:f.audit},p(g));e.on(`${x}:debugLog`,(e,t)=>{Array.isArray(t?.args)&&t.args.map(N),`${t?.module||`unknown`}`,t?.level}),e.handle(`${x}:models`,()=>o(h)),e.handle(`${x}:getAllTools`,async()=>(await B.ensureInitialized(),B.getAllTools())),e.handle(`${x}:getToolDefinitions`,async()=>(await B.ensureInitialized(),Array.from(B.getToolRuntimeManager().getSessionTools().values()).map(e=>({name:e.name,description:e.description,parameters:{type:`object`,properties:e.parameters?.properties||{},required:e.parameters?.required||[]}})))),e.handle(`${x}:executeTool`,async(e,t)=>{let{name:n,args:r,toolCallId:i,sessionId:a}=t;await B.ensureInitialized();try{let e=()=>B.executeTool(n,r,void 0,{toolCallId:i??`client-tool-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`,toolName:n}),t=f.audit?await f.audit.runWithContext({conversationId:a??null},e):await e(),o=B.getToolRuntimeManager().getSessionTools().get(n),s=await l(o,r),p,m;typeof t==`string`?m=t:t&&typeof t==`object`&&`result`in t?m=String(t.result??``):(p=c(t),m=JSON.stringify(d(p)));let h=p?u(p,o?.ui):o?.ui;return{success:!0,result:m,...h?{ui:h}:{},...s.approvalPolicy?{approvalPolicy:s.approvalPolicy}:{},...s.sideEffectLevel?{sideEffectLevel:s.sideEffectLevel}:{},...s.hostDependency?{hostDependency:s.hostDependency}:{},...s.riskSummary?{riskSummary:s.riskSummary}:{},...s.riskTags?.length?{riskTags:s.riskTags}:{},...s.riskSignals?.length?{riskSignals:s.riskSignals}:{}}}catch(e){let t=e instanceof Error?e.message:String(e),n=s(e)?e.toolError:void 0,r=n?.code===`TIMEOUT`?`timeout`:`execution_error`,i={success:!1,result:JSON.stringify(A({message:n?.message??t,failureReason:r,code:n?.code,category:n?.category??k(n?.code,`runtime`),retryable:n?.retryable,suggestion:n?.suggestion,details:n?.details,cause:e instanceof Error&&e.cause?String(e.cause):void 0,stack:e instanceof Error?e.stack:void 0})),error:n?.message??t};return n?{...i,toolError:n}:i}}),e.handle(`${x}:send`,async(e,t)=>{let n=e.sender,{message:r,images:i,sessionId:a}=t,o=t.options||{};f.beforeChat&&(o=await f.beforeChat(o)||o);let s=await z();s&&(o={...s,...o});let c=f.audit?.startTurn({conversationId:a??null,model:o.model??null,mode:o.mode??null,userMessage:r,metadata:{imageCount:i?.length??0}});global.currentApprovalContext={webContents:n,auditContext:{conversationId:a??null,turnId:c??null}};let l=0,u=async()=>{for await(let e of B.chat(r,o,i))l+=1,n.isDestroyed()||n.send(`${x}:progress`,{...e,sessionId:a})};try{f.audit?await f.audit.runWithContext({conversationId:a??null,turnId:c??null},u):await u(),c&&f.audit?.finishTurn({turnId:c,eventCount:l})}catch(e){if(c&&f.audit?.failTurn({turnId:c,eventCount:l,error:e}),e instanceof Error,!n.isDestroyed()){let t=e instanceof Error?{category:`api`,message:e.message||String(e),cause:e.stack}:{category:`api`,message:String(e)};n.send(`${x}:progress`,{type:`error`,data:t,sessionId:a})}}finally{delete global.currentApprovalContext}}),e.handle(`${x}:toolApprovalResponse`,(e,t)=>{let{id:n,approved:r}=t,i=P.get(n);i&&(P.delete(n),f.audit?.recordToolApprovalResponse?.({id:n,name:i.name,toolName:i.toolName??null,extensionId:i.extensionId??null,displayName:i.displayName??null,approved:r,context:i.auditContext}),i.resolve(r))}),e.handle(`${x}:cancel`,()=>{B.abort()}),e.handle(`${x}:settings:get`,async(e,t)=>I.getUserSetting(t,L())),e.handle(`${x}:settings:set`,async(e,t,n)=>(await I.setUserSetting(t,n,L()),{success:!0})),e.handle(`${x}:settings:getAll`,async()=>I.getUserSettings(L())),e.handle(`${x}:settings:delete`,async(e,t)=>(await I.deleteUserSetting(t,L()),{success:!0})),e.handle(`${x}:setCwd`,(e,t)=>{B.setCwd(t)}),e.handle(`${x}:config`,async()=>{let[e,t]=await Promise.all([R(),z()]);return{...B.getConfig(),currentAutoRunConfig:e,currentExecutionBudget:t}}),e.handle(`${x}:sessions:list`,async()=>I.getSessions(L())),e.handle(`${x}:sessions:get`,async(e,t)=>I.getSession(t,L())),e.handle(`${x}:sessions:create`,async(e,t)=>{let n={id:t.id||crypto.randomUUID(),title:t.title||`新对话`,model:t.model||a,mode:t.mode||`agent`,webSearchEnabled:t.webSearchEnabled??!0,thinkingEnabled:t.thinkingEnabled??!0,hidden:t.hidden??!1};return I.createSession(n,L())}),e.handle(`${x}:sessions:update`,async(e,t,n)=>(await I.updateSession(t,n,L()),I.getSession(t,L()))),e.handle(`${x}:sessions:delete`,async(e,t)=>(await I.deleteSession(t,L()),{success:!0})),e.handle(`${x}:messages:list`,async(e,t)=>I.getMessages(t,L())),e.handle(`${x}:messages:listPage`,async(e,t,n)=>I.getMessagesPage(t,n,L())),e.handle(`${x}:at:chats:search`,async(e,t,n)=>I.searchAtChats(t,n,L())),e.handle(`${x}:messages:save`,async(e,t)=>{let n=t.id||crypto.randomUUID(),r={id:n,clientId:n,sessionId:t.sessionId,role:t.role,content:t.content,atContextItems:t.atContextItems||null,images:t.images||[],model:t.model||null,mode:t.mode||null,webSearchEnabled:t.webSearchEnabled??null,thinkingEnabled:t.thinkingEnabled??null,parts:t.parts||[],operationIds:t.operationIds||null,finishReason:t.finishReason??null};return I.saveMessage(r,L())}),e.handle(`${x}:messages:update`,async(e,t)=>(await I.updateMessage(t.id,{content:t.content,atContextItems:t.atContextItems,parts:t.parts,usage:t.usage,duration:t.duration,finishReason:t.finishReason},L()),{success:!0})),e.handle(`${x}:messages:deleteAfter`,async(e,t,n)=>(await I.deleteMessagesAfter(t,new Date(n),L()),{success:!0})),e.handle(`${x}:messages:deleteAfterMessageId`,async(e,t,n)=>(await I.deleteMessagesAfterMessageId(t,n,L()),{success:!0})),e.handle(`${x}:operations:list`,async(e,t)=>I.getOperations(t,L())),e.handle(`${x}:trash:list`,async()=>I.getTrashItems?.(L())||[]),e.handle(`${x}:trash:restore`,async(e,t)=>I.restoreFromTrash?.(t,L())),e.handle(`${x}:openExternal`,async(e,n)=>t.openExternal(n)),e.handle(`${x}:fs:listDir`,async(e,t)=>{try{let e=n.readdirSync(t,{withFileTypes:!0}),i=[];for(let a of e){let e=r.join(t,a.name);try{let t=n.statSync(e);i.push({name:a.name,path:e,isDirectory:a.isDirectory(),size:t.size,modifiedAt:t.mtime,extension:a.isDirectory()?``:r.extname(a.name).toLowerCase()})}catch{}}return i.sort((e,t)=>e.isDirectory&&!t.isDirectory?-1:!e.isDirectory&&t.isDirectory?1:e.name.localeCompare(t.name))}catch{return[]}}),e.handle(`${x}:fs:exists`,async(e,t)=>n.existsSync(t)),e.handle(`${x}:fs:stat`,async(e,t)=>{try{let e=n.statSync(t);return{name:r.basename(t),path:t,isDirectory:e.isDirectory(),size:e.size,modifiedAt:e.mtime,extension:e.isDirectory()?``:r.extname(t).toLowerCase()}}catch{return null}}),e.handle(`${x}:fs:readFile`,async(e,t)=>{try{return n.readFileSync(t,`utf-8`)}catch{return null}}),e.handle(`${x}:fs:resolveAtFileContext`,async(e,t)=>{if(!O)return null;try{return await O(t)}catch{return null}}),e.handle(`${x}:fs:readFileBase64`,async(e,t)=>{try{return n.readFileSync(t).toString(`base64`)}catch{return null}}),e.handle(`${x}:fs:homeDir`,async()=>process.env.HOME||process.env.USERPROFILE||`/`),e.handle(`${x}:fs:resolvePath`,async(e,t)=>{if(t.startsWith(`~`)){let e=process.env.HOME||process.env.USERPROFILE||`/`;return r.join(e,t.slice(1))}return r.resolve(t)}),e.handle(`${x}:fs:parentDir`,async(e,t)=>r.dirname(t));let V=new Map;return e.handle(`${x}:fs:watchDir`,async(e,t)=>{let r=e.sender;V.has(t)&&(V.get(t)?.close(),V.delete(t));try{let e=n.watch(t,{persistent:!1},(e,n)=>{r.isDestroyed()||r.send(`${x}:fs:dirChange`,{dirPath:t,eventType:e,filename:n})});return e.on(`error`,e=>{V.delete(t)}),V.set(t,e),!0}catch{return!1}}),e.handle(`${x}:fs:unwatchDir`,async(e,t)=>{let n=V.get(t);n&&(n.close(),V.delete(t))}),{agent:B,storage:I}}export{o as buildModelOptions,D as createAsrBridge,P as createElectronBridge,O as createElectronChat};
|
package/dist/preload/index.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Electron Preload 桥接
|
|
3
|
+
*
|
|
4
|
+
* 在 preload 脚本中调用,暴露 API 给渲染进程
|
|
5
|
+
*
|
|
6
|
+
* 类型定义统一从 @huyooo/ai-chat-types 导入
|
|
7
|
+
*/
|
|
8
|
+
import type { AtChatContextItem, AtResolvedFileContext, AtDocumentContextItem, AtTerminalContextItem, ModelOption, SessionRecord, MessageRecord, OperationRecord, TrashRecord, FileInfo, AsrSessionConfig, AsrResultData, SendMessageParams, CreateSessionParams, UpdateSessionParams, SaveMessageParams, UpdateMessageParams, ToolApprovalRequest, ToolInfo, ToolExecutionResult, ChatEvent } from '@huyooo/ai-chat-types';
|
|
9
|
+
export type { ToolExecutionResult } from '@huyooo/ai-chat-types';
|
|
5
10
|
/** 用户工具定义(只有 schema,用于传给 ai-server) */
|
|
6
|
-
interface UserToolDefinition {
|
|
11
|
+
export interface UserToolDefinition {
|
|
7
12
|
name: string;
|
|
8
13
|
description: string;
|
|
9
14
|
parameters: {
|
|
@@ -19,27 +24,12 @@ interface UserToolDefinition {
|
|
|
19
24
|
required?: string[];
|
|
20
25
|
};
|
|
21
26
|
}
|
|
22
|
-
/** 工具执行结果(与 ai-chat-types ToolExecutionResult 一致) */
|
|
23
|
-
interface ToolExecutionResult {
|
|
24
|
-
success: boolean;
|
|
25
|
-
result: string;
|
|
26
|
-
error?: string;
|
|
27
|
-
ui?: {
|
|
28
|
-
type: 'render' | 'action';
|
|
29
|
-
name: string;
|
|
30
|
-
props?: Record<string, unknown>;
|
|
31
|
-
};
|
|
32
|
-
toolError?: _huyooo_ai_chat_core_events.ToolErrorShape;
|
|
33
|
-
}
|
|
34
27
|
/** Electron Bridge 接口(完整的 IPC 桥接) */
|
|
35
|
-
interface AiChatBridge {
|
|
28
|
+
export interface AiChatBridge {
|
|
36
29
|
/** 获取可用模型 */
|
|
37
30
|
getModels(): Promise<ModelOption[]>;
|
|
38
|
-
/**
|
|
39
|
-
getAllTools(): Promise<
|
|
40
|
-
name: string;
|
|
41
|
-
description: string;
|
|
42
|
-
}>>;
|
|
31
|
+
/** 获取所有工具列表(用于工具设置或管理视图) */
|
|
32
|
+
getAllTools(): Promise<ToolInfo[]>;
|
|
43
33
|
/**
|
|
44
34
|
* 获取工具定义(用于传给 ai-server)
|
|
45
35
|
* 返回工具的 schema,不包含 execute 函数
|
|
@@ -50,7 +40,10 @@ interface AiChatBridge {
|
|
|
50
40
|
* @param name 工具名称
|
|
51
41
|
* @param args 工具参数
|
|
52
42
|
*/
|
|
53
|
-
executeTool(name: string, args: Record<string, unknown
|
|
43
|
+
executeTool(name: string, args: Record<string, unknown>, context?: {
|
|
44
|
+
toolCallId?: string;
|
|
45
|
+
sessionId?: string;
|
|
46
|
+
}): Promise<ToolExecutionResult>;
|
|
54
47
|
/** 发送消息 */
|
|
55
48
|
send(params: SendMessageParams): Promise<void>;
|
|
56
49
|
/** 取消当前请求 */
|
|
@@ -59,6 +52,12 @@ interface AiChatBridge {
|
|
|
59
52
|
setCwd(dir: string): Promise<void>;
|
|
60
53
|
/** 获取配置 */
|
|
61
54
|
getConfig(): Promise<unknown>;
|
|
55
|
+
/** 将渲染进程调试日志转发到主进程终端 */
|
|
56
|
+
debugLog?(payload: {
|
|
57
|
+
module: string;
|
|
58
|
+
level: 'debug' | 'info';
|
|
59
|
+
args: unknown[];
|
|
60
|
+
}): void;
|
|
62
61
|
/** 监听进度事件 */
|
|
63
62
|
onProgress(callback: (progress: ChatEvent) => void): () => void;
|
|
64
63
|
getSessions(): Promise<SessionRecord[]>;
|
|
@@ -69,6 +68,14 @@ interface AiChatBridge {
|
|
|
69
68
|
success: boolean;
|
|
70
69
|
}>;
|
|
71
70
|
getMessages(sessionId: string): Promise<MessageRecord[]>;
|
|
71
|
+
getMessagesPage(sessionId: string, params?: {
|
|
72
|
+
limit?: number;
|
|
73
|
+
beforeSequence?: number;
|
|
74
|
+
}): Promise<{
|
|
75
|
+
messages: MessageRecord[];
|
|
76
|
+
hasMore: boolean;
|
|
77
|
+
nextBeforeSequence: number | null;
|
|
78
|
+
}>;
|
|
72
79
|
saveMessage(params: SaveMessageParams): Promise<MessageRecord>;
|
|
73
80
|
updateMessage(params: UpdateMessageParams): Promise<{
|
|
74
81
|
success: boolean;
|
|
@@ -87,6 +94,7 @@ interface AiChatBridge {
|
|
|
87
94
|
exists(filePath: string): Promise<boolean>;
|
|
88
95
|
stat(filePath: string): Promise<FileInfo | null>;
|
|
89
96
|
readFile(filePath: string): Promise<string | null>;
|
|
97
|
+
resolveAtFileContext(filePath: string): Promise<AtResolvedFileContext | null>;
|
|
90
98
|
readFileBase64(filePath: string): Promise<string | null>;
|
|
91
99
|
homeDir(): Promise<string>;
|
|
92
100
|
resolvePath(inputPath: string): Promise<string>;
|
|
@@ -142,6 +150,18 @@ interface AiChatBridge {
|
|
|
142
150
|
stage: string;
|
|
143
151
|
error?: string;
|
|
144
152
|
}) => void): () => void;
|
|
153
|
+
searchAtDocuments(query: string, options?: {
|
|
154
|
+
limit?: number;
|
|
155
|
+
mode?: 'semantic' | 'fulltext' | 'hybrid';
|
|
156
|
+
}): Promise<AtDocumentContextItem[]>;
|
|
157
|
+
listAtTerminals(options?: {
|
|
158
|
+
query?: string;
|
|
159
|
+
limit?: number;
|
|
160
|
+
workspaceRoot?: string;
|
|
161
|
+
}): Promise<AtTerminalContextItem[]>;
|
|
162
|
+
searchAtChats(query: string, options?: {
|
|
163
|
+
limit?: number;
|
|
164
|
+
}): Promise<AtChatContextItem[]>;
|
|
145
165
|
onToolApprovalRequest(callback: (request: ToolApprovalRequest) => void): () => void;
|
|
146
166
|
respondToolApproval(id: string, approved: boolean): Promise<void>;
|
|
147
167
|
asrStart(config?: AsrSessionConfig): Promise<{
|
|
@@ -176,7 +196,7 @@ interface AiChatBridge {
|
|
|
176
196
|
}) => void): () => void;
|
|
177
197
|
onAsrClosed(callback: () => void): () => void;
|
|
178
198
|
}
|
|
179
|
-
interface ExposeOptions {
|
|
199
|
+
export interface ExposeOptions {
|
|
180
200
|
/** IPC channel 前缀 */
|
|
181
201
|
channelPrefix?: string;
|
|
182
202
|
/** 暴露的全局变量名 */
|
|
@@ -185,6 +205,5 @@ interface ExposeOptions {
|
|
|
185
205
|
/**
|
|
186
206
|
* 暴露 AI Chat API 给渲染进程
|
|
187
207
|
*/
|
|
188
|
-
declare function exposeElectronBridge(options?: ExposeOptions): void;
|
|
189
|
-
|
|
190
|
-
export { type AiChatBridge, type ExposeOptions, type ToolExecutionResult, type UserToolDefinition, exposeElectronBridge };
|
|
208
|
+
export declare function exposeElectronBridge(options?: ExposeOptions): void;
|
|
209
|
+
export type { ModelOption, SessionRecord, MessageRecord, OperationRecord, TrashRecord, FileInfo, AsrSessionConfig, AsrResultData, SendMessageParams, CreateSessionParams, UpdateSessionParams, SaveMessageParams, UpdateMessageParams, ToolApprovalRequest, ChatEvent, } from '@huyooo/ai-chat-types';
|
package/dist/preload/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{contextBridge as e,ipcRenderer as
|
|
1
|
+
import{contextBridge as e,ipcRenderer as t}from"electron";function n(n={}){let{channelPrefix:r=`ai-chat`,exposeName:i=`aiChatBridge`}=n;e.exposeInMainWorld(i,{getModels:()=>t.invoke(`${r}:models`),getAllTools:()=>t.invoke(`${r}:getAllTools`),getToolDefinitions:()=>t.invoke(`${r}:getToolDefinitions`),executeTool:(e,n,i)=>t.invoke(`${r}:executeTool`,{name:e,args:n,...i}),send:e=>t.invoke(`${r}:send`,e),cancel:()=>t.invoke(`${r}:cancel`),setCwd:e=>t.invoke(`${r}:setCwd`,e),getConfig:()=>t.invoke(`${r}:config`),debugLog:e=>t.send(`${r}:debugLog`,e),onProgress:e=>{let n=(t,n)=>{e(n)};return t.on(`${r}:progress`,n),()=>{t.removeListener(`${r}:progress`,n)}},onToolApprovalRequest:e=>{let n=(t,n)=>{e(n)};return t.on(`${r}:toolApprovalRequest`,n),()=>{t.removeListener(`${r}:toolApprovalRequest`,n)}},respondToolApproval:(e,n)=>t.invoke(`${r}:toolApprovalResponse`,{id:e,approved:n}),getSessions:()=>t.invoke(`${r}:sessions:list`),getSession:e=>t.invoke(`${r}:sessions:get`,e),createSession:e=>t.invoke(`${r}:sessions:create`,e||{}),updateSession:(e,n)=>t.invoke(`${r}:sessions:update`,e,n),deleteSession:e=>t.invoke(`${r}:sessions:delete`,e),getMessages:e=>t.invoke(`${r}:messages:list`,e),getMessagesPage:(e,n)=>t.invoke(`${r}:messages:listPage`,e,n||{}),saveMessage:e=>t.invoke(`${r}:messages:save`,e),updateMessage:e=>t.invoke(`${r}:messages:update`,e),deleteMessagesAfter:(e,n)=>t.invoke(`${r}:messages:deleteAfter`,e,n),deleteMessagesAfterMessageId:(e,n)=>t.invoke(`${r}:messages:deleteAfterMessageId`,e,n),getOperations:e=>t.invoke(`${r}:operations:list`,e),getTrashItems:()=>t.invoke(`${r}:trash:list`),restoreFromTrash:e=>t.invoke(`${r}:trash:restore`,e),openExternal:e=>t.invoke(`${r}:openExternal`,e),listDir:e=>t.invoke(`${r}:fs:listDir`,e),exists:e=>t.invoke(`${r}:fs:exists`,e),stat:e=>t.invoke(`${r}:fs:stat`,e),readFile:e=>t.invoke(`${r}:fs:readFile`,e),resolveAtFileContext:e=>t.invoke(`${r}:fs:resolveAtFileContext`,e),readFileBase64:e=>t.invoke(`${r}:fs:readFileBase64`,e),homeDir:()=>t.invoke(`${r}:fs:homeDir`),resolvePath:e=>t.invoke(`${r}:fs:resolvePath`,e),parentDir:e=>t.invoke(`${r}:fs:parentDir`,e),watchDir:e=>t.invoke(`${r}:fs:watchDir`,e),unwatchDir:e=>t.invoke(`${r}:fs:unwatchDir`,e),onDirChange:e=>{let n=(t,n)=>{e(n)};return t.on(`${r}:fs:dirChange`,n),()=>{t.removeListener(`${r}:fs:dirChange`,n)}},getSetting:e=>t.invoke(`${r}:settings:get`,e),setSetting:(e,n)=>t.invoke(`${r}:settings:set`,e,n),getAllSettings:()=>t.invoke(`${r}:settings:getAll`),deleteSetting:e=>t.invoke(`${r}:settings:delete`,e),getIndexStats:()=>t.invoke(`${r}:index:getStats`),getIndexStatus:()=>t.invoke(`${r}:index:status`),syncIndex:()=>t.invoke(`${r}:index:sync`),cancelIndex:()=>t.invoke(`${r}:index:cancel`),deleteIndex:()=>t.invoke(`${r}:index:delete`),registerIndexListener:()=>t.invoke(`${r}:index:registerListener`),unregisterIndexListener:()=>t.invoke(`${r}:index:unregisterListener`),onIndexProgress:e=>{let n=(t,n)=>{e(n)};return t.on(`${r}:index:progress`,n),()=>{t.removeListener(`${r}:index:progress`,n)}},searchAtDocuments:async(e,n)=>{let i=e.trim();return i?(await t.invoke(`${r}:search:query`,i,{limit:n?.limit,mode:n?.mode??`hybrid`})).map(e=>({kind:`doc`,id:e.id,documentId:e.id,label:e.name,mention:`@doc:${e.id}`,description:e.id,source:e.projectPath||e.projectName||e.id,snippet:e.snippet,score:e.score,matchType:e.matchType})):(await t.invoke(`${r}:search:listDocuments`,n?.limit)).map(e=>({kind:`doc`,id:e.id,documentId:e.path,label:e.name,mention:`@doc:${e.path}`,description:e.path,source:e.projectPath||e.projectName||e.path}))},listAtTerminals:async e=>{let n=e?.query?.trim().toLowerCase()??``,r=e?.limit??20,i=e?.workspaceRoot,[a,o]=await Promise.all([t.invoke(`terminal:listSessions`,i),i?t.invoke(`terminal:getActiveSessionId`,i):Promise.resolve(null)]);return[...a].sort((e,t)=>{if(o){if(e.id===o)return-1;if(t.id===o)return 1}return t.updatedAt.localeCompare(e.updatedAt)}).filter(e=>n?`${e.title} ${e.cwd} ${e.status}`.toLowerCase().includes(n):!0).slice(0,r).map(e=>({kind:`terminal`,id:e.id,sessionId:e.id,label:e.title,mention:`@terminal:${e.id}`,description:`${e.cwd} · ${e.status}`,cwd:e.cwd,status:e.status,updatedAt:e.updatedAt}))},searchAtChats:async(e,n)=>t.invoke(`${r}:at:chats:search`,e,n),asrStart:e=>t.invoke(`${r}:asr:start`,e),asrSendAudio:e=>t.invoke(`${r}:asr:sendAudio`,e),asrFinish:()=>t.invoke(`${r}:asr:finish`),asrStop:()=>t.invoke(`${r}:asr:stop`),asrStatus:()=>t.invoke(`${r}:asr:status`),asrWarmup:e=>t.invoke(`${r}:asr:warmup`,e),onAsrConnected:e=>{let n=()=>e();return t.on(`${r}:asr:connected`,n),()=>{t.removeListener(`${r}:asr:connected`,n)}},onAsrResult:e=>{let n=(t,n)=>{e(n)};return t.on(`${r}:asr:result`,n),()=>{t.removeListener(`${r}:asr:result`,n)}},onAsrError:e=>{let n=(t,n)=>{e(n)};return t.on(`${r}:asr:error`,n),()=>{t.removeListener(`${r}:asr:error`,n)}},onAsrClosed:e=>{let n=()=>e();return t.on(`${r}:asr:closed`,n),()=>{t.removeListener(`${r}:asr:closed`,n)}}})}export{n as exposeElectronBridge};
|
package/dist/renderer/index.d.ts
CHANGED
|
@@ -1,199 +1,3 @@
|
|
|
1
|
-
import * as _huyooo_ai_chat_core_events from '@huyooo/ai-chat-core/events';
|
|
2
|
-
import { ModelOption, SendMessageParams, ChatEvent, SessionRecord, CreateSessionParams, UpdateSessionParams, MessageRecord, SaveMessageParams, UpdateMessageParams, OperationRecord, TrashRecord, FileInfo, ToolApprovalRequest, AsrSessionConfig, AsrResultData, ChatAdapter } from '@huyooo/ai-chat-types';
|
|
3
|
-
export * from '@huyooo/ai-chat-types';
|
|
4
|
-
|
|
5
|
-
/** 用户工具定义(只有 schema,用于传给 ai-server) */
|
|
6
|
-
interface UserToolDefinition {
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
parameters: {
|
|
10
|
-
type: 'object';
|
|
11
|
-
properties: Record<string, {
|
|
12
|
-
type: string;
|
|
13
|
-
description: string;
|
|
14
|
-
enum?: string[];
|
|
15
|
-
items?: {
|
|
16
|
-
type: string;
|
|
17
|
-
};
|
|
18
|
-
}>;
|
|
19
|
-
required?: string[];
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/** 工具执行结果(与 ai-chat-types ToolExecutionResult 一致) */
|
|
23
|
-
interface ToolExecutionResult {
|
|
24
|
-
success: boolean;
|
|
25
|
-
result: string;
|
|
26
|
-
error?: string;
|
|
27
|
-
ui?: {
|
|
28
|
-
type: 'render' | 'action';
|
|
29
|
-
name: string;
|
|
30
|
-
props?: Record<string, unknown>;
|
|
31
|
-
};
|
|
32
|
-
toolError?: _huyooo_ai_chat_core_events.ToolErrorShape;
|
|
33
|
-
}
|
|
34
|
-
/** Electron Bridge 接口(完整的 IPC 桥接) */
|
|
35
|
-
interface AiChatBridge {
|
|
36
|
-
/** 获取可用模型 */
|
|
37
|
-
getModels(): Promise<ModelOption[]>;
|
|
38
|
-
/** 获取所有工具列表(用于设置面板) */
|
|
39
|
-
getAllTools(): Promise<Array<{
|
|
40
|
-
name: string;
|
|
41
|
-
description: string;
|
|
42
|
-
}>>;
|
|
43
|
-
/**
|
|
44
|
-
* 获取工具定义(用于传给 ai-server)
|
|
45
|
-
* 返回工具的 schema,不包含 execute 函数
|
|
46
|
-
*/
|
|
47
|
-
getToolDefinitions(): Promise<UserToolDefinition[]>;
|
|
48
|
-
/**
|
|
49
|
-
* 执行单个工具(用于处理 ai-server 的 tool_call_request)
|
|
50
|
-
* @param name 工具名称
|
|
51
|
-
* @param args 工具参数
|
|
52
|
-
*/
|
|
53
|
-
executeTool(name: string, args: Record<string, unknown>): Promise<ToolExecutionResult>;
|
|
54
|
-
/** 发送消息 */
|
|
55
|
-
send(params: SendMessageParams): Promise<void>;
|
|
56
|
-
/** 取消当前请求 */
|
|
57
|
-
cancel(): Promise<void>;
|
|
58
|
-
/** 设置当前工作目录 */
|
|
59
|
-
setCwd(dir: string): Promise<void>;
|
|
60
|
-
/** 获取配置 */
|
|
61
|
-
getConfig(): Promise<unknown>;
|
|
62
|
-
/** 监听进度事件 */
|
|
63
|
-
onProgress(callback: (progress: ChatEvent) => void): () => void;
|
|
64
|
-
getSessions(): Promise<SessionRecord[]>;
|
|
65
|
-
getSession(id: string): Promise<SessionRecord | null>;
|
|
66
|
-
createSession(params?: CreateSessionParams): Promise<SessionRecord>;
|
|
67
|
-
updateSession(id: string, data: UpdateSessionParams): Promise<SessionRecord | null>;
|
|
68
|
-
deleteSession(id: string): Promise<{
|
|
69
|
-
success: boolean;
|
|
70
|
-
}>;
|
|
71
|
-
getMessages(sessionId: string): Promise<MessageRecord[]>;
|
|
72
|
-
saveMessage(params: SaveMessageParams): Promise<MessageRecord>;
|
|
73
|
-
updateMessage(params: UpdateMessageParams): Promise<{
|
|
74
|
-
success: boolean;
|
|
75
|
-
}>;
|
|
76
|
-
deleteMessagesAfter(sessionId: string, timestamp: number): Promise<{
|
|
77
|
-
success: boolean;
|
|
78
|
-
}>;
|
|
79
|
-
deleteMessagesAfterMessageId(sessionId: string, messageId: string): Promise<{
|
|
80
|
-
success: boolean;
|
|
81
|
-
}>;
|
|
82
|
-
getOperations(sessionId: string): Promise<OperationRecord[]>;
|
|
83
|
-
getTrashItems(): Promise<TrashRecord[]>;
|
|
84
|
-
restoreFromTrash(id: string): Promise<TrashRecord | undefined>;
|
|
85
|
-
openExternal(url: string): Promise<void>;
|
|
86
|
-
listDir(dirPath: string): Promise<FileInfo[]>;
|
|
87
|
-
exists(filePath: string): Promise<boolean>;
|
|
88
|
-
stat(filePath: string): Promise<FileInfo | null>;
|
|
89
|
-
readFile(filePath: string): Promise<string | null>;
|
|
90
|
-
readFileBase64(filePath: string): Promise<string | null>;
|
|
91
|
-
homeDir(): Promise<string>;
|
|
92
|
-
resolvePath(inputPath: string): Promise<string>;
|
|
93
|
-
parentDir(dirPath: string): Promise<string>;
|
|
94
|
-
watchDir(dirPath: string): Promise<boolean>;
|
|
95
|
-
unwatchDir(dirPath: string): Promise<void>;
|
|
96
|
-
onDirChange(callback: (data: {
|
|
97
|
-
dirPath: string;
|
|
98
|
-
eventType: string;
|
|
99
|
-
filename: string | null;
|
|
100
|
-
}) => void): () => void;
|
|
101
|
-
getSetting(key: string): Promise<string | null>;
|
|
102
|
-
setSetting(key: string, value: string): Promise<{
|
|
103
|
-
success: boolean;
|
|
104
|
-
}>;
|
|
105
|
-
getAllSettings(): Promise<Record<string, string>>;
|
|
106
|
-
deleteSetting(key: string): Promise<{
|
|
107
|
-
success: boolean;
|
|
108
|
-
}>;
|
|
109
|
-
getIndexStats(): Promise<{
|
|
110
|
-
totalDocuments: number;
|
|
111
|
-
indexSize: number;
|
|
112
|
-
lastUpdated: string | null;
|
|
113
|
-
}>;
|
|
114
|
-
getIndexStatus(): Promise<{
|
|
115
|
-
isIndexing: boolean;
|
|
116
|
-
lastProgress: {
|
|
117
|
-
indexed: number;
|
|
118
|
-
total: number;
|
|
119
|
-
currentFile?: string;
|
|
120
|
-
stage: string;
|
|
121
|
-
} | null;
|
|
122
|
-
}>;
|
|
123
|
-
syncIndex(): Promise<{
|
|
124
|
-
success: boolean;
|
|
125
|
-
}>;
|
|
126
|
-
cancelIndex(): Promise<{
|
|
127
|
-
success: boolean;
|
|
128
|
-
}>;
|
|
129
|
-
deleteIndex(): Promise<{
|
|
130
|
-
success: boolean;
|
|
131
|
-
}>;
|
|
132
|
-
registerIndexListener(): Promise<{
|
|
133
|
-
success: boolean;
|
|
134
|
-
}>;
|
|
135
|
-
unregisterIndexListener(): Promise<{
|
|
136
|
-
success: boolean;
|
|
137
|
-
}>;
|
|
138
|
-
onIndexProgress(callback: (progress: {
|
|
139
|
-
indexed: number;
|
|
140
|
-
total: number;
|
|
141
|
-
currentFile?: string;
|
|
142
|
-
stage: string;
|
|
143
|
-
error?: string;
|
|
144
|
-
}) => void): () => void;
|
|
145
|
-
onToolApprovalRequest(callback: (request: ToolApprovalRequest) => void): () => void;
|
|
146
|
-
respondToolApproval(id: string, approved: boolean): Promise<void>;
|
|
147
|
-
asrStart(config?: AsrSessionConfig): Promise<{
|
|
148
|
-
success: boolean;
|
|
149
|
-
error?: string;
|
|
150
|
-
}>;
|
|
151
|
-
asrSendAudio(audioData: ArrayBufferLike): Promise<{
|
|
152
|
-
success: boolean;
|
|
153
|
-
error?: string;
|
|
154
|
-
}>;
|
|
155
|
-
asrFinish(): Promise<{
|
|
156
|
-
success: boolean;
|
|
157
|
-
error?: string;
|
|
158
|
-
}>;
|
|
159
|
-
asrStop(): Promise<{
|
|
160
|
-
success: boolean;
|
|
161
|
-
}>;
|
|
162
|
-
asrStatus(): Promise<{
|
|
163
|
-
connected: boolean;
|
|
164
|
-
}>;
|
|
165
|
-
asrWarmup(config?: AsrSessionConfig): Promise<{
|
|
166
|
-
success: boolean;
|
|
167
|
-
error?: string;
|
|
168
|
-
}>;
|
|
169
|
-
onAsrConnected(callback: () => void): () => void;
|
|
170
|
-
onAsrResult(callback: (data: {
|
|
171
|
-
result: AsrResultData;
|
|
172
|
-
isLast: boolean;
|
|
173
|
-
}) => void): () => void;
|
|
174
|
-
onAsrError(callback: (error: {
|
|
175
|
-
message: string;
|
|
176
|
-
}) => void): () => void;
|
|
177
|
-
onAsrClosed(callback: () => void): () => void;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* 浏览器端日志工具
|
|
182
|
-
*
|
|
183
|
-
* API 与 ai-chat-core 的 DebugLogger 对齐。
|
|
184
|
-
* 开关:localStorage.setItem('AI_CHAT_DEBUG', 'true')
|
|
185
|
-
*
|
|
186
|
-
* - warn / error 始终输出(生产可见)
|
|
187
|
-
* - debug / info 受开关控制(默认关闭)
|
|
188
|
-
*/
|
|
189
|
-
interface Logger {
|
|
190
|
-
debug(...args: unknown[]): void;
|
|
191
|
-
info(...args: unknown[]): void;
|
|
192
|
-
warn(...args: unknown[]): void;
|
|
193
|
-
error(...args: unknown[]): void;
|
|
194
|
-
}
|
|
195
|
-
declare function createLogger(module: string): Logger;
|
|
196
|
-
|
|
197
1
|
/**
|
|
198
2
|
* Electron 渲染进程 Adapter
|
|
199
3
|
*
|
|
@@ -201,18 +5,22 @@ declare function createLogger(module: string): Logger;
|
|
|
201
5
|
*
|
|
202
6
|
* 类型定义统一从 @huyooo/ai-chat-types 导入
|
|
203
7
|
*/
|
|
204
|
-
|
|
8
|
+
import type { AiChatBridge } from '../preload';
|
|
9
|
+
export * from '@huyooo/ai-chat-types';
|
|
10
|
+
export { createLogger } from './logger';
|
|
11
|
+
export type { Logger } from './logger';
|
|
12
|
+
export type { AiChatBridge, UserToolDefinition, ToolExecutionResult } from '../preload';
|
|
205
13
|
declare global {
|
|
206
14
|
interface Window {
|
|
207
15
|
aiChatBridge?: AiChatBridge;
|
|
208
16
|
}
|
|
209
17
|
}
|
|
210
|
-
interface CreateAdapterOptions {
|
|
18
|
+
export interface CreateAdapterOptions {
|
|
211
19
|
/** 全局变量名 */
|
|
212
20
|
bridgeName?: string;
|
|
213
21
|
}
|
|
214
22
|
/** 混合适配器配置 */
|
|
215
|
-
interface CreateHybridAdapterOptions extends CreateAdapterOptions {
|
|
23
|
+
export interface CreateHybridAdapterOptions extends CreateAdapterOptions {
|
|
216
24
|
/** 远程 AI 服务配置 */
|
|
217
25
|
remote: {
|
|
218
26
|
/** API 基础 URL (如 'http://localhost:3002/aiRestfulApi') */
|
|
@@ -223,11 +31,11 @@ interface CreateHybridAdapterOptions extends CreateAdapterOptions {
|
|
|
223
31
|
getAppId?: () => string | null | Promise<string | null>;
|
|
224
32
|
};
|
|
225
33
|
}
|
|
226
|
-
|
|
34
|
+
import type { ChatAdapter } from '@huyooo/ai-chat-types';
|
|
227
35
|
/**
|
|
228
36
|
* 创建 Electron Adapter
|
|
229
37
|
*/
|
|
230
|
-
declare function createElectronAdapter(options?: CreateAdapterOptions): ChatAdapter;
|
|
38
|
+
export declare function createElectronAdapter(options?: CreateAdapterOptions): ChatAdapter;
|
|
231
39
|
/**
|
|
232
40
|
* 创建混合适配器
|
|
233
41
|
*
|
|
@@ -244,6 +52,4 @@ declare function createElectronAdapter(options?: CreateAdapterOptions): ChatAdap
|
|
|
244
52
|
* })
|
|
245
53
|
* ```
|
|
246
54
|
*/
|
|
247
|
-
declare function createHybridAdapter(options: CreateHybridAdapterOptions): ChatAdapter;
|
|
248
|
-
|
|
249
|
-
export { type AiChatBridge, type CreateAdapterOptions, type CreateHybridAdapterOptions, type Logger, type ToolExecutionResult, type UserToolDefinition, createElectronAdapter, createHybridAdapter, createLogger };
|
|
55
|
+
export declare function createHybridAdapter(options: CreateHybridAdapterOptions): ChatAdapter;
|
package/dist/renderer/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
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,toolError:r.toolError,ui:r.ui,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};
|
|
1
|
+
export*from"@huyooo/ai-chat-types";function e(){try{return typeof localStorage<`u`&&localStorage.getItem(`AI_CHAT_DEBUG`)===`true`}catch{return!1}}function t(e){if(e instanceof Error)return{name:e.name,message:e.message,stack:e.stack};if(e==null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e;if(typeof e==`bigint`||typeof e==`symbol`||typeof e==`function`)return String(e);try{return JSON.parse(JSON.stringify(e))}catch{return String(e)}}function n(e,n,r){try{globalThis.aiChatBridge?.debugLog?.({module:e,level:n,args:r.map(t)})}catch{}}function r(t){return`${t}`,{debug:(...r)=>{e()&&n(t,`debug`,r)},info:(...r)=>{e()&&n(t,`info`,r)},warn:(...e)=>void 0,error:(...e)=>void 0}}const i=r(`HybridAdapter`);function a(e={}){let{bridgeName:t=`aiChatBridge`}=e,n=()=>{let e=window[t];if(!e)throw Error(`AI Chat Bridge not found. Make sure to call exposeElectronBridge() in preload.`);return e};return{async getModels(){return n().getModels()},async getAllTools(){let e=n();return typeof e.getAllTools==`function`?e.getAllTools():[]},async*sendMessage(e,t,r,i){let a=n(),o=[],s=null,c=!1,l=a.onProgress(e=>{let t=e;i&&t.sessionId&&t.sessionId!==i||(o.push(e),s?.(),(e.type===`done`||e.type===`error`)&&(c=!0))});a.send({message:e,images:r,options:t,sessionId:i});try{for(;!c||o.length>0;){for(;o.length===0&&!c;)await new Promise(e=>s=e);if(o.length>0){let e=o.shift();if(yield e,e.type===`done`||e.type===`error`)break}}}finally{l()}},cancel(){n().cancel()},setCwd(e){n().setCwd(e)},async getSessions(){return n().getSessions()},async getSession(e){return n().getSession(e)},async createSession(e){return n().createSession(e)},async updateSession(e,t){return n().updateSession(e,t)},async deleteSession(e){await n().deleteSession(e)},async getMessages(e){return n().getMessages(e)},async getMessagesPage(e,t){return n().getMessagesPage(e,t)},async saveMessage(e){return n().saveMessage(e)},async updateMessage(e){await n().updateMessage(e)},async deleteMessagesAfter(e,t){await n().deleteMessagesAfter(e,t)},async deleteMessagesAfterMessageId(e,t){await n().deleteMessagesAfterMessageId(e,t)},async getOperations(e){return n().getOperations(e)},async getTrashItems(){return n().getTrashItems()},async restoreFromTrash(e){return n().restoreFromTrash(e)},async listDir(e){return n().listDir(e)},async exists(e){return n().exists(e)},async stat(e){return n().stat(e)},async readFile(e){return n().readFile(e)},async resolveAtFileContext(e){return n().resolveAtFileContext(e)},async readFileBase64(e){return n().readFileBase64(e)},async homeDir(){return n().homeDir()},async resolvePath(e){return n().resolvePath(e)},async parentDir(e){return n().parentDir(e)},async watchDir(e){return n().watchDir(e)},async unwatchDir(e){return n().unwatchDir(e)},onDirChange(e){return n().onDirChange(e)},async getSetting(e){let t=n();return t.getSetting?t.getSetting(e):null},async setSetting(e,t){let r=n();r.setSetting&&await r.setSetting(e,t)},async getAllSettings(){let e=n();return e.getAllSettings?e.getAllSettings():{}},async deleteSetting(e){let t=n();t.deleteSetting&&await t.deleteSetting(e)},async getIndexStats(){let e=n();return e.getIndexStats?e.getIndexStats():{totalDocuments:0,indexSize:0,lastUpdated:null}},async getIndexStatus(){let e=n();return e.getIndexStatus?e.getIndexStatus():{isIndexing:!1,lastProgress:null}},async syncIndex(){let e=n();return e.syncIndex?e.syncIndex():{success:!1}},async cancelIndex(){let e=n();return e.cancelIndex?e.cancelIndex():{success:!1}},async deleteIndex(){let e=n();return e.deleteIndex?e.deleteIndex():{success:!1}},async registerIndexListener(){let e=n();return e.registerIndexListener?e.registerIndexListener():{success:!1}},async unregisterIndexListener(){let e=n();return e.unregisterIndexListener?e.unregisterIndexListener():{success:!1}},onIndexProgress(e){let t=n();return t.onIndexProgress?t.onIndexProgress(e):()=>{}},async searchAtDocuments(e,t){let r=n();if(!r.searchAtDocuments)return[];try{return await r.searchAtDocuments(e,{limit:t?.limit,mode:`hybrid`})}catch{return[]}},async listAtTerminals(e){let t=n();if(!t.listAtTerminals)return[];try{return await t.listAtTerminals(e)}catch{return[]}},async searchAtChats(e,t){try{return await n().searchAtChats(e,t)}catch{return[]}},onToolApprovalRequest(e){let t=n();return t.onToolApprovalRequest?t.onToolApprovalRequest(e):()=>{}},async respondToolApproval(e,t){let r=n();if(r.respondToolApproval)return r.respondToolApproval(e,t)},async asrStart(e){let t=n();return t.asrStart?t.asrStart(e):{success:!1,error:`ASR not supported`}},async asrSendAudio(e){let t=n();return t.asrSendAudio?t.asrSendAudio(e):{success:!1,error:`ASR not supported`}},async asrFinish(){let e=n();return e.asrFinish?e.asrFinish():{success:!1,error:`ASR not supported`}},async asrStop(){let e=n();return e.asrStop?e.asrStop():{success:!0}},async asrStatus(){let e=n();return e.asrStatus?e.asrStatus():{connected:!1}},async asrWarmup(e){let t=n();return t.asrWarmup?t.asrWarmup(e):{success:!1,error:`ASR not supported`}},onAsrConnected(e){let t=n();return t.onAsrConnected?t.onAsrConnected(e):()=>{}},onAsrResult(e){let t=n();return t.onAsrResult?t.onAsrResult(e):()=>{}},onAsrError(e){let t=n();return t.onAsrError?t.onAsrError(e):()=>{}},onAsrClosed(e){let t=n();return t.onAsrClosed?t.onAsrClosed(e):()=>{}},async openExternal(e){let t=n();if(t.openExternal)return t.openExternal(e)}}}function o(e){let{bridgeName:t=`aiChatBridge`,remote:n}=e,{baseURL:r,getToken:a,getAppId:o}=n,s=()=>{let e=window[t];if(!e)throw Error(`AI Chat Bridge not found. Make sure to call exposeElectronBridge() in preload.`);return e};async function c(){let e=await a(),t=o?await o():null,n={};return e&&(n.Authorization=`Bearer ${e}`),t&&(n[`app-id`]=t),n}async function l(e,t={}){let n=await c(),i=t.method?.toUpperCase()||`GET`;[`POST`,`PUT`,`PATCH`].includes(i)&&(n[`Content-Type`]=`application/json`);let a=await fetch(`${r}${e}`,{...t,headers:{...n,...t.headers||{}}});if(!a.ok)throw Error(`HTTP ${a.status}: ${a.statusText}`);return a.json()}function u(e){try{return JSON.parse(e)}catch{return null}}let d=null;return{async getModels(){return(await l(`/chat/models`)).models||[]},async getAllTools(){let e=s();return typeof e.getAllTools==`function`?e.getAllTools():[]},async*sendMessage(e,t,n,a){d&&d.abort(),d=new AbortController;let{signal:o}=d;try{let l=s(),d=typeof l.getToolDefinitions==`function`?await l.getToolDefinitions():[],f=e,p=t,m=n,h=0;for(let e=0;e<10;e++){i.debug(`开始远端流式请求`,{iteration:e+1,stepNumberOffset:h,hasHistory:!!p?.history?.length});let t=await c(),n=await fetch(`${r}/chat/stream`,{method:`POST`,headers:{...t,"Content-Type":`application/json`,Accept:`text/event-stream`},body:JSON.stringify({message:f,options:p,images:m,sessionId:a,tools:d}),signal:o});if(!n.ok)throw Error(`HTTP ${n.status}: ${n.statusText}`);let s=n.body?.getReader();if(!s)throw Error(`Response body is not readable`);let g=new TextDecoder,_=``,v=[],y=``,b=!1,x=0;for(;;){let{done:t,value:n}=await s.read();if(t)break;_+=g.decode(n,{stream:!0});let r=_.split(`
|
|
2
|
+
`);_=r.pop()||``;for(let t of r)if(t.startsWith(`data: `)){let n=t.slice(6).trim();if(n===`[DONE]`)break;let r=u(n);if(r){let t=r.type===`step_start`||r.type===`step_end`||r.type===`assistant_segment_start`?(typeof r.data.stepNumber==`number`&&(x=Math.max(x,r.data.stepNumber)),{...r,data:{...r.data,...typeof r.data.stepNumber==`number`?{stepNumber:r.data.stepNumber+h}:{}}}):r;if((t.type===`assistant_segment_start`||t.type===`step_start`||t.type===`step_end`||t.type===`text_start`||t.type===`text_end`||t.type===`done`)&&i.debug(`出站事件`,{iteration:e+1,rawType:r.type,outgoingType:t.type,rawStepNumber:`stepNumber`in r.data?r.data.stepNumber:void 0,outgoingStepNumber:`stepNumber`in t.data?t.data.stepNumber:void 0,blockId:`blockId`in t.data?t.data.blockId:void 0}),r.type===`text_delta`&&(y+=r.data.content||``),r.type===`tool_call_request`){let{id:e,name:t,args:n,ui:a,approvalPolicy:o,sideEffectLevel:s,hostDependency:c,riskSummary:l,riskTags:u,riskSignals:d}=r.data;i.debug(`收到 tool_call_request:`,t,`args:`,JSON.stringify(n).slice(0,500)),v.push({id:e,name:t,args:n}),yield{type:`tool_call_start`,data:{id:e,name:t,args:n,...a?{ui:a}:{},...o?{approvalPolicy:o}:{},...s?{sideEffectLevel:s}:{},...c?{hostDependency:c}:{},...l?{riskSummary:l}:{},...u?.length?{riskTags:u}:{},...d?.length?{riskSignals:d}:{},startedAt:Date.now()}}}else if(r.type===`done`)v.length>0?b=!0:yield r;else if(yield t,r.type===`error`)return}}}if(_.startsWith(`data: `)){let t=_.slice(6).trim();if(t&&t!==`[DONE]`){let n=u(t);if(n&&n.type!==`tool_call_request`){let t=n.type===`step_start`||n.type===`step_end`||n.type===`assistant_segment_start`?(typeof n.data.stepNumber==`number`&&(x=Math.max(x,n.data.stepNumber)),{...n,data:{...n.data,...typeof n.data.stepNumber==`number`?{stepNumber:n.data.stepNumber+h}:{}}}):n;(t.type===`assistant_segment_start`||t.type===`step_start`||t.type===`step_end`||t.type===`text_start`||t.type===`text_end`||t.type===`done`)&&i.debug(`出站尾事件`,{iteration:e+1,rawType:n.type,outgoingType:t.type,rawStepNumber:`stepNumber`in n.data?n.data.stepNumber:void 0,outgoingStepNumber:`stepNumber`in t.data?t.data.stepNumber:void 0,blockId:`blockId`in t.data?t.data.blockId:void 0}),n.type===`done`&&v.length>0?b=!0:yield t}}}if(v.length>0&&b){i.debug(`执行工具:`,v.map(e=>e.name).join(`, `));let t=[];for(let e of v){let n=Date.now();i.debug(`executeTool(${e.name}) args:`,JSON.stringify(e.args).slice(0,500));let r=await l.executeTool(e.name,e.args,{toolCallId:e.id,sessionId:a});i.debug(`executeTool(${e.name}) result:`,JSON.stringify(r).slice(0,500)),yield{type:`tool_call_result`,data:{id:e.id,name:e.name,result:r.result,success:r.success,error:r.error,toolError:r.toolError,ui:r.ui,approvalPolicy:r.approvalPolicy,sideEffectLevel:r.sideEffectLevel,hostDependency:r.hostDependency,riskSummary:r.riskSummary,riskTags:r.riskTags,riskSignals:r.riskSignals,endedAt:Date.now(),duration:Date.now()-n}},t.push({role:`tool`,content:r.result,tool_call_id:e.id})}let n=v.map(e=>({id:e.id,type:`function`,function:{name:e.name,arguments:JSON.stringify(e.args)}})),r=[...p?.history||[],...f?[{role:`user`,content:f}]:[],{role:`assistant`,content:y,tool_calls:n},...t];i.debug(`继续对话,新 history 长度:`,r.length),f=``,p={...p,history:r},m=void 0,y=``,i.debug(`进入 continuation`,{iteration:e+1,requestMaxStepNumber:x,nextStepNumberOffset:h+Math.max(x,1),toolCalls:v.map(e=>e.name)}),h+=Math.max(x,1)}else{i.debug(`流式请求结束,无 continuation`,{iteration:e+1,requestMaxStepNumber:x,stepNumberOffset:h});break}}}finally{d=null}},cancel(){d&&=(d.abort(),null)},setCwd(e){s().setCwd(e)},async getSessions(){return s().getSessions()},async getSession(e){return s().getSession(e)},async createSession(e){return s().createSession(e)},async updateSession(e,t){return s().updateSession(e,t)},async deleteSession(e){await s().deleteSession(e)},async getMessages(e){return s().getMessages(e)},async getMessagesPage(e,t){return s().getMessagesPage(e,t)},async saveMessage(e){return s().saveMessage(e)},async updateMessage(e){await s().updateMessage(e)},async deleteMessagesAfter(e,t){await s().deleteMessagesAfter(e,t)},async deleteMessagesAfterMessageId(e,t){await s().deleteMessagesAfterMessageId(e,t)},async getOperations(e){return s().getOperations(e)},async getTrashItems(){return s().getTrashItems()},async restoreFromTrash(e){return s().restoreFromTrash(e)},async listDir(e){return s().listDir(e)},async exists(e){return s().exists(e)},async stat(e){return s().stat(e)},async readFile(e){return s().readFile(e)},async resolveAtFileContext(e){return s().resolveAtFileContext(e)},async readFileBase64(e){return s().readFileBase64(e)},async homeDir(){return s().homeDir()},async resolvePath(e){return s().resolvePath(e)},async parentDir(e){return s().parentDir(e)},async watchDir(e){return s().watchDir(e)},async unwatchDir(e){return s().unwatchDir(e)},onDirChange(e){return s().onDirChange(e)},async getSetting(e){let t=s();return t.getSetting?t.getSetting(e):null},async setSetting(e,t){let n=s();n.setSetting&&await n.setSetting(e,t)},async getAllSettings(){let e=s();return e.getAllSettings?e.getAllSettings():{}},async deleteSetting(e){let t=s();t.deleteSetting&&await t.deleteSetting(e)},async getIndexStats(){let e=s();return e.getIndexStats?e.getIndexStats():{totalDocuments:0,indexSize:0,lastUpdated:null}},async getIndexStatus(){let e=s();return e.getIndexStatus?e.getIndexStatus():{isIndexing:!1,lastProgress:null}},async syncIndex(){let e=s();return e.syncIndex?e.syncIndex():{success:!1}},async cancelIndex(){let e=s();return e.cancelIndex?e.cancelIndex():{success:!1}},async deleteIndex(){let e=s();return e.deleteIndex?e.deleteIndex():{success:!1}},async registerIndexListener(){let e=s();return e.registerIndexListener?e.registerIndexListener():{success:!1}},async unregisterIndexListener(){let e=s();return e.unregisterIndexListener?e.unregisterIndexListener():{success:!1}},onIndexProgress(e){let t=s();return t.onIndexProgress?t.onIndexProgress(e):()=>{}},async searchAtDocuments(e,t){let n=s();if(!n.searchAtDocuments)return[];try{return await n.searchAtDocuments(e,{limit:t?.limit,mode:`hybrid`})}catch{return[]}},async listAtTerminals(e){let t=s();if(!t.listAtTerminals)return[];try{return await t.listAtTerminals(e)}catch{return[]}},async searchAtChats(e,t){try{return await s().searchAtChats(e,t)}catch{return[]}},onToolApprovalRequest(e){return()=>{}},async respondToolApproval(e,t){},async asrStart(e){let t=s();return t.asrStart?t.asrStart(e):{success:!1,error:`ASR not supported`}},async asrSendAudio(e){let t=s();return t.asrSendAudio?t.asrSendAudio(e):{success:!1,error:`ASR not supported`}},async asrFinish(){let e=s();return e.asrFinish?e.asrFinish():{success:!1,error:`ASR not supported`}},async asrStop(){let e=s();return e.asrStop?e.asrStop():{success:!0}},async asrStatus(){let e=s();return e.asrStatus?e.asrStatus():{connected:!1}},async asrWarmup(e){let t=s();return t.asrWarmup?t.asrWarmup(e):{success:!1,error:`ASR not supported`}},onAsrConnected(e){let t=s();return t.onAsrConnected?t.onAsrConnected(e):()=>{}},onAsrResult(e){let t=s();return t.onAsrResult?t.onAsrResult(e):()=>{}},onAsrError(e){let t=s();return t.onAsrError?t.onAsrError(e):()=>{}},onAsrClosed(e){let t=s();return t.onAsrClosed?t.onAsrClosed(e):()=>{}},async openExternal(e){let t=s();if(t.openExternal)return t.openExternal(e)}}}export{a as createElectronAdapter,o as createHybridAdapter,r as createLogger};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 浏览器端日志工具
|
|
3
|
+
*
|
|
4
|
+
* API 与 ai-chat-core 的 DebugLogger 对齐。
|
|
5
|
+
* 开关:localStorage.setItem('AI_CHAT_DEBUG', 'true')
|
|
6
|
+
*
|
|
7
|
+
* - warn / error 始终输出(生产可见)
|
|
8
|
+
* - debug / info 受开关控制(默认关闭)
|
|
9
|
+
*/
|
|
10
|
+
export interface Logger {
|
|
11
|
+
debug(...args: unknown[]): void;
|
|
12
|
+
info(...args: unknown[]): void;
|
|
13
|
+
warn(...args: unknown[]): void;
|
|
14
|
+
error(...args: unknown[]): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function createLogger(module: string): Logger;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@huyooo/ai-chat-bridge-electron",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "AI Chat Electron Bridge - IPC integration for Electron apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/main/index.js",
|
|
@@ -24,19 +24,24 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "
|
|
28
|
-
"
|
|
27
|
+
"build": "npm run clean && npm run build:js && npm run build:types",
|
|
28
|
+
"build:js": "tsdown",
|
|
29
|
+
"build:types": "tsc -b tsconfig.json --emitDeclarationOnly",
|
|
30
|
+
"dev": "tsdown --watch",
|
|
29
31
|
"typecheck": "tsc --noEmit",
|
|
30
|
-
"clean": "rm -rf dist"
|
|
32
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo"
|
|
31
33
|
},
|
|
32
34
|
"dependencies": {
|
|
33
|
-
"@huyooo/ai-chat-core": "^0.
|
|
34
|
-
"@huyooo/ai-chat-
|
|
35
|
-
"@huyooo/ai-chat-
|
|
35
|
+
"@huyooo/ai-chat-core": "^0.3.6",
|
|
36
|
+
"@huyooo/ai-chat-host-node": "^0.3.6",
|
|
37
|
+
"@huyooo/ai-chat-storage": "^0.3.6",
|
|
38
|
+
"@huyooo/ai-chat-tools-node": "^0.3.6",
|
|
39
|
+
"@huyooo/ai-chat-types": "^0.3.6",
|
|
36
40
|
"uuid": "^11.1.0",
|
|
37
41
|
"ws": "^8.18.3"
|
|
38
42
|
},
|
|
39
43
|
"peerDependencies": {
|
|
44
|
+
"better-sqlite3": ">=9.0.0",
|
|
40
45
|
"electron": ">=20.0.0"
|
|
41
46
|
},
|
|
42
47
|
"peerDependenciesMeta": {
|
|
@@ -49,7 +54,7 @@
|
|
|
49
54
|
"@types/uuid": "^10.0.0",
|
|
50
55
|
"@types/ws": "^8.18.1",
|
|
51
56
|
"electron": "^33.0.0",
|
|
52
|
-
"
|
|
57
|
+
"tsdown": "^0.21.0",
|
|
53
58
|
"typescript": "^5.0.0"
|
|
54
59
|
},
|
|
55
60
|
"keywords": [
|