From cb597ea78bcb52119bbc03e885ac65ddec4e1be5 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Wed, 13 May 2026 20:17:29 -0700 Subject: [PATCH 1/2] Add bundled Python guest options Add HyperlightCodeActProviderOptions.CreateForPython() backed by the Hyperlight Python guest package. Resolve the bundled module through PythonGuestModule.GetModulePath() so the existing backend/module path configuration stays simple and consistent with custom Wasm modules. Adding the bundled package makes it easier to get started with using python. Signed-off-by: James Sturtevant --- dotnet/Directory.Packages.props | 1 + .../HyperlightCodeActProvider.cs | 5 +- .../HyperlightCodeActProviderOptions.cs | 21 +++++-- .../Microsoft.Agents.AI.Hyperlight.csproj | 1 + .../Microsoft.Agents.AI.Hyperlight/README.md | 45 ++++++++++--- .../HyperlightCodeActProviderTests.cs | 63 +++++++++++++++++++ 6 files changed, 123 insertions(+), 13 deletions(-) diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index 75106b5fcb..41fd7e9ef3 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -112,6 +112,7 @@ + diff --git a/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProvider.cs b/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProvider.cs index 3065a0a893..e70a25033f 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProvider.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProvider.cs @@ -68,8 +68,9 @@ public sealed class HyperlightCodeActProvider : AIContextProvider, IDisposable /// Optional configuration options for the provider. When the provider /// uses the defaults of (the /// backend with no tools, mounts, or allow-list entries). - /// Use to target a Wasm - /// guest module instead. + /// Use for the bundled Python + /// guest module, or for a + /// custom Wasm guest. /// public HyperlightCodeActProvider(HyperlightCodeActProviderOptions? options = null) { diff --git a/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs b/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs index 93e5a09c39..a29a11ce0e 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using HyperlightSandbox.Api; +using HyperlightSandbox.Guest.Python; using Microsoft.Extensions.AI; using Microsoft.Shared.Diagnostics; @@ -12,8 +13,9 @@ namespace Microsoft.Agents.AI.Hyperlight; /// . /// /// -/// Use the and -/// factory methods to construct an instance with the desired sandbox backend. +/// Use the , , +/// and factory methods to construct an instance +/// with the desired sandbox backend. /// The parameterless constructor is equivalent to . /// public sealed class HyperlightCodeActProviderOptions @@ -34,7 +36,17 @@ private HyperlightCodeActProviderOptions(SandboxBackend backend, string? moduleP } /// - /// Creates options targeting the backend. + /// Creates options targeting the backend + /// with the bundled Python guest module from the + /// Hyperlight.HyperlightSandbox.Guest.Python NuGet package. + /// No explicit module path is required. + /// + public static HyperlightCodeActProviderOptions CreateForPython() + => new(SandboxBackend.Wasm, PythonGuestModule.GetModulePath()); + + /// + /// Creates options targeting the backend + /// with a custom guest module. /// /// Path to the guest module (.wasm or .aot file). public static HyperlightCodeActProviderOptions CreateForWasm(string modulePath) @@ -53,7 +65,8 @@ public static HyperlightCodeActProviderOptions CreateForJavaScript() /// /// Gets the path to the guest module. Set when the options were created via - /// ; otherwise. + /// or ; + /// when using the built-in JavaScript backend. /// public string? ModulePath { get; } diff --git a/dotnet/src/Microsoft.Agents.AI.Hyperlight/Microsoft.Agents.AI.Hyperlight.csproj b/dotnet/src/Microsoft.Agents.AI.Hyperlight/Microsoft.Agents.AI.Hyperlight.csproj index a6fd3d9c9e..af7800c0c6 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hyperlight/Microsoft.Agents.AI.Hyperlight.csproj +++ b/dotnet/src/Microsoft.Agents.AI.Hyperlight/Microsoft.Agents.AI.Hyperlight.csproj @@ -13,6 +13,7 @@ + diff --git a/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md b/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md index 5f6efdb0f6..5eff5fb8e9 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md +++ b/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md @@ -25,15 +25,46 @@ Both surfaces support: * Snapshot/restore per run so the guest starts from a known clean state every invocation. +## Quick Start — Bundled Python Guest + +The simplest way to get started is with the bundled Python guest module. +This package includes +[`Hyperlight.HyperlightSandbox.Guest.Python`](https://www.nuget.org/packages/Hyperlight.HyperlightSandbox.Guest.Python), +so no separate module path is needed: + +```csharp +using Microsoft.Agents.AI.Hyperlight; + +// Use the bundled Python guest — no module path required +var options = HyperlightCodeActProviderOptions.CreateForPython(); +using var provider = new HyperlightCodeActProvider(options); +``` + +Or with the standalone function: + +```csharp +using var executeCode = new HyperlightExecuteCodeFunction( + HyperlightCodeActProviderOptions.CreateForPython()); +``` + +## Other Backends + +```csharp +// Built-in JavaScript (QuickJS) — default +var jsOptions = HyperlightCodeActProviderOptions.CreateForJavaScript(); + +// Custom Wasm guest module see hyperlight-sandbox docs for creating a custom wasm module +var wasmOptions = HyperlightCodeActProviderOptions.CreateForWasm("/path/to/guest.aot"); +``` + ## Requirements -* The `Hyperlight.HyperlightSandbox.Api` NuGet package, published from the - `src/sdk/dotnet` SDK in [hyperlight-dev/hyperlight-sandbox](https://github.com/hyperlight-dev/hyperlight-sandbox) - (the .NET API was added in [PR #46](https://github.com/hyperlight-dev/hyperlight-sandbox/pull/46), - now merged). Until the package is published to nuget.org the project - restore will fail; this project is intentionally `IsPackable=false` in - the meantime. -* A Hyperlight Python guest module when using `SandboxBackend.Wasm`. +* The [`Hyperlight.HyperlightSandbox.Api`](https://www.nuget.org/packages/Hyperlight.HyperlightSandbox.Api) + and [`Hyperlight.HyperlightSandbox.Guest.Python`](https://www.nuget.org/packages/Hyperlight.HyperlightSandbox.Guest.Python) + NuGet packages (included as dependencies). +* A hypervisor: [KVM](https://help.ubuntu.com/community/KVM/Installation) (Linux), + [MSHV](https://github.com/rust-vmm/mshv), or + [Hyper-V](https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/get-started/Install-Hyper-V) (Windows). ## Status diff --git a/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs index eb8d941ea5..aef2103abe 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs @@ -170,4 +170,67 @@ public void Dispose_IsIdempotentAndBlocksFurtherAddTools() // Assert Assert.Throws(() => provider.AddTools(tool)); } + + [Fact] + public void CreateForPython_SetsWasmBackendAndBundledGuest() + { + // Act + var options = HyperlightCodeActProviderOptions.CreateForPython(); + + // Assert + Assert.Equal(HyperlightSandbox.Api.SandboxBackend.Wasm, options.Backend); + Assert.EndsWith("python-sandbox.aot", options.ModulePath); + } + + [Fact] + public void CreateForWasm_SetsWasmBackendAndCustomPath() + { + // Act + var options = HyperlightCodeActProviderOptions.CreateForWasm("/path/to/guest.aot"); + + // Assert + Assert.Equal(HyperlightSandbox.Api.SandboxBackend.Wasm, options.Backend); + Assert.Equal("/path/to/guest.aot", options.ModulePath); + } + + [Fact] + public void CreateForJavaScript_SetsJavaScriptBackend() + { + // Act + var options = HyperlightCodeActProviderOptions.CreateForJavaScript(); + + // Assert + Assert.Equal(HyperlightSandbox.Api.SandboxBackend.JavaScript, options.Backend); + Assert.Null(options.ModulePath); + } + + [Fact] + public void DefaultCtor_EquivalentToCreateForJavaScript() + { + // Act + var options = new HyperlightCodeActProviderOptions(); + + // Assert + Assert.Equal(HyperlightSandbox.Api.SandboxBackend.JavaScript, options.Backend); + Assert.Null(options.ModulePath); + } + + [Fact] + public void Ctor_WithPythonOptions_SeedsFromOptions() + { + // Arrange + var tool = AIFunctionFactory.Create(() => "x", name: "x"); + var options = HyperlightCodeActProviderOptions.CreateForPython(); + options.Tools = new[] { tool }; + options.FileMounts = new[] { new FileMount("/h", "/m") }; + options.AllowedDomains = new[] { new AllowedDomain("https://a") }; + + // Act + using var provider = new HyperlightCodeActProvider(options); + + // Assert + Assert.Single(provider.GetTools()); + Assert.Single(provider.GetFileMounts()); + Assert.Single(provider.GetAllowedDomains()); + } } From 39808416f0fe0a6cbadbfbcc61cbe7cd657fc028 Mon Sep 17 00:00:00 2001 From: James Sturtevant Date: Thu, 14 May 2026 11:43:15 -0700 Subject: [PATCH 2/2] Respond to feedback Signed-off-by: James Sturtevant --- .../HyperlightCodeActProviderOptions.cs | 2 +- dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md | 2 +- .../HyperlightCodeActProviderTests.cs | 11 ++++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs b/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs index a29a11ce0e..32f61cbf7b 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hyperlight/HyperlightCodeActProviderOptions.cs @@ -39,7 +39,7 @@ private HyperlightCodeActProviderOptions(SandboxBackend backend, string? moduleP /// Creates options targeting the backend /// with the bundled Python guest module from the /// Hyperlight.HyperlightSandbox.Guest.Python NuGet package. - /// No explicit module path is required. + /// No explicit module path needs to be provided by the caller. /// public static HyperlightCodeActProviderOptions CreateForPython() => new(SandboxBackend.Wasm, PythonGuestModule.GetModulePath()); diff --git a/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md b/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md index 5eff5fb8e9..f875443560 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md +++ b/dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md @@ -53,7 +53,7 @@ using var executeCode = new HyperlightExecuteCodeFunction( // Built-in JavaScript (QuickJS) — default var jsOptions = HyperlightCodeActProviderOptions.CreateForJavaScript(); -// Custom Wasm guest module see hyperlight-sandbox docs for creating a custom wasm module +// Custom Wasm guest module. See the Hyperlight Sandbox docs for creating a custom Wasm module. var wasmOptions = HyperlightCodeActProviderOptions.CreateForWasm("/path/to/guest.aot"); ``` diff --git a/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs index aef2103abe..7fae5746e2 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Hyperlight.UnitTests/HyperlightCodeActProviderTests.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System.IO; using System.Linq; using Microsoft.Extensions.AI; @@ -179,18 +180,22 @@ public void CreateForPython_SetsWasmBackendAndBundledGuest() // Assert Assert.Equal(HyperlightSandbox.Api.SandboxBackend.Wasm, options.Backend); - Assert.EndsWith("python-sandbox.aot", options.ModulePath); + Assert.False(string.IsNullOrWhiteSpace(options.ModulePath)); + Assert.False(string.IsNullOrWhiteSpace(Path.GetFileName(options.ModulePath))); } [Fact] public void CreateForWasm_SetsWasmBackendAndCustomPath() { + // Arrange + var modulePath = Path.Combine("path", "to", "guest.aot"); + // Act - var options = HyperlightCodeActProviderOptions.CreateForWasm("/path/to/guest.aot"); + var options = HyperlightCodeActProviderOptions.CreateForWasm(modulePath); // Assert Assert.Equal(HyperlightSandbox.Api.SandboxBackend.Wasm, options.Backend); - Assert.Equal("/path/to/guest.aot", options.ModulePath); + Assert.Equal(modulePath, options.ModulePath); } [Fact]