Commit 206c104
feat(plugin-sdk): @llm_tool 装饰器 — 插件一行注册 LLM 工具 (#1055)
* feat(plugin-sdk): @llm_tool 装饰器 — 一行注册插件 LLM 工具
PR #1035 把 main_server 的 ToolRegistry 统一了,但插件仍要自己起 HTTP server、
轮询注册、写 callback 路由、shutdown 时清理。这次把这些样板全部下沉到 SDK:
- @llm_tool 装饰器:把方法的 JSON Schema/描述/超时直接挂在方法上,
NekoPluginBase.__init__ 自动扫并注册。也提供 register_llm_tool/
unregister_llm_tool/list_llm_tools 实例方法用于运行时动态注册。
- 路径全程复用既有 IPC:方法注册成 dynamic entry(id=__llm_tool__{name}),
调用走 host.trigger,与 @plugin_entry 的派发管线完全一致。
- 新增 user_plugin_server 端点 /api/llm-tools/callback/{plugin_id}/{tool_name}
接收 main_server 的 dispatch、转发到对应插件进程。callback URL 用实际
绑定端口(NEKO_USER_PLUGIN_SERVER_PORT),避免 48916 被占用时回落失效。
- plugin/server/messaging/llm_tool_registry.py 维护 (plugin_id → tool 名集合)
本地索引;插件 stop 时 lifecycle_service.stop_plugin 调
/api/tools/clear?source=plugin:{plugin_id} 一把清空。
文档 docs/plugins/tool-calling.md 顶部加 TL;DR + SDK Helper Reference;
docs/changelog/plugin-llm-tool-sdk.md 写完整迁移说明。
新增 tests/unit/test_plugin_llm_tool_sdk.py 18 个单测覆盖装饰器、自动注册、
imperative API、URL 构造、callback 路由 4 种返回路径。
纯 additive,PR #1035 的 /api/tools/* 接口无改动;旧路插件继续可用。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(plugin-sdk): 清理 lint —— 删未用 import + 给 inner-except 加注释
github-code-quality bot 在 #1055 上指出的 5 处:
- plugin/sdk/plugin/base.py: 未用的 LLM_TOOL_ENTRY_PREFIX import
- tests/unit/test_plugin_llm_tool_sdk.py: 未用的 asyncio / AsyncMock / patch
- plugin/sdk/plugin/base.py: 两个内层 except Exception: pass 没注释(外层
except 已有完整说明,内层是“连日志都失败了,吞掉”——与本文件
_notify_host_comm 的既有 idiom 一致;按 bot 建议加一行说明对齐 lint)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(plugin-sdk): callback 路由用每个工具自己的 timeout + 修文档契约描述
CodeRabbit 在 #1055 上指出 4 处:
1. plugin/server/routes/llm_tools.py 把工具执行 timeout 硬编码成 30s,但
注册时每个工具的 timeout_seconds 是已知的 —— 一个 90s 的工具会被
plugin 侧提前砍掉,main_server 那边仍在等 HTTP 响应。改:registry 从
set[str] 升级成 dict[str, {"timeout_seconds": float}],新增
get_plugin_tool_timeout(plugin_id, name);callback 路由读这个值传给
host.trigger。
2/3. docs 把 /api/tools/clear 写成了 query string + atomic,实际是
POST JSON body + best-effort(HTTP 出错就吞掉)。两处都改正。
4. 三个 fenced ASCII 架构图缺 language tag,markdownlint MD040 报警,
全部加 ```text。
测试:新增 test_callback_route_falls_back_to_default_timeout_when_unknown
覆盖 desync 兜底;test_callback_route_invokes_host_trigger 加断言验证
timeout=90.0 一路传到 host.trigger。19/19 通过。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(plugin-sdk): register/unregister 检查 main_server 的 ok=false 响应 + 文档收紧
CodeRabbit 在 #1055 上又指出 3 处:
1. register_remote_tool: HTTP 200 但 body.ok=false("no role accepted")
时仍然会写本地 _plugin_tools,导致 has_plugin_tool 误报已注册。改成
先检查 body.ok,false 则 raise 不写本地。
2. unregister_remote_tool: 之前先删本地再发 HTTP,partial failure
(body.failed_roles 非空但 status=200)时本地索引已丢,shutdown 的
clear 兜不到那个 role。改成 HTTP 先发、检查 failed_roles,全成功才
删本地;partial failure 保留本地索引并 raise。
3. docs(changelog 和 tool-calling.md)原本写"自动处理 re-registration
logic",过度承诺;helper 实际只做首轮注册,main_server 重启/启动
竞态后插件需 reload 或 imperative API 自己补。明确加警告 callout。
新测试:
- test_register_remote_tool_skips_local_tracking_on_ok_false
- test_unregister_remote_tool_keeps_local_on_partial_failure
- test_unregister_remote_tool_drops_local_on_full_success
22/22 通过。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(i18n): 同步 zh-CN + ja 版 tool-calling 文档加上 @llm_tool helper 章节
英文版(PR #1055 主体改动)已经加了 TL;DR + SDK Helper Reference 两节,
zh-CN 和 ja 翻译版漏了。补齐:
- TL;DR 推荐路径示例
- 双层架构图(Layer 1 raw HTTP / Layer 2 SDK helper)+ 重启限制 callout
- SDK Helper Reference:装饰器签名、imperative API、错误返回 shape、
生命周期时序、各文件职责表
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Hongzhi Wen <cartabio.coder1@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 5be8d98 commit 206c104
14 files changed
Lines changed: 2432 additions & 3 deletions
File tree
- docs
- changelog
- ja/plugins
- plugins
- zh-CN/plugins
- plugin
- core
- sdk/plugin
- server
- application/plugins
- messaging
- routes
- tests/unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
0 commit comments