6.11. Handoff Client¶
The Handoff Client talks to the sw4rm.handoff.HandoffService service. Use it to:
- Request agent-to-agent handoffs with context snapshots.
- Accept or reject pending handoffs.
- Query pending handoffs and handoff status.
- Mark handoffs complete (Python/Rust SDKs).
6.11.1. Service Overview¶
The service exposes five RPCs:
RequestHandoff(HandoffRequest) -> EmptyAcceptHandoff(HandoffResponse) -> EmptyRejectHandoff(HandoffResponse) -> EmptyGetPendingHandoffs(GetPendingHandoffsRequest) -> GetPendingHandoffsResponseCompleteHandoff(CompleteHandoffRequest) -> CompleteHandoffResponse
Current SDKs provide an in-memory implementation for development and testing.
HandoffStatus values¶
| Value | Description |
|---|---|
PENDING | Awaiting acceptance or rejection |
ACCEPTED | Accepted by the target agent |
REJECTED | Rejected by the target agent |
COMPLETED | Completed by the receiving agent |
EXPIRED | Timed out before acceptance |
HandoffRequest fields¶
| Field | Type | Description |
|---|---|---|
request_id | string | Request identifier (JS/TS supplies this; Rust generates it) |
from_agent | string | Initiating agent ID |
to_agent | string | Target agent ID (may be empty for capability routing) |
reason | string | Human-readable reason |
context_snapshot | bytes | Serialized context for the receiving agent |
capabilities_required | list[string] | Required capabilities for the target agent |
priority | int | Priority (lower is higher priority) |
timeout | duration | Timeout for acceptance (optional) |
HandoffResponse fields¶
| Field | Type | Description |
|---|---|---|
request_id | string | Request identifier being responded to |
accepted | bool | Whether the handoff was accepted |
accepting_agent | string | Agent that accepted the handoff |
rejection_reason | string | Reason for rejection (if any) |
GetPendingHandoffsResponse fields¶
| Field | Type | Description |
|---|---|---|
pending_requests | list[HandoffRequest] | Pending requests for the agent |
CompleteHandoffResponse fields¶
| Field | Type | Description |
|---|---|---|
success | bool | Whether the completion was recorded |
message | string | Optional message on completion |
6.11.2. Constructors¶
Python¶
HandoffClient(channel: grpc.Channel | None = None)
channel: Optional gRPC channel. If omitted, uses in-memory storage.
JavaScript/TypeScript¶
new HandoffClient()
- In-memory client (no gRPC options yet).
Rust¶
HandoffClient::new() -> HandoffClient
6.11.3. Key Methods¶
request_handoff / requestHandoff¶
Python request_handoff(request: HandoffRequest) -> HandoffResponse
JavaScript/TypeScript requestHandoff(request: HandoffRequest): Promise<HandoffResponse>
Rust request_handoff(&self, request: HandoffRequest) -> Result<HandoffResponse>
Note: The underlying gRPC proto returns Empty; SDK clients wrap this into a HandoffResponse with accepted=True and status=PENDING for convenience.
accept_handoff / acceptHandoff¶
Python accept_handoff(handoff_id: str) -> HandoffResponse
JavaScript/TypeScript acceptHandoff(handoffId: string): Promise<void>
Rust accept_handoff(&self, handoff_id: &str) -> Result<()>
reject_handoff / rejectHandoff¶
Python reject_handoff(handoff_id: str, reason: str) -> HandoffResponse
JavaScript/TypeScript rejectHandoff(handoffId: string, reason: string): Promise<void>
Rust reject_handoff(&self, handoff_id: &str, reason: &str) -> Result<()>
complete_handoff¶
Python complete_handoff(handoff_id: str) -> HandoffResponse
Rust complete_handoff(&self, handoff_id: &str) -> Result<()>
get_pending_handoffs / getPendingHandoffs¶
Python get_pending_handoffs(agent_id: str) -> list[HandoffRequest]
JavaScript/TypeScript getPendingHandoffs(agentId: string): Promise<HandoffRequest[]>
Rust get_pending_handoffs(&self, agent_id: &str) -> Result<Vec<HandoffRequest>>
get_handoff_status / getHandoffResponse¶
Python get_handoff_status(handoff_id: str) -> HandoffResponse | None
JavaScript/TypeScript getHandoffResponse(handoffId: string): Promise<HandoffResponse | null>
Rust get_handoff_status(&self, handoff_id: &str) -> Result<Option<HandoffResponse>>
clear_all_handoffs¶
Python clear_all_handoffs() -> None (static, testing only)
Rust clear_all_handoffs(&self) -> Result<()>
6.11.4. Usage Examples¶
from sw4rm.clients import HandoffClient
from sw4rm.handoff.types import HandoffRequest
client = HandoffClient()
request = HandoffRequest(
from_agent="agent-a",
to_agent="agent-b",
reason="Need code review",
capabilities_required=["code_review"],
)
response = client.request_handoff(request)
print(response.handoff_id, response.status)
pending = client.get_pending_handoffs("agent-b")
if pending:
accepted = client.accept_handoff(response.handoff_id)
client.complete_handoff(accepted.handoff_id)
import { HandoffClient } from '@sw4rm/js-sdk';
const client = new HandoffClient();
const responsePromise = client.requestHandoff({
requestId: 'handoff-123',
fromAgent: 'agent-a',
toAgent: 'agent-b',
reason: 'Need code review',
contextSnapshot: new TextEncoder().encode('{"state":"in_progress"}'),
capabilitiesRequired: ['code_review'],
priority: 5,
});
const pending = await client.getPendingHandoffs('agent-b');
if (pending.length > 0) {
await client.acceptHandoff(pending[0].requestId);
}
const response = await responsePromise;
console.log(response.accepted, response.rejectionReason);
use sw4rm_sdk::clients::handoff::{HandoffClient, HandoffRequest};
let client = HandoffClient::new();
let request = HandoffRequest::new(
"agent-a".to_string(),
"agent-b".to_string(),
"Need code review".to_string(),
)
.with_capabilities(vec!["code_review".to_string()])
.with_priority(5);
let response = client.request_handoff(request)?;
let pending = client.get_pending_handoffs("agent-b")?;
if !pending.is_empty() {
client.accept_handoff(&response.handoff_id)?;
client.complete_handoff(&response.handoff_id)?;
}
Working Examples¶
For complete runnable examples demonstrating Handoff usage:
6.11.5. Error Handling¶
- Python raises
RuntimeErrorif a gRPC stub is configured but unavailable. - Python raises
ValueErrorfor missing handoff IDs or invalid state transitions. - JavaScript/TypeScript throws
HandoffValidationErrorfor invalid requests andHandoffTimeoutErrorwhen a request times out. - Rust returns
Error::Configfor invalid state transitions andError::Internalfor storage lock failures.