Skip to content

Commit 293cc0a

Browse files
feat: parses OpenAI Web Tool and GPT-5 responses (envoyproxy#1076)
**Description** This parses OpenAI Web Tool requests and obfuscation used in gpt-5. As a part of this, we re-record all the affected requests. **Related Issues/PRs (if applicable)** envoyproxy#1068 --------- Signed-off-by: Adrian Cole <[email protected]>
1 parent 5095140 commit 293cc0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2740
-1887
lines changed

internal/apischema/openai/openai.go

Lines changed: 108 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,18 @@ const (
3333

3434
// Model names for testing.
3535
const (
36-
// ModelGPT41Nano is the cheapest model usable with /chat/completions.
37-
ModelGPT41Nano = "gpt-4.1-nano"
36+
// ModelGPT5Nano is the cheapest model usable with /chat/completions.
37+
ModelGPT5Nano = "gpt-5-nano"
3838
// ModelO3Mini is the cheapest reasoning model usable with /chat/completions.
3939
ModelO3Mini = "o3-mini"
4040
// ModelGPT4oMiniAudioPreview is the cheapest audio synthesis model usable with /chat/completions.
4141
ModelGPT4oMiniAudioPreview = "gpt-4o-mini-audio-preview"
42-
// ModelGPT4oAudioPreview s the cheapest audio transcription model usable with /chat/completions.
42+
// ModelGPT4oAudioPreview is the cheapest audio transcription model usable with /chat/completions.
4343
// Note: gpt-4o-mini-transcribe is NOT a chat model, so cannot be used with /v1/chat/completions.
4444
ModelGPT4oAudioPreview = "gpt-4o-audio-preview"
45+
// ModelGPT4oMiniSearchPreview is the cheapest web search model usable with /chat/completions.
46+
// Note: gpt-5 series supports web search, but only in the /responses API.
47+
ModelGPT4oMiniSearchPreview = "gpt-4o-mini-search-preview"
4548
)
4649

4750
// ChatCompletionContentPartRefusalType The type of the content part.
@@ -567,6 +570,44 @@ type PredictionContent struct {
567570
Content StringOrArray `json:"content"`
568571
}
569572

573+
// WebSearchContextSize represents the context size for web search.
574+
type WebSearchContextSize string
575+
576+
const (
577+
// WebSearchContextSizeLow provides minimal context from search results.
578+
WebSearchContextSizeLow WebSearchContextSize = "low"
579+
// WebSearchContextSizeMedium provides moderate context from search results.
580+
WebSearchContextSizeMedium WebSearchContextSize = "medium"
581+
// WebSearchContextSizeHigh provides maximum context from search results.
582+
WebSearchContextSizeHigh WebSearchContextSize = "high"
583+
)
584+
585+
// WebSearchOptions configures the web search tool behavior.
586+
type WebSearchOptions struct {
587+
// UserLocation provides approximate location parameters for the search.
588+
UserLocation *WebSearchUserLocation `json:"user_location,omitempty"` //nolint:tagliatelle //follow openai api
589+
// SearchContextSize controls how much context to include from search results.
590+
SearchContextSize WebSearchContextSize `json:"search_context_size,omitempty"` //nolint:tagliatelle //follow openai api
591+
}
592+
593+
// WebSearchUserLocation represents approximate location for web search.
594+
type WebSearchUserLocation struct {
595+
// Type is the type of location approximation. Always "approximate".
596+
Type string `json:"type"`
597+
// Approximate contains the approximate location details.
598+
Approximate WebSearchLocation `json:"approximate"`
599+
}
600+
601+
// WebSearchLocation contains location details for web search.
602+
type WebSearchLocation struct {
603+
// City is the approximate city name.
604+
City string `json:"city,omitempty"`
605+
// Region is the approximate region or state.
606+
Region string `json:"region,omitempty"`
607+
// Country is the approximate country.
608+
Country string `json:"country,omitempty"`
609+
}
610+
570611
type ChatCompletionRequest struct {
571612
// Messages: A list of messages comprising the conversation so far.
572613
// Depending on the model you use, different message types (modalities) are supported,
@@ -702,6 +743,11 @@ type ChatCompletionRequest struct {
702743
// PredictionContent provides configuration for a Predicted Output, which can greatly improve response times when large parts of the model response are known ahead of time.
703744
PredictionContent *PredictionContent `json:"prediction,omitempty"`
704745

746+
// WebSearchOptions configures web search tool for models that support it.
747+
// This tool searches the web for relevant results to use in a response.
748+
// Docs: https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat
749+
WebSearchOptions *WebSearchOptions `json:"web_search_options,omitempty"` //nolint:tagliatelle //follow openai api
750+
705751
*GCPVertexAIVendorFields `json:",inline,omitempty"`
706752
*AnthropicVendorFields `json:",inline,omitempty"`
707753
}
@@ -837,6 +883,11 @@ type ChatCompletionResponse struct {
837883
// Usage is described in the OpenAI API documentation:
838884
// https://platform.openai.com/docs/api-reference/chat/object#chat/object-usage
839885
Usage ChatCompletionResponseUsage `json:"usage,omitzero"`
886+
887+
// Obfuscation are random characters that normalize payload sizes as a
888+
// mitigation to certain side-channel attacks.
889+
// https://platform.openai.com/docs/api-reference/responses/get#responses_get-include_obfuscation
890+
Obfuscation string `json:"obfuscation,omitempty"`
840891
}
841892

842893
// ChatCompletionChoicesFinishReason The reason the model stopped generating tokens. This will be `stop` if the model
@@ -924,6 +975,43 @@ type ChatCompletionResponseChoiceMessage struct {
924975

925976
// The tool calls generated by the model, such as function calls.
926977
ToolCalls []ChatCompletionMessageToolCallParam `json:"tool_calls,omitempty"`
978+
979+
// Annotations for the message, when applicable, as when using the web search tool.
980+
Annotations []Annotation `json:"annotations,omitempty"`
981+
982+
// Audio is the audio response generated by the model, if applicable.
983+
Audio *ChatCompletionResponseChoiceMessageAudio `json:"audio,omitempty"`
984+
}
985+
986+
// URLCitation contains citation information for web search results.
987+
// Docs: https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat
988+
type URLCitation struct {
989+
// EndIndex is the index of the last character of the URL citation in the message.
990+
EndIndex int `json:"end_index"`
991+
// StartIndex is the index of the first character of the URL citation in the message.
992+
StartIndex int `json:"start_index"`
993+
// URL is the URL of the web resource.
994+
URL string `json:"url"`
995+
// Title is the title of the web resource.
996+
Title string `json:"title"`
997+
}
998+
999+
// Annotation represents a URL citation when using web search.
1000+
// The annotation appears in message content when the model cites web sources.
1001+
// Docs: https://platform.openai.com/docs/guides/tools-web-search?api-mode=chat
1002+
type Annotation struct {
1003+
// Type is the type of the annotation. Always "url_citation" for web search.
1004+
Type string `json:"type"`
1005+
// URLCitation contains the citation details when type is "url_citation".
1006+
URLCitation *URLCitation `json:"url_citation,omitempty"` //nolint:tagliatelle //follow openai api
1007+
}
1008+
1009+
// ChatCompletionResponseChoiceMessageAudio is described in the OpenAI API documentation.
1010+
type ChatCompletionResponseChoiceMessageAudio struct {
1011+
Data string `json:"data"`
1012+
ExpiresAt int64 `json:"expires_at"`
1013+
ID string `json:"id"`
1014+
Transcript string `json:"transcript"`
9271015
}
9281016

9291017
// ChatCompletionResponseUsage is described in the OpenAI API documentation:
@@ -941,6 +1029,10 @@ type ChatCompletionResponseUsage struct {
9411029

9421030
// CompletionTokensDetails breakdown of tokens used in a completion.
9431031
type CompletionTokensDetails struct {
1032+
// Text input tokens present in the prompt.
1033+
TextTokens int `json:"text_tokens,omitzero"`
1034+
// ^^ TODO: no idea why this is undocumented on the official OpenAI API docs.
1035+
9441036
// When using Predicted Outputs, the number of tokens in the prediction that appeared in the completion.
9451037
AcceptedPredictionTokens int `json:"accepted_prediction_tokens,omitzero"`
9461038
// Audio input tokens generated by the model.
@@ -955,6 +1047,10 @@ type CompletionTokensDetails struct {
9551047

9561048
// PromptTokensDetails breakdown of tokens used in the prompt.
9571049
type PromptTokensDetails struct {
1050+
// Text input tokens present in the prompt.
1051+
TextTokens int `json:"text_tokens,omitzero"`
1052+
// ^^ TODO: no idea why this is undocumented on the official OpenAI API docs.
1053+
9581054
// Audio input tokens present in the prompt.
9591055
AudioTokens int `json:"audio_tokens,omitzero"`
9601056
// Cached tokens present in the prompt.
@@ -989,6 +1085,11 @@ type ChatCompletionResponseChunk struct {
9891085
// Usage is described in the OpenAI API documentation:
9901086
// https://platform.openai.com/docs/api-reference/chat/streaming#chat/streaming-usage
9911087
Usage *ChatCompletionResponseUsage `json:"usage,omitempty"`
1088+
1089+
// Obfuscation are random characters that normalize payload sizes as a
1090+
// mitigation to certain side-channel attacks.
1091+
// https://platform.openai.com/docs/api-reference/responses/get#responses_get-include_obfuscation
1092+
Obfuscation string `json:"obfuscation,omitempty"`
9921093
}
9931094

9941095
// String implements fmt.Stringer.
@@ -1009,9 +1110,10 @@ type ChatCompletionResponseChunkChoice struct {
10091110
// ChatCompletionResponseChunkChoiceDelta is described in the OpenAI API documentation:
10101111
// https://platform.openai.com/docs/api-reference/chat/streaming#chat/streaming-choices
10111112
type ChatCompletionResponseChunkChoiceDelta struct {
1012-
Content *string `json:"content,omitempty"`
1013-
Role string `json:"role,omitempty"`
1014-
ToolCalls []ChatCompletionMessageToolCallParam `json:"tool_calls,omitempty"`
1113+
Content *string `json:"content,omitempty"`
1114+
Role string `json:"role,omitempty"`
1115+
ToolCalls []ChatCompletionMessageToolCallParam `json:"tool_calls,omitempty"`
1116+
Annotations []Annotation `json:"annotations,omitempty"`
10151117
}
10161118

10171119
// Error is described in the OpenAI API documentation

0 commit comments

Comments
 (0)