cyreneai-plugin-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. cyreneai_plugin_sdk-0.1.0/LICENSE +21 -0
  2. cyreneai_plugin_sdk-0.1.0/MANIFEST.in +34 -0
  3. cyreneai_plugin_sdk-0.1.0/PKG-INFO +340 -0
  4. cyreneai_plugin_sdk-0.1.0/README.md +330 -0
  5. cyreneai_plugin_sdk-0.1.0/pyproject.toml +104 -0
  6. cyreneai_plugin_sdk-0.1.0/setup.cfg +4 -0
  7. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/__init__.py +49 -0
  8. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/_arguments.py +1002 -0
  9. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/_depends.py +139 -0
  10. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/_executors.py +200 -0
  11. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/_replies.py +107 -0
  12. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/_routing.py +815 -0
  13. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/_types.py +43 -0
  14. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/cli.py +242 -0
  15. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/plugin.py +40 -0
  16. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/py.typed +1 -0
  17. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/api/testing.py +899 -0
  18. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/__init__.py +1 -0
  19. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/bot/__init__.py +1 -0
  20. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/bot/bot_protocol.py +90 -0
  21. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/bot/polling_protocol.py +39 -0
  22. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/bot/registry.py +68 -0
  23. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/bot/session_manager.py +124 -0
  24. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/bot/session_protocol.py +45 -0
  25. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/context/__init__.py +1 -0
  26. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/context/builder.py +111 -0
  27. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/context/context_protocol.py +114 -0
  28. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/context/manager.py +45 -0
  29. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/context/policy.py +67 -0
  30. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/__init__.py +3 -0
  31. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/base.py +124 -0
  32. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/bot.py +75 -0
  33. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/chat.py +54 -0
  34. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/context.py +92 -0
  35. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/plugin.py +66 -0
  36. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/provider.py +85 -0
  37. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/skill.py +57 -0
  38. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/tool.py +67 -0
  39. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/errors/vector.py +40 -0
  40. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/plugin/__init__.py +1 -0
  41. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/plugin/manager.py +251 -0
  42. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/plugin/plugin_protocol.py +679 -0
  43. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/plugin/registry.py +289 -0
  44. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/plugin/runtime_capabilities.py +183 -0
  45. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/provider/factory.py +56 -0
  46. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/provider/manager.py +143 -0
  47. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/provider/provider_protocol.py +71 -0
  48. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/provider/registry.py +72 -0
  49. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/py.typed +1 -0
  50. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/__init__.py +1 -0
  51. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/application.py +409 -0
  52. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/base.py +11 -0
  53. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/bot.py +146 -0
  54. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/chat.py +58 -0
  55. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/context.py +144 -0
  56. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/document.py +29 -0
  57. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/embedding.py +42 -0
  58. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/image.py +46 -0
  59. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/message.py +58 -0
  60. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/plugin.py +417 -0
  61. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/provider.py +104 -0
  62. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/server.py +90 -0
  63. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/skill.py +66 -0
  64. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/tool.py +47 -0
  65. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/usage.py +12 -0
  66. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/schema/vector.py +49 -0
  67. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/skill/__init__.py +1 -0
  68. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/skill/manager.py +45 -0
  69. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/skill/policy.py +110 -0
  70. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/skill/registry.py +51 -0
  71. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/skill/selector.py +24 -0
  72. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/skill/skill_protocol.py +73 -0
  73. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/tool/__init__.py +1 -0
  74. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/tool/manager.py +29 -0
  75. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/tool/registry.py +68 -0
  76. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/tool/tool_protocol.py +59 -0
  77. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/tool/validation.py +150 -0
  78. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/vector/__init__.py +1 -0
  79. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/vector/manager.py +49 -0
  80. cyreneai_plugin_sdk-0.1.0/src/cyreneAI/core/vector/vector_protocol.py +39 -0
  81. cyreneai_plugin_sdk-0.1.0/src/cyreneai_plugin_sdk.egg-info/PKG-INFO +340 -0
  82. cyreneai_plugin_sdk-0.1.0/src/cyreneai_plugin_sdk.egg-info/SOURCES.txt +84 -0
  83. cyreneai_plugin_sdk-0.1.0/src/cyreneai_plugin_sdk.egg-info/dependency_links.txt +1 -0
  84. cyreneai_plugin_sdk-0.1.0/src/cyreneai_plugin_sdk.egg-info/entry_points.txt +2 -0
  85. cyreneai_plugin_sdk-0.1.0/src/cyreneai_plugin_sdk.egg-info/requires.txt +1 -0
  86. cyreneai_plugin_sdk-0.1.0/src/cyreneai_plugin_sdk.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CyreneAI contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,34 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ exclude src/cyreneAI/__init__.py
5
+ exclude src/cyreneAI/bootstrap.py
6
+
7
+ graft src/cyreneAI/api
8
+ graft src/cyreneAI/core
9
+
10
+ prune src/cyreneAI/adapters
11
+ prune src/cyreneAI/application
12
+ prune src/cyreneAI/infra
13
+ prune src/cyreneAI/server
14
+ prune src/cyreneAI/tests
15
+ prune examples
16
+ prune data
17
+ prune .github
18
+ prune .claude
19
+ prune .venv
20
+ prune build
21
+ prune dist
22
+
23
+ global-exclude __pycache__
24
+ global-exclude *.py[cod]
25
+ global-exclude *.egg-info
26
+ global-exclude .env
27
+ global-exclude .env.*
28
+ global-exclude Dockerfile
29
+ global-exclude docker-compose.yml
30
+ global-exclude docker-compose.yaml
31
+ global-exclude *.db
32
+ global-exclude *.sqlite
33
+ global-exclude *.sqlite3
34
+ global-exclude *.log
@@ -0,0 +1,340 @@
1
+ Metadata-Version: 2.4
2
+ Name: cyreneai-plugin-sdk
3
+ Version: 0.1.0
4
+ Summary: Plugin author SDK for CyreneAI.
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: pydantic
9
+ Dynamic: license-file
10
+
11
+ # CyreneBot
12
+
13
+ CyreneBot 是一个分层的 AI bot framework,用于组织 channel、provider、context、skill、tool、embedding、vector store 与 RAG 编排。
14
+
15
+ 当前代码包名仍保留为 `cyreneAI`,用于保护已有导入路径;对外项目定位和后续内核演进以 CyreneBot 为准。
16
+
17
+ ## 当前能力
18
+
19
+ ```text
20
+ provider lifecycle
21
+ chat orchestration
22
+ embedding orchestration
23
+ document indexing
24
+ retrieval orchestration
25
+ RAG chat orchestration
26
+ memory / SQLite vector store
27
+ context snapshot persistence
28
+ skill and tool orchestration
29
+ OpenAI-compatible / OpenAI Responses / Anthropic / Google GenAI adapters
30
+ ```
31
+
32
+ ## 架构边界
33
+
34
+ CyreneBot 的核心约束是让变化只发生在合适的层:
35
+
36
+ ```text
37
+ core
38
+ 定义 schema、protocol、manager、registry、通用错误和规则。
39
+ 不 import provider SDK,不读取环境变量,不创建外部 client。
40
+
41
+ infra/provider_catalog
42
+ 只声明 provider info。
43
+
44
+ infra/adapters
45
+ 实现外部系统适配,例如 provider SDK、tool executor、skill loader、vector store。
46
+
47
+ adapters
48
+ 公共适配层,提供面向使用方的轻量 adapter 和稳定导出。
49
+
50
+ infra/bootstrap
51
+ 装配 provider info、adapter builder、registry、factory。
52
+
53
+ application
54
+ 编排业务流程,例如 chat、embedding、indexing、retrieval、RAG chat 和 runtime bootstrap。
55
+ ```
56
+
57
+ 这让新增业务策略时通常只需要改 application 层;只有接入新的外部系统时才进入 infra/adapters。
58
+
59
+ 应用使用方优先从 `cyreneAI.adapters` 导入公共适配器:
60
+
61
+ ```python
62
+ from cyreneAI.adapters.documents import FileSystemDocumentLoader
63
+ from cyreneAI.adapters.vector_stores import create_memory_vector_store
64
+ ```
65
+
66
+ `cyreneAI.infra.adapters` 是重型外部系统实现落点,适合 provider SDK、外部 tool executor、持久化 vector store 等实现,不建议作为业务代码的长期依赖路径。
67
+
68
+ ## RAG 主路径
69
+
70
+ 当前 RAG 流程由 application 层组合完成:
71
+
72
+ ```text
73
+ build runtime
74
+ -> configure provider
75
+ -> index documents
76
+ -> embed chunks
77
+ -> upsert vectors
78
+ -> embed query
79
+ -> vector search
80
+ -> inject retrieved context
81
+ -> chat provider
82
+ -> close runtime
83
+ ```
84
+
85
+ 索引支持两种切块策略:
86
+
87
+ ```python
88
+ from cyreneAI.application.indexing_orchestrator import ChunkStrategy
89
+
90
+ chunk_strategy=ChunkStrategy.CHARACTER
91
+ chunk_strategy=ChunkStrategy.PARAGRAPH
92
+ ```
93
+
94
+ RAG 支持 collection 隔离:
95
+
96
+ ```python
97
+ collection_id="project-docs"
98
+ ```
99
+
100
+ 索引时会写入 vector metadata;检索和 RAG chat 时会自动追加 vector filter,避免不同知识库混搜。
101
+
102
+ RAG context 注入支持多种格式:
103
+
104
+ ```python
105
+ from cyreneAI.application.rag_chat_orchestrator import RAGContextFormat
106
+
107
+ retrieval_context_format=RAGContextFormat.PLAIN
108
+ retrieval_context_format=RAGContextFormat.NUMBERED
109
+ retrieval_context_format=RAGContextFormat.SOURCE_TAGGED
110
+ retrieval_context_format=RAGContextFormat.COMPACT
111
+ ```
112
+
113
+ 可以限制每条检索内容长度,也可以把来源元数据注入 prompt:
114
+
115
+ ```python
116
+ max_retrieved_content_chars=1200
117
+ include_retrieval_metadata=True
118
+ ```
119
+
120
+ ## 最小内存 RAG 用例
121
+
122
+ 下面示例演示完整流程:
123
+
124
+ ```text
125
+ build runtime -> 配置 provider -> index documents -> RAG chat -> close runtime
126
+ ```
127
+
128
+ 需要环境变量:
129
+
130
+ ```bash
131
+ export OPENAI_COMPATIBLE_API_KEY="..."
132
+ export OPENAI_COMPATIBLE_BASE_URL="https://..."
133
+ export OPENAI_COMPATIBLE_MODEL="..."
134
+ export OPENAI_COMPATIBLE_EMBEDDING_MODEL="..."
135
+ ```
136
+
137
+ `OPENAI_COMPATIBLE_BASE_URL` 可选;如果使用默认 OpenAI endpoint,可以改用 `OPENAI_API_KEY`、`OPENAI_MODEL`、`OPENAI_EMBEDDING_MODEL`。
138
+
139
+ ```python
140
+ from __future__ import annotations
141
+
142
+ import asyncio
143
+ import os
144
+ from datetime import timedelta
145
+
146
+ from cyreneAI.application.bootstrap import build_cyrene_ai_runtime
147
+ from cyreneAI.application.indexing_orchestrator import (
148
+ ApplicationIndexingRequest,
149
+ ChunkStrategy,
150
+ IndexingOrchestrator,
151
+ )
152
+ from cyreneAI.application.rag_chat_orchestrator import (
153
+ ApplicationRAGChatRequest,
154
+ RAGContextFormat,
155
+ RAGChatOrchestrator,
156
+ )
157
+ from cyreneAI.adapters.documents import FileSystemDocumentLoader
158
+ from cyreneAI.adapters.vector_stores import create_memory_vector_store
159
+ from cyreneAI.core.schema.message import (
160
+ ContentPart,
161
+ ContentPartType,
162
+ Message,
163
+ MessageRole,
164
+ )
165
+ from cyreneAI.core.schema.provider import ProviderConfig, ProviderType
166
+
167
+
168
+ async def main() -> None:
169
+ api_key = os.getenv("OPENAI_COMPATIBLE_API_KEY") or os.environ["OPENAI_API_KEY"]
170
+ base_url = os.getenv("OPENAI_COMPATIBLE_BASE_URL") or os.getenv("OPENAI_BASE_URL")
171
+ chat_model = os.getenv("OPENAI_COMPATIBLE_MODEL") or os.environ["OPENAI_MODEL"]
172
+ embedding_model = os.getenv("OPENAI_COMPATIBLE_EMBEDDING_MODEL") or os.environ[
173
+ "OPENAI_EMBEDDING_MODEL"
174
+ ]
175
+
176
+ runtime = await build_cyrene_ai_runtime(
177
+ provider_configs=[
178
+ ProviderConfig(
179
+ provider_id="openai-compatible",
180
+ provider_type=ProviderType.OPENAI_COMPATIBLE,
181
+ api_key=api_key,
182
+ base_url=base_url,
183
+ timeout=timedelta(seconds=30),
184
+ )
185
+ ],
186
+ vector_store=create_memory_vector_store(),
187
+ )
188
+
189
+ try:
190
+ documents = FileSystemDocumentLoader("docs").load()
191
+ await IndexingOrchestrator(runtime).index(
192
+ ApplicationIndexingRequest(
193
+ provider_id="openai-compatible",
194
+ model=embedding_model,
195
+ documents=documents,
196
+ chunk_size=500,
197
+ chunk_strategy=ChunkStrategy.PARAGRAPH,
198
+ collection_id="docs",
199
+ metadata={"purpose": "readme-rag"},
200
+ )
201
+ )
202
+
203
+ result = await RAGChatOrchestrator(runtime).chat(
204
+ ApplicationRAGChatRequest(
205
+ session_id="readme-session",
206
+ provider_id="openai-compatible",
207
+ model=chat_model,
208
+ retrieval_provider_id="openai-compatible",
209
+ retrieval_model=embedding_model,
210
+ messages=[
211
+ Message(
212
+ role=MessageRole.USER,
213
+ content=[
214
+ ContentPart(
215
+ type=ContentPartType.TEXT,
216
+ text="Where should provider SDK calls live?",
217
+ )
218
+ ],
219
+ )
220
+ ],
221
+ retrieval_top_k=3,
222
+ collection_id="docs",
223
+ retrieval_context_format=RAGContextFormat.SOURCE_TAGGED,
224
+ include_retrieval_metadata=True,
225
+ temperature=0,
226
+ max_tokens=128,
227
+ )
228
+ )
229
+
230
+ message = result.chat_result.response.message
231
+ if message is not None and message.content:
232
+ print(message.content[0].text)
233
+ finally:
234
+ await runtime.close()
235
+
236
+
237
+ asyncio.run(main())
238
+ ```
239
+
240
+ 运行示例前,把要索引的 `.md` 或 `.txt` 文件放到 `docs/` 目录。
241
+
242
+ ## 从文件加载文档
243
+
244
+ `cyreneAI.adapters.documents` 提供文件系统文档加载器,适合把本地 `.md` / `.txt` 文件转换为索引用的 `Document`:
245
+
246
+ ```python
247
+ from cyreneAI.adapters.documents import FileSystemDocumentLoader
248
+
249
+ documents = FileSystemDocumentLoader("docs").load()
250
+ ```
251
+
252
+ 默认递归读取 `.md` 和 `.txt`,每个文档 metadata 会包含:
253
+
254
+ ```text
255
+ source
256
+ path
257
+ relative_path
258
+ filename
259
+ extension
260
+ ```
261
+
262
+ 也可以从 JSON / JSONL / CSV 加载结构化文本:
263
+
264
+ ```python
265
+ from cyreneAI.adapters.documents import CsvDocumentLoader, JsonDocumentLoader
266
+
267
+ json_documents = JsonDocumentLoader(
268
+ "data/articles.jsonl",
269
+ content_field="text",
270
+ id_field="id",
271
+ metadata_fields=["title", "url"],
272
+ ).load()
273
+
274
+ csv_documents = CsvDocumentLoader(
275
+ "data/articles.csv",
276
+ content_field="text",
277
+ id_field="id",
278
+ metadata_fields=["title", "url"],
279
+ ).load()
280
+ ```
281
+
282
+ ## SQLite 持久化 RAG
283
+
284
+ 如果需要让索引后的向量跨进程保留,使用 `vector_database_path` 让 runtime 自动创建 SQLite 向量存储:
285
+
286
+ ```python
287
+ runtime = await build_cyrene_ai_runtime(
288
+ provider_configs=[
289
+ ProviderConfig(
290
+ provider_id="openai-compatible",
291
+ provider_type=ProviderType.OPENAI_COMPATIBLE,
292
+ api_key=api_key,
293
+ base_url=base_url,
294
+ timeout=timedelta(seconds=30),
295
+ )
296
+ ],
297
+ vector_database_path="data/vectors.db",
298
+ )
299
+ ```
300
+
301
+ 其余索引和 RAG chat 流程与内存示例一致。关闭 runtime 时使用:
302
+
303
+ ```python
304
+ await runtime.close()
305
+ ```
306
+
307
+ ## 定义 Python 工具
308
+
309
+ `cyreneAI.adapters.tools` 提供轻量工具 helper,只负责创建 `ToolDefinition` 和 executor;注册仍由 runtime 的 tool registry 完成:
310
+
311
+ ```python
312
+ from cyreneAI.adapters.tools import define_python_tool
313
+
314
+
315
+ def lookup_order(args: dict) -> dict:
316
+ return {"order_id": args["order_id"], "status": "shipped"}
317
+
318
+
319
+ definition, executor = define_python_tool(
320
+ name="lookup_order",
321
+ description="Lookup order status.",
322
+ function=lookup_order,
323
+ parameters_schema={
324
+ "type": "object",
325
+ "properties": {
326
+ "order_id": {"type": "string"},
327
+ },
328
+ "required": ["order_id"],
329
+ },
330
+ )
331
+
332
+ runtime.tool_registry.register(definition, executor)
333
+ ```
334
+
335
+ ## 验证
336
+
337
+ ```bash
338
+ uv run python -m compileall src
339
+ uv run pytest src/cyreneAI/tests
340
+ ```