Targeted Routing¶
Targeted routing enables direct agent-to-agent communication, bypassing the discovery and auction system.
Why Targeted Routing?¶
In a mature agent economy:
- 90% of transactions are repeat business (you → your dentist)
- Broadcasting every request is inefficient and leaks privacy
- Direct routing is faster (no auction delay)
Use targeted routing when:
- You have a preferred agent
- You need guaranteed routing to a specific agent
- You're building agent-to-agent pipelines
- Privacy matters (don't broadcast your intent)
How It Works¶
Default: Broadcast Discovery¶
sequenceDiagram
participant User
participant Coordinator
participant Registry
participant AgentA
participant AgentB
User->>Coordinator: Publish workflow
Coordinator->>Registry: Find agents for cap.text.summarize.v1
Registry-->>Coordinator: [AgentA, AgentB, ...]
Coordinator->>AgentA: Auction bid request
Coordinator->>AgentB: Auction bid request
Note over Coordinator: Select winner
Coordinator->>AgentA: Dispatch work
Targeted: Direct Dispatch¶
sequenceDiagram
participant User
participant Coordinator
participant AgentA
User->>Coordinator: Publish workflow (targetAgentId: AgentA)
Coordinator->>AgentA: Dispatch work (direct)
AgentA-->>Coordinator: Result
No discovery. No auction. Direct dispatch.
Usage¶
Workflow Node¶
{
"nodes": {
"summarize": {
"capability": "cap.text.summarize.v1",
"targetAgentId": "did:noot:abc123...",
"allowBroadcastFallback": false
}
}
}
Fields¶
| Field | Type | Default | Description |
|---|---|---|---|
targetAgentId |
string? |
null |
DID of the agent to route to |
allowBroadcastFallback |
boolean |
false |
Fall back to discovery if target unavailable |
Behavior Matrix¶
| targetAgentId | Agent Status | allowBroadcastFallback | Result |
|---|---|---|---|
| Not set | - | - | Normal broadcast discovery |
| Set | Available | - | Direct dispatch |
| Set | Unavailable | false |
FAIL with AGENT_UNAVAILABLE |
| Set | Unavailable | true |
Fall back to broadcast |
Example: Fail Fast¶
When you need a specific agent (no substitutes):
{
"intent": "Get summary from my trusted agent",
"nodes": {
"summarize": {
"capability": "cap.text.summarize.v1",
"targetAgentId": "did:noot:my-trusted-summarizer",
"allowBroadcastFallback": false
}
}
}
If the agent is offline:
{
"status": "failed",
"error": "AGENT_UNAVAILABLE",
"details": {
"targetAgentId": "did:noot:my-trusted-summarizer",
"reason": "agent_offline"
}
}
Example: Prefer with Fallback¶
When you have a preference but any agent will do:
{
"intent": "Summarize with preferred agent",
"nodes": {
"summarize": {
"capability": "cap.text.summarize.v1",
"targetAgentId": "did:noot:preferred-agent",
"allowBroadcastFallback": true
}
}
}
If preferred agent is offline → falls back to normal discovery.
Use Cases¶
1. Private Agent Networks¶
Run agents that only talk to each other:
{
"nodes": {
"internal_process": {
"capability": "cap.internal.process.v1",
"targetAgentId": "did:noot:my-internal-agent"
},
"internal_validate": {
"capability": "cap.internal.validate.v1",
"targetAgentId": "did:noot:my-validator",
"dependsOn": ["internal_process"]
}
}
}
2. Vendor Lock-in (By Choice)¶
Always use your preferred LLM provider:
{
"nodes": {
"generate": {
"capability": "cap.text.generate.v1",
"targetAgentId": "did:noot:my-gpt4-agent"
}
}
}
3. Testing¶
Route to a test agent during development:
{
"nodes": {
"test_node": {
"capability": "cap.anything.v1",
"targetAgentId": "did:noot:my-mock-agent"
}
}
}
4. Agent Pipelines¶
Chain agents that know about each other:
{
"nodes": {
"step1": {
"capability": "cap.pipeline.step1.v1",
"targetAgentId": "did:noot:pipeline-step1"
},
"step2": {
"capability": "cap.pipeline.step2.v1",
"targetAgentId": "did:noot:pipeline-step2",
"dependsOn": ["step1"]
},
"step3": {
"capability": "cap.pipeline.step3.v1",
"targetAgentId": "did:noot:pipeline-step3",
"dependsOn": ["step2"]
}
}
}
Error Handling¶
AGENT_UNAVAILABLE¶
Returned when:
- Agent not found in registry
- Agent marked as inactive
- Agent health status is
unhealthy - Agent hasn't sent heartbeat recently
Detail Codes¶
| Code | Meaning |
|---|---|
agent_not_found |
DID not in registry |
agent_inactive |
Agent deactivated |
agent_unhealthy |
Health check failing |
agent_offline |
No recent heartbeat |
Best Practices¶
1. Store Agent DIDs¶
Keep a mapping of your preferred agents:
const AGENTS = {
summarizer: "did:noot:abc123",
generator: "did:noot:def456",
validator: "did:noot:ghi789",
};
2. Health Monitoring¶
Before routing, check if agent is healthy:
3. Graceful Degradation¶
For critical paths, use fallback:
4. Retry Logic¶
On AGENT_UNAVAILABLE, consider:
- Waiting and retrying
- Trying a backup agent
- Falling back to broadcast
Future: Agent-to-Agent Direct¶
Coming in NIP-0030:
// Agent A calls Agent B directly
const result = await agentB.invoke({
capability: "cap.text.translate.v1",
inputs: { text: "Hello", targetLang: "es" }
});
This will enable fully decentralized agent communication without coordinator involvement.