Repository navigation
feat(core): 插件函数跨插件中转(API-35 第一阶段) - #1742
Merged
Merged
Conversation
- 清单新增 requires.pluginFunctions:导出项 {id, version, context},调用声明 {id, version},context 第一阶段只有 workspace
- litheFunctions 协商版本新增 4,开放 lithe/host/functions/providers 与 lithe/host/functions/invoke
- 被调方收到由 Core 写入的 caller.pluginID(仅协议 4 以上)
- 新增 9 个 plugin.function.* 拒绝原因及对应数值错误码
- 旧的 wrongPlugin / recursiveCall 检查保持不变
Add the cross-plugin function relay state machine (function_relay.rs) and wire it into the LSP interface engine. A backend that negotiated litheFunctions 4 can discover providers and invoke an exported function through Core. Core checks declaration, export, enablement, version, context, call chain, depth, per-caller concurrency and byte limits, and propagates cancellation down the chain. Refs #1495
Scripted Python, Go and Rust plugin backends exercise the relay through the engine: the call path with the Core-written caller field, discovery, every refusal, cycles, cancellation down the chain, timeouts, loss of a caller or callee, hot disabling, waiting for a provider the host starts, and provider selection by workspace. The old recursiveCall and wrongPlugin refusals are asserted unchanged.
- schema 新增 requires.pluginFunctions 与 pluginFunctions(exports 为 {id, version, context},calls 为 {id, version})
- 新增导出方、调用方两个有效夹具,以及 12 个无效清单用例
- README 新增“跨插件调用(协议第 4 版)”:私有与导出、发现与调用方法、调用链、caller 字段、错误码
- verify-shared-contracts.sh 校验 invocationCallers 与 relayErrors,并要求新错误码一码一号
- Core 夹具测试覆盖导出排序与 functions 宿主服务授权
Core 负责中转的全部判断,macOS 只做 I/O: - MacPluginBackendSessions 在注册、工作区上下文变化、启用、禁用和包变更后, 把清单里的 pluginFunctions 原样和上下文事实一起交给 Core (lsp.configureFunctionRelay),快照没变就不重复发布。 - 收到 functionProviderStartRequired 时,用普通的插件启动流程启动被调方后端, 失败走既有的激活失败回报,等待上限由 Core 的 30 秒和会话初始化超时共同限定。 - PluginHostServiceDispatch 把 functions 服务列为 Core 直接应答的授权, 不再被 supportedGrants 丢弃。 - hostCapabilities 增加 pluginFunctions,旧宿主仍会拒绝声明它的插件。 - 增加快照发布、被调方启动和 functions 授权的单测。
补充 Rust Core API 文档中的命令表和说明:载荷是插件的 exports/calls 与 工作区上下文快照,返回空对象,并链接到契约 README 的跨插件调用一节。
- 已实现 Note(插件函数契约)新增决策 8:清单导出与调用声明、协议 4 的两个 宿主请求、Core 检查顺序、调用链与取消、信任不传递与 caller 字段、被调方 未运行时的启动请求、热激活、远程工作区,以及被否的方案和后果。 - 提议 Note(插件依赖与导出)只更新已落地的第一阶段,并写明依赖解析、版本 冲突、依赖闭包、资源租约仍未实现,整篇 Note 仍留在提议中。 - 功能矩阵新增 plugin-cross-plugin-function-calls:macOS 部分实现、待原生 验收,Windows 无插件后端宿主、行为不变;plugin-functions 指向新条目。
被调函数返回错误(plugin.function.failed)和没有可用结果 (plugin.function.invalidResult)此前都回退到 -32603,与 Core 内部失败 plugin.host.failed 共用一个数值,调用方只凭数值分不清。改为 -32070 和 -32071,invalidResult 不再并入 failed;契约 README 与 fixture 同步。 同时删除未被使用的 plugin_functions 访问器。
xiaoyumuxi
marked this pull request as ready for review
November 4, 2026 23:47
Lithe Review结论: ⛔ 有阻塞 Findings
Scope Check
Suggestions
SummaryCore 归属和基础设施复用方向合理,但阻塞写入缺少隔离,上下文失效与并发取消也未满足所声明的生命周期保证。现有成功路径测试不能覆盖这些问题。 Verification
|
Lithe 运行验收版本: 对照:共同祖先
未覆盖:
工作副本与运行状态已清理;可复用编译缓存按 12 GiB / 7 天预算保留。 |
This was referenced Nov 5, 2026
# Conflicts: # rust/lithe-core/src/tests/declarative_plugins.rs # shared/contracts/plugins/v1/README.md
# Conflicts: # rust/lithe-core/src/plugins/capabilities.rs # rust/lithe-core/src/tests/declarative_plugins.rs # shared/contracts/plugins/v1/fixtures/manifest/invalid-manifests.json
- #1752 新增的 toolchain_vectors.rs 写死了 9 处工具名,Verify Host Language Specifics 在 preview 上失败 - 工具 ID 改从 fixtures/toolchains/tool-definition.plugin.json 读取,路径里的工具名换成中性的 tool - toolchain_resolution.rs 复用 MANUAL_HOME,计数 90 -> 89,基线只调低这一行
- 每个目标会话一条写入车道,主工作线程只做规划;停止读取 stdin 的后端只拖住发往自己的写入 - 中转写入有截止时间(会话请求超时),超时后 monitor 让该会话失败(transportFailed/relayWrite)并结束进程 - lithe/host/functions/invoke 新增可选 parentOperationID:指定所服务的调用,调用链和取消只沿这一条走; 不在调用方会话里运行的父调用返回 plugin.host.cancelled,格式错误返回 invalidParams - 新快照让调用的工作区上下文关闭或换代时,等待中和运行中的调用都以 plugin.host.contextExpired 结束 - 运行中的调用在截止时间后再给 2 秒宽限,被调方仍不回答则以 plugin.host.timeout 结束并取消被调方 - functionProviderStartRequired 复用已有事件构造函数,新文件不再出现宿主语言词 - Swift 解码失败的 try? 和 Rust 的 let _ = 补 log-exempt 标注 - 契约 README、function-protocol fixture、Note 同步;热激活描述更正 - 新增引擎级测试:阻塞后端不拖住其他调用、父调用限定取消、未知/已结束/格式错误的父调用、上下文关闭或换代
# Conflicts: # shared/contracts/plugins/v1/README.md # shared/contracts/plugins/v1/fixtures/manifest/invalid-manifests.json
xiaoyumuxi
added a commit
that referenced
this pull request
Nov 5, 2026
合入 #1742(插件函数中转)。冲突全部是两边在同一位置各自新增: plugins 模块声明、HOST_METHODS 表(run/debug 与 functions 方法并存)、 错误码表(-32025 与 -32027..-32071 不重叠)、manifest 字段、 provider_query_trigger 与 runtime_tools、capability 列表、契约 fixture。
xiaoyumuxi
added a commit
that referenced
this pull request
Nov 5, 2026
合入 #1742(插件函数中转)。冲突全部是两边在同一位置各自新增: HostParams 与校验函数、错误码表(-32022..-32026 与 -32027..-32071 不重叠)、 SessionState 字段、request 事件分发、契约 README 与 fixture。 provider_query_trigger 合成为 toolchain、keymap、后端启动语言服务器、 导出函数四个条件之一即可。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #1495
API-35 第一阶段:两个已安装、已启用的插件之间,可以经 Rust Core 中转调用对方明确导出的插件函数(插件 1 → Core → 插件 2)。本 PR 不含安装期依赖解析、版本冲突处理、依赖闭包和资源租约。不新增 API 编号。
改动
清单:新增能力键
requires.pluginFunctions: 1和顶层pluginFunctions { exports, calls }。{ id, version, context }。context第一阶段只能是"workspace",缺失或取未知值时整个清单被拒。{ id, version },版本必须与导出方完全相等。lithe/function/register注册。hostCapabilities镜像和verify-shared-contracts.sh一起更新。协议:
litheFunctions增加版本 4。协商到 4 且声明了calls的后端可以使用lithe/host/functions/providers(发现提供方)和lithe/host/functions/invoke(调用)。协议 3 及以下返回plugin.host.unavailable;没声明calls返回plugin.host.permissionDenied。Core 中转(
function_relay.rs、engine_function_relay.rs、plugins/plugin_functions.rs):信任不传递:被调方用自己的权限运行,调用方的 pluginID 不写进被调方的会话身份。Core 在转发的
lithe/function/invoke里写入顶层caller: { pluginID }:只发给协商到协议 4 的被调方;宿主发起的调用没有这个字段;调用方伪造会得到plugin.host.unsupportedOption。契约要求导出函数不得接受调用方传来的可执行路径或命令。没有新增权限项:调用方声明calls、被调方声明exports,就是双方的同意。被调方未运行:Core 只发出
functionProviderStartRequired,由 macOS 作为 I/O 启动它的后端。Core 最多等 30 秒,超时返回plugin.function.providerUnavailable。热激活:宿主用新命令
lsp.configureFunctionRelay向 Core 发布插件与上下文快照。被调方被禁用、卸载,或更新后不再导出时,发现结果立即更新,进行中的调用以明确的错误结束。错误码,每个数值只对应一种错误:
plugin.function.notDeclaredplugin.function.notExportedplugin.function.providerDisabledplugin.function.versionMismatchplugin.function.callCycleplugin.function.depthExceededplugin.function.tooManyCallsplugin.function.payloadTooLargeplugin.function.providerUnavailableplugin.function.failed(被调函数自己返回错误)plugin.function.invalidResult(被调方没有返回 result,或结果超过 1 MiB)-32603仍只表示plugin.host.failed,即 Core 内部失败。-32031..-32064 留给并行中的其他插件 API PR;-32060..-32063 是 Core 命令 API(日志查看器)的码,属于另一个命名空间,不冲突。旧规则不变:后端发
lithe/function/invoke或lithe/build/*仍然得到recursiveCall;引用别的插件的私有函数仍然是wrongPlugin。macOS(只做 I/O):
MacPluginBackendSessions发布快照并响应启动请求;PluginHostServiceDispatch把functions服务列为由 Core 直接应答的授权;hostCapabilities增加pluginFunctions。文档:README 新增 “Cross-plugin calls (protocol version 4)” 一节;
rust-core-api.md补充lsp.configureFunctionRelay;已实现 Note2026-10-20-plugin-function-contract.md增加决策 8;提议 Note2026-10-25-plugin-dependencies-and-exports.md标出第一阶段已落地的部分;功能矩阵新增plugin-cross-plugin-function-calls(Windows 行为不变,不声明pluginFunctions)。宿主方法
lithe/host/functions/providerslithe/host/functions/invokeparentOperationID评审修复(本轮)
Lanes/run_lane)。一个后端不读输入,只会拖慢发给它自己的调用、回复和取消。bounded_relay_write,等于会话的请求超时)。超时后由会话 monitor 让该会话失败(transportFailed,阶段relayWrite)并结束进程,被卡住的写入随之释放,这个会话上的调用按会话失败的规则结束。lithe/host/functions/invoke增加可选的parentOperationID,值是被调方收到的那个调用的operationID。调用链和取消只沿这一条走。plugin.host.cancelled;值不是 1–128 字节的字符串时返回plugin.host.invalidParams。plugin.host.contextExpired结束,运行中的调用同时取消被调方。RUNNING_GRACE),让被调方自己的超时先回答;宽限过后仍没有回答,就以plugin.host.timeout结束并取消被调方。等待被调方启动的那段时间不会把已经开始运行的调用判为超时。let _ =和 Swift 解码清单的try?补了log-exempt标注(Swift 只改了这一行注释)。functionProviderStartRequired事件改为复用已有的push_negotiated_provider_event,这个新文件不再出现工具名,基线没有增加。function-protocol.jsonfixture、Note 决策 8 一起更新。顺带更正了“热激活”的描述:只有新安装或更新后端插件才需要重启,禁用、启用、替换和卸载都是即时生效的。is_running。同步 preview
invalid-manifests.json两边新增的用例也都保留。MacPluginBackendSessionsTests的installFunctionPlugin改为从fixtures/backend/读取plugin-functions-exporter/-caller清单,否则三个跨插件调用的 Swift 测试找不到文件。验证
合入 preview
cf2697c83之后在本地执行:cargo test -p lithe-core:1967 个单元测试和全部集成测试通过。合入之前的一次全量运行中,search_everywhere_pages_all_sources_past_200...超时失败过一次;它和本 PR 无关,单独运行通过,合入之后的全量运行也通过。function_relay/engine_function_relay相关测试连续跑 5 次,结果稳定。scripts/macos/test/test-macos.sh --filter 'MacPluginBackendSessionsTests|PluginHostServiceDispatchTests|PluginPublicHostAPITests|PluginEditorProvider':4 个套件共 51 个测试通过;脚本自带的 bundle 不可变检查和 i18n 检查也通过。node scripts/sdk-e2e.mjs --source <本仓库> --ref review/1742:Node、Java、Rust 三个 SDK 的示例后端共 9 个测试通过。verify-shared-contracts.sh、Rust 注释规范、generate-i18n.mjs --check、verify-app-language-localization.mjs、日志门禁(0 违规)、Agent Note 校验、功能矩阵、测试稳定性规则、verify-no-host-language-specifics.mjs(绝对模式和--base origin/preview都通过,基线没有增加)、git diff --check。已知未完成
root_uri相同的会话,否则取会话 ID 字典序第一个。parentOperationID。不填时行为和以前一样,SDK 的 relay 封装和这个字段在 lithe-plugin-docs 另开 PR 处理。docs/development/macos-plugin-api-plan.md中 API-35 一行还没更新,等 fix(remote): #1507 远程工作区、构建与插件执行适配 #1515 合入后统一改。node scripts/contract.mjs sync --revision <合并后的 preview commit>,并在协议更新记录、API 总表和“宿主方法(按 API 编号)”索引里登记。