NexusLabs.Eve 0.1.0-alpha-0015

This is a prerelease version of NexusLabs.Eve.
dotnet add package NexusLabs.Eve --version 0.1.0-alpha-0015
                    
NuGet\Install-Package NexusLabs.Eve -Version 0.1.0-alpha-0015
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NexusLabs.Eve" Version="0.1.0-alpha-0015" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NexusLabs.Eve" Version="0.1.0-alpha-0015" />
                    
Directory.Packages.props
<PackageReference Include="NexusLabs.Eve" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NexusLabs.Eve --version 0.1.0-alpha-0015
                    
#r "nuget: NexusLabs.Eve, 0.1.0-alpha-0015"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NexusLabs.Eve@0.1.0-alpha-0015
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NexusLabs.Eve&version=0.1.0-alpha-0015&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=NexusLabs.Eve&version=0.1.0-alpha-0015&prerelease
                    
Install as a Cake Tool

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>

CI Documentation NuGet

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 HttpMessageInvoker transport; no DI framework dependency.
  • Immutable session cursors suitable for persistence.
  • System.Text.Json DOM 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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