docs(plugins): clarify tool description sources
Explain that schema.description is model-facing while register_tool(description=...) only populates ToolEntry metadata, and remove the duplicated hello-world description in English and zh-Hans docs. Refs #60735 Co-authored-by: Shiki <132348332+songshikang0111@users.noreply.github.com>
This commit is contained in:
parent
934546fd5a
commit
26b3918dd9
|
|
@ -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.<plugin_id>.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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()` 调用的模块,然后导入它们:
|
||||
|
|
|
|||
|
|
@ -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`。
|
||||
|
||||
## 插件能做什么
|
||||
|
|
|
|||
Loading…
Reference in New Issue