Skip to main content

Agent Connectivity

Every dispatch the mesh sends must reach your agent. Svantic supports two connectivity modes that you pick per-instance at registration time:
  • Connected (default) — your agent dials Svantic over a persistent WebSocket and the mesh pushes dispatches down that socket. Works anywhere outbound HTTPS/WSS works — behind firewalls, NATs, corporate egress-only networks, laptops, CI runners, or ephemeral containers without stable DNS. This is the default because it is table stakes for a great out-of-the-box experience.
  • Hosted — your agent exposes a public HTTPS surface the mesh calls into. Opt in when your agent already runs as an HTTP service on infrastructure that can accept inbound traffic and you want a pure request/response shape.
You choose once, per instance_id. Deployment mode is not a deploy-time topology concern (see Deployment Models for that) — it’s a statement about how the mesh reaches this particular instance. Two instances of the same agent type can use different modes.

Connected mode (default)

Connected mode: agent dials Svantic via WebSocket, dispatches pushed bidirectionally How it works. Connected mode is the default — you get it by calling new MeshConnector(agent, { svantic_url, client_id, client_secret }) with no deployment_mode set and no public_url. The edge routes the single svantic_url to the gateway for registration and to the mesh for dispatch — you never hardcode service-specific hosts. The gateway registration response carries back a connect_url; the SDK dials it immediately and keeps the WebSocket open for the agent’s lifetime. The mesh pushes dispatch frames down the socket; your agent pushes dispatch_result frames back. Full protocol details live in WebSocket API: agents/connect. When it’s right (almost always).
  • The agent runs behind a firewall, NAT, or a corporate proxy with no inbound exception.
  • The agent runs on a developer laptop, a CI runner, an ephemeral container, or any host without a stable DNS entry.
  • You want zero inbound exposure — outbound-only is a compliance win.
  • You want the easiest onboarding path: no ingress, no TLS cert, no reverse proxy.
What it costs.
  • One WebSocket per live instance. Idle connections still cost a pod-local file descriptor; plan capacity like you would SSE.
  • Reconnect semantics are the SDK’s responsibility. The SDK handles it automatically (bounded backoff, resume cursor, outbox replay) — your handler code is oblivious — but long-term disconnects will surface as AgentDisconnectedError on the caller.
  • The WebSocket JWT authenticates the transport (who opened the socket). Per-invocation authentication still flows through the dispatch_auth envelope; see Dispatch auth below.

Hosted mode

Hosted mode: Svantic sends HTTPS dispatch to agent, agent returns response How it works. Opt in by passing a public_url at registration (or setting deployment_mode: hosted explicitly). The gateway probes GET {public_url}/.well-known/agent-card.json to confirm the agent is reachable and publishing a valid card, then admits the instance. Every subsequent dispatch is an HTTPS POST from the mesh to {public_url}/send, authenticated per the dispatch_auth block you chose. When to pick it.
  • Your agent already runs as a long-lived HTTP service on infrastructure that accepts inbound traffic and you don’t want to hold a socket open.
  • You have an existing ingress, LB, or API gateway you want to reuse.
  • You prefer the simplest request/response mental model and control the infra on both sides.
Requirements.
  • Publicly reachable HTTPS URL (ingress through your own LB or API gateway is fine).
  • /.well-known/agent-card.json served at the root of that URL.
  • TLS terminated by you. The mesh will not call http:// endpoints.
Dispatch authentication. See the Dispatch auth section below — the same model applies to hosted and connected agents.

Dispatch auth

Regardless of transport, every dispatch carries a per-invocation authentication envelope when the mesh runs with SVANTIC_DISPATCH_AUTH_ENABLED=true. Three schemes:
  • svantic_jwt (default) — the mesh mints a short-lived HS256 JWT against its SIGNING_SECRET and the SDK verifies with the same secret. No per-agent credential management; rotating the secret rotates every agent.
  • shared_secret — you supply a raw secret at registration time under a vault:// reference. The mesh stores it encrypted, resolves it at dispatch time, and attaches it to the envelope; the SDK compares against its local copy. Use this when the agent must prove possession of an account-minted secret.
  • mtls — reserved, not implemented.
The envelope is fail-closed: if resolution fails (signing secret missing, vault unreachable, stale credentials_ref), the dispatch fails with AgentUnhealthyError and no frame reaches the agent. See Registering Agents — Dispatch Auth for the step-by-step setup and Mesh Security — Dispatch Auth for the security rationale.

Strict control plane / data plane split

Regardless of mode, these operations are always plain HTTPS calls to the gateway, never WebSocket:
  • POST /agents/register, POST /agents/deregister
  • POST /sessions/init
  • File uploads, knowledge ingestion, credential rotation
  • Any administrative action visible in the dashboard
The WebSocket carries only real-time messaging: dispatches, streaming chunks, status updates, heartbeats. This is a deliberate split so that the control plane remains inspectable, auditable, and version-skew tolerant — and so a dropped socket never loses control state.

Choosing a mode: quick guide

You have…Pick
A public HTTPS servicehosted
Corporate firewall, egress-only allowedconnected
Ephemeral containers (Fly, Vercel CI)connected
Kubernetes pod with Ingresshosted
Developer laptop for demosconnected
Agent that must be callable from outside Svantichosted
You can migrate an existing agent-type from one mode to another by registering a new instance_id with the target mode and draining traffic off the old one. Svantic rejects an in-place mode switch on the same instance_id with 409 DEPLOYMENT_MODE_MISMATCH.

Observability

Both modes populate the same last_dispatch_error snapshot on the instance detail — same status codes, same error taxonomy — so dashboards and alerts work uniformly regardless of transport. Trace context (W3C traceparent, baggage) also propagates identically: the SDK parses it off the dispatch payload and exposes it on CapabilitySessionContext whether the dispatch arrived via HTTPS or WebSocket.

Connection-state endpoints

The gateway exposes two read endpoints for live transport state:
  • POST /agents/get_connection — returns a unified envelope for one instance_id. Shape is identical for hosted and connected agents: the consumer switches on transport (callback vs. ws) and connection_status (online / healthy / degraded / offline / unknown).
  • POST /agents/get_connection_stats — returns fleet-wide aggregates grouped by deployment_mode, connection_status, and transport. Optional agent_type filter.
The dashboard uses these endpoints to display agent health panels.

Events

The mesh emits transport-lifecycle events in real time so dashboards update without polling:
  • agent.connected — WebSocket upgrade accepted.
  • agent.disconnected — WebSocket closed.
Time-based transitions (stale heartbeat → unhealthy) remain the reaper’s job. See Agent Health for the full split and the status value catalog.

Metrics

Every mesh pod exposes GET /metrics in Prometheus exposition format with per-transport dispatch counters, WebSocket-connection gauges, inter-pod routing latency, and event-loop lag. Per-instance state is deliberately not labeled on /metrics — use the connection endpoints above for that. See the API documentation for the full metrics schema.

See also