Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<PackageVersion Include="ModelContextProtocol" Version="1.1.0" />
<!-- Hyperlight -->
<PackageVersion Include="Hyperlight.HyperlightSandbox.Api" Version="0.4.0" />
<PackageVersion Include="Hyperlight.HyperlightSandbox.Guest.Python" Version="0.4.0" />
<!-- Inference SDKs -->
<PackageVersion Include="Microsoft.ML.OnnxRuntimeGenAI" Version="0.10.0" />
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="2.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ public sealed class HyperlightCodeActProvider : AIContextProvider, IDisposable
/// Optional configuration options for the provider. When <see langword="null"/> the provider
/// uses the defaults of <see cref="HyperlightCodeActProviderOptions"/> (the
/// <see cref="HyperlightSandbox.Api.SandboxBackend.JavaScript"/> backend with no tools, mounts, or allow-list entries).
/// Use <see cref="HyperlightCodeActProviderOptions.CreateForWasm(string)"/> to target a Wasm
/// guest module instead.
/// Use <see cref="HyperlightCodeActProviderOptions.CreateForPython()"/> for the bundled Python
/// guest module, or <see cref="HyperlightCodeActProviderOptions.CreateForWasm(string)"/> for a
/// custom Wasm guest.
/// </param>
public HyperlightCodeActProvider(HyperlightCodeActProviderOptions? options = null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System.Collections.Generic;
using HyperlightSandbox.Api;
using HyperlightSandbox.Guest.Python;
using Microsoft.Extensions.AI;
using Microsoft.Shared.Diagnostics;

Expand All @@ -12,8 +13,9 @@ namespace Microsoft.Agents.AI.Hyperlight;
/// <see cref="HyperlightExecuteCodeFunction"/>.
/// </summary>
/// <remarks>
/// Use the <see cref="CreateForWasm(string)"/> and <see cref="CreateForJavaScript()"/>
/// factory methods to construct an instance with the desired sandbox backend.
/// Use the <see cref="CreateForPython()"/>, <see cref="CreateForWasm(string)"/>,
/// and <see cref="CreateForJavaScript()"/> factory methods to construct an instance
/// with the desired sandbox backend.
/// The parameterless constructor is equivalent to <see cref="CreateForJavaScript()"/>.
/// </remarks>
public sealed class HyperlightCodeActProviderOptions
Expand All @@ -34,7 +36,17 @@ private HyperlightCodeActProviderOptions(SandboxBackend backend, string? moduleP
}

/// <summary>
/// Creates options targeting the <see cref="SandboxBackend.Wasm"/> backend.
/// Creates options targeting the <see cref="SandboxBackend.Wasm"/> backend
/// with the bundled Python guest module from the
/// <c>Hyperlight.HyperlightSandbox.Guest.Python</c> NuGet package.
/// No explicit module path needs to be provided by the caller.
/// </summary>
public static HyperlightCodeActProviderOptions CreateForPython()
=> new(SandboxBackend.Wasm, PythonGuestModule.GetModulePath());

/// <summary>
/// Creates options targeting the <see cref="SandboxBackend.Wasm"/> backend
/// with a custom guest module.
/// </summary>
/// <param name="modulePath">Path to the guest module (<c>.wasm</c> or <c>.aot</c> file).</param>
public static HyperlightCodeActProviderOptions CreateForWasm(string modulePath)
Expand All @@ -53,7 +65,8 @@ public static HyperlightCodeActProviderOptions CreateForJavaScript()

/// <summary>
/// Gets the path to the guest module. Set when the options were created via
/// <see cref="CreateForWasm(string)"/>; <see langword="null"/> otherwise.
/// <see cref="CreateForPython()"/> or <see cref="CreateForWasm(string)"/>;
/// <see langword="null"/> when using the built-in JavaScript backend.
/// </summary>
public string? ModulePath { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<ItemGroup>
<PackageReference Include="Hyperlight.HyperlightSandbox.Api" />
<PackageReference Include="Hyperlight.HyperlightSandbox.Guest.Python" />
</ItemGroup>

<ItemGroup>
Expand Down
45 changes: 38 additions & 7 deletions dotnet/src/Microsoft.Agents.AI.Hyperlight/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 the 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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

using System.IO;
using System.Linq;
using Microsoft.Extensions.AI;

Expand Down Expand Up @@ -170,4 +171,71 @@ public void Dispose_IsIdempotentAndBlocksFurtherAddTools()
// Assert
Assert.Throws<System.ObjectDisposedException>(() => provider.AddTools(tool));
}

[Fact]
public void CreateForPython_SetsWasmBackendAndBundledGuest()
{
// Act
var options = HyperlightCodeActProviderOptions.CreateForPython();

// Assert
Assert.Equal(HyperlightSandbox.Api.SandboxBackend.Wasm, options.Backend);
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(modulePath);

// Assert
Assert.Equal(HyperlightSandbox.Api.SandboxBackend.Wasm, options.Backend);
Assert.Equal(modulePath, 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());
}
}
Loading