diff --git a/Roslyn.sln b/Roslyn.sln
index 34d550842ddc4..e78ca2d58f566 100644
--- a/Roslyn.sln
+++ b/Roslyn.sln
@@ -579,6 +579,8 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Cont
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Contracts.Package", "src\Dependencies\Contracts\Microsoft.CodeAnalysis.Contracts.Package.csproj", "{A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot", "src\VisualStudio\ExternalAccess\Copilot\Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj", "{9EB058F3-10C9-8F3F-AD9E-72CB362A0928}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -1365,6 +1367,10 @@ Global
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Release|Any CPU.Build.0 = Release|Any CPU
{09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09AEDEE4-6358-47C9-8022-3BD37A518070}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09AEDEE4-6358-47C9-8022-3BD37A518070}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1409,10 +1415,6 @@ Global
{900168D7-D982-86CE-5097-C5F173BA4D8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{900168D7-D982-86CE-5097-C5F173BA4D8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{900168D7-D982-86CE-5097-C5F173BA4D8B}.Release|Any CPU.Build.0 = Release|Any CPU
- {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5D60CF30-28A9-9F0F-7610-D90E4A69AE73}.Release|Any CPU.Build.0 = Release|Any CPU
{2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2559DAF9-784E-4C29-E0E1-70204B1FD56E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -1421,6 +1423,10 @@ Global
{A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9EB058F3-10C9-8F3F-AD9E-72CB362A0928}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1666,6 +1672,7 @@ Global
{A833B11C-5072-4A1F-A32B-2700433B0D3D} = {806F0C6F-3640-4C92-8D55-6767B1535467}
{8988270E-393A-4B92-AC1A-534F903CFD34} = {8977A560-45C2-4EC2-A849-97335B382C74}
{B1481D94-682E-46EC-ADBE-A16EB46FEEE9} = {55A62CFA-1155-46F1-ADF3-BEEE51B58AB5}
+ {5D60CF30-28A9-9F0F-7610-D90E4A69AE73} = {58A2876A-618D-4AE6-A136-E44B42BBDE11}
{09AEDEE4-6358-47C9-8022-3BD37A518070} = {5880FECB-91F1-4AB8-8726-75EAFA8A918E}
{5BABC440-4F1B-46E8-9068-DD7F02ED25D3} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6}
{5762E483-75CE-4328-A410-511F30737712} = {3E5FE3DB-45F7-4D83-9097-8F05D3B3AEC6}
@@ -1683,11 +1690,11 @@ Global
{806F0C6F-3640-4C92-8D55-6767B1535467} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A}
{7465CE63-A7B7-475F-8C57-48D2F8BC665A} = {D449D505-CC6A-4E0B-AF1B-976E2D0AE67A}
{900168D7-D982-86CE-5097-C5F173BA4D8B} = {806F0C6F-3640-4C92-8D55-6767B1535467}
- {5D60CF30-28A9-9F0F-7610-D90E4A69AE73} = {58A2876A-618D-4AE6-A136-E44B42BBDE11}
{967723E8-4FDD-447B-99F6-4F8C47CB5433} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{2559DAF9-784E-4C29-E0E1-70204B1FD56E} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{BD974609-C68B-4BE6-9682-EB132462B50D} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{A8D5CFFA-7F9E-C35B-4F19-D63F6EC1D5CA} = {C2D1346B-9665-4150-B644-075CF1636BAA}
+ {9EB058F3-10C9-8F3F-AD9E-72CB362A0928} = {5880FECB-91F1-4AB8-8726-75EAFA8A918E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {604E6B91-7BC0-4126-AE07-D4D2FEFC3D29}
diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json
index 8972709bd7985..fd1663b39f141 100644
--- a/eng/config/PublishData.json
+++ b/eng/config/PublishData.json
@@ -83,7 +83,7 @@
"Microsoft.CodeAnalysis.ExternalAccess.UnitTesting": "vs-impl",
"Microsoft.CodeAnalysis.ExternalAccess.VisualDiagnostics": "vs-impl",
"Microsoft.CodeAnalysis.ExternalAccess.Xamarin.Remote": "vs-impl",
- "Microsoft.CodeAnalysis.ExternalAccess.Xaml": "vs-impl",
+ "Microsoft.CodeAnalysis.ExternalAccess.Xaml": "vs-impl",
"Microsoft.CodeAnalysis.ExternalAccess.DotNetWatch": "vs-impl",
"Microsoft.CodeAnalysis.LanguageServer.ExternalAccess.Copilot": "vs-impl",
"Microsoft.CodeAnalysis.Remote.Razor.ServiceHub": "vs-impl",
@@ -91,6 +91,7 @@
"Microsoft.CodeAnalysis.Remote.Workspaces": "vs-impl",
"Microsoft.VisualStudio.LanguageServices.LiveShare": "vs-impl",
"Microsoft.VisualStudio.LanguageServices.Razor.RemoteClient": "vs-impl",
+ "Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot": "vs-impl",
"Microsoft.CommonLanguageServerProtocol.Framework": "vs-impl",
"Microsoft.CommonLanguageServerProtocol.Framework.Binary": "vs-impl"
}
diff --git a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj
index ae74faa7622ea..e92b4dd72771f 100644
--- a/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj
+++ b/src/EditorFeatures/Core/Microsoft.CodeAnalysis.EditorFeatures.csproj
@@ -78,6 +78,7 @@
+
diff --git a/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs b/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs
index 77c6da34af215..bb4e2d8d84df3 100644
--- a/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs
+++ b/src/Features/CSharp/Portable/SemanticSearch/CSharpSemanticSearchUtilities.cs
@@ -17,7 +17,7 @@ internal sealed class CSharpSemanticSearchUtilities
Query = """
static IEnumerable Find(Compilation compilation)
{
- return compilation.GlobalNamespace.GetMembers("C");
+ return compilation.Assembly.GlobalNamespace.GetMembers("C");
}
""",
GlobalUsings = """
diff --git a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj
index c3729dd724429..1424adb97aa32 100644
--- a/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj
+++ b/src/Features/Core/Portable/Microsoft.CodeAnalysis.Features.csproj
@@ -96,6 +96,7 @@
+
diff --git a/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs b/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs
new file mode 100644
index 0000000000000..895018ce8d485
--- /dev/null
+++ b/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.CodeAnalysis.SemanticSearch;
+
+internal interface ISemanticSearchCopilotService
+{
+ bool IsAvailable { get; }
+
+ ///
+ /// Translates natural language to C# query.
+ ///
+ ValueTask TryGetQueryAsync(string text, SemanticSearchCopilotContext context, CancellationToken cancellationToken);
+}
diff --git a/src/Features/Core/Portable/SemanticSearch/SemanticSearchCopilotContext.cs b/src/Features/Core/Portable/SemanticSearch/SemanticSearchCopilotContext.cs
new file mode 100644
index 0000000000000..dcdfd21810a39
--- /dev/null
+++ b/src/Features/Core/Portable/SemanticSearch/SemanticSearchCopilotContext.cs
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+
+namespace Microsoft.CodeAnalysis.SemanticSearch;
+
+///
+/// Context necessary to generate Copilot prompt for semantic search query.
+///
+internal sealed class SemanticSearchCopilotContext
+{
+ public required string ModelName { get; init; }
+
+ ///
+ /// List of package names and versions that to include in the prompt.
+ ///
+ public required IEnumerable<(string name, Version version)> AvailablePackages { get; init; }
+}
+
+internal readonly struct SemanticSearchCopilotGeneratedQuery
+{
+ ///
+ /// The generated code or an error message.
+ ///
+ public required string Text { get; init; }
+
+ ///
+ /// True if is an error message.
+ ///
+ public required bool IsError { get; init; }
+}
+
diff --git a/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs b/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs
new file mode 100644
index 0000000000000..accb6ead3824b
--- /dev/null
+++ b/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
+using Microsoft.CodeAnalysis.SemanticSearch;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch;
+
+[Export(typeof(ISemanticSearchCopilotService)), Shared]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class SemanticSearchCopilotServiceWrapper(
+ [Import(AllowDefault = true)] Lazy? impl) : ISemanticSearchCopilotService
+{
+ bool ISemanticSearchCopilotService.IsAvailable
+ => impl != null;
+
+ async ValueTask ISemanticSearchCopilotService.TryGetQueryAsync(string text, SemanticSearchCopilotContext context, CancellationToken cancellationToken)
+ {
+ Contract.ThrowIfNull(impl);
+
+ var result = await impl.Value.TryGetQueryAsync(
+ text,
+ new SemanticSearchCopilotContextImpl()
+ {
+ ModelName = context.ModelName,
+ AvailablePackages = context.AvailablePackages,
+ },
+ cancellationToken).ConfigureAwait(false);
+
+ return new SemanticSearchCopilotGeneratedQuery()
+ {
+ IsError = result.IsError,
+ Text = result.Text,
+ };
+ }
+}
diff --git a/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
index aca2e87cc9e53..22b9cd3805bd8 100644
--- a/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
+++ b/src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
@@ -31,6 +31,22 @@ Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateDocu
Microsoft.CodeAnalysis.ExternalAccess.Copilot.IExternalCSharpCopilotGenerateDocumentationService.GetDocumentationCommentAsync(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper! proposal, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<(System.Collections.Generic.Dictionary? responseDictionary, bool isQuotaExceeded)>!
Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments.ICopilotRelatedDocumentsService
Microsoft.CodeAnalysis.ExternalAccess.Copilot.RelatedDocuments.ICopilotRelatedDocumentsService.GetRelatedDocumentIdsAsync(Microsoft.CodeAnalysis.Document! document, int position, System.Func, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask>! callbackAsync, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotServiceImpl
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotServiceImpl.TryGetQueryAsync(string! text, Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl! context, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.AvailablePackages.get -> System.Collections.Generic.IEnumerable<(string! name, System.Version! version)>!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.AvailablePackages.init -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.ModelName.get -> string!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.ModelName.init -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotContextImpl.SemanticSearchCopilotContextImpl() -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.IsError.get -> bool
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.IsError.init -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.SemanticSearchCopilotGeneratedQueryImpl() -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.Text.get -> string!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.Text.init -> void
+Microsoft.CodeAnalysis.SemanticSearch.SemanticSearchCopilotServiceWrapper
+Microsoft.CodeAnalysis.SemanticSearch.SemanticSearchCopilotServiceWrapper.SemanticSearchCopilotServiceWrapper(System.Lazy? impl) -> void
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Equals(object? obj) -> bool
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.GetHashCode() -> int
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Create(System.Collections.Immutable.ImmutableArray values) -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper!
diff --git a/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs b/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs
new file mode 100644
index 0000000000000..4b3a34a53bb6b
--- /dev/null
+++ b/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
+
+internal interface ISemanticSearchCopilotServiceImpl
+{
+ ValueTask TryGetQueryAsync(string text, SemanticSearchCopilotContextImpl context, CancellationToken cancellationToken);
+}
+
+internal sealed class SemanticSearchCopilotContextImpl
+{
+ public required string ModelName { get; init; }
+
+ ///
+ /// List of package names and versions that to include in the prompt.
+ ///
+ public required IEnumerable<(string name, Version version)> AvailablePackages { get; init; }
+}
+
+internal readonly struct SemanticSearchCopilotGeneratedQueryImpl
+{
+ ///
+ /// True if is an error message.
+ ///
+ public required bool IsError { get; init; }
+
+ ///
+ /// The generated code or an error message.
+ ///
+ public required string Text { get; init; }
+}
diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/CSharpSemanticSearchContentType.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/CSharpSemanticSearchContentType.cs
new file mode 100644
index 0000000000000..2a503d3dd90d5
--- /dev/null
+++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/CSharpSemanticSearchContentType.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel.Composition;
+using Microsoft.CodeAnalysis.Editor;
+using Microsoft.VisualStudio.Utilities;
+
+namespace Microsoft.VisualStudio.LanguageServices.CSharp;
+
+internal static class CSharpSemanticSearchContentType
+{
+ public const string Name = "SemanticSearch-CSharp";
+
+ [Export]
+ [Name(Name)]
+ [BaseDefinition(ContentTypeNames.CSharpContentType)]
+ public static readonly ContentTypeDefinition Definition = null!;
+}
diff --git a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs
index d51c7b44a8e87..ad9cfd908e738 100644
--- a/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs
+++ b/src/VisualStudio/CSharp/Impl/SemanticSearch/SemanticSearchToolWindowImpl.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Immutable;
using System.Composition;
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -36,6 +37,7 @@
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities;
@@ -61,6 +63,9 @@ internal sealed class SemanticSearchToolWindowImpl(
IGlobalOptionService globalOptions,
VisualStudioWorkspace workspace,
IStreamingFindUsagesPresenter resultsPresenter,
+ ITextUndoHistoryRegistry undoHistoryRegistry,
+ ISemanticSearchCopilotService copilotService,
+ ISemanticSearchCopilotUIProvider copilotUIProvider,
IVsService vsUIShellProvider) : ISemanticSearchWorkspaceHost, OptionsProvider
{
private const int ToolBarHeight = 26;
@@ -68,7 +73,7 @@ internal sealed class SemanticSearchToolWindowImpl(
private static readonly Lazy s_buttonTemplate = new(CreateButtonTemplate);
- private readonly IContentType _contentType = contentTypeRegistry.GetContentType(ContentTypeNames.CSharpContentType);
+ private readonly IContentType _contentType = contentTypeRegistry.GetContentType(CSharpSemanticSearchContentType.Name);
private readonly IAsynchronousOperationListener _asyncListener = listenerProvider.GetListener(FeatureAttribute.SemanticSearch);
private readonly Lazy _semanticSearchWorkspace
@@ -100,7 +105,9 @@ public async Task InitializeAsync(CancellationToken cancellati
var vsUIShell = await vsUIShellProvider.GetValueAsync(cancellationToken).ConfigureAwait(false);
- var textViewHost = CreateTextViewHost(vsUIShell);
+ var copilotUI = CreateCopilotUI();
+
+ var textViewHost = CreateTextViewHost(vsUIShell, copilotUI);
var textViewControl = textViewHost.HostControl;
_textView = textViewHost.TextView;
_textBuffer = textViewHost.TextView.TextBuffer;
@@ -112,7 +119,8 @@ public async Task InitializeAsync(CancellationToken cancellati
var toolWindowGrid = new Grid();
toolWindowGrid.ColumnDefinitions.Add(new ColumnDefinition());
toolWindowGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(ToolBarHeight, GridUnitType.Pixel) });
- toolWindowGrid.RowDefinitions.Add(new RowDefinition());
+ toolWindowGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
+ toolWindowGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
var toolbarGrid = new Grid();
@@ -143,18 +151,30 @@ public async Task InitializeAsync(CancellationToken cancellati
_cancelButton = cancelButton;
toolWindowGrid.Children.Add(toolbarGrid);
+
+ if (copilotUI != null)
+ {
+ toolWindowGrid.Children.Add(copilotUI.Control);
+ }
+
toolWindowGrid.Children.Add(textViewControl);
toolbarGrid.Children.Add(executeButton);
toolbarGrid.Children.Add(cancelButton);
// placement within the tool window grid:
- Grid.SetRow(textViewControl, 1);
- Grid.SetColumn(textViewControl, 0);
-
Grid.SetRow(toolbarGrid, 0);
Grid.SetColumn(toolbarGrid, 0);
+ if (copilotUI != null)
+ {
+ Grid.SetRow(copilotUI.Control, 1);
+ Grid.SetColumn(copilotUI.Control, 0);
+ }
+
+ Grid.SetRow(textViewControl, 2);
+ Grid.SetColumn(textViewControl, 0);
+
// placement within the toolbar grid:
Grid.SetRow(executeButton, 0);
@@ -172,6 +192,101 @@ public async Task InitializeAsync(CancellationToken cancellati
SemanticSearchWorkspace ISemanticSearchWorkspaceHost.Workspace => _semanticSearchWorkspace.Value;
+ private CopilotUI? CreateCopilotUI()
+ {
+ if (!copilotUIProvider.IsAvailable || !copilotService.IsAvailable)
+ {
+ return null;
+ }
+
+ var outerGrid = new Grid()
+ {
+ Background = (Brush)Application.Current.FindResource(CommonControlsColors.TextBoxBackgroundBrushKey),
+ };
+
+ ImageThemingUtilities.SetImageBackgroundColor(outerGrid, (Color)Application.Current.Resources[CommonDocumentColors.PageBackgroundColorKey]);
+ ThemedDialogStyleLoader.SetUseDefaultThemedDialogStyles(outerGrid, true);
+
+ // [ prompt border | empty ]
+ outerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
+ outerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
+
+ var promptGrid = new Grid();
+
+ // [ input | panel ]
+ promptGrid.ColumnDefinitions.Add(new ColumnDefinition { MaxWidth = 600, Width = GridLength.Auto });
+ promptGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
+
+ var promptTextBox = copilotUIProvider.GetTextBox();
+
+ var panel = new StackPanel()
+ {
+ Orientation = Orientation.Horizontal,
+ HorizontalAlignment = HorizontalAlignment.Left,
+ VerticalAlignment = VerticalAlignment.Bottom,
+ Margin = new Thickness(8, 8, 0, 8),
+ };
+
+ Grid.SetColumn(promptTextBox.Control, 0);
+ promptGrid.Children.Add(promptTextBox.Control);
+
+ Grid.SetColumn(panel, 1);
+ promptGrid.Children.Add(panel);
+
+ var promptGridBorder = new Border
+ {
+ Name = "PromptBorder",
+ BorderBrush = (Brush)Application.Current.Resources[EnvironmentColors.SystemHighlightBrushKey],
+ BorderThickness = new Thickness(1),
+ Child = promptGrid
+ };
+
+ Grid.SetColumn(promptGridBorder, 0);
+ outerGrid.Children.Add(promptGridBorder);
+
+ // ComboBox for model selection
+ var modelPicker = new ComboBox
+ {
+ SelectedIndex = 0,
+ HorizontalAlignment = HorizontalAlignment.Right,
+ VerticalAlignment = VerticalAlignment.Top,
+ Margin = new Thickness(4, 0, 4, 0),
+ Height = 24,
+ IsEditable = false,
+ IsReadOnly = true,
+ BorderThickness = new Thickness(0),
+ MinHeight = 24,
+ VerticalContentAlignment = VerticalAlignment.Top,
+ TabIndex = 1,
+ Style = (Style)Application.Current.FindResource(VsResourceKeys.ComboBoxStyleKey)
+ };
+
+ modelPicker.Items.Add("gpt-4o");
+ modelPicker.Items.Add("gpt-4o-mini");
+ modelPicker.Items.Add("o1");
+ modelPicker.Items.Add("o1-ga");
+ modelPicker.Items.Add("o1-mini");
+
+ panel.Children.Add(modelPicker);
+
+ var submitButton = CreateButton(
+ KnownMonikers.Send,
+ automationName: "Generate query",
+ acceleratorKey: "Ctrl+Enter",
+ toolTip: "Generate query");
+
+ panel.Children.Add(submitButton);
+
+ submitButton.Click += (_, _) => SubmitCopilotQuery(promptTextBox.Text, modelPicker.Text);
+
+ return new CopilotUI()
+ {
+ Control = outerGrid,
+ Input = promptTextBox,
+ ModelPicker = modelPicker,
+ };
+ }
+
private static Button CreateButton(
Imaging.Interop.ImageMoniker moniker,
string automationName,
@@ -250,7 +365,7 @@ private static ControlTemplate CreateButtonTemplate()
""", context);
}
- private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell)
+ private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell, CopilotUI? copilotUI)
{
Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread);
@@ -289,7 +404,7 @@ private IWpfTextViewHost CreateTextViewHost(IVsUIShell vsUIShell)
ErrorHandler.ThrowOnFailure(windowFrame.SetProperty((int)__VSFPROPID.VSFPROPID_ViewHelper, textViewAdapter));
- _ = new CommandFilter(this, textViewAdapter);
+ _ = new CommandFilter(this, textViewAdapter, copilotUI);
return textViewHost;
}
@@ -315,6 +430,74 @@ private void UpdateUIState()
_cancelButton.IsEnabled = isExecuting;
}
+ private void SubmitCopilotQuery(string input, string model)
+ {
+ Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread);
+ Contract.ThrowIfNull(_textBuffer);
+ Contract.ThrowIfNull(copilotService);
+
+ // TODO: hook up cancel button for copilot queries
+ var cancellationSource = new CancellationTokenSource();
+
+ // TODO: fade out current content and show overlay spinner
+
+ var completionToken = _asyncListener.BeginAsyncOperation(nameof(SemanticSearchToolWindow) + "." + nameof(SubmitCopilotQuery));
+ _ = ExecuteAsync(cancellationSource.Token).ReportNonFatalErrorAsync().CompletesAsyncOperation(completionToken);
+
+ async Task ExecuteAsync(CancellationToken cancellationToken)
+ {
+ await TaskScheduler.Default;
+
+ SemanticSearchCopilotGeneratedQuery query;
+
+ // TODO: generate list from SemanticSearch.ReferenceAssemblies:
+ var codeAnalysisVersion = new Version(4, 14, 0);
+ var sdkVersion = new Version(9, 0, 0);
+
+ var context = new SemanticSearchCopilotContext()
+ {
+ ModelName = model,
+ AvailablePackages =
+ [
+ ("Microsoft.CodeAnalysis", codeAnalysisVersion),
+ ("Microsoft.CodeAnalysis.CSharp", codeAnalysisVersion),
+ ("System.Collections.Immutable", sdkVersion),
+ ("System.Collections", sdkVersion),
+ ("System.Linq", sdkVersion),
+ ("System.Runtime", sdkVersion),
+ ]
+ };
+
+ try
+ {
+ query = await copilotService.TryGetQueryAsync(input, context, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken, ErrorSeverity.Critical))
+ {
+ return;
+ }
+ catch (OperationCanceledException)
+ {
+ return;
+ }
+
+ // Replace text buffer content. Allow using Ctrl+Z to revert to the previous content.
+
+ await threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(CancellationToken.None);
+
+ Contract.ThrowIfFalse(undoHistoryRegistry.TryGetHistory(_textBuffer, out var undoHistory));
+ using var undoTransaction = undoHistory.CreateTransaction(FeaturesResources.SemanticSearch);
+
+ using (var edit = _textBuffer.CreateEdit())
+ {
+ edit.Replace(0, _textBuffer.CurrentSnapshot.Length, query.Text);
+ edit.Apply();
+ }
+
+ undoTransaction.Complete();
+ }
+ }
+
private void CancelQuery()
{
Contract.ThrowIfFalse(threadingContext.JoinableTaskContext.IsOnMainThread);
@@ -485,7 +668,14 @@ public NavigableLocation GetNavigableLocation(TextSpan textSpan)
public ValueTask GetOptionsAsync(Microsoft.CodeAnalysis.Host.LanguageServices languageServices, CancellationToken cancellationToken)
=> new(globalOptions.GetClassificationOptions(languageServices.Language));
- internal sealed class ResultsObserver(Document queryDocument, IFindUsagesContext presenterContext) : ISemanticSearchResultsObserver
+ private sealed class CopilotUI
+ {
+ public required FrameworkElement Control { get; init; }
+ public required ITextBoxControl Input { get; init; }
+ public required ComboBox ModelPicker { get; init; }
+ }
+
+ private sealed class ResultsObserver(Document queryDocument, IFindUsagesContext presenterContext) : ISemanticSearchResultsObserver
{
public ValueTask OnDefinitionFoundAsync(DefinitionItem definition, CancellationToken cancellationToken)
=> presenterContext.OnDefinitionFoundAsync(definition, cancellationToken);
@@ -509,19 +699,29 @@ public async ValueTask OnCompilationFailureAsync(ImmutableArray _copilotUI?.Input.View.HasAggregateFocus == true;
+
public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
- => _editorCommandTarget.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ {
+ var target = HasCopilotInputFocus ? _copilotUI.Input.CommandTarget : _editorCommandTarget;
+
+ return target.QueryStatus(ref pguidCmdGroup, cCmds, prgCmds, pCmdText);
+ }
public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
@@ -530,6 +730,12 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv
switch ((VSConstants.VSStd2KCmdID)nCmdID)
{
case VSConstants.VSStd2KCmdID.OPENLINEABOVE:
+ if (HasCopilotInputFocus)
+ {
+ _window.SubmitCopilotQuery(_copilotUI.Input.Text, _copilotUI.ModelPicker.Text);
+ return VSConstants.S_OK;
+ }
+
if (!_window.IsExecutingUIState())
{
_window.RunQuery();
@@ -549,7 +755,8 @@ public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pv
}
}
- return _editorCommandTarget.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+ var target = HasCopilotInputFocus ? _copilotUI.Input.CommandTarget : _editorCommandTarget;
+ return target.Exec(ref pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
}
}
}
diff --git a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj
index 6bb7c7aca2d1f..7ecc7bdaa2455 100644
--- a/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj
+++ b/src/VisualStudio/Core/Def/Microsoft.VisualStudio.LanguageServices.csproj
@@ -91,6 +91,7 @@
+
diff --git a/src/VisualStudio/Core/Def/SemanticSearch/ISemanticSearchCopilotUIProvider.cs b/src/VisualStudio/Core/Def/SemanticSearch/ISemanticSearchCopilotUIProvider.cs
new file mode 100644
index 0000000000000..2c29f61682813
--- /dev/null
+++ b/src/VisualStudio/Core/Def/SemanticSearch/ISemanticSearchCopilotUIProvider.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Windows.Controls;
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.SemanticSearch;
+
+///
+/// Abstraction over Copilot prompt text box UI.
+///
+internal interface ITextBoxControl
+{
+ Control Control { get; }
+ string Text { get; set; }
+ IOleCommandTarget CommandTarget { get; }
+ IWpfTextView View { get; }
+}
+
+///
+/// Abstraction over Copilot prompt UI.
+///
+internal interface ISemanticSearchCopilotUIProvider
+{
+ bool IsAvailable { get; }
+ ITextBoxControl GetTextBox();
+}
diff --git a/src/VisualStudio/ExternalAccess/Copilot/.editorconfig b/src/VisualStudio/ExternalAccess/Copilot/.editorconfig
new file mode 100644
index 0000000000000..8b8e284ec0a39
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/.editorconfig
@@ -0,0 +1,3 @@
+[**]
+dotnet_public_api_analyzer.skip_namespaces = Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal
+
diff --git a/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs b/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs
new file mode 100644
index 0000000000000..12966f1629140
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotUIProviderWrapper.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Composition;
+using System.Windows.Controls;
+using Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.SemanticSearch;
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch;
+
+[Export(typeof(ISemanticSearchCopilotUIProvider)), Shared]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class SemanticSearchCopilotUIProviderWrapper(
+ [Import(AllowDefault = true)] Lazy? impl) : ISemanticSearchCopilotUIProvider
+{
+ private sealed class TextBoxWrapper(ITextBoxControlImpl impl) : ITextBoxControl
+ {
+ Control ITextBoxControl.Control => impl.Control;
+ string ITextBoxControl.Text { get => impl.Text; set => impl.Text = value; }
+ IOleCommandTarget ITextBoxControl.CommandTarget => impl.CommandTarget;
+ IWpfTextView ITextBoxControl.View => impl.View;
+ }
+
+ bool ISemanticSearchCopilotUIProvider.IsAvailable
+ => impl != null;
+
+ ITextBoxControl ISemanticSearchCopilotUIProvider.GetTextBox()
+ {
+ Contract.ThrowIfNull(impl);
+ return new TextBoxWrapper(impl.Value.GetTextBox());
+ }
+}
diff --git a/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Shipped.txt b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Shipped.txt
new file mode 100644
index 0000000000000..7dc5c58110bfa
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Unshipped.txt b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
new file mode 100644
index 0000000000000..d14e794951821
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/InternalAPI.Unshipped.txt
@@ -0,0 +1,13 @@
+#nullable enable
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotUIProviderImpl
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotUIProviderImpl.GetTextBox() -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.CommandTarget.get -> Microsoft.VisualStudio.OLE.Interop.IOleCommandTarget!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.Control.get -> System.Windows.Controls.Control!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.Text.get -> string!
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.Text.set -> void
+Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ITextBoxControlImpl.View.get -> Microsoft.VisualStudio.Text.Editor.IWpfTextView!
+Microsoft.CodeAnalysis.SemanticSearch.ISemanticSearchCopilotUIProviderWrapper
+Microsoft.CodeAnalysis.SemanticSearch.ISemanticSearchCopilotUIProviderWrapper.IsAvailable.get -> bool
+Microsoft.CodeAnalysis.SemanticSearch.ISemanticSearchCopilotUIProviderWrapper.ISemanticSearchCopilotUIProviderWrapper(System.Lazy? impl) -> void
+Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.Internal.ISemanticSearchCopilotUIProviderWrapper
diff --git a/src/VisualStudio/ExternalAccess/Copilot/Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj b/src/VisualStudio/ExternalAccess/Copilot/Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj
new file mode 100644
index 0000000000000..b3e5e06c4d54b
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot.csproj
@@ -0,0 +1,37 @@
+
+
+
+
+ Library
+ Microsoft.CodeAnalysis.ExternalAccess.Copilot
+ net472
+ true
+
+
+ true
+ Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot
+
+ A supporting package for Copilot features:
+ https://devdiv.visualstudio.com/DefaultCollection/DevDiv/_git/VisualStudio.Conversations
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Shipped.txt b/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Unshipped.txt b/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000000..8b137891791fe
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/PublicAPI.Unshipped.txt
@@ -0,0 +1 @@
+
diff --git a/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs b/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs
new file mode 100644
index 0000000000000..be63658590193
--- /dev/null
+++ b/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Windows.Controls;
+using Microsoft.VisualStudio.OLE.Interop;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
+
+internal interface ITextBoxControlImpl
+{
+ Control Control { get; }
+ string Text { get; set; }
+ IOleCommandTarget CommandTarget { get; }
+ IWpfTextView View { get; }
+}
+
+internal interface ISemanticSearchCopilotUIProviderImpl
+{
+ ITextBoxControlImpl GetTextBox();
+}
diff --git a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj
index b95e19e642ebc..d54d721a87fa1 100644
--- a/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj
+++ b/src/VisualStudio/Setup/Roslyn.VisualStudio.Setup.csproj
@@ -235,6 +235,12 @@
BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup
BindingRedirect
+
+ Microsoft.VisualStudio.LanguageServices.ExternalAccess.Copilot
+ BuiltProjectOutputGroup
+ true
+ BindingRedirect
+
RemoteWorkspaces
BuiltProjectOutputGroup;SatelliteDllsProjectOutputGroup
diff --git a/src/VisualStudio/Setup/source.extension.vsixmanifest b/src/VisualStudio/Setup/source.extension.vsixmanifest
index 545f5f5674c87..add0ea3be74b0 100644
--- a/src/VisualStudio/Setup/source.extension.vsixmanifest
+++ b/src/VisualStudio/Setup/source.extension.vsixmanifest
@@ -67,6 +67,7 @@
+
diff --git a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj
index 4196dfa0a75af..dcbbdeb8f2597 100644
--- a/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj
+++ b/src/Workspaces/Core/Portable/Microsoft.CodeAnalysis.Workspaces.csproj
@@ -123,6 +123,7 @@
+