Skip to content

Introduce a Dynamic Toolset #2366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

strawgate
Copy link
Contributor

@strawgate strawgate commented Jul 29, 2025

Introduces a dynamic toolset that builds a toolset during the Agent run using a provided BuildToolsetFunc function.

  1. Each time the Toolset context is entered, a placeholder toolset is placed onto a thread/context-aware toolset stack.
  2. When get_tools is called, the placeholder is swapped with the result of the BuildToolsetFunc function and that new toolset becomes the "current" toolset.
  3. When the context is exited, the most recent toolset is popped off the stack and the previous toolset becomes the "current" toolset

I was thinking about trying to have it re-use the existing toolset if the deps are the same (and still could) but because deps can be anything, im not sure how straightforward checking equality would be.

This PR likely requires #2361 to work

@strawgate strawgate changed the title [Draft] Example of Dynamic toolset Introduce a Dynamic Toolset Jul 30, 2025
@DouweM
Copy link
Contributor

DouweM commented Jul 30, 2025

@strawgate Thanks! My main concern is that the function taking ctx suggests that a new toolset is going to be built when the context changes (on each run step) or at least when a new run is performed (and the ctx.deps would likely change), so that you can safely use run/user-specific details from ctx.deps like in your filesystem root directory example, without accidentally using a toolset built for another user/run.

But in reality it is tied to toolset enters/exits and there's no such guarantee... Those could align with agent runs, but wouldn't if you have your own async with agent: wrapping multiple agent runs (which you may want to do to keep MCP servers running during an entire request that could include multiple agent runs) because of the entered_count stuff we do in Agent.__aenter__ and CombinedToolset.__aenter__. Maybe we should just rip that out, so that we know for sure we enter/exit each toolset whenever a new agent run starts? Maybe we should also pass only deps instead of RunContext to make it clear you're not actually getting run-step specific context?

I want to make sure we don't accidentally introduce a footgun where the behavior will change completely when you add an async with agent: around a request or the entire FastAPI lifecycle or something, thinking you're just optimizing e.g. MCP server start/shutdowns.

Maybe we need to add a new hook to toolsets that's only called when a new run/step is actually started, so we don't rely on the enters/exits which could happen at any level?

This is all a bit complicated and my analysis here may very well be wrong. Either way I think we'll need tests with different patterns to make sure we get the desired behavior in each case.

We should probably chat about this directly, would you mind joining our public Slack so we can huddle?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dynamic toolsets based on run context
2 participants