Expand description
§Nanocodex Tools
Tool building blocks for OpenAI agents.
nanocodex-tools is useful without the Nanocodex agent loop. It provides the
caller-defined Tool contract, tool macro, heterogeneous Tools
registry, Code Mode runtime, standard workspace tools, and native MCP clients.
The shared contract types are defined by nanocodex-oai-api and re-exported
here so a tool implementation has one import surface.
§Define and select tools
The definition is the single source of truth for a tool’s registry name. The macro derives its input and output schemas from the function:
use nanocodex_tools::{Tools, tool};
#[tool(
name = "deployment_region",
description = "Return the production region for a named service.",
parallel = true
)]
async fn deployment_region(service: String) -> Result<String, std::io::Error> {
Ok(format!("{service}: us-west-2"))
}
let tools = Tools::builder()
.without_defaults()
.tool(deployment_region)
.build()?;Tools defaults to ToolExposure::CodeModeOnly, where ordinary tools are
available through exec and only Code Mode entrypoints are directly visible.
Select ToolExposure::DirectAndCodeMode when a consumer needs the same
ordinary tools directly as well as through exec:
use nanocodex_tools::{ToolExposure, Tools};
let tools = Tools::builder()
.exposure(ToolExposure::DirectAndCodeMode)
.build()?;Matching Codex, direct-plus-Code-Mode exposure keeps exec terse and
adds each typed exec declaration to the corresponding direct tool; Code
Mode-only instead carries the complete nested catalog in exec. Selection
changes model-visible exposure, not registration or dispatch behavior.
tool_with_exposure can override one registered tool with DirectOnly,
CodeModeOnly, DirectAndCodeMode, or Hidden while preserving the global
default for the rest. Host-owned exec, wait, and tool_search names cannot
be replaced, and colliding normalized JavaScript names are rejected when the
recipe is built.
ToolsBuilder::add composes the same recipe from a fixed Tool, a
WorkspaceTools value, or Mcp. A workspace source selects canonical
local workspace tools rooted at its directory; adding a second workspace source
is rejected.
Namespaced Code Mode names such as image_gen__imagegen remain available to
exec; normal Code Mode exposes the Codex-compatible image_gen.imagegen
Responses namespace and routes its namespaced call to the same handler.
Macro tools execute serially unless parallel = true explicitly marks their
local effects as safe to overlap. This does not change the provider wire
protocol.
Implement Tool directly when execution needs ToolContext, freeform
input, multimodal ToolOutput, or a custom definition:
use nanocodex_tools::{
Tool, ToolContext, ToolDefinition, ToolInput, ToolOutput, ToolResult,
contract::async_trait,
};
use serde_json::json;
struct DeploymentRegion;
#[async_trait]
impl Tool for DeploymentRegion {
fn definition(&self) -> ToolDefinition {
ToolDefinition::function(
"deployment_region",
"Return the production region for a named service.",
json!({
"type": "object",
"properties": { "service": { "type": "string" } },
"required": ["service"],
"additionalProperties": false
}),
)
}
async fn execute(
&self,
input: ToolInput,
_context: ToolContext<'_>,
) -> ToolResult {
let input: serde_json::Value = input.decode_json()?;
let service = input["service"].as_str().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"service must be a string",
)
})?;
Ok(ToolOutput::text(format!("{service}: us-west-2")))
}
}§Embed Code Mode in another host
embedded is the portable boundary for environments that own JavaScript
execution outside Rust. Build the ordinary Tools recipe, implement
embedded::CodeModeHost, and bind that host at the embedding boundary. The
adapter reuses the same execution, nested-call, notification, observer, and
owned-context types as native Code Mode. The embedded module documentation
includes a complete host implementation.
§MCP is native and always available
MCP is not a feature flag. Native consumers configure stdio or Streamable HTTP servers and install the provider into the same registry:
use nanocodex_tools::{
Tools,
mcp::{Mcp, McpServer},
};
let mcp = Mcp::builder()
.server(
"company_docs",
McpServer::stdio("company-docs-mcp").arg("--readonly"),
)
.build()?;
let tools = Tools::builder().add(mcp).build()?;Handshakes and discovery start with the owning runtime. Both exposure policies
keep the provider-native tool_search visible while omitting deferred MCP
schemas from the initial request. Code Mode lists those deferred tools as
compact name/description entries in ALL_TOOLS. Search results contain loadable
MCP namespaces for direct model calls and also activate matching Code Mode
definitions, keeping large catalogs out of the initial tool list.
McpServer::tool_exposure independently selects DeferredOnly,
CodeModeOnly, DeferredAndCodeMode, or Hidden for each server. Automatic
catalog pagination is bounded by page, item, cursor, and wall-clock limits.
§Attach one immutable recipe
With the attachment feature, the same Tools value can execute behind a
reverse WebSocket. Attachment consumes the complete recipe, finishes MCP
discovery, validates the immutable catalog, connects, and waits for the remote
catalog acknowledgement:
use nanocodex_tools::{Tools, attachment::AttachmentTarget};
let tools = Tools::builder().without_defaults().build()?;
let target = AttachmentTarget::new("wss://tools.example.test/v1/attach", "bearer")?;
let (attachment, mut events) = tools.attach(target).connect().await?;
let observer = tokio::spawn(async move {
while let Some(event) = events.recv().await {
println!("{event:?}");
}
});
attachment.detach().await?;
observer.await?;Only sources with a concrete attached executor are accepted: fixed tools,
MCP added with add, and pinned WorkspaceTools. Generic dynamic providers
remain local-only. Built-in web search and image generation also remain at the
model backend, so attached recipes disable defaults and opt into concrete
sources. Preparation and discovery errors happen before a socket is opened;
connect returns only after readiness. The cheap Attachment control handle
is cloneable and its last drop detaches. AttachmentEvents is an independent,
bounded, best-effort observer: lag may drop events but can never delay tool
execution or protocol progress. Attachment::status and closed are the
authoritative lifecycle APIs.
§Deferred: workspace replication
Attachment chooses where a tool call executes; it does not move or merge
workspace data. An attached local workspace and the detached cloud
/workspace may therefore diverge. Automatic replication and reconciliation
are intentionally deferred to a separate capability with explicit direction,
conflict, and recovery policy. Until that capability exists, attach and detach
must never imply synchronization.
§Companion workspace runtimes
The default native feature remains the complete tools crate: registry, Code
Mode, MCP, web/image tools, macros, and standard workspace tools.
The narrower workspace-runtime feature exists only for process companions
such as nanocodex-vm-guest. With default features disabled, it exposes the
canonical workspace_runtime::WorkspaceToolRuntime, standard tool
identities, and their shared contracts without linking OpenAI transports, Code
Mode/QuickJS, MCP, or HTTP clients. This is artifact separation, not a second
tool implementation or an alternate mode for normal native applications.
Both runtimes retain yielded shell sessions until their exit is collected or the owner cancels or shuts down the runtime. Opening another command never evicts an existing process, and there is no application-level process-count cap. The host operating system remains responsible for resource limits.
§Going lower level
The crate root intentionally contains only the normal registry path:
Tools, ToolsBuilder, ToolsBuildError, Tool, tool, and the types
required by the Tool methods. ToolExposure is the advanced declaration
policy for consumers that compare direct and Code Mode calls. The root also exposes
ambient_sensitive_environment for
deliberately restoring proxy-safe credential markers to tool subprocesses.
contractcontains complete model-visible inputs, outputs, errors, and retained wire forms.embeddedcontains the portable application-owned Code Mode boundary.runtimecontains the stateful per-agent executor, built-in connection configuration, and dynamic-provider contract.code_modecontains cell results, notifications, and nested-tool updates.mcpcontains transport configuration, authentication, discovery, login, and runtime control.standardcontains reusable standard-tool identities and the host-owned plan implementation.workspace_runtimecontains the retained canonical workspace-tool runtime used by process companions.imagecontains prompt-image preparation and tool-output normalization.
Re-exports§
pub use workspace_runtime::WorkspaceTools;workspace-runtimeand non-target_family=wasm
Modules§
- attachment
Non- target_family=wasm - Generic WebSocket attachment for one immutable
Toolsrecipe. - code_
mode Non- target_family=wasm - Code Mode execution results, notifications, and nested-tool observation.
- contract
- Model-visible tool definitions, inputs, outputs, and execution contracts.
- embedded
native - Portable adapter for Code Mode runtimes owned by an embedding host.
- image
Non- target_family=wasm - Prompt image preparation and model-output image normalization.
- mcp
Non- target_family=wasm - Background-handshaken MCP tools for Nanocodex Code Mode.
- runtime
Non- target_family=wasm - Declarative tool selection and the stateful per-agent execution runtime.
- standard
Non- target_family=wasm - Stable identities and reusable implementations for standard workspace tools.
- workspace_
runtime Non- target_family=wasm - Focused retained runtime for the canonical local workspace tools.
Structs§
- Tool
Context - Read-only context for one tool invocation.
- Tool
Output - Complete output of one tool invocation.
- Tools
native, orattachmentand non-target_family=wasm - Declarative selection of the built-in tools installed for an agent.
- Tools
Builder native, orattachmentand non-target_family=wasm - Builder for the built-in tool selection.
Enums§
- Tool
Definition - Model-visible tool definition carried by Responses Lite input.
- Tool
Exposure native, orattachmentand non-target_family=wasm - Nanocodex’s model-visible tool exposure policy.
- Tool
Input - Canonical input presented to function and freeform tools.
- Tools
Build Error native, orattachmentand non-target_family=wasm - Invalid declarative tool selection.
Traits§
- Tool
- A caller-defined model-visible tool.
- Tool
Source native, orattachmentand non-target_family=wasm - One capability source accepted by
ToolsBuilder::add.
Functions§
- ambient_
sensitive_ environment nativeand non-target_family=wasm - Returns the ambient environment variables the shell tool withholds from tool subprocesses because their names look sensitive.
Type Aliases§
- Tool
Result - Result returned by
Tool::execute.
Attribute Macros§
- tool
Non- target_family=wasm - Defines a typed JSON function tool from an async Rust function.