Clients
In Naylence, clients are not second-class citizens.
A client is simply code running on a node that initiates interactions with other agents. That same client node can also:
- listen for incoming envelopes,
- handle streaming (sending/receiving incremental responses),
- and host local agents or handlers when that makes sense.
This is why a browser client still “counts” as part of the fabric: it runs on a node, participates in routing, and can both send and receive messages.
The difference between “client” and “agent” is usually role, not capability:
- client role: start a request, drive a workflow, present results.
- agent role: provide an addressable capability (tool/service/worker) that others call.
In many systems the same process can do both.
Ways to Connect
There are two ways to interact with agents in the Naylence fabric:
| Approach | Best For |
|---|---|
| SDK Clients | Native apps, microservices, browser SPAs — full fabric features |
| HTTP Gateway | External integrations, scripts, webhooks — simple HTTP calls |
SDK Clients
SDK clients use the Naylence SDK (@naylence/agent-sdk or naylence-agent-sdk) to connect to the fabric. They run on a node and participate fully in the fabric protocol.
How SDK Clients Work
- Create a client node with
CLIENT_CONFIGor custom configuration - Connect to a sentinel (or run standalone)
- Use proxy objects to invoke remote agents
- Receive responses, including streaming data
import { Client, Agent, CLIENT_CONFIG } from '@naylence/agent-sdk';
// Define the remote agent interface
class GreeterAgent extends Agent {
async greet(name: string): Promise<string> {
return ''; // Implemented remotely
}
}
// Create and start a client
const client = new Client(CLIENT_CONFIG);
await client.start();
// Get a proxy to the remote agent
const greeter = Agent.remoteByAddress(GreeterAgent, 'greeter@fame.fabric', client);
// Invoke the remote method
const result = await greeter.greet('World');
console.log(result); // "Hello, World!"
await client.stop();from naylence.agent import Client, Agent, CLIENT_CONFIG
# Define the remote agent interface
class GreeterAgent(Agent):
async def greet(self, name: str) -> str:
return "" # Implemented remotely
# Create and start a client
client = Client(CLIENT_CONFIG)
await client.start()
# Get a proxy to the remote agent
greeter = Agent.remote_by_address(GreeterAgent, "greeter@fame.fabric", client)
# Invoke the remote method
result = await greeter.greet("World")
print(result) # "Hello, World!"
await client.stop()SDK Client Capabilities
- RPC (request/response) — Call agent methods and get results
- Streaming — Receive incremental responses as they’re generated
- Bidirectional messaging — Send and receive messages asynchronously
- Routing participation — Your client can be addressed by other nodes
- Event subscriptions — React to fabric events
- Local agents — Host your own agents alongside client code
HTTP Gateway Clients
The Agent HTTP Gateway provides a simple REST API for invoking agents. It requires no SDK—any HTTP client works (curl, fetch, requests, etc.).
The HTTP Gateway is provided by the AgentHttpGatewayListener. See Listeners for configuration details.
Enabling the Gateway
The gateway is disabled by default. Enable it via environment variable:
export FAME_LISTENER_AGENT_HTTP_GATEWAY_ENABLED=trueGateway Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/fame/v1/gateway/rpc | POST | Synchronous RPC invocations |
/fame/v1/gateway/messages | POST | Fire-and-forget message delivery |
/fame/v1/gateway/health | GET | Health check |
RPC Requests
Send a POST request with JSON body:
curl -X POST http://localhost:8000/fame/v1/gateway/rpc \
-H "Content-Type: application/json" \
-d '{
"targetAddr": "greeter@fame.fabric",
"method": "greet",
"params": {"name": "World"}
}'Response:
{"ok": true, "result": "Hello, World!"}RPC Request Format
| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | The agent method to invoke |
targetAddr | string | One of these | Direct address of the agent (e.g., greeter@fame.fabric) |
capabilities | string[] | One of these | Discover agent by capabilities |
params | object | No | Method parameters as key-value pairs |
timeoutMs | number | No | Request timeout in milliseconds (default: 30000, max: 120000) |
By address:
{
"targetAddr": "math@fame.fabric",
"method": "add",
"params": {"x": 5, "y": 3}
}By capabilities:
{
"capabilities": ["math", "calculator"],
"method": "add",
"params": {"x": 5, "y": 3}
}Message Requests
Send fire-and-forget messages:
curl -X POST http://localhost:8000/fame/v1/gateway/messages \
-H "Content-Type: application/json" \
-d '{
"targetAddr": "logger@fame.fabric",
"type": "log.info",
"payload": {"message": "User logged in", "userId": "123"}
}'Response:
{"status": "message_accepted"}Message Request Format
| Field | Type | Required | Description |
|---|---|---|---|
targetAddr | string | One of these | Direct address of the agent |
capabilities | string[] | One of these | Discover agent by capabilities |
type | string | No | Message type identifier |
payload | any | No | Message payload (any JSON value) |
Authentication
If the sentinel uses security profiles, include the Authorization header:
curl -X POST http://localhost:8000/fame/v1/gateway/rpc \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{"targetAddr": "agent@fame.fabric", "method": "doSomething"}'Error Responses
The gateway returns structured error responses:
{"ok": false, "error": "No route to agent@fame.fabric", "code": "not_found"}| HTTP Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed request body |
| 401 | unauthorized | Authentication failed |
| 403 | forbidden | Not authorized for this operation |
| 404 | not_found | No route to target agent |
| 429 | queue_full | Agent is overloaded (back pressure) |
| 504 | timeout | Request timed out |
| 503 | — | Node not initialized |
JavaScript/TypeScript Example
async function invokeAgent(method: string, params: Record<string, any>) {
const response = await fetch('http://localhost:8000/fame/v1/gateway/rpc', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
targetAddr: 'math@fame.fabric',
method,
params,
}),
});
const data = await response.json();
if (!data.ok) {
throw new Error(data.error);
}
return data.result;
}
// Usage
const sum = await invokeAgent('add', { x: 5, y: 3 });
console.log(sum); // 8Python Example
import requests
def invoke_agent(method: str, params: dict):
response = requests.post(
"http://localhost:8000/fame/v1/gateway/rpc",
json={
"targetAddr": "math@fame.fabric",
"method": method,
"params": params,
},
)
data = response.json()
if not data.get("ok"):
raise Exception(data.get("error"))
return data["result"]
# Usage
result = invoke_agent("add", {"x": 5, "y": 3})
print(result) # 8Feature Comparison
| Feature | SDK Client | HTTP Gateway |
|---|---|---|
| RPC (request/response) | âś… | âś… |
| Streaming responses | ✅ | ❌ |
| Bidirectional messaging | ✅ | ❌ |
| Fire-and-forget messages | âś… | âś… |
| Routing participation | ✅ | ❌ |
| Event subscriptions | ✅ | ❌ |
| Host local agents | ✅ | ❌ |
| Connection persistence | ✅ | ❌ |
| No SDK required | ❌ | ✅ |
| Works with any HTTP client | ❌ | ✅ |
Choosing the Right Approach
Use SDK Clients when:
- You need streaming responses (e.g., LLM token-by-token output)
- You need bidirectional real-time communication
- Your app will host agents alongside client code
- You want full routing capabilities (your client can be addressed)
- You’re building a native application or microservice
- You’re using React or Vue with the Naylence integrations
Use HTTP Gateway when:
- Integrating from systems that only support HTTP (webhooks, CI/CD pipelines, cron jobs)
- Writing quick scripts or debugging with curl
- Building serverless functions that invoke agents
- You don’t need streaming or real-time features
- You want the simplest possible integration
- The calling system is outside your control (third-party integrations)
The HTTP Gateway is stateless—each request is independent. For long-running conversations or stateful interactions, consider using the SDK client or managing state within your agents.
See Also
- Listeners — Configure the Agent HTTP Gateway Listener
- Agent API Reference — Complete SDK client documentation
- Configuration — Environment variables for client configuration