Skip to content

Add experimental AHP endpoints with SDK-owned transports for Node and .NET - #2621

Draft
SteveSandersonMS wants to merge 4 commits into
mainfrom
prototype/sdk-ahp-host
Draft

Add experimental AHP endpoints with SDK-owned transports for Node and .NET#2621
SteveSandersonMS wants to merge 4 commits into
mainfrom
prototype/sdk-ahp-host

Conversation

@SteveSandersonMS

Copy link
Copy Markdown
Contributor

SteveSandersonMS and others added 4 commits September 11, 2026 10:17
Expose startAhpHost and stopAhpHost over the runtime RPC connection, preserving the SDK session lifecycle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Demonstrate an SDK-defined Bert agent through an independent standard AHP 0.7 client. Add RPC-only Node generation and document local runtime builds, schema inputs, and existing SDK e2e selectors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace runtime listener controls with endpoint and connection callbacks, bounded message forwarding, and lifecycle cleanup. Demonstrate streamed Bert turns through Express and a standard independent AHP client.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add bounded message and fragment forwarding, per-connection transport callbacks, and lifecycle cleanup. Use ValueTask reverse RPC handlers and return logical cancellation errors without canceling outer dispatch. Demonstrate streamed Bert turns through the standard AHP client.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review

This PR (draft, title: "Add experimental AHP endpoints with SDK-owned transports for Node and .NET") introduces a new opaque-transport AHP (Agent Host Protocol) endpoint feature to the Node.js and .NET SDKs only, plus a matching samples/ahp/ demo for both.

Cross-language parity between the two implemented SDKs ✅

The Node.js (nodejs/src/ahp.ts) and .NET (dotnet/src/Ahp.cs) implementations look well aligned:

Concept Node.js .NET
Create endpoint client.createAhpEndpoint() client.CreateAhpEndpointAsync()
Accept connection endpoint.acceptConnection(transport) (sync) endpoint.AcceptConnection(transport) (sync)
Feed a message connection.receive(text) connection.ReceiveAsync(message, ct)
Feed a fragment connection.receiveChunk(bytes, { endOfMessage }) connection.ReceiveChunkAsync(bytes, endOfMessage, ct)
Closure signal connection.closed: Promise<void> connection.Closed: Task
Teardown connection.end() / endpoint.dispose() connection.EndAsync() / endpoint.DisposeAsync()
Transport interface AhpTransport.send/close IAhpTransport.SendAsync/CloseAsync

Naming differences (async suffixes, camelCase vs PascalCase, options-object vs positional bool for endOfMessage) are consistent with each language's normal conventions, and both sides share the same 8 MiB / 64-pending-message limits and 10s deadlines, wired through the same ahp.* / ahpTransport.* RPC methods. No inconsistency found between the two implementations.

Feature parity across the other SDKs i️

Python, Go, Java, and Rust do not yet have any AHP-related code — this is expected here since:

  • The PR title explicitly scopes this to Node and .NET as an experimental feature (@experimental in the public Node API doc comment), and
  • The PR is still marked draft and references a companion runtime change (github/copilot-agent-runtime#20118) that hasn't landed yet.

No action is needed in this PR for the other SDKs. When this feature graduates from experimental, it would be worth tracking follow-up work to bring equivalent CreateAhpEndpoint/create_ahp_endpoint/CreateAHPEndpoint APIs to Python, Go, Java, and Rust for full parity, following the same acceptConnection/receive/receiveChunk/end/dispose shape established here.

No inline review comments are needed — this PR maintains consistency for the languages it touches.

Generated by SDK Consistency Review Agent for #2621 · copilot · sonnet50 · 45.6 AIC · ⌖ 12.3 AIC · ⊞ 8.3K ·

Comment thread dotnet/src/Ahp.cs
try
{
var message = s_utf8.GetString(_chunks.GetBuffer(), 0, checked((int)_chunks.Length));
_chunks.Dispose();
Comment thread dotnet/src/Ahp.cs
// These isolated closures must not capture the connection/client: an arbitrary callback can hang forever.
private static async Task InvokeSendAsync(IAhpTransport transport, string message, ILogger logger, CancellationToken token)
{
var callbackCancellation = new CancellationTokenSource();
Comment thread dotnet/src/Ahp.cs
Comment on lines +82 to +88
foreach (var endpoint in _ahpEndpoints.Values)
{
if (rpc is null || ReferenceEquals(endpoint.Rpc, rpc))
{
endpoint.Retire(new IOException("AHP runtime connection closed"));
}
}
Comment thread dotnet/src/Client.cs

var ahpDisposals = _ahpEndpoints.Values.Select(endpoint => endpoint.DisposeAsync().AsTask()).ToArray();
try { await Task.WhenAll(ahpDisposals).ConfigureAwait(false); }
catch (Exception ex) { errors.Add(ex); }
var one = new byte[1];
while (!_lifetime.IsCancellationRequested)
{
var header = new StringBuilder();
}
}
}
catch (Exception error) when (error is OperationCanceledException or IOException or ObjectDisposedException or SocketException) { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants