Skip to content

Commit

Permalink
Support optional 'strict' parameter in function definition
Browse files Browse the repository at this point in the history
  • Loading branch information
neelvirdy committed Aug 30, 2024
1 parent 843e087 commit 3c970ea
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
7 changes: 6 additions & 1 deletion Sources/OpenAI/Public/Models/ChatQuery.swift
Original file line number Diff line number Diff line change
Expand Up @@ -676,14 +676,19 @@ public struct ChatQuery: Equatable, Codable, Streamable {
/// **Python library defines only [String: Object] dictionary.
public let parameters: Self.FunctionParameters?

/// Whether to enable strict schema adherence when generating the function call. If set to true, the model will follow the exact schema defined in the parameters field. Only a subset of JSON Schema is supported when strict is true.
public let strict: Bool?

public init(
name: String,
description: String? = nil,
parameters: Self.FunctionParameters? = nil
parameters: Self.FunctionParameters? = nil,
strict: Bool? = nil
) {
self.name = name
self.description = description
self.parameters = parameters
self.strict = strict
}

/// See the [guide](/docs/guides/gpt/function-calling) for examples, and the [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for documentation about the format.
Expand Down
64 changes: 64 additions & 0 deletions Tests/OpenAITests/OpenAITestsDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,70 @@ class OpenAITestsDecoder: XCTestCase {
XCTAssertEqual(chatQueryAsDict, expectedValueAsDict)
}

func testChatQueryWithFunctionCallStrict() async throws {
let chatQuery = ChatQuery(
messages: [
.user(.init(content: .string("What's the weather like in Boston?")))
],
model: .gpt3_5Turbo,
responseFormat: ChatQuery.ResponseFormat.jsonObject,
tools: [
.init(function: .init(
name: "get_current_weather",
description: "Get the current weather in a given location",
parameters: .init(
type: .object,
properties: [
"location": .init(type: .string, description: "The city and state, e.g. San Francisco, CA"),
"unit": .init(type: .string, enum: ["celsius", "fahrenheit"])
],
required: ["location"]
),
strict: true
))
]
)
let expectedValue = """
{
"model": "gpt-3.5-turbo",
"messages": [
{ "role": "user", "content": "What's the weather like in Boston?" }
],
"response_format": {
"type": "json_object"
},
"tools": [
{
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": { "type": "string", "enum": ["celsius", "fahrenheit"] }
},
"required": ["location"]
},
"strict": true
},
"type": "function"
}
],
"stream": false
}
"""

// To compare serialized JSONs we first convert them both into NSDictionary which are comparable (unline native swift dictionaries)
let chatQueryAsDict = try jsonDataAsNSDictionary(JSONEncoder().encode(chatQuery))
let expectedValueAsDict = try jsonDataAsNSDictionary(expectedValue.data(using: .utf8)!)

XCTAssertEqual(chatQueryAsDict, expectedValueAsDict)
}

func testChatCompletionWithFunctionCall() async throws {
let data = """
{
Expand Down

0 comments on commit 3c970ea

Please sign in to comment.