diff --git a/shell/AIShell.Abstraction/ILLMAgent.cs b/shell/AIShell.Abstraction/ILLMAgent.cs
index a4e3fb2f..1119db31 100644
--- a/shell/AIShell.Abstraction/ILLMAgent.cs
+++ b/shell/AIShell.Abstraction/ILLMAgent.cs
@@ -138,7 +138,7 @@ public interface ILLMAgent : IDisposable
///
/// Refresh the current chat or force starting a new chat session.
- /// This method allows an agent to reset chat states, interact with user for authentication, print welcome message, and more.
+ /// This method allows an agent to reset chat states, refresh token or settings, interact with user for authentication, print welcome message, and more.
///
/// The interface for interacting with the shell.
/// Whether or not to force creating a new chat session.
diff --git a/shell/AIShell.Kernel/LLMAgent.cs b/shell/AIShell.Kernel/LLMAgent.cs
index 20df609f..1b653d76 100644
--- a/shell/AIShell.Kernel/LLMAgent.cs
+++ b/shell/AIShell.Kernel/LLMAgent.cs
@@ -13,7 +13,7 @@ internal LLMAgent(ILLMAgent agent, AgentAssemblyLoadContext loadContext)
{
Impl = agent;
LoadContext = loadContext;
- Prompt = agent.Name;
+ Prompt = $"@{agent.Name}";
}
internal void Display(Host host, string description = null)
diff --git a/shell/AIShell.Kernel/Shell.cs b/shell/AIShell.Kernel/Shell.cs
index dd99b309..c646d2e5 100644
--- a/shell/AIShell.Kernel/Shell.cs
+++ b/shell/AIShell.Kernel/Shell.cs
@@ -285,7 +285,7 @@ private void LoadAvailableAgents()
chosenAgent ??= _agents.Count is 1
? _agents[0]
: Host.PromptForSelectionAsync(
- title: "[orange1]Please select an [Blue]agent[/] to use[/]:",
+ title: "[orange1]Please select an [Blue]agent[/] to use[/]:\n[grey](You can switch to another agent later by typing [Blue]@[/])[/]",
choices: _agents,
converter: static a => a.Impl.Name)
.GetAwaiter().GetResult();
@@ -538,6 +538,18 @@ private async Task ReadUserInput(string prompt, CancellationToken cancel
return input;
}
+ ///
+ /// Give an agent the opportunity to refresh its chat session, in the unforced way.
+ ///
+ private async Task RefreshChatAsNeeded(LLMAgent agent)
+ {
+ if (_shouldRefresh)
+ {
+ _shouldRefresh = false;
+ await agent?.Impl.RefreshChatAsync(this, force: false);
+ }
+ }
+
///
/// Run a chat REPL.
///
@@ -552,11 +564,7 @@ internal async Task RunREPLAsync()
try
{
- if (_shouldRefresh)
- {
- _shouldRefresh = false;
- await agent?.Impl.RefreshChatAsync(this, force: false);
- }
+ await RefreshChatAsNeeded(agent);
if (Regenerate)
{
@@ -595,6 +603,12 @@ internal async Task RunREPLAsync()
{
continue;
}
+ else
+ {
+ // We may be switching to an agent that hasn't setup its chat session yet.
+ // So, give it a chance to do so before calling its 'Chat' method.
+ await RefreshChatAsNeeded(agent);
+ }
}
string copiedText = await GetClipboardContent(input);
diff --git a/shell/agents/AIShell.Interpreter.Agent/Agent.cs b/shell/agents/AIShell.Interpreter.Agent/Agent.cs
index 62b0da85..1a3c6ee3 100644
--- a/shell/agents/AIShell.Interpreter.Agent/Agent.cs
+++ b/shell/agents/AIShell.Interpreter.Agent/Agent.cs
@@ -74,12 +74,15 @@ public void Initialize(AgentConfig config)
///
public Task RefreshChatAsync(IShell shell, bool force)
{
- // Reload the setting file if needed.
- ReloadSettings();
- // Reset the history so the subsequent chat can start fresh.
- _chatService.RefreshChat();
- // Shut down the execution service to start fresh.
- _executionService.Terminate();
+ if (force)
+ {
+ // Reload the setting file if needed.
+ ReloadSettings();
+ // Reset the history so the subsequent chat can start fresh.
+ _chatService.RefreshChat();
+ // Shut down the execution service to start fresh.
+ _executionService.Terminate();
+ }
return Task.CompletedTask;
}
diff --git a/shell/agents/AIShell.OpenAI.Agent/Agent.cs b/shell/agents/AIShell.OpenAI.Agent/Agent.cs
index 4da54ccc..16a86d4e 100644
--- a/shell/agents/AIShell.OpenAI.Agent/Agent.cs
+++ b/shell/agents/AIShell.OpenAI.Agent/Agent.cs
@@ -79,10 +79,13 @@ public void OnUserAction(UserActionPayload actionPayload) {}
///
public Task RefreshChatAsync(IShell shell, bool force)
{
- // Reload the setting file if needed.
- ReloadSettings();
- // Reset the history so the subsequent chat can start fresh.
- _chatService.ChatHistory.Clear();
+ if (force)
+ {
+ // Reload the setting file if needed.
+ ReloadSettings();
+ // Reset the history so the subsequent chat can start fresh.
+ _chatService.ChatHistory.Clear();
+ }
return Task.CompletedTask;
}
diff --git a/shell/agents/Microsoft.Azure.Agent/AzureAgent.cs b/shell/agents/Microsoft.Azure.Agent/AzureAgent.cs
index 034e84df..2236b95b 100644
--- a/shell/agents/Microsoft.Azure.Agent/AzureAgent.cs
+++ b/shell/agents/Microsoft.Azure.Agent/AzureAgent.cs
@@ -77,7 +77,7 @@ public AzureAgent()
public void Dispose()
{
- ArgPlaceholder?.DataRetriever?.Dispose();
+ ResetArgumentPlaceholder();
_chatSession.Dispose();
_httpClient.Dispose();
@@ -120,6 +120,7 @@ public async Task RefreshChatAsync(IShell shell, bool force)
{
IHost host = shell.Host;
CancellationToken cancellationToken = shell.CancellationToken;
+ ResetArgumentPlaceholder();
try
{
@@ -179,8 +180,7 @@ public async Task ChatAsync(string input, IShell shell)
if (_copilotResponse.ChunkReader is null)
{
- ArgPlaceholder?.DataRetriever?.Dispose();
- ArgPlaceholder = null;
+ ResetArgumentPlaceholder();
// Process CLI handler response specially to support parameter injection.
ResponseData data = null;
@@ -360,6 +360,12 @@ private ResponseData ParseCLIHandlerResponse(IShell shell)
return data;
}
+ internal void ResetArgumentPlaceholder()
+ {
+ ArgPlaceholder?.DataRetriever?.Dispose();
+ ArgPlaceholder = null;
+ }
+
internal void SaveUserValue(string phName, string value)
{
ArgumentException.ThrowIfNullOrEmpty(phName);
@@ -465,7 +471,9 @@ internal string GenerateAnswer(ResponseData data)
_buffer.Append($"- `{phItem.Name}`: {phItem.Desc}\n");
}
- _buffer.Append("\nRun `/replace` to get assistance in placeholder replacement.\n");
+ // Use green (0,195,0) on grey (48,48,48) for rendering the command '/replace'.
+ // TODO: the color formatting should be exposed by the shell as utility method.
+ _buffer.Append("\nRun \x1b[38;2;0;195;0;48;2;48;48;48m /replace \x1b[0m to get assistance in placeholder replacement.\n");
}
}
diff --git a/shell/agents/Microsoft.Azure.Agent/ChatSession.cs b/shell/agents/Microsoft.Azure.Agent/ChatSession.cs
index 17a60723..888fd55a 100644
--- a/shell/agents/Microsoft.Azure.Agent/ChatSession.cs
+++ b/shell/agents/Microsoft.Azure.Agent/ChatSession.cs
@@ -70,7 +70,7 @@ internal async Task RefreshAsync(IStatusContext context, bool force, Can
if (force)
{
// End the existing conversation.
- context.Status("End current chat ...");
+ context.Status("Ending current chat ...");
EndConversation();
Reset();
}
@@ -78,7 +78,7 @@ internal async Task RefreshAsync(IStatusContext context, bool force, Can
{
try
{
- context.Status("Refresh DirectLine token ...");
+ context.Status("Refreshing token ...");
await RenewTokenAsync(cancellationToken);
return null;
}
diff --git a/shell/agents/Microsoft.Azure.Agent/Command.cs b/shell/agents/Microsoft.Azure.Agent/Command.cs
index f79800f2..e664417a 100644
--- a/shell/agents/Microsoft.Azure.Agent/Command.cs
+++ b/shell/agents/Microsoft.Azure.Agent/Command.cs
@@ -238,8 +238,7 @@ private async Task RegenerateAsync()
if (data.PlaceholderSet is null)
{
- _agent.ArgPlaceholder.DataRetriever.Dispose();
- _agent.ArgPlaceholder = null;
+ _agent.ResetArgumentPlaceholder();
}
return _agent.GenerateAnswer(data);