Skip to content

Add asynchronous tool support with agent pause/resume#105

Draft
weeco wants to merge 1 commit into
mainfrom
claude/human-in-the-loop-pause-resume-mcp-elicitation-and-UYhXO
Draft

Add asynchronous tool support with agent pause/resume#105
weeco wants to merge 1 commit into
mainfrom
claude/human-in-the-loop-pause-resume-mcp-elicitation-and-UYhXO

Conversation

@weeco
Copy link
Copy Markdown
Contributor

@weeco weeco commented Apr 8, 2026

Summary

This PR adds support for asynchronous tools that require external completion (e.g., user input, long-running deployments). When an asynchronous tool is executed, the agent pauses with FinishReasonInputRequired and can be resumed later via Runner.Resume() with the final tool results.

Key Changes

  • Tool Interface Enhancement: Added IsAsynchronous() method to the Tool interface to declare whether a tool requires external completion

  • Agent Pause/Resume Logic:

    • Modified LLMAgent.executeSingleTurn() to detect asynchronous tools and pause execution with FinishReasonInputRequired
    • Tracks tool call IDs requiring external input and includes them in InvocationEndEvent.InputRequiredToolIDs
    • Emits StatusStageInputRequired event when pausing for external input
  • Runner Resume Support:

    • Added Runner.Resume() method to continue paused invocations by providing tool results
    • Extracted shared agent execution logic into runAgent() helper used by both Run() and Resume()
    • Tool results are added as a user message with ToolResponse parts before resuming
  • Tool Registry Enhancement: Registry now appends a note to asynchronous tool descriptions instructing the LLM not to re-invoke them after a pending status

  • MCP Elicitation Support: Added ElicitationHandler and WithElicitationHandler() to support MCP server requests for user input during tool execution

  • Built-in Tool Updates:

    • RequireInputTool now declares itself as asynchronous
    • All existing tools implement IsAsynchronous() returning false
  • Comprehensive Tests: Added TestRun_AsyncToolPausesExecution and TestRun_MixedSyncAndAsyncTools to verify pause/resume behavior with mixed tool types

Implementation Details

  • Asynchronous tool detection happens during concurrent tool execution in executeTools()
  • The executeToolsResult struct now tracks both response parts and IDs of tools requiring external input
  • Session persistence occurs after each assistant message and on exit, ensuring consistency across pause/resume cycles
  • The LLM receives full context: original tool call, initial pending result, and final result provided via Resume()

https://claude.ai/code/session_01WFwbKjni1JS6Rf17VNySb1

…104)

Wire the existing FinishReasonInputRequired scaffolding into a working
pause/resume system for human-in-the-loop and long-running tools.

Breaking change: Tool interface gains IsAsynchronous() bool. All Tool
implementations must add this method (return false for synchronous tools).

Core changes:
- tool.Tool: add IsAsynchronous() to signal tools that cannot complete
  in a single synchronous call (user input, CI/CD, batch jobs)
- agent/llmagent: executeTools() detects async tools via IsAsynchronous()
  and returns inputRequiredIDs; executeSingleTurn() emits
  FinishReasonInputRequired with InputRequiredToolIDs
- runner: add Resume() for providing tool results after pause; refactor
  Run()/Resume() to share runAgent() helper
- tool/registry: annotate async tool descriptions with re-invocation
  warning for the LLM
- tool/mcp: wire ElicitationHandler to MCP SDK ClientOptions for
  server-initiated user input requests
- tool/builtin/require_input: mark as IsAsynchronous()=true; simplify
  Execute() to return pending status

https://claude.ai/code/session_01WFwbKjni1JS6Rf17VNySb1
@blacksmith-sh
Copy link
Copy Markdown

blacksmith-sh Bot commented Apr 8, 2026

Found 1 test failure on Blacksmith runners:

Failure

Test View Logs
github.com/redpanda-data/ai-sdk-go/tool/TestRegistry_WebfetchToolWithLLM_Integration View Logs

Fix in Cursor

@weeco
Copy link
Copy Markdown
Contributor Author

weeco commented Apr 8, 2026

This was a test using the new ultraplan feature. Still have to review and check if I'd be happy with that API, I only planned and let it go create the PR without loooking into it

@weeco weeco marked this pull request as draft April 8, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants