Skip to content
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
27 changes: 14 additions & 13 deletions shell/agents/Microsoft.Azure.Agent/AzureAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ 7. DO NOT include the placeholder summary when the commands contains no placehol
""";

private int _turnsLeft;
private CopilotResponse _copilotResponse;

private readonly string _instructions;
private readonly StringBuilder _buffer;
Expand Down Expand Up @@ -120,36 +121,36 @@ public async Task<bool> ChatAsync(string input, IShell shell)
try
{
string query = $"{input}\n\n---\n\n{_instructions}";
CopilotResponse copilotResponse = await host.RunWithSpinnerAsync(
_copilotResponse = await host.RunWithSpinnerAsync(
status: "Thinking ...",
spinnerKind: SpinnerKind.Processing,
func: async context => await _chatSession.GetChatResponseAsync(query, context, token)
).ConfigureAwait(false);

if (copilotResponse is null)
if (_copilotResponse is null)
{
// User cancelled the operation.
return true;
}

if (copilotResponse.ChunkReader is null)
if (_copilotResponse.ChunkReader is null)
{
ArgPlaceholder?.DataRetriever?.Dispose();
ArgPlaceholder = null;

// Process CLI handler response specially to support parameter injection.
ResponseData data = null;
if (copilotResponse.TopicName == CopilotActivity.CLIHandlerTopic)
if (_copilotResponse.TopicName == CopilotActivity.CLIHandlerTopic)
{
data = ParseCLIHandlerResponse(copilotResponse, shell);
data = ParseCLIHandlerResponse(shell);
}

if (data?.PlaceholderSet is not null)
{
ArgPlaceholder = new ArgumentPlaceholder(input, data, _httpClient);
}

string answer = data is null ? copilotResponse.Text : GenerateAnswer(data);
string answer = data is null ? _copilotResponse.Text : GenerateAnswer(data);
host.RenderFullResponse(answer);
}
else
Expand All @@ -161,12 +162,12 @@ public async Task<bool> ChatAsync(string input, IShell shell)

while (true)
{
CopilotActivity activity = copilotResponse.ChunkReader.ReadChunk(token);
CopilotActivity activity = _copilotResponse.ChunkReader.ReadChunk(token);
if (activity is null)
{
prevActivity.ExtractMetadata(out string[] suggestion, out ConversationState state);
copilotResponse.SuggestedUserResponses = suggestion;
copilotResponse.ConversationState = state;
_copilotResponse.SuggestedUserResponses = suggestion;
_copilotResponse.ConversationState = state;
break;
}

Expand All @@ -182,7 +183,7 @@ public async Task<bool> ChatAsync(string input, IShell shell)
}
}

var conversationState = copilotResponse.ConversationState;
var conversationState = _copilotResponse.ConversationState;
_turnsLeft = conversationState.TurnLimit - conversationState.TurnNumber;
if (_turnsLeft <= 5)
{
Expand Down Expand Up @@ -210,9 +211,9 @@ public async Task<bool> ChatAsync(string input, IShell shell)
return true;
}

private ResponseData ParseCLIHandlerResponse(CopilotResponse copilotResponse, IShell shell)
private ResponseData ParseCLIHandlerResponse(IShell shell)
{
string text = copilotResponse.Text;
string text = _copilotResponse.Text;
List<CodeBlock> codeBlocks = shell.ExtractCodeBlocks(text, out List<SourceInfo> sourceInfos);
if (codeBlocks is null || codeBlocks.Count is 0)
{
Expand Down Expand Up @@ -264,7 +265,7 @@ private ResponseData ParseCLIHandlerResponse(CopilotResponse copilotResponse, IS
Text = text,
CommandSet = commands,
PlaceholderSet = placeholders,
Locale = copilotResponse.Locale,
Locale = _copilotResponse.Locale,
};

string first = placeholders[0].Name;
Expand Down
11 changes: 8 additions & 3 deletions shell/agents/Microsoft.Azure.Agent/ChatSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ internal class ChatSession : IDisposable

private string _token;
private string _streamUrl;
private string _conversationId;
private string _conversationUrl;
private DateTime _expireOn;
private AzureCopilotReceiver _copilotReceiver;
Expand All @@ -24,6 +25,8 @@ internal class ChatSession : IDisposable
private readonly HttpClient _httpClient;
private readonly Dictionary<string, object> _flights;

internal string ConversationId => _conversationId;

internal ChatSession(HttpClient httpClient)
{
_dl_secret = Environment.GetEnvironmentVariable("DL_SECRET");
Expand Down Expand Up @@ -88,6 +91,7 @@ private void Reset()
{
_token = null;
_streamUrl = null;
_conversationId = null;
_conversationUrl = null;
_expireOn = DateTime.MinValue;

Expand Down Expand Up @@ -135,7 +139,8 @@ private async Task StartConversationAsync(IHost host, CancellationToken cancella
SessionPayload spl = JsonSerializer.Deserialize<SessionPayload>(content, Utils.JsonOptions);

_token = spl.Token;
_conversationUrl = $"{CONVERSATION_URL}/{spl.ConversationId}/activities";
_conversationId = spl.ConversationId;
_conversationUrl = $"{CONVERSATION_URL}/{_conversationId}/activities";
_streamUrl = spl.StreamUrl;
_expireOn = DateTime.UtcNow.AddSeconds(spl.ExpiresIn);
_copilotReceiver = await AzureCopilotReceiver.CreateAsync(_streamUrl);
Expand Down Expand Up @@ -278,8 +283,8 @@ internal async Task<CopilotResponse> GetChatResponseAsync(string input, IStatusC
{
CopilotResponse ret = activity.InputHint switch
{
"typing" => new CopilotResponse(new ChunkReader(_copilotReceiver, activity), activity.Locale, activity.TopicName),
"acceptingInput" => new CopilotResponse(activity.Text, activity.Locale, activity.TopicName),
"typing" => new CopilotResponse(activity, new ChunkReader(_copilotReceiver, activity)),
"acceptingInput" => new CopilotResponse(activity),
_ => throw CorruptDataException.Create($"The 'inputHint' is {activity.InputHint}.", activity)
};

Expand Down
20 changes: 9 additions & 11 deletions shell/agents/Microsoft.Azure.Agent/Schema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,30 +102,28 @@ internal class ConversationState

internal class CopilotResponse
{
internal CopilotResponse(ChunkReader chunkReader, string locale, string topicName)
internal CopilotResponse(CopilotActivity activity, ChunkReader chunkReader)
: this(activity)
{
ArgumentNullException.ThrowIfNull(chunkReader);
ArgumentException.ThrowIfNullOrEmpty(topicName);

ChunkReader = chunkReader;
Locale = locale;
TopicName = topicName;
}

internal CopilotResponse(string text, string locale, string topicName)
internal CopilotResponse(CopilotActivity activity)
{
ArgumentException.ThrowIfNullOrEmpty(text);
ArgumentException.ThrowIfNullOrEmpty(topicName);
ArgumentNullException.ThrowIfNull(activity);

Text = text;
Locale = locale;
TopicName = topicName;
Text = activity.Text;
Locale = activity.Locale;
TopicName = activity.TopicName;
ReplyToId = activity.ReplyToId;
}

internal ChunkReader ChunkReader { get; }
internal string Text { get; }
internal string Locale { get; }
internal string TopicName { get; }
internal string ReplyToId { get; }
internal string[] SuggestedUserResponses { get; set; }
internal ConversationState ConversationState { get; set; }
}
Expand Down