Bring your own agent
Your agent can keep running where it runs today, whether you built it with Flue, the Cloudflare Agents SDK, the Vercel AI SDK, LangGraph, the OpenAI Agents SDK, Mastra, OpenClaw, Hermes, Pi, or your own loop. Runtype adds the Runs view, Logs, trace trees, cost estimates, eval capture, the Persona chat widget, surfaces, and the trace-to-eval improvement loop.
This page maps the three ways to connect an agent. You can use more than one of them for the same agent.
Choose how to connect your agent
The following table lists the three options, what you do for each, and what each one gives you:
What each option gives you
Capturing a run as an eval case needs a transcript on the run. Re-running an eval suite needs Runtype to be able to call the agent. The following table compares the first two options feature by feature:
Before you begin
To set up the agent and a telemetry API key in one place, click
New > Connect an agent in the dashboard. The Connect an agent page
opens. Inside a product, the agent joins that product when its first run
arrives. In a workspace with no agents, the page creates the agent and a test
key for you. Otherwise, you pick or create the agent on that page. If you
choose Your coding agent, its setup prompt requests the key and you approve
the request in the browser. If you choose Yourself, you create the key in
the Add your key step, and the page fills the agent ID and key into an
environment block. For OpenClaw, Hermes, and Pi, set those variables on the agent
process, not in your project’s .env file.
To set them up separately, complete these steps:
- Create an agent to own the runs. Runtype files ingested traces under a
Runtype agent ID. Any agent works as an attribution target. To let Runtype
call the agent, create it as an
externalagent instead. Copy theagent_...ID from the agent’s page or from thelist_agentstool. - Create a telemetry API key. On the Settings > API Keys page, choose the
Telemetry Ingest permission group (
TELEMETRY:WRITE, append-only). Keys withAGENTS:WRITEalso work. For the steps, see Create a telemetry API key.
Send telemetry to Runtype
Pick the section that matches how your agent is built and where it runs.
Flue on Cloudflare Workers, no code
Workers Observability traces Flue 2 agents deployed with @flue/vite and
@cloudflare/vite-plugin automatically. It emits an invoke_agent span per
run, a chat span per model turn, and an execute_tool span per tool call.
The spans follow the OpenTelemetry GenAI semantic conventions and include
conversation content by default.
Exporting Workers traces to an OTLP destination requires a Workers Paid plan.
To export those traces to Runtype, follow these steps:
-
In the Cloudflare dashboard, open Workers Observability and add a destination of type Traces.
-
Set the destination endpoint to
https://api.runtype.com/v1/otel/v1/traces. -
Add the custom header
Authorizationwith the valueBearer rt_YOUR_TELEMETRY_KEY. -
Add the custom header
x-runtype-agent-idwith the valueagent_YOUR_AGENT_ID.Replace the following:
rt_YOUR_TELEMETRY_KEY: your telemetry API keyagent_YOUR_AGENT_ID: the ID of the Runtype agent that owns the runs
-
Reference the destination in
wrangler.jsoncand sample every request while you iterate:wrangler.jsonc -
Build and deploy (
npx vite build && npx wrangler deploy), then run one conversation. The run appears under the agent’s Runs with a transcript, so you can capture it as an eval case.
To keep prompts and tool payloads out of the export, register
instrument(createCloudflareTracing({ content: false })) from
@flue/runtime/cloudflare at module scope in app.ts. This also removes the
transcript, and with it eval capture.
For a Cloudflare Agents SDK agent, wrap the AI SDK with wrapAISDK and export
through the same kind of Workers Observability destination. For the setup, see
Cloudflare Agents SDK.
A separate Cloudflare Agents SDK adapter, @runtypelabs/cloudflare-agents, is
in beta and published to npm. It adds durable delivery from your own Worker.
For its setup, see
Cloudflare Agents SDK adapter.
Flue on Node, Cloud Run, or another host
Flue’s instrument() accepts either of two instrumentations. Point exactly one
of them at Runtype. Both emit an invoke_agent span per run, so exporting both
to the same endpoint doubles token counts and cost.
The following table compares the two instrumentations:
Both need your application to own the OpenTelemetry SDK and exporter. The full pipeline, attribution options, and flush rules are in Instrumenting a Flue agent.
Any OpenTelemetry-instrumented agent
Use the stock exporter settings. Runtype accepts OTLP over HTTP, not gRPC:
Runtype reads invoke_agent, chat, and execute_tool spans anywhere in the
trace (an enclosing HTTP server span is fine) and the GenAI content attributes
for the transcript. For details, attribution precedence, and the JSON
compatibility endpoint, see
Reporting telemetry from an external agent.
Let Runtype call your agent
The agent’s endpoint must be a public HTTPS URL. Runtype rejects http: URLs,
localhost, and private IP addresses. To test an agent that runs on your
machine, expose it through a tunnel, such as Cloudflare Tunnel or ngrok, and
register the tunnel URL.
Set protocol to runtype-stream for an endpoint that streams Runtype events.
Omit protocol for an endpoint that speaks A2A JSON-RPC.
Register the agent
To register an A2A agent in the dashboard, go to the Agents page, click New agent, and choose A2A Agent. The Connect A2A Agent form takes an optional agent card URL, the agent name, and the A2A endpoint URL. After you click Connect Agent, set the framework and authentication on the agent’s page.
The dashboard form has no protocol setting. To register a runtype-stream
agent, send a POST /v1/agents request or use the MCP create_agent tool,
which takes the same fields as agent_type and external_config. The following
request body registers a Flue agent:
The following table describes the externalConfig fields:
For an A2A agent, Runtype fetches the agent card when you register the agent.
The agent must serve its card at /.well-known/agent-card.json on the
endpoint’s origin, or you must set agentCardUrl.
Connect an agent from the dashboard
On the Connect an agent page, the Flue, AI SDK, LangGraph, OpenAI Agents SDK, Mastra, Cloudflare Agents, and Any OTel source chips support an A2A connection over a public URL or a local listener. OpenClaw, Hermes, and Pi support telemetry only. The call setup includes the telemetry setup, so Runtype also receives the agent’s runs.
Framework selection does not convert a native framework API into A2A. If your agent has no A2A server, add the SDK adapter. Mastra serves A2A itself and needs no adapter.
To let Runtype call the agent, follow these steps:
- Select your framework. Under What you want, keep Let Runtype call it.
- Under Who sets it up, select Your coding agent or Yourself.
With Your coding agent, the setup prompt also has the coding agent add
the A2A adapter and run
runtype devices listenon your machine. With Yourself, copy the blocks in the Add the adapter step. - In Where it runs, select On this machine or Public URL. Only you can test against your machine. Flows, surfaces, and schedules need a public URL.
- In Endpoint, enter the A2A endpoint. The page derives the agent card URL from it. To change the agent card URL, click Edit.
- For On this machine, select the computer that runs the agent in Listener. If exactly one listener is online, the page selects it. For Public URL, use HTTPS. If your server requires a bearer token, enter it in Bearer token.
- Click Test. The result lists the agent’s Name, Skills, Responses, and Auth.
- Click Connect agent. The button appears only after a test succeeds.
If the receiving agent is an external agent or has no model or system prompt,
connecting converts it in place. Runtype never converts a configured Runtype
agent. It creates a separate external agent with the same name instead.
Add an A2A adapter
For a JavaScript or TypeScript agent, createA2AHandler from @runtypelabs/sdk
provides an A2A 0.3 Agent Card and a buffered text-call endpoint. On the
Connect an agent page, the Add the adapter step shows a JavaScript
adapter and its install command for each framework. The adapter does not start
or control a terminal session.
Install the SDK and a Node HTTP server in your agent project:
Wrap your existing agent function in a request handler:
Replace runAgent with your application’s function. It must return a string or
a promise of a string. Start the file with your project’s TypeScript runner.
The endpoint is http://127.0.0.1:4111/a2a and the Agent Card URL is
http://127.0.0.1:4111/.well-known/agent-card.json.
Use the callback that matches your framework:
These callbacks use JavaScript SDKs. A Python agent needs an A2A server in its own process. LangGraph Agent Server provides A2A endpoints. Mastra’s A2A server also provides its own endpoint and Agent Card.
The handler passes the incoming message, request metadata, contextId, and
request abort signal to your callback. It stores no conversation history.
For multi-turn conversations, configure your framework’s persistent session or
checkpointer using contextId. The AI SDK and OpenAI examples are single-turn
until you add that storage. With Flue, cancellation stops waiting for a reply;
it does not stop an already dispatched durable run.
For public deployment, set url to your HTTPS endpoint and authenticate POST
requests before they reach the handler. Keep the basic Agent Card public so
Runtype can discover it. Authorize access to each conversation ID in
your application. The adapter does not authenticate requests or authorize
conversations. The request body limit is 1 MiB by default. Streaming, task
lookup, task resumption, and push notifications require a fuller A2A server,
such as the official A2A JavaScript SDK.
Connect a local agent
Start your Mastra agent with its A2A endpoint available on
http://127.0.0.1:4111. Authenticate the CLI to the same account and workspace
you use in the dashboard.
An API key used by the listener needs DEVICES:WRITE to pair and DEVICES:READ
to verify an existing device. An API key that registers or calls the agent also
needs DEVICES:EXECUTE, alongside the relevant agent permissions.
Keep a terminal open with the listener running:
The command prints a device ID. It forwards calls to the specified loopback port without publishing a public URL. Stopping the command disconnects the listener. Changing accounts or workspaces creates a separate device identity.
On the Connect an agent page, select your framework, then On this
machine in Where it runs. Enter the local A2A endpoint, for example
http://127.0.0.1:4111/api/a2a/supportAgent for Mastra. The endpoint and the
agent card URL must use the same loopback origin and port. In Listener,
select the listener with the device ID that the command printed. Only online
listeners with HTTP forwarding appear. Click Test, then click Connect
agent. The test fetches the agent card through the listener. To do the same
through the API, send POST /v1/agents/fetch-agent-card with the card url,
"transport": "device", and the deviceId.
For API registration, send the device ID with the Mastra endpoint and discovery URL:
Replace YOUR_API_KEY with your Runtype API key and YOUR_DEVICE_ID with the
printed device ID. Replace supportAgent in both URLs with your Mastra agent ID.
If the agent requires authentication, include externalConfig.auth as in the
public endpoint example.
For organization-owned agents, use the listener for direct calls authenticated
as the device owner. Flow runs, MCP capability execution, channels, and schedules
do not carry that device authority. Use Public URL with an HTTPS origin for
those runs. Public connections use transport: "http" and do
not need a device ID. Device transport supports only A2A; the runtype-stream
protocol requires a public connection. Local device connections return buffered A2A responses
even when the agent advertises streaming.
Changing the selected device or transport requires submitting authentication again. If a call ends without confirmation, check the local agent before manually retrying an action that changes data.
Implement a runtype-stream endpoint
Runtype sends POST {endpoint} with a JSON body and reads a
text/event-stream response. The request body has these fields:
messages: the full conversation history, as{ "role", "content" }objects, on every call.context.conversationId: present only when the run has a conversation ID.metadata: an object that includessourceandagentId.
The response must follow these rules:
- The first frame is
execution_start. - Text and tool frames come next.
- The last frame is one terminal
execution_completeorexecution_error. Set its optionaloutcomefield tocompleted,error, oraborted. - Each frame’s SSE
id:equals its 0-basedseq.
The event schemas are the ExecutionStreamEvent union in the
API reference. It is the same stream that the Runtype API
emits for its own agents.
A Flue agent needs one route. Run the turn with
init(agent, { id: conversationId }) and handle.dispatch(message). Then map
each chunk that handle.read(receipt, { onEvent }) delivers onto the matching
frame. Because the Flue session already keeps its history under
conversationId, dispatch only the last user message in messages, not the
whole array.
Call Hermes over A2A
The Connect an agent page sets up telemetry for Hermes. Hermes also serves
A2A itself when its a2a gateway platform is enabled, by default on port
9900 with its agent card at /.well-known/agent-card.json. Register that
endpoint as an A2A agent, or reach it on your machine through
runtype devices listen.
Before you register it, set the following on the Hermes gateway process:
A2A_BEARER_TOKEN: enter the same token as the agent’s bearer token in Runtype. Without a token, Hermes accepts calls from localhost only.A2A_MAX_PINGPONG_TURNS=20: Runtype sends the same A2AcontextIdon every turn of a conversation, so Hermes keeps its session. Hermes counts the turns in each context as loop protection and, by default, rejects the sixth turn.20is the highest value Hermes accepts.
Hermes resets the count after a conversation is idle for an hour. A busier
conversation fails at turn 21 with Anti-loop protection: context ... exceeded 20 turns. Start a new conversation to continue.
Use the registered agent
After you register the agent, you can test it from its dashboard page, the MCP
execute_agent tool, or the SDK. You can also add it to a product as a
capability (Adding capabilities to a product)
or embed it in a Persona chat widget
(Embedding the chat widget).
Run a Runtype agent on your cloud
Exporting an agent requires an Enterprise plan and an API key with the
RUNTIME:EXPORT scope.
Export an agent authored in Runtype with
runtype deploy --agent <agent-id> --target cloudflare, or use the
cloud-run or vercel target. The export_agent_runtime tool also exports
the agent. Host it with @runtypelabs/runtime.
Set RUNTYPE_API_KEY on the deployment to a telemetry API key
(TELEMETRY:WRITE). The runtime then reports every run to the /v1/otel
endpoint with no instrumentation of your own. Each run carries its trace tree,
transcript, tool arguments and results, token usage, and cost estimate.
RUNTYPE_TELEMETRY=off stops reporting, and RUNTYPE_TELEMETRY_CONTENT=off
reports runs without conversation content. For setup, the hosted
/v1/runtime/* endpoints, and PII redaction, see
Self-hosting (BYOC).
The improvement loop for an external agent
Improving your agents from production traces describes the loop for hosted agents. For an external agent, two steps change:
- Fix happens in your repository, not with
update_agent. - Verify with
run_eval_suiteonly when Runtype can call the agent over A2A. Otherwise, re-run the scenario against your redeployed agent and inspect the resulting run. The captured cases remain the regression record.
Runs ingested over telemetry show an external badge in the Runs view. Their timings and cost are what the agent reported, not what Runtype metered.
Troubleshooting
Use the following checks when telemetry does not arrive as expected:
-
Verify the key and endpoint with an empty export. The response is
200with{}. A403means the key has neitherTELEMETRY:WRITEnorAGENTS:WRITE.cURL smoke test -
A run that stays in flight never received its closing
invoke_agentspan. Flush the provider before the process exits or the handler returns. -
missing_agent_attributionmeans Runtype found no agent ID for the trace. Set theruntype.agent.idresource attribute or thex-runtype-agent-idheader. -
ambiguous_agent_attributionmeans the trace’s spans claim more than one agent. Export each agent invocation as its own trace, or set oneruntype.agent.id. -
An attributed trace with no Run has no GenAI operation, model or inference signal, or recognized Runtype execution telemetry. Runtype retains it as a diagnostic in Logs.
-
A
429or503response is temporary. Retry the export after theRetry-Afterdelay. OpenTelemetry exporters do this by default. -
Doubled tokens and cost mean two instrumentations export to the same endpoint.
-
A tool card that reads “No tool content in this trace” means content capture is off on the producer.
-
A
partial_successresponse means Runtype rejected some traces in the export and stored the rest. The message names the rejected traces and their reasons.
Use the following checks when Runtype cannot call your agent:
Failed to fetch agent cardorAgent card response is not JSONwhen you register an A2A agent means Runtype could not load the card. Serve it as JSON at/.well-known/agent-card.jsonon the endpoint’s origin, or setagentCardUrl.Failed to connect to external agentfrom aruntype-streamendpoint means the endpoint failed URL validation, returned a non-2xx status, or did not answer withintimeoutMs. Check the HTTPS and public-address rules, theauthsettings, and the timeout.External agent stream is not conformantmeans a frame broke the stream rules. The bracketed code in the message names the rule.External agent stream ended without a terminal eventmeans the stream closed beforeexecution_completeorexecution_error.- A
runtype-streamresponse fails if it exceeds 20,000 events, 8 MiB in total, or 1 MiB in one frame. Runtype does not retry a stream that fails partway through. Anti-loop protection: context ... exceeded 5 turnsfrom a Hermes agent means its turn limit is at the default. SetA2A_MAX_PINGPONG_TURNS=20on the Hermes gateway, as described in Call Hermes over A2A.
Next steps
- Instrumenting a Flue agent: the Node pipeline, attribution, and tool-content options.
- Reporting telemetry from an external agent: the generic OTLP contract.
- Self-hosting (BYOC): export a Runtype agent and run it on your own cloud.
- Improving your agents from production traces: the capture-fix-verify loop.
- Connect Runtype to coding agents: run the loop from Claude Code, Cursor, or Codex.