1. Wasmtime
  2. Requirements
  3. Plugin Implementation
  4. Result
  5. Conclusion
  6. Next steps

This article outlines the implementation of a Semantic Kernel plugin, which leverages Wasmtime to execute Python code generated from an LLM. The plugin facilitates running Python scripts securely and efficiently, adhering to the sandboxing principles of Wasmtime.

Wasmtime

Wasmtime is a high-performance WebAssembly runtime for applications written in C, C++, Rust, and other system programming languages. It provides a safe and efficient way to execute code in a sandboxed environment, making it ideal for running untrusted code like user-provided or LLM-generated scripts.

In the context of the plugin, Wasmtime is used to run Python scripts. The plugin defines the necessary Wasi configuration to provide a Python environment for the scripts to execute in.

Requirements

The plugin will require the following packages for C#: Microsoft.SemanticKernel and Wasmtime.
To run a Python CLI in WebAssembly, a Wasi implementation is needed. The directory structure could look like the following:

1
2
3
4
5
6
7
8
9
10
11
Project
├───Plugin.cs
├───Project.csproj
└───Resources
└───Python
├───lib
│ └───python3.13
│ ├───asyncio
│ ├───collections
│ └───...
└───python3.13.wasm

In this case, the folder Resources is copied to the output directory.

Plugin Implementation

The plugin can be organized in two separate functions: RunScriptAsync and RunCodeAsync. The former takes care of running a single script file in the Python interpreter running on Wasmtime and the latter is a Semantic Kernel function that receives the code from the LLM plan.

Plugin.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private async Task<string> RunScriptAsync(string dir, string file, string stdout)
{
using var engine = new Engine();
using var store = new Store(engine);
using var linker = new Linker(engine);
linker.DefineWasi();

using var module = Module.FromFile(engine, "Resources\\Python\\python3.13.wasm");

var wasiConfig = new WasiConfiguration()
.WithArgs("-c", "/scripts/" + file)
.WithPreopenedDirectory("Resources/Python/lib", "/usr/local/lib")
.WithPreopenedDirectory(dir, "/scripts")
.WithInheritedStandardError()
.WithStandardOutput(stdout);
store.SetWasiConfiguration(wasiConfig);

var instance = linker.Instantiate(store, module);
instance.GetFunction("_start")!.Invoke();
return stdout;
}
  1. RunScriptAsync: This method handles the execution of a Python script using Wasmtime. It takes the script’s directory, file name, and the desired standard output file as input. The method performs the following steps:

    • Initializes a Wasmtime engine, store, and linker.
    • Defines the Wasi environment for the script to run in.
    • Loads the Python WebAssembly module (python3.13.wasm).
    • Configures the Wasi environment with the script’s directory, Python library paths, and standard output.
    • Instantiates the WebAssembly module and invokes the _start function to execute the script.
    • Returns the standard output of the script.
Plugin.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[KernelFunction("run_code")]
[Description("Runs a script in Python language and returns the standard output")]
[return: Description("The standard output of the script execution")]
public async Task<string> RunCodeAsync(
[Description("The code in Python language to be executed")]
string code,
CancellationToken cancellationToken)
{
var temp = Path.GetTempFileName();
var lines = code.Replace("\"", "'").Split("\\n");
await File.WriteAllLinesAsync(temp, lines, cancellationToken);
var tempDir = Path.GetDirectoryName(temp) ?? string.Empty;
var tempFile = Path.GetFileName(temp);
var outFile = Path.GetTempFileName();
var fileOut = await RunScript(tempDir, tempFile, outFile);
return await File.ReadAllTextAsync(fileOut, cancellationToken);
}
  1. RunCodeAsync: This method is the entry point for the Semantic Kernel plugin. It takes a string of Python code as input, writes it to a temporary file, and then calls RunScriptAsync to execute the script. The method performs the following steps:

    • Replaces any double quotes in the input Python code with single quotes for safe file writing.
    • Splits the code into lines and writes it to a temporary file.
    • Retrieves the temporary file’s directory and name.
    • Calls RunScriptAsync to execute the script, passing the temporary directory, file name, and another temporary file for standard output.
    • Reads the standard output from the temporary file and returns it.

Result

Example output from a console application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
User > 
What is the 10th number of the Fibonacci sequence? You can write and execute a Python script for the answer
Microsoft.SemanticKernel.KernelFunction: Information: Function Code-run_code invoking.
info: Microsoft.SemanticKernel.KernelFunction[0]
Function Code-run_code invoking.
trce: Microsoft.SemanticKernel.KernelFunction[0]
Function Code-run_code arguments: {"code":"def fib(n):\n a, b = 0, 1\n for _ in range(n):\n a, b = b, a \u002B b\n return a\n\nprint(fib(10))"}
Microsoft.SemanticKernel.KernelFunction: Trace: Function Code-run_code arguments: {"code":"def fib(n):\n a, b = 0, 1\n for _ in range(n):\n a, b = b, a \u002B b\n return a\n\nprint(fib(10))"}
Microsoft.SemanticKernel.KernelFunction: Information: Function Code-run_code succeeded.
info: Microsoft.SemanticKernel.KernelFunction[0]
Function Code-run_code succeeded.
Microsoft.SemanticKernel.KernelFunction: Trace: Function Code-run_code result: 55
trce: Microsoft.SemanticKernel.KernelFunction[0]
Function Code-run_code result: 55
info: Microsoft.SemanticKernel.KernelFunction[0]
Function Code-run_code completed. Duration: 6.6005792s
Microsoft.SemanticKernel.KernelFunction: Information: Function Code-run_code completed. Duration: 6.6005792s
Assistant > The 10th number in the Fibonacci sequence is 55.

Conclusion

The plugin demonstrates how to use Wasmtime to execute Python code within a sandboxed environment as a Semantic Kernel plugin in C#. By leveraging Wasmtime’s WebAssembly support and Wasi configuration, the plugin enables secure and efficient execution of user-provided Python scripts, adhering to the principles of sandboxing and code isolation.

Next steps

  • Avoid using files to communicate with the Python interpreter
  • Have proper socket support in the Python interpreter on WebAssembly
  • Create an agent that can use the plugin to iterate on code to fit the user request
  • Consider using interpreters other than Python