Skip to content

Commit 637e9d4

Browse files
committed
refactor(openai): inline chat tool choice validation
1 parent febaf8e commit 637e9d4

2 files changed

Lines changed: 59 additions & 73 deletions

File tree

Sources/AgentRunKit/LLM/Providers/OpenAIChat/OpenAIChatToolChoiceValidation.swift

Lines changed: 0 additions & 71 deletions
This file was deleted.

Sources/AgentRunKit/LLM/Providers/OpenAIChat/OpenAIClient.swift

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,15 @@ extension OpenAIClient {
200200

201201
switch toolChoice {
202202
case .required:
203-
try validateRequiredToolChoice(requestTools)
203+
guard !requestTools.isEmpty else {
204+
throw AgentError.llmError(.other("OpenAI Chat toolChoice.required requires at least one tool"))
205+
}
204206
case let .function(name):
205-
try validateRequestedFunctionChoice(name, functions: functions)
207+
guard functions.contains(name) else {
208+
throw AgentError.llmError(.other(
209+
"OpenAI Chat toolChoice.function requires tool '\(name)' in the request"
210+
))
211+
}
206212
case let .custom(name):
207213
try validateRequestedCustomChoice(name, customs: customs, capabilities: capabilities)
208214
case let .allowedTools(_, tools):
@@ -214,6 +220,57 @@ extension OpenAIClient {
214220
return toolChoice
215221
}
216222

223+
private func validateRequestedCustomChoice(
224+
_ name: String,
225+
customs: Set<String>,
226+
capabilities: OpenAIChatCapabilities
227+
) throws {
228+
guard capabilities.supportsCustomTools else {
229+
throw AgentError.llmError(.featureUnsupported(
230+
provider: "openai-chat-\(capabilities.profile)",
231+
feature: "custom tool choice"
232+
))
233+
}
234+
guard customs.contains(name) else {
235+
throw AgentError.llmError(.other(
236+
"OpenAI Chat toolChoice.custom requires custom tool '\(name)' in the request"
237+
))
238+
}
239+
}
240+
241+
private func validateAllowedTools(
242+
_ tools: [OpenAIChatAllowedTool],
243+
functions: Set<String>,
244+
customs: Set<String>,
245+
capabilities: OpenAIChatCapabilities
246+
) throws {
247+
guard capabilities.profile == .firstParty else {
248+
throw AgentError.llmError(.featureUnsupported(
249+
provider: "openai-chat-\(capabilities.profile)",
250+
feature: "allowed tools"
251+
))
252+
}
253+
guard !tools.isEmpty else {
254+
throw AgentError.llmError(.other("OpenAI Chat allowed tools must not be empty"))
255+
}
256+
for tool in tools {
257+
switch tool {
258+
case let .function(name):
259+
guard functions.contains(name) else {
260+
throw AgentError.llmError(.other(
261+
"OpenAI Chat allowed function tool '\(name)' is missing from the request"
262+
))
263+
}
264+
case let .custom(name):
265+
guard customs.contains(name) else {
266+
throw AgentError.llmError(.other(
267+
"OpenAI Chat allowed custom tool '\(name)' is missing from the request"
268+
))
269+
}
270+
}
271+
}
272+
}
273+
217274
func buildURLRequest(_ request: ChatCompletionRequest) throws -> URLRequest {
218275
let url = baseURL.appendingPathComponent(chatCompletionPath)
219276
var headers: [(String, String)] = []

0 commit comments

Comments
 (0)