多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Maka 核心技术解读:本地优先 Agent 工作台的 Runtime 内核、权限门控与崩溃恢复架构

Maka 核心技术解读:本地优先 Agent 工作台的 Runtime 内核、权限门控与崩溃恢复架构 Maka 核心技术解读本地优先 Agent 工作台的 Runtime 内核、权限门控与崩溃恢复架构【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka本文基于 docs/archive/maka-core-tech-walkthrough.md2026-06-25 生成、2026-07-13 归档的技术通读笔记展开并结合当前仓库源码、配置与测试用例进行验证与补充。面向工程师帮助你理解 Maka 的 runtime 内核分层、四档权限模型、ledger 持久化恢复以及 Electron 集成边界并掌握崩溃可恢复、权限可控、诊断不影响主路径这三条核心设计如何在代码中落地。整体定位Maka 是一个本地优先local-first的 Electron 桌面 AI agent 工作台。它的技术追求可以概括为一句话让用户在自己的电脑上跑一个可观察、可控、可恢复的 agent——所有数据本地落盘敏感值按各自边界保存在本地工具调用走权限策略单次对话崩溃后能从 ledger 恢复。当前官方 README 将其定位为 a high-performance agent workspace that keeps a complete record of everything it did高性能 agent 工作区完整记录它所做的一切这与下面要讲的 ledger projection 架构完全对应完整记录正是靠 run 事件日志ledger实现的。仓库分层monorepo 使用 npm workspaces分层清晰包定位说明packages/core纯契约层零运行时依赖只定义类型、纯函数与策略表如 packages/core/src/permission.tspackages/storage文件持久化层run ledger、原子写、session 消息 JSONLpackages/runtime内核实现最核心的部分SessionManager / AgentRun / backend / ToolRuntimepackages/ui共享渲染组件React 组件与 storiesapps/desktopElectron 壳子把 runtime 装进窗口提供 IPC、preload、OAuth、bot、gateway核心设计原则契约与实现分离。runtime 内核再拆成可独立理解的边界session → run → backend → model/tool公共 API 保持稳定内部可演化。例如契约层的permission.ts只声明类型与纯策略而真正的运行时状态requestId、parked Promise由 runtime 层管理。Runtime 内核架构这是整个项目最核心的部分。分层关系如下SessionManager ← 对外公共 API桌面 / bot / gateway 都走它 - AgentRun ← 单次 turn 的生命周期 启动恢复 - AiSdkBackend ← 流式 工具循环引擎 - ModelAdapter ← provider stream / usage / error 归一化 - ToolRuntime ← 工具输入校验 / 权限 / watchdog / abort / telemetry - RunTrace ← best-effort 诊断 trace写失败不影响对话 - AgentRunStore ← durable run ledger关键代码入口已按当前仓库核实模块文件SessionManager类packages/runtime/src/session-manager.tsexport class SessionManager位于 905 行附近AgentRun类packages/runtime/src/agent-run.tsexport class AgentRun242 行AiSdkBackend.send()流式泵packages/runtime/src/ai-sdk-backend.tsToolRuntime权限门控packages/runtime/src/tool-runtime.tsexport class ToolRuntime477 行ModelAdapterprovider 适配packages/runtime/src/model-adapter.tsexport class ModelAdapter145 行RunTrace诊断packages/runtime/src/run-trace.tsexport class RunTrace107 行SessionManager公共 runtime APISessionManager是对外桌面 IPC、bot adapter、open-gateway 三类入口暴露的唯一 runtime 门面职责包括session CRUDbackend registry 编排active run 查找恢复入口recoverInterruptedSessions()参见 packages/runtime/src/session-manager.ts 及测试 packages/runtime/src/tests/runtime-continuation-crash.test.ts真正干活的 turn 生命周期被委派给AgentRun。AgentRun单 turn 的 durable 编排理解恢复机制的关键。一次sendMessage会创建一个AgentRun它负责生成 runId写run_created事件到 ledger追加用户消息、写初始 turn 状态锁定连接快照connectionLocked防止 turn 跑到一半连接被改构建 prior runtime context从历史 run 的RuntimeEvent投影成模型历史驱动 backend 流事件投影 session 状态写 turn 完成 / 失败 / abort / permission-wait 状态finalize()收尾注销 active run、更新 header、写run_completed / run_failed / run_cancelled。execute()是 async generator核心结构packages/runtime/src/agent-run.tsasync *execute(): AsyncIterableSessionEvent { try { const begin await this.begin(); for await (const ev of begin.backend.send(begin.backendInput)) { await this.recordSessionEvent(ev); yield ev; } } catch (error) { await this.recordFailure(error); throw error; } finally { await this.finalize(); } }每个 backend 事件都会被recordSessionEvent投影成 session 状态变更running / blocked / aborted并记录到 run ledger。即使进程崩溃重启时也能从 ledger 重建。AgentRun还定义了AgentRunDurability best_effort | requiredpackages/runtime/src/agent-run.ts 159 行区分尽力持久化与必须持久化两种耐用性级别。AiSdkBackend流式 多步工具循环agent loop 的引擎用 Vercel AI SDK 的streamText配合stopWhen: stepCountIs(N)驱动多步工具调用循环——循环本身交给 AI SDK但所有自己的机器权限、持久化、materializer、watchdog都保留在 Maka 这边。send()的当前实现packages/runtime/src/ai-sdk-backend.tsasync *send(input: BackendSendInput): AsyncIterableSessionEvent { const turn this.openTurnScope(input); try { yield* turn.run(); } finally { this.activeTurns.delete(turn); await turn.close(); } }相比归档笔记中单 turn 单后台泵的描述当前实现已演化为per-turn scope 模型每次send()打开一个AiSdkTurnopenTurnScope该 turn 拥有自己的 abort controller、自己的ToolRuntime、自己的 watchdog 与 run trace。这带来两个重要特性并发 turn 互不串扰stop()以广播方式停止所有 active turn但每个 turn 以自身身份收尾不再共享一个currentTurnId导致重叠 turn 被错误标记清理顺序保证teardown 对每个 scope 全部 settle 后才抛错——因为endTurn是唯一能 reject 停在askUserQuestion上的工具的东西abort signal 不会唤醒 registry若中途 bail 会导致兄弟 turn 永远 parked代码注释对此有详细说明。stop()支持mode: immediate | after_step两种停止策略且会先abortHistoryCompact()中止手动历史压缩。backend 层的精巧点还包括StreamWatchdog流式连接有 connect timeout 和 idle timeout超时会 abort controller 并推 error 事件防止挂死工具执行期间 watchdog 会被暂停见下文 ToolRuntime。step cap grace当finishReason tool-calls撞了 step 上限且没有 assistant 文本时注入一条确定性提示告诉用户已达本轮工具上限、可发继续。prepareStep 动态工具加载同 turn 内可以逐步激活更多工具deferred loadactive 工具集按 step 重算snapshotToolAvailability()packages/runtime/src/ai-sdk-backend.ts负责冻结 host tools 并注入 memory trigger 工具且保留MEMORY_REMEMBER_TOOL_NAME/MEMORY_EXTRACT_TOOL_NAME两个保留名防止用户工具冲突。ToolRuntime权限门控 seam整个安全模型的执行点。每个send()会createToolRuntime(...)创建一个与 turn 身份绑定的ToolRuntimepackages/runtime/src/ai-sdk-backend.ts其 scope 闭包保证工具在 step 之后很久才 settle 时仍能解析到本 turn 的 watchdog、trace 和 run。工具调用经过的链loop-gate同一个 tool 同一组 args 连续失败 N 次直接 block防止 agent 死循环。block 本身不记 outcomestreak 停在阈值后续相同调用继续被拦。权限评估三态allow→ 跑真实实现写ToolResultblock→ 合成isError: true的工具结果返回给模型不执行真实逻辑prompt→ 推PermissionRequestEvent给 UIawait 一个 parked Promise等用户决定。allow 则跑deny 则合成用户拒绝。工具执行期间暂停 stream watchdog避免长任务被判超时finally里恢复。abort signal 透传进工具stop 按钮能中断。记录 telemetry、artifact candidate、错误分类。此外当前 ToolRuntime 还接入了sandbox boundary 请求AwaitRegistrySandboxBoundarySettlement支持沙箱边界升级的异步等待与respondToSandboxBoundary()路由。ModelAdapterprovider 归一化把 provider / AI SDK 的细节挡在外面stream chunk 类型、provider setup、usage 归一化、provider error mapping。startStream统一调streamTexthandleStreamChunk把各种 chunk 翻译成 Maka 的SessionEventtext delta、thinking delta、complete 等ModelAdapter还维护OpenAiChatReasoningTransportState处理 OpenAI chat 推理通道的状态packages/runtime/src/model-adapter.ts。这样未来加 provider 不需要重复权限 / 工具 / run / session 逻辑。RunTracebest-effort 诊断记录 turn 的里程碑事件RunTracePhase见 packages/runtime/src/run-trace.ts 79 行附近turn started、model resolved / stream started / completed / failed、tool started / completed / failed、permission requested / decided、usage recorded、abort requested。关键约束trace 写失败绝不影响用户对话。错误消息被截断到 2048 字符REDACTED_ERROR_MESSAGE_MAX_CHARS且它与 session 消息 JSONL 是分开的两套持久化。权限系统这是 Maka 区别于普通 chat demo 的核心安全设计定义在 packages/core/src/permission.ts。注意当前仓库中的权限模型相比归档笔记已有所演化下面以当前源码为准说明。权限模式PermissionMode当前PERMISSION_MODES [explore, ask, bypass]packages/core/src/permission.ts。归档笔记中提到的execute模式已被退役RETIRED_PERMISSION_MODES将execute折叠为ask——因为它从未有独立行为编译结果与ask相同、显示为ask、产生相同的执行边界。为了兼容历史记录decodePersistedPermissionMode()允许旧记录中的execute读回为ask但新输入与线上值使用严格的isPermissionMode()检查。模式语义explore只读探索读工具放行写与危险操作被 block网络读取需要 promptask默认交互模式读放行写/危险/网络/浏览器均需用户确认bypass全自动全部 allow仅用户显式选择时进入工具类别ToolCategoryTOOL_CATEGORIES共 14 类比归档笔记的 12 类多了computer_use与client_capability两类read, web_read, file_write, fs_destructive, shell_safe, shell_unsafe, git_destructive, network_send, privileged, browser, computer_use, client_capability, custom_tool, subagent类别名沿用 Claude SDK 术语Pi adapter 必须把 Pi 原生工具名翻译成这些类别后再进入 runtime见 packages/core/src/permission.ts 注释。BUILTIN_TOOL_CATEGORY把常见工具名映射到类别Read/search_files/Grep/Glob→readWebFetch/WebSearch→web_readWrite/Edit/apply_patch/patch→file_writeBash/WriteStdin→shell_unsafe。mode × category 策略矩阵契约层用PolicyDecision allow | prompt | block表示决策三态。虽然当前源码中策略矩阵的实现已迁移到运行时runtime 层根据readExecutionBoundary/readPermissionMode计算而不是 core 里一份静态PERMISSION_POLICY表归档笔记总结的行为模型仍然有效可帮助理解各模式的意图模式读写危险操作网络浏览器exploreallowblockblockweb_readpromptblockaskallowpromptpromptpromptpromptbypassallowallowallowallowallow核心规则依然成立不可逆操作fs_destructive、git_destructive、privileged、browser在任何非 bypass 模式下都强制 prompt——浏览器操作可能发帖/下单视为不可逆。bypass全 allow仅用户显式选择时进入。Shell 命令分类从安全降级到fail-closed这是当前源码相对归档笔记最重要的演化。归档笔记描述categorizeBash()可根据命令前缀动态降级/升级ls/pwd→shell_saferm→fs_destructivegit push --force→git_destructive。当前源码明确移除了shell_safe的产出路径There is no SAFE_SHELL_PREFIXES allowlist: a shell command cannot be proven safe from its string... Eight review rounds of enumerating dangerous shapes proved the futility of the inverse (deciding a Turing-complete shells runtime effect from a static string is undecidable). SocategorizeBashnever returnsshell_safe; read-only needs go through typed tools (Read/Glob/Grep — fixed argv, no shell), and every shell command is at leastshell_unsafe→ prompt.也就是说从静态字符串证明 shell 命令安全是不可判定的echo $(rm x)、PowerShell 的$(...)、反引号、iex都能在参数里藏执行因此不再允许任何 shell 命令自动放行——只读需求走固定 argv 的 typed toolsRead/Glob/Grep其余 shell 命令至少shell_unsafe→ prompt。类别划分仍然保留但作用从安全边界降级为让确认原因REASON更准确delete vs elevate vs generic漏配只是措辞问题而非绕过漏洞。相应的分类器以纯函数 正则表实现packages/core/src/permission.tsPRIVILEGED_SHELL_PREFIXESsudo、su、chmod、chown、mount、kill、systemctl、shutdown、reboot 等与PRIVILEGED_SHELL_PATTERNSPowerShell/cmd 等价物stop-process、-verb runas、service 控制、icacls/takeown等大小写不敏感FS_DESTRUCTIVE_PATTERNSdd、truncate、shred、mkfs、find -delete、rm家族、remove-item/clear-content等锚定在每个语句段的开头commandSegments按|;\n(){}切分而不是整个命令开头PIPE_DESTRUCTIVE_PATTERNS| xargs rm/shred/truncate/dd、| sh/bash/zshDESTRUCTIVE_GIT_PATTERNSgit reset --hard、git push --force/-f、git branch -D、git clean -fd?、git checkout .、git rebase -i。切分策略刻意quote-naive引号感知切分会更糟$( )与反引号在双引号内也会展开所以 naive 切分永不丢内容、只会切碎多出的边界只增加扫描候选不会隐藏危险片段。纯函数原则preToolUse()给定输入必然返回相同结果不生成 UUIDrequestId 由 runtime 层的权限引擎生成便于测试。parked Promise 机制权限引擎为每个 outstanding 权限请求维护一个 parked PromiseUI 的决定通过respondToSandboxBoundary()/respondToUserQuestion()packages/runtime/src/ai-sdk-backend.tsresolve 回等待中的 adapter。turn 结束时未回答的请求会被 reject 成user_stop。如前述endTurn是唯一能 reject 停在askUserQuestion上的工具的地方abort signal 不会唤醒 registry——这保证了 stop 时不会留下永久悬挂的 parked 请求。持久化与恢复文件布局工作数据放 ElectronuserData下的 workspace 目录Electron userData/workspaces/default/ llm-connections.json credentials.json settings.json sessions/sessionId/ messages.jsonl runs/runId/ run.json ← run header原子写 events.jsonl ← append-only run 事件AgentRun ledger存储层在 packages/storage/src/agent-run-store.ts对应测试见 packages/storage/src/tests/atomic-file-write.test.ts。核心保障run.json原子写writeAtomicFile先写临时文件再 rename测试验证写出精确字节且不残留临时文件events.jsonlappend-only同 run 写串行化per sessionIdrunId 的 Promise 链避免并发写竞争ID 校验SAFE_ID_PATTERN防路径穿越读事件时容忍损坏行event_corrupt和未终止尾部。这套 ledger 和用户可见的 session 消息 JSONL 分开诊断 / 恢复状态不污染对话历史。此外还配套了agent-run-inspect.ts/execution-inspect.tscore 层提供 run 审计文档schemaVersion、source health、projection summary、compaction checkpoint 等。启动恢复recoverInterruptedSessions()优先用 run ledger扫描持久化的 run header 和事件分类非终态 runcreated/running/waiting_permission修复后收敛 session / turn 投影。恢复入口的严格版本recoverInterruptedSessionsStrict()在 packages/runtime/src/tests/runtime-ledger-repair.test.ts 中有覆盖对 pending invocation 进行 run ledger 修复断言。覆盖的恢复场景stale 的created/runningrun停在run_started/model_stream_started的 runtool_started后的残留permission_requested后的等待缺终态事件的model_stream_completed损坏事件行。没有 run ledger 的老 session 走旧的 message turn-state 恢复路径。相关回归测试还包括 packages/runtime/src/tests/runtime-continuation-crash.test.ts、packages/runtime/src/tests/sandbox-boundary-restart-recovery.test.ts 与 packages/runtime/src/tests/runtime-handoff.test.ts。Electron 集成层进程边界进程文件职责mainapps/desktop/src/main/main.ts装配SessionManager、注册 IPC、管理窗口、OAuth、bot、gatewaypreloadapps/desktop/src/preload/preload.tscontextBridge暴露window.maka.*白名单 APIrendererapps/desktop/src/renderer/React UI Settingsmain 进程装配runtime new SessionManager({...})并启动 gateway 服务IPC 用ipcMain.handle注册大量通道memory、artifacts、settings、connection、session 等。密钥安全边界Provider/API key、bot token、proxy password、gateway token 等写入本机凭据文件依赖 OS 账号边界和文件权限subscription OAuth token 使用独立的系统安全存储Renderer 永远拿不到明文密钥Settings 只显示 masked 状态和测试结果。多入口除了桌面 UIruntime 还服务两类外部入口Bot adapterpackages/runtime/src/bots/Telegram、飞书、企业微信、微信 iLink、Discord、钉钉、QQ 等统一对接 SessionManagerOpen Gateway本地 HTTP / SSE API用 token 保护让外部读取会话状态 / 事件 / 能力 / 健康摘要。数据流一次对话的完整路径用户在 renderer 输入消息 →window.maka.session.send→ IPC →SessionManager.sendMessage创建AgentRun写run_created到 ledgerappend 用户消息到messages.jsonl从历史 run 的 RuntimeEvent 投影模型上下文AiSdkBackend.send()打开 turn scope → 构建权限包裹的工具 →streamText(stepCountIs(N))→ 后台泵 fullStream每个流 chunk 经ModelAdapter.handleStreamChunk归一化成SessionEvent→ 推 queue → 前台 yield → IPC 流到 renderer模型调用工具 → 权限门控链 → loop-gate → 权限评估三态allow / block / prompt→ 执行、合成错误或等待用户决定assistant 文本落messages.jsonlusage 记 telemetrytrace 写 run ledgerfinalize()收尾写run_completed更新 session header。技术亮点小结ledger projection 模式run 事件是 source of truthsession 状态是投影崩溃可重建——整个恢复能力的根基纯函数策略 runtime 包装权限决策表是纯函数好测试requestId / parking 状态由 runtime 管职责分明权限门控作为工具 execute 的 seam不动 AI SDK 的循环在 execute 回调里插入 allow / block / prompt最小侵入fail-closed 的 shell 分类承认静态判定 shell 安全性不可判定取消shell_safe自动放行只读走 typed tools类别只用于精确确认原因best-effort trace 不影响主路径诊断信息尽力写失败静默对话绝不受拖累同 run 写串行化 原子写文件持久化的并发安全靠 Promise 链和 rename 保证per-turn scope 模型每次 send 绑定独立的 watchdog / ToolRuntime / trace并发 turn 互不串扰stop 与 teardown 顺序有严格保证安全分层模式 × 类别矩阵 命令分类器 凭据文件权限 / subscription token 安全存储 preload 白名单多层防御。延伸阅读本笔记已归档2026-07-13当前 backend 体系的最新指引以仓库根目录 ARCHITECTURE.md 及其架构章节、源码和测试为准。【免费下载链接】makaApache Maka (Incubating) is a high-performance agent workspace that keeps a complete record of everything it did.项目地址: https://gitcode.com/GitHub_Trending/mak/maka创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表