gRPC Transport
Open Astra includes an optional gRPC sidecar that runs alongside the main HTTP gateway on a separate port. It exposes the same agent loop, spawn, and health-check capabilities over gRPC — useful for inter-service communication in microservice deployments or when you need low-latency binary transport between services.
GRPC_ENABLED=true to start it alongside the HTTP gateway. Service definition
The AgentService is defined in src/grpc/protos/agent.proto and provides four RPCs.
service AgentService {
rpc RunAgentLoop (AgentRequest) returns (AgentResponse);
rpc RunAgentLoopStream (AgentRequest) returns (stream StreamEvent);
rpc SpawnAgent (SpawnRequest) returns (SpawnResponse);
rpc HealthCheck (Empty) returns (HealthResponse);
}| RPC | Type | Description |
|---|---|---|
RunAgentLoop | Unary | Runs the full agent loop and returns the final response, session ID, and token usage |
RunAgentLoopStream | Server streaming | Streams events as the agent works — deltas, tool calls, tool results, and completion |
SpawnAgent | Unary | Delegates a task to a sub-agent and returns its response |
HealthCheck | Unary | Returns { status: "ok", timestamp } |
Message types
message AgentRequest {
string uid = 1;
string message = 2;
string agent_id = 3;
string surface = 4;
string surface_id = 5;
string session_id = 6;
}
message SpawnRequest {
string uid = 1;
string parent_agent_id = 2;
string target_agent_id = 3;
string task = 4;
int32 depth = 5;
}
message AgentResponse {
string content = 1;
string session_id = 2;
TokenUsage usage = 3;
}
message SpawnResponse {
string task_id = 1;
string target_agent_id = 2;
string content = 3;
bool success = 4;
int32 duration_ms = 5;
string session_id = 6;
}
message StreamEvent {
string type = 1; // session_resolved | stream_delta | tool_call_start
string data = 2; // tool_call_complete | tool_result | completed | error
}Stream event types
RunAgentLoopStream emits the following event types in order.
| Type | When |
|---|---|
session_resolved | Session found or created |
stream_delta | Each chunk of the agent's response text |
tool_call_start | Agent begins a tool call |
tool_call_complete | Tool call arguments fully received |
tool_result | Tool execution finished (includes duration) |
completed | Agent loop finished — final content and usage |
error | An error occurred during the loop |
Configuration
# Enable the gRPC sidecar (default: false)
GRPC_ENABLED=true
GRPC_PORT=50051 # default: 50051
# mTLS — provide all three for mutual TLS
GRPC_TLS_CERT=/path/to/server.crt
GRPC_TLS_KEY=/path/to/server.key
GRPC_TLS_CA=/path/to/ca.crt| Variable | Default | Purpose |
|---|---|---|
GRPC_ENABLED | false | Enable the gRPC sidecar |
GRPC_PORT | 50051 | Listen port |
GRPC_TLS_CERT | — | Path to TLS certificate chain |
GRPC_TLS_KEY | — | Path to TLS private key |
GRPC_TLS_CA | — | Path to CA certificate for mTLS |
Mutual TLS (mTLS)
When all three TLS environment variables are set, the server starts with mutual TLS — both the server and client must present valid certificates signed by the same CA. If any variable is missing, the server falls back to insecure (plaintext) transport.
Client usage
Open Astra exports a typed client for internal use (e.g., from agent spawn logic or external orchestrators).
import { createGrpcAgentClient } from './grpc/client.js'
const client = createGrpcAgentClient('localhost:50051')
// Unary call
const response = await client.runAgentLoop({
uid: 'user-123',
message: 'Summarize the latest research',
agentId: 'researcher',
surface: 'api',
surfaceId: 'grpc-test'
})
// Server-streaming call
const stream = client.runAgentLoopStream({
uid: 'user-123',
message: 'Analyze this codebase',
agentId: 'coder',
surface: 'api',
surfaceId: 'grpc-stream'
})
for await (const event of stream) {
console.log(event.type, event.data)
}How it integrates
The gRPC handlers call the same internal functions as the HTTP gateway — runAgentLoop, spawnAgent, getAgentConfig, and getInferenceClientForAgent. There is no separate code path. The gRPC layer is a thin transport wrapper.
- The gateway starts the gRPC server after HTTP is listening (conditional on
GRPC_ENABLED) - Graceful shutdown calls
tryShutdown()with a forced fallback after timeout - Proto files are loaded at runtime relative to the source directory — works in both
tsx(dev) and compileddist/