How OpenHuman Handles Tool Disclosure Using Pack-Based Methods
OpenHuman implements a three-stage, pack-centric disclosure system that uses the GroupMode enum—Advertised, Withheld, and Off—to control which tools appear in LLM prompts while maintaining full runtime access through the PackRegistryHandle.
The tinyhumansai/openhuman repository provides a robust framework for AI agent tool management through pack-based disclosure methods. This architecture allows developers to selectively control tool visibility in language model prompts without sacrificing the ability to invoke any registered tool at runtime.
Core Components of Pack-Based Disclosure
The tool disclosure system relies on several key structures defined across the OpenHuman codebase. These components work together to separate tool registration from tool visibility.
PackRegistryHandle
The PackRegistryHandle serves as the central registry holding all tools bound to the core during a turn. Defined in src/openhuman/tools/traits.rs at lines 235-242, this handle persists the complete tool set throughout the agent's lifecycle, ensuring withheld tools remain callable even when excluded from prompts.
GroupMode and ToolGroups
Tool visibility is controlled through the GroupMode enum and ToolGroups configuration structure located in src/openhuman/tools/toolpacks/groups.rs. The GroupMode enum defines three disclosure states:
Advertised— Tools appear in the LLM prompt's tool catalogWithheld— Tools remain callable but are hidden from the promptOff— Tools are completely disabled and unregistered
The ToolGroups builder allows hosts to specify disclosure policies for entire tool packs, enabling fine-grained control over which functional domains the model can access.
Filtering and Binding Functions
The system implements specific functions to manage the transition from configuration to execution:
-
strip_packed_from_visibleinsrc/openhuman/agent/harness/session/turn/tools.rsat line 612 filters the tool list before sending to the LLM, removing any tools whoseGroupModeis notAdvertised -
bind_pack_registryinsrc/openhuman/agent/harness/session/builder/setters.rsat lines 590-595 stores the complete tool set in thePackRegistryHandlefor later dispatch -
append_pack_toolsinsrc/openhuman/tools/ops.rsat lines 1186-1203 injects pack-based tools into the final tool vector after domain-specific tools are collected
The Five-Stage Disclosure Pipeline
OpenHuman processes tool disclosure through a sequential pipeline that separates configuration from runtime execution.
1. Builder Configuration
When constructing a Harness or CoreBuilder, developers supply a ToolGroups instance to define default disclosure policies. The core builder API in src/core/runtime/builder.rs at lines 449-510 exposes the tool_groups method for this configuration. Desktop builds typically use ToolGroups::advertised() while lightweight embedders may use ToolGroups::none().
2. Tool Collection
The system gathers tools from all active domain-specific agents, then appends pack-based tools via append_pack_tools. This occurs in src/openhuman/tools/ops.rs, ensuring the full tool set is assembled before visibility filtering.
3. Registry Binding
The bind_pack_registry function stores the assembled tool list in a PackRegistryHandle. This binding, performed during session building, makes the complete registry available to the dispatcher for resolving tool calls that reference withheld tools.
4. Visibility Filtering
Just before transmitting the turn to the LLM, strip_packed_from_visible traverses the tool list and removes any tools where GroupMode is Withheld or Off. Only Advertised tools render into the prompt's tool catalog, reducing token consumption and preventing exposure of sensitive functionality.
5. Runtime Dispatch
If the model references a withheld tool by name—either from prior context or system messages—the dispatcher consults the PackRegistryHandle to locate and execute the tool. Because the registry contains all bound tools regardless of disclosure state, withheld tools remain fully functional.
Configuring Tool Groups in Practice
The framework provides flexible APIs for configuring tool disclosure at build time.
Advertising All Default Tools
To expose all pack-based tools to the model, use ToolGroups::advertised():
use openhuman_core::openhuman::tools::toolpacks::ToolGroups;
use openhuman_core::embed::harness::Builder as HarnessBuilder;
let harness = HarnessBuilder::new()
.tool_groups(ToolGroups::advertised())
.build()
.await?;
Disabling All Pack-Based Tools
For lightweight deployments where pack tools should not be available, use ToolGroups::none():
use openhuman_core::openhuman::tools::toolpacks::ToolGroups;
let harness = HarnessBuilder::new()
.tool_groups(ToolGroups::none())
.build()
.await?;
Withholding Specific Packs
To hide specific tool packs from the prompt while preserving runtime access:
use openhuman_core::openhuman::tools::toolpacks::{GroupMode, ToolGroups};
let mut groups = ToolGroups::advertised();
groups.set_mode("documents", GroupMode::Withheld);
let harness = HarnessBuilder::new()
.tool_groups(groups)
.build()
.await?;
Runtime Dispatch of Withheld Tools
The dispatcher can execute tools even when they were not advertised:
let registry = ctx.pack_registry_handle();
if let Some(tool) = registry.get("generate_document") {
tool.run(args).await?;
}
Why Pack-Based Disclosure Matters
The pack-centric approach provides several architectural advantages for production AI systems.
Security and Cost Control. Large tool packs for document generation, media processing, or web3 operations can be expensive or present security risks. The disclosure system ensures these tools are only advertised when hosts explicitly opt-in, preventing accidental invocation.
Prompt Size Management. LLM prompts have strict token limits. Hiding rarely-used tools through GroupMode::Withheld reduces prompt length and associated API costs without removing functionality.
Feature Flag Integration. Each tool pack maps to a Cargo feature flag. Setting GroupMode::Off guarantees that disabled features do not leak tool schemas into prompts, maintaining clean separation between compiled and exposed functionality.
Summary
- OpenHuman uses a three-state disclosure system (
Advertised,Withheld,Off) controlled by theGroupModeenum to manage tool visibility - The
PackRegistryHandlemaintains a complete registry of all bound tools, ensuring withheld tools remain callable at runtime strip_packed_from_visiblefilters non-advertised tools from prompts before LLM transmissionbind_pack_registryandappend_pack_toolsmanage the transition from build-time configuration to runtime execution- This architecture enables token-efficient prompts while preserving access to the full tool registry for advanced use cases
Frequently Asked Questions
What is the difference between Withheld and Off tools in OpenHuman?
Withheld tools are removed from the LLM prompt but remain registered in the PackRegistryHandle, allowing the model to call them if referenced by name from prior context. Off tools are completely disabled—they are neither advertised nor callable, effectively removing them from the runtime registry.
How does OpenHuman prevent withheld tools from appearing in prompts?
The framework invokes strip_packed_from_visible in src/openhuman/agent/harness/session/turn/tools.rs immediately before sending the turn to the language model. This function iterates the tool list and excludes any tools where GroupMode is not Advertised, ensuring only explicitly disclosed tools render into the prompt's tool catalog.
Can a language model call a tool that wasn't advertised in the prompt?
Yes. If the model references a withheld tool by name—either learned from system messages or previous turns—the dispatcher consults the PackRegistryHandle established during bind_pack_registry. Since this registry contains all tools regardless of disclosure state, the system can execute withheld tools on demand.
Where is the tool pack configuration defined in the OpenHuman codebase?
The primary configuration structures reside in src/openhuman/tools/toolpacks/groups.rs, which defines ToolGroups and the GroupMode enum. The core builder API exposing these controls is implemented in src/core/runtime/builder.rs at lines 449-510, while the runtime binding logic exists in src/openhuman/tools/toolpacks/ops.rs.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →