NexusLabs.Eve
0.1.0-alpha-0015
dotnet add package NexusLabs.Eve --version 0.1.0-alpha-0015
NuGet\Install-Package NexusLabs.Eve -Version 0.1.0-alpha-0015
<PackageReference Include="NexusLabs.Eve" Version="0.1.0-alpha-0015" />
<PackageVersion Include="NexusLabs.Eve" Version="0.1.0-alpha-0015" />
<PackageReference Include="NexusLabs.Eve" />
paket add NexusLabs.Eve --version 0.1.0-alpha-0015
#r "nuget: NexusLabs.Eve, 0.1.0-alpha-0015"
#:package NexusLabs.Eve@0.1.0-alpha-0015
#addin nuget:?package=NexusLabs.Eve&version=0.1.0-alpha-0015&prerelease
#tool nuget:?package=NexusLabs.Eve&version=0.1.0-alpha-0015&prerelease
NexusLabs.Eve
<p align="center"> <img src="https://raw.githubusercontent.com/ncosentino/eve-client/main/docs/assets/eve-brand.png" alt="eve.NET logo" width="320" /> </p>
A C# client for the Vercel eve HTTP API.
NexusLabs.Eve ports the framework-neutral eve/client protocol surface to .NET:
health and agent inspection, authentication, durable sessions, human-input responses,
cooperative cancellation, session context clear, session reset, manual session compaction,
remote session prewarming, compact named-agent mounts, NDJSON streaming,
reconnect-by-index, attachments, and structured output.
This package requires Vercel eve 0.54.2 or newer and currently targets
0.71.0, using message-stream protocol 26, stream-control protocol 1, and
agent-info schema v5. Earlier supported stream and inspection schemas remain accepted.
Eve 0.54.2 is the first published release whose strict schema-v4 kernel-effect action
set is exactly subagent-call, task-cancel, and workflow-tool-call. Earlier
schema-v4 servers can still advertise the obsolete task-update action under the same
schema version, so upgrade the eve server before upgrading this client.
Eve 0.59.0 adds message-free remote session prewarming and readiness retries for the
first later send. It also uses compact /eve/<agent>/v1/* routes for named workspace
agents and advances live session cursors before yielding each consumed event.
Eve 0.59.1 adds renewable leased stream responses and in-place steering semantics.
Eve 0.64.0 introduces schema-v5 inspection, 0.66.1 adds parent-authenticated child
streams, 0.69.0 introduces message-stream version 26, and 0.70.0 holds turns on
human input. The client handles both historical and current child descriptors and
returns Waiting outcomes at human-input parks without ending task-backed work.
Eve 0.52.3 separately introduced the accepted response deliveryId used to skip stale
durable events and return the accepted existing-session delivery. The initial SendAsync
that creates a session and RespondAsync human-input continuation do not require that
correlation; every SendAsync on an existing session does. eve is still a preview, so
pin and test compatible versions before upgrading. See
Compatibility and Migration.
Prerequisites
- .NET 10 SDK
Install
dotnet add package NexusLabs.Eve
The package has no runtime dependencies outside .NET. Supply a caller-managed
HttpMessageInvoker; an HttpClient created by IHttpClientFactory can be passed
directly because it derives from HttpMessageInvoker.
Full documentation is published at www.devleader.ca/projects/eve-client.
Quick start
using NexusLabs.Eve;
using HttpClient transport = httpClientFactory.CreateClient("eve");
EveClient client = new(
transport,
new EveClientOptions("https://agent.example.com")
{
Authentication = new EveBearerAuthentication(
cancellationToken => GetAccessTokenAsync(cancellationToken)),
});
EveHealthStatus health = await client.GetHealthAsync(cancellationToken);
EveSession session = client.CreateSession();
EveMessageResponse response = await session.SendAsync(
"What is the weather in Brooklyn?",
cancellationToken);
EveTurnOutcome outcome = await response.GetOutcomeAsync(cancellationToken);
Console.WriteLine($"{health.Status}: {outcome.Message}");
Keep the transport alive until every response stream has finished. For credential-bearing clients, configure the transport not to follow redirects across origins:
services
.AddHttpClient("eve")
.ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
{
AllowAutoRedirect = false,
});
Authentication
Credentials and dynamic headers are resolved before every HTTP request, including stream reconnects:
EveClientOptions options = new("https://agent.example.com")
{
Authentication = new EveVercelOidcAuthentication(
cancellationToken => GetVercelOidcTokenAsync(cancellationToken)),
HeadersProvider = async cancellationToken => new Dictionary<string, string>
{
["x-vercel-protection-bypass"] =
await GetProtectionBypassAsync(cancellationToken),
},
};
Built-in providers cover bearer, Basic, and Vercel OIDC authentication. Generic per-request headers override non-protected client-wide values, while authentication-owned headers remain protected by default. Replacing a credential requires both a client allowlist and the dedicated protected-header override property on the individual turn or raw request.
Use RequestHeadersProvider to select dynamic headers by EveRequestKind, such as
limiting a bootstrap credential to CreateSession while continuing to resolve normal
authentication and infrastructure headers for stream reconnects.
Streaming
EveMessageResponse is single-use. Aggregate it with GetOutcomeAsync, or consume
events as they arrive:
EveMessageResponse response = await session.SendAsync(
"Draft a plan and show your work.",
cancellationToken);
await foreach (EveStreamEvent streamEvent in response.WithCancellation(cancellationToken))
{
if (streamEvent.Kind == EveStreamEventKind.MessageAppended)
{
Console.Write(streamEvent.Data.GetProperty("messageDelta").GetString());
}
}
Known wire types map to EveStreamEventKind; the original Type and Data JSON are
always preserved so newer eve events remain consumable before this package adds a
stronger projection.
The default reconnect policy mirrors the TypeScript client. Active SendAsync and
RespondAsync responses reconnect until a turn boundary or caller cancellation,
while manually attached StreamAsync reads retain a finite idle budget. Set
StreamIdleRetry.MaxAttempts to bound an active response explicitly.
A relay that owns cursor recovery can disable reconnection:
EveMessageResponse response = await session.SendAsync(
EveMessageContent.FromText("Run the long operation."),
new EveTurnOptions
{
StreamReconnectPolicy = EveStreamReconnectPolicy.Disabled,
},
cancellationToken);
Set EveClientOptions.MaxStreamEventBytes to opt into a client-wide UTF-8 byte limit
for one NDJSON event. The default remains unbounded to preserve upstream compatibility.
Continuations and cancellation
Persist session.State after consuming a stream, then resume it later:
EveSession resumed = client.CreateSession(savedState);
EveMessageResponse response = await resumed.SendAsync(
"Continue where we left off.",
cancellationToken);
SessionId addresses every turn, control, and stream; StreamIndex prevents
replaying consumed events. When only the identifier was persisted, attach to it
with client.AttachSession(sessionId).
Once a turn is accepted, cancellation can be requested before its stream settles:
EveMessageResponse response = await session.SendAsync(
"Run the long operation.",
cancellationToken);
Task<EveTurnOutcome> outcomeTask = response.GetOutcomeAsync(cancellationToken);
EveCancellationOutcome cancellation = await response.CancelAsync(cancellationToken);
EveTurnOutcome outcome = await outcomeTask;
Start consuming the response before awaiting cancellation so it can identify and guard
the exact turn. Use session.CancelAsync(turnId, cancellationToken) when working from an
attached session and an already observed turn identifier.
Continue consuming the stream after cancellation to observe turn.cancelled followed
by session.waiting and to advance the cursor.
Both cancellation results are successful. EveCancellationStatus.Accepted carries the
session identifier; EveCancellationStatus.NoActiveTurn means there was nothing left to
cancel and reports a null SessionId.
ClearAsync queues removal of durable model-message history while preserving the
session identity and local cursor. Consume the stream through context.cleared and the
following session.waiting boundary before sending another turn:
EveClearOutcome clear = await session.ClearAsync(cancellationToken);
Context clear is covered by contract tests and by the pinned 0.54.2 fixture.
ResetAsync retires the durable session instead of only stopping the active turn:
EveResetOutcome reset = await session.ResetAsync(cancellationToken);
The handle keeps its session identifier after a reset. Reusing it is refused with HTTP
409, so call client.CreateSession() to start a fresh conversation.
CompactAsync queues context compaction without sending model input and without
clearing the local cursor. Consume the durable stream through the next session
boundary before the next turn; compaction.completed confirms summarization.
EveCompactOutcome compact = await session.CompactAsync(cancellationToken);
Attachments and human input
EveMessageContent message = EveMessageContent.FromParts(
EveContentPart.CreateText("Summarize this report."),
EveContentPart.CreateFile(
reportBytes,
"application/pdf",
"report.pdf"));
EveMessageResponse response = await session.SendAsync(message, cancellationToken);
EveTurnOutcome outcome = await response.GetOutcomeAsync(cancellationToken);
if (outcome.InputRequests.Count > 0)
{
EveMessageResponse resumed = await session.RespondAsync(
[
new EveInputResponse(
outcome.InputRequests[0].RequestId,
optionId: "approve"),
],
cancellationToken);
}
The resumed outcome includes durable authoritative results in
InputResolutions. Each resolution retains its request kind, outcome, optional accepted
response, and original turn coordinates. Resolutions such as Ignored may intentionally
carry no response.
Structured output
Pass raw JSON Schema in EveTurnOptions.OutputSchema. The server remains
authoritative for validation. Deserialize the final result.completed value with
source-generated metadata:
Summary? summary = outcome.DeserializeData(AppJsonContext.Default.Summary);
Scope
This package covers the transport-neutral TypeScript Client, ClientSession,
MessageResponse, session state, protocol events, and file-part helpers. The
TypeScript-only React/Vue/Svelte hooks, EveAgentStore, and UI message reducer are not
ported because they depend on JavaScript UI and AI SDK types rather than the HTTP
protocol.
GetInfoAsync validates agent-info schemas 1 through 4 and exposes the complete JSON
through EveAgentInfo.Raw. Schema v3 includes canonical source ownership, bindings,
composition diagnostics, and node identities; schema v4 adds first-class memory-provider
inspection. Schema v3 retains the historical task-update kernel effect, while schema
v4 accepts only subagent-call, task-cancel, and workflow-tool-call. Preserving the
raw document keeps accepted preview inspection fields available without expanding the
strong projection.
GetHealthAsync accepts only the exact successful health shape. Invalid JSON or schema
violations throw EveHealthResponseException, whose Issues collection contains at most
five path-qualified diagnostics. Non-success HTTP responses remain EveClientException.
Development
dotnet tool restore
dotnet build
dotnet test
npm ci --prefix test/fixtures/eve-agent
npm run test:client --prefix test/fixtures/eve-agent
dotnet pack --no-build
pwsh scripts/validate-packages.ps1
Architecture
- Caller-owned
HttpMessageInvokertransport; no DI framework dependency. - Immutable session cursors suitable for persistence.
System.Text.JsonDOM values at preview protocol boundaries for forward compatibility.- Single-use async response streams with automatic absolute-cursor reconnection.
- TUnit contract tests modeled on Vercel's TypeScript client behavior.
Project Structure
src/
NexusLabs.Eve/ # Library source
NexusLabs.Eve.Tests/ # Unit tests
Contributing
See .github/instructions/ for coding conventions enforced by Copilot.
See RELEASING.md for versioning, trusted publishing, and
release gates.
License
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-alpha-0015 | 44 | 10/3/2026 |
| 0.1.0-alpha-0014 | 58 | 9/20/2026 |
| 0.1.0-alpha-0013 | 55 | 9/20/2026 |
| 0.1.0-alpha-0012 | 228 | 9/11/2026 |
| 0.1.0-alpha-0011 | 63 | 9/11/2026 |
| 0.1.0-alpha-0010 | 203 | 8/28/2026 |
| 0.1.0-alpha-0009 | 74 | 8/26/2026 |
| 0.1.0-alpha-0008 | 75 | 8/25/2026 |
| 0.1.0-alpha-0007 | 78 | 8/22/2026 |
| 0.1.0-alpha-0006 | 531 | 8/13/2026 |
| 0.1.0-alpha-0005 | 76 | 8/13/2026 |
| 0.1.0-alpha-0004 | 72 | 8/9/2026 |
| 0.1.0-alpha-0003 | 75 | 8/8/2026 |
| 0.1.0-alpha-0002 | 225 | 7/24/2026 |
| 0.1.0-alpha-0001 | 79 | 7/24/2026 |