From 7997ce72776449a011c5944265a553527cd51887 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 22 Jan 2026 21:41:10 +0000 Subject: [PATCH] docs: add async/deferred tools guide with remind tool example This adds documentation for the remind tool example (examples/01_standalone_sdk/33_remind_tool.py) which demonstrates how to create tools that return immediately but schedule future actions. Co-authored-by: openhands --- docs.json | 1 + sdk/guides/async-tools.mdx | 93 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 sdk/guides/async-tools.mdx diff --git a/docs.json b/docs.json index 3738b767..38a54914 100644 --- a/docs.json +++ b/docs.json @@ -239,6 +239,7 @@ "pages": [ "sdk/guides/hello-world", "sdk/guides/custom-tools", + "sdk/guides/async-tools", "sdk/guides/mcp", "sdk/guides/skill", "sdk/guides/plugins", diff --git a/sdk/guides/async-tools.mdx b/sdk/guides/async-tools.mdx new file mode 100644 index 00000000..d1cd3746 --- /dev/null +++ b/sdk/guides/async-tools.mdx @@ -0,0 +1,93 @@ +--- +title: Async/Deferred Tools +description: Create tools that return immediately but schedule future actions, enabling patterns like reminders and human-in-the-loop interactions. +--- + +## Overview + +Sometimes you need tools that can schedule actions to happen in the future without blocking the agent. The SDK supports this through **deferred tool execution** - the tool returns an observation immediately, but spawns a background task that can inject messages into the conversation later. + +This pattern is useful for: +- **Reminders** - Schedule messages to be sent after a delay +- **Human-in-the-loop** - Allow external input to be injected into conversations +- **Async operations** - Start long-running tasks without blocking the agent + +## Example: Remind Tool + + +This example is available on GitHub: [examples/01_standalone_sdk/33_remind_tool.py](https://github.com/OpenHands/software-agent-sdk/blob/main/examples/01_standalone_sdk/33_remind_tool.py) + + +The remind tool demonstrates how to create a deferred action tool: + +```python icon="python" expandable examples/01_standalone_sdk/33_remind_tool.py +``` + +```bash Running the Example +export LLM_API_KEY="your-api-key" +cd agent-sdk +uv run python examples/01_standalone_sdk/33_remind_tool.py +``` + +## Key Implementation Details + +### 1. The Executor Receives the Conversation + +The key to deferred tools is that the executor receives the `conversation` parameter in its `__call__` method: + +```python +class RemindExecutor(ToolExecutor[RemindAction, RemindObservation]): + def __call__( + self, action: RemindAction, conversation: "LocalConversation | None" = None + ) -> RemindObservation: + # conversation is available here for deferred actions +``` + +### 2. Background Thread for Deferred Action + +The executor spawns a background thread that sleeps for the specified delay, then uses `conversation.send_message()` to inject the reminder: + +```python +def send_reminder(): + time.sleep(action.delay_seconds) + reminder_text = f"[REMINDER]: {action.message}" + conversation.send_message(reminder_text) + +thread = threading.Thread(target=send_reminder, daemon=True) +thread.start() +``` + +### 3. Immediate Return + +The tool returns immediately with an observation confirming the reminder was scheduled, allowing the agent to continue working: + +```python +return RemindObservation( + scheduled=True, + message=action.message, + delay_seconds=action.delay_seconds, +) +``` + +## Use Cases + +### Human-in-the-Loop + +This pattern enables human-in-the-loop interactions where external input can be injected into a conversation at any time. For example, you could create a tool that: + +1. Registers a callback with an external system +2. Returns immediately to let the agent continue +3. Injects messages when the external system responds + +### Long-Running Operations + +For operations that take significant time (like API calls to slow services), you can: + +1. Start the operation in a background thread +2. Return a "processing" observation immediately +3. Inject the results when they're ready + +## Next Steps + +- **[Custom Tools](/sdk/guides/custom-tools)** - Learn the fundamentals of creating custom tools +- **[Send Messages While Running](/sdk/guides/convo-send-message-while-running)** - Inject messages into running conversations