mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 17:32:11 +00:00
The LLM answers now with a final message if the maximum of tool calls is reached.
This commit is contained in:
parent
43665b2caa
commit
c43820756e
@ -1044,7 +1044,17 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
var toolCallCount = 0;
|
||||
while (true)
|
||||
{
|
||||
ChatCompletionAPIRequest requestDtoBase = await requestFactory(systemPrompt, apiParameters, providerTools);
|
||||
var finalResponseRequired = toolCallCount >= ToolSelectionRules.MAX_TOOL_CALLS;
|
||||
var requestSystemPrompt = finalResponseRequired
|
||||
? systemPrompt with
|
||||
{
|
||||
Content = $"{systemPrompt.Content}{Environment.NewLine}{Environment.NewLine}{ToolSelectionRules.GetMaxToolCallsFinalResponseInstruction()}",
|
||||
}
|
||||
: systemPrompt;
|
||||
ChatCompletionAPIRequest requestDtoBase = await requestFactory(
|
||||
requestSystemPrompt,
|
||||
apiParameters,
|
||||
finalResponseRequired ? null : providerTools);
|
||||
var requestDto = requestDtoBase with
|
||||
{
|
||||
Messages = [..requestDtoBase.Messages, ..internalMessages],
|
||||
@ -1070,6 +1080,17 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (finalResponseRequired)
|
||||
{
|
||||
await ResetToolRuntimeStatusAsync();
|
||||
if (!string.IsNullOrWhiteSpace(responseMessage.Content))
|
||||
yield return new ContentStreamChunk(responseMessage.Content, []);
|
||||
else
|
||||
yield return new ContentStreamChunk("The model did not return a final answer after completing the available tool calls.", []);
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
await ShowToolRuntimeStatusAsync(toolCalls
|
||||
.Select(x => runnableTools.FirstOrDefault(tool => tool.Definition.Function.Name.Equals(x.Function.Name, StringComparison.Ordinal)).Implementation?.GetDisplayName() ?? x.Function.Name));
|
||||
|
||||
@ -1081,25 +1102,18 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
|
||||
foreach (var toolCall in toolCalls)
|
||||
{
|
||||
toolCallCount++;
|
||||
if (toolCallCount > ToolSelectionRules.MAX_TOOL_CALLS)
|
||||
if (toolCallCount >= ToolSelectionRules.MAX_TOOL_CALLS)
|
||||
{
|
||||
var limitMessage = ToolSelectionRules.GetMaxToolCallsLimitMessage();
|
||||
currentAssistantContent?.ToolInvocations.Add(new ToolInvocationTrace
|
||||
var finalResponseInstruction = ToolSelectionRules.GetMaxToolCallsFinalResponseInstruction();
|
||||
internalMessages.Add(new ToolResultMessage
|
||||
{
|
||||
Order = toolCallCount,
|
||||
ToolId = toolCall.Function.Name,
|
||||
ToolName = toolCall.Function.Name,
|
||||
Content = finalResponseInstruction,
|
||||
ToolCallId = toolCall.Id,
|
||||
Status = ToolInvocationTraceStatus.BLOCKED,
|
||||
StatusMessage = limitMessage,
|
||||
Result = limitMessage,
|
||||
});
|
||||
await ResetToolRuntimeStatusAsync();
|
||||
yield return new ContentStreamChunk(limitMessage, []);
|
||||
yield break;
|
||||
continue;
|
||||
}
|
||||
|
||||
toolCallCount++;
|
||||
var (toolContent, trace) = await toolExecutor.ExecuteAsync(
|
||||
toolCall.Id,
|
||||
toolCall.Function.Name,
|
||||
|
||||
@ -326,13 +326,24 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
|
||||
while (true)
|
||||
{
|
||||
var finalResponseRequired = toolCallCount >= ToolSelectionRules.MAX_TOOL_CALLS;
|
||||
var requestInput = new List<object>(baseInput);
|
||||
if (finalResponseRequired && requestInput.FirstOrDefault() is TextMessage systemPrompt)
|
||||
{
|
||||
requestInput[0] = systemPrompt with
|
||||
{
|
||||
Content = $"{systemPrompt.Content}{Environment.NewLine}{Environment.NewLine}{ToolSelectionRules.GetMaxToolCallsFinalResponseInstruction()}",
|
||||
};
|
||||
}
|
||||
requestInput.AddRange(internalItems);
|
||||
|
||||
var requestDto = new ResponsesAPIRequest
|
||||
{
|
||||
Model = chatModel.Id,
|
||||
Input = [..baseInput, ..internalItems],
|
||||
Input = requestInput,
|
||||
Stream = false,
|
||||
Store = false,
|
||||
Tools = providerTools,
|
||||
Tools = finalResponseRequired ? [] : providerTools,
|
||||
AdditionalApiParameters = apiParameters,
|
||||
};
|
||||
var response = await this.ExecuteResponsesRequest(requestDto, requestedSecret, token);
|
||||
@ -342,6 +353,19 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (finalResponseRequired)
|
||||
{
|
||||
await ResetToolRuntimeStatusAsync(currentAssistantContent);
|
||||
|
||||
var textOutput = response.GetTextOutput();
|
||||
if (!string.IsNullOrWhiteSpace(textOutput))
|
||||
yield return new ContentStreamChunk(textOutput, []);
|
||||
else
|
||||
yield return new ContentStreamChunk("The model did not return a final answer after completing the available tool calls.", []);
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
var functionCalls = response.GetFunctionCalls();
|
||||
if (functionCalls.Count == 0)
|
||||
{
|
||||
@ -364,26 +388,18 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
|
||||
foreach (var functionCall in functionCalls)
|
||||
{
|
||||
toolCallCount++;
|
||||
if (toolCallCount > ToolSelectionRules.MAX_TOOL_CALLS)
|
||||
if (toolCallCount >= ToolSelectionRules.MAX_TOOL_CALLS)
|
||||
{
|
||||
var limitMessage = ToolSelectionRules.GetMaxToolCallsLimitMessage();
|
||||
currentAssistantContent?.ToolInvocations.Add(new ToolInvocationTrace
|
||||
var finalResponseInstruction = ToolSelectionRules.GetMaxToolCallsFinalResponseInstruction();
|
||||
internalItems.Add(new ResponsesFunctionCallOutputItem
|
||||
{
|
||||
Order = toolCallCount,
|
||||
ToolId = functionCall.Name,
|
||||
ToolName = functionCall.Name,
|
||||
ToolCallId = functionCall.CallId,
|
||||
Status = ToolInvocationTraceStatus.BLOCKED,
|
||||
StatusMessage = limitMessage,
|
||||
Result = limitMessage,
|
||||
CallId = functionCall.CallId,
|
||||
Output = finalResponseInstruction,
|
||||
});
|
||||
|
||||
await ResetToolRuntimeStatusAsync(currentAssistantContent);
|
||||
yield return new ContentStreamChunk(limitMessage, []);
|
||||
yield break;
|
||||
continue;
|
||||
}
|
||||
|
||||
toolCallCount++;
|
||||
var (toolContent, trace) = await toolExecutor.ExecuteAsync(
|
||||
functionCall.CallId,
|
||||
functionCall.Name,
|
||||
|
||||
@ -43,9 +43,9 @@ public sealed class ReadWebPageTool(HTMLParser htmlParser, ILogger<ReadWebPageTo
|
||||
|
||||
public string GetSettingsFieldDescription(string fieldName, ToolSettingsFieldDefinition fieldDefinition) => fieldName switch
|
||||
{
|
||||
"timeoutSeconds" => TB("Optional HTTP timeout for loading a web page in seconds."),
|
||||
"maxContentCharacters" => TB("Optional global truncation limit for extracted characters returned to the model."),
|
||||
ALLOWED_PRIVATE_HOSTS_SETTING => TB("Optional host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a high-confidence provider. For allowed internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication."),
|
||||
"timeoutSeconds" => TB("(Optional) HTTP timeout for loading a web page in seconds."),
|
||||
"maxContentCharacters" => TB("(Optional) Global truncation limit for extracted characters returned to the model."),
|
||||
ALLOWED_PRIVATE_HOSTS_SETTING => TB("(Optional) Host allowlist for private or VPN web pages. For security reasons, private or VPN web pages aren't allowed to be read by default. Separate host patterns with commas, such as example.de, *.example.de. Allowed private hosts require a high-confidence provider. For allowed internal hosts, AI Studio also tries the operating system's default sign-in automatically when the server responds with integrated authentication."),
|
||||
_ => TB(fieldDefinition.Description),
|
||||
};
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ public static class ToolSelectionRules
|
||||
_ => ConfidenceLevel.NONE,
|
||||
};
|
||||
|
||||
public static string GetMaxToolCallsLimitMessage() => $"Tool calling stopped because the maximum of {MAX_TOOL_CALLS} tool calls was reached.";
|
||||
public static string GetMaxToolCallsFinalResponseInstruction() => $"The maximum of {MAX_TOOL_CALLS} tool calls has been reached. No more tools are available. Provide the best possible final answer to the user based on the tool results already available.";
|
||||
|
||||
public static string BuildToolPolicyPrompt(IEnumerable<ToolDefinition> definitions)
|
||||
{
|
||||
|
||||
Loading…
Reference in New Issue
Block a user