Tool Selection
Overview
tool_selection is a decision plugin that controls how tools are chosen for a matched route.
It supports two modes:
add: retrieve tools from a tools databasefilter: filter tools that are already present in the incoming request
Database tool names are trimmed and must be unique. Catalog enumeration uses
name order; equal similarity scores use name order before top_k truncation.
File loads and incremental additions reject duplicate names or non-finite
embedding values. A failed file batch leaves the existing catalog unchanged.
Key Advantages
- Separates route decision logic from tool retrieval/filter behavior.
- Supports both database-driven tool addition and request-tool semantic filtering.
- Keeps compatibility with route-local tool policies while making selection behavior explicit.
What Problem Does It Solve?
Different routes need different tool-selection behavior. Some routes should add tools from a curated database, while others should keep only the most relevant tools from the caller-provided set. tool_selection provides one plugin contract for both cases, with per-route controls such as threshold, top_k, and preserve behavior.
When to Use
- when a decision should add the most relevant tools from
tools_db - when a decision should semantically filter caller-provided
tools - when per-route tool selection mode must be explicit and configurable
Configuration
Add the plugin under routing.decisions[].plugins:
plugins:
- type: tool_selection
configuration:
enabled: true
mode: filter
relevance_threshold: 0.25
preserve_count: 2
For add mode:
plugins:
- type: tool_selection
configuration:
enabled: true
mode: add
tools_db_path: config/tools_db.json
top_k: 5
similarity_threshold: 0.35
add mode requires a populated tool database; filter mode only considers
tools already supplied by the caller. Semantic relevance is not authorization,
so enforce tool permissions separately. See complete examples:
add-from-database.yaml
and
filter-request-tools.yaml.
Session-scoped sticky selection
sticky is an opt-in, bounded policy layered on top of either mode (issue
#3347). A
trusted session retains the exact order of previously selected tools, pins
tools observed in assistant tool calls, and appends a bounded number of newly
relevant tools per turn — reducing prompt churn across a multi-turn tool-use
session without ever skipping current-turn authorization or availability
checks.
plugins:
- type: tool_selection
configuration:
enabled: true
mode: add
top_k: 3
sticky:
enabled: false
max_tools: 16
max_new_tools_per_turn: 2
pin_called_tools: true
max_tools(1-128, default16): hard bound on retained tools; once full, only called or definitionally-changed tools are re-evaluated.max_new_tools_per_turn(0-max_tools, default2): how many newly relevant tools may be appended in one turn.0disables relevance-driven growth entirely (reuse and call-pinning only) — this is a valid explicit setting, distinct from omitting the field.pin_called_tools(defaulttrue): tools observed in an assistant tool call are pinned and are not evicted by ordinary bounded growth.
Sticky state is scoped to a trusted, authenticated session — it is never
active for an anonymous or derived session identity — and every stored
identity is re-authorized and re-validated against the current request's
catalog, policy, and model/wire capabilities before use; a stored identity
is never trusted blindly. Runtime enablement remains unavailable: sticky.enabled: true is rejected
at both configuration admission and direct router construction.
Phase 2 (#4517)
adds a library planner and bounded state updates, without reading or writing
sticky state in the request path. Runtime integration is
Phase 3 (#4519),
which keeps reuse, authorization, invalidation, recovery, and fallback together.
The implementation sequence is recorded in
PL-0042.
See the complete disabled example:
sticky-add-from-database.yaml.