[.Net][AutoGen.DotnetInteractive] add DotnetInteractiveStdioConnector (#3337)

* add DotnetInteractiveStdioCOnector

* update

* update

* comment out DotnetInteractive test

* add header

* update
This commit is contained in:
Xiaoyun Zhang 2024-08-09 18:53:48 -07:00 committed by GitHub
parent 972b4ed024
commit f49ed29b4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 367 additions and 186 deletions

View File

@ -16,7 +16,7 @@ public class RunCodeSnippetCodeSnippet
#region code_snippet_1_1
var kernel = DotnetInteractiveKernelBuilder
.CreateDefaultBuilder() // add C# and F# kernels
.CreateDefaultInProcessKernelBuilder() // add C# and F# kernels
.Build();
#endregion code_snippet_1_1
@ -67,7 +67,7 @@ public class RunCodeSnippetCodeSnippet
#region code_snippet_1_4
var pythonKernel = DotnetInteractiveKernelBuilder
.CreateDefaultBuilder()
.CreateDefaultInProcessKernelBuilder()
.AddPythonKernel(venv: "python3")
.Build();

View File

@ -16,7 +16,7 @@ public partial class Example04_Dynamic_GroupChat_Coding_Task
var instance = new Example04_Dynamic_GroupChat_Coding_Task();
var kernel = DotnetInteractiveKernelBuilder
.CreateDefaultBuilder()
.CreateDefaultInProcessKernelBuilder()
.AddPythonKernel("python3")
.Build();

View File

@ -233,7 +233,9 @@ public partial class Example07_Dynamic_GroupChat_Calculate_Fibonacci
public static async Task RunWorkflowAsync()
{
long the39thFibonacciNumber = 63245986;
var kernel = DotnetInteractiveKernelBuilder.CreateDefaultBuilder().Build();
var kernel = DotnetInteractiveKernelBuilder
.CreateDefaultInProcessKernelBuilder()
.Build();
var config = LLMConfiguration.GetAzureOpenAIGPT3_5_Turbo();
var openaiClient = new OpenAIClient(new Uri(config.Endpoint), new Azure.AzureKeyCredential(config.ApiKey));
@ -344,7 +346,9 @@ public partial class Example07_Dynamic_GroupChat_Calculate_Fibonacci
var config = LLMConfiguration.GetAzureOpenAIGPT3_5_Turbo();
var openaiClient = new OpenAIClient(new Uri(config.Endpoint), new Azure.AzureKeyCredential(config.ApiKey));
var kernel = DotnetInteractiveKernelBuilder.CreateDefaultBuilder().Build();
var kernel = DotnetInteractiveKernelBuilder
.CreateDefaultInProcessKernelBuilder()
.Build();
#region create_group_chat
var reviewer = await CreateReviewerAgentAsync(openaiClient, config.DeploymentName);
var coder = await CreateCoderAgentAsync(openaiClient, config.DeploymentName);

View File

@ -1,127 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// DotnetInteractiveKernelBuilder.cs
#if NET8_0_OR_GREATER
using AutoGen.DotnetInteractive.Extension;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.CSharp;
using Microsoft.DotNet.Interactive.FSharp;
using Microsoft.DotNet.Interactive.Jupyter;
using Microsoft.DotNet.Interactive.PackageManagement;
using Microsoft.DotNet.Interactive.PowerShell;
namespace AutoGen.DotnetInteractive;
public class DotnetInteractiveKernelBuilder
public static class DotnetInteractiveKernelBuilder
{
private readonly CompositeKernel compositeKernel;
private DotnetInteractiveKernelBuilder()
#if NET8_0_OR_GREATER
public static InProccessDotnetInteractiveKernelBuilder CreateEmptyInProcessKernelBuilder()
{
this.compositeKernel = new CompositeKernel();
// add jupyter connector
this.compositeKernel.AddKernelConnector(
new ConnectJupyterKernelCommand()
.AddConnectionOptions(new JupyterHttpKernelConnectionOptions())
.AddConnectionOptions(new JupyterLocalKernelConnectionOptions()));
return new InProccessDotnetInteractiveKernelBuilder();
}
/// <summary>
/// Create an empty builder.
/// </summary>
/// <returns></returns>
public static DotnetInteractiveKernelBuilder CreateEmptyBuilder()
{
return new DotnetInteractiveKernelBuilder();
}
/// <summary>
/// Create a default builder with C# and F# kernels.
/// </summary>
public static DotnetInteractiveKernelBuilder CreateDefaultBuilder()
public static InProccessDotnetInteractiveKernelBuilder CreateDefaultInProcessKernelBuilder()
{
return new DotnetInteractiveKernelBuilder()
return new InProccessDotnetInteractiveKernelBuilder()
.AddCSharpKernel()
.AddFSharpKernel();
}
#endif
public DotnetInteractiveKernelBuilder AddCSharpKernel(IEnumerable<string>? aliases = null)
public static DotnetInteractiveStdioKernelConnector CreateKernelBuilder(string workingDirectory, string kernelName = "root-proxy")
{
aliases ??= ["c#", "C#"];
// create csharp kernel
var csharpKernel = new CSharpKernel()
.UseNugetDirective((k, resolvedPackageReference) =>
{
k.AddAssemblyReferences(resolvedPackageReference
.SelectMany(r => r.AssemblyPaths));
return Task.CompletedTask;
})
.UseKernelHelpers()
.UseWho()
.UseMathAndLaTeX()
.UseValueSharing();
this.AddKernel(csharpKernel, aliases);
return this;
}
public DotnetInteractiveKernelBuilder AddFSharpKernel(IEnumerable<string>? aliases = null)
{
aliases ??= ["f#", "F#"];
// create fsharp kernel
var fsharpKernel = new FSharpKernel()
.UseDefaultFormatting()
.UseKernelHelpers()
.UseWho()
.UseMathAndLaTeX()
.UseValueSharing();
this.AddKernel(fsharpKernel, aliases);
return this;
}
public DotnetInteractiveKernelBuilder AddPowershellKernel(IEnumerable<string>? aliases = null)
{
aliases ??= ["pwsh", "powershell"];
// create powershell kernel
var powershellKernel = new PowerShellKernel()
.UseProfiles()
.UseValueSharing();
this.AddKernel(powershellKernel, aliases);
return this;
}
public DotnetInteractiveKernelBuilder AddPythonKernel(string venv, string kernelName = "python", IEnumerable<string>? aliases = null)
{
aliases ??= [kernelName];
// create python kernel
var magicCommand = $"#!connect jupyter --kernel-name {kernelName} --kernel-spec {venv}";
var connectCommand = new SubmitCode(magicCommand);
var result = this.compositeKernel.SendAsync(connectCommand).Result;
result.ThrowOnCommandFailed();
return this;
}
public CompositeKernel Build()
{
return this.compositeKernel
.UseDefaultMagicCommands()
.UseImportMagicCommand();
}
private DotnetInteractiveKernelBuilder AddKernel(Kernel kernel, IEnumerable<string>? aliases = null)
{
this.compositeKernel.Add(kernel, aliases);
return this;
return new DotnetInteractiveStdioKernelConnector(workingDirectory, kernelName);
}
}
#endif

View File

@ -0,0 +1,86 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// DotnetInteractiveStdioKernelConnector.cs
using AutoGen.DotnetInteractive.Extension;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Connection;
namespace AutoGen.DotnetInteractive;
public class DotnetInteractiveStdioKernelConnector
{
private string workingDirectory;
private InteractiveService interactiveService;
private string kernelName;
private List<SubmitCode> setupCommands = new List<SubmitCode>();
internal DotnetInteractiveStdioKernelConnector(string workingDirectory, string kernelName = "root-proxy")
{
this.workingDirectory = workingDirectory;
this.interactiveService = new InteractiveService(workingDirectory);
this.kernelName = kernelName;
}
public DotnetInteractiveStdioKernelConnector RestoreDotnetInteractive()
{
if (this.interactiveService.RestoreDotnetInteractive())
{
return this;
}
else
{
throw new Exception("Failed to restore dotnet interactive tool.");
}
}
public DotnetInteractiveStdioKernelConnector AddPythonKernel(
string venv,
string kernelName = "python")
{
var magicCommand = $"#!connect jupyter --kernel-name {kernelName} --kernel-spec {venv}";
var connectCommand = new SubmitCode(magicCommand);
this.setupCommands.Add(connectCommand);
return this;
}
public async Task<Kernel> BuildAsync(CancellationToken ct = default)
{
var compositeKernel = new CompositeKernel();
var url = KernelHost.CreateHostUri(this.kernelName);
var cmd = new string[]
{
"dotnet",
"tool",
"run",
"dotnet-interactive",
$"[cb-{this.kernelName}]",
"stdio",
//"--default-kernel",
//"csharp",
"--working-dir",
$@"""{workingDirectory}""",
};
var connector = new StdIoKernelConnector(
cmd,
this.kernelName,
url,
new DirectoryInfo(this.workingDirectory));
var rootProxyKernel = await connector.CreateRootProxyKernelAsync();
rootProxyKernel.KernelInfo.SupportedKernelCommands.Add(new(nameof(SubmitCode)));
var dotnetKernel = await connector.CreateProxyKernelAsync(".NET");
foreach (var setupCommand in this.setupCommands)
{
var setupCommandResult = await rootProxyKernel.SendAsync(setupCommand, ct);
setupCommandResult.ThrowOnCommandFailed();
}
return rootProxyKernel;
}
}

View File

@ -0,0 +1,110 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// InProccessDotnetInteractiveKernelBuilder.cs
#if NET8_0_OR_GREATER
using AutoGen.DotnetInteractive.Extension;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.CSharp;
using Microsoft.DotNet.Interactive.FSharp;
using Microsoft.DotNet.Interactive.Jupyter;
using Microsoft.DotNet.Interactive.PackageManagement;
using Microsoft.DotNet.Interactive.PowerShell;
namespace AutoGen.DotnetInteractive;
/// <summary>
/// Build an in-proc dotnet interactive kernel.
/// </summary>
public class InProccessDotnetInteractiveKernelBuilder
{
private readonly CompositeKernel compositeKernel;
internal InProccessDotnetInteractiveKernelBuilder()
{
this.compositeKernel = new CompositeKernel();
// add jupyter connector
this.compositeKernel.AddKernelConnector(
new ConnectJupyterKernelCommand()
.AddConnectionOptions(new JupyterHttpKernelConnectionOptions())
.AddConnectionOptions(new JupyterLocalKernelConnectionOptions()));
}
public InProccessDotnetInteractiveKernelBuilder AddCSharpKernel(IEnumerable<string>? aliases = null)
{
aliases ??= ["c#", "C#", "csharp"];
// create csharp kernel
var csharpKernel = new CSharpKernel()
.UseNugetDirective((k, resolvedPackageReference) =>
{
k.AddAssemblyReferences(resolvedPackageReference
.SelectMany(r => r.AssemblyPaths));
return Task.CompletedTask;
})
.UseKernelHelpers()
.UseWho()
.UseMathAndLaTeX()
.UseValueSharing();
this.AddKernel(csharpKernel, aliases);
return this;
}
public InProccessDotnetInteractiveKernelBuilder AddFSharpKernel(IEnumerable<string>? aliases = null)
{
aliases ??= ["f#", "F#", "fsharp"];
// create fsharp kernel
var fsharpKernel = new FSharpKernel()
.UseDefaultFormatting()
.UseKernelHelpers()
.UseWho()
.UseMathAndLaTeX()
.UseValueSharing();
this.AddKernel(fsharpKernel, aliases);
return this;
}
public InProccessDotnetInteractiveKernelBuilder AddPowershellKernel(IEnumerable<string>? aliases = null)
{
aliases ??= ["pwsh", "powershell"];
// create powershell kernel
var powershellKernel = new PowerShellKernel()
.UseProfiles()
.UseValueSharing();
this.AddKernel(powershellKernel, aliases);
return this;
}
public InProccessDotnetInteractiveKernelBuilder AddPythonKernel(string venv, string kernelName = "python")
{
// create python kernel
var magicCommand = $"#!connect jupyter --kernel-name {kernelName} --kernel-spec {venv}";
var connectCommand = new SubmitCode(magicCommand);
var result = this.compositeKernel.SendAsync(connectCommand).Result;
result.ThrowOnCommandFailed();
return this;
}
public CompositeKernel Build()
{
return this.compositeKernel
.UseDefaultMagicCommands()
.UseImportMagicCommand();
}
private InProccessDotnetInteractiveKernelBuilder AddKernel(Kernel kernel, IEnumerable<string>? aliases = null)
{
this.compositeKernel.Add(kernel, aliases);
return this;
}
}
#endif

View File

@ -1,82 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// DotnetInteractiveServiceTest.cs
using FluentAssertions;
using Xunit;
using Xunit.Abstractions;
//using FluentAssertions;
//using Xunit;
//using Xunit.Abstractions;
namespace AutoGen.DotnetInteractive.Tests;
//namespace AutoGen.DotnetInteractive.Tests;
public class DotnetInteractiveServiceTest : IDisposable
{
private ITestOutputHelper _output;
private InteractiveService _interactiveService;
private string _workingDir;
//public class DotnetInteractiveServiceTest : IDisposable
//{
// private ITestOutputHelper _output;
// private InteractiveService _interactiveService;
// private string _workingDir;
public DotnetInteractiveServiceTest(ITestOutputHelper output)
{
_output = output;
_workingDir = Path.Combine(Path.GetTempPath(), "test", Path.GetRandomFileName());
if (!Directory.Exists(_workingDir))
{
Directory.CreateDirectory(_workingDir);
}
// public DotnetInteractiveServiceTest(ITestOutputHelper output)
// {
// _output = output;
// _workingDir = Path.Combine(Path.GetTempPath(), "test", Path.GetRandomFileName());
// if (!Directory.Exists(_workingDir))
// {
// Directory.CreateDirectory(_workingDir);
// }
_interactiveService = new InteractiveService(_workingDir);
_interactiveService.StartAsync(_workingDir, default).Wait();
}
// _interactiveService = new InteractiveService(_workingDir);
// _interactiveService.StartAsync(_workingDir, default).Wait();
// }
public void Dispose()
{
_interactiveService.Dispose();
}
// public void Dispose()
// {
// _interactiveService.Dispose();
// }
[Fact]
public async Task ItRunCSharpCodeSnippetTestsAsync()
{
var cts = new CancellationTokenSource();
var isRunning = await _interactiveService.StartAsync(_workingDir, cts.Token);
// [Fact]
// public async Task ItRunCSharpCodeSnippetTestsAsync()
// {
// var cts = new CancellationTokenSource();
// var isRunning = await _interactiveService.StartAsync(_workingDir, cts.Token);
isRunning.Should().BeTrue();
// isRunning.Should().BeTrue();
_interactiveService.IsRunning().Should().BeTrue();
// _interactiveService.IsRunning().Should().BeTrue();
// test code snippet
var hello_world = @"
Console.WriteLine(""hello world"");
";
// // test code snippet
// var hello_world = @"
//Console.WriteLine(""hello world"");
//";
await this.TestCSharpCodeSnippet(_interactiveService, hello_world, "hello world");
await this.TestCSharpCodeSnippet(
_interactiveService,
code: @"
Console.WriteLine(""hello world""
",
expectedOutput: "Error: (2,32): error CS1026: ) expected");
// await this.TestCSharpCodeSnippet(_interactiveService, hello_world, "hello world");
// await this.TestCSharpCodeSnippet(
// _interactiveService,
// code: @"
//Console.WriteLine(""hello world""
//",
// expectedOutput: "Error: (2,32): error CS1026: ) expected");
await this.TestCSharpCodeSnippet(
service: _interactiveService,
code: "throw new Exception();",
expectedOutput: "Error: System.Exception: Exception of type 'System.Exception' was thrown");
}
// await this.TestCSharpCodeSnippet(
// service: _interactiveService,
// code: "throw new Exception();",
// expectedOutput: "Error: System.Exception: Exception of type 'System.Exception' was thrown");
// }
[Fact]
public async Task ItRunPowershellScriptTestsAsync()
{
// test power shell
var ps = @"Write-Output ""hello world""";
await this.TestPowershellCodeSnippet(_interactiveService, ps, "hello world");
}
// [Fact]
// public async Task ItRunPowershellScriptTestsAsync()
// {
// // test power shell
// var ps = @"Write-Output ""hello world""";
// await this.TestPowershellCodeSnippet(_interactiveService, ps, "hello world");
// }
private async Task TestPowershellCodeSnippet(InteractiveService service, string code, string expectedOutput)
{
var result = await service.SubmitPowershellCodeAsync(code, CancellationToken.None);
result.Should().StartWith(expectedOutput);
}
// private async Task TestPowershellCodeSnippet(InteractiveService service, string code, string expectedOutput)
// {
// var result = await service.SubmitPowershellCodeAsync(code, CancellationToken.None);
// result.Should().StartWith(expectedOutput);
// }
private async Task TestCSharpCodeSnippet(InteractiveService service, string code, string expectedOutput)
{
var result = await service.SubmitCSharpCodeAsync(code, CancellationToken.None);
result.Should().StartWith(expectedOutput);
}
}
// private async Task TestCSharpCodeSnippet(InteractiveService service, string code, string expectedOutput)
// {
// var result = await service.SubmitCSharpCodeAsync(code, CancellationToken.None);
// result.Should().StartWith(expectedOutput);
// }
//}

View File

@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// DotnetInteractiveStdioKernelConnectorTests.cs
using AutoGen.DotnetInteractive.Extension;
using FluentAssertions;
using Microsoft.DotNet.Interactive;
using Xunit;
using Xunit.Abstractions;
namespace AutoGen.DotnetInteractive.Tests;
[Collection("Sequential")]
public class DotnetInteractiveStdioKernelConnectorTests
{
private string _workingDir;
private Kernel kernel;
public DotnetInteractiveStdioKernelConnectorTests(ITestOutputHelper output)
{
_workingDir = Path.Combine(Path.GetTempPath(), "test", Path.GetRandomFileName());
if (!Directory.Exists(_workingDir))
{
Directory.CreateDirectory(_workingDir);
}
kernel = DotnetInteractiveKernelBuilder
.CreateKernelBuilder(_workingDir)
.RestoreDotnetInteractive()
.AddPythonKernel("python3")
.BuildAsync().Result;
}
[Fact]
public async Task ItAddCSharpKernelTestAsync()
{
var csharpCode = """
#r "nuget:Microsoft.ML, 1.5.2"
var str = "Hello" + ", World!";
Console.WriteLine(str);
""";
var result = await this.kernel.RunSubmitCodeCommandAsync(csharpCode, "csharp");
result.Should().Contain("Hello, World!");
}
[Fact]
public async Task ItAddPowershellKernelTestAsync()
{
var powershellCode = @"
Write-Host 'Hello, World!'
";
var result = await this.kernel.RunSubmitCodeCommandAsync(powershellCode, "pwsh");
result.Should().Contain("Hello, World!");
}
[Fact]
public async Task ItAddFSharpKernelTestAsync()
{
var fsharpCode = """
printfn "Hello, World!"
""";
var result = await this.kernel.RunSubmitCodeCommandAsync(fsharpCode, "fsharp");
result.Should().Contain("Hello, World!");
}
[Fact]
public async Task ItAddPythonKernelTestAsync()
{
var pythonCode = """
%pip install numpy
str = 'Hello' + ', World!'
print(str)
""";
var result = await this.kernel.RunSubmitCodeCommandAsync(pythonCode, "python");
result.Should().Contain("Hello, World!");
}
}

View File

@ -1,5 +1,5 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// DotnetInteractiveKernelBuilderTest.cs
// InProcessDotnetInteractiveKernelBuilderTest.cs
using AutoGen.DotnetInteractive.Extension;
using FluentAssertions;
@ -7,13 +7,13 @@ using Xunit;
namespace AutoGen.DotnetInteractive.Tests;
public class DotnetInteractiveKernelBuilderTest
public class InProcessDotnetInteractiveKernelBuilderTest
{
[Fact]
public async Task ItAddCSharpKernelTestAsync()
{
var kernel = DotnetInteractiveKernelBuilder
.CreateEmptyBuilder()
.CreateEmptyInProcessKernelBuilder()
.AddCSharpKernel()
.Build();
@ -22,7 +22,7 @@ public class DotnetInteractiveKernelBuilderTest
Console.WriteLine("Hello, World!");
""";
var result = await kernel.RunSubmitCodeCommandAsync(csharpCode, "C#");
var result = await kernel.RunSubmitCodeCommandAsync(csharpCode, "csharp");
result.Should().Contain("Hello, World!");
}
@ -30,7 +30,7 @@ public class DotnetInteractiveKernelBuilderTest
public async Task ItAddPowershellKernelTestAsync()
{
var kernel = DotnetInteractiveKernelBuilder
.CreateEmptyBuilder()
.CreateEmptyInProcessKernelBuilder()
.AddPowershellKernel()
.Build();
@ -46,7 +46,7 @@ public class DotnetInteractiveKernelBuilderTest
public async Task ItAddFSharpKernelTestAsync()
{
var kernel = DotnetInteractiveKernelBuilder
.CreateEmptyBuilder()
.CreateEmptyInProcessKernelBuilder()
.AddFSharpKernel()
.Build();
@ -55,7 +55,7 @@ public class DotnetInteractiveKernelBuilderTest
printfn "Hello, World!"
""";
var result = await kernel.RunSubmitCodeCommandAsync(fsharpCode, "F#");
var result = await kernel.RunSubmitCodeCommandAsync(fsharpCode, "fsharp");
result.Should().Contain("Hello, World!");
}
@ -63,7 +63,7 @@ public class DotnetInteractiveKernelBuilderTest
public async Task ItAddPythonKernelTestAsync()
{
var kernel = DotnetInteractiveKernelBuilder
.CreateEmptyBuilder()
.CreateEmptyInProcessKernelBuilder()
.AddPythonKernel("python3")
.Build();