This example shows how a graph agent can orchestrate an external tool followed by internal tools with the model in control. The assistant first returns a tool call (external_fetch), the client executes the tool outside the graph process, submits the result back, and the assistant immediately continues with internal tools (summarize_text, optionally format_bullets).
The source code is in main.go.
- Runner: streams Large Language Model (LLM) output to the CLI.
- GraphAgent: wraps the compiled graph with checkpoint persistence.
- Graph: defines nodes, state schema, and conditional tool edges.
- LLM node (
assistant_plan): decides when to call tools. - Tool node (
external_tools): intercepts tool calls, pauses viagraph.Interruptonly for external_fetch, and resumes when the client provides the tool result.
prepare_input– trims user input and stores it in state.assistant_plan– streams the assistant response and makes tool calls.external_tools– pauses for external_fetch and waits for results.finalize– ensures there is a final assistant answer.
Edges:
prepare_input → assistant_planassistant_plan → external_tools(when tool calls are present)assistant_plan → finalize(when no tools are needed)external_tools → assistant_plan(continue after each tool result)
cd examples/graph/externaltool
go run .CLI commands:
- Type a question to start a run
- When external_fetch appears, execute it on your side and respond with:
/resume <content> /helpprints a short command summary/exitends the program
🔌 External Tools (Client‑Executed)
Model: deepseek-v4-flash
==================================================
Type a question to start the workflow.
Commands:
/resume <content> Resume with extract result
/help Show this help message
/exit Quit the program
You> First fetch the content at https://example.com/doc, then summarize it.
🔧 Tool call requested:
• external_fetch (ID: call_0)
args: {"source":"https://example.com/doc"}
⏸️ Waiting for external tool result.
🛑 External tool requested:
Run external_fetch and return the content.
Reply: /resume <content>
You> /resume <document text here>
🧰 Tool result: {"content":"<document text here>"}
🤖 Assistant: Here is the summary:
• ...
(Optionally, the assistant may also call format_bullets internally.)
You>
🔌 External Tools (Client‑Executed)
Model: deepseek-v4-flash
==================================================
Type a question to start the workflow.
Commands:
/resume <content> Resume with extract result
/help Show this help message
/exit Quit the program
You> fetch and summarize content from www.qq.com
🤖 Assistant: I'll fetch content from www.qq.com and then summarize it for you. Let me start by retrieving the content.
🔧 Tool call requested:
• external_fetch (ID: call_00_550LIAwSjCvBxRRzHNHQYV6D)
args: {"source": "www.qq.com"}
🛑 External tool requested:
Run extract externally and return content.
Reply: /resume <content>
⏸️ Waiting for external tool result.
You> /resume "qq.com is a website that provides rich content for qq"
🧰 Tool result: {"content":"\"qq.com is a website that provides rich content for qq\""}
🤖 Assistant: {"content":"\"qq.com is a website that provides rich content for qq\""}
Now let me summarize this content for you:
🔧 Tool call requested:
• summarize_text (ID: call_00_CDYXfRZV6ihEJbTIIQQ4n9gg)
args: {"text": "qq.com is a website that provides rich content for qq"}
🧰 Tool result: {"summary":"qq.com is a website that provides rich content for qq"}
Here's the summary of the content from www.qq.com:
- qq.com is a website that provides rich content for qq
The content appears to be quite brief and describes qq.com as a platform offering various content related to QQ services.
- The tool node installs a
BeforeToolCallbackthat intercepts external_fetch before execution. - The callback emits
graph.Interrupt, so the runner saves a checkpoint and the CLI prompts for a resume value. - The client submits the result via
/resume <content>. - The callback wraps the plain string into
{content: ...}and returns it as the tool result, letting the graph continue.
Tip: You can provide a different sequence. The assistant follows your plan and only pauses on external_fetch.