news 2026/9/12 14:57:51

Reasonix 扩展开发实战:Extension Protocol v2 代码运行时插件完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Reasonix 扩展开发实战:Extension Protocol v2 代码运行时插件完整指南

Reasonix 扩展开发实战:Extension Protocol v2 代码运行时插件完整指南

【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix

Reasonix 通过扩展(Extensions)机制允许插件包在运行时改变 Agent 的行为——重写输入、拦截工具调用、替换系统提示词、贡献流式模型 Provider、发布结构化 UI,以及随包发布提示词模板和主题。本文以 docs/EXTENSIONS.md 为主线,结合 Extension Protocol v2 线协议文档、插件包文档 与 Go SDK 示例,完整讲解扩展的安装管理、能力模型、运行时重载、缓存性能、开发流程与安全边界,读完即可从零开发、安装并验证一个自己的 Reasonix 代码扩展。

两类插件能力:声明式与代码运行时

Reasonix 的扩展机制区分两种能力形态:

  • 声明式能力(任何插件包都可以有):skills、agents、commands、prompts、hooks、MCP servers、themes。它们本质是文件与配置,以宿主(host)的正常权限运行,不引入独立进程。
  • 代码运行时(Manifest v2runtime块):一个以 sidecar 子进程形态存在、通过 Extension Protocol 与宿主对话的代码扩展。代码扩展是**完全信任(full trust)**的——安装前务必阅读下文安全模型一节。

正是这一"声明式 + 代码运行时"的双层设计,让 Reasonix 在不链接进宿主二进制的前提下,获得"改写运行时行为"的能力。

安装与管理

扩展与普通插件包的安装方式完全一致,走reasonix plugin命令族:

reasonix plugin install git:github.com/owner/extension --dry-run # 预览,不写文件 reasonix plugin install git:github.com/owner/extension --yes # 正式安装 reasonix plugin show <name> # 查看详情 reasonix plugin doctor <name> # 校验有效性

install接受三类来源:GitHub 仓库(如git:github.com/owner/repo或完整 HTTPS URL)、GitHub 分支/子目录 URL、以及包含reasonix-plugin.json(或 Codex/Claude 兼容清单)的本地目录。本地开发推荐--link模式以目录链接代替复制:

reasonix plugin install /path/to/plugin --link --replace --yes

关键标志:--dry-run只做计划与校验;--yes是任何写盘安装的必要条件;--replace允许替换同名插件;--name覆盖清单中的插件名;--link链接本地目录而非复制(移动或删除该目录会破坏链接)。

对于带runtime块的插件,--dry-run预览与show输出都会包含一个醒目的FULL TRUST块:列出运行时命令、它拦截的事件、拥有的替换槽(replacement slots),以及 Provider/UI 能力。安装、更新、替换或--link本身就是授权动作——没有第二次确认,且--link会持续信任后续被修改的内容。因此只应安装你完全信任的运行时。

已安装状态持久化在~/.reasonix/plugin-packages.json~/.reasonix/plugins/<name>/(详见 插件包文档)。禁用/启用不卸载:reasonix plugin disable <name>/reasonix plugin enable <name>

扩展能做什么

拦截器(Interceptors):17 个冻结的钩子点

扩展可以观测并对 17 个钩子点做出裁决(输入、工具调用、权限决策、Provider 请求/响应、压缩(compaction)、会话生命周期、前端事件)。每次拦截调用的裁决有四种:

  • continue:放行载荷;
  • block:以用户可见的原因中止操作;
  • replace:替换载荷——宿主会对每个替换结果按该钩子点的 DTO 与 schema重新校验
  • allow/deny:仅在permission.decision钩子点合法;来自完全信任扩展的allow会覆盖宿主自身的拒绝,并被审计。

拦截器按确定性顺序串行执行:清单priority升序(范围 -1000..1000,默认 0)→ 插件 ID → 注册顺序。超时方面:input/tool/permission 系列默认 5 秒;session/context/compaction/system-prompt 系列默认 30 秒;清单可按运行时调高,上限 60 秒。仅观测的扩展超时只警告一次并跳过;必需扩展与替换槽属主超时则直接导致操作失败。

替换策略槽(Replacement Strategies):单属主槽位

以下槽位在整个已安装插件集合中只有一个属主system_promptcontextprovider_requestprovider_responsecompactionsession_policypermissionfrontend_eventstool:<name>provider:<ref>。拦截器链先运行,槽属主拥有最终决定权;属主超时或报错必然使操作失败。如果两个插件声明了同一槽位,运行时构建会失败并同时点出两个来源——冲突在构建期暴露,而不是在运行期静默覆盖。

流式 Provider:plugin/<plugin>/<provider>/<model>命名空间

providers能力的扩展通过extension/provider/catalog声明与宿主 Provider 等价的描述符(模型、上下文窗口、定价、视觉、推理、effort——但绝不涉及凭据)。新模型在模型选择器中以plugin/<plugin>/<provider>/<model>形式出现,并采用与内置 Provider 相同的 text/reasoning/tool-call/usage 流语义。该 ref 在一切内置 ref 可用的地方都可用:default_model--model、CLI/Desktop/ACP 选择器、会话中途切模型——包括首次启动

结构化 UI

ui能力的扩展可发布statuscardformnotification载荷(host/ui/publish),并通过host/ui/request向用户提问(confirm、input、select、multiselect)。表面是纯结构化的:没有 HTML/CSS/JS、远程脚本、任意前端组件或不受控 URL,Markdown 走各前端已有的安全渲染器。每次表面更新都携带插件 ID、表面 ID、会话 ID 与运行时代数(generation);过期代数(stale-generation)的更新会被丢弃,因此标签切换或重载后的迟到结果永远无法覆盖当前状态。初始化时声明的动作被命名为/<plugin>:<action>,通过extension/ui/action调用,表单提交走extension/ui/submit;这些动作会出现在斜杠菜单、Desktop 命令面板与 ACP 的可发现命令中。

Prompts 与主题

/<plugin>:<name>提示词模板(与 commands 相同语义、支持参数替换,commands是兼容别名),以及 Desktop Settings 中只读的插件主题plugin:<plugin>:<theme>.reasonix-theme文件,从不复制进用户主题库;插件被禁用/卸载时桌面回退到基础样式但保留 ID,重装同款插件即可恢复主题)。

运行时重载(Runtime Reload):一次失败原子的快照切换

修改已安装扩展(安装、更新、启用/禁用、或--link内容变化)绝不会改变正在运行的 turn。重载在所有交互前端都是一次失败原子的操作,入口包括:CLI/reload、Desktop/reload(composer 斜杠菜单)或命令面板的Reload Runtime、Serve/reload,以及 ACP 供应商方法_reasonix.io/session/reloadExtensions。流程共五步:

  1. 若正在运行 turn 或后台任务,CLI/Desktop/ACP 会只排队一次重载;Serve 则直接拒绝请求,由浏览器在空闲后重试。
  2. 空闲后,Reasonix 启动新的 sidecar 并构建新的运行时快照。
  3. 全部成功后原子切换,并携带会话路径、transcript、审批授权、目标/恢复状态。
  4. 若新构建失败,旧运行时原样继续工作。
  5. 只有切换完成后,旧的 sidecar 才被退役。

每个 turn 在整个 turn、工具批次与压缩期间固定(pin)一个运行时代数——扩展变更应用到下一个turn;无操作重载(no-op reload)会让 Provider 的提示词缓存前缀保持逐字节一致。

性能与提示词缓存(Prompt Cache)

  • 零运行时路径:未安装任何代码运行时,Agent 走既有的 nil-dispatcher 路径,不涉及 sidecar 进程、JSON 编码、RPC 或事件队列。
  • 启动预算:安装运行时后,Reasonix 在一个共享的 30 秒启动预算内至多并行初始化 4 个 sidecar。因此某个卡住的非必需运行时不会让启动/重载时间按已装插件数量翻倍。未在预算内启动的包,按其runtime.required设置降级或失败。
  • 热路径取舍:启用的同步拦截器刻意位于对应热路径上且串行执行,其 RPC 与 handler 延迟是累加的——input、tool、permission、provider 拦截器应保持短小且确定性。观测事件走有界非阻塞队列,背压时丢弃并告警,而不是拖住 turn。
  • 缓存前缀影响:仅观测的扩展不改变 Provider 可见的缓存前缀;稳定的 system-prompt 或 tool 替换会在安装/重载后制造一次有意的冷前缀,此后保持可缓存。若在系统提示词、工具 schema、上下文前缀或 Provider 请求中注入时间戳、随机值、会话 ID 等逐 turn 数据,会摧毁缓存复用——动态数据应尽量留在当前 turn 的尾部(turn tail)。
  • 宿主开销度量(仓库自带基准):
go test ./internal/extension/... -run '^$' -bench 'Extension|Dispatch' -benchmem

对应的基准与分发实现位于 internal/extension/dispatch 与 internal/extension 目录 下的 benchmark 测试中。

开发一个扩展

官方建议从完整的starterextension示例包开始:它在同一目录里包含了 Manifest、Sidecar 源码、跨平台构建命令、链接安装方式与首个可观测拦截。典型开发循环四步:

  1. reasonix-plugin.json中加入apiVersion: "reasonix.io/plugin/v2",声明contributes与(可选的)runtime,详见 插件包文档的 Manifest v2 一节。
  2. 实现 Sidecar。Go SDK(纯标准库、零依赖)处理传输、握手、时序、内容引用与关停;语言无关的参考是 线协议文档 与 生成的方法索引。
  3. 构建运行时二进制,用reasonix plugin install /path/to/plugin --dry-run预览其信任与能力,再以--link --yes安装。
  4. reasonix plugin doctor <name>校验,空闲时执行/reload,然后实际触发贡献的拦截、Provider、UI 动作或资源。

SDK 发布使用不可变标签sdk/go/vX.Y.Z,首个公开版本为sdk/go/v1.0.0;在该标签存在之前,请基于源码检出使用 starter,而不是依赖无版本号的模块。

最小可运行示例:starterextension

示例清单 sdk/go/examples/starterextension/reasonix-plugin.json:

{ "apiVersion": "reasonix.io/plugin/v2", "name": "starter-extension", "version": "0.1.0", "description": "Minimal Reasonix Extension Protocol sidecar", "provides": [ { "namespace": "plugin/starter-extension", "kind": "interceptors", "id": "default", "version": "1.0.0" } ], "contributes": {}, "runtime": { "command": "${REASONIX_PLUGIN_ROOT}/bin/starter-extension.exe", "args": [], "env": {}, "required": false, "priority": 0, "intercepts": ["input.receive"], "replaces": [], "capabilities": ["interceptors"] } }

注意.exe后缀是刻意为之:固定运行时路径使同一份清单在所有平台一致(Unix 直接执行,Windows 需要可执行后缀)。${REASONIX_PLUGIN_ROOT}在启动时展开为已安装插件根目录。

Sidecar 本体 sdk/go/examples/starterextension/main.go 展示 SDK 的核心用法——实现Initialize声明订阅,注册拦截器,用extension.Continue()/extension.Replace(...)返回裁决:

func (starter) Initialize(context.Context, extension.InitializeParams) (*extension.InitializeResult, error) { return &extension.InitializeResult{ Subscriptions: []string{"input.receive"}, }, nil } func interceptInput(_ context.Context, _ string, payload json.RawMessage) (*extension.InterceptResult, error) { var input struct { Text string `json:"text"` } if err := json.Unmarshal(payload, &input); err != nil || !strings.HasPrefix(input.Text, inputPrefix) { return extension.Continue(), nil } return extension.Replace(map[string]string{ "text": strings.TrimPrefix(input.Text, inputPrefix) + " [rewritten by starter-extension]", }) } func main() { err := extension.Serve(context.Background(), starter{}, extension.Options{ Name: "starter-extension", Version: "0.1.0", Interceptors: map[string]extension.InterceptorFunc{ "input.receive": interceptInput, }, }) if err != nil { os.Exit(1) } }

构建并安装(macOS/Linux):

go build -o bin/starter-extension.exe . plugin_root="$(pwd -P)" reasonix plugin install "$plugin_root" --dry-run reasonix plugin install "$plugin_root" --link --replace --yes

先审阅 dry-run 输出中的FULL TRUST块再安装。然后新开会话(或在空闲会话中/reload),发送starter: explain what an Extension Protocol sidecar does——模型收到的将是重写后的文本(追加了[rewritten by starter-extension])。改main.go、重编、/reload,即可迭代。

更完整的参考实现是fullsidecar:输入重写、工具拦截(block + 参数重写)、system-prompt 策略替换、一个伪流式 Provider(文本块、工具调用、usage)、结构化 UI(会话启动时 status + card,demo动作背后的表单提示),以及有界的干净关停——全部在一个纯标准库小程序中。其清单 sdk/go/examples/fullsidecar/reasonix-plugin.json 同时声明了interceptorsstrategiesprovidersui四种能力与system_prompt替换槽,可直接对照研究。该目录会被 internal/extension/conformance 以真实宿主端到端驱动。

SDK 的并发契约值得留意:Initialize先于一切回调且只运行一次;之后 SDK 可并发执行至多 32 个入站回调(拦截器、观测者、资源通知、Provider Catalog/Stream、UI 回调可重叠,多个 Provider 流可同时活跃),回调输入按调用本地对待,共享可变状态需自行加锁;SDK 自行串行化协议写入,扩展不得直接写 stdout,stderr 留给诊断。

Manifest v2 解析规则要点

v2 清单是严格的:必须声明精确的reasonix.io/plugin/v2(v1 与缺失版本被拒绝,无 v1 双读或自动迁移);任何未知字段——根级或contributes/runtime嵌套级——都是指明字段路径的报错;requires/provides声明依赖约束与能力上限,Sidecar 握手时按此校验,任何超出清单的声明都会以capability_not_declared失败。runtime块中command/args/env只支持exec form(命令不会被 shell 解释),intercepts/replaces/capabilities分别声明事件订阅、可拥有的替换槽与能力族(interceptorsstrategiesprovidersui)。所有相对路径与 glob 必须留在插件根内:路径穿越、绝对路径、符号链接逃逸与非规则的 theme 文件都会被拒绝。完整字段语义见 插件包文档。

线协议:Extension Protocol v2 的关键契约

协议 ID 为reasonix.extension.v2,机器可读 schema 位于 internal/extension/protocol/schema.generated.json,方法/事件/限制/错误索引见 生成索引文档(由 cmd/extension-protocol-gen 生成,CI 校验漂移)。

  • 传输:严格的 JSON-RPC 2.0 overNDJSON(stdin/stdout 每行一个完整 JSON 对象);stderr 归扩展用于诊断,宿主只捕获有界、凭据脱敏的尾部用于报错。帧在双向上限8 MiB,超限为连接致命错误frame_too_large。请求 ID 为整数,params必须是对象;帧层面容忍未知成员,但 DTO 解码是严格的(未知字段被拒绝),拼写错误会立刻暴露。
  • 生命周期:宿主以 exec form 拉起 sidecar,先发extension/initialize(参数携带宿主将接受的清单预期;一代运行时的 4 个 sidecar 在共享 30 秒预算内并行初始化)→ sidecar 回声明,宿主校验(精确协议主版本、所有订阅/替换槽/Provider/UI 动作必须是清单子集)→ 宿主发extension/initialized此前任何扩展→宿主流量都会毒化连接。关停有界:extension/shutdown带超时 → 关 stdin → 仍未退出则杀进程树。崩溃语义:sidecar 死亡会取消其全部挂起 RPC;若它正持有当前选中 Provider 或某个替换槽,当前操作显式失败——宿主从不静默回退到其他模型或策略;崩溃的 sidecar 只能由空闲时的运行时重载重启。
  • 内容引用:可外部化的载荷字段超过64 KiB时被卸载进宿主内容存储——帧只带ExternalizedField描述符(JSON 指针、内容 ref、字节数、SHA-256)与null占位;对端以256 KiB分块用host/content/read回读,校验字节数与哈希;单个内容对象上限8 MiB;未知或过期 ref 报content_ref_expired
  • 流式 Providerextension/provider/stream/openstream/chunkstream/end;块携带从 1 开始的连续序号,stream/end.lastSeq冻结终止边界;宿主缓冲乱序块、丢弃重复块,缺口持续存在则以缺失序号判定流为provider_interrupted。块类型含textreasoning(带signature)、tool_call_starttool_call_args_deltatool_callusage(含缓存 token)、doneerror。取消流上下文发送stream/cancel。扩展读取自己的环境与凭据——宿主从不转发其他 Provider 的 API key 或 header。
  • 错误:领域错误走 JSON-RPC 错误码-32000并带结构化数据(reason、retryable、action);protocol_errorunknown_methodinvalid_paramsinternal使用标准 JSON-RPC 码。冻结的 reason 表(capability_not_declaredcontent_ref_expiredframe_too_largeintercept_timeoutprovider_failedstale_generationstream_gap等)在 生成索引 中可查。
  • 稳定性契约:主版本 2 之内只允许三类演进——新增可选字段、新枚举值、新方法;既有必需字段、方向、限制、错误 reason 与语义永不改变。规范 schema 及其 SHA-256 由cmd/extension-protocol-gen产出,CI 的go test ./...通过确定性生成测试(TestGeneratedArtifactsAreDeterministicAndCommitted)强制约束,任何漂移——包括无意的语义变更——都会让构建失败。

兼容性

  • 原生reasonix-plugin.json清单必须声明精确的reasonix.io/plugin/v2API 版本;没有 v1 双读或自动迁移(v1 上从未公开发布扩展清单)。次要别名(v2.0v2.1…)与未知主版本同样被拒绝。
  • 旧版 Reasonix 会忽略扩展专属状态:每会话的<session>.extensions.jsonsidecar 文件、plugin/...模型 ref(直接解析为不可用模型)、extension_surface/extension_status事件种类(旧前端丢弃未知种类;无reasonix.extensionSurface的 ACP 客户端获得文本回退)。
  • plugin-packages.json保持既有 schema;一个已启用、已安装的运行时本身就是信任记录

安全模型:完全信任的边界与宿主约束

代码扩展在 Reasonix 沙箱之外、以未过滤的继承环境运行:它可以读取完整会话与环境、绕过权限与工作区限制、直接操作机器;其permission.decisionallow会覆盖宿主拒绝。作为回报,宿主强制以下约束:

  • 只有通过插件流(plugin flow)安装的插件才能启动运行时——项目配置永远不能声明运行时(这与"链接安装即授权"共同构成信任链);
  • 握手拒绝任何超出清单的能力声明;
  • 每次替换都针对该点的 DTO 与 schema 重新校验;
  • sidecar 诊断、结构化 UI、拦截器 reason 与 Provider 错误在到达 UI、日志或错误面之前,都经过宿主的凭据脱敏(credential redaction)通道;普通 Provider/模型内容按产品数据原样保留;
  • 崩溃的 sidecar 让自身操作显式失败——Reasonix 从不静默回退到另一模型或策略。

因此使用守则很简单:安装前审阅--dry-runplugin show输出的FULL TRUST块(运行时命令、拦截事件、替换槽、Provider/UI 能力一览);只安装完全信任的运行时;--link会持续信任目录内后续的改动。

参考资源

  • 扩展总览:重载、性能、缓存行为、兼容性与信任
  • 线协议参考:传输、生命周期、内容引用、拦截、Provider、UI、错误、稳定性契约
  • 生成的方法索引:17 个钩子点、全部方法方向、限制与错误表
  • 插件包文档:Manifest v2 每个字段、CLI/Desktop 安装管理、Codex/Claude 兼容映射
  • Go SDK 文档:SDK 回调与并发契约、最小示例
  • starterextension 示例:首个可安装扩展
  • fullsidecar 参考实现:Provider、UI、策略、内容引用的完整演示
  • 宿主侧实现:internal/extension(sidecar 管理、dispatch、协议、uihub、conformance 等)

【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 14:57:48

NodeXL社会网络分析工具入门与实践指南

1. NodeXL社会网络分析基础概述 NodeXL是一款功能强大的社会网络分析工具&#xff0c;它基于Excel平台开发&#xff0c;为用户提供了直观易用的网络数据分析和可视化界面。作为社会网络分析&#xff08;SNA&#xff09;领域的入门工具&#xff0c;NodeXL特别适合那些需要快速上…

作者头像 李华
网站建设 2026/9/12 14:57:27

雅思写作Simon小作文高分技巧与结构解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:56:49

Neo4j图数据库入门与实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:53:04

DeepSeek V4.1 Flash内测攻略:API接入、Codex集成与thinking mode避坑实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 14:52:53

Spring Boot批量操作性能优化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华