Sessions¶
An EveSession is a fixed handle. It tracks two values:
SessionIdidentifies the durable runtime session. It addresses every turn, control, and stream, and never changes once assigned.StreamIndexcounts events already consumed.
eve 0.31.0 removed continuation tokens from the client protocol. A handle
keeps its identifier across every session boundary, so a completed or failed
conversation stays inspectable and streamable.
Persist state¶
Consume the response before saving the fully advanced cursor:
EveMessageResponse response = await session.SendAsync(
"Create a checklist.",
cancellationToken);
await response.GetOutcomeAsync(cancellationToken);
await SaveAsync(session.State, cancellationToken);
Resume state¶
EveSession resumed = client.CreateSession(savedState);
EveMessageResponse response = await resumed.SendAsync(
"Shorten the checklist.",
cancellationToken);
When only the session identifier was persisted, attach to it directly:
EveSession resumed = client.AttachSession(sessionId);
EveSession rewound = client.AttachSession(sessionId, streamIndex: 12);
Prewarm a remote session¶
Eve 0.59.0 and newer can create a durable conversation before its first user
message:
EveSession session = await client.PrewarmSessionAsync(cancellationToken);
await SaveAsync(session.State, cancellationToken);
EveMessageResponse response = await session.SendAsync(
"Begin the conversation.",
cancellationToken);
Unlike CreateSession(), PrewarmSessionAsync performs remote I/O. It sends a
message-free session request, returns the accepted session identifier at cursor
zero, and makes the first later send use the existing-session route. The
message-free request does not accept turn-scoped client context, output schemas,
or delivery policies; supply those options with the first SendAsync call.
The remote workflow can accept the prewarm request before its session inbox is
ready. If the first later message receives 409 session_not_ready, SendAsync
re-resolves dynamic headers and retries for up to 20 seconds. Backoff starts at
250 milliseconds, doubles to a two-second cap, and stops immediately on
cancellation. RespondAsync does not use this readiness retry.
Overlapping sends¶
A message that reaches a session which already has an active turn is governed by
a delivery policy. eve 0.33.0 changed the server-side default from waiting to
steering.
eve 0.33.0 steers by default
Sending no policy means eve 0.33.0 and later steer. Set TurnPolicy to
EveTurnPolicy.Queue to keep the earlier wait-for-completion behavior.
Nothing fails loudly, because the request format did not change.
Eve 0.59.1 changed steering from cancel-and-replace to an in-place update at
the next committed boundary. Steering accepted while a turn is active preserves
that turn's identifier and accumulated usage; the response can therefore begin
with message.received or another same-turn event rather than a new
turn.started. Steering accepted after the answer settles starts a normal
follow-up turn with a new identifier.
EveMessageResponse response = await session.SendAsync(
EveMessageContent.FromText("Actually, summarize it instead."),
new EveTurnOptions { TurnPolicy = EveTurnPolicy.Queue },
cancellationToken);
The policy is sent only for a message continuing an existing session. It is omitted when the turn creates the session, because a new session has no active turn, and when the turn carries only input responses. Awaiting each turn before sending the next one never overlaps, so sequential callers are unaffected.
Clear session context¶
Control operations require identifier-addressed routes
ClearAsync, CompactAsync, and ResetAsync post to
/eve/v1/session/{sessionId}/clear, /compact, and /reset, which exist only in eve
0.31.0 and newer. They report HTTP 404 on an earlier agent. Turns, streaming, and
cancellation are unaffected. See Migration.
ClearAsync queues removal of durable model-message history while keeping the
session identity, configuration, non-message state, limits, and sandbox:
EveClearOutcome clear = await session.ClearAsync(cancellationToken);
if (clear.Status == EveClearStatus.Accepted)
{
await foreach (EveStreamEvent streamEvent in session.StreamAsync(cancellationToken))
{
if (streamEvent.Kind == EveStreamEventKind.ContextCleared)
{
// History was cleared on the durable stream.
}
if (streamEvent.Kind == EveStreamEventKind.SessionWaiting)
{
break;
}
}
}
- The session identifier is recorded as soon as
SendAsyncreturns, so clear can run before the response stream is consumed. - A session that never started returns
EveClearStatus.NoActiveSessionand issues no HTTP request. - A successful clear leaves the local cursor unchanged. Consume the durable
stream through
context.clearedand the followingsession.waitingboundary before sending another turn. - The route is
POST /eve/v1/session/{sessionId}/clearand requires eve0.31.0or newer.
ClearAsync is not an alias for ResetAsync. ResetAsync retires the
conversation; ClearAsync keeps the same durable session and only discards
model-message history.
Reset a session¶
ResetAsync terminally retires the durable session addressed by this handle:
EveResetOutcome reset = await session.ResetAsync(cancellationToken);
if (reset.Status == EveResetStatus.Reset)
{
EveSession next = client.CreateSession();
}
- A session that never started returns
EveResetStatus.NoActiveSessionand issues no HTTP request. - The handle keeps its session identifier after a successful reset. It does not
recycle into a new conversation; call
CreateSession()for that. - The route is
POST /eve/v1/session/{sessionId}/resetand requires eve0.31.0or newer.
ResetAsync is not an alias for CancelAsync. CancelAsync only requests
cooperative cancellation of the active turn and keeps the conversation
resumable; ResetAsync retires the conversation itself.
Compact a session¶
CompactAsync queues context compaction for the durable session without
sending model input:
EveCompactOutcome compact = await session.CompactAsync(cancellationToken);
if (compact.Status == EveCompactStatus.Accepted)
{
await foreach (EveStreamEvent streamEvent in session.StreamAsync(cancellationToken))
{
if (streamEvent.Kind is EveStreamEventKind.SessionWaiting
or EveStreamEventKind.SessionCompleted
or EveStreamEventKind.SessionFailed)
{
break;
}
}
}
- Compaction is asynchronous. Consume the durable stream through the next
session boundary before sending another turn.
compaction.completedconfirms successful summarization. - A session that never started returns
EveCompactStatus.NoActiveSessionand issues no HTTP request. - Unlike reset, compaction preserves the local session cursor.
- The route is
POST /eve/v1/session/{sessionId}/compactand requires eve0.31.0or newer.
CompactAsync is not an alias for ResetAsync. Compaction summarizes history
in place and keeps the conversation resumable; reset retires the conversation.
Terminal behavior¶
Every session boundary advances the cursor and preserves the session
identifier. session.waiting parks the conversation for another turn;
session.completed and session.failed end it. In all three cases the handle
remains valid for streaming and inspection, so a finished conversation can
still be replayed from index 0.