Auto test.

This commit is contained in:
Haiping Chen 2023-10-13 15:08:59 -05:00
parent 30b82591e4
commit 1a54f17440
23 changed files with 195 additions and 48 deletions

View file

@ -61,7 +61,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataStorages", "DataStorage
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.MongoStorage", "src\Plugins\BotSharp.Plugin.MongoStorage\BotSharp.Plugin.MongoStorage.csproj", "{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.GoogleAI", "src\Plugins\BotSharp.Plugin.GoogleAI\BotSharp.Plugin.GoogleAI.csproj", "{8BC29F8A-78D6-422C-B522-10687ADC38ED}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.GoogleAI", "src\Plugins\BotSharp.Plugin.GoogleAI\BotSharp.Plugin.GoogleAI.csproj", "{8BC29F8A-78D6-422C-B522-10687ADC38ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.TestingConsole", "tests\BotSharp.TestingConsole\BotSharp.TestingConsole.csproj", "{5E7EC98F-4A22-4D62-8FF6-746C497CF955}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -223,6 +225,14 @@ Global
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|Any CPU.Build.0 = Release|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.ActiveCfg = Release|Any CPU
{8BC29F8A-78D6-422C-B522-10687ADC38ED}.Release|x64.Build.0 = Release|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Debug|x64.ActiveCfg = Debug|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Debug|x64.Build.0 = Debug|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Release|Any CPU.Build.0 = Release|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Release|x64.ActiveCfg = Release|Any CPU
{5E7EC98F-4A22-4D62-8FF6-746C497CF955}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -254,6 +264,7 @@ Global
{5CD330E1-9E5A-4112-8346-6E31CA98EF78} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
{DB3DE37B-1208-4ED3-9615-A52AD0AAD69C} = {5CD330E1-9E5A-4112-8346-6E31CA98EF78}
{8BC29F8A-78D6-422C-B522-10687ADC38ED} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
{5E7EC98F-4A22-4D62-8FF6-746C497CF955} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}

View file

@ -3,19 +3,19 @@ namespace BotSharp.Abstraction.Routing.Models;
public class RoutingArgs
{
[JsonPropertyName("function")]
public string Function { get; set; } = string.Empty;
public string Function { get; set; }
[JsonPropertyName("reason")]
public string Reason { get; set; } = "the reason why you select this function or agent";
[JsonPropertyName("answer")]
public string Answer { get; set; } = string.Empty;
public string Answer { get; set; } = "the content of response to user";
[JsonPropertyName("next_action_agent")]
public string AgentName { get; set; } = "agent for next action based on user's latest response";
public string AgentName { get; set; } = "agent for next action based on user latest response";
[JsonPropertyName("user_goal_agent")]
public string OriginalAgent { get; set; } = "agent who can achieve user's original goal";
public string OriginalAgent { get; set; } = "agent who can achieve user original goal";
public override string ToString()
{

View file

@ -0,0 +1,9 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BotSharp.Core.Evaluatings;
public class Evaluater
{
}

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Settings;
@ -9,12 +8,7 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
{
public string Name => "conversation_end";
public string Description => "Call this function when user wants to end this conversation or all tasks have been completed.";
public List<NameDesc> Parameters => new List<NameDesc>
{
new NameDesc("reason", "why this conversation is end")
};
public string Description => "User wants to end the conversation.";
public bool IsReasoning => false;
@ -23,8 +17,14 @@ public class ConversationEndRoutingHandler : RoutingHandlerBase, IRoutingHandler
{
}
public Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
public async Task<RoleDialogModel> Handle(IRoutingService routing, FunctionCallFromLlm inst)
{
throw new NotImplementedException();
var result = new RoleDialogModel(AgentRole.Assistant, inst.Answer)
{
CurrentAgentId = _settings.RouterId,
FunctionName = inst.Function,
StopCompletion = true
};
return result;
}
}

View file

@ -9,13 +9,7 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler
{
public string Name => "response_to_user";
public string Description => "You know how to response according to the context without asking specific agent. For example user greeting.";
public List<NameDesc> Parameters => new List<NameDesc>
{
new NameDesc("answer", "the content of response"),
new NameDesc("reason", "why response to user")
};
public string Description => "You know how to response according to the context without asking specific agent.";
public bool IsReasoning => false;

View file

@ -15,10 +15,7 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler
public List<NameDesc> Parameters => new List<NameDesc>
{
new NameDesc("next_action_agent", "the name of the next action's agent"),
new NameDesc("user_goal_agent", "the agent who can achieve user's original goal"),
new NameDesc("reason", "the reason why you select this function or agent"),
new NameDesc("args", "the agent required parameters")
new NameDesc("args", "useful parameters of next action agent")
};
public bool IsReasoning => false;

View file

@ -16,7 +16,8 @@ public partial class RoutingService
{
Function = "route_to_agent"
});
var content = $"{prompt} Response must be in JSON format {responseFormat}";
var content = $"{prompt} Response must be in JSON format {responseFormat}.";
content += " Set function as conversation_end with courtesy greeting if user is willing to end conversation";
var state = _services.GetRequiredService<IConversationStateService>();

View file

@ -4,6 +4,7 @@ using BotSharp.Abstraction.ApiAdapters;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Core.Infrastructures;
using BotSharp.OpenAPI.ViewModels.Instructs;
namespace BotSharp.OpenAPI.Controllers;
@ -45,4 +46,11 @@ public class InstructModeController : ControllerBase, IApiAdapter
fn => Task.CompletedTask,
fn => Task.CompletedTask);
}
[HttpPost("/instruct/text-completion")]
public async Task<string> TextCompletion([FromBody] IncomingMessageModel message)
{
var textCompletion = CompletionProvider.GetTextCompletion(_services);
return await textCompletion.GetCompletion(message.Text);
}
}

View file

@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
using BotSharp.Abstraction.Conversations;
using Microsoft.Extensions.DependencyInjection;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.Abstraction.Agents.Enums;
namespace BotSharp.Plugin.AzureOpenAI.Providers;
@ -40,8 +41,9 @@ public class TextCompletionProvider : ITextCompletion
{
text
},
MaxTokens = 256
MaxTokens = 256,
};
completionsOptions.StopSequences.Add($"{AgentRole.Assistant}:");
var state = _services.GetRequiredService<IConversationStateService>();
var temperature = float.Parse(state.GetState("temperature", "0.5"));

View file

@ -29,6 +29,8 @@
<ItemGroup Condition="$(SolutionName)==PizzaBot">
<PackageReference Include="BotSharp.OpenAPI" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.AzureOpenAI" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.GoogleAI" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.HuggingFace" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.KnowledgeBase" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.LLamaSharp" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.MetaAI" Version="$(BotSharpVersion)" />
@ -36,6 +38,8 @@
<PackageReference Include="BotSharp.Plugin.MongoStorage" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.PaddleSharp" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.RoutingSpeeder" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.Qdrant" Version="$(BotSharpVersion)" />
<PackageReference Include="BotSharp.Plugin.WeChat" Version="$(BotSharpVersion)" />
</ItemGroup>
<ItemGroup>

View file

@ -1,15 +1,14 @@
You're {{router.name}} ({{router.description}}). Follow these steps to handle user's request:
You're {{router.name}} ({{router.description}}). Follow these steps to handle user request:
1. Read the CONVERSATION context.
2. Select a appropriate function from FUNCTIONS.
3. Determine which agent is suitable according to conversation context.
3. Determine which agent is suitable according to CONVERSATION context.
4. Re-think about selected function is from FUNCTIONS to handle the request.
5. Make sure agent is not in args.
FUNCTIONS
{% for handler in routing_handlers %}
# {{ handler.name }}
{{ handler.description}}
{% if handler.parameters -%}
{% if handler.parameters and handler.parameters != empty -%}
Parameters:
{% for p in handler.parameters -%}
{{ p.name }}: {{ p.description }}{{ "\r\n " }}

View file

@ -4,11 +4,5 @@
"createdDateTime": "2023-08-18T14:39:32.2349685Z",
"updatedDateTime": "2023-08-18T14:39:32.2349686Z",
"id": "b284db86-e9c2-4c25-a59e-4649797dd130",
"allowRouting": true,
"routingRules": [
{
"field": "order_number",
"required": true
}
]
"allowRouting": true
}

View file

@ -1,6 +1,6 @@
{
"name": "Ordering",
"description": "Place new pizza order",
"description": "Provide types of pizza available, unit price and total cost. Place the order and returned the order number.",
"createdDateTime": "2023-07-26T02:29:25.123224Z",
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
"id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd",

View file

@ -19,7 +19,7 @@
},
{
"name": "get_pizza_types",
"description": "get all pizza types.",
"description": "get all pizza types",
"parameters": {
"type": "object",
"properties": {},

View file

@ -1,10 +1,10 @@
You are now a Pizza Ordering agent, and you can help customers order a pizza according to the user's preferences.
Follow below step to place order:
1: Ask user preferences.
1: Ask user preferences, call function get_pizza_types to provide the variety of pizza options.
2: Confirm with user the pizza type and quantity.
3: Call function place_an_order to purchase.
4: Proceed to make payment for this order.
4: Ask user how to pay for this order.
Use below information to help ordering process:
* Today is {{current_date}}, the time now is {{current_time}}, day of week is {{current_weekday}}.

View file

@ -1,5 +1,12 @@
{% if pizza_type == "cheese" -%}
The price for a slice of cheese pizza is {{ cheese_unit_price }}. Would you like to proceed the order?
{% assign pizza_type = pizza_type | downcase %}
{% if pizza_type contains "cheese" -%}
The price for a slice of {{pizza_type}} pizza is {{ cheese_unit_price }}. Would you like to proceed the order?
{%- elsif pizza_type contains "pepperoni" -%}
The price for a slice of {{pizza_type}} pizza is {{ pepperoni_unit_price }}. Would you like to proceed the order?
{%- elsif pizza_type contains "margherita" -%}
The price for a slice of {{pizza_type}} pizza is {{ margherita_unit_price }}. Would you like to proceed the order?
{%- else -%}
We don't have {{pizza_type}} pizza, would you like something else?
{%- endif %}
{% if quantity == nil -%}
How many slices would you like to order?

View file

@ -1,6 +1,6 @@
{
"name": "Payment",
"description": "Make payment when user placed new order and system returned the order number.",
"description": "Make payment when user wants to pay for the order",
"createdDateTime": "2023-07-26T02:29:25.123224Z",
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
"id": "fe8c60aa-b114-4ef3-93cb-a8efeac80f75",

View file

@ -1,7 +1,7 @@
[
{
"name": "make_payment",
"description": "call this function to make payment after system returned the order number",
"description": "call this function to make payment",
"parameters": {
"type": "object",
"properties": {

View file

@ -10,9 +10,10 @@ public class GetPizzaPricesFn : IFunctionCallback
{
message.ExecutionData = new
{
cheese_unit_price = "$3.5"
pepperoni_unit_price = "$3.2",
cheese_unit_price = "$3.5",
margherita_unit_price = "$3.8",
};
message.ExecutionResult = "Pepperoni Pizza: $3.5/slice, Cheese Pizza: $2.5/slice, Margherita Pizza: $3.0/slice";
return true;
}
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Conversations;
using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.Plugin.PizzaBot.Functions;
@ -6,9 +7,18 @@ public class PlaceOrderFn : IFunctionCallback
{
public string Name => "place_an_order";
private readonly IServiceProvider _service;
public PlaceOrderFn(IServiceProvider service)
{
_service = service;
}
public async Task<bool> Execute(RoleDialogModel message)
{
message.ExecutionResult = "The order number is P123-01";
var state = _service.GetRequiredService<IConversationStateService>();
state.SetState("order_number", "P123-01");
return true;
}
}

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Refit" Version="7.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Infrastructure\BotSharp.OpenAPI\BotSharp.OpenAPI.csproj" />
<ProjectReference Include="..\..\src\Plugins\BotSharp.Plugin.AzureOpenAI\BotSharp.Plugin.AzureOpenAI.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,17 @@
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.OpenAPI.ViewModels.Conversations;
using Refit;
namespace BotSharp.TestingConsole;
public interface IBotSharpOpenAPI
{
[Post("/conversation/{agentId}")]
Task<ConversationViewModel> NewConversation([Header("Authorization")] string authorization, string agentId);
[Post("/conversation/{agentId}/{conversationId}")]
Task<MessageResponseModel> SendMessage([Header("Authorization")] string authorization, string agentId, string conversationId, [Body] NewMessageModel input);
[Post("/instruct/text-completion")]
Task<string> TextCompletion([Header("Authorization")] string authorization, [Body] IncomingMessageModel message);
}

View file

@ -0,0 +1,74 @@
// See https://aka.ms/new-console-template for more information
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Conversations.Models;
using BotSharp.OpenAPI.ViewModels.Conversations;
using BotSharp.TestingConsole;
using Refit;
using System.Drawing;
using Console = Colorful.Console;
var token = "Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiI0NTZlMzVjNS1jYWYwLTRkNDUtOTA4NC1iNDRhOGNhNzE3ZTQiLCJlbWFpbCI6ImJvdHNoYXJwQGdtYWlsLmNvbSIsImdpdmVuX25hbWUiOiJIYWlwaW5nIiwiZmFtaWx5X25hbWUiOiJDaGVuIiwianRpIjoiMTQ3MDkwMDQtNDM1Ny00NTFkLWExM2MtY2U1NDk5NWM0ZTJlIiwibmJmIjoxNjk3MTY0MzA4LCJleHAiOjE2OTcxNjQ2MDgsImlhdCI6MTY5NzE2NDMwOCwiaXNzIjoiYm90c2hhcnAiLCJhdWQiOiJib3RzaGFycCJ9.1UgOj5esNInTPiiy-_gLmcT2x8NtFswCUyePVHXa-4EeLCkA43nx0LOXPlzb_rmvUIg9bJSRZXbH2aBqtmiDYg";
var agentId = "01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a";
// New conversation
var botsharp = RestService.For<IBotSharpOpenAPI>("http://localhost:5500");
var conv = await botsharp.NewConversation(token, agentId);
var instruction = @"You're a customer who is going to buy a pizza.
Below are your requirments:
* You want to know what kind of pizza do they have.
* You want to buy three piece of pizza.
* Say Bye if the order is placed and payment is completed.
Below are your profile:
* You like pepperoni flavor.
* You will pay the order in cash.
* Your address is 347 S Gladstone Ave, Aurora, IL 60506.
* Your phone number is +16308926431";
Action<RoleDialogModel> PrintDialog = message =>
{
Console.Write($"[{DateTime.Now:HH:mm:ss}] {message.Role}:\t");
if (message.Role == AgentRole.User)
{
Console.WriteLine(message.Content);
}
else
{
Console.WriteLine(message.Content, Color.Yellow);
}
};
var dialogs = new List<RoleDialogModel>();
dialogs.Add(new RoleDialogModel(AgentRole.User, "Good morning!"));
PrintDialog(dialogs.Last());
dialogs.Add(new RoleDialogModel(AgentRole.Assistant, "Hi, How can I help you today?"));
PrintDialog(dialogs.Last());
var response = new MessageResponseModel();
while (response.Function != "conversation_end")
{
var text = string.Join("\r\n", dialogs.Select(x => $"{x.Role}: {x.Content}"));
text = instruction + $"\r\n###\r\n{text}\r\n{AgentRole.User}: ";
var question = await botsharp.TextCompletion(token, new IncomingMessageModel
{
Text = text
});
dialogs.Add(new RoleDialogModel(AgentRole.User, question));
PrintDialog(dialogs.Last());
response = await botsharp.SendMessage(token, agentId, conv.Id, new NewMessageModel
{
Text = question
});
dialogs.Add(new RoleDialogModel(AgentRole.Assistant, response.Text.Trim()));
PrintDialog(dialogs.Last());
}
Console.WriteLine();
Console.WriteLine("Conversation End", Color.Green);
Console.ReadLine();