An Oda runtime can serve an out-of-process client over a newline-delimited JSON-RPC connection instead of an interactive chat. This page describes the messages on that connection, so you can read a trace, debug an integration or build a client of your own.
If you are new to the family, start with the Oda SDK overview.
Your program owns the connection. The runtime reads requests on its standard input and writes messages back on its standard output.
\n.id and a method. Request ids look like req_ followed by a UUID.id of the request it answers, and no method.method and no id.Standard output carries protocol frames only, so a deployment must not compose a stdout logger.
initializeSets up the connection and resolves the model route.
cwd), the provider and model route, an optional reasoningEffort and an optional maxTokens.reasoningEffort must be a non-empty string: initialize reasoningEffort must be a non-empty string. Leave it out to keep the model's default effort.maxTokens must be a positive safe integer: initialize maxTokens must be a positive safe integer. Zero, negative values, fractions and oversized values are refused.no adapter registered for provider "<p>".session/ prompt is refused until one initialize has completed.session/ promptQueues one user message and returns a receipt straight away.
sessionId the runtime has not seen before starts that session.{ "messageId": ". . . " }. The message id does not identify a later assistant message, a turn ending or the result of that prompt.image/ png, image/ jpeg, image/ webp and image/ gif, in a block like this:{ "type": "image", "mimeType": "image/png", "data": "..." }shutdownFlushes what the runtime has written, winds its work down and exits. The reply carries an empty result.
Notifications travel from the runtime to your client; they carry no id and expect no answer.
session. event streams a session's events as they are appended.session. status reports the whole agent as running or idle.subagent. started announces a sub-agent session and links it to its parent.subagent. finished reports a sub-agent run that executed in the same process, with a status of ok or error. When the sub-agent produced no reply, its last assistant message is left out rather than sent empty.initialize with the working folder and the model route you want. A route the runtime cannot serve fails here, not at the prompt.session/ prompt and keep the messageId from the receipt.session. event streams the session's events, session. status reports work as running, and a sub-agent run announces itself with subagent. started.session. status to report idle: the turn has settled. The last committed assistant message of the session is its final text, and it is not assigned to one prompt.shutdown to end the connection.Follow the lineage in subagent. to tell a run's own session events apart from the wider tree. A turn ending carries a reason; when a turn is aborted, the reason names the kind (user, parent, disposed, legacy or hook), and a hook abort carries its reason string.
| What you receive | What it means |
|---|---|
method not found: <m>, code -32601 | No handler is registered for that method. |
The handler's message, code -32603 | The handler failed, and its error message is returned. |
JSON-RPC input closed | The input side of the connection closed, so no further requests are accepted. |
JSON-RPC transport closed | The transport closed; pending requests fail and nothing is retried for you. |
JSON-RPC request aborted: <reason> | The request was aborted and its pending state dropped: no state is retained for a response that may never come. |
JSON-RPC error | The fallback text for a failure that carries no other message. |
For the client side of the SDK, see the Oda SDK client. To serve clients from a runtime, see Running an Oda runtime server.
No. Every message must be one line of valid JSON terminated by \n, and a line that does not parse as a message gets no answer. An object spread over several lines never arrives as a message.
initialize before sending a prompt?Yes. session/ is refused until one initialize has completed, and the handshake is where the model route is resolved. A route problem fails the handshake instead of the prompt.
maxTokens accept?A positive safe integer. Zero, negative values, fractions and oversized values are refused with initialize maxTokens must be a positive safe integer. The field is optional; send it only when you want a cap on the work the handshake starts.
initialize fail with a missing adapter?The provider you named has no registered adapter, so the route could not be resolved. Check the provider and model you send; a route that cannot be resolved fails the handshake and cannot fall back to a default.
Inline images with image/, image/, image/ or image/. Each inline image becomes a durable reference in the session before the prompt is enqueued.
By id. Every request carries an id (req_ followed by a UUID), and the response returns the same id. Notifications carry no id.
Not at the connection level. session/ returns only the enqueue receipt, and its messageId does not identify a later assistant message, a turn ending or the prompt's result. Read the stream until the agent is idle.
Its pending state is dropped, so no state is retained for a response that may never come. The rejection names the reason: JSON-RPC request aborted: <reason>.
They fail. A closed input reports JSON-RPC input closed, and a closed transport reports JSON-RPC transport closed; nothing is retried for you.
No. The protocol has no cancel method and no way to close a single session. A turn runs until the agent reports idle, and shutdown ends the connection itself.
No. The handshake result reports the runtime's identity, but there is no version negotiation; a client must be built for the same version as the runtime it drives.