Vercel Logo

Drive It Over HTTP

The TUI (terminal user interface) is a comfortable place to test an agent, but no customer is ever going to open your terminal. A real dispatcher gets reached over the wire: from a web page, a Slack message, a phone. Before we wire up any of those surfaces, it's worth seeing the thing they all sit on top of.

Here's the part that makes eve click: every eve app exposes the same HTTP session API, no matter what you build on top. The TUI you've been using is just one client of it. Slack will be another. Your dashboard will be a third. They all start sessions, stream events, and send follow-ups through the same three routes.

So let's skip the surfaces for a second and talk to the dispatcher the way every surface does, with plain curl.

Outcome

You start a durable session with the dispatcher over HTTP, stream its reply as events, and send a follow-up that resumes the same conversation.

Hands-on exercise

With npx eve dev running, open a second terminal. There's nothing to write this lesson, you're learning the contract every channel speaks, so we drive it by hand.

Start a session. Send the customer's first message:

curl -X POST http://127.0.0.1:2000/eve/v1/session \
  -H 'content-type: application/json' \
  -d '{"message":"what does a basic tune-up cost?"}'

The response hands you two things you'll reuse, and they do different jobs:

  • An x-eve-session-id response header. This is the stream-and-inspect handle: it names the run so you can watch it.
  • A continuationToken in the JSON body. This is the resume handle: you send it back to add the next message to this conversation.
Two handles, two jobs

Mixing these up is the most common early mistake. The session id is for watching a run (the stream). The continuation token is for continuing it (the next message). One identifies, one resumes.

Stream the session. Point at the stream route with the id from that header:

curl http://127.0.0.1:2000/eve/v1/session/<sessionId>/stream

You get newline-delimited JSON, one event per line: the turn starting, the lookup_service call going out, its result coming back, the assistant's text, and the turn completing. This is the same event log the TUI renders as those nice lines, just raw.

Send a follow-up. When the session is waiting for you (session.waiting), continue it with the token from the first response:

curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId> \
  -H 'content-type: application/json' \
  -d '{"continuationToken":"<token>","message":"and how long does it take?"}'

Same session, same history. The dispatcher already knows you're asking about the tune-up, you don't repeat yourself.

Try It

The first POST returns something like this (headers shown above the body):

x-eve-session-id: sess_8f2c1a...

{ "sessionId": "sess_8f2c1a...", "continuationToken": "ct_b91e..." }

And the stream prints the turn as it happens:

{"type":"session.started"}
{"type":"turn.started"}
{"type":"actions.requested","data":{"calls":[{"name":"lookup_service","input":{"query":"tune-up"}}]}}
{"type":"action.result","data":{"result":[{"name":"Basic Tune-Up","price":"$65.00","estMinutes":60}]}}
{"type":"message.completed","data":{"finishReason":"stop"}}
{"type":"turn.completed"}
{"type":"session.waiting"}

That session.waiting at the end is the agent telling you it's done with this turn and ready for the next message, the exact moment your follow-up token becomes useful. That waiting-then-resuming is not a toy: it's the same durable machinery that will let a turn park for human approval in Section 3 and pick up days later.

Send one turn at a time

For predictable ordering, wait for session.waiting before sending the next message to the same session. Fire two messages at once and you're racing the runtime, which is rarely what you want in a chat.

Getting a 401? The dev server accepts local requests, but make sure you're hitting 127.0.0.1/localhost and not a deployed URL. A rejected continuationToken usually means it's stale, each session has exactly one active token, so always use the most recent one the API handed back.

Done-When

  • POST /eve/v1/session returns a sessionId and a continuationToken.
  • Streaming the session prints NDJSON events, including the lookup_service call and session.waiting.
  • A follow-up POST with the continuationToken continues the same conversation without repeating context.
  • You can say which handle streams a run and which one resumes it.

Solution

There's no code to write here, the agent already exposed these routes the moment you ran it. The "solution" is the shape of the contract every channel is built on:

RouteWhat It Does
POST /eve/v1/sessionStart a durable session; returns sessionId + continuationToken.
GET /eve/v1/session/:id/streamStream the run as NDJSON events (reconnectable).
POST /eve/v1/session/:idSend a follow-up with the continuationToken.

Hold onto this picture. In Section 4 you'll put a web dashboard and Slack in front of the dispatcher, and neither one invents a new way to talk to it. useEveAgent calls these same routes from the browser; the Slack channel calls them from a webhook.

Was this helpful?

supported.