Skip to content

Add agent_send_async with channel-agnostic callback delivery#797

Open
pbranchu wants to merge 3 commits intoRightNow-AI:mainfrom
pbranchu:feat/async-agent-delegation
Open

Add agent_send_async with channel-agnostic callback delivery#797
pbranchu wants to merge 3 commits intoRightNow-AI:mainfrom
pbranchu:feat/async-agent-delegation

Conversation

@pbranchu
Copy link
Copy Markdown
Contributor

@pbranchu pbranchu commented Mar 23, 2026

Summary

  • Add agent_send_async tool for non-blocking delegation to other agents (hands)
  • Add agent_cancel tool to abort in-flight delegations
  • Callback results are delivered through the channel bridge, not a hardcoded voice channel — works on Chat, Voice, Email, and all other channels
  • One-turn callback framing: the hand's name appears as the sender (e.g. "workspace-hand wrote: ...") so the agent can present results naturally

Design

When agent_send_async is called:

  1. Capture channel context (channel type, sender, thread) from the bridge dispatch
  2. Spawn background task to run the target agent
  3. Return immediately so the caller can acknowledge the user

When delegation completes:

  1. Call inject_async_callback on the kernel handle
  2. Send the result to the caller agent with hand attribution
  3. Route the agent's formatted response to the original user on the originating channel via send_channel_message

Closes #891.

Test plan

  • Chat delegation: message on Chat → delegate → result appears in Chat
  • Voice delegation: same flow, result spoken via TTS
  • Cancel: agent_cancel aborts in-flight task
  • cargo check -p openfang-kernel -p openfang-runtime -p openfang-channels -p openfang-api
  • cargo fmt --check

🤖 Generated with Claude Code

@jaberjaber23
Copy link
Copy Markdown
Member

Reviewed and approved. This PR has merge conflicts with recent changes on main. Please rebase onto current main and we will merge it.

@pbranchu pbranchu force-pushed the feat/async-agent-delegation branch 7 times, most recently from 757f54b to f77c688 Compare March 27, 2026 16:00
@jaberjaber23
Copy link
Copy Markdown
Member

Reviewed and approved. Has merge conflicts with recent changes on main. Please rebase and we will merge immediately.

@pbranchu pbranchu force-pushed the feat/async-agent-delegation branch 2 times, most recently from 024c26a to e9c4e4a Compare March 27, 2026 23:15
@pbranchu
Copy link
Copy Markdown
Contributor Author

Update needed: channel-agnostic callback delivery

The current implementation delivers async delegation results via a voice-only channel (ASYNC_RESULT_TX). This works for voice sessions but silently drops results for Chat, Email, and all other channels.

Design and implementation plan in #891 — the fix routes callbacks through the channel bridge using the existing per-turn system prompt injection mechanism. Key changes:

  • Store minimal channel context (channel type, sender, thread) at delegation time
  • On completion, inject callback through BridgeManager::inject_callback()
  • Bridge applies channel overrides, system prompt, and routes response to the originating channel
  • Removes the voice-specific ASYNC_RESULT_TX side channel

Will update this PR with the fix.

@pbranchu pbranchu force-pushed the feat/async-agent-delegation branch from 16c7a72 to 77fe35c Compare March 28, 2026 09:53
@pbranchu pbranchu changed the title Add agent_send_async and agent_cancel tools for non-blocking delegation Add agent_send_async with channel-agnostic callback delivery Mar 28, 2026
Add asynchronous agent delegation via agent_send_async and agent_cancel
tools. When an agent delegates work asynchronously, the caller's channel
context (channel type, recipient, thread) is captured and stored so the
result can be delivered back to the originating channel when the delegate
finishes. This avoids blocking the caller's conversation during long-
running tasks.

Key changes:
- ChannelCallbackContext struct in openfang-types
- get/set_channel_context + inject_async_callback on KernelHandle trait
- agent_send_async / agent_cancel tools in tool_runner
- Channel bridge stores context before each send_message call
- Kernel implements inject_async_callback: sends result to agent, then
  delivers agent's response to the originating channel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pbranchu pbranchu force-pushed the feat/async-agent-delegation branch from 77fe35c to 2c69fa5 Compare March 28, 2026 13:18
MALFORMED_FUNCTION_CALL is a transient generation quality issue — the
model tried to call a tool but produced invalid JSON. Previously
classified as LlmError::Parse (non-retryable, fatal). Now classified
as LlmError::Overloaded (retryable) so the agent loop retries
automatically. This is especially important with large tool sets
where the model occasionally generates malformed calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pbranchu pbranchu force-pushed the feat/async-agent-delegation branch from 0ffe4b3 to f6aec42 Compare March 28, 2026 16:23
@pbranchu pbranchu force-pushed the feat/async-agent-delegation branch from f6aec42 to d21d77e Compare March 28, 2026 23:19
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.

agent_send_async: deliver callback results through channel bridge

2 participants