Skip to content

Commit

Permalink
Autocomplete (#166)
Browse files Browse the repository at this point in the history
- implemented the agent protocols for autocompletions
- inline text changes that can be accepted with the `Tab` keyboard press
(`lalt+,` for rotating suggestions if there is more than one)
- explicitly trigger completion suggestions (`lalt+.`)
- user option to enable/disable Autocompletions
- telemetry to compute CAR
- tests

## Test plan
- Create a new solution
- Start adding code
- Check if 'grey code' with suggestions appears
- Accept the suggestions by pressing `Tab`
- Reject the suggestion by pressing `Esc`
<!-- REQUIRED; info at
https://docs-legacy.sourcegraph.com/dev/background-information/testing_principles
-->

---------

Co-authored-by: Tomasz Gołębiowski <[email protected]>
  • Loading branch information
tomaszgolebiowski and Tomasz Gołębiowski authored Jan 6, 2025
1 parent b52b944 commit 3cb8d9d
Show file tree
Hide file tree
Showing 40 changed files with 908 additions and 117 deletions.
2 changes: 1 addition & 1 deletion agent/agent.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
vscode-v1.54.x
vscode-v1.54.0
18 changes: 17 additions & 1 deletion src/Cody.Core/Agent/IAgentService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Cody.Core.Agent.Protocol;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Cody.Core.Agent
Expand Down Expand Up @@ -61,6 +62,21 @@ public interface IAgentService
[AgentCall("progress/cancel")]
void CancelProgress(string id);

[AgentCall("autocomplete/execute")]
Task<AutocompleteResult> Autocomplete(AutocompleteParams autocomplete, CancellationToken cancellationToken);

[AgentCall("autocomplete/clearLastCandidate")]
void ClearLastCandidate();

[AgentCall("autocomplete/completionSuggested")]
void CompletionSuggested(CompletionItemParams completionItem);

[AgentCall("autocomplete/completionAccepted")]
void CompletionAccepted(CompletionItemParams completionItem);

[AgentCall("testing/workspaceDocuments")]
Task<GetDocumentsResult> GetWorkspaceDocuments(GetDocumentsParams documents);

//---------------------------------------------------------
// For notifications return type MUST be void!
//---------------------------------------------------------
Expand Down
8 changes: 6 additions & 2 deletions src/Cody.Core/Agent/NotificationHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Cody.Core.Infrastructure;
using Cody.Core.Logging;
using Cody.Core.Settings;
using Cody.Core.Trace;
using Cody.Core.Workspace;
using Newtonsoft.Json.Linq;
using System;
Expand All @@ -11,6 +12,8 @@ namespace Cody.Core.Agent
{
public class NotificationHandlers : INotificationHandler
{
private static TraceLogger trace = new TraceLogger(nameof(NotificationHandlers));

private readonly WebviewMessageHandler _messageFilter;
private readonly IUserSettingsService _settingsService;
private readonly IFileService _fileService;
Expand Down Expand Up @@ -57,9 +60,10 @@ await agentClient.ReceiveMessageStringEncoded(new ReceiveMessageStringEncodedPar
}

[AgentCallback("debug/message")]
public void Debug(string channel, string message)
public void Debug(string channel, string message, string level)
{
_logger.Debug($"[{channel} {message}]");
//_logger.Debug($"[{channel} {message}]");
trace.TraceEvent("AgentDebug", message);
}

[AgentCallback("webview/registerWebview")]
Expand Down
11 changes: 11 additions & 0 deletions src/Cody.Core/Agent/Protocol/AutocompleteItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Cody.Core.Agent.Protocol
{
public class AutocompleteItem
{
public string Id { get; set; }
public string InsertText { get; set; }
public Range Range { get; set; }
}
}
27 changes: 27 additions & 0 deletions src/Cody.Core/Agent/Protocol/AutocompleteParams.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace Cody.Core.Agent.Protocol
{
public class AutocompleteParams
{
public string Uri { get; set; }
public string FilePath { get; set; }

public Position Position { get; set; }

public TriggerKind? TriggerKind { get; set; }

public SelectedCompletionInfo SelectedCompletionInfo { get; set; }
}

public enum TriggerKind
{
[EnumMember(Value = nameof(Automatic))] //overwrites default camelCase naming convention
Automatic,

[EnumMember(Value = nameof(Invoke))]
Invoke
}
}
12 changes: 12 additions & 0 deletions src/Cody.Core/Agent/Protocol/AutocompleteResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;

namespace Cody.Core.Agent.Protocol
{
public class AutocompleteResult
{
public AutocompleteItem[] Items { get; set; }

public CompletionBookkeepingEvent CompletionEvent { get; set; }
}
}
9 changes: 9 additions & 0 deletions src/Cody.Core/Agent/Protocol/CompletionBookkeepingEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace Cody.Core.Agent.Protocol
{
public class CompletionBookkeepingEvent
{
public CompletionItemInfo[] Items { get; set; }
}
}
14 changes: 14 additions & 0 deletions src/Cody.Core/Agent/Protocol/CompletionItemInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Cody.Core.Agent.Protocol
{
public class CompletionItemInfo
{
public int LineCount { get; set; }
public int CharCount { get; set; }

public string InsertText { get; set; }

public string StopReason { get; set; }
}
}
9 changes: 9 additions & 0 deletions src/Cody.Core/Agent/Protocol/CompletionItemParams.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace Cody.Core.Agent.Protocol
{
public class CompletionItemParams
{
public string CompletionID { get; set; }
}
}
10 changes: 10 additions & 0 deletions src/Cody.Core/Agent/Protocol/GetDocumentsParams.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;

namespace Cody.Core.Agent.Protocol
{
public class GetDocumentsParams
{
public string[] Uris { get; set; }
}
}
10 changes: 10 additions & 0 deletions src/Cody.Core/Agent/Protocol/GetDocumentsResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;

namespace Cody.Core.Agent.Protocol
{
public class GetDocumentsResult
{
public ProtocolTextDocument[] Documents { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/Cody.Core/Agent/Protocol/SelectedCompletionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;

namespace Cody.Core.Agent.Protocol
{
public class SelectedCompletionInfo
{
public Range Range { get; set; }

public string Text { get; set; }
}
}
11 changes: 11 additions & 0 deletions src/Cody.Core/Cody.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
Expand All @@ -54,11 +55,20 @@
<Compile Include="Agent\NotificationHandlers.cs" />
<Compile Include="Agent\ProgressNotificationHandlers.cs" />
<Compile Include="Agent\Protocol\AuthStatus.cs" />
<Compile Include="Agent\Protocol\AutocompleteItem.cs" />
<Compile Include="Agent\Protocol\AutocompleteParams.cs" />
<Compile Include="Agent\Protocol\AutocompleteResult.cs" />
<Compile Include="Agent\Protocol\ChatPanelInfo.cs" />
<Compile Include="Agent\Protocol\CompletionBookkeepingEvent.cs" />
<Compile Include="Agent\Protocol\CompletionItemInfo.cs" />
<Compile Include="Agent\Protocol\CompletionItemParams.cs" />
<Compile Include="Agent\Protocol\GetDocumentsParams.cs" />
<Compile Include="Agent\Protocol\GetDocumentsResult.cs" />
<Compile Include="Agent\Protocol\ProgressOptions.cs" />
<Compile Include="Agent\Protocol\ProgressReportParams.cs" />
<Compile Include="Agent\Protocol\ProgressStartParams.cs" />
<Compile Include="Agent\Protocol\SaveDialogOptionsParams.cs" />
<Compile Include="Agent\Protocol\SelectedCompletionInfo.cs" />
<Compile Include="Agent\Protocol\TestProgress.cs" />
<Compile Include="Agent\Protocol\WorkspaceFolderDidChangeEvent.cs" />
<Compile Include="Agent\Protocol\TextDocumentShowParamsOptions.cs" />
Expand All @@ -81,6 +91,7 @@
<Compile Include="Agent\Protocol\ResolveWebviewViewParams.cs" />
<Compile Include="Agent\SetHtmlEvent.cs" />
<Compile Include="Agent\WebviewMessageHandler.cs" />
<Compile Include="Common\StringExtensions.cs" />
<Compile Include="Common\Configuration.cs" />
<Compile Include="Common\Configuration.Setup.cs" />
<Compile Include="DocumentSync\DocumentSyncCallback.cs" />
Expand Down
23 changes: 23 additions & 0 deletions src/Cody.Core/Common/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Cody.Core.Common
{
public static class StringExtensions
{
public static string ToUri(this string path)
{
var uri = new Uri(path).AbsoluteUri;
return Regex.Replace(uri, "(file:///)(\\D+)(:)", m => m.Groups[1].Value + m.Groups[2].Value.ToLower() + "%3A");
}

public static string ConvertLineBreaks(this string text, string lineBrakeChars)
{
return Regex.Replace(text, @"\r\n?|\n", lineBrakeChars);
}
}
}
24 changes: 10 additions & 14 deletions src/Cody.Core/DocumentSync/DocumentSyncCallback.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Cody.Core.Agent;
using Cody.Core.Agent.Protocol;
using Cody.Core.Common;
using Cody.Core.Logging;
using Cody.Core.Trace;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace Cody.Core.DocumentSync
{
Expand All @@ -22,12 +22,6 @@ public DocumentSyncCallback(IAgentService agentService, ILog logger)
this.logger = logger;
}

private string ToUri(string path)
{
var uri = new Uri(path).AbsoluteUri;
return Regex.Replace(uri, "(file:///)(\\D+)(:)", m => m.Groups[1].Value + m.Groups[2].Value.ToLower() + "%3A");
}

public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange selection, IEnumerable<DocumentChange> changes)
{
trace.TraceEvent("DidChange", "ch: '{0}', sel:{1}, vr:{2}, path:{3}", string.Join("", changes), selection, visibleRange, fullPath);
Expand All @@ -52,7 +46,7 @@ public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange

var docState = new ProtocolTextDocument
{
Uri = ToUri(fullPath),
Uri = fullPath.ToUri(),
VisibleRange = vRange,
Selection = new Range
{
Expand All @@ -69,7 +63,7 @@ public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange
},
ContentChanges = changes.Select(x => new ProtocolTextDocumentContentChangeEvent
{
Text = x.Text,
Text = x.Text.ConvertLineBreaks("\n"),
Range = new Range
{
Start = new Position
Expand All @@ -87,6 +81,8 @@ public void OnChanged(string fullPath, DocumentRange visibleRange, DocumentRange
};

agentService.DidChange(docState);
//var result = agentService.GetWorkspaceDocuments(new GetDocumentsParams { Uris = new[] { fullPath.ToUri() } }).Result;
//trace.TraceEvent("AfterDidChange", result.Documents.First().Content);
}

public void OnClosed(string fullPath)
Expand All @@ -95,7 +91,7 @@ public void OnClosed(string fullPath)

var docState = new ProtocolTextDocument
{
Uri = ToUri(fullPath),
Uri = fullPath.ToUri(),
};

// Only the 'uri' property is required, other properties are ignored.
Expand All @@ -105,7 +101,7 @@ public void OnClosed(string fullPath)
public void OnFocus(string fullPath)
{
trace.TraceEvent("DidFocus", "{0}", fullPath);
agentService.DidFocus(new CodyFilePath { Uri = ToUri(fullPath) });
agentService.DidFocus(new CodyFilePath { Uri = fullPath.ToUri() });
}

public void OnOpened(string fullPath, string content, DocumentRange visibleRange, DocumentRange selection)
Expand All @@ -132,8 +128,8 @@ public void OnOpened(string fullPath, string content, DocumentRange visibleRange

var docState = new ProtocolTextDocument
{
Uri = ToUri(fullPath),
Content = content,
Uri = fullPath.ToUri(),
Content = content.ConvertLineBreaks("\n"),
VisibleRange = vRange,
Selection = new Range
{
Expand All @@ -156,7 +152,7 @@ public void OnOpened(string fullPath, string content, DocumentRange visibleRange
public void OnSaved(string fullPath)
{
trace.TraceEvent("DidSave", "{0}", fullPath);
agentService.DidSave(new CodyFilePath { Uri = ToUri(fullPath) });
agentService.DidSave(new CodyFilePath { Uri = fullPath.ToUri() });
}
}
}
1 change: 1 addition & 0 deletions src/Cody.Core/Settings/IUserSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface IUserSettingsService
string ServerEndpoint { get; set; }
string CustomConfiguration { get; set; }
bool AcceptNonTrustedCert { get; set; }
bool AutomaticallyTriggerCompletions { get; set; }


event EventHandler AuthorizationDetailsChanged;
Expand Down
10 changes: 10 additions & 0 deletions src/Cody.Core/Settings/UserSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,15 @@ public bool AcceptNonTrustedCert
}
set => Set(nameof(AcceptNonTrustedCert), value.ToString());
}

public bool AutomaticallyTriggerCompletions
{
get
{
var value = GetOrDefault(nameof(AutomaticallyTriggerCompletions), true.ToString());
return bool.Parse(value);
}
set => Set(nameof(AutomaticallyTriggerCompletions), value.ToString());
}
}
}
3 changes: 2 additions & 1 deletion src/Cody.Core/Trace/FileTraceListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ protected string FormatTraceEvent(TraceEvent traceEvent)

if (!string.IsNullOrEmpty(traceEvent.Message))
{
sb.AppendFormat(traceEvent.Message, traceEvent.MessageArgs);
if (traceEvent.MessageArgs != null && traceEvent.MessageArgs.Any()) sb.AppendFormat(traceEvent.Message, traceEvent.MessageArgs);
else sb.Append(traceEvent.Message);
}

if (traceEvent.Data != null)
Expand Down
3 changes: 2 additions & 1 deletion src/Cody.Core/Trace/LogioTraceListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ protected override void Write(TraceEvent traceEvent)
if (!string.IsNullOrEmpty(traceEvent.Message))
{
sb.Append(" ");
sb.AppendFormat(traceEvent.Message, traceEvent.MessageArgs);
if (traceEvent.MessageArgs != null && traceEvent.MessageArgs.Any()) sb.AppendFormat(traceEvent.Message, traceEvent.MessageArgs);
else sb.Append(traceEvent.Message);
}

if (traceEvent.Data != null)
Expand Down
Loading

0 comments on commit 3cb8d9d

Please sign in to comment.