Tool Chaining & Data-by-Reference

When an agent needs to pass 50MB of query output from a database into a Python analysis script, standard agent architectures send that entire 50MB back through the LLM context window. This creates massive latency and token waste.

Agent Substrate solves this through Sandboxed Tool Chaining by Reference via ToolChainTool and ChainPolicy.


How It Works

Instead of routing intermediate large payloads through the LLM:

  1. Tool Invocation in Sandbox: The model writes a Python script that invokes multiple tools in a single turn.
  2. Data-by-Reference: Small results are inlined in variables. Large results (> ChainPolicy.max_inline_result_bytes) are persisted directly to the artifact/blob store, sending only a lightweight InvocationResult handle with a preview across the bridge.
  3. Store-to-Tool Resolution: The next tool consumes the handle reference directly.
  4. Context Conservation: Only the concise final summary report is returned to the model context.

Usage Example

python
import asyncio
from substrate.agents import ReActAgent
from substrate.tools.chain import ChainPolicy
from substrate.integrations.tools.chain import ToolChainTool
from substrate.runtime import Runtime
from substrate.tools import ToolRisk

async def main() -> None:
    # 1. Define conservative execution policies for the chained script
    policy = ChainPolicy(
        max_tool_calls=20,
        call_timeout_s=30.0,
        max_inline_result_bytes=4096,
        max_risk_unapproved=ToolRisk.SAFE,
    )

    # 2. ReActAgent passes the tool_policy to govern all chain executions
    agent = ReActAgent(
        "data_analyst",
        model=my_chat_model,
        tool_policy=policy,
        system_instructions="You can chain tools within a single Python script turn.",
    )

    async with Runtime.open("./.substrate") as runtime:
        outcome = await runtime.run(
            agent,
            "Fetch the top 50,000 transaction rows and compute the standard deviation of latency."
        )
        print(outcome.output)

if __name__ == "__main__":
    asyncio.run(main())
Was this page helpful?