Wymcp. Help
(Wymcp v0.8.7)
View Source
The framework-owned introspection tool — the server's entire introspection
surface, injected by Wymcp.Router into every server under the reserved
tool name help.
Help answers at three levels: a bare call returns the server index (every
tool with its action summaries); tool returns that tool complete (all
action schemas with notes, related actions, and examples); tool plus
action returns one action complete, with the target tool's
Wymcp.Tool.action_context/2 output under "context". Resolution order
is tool first, then action — action without tool is an error, and
unknown targets error naming the valid ones and pointing at the help
index (isError: true content the calling LLM can self-correct from),
never a silent fallback to a broader answer. Those answers quote the
requested name under the rule Wymcp.Bound states in "What a refusal
quotes".
The index renders through Wymcp.Tool.Schema.action_summaries/1, which
shares its content source with the tools/list description builder
(Wymcp.Tool.Schema.build/1) rather than being called by it, so the two
cannot drift.
Server-level prose does not live here — it belongs in the
instructions router option.
Help answers from ctx.tools — the request's tool list, which
Wymcp.Methods.ToolsCall sets on every context.
It will not render around a gap, at any of the three levels. Help obtains
every action schema it renders through Wymcp.Tool.Actions.fetch_schema/2
or Wymcp.Tool.Actions.fetch_schemas!/1, which check the mandatory keys
where the schema is obtained — the read-side corollary stated in
Wymcp.Tool.Actions — so a schema missing one raises ArgumentError
naming the tool, the action and the key before anything is rendered.
Publishing the entry instead would assert something false about the action:
silence about :properties reads as a claim that it takes none, and a null
description reaches the wire as the action's description.
An action's properties are published with the closure dispatch
enforces: Wymcp.Tool.KeySet.close_properties/1 writes
additionalProperties: false into every nested object schema whose key
set is closed, and leaves one whose author wrote the keyword as written.
Under JSON Schema an object without the keyword is open, so the schema
published verbatim would tell a reader that dispatch accepts keys it
refuses (the rule: "Dispatch errors and self-correction" in Wymcp.Tool).
This module implements the tool wire contract by hand (input_schema/0,
run/2) rather than through use Wymcp.Tool: help has no action
dispatch, its two parameters live at the top level of arguments, and
its input schema sets additionalProperties: false so a misspelled
parameter is a stated contract violation rather than a silent answer to
the wrong question. Publishing that is one half; the other is the gate
pair in run/2: vocabulary through the same Wymcp.Tool.check_arguments/4
a generated tool's dispatch uses, and types through help's own
check_argument_types/2 — a tool that hand-writes its schema owns the
types of the keys it declares, and the framework's two type checks cover
only its own action/data. Both valid sets derive from the schema
above. Both halves are needed: argument validation in
Wymcp.Methods.ToolsCall checks structure only — a stray name is a
dispatch gate's answer everywhere in wymcp, never a -32602 naming no
key — so without the gate a misspelled tol would silently answer the
index. Its tools/list definition is assembled by the same
Wymcp.Tool.build_definition/1 every other tool's is, so a definition key
added there reaches help without hand-sync.
It is the framework's only @behaviour Wymcp.Tool tool, and the only
reason that path exists. Wymcp.Tool's run/2 and input_schema/0 come
from __before_compile__ and are not defoverridable, so a tool without
action dispatch cannot use the macro — the path is an internal
accommodation, not a consumer contract; a consumer tool uses the macro.
Being behaviour-only, this module owes every required callback by hand:
actions/0, run_action/3, hints/2 and handle_error/1 are dead
stubs carried for that reason alone, and Wymcp.Router.init/1 checks
them while a mount module compiles (the callback-surface invariant,
homed in Wymcp.Tool).
Every call that reaches an answer emits [:wymcp, :help, :called] after
that answer is resolved — see Wymcp.Telemetry. A call rejected by the
arguments gate above does not: it resolved no target, so the event's
tool, action and level would describe an index call that never
happened. Such a rejection stays observable as [:wymcp, :tool, :stop]
with error_kind: :dispatch, like any other tool's gate rejection. (A
mistyped action or data never gets this far: ToolsCall's argument
validation answers it -32602 before any tool runs, unobserved by tool
telemetry — a property of the -32602 path, not of help.)
flowchart TD
H[Wymcp.Help] --> R["run/2"]
subgraph External
R -->|"action_summaries/1"| SC[Tool.Schema]
R -->|"fetch_schemas!/1, fetch_schema/2"| AC[Tool.Actions]
R -->|"close_properties/1"| KS[Tool.KeySet]
R -->|"shared tool-surface helpers"| WT[Wymcp.Tool]
WT -->|"action_context/2"| T(Target tool)
R --> TE[Telemetry]
end
Summary
Functions
True when module claims the reserved tool name.
Functions
True when module claims the reserved tool name.
The reserved name is "help" — the tool name only the framework may
use: a consumer tool may not claim it at a mount module's compile
(Wymcp.Router.init/1), whose raise routes through this predicate.