commit
d0144a686e
|
|
@ -42,6 +42,9 @@ public class RoleDialogModel : ITrackableMessage
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? FunctionName { get; set; }
|
public string? FunctionName { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public string? ToolCallId { get; set; }
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? PostbackFunctionName { get; set; }
|
public string? PostbackFunctionName { get; set; }
|
||||||
|
|
||||||
|
|
@ -108,6 +111,7 @@ public class RoleDialogModel : ITrackableMessage
|
||||||
MessageId = source.MessageId,
|
MessageId = source.MessageId,
|
||||||
FunctionArgs = source.FunctionArgs,
|
FunctionArgs = source.FunctionArgs,
|
||||||
FunctionName = source.FunctionName,
|
FunctionName = source.FunctionName,
|
||||||
|
ToolCallId = source.ToolCallId,
|
||||||
PostbackFunctionName = source.PostbackFunctionName,
|
PostbackFunctionName = source.PostbackFunctionName,
|
||||||
RichContent = source.RichContent,
|
RichContent = source.RichContent,
|
||||||
StopCompletion = source.StopCompletion,
|
StopCompletion = source.StopCompletion,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ public class FunctionCallingResponse
|
||||||
[JsonPropertyName("content")]
|
[JsonPropertyName("content")]
|
||||||
public string? Content { get; set; }
|
public string? Content { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("function_name")]
|
[JsonPropertyName("function")]
|
||||||
public string? FunctionName { get; set; }
|
public string? FunctionName { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("args")]
|
[JsonPropertyName("args")]
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ namespace BotSharp.Abstraction.Functions.Models;
|
||||||
|
|
||||||
public class FunctionDef
|
public class FunctionDef
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
[JsonPropertyName("name")]
|
||||||
public string Description { get; set; }
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[JsonPropertyName("description")]
|
||||||
|
public string Description { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("visibility_expression")]
|
[JsonPropertyName("visibility_expression")]
|
||||||
public string? VisibilityExpression { get; set; }
|
public string? VisibilityExpression { get; set; }
|
||||||
|
|
@ -11,6 +14,7 @@ public class FunctionDef
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string? Impact { get; set; }
|
public string? Impact { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("parameters")]
|
||||||
public FunctionParametersDef Parameters { get; set; } = new FunctionParametersDef();
|
public FunctionParametersDef Parameters { get; set; } = new FunctionParametersDef();
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,11 @@ public class FunctionParametersDef
|
||||||
[JsonPropertyName("required")]
|
[JsonPropertyName("required")]
|
||||||
public List<string> Required { get; set; } = new List<string>();
|
public List<string> Required { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{{\"type\":\"{Type}\", \"properties\":{JsonSerializer.Serialize(Properties)}, \"required\":[{string.Join(",", Required.Select(x => "\"" + x + "\""))}]}}";
|
||||||
|
}
|
||||||
|
|
||||||
public FunctionParametersDef()
|
public FunctionParametersDef()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
|
@ -150,7 +150,7 @@
|
||||||
<PackageReference Include="Aspects.Cache" Version="2.0.4" />
|
<PackageReference Include="Aspects.Cache" Version="2.0.4" />
|
||||||
<PackageReference Include="Colorful.Console" Version="1.2.15" />
|
<PackageReference Include="Colorful.Console" Version="1.2.15" />
|
||||||
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.2.1" />
|
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.2.1" />
|
||||||
<PackageReference Include="Fluid.Core" Version="2.8.0" />
|
<PackageReference Include="Fluid.Core" Version="2.9.0" />
|
||||||
<PackageReference Include="Nanoid" Version="3.0.0" />
|
<PackageReference Include="Nanoid" Version="3.0.0" />
|
||||||
<PackageReference Include="RedLock.net" Version="2.3.2" />
|
<PackageReference Include="RedLock.net" Version="2.3.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,19 @@ public partial class RoutingService
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var provide = agent.LlmConfig.Provider;
|
||||||
|
var model = agent.LlmConfig.Model;
|
||||||
|
|
||||||
|
if (provide == null || model == null)
|
||||||
|
{
|
||||||
|
var agentSettings = _services.GetRequiredService<AgentSettings>();
|
||||||
|
provide = agentSettings.LlmConfig.Provider;
|
||||||
|
model = agentSettings.LlmConfig.Model;
|
||||||
|
}
|
||||||
|
|
||||||
var chatCompletion = CompletionProvider.GetChatCompletion(_services,
|
var chatCompletion = CompletionProvider.GetChatCompletion(_services,
|
||||||
agentConfig: agent.LlmConfig);
|
provider: provide,
|
||||||
|
model: model);
|
||||||
|
|
||||||
var message = dialogs.Last();
|
var message = dialogs.Last();
|
||||||
var response = await chatCompletion.GetChatCompletions(agent, dialogs);
|
var response = await chatCompletion.GetChatCompletions(agent, dialogs);
|
||||||
|
|
@ -31,6 +42,7 @@ public partial class RoutingService
|
||||||
{
|
{
|
||||||
response.FunctionName = response.FunctionName.Split("/").Last();
|
response.FunctionName = response.FunctionName.Split("/").Last();
|
||||||
}
|
}
|
||||||
|
message.ToolCallId = response.ToolCallId;
|
||||||
message.FunctionName = response.FunctionName;
|
message.FunctionName = response.FunctionName;
|
||||||
message.FunctionArgs = response.FunctionArgs;
|
message.FunctionArgs = response.FunctionArgs;
|
||||||
message.CurrentAgentId = agent.Id;
|
message.CurrentAgentId = agent.Id;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ public class TemplateRender : ITemplateRender
|
||||||
_options.MemberAccessStrategy.Register<Agent>();
|
_options.MemberAccessStrategy.Register<Agent>();
|
||||||
_options.MemberAccessStrategy.Register<RoutableAgent>();
|
_options.MemberAccessStrategy.Register<RoutableAgent>();
|
||||||
_options.MemberAccessStrategy.Register<RoutingHandlerDef>();
|
_options.MemberAccessStrategy.Register<RoutingHandlerDef>();
|
||||||
|
_options.MemberAccessStrategy.Register<FunctionDef>();
|
||||||
|
_options.MemberAccessStrategy.Register<FunctionParametersDef>();
|
||||||
_options.MemberAccessStrategy.Register<UserIdentity>();
|
_options.MemberAccessStrategy.Register<UserIdentity>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
[Output Requirements]
|
{% if functions and functions != empty %}
|
||||||
1. Read the [Functions] definition, you can utilize the function to retrieve data or execute actions.
|
[FUNCTIONS]
|
||||||
2. Think step by step, check if specific function will provider data to help complete user request based on the conversation.
|
{% for fn in functions -%}
|
||||||
3. If you need to call a function to decide how to response user,
|
{{ fn.name }}: {{ fn.description }}
|
||||||
response in format: {"role": "function", "reason":"why choose this function", "function_name": "", "args": {}},
|
{{ fn.parameters }}
|
||||||
otherwise response in format: {"role": "assistant", "reason":"why response to user", "content":"next step question"}.
|
{{ "\r\n" }}
|
||||||
4. If the conversation already contains the function execution result, don't need to call it again.
|
{%- endfor %}
|
||||||
5. If user mentioned some specific requirment, don't ask this question in your response.
|
response_to_user: response to user directly without using any function.
|
||||||
6. Don't repeat the same question in your response.
|
{"type": "object", "properties": {"content":{"type": "string", "description": "The content responsed to user"}}, "required":["content"]}
|
||||||
|
|
||||||
|
[RESPONSE OUTPUT REQUIREMENTS]
|
||||||
|
* Pick the appropriate function and populate the arguments defined in properties.
|
||||||
|
* Output the JSON {"function": "", "args":{}} without other text
|
||||||
|
{% endif %}
|
||||||
27
src/Plugins/BotSharp.Plugin.AnthropicAI/AnthropicPlugin.cs
Normal file
27
src/Plugins/BotSharp.Plugin.AnthropicAI/AnthropicPlugin.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
using BotSharp.Abstraction.MLTasks;
|
||||||
|
using BotSharp.Abstraction.Plugins;
|
||||||
|
using BotSharp.Plugin.AnthropicAI.Providers;
|
||||||
|
using BotSharp.Plugin.AnthropicAI.Settings;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.AnthropicAI;
|
||||||
|
|
||||||
|
public class AnthropicPlugin : IBotSharpPlugin
|
||||||
|
{
|
||||||
|
public string Id => "012119da-8367-4be8-9a75-ab6ae55071e6";
|
||||||
|
|
||||||
|
public void RegisterDI(IServiceCollection services, IConfiguration config)
|
||||||
|
{
|
||||||
|
var settings = new AnthropicSettings();
|
||||||
|
config.Bind("Anthropic", settings);
|
||||||
|
services.AddSingleton(x =>
|
||||||
|
{
|
||||||
|
// Console.WriteLine($"Loaded Anthropic settings: {settings.Claude.ApiKey.SubstringMax(4)}");
|
||||||
|
return settings;
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddScoped<IChatCompletion, ChatCompletionProvider>();
|
||||||
|
// services.AddScoped<ITextCompletion, TextCompletionProvider>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Anthropic.SDK" Version="3.2.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Infrastructure\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
using Anthropic.SDK.Common;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace BotSharp.Plugin.AnthropicAI.Providers;
|
||||||
|
|
||||||
|
public class ChatCompletionProvider : IChatCompletion
|
||||||
|
{
|
||||||
|
public string Provider => "anthropic";
|
||||||
|
|
||||||
|
protected readonly AnthropicSettings _settings;
|
||||||
|
protected readonly IServiceProvider _services;
|
||||||
|
protected readonly ILogger _logger;
|
||||||
|
|
||||||
|
protected string _model;
|
||||||
|
|
||||||
|
public ChatCompletionProvider(AnthropicSettings settings,
|
||||||
|
ILogger<ChatCompletionProvider> logger,
|
||||||
|
IServiceProvider services)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
_logger = logger;
|
||||||
|
_services = services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RoleDialogModel> GetChatCompletions(Agent agent, List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
var contentHooks = _services.GetServices<IContentGeneratingHook>().ToList();
|
||||||
|
|
||||||
|
// Before chat completion hook
|
||||||
|
foreach (var hook in contentHooks)
|
||||||
|
{
|
||||||
|
await hook.BeforeGenerating(agent, conversations);
|
||||||
|
}
|
||||||
|
|
||||||
|
var settingsService = _services.GetRequiredService<ILlmProviderService>();
|
||||||
|
var settings = settingsService.GetSetting("anthropic", agent.LlmConfig?.Model ?? "claude-3-haiku");
|
||||||
|
|
||||||
|
var client = new AnthropicClient(new APIAuthentication(settings.ApiKey));
|
||||||
|
var (prompt, parameters) = PrepareOptions(agent, conversations);
|
||||||
|
|
||||||
|
var response = await client.Messages.GetClaudeMessageAsync(parameters);
|
||||||
|
|
||||||
|
RoleDialogModel responseMessage;
|
||||||
|
|
||||||
|
if (response.StopReason == "tool_use")
|
||||||
|
{
|
||||||
|
var toolResult = response.Content.OfType<ToolUseContent>().First();
|
||||||
|
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Function, response.FirstMessage?.Text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId,
|
||||||
|
ToolCallId = toolResult.Id,
|
||||||
|
FunctionName = toolResult.Name,
|
||||||
|
FunctionArgs = JsonSerializer.Serialize(toolResult.Input)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var message = response.FirstMessage;
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Assistant, message.Text)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// After chat completion hook
|
||||||
|
foreach (var hook in contentHooks)
|
||||||
|
{
|
||||||
|
await hook.AfterGenerated(responseMessage, new TokenStatsModel
|
||||||
|
{
|
||||||
|
Prompt = prompt,
|
||||||
|
Provider = Provider,
|
||||||
|
Model = _model,
|
||||||
|
PromptCount = response.Usage.InputTokens,
|
||||||
|
CompletionCount = response.Usage.OutputTokens
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return responseMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> GetChatCompletionsAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived, Func<RoleDialogModel, Task> onFunctionExecuting)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> GetChatCompletionsStreamingAsync(Agent agent, List<RoleDialogModel> conversations, Func<RoleDialogModel, Task> onMessageReceived)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private (string, MessageParameters) PrepareOptions(Agent agent, List<RoleDialogModel> conversations)
|
||||||
|
{
|
||||||
|
var instruction = "";
|
||||||
|
|
||||||
|
var agentService = _services.GetRequiredService<IAgentService>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(agent.Instruction))
|
||||||
|
{
|
||||||
|
instruction += agentService.RenderedInstruction(agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*var routing = _services.GetRequiredService<IRoutingService>();
|
||||||
|
var router = routing.Router;
|
||||||
|
|
||||||
|
var render = _services.GetRequiredService<ITemplateRender>();
|
||||||
|
var template = router.Templates.FirstOrDefault(x => x.Name == "response_with_function").Content;
|
||||||
|
|
||||||
|
var response_with_function = render.Render(template, new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "functions", agent.Functions }
|
||||||
|
});
|
||||||
|
|
||||||
|
prompt += "\r\n\r\n" + response_with_function;*/
|
||||||
|
|
||||||
|
var messages = new List<Message>();
|
||||||
|
foreach (var conv in conversations)
|
||||||
|
{
|
||||||
|
if (conv.Role == AgentRole.User)
|
||||||
|
{
|
||||||
|
messages.Add(new Message(RoleType.User, conv.Content));
|
||||||
|
}
|
||||||
|
else if (conv.Role == AgentRole.Assistant)
|
||||||
|
{
|
||||||
|
messages.Add(new Message(RoleType.Assistant, conv.Content));
|
||||||
|
}
|
||||||
|
else if (conv.Role == AgentRole.Function)
|
||||||
|
{
|
||||||
|
messages.Add(new Message
|
||||||
|
{
|
||||||
|
Role = RoleType.Assistant,
|
||||||
|
Content = new List<ContentBase>
|
||||||
|
{
|
||||||
|
new ToolUseContent()
|
||||||
|
{
|
||||||
|
Id = conv.ToolCallId,
|
||||||
|
Name = conv.FunctionName,
|
||||||
|
Input = JsonNode.Parse(conv.FunctionArgs ?? "{}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
messages.Add(new Message()
|
||||||
|
{
|
||||||
|
Role = RoleType.User,
|
||||||
|
Content = new List<ContentBase>
|
||||||
|
{
|
||||||
|
new ToolResultContent()
|
||||||
|
{
|
||||||
|
ToolUseId = conv.ToolCallId,
|
||||||
|
Content = conv.Content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = new MessageParameters()
|
||||||
|
{
|
||||||
|
Messages = messages,
|
||||||
|
MaxTokens = 256,
|
||||||
|
Model = AnthropicModels.Claude3Haiku,
|
||||||
|
Stream = false,
|
||||||
|
Temperature = 0m,
|
||||||
|
SystemMessage = instruction,
|
||||||
|
Tools = new List<Function>() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonSerializationOptions = new()
|
||||||
|
{
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
Converters = { new JsonStringEnumConverter() },
|
||||||
|
ReferenceHandler = ReferenceHandler.IgnoreCycles,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var fn in agent.Functions)
|
||||||
|
{
|
||||||
|
/*var inputschema = new InputSchema()
|
||||||
|
{
|
||||||
|
Type = fn.Parameters.Type,
|
||||||
|
Properties = new Dictionary<string, Property>()
|
||||||
|
{
|
||||||
|
{ "location", new Property() { Type = "string", Description = "The location of the weather" } },
|
||||||
|
{
|
||||||
|
"tempType", new Property()
|
||||||
|
{
|
||||||
|
Type = "string", Enum = Enum.GetNames(typeof(TempType)),
|
||||||
|
Description = "The unit of temperature, celsius or fahrenheit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Required = fn.Parameters.Required
|
||||||
|
};*/
|
||||||
|
|
||||||
|
string jsonString = JsonSerializer.Serialize(fn.Parameters, jsonSerializationOptions);
|
||||||
|
parameters.Tools.Add(new Function(fn.Name, fn.Description,
|
||||||
|
JsonNode.Parse(jsonString)));
|
||||||
|
}
|
||||||
|
|
||||||
|
var prompt = GetPrompt(parameters);
|
||||||
|
|
||||||
|
return (prompt, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetPrompt(MessageParameters parameters)
|
||||||
|
{
|
||||||
|
var prompt = $"{parameters.SystemMessage}\r\n";
|
||||||
|
prompt += "\r\n[CONVERSATION]";
|
||||||
|
|
||||||
|
var verbose = string.Join("\r\n", parameters.Messages
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
var role = x.Role.ToString().ToLower();
|
||||||
|
|
||||||
|
if (x.Role == RoleType.User)
|
||||||
|
{
|
||||||
|
var content = string.Join("\r\n", x.Content.Select(c =>
|
||||||
|
{
|
||||||
|
if (c is TextContent text)
|
||||||
|
return text.Text;
|
||||||
|
else if (c is ToolResultContent tool)
|
||||||
|
return $"{tool.Content}";
|
||||||
|
else
|
||||||
|
return string.Empty;
|
||||||
|
}));
|
||||||
|
return $"{role}: {content}";
|
||||||
|
}
|
||||||
|
else if (x.Role == RoleType.Assistant)
|
||||||
|
{
|
||||||
|
var content = string.Join("\r\n", x.Content.Select(c =>
|
||||||
|
{
|
||||||
|
if (c is TextContent text)
|
||||||
|
return text.Text;
|
||||||
|
else if (c is ToolUseContent tool)
|
||||||
|
return $"Call function {tool.Name}({JsonSerializer.Serialize(tool.Input)})";
|
||||||
|
else
|
||||||
|
return string.Empty;
|
||||||
|
}));
|
||||||
|
return $"{role}: {content}";
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}));
|
||||||
|
|
||||||
|
prompt += $"\r\n{verbose}\r\n";
|
||||||
|
|
||||||
|
if (parameters.Tools != null && parameters.Tools.Count > 0)
|
||||||
|
{
|
||||||
|
var functions = string.Join("\r\n", parameters.Tools.Select(x =>
|
||||||
|
{
|
||||||
|
return $"\r\n{x.Name}: {x.Description}\r\n{JsonSerializer.Serialize(x.Parameters)}";
|
||||||
|
}));
|
||||||
|
prompt += $"\r\n[FUNCTIONS]\r\n{functions}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return prompt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetModelName(string model)
|
||||||
|
{
|
||||||
|
_model = model;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace BotSharp.Plugin.AnthropicAI.Settings;
|
||||||
|
|
||||||
|
public class AnthropicSettings
|
||||||
|
{
|
||||||
|
public ClaudeSetting Claude { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
namespace BotSharp.Plugin.AnthropicAI.Settings;
|
||||||
|
|
||||||
|
public class ClaudeSetting
|
||||||
|
{
|
||||||
|
}
|
||||||
16
src/Plugins/BotSharp.Plugin.AnthropicAI/Using.cs
Normal file
16
src/Plugins/BotSharp.Plugin.AnthropicAI/Using.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
global using Anthropic.SDK;
|
||||||
|
global using Anthropic.SDK.Constants;
|
||||||
|
global using Anthropic.SDK.Messaging;
|
||||||
|
global using BotSharp.Abstraction.Agents;
|
||||||
|
global using BotSharp.Abstraction.Agents.Enums;
|
||||||
|
global using BotSharp.Abstraction.Agents.Models;
|
||||||
|
global using BotSharp.Abstraction.Conversations.Models;
|
||||||
|
global using BotSharp.Abstraction.Functions.Models;
|
||||||
|
global using BotSharp.Abstraction.Loggers;
|
||||||
|
global using BotSharp.Abstraction.MLTasks;
|
||||||
|
global using BotSharp.Abstraction.Routing;
|
||||||
|
global using BotSharp.Abstraction.Templating;
|
||||||
|
global using BotSharp.Plugin.AnthropicAI.Settings;
|
||||||
|
global using Microsoft.Extensions.DependencyInjection;
|
||||||
|
global using Microsoft.Extensions.Logging;
|
||||||
|
global using BotSharp.Abstraction.Utilities;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.15" />
|
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.16" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,7 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
var choice = response.Value.Choices[0];
|
var choice = response.Value.Choices[0];
|
||||||
var message = choice.Message;
|
var message = choice.Message;
|
||||||
|
|
||||||
var responseMessage = new RoleDialogModel(AgentRole.Assistant, message.Content)
|
RoleDialogModel responseMessage;
|
||||||
{
|
|
||||||
CurrentAgentId = agent.Id,
|
|
||||||
MessageId = conversations.Last().MessageId
|
|
||||||
};
|
|
||||||
|
|
||||||
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
|
if (choice.FinishReason == CompletionsFinishReason.FunctionCall)
|
||||||
{
|
{
|
||||||
|
|
@ -74,6 +70,33 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
responseMessage.FunctionName = responseMessage.FunctionName.Split('.').Last();
|
responseMessage.FunctionName = responseMessage.FunctionName.Split('.').Last();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (choice.FinishReason == CompletionsFinishReason.ToolCalls)
|
||||||
|
{
|
||||||
|
// Add the assistant message with tool calls to the conversation history
|
||||||
|
// ChatRequestAssistantMessage toolCallHistoryMessage = new(message);
|
||||||
|
// chatCompletionsOptions.Messages.Add(toolCallHistoryMessage);
|
||||||
|
|
||||||
|
// Add a new tool message for each tool call that is resolved
|
||||||
|
var toolCall = message.ToolCalls.First() as ChatCompletionsFunctionToolCall;
|
||||||
|
// var toolCallResponseMessage = GetToolCallResponseMessage(toolCall);
|
||||||
|
// Now make a new request with all the messages thus far, including the original
|
||||||
|
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Function, message.Content)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId,
|
||||||
|
FunctionName = toolCall.Name,
|
||||||
|
FunctionArgs = toolCall.Arguments
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
responseMessage = new RoleDialogModel(AgentRole.Assistant, message.Content)
|
||||||
|
{
|
||||||
|
CurrentAgentId = agent.Id,
|
||||||
|
MessageId = conversations.Last().MessageId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// After chat completion hook
|
// After chat completion hook
|
||||||
foreach(var hook in contentHooks)
|
foreach(var hook in contentHooks)
|
||||||
|
|
@ -222,7 +245,17 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
if (agentService.RenderFunction(agent, function))
|
if (agentService.RenderFunction(agent, function))
|
||||||
{
|
{
|
||||||
var property = agentService.RenderFunctionProperty(agent, function);
|
var property = agentService.RenderFunctionProperty(agent, function);
|
||||||
chatCompletionsOptions.Functions.Add(new FunctionDefinition
|
|
||||||
|
// legacy function call
|
||||||
|
/*chatCompletionsOptions.Functions.Add(new FunctionDefinition
|
||||||
|
{
|
||||||
|
Name = function.Name,
|
||||||
|
Description = function.Description,
|
||||||
|
Parameters = BinaryData.FromObjectAsJson(property)
|
||||||
|
});*/
|
||||||
|
|
||||||
|
// new chat tool
|
||||||
|
chatCompletionsOptions.Tools.Add(new ChatCompletionsFunctionToolDefinition
|
||||||
{
|
{
|
||||||
Name = function.Name,
|
Name = function.Name,
|
||||||
Description = function.Description,
|
Description = function.Description,
|
||||||
|
|
@ -241,6 +274,7 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
});
|
});
|
||||||
|
|
||||||
chatCompletionsOptions.Messages.Add(new ChatRequestFunctionMessage(message.FunctionName, message.Content));
|
chatCompletionsOptions.Messages.Add(new ChatRequestFunctionMessage(message.FunctionName, message.Content));
|
||||||
|
// chatCompletionsOptions.Messages.Add(new ChatRequestToolMessage(message.Content, message.ToolCallId));
|
||||||
}
|
}
|
||||||
else if (message.Role == ChatRole.User)
|
else if (message.Role == ChatRole.User)
|
||||||
{
|
{
|
||||||
|
|
@ -346,4 +380,15 @@ public class ChatCompletionProvider : IChatCompletion
|
||||||
{
|
{
|
||||||
_model = model;
|
_model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatRequestToolMessage GetToolCallResponseMessage(ChatCompletionsToolCall toolCall)
|
||||||
|
{
|
||||||
|
var functionToolCall = toolCall as ChatCompletionsFunctionToolCall;
|
||||||
|
// Validate and process the JSON arguments for the function call
|
||||||
|
string unvalidatedArguments = functionToolCall.Arguments;
|
||||||
|
var functionResultData = (object)null; // GetYourFunctionResultData(unvalidatedArguments);
|
||||||
|
// Here, replacing with an example as if returned from "GetYourFunctionResultData"
|
||||||
|
functionResultData = "31 celsius";
|
||||||
|
return new ChatRequestToolMessage(functionResultData.ToString(), toolCall.Id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue