Dependency graphs for tool-using agents
This mini-project came out of a pre-interview question that I liked right away. It asks about something that feels obvious once you see it, but that a lot of people skip when they build agents or tool systems: before you wire tools together, you should understand how one tool unlocks the next.
The part I care about most here is not the graph itself. It is the automatic pipeline that goes from a raw set of tool schemas, to a normalized schema, to a dependency graph that makes those paths legible.
If a tool needs a thread_id, issue_number, or calendar_id, the agent has to know where that value comes from. Does the user provide it? Does another tool return it? Can it be inferred from a previous step? That dependency logic is usually buried in the schemas.
So the goal was to make that explicit, automatically, from the tool definitions themselves.
A lot of agent work jumps straight from “here are the tools” to “let’s orchestrate them.” In practice, you usually need one pass in the middle that makes the tool surface understandable in a consistent way.
- It helps separate what the user must provide from what the system can fetch on its own.
- It makes tool routing easier to debug instead of leaving it hidden in prompt logic.
- It gives you a reusable path from any tool dump to something an agent can reason over.
That is why I liked the interview question. It points at an important systems step, not just a visualization trick.
- Start with the raw list of schemas, they can have a ton of arguments, include deprecated tools that should be ignored, different versions, long descriptions, and tags.
-
Normalize them, decide which arguments are needed. In the end, you want to have inputs -> outputs, you may want also what tools feed you, or what tools you feed too. Ids, optional and required arguments, keys if needed.
Here is where the normalization matters, cause it is going to help automate the whole process, and every good decision we take here is going to help build and improve our graph.
So using an LLM here is perfect, cause when we detect a complicated tool, or set of tools, we can use it to get the nuance and return the schema that best fits our purposes.
- Get the input seeds, edges, type relationships, confidence, and build your graph.
Graph snapshot
The graph below is the compact portfolio view. The main thing behind it is the pipeline that produced it, not the screenshot itself.
Things that can be observed from the graph
There are several isolated islands in the graph. If we want the agent to move between them, we need to add additional tooling that creates those bridges. That is not necessarily bad. It can just mean the API, or the agent itself, has different modes or capabilities, and that each island can work well on its own.
From a design perspective, knowing in advance what actions are available and what paths are probably going to be used allows for smarter orchestration of the tools.
That matters even more when the tools themselves depend on external servers or systems, which is clearly the case for ecosystems like GitHub and Google.
What I would extend next
- Add reachability checks so the graph can answer what sequences are actually possible from a given starting point.
- Improve the matching logic so weak relationships get filtered more aggressively.
- Keep the LLM-based normalization where it helps, but fall back to deterministic parsing when the schema is already clean.
The broader point is that if you want agents to use tools well, you usually need an intermediate representation of the tool system first. This mini-project was a quick way to make that concrete.
Go to repo