mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-18 05:58:00 +00:00
Added tool calling support (#731)
Co-authored-by: krut_ni <nils.kruthoff@dlr.de> Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
266 files changed
+11186
-740
No files matched your search
@@ -34,6 +34,18 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
public string SystemPrompt { get; private set; } = string.Empty;
|
||||
public string SubmitText { get; private set; } = string.Empty;
|
||||
public bool AllowProfiles { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// The tools this assistant runs with, when its plugin names any.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null means the plugin says nothing about tools, and the user picks them as in any other
|
||||
/// assistant. A list takes that choice away: the assistant then runs with exactly these tools,
|
||||
/// which is what an author who tested their assistant with them wants. It is a wish, not a
|
||||
/// permission — a tool switched off in the settings, or one the selected provider is not
|
||||
/// trusted enough to receive, stays out of reach either way.
|
||||
/// </remarks>
|
||||
public IReadOnlyList<string>? AssistantToolIds { get; private set; }
|
||||
public bool HasEmbeddedProfileSelection { get; private set; }
|
||||
public bool HasCustomPromptBuilder => this.buildPromptFunction is not null;
|
||||
public bool IsAssistantBuilderGenerated { get; private set; }
|
||||
@@ -72,6 +84,7 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
this.SystemPrompt = string.Empty;
|
||||
this.SubmitText = string.Empty;
|
||||
this.AllowProfiles = true;
|
||||
this.AssistantToolIds = null;
|
||||
this.HasEmbeddedProfileSelection = false;
|
||||
this.IsAssistantBuilderGenerated = false;
|
||||
this.HasDeploymentManagementMetadata = false;
|
||||
@@ -138,6 +151,9 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryReadOptionalToolIds(assistantTable, out var assistantToolIds, out message))
|
||||
return false;
|
||||
|
||||
if (assistantTable.TryGetValue("BuildPrompt", out var buildPromptValue))
|
||||
{
|
||||
if (buildPromptValue.TryRead<LuaFunction>(out var buildPrompt))
|
||||
@@ -152,6 +168,7 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
this.SystemPrompt = BuildSecureSystemPrompt(rawSystemPrompt);
|
||||
this.SubmitText = assistantSubmitText;
|
||||
this.AllowProfiles = assistantAllowProfiles;
|
||||
this.AssistantToolIds = assistantToolIds;
|
||||
|
||||
// Ensure that the UI table exists nested in the ASSISTANT table and is a valid Lua table:
|
||||
if (!assistantTable.TryGetValue("UI", out var uiVal) || !uiVal.TryRead<LuaTable>(out var uiTable))
|
||||
@@ -226,10 +243,11 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
if (!TryReadOptionalGuid(assistantTable, "ProviderId", false, out var providerId, out message) ||
|
||||
!TryReadOptionalGuid(assistantTable, "ProfileId", true, out var profileId, out message) ||
|
||||
!TryReadOptionalGuid(assistantTable, "ChatTemplateId", true, out var chatTemplateId, out message) ||
|
||||
!TryReadOptionalDataSourceIds(assistantTable, out var dataSourceIds, out message))
|
||||
!TryReadOptionalDataSourceIds(assistantTable, out var dataSourceIds, out message) ||
|
||||
!TryReadOptionalToolIds(assistantTable, out var toolIds, out message))
|
||||
return false;
|
||||
|
||||
this.ChatLaunchConfiguration = new(workspaceName, providerId, profileId, chatTemplateId, dataSourceIds);
|
||||
this.ChatLaunchConfiguration = new(workspaceName, providerId, profileId, chatTemplateId, dataSourceIds, toolIds);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -291,6 +309,48 @@ public sealed class PluginAssistants(bool isInternal, LuaState state, PluginType
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the tools an assistant names: the ones a launcher preselects for its chat, or the ones
|
||||
/// the assistant itself runs with.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Unlike the data sources, these are plain tool IDs rather than GUIDs, and an ID unknown to
|
||||
/// this installation is not an error: a plugin may name a tool that arrives with another plugin
|
||||
/// which is not installed yet. Whoever runs the tools drops what they cannot offer.
|
||||
/// </remarks>
|
||||
private static bool TryReadOptionalToolIds(LuaTable assistantTable, out IReadOnlyList<string>? toolIds, out string message)
|
||||
{
|
||||
toolIds = null;
|
||||
message = string.Empty;
|
||||
|
||||
if (!assistantTable.TryGetValue("ToolIds", out var toolIdsValue))
|
||||
return true;
|
||||
|
||||
if (!toolIdsValue.TryRead<LuaTable>(out var toolIdsTable) || toolIdsTable.ArrayLength == 0)
|
||||
{
|
||||
message = TB("The ASSISTANT table contains invalid ToolIds. Expected a non-empty list of unique, non-empty tool IDs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var parsedIds = new List<string>(toolIdsTable.ArrayLength);
|
||||
var uniqueIds = new HashSet<string>(StringComparer.Ordinal);
|
||||
for (var index = 1; index <= toolIdsTable.ArrayLength; index++)
|
||||
{
|
||||
if (!toolIdsTable[index].TryRead<string>(out var toolId) ||
|
||||
string.IsNullOrWhiteSpace(toolId) ||
|
||||
!uniqueIds.Add(toolId.Trim()))
|
||||
{
|
||||
message = TB("The ASSISTANT table contains invalid ToolIds. Expected a non-empty list of unique, non-empty tool IDs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
parsedIds.Add(toolId.Trim());
|
||||
}
|
||||
|
||||
toolIds = parsedIds.ToImmutableArray();
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<string?> TryBuildPromptAsync(LuaTable input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.buildPromptFunction is null)
|
||||
|
||||
Reference in new issue
Block a user