mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-11 18:53:48 +00:00
Fixed OpenAI requests always offering OpenAI's own web search (#1041)
This commit is contained in:
1 parent
9215011b08
commit
ca6ad6b1f0
8 files changed
+9
-69
No files matched your search
@@ -87,18 +87,6 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
var toolRegistry = Program.SERVICE_PROVIDER.GetService<ToolRegistry>();
|
||||
var providerConfidence = this.Provider.GetConfidence(settingsManager).Level;
|
||||
|
||||
//
|
||||
// The provider-native web search is held to the same confidence the local web search tool
|
||||
// asks for: to the user it is the same act, whoever performs the search.
|
||||
//
|
||||
var minimumWebSearchConfidence = toolRegistry?.GetMinimumProviderConfidence(ToolSelectionRules.WEB_SEARCH_TOOL_ID) ?? ConfidenceLevel.NONE;
|
||||
var isWebSearchAllowed = toolRegistry?.IsToolActive(ToolSelectionRules.WEB_SEARCH_TOOL_ID) is true &&
|
||||
ToolSelectionRules.IsProviderConfidenceAllowed(providerConfidence, minimumWebSearchConfidence);
|
||||
IList<object> providerTools = modelProfile.Has(Capability.WEB_SEARCH) && isWebSearchAllowed
|
||||
? [ ProviderTools.WEB_SEARCH ]
|
||||
: [];
|
||||
|
||||
|
||||
// Parse the API parameters:
|
||||
var additionalApiParameters = this.ParseAdditionalApiParameters("input", "store", "tools");
|
||||
|
||||
@@ -220,7 +208,6 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
chatModel,
|
||||
baseInput,
|
||||
additionalApiParameters,
|
||||
providerTools,
|
||||
runnableTools,
|
||||
(requestDto, requestToken) => this.StreamResponsesRequest(requestDto, requestedSecret, requestToken));
|
||||
|
||||
@@ -243,9 +230,6 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (runnableTools.Count > 0)
|
||||
providerTools = [];
|
||||
|
||||
//
|
||||
// Create the request: either for the Responses API or the Chat Completion API
|
||||
//
|
||||
@@ -277,10 +261,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
|
||||
// We do not want to store any data on OpenAI's servers:
|
||||
Store = false,
|
||||
|
||||
// Tools we want to use:
|
||||
Tools = providerTools,
|
||||
|
||||
|
||||
// Additional API parameters:
|
||||
AdditionalApiParameters = additionalApiParameters
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace AIStudio.Provider.OpenAI;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a tool executed on the provider side.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Right now, only our OpenAI provider is using tools. Thus, this class is located in the
|
||||
/// OpenAI namespace. In the future, when other providers also support tools, this class can
|
||||
/// be moved into the provider namespace.
|
||||
/// </remarks>
|
||||
/// <param name="Type">The type of the tool.</param>
|
||||
public record ProviderTool(string Type);
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace AIStudio.Provider.OpenAI;
|
||||
|
||||
/// <summary>
|
||||
/// Known provider-side tools for LLM providers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Right now, only our OpenAI provider is using tools. Thus, this class is located in the
|
||||
/// OpenAI namespace. In the future, when other providers also support tools, this class can
|
||||
/// be moved into the provider namespace.
|
||||
/// </remarks>
|
||||
public static class ProviderTools
|
||||
{
|
||||
public static readonly ProviderTool WEB_SEARCH = new("web_search");
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace AIStudio.Provider.OpenAI;
|
||||
/// <param name="Input">The chat messages and Responses API input items.</param>
|
||||
/// <param name="Stream">Whether to stream the response.</param>
|
||||
/// <param name="Store">Whether to store the response on the server (usually OpenAI's infrastructure).</param>
|
||||
/// <param name="Tools">The provider-side tools and local function tools to use for the request.</param>
|
||||
/// <param name="Tools">The local function tools to use for the request.</param>
|
||||
public record ResponsesAPIRequest(
|
||||
string Model,
|
||||
IList<object> Input,
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace AIStudio.Provider.OpenAI;
|
||||
/// correlated by call ID. Unlike Chat Completions, the whole output of a round has to be sent
|
||||
/// back for the next one, reasoning items included, or the API refuses to continue.
|
||||
/// </remarks>
|
||||
public sealed class ResponsesToolCallingAdapter(Model chatModel, IList<object> baseInput, IDictionary<string, object> apiParameters, IList<object> providerTools,
|
||||
public sealed class ResponsesToolCallingAdapter(Model chatModel, IList<object> baseInput, IDictionary<string, object> apiParameters,
|
||||
IReadOnlyList<(ToolDefinition Definition, IToolImplementation Implementation)> runnableTools,
|
||||
Func<ResponsesAPIRequest, CancellationToken, IAsyncEnumerable<ServerSentEvent>> streamRequestAsync) : IToolCallingProviderAdapter
|
||||
{
|
||||
@@ -25,13 +25,9 @@ public sealed class ResponsesToolCallingAdapter(Model chatModel, IList<object> b
|
||||
public IReadOnlyList<string> RecordedRequestTexts => this.recordedRequestTexts;
|
||||
|
||||
/// <summary>
|
||||
/// The tools offered to the model: the provider-native ones plus our local functions.
|
||||
/// The tools offered to the model: our local functions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A provider-native tool whose type collides with one of our function names is dropped
|
||||
/// because the model could not tell the two apart.
|
||||
/// </remarks>
|
||||
private readonly IList<object> effectiveProviderTools = BuildEffectiveProviderTools(providerTools, runnableTools);
|
||||
private readonly IList<object> offeredTools = runnableTools.Select(x => (object)ProviderToolAdapters.ToResponsesTool(x.Definition)).ToList();
|
||||
|
||||
/// <inheritdoc />
|
||||
public async IAsyncEnumerable<ToolCallingStreamEvent> ExecuteRoundAsync(string? finalResponseInstruction, bool includeTools, [EnumeratorCancellation] CancellationToken token = default)
|
||||
@@ -53,7 +49,7 @@ public sealed class ResponsesToolCallingAdapter(Model chatModel, IList<object> b
|
||||
Input = requestInput,
|
||||
Stream = true,
|
||||
Store = false,
|
||||
Tools = includeTools ? this.effectiveProviderTools : [],
|
||||
Tools = includeTools ? this.offeredTools : [],
|
||||
AdditionalApiParameters = apiParameters,
|
||||
};
|
||||
|
||||
@@ -127,16 +123,4 @@ public sealed class ResponsesToolCallingAdapter(Model chatModel, IList<object> b
|
||||
if (!string.IsNullOrWhiteSpace(content))
|
||||
this.recordedRequestTexts.Add(content);
|
||||
}
|
||||
|
||||
private static IList<object> BuildEffectiveProviderTools(IList<object> providerTools, IReadOnlyList<(ToolDefinition Definition, IToolImplementation Implementation)> runnableTools)
|
||||
{
|
||||
var localFunctionNames = runnableTools
|
||||
.Select(x => x.Definition.Function.Name)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
return providerTools
|
||||
.Where(x => x is not ProviderTool providerTool || !localFunctionNames.Contains(providerTool.Type))
|
||||
.Concat(runnableTools.Select(x => (object)ProviderToolAdapters.ToResponsesTool(x.Definition)))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
- Fixed saving the settings taking about 20 seconds each time when a chat template had an attachment on a network drive that was out of reach. Since AI Studio saves its settings while starting, this also slowed down every start.
|
||||
- Fixed local data sources taking up more and more space on your disk with every change to your documents. AI Studio now removes what the vector database no longer needs.
|
||||
- Fixed answers breaking off with an error message from self-hosted AI servers such as vLLM when the AI made up the name of a tool or sent broken details for one. AI Studio now tells the AI that its tool call was invalid, and the AI can finish its answer.
|
||||
- Fixed OpenAI models using about 4,300 more tokens than necessary with every request. AI Studio offered them OpenAI's own web search in the background, even when you had not selected a web search. To let a model search the web, select the Web Search tool below the message field.
|
||||
- Fixed AI Studio sometimes rebuilding the index of a data source from scratch when the configuration of your organization was applied while the data source was being updated.
|
||||
- Fixed justified texts being hyphenated by the rules of English even when AI Studio shows another language, such as German. Screen readers now also know which language AI Studio uses.
|
||||
- Updated the code contributions on the supporters page, which now thank everyone who has contributed code to AI Studio so far.
|
||||
|
||||
@@ -96,7 +96,7 @@ public sealed class ResponsesToolCallingAdapterTests
|
||||
private static ResponsesToolCallingAdapter Adapter(params string[][] rounds)
|
||||
{
|
||||
var nextRound = 0;
|
||||
return new(new Model("gpt-5", null), [], new Dictionary<string, object>(), [], [], (_, token) => Lines(rounds[nextRound++], token));
|
||||
return new(new Model("gpt-5", null), [], new Dictionary<string, object>(), [], (_, token) => Lines(rounds[nextRound++], token));
|
||||
}
|
||||
|
||||
private static async IAsyncEnumerable<ServerSentEvent> Lines(string[] data, [EnumeratorCancellation] CancellationToken token = default)
|
||||
|
||||
@@ -45,7 +45,7 @@ The exception is a provider which rejects the parameter. Hugging Face answers it
|
||||
|
||||
The OpenAI Responses API may continue to return multiple function calls in one response. AI Studio processes those calls sequentially as well; concurrent execution of separate local tool calls is not currently implemented. This does not restrict concurrency used internally by an individual tool.
|
||||
|
||||
Provider-native tools are separate from local function tools and do not have a `ToolDefinition` or an `IToolImplementation`. The local tool calling implementation does not influence the provider-native tool selection at all.
|
||||
AI Studio offers no provider-native tools, i.e., tools which the provider runs on its own servers, such as OpenAI's hosted web search. That search used to go along with every Responses API request, whatever the user had selected. Merely offering it cost about 4,300 input tokens per request — in a tool calling loop, per round — and it bypassed the rules our own tools follow: the selection below the message field, and the outbound data restriction of a chat which read a mailbox, see `ToolOutboundData`. Nor did it show up in the tool trace. A provider-native tool belongs into the tool selection instead, as a choice the user makes, so that the selection, the minimum provider confidence, and the outbound data restriction apply to it. Its results never reach AI Studio, though, so the prompt injection filter cannot check them; whoever adds such a tool has to decide how to deal with that.
|
||||
|
||||
If a tool throws `ToolExecutionBlockedException`, `ToolExecutor` returns the exception message as plain text to the model and records the trace as `BLOCKED`. Other exceptions are logged with details and returned to the model as plain text in the form `Tool execution failed: ...`, with the trace recorded as `ERROR`.
|
||||
|
||||
|
||||
Reference in new issue
Block a user