Add experimental AHP endpoints with SDK-owned transports for Node and .NET - #2621
Add experimental AHP endpoints with SDK-owned transports for Node and .NET#2621SteveSandersonMS wants to merge 4 commits into
Conversation
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>
Cross-SDK Consistency ReviewThis 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 Cross-language parity between the two implemented SDKs ✅The Node.js (
Naming differences (async suffixes, camelCase vs PascalCase, options-object vs positional bool for 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:
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 No inline review comments are needed — this PR maintains consistency for the languages it touches.
|
| try | ||
| { | ||
| var message = s_utf8.GetString(_chunks.GetBuffer(), 0, checked((int)_chunks.Length)); | ||
| _chunks.Dispose(); |
| // 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(); |
| foreach (var endpoint in _ahpEndpoints.Values) | ||
| { | ||
| if (rpc is null || ReferenceEquals(endpoint.Rpc, rpc)) | ||
| { | ||
| endpoint.Retire(new IOException("AHP runtime connection closed")); | ||
| } | ||
| } |
|
|
||
| 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) { } |
https://github.com/github/copilot-agent-runtime/pull/20118