diff --git a/website/docs/developer-guide/tools-runtime.md b/website/docs/developer-guide/tools-runtime.md index effd5f9b99938..7fcbb4d7cd0a8 100644 --- a/website/docs/developer-guide/tools-runtime.md +++ b/website/docs/developer-guide/tools-runtime.md @@ -30,18 +30,20 @@ Every tool file in `tools/` calls `registry.register()` at module level to decla registry.register( name="terminal", # Unique tool name (used in API schemas) toolset="terminal", # Toolset this tool belongs to - schema={...}, # OpenAI function-calling schema (description, parameters) + schema={...}, # Model-facing schema (description, parameters) handler=handle_terminal, # The function that executes when the tool is called check_fn=check_terminal, # Optional: returns True/False for availability requires_env=["SOME_VAR"], # Optional: env vars needed (for UI display) is_async=False, # Whether the handler is an async coroutine - description="Run commands", # Human-readable description + description="Run commands", # Optional ToolEntry registry metadata emoji="💻", # Emoji for spinner/progress display ) ``` Each call creates a `ToolEntry` stored in the singleton `ToolRegistry._tools` dict keyed by tool name. A registration that would shadow an existing tool from a **different** toolset is rejected (with an error log) unless the caller passes `override=True`; plugin overrides of built-in tools additionally require the operator opt-in `plugins.entries..allow_tool_override: true` in `config.yaml`. +`schema["description"]` is the authoritative model-facing description. The separate `description=` argument populates `ToolEntry.description`; when it is omitted, the registry metadata falls back to the schema description. `get_definitions()` builds the OpenAI function definition from `entry.schema` and does not copy `entry.description` into a schema that lacks `description`. Therefore, `description=` alone does not describe the tool to the model, and when both values differ the model sees the schema value. Prefer defining the description once in the schema unless a registry consumer intentionally needs different metadata. + ### Discovery: `discover_builtin_tools()` When `model_tools.py` is imported, it calls `discover_builtin_tools()` from `tools/registry.py`. This function scans every `tools/*.py` file using AST parsing to find modules that contain top-level `registry.register()` calls, then imports them: diff --git a/website/docs/user-guide/features/plugins.md b/website/docs/user-guide/features/plugins.md index ed8012325b6e5..078949d0eb76c 100644 --- a/website/docs/user-guide/features/plugins.md +++ b/website/docs/user-guide/features/plugins.md @@ -77,7 +77,6 @@ def register(ctx): toolset="hello_world", schema=schema, handler=handle_hello, - description="Return a friendly greeting for the given name.", ) # --- Hook: log every tool call --- @@ -89,6 +88,8 @@ def register(ctx): Drop both files into `~/.hermes/plugins/hello-world/`, restart Hermes, and the model can immediately call `hello_world`. The hook prints a log line after every tool invocation. +The model-facing tool description belongs in `schema["description"]`. The optional `ctx.register_tool(description=...)` value is separate `ToolEntry` registry metadata: when omitted, it defaults to the schema description, but Hermes does not copy it back into a schema that lacks `description`. Prefer defining the text once in the schema. If you provide both values, keep them synchronized; the model sees the schema value. + Project-local plugins under `./.hermes/plugins/` are disabled by default. Enable them only for trusted repositories by setting `HERMES_ENABLE_PROJECT_PLUGINS=true` before starting Hermes. ## What plugins can do diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/developer-guide/tools-runtime.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/developer-guide/tools-runtime.md index f167dc4486031..c19c522ed0436 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/developer-guide/tools-runtime.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/developer-guide/tools-runtime.md @@ -30,18 +30,20 @@ Hermes 工具是自注册函数,按 toolset(工具集)分组,并通过 registry.register( name="terminal", # 唯一工具名称(用于 API schema) toolset="terminal", # 该工具所属的 toolset - schema={...}, # OpenAI function-calling schema(描述、参数) + schema={...}, # 面向模型的 schema(描述、参数) handler=handle_terminal, # 工具被调用时执行的函数 check_fn=check_terminal, # 可选:返回 True/False 表示是否可用 requires_env=["SOME_VAR"], # 可选:所需的环境变量(用于 UI 显示) is_async=False, # handler 是否为异步协程 - description="Run commands", # 人类可读的描述 + description="Run commands", # 可选的 ToolEntry 注册表元数据 emoji="💻", # 用于 spinner/进度显示的 emoji ) ``` 每次调用都会创建一个 `ToolEntry`,以工具名称为键存储在单例 `ToolRegistry._tools` 字典中。若不同 toolset 之间出现名称冲突,会记录警告,后注册的条目覆盖前者。 +`schema["description"]` 是面向模型的权威描述。独立的 `description=` 参数用于填充 `ToolEntry.description`;省略该参数时,注册表元数据会回退到 schema 中的描述。`get_definitions()` 根据 `entry.schema` 构建 OpenAI function definition,并不会在 schema 缺少 `description` 时把 `entry.description` 复制进去。因此,只提供 `description=` 不会向模型描述该工具;如果两个值不同,模型看到的是 schema 中的值。除非某个注册表消费者确实需要不同的元数据,否则应只在 schema 中定义一次描述。 + ### 发现机制:`discover_builtin_tools()` 当 `model_tools.py` 被导入时,会调用 `tools/registry.py` 中的 `discover_builtin_tools()`。该函数使用 AST 解析扫描所有 `tools/*.py` 文件,找出包含顶层 `registry.register()` 调用的模块,然后导入它们: diff --git a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/plugins.md b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/plugins.md index 7e8aa776b82fb..be0199f2e1f6c 100644 --- a/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/plugins.md +++ b/website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/user-guide/features/plugins.md @@ -75,7 +75,6 @@ def register(ctx): toolset="hello_world", schema=schema, handler=handle_hello, - description="Return a friendly greeting for the given name.", ) # --- Hook: log every tool call --- @@ -87,6 +86,8 @@ def register(ctx): 将两个文件放入 `~/.hermes/plugins/hello-world/`,重启 Hermes,模型即可立即调用 `hello_world`。每次工具调用后,hook 会打印一行日志。 +面向模型的工具描述应写在 `schema["description"]` 中。可选的 `ctx.register_tool(description=...)` 值是独立的 `ToolEntry` 注册表元数据:省略时,它会默认使用 schema 中的描述;但如果 schema 缺少 `description`,Hermes 不会把该元数据反向复制到 schema。建议只在 schema 中定义一次描述。如果同时提供两个值,请保持同步;模型看到的是 schema 中的值。 + `./.hermes/plugins/` 下的项目本地插件默认禁用。仅对可信仓库启用,方法是在启动 Hermes 前设置 `HERMES_ENABLE_PROJECT_PLUGINS=true`。 ## 插件能做什么