How Reasonix Handles Built-In Tool Schemas and the Tool Execution Contract

Reasonix enforces a strict tool execution contract by centralizing built-in tool schemas in a canonical registry, validating all arguments against JSON-Schema definitions, and baking schema hashes into session state to guarantee deterministic behavior across provider integrations.

DeepSeek-Reasonix implements a rigorous architecture for managing built-in tool schemas that separates tool definition, schema handling, and runtime enforcement into clearly-scoped components. This design ensures that language models can only invoke registered tools with arguments that conform to canonical schemas, maintaining system determinism and auditability.

Built-In Tool Registry and Canonical Schemas

All built-in tools register themselves at startup through the tool registry located in internal/tool/tool.go. The Builtins() function initializes this registry during application bootstrap, storing each tool's implementation alongside its canonical JSON-Schema definition.

The (*Registry).Schemas() method exports the provider-visible tool list in stable alphabetical order. Each entry contains the tool name, description, and the canonical schema (provider.ToolSchema). This ordered list is essential for provider integrations because it ensures consistent tool presentation to OpenAI, Anthropic, and other LLM APIs.

// Retrieve the stable schema list for a provider (e.g., OpenAI).
func getProviderSchemas(reg *tool.Registry) []provider.ToolSchema {
    return reg.Schemas() // alphabetical, ready for the API request
}

The Tool Execution Contract

Reasonix formalizes the relationship between available tools and runtime behavior through a contract snapshot mechanism defined in internal/tool/contract.go. The (*Registry).ContractEntries() method builds a ContractEntry for every registered tool, capturing:

  • Name and description
  • Read-only flag indicating tool safety characteristics
  • Canonical schema for parameter validation

This snapshot serves dual purposes: runtime consistency checks and documentation generation. The contract guarantees that cached execution plans remain valid by baking a ToolSchemaHash into the session state, ensuring that any schema changes invalidate previous caches.

// Build a provider request that includes the schemas.
req := provider.Request{
    Model: "deepseek-chat",
    Messages: []provider.Message{
        {Role: "user", Content: "Summarize the file."},
    },
    // The LLM will be allowed to call any of these tools.
    Tools: getProviderSchemas(tool.GlobalRegistry),
}

Runtime Schema Validation

Before any tool call reaches a provider, Reasonix validates schemas through internal/provider/schema_validate.go. The provider.ValidateToolSchema function parses JSON-Schema definitions, enforcing Draft-07/2020-12 compliance while rejecting malformed structures or external $ref references.

When validation fails, provider.AnnotateToolSchemaError wraps the error with tool-index information, providing deterministic "tool" location metadata that allows the model to understand exactly which parameter failed validation. This error annotation appears in the OpenAI client implementation at internal/provider/openai/openai.go (lines 492-517), where runtime enforcement occurs.

// At runtime the OpenAI client validates a tool call.
func callTool(ctx context.Context, toolName string, args json.RawMessage) error {
    // Provider checks that `toolName` exists in req.Tools and that
    // `args` matches the canonical schema (ValidateToolSchema).
    // Errors are wrapped with AnnotateToolSchemaError for clear feedback.
}

Provider Integration and Token Accounting

The provider.Request struct defined in internal/provider/provider.go contains a Tools []provider.ToolSchema field that implements the execution contract boundary. When the model issues a tool call, the provider client extracts the matching schema, validates supplied arguments, and tracks ToolSchemaTokens through the eventwire.Wire protocol (see internal/eventwire/wire.go).

This integration enforces four critical guarantees:

  1. The model only calls tools declared in the original request
  2. Arguments conform to the registered JSON-Schema
  3. Errors report deterministic location metadata via provider.AnnotateToolSchemaError
  4. Schema hashes remain consistent throughout the session lifecycle

Documentation Generation

To prevent documentation drift, Reasonix generates human-readable contracts directly from the registry snapshot. The RenderContractMarkdown function in internal/tool/contract.go (lines 64-88) converts ContractEntry data into markdown tables and per-tool schema blocks, outputting to docs/TOOL_CONTRACT.md. This ensures that published documentation always reflects the actual runtime contract enforced by the system.

// Register a new built-in tool (usually done in init()).
func init() {
    tool.MustRegister(&myTool{})
}

Summary

  • Canonical Registry: internal/tool/tool.go maintains the single source of truth for built-in tool definitions and their JSON-Schemas.
  • Contract Snapshots: ContractEntries() in internal/tool/contract.go creates stable records including read-only flags and schema hashes for session consistency.
  • Schema Validation: ValidateToolSchema enforces Draft-07/2020-12 compliance and rejects external references before provider submission.
  • Runtime Enforcement: The OpenAI client (internal/provider/openai/openai.go) validates tool calls against the request's Tools field and annotates errors with deterministic locations.
  • Token Tracking: ToolSchemaTokens in the event wire protocol accounts for schema overhead in provider requests.
  • Documentation Sync: RenderContractMarkdown generates docs/TOOL_CONTRACT.md directly from the contract snapshot to eliminate documentation drift.

Frequently Asked Questions

How does Reasonix ensure that LLMs only call registered tools?

Reasonix enforces this through the provider.Request structure, which contains a Tools []provider.ToolSchema field listing only the permitted tools for that session. The OpenAI client implementation validates every incoming tool call against this list, rejecting any invocation of tools not present in the original request schema set.

What happens when a tool schema changes in a new version?

The contract snapshot includes a ToolSchemaHash that is baked into the session state. When schemas change, this hash differs from cached values, automatically invalidating previous execution plans and ensuring that cached responses do not reference outdated tool definitions.

How does Reasonix handle invalid tool arguments?

Invalid arguments trigger the ValidateToolSchema function in internal/provider/schema_validate.go, which parses the JSON-Schema and validates compliance. Errors are wrapped by AnnotateToolSchemaError to include the specific tool index and parameter location, allowing the model to receive structured feedback about which arguments failed validation.

Where are built-in tools registered in the codebase?

Built-in tools register themselves at startup through tool.MustRegister() calls, typically inside init() functions. The Builtins() function in internal/tool/tool.go orchestrates this registration process, populating the global registry with tool implementations and their canonical schemas before the application serves requests.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →