Session 8· 02· 15 min

Static vs Dynamic Tools

What you'll learn
  • Filter available tools based on agent state (auth level)
  • Use @wrap_model_call middleware to adjust tools at runtime
  • See the difference between static (fixed) and dynamic (state-driven) tools

What you will build

An agent where basic users can only search public docs, but admin users can also search internal docs. The middleware reads auth_level from state and filters the tool list dynamically.

Static tools
lesson 00
  • tools=[a, b, c] at creation
  • Same tools every call
  • Simple, predictable
Dynamic tools
this lesson
  • Middleware filters tools per call
  • Based on state (auth, step, flags)
  • Fine-grained access control
02_dynamic_tools.py (middleware)
@wrap_model_call
def filter_tools_by_auth(
    request: ModelRequest,                                      ①
    handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
    auth = request.state.get("auth_level", "basic")              ②
    if auth == "admin":
        tools = [search_public, search_internal]
    else:
        tools = [search_public]
    request = request.override(tools=tools)                      ③
    return handler(request)
ModelRequest gives you access to the current state and tools.
Read state to decide which tools the model should see.
request.override returns a new request with the filtered tool list.
$ python 02_dynamic_tools.py
Knowledge Check
Why would you hide tools from the model instead of just checking permissions in the tool function?
Recap — what you just learned
  • @wrap_model_call middleware runs before every LLM call
  • request.state lets you read agent state (auth, step, flags)
  • request.override(tools=...) swaps the tool list dynamically
Next up: 03 — Tool Error Handling