Sessions, Runs, and Streaming
Purpose and Scope
This page explains the runtime contract that application code, channel adapters, and frontend clients share when they talk to an eve agent. In eve, a durable session is the long-lived conversation, while each user message creates a turn of work inside that session. Streaming is the way an application watches the runtime make progress: messages arrive, model steps begin, tools are requested, human input may be needed, and final output is delivered as ordered events. Understanding these names matters because the handles returned by the API are intentionally split by responsibility.
The key practical distinction is between resuming a conversation and observing a run. A continuationToken is the resume handle: it is what a channel or client uses to send the next follow-up message to the same conversation. A sessionId, and where applicable a runId, is the stream-and-inspect handle: it is what a client uses to attach to the event stream and watch runtime progress. Mixing those handles is the most common integration error because the token that continues a conversation is not the same identifier that names the durable stream.
Sources: docs/concepts/sessions-runs-and-streaming.md
Relevant Source Files
docs/concepts/sessions-runs-and-streaming.md- Defines the public concept page for the session and run contract, including continuation tokens,sessionIdandrunIdhandles, the HTTP session routes, the NDJSON stream shape, and the event names clients should expect.
This source file is reader-facing documentation rather than a low-level implementation file, so it is the best entry point for product-level semantics. It describes the API surfaces that every eve app touches regardless of whether the app is a hand-written HTTP client, a React/Vue/Svelte frontend using useEveAgent(), or a Next.js/Nuxt app proxying requests to the eve runtime from the same origin. The document intentionally frames these details as a stable contract, not an incidental implementation detail.
Sources: docs/concepts/sessions-runs-and-streaming.md
Core Concepts
A session is the durable conversation boundary. It may contain multiple turns, and it can survive waiting periods such as approvals, questions, or external authorization steps. A turn is the unit of work triggered by one inbound message or continuation. During a turn, eve may call tools, delegate to subagents, emit assistant text, request human input, or complete with structured output. Client code should treat the stream as the ordered record of those runtime changes rather than assuming a single request produces a single synchronous answer.
The continuationToken belongs to the channel-side continuation flow. The concept document states that a session has one active continuation at a time: each follow-up must use the current token, and a stale token is rejected. This design prevents two callers from unknowingly racing the same waiting conversation with an old resume handle. If your application persists conversation state, persist the latest continuation token after each turn that can be resumed, and do not treat an earlier token as a reusable conversation ID.
The sessionId and runId belong to observation. The session identifier names the durable session to stream, and the run identifier is used where a specific run needs to be inspected. This separation lets a user-facing channel own resumption while the runtime owns event history and inspection. In frontend integrations, higher-level client helpers can track both handles for you, but the underlying model is the same: resume with the continuation handle, stream with the session or run handle.
Sources: docs/concepts/sessions-runs-and-streaming.md
Execution Flow
To start a session directly over HTTP, post a message to the session route. The concept page demonstrates a POST to http://127.0.0.1:3000/eve/v1/session with a JSON body such as {"message":"Summarize the latest forecast."}. eve responds immediately rather than waiting for the whole agent turn to finish. That response includes a JSON sessionId and continuationToken, and the x-eve-session-id response header also names the durable session that can be streamed.
curl -X POST http://127.0.0.1:3000/eve/v1/session \
-H 'content-type: application/json' \
-d '{"message":"Summarize the latest forecast."}'After receiving the session identifier, attach to the stream endpoint for that session. The documented form is GET /eve/v1/session/<sessionId>/stream, shown locally as curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream. The response is newline-delimited JSON, or NDJSON: each line is a complete JSON event. This makes it possible for command-line clients, servers, and browser-facing adapters to process progress incrementally without waiting for the connection to close.
curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/streamThe stream is not only for assistant text. It is the runtime event feed for the turn. Early events such as session.started, turn.started, and message.received tell the client that the durable session was created, a new turn began, and the inbound user message was accepted. Step and action events then expose the model-to-tool loop. Text and reasoning events may arrive incrementally, and final events tell the client when a message, reasoning block, structured result, or session boundary has settled.
Sources: docs/concepts/sessions-runs-and-streaming.md
Stream Event Contract
The event names in the concept document are the vocabulary a renderer, channel adapter, or diagnostics tool should recognize. step.started marks the beginning of a model step. actions.requested indicates that the model requested one or more actions, including tool calls, and those calls stream before execution. action.result reports the return value of a tool call. Together, those events let an operator or UI show what the agent is doing before the final answer is available.
Human-in-the-loop and delegation events need special handling. input.requested means the run paused for human input, such as an approval or an ask_question request, and the event carries requests that a client must present or answer. subagent.called means work was delegated to another agent-like execution and carries a childSessionId that can be attached to if the client wants to observe the child. subagent.completed closes that delegated work. These events are why stream consumers should be designed around typed event handling rather than only concatenating assistant text.
For output rendering, the incremental and completed forms serve different client needs. reasoning.appended and message.appended are delta-style events that carry the cumulative text so far, allowing live displays to update as the model produces content. reasoning.completed and message.completed provide finalized blocks for clients that prefer compatibility or only render completed content. When a turn uses a structured output schema, result.completed carries the finalized result, so typed workflows do not have to scrape assistant prose.
Sources: docs/concepts/sessions-runs-and-streaming.md
Client and Frontend Integration Notes
Most application authors should not hand-code every route unless they are building an adapter, a custom transport, or a low-level integration. The concept page explicitly points React, Vue, and Svelte apps toward useEveAgent(), and notes that Next.js and Nuxt apps can proxy the same HTTP API to the eve runtime from the same origin. The abstraction changes the ergonomics, not the contract: the client still starts or resumes sessions, tracks handles, and consumes the NDJSON event stream under the hood.
When building your own persistence, store the conversation cursor separately from the rendered chat transcript. The continuation token answers the question, “How do I send the next turn?” The session identifier answers, “Which durable stream do I inspect?” A stream cursor, when used by higher-level client code, answers, “Which events have I already consumed?” Keeping those concepts separate makes reconnect behavior predictable and prevents a UI refresh from either replaying old events as new output or losing the ability to continue a waiting turn.
A useful mental model is that message delivery is event-sourced from the stream. The user message is acknowledged by message.received; model and tool work appears as step, action, and result events; human pauses appear as input requests; and assistant output appears through appended and completed message events. A UI can choose to render only assistant text, but robust channel integrations should preserve the complete event log or at least enough state to recover after reloads and reconnects.
Sources: docs/concepts/sessions-runs-and-streaming.md
Compact Reference
| Name | Role | Use it for | Do not use it for |
|---|---|---|---|
continuationToken | Resume handle owned by the channel | Sending a follow-up message to the same conversation | Attaching to or inspecting the event stream |
sessionId | Stream-and-inspect handle owned by the runtime | Streaming session events and reconnecting to event history | Resuming a conversation as the next user input |
runId | Run inspection handle where a specific run is exposed | Watching or inspecting a runtime run | Replacing the continuation token |
POST /eve/v1/session | Start a session route | Sending the first message payload | Long-lived event consumption |
GET /eve/v1/session/<sessionId>/stream | Stream route | Reading NDJSON events for the durable session | Submitting follow-up input |
The most important operational rule is to update state after every turn boundary. If the runtime gives you a new continuation token, persist that token before accepting another user action for the same conversation. If your client tracks stream position, persist that cursor after consuming events. If the stream emits input.requested, surface the request to the user and resume through the same session rather than starting an unrelated conversation. These small practices preserve eve’s durability guarantees at the application boundary.
Sources: docs/concepts/sessions-runs-and-streaming.md
Next Steps
If you are implementing an application UI, continue with the client and frontend integration pages so that useEveAgent(), same-origin proxying, and stream rendering conventions are handled consistently. If you are implementing a channel, focus on storing the current continuationToken and mapping channel messages to resumed turns. If you are debugging runtime behavior, attach to the session stream and inspect the ordered event feed before assuming a tool, subagent, approval, or renderer is responsible for missing output.
Related pages: Execution Model and Durability; Client Overview; Messages and Streaming; Continuations and Output Schema; Channels Overview.