Skip to content

feat(chat): support web_search_options parameter for search #438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,29 @@ class TestChatCompletions : TestOpenAI() {
assertNotNull(results.last().usage?.completionTokens)
assertNotNull(results.last().usage?.totalTokens)
}

@Test
fun webSearchOptions() = test {
val request = chatCompletionRequest {
model = ModelId("gpt-4o-search-preview")
messages {
message {
role = ChatRole.System
content = "You are a helpful assistant.!"
}
message {
role = ChatRole.User
content = "Who won the world series last year?"
}
}
webSearchOptions = webSearchOptions {
searchContextSize = SearchContextSize("low")
}
}

val result = openAI.chatCompletion(request)

val resultChoices = result.choices
assertTrue(resultChoices.isNotEmpty())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,18 @@ public data class ChatCompletionRequest(
/**
* Options for streaming response. Only used when in streaming mode.
*/
@SerialName("stream_options") public val streamOptions: StreamOptions? = null
@SerialName("stream_options") public val streamOptions: StreamOptions? = null,

/**
* Using the Chat Completions API, you can directly access the fine-tuned models and tool used by Search in ChatGPT.
*
* When using Chat Completions, the model always retrieves information from the web before responding to your query.
* To use web_search_preview as a tool that models like gpt-4o and gpt-4o-mini invoke only when necessary,
* switch to using the Responses API.
*
* [Read more](https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat)
*/
@SerialName("web_search_options") public val webSearchOptions: WebSearchOptions? = null
)

/**
Expand Down Expand Up @@ -384,6 +395,12 @@ public class ChatCompletionRequestBuilder {
*/
public var streamOptions: StreamOptions? = null

/**
* Options for web search.
* Only used when the gpt model supported web search in chat completion (gpt-4o-search-preview for example)
*/
public var webSearchOptions: WebSearchOptions? = null

/**
* Builder of [ChatCompletionRequest] instances.
*/
Expand Down Expand Up @@ -411,6 +428,7 @@ public class ChatCompletionRequestBuilder {
topLogprobs = topLogprobs,
instanceId = instanceId,
streamOptions = streamOptions,
webSearchOptions = webSearchOptions,
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.aallam.openai.api.chat

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline

@Serializable
public data class WebSearchOptions(
@SerialName("search_context_size")
val searchContextSize: SearchContextSize? = null,
@SerialName("user_location")
val userLocation: UserLocation? = null
)

/**
* High-level guidance for the amount of context window space to use for the search.
* One of low, medium, or high. `medium` is the default.
*/
@Serializable
@JvmInline
public value class SearchContextSize(public val id: String)

@Serializable
public data class UserLocation(
val approximate: UserLocationApproximate? = null,
val type: String = "approximate" // The type of location approximation. Always approximate.
)

@Serializable
public data class UserLocationApproximate(
val city: String? = null,
val country: String? = null,
val region: String? = null,
val timezone: String? = null
)

/**
* Create a new [WebSearchOptions] instance.
*/
public fun webSearchOptions(block: WebSearchOptionsBuilder.() -> Unit): WebSearchOptions {
return WebSearchOptionsBuilder().apply(block).build()
}

/**
* Builder for [WebSearchOptions].
*/
public class WebSearchOptionsBuilder {
/**
* Possible values: low, medium, high. `medium` is the default
*/
public var searchContextSize: SearchContextSize? = null

public var userLocation: UserLocation? = null

/**
* Build the [WebSearchOptions] instance.
*/
public fun build(): WebSearchOptions = WebSearchOptions(
searchContextSize = searchContextSize,
userLocation = userLocation
)
}