Skip to content

Commit a466013

Browse files
akhera99genluCyrusNajmabadi
authored
[17.14] Move Copilot context provider to EA.Copilot and handler to LanguageServer (#79760)
* Move Copilot context provider to EA.Copilot and handler to LanguageServer (#77973) * remove semantic search from expected errors * Revert "remove semantic search from expected errors" This reverts commit 3f613ee. * use a producer/consumer pattern * Revert "use a producer/consumer pattern" This reverts commit 86802b4. * Cleanup the code we have to run copilot code in parallel * Simplify further * Move into helper * Simplify * Update src/Features/ExternalAccess/Copilot/Completion/ICSharpCopilotContextProviderService.cs * fix * Add copilot tests IVT to ExternalAccess.Copilot (#78455) --------- Co-authored-by: Gen Lu <genlu@users.noreply.github.com> Co-authored-by: Cyrus Najmabadi <cyrus.najmabadi@gmail.com>
1 parent e7629a6 commit a466013

File tree

16 files changed

+416
-2
lines changed

16 files changed

+416
-2
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Text.Json.Serialization;
6+
7+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
8+
9+
internal record CodeSnippetItem : IContextItem
10+
{
11+
public CodeSnippetItem(string uri, string value, string[]? additionalUris = null, int importance = Completion.Importance.Default)
12+
{
13+
this.Uri = uri;
14+
this.Value = value;
15+
this.AdditionalUris = additionalUris;
16+
this.Importance = importance;
17+
}
18+
19+
[JsonPropertyName("uri")]
20+
public string Uri { get; init; }
21+
22+
[JsonPropertyName("value")]
23+
public string Value { get; init; }
24+
25+
[JsonPropertyName("additionalUris")]
26+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
27+
public string[]? AdditionalUris { get; init; }
28+
29+
[JsonPropertyName("importance")]
30+
public int Importance { get; init; }
31+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Generic;
6+
using System.Threading;
7+
8+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
9+
10+
internal interface ICSharpCopilotContextProviderService
11+
{
12+
IAsyncEnumerable<IContextItem> GetContextItemsAsync(Document document, int position, IReadOnlyDictionary<string, object> activeExperiments, CancellationToken cancellationToken);
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Text.Json.Serialization;
6+
7+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
8+
9+
[JsonDerivedType(typeof(CodeSnippetItem))]
10+
[JsonDerivedType(typeof(TraitItem))]
11+
internal interface IContextItem
12+
{
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
12+
13+
internal interface IContextProvider
14+
{
15+
ValueTask ProvideContextItemsAsync(
16+
Document document,
17+
int position,
18+
IReadOnlyDictionary<string, object> activeExperiments,
19+
Func<ImmutableArray<IContextItem>, CancellationToken, ValueTask> callback,
20+
CancellationToken cancellationToken);
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
6+
7+
internal static class Importance
8+
{
9+
public const int Lowest = 0;
10+
public const int Highest = 100;
11+
12+
public const int Default = Lowest;
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Text.Json.Serialization;
6+
7+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
8+
9+
internal record TraitItem : IContextItem
10+
{
11+
public TraitItem(string name, string value, int importance = Completion.Importance.Default)
12+
{
13+
this.Name = name;
14+
this.Value = value;
15+
this.Importance = importance;
16+
}
17+
18+
[JsonPropertyName("name")]
19+
public string Name { get; init; }
20+
21+
[JsonPropertyName("value")]
22+
public string Value { get; init; }
23+
24+
[JsonPropertyName("importance")]
25+
public int Importance { get; init; }
26+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.Composition;
9+
using System.Threading;
10+
using Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion;
11+
using Microsoft.CodeAnalysis.Host.Mef;
12+
using Microsoft.CodeAnalysis.Shared.Utilities;
13+
14+
namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.Completion;
15+
16+
[Export(typeof(ICSharpCopilotContextProviderService)), Shared]
17+
[method: ImportingConstructor]
18+
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
19+
internal sealed class CSharpContextProviderService([ImportMany] IEnumerable<IContextProvider> providers)
20+
: ICSharpCopilotContextProviderService
21+
{
22+
private readonly ImmutableArray<IContextProvider> _providers = [.. providers];
23+
24+
public IAsyncEnumerable<IContextItem> GetContextItemsAsync(Document document, int position, IReadOnlyDictionary<string, object> activeExperiments, CancellationToken cancellationToken)
25+
=> ProducerConsumer<IContextItem>.RunParallelStreamAsync(
26+
_providers,
27+
static async (provider, callback, args, cancellationToken) =>
28+
await provider.ProvideContextItemsAsync(
29+
args.document, args.position, args.activeExperiments,
30+
(items, cancellationToken) =>
31+
{
32+
foreach (var item in items)
33+
callback(item);
34+
35+
return default;
36+
}, cancellationToken).ConfigureAwait(false),
37+
args: (document, position, activeExperiments),
38+
cancellationToken);
39+
}

src/Features/ExternalAccess/Copilot/InternalAPI.Unshipped.txt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,35 @@
11
#nullable enable
2+
const Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.Importance.Default = 0 -> int
3+
const Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.Importance.Highest = 100 -> int
4+
const Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.Importance.Lowest = 0 -> int
25
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService
36
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService.MapCodeAsync(Microsoft.CodeAnalysis.Document! document, System.Collections.Immutable.ImmutableArray<string!> contents, System.Collections.Immutable.ImmutableArray<(Microsoft.CodeAnalysis.Document! document, Microsoft.CodeAnalysis.Text.TextSpan textSpan)> prioritizedFocusLocations, System.Collections.Generic.Dictionary<string!, object!>! options, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Text.TextChange>?>!
7+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem
8+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.AdditionalUris.get -> string![]?
9+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.AdditionalUris.init -> void
10+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.CodeSnippetItem(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem! original) -> void
11+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.CodeSnippetItem(string! uri, string! value, string![]? additionalUris = null, int importance = 0) -> void
12+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Importance.get -> int
13+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Importance.init -> void
14+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Uri.get -> string!
15+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Uri.init -> void
16+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Value.get -> string!
17+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Value.init -> void
18+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.IContextItem
19+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.IContextProvider
20+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.IContextProvider.ProvideContextItemsAsync(Microsoft.CodeAnalysis.Document! document, int position, System.Collections.Generic.IReadOnlyDictionary<string!, object!>! activeExperiments, System.Func<System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.IContextItem!>, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask>! callback, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask
21+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.ICSharpCopilotContextProviderService
22+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.ICSharpCopilotContextProviderService.GetContextItemsAsync(Microsoft.CodeAnalysis.Document! document, int position, System.Collections.Generic.IReadOnlyDictionary<string!, object!>! activeExperiments, System.Threading.CancellationToken cancellationToken) -> System.Collections.Generic.IAsyncEnumerable<Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.IContextItem!>!
23+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.Importance
24+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem
25+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Importance.get -> int
26+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Importance.init -> void
27+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Name.get -> string!
28+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Name.init -> void
29+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.TraitItem(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem! original) -> void
30+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.TraitItem(string! name, string! value, int importance = 0) -> void
31+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Value.get -> string!
32+
Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Value.init -> void
433
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper
534
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Equals(Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper? other) -> bool
635
Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotDocumentationCommentProposalWrapper
@@ -84,10 +113,28 @@ Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopil
84113
Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.SemanticSearchCopilotGeneratedQueryImpl.Text.init -> void
85114
Microsoft.CodeAnalysis.SemanticSearch.SemanticSearchCopilotServiceWrapper
86115
Microsoft.CodeAnalysis.SemanticSearch.SemanticSearchCopilotServiceWrapper.SemanticSearchCopilotServiceWrapper(System.Lazy<Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch.ISemanticSearchCopilotServiceImpl!>? impl) -> void
116+
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Equals(object? obj) -> bool
117+
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.GetHashCode() -> int
118+
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.ToString() -> string!
119+
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Equals(object? obj) -> bool
120+
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.GetHashCode() -> int
121+
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.ToString() -> string!
87122
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Equals(object? obj) -> bool
88123
override Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.GetHashCode() -> int
124+
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.operator !=(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem? left, Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem? right) -> bool
125+
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.operator ==(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem? left, Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem? right) -> bool
126+
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.operator !=(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem? left, Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem? right) -> bool
127+
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.operator ==(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem? left, Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem? right) -> bool
89128
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper.Create(System.Collections.Immutable.ImmutableArray<string!> values) -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotChecksumWrapper!
90129
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.GetContainingMethodDeclarationAsync(Microsoft.CodeAnalysis.Document! document, int position, bool useFullSpan, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task<Microsoft.CodeAnalysis.SyntaxNode?>!
91130
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.GetCopilotSuggestionDiagnosticTag() -> string!
92131
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.IsResultantVisibilityPublic(this Microsoft.CodeAnalysis.ISymbol! symbol) -> bool
93132
static Microsoft.CodeAnalysis.ExternalAccess.Copilot.CopilotUtilities.IsValidIdentifier(string? name) -> bool
133+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.<Clone>$() -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem!
134+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.EqualityContract.get -> System.Type!
135+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.Equals(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem? other) -> bool
136+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.CodeSnippetItem.PrintMembers(System.Text.StringBuilder! builder) -> bool
137+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.<Clone>$() -> Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem!
138+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.EqualityContract.get -> System.Type!
139+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.Equals(Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem? other) -> bool
140+
virtual Microsoft.CodeAnalysis.ExternalAccess.Copilot.Completion.TraitItem.PrintMembers(System.Text.StringBuilder! builder) -> bool

src/Features/ExternalAccess/Copilot/Microsoft.CodeAnalysis.ExternalAccess.Copilot.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,11 @@
2020
<!--
2121
⚠ ONLY COPILOT ASSEMBLIES MAY BE ADDED HERE ⚠
2222
-->
23+
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.LanguageServer" />
2324
<InternalsVisibleTo Include="Microsoft.VisualStudio.Copilot.CodeMappers.CSharp" Key="$(CopilotKey)" />
2425
<InternalsVisibleTo Include="Microsoft.VisualStudio.Copilot.Roslyn" Key="$(CopilotKey)" />
2526
<InternalsVisibleTo Include="Microsoft.VisualStudio.Copilot.Roslyn.LanguageServer" Key="$(CopilotKey)" />
27+
<InternalsVisibleTo Include="Microsoft.VisualStudio.Copilot.Roslyn.Tests" Key="$(CopilotKey)" />
2628
</ItemGroup>
2729

2830
<ItemGroup>

src/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/ExportProviderBuilder.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,26 @@ private static void ThrowOnUnexpectedErrors(CompositionConfiguration configurati
182182
// Verify that we have exactly the MEF errors that we expect. If we have less or more this needs to be updated to assert the expected behavior.
183183
// Currently we are expecting the following:
184184
// "----- CompositionError level 1 ------
185+
// Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.CodeMapper.CSharpMapCodeService.ctor(service): expected exactly 1 export matching constraints:
186+
// Contract name: Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService
187+
// TypeIdentityName: Microsoft.CodeAnalysis.ExternalAccess.Copilot.CodeMapper.ICSharpCopilotMapCodeService
188+
// but found 0.
189+
// part definition Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.CodeMapper.CSharpMapCodeService
190+
//
185191
// Microsoft.CodeAnalysis.ExternalAccess.Pythia.PythiaSignatureHelpProvider.ctor(implementation): expected exactly 1 export matching constraints:
186192
// Contract name: Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api.IPythiaSignatureHelpProviderImplementation
187193
// TypeIdentityName: Microsoft.CodeAnalysis.ExternalAccess.Pythia.Api.IPythiaSignatureHelpProviderImplementation
188194
// but found 0.
189-
// part definition Microsoft.CodeAnalysis.ExternalAccess.Pythia.PythiaSignatureHelpProvider
195+
// part definition Microsoft.CodeAnalysis.ExternalAccess.Pythia.PythiaSignatureHelpProvider
196+
//
197+
// Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch.CopilotSemanticSearchQueryExecutor.ctor(workspaceProvider): expected exactly 1 export matching constraints:
198+
// Contract name: Microsoft.CodeAnalysis.Host.IHostWorkspaceProvider
199+
// TypeIdentityName: Microsoft.CodeAnalysis.Host.IHostWorkspaceProvider
200+
// but found 0.
201+
// part definition Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch.CopilotSemanticSearchQueryExecutor
202+
190203
var erroredParts = configuration.CompositionErrors.FirstOrDefault()?.SelectMany(error => error.Parts).Select(part => part.Definition.Type.Name) ?? [];
191-
var expectedErroredParts = new string[] { "PythiaSignatureHelpProvider" };
204+
var expectedErroredParts = new string[] { "CSharpMapCodeService", "PythiaSignatureHelpProvider", "CopilotSemanticSearchQueryExecutor" };
192205
var hasUnexpectedErroredParts = erroredParts.Any(part => !expectedErroredParts.Contains(part));
193206

194207
if (hasUnexpectedErroredParts || !catalog.DiscoveredParts.DiscoveryErrors.IsEmpty)

0 commit comments

Comments
 (0)