Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[.Net] Fix #2660 and add tests for AutoGen.DotnetInteractive #2676

Merged
merged 4 commits into from
May 14, 2024
Merged
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
9 changes: 8 additions & 1 deletion dotnet/AutoGen.sln
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.Mistral", "src\Auto
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.Mistral.Tests", "test\AutoGen.Mistral.Tests\AutoGen.Mistral.Tests.csproj", "{15441693-3659-4868-B6C1-B106F52FF3BA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.SemanticKernel.Tests", "test\AutoGen.SemanticKernel.Tests\AutoGen.SemanticKernel.Tests.csproj", "{1DFABC4A-8458-4875-8DCB-59F3802DAC65}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.SemanticKernel.Tests", "test\AutoGen.SemanticKernel.Tests\AutoGen.SemanticKernel.Tests.csproj", "{1DFABC4A-8458-4875-8DCB-59F3802DAC65}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoGen.DotnetInteractive.Tests", "test\AutoGen.DotnetInteractive.Tests\AutoGen.DotnetInteractive.Tests.csproj", "{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -93,6 +95,10 @@ Global
{1DFABC4A-8458-4875-8DCB-59F3802DAC65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DFABC4A-8458-4875-8DCB-59F3802DAC65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DFABC4A-8458-4875-8DCB-59F3802DAC65}.Release|Any CPU.Build.0 = Release|Any CPU
{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -111,6 +117,7 @@ Global
{6585D1A4-3D97-4D76-A688-1933B61AEB19} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
{15441693-3659-4868-B6C1-B106F52FF3BA} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
{1DFABC4A-8458-4875-8DCB-59F3802DAC65} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
{B61388CA-DC73-4B7F-A7B2-7B9A86C9229E} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}
Expand Down
2 changes: 0 additions & 2 deletions dotnet/NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
<configuration>
<packageSources>
<clear />
<add key="dotnet-public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
<add key="dotnet-tools" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" />
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<disabledPackageSources />
Expand Down
2 changes: 1 addition & 1 deletion dotnet/eng/Version.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<FluentAssertionVersion>6.8.0</FluentAssertionVersion>
<XUnitVersion>2.4.2</XUnitVersion>
<MicrosoftNETTestSdkVersion>17.7.0</MicrosoftNETTestSdkVersion>
<MicrosoftDotnetInteractive>1.0.0-beta.23523.2</MicrosoftDotnetInteractive>
<MicrosoftDotnetInteractive>1.0.0-beta.24229.4</MicrosoftDotnetInteractive>
<MicrosoftSourceLinkGitHubVersion>8.0.0</MicrosoftSourceLinkGitHubVersion>
<JsonSchemaVersion>4.0.0</JsonSchemaVersion>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,20 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.DotNet.Interactive.VisualStudio" Version="$(MicrosoftDotnetInteractive)" />
<PackageReference Include="Microsoft.DotNet.Interactive" Version="$(MicrosoftDotnetInteractive)" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="dotnet-tools.json" />
<EmbeddedResource Include="RestoreInteractive.config" />
</ItemGroup>


<ItemGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="$(AzureOpenAIVersion)" />
</ItemGroup>


<ItemGroup>
<ProjectReference Include="..\AutoGen\AutoGen.csproj" />
<ProjectReference Include="..\AutoGen.Core\AutoGen.Core.csproj" />
</ItemGroup>

</Project>
71 changes: 36 additions & 35 deletions dotnet/src/AutoGen.DotnetInteractive/DotnetInteractiveFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,58 @@ namespace AutoGen.DotnetInteractive;
public class DotnetInteractiveFunction : IDisposable
{
private readonly InteractiveService? _interactiveService = null;
private string? _notebookPath;
private string _notebookPath;
private readonly KernelInfoCollection _kernelInfoCollection = new KernelInfoCollection();

/// <summary>
/// Create an instance of <see cref="DotnetInteractiveFunction"/>"
/// </summary>
/// <param name="interactiveService">interactive service to use.</param>
/// <param name="notebookPath">notebook path if provided.</param>
public DotnetInteractiveFunction(InteractiveService interactiveService, string? notebookPath = null, bool continueFromExistingNotebook = false)
{
this._interactiveService = interactiveService;
this._notebookPath = notebookPath;
this._notebookPath = notebookPath ?? Path.GetTempPath() + "notebook.ipynb";
this._kernelInfoCollection.Add(new KernelInfo("csharp"));
this._kernelInfoCollection.Add(new KernelInfo("markdown"));

if (this._notebookPath != null)
if (continueFromExistingNotebook == false)
{
if (continueFromExistingNotebook == false)
// remove existing notebook
if (File.Exists(this._notebookPath))
{
// remove existing notebook
if (File.Exists(this._notebookPath))
{
File.Delete(this._notebookPath);
}
File.Delete(this._notebookPath);
}

var document = new InteractiveDocument();
var document = new InteractiveDocument();

using var stream = File.OpenWrite(_notebookPath);
Notebook.Write(document, stream, this._kernelInfoCollection);
stream.Flush();
stream.Dispose();
}
else if (continueFromExistingNotebook == true && File.Exists(this._notebookPath))
using var stream = File.OpenWrite(_notebookPath);
Notebook.Write(document, stream, this._kernelInfoCollection);
stream.Flush();
stream.Dispose();
}
else if (continueFromExistingNotebook == true && File.Exists(this._notebookPath))
{
// load existing notebook
using var readStream = File.OpenRead(this._notebookPath);
var document = Notebook.Read(readStream, this._kernelInfoCollection);
foreach (var cell in document.Elements)
{
// load existing notebook
using var readStream = File.OpenRead(this._notebookPath);
var document = Notebook.Read(readStream, this._kernelInfoCollection);
foreach (var cell in document.Elements)
if (cell.KernelName == "csharp")
{
if (cell.KernelName == "csharp")
{
var code = cell.Contents;
this._interactiveService.SubmitCSharpCodeAsync(code, default).Wait();
}
var code = cell.Contents;
this._interactiveService.SubmitCSharpCodeAsync(code, default).Wait();
}
}
else
{
// create an empty notebook
var document = new InteractiveDocument();
}
else
{
// create an empty notebook
var document = new InteractiveDocument();

using var stream = File.OpenWrite(_notebookPath);
Notebook.Write(document, stream, this._kernelInfoCollection);
stream.Flush();
stream.Dispose();
}
using var stream = File.OpenWrite(_notebookPath);
Notebook.Write(document, stream, this._kernelInfoCollection);
stream.Flush();
stream.Dispose();
}
}

Expand Down
97 changes: 48 additions & 49 deletions dotnet/src/AutoGen.DotnetInteractive/InteractiveService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Reactive.Linq;
using System.Reflection;
using Microsoft.DotNet.Interactive;
using Microsoft.DotNet.Interactive.App.Connection;
using Microsoft.DotNet.Interactive.Commands;
using Microsoft.DotNet.Interactive.Connection;
using Microsoft.DotNet.Interactive.Events;
Expand Down Expand Up @@ -41,7 +40,7 @@ public InteractiveService(string installingDirectory)

public async Task<bool> StartAsync(string workingDirectory, CancellationToken ct = default)
{
this.kernel = await this.CreateKernelAsync(workingDirectory, ct);
this.kernel = await this.CreateKernelAsync(workingDirectory, true, ct);
return true;
}

Expand Down Expand Up @@ -84,7 +83,51 @@ public async Task<bool> StartAsync(string workingDirectory, CancellationToken ct
return await this.SubmitCommandAsync(command, ct);
}

private async Task<Kernel> CreateKernelAsync(string workingDirectory, CancellationToken ct = default)
public bool RestoreDotnetInteractive()
{
this.WriteLine("Restore dotnet interactive tool");
// write RestoreInteractive.config from embedded resource to this.workingDirectory
var assembly = Assembly.GetAssembly(typeof(InteractiveService))!;
var resourceName = "AutoGen.DotnetInteractive.RestoreInteractive.config";
using (var stream = assembly.GetManifestResourceStream(resourceName)!)
using (var fileStream = File.Create(Path.Combine(this.installingDirectory, "RestoreInteractive.config")))
{
stream.CopyTo(fileStream);
}

// write dotnet-tool.json from embedded resource to this.workingDirectory

resourceName = "AutoGen.DotnetInteractive.dotnet-tools.json";
using (var stream2 = assembly.GetManifestResourceStream(resourceName)!)
using (var fileStream2 = File.Create(Path.Combine(this.installingDirectory, "dotnet-tools.json")))
{
stream2.CopyTo(fileStream2);
}

var psi = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = $"tool restore --configfile RestoreInteractive.config",
WorkingDirectory = this.installingDirectory,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};

using var process = new Process { StartInfo = psi };
process.OutputDataReceived += this.PrintProcessOutput;
process.ErrorDataReceived += this.PrintProcessOutput;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();

return process.ExitCode == 0;
}

private async Task<Kernel> CreateKernelAsync(string workingDirectory, bool restoreWhenFail = true, CancellationToken ct = default)
{
try
{
Expand Down Expand Up @@ -139,13 +182,13 @@ await rootProxyKernel.SendAsync(

return compositeKernel;
}
catch (CommandLineInvocationException ex) when (ex.Message.Contains("Cannot find a tool in the manifest file that has a command named 'dotnet-interactive'"))
catch (CommandLineInvocationException) when (restoreWhenFail)
{
var success = this.RestoreDotnetInteractive();

if (success)
{
return await this.CreateKernelAsync(workingDirectory, ct);
return await this.CreateKernelAsync(workingDirectory, false, ct);
}

throw;
Expand Down Expand Up @@ -176,50 +219,6 @@ private void WriteLine(string data)
this.Output?.Invoke(this, data);
}

private bool RestoreDotnetInteractive()
{
this.WriteLine("Restore dotnet interactive tool");
// write RestoreInteractive.config from embedded resource to this.workingDirectory
var assembly = Assembly.GetAssembly(typeof(InteractiveService))!;
var resourceName = "AutoGen.DotnetInteractive.RestoreInteractive.config";
using (var stream = assembly.GetManifestResourceStream(resourceName)!)
using (var fileStream = File.Create(Path.Combine(this.installingDirectory, "RestoreInteractive.config")))
{
stream.CopyTo(fileStream);
}

// write dotnet-tool.json from embedded resource to this.workingDirectory

resourceName = "AutoGen.DotnetInteractive.dotnet-tools.json";
using (var stream2 = assembly.GetManifestResourceStream(resourceName)!)
using (var fileStream2 = File.Create(Path.Combine(this.installingDirectory, "dotnet-tools.json")))
{
stream2.CopyTo(fileStream2);
}

var psi = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = $"tool restore --configfile RestoreInteractive.config",
WorkingDirectory = this.installingDirectory,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};

using var process = new Process { StartInfo = psi };
process.OutputDataReceived += this.PrintProcessOutput;
process.ErrorDataReceived += this.PrintProcessOutput;
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();

return process.ExitCode == 0;
}

private void PrintProcessOutput(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
Expand Down
2 changes: 1 addition & 1 deletion dotnet/src/AutoGen.DotnetInteractive/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"Microsoft.dotnet-interactive": {
"version": "1.0.431302",
"version": "1.0.522904",
"commands": [
"dotnet-interactive"
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(TestTargetFramework)</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ApprovalTests" Version="$(ApprovalTestVersion)" />
<PackageReference Include="FluentAssertions" Version="$(FluentAssertionVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkVersion)" />
<PackageReference Include="xunit" Version="$(XUnitVersion)" />
<PackageReference Include="xunit.runner.console" Version="$(XUnitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XUnitVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\AutoGen.SourceGenerator\AutoGen.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\AutoGen.Tests\AutoGen.Tests.csproj" />
</ItemGroup>

</Project>
Loading
Loading