AgnesCode IPC 协议分析报告
协议端点: Renderer (React) ↔ Main Process (Electron Node.js)
通信方式: Electron IPC (contextBridge)
报告日期: 2026-07-25
分析版本: v1.0.17
1. 架构概述
┌────────────────────────────────────────────────────────────┐
│ Renderer Process (React 19) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ window.electron.xxx() ← contextBridge.exposeInMainWorld │
│ │ window.appConfig.xxx() │ │
│ └──────────────────────┬───────────────────────────────┘ │
│ │ IPC │
│ ┌──────────────────────▼───────────────────────────────┐ │
│ │ Main Process (Node.js 24) │ │
│ │ ipcMain.handle("channel", handler) ← invoke │ │
│ │ ipcMain.on("channel", handler) ← send │ │
│ │ webContents.send("channel", data) → on │ │
│ └──────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘安全模型:
contextIsolation: true— 上下文隔离开启nodeIntegration: false— 渲染进程无法直接访问 Node.js- 所有系统功能通过
contextBridge.exposeInMainWorld暴露 - 严格的 CSP (Content-Security-Policy) 限制
2. IPC 通信模型
AgnesCode 使用三种 IPC 模式:
2.1 invoke/handle (双向请求-响应)
Renderer 调用 window.electron.xxx() → ipcRenderer.invoke() → Main Process 的 ipcMain.handle() 处理 → 返回 Promise
javascript
// Renderer (preload.js)
startAuthLogin: () => ipcRenderer.invoke("start-auth-login")
// Main Process (main.js)
ipcMain.handle("start-auth-login", async (event) => {
// ... 处理逻辑
return { state: hexState };
});2.2 send/on (单向消息)
Renderer 通过 ipcRenderer.send() 发送消息,Main Process 监听:
javascript
// Renderer
reactReady: () => ipcRenderer.send("react-ready")
// Main Process
ipcMain.on("react-ready", async (event) => { ... });2.3 on/webContents.send (主进程推送)
Main Process 通过 webContents.send() 向 Renderer 推送事件:
javascript
// Main Process
webContents.send("auth-deeplink", { code, state });
// Renderer (preload.js)
on: (channel, callback) => { ipcRenderer.on(channel, callback) }3. 完整 IPC API 清单
3.1 认证 & OAuth
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
startAuthLogin | invoke | R→M | 无 | { state: string } |
authListenerReady | send | R→M | 无 | - |
getSecretKey | invoke | R→M | 无 | string |
事件 auth-deeplink | on | M→R | { code: string, state: string } | - |
认证流程:
- Renderer 调用
window.electron.startAuthLogin() - Main Process 生成 32 字节 state, 打开浏览器登录页
- 用户登录后, 浏览器回调
agnes://auth/callback?code=...&state=... - Main Process 验证 state 后发送
auth-deeplink事件到 Renderer - Renderer 用 code 调用远程 API 交换 access_token
3.2 后端管理 (agnest)
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
waitForBackendReady | invoke | R→M | 无 | boolean |
getAcpUrl | invoke | R→M | 无 | string | null (WebSocket URL) |
getGoosedHostPort | invoke | R→M | 无 | string | null (baseUrl) |
reactReady | send | R→M | 无 | - |
启动流程:
- Renderer 发送
react-ready表示 UI 就绪 - Main Process 启动 agnesd 子进程
- 健康检查轮询:
GET /health_check(每 250ms, 最长 30s) - 就绪后, Renderer 通过
getAcpUrl()获取 WebSocket URL - WebSocket URL:
wss://127.0.0.1:{port}/acp?token={secretKey}
3.3 窗口管理
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
hideWindow | send | R→M | 无 | - |
closeWindow | send | R→M | 无 | - |
createChatWindow | send | R→M | {...}? | - |
raiseMainWindow | send | R→M | 无 | - |
setAlwaysOnTop | invoke | R→M | boolean | boolean |
getAlwaysOnTop | invoke | R→M | 无 | boolean |
getIsFullScreen | invoke | R→M | 无 | boolean |
isAnyWindowFocused | invoke | R→M | 无 | boolean |
setWindowsTitleBarOverlaySurface | send | R→M | string | - |
3.4 文件系统
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
readFile | invoke | R→M | string (path) | string (content) |
writeFile | invoke | R→M | (path, content) | - |
readFileDataUrl | invoke | R→M | (path, encoding?) | string |
readImageFile | invoke | R→M | string (path) | ArrayBuffer |
readOfficePreview | invoke | R→M | string (path) | any |
directoryChooser | invoke | R→M | 无 | string | null |
selectFileOrDirectory | invoke | R→M | string? (defaultPath) | string | null |
selectImportSessionFile | invoke | R→M | 无 | { filePath, contents, error? } | null |
listFiles | invoke | R→M | (dir, pattern?) | string[] |
ensureDirectory | invoke | R→M | string (path) | - |
showItemInFolder | invoke | R→M | string (path) | - |
openPath | invoke | R→M | string (path) | - |
openDirectoryInExplorer | invoke | R→M | string (path) | - |
shareExportZip | invoke | R→M | {...} | - |
writeSkillPreviewFile | invoke | R→M | (path, content) | - |
uploadBinaryToPresignedUrl | invoke | R→M | { uploadUrl, contentType, body } | - |
3.5 设置 & 配置
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
getSetting | invoke | R→M | string (key) | any |
setSetting | invoke | R→M | (key, value) | - |
getConfig | 同步 | R→M | 无 | object (启动参数) |
getAll | 同步 | R→M | 无 | object (全部 env) |
getVersion | 同步 | R→M | 无 | string |
appConfig 对象 (通过 contextBridge 暴露):
javascript
window.appConfig = {
get: (key) => config[key], // 获取单个环境变量
getAll: () => ({ ...config }) // 获取所有环境变量
};暴露的环境变量:
AGNES_DEFAULT_PROVIDER, AGNES_DEFAULT_MODEL, AGNES_PREDEFINED_MODELS,
AGNES_VERSION, AGNES_API_HOST, AGNES_PATH_ROOT, AGNES_WORKING_DIR,
AGNES_INITIAL_THEME, AGNES_LOCALE, AGNES_API_URL3.6 应用更新
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
checkForUpdates | invoke | R→M | 无 | UpdateInfo |
downloadUpdate | invoke | R→M | 无 | - |
installUpdate | invoke | R→M | 无 | - |
getUpdateState | invoke | R→M | 无 | UpdateState |
restartApp | send | R→M | 无 | - |
reloadApp | send | R→M | 无 | - |
事件 updater-event | on | M→R | UpdateEvent | - |
3.7 伪终端 (PTY)
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
createPtySession | invoke | R→M | (cwd, cmd, args?) | sessionId |
writePtySession | invoke | R→M | (sessionId, data) | - |
resizePtySession | invoke | R→M | (sessionId, cols, rows) | - |
closePtySession | invoke | R→M | sessionId | - |
事件 agnes-pty-event | on | M→R | { sessionId, event, data } | - |
3.8 Git 集成
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
getGitSummary | invoke | R→M | string (dir) | GitSummary |
watchGitSummary | invoke | R→M | string (dir) | - |
unwatchGitSummary | invoke | R→M | string (dir) | - |
listGitWorktreeDirs | invoke | R→M | string (dir) | string[] |
事件 agnes-git-summary-changed | on | M→R | GitSummary | - |
3.9 Workspace 管理
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
listWorkspaceTree | invoke | R→M | string (dir) | TreeNode[] |
listWorkspaceTreeChildren | invoke | R→M | (dir, path) | TreeNode[] |
readWorkspaceFile | invoke | R→M | (dir, path) | string |
checkLocalPreview | invoke | R→M | string (path) | boolean |
addRecentDir | invoke | R→M | string (dir) | - |
listRecentDirs | invoke | R→M | 无 | string[] |
3.10 通知 & 对话框
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
showNotification | send | R→M | NotificationOptions | - |
showMessageBox | invoke | R→M | MessageBoxOptions | { response: number } |
showSaveDialog | invoke | R→M | SaveDialogOptions | { filePath: string } |
openNotificationsSettings | invoke | R→M | 无 | boolean |
3.11 外部链接
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
openExternal | invoke | R→M | string (url) | - |
openInChrome | send | R→M | string (url) | - |
launchApp | invoke | R→M | string (app) | - |
getLaunchedApp | invoke | R→M | string (app) | any |
refreshApp | invoke | R→M | string (app) | - |
closeApp | invoke | R→M | string (app) | - |
3.12 语音 (腾讯云)
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
getTencentVoiceConfig | invoke | R→M | 无 | TencentVoiceConfig |
transcribeTencentVoice | invoke | R→M | (audio, mimeType) | string |
startTencentRealtimeSession | invoke | R→M | 无 | sessionId |
sendTencentRealtimePcm | send | R→M | (voiceId, pcmBase64) | - |
stopTencentRealtimeSession | invoke | R→M | voiceId | - |
cancelTencentRealtimeSession | invoke | R→M | voiceId | - |
事件 tencent-voice-realtime-event | on | M→R | event | - |
3.13 mesh-llm (P2P 模型网络)
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
checkMesh | invoke | R→M | 无 | { running, installed, models, ... } |
startMesh | invoke | R→M | args[] | { started, pid, error? } |
stopMesh | invoke | R→M | 无 | { stopped } |
checkOllama | invoke | R→M | 无 | boolean |
3.14 其他
| 方法 | 类型 | 方向 | 参数 | 返回值 |
|---|---|---|---|---|
capturePage | invoke | R→M | 无 | NativeImage |
collectElectronLogs | invoke | R→M | 无 | string |
invokeAppMenuAction | invoke | R→M | string | - |
setMenuBarIcon | invoke | R→M | boolean | - |
getMenuBarIconState | invoke | R→M | 无 | boolean |
setDockIcon | invoke | R→M | boolean | - |
getDockIconState | invoke | R→M | 无 | boolean |
setWakelock | invoke | R→M | boolean | - |
getWakelockState | invoke | R→M | 无 | boolean |
setSpellcheck | invoke | R→M | boolean | - |
getSpellcheckState | invoke | R→M | 无 | boolean |
setVisualPinchZoomLock | invoke | R→M | boolean | - |
broadcastThemeChange | invoke | R→M | string (theme) | - |
hasAcceptedRecipeBefore | invoke | R→M | string (recipe) | boolean |
recordRecipeHash | invoke | R→M | string (recipe) | - |
getGlobalShortcutFailures | invoke | R→M | 无 | string[] |
事件 mouse-back-button-clicked | on | M→R | 无 | - |
事件 network-interface-changed | on | M→R | event | - |
4. 预定义设置项
从 preload.js 提取的默认配置:
javascript
const R = {
showMenuBarIcon: true,
disableAutoDownload: false,
showDockIcon: true,
enableWakelock: false,
enableNotifications: true,
spellcheckEnabled: true,
keyboardShortcuts: {
focusWindow: "CommandOrControl+Alt+G",
quickLauncher: "CommandOrControl+Alt+Shift+G",
newChat: "CommandOrControl+T",
newChatWindow: "CommandOrControl+N",
openDirectory: "CommandOrControl+O",
settings: "CommandOrControl+,",
find: "CommandOrControl+F",
findNext: "CommandOrControl+G",
findPrevious: "CommandOrControl+Shift+G",
alwaysOnTop: "CommandOrControl+Shift+T",
toggleNavigation: "CommandOrControl+/"
},
disabledKeyboardShortcuts: {},
externalGoosed: { enabled: false, url: "", secret: "" },
theme: "light",
useSystemTheme: true,
language: "system",
agentMode: "smart",
responseStyle: "concise",
showPricing: true,
sessionSharing: { enabled: false, baseUrl: "" }
};5. 安全性分析
- contextIsolation: Renderer 无法直接访问 Node.js API
- nodeIntegration: false: 渲染进程无法 require 模块
- CSP: 严格的 Content-Security-Policy, 限制 script-src 和 connect-src
- 预定义白名单: preload.js 只暴露了有限的方法
- 协议白名单:
openExternal检查危险协议 (如file://) - Secret Key 保护: 密钥通过 IPC 传递, 不在渲染进程存储
6. 关键数据流图
┌──────────┐ IPC invoke ┌──────────────┐ spawn ┌──────────┐
│ Renderer │◄───────────────►│ Main Process │◄───────────►│ agnesd │
│ (React) │ contextBridge │ (Node.js) │ HTTPS+WS │ (Rust) │
└────┬─────┘ └──────┬───────┘ └──────────┘
│ │
│ fetch (HTTPS) │ shell.openExternal
▼ ▼
┌──────────┐ ┌──────────────┐
│ Agnes │ │ System │
│ API │ │ Browser │
│ Server │ │ (OAuth) │
└──────────┘ └──────────────┘