Skip to content

For developers

The Tool module is a plugin type. You extend it by writing tool plugins in your own module, and you integrate with it by discovering and running those plugins through the tool manager.

Extension points

  • Tool plugins. Define a tool by adding a class under src/Plugin/tool/Tool/ with the #[Tool] attribute, extending ToolBase. See Creating a tool.
  • Typed data adapters. The type system that maps input and output definitions to form elements and config schema is itself a plugin type, Plugin/tool/TypedData/Adapter/. Add an adapter to support a new data type. See Input and output definitions.
  • Events. Subscribe to input and output transform events to change values based on the invoker, and to normalize events to change how definitions are serialized. See Events.

Core services

Service Purpose
plugin.manager.tool Discovers, instantiates, and runs tool plugins.
plugin.manager.tool.typed_data_adapter Maps data definitions to adapters.
tool.handle_store Stores and resolves opaque handles for values.
tool.entity_handle_transformer Swaps entities for handles and back.
tool.definition_serializer Serializes tool definitions.

The tool lifecycle

  1. A caller asks plugin.manager.tool for a tool instance, optionally passing an invoker identifier.
  2. The caller sets input values. Each setInputValue() dispatches a ToolInputTransformEvent, so subscribers can transform the value for the invoker before it is stored.
  3. The caller calls execute(). The tool validates inputs, runs its doExecute() logic, and captures an ExecutableResult.
  4. The caller reads the result. getResult() returns the raw result; getFormattedResult() applies per output transforms and returns a FormattedExecutableResult ready for the invoker.

The invoker is the key idea: the same tool produces raw values for a deterministic caller and transformed, handle backed values for an AI or remote caller, without the tool's own code branching on the caller.