Repository navigation
Labels
bugSomething isn't workingSomething isn't working
Description
🔴 Required Information
Describe the Bug:
The agent graph generator leaves out part of an llmagent tree:
- Tools from
Toolsetsare not drawn.buildGraphonly reads the agent'sToolsfield, so tools that come from atool.Toolset(for example an MCP toolset or a skills toolset) never appear in the graph:
https://github.com/google/adk-go/blob/8c7ab1baf9bc/server/adkrest/internal/services/agentgraphgenerator.go#L292 - Sub-agents of an
llmagentare drawn without an edge to their parent.buildGraphvisitsSubAgents()only to draw their nodes, so a coordinator and its sub-agents show up as unconnected nodes:
https://github.com/google/adk-go/blob/8c7ab1baf9bc/server/adkrest/internal/services/agentgraphgenerator.go#L304-L309
adk-python handles both cases in agent_graph.py: it draws tools from await agent.canonical_tools(), which resolves toolsets, and it draws an edge from a non-workflow agent to each of its sub-agents (draw_edge(agent.name, sub_agent.name)).
Steps to Reproduce:
- Save the minimal reproduction code below as
main.goin a new module (go mod init graphrepro && go get google.golang.org/adk/[email protected]). It uses a fake model that is never called, so no API key is needed. - Run
go run . web -port 8097 api -include_debug_api - Request the graph:
curl http://localhost:8097/api/dev/apps/root/build_graph_image - Or open the web UI (
go run . web -port 8097 api -include_debug_api webui) and look at the graph panel.
Expected Behavior:
The graph shows root connected to direct_tool, to toolset_tool (from the toolset) and to its sub-agent helper.
Observed Behavior:
Only direct_tool is connected. toolset_tool is missing and helper is a loose node:
digraph AgentGraph {
bgcolor="#ffffff";
rankdir=LR;
root->direct_tool[ arrowhead=none, color="#3c4043" ];
direct_tool [ color="#3c4043", fontcolor="#3c4043", label="🔧 direct_tool", shape=box, style=rounded ];
helper [ color="#3c4043", fontcolor="#3c4043", label="🤖 helper", shape=ellipse, style=rounded ];
root [ color="#3c4043", fontcolor="#3c4043", label="🤖 root", shape=ellipse, style=rounded ];
}Environment Details:
- ADK Library Version: v2.5.0 (the code is unchanged on
mainat 8c7ab1b) - OS: macOS
- Go Version: go1.26.6 darwin/arm64
Model Information:
- Which model is being used: N/A (the reproduction uses a fake model; originally found with Gemini agents using an MCP toolset and sub-agents)
🟡 Optional Information
Regression:
Unknown.
Minimal Reproduction Code:
package main
import (
"context"
"iter"
"log"
"os"
"google.golang.org/adk/v2/agent"
"google.golang.org/adk/v2/agent/llmagent"
"google.golang.org/adk/v2/cmd/launcher"
"google.golang.org/adk/v2/cmd/launcher/full"
"google.golang.org/adk/v2/model"
"google.golang.org/adk/v2/tool"
"google.golang.org/adk/v2/tool/functiontool"
)
// fakeModel is never called: rendering the graph does not need a model.
type fakeModel struct{}
func (fakeModel) Name() string { return "fake" }
func (fakeModel) GenerateContent(context.Context, *model.LLMRequest, bool) iter.Seq2[*model.LLMResponse, error] {
return func(func(*model.LLMResponse, error) bool) {}
}
type args struct{}
func newTool(name string) tool.Tool {
t, err := functiontool.New(functiontool.Config{Name: name, Description: name},
func(agent.Context, args) (string, error) { return "", nil })
if err != nil {
log.Fatal(err)
}
return t
}
// staticToolset stands in for an MCP toolset (mcptoolset) or a skills toolset.
type staticToolset struct{}
func (staticToolset) Name() string { return "my_toolset" }
func (staticToolset) Tools(agent.ReadonlyContext) ([]tool.Tool, error) {
return []tool.Tool{newTool("toolset_tool")}, nil
}
func main() {
helper, err := llmagent.New(llmagent.Config{Name: "helper", Description: "helper", Model: fakeModel{}})
if err != nil {
log.Fatal(err)
}
root, err := llmagent.New(llmagent.Config{
Name: "root",
Model: fakeModel{},
Tools: []tool.Tool{newTool("direct_tool")},
Toolsets: []tool.Toolset{staticToolset{}},
SubAgents: []agent.Agent{helper},
})
if err != nil {
log.Fatal(err)
}
cfg := &launcher.Config{AgentLoader: agent.NewSingleLoader(root)}
if err := full.NewLauncher().Execute(context.Background(), cfg, os.Args[1:]); err != nil {
log.Fatal(err)
}
}Additional Context:
- Resolving toolsets needs an
agent.ReadonlyContext(Toolset.Tools(ctx)), and the graph endpoint has no invocation. An MCP toolset would also have to connect to its server just to list tools. If that is not desirable, drawing the toolset itself as a single node (byToolset.Name()) would already make it visible. - Related: Agent graph fails to render when a workflow agent is nested inside a sequential or loop agent #1723 (nested workflow agents break the graph).
How often has this issue occurred?:
- Always (100%)
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
karthik-0306 commentedon Oct 5, 2026
I have checked and verified that this issue exists. I'll be working on a fix for this!
My approach to solving this is:
context.ContexttobuildGraphso that we can wrap it in anicontext.NewReadonlyContextto calltoolset.Tools(ctx)and draw the toolset tools.drawEdgefor sub-agents recursively when the parent is not a workflow cluster.I will open a PR with these changes shortly.
fix(adkrest): render missing toolset tools and sub-agent connections …
fix(adkrest): render missing toolset tools and sub-agent connections …
indurireddy-TF commentedon Oct 9, 2026
Hi @alexyslozada Thank you for reporting this issue. We were able to reproduce both behaviors via the /api/dev/apps/{agent}/build_graph_image endpoint:
1.Tools provided via Toolsets are omitted from the generated DOT graph.
2.Sub-agents are declared as nodes without connecting edges from the parent coordinator agent.
fix(adkrest): render missing toolset tools and sub-agent connections …
fix(adkrest): quote DOT IDs, test, log and bound toolset resolution i…
fix(adkrest): quote DOT IDs, test, log and bound toolset resolution i…
fix(adkrest): stop the agent graph from canceling toolset listings
fix(adkrest): draw toolsets as nodes instead of listing their tools