From 5e242e6426895ac02a9c2a02561d9d735662ee6f Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Mon, 24 Nov 2025 21:44:21 -0800 Subject: [PATCH 01/36] cargo.toml with feature flags --- async-openai/Cargo.toml | 154 +++++++++++++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 27 deletions(-) diff --git a/async-openai/Cargo.toml b/async-openai/Cargo.toml index 7ce46154..2b89a7a0 100644 --- a/async-openai/Cargo.toml +++ b/async-openai/Cargo.toml @@ -15,43 +15,143 @@ repository = "https://github.com/64bit/async-openai" [features] default = ["rustls"] # Enable rustls for TLS support -rustls = ["reqwest/rustls-tls-native-roots"] +rustls = ["_api", "dep:reqwest", "reqwest/rustls-tls-native-roots"] # Enable rustls and webpki-roots -rustls-webpki-roots = ["reqwest/rustls-tls-webpki-roots"] +rustls-webpki-roots = ["_api", "dep:reqwest", "reqwest/rustls-tls-webpki-roots"] # Enable native-tls for TLS support -native-tls = ["reqwest/native-tls"] +native-tls = ["_api","dep:reqwest", "reqwest/native-tls"] # Remove dependency on OpenSSL -native-tls-vendored = ["reqwest/native-tls-vendored"] -realtime = ["dep:tokio-tungstenite"] +native-tls-vendored = ["_api", "dep:reqwest", "reqwest/native-tls-vendored"] # Bring your own types -byot = [] -webhook = ["dep:hmac", "dep:sha2", "dep:hex"] +byot = ["_api"] + +# API feature flags - these enable both the API wrapper and types +responses = ["response-types", "_api"] +webhook = ["webhook-types", "_api", "dep:hmac", "dep:sha2", "dep:hex"] +# start - Platform APIs +audio = ["audio-types", "_api"] +video = ["video-types", "_api"] +image = ["image-types", "_api"] +embedding = ["embedding-types", "_api"] +evals = ["eval-types", "_api"] +finetuning = ["finetuning-types", "_api"] +grader = ["grader-types"] +batch = ["batch-types", "_api"] +file = ["file-types", "_api"] +upload = ["upload-types", "_api"] +model = ["model-types", "_api"] +moderation = ["moderation-types", "_api"] +# end - Platform APIs +vectorstore = ["vectorstore-types", "_api"] +chatkit = ["chatkit-types", "_api"] +container = ["container-types", "_api"] +realtime = ["realtime-types", "_api", "dep:tokio-tungstenite"] +chat-completion = ["chat-completion-types", "_api"] +assistant = ["assistant-types", "_api", ] +administration = ["administration-types", "_api"] +completions = ["completion-types", "_api"] + +# Type feature flags - these enable only the types +response-types = ["dep:derive_builder", "dep:bytes"] +webhook-types = ["dep:derive_builder", "dep:bytes"] +audio-types = ["dep:derive_builder", "dep:bytes"] +video-types = ["dep:derive_builder", "dep:bytes"] +image-types = ["dep:derive_builder", "dep:bytes"] +embedding-types = ["dep:derive_builder", "dep:bytes"] +eval-types = ["dep:derive_builder", "dep:bytes"] +finetuning-types = ["dep:derive_builder", "dep:bytes"] +grader-types = ["dep:derive_builder", "dep:bytes"] +batch-types = ["dep:derive_builder", "dep:bytes"] +file-types = ["dep:derive_builder", "dep:bytes"] +upload-types = ["dep:derive_builder", "dep:bytes"] +model-types = ["dep:derive_builder", "dep:bytes"] +moderation-types = ["dep:derive_builder", "dep:bytes"] +vectorstore-types = ["dep:derive_builder", "dep:bytes"] +chatkit-types = ["dep:derive_builder", "dep:bytes"] +container-types = ["dep:derive_builder", "dep:bytes"] +realtime-types = ["dep:derive_builder", "dep:bytes"] +chat-completion-types = ["dep:derive_builder", "dep:bytes"] +assistant-types = ["dep:derive_builder", "dep:bytes"] +administration-types = ["dep:derive_builder", "dep:bytes"] +completion-types = ["dep:derive_builder", "dep:bytes"] + +# Enable all types +types = [ + "response-types", + "webhook-types", + "audio-types", + "video-types", + "image-types", + "embedding-types", + "eval-types", + "finetuning-types", + "grader-types", + "batch-types", + "file-types", + "upload-types", + "model-types", + "moderation-types", + "vectorstore-types", + "chatkit-types", + "container-types", + "realtime-types", + "chat-completion-types", + "assistant-types", + "administration-types", + "completion-types", +] + +# Internal feature to enable API dependencies +_api = [ + "dep:async-openai-macros", + "dep:backoff", + "dep:base64", + "dep:bytes", + "dep:futures", + "dep:rand", + "dep:reqwest", + "dep:reqwest-eventsource", + "dep:thiserror", + "dep:tokio", + "dep:tokio-stream", + "dep:tokio-util", + "dep:tracing", + "dep:secrecy", + "dep:eventsource-stream", + "dep:serde_urlencoded", + "dep:url", +] + [dependencies] -async-openai-macros = { path = "../async-openai-macros", version = "0.1.0" } -backoff = { version = "0.4.0", features = ["tokio"] } -base64 = "0.22.1" -futures = "0.3.31" -rand = "0.9.0" +# Core dependencies - always needed for types +serde = { version = "1.0.217", features = ["derive", "rc"] } +serde_json = "1.0.135" +derive_builder = { version = "0.20.2", optional = true } +bytes = { version = "1.9.0", optional = true } + +# API dependencies - only needed when API features are enabled +# We use a feature gate to enable these when any API feature is enabled +async-openai-macros = { path = "../async-openai-macros", version = "0.1.0", optional = true } +backoff = { version = "0.4.0", features = ["tokio"], optional = true } +base64 = { version = "0.22.1", optional = true } +futures = { version = "0.3.31", optional = true } +rand = { version = "0.9.0", optional = true } reqwest = { version = "0.12.12", features = [ "json", "stream", "multipart", -], default-features = false } -reqwest-eventsource = "0.6.0" -serde = { version = "1.0.217", features = ["derive", "rc"] } -serde_json = "1.0.135" -thiserror = "2.0.11" -tokio = { version = "1.43.0", features = ["fs", "macros"] } -tokio-stream = "0.1.17" -tokio-util = { version = "0.7.13", features = ["codec", "io-util"] } -tracing = "0.1.41" -derive_builder = "0.20.2" -secrecy = { version = "0.10.3", features = ["serde"] } -bytes = "1.9.0" -eventsource-stream = "0.2.3" -serde_urlencoded = "0.7.1" -url = "2.5" +], default-features = false, optional = true } +reqwest-eventsource = { version = "0.6.0", optional = true } +thiserror = { version = "2.0.11", optional = true } +tokio = { version = "1.43.0", features = ["fs", "macros"], optional = true } +tokio-stream = { version = "0.1.17", optional = true } +tokio-util = { version = "0.7.13", features = ["codec", "io-util"], optional = true } +tracing = { version = "0.1.41", optional = true } +secrecy = { version = "0.10.3", features = ["serde"], optional = true } +eventsource-stream = { version = "0.2.3", optional = true } +serde_urlencoded = { version = "0.7.1", optional = true } +url = { version = "2.5", optional = true } tokio-tungstenite = { version = "0.26.1", optional = true, default-features = false } hmac = { version = "0.12", optional = true, default-features = false} sha2 = { version = "0.10", optional = true, default-features = false } From 276f65157f9bf3ec90ef67e4e5ecd389aff9b84b Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 14:20:06 -0800 Subject: [PATCH 02/36] examples having correct feature flags --- examples/assistants-code-interpreter/Cargo.toml | 2 +- examples/assistants-file-search/Cargo.toml | 2 +- examples/assistants-func-call-stream/Cargo.toml | 2 +- examples/assistants/Cargo.toml | 2 +- examples/audio-speech-stream/Cargo.toml | 2 +- examples/audio-speech/Cargo.toml | 2 +- examples/audio-transcribe/Cargo.toml | 2 +- examples/audio-translate/Cargo.toml | 2 +- examples/azure-openai-service/Cargo.toml | 2 +- examples/bring-your-own-type/Cargo.toml | 2 +- examples/chat-store/Cargo.toml | 2 +- examples/chat-stream/Cargo.toml | 2 +- examples/chat/Cargo.toml | 2 +- examples/chatkit/Cargo.toml | 2 +- examples/completions-stream/Cargo.toml | 2 +- examples/completions-web-search/Cargo.toml | 2 +- examples/completions/Cargo.toml | 2 +- examples/containers/Cargo.toml | 2 +- examples/conversations/Cargo.toml | 2 +- examples/create-image-variation/Cargo.toml | 2 +- examples/embeddings/Cargo.toml | 2 +- examples/gemini-openai-compatibility/Cargo.toml | 2 +- examples/image-edit-stream/Cargo.toml | 2 +- examples/image-edit/Cargo.toml | 2 +- examples/image-gen-stream/Cargo.toml | 2 +- examples/image-generate-b64-json/Cargo.toml | 2 +- examples/image-generate/Cargo.toml | 2 +- examples/in-memory-file/Cargo.toml | 2 +- examples/models/Cargo.toml | 2 +- examples/moderations/Cargo.toml | 2 +- examples/ollama-chat/Cargo.toml | 2 +- examples/responses-function-call/Cargo.toml | 2 +- examples/responses-images-and-vision/Cargo.toml | 2 +- examples/responses-retrieve-stream/Cargo.toml | 2 +- examples/responses-stream/Cargo.toml | 2 +- examples/responses-structured-outputs/Cargo.toml | 2 +- examples/responses/Cargo.toml | 2 +- examples/structured-outputs-schemars/Cargo.toml | 2 +- examples/structured-outputs/Cargo.toml | 2 +- examples/tool-call-stream/Cargo.toml | 2 +- examples/tool-call/Cargo.toml | 2 +- examples/usage/Cargo.toml | 2 +- examples/vector-store-retrieval/Cargo.toml | 2 +- examples/video/Cargo.toml | 2 +- examples/vision-chat/Cargo.toml | 2 +- examples/webhooks/Cargo.toml | 2 +- 46 files changed, 46 insertions(+), 46 deletions(-) diff --git a/examples/assistants-code-interpreter/Cargo.toml b/examples/assistants-code-interpreter/Cargo.toml index c53112ae..4b6d2980 100644 --- a/examples/assistants-code-interpreter/Cargo.toml +++ b/examples/assistants-code-interpreter/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["assistant", "file"] } tokio = { version = "1.43.0", features = ["full"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"]} diff --git a/examples/assistants-file-search/Cargo.toml b/examples/assistants-file-search/Cargo.toml index 7c94c891..47104d74 100644 --- a/examples/assistants-file-search/Cargo.toml +++ b/examples/assistants-file-search/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["assistant", "file", "vectorstore"] } tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/assistants-func-call-stream/Cargo.toml b/examples/assistants-func-call-stream/Cargo.toml index 9767e2b0..dbc3e1da 100644 --- a/examples/assistants-func-call-stream/Cargo.toml +++ b/examples/assistants-func-call-stream/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["assistant"] } tokio = { version = "1.43.0", features = ["full"] } serde_json = "1.0.135" futures = "0.3.31" diff --git a/examples/assistants/Cargo.toml b/examples/assistants/Cargo.toml index d7595fd4..339268df 100644 --- a/examples/assistants/Cargo.toml +++ b/examples/assistants/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["assistant"]} tokio = { version = "1.43.0", features = ["full"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"]} diff --git a/examples/audio-speech-stream/Cargo.toml b/examples/audio-speech-stream/Cargo.toml index 7b644292..53603c6a 100644 --- a/examples/audio-speech-stream/Cargo.toml +++ b/examples/audio-speech-stream/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["audio"]} tokio = { version = "1.43.0", features = ["full"] } futures = "0.3.31" base64 = "0.22.1" diff --git a/examples/audio-speech/Cargo.toml b/examples/audio-speech/Cargo.toml index 32c19367..7f38c2e6 100644 --- a/examples/audio-speech/Cargo.toml +++ b/examples/audio-speech/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["audio"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/audio-transcribe/Cargo.toml b/examples/audio-transcribe/Cargo.toml index 73dd52ae..5090fd6a 100644 --- a/examples/audio-transcribe/Cargo.toml +++ b/examples/audio-transcribe/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["audio"]} tokio = { version = "1.43.0", features = ["full"] } futures = "0.3.31" diff --git a/examples/audio-translate/Cargo.toml b/examples/audio-translate/Cargo.toml index ba64e89a..d98bf28e 100644 --- a/examples/audio-translate/Cargo.toml +++ b/examples/audio-translate/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["audio"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/azure-openai-service/Cargo.toml b/examples/azure-openai-service/Cargo.toml index ec8f0b41..06d24c94 100644 --- a/examples/azure-openai-service/Cargo.toml +++ b/examples/azure-openai-service/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion", "embedding"]} tokio = { version = "1.43.0", features = ["full"] } futures = "0.3.31" diff --git a/examples/bring-your-own-type/Cargo.toml b/examples/bring-your-own-type/Cargo.toml index e99a7454..1c29fbd9 100644 --- a/examples/bring-your-own-type/Cargo.toml +++ b/examples/bring-your-own-type/Cargo.toml @@ -6,7 +6,7 @@ rust-version.workspace = true publish = false [dependencies] -async-openai = {path = "../../async-openai", features = ["byot"]} +async-openai = {path = "../../async-openai", features = ["byot", "chat-completion"]} tokio = { version = "1.43.0", features = ["full"] } serde_json = "1" futures-core = "0.3" diff --git a/examples/chat-store/Cargo.toml b/examples/chat-store/Cargo.toml index 0bf77f5f..f28d3d0c 100644 --- a/examples/chat-store/Cargo.toml +++ b/examples/chat-store/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/chat-stream/Cargo.toml b/examples/chat-stream/Cargo.toml index 85b4cf43..e33b8323 100644 --- a/examples/chat-stream/Cargo.toml +++ b/examples/chat-stream/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} tokio = { version = "1.43.0", features = ["full"] } futures = "0.3.31" diff --git a/examples/chat/Cargo.toml b/examples/chat/Cargo.toml index b7251e36..9cf9994b 100644 --- a/examples/chat/Cargo.toml +++ b/examples/chat/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/chatkit/Cargo.toml b/examples/chatkit/Cargo.toml index 7ff906d9..3d9bfadb 100644 --- a/examples/chatkit/Cargo.toml +++ b/examples/chatkit/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chatkit"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/completions-stream/Cargo.toml b/examples/completions-stream/Cargo.toml index fd6d5e59..8bed6947 100644 --- a/examples/completions-stream/Cargo.toml +++ b/examples/completions-stream/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["completions"]} futures = "0.3.30" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/completions-web-search/Cargo.toml b/examples/completions-web-search/Cargo.toml index f58d4f8b..637845e8 100644 --- a/examples/completions-web-search/Cargo.toml +++ b/examples/completions-web-search/Cargo.toml @@ -6,5 +6,5 @@ publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/completions/Cargo.toml b/examples/completions/Cargo.toml index 0574060f..61dfe196 100644 --- a/examples/completions/Cargo.toml +++ b/examples/completions/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["completions"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/containers/Cargo.toml b/examples/containers/Cargo.toml index 40736578..103b6daf 100644 --- a/examples/containers/Cargo.toml +++ b/examples/containers/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["container"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/conversations/Cargo.toml b/examples/conversations/Cargo.toml index 36a4799e..3a2616fc 100644 --- a/examples/conversations/Cargo.toml +++ b/examples/conversations/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["responses"] } tokio = { version = "1.41.1", features = ["full"] } serde_json = "1" diff --git a/examples/create-image-variation/Cargo.toml b/examples/create-image-variation/Cargo.toml index 12de47cb..4a932bab 100644 --- a/examples/create-image-variation/Cargo.toml +++ b/examples/create-image-variation/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["image"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/embeddings/Cargo.toml b/examples/embeddings/Cargo.toml index 49855f24..9809ddcc 100644 --- a/examples/embeddings/Cargo.toml +++ b/examples/embeddings/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["embedding"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/gemini-openai-compatibility/Cargo.toml b/examples/gemini-openai-compatibility/Cargo.toml index f75bbda2..698d0fed 100644 --- a/examples/gemini-openai-compatibility/Cargo.toml +++ b/examples/gemini-openai-compatibility/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai", features = ["byot"]} +async-openai = {path = "../../async-openai", features = ["byot", "chat-completion", "image", "embedding", "model"]} tokio = { version = "1.43.0", features = ["full"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"]} dotenv = "0.15.0" diff --git a/examples/image-edit-stream/Cargo.toml b/examples/image-edit-stream/Cargo.toml index 14b9d759..40e3d8bd 100644 --- a/examples/image-edit-stream/Cargo.toml +++ b/examples/image-edit-stream/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["image"]} tokio = { version = "1.43.0", features = ["full"] } futures = "0.3.31" base64 = "0.22.1" diff --git a/examples/image-edit/Cargo.toml b/examples/image-edit/Cargo.toml index 24eb2f63..dda7e43b 100644 --- a/examples/image-edit/Cargo.toml +++ b/examples/image-edit/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["image"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/image-gen-stream/Cargo.toml b/examples/image-gen-stream/Cargo.toml index 907e9882..3f61be42 100644 --- a/examples/image-gen-stream/Cargo.toml +++ b/examples/image-gen-stream/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["image"]} tokio = { version = "1.43.0", features = ["full"] } futures = "0.3.31" base64 = "0.22.1" diff --git a/examples/image-generate-b64-json/Cargo.toml b/examples/image-generate-b64-json/Cargo.toml index 87a2b045..c0e7812b 100644 --- a/examples/image-generate-b64-json/Cargo.toml +++ b/examples/image-generate-b64-json/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["image"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/image-generate/Cargo.toml b/examples/image-generate/Cargo.toml index 71b5cbe0..42580b1a 100644 --- a/examples/image-generate/Cargo.toml +++ b/examples/image-generate/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["image"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/in-memory-file/Cargo.toml b/examples/in-memory-file/Cargo.toml index 1d5c4458..cc2dfbfb 100644 --- a/examples/in-memory-file/Cargo.toml +++ b/examples/in-memory-file/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["audio"]} tokio = { version = "1.43.0", features = ["full"] } bytes = "1.9.0" diff --git a/examples/models/Cargo.toml b/examples/models/Cargo.toml index bc38c36f..e8873b53 100644 --- a/examples/models/Cargo.toml +++ b/examples/models/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["model"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/moderations/Cargo.toml b/examples/moderations/Cargo.toml index 12cf62eb..919b3d56 100644 --- a/examples/moderations/Cargo.toml +++ b/examples/moderations/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["moderation"] } tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/ollama-chat/Cargo.toml b/examples/ollama-chat/Cargo.toml index cbdd7cc2..bc121558 100644 --- a/examples/ollama-chat/Cargo.toml +++ b/examples/ollama-chat/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/responses-function-call/Cargo.toml b/examples/responses-function-call/Cargo.toml index fae73d83..eb61b286 100644 --- a/examples/responses-function-call/Cargo.toml +++ b/examples/responses-function-call/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["responses"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } serde = { version = "1.0.219", features = ["derive"] } diff --git a/examples/responses-images-and-vision/Cargo.toml b/examples/responses-images-and-vision/Cargo.toml index 6258b396..74cf62b8 100644 --- a/examples/responses-images-and-vision/Cargo.toml +++ b/examples/responses-images-and-vision/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["responses"] } tokio = { version = "1.0", features = ["full"] } futures = "0.3" base64 = "0.22.1" diff --git a/examples/responses-retrieve-stream/Cargo.toml b/examples/responses-retrieve-stream/Cargo.toml index 8f57a2a8..53275a32 100644 --- a/examples/responses-retrieve-stream/Cargo.toml +++ b/examples/responses-retrieve-stream/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["responses"] } tokio = { version = "1.0", features = ["full"] } futures = "0.3" serde_json = "1.0" diff --git a/examples/responses-stream/Cargo.toml b/examples/responses-stream/Cargo.toml index 5a276ba0..feaa5fc6 100644 --- a/examples/responses-stream/Cargo.toml +++ b/examples/responses-stream/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["responses"] } tokio = { version = "1.0", features = ["full"] } futures = "0.3" serde_json = "1.0" diff --git a/examples/responses-structured-outputs/Cargo.toml b/examples/responses-structured-outputs/Cargo.toml index 869d3436..1bb475de 100644 --- a/examples/responses-structured-outputs/Cargo.toml +++ b/examples/responses-structured-outputs/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["responses"] } serde_json = "1.0" tokio = { version = "1", features = ["full"] } clap = { version = "4", features = ["derive"] } diff --git a/examples/responses/Cargo.toml b/examples/responses/Cargo.toml index 5de7c1e4..39d5ace2 100644 --- a/examples/responses/Cargo.toml +++ b/examples/responses/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["responses"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/structured-outputs-schemars/Cargo.toml b/examples/structured-outputs-schemars/Cargo.toml index 029298c1..75c93280 100644 --- a/examples/structured-outputs-schemars/Cargo.toml +++ b/examples/structured-outputs-schemars/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} serde_json = "1.0.127" tokio = { version = "1.39.3", features = ["full"] } schemars = "0.8.21" diff --git a/examples/structured-outputs/Cargo.toml b/examples/structured-outputs/Cargo.toml index 0005568b..6e268e57 100644 --- a/examples/structured-outputs/Cargo.toml +++ b/examples/structured-outputs/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/tool-call-stream/Cargo.toml b/examples/tool-call-stream/Cargo.toml index 6d68ba36..9ab536c9 100644 --- a/examples/tool-call-stream/Cargo.toml +++ b/examples/tool-call-stream/Cargo.toml @@ -7,7 +7,7 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} rand = "0.8.5" serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/tool-call/Cargo.toml b/examples/tool-call/Cargo.toml index e6a2dc63..967e47c7 100644 --- a/examples/tool-call/Cargo.toml +++ b/examples/tool-call/Cargo.toml @@ -7,7 +7,7 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["chat-completion"]} rand = "0.8.5" serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/usage/Cargo.toml b/examples/usage/Cargo.toml index 669ef3c2..3553dbd8 100644 --- a/examples/usage/Cargo.toml +++ b/examples/usage/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["administration"]} tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/vector-store-retrieval/Cargo.toml b/examples/vector-store-retrieval/Cargo.toml index a4b8bb22..9a11003d 100644 --- a/examples/vector-store-retrieval/Cargo.toml +++ b/examples/vector-store-retrieval/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["vectorstore", "file"] } tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/video/Cargo.toml b/examples/video/Cargo.toml index 601bd03d..5514380f 100644 --- a/examples/video/Cargo.toml +++ b/examples/video/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = {path = "../../async-openai"} +async-openai = {path = "../../async-openai", features = ["video"]} tokio = { version = "1.43.0", features = ["full"] } bytes = "1.9.0" diff --git a/examples/vision-chat/Cargo.toml b/examples/vision-chat/Cargo.toml index 11a7cde5..b2ac34b7 100644 --- a/examples/vision-chat/Cargo.toml +++ b/examples/vision-chat/Cargo.toml @@ -7,6 +7,6 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -async-openai = { path = "../../async-openai" } +async-openai = { path = "../../async-openai", features = ["chat-completion"] } serde_json = "1.0.135" tokio = { version = "1.43.0", features = ["full"] } diff --git a/examples/webhooks/Cargo.toml b/examples/webhooks/Cargo.toml index fb004089..f2f4a49a 100644 --- a/examples/webhooks/Cargo.toml +++ b/examples/webhooks/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" publish = false [dependencies] -async-openai = { path = "../../async-openai", features = ["webhook"] } +async-openai = { path = "../../async-openai", features = ["webhook", "responses"] } tokio = { version = "1.42.0", features = ["full"] } axum = "0.7.9" tracing = "0.1.41" From 7bf7ed481b45c4a6a99722d245441e4b49051375 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 14:26:30 -0800 Subject: [PATCH 03/36] response-types: cargo b -F response-types --no-default-features --- .../src/types/responses/conversation.rs | 2 +- async-openai/src/types/responses/stream.rs | 25 ++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/async-openai/src/types/responses/conversation.rs b/async-openai/src/types/responses/conversation.rs index 94d23545..bd87c435 100644 --- a/async-openai/src/types/responses/conversation.rs +++ b/async-openai/src/types/responses/conversation.rs @@ -13,7 +13,7 @@ use crate::{ }, }; -use crate::types::common::Metadata; +use crate::types::Metadata; /// Represents a conversation object. #[derive(Clone, Serialize, Debug, Deserialize, PartialEq)] diff --git a/async-openai/src/types/responses/stream.rs b/async-openai/src/types/responses/stream.rs index 6e58dff2..86bfc261 100644 --- a/async-openai/src/types/responses/stream.rs +++ b/async-openai/src/types/responses/stream.rs @@ -1,15 +1,6 @@ -use futures::Stream; use serde::{Deserialize, Serialize}; -use std::pin::Pin; -use crate::{ - error::OpenAIError, - types::responses::{OutputContent, OutputItem, Response, ResponseLogProb, SummaryPart}, -}; - -/// Stream of response events -pub type ResponseStream = - Pin> + Send>>; +use crate::types::responses::{OutputContent, OutputItem, Response, ResponseLogProb, SummaryPart}; /// Event types for streaming responses from the Responses API #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] @@ -544,14 +535,18 @@ pub struct ResponseErrorEvent { pub param: Option, } -use crate::traits::EventType; +/// Stream of response events +#[cfg(feature = "_api")] +pub type ResponseStream = std::pin::Pin< + Box> + Send>, +>; // Implement EventType trait for all event types in this file - +#[cfg(feature = "_api")] macro_rules! impl_event_type { ($($ty:ty => $event_type:expr),* $(,)?) => { $( - impl EventType for $ty { + impl crate::traits::EventType for $ty { fn event_type(&self) -> &'static str { $event_type } @@ -561,6 +556,7 @@ macro_rules! impl_event_type { } // Apply macro for each event struct type in this file. +#[cfg(feature = "_api")] impl_event_type! { ResponseCreatedEvent => "response.created", ResponseInProgressEvent => "response.in_progress", @@ -613,7 +609,8 @@ impl_event_type! { ResponseErrorEvent => "error", } -impl EventType for ResponseStreamEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for ResponseStreamEvent { fn event_type(&self) -> &'static str { match self { ResponseStreamEvent::ResponseCreated(event) => event.event_type(), From 47236718e625310fec7e2fe88097d3b990ef797c Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 14:40:13 -0800 Subject: [PATCH 04/36] webhook-types: cargo b -F webhook-types --no-default-features --- async-openai/src/types/webhooks/webhooks.rs | 261 ++++++-------------- 1 file changed, 70 insertions(+), 191 deletions(-) diff --git a/async-openai/src/types/webhooks/webhooks.rs b/async-openai/src/types/webhooks/webhooks.rs index 15548c18..51aff984 100644 --- a/async-openai/src/types/webhooks/webhooks.rs +++ b/async-openai/src/types/webhooks/webhooks.rs @@ -1,7 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::traits::{EventId, EventType}; - /// Sent when a batch API request has been cancelled. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct WebhookBatchCancelled { @@ -77,56 +75,6 @@ pub struct WebhookBatchData { pub id: String, } -// EventType and EventId implementations for batch events - -impl EventType for WebhookBatchCancelled { - fn event_type(&self) -> &'static str { - "batch.cancelled" - } -} - -impl EventId for WebhookBatchCancelled { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookBatchCompleted { - fn event_type(&self) -> &'static str { - "batch.completed" - } -} - -impl EventId for WebhookBatchCompleted { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookBatchExpired { - fn event_type(&self) -> &'static str { - "batch.expired" - } -} - -impl EventId for WebhookBatchExpired { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookBatchFailed { - fn event_type(&self) -> &'static str { - "batch.failed" - } -} - -impl EventId for WebhookBatchFailed { - fn event_id(&self) -> &str { - &self.id - } -} - /// Sent when an eval run has been canceled. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct WebhookEvalRunCanceled { @@ -185,44 +133,6 @@ pub struct WebhookEvalRunData { pub id: String, } -// EventType and EventId implementations for eval run events - -impl EventType for WebhookEvalRunCanceled { - fn event_type(&self) -> &'static str { - "eval.run.canceled" - } -} - -impl EventId for WebhookEvalRunCanceled { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookEvalRunFailed { - fn event_type(&self) -> &'static str { - "eval.run.failed" - } -} - -impl EventId for WebhookEvalRunFailed { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookEvalRunSucceeded { - fn event_type(&self) -> &'static str { - "eval.run.succeeded" - } -} - -impl EventId for WebhookEvalRunSucceeded { - fn event_id(&self) -> &str { - &self.id - } -} - /// Sent when a fine-tuning job has been cancelled. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct WebhookFineTuningJobCancelled { @@ -283,42 +193,6 @@ pub struct WebhookFineTuningJobData { // EventType and EventId implementations for fine-tuning job events -impl EventType for WebhookFineTuningJobCancelled { - fn event_type(&self) -> &'static str { - "fine_tuning.job.cancelled" - } -} - -impl EventId for WebhookFineTuningJobCancelled { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookFineTuningJobFailed { - fn event_type(&self) -> &'static str { - "fine_tuning.job.failed" - } -} - -impl EventId for WebhookFineTuningJobFailed { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookFineTuningJobSucceeded { - fn event_type(&self) -> &'static str { - "fine_tuning.job.succeeded" - } -} - -impl EventId for WebhookFineTuningJobSucceeded { - fn event_id(&self) -> &str { - &self.id - } -} - /// Sent when Realtime API receives an incoming SIP call. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct WebhookRealtimeCallIncoming { @@ -356,20 +230,6 @@ pub struct SipHeader { pub value: String, } -// EventType and EventId implementations for realtime call events - -impl EventType for WebhookRealtimeCallIncoming { - fn event_type(&self) -> &'static str { - "realtime.call.incoming" - } -} - -impl EventId for WebhookRealtimeCallIncoming { - fn event_id(&self) -> &str { - &self.id - } -} - /// Sent when a background response has been cancelled. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct WebhookResponseCancelled { @@ -447,54 +307,6 @@ pub struct WebhookResponseData { // EventType and EventId implementations for response events -impl EventType for WebhookResponseCancelled { - fn event_type(&self) -> &'static str { - "response.cancelled" - } -} - -impl EventId for WebhookResponseCancelled { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookResponseCompleted { - fn event_type(&self) -> &'static str { - "response.completed" - } -} - -impl EventId for WebhookResponseCompleted { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookResponseFailed { - fn event_type(&self) -> &'static str { - "response.failed" - } -} - -impl EventId for WebhookResponseFailed { - fn event_id(&self) -> &str { - &self.id - } -} - -impl EventType for WebhookResponseIncomplete { - fn event_type(&self) -> &'static str { - "response.incomplete" - } -} - -impl EventId for WebhookResponseIncomplete { - fn event_id(&self) -> &str { - &self.id - } -} - #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(tag = "type")] pub enum WebhookEvent { @@ -544,9 +356,75 @@ pub enum WebhookEvent { ResponseIncomplete(WebhookResponseIncomplete), } -// Trait implementations for WebhookEvent enum +// Implement EventType trait for all event types in this file +#[cfg(feature = "_api")] +macro_rules! impl_event_type { + ($($ty:ty => $event_type:expr),* $(,)?) => { + $( + impl crate::traits::EventType for $ty { + fn event_type(&self) -> &'static str { + $event_type + } + } + )* + }; +} + +#[cfg(feature = "_api")] +macro_rules! impl_event_id { + ($($ty:ty),* $(,)?) => { + $( + impl crate::traits::EventId for $ty { + fn event_id(&self) -> &str { + &self.id + } + } + )* + }; +} +// Use the macro to implement EventType for all webhook event structs +#[cfg(feature = "_api")] +impl_event_type! { + WebhookBatchCancelled => "batch.cancelled", + WebhookBatchCompleted => "batch.completed", + WebhookBatchExpired => "batch.expired", + WebhookBatchFailed => "batch.failed", + WebhookEvalRunCanceled => "eval.run.canceled", + WebhookEvalRunFailed => "eval.run.failed", + WebhookEvalRunSucceeded => "eval.run.succeeded", + WebhookFineTuningJobCancelled => "fine_tuning.job.cancelled", + WebhookFineTuningJobFailed => "fine_tuning.job.failed", + WebhookFineTuningJobSucceeded => "fine_tuning.job.succeeded", + WebhookRealtimeCallIncoming => "realtime.call.incoming", + WebhookResponseCancelled => "response.cancelled", + WebhookResponseCompleted => "response.completed", + WebhookResponseFailed => "response.failed", + WebhookResponseIncomplete => "response.incomplete", +} + +// Use the macro to implement EventId for all webhook event structs +#[cfg(feature = "_api")] +impl_event_id! { + WebhookBatchCancelled, + WebhookBatchCompleted, + WebhookBatchExpired, + WebhookBatchFailed, + WebhookEvalRunCanceled, + WebhookEvalRunFailed, + WebhookEvalRunSucceeded, + WebhookFineTuningJobCancelled, + WebhookFineTuningJobFailed, + WebhookFineTuningJobSucceeded, + WebhookRealtimeCallIncoming, + WebhookResponseCancelled, + WebhookResponseCompleted, + WebhookResponseFailed, + WebhookResponseIncomplete, +} -impl EventType for WebhookEvent { +// Trait implementations for WebhookEvent enum +#[cfg(feature = "_api")] +impl crate::traits::EventType for WebhookEvent { fn event_type(&self) -> &'static str { match self { WebhookEvent::BatchCancelled(e) => e.event_type(), @@ -568,7 +446,8 @@ impl EventType for WebhookEvent { } } -impl EventId for WebhookEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventId for WebhookEvent { fn event_id(&self) -> &str { match self { WebhookEvent::BatchCancelled(e) => e.event_id(), From 9d3237b83be015fef411bc7daef9514d15e4ad11 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:00:01 -0800 Subject: [PATCH 05/36] audio-types: cargo b -F audio-types --no-default-features --- async-openai/src/types/audio/audio_.rs | 2 +- async-openai/src/types/audio/mod.rs | 2 + async-openai/src/types/audio/stream.rs | 83 +++++++++++++------------- 3 files changed, 44 insertions(+), 43 deletions(-) diff --git a/async-openai/src/types/audio/audio_.rs b/async-openai/src/types/audio/audio_.rs index 156008a5..b8ec683a 100644 --- a/async-openai/src/types/audio/audio_.rs +++ b/async-openai/src/types/audio/audio_.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::error::OpenAIError; use crate::types::audio::{LogProbProperties, TranscriptTextUsageDuration, TranscriptionUsage}; -use crate::types::common::InputSource; +use crate::types::InputSource; // openapi spec type: VoiceIdsShared #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)] diff --git a/async-openai/src/types/audio/mod.rs b/async-openai/src/types/audio/mod.rs index 2d1472a7..1c62dd86 100644 --- a/async-openai/src/types/audio/mod.rs +++ b/async-openai/src/types/audio/mod.rs @@ -1,6 +1,8 @@ mod audio_; +#[cfg(feature = "_api")] mod form; mod impls; +#[cfg(feature = "_api")] mod sdk; mod stream; diff --git a/async-openai/src/types/audio/stream.rs b/async-openai/src/types/audio/stream.rs index 1197dff2..362baa9e 100644 --- a/async-openai/src/types/audio/stream.rs +++ b/async-openai/src/types/audio/stream.rs @@ -1,13 +1,6 @@ -use std::pin::Pin; - -use futures::Stream; use serde::{Deserialize, Serialize}; -use crate::{ - error::OpenAIError, - traits::EventType, - types::audio::{LogProbProperties, TranscriptTextUsageTokens}, -}; +use crate::types::audio::{LogProbProperties, TranscriptTextUsageTokens}; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] #[serde(tag = "type", rename_all = "snake_case")] @@ -42,10 +35,6 @@ pub struct SpeechAudioDoneEvent { pub usage: SpeechUsage, } -/// Stream of response events -pub type SpeechResponseStream = - Pin> + Send>>; - #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct TranscriptionTextSegmentEvent { /// Unique identifier for the segment. @@ -102,22 +91,49 @@ pub enum CreateTranscriptionResponseStreamEvent { TranscriptTextDone(TranscriptionTextDoneEvent), } -pub type TranscriptionResponseStream = - Pin> + Send>>; +#[cfg(feature = "_api")] +pub type TranscriptionResponseStream = std::pin::Pin< + Box< + dyn futures::Stream< + Item = Result, + > + Send, + >, +>; -impl EventType for SpeechAudioDeltaEvent { - fn event_type(&self) -> &'static str { - "speech.audio.delta" - } +/// Stream of response events +#[cfg(feature = "_api")] +pub type SpeechResponseStream = std::pin::Pin< + Box< + dyn futures::Stream< + Item = Result, + > + Send, + >, +>; + +#[cfg(feature = "_api")] +macro_rules! impl_event_type { + ($($ty:ty => $event_type:expr),* $(,)?) => { + $( + impl crate::traits::EventType for $ty { + fn event_type(&self) -> &'static str { + $event_type + } + } + )* + }; } -impl EventType for SpeechAudioDoneEvent { - fn event_type(&self) -> &'static str { - "speech.audio.done" - } +#[cfg(feature = "_api")] +impl_event_type! { + SpeechAudioDeltaEvent => "speech.audio.delta", + SpeechAudioDoneEvent => "speech.audio.done", + TranscriptionTextSegmentEvent => "transcript.text.segment", + TranscriptionTextDeltaEvent => "transcript.text.delta", + TranscriptionTextDoneEvent => "transcript.text.done", } -impl EventType for CreateSpeechResponseStreamEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for CreateSpeechResponseStreamEvent { fn event_type(&self) -> &'static str { match self { CreateSpeechResponseStreamEvent::SpeechAudioDelta(event) => event.event_type(), @@ -126,25 +142,8 @@ impl EventType for CreateSpeechResponseStreamEvent { } } -impl EventType for TranscriptionTextSegmentEvent { - fn event_type(&self) -> &'static str { - "transcript.text.segment" - } -} - -impl EventType for TranscriptionTextDeltaEvent { - fn event_type(&self) -> &'static str { - "transcript.text.delta" - } -} - -impl EventType for TranscriptionTextDoneEvent { - fn event_type(&self) -> &'static str { - "transcript.text.done" - } -} - -impl EventType for CreateTranscriptionResponseStreamEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for CreateTranscriptionResponseStreamEvent { fn event_type(&self) -> &'static str { match self { CreateTranscriptionResponseStreamEvent::TranscriptTextSegment(event) => { From 7cb57baf7a7b0563a3e4fe3306e03177a48ddcda Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:06:00 -0800 Subject: [PATCH 06/36] video-types: cargo b -F video-types --no-default-features --- async-openai/src/types/videos/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/async-openai/src/types/videos/mod.rs b/async-openai/src/types/videos/mod.rs index 9d3c3821..d8eef6cc 100644 --- a/async-openai/src/types/videos/mod.rs +++ b/async-openai/src/types/videos/mod.rs @@ -1,4 +1,5 @@ mod api; +#[cfg(feature = "_api")] mod form; mod impls; mod video; From 02b5509b6ed2d7598892072b69bebdeaa6237fbe Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:19:45 -0800 Subject: [PATCH 07/36] image-types: cargo b -F image-types --no-default-features --- async-openai/src/types/images/mod.rs | 2 + async-openai/src/types/images/stream.rs | 68 ++++++++++++------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/async-openai/src/types/images/mod.rs b/async-openai/src/types/images/mod.rs index 3afe4dd1..317df2c6 100644 --- a/async-openai/src/types/images/mod.rs +++ b/async-openai/src/types/images/mod.rs @@ -1,6 +1,8 @@ +#[cfg(feature = "_api")] mod form; mod image; mod impls; +#[cfg(feature = "_api")] mod sdk; mod stream; diff --git a/async-openai/src/types/images/stream.rs b/async-openai/src/types/images/stream.rs index 749dd46d..9f07d991 100644 --- a/async-openai/src/types/images/stream.rs +++ b/async-openai/src/types/images/stream.rs @@ -1,12 +1,7 @@ -use std::pin::Pin; - -use futures::Stream; use serde::{Deserialize, Serialize}; -use crate::{ - error::OpenAIError, - traits::EventType, - types::images::{ImageBackground, ImageGenUsage, ImageOutputFormat, ImageQuality, ImageSize}, +use crate::types::images::{ + ImageBackground, ImageGenUsage, ImageOutputFormat, ImageQuality, ImageSize, }; /// Emitted when a partial image is available during image generation streaming. @@ -58,9 +53,6 @@ pub enum ImageGenStreamEvent { Completed(ImageGenCompletedEvent), } -pub type ImageGenStream = - Pin> + Send>>; - /// Emitted when a partial image is available during image editing streaming. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ImageEditPartialImageEvent { @@ -99,9 +91,6 @@ pub struct ImageEditCompletedEvent { pub usage: ImageGenUsage, } -pub type ImageEditStream = - Pin> + Send>>; - #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type")] pub enum ImageEditStreamEvent { @@ -113,19 +102,39 @@ pub enum ImageEditStreamEvent { Completed(ImageEditCompletedEvent), } -impl EventType for ImageGenPartialImageEvent { - fn event_type(&self) -> &'static str { - "image_generation.partial_image" - } +#[cfg(feature = "_api")] +pub type ImageEditStream = std::pin::Pin< + Box> + Send>, +>; + +#[cfg(feature = "_api")] +pub type ImageGenStream = std::pin::Pin< + Box> + Send>, +>; + +#[cfg(feature = "_api")] +macro_rules! impl_event_type { + ($($ty:ty => $event_type:expr),* $(,)?) => { + $( + impl crate::traits::EventType for $ty { + fn event_type(&self) -> &'static str { + $event_type + } + } + )* + }; } -impl EventType for ImageGenCompletedEvent { - fn event_type(&self) -> &'static str { - "image_generation.completed" - } +#[cfg(feature = "_api")] +impl_event_type! { + ImageGenPartialImageEvent => "image_generation.partial_image", + ImageGenCompletedEvent => "image_generation.completed", + ImageEditPartialImageEvent => "image_edit.partial_image", + ImageEditCompletedEvent => "image_edit.completed", } -impl EventType for ImageGenStreamEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for ImageGenStreamEvent { fn event_type(&self) -> &'static str { match self { ImageGenStreamEvent::PartialImage(event) => event.event_type(), @@ -134,19 +143,8 @@ impl EventType for ImageGenStreamEvent { } } -impl EventType for ImageEditPartialImageEvent { - fn event_type(&self) -> &'static str { - "image_edit.partial_image" - } -} - -impl EventType for ImageEditCompletedEvent { - fn event_type(&self) -> &'static str { - "image_edit.completed" - } -} - -impl EventType for ImageEditStreamEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for ImageEditStreamEvent { fn event_type(&self) -> &'static str { match self { ImageEditStreamEvent::PartialImage(event) => event.event_type(), From 902e296f385a3bd2d3de75c1cfc3fc93aa6eee23 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:27:14 -0800 Subject: [PATCH 08/36] embedding-types: cargo b -F embedding-types --no-default-features --- async-openai/src/types/embeddings/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/async-openai/src/types/embeddings/mod.rs b/async-openai/src/types/embeddings/mod.rs index e3173eb2..ad84133d 100644 --- a/async-openai/src/types/embeddings/mod.rs +++ b/async-openai/src/types/embeddings/mod.rs @@ -1,4 +1,5 @@ mod embedding; +#[cfg(feature = "_api")] mod impls; pub use embedding::*; From 5c27e75932cd5ab5763396ea49536d0b4bbf0558 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:37:13 -0800 Subject: [PATCH 09/36] file-types: cargo b -F file-types --no-default-features --- async-openai/src/types/files/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/async-openai/src/types/files/mod.rs b/async-openai/src/types/files/mod.rs index f2e99112..14a5a5ff 100644 --- a/async-openai/src/types/files/mod.rs +++ b/async-openai/src/types/files/mod.rs @@ -1,5 +1,6 @@ mod api; mod file; +#[cfg(feature = "_api")] mod form; mod impls; From 1c6ecf87628122065622431c7407b02659ce2118 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:39:06 -0800 Subject: [PATCH 10/36] upload-types: cargo b -F upload-types --no-default-features --- async-openai/src/types/uploads/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/async-openai/src/types/uploads/mod.rs b/async-openai/src/types/uploads/mod.rs index 879d91d8..c2a8fbe7 100644 --- a/async-openai/src/types/uploads/mod.rs +++ b/async-openai/src/types/uploads/mod.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "_api")] mod form; mod upload; From e2b7c474e88b57919967d8fea07db41197268a52 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 15:48:45 -0800 Subject: [PATCH 11/36] container-types: cargo b -F container-types --no-default-features --- async-openai/src/types/containers/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/async-openai/src/types/containers/mod.rs b/async-openai/src/types/containers/mod.rs index 50ff2afb..080c3535 100644 --- a/async-openai/src/types/containers/mod.rs +++ b/async-openai/src/types/containers/mod.rs @@ -1,5 +1,6 @@ mod api; mod container; +#[cfg(feature = "_api")] mod form; pub use api::*; From d1875ffb5ff71882b02756f07723a6691e91452c Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:01:01 -0800 Subject: [PATCH 12/36] realtime-types: cargo b -F realtime-types --no-default-features --- .../src/types/realtime/client_event.rs | 75 +++++++++++-------- async-openai/src/types/realtime/mod.rs | 1 + .../src/types/realtime/server_event.rs | 9 ++- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/async-openai/src/types/realtime/client_event.rs b/async-openai/src/types/realtime/client_event.rs index b9089f7b..2a0e4276 100644 --- a/async-openai/src/types/realtime/client_event.rs +++ b/async-openai/src/types/realtime/client_event.rs @@ -1,7 +1,5 @@ use serde::{Deserialize, Serialize}; -use tokio_tungstenite::tungstenite::Message; -use crate::traits::EventType; use crate::types::realtime::{RealtimeConversationItem, RealtimeResponseCreateParams, Session}; #[derive(Debug, Serialize, Deserialize, Clone)] @@ -239,22 +237,6 @@ impl From<&RealtimeClientEvent> for String { } } -impl From for Message { - fn from(value: RealtimeClientEvent) -> Self { - Message::Text(String::from(&value).into()) - } -} - -macro_rules! message_from_event { - ($from_typ:ty, $evt_typ:ty) => { - impl From<$from_typ> for Message { - fn from(value: $from_typ) -> Self { - Self::from(<$evt_typ>::from(value)) - } - } - }; -} - macro_rules! event_from { ($from_typ:ty, $evt_typ:ty, $variant:ident) => { impl From<$from_typ> for $evt_typ { @@ -321,58 +303,87 @@ event_from!( OutputAudioBufferClear ); +impl From for RealtimeClientEventConversationItemCreate { + fn from(value: RealtimeConversationItem) -> Self { + Self { + event_id: None, + previous_item_id: None, + item: value, + } + } +} + +#[cfg(feature = "_api")] +impl From for tokio_tungstenite::tungstenite::Message { + fn from(value: RealtimeClientEvent) -> Self { + tokio_tungstenite::tungstenite::Message::Text(String::from(&value).into()) + } +} + +#[cfg(feature = "_api")] +macro_rules! message_from_event { + ($from_typ:ty, $evt_typ:ty) => { + impl From<$from_typ> for tokio_tungstenite::tungstenite::Message { + fn from(value: $from_typ) -> Self { + Self::from(<$evt_typ>::from(value)) + } + } + }; +} + +#[cfg(feature = "_api")] message_from_event!(RealtimeClientEventSessionUpdate, RealtimeClientEvent); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventInputAudioBufferAppend, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventInputAudioBufferCommit, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventInputAudioBufferClear, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventConversationItemCreate, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventConversationItemTruncate, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventConversationItemDelete, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventConversationItemRetrieve, RealtimeClientEvent ); +#[cfg(feature = "_api")] message_from_event!(RealtimeClientEventResponseCreate, RealtimeClientEvent); +#[cfg(feature = "_api")] message_from_event!(RealtimeClientEventResponseCancel, RealtimeClientEvent); +#[cfg(feature = "_api")] message_from_event!( RealtimeClientEventOutputAudioBufferClear, RealtimeClientEvent ); -impl From for RealtimeClientEventConversationItemCreate { - fn from(value: RealtimeConversationItem) -> Self { - Self { - event_id: None, - previous_item_id: None, - item: value, - } - } -} - // Implement EventType trait for all event types in this file - +#[cfg(feature = "_api")] macro_rules! impl_event_type { ($($ty:ty => $event_type:expr),* $(,)?) => { $( - impl EventType for $ty { + impl crate::traits::EventType for $ty { fn event_type(&self) -> &'static str { $event_type } @@ -381,6 +392,7 @@ macro_rules! impl_event_type { }; } +#[cfg(feature = "_api")] impl_event_type! { RealtimeClientEventSessionUpdate => "session.update", RealtimeClientEventInputAudioBufferAppend => "input_audio_buffer.append", @@ -395,7 +407,8 @@ impl_event_type! { RealtimeClientEventOutputAudioBufferClear => "output_audio_buffer.clear", } -impl EventType for RealtimeClientEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for RealtimeClientEvent { fn event_type(&self) -> &'static str { match self { RealtimeClientEvent::SessionUpdate(e) => e.event_type(), diff --git a/async-openai/src/types/realtime/mod.rs b/async-openai/src/types/realtime/mod.rs index 0f9c3e18..1def8978 100644 --- a/async-openai/src/types/realtime/mod.rs +++ b/async-openai/src/types/realtime/mod.rs @@ -2,6 +2,7 @@ mod api; mod client_event; mod conversation_item; mod error; +#[cfg(feature = "_api")] mod form; mod response; mod server_event; diff --git a/async-openai/src/types/realtime/server_event.rs b/async-openai/src/types/realtime/server_event.rs index 1c6c3fab..3df1a4df 100644 --- a/async-openai/src/types/realtime/server_event.rs +++ b/async-openai/src/types/realtime/server_event.rs @@ -1,6 +1,5 @@ use serde::{Deserialize, Serialize}; -use crate::traits::EventType; use crate::types::realtime::{LogProbProperties, TranscriptionUsage}; use super::{ @@ -807,11 +806,11 @@ pub enum RealtimeServerEvent { } // Implement EventType trait for all event types in this file - +#[cfg(feature = "_api")] macro_rules! impl_event_type { ($($ty:ty => $event_type:expr),* $(,)?) => { $( - impl EventType for $ty { + impl crate::traits::EventType for $ty { fn event_type(&self) -> &'static str { $event_type } @@ -820,6 +819,7 @@ macro_rules! impl_event_type { }; } +#[cfg(feature = "_api")] impl_event_type! { RealtimeServerEventError => "error", RealtimeServerEventSessionCreated => "session.created", @@ -866,7 +866,8 @@ impl_event_type! { RealtimeServerEventRateLimitsUpdated => "rate_limits.updated", } -impl EventType for RealtimeServerEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for RealtimeServerEvent { fn event_type(&self) -> &'static str { match self { RealtimeServerEvent::Error(e) => e.event_type(), From bfbf1fd888aea7a188344895e3be71954ab7b511 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:11:23 -0800 Subject: [PATCH 13/36] assistant-types: cargo b -F assistant-types --no-default-features --- async-openai/src/types/assistants/stream.rs | 71 ++++++++++----------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/async-openai/src/types/assistants/stream.rs b/async-openai/src/types/assistants/stream.rs index cbf39a86..f32fe0f5 100644 --- a/async-openai/src/types/assistants/stream.rs +++ b/async-openai/src/types/assistants/stream.rs @@ -1,10 +1,6 @@ -use std::pin::Pin; - -use futures::Stream; use serde::Deserialize; -use crate::error::{map_deserialization_error, ApiError, OpenAIError, StreamError}; -use crate::traits::EventType; +use crate::error::ApiError; use crate::types::assistants::{ MessageDeltaObject, MessageObject, RunObject, RunStepDeltaObject, RunStepObject, ThreadObject, }; @@ -31,7 +27,6 @@ use crate::types::assistants::{ #[derive(Debug, Deserialize, Clone)] #[serde(tag = "event", content = "data")] -#[non_exhaustive] pub enum AssistantStreamEvent { /// Occurs when a new [thread](https://platform.openai.com/docs/api-reference/threads/object) is created. #[serde(rename = "thread.created")] @@ -110,111 +105,115 @@ pub enum AssistantStreamEvent { Done(String), } -pub type AssistantEventStream = - Pin> + Send>>; +#[cfg(feature = "_api")] +pub type AssistantEventStream = std::pin::Pin< + Box> + Send>, +>; +#[cfg(feature = "_api")] impl TryFrom for AssistantStreamEvent { - type Error = OpenAIError; + type Error = crate::error::OpenAIError; fn try_from(value: eventsource_stream::Event) -> Result { match value.event.as_str() { "thread.created" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadCreated), "thread.run.created" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunCreated), "thread.run.queued" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunQueued), "thread.run.in_progress" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunInProgress), "thread.run.requires_action" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunRequiresAction), "thread.run.completed" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunCompleted), "thread.run.incomplete" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunIncomplete), "thread.run.failed" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunFailed), "thread.run.cancelling" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunCancelling), "thread.run.cancelled" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunCancelled), "thread.run.expired" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunExpired), "thread.run.step.created" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepCreated), "thread.run.step.in_progress" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepInProgress) } "thread.run.step.delta" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepDelta) } "thread.run.step.completed" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepCompleted) } "thread.run.step.failed" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepFailed), "thread.run.step.cancelled" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepCancelled) } "thread.run.step.expired" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadRunStepExpired), "thread.message.created" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadMessageCreated), "thread.message.in_progress" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadMessageInProgress) } "thread.message.delta" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadMessageDelta) } "thread.message.completed" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadMessageCompleted) } "thread.message.incomplete" => { serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ThreadMessageIncomplete) } "error" => serde_json::from_str::(value.data.as_str()) - .map_err(|e| map_deserialization_error(e, value.data.as_bytes())) + .map_err(|e| crate::error::map_deserialization_error(e, value.data.as_bytes())) .map(AssistantStreamEvent::ErrorEvent), "done" => Ok(AssistantStreamEvent::Done(value.data)), - _ => Err(OpenAIError::StreamError(Box::new( - StreamError::UnknownEvent(value), + _ => Err(crate::error::OpenAIError::StreamError(Box::new( + crate::error::StreamError::UnknownEvent(value), ))), } } } -impl EventType for AssistantStreamEvent { +#[cfg(feature = "_api")] +impl crate::traits::EventType for AssistantStreamEvent { fn event_type(&self) -> &'static str { match self { AssistantStreamEvent::ThreadCreated(_) => "thread.created", From 18d086e5d76083c0596633b7a7bac0b1e25f40e7 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:14:43 -0800 Subject: [PATCH 14/36] administration-types: cargo b -F administration-types --no-default-features --- async-openai/src/types/admin/api_keys/api.rs | 2 +- async-openai/src/types/admin/api_keys/api_keys_.rs | 2 +- async-openai/src/types/admin/groups/api.rs | 2 +- async-openai/src/types/admin/groups/groups_.rs | 2 +- async-openai/src/types/admin/invites/api.rs | 2 +- async-openai/src/types/admin/invites/invites_.rs | 2 +- async-openai/src/types/admin/project_users/api.rs | 2 +- async-openai/src/types/admin/project_users/project_users_.rs | 2 +- async-openai/src/types/admin/projects/api.rs | 2 +- async-openai/src/types/admin/projects/projects_.rs | 2 +- async-openai/src/types/admin/roles/api.rs | 2 +- async-openai/src/types/admin/roles/roles_.rs | 2 +- async-openai/src/types/admin/usage/api.rs | 2 +- async-openai/src/types/admin/users/api.rs | 2 +- async-openai/src/types/admin/users/users_.rs | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/async-openai/src/types/admin/api_keys/api.rs b/async-openai/src/types/admin/api_keys/api.rs index bc6f9c80..1ec38c15 100644 --- a/async-openai/src/types/admin/api_keys/api.rs +++ b/async-openai/src/types/admin/api_keys/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/api_keys/api_keys_.rs b/async-openai/src/types/admin/api_keys/api_keys_.rs index 0be8723f..2eee47be 100644 --- a/async-openai/src/types/admin/api_keys/api_keys_.rs +++ b/async-openai/src/types/admin/api_keys/api_keys_.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/groups/api.rs b/async-openai/src/types/admin/groups/api.rs index cdef7850..d2579851 100644 --- a/async-openai/src/types/admin/groups/api.rs +++ b/async-openai/src/types/admin/groups/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/groups/groups_.rs b/async-openai/src/types/admin/groups/groups_.rs index 33dbc66e..fa759084 100644 --- a/async-openai/src/types/admin/groups/groups_.rs +++ b/async-openai/src/types/admin/groups/groups_.rs @@ -1,6 +1,6 @@ +use crate::error::OpenAIError; use crate::types::admin::roles::Role; use crate::types::admin::users::User; -use crate::types::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/invites/api.rs b/async-openai/src/types/admin/invites/api.rs index fb8f0845..aa36efc9 100644 --- a/async-openai/src/types/admin/invites/api.rs +++ b/async-openai/src/types/admin/invites/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::Serialize; diff --git a/async-openai/src/types/admin/invites/invites_.rs b/async-openai/src/types/admin/invites/invites_.rs index 934ca14a..0af71ef9 100644 --- a/async-openai/src/types/admin/invites/invites_.rs +++ b/async-openai/src/types/admin/invites/invites_.rs @@ -1,5 +1,5 @@ +use crate::error::OpenAIError; use crate::types::admin::roles::OrganizationRole; -use crate::types::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/project_users/api.rs b/async-openai/src/types/admin/project_users/api.rs index c306b2c8..cb0df2d9 100644 --- a/async-openai/src/types/admin/project_users/api.rs +++ b/async-openai/src/types/admin/project_users/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::Serialize; diff --git a/async-openai/src/types/admin/project_users/project_users_.rs b/async-openai/src/types/admin/project_users/project_users_.rs index 51a88199..5ab9eefe 100644 --- a/async-openai/src/types/admin/project_users/project_users_.rs +++ b/async-openai/src/types/admin/project_users/project_users_.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/projects/api.rs b/async-openai/src/types/admin/projects/api.rs index fbf7c16a..c1102796 100644 --- a/async-openai/src/types/admin/projects/api.rs +++ b/async-openai/src/types/admin/projects/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::Serialize; diff --git a/async-openai/src/types/admin/projects/projects_.rs b/async-openai/src/types/admin/projects/projects_.rs index ae2b5831..8e4be725 100644 --- a/async-openai/src/types/admin/projects/projects_.rs +++ b/async-openai/src/types/admin/projects/projects_.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/roles/api.rs b/async-openai/src/types/admin/roles/api.rs index d0d9f616..e427e6d2 100644 --- a/async-openai/src/types/admin/roles/api.rs +++ b/async-openai/src/types/admin/roles/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/roles/roles_.rs b/async-openai/src/types/admin/roles/roles_.rs index c7176b3b..b6c7af21 100644 --- a/async-openai/src/types/admin/roles/roles_.rs +++ b/async-openai/src/types/admin/roles/roles_.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/usage/api.rs b/async-openai/src/types/admin/usage/api.rs index efef043b..40e60250 100644 --- a/async-openai/src/types/admin/usage/api.rs +++ b/async-openai/src/types/admin/usage/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; diff --git a/async-openai/src/types/admin/users/api.rs b/async-openai/src/types/admin/users/api.rs index 4e4c7728..332a770b 100644 --- a/async-openai/src/types/admin/users/api.rs +++ b/async-openai/src/types/admin/users/api.rs @@ -1,4 +1,4 @@ -use crate::types::OpenAIError; +use crate::error::OpenAIError; use derive_builder::Builder; use serde::Serialize; diff --git a/async-openai/src/types/admin/users/users_.rs b/async-openai/src/types/admin/users/users_.rs index d735103e..7094c414 100644 --- a/async-openai/src/types/admin/users/users_.rs +++ b/async-openai/src/types/admin/users/users_.rs @@ -1,6 +1,6 @@ +use crate::error::OpenAIError; use crate::types::admin::roles::OrganizationRole; use crate::types::admin::roles::Role; -use crate::types::OpenAIError; use derive_builder::Builder; use serde::{Deserialize, Serialize}; From 73bc3e01b1000205e4b65088ca9d22d9fe9e151d Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:21:01 -0800 Subject: [PATCH 15/36] completion-types and chat-completino-types --- async-openai/src/types/chat/chat_.rs | 9 +++++---- async-openai/src/types/completions/completion.rs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/async-openai/src/types/chat/chat_.rs b/async-openai/src/types/chat/chat_.rs index fe18a83a..4fc7128c 100644 --- a/async-openai/src/types/chat/chat_.rs +++ b/async-openai/src/types/chat/chat_.rs @@ -1,7 +1,6 @@ -use std::{collections::HashMap, pin::Pin}; +use std::collections::HashMap; use derive_builder::Builder; -use futures::Stream; use serde::{Deserialize, Serialize}; use crate::{ @@ -1100,8 +1099,10 @@ pub struct CreateChatCompletionResponse { } /// Parsed server side events stream until an \[DONE\] is received from server. -pub type ChatCompletionResponseStream = - Pin> + Send>>; +#[cfg(feature = "_api")] +pub type ChatCompletionResponseStream = std::pin::Pin< + Box> + Send>, +>; #[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct FunctionCallStream { diff --git a/async-openai/src/types/completions/completion.rs b/async-openai/src/types/completions/completion.rs index d3c22d88..178b447a 100644 --- a/async-openai/src/types/completions/completion.rs +++ b/async-openai/src/types/completions/completion.rs @@ -1,7 +1,6 @@ -use std::{collections::HashMap, pin::Pin}; +use std::collections::HashMap; use derive_builder::Builder; -use futures::Stream; use serde::{Deserialize, Serialize}; use crate::error::OpenAIError; @@ -139,5 +138,7 @@ pub struct CreateCompletionResponse { } /// Parsed server side events stream until an \[DONE\] is received from server. -pub type CompletionResponseStream = - Pin> + Send>>; +#[cfg(feature = "_api")] +pub type CompletionResponseStream = std::pin::Pin< + Box> + Send>, +>; From 59c6c2db5b38519c8f9dc0c637bfdcd0eca6a81a Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:25:04 -0800 Subject: [PATCH 16/36] grader-types --- async-openai/src/types/graders/grader.rs | 3 ++- async-openai/src/types/graders/mod.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/async-openai/src/types/graders/grader.rs b/async-openai/src/types/graders/grader.rs index 88915390..a5fc9527 100644 --- a/async-openai/src/types/graders/grader.rs +++ b/async-openai/src/types/graders/grader.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; -use crate::types::{chat::ReasoningEffort, evals::EvalItem}; +use crate::types::evals::EvalItem; +use crate::types::graders::ReasoningEffort; /// String check operation. #[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq)] diff --git a/async-openai/src/types/graders/mod.rs b/async-openai/src/types/graders/mod.rs index f8d5d1e4..f8c78b08 100644 --- a/async-openai/src/types/graders/mod.rs +++ b/async-openai/src/types/graders/mod.rs @@ -1,3 +1,6 @@ mod grader; pub use grader::*; + +// re export shared types +pub use crate::types::shared::ReasoningEffort; From db18cac74cde5877e7d42ca496d28bd9a96cfedb Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:27:41 -0800 Subject: [PATCH 17/36] shared types with feature flags --- async-openai/src/types/shared/image_input.rs | 2 +- async-openai/src/types/shared/mod.rs | 57 ++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/async-openai/src/types/shared/image_input.rs b/async-openai/src/types/shared/image_input.rs index 7a3e358b..38fd4819 100644 --- a/async-openai/src/types/shared/image_input.rs +++ b/async-openai/src/types/shared/image_input.rs @@ -1,6 +1,6 @@ use crate::types::InputSource; -#[derive(Debug, Default, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq)] pub struct ImageInput { pub source: InputSource, } diff --git a/async-openai/src/types/shared/mod.rs b/async-openai/src/types/shared/mod.rs index 7847a550..76359d8c 100644 --- a/async-openai/src/types/shared/mod.rs +++ b/async-openai/src/types/shared/mod.rs @@ -1,36 +1,93 @@ //! Shared types - these types are use by multiple type modules //! and not exported directly, instead they are re-exported //! by the modules that use them. + +#[cfg(any(feature = "chat-completion-types", feature = "response-types"))] mod completion_tokens_details; +#[cfg(any(feature = "chat-completion-types", feature = "response-types"))] mod custom_grammar_format_param; +#[cfg(any(feature = "response-types", feature = "vectorstore-types"))] mod filter; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] mod function_call; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] mod function_name; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] mod function_object; +#[cfg(any( + feature = "chat-completion-types", + feature = "response-types", + feature = "assistant-types" +))] mod image_detail; +#[cfg(any(feature = "image-types", feature = "video-types"))] mod image_input; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] mod image_url; +#[cfg(any(feature = "audio-types", feature = "realtime-types"))] mod log_prob_properties; +#[cfg(any(feature = "chat-completion-types", feature = "response-types"))] mod prompt_tokens_details; +#[cfg(any( + feature = "chat-completion-types", + feature = "response-types", + feature = "grader-types" +))] mod reasoning_effort; +#[cfg(any( + feature = "chat-completion-types", + feature = "response-types", + feature = "assistant-types" +))] mod response_format; +#[cfg(any(feature = "response-types", feature = "batch-types"))] mod response_usage; +#[cfg(any(feature = "assistant-types", feature = "vectorstore-types"))] mod static_chunking_strategy; +#[cfg(any(feature = "audio-types", feature = "realtime-types"))] mod transcription_usage; +#[cfg(any(feature = "chat-completion-types", feature = "response-types"))] pub use completion_tokens_details::*; +#[cfg(any(feature = "chat-completion-types", feature = "response-types"))] pub use custom_grammar_format_param::*; +#[cfg(any(feature = "response-types", feature = "vectorstore-types"))] pub use filter::*; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] pub use function_call::*; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] pub use function_name::*; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] pub use function_object::*; +#[cfg(any( + feature = "chat-completion-types", + feature = "response-types", + feature = "assistant-types" +))] pub use image_detail::*; +#[cfg(any(feature = "image-types", feature = "video-types"))] pub use image_input::*; +#[cfg(any(feature = "chat-completion-types", feature = "assistant-types"))] pub use image_url::*; +#[cfg(any(feature = "audio-types", feature = "realtime-types"))] pub use log_prob_properties::*; +#[cfg(any(feature = "chat-completion-types", feature = "response-types"))] pub use prompt_tokens_details::*; +#[cfg(any( + feature = "chat-completion-types", + feature = "response-types", + feature = "grader-types" +))] pub use reasoning_effort::*; +#[cfg(any( + feature = "chat-completion-types", + feature = "response-types", + feature = "assistant-types" +))] pub use response_format::*; +#[cfg(any(feature = "response-types", feature = "batch-types"))] pub use response_usage::*; +#[cfg(any(feature = "assistant-types", feature = "vectorstore-types"))] pub use static_chunking_strategy::*; +#[cfg(any(feature = "audio-types", feature = "realtime-types"))] pub use transcription_usage::*; From 1240a8dfaf450d97212c75d3150d739f5171e2ae Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:32:50 -0800 Subject: [PATCH 18/36] src/types works with all type feature flags --- async-openai/src/types/impls.rs | 100 +++++++++++--- async-openai/src/types/input_source.rs | 14 ++ .../src/types/{common.rs => metadata.rs} | 14 +- async-openai/src/types/mod.rs | 123 ++++++++++++++++-- 4 files changed, 210 insertions(+), 41 deletions(-) create mode 100644 async-openai/src/types/input_source.rs rename async-openai/src/types/{common.rs => metadata.rs} (61%) diff --git a/async-openai/src/types/impls.rs b/async-openai/src/types/impls.rs index 9289d972..7c9bf446 100644 --- a/async-openai/src/types/impls.rs +++ b/async-openai/src/types/impls.rs @@ -1,16 +1,21 @@ -use std::path::{Path, PathBuf}; - -use crate::types::{ - audio::AudioInput, - chat::{Prompt, StopConfiguration}, - embeddings::EmbeddingInput, - files::FileInput, - moderations::ModerationInput, - shared::ImageInput, - InputSource, -}; - -use bytes::Bytes; +#[cfg(feature = "audio-types")] +use crate::types::audio::AudioInput; +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] +use crate::types::chat::{Prompt, StopConfiguration}; +#[cfg(feature = "embedding-types")] +use crate::types::embeddings::EmbeddingInput; +#[cfg(feature = "file-types")] +use crate::types::files::FileInput; +#[cfg(feature = "moderation-types")] +use crate::types::moderations::ModerationInput; +#[cfg(feature = "image-types")] +use crate::types::shared::ImageInput; +#[cfg(any( + feature = "audio-types", + feature = "file-types", + feature = "image-types" +))] +use crate::types::InputSource; /// for `impl_from!(T, Enum)`, implements /// - `From` @@ -20,6 +25,12 @@ use bytes::Bytes; /// - `From<&[T; N]>` /// /// for `T: Into` and `Enum` having variants `String(String)` and `StringArray(Vec)` +#[cfg(any( + feature = "chat-completion-types", + feature = "completion-types", + feature = "embedding-types", + feature = "moderation-types" +))] macro_rules! impl_from { ($from_typ:ty, $to_typ:ty) => { // From -> String variant @@ -60,26 +71,44 @@ macro_rules! impl_from { } // From String "family" to Prompt +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from!(&str, Prompt); +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from!(String, Prompt); +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from!(&String, Prompt); // From String "family" to StopConfiguration +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from!(&str, StopConfiguration); +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from!(String, StopConfiguration); +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from!(&String, StopConfiguration); // From String "family" to ModerationInput +#[cfg(feature = "moderation-types")] impl_from!(&str, ModerationInput); +#[cfg(feature = "moderation-types")] impl_from!(String, ModerationInput); +#[cfg(feature = "moderation-types")] impl_from!(&String, ModerationInput); // From String "family" to EmbeddingInput +#[cfg(feature = "embedding-types")] impl_from!(&str, EmbeddingInput); +#[cfg(feature = "embedding-types")] impl_from!(String, EmbeddingInput); +#[cfg(feature = "embedding-types")] impl_from!(&String, EmbeddingInput); /// for `impl_default!(Enum)`, implements `Default` for `Enum` as `Enum::String("")` where `Enum` has `String` variant +#[cfg(any( + feature = "chat-completion-types", + feature = "completion-types", + feature = "embedding-types", + feature = "moderation-types" +))] macro_rules! impl_default { ($for_typ:ty) => { impl Default for $for_typ { @@ -90,14 +119,31 @@ macro_rules! impl_default { }; } +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_default!(Prompt); +#[cfg(feature = "moderation-types")] impl_default!(ModerationInput); +#[cfg(feature = "embedding-types")] impl_default!(EmbeddingInput); +#[cfg(any( + feature = "audio-types", + feature = "file-types", + feature = "image-types" +))] impl Default for InputSource { fn default() -> Self { InputSource::Path { - path: PathBuf::new(), + path: std::path::PathBuf::new(), + } + } +} + +#[cfg(any(feature = "image-types", feature = "video-types"))] +impl Default for ImageInput { + fn default() -> Self { + Self { + source: InputSource::default(), } } } @@ -110,10 +156,15 @@ impl Default for InputSource { /// ``` /// implements methods `from_bytes` and `from_vec_u8`, /// and `From

` for `P: AsRef` +#[cfg(any( + feature = "audio-types", + feature = "file-types", + feature = "image-types" +))] macro_rules! impl_input { ($for_typ:ty) => { impl $for_typ { - pub fn from_bytes(filename: String, bytes: Bytes) -> Self { + pub fn from_bytes(filename: String, bytes: bytes::Bytes) -> Self { Self { source: InputSource::Bytes { filename, bytes }, } @@ -126,7 +177,7 @@ macro_rules! impl_input { } } - impl> From

for $for_typ { + impl> From

for $for_typ { fn from(path: P) -> Self { let path_buf = path.as_ref().to_path_buf(); Self { @@ -137,10 +188,18 @@ macro_rules! impl_input { }; } +#[cfg(feature = "audio-types")] impl_input!(AudioInput); +#[cfg(feature = "file-types")] impl_input!(FileInput); +#[cfg(feature = "image-types")] impl_input!(ImageInput); +#[cfg(any( + feature = "chat-completion-types", + feature = "completion-types", + feature = "embedding-types" +))] macro_rules! impl_from_for_integer_array { ($from_typ:ty, $to_typ:ty) => { impl From<[$from_typ; N]> for $to_typ { @@ -169,9 +228,16 @@ macro_rules! impl_from_for_integer_array { }; } +#[cfg(feature = "embedding-types")] impl_from_for_integer_array!(u32, EmbeddingInput); +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from_for_integer_array!(u32, Prompt); +#[cfg(any( + feature = "chat-completion-types", + feature = "completion-types", + feature = "embedding-types" +))] macro_rules! impl_from_for_array_of_integer_array { ($from_typ:ty, $to_typ:ty) => { impl From>> for $to_typ { @@ -266,5 +332,7 @@ macro_rules! impl_from_for_array_of_integer_array { }; } +#[cfg(feature = "embedding-types")] impl_from_for_array_of_integer_array!(u32, EmbeddingInput); +#[cfg(any(feature = "chat-completion-types", feature = "completion-types"))] impl_from_for_array_of_integer_array!(u32, Prompt); diff --git a/async-openai/src/types/input_source.rs b/async-openai/src/types/input_source.rs new file mode 100644 index 00000000..44704056 --- /dev/null +++ b/async-openai/src/types/input_source.rs @@ -0,0 +1,14 @@ +#[derive(Debug, Clone, PartialEq)] +pub enum InputSource { + Path { + path: std::path::PathBuf, + }, + Bytes { + filename: String, + bytes: bytes::Bytes, + }, + VecU8 { + filename: String, + vec: Vec, + }, +} diff --git a/async-openai/src/types/common.rs b/async-openai/src/types/metadata.rs similarity index 61% rename from async-openai/src/types/common.rs rename to async-openai/src/types/metadata.rs index b8170673..63169da4 100644 --- a/async-openai/src/types/common.rs +++ b/async-openai/src/types/metadata.rs @@ -1,22 +1,10 @@ -use std::path::PathBuf; - -use bytes::Bytes; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq)] -pub enum InputSource { - Path { path: PathBuf }, - Bytes { filename: String, bytes: Bytes }, - VecU8 { filename: String, vec: Vec }, -} - /// Set of 16 key-value pairs that can be attached to an object. /// This can be useful for storing additional information about the /// object in a structured format, and querying for objects via API /// or the dashboard. Keys are strings with a maximum length of 64 /// characters. Values are strings with a maximum length of 512 /// characters. -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)] +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq, Default)] #[serde(transparent)] pub struct Metadata(serde_json::Value); diff --git a/async-openai/src/types/mod.rs b/async-openai/src/types/mod.rs index 3309d519..550d8d65 100644 --- a/async-openai/src/types/mod.rs +++ b/async-openai/src/types/mod.rs @@ -1,44 +1,143 @@ //! Types used in OpenAI API requests and responses. //! These types are created from component schemas in the [OpenAPI spec](https://github.com/openai/openai-openapi) +#[cfg(feature = "administration-types")] pub mod admin; +#[cfg(feature = "assistant-types")] pub mod assistants; +#[cfg(feature = "audio-types")] pub mod audio; +#[cfg(feature = "batch-types")] pub mod batches; +#[cfg(feature = "chat-completion-types")] pub mod chat; +#[cfg(feature = "chatkit-types")] pub mod chatkit; -mod common; +#[cfg(feature = "completion-types")] pub mod completions; +#[cfg(feature = "container-types")] pub mod containers; +#[cfg(feature = "embedding-types")] pub mod embeddings; +#[cfg(feature = "eval-types")] pub mod evals; +#[cfg(feature = "file-types")] pub mod files; +#[cfg(feature = "finetuning-types")] pub mod finetuning; +#[cfg(feature = "grader-types")] pub mod graders; +#[cfg(feature = "image-types")] pub mod images; +#[cfg(any( + feature = "audio-types", + feature = "file-types", + feature = "upload-types", + feature = "image-types", + feature = "video-types", + feature = "container-types", + feature = "chat-completion-types", + feature = "realtime-types" +))] +mod input_source; +#[cfg(any(feature = "response-types", feature = "realtime-types"))] pub mod mcp; +#[cfg(any( + feature = "response-types", + feature = "audio-types", + feature = "video-types", + feature = "image-types", + feature = "batch-types", + feature = "file-types", + feature = "upload-types", + feature = "vectorstore-types", + feature = "container-types", + feature = "chat-completion-types", + feature = "realtime-types" +))] +mod metadata; +#[cfg(feature = "model-types")] pub mod models; +#[cfg(feature = "moderation-types")] pub mod moderations; -#[cfg_attr(docsrs, doc(cfg(feature = "realtime")))] -#[cfg(feature = "realtime")] +#[cfg_attr(docsrs, doc(cfg(feature = "realtime-types")))] +#[cfg(feature = "realtime-types")] pub mod realtime; +#[cfg(feature = "response-types")] pub mod responses; +#[cfg(any( + feature = "response-types", + feature = "video-types", + feature = "vectorstore-types", + feature = "chat-completion-types", + feature = "assistant-types", + feature = "batch-types", + feature = "audio-types", + feature = "realtime-types", + feature = "image-types" +))] mod shared; +#[cfg(feature = "upload-types")] pub mod uploads; +#[cfg(feature = "vectorstore-types")] pub mod vectorstores; +#[cfg(feature = "video-types")] pub mod videos; -#[cfg_attr(docsrs, doc(cfg(feature = "webhook")))] -#[cfg(feature = "webhook")] +#[cfg_attr(docsrs, doc(cfg(feature = "webhook-types")))] +#[cfg(feature = "webhook-types")] pub mod webhooks; -pub use common::*; +#[cfg(any( + feature = "audio-types", + feature = "file-types", + feature = "upload-types", + feature = "image-types", + feature = "video-types", + feature = "container-types", + feature = "chat-completion-types", + feature = "realtime-types" +))] +pub use input_source::*; -mod impls; -use derive_builder::UninitializedFieldError; +#[cfg(any( + feature = "audio-types", + feature = "batch-types", + feature = "file-types", + feature = "upload-types", + feature = "image-types", + feature = "video-types", + feature = "vectorstore-types", + feature = "container-types", + feature = "response-types", + feature = "chat-completion-types", + feature = "realtime-types" +))] +pub use metadata::*; -use crate::error::OpenAIError; +#[cfg(any( + feature = "audio-types", + feature = "file-types", + feature = "image-types", + feature = "chat-completion-types", + feature = "completion-types", + feature = "embedding-types", + feature = "moderation-types" +))] +mod impls; -impl From for OpenAIError { - fn from(value: UninitializedFieldError) -> Self { - OpenAIError::InvalidArgument(value.to_string()) +#[cfg(any( + feature = "response-types", + feature = "audio-types", + feature = "file-types", + feature = "image-types", + feature = "chat-completion-types", + feature = "completion-types", + feature = "embedding-types", + feature = "moderation-types", + feature = "administration-types", + feature = "_api" +))] +impl From for crate::error::OpenAIError { + fn from(value: derive_builder::UninitializedFieldError) -> Self { + crate::error::OpenAIError::InvalidArgument(value.to_string()) } } From 917eb8e4c708cba8e0c2639a74aa00c8b7a747d8 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 16:59:32 -0800 Subject: [PATCH 19/36] add byot to realtime apis --- async-openai/src/realtime.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/async-openai/src/realtime.rs b/async-openai/src/realtime.rs index e3cbe53a..8746ecd3 100644 --- a/async-openai/src/realtime.rs +++ b/async-openai/src/realtime.rs @@ -55,6 +55,7 @@ impl<'c, C: Config> Realtime<'c, C> { /// Accept an incoming SIP call and configure the realtime session that will /// handle the call. + #[crate::byot(T0 = std::fmt::Display, T1 = serde::Serialize, R = serde::de::DeserializeOwned)] pub async fn accept_call( &self, call_id: &str, @@ -70,6 +71,7 @@ impl<'c, C: Config> Realtime<'c, C> { } /// End an active Realtime API call, whether it was initiated over SIP or WebRTC. + #[crate::byot(T0 = std::fmt::Display, R = serde::de::DeserializeOwned)] pub async fn hangup_call(&self, call_id: &str) -> Result<(), OpenAIError> { self.client .post( @@ -81,6 +83,7 @@ impl<'c, C: Config> Realtime<'c, C> { } /// Transfer a SIP call to a new destination using the Realtime API. + #[crate::byot(T0 = std::fmt::Display, T1 = serde::Serialize, R = serde::de::DeserializeOwned)] pub async fn refer_call( &self, call_id: &str, @@ -96,21 +99,23 @@ impl<'c, C: Config> Realtime<'c, C> { } /// Decline an incoming SIP call handled by the Realtime API. + #[crate::byot(T0 = std::fmt::Display, T1 = serde::Serialize, R = serde::de::DeserializeOwned)] pub async fn reject_call( &self, call_id: &str, - request: Option, + request: RealtimeCallRejectRequest, ) -> Result<(), OpenAIError> { self.client .post( &format!("/realtime/calls/{}/reject", call_id), - request.unwrap_or_default(), + request, &self.request_options, ) .await } /// Create a Realtime client secret with an associated session configuration. + #[crate::byot(T0 = serde::Serialize, R = serde::de::DeserializeOwned)] pub async fn create_client_secret( &self, request: RealtimeCreateClientSecretRequest, From c882490fa28fbb1b1b238220ee23dbd6c8841ade Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:00:56 -0800 Subject: [PATCH 20/36] feature flags added to client.rs --- async-openai/src/client.rs | 84 ++++++++++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/async-openai/src/client.rs b/async-openai/src/client.rs index 1e0e3682..2cd92931 100644 --- a/async-openai/src/client.rs +++ b/async-openai/src/client.rs @@ -7,20 +7,56 @@ use reqwest_eventsource::{Error as EventSourceError, Event, EventSource, Request use serde::{de::DeserializeOwned, Serialize}; use crate::{ - admin::Admin, - chatkit::Chatkit, config::{Config, OpenAIConfig}, error::{map_deserialization_error, ApiError, OpenAIError, StreamError, WrappedError}, - file::Files, - image::Images, - moderation::Moderations, traits::AsyncTryFrom, - Assistants, Audio, Batches, Chat, Completions, Containers, Conversations, Embeddings, Evals, - FineTuning, Models, RequestOptions, Responses, Threads, Uploads, VectorStores, Videos, + RequestOptions, }; +#[cfg(feature = "administration")] +use crate::admin::Admin; +#[cfg(feature = "chatkit")] +use crate::chatkit::Chatkit; +#[cfg(feature = "file")] +use crate::file::Files; +#[cfg(feature = "image")] +use crate::image::Images; +#[cfg(feature = "moderation")] +use crate::moderation::Moderations; +#[cfg(feature = "assistant")] +use crate::Assistants; +#[cfg(feature = "audio")] +use crate::Audio; +#[cfg(feature = "batch")] +use crate::Batches; +#[cfg(feature = "chat-completion")] +use crate::Chat; +#[cfg(feature = "completions")] +use crate::Completions; +#[cfg(feature = "container")] +use crate::Containers; +#[cfg(feature = "responses")] +use crate::Conversations; +#[cfg(feature = "embedding")] +use crate::Embeddings; +#[cfg(feature = "evals")] +use crate::Evals; +#[cfg(feature = "finetuning")] +use crate::FineTuning; +#[cfg(feature = "model")] +use crate::Models; #[cfg(feature = "realtime")] use crate::Realtime; +#[cfg(feature = "responses")] +use crate::Responses; +#[cfg(feature = "assistant")] +use crate::Threads; +#[cfg(feature = "upload")] +use crate::Uploads; +#[cfg(feature = "vectorstore")] +use crate::VectorStores; +#[cfg(feature = "video")] +use crate::Videos; #[derive(Debug, Clone, Default)] /// Client is a container for config, backoff and http_client @@ -78,112 +114,133 @@ impl Client { // API groups /// To call [Models] group related APIs using this client. + #[cfg(feature = "model")] pub fn models(&self) -> Models<'_, C> { Models::new(self) } /// To call [Completions] group related APIs using this client. + #[cfg(feature = "completions")] pub fn completions(&self) -> Completions<'_, C> { Completions::new(self) } /// To call [Chat] group related APIs using this client. + #[cfg(feature = "chat-completion")] pub fn chat(&self) -> Chat<'_, C> { Chat::new(self) } /// To call [Images] group related APIs using this client. + #[cfg(feature = "image")] pub fn images(&self) -> Images<'_, C> { Images::new(self) } /// To call [Moderations] group related APIs using this client. + #[cfg(feature = "moderation")] pub fn moderations(&self) -> Moderations<'_, C> { Moderations::new(self) } /// To call [Files] group related APIs using this client. + #[cfg(feature = "file")] pub fn files(&self) -> Files<'_, C> { Files::new(self) } /// To call [Uploads] group related APIs using this client. + #[cfg(feature = "upload")] pub fn uploads(&self) -> Uploads<'_, C> { Uploads::new(self) } /// To call [FineTuning] group related APIs using this client. + #[cfg(feature = "finetuning")] pub fn fine_tuning(&self) -> FineTuning<'_, C> { FineTuning::new(self) } /// To call [Embeddings] group related APIs using this client. + #[cfg(feature = "embedding")] pub fn embeddings(&self) -> Embeddings<'_, C> { Embeddings::new(self) } /// To call [Audio] group related APIs using this client. + #[cfg(feature = "audio")] pub fn audio(&self) -> Audio<'_, C> { Audio::new(self) } /// To call [Videos] group related APIs using this client. + #[cfg(feature = "video")] pub fn videos(&self) -> Videos<'_, C> { Videos::new(self) } /// To call [Assistants] group related APIs using this client. + #[cfg(feature = "assistant")] pub fn assistants(&self) -> Assistants<'_, C> { Assistants::new(self) } /// To call [Threads] group related APIs using this client. + #[cfg(feature = "assistant")] pub fn threads(&self) -> Threads<'_, C> { Threads::new(self) } /// To call [VectorStores] group related APIs using this client. + #[cfg(feature = "vectorstore")] pub fn vector_stores(&self) -> VectorStores<'_, C> { VectorStores::new(self) } /// To call [Batches] group related APIs using this client. + #[cfg(feature = "batch")] pub fn batches(&self) -> Batches<'_, C> { Batches::new(self) } /// To call [Admin] group related APIs using this client. /// This groups together admin API keys, invites, users, projects, audit logs, and certificates. + #[cfg(feature = "administration")] pub fn admin(&self) -> Admin<'_, C> { Admin::new(self) } /// To call [Responses] group related APIs using this client. + #[cfg(feature = "responses")] pub fn responses(&self) -> Responses<'_, C> { Responses::new(self) } /// To call [Conversations] group related APIs using this client. + #[cfg(feature = "responses")] pub fn conversations(&self) -> Conversations<'_, C> { Conversations::new(self) } /// To call [Containers] group related APIs using this client. + #[cfg(feature = "container")] pub fn containers(&self) -> Containers<'_, C> { Containers::new(self) } /// To call [Evals] group related APIs using this client. + #[cfg(feature = "evals")] pub fn evals(&self) -> Evals<'_, C> { Evals::new(self) } + #[cfg(feature = "chatkit")] pub fn chatkit(&self) -> Chatkit<'_, C> { Chatkit::new(self) } - #[cfg(feature = "realtime")] /// To call [Realtime] group related APIs using this client. + #[cfg(feature = "realtime")] pub fn realtime(&self) -> Realtime<'_, C> { Realtime::new(self) } @@ -222,6 +279,7 @@ impl Client { } /// Make a GET request to {path} and deserialize the response body + #[allow(unused)] pub(crate) async fn get( &self, path: &str, @@ -240,6 +298,7 @@ impl Client { } /// Make a DELETE request to {path} and deserialize the response body + #[allow(unused)] pub(crate) async fn delete( &self, path: &str, @@ -258,6 +317,7 @@ impl Client { } /// Make a GET request to {path} and return the response body + #[allow(unused)] pub(crate) async fn get_raw( &self, path: &str, @@ -273,6 +333,7 @@ impl Client { } /// Make a POST request to {path} and return the response body + #[allow(unused)] pub(crate) async fn post_raw( &self, path: &str, @@ -293,6 +354,7 @@ impl Client { } /// Make a POST request to {path} and deserialize the response body + #[allow(unused)] pub(crate) async fn post( &self, path: &str, @@ -314,6 +376,7 @@ impl Client { } /// POST a form at {path} and return the response body + #[allow(unused)] pub(crate) async fn post_form_raw( &self, path: &str, @@ -335,6 +398,7 @@ impl Client { } /// POST a form at {path} and deserialize the response body + #[allow(unused)] pub(crate) async fn post_form( &self, path: &str, @@ -356,6 +420,7 @@ impl Client { self.execute(request_maker).await } + #[allow(unused)] pub(crate) async fn post_form_stream( &self, path: &str, @@ -499,6 +564,7 @@ impl Client { } /// Make HTTP POST request to receive SSE + #[allow(unused)] pub(crate) async fn post_stream( &self, path: &str, @@ -518,6 +584,7 @@ impl Client { stream(event_source).await } + #[allow(unused)] pub(crate) async fn post_stream_mapped_raw_events( &self, path: &str, @@ -539,6 +606,7 @@ impl Client { } /// Make HTTP GET request to receive SSE + #[allow(unused)] pub(crate) async fn get_stream( &self, path: &str, From 4668bcb01e6e4e932aa243a2017296d89c6e1996 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:01:09 -0800 Subject: [PATCH 21/36] feature flag for test in config.rs --- async-openai/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/async-openai/src/config.rs b/async-openai/src/config.rs index 58ab9c22..a5e9e955 100644 --- a/async-openai/src/config.rs +++ b/async-openai/src/config.rs @@ -266,7 +266,7 @@ impl Config for AzureConfig { } } -#[cfg(test)] +#[cfg(all(test, feature = "chat-completion"))] mod test { use super::*; use crate::types::chat::{ From 4257cc0e3d25898f3c4e8b3759262c3ee2016b5e Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:01:25 -0800 Subject: [PATCH 22/36] feature flags in util.rs --- async-openai/src/util.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/async-openai/src/util.rs b/async-openai/src/util.rs index eab55caf..56db1ee6 100644 --- a/async-openai/src/util.rs +++ b/async-openai/src/util.rs @@ -1,5 +1,3 @@ -use std::path::Path; - use reqwest::Body; use tokio::fs::File; use tokio_util::codec::{BytesCodec, FramedRead}; @@ -57,8 +55,9 @@ pub(crate) async fn create_file_part( Ok(file_part) } -pub(crate) fn create_all_dir>(dir: P) -> Result<(), OpenAIError> { - let exists = match Path::try_exists(dir.as_ref()) { +#[cfg(any(feature = "image", feature = "audio"))] +pub(crate) fn create_all_dir>(dir: P) -> Result<(), OpenAIError> { + let exists = match std::path::Path::try_exists(dir.as_ref()) { Ok(exists) => exists, Err(e) => return Err(OpenAIError::FileSaveError(e.to_string())), }; From f0d2f89fe82e4a22722b7edfcb298aeaa8d080ee Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:01:45 -0800 Subject: [PATCH 23/36] feature flag in error.rs --- async-openai/src/error.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/async-openai/src/error.rs b/async-openai/src/error.rs index 70fb6d22..835a3dce 100644 --- a/async-openai/src/error.rs +++ b/async-openai/src/error.rs @@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize}; +#[cfg(feature = "_api")] #[derive(Debug, thiserror::Error)] pub enum OpenAIError { /// Underlying error from reqwest library after an API call was made @@ -28,6 +29,27 @@ pub enum OpenAIError { InvalidArgument(String), } +#[cfg(not(feature = "_api"))] +#[derive(Debug)] +pub enum OpenAIError { + /// Error from client side validation + /// or when builder fails to build request before making API call + InvalidArgument(String), +} + +#[cfg(not(feature = "_api"))] +impl std::fmt::Display for OpenAIError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OpenAIError::InvalidArgument(msg) => write!(f, "invalid args: {}", msg), + } + } +} + +#[cfg(not(feature = "_api"))] +impl std::error::Error for OpenAIError {} + +#[cfg(feature = "_api")] #[derive(Debug, thiserror::Error)] pub enum StreamError { /// Underlying error from reqwest_eventsource library when reading the stream @@ -81,6 +103,7 @@ pub struct WrappedError { pub error: ApiError, } +#[cfg(feature = "_api")] pub(crate) fn map_deserialization_error(e: serde_json::Error, bytes: &[u8]) -> OpenAIError { let json_content = String::from_utf8_lossy(bytes); tracing::error!("failed deserialization of: {}", json_content); From 6d151008db92c3315ee832cce95863fdf649a982 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:02:15 -0800 Subject: [PATCH 24/36] feature flag for api wrappers in impl.rs --- async-openai/src/impls.rs | 159 +++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 54 deletions(-) diff --git a/async-openai/src/impls.rs b/async-openai/src/impls.rs index 09d42dbb..508aa559 100644 --- a/async-openai/src/impls.rs +++ b/async-openai/src/impls.rs @@ -1,62 +1,61 @@ +#[cfg(feature = "batch")] +use crate::batches::Batches; +#[cfg(feature = "chat-completion")] +use crate::chat::Chat; +#[cfg(feature = "chatkit")] +use crate::chatkit::{Chatkit, ChatkitSessions, ChatkitThreads}; +#[cfg(feature = "completions")] +use crate::completion::Completions; +#[cfg(feature = "embedding")] +use crate::embedding::Embeddings; +#[cfg(feature = "file")] +use crate::file::Files; +#[cfg(feature = "finetuning")] +use crate::fine_tuning::FineTuning; +#[cfg(feature = "image")] +use crate::image::Images; +#[cfg(feature = "model")] +use crate::model::Models; +#[cfg(feature = "moderation")] +use crate::moderation::Moderations; +#[cfg(feature = "upload")] +use crate::uploads::Uploads; +#[cfg(feature = "video")] +use crate::video::Videos; +#[cfg(feature = "realtime")] +use crate::Realtime; +#[cfg(feature = "administration")] use crate::{ - admin::AdminAPIKeys, - admin::AuditLogs, - admin::Certificates, - admin::GroupRoles, - admin::GroupUsers, - admin::Groups, - admin::Invites, - admin::ProjectAPIKeys, - admin::ProjectCertificates, - admin::ProjectGroupRoles, - admin::ProjectGroups, - admin::ProjectRateLimits, - admin::ProjectRoles, - admin::ProjectServiceAccounts, - admin::ProjectUserRoles, - admin::ProjectUsers, - admin::Projects, - admin::Roles, - admin::Usage, - admin::UserRoles, - admin::Users, - assistants::Assistants, - assistants::Messages, - assistants::Runs, - assistants::Steps, + admin::AdminAPIKeys, admin::AuditLogs, admin::Certificates, admin::GroupRoles, + admin::GroupUsers, admin::Groups, admin::Invites, admin::ProjectAPIKeys, + admin::ProjectCertificates, admin::ProjectGroupRoles, admin::ProjectGroups, + admin::ProjectRateLimits, admin::ProjectRoles, admin::ProjectServiceAccounts, + admin::ProjectUserRoles, admin::ProjectUsers, admin::Projects, admin::Roles, admin::Usage, + admin::UserRoles, admin::Users, +}; +#[cfg(feature = "assistant")] +use crate::{ + assistants::Assistants, assistants::Messages, assistants::Runs, assistants::Steps, assistants::Threads, - audio::Audio, - audio::Speech, - audio::Transcriptions, - audio::Translations, - batches::Batches, - chat::Chat, - chatkit::{Chatkit, ChatkitSessions, ChatkitThreads}, - completion::Completions, - containers::ContainerFiles, - containers::Containers, - embedding::Embeddings, - evals::EvalRunOutputItems, - evals::EvalRuns, - evals::Evals, - file::Files, - fine_tuning::FineTuning, - image::Images, - model::Models, - moderation::Moderations, - responses::ConversationItems, - responses::Conversations, - responses::Responses, - uploads::Uploads, - vectorstores::VectorStoreFileBatches, - vectorstores::VectorStoreFiles, +}; +#[cfg(feature = "audio")] +use crate::{audio::Audio, audio::Speech, audio::Transcriptions, audio::Translations}; +#[cfg(feature = "container")] +use crate::{containers::ContainerFiles, containers::Containers}; +#[cfg(feature = "evals")] +use crate::{evals::EvalRunOutputItems, evals::EvalRuns, evals::Evals}; +#[cfg(feature = "responses")] +use crate::{responses::ConversationItems, responses::Conversations, responses::Responses}; +#[cfg(feature = "vectorstore")] +use crate::{ + vectorstores::VectorStoreFileBatches, vectorstores::VectorStoreFiles, vectorstores::VectorStores, - video::Videos, }; // request builder impls macro /// Macro to implement `RequestOptionsBuilder` for wrapper types containing `RequestOptions` +#[cfg(feature = "_api")] macro_rules! impl_request_options_builder { ($type:ident) => { impl<'c, C: crate::config::Config> crate::traits::RequestOptionsBuilder for $type<'c, C> { @@ -71,63 +70,115 @@ macro_rules! impl_request_options_builder { }; } -#[cfg(feature = "realtime")] -use crate::Realtime; - +#[cfg(feature = "administration")] impl_request_options_builder!(AdminAPIKeys); +#[cfg(feature = "assistant")] impl_request_options_builder!(Assistants); +#[cfg(feature = "audio")] impl_request_options_builder!(Audio); +#[cfg(feature = "administration")] impl_request_options_builder!(AuditLogs); +#[cfg(feature = "batch")] impl_request_options_builder!(Batches); +#[cfg(feature = "administration")] impl_request_options_builder!(Certificates); +#[cfg(feature = "chat-completion")] impl_request_options_builder!(Chat); +#[cfg(feature = "chatkit")] impl_request_options_builder!(Chatkit); +#[cfg(feature = "chatkit")] impl_request_options_builder!(ChatkitSessions); +#[cfg(feature = "chatkit")] impl_request_options_builder!(ChatkitThreads); +#[cfg(feature = "completions")] impl_request_options_builder!(Completions); +#[cfg(feature = "container")] impl_request_options_builder!(ContainerFiles); +#[cfg(feature = "container")] impl_request_options_builder!(Containers); +#[cfg(feature = "responses")] impl_request_options_builder!(ConversationItems); +#[cfg(feature = "responses")] impl_request_options_builder!(Conversations); +#[cfg(feature = "embedding")] impl_request_options_builder!(Embeddings); +#[cfg(feature = "evals")] impl_request_options_builder!(Evals); +#[cfg(feature = "evals")] impl_request_options_builder!(EvalRunOutputItems); +#[cfg(feature = "evals")] impl_request_options_builder!(EvalRuns); +#[cfg(feature = "file")] impl_request_options_builder!(Files); +#[cfg(feature = "finetuning")] impl_request_options_builder!(FineTuning); +#[cfg(feature = "administration")] impl_request_options_builder!(GroupRoles); +#[cfg(feature = "administration")] impl_request_options_builder!(GroupUsers); +#[cfg(feature = "administration")] impl_request_options_builder!(Groups); +#[cfg(feature = "image")] impl_request_options_builder!(Images); +#[cfg(feature = "administration")] impl_request_options_builder!(Invites); +#[cfg(feature = "assistant")] impl_request_options_builder!(Messages); +#[cfg(feature = "model")] impl_request_options_builder!(Models); +#[cfg(feature = "moderation")] impl_request_options_builder!(Moderations); +#[cfg(feature = "administration")] impl_request_options_builder!(Projects); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectGroupRoles); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectGroups); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectRoles); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectUserRoles); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectUsers); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectServiceAccounts); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectAPIKeys); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectRateLimits); +#[cfg(feature = "administration")] impl_request_options_builder!(ProjectCertificates); +#[cfg(feature = "administration")] impl_request_options_builder!(Roles); #[cfg(feature = "realtime")] impl_request_options_builder!(Realtime); +#[cfg(feature = "responses")] impl_request_options_builder!(Responses); +#[cfg(feature = "assistant")] impl_request_options_builder!(Runs); +#[cfg(feature = "audio")] impl_request_options_builder!(Speech); +#[cfg(feature = "assistant")] impl_request_options_builder!(Steps); +#[cfg(feature = "assistant")] impl_request_options_builder!(Threads); +#[cfg(feature = "audio")] impl_request_options_builder!(Transcriptions); +#[cfg(feature = "audio")] impl_request_options_builder!(Translations); +#[cfg(feature = "upload")] impl_request_options_builder!(Uploads); +#[cfg(feature = "administration")] impl_request_options_builder!(Usage); +#[cfg(feature = "administration")] impl_request_options_builder!(UserRoles); +#[cfg(feature = "administration")] impl_request_options_builder!(Users); +#[cfg(feature = "vectorstore")] impl_request_options_builder!(VectorStoreFileBatches); +#[cfg(feature = "vectorstore")] impl_request_options_builder!(VectorStoreFiles); +#[cfg(feature = "vectorstore")] impl_request_options_builder!(VectorStores); +#[cfg(feature = "video")] impl_request_options_builder!(Videos); From f97e04e0c73588931f64a8761f7394ac05b9f8dc Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:10:18 -0800 Subject: [PATCH 25/36] remove unused feature flag --- async-openai/src/types/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/async-openai/src/types/mod.rs b/async-openai/src/types/mod.rs index 550d8d65..b30d670a 100644 --- a/async-openai/src/types/mod.rs +++ b/async-openai/src/types/mod.rs @@ -134,7 +134,6 @@ mod impls; feature = "embedding-types", feature = "moderation-types", feature = "administration-types", - feature = "_api" ))] impl From for crate::error::OpenAIError { fn from(value: derive_builder::UninitializedFieldError) -> Self { From 34effae41bd884181fa371f1fd9c0b0bede0fa87 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:10:49 -0800 Subject: [PATCH 26/36] updated cargo.toml with feature flags --- async-openai/Cargo.toml | 62 ++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/async-openai/Cargo.toml b/async-openai/Cargo.toml index 2b89a7a0..8fa9ac6e 100644 --- a/async-openai/Cargo.toml +++ b/async-openai/Cargo.toml @@ -13,7 +13,7 @@ homepage = "https://github.com/64bit/async-openai" repository = "https://github.com/64bit/async-openai" [features] -default = ["rustls"] +default = [] # Enable rustls for TLS support rustls = ["_api", "dep:reqwest", "reqwest/rustls-tls-native-roots"] # Enable rustls and webpki-roots @@ -23,11 +23,11 @@ native-tls = ["_api","dep:reqwest", "reqwest/native-tls"] # Remove dependency on OpenSSL native-tls-vendored = ["_api", "dep:reqwest", "reqwest/native-tls-vendored"] # Bring your own types -byot = ["_api"] +byot = ["dep:async-openai-macros"] # API feature flags - these enable both the API wrapper and types responses = ["response-types", "_api"] -webhook = ["webhook-types", "_api", "dep:hmac", "dep:sha2", "dep:hex"] +webhook = ["webhook-types", "dep:base64", "dep:thiserror", "dep:hmac", "dep:sha2", "dep:hex"] # start - Platform APIs audio = ["audio-types", "_api"] video = ["video-types", "_api"] @@ -52,28 +52,28 @@ administration = ["administration-types", "_api"] completions = ["completion-types", "_api"] # Type feature flags - these enable only the types -response-types = ["dep:derive_builder", "dep:bytes"] -webhook-types = ["dep:derive_builder", "dep:bytes"] +response-types = ["dep:derive_builder"] +webhook-types = ["dep:derive_builder"] audio-types = ["dep:derive_builder", "dep:bytes"] video-types = ["dep:derive_builder", "dep:bytes"] image-types = ["dep:derive_builder", "dep:bytes"] -embedding-types = ["dep:derive_builder", "dep:bytes"] -eval-types = ["dep:derive_builder", "dep:bytes"] -finetuning-types = ["dep:derive_builder", "dep:bytes"] -grader-types = ["dep:derive_builder", "dep:bytes"] -batch-types = ["dep:derive_builder", "dep:bytes"] +embedding-types = ["dep:derive_builder"] +eval-types = ["dep:derive_builder", "chat-completion-types", "response-types", "grader-types"] +finetuning-types = ["dep:derive_builder", "grader-types"] +grader-types = ["dep:derive_builder", "eval-types"] +batch-types = ["dep:derive_builder"] file-types = ["dep:derive_builder", "dep:bytes"] -upload-types = ["dep:derive_builder", "dep:bytes"] -model-types = ["dep:derive_builder", "dep:bytes"] -moderation-types = ["dep:derive_builder", "dep:bytes"] -vectorstore-types = ["dep:derive_builder", "dep:bytes"] -chatkit-types = ["dep:derive_builder", "dep:bytes"] +upload-types = ["dep:derive_builder", "dep:bytes", "file-types"] +model-types = ["dep:derive_builder"] +moderation-types = ["dep:derive_builder"] +vectorstore-types = ["dep:derive_builder"] +chatkit-types = ["dep:derive_builder"] container-types = ["dep:derive_builder", "dep:bytes"] -realtime-types = ["dep:derive_builder", "dep:bytes"] +realtime-types = ["dep:derive_builder", "dep:bytes", "response-types"] chat-completion-types = ["dep:derive_builder", "dep:bytes"] -assistant-types = ["dep:derive_builder", "dep:bytes"] -administration-types = ["dep:derive_builder", "dep:bytes"] -completion-types = ["dep:derive_builder", "dep:bytes"] +assistant-types = ["dep:derive_builder"] +administration-types = ["dep:derive_builder"] +completion-types = ["dep:derive_builder", "chat-completion-types" ] # Enable all types types = [ @@ -152,7 +152,9 @@ secrecy = { version = "0.10.3", features = ["serde"], optional = true } eventsource-stream = { version = "0.2.3", optional = true } serde_urlencoded = { version = "0.7.1", optional = true } url = { version = "2.5", optional = true } +# For Realtime websocket tokio-tungstenite = { version = "0.26.1", optional = true, default-features = false } +# For Webhook signature verification hmac = { version = "0.12", optional = true, default-features = false} sha2 = { version = "0.10", optional = true, default-features = false } hex = { version = "0.4", optional = true, default-features = false } @@ -163,7 +165,27 @@ serde_json = "1.0" [[test]] name = "bring_your_own_type" -required-features = ["byot"] +required-features = ["byot", "file", "assistant", "model", "moderation", "image", "chat-completion", "completions", "audio", "embedding", "finetuning", "batch", "administration", "upload", "vectorstore", "responses", "chatkit", "container", "evals", "video"] + +[[test]] +name = "boxed_future" +required-features = ["completions", "chat-completion-types"] + +[[test]] +name = "chat_completion" +required-features = ["chat-completion-types"] + +[[test]] +name = "embeddings" +required-features = ["embedding-types", "chat-completion-types"] + +[[test]] +name = "ser_de" +required-features = ["chat-completion-types"] + +[[test]] +name = "whisper" +required-features = ["audio", "file-types"] [package.metadata.docs.rs] all-features = true From 0bd05cd24dcc3b8e9f69c96690a2381fada223f7 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:18:17 -0800 Subject: [PATCH 27/36] updated lib.rs for feature flags --- async-openai/src/lib.rs | 67 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/async-openai/src/lib.rs b/async-openai/src/lib.rs index 57a3179c..6d7905db 100644 --- a/async-openai/src/lib.rs +++ b/async-openai/src/lib.rs @@ -134,66 +134,127 @@ //! #![cfg_attr(docsrs, feature(doc_cfg))] -#[cfg(feature = "byot")] +#[cfg(all(feature = "_api", feature = "byot"))] pub(crate) use async_openai_macros::byot; -#[cfg(not(feature = "byot"))] +#[cfg(all(feature = "_api", not(feature = "byot")))] pub(crate) use async_openai_macros::byot_passthrough as byot; +// #[cfg(all(not(feature = "_api"), not(feature = "byot")))] +// #[macro_export] +// macro_rules! byot { +// ($($tt:tt)*) => { +// $($tt)* +// }; +// } + +#[cfg(feature = "administration")] mod admin; +#[cfg(feature = "assistant")] mod assistants; +#[cfg(feature = "audio")] mod audio; +#[cfg(feature = "batch")] mod batches; +#[cfg(feature = "chat-completion")] mod chat; +#[cfg(feature = "chatkit")] mod chatkit; +#[cfg(feature = "_api")] mod client; +#[cfg(feature = "completions")] mod completion; +#[cfg(feature = "_api")] pub mod config; +#[cfg(feature = "container")] mod containers; +#[cfg(feature = "image")] mod download; +#[cfg(feature = "embedding")] mod embedding; pub mod error; +#[cfg(feature = "evals")] mod evals; +#[cfg(feature = "file")] mod file; +#[cfg(feature = "finetuning")] mod fine_tuning; +#[cfg(feature = "image")] mod image; +#[cfg(feature = "_api")] mod impls; +#[cfg(feature = "model")] mod model; +#[cfg(feature = "moderation")] mod moderation; #[cfg(feature = "realtime")] mod realtime; +#[cfg(feature = "_api")] mod request_options; +#[cfg(feature = "responses")] mod responses; +#[cfg(feature = "_api")] pub mod traits; pub mod types; +#[cfg(feature = "upload")] mod uploads; +#[cfg(any( + feature = "audio", + feature = "file", + feature = "upload", + feature = "image", + feature = "video", + feature = "container" +))] mod util; +#[cfg(feature = "vectorstore")] mod vectorstores; +#[cfg(feature = "video")] mod video; #[cfg(feature = "webhook")] pub mod webhooks; +#[cfg(feature = "administration")] pub use admin::*; +#[cfg(feature = "assistant")] pub use assistants::*; -pub use audio::Audio; +#[cfg(feature = "audio")] pub use audio::*; +#[cfg(feature = "batch")] pub use batches::Batches; +#[cfg(feature = "chat-completion")] pub use chat::Chat; +#[cfg(feature = "chatkit")] pub use chatkit::Chatkit; +#[cfg(feature = "_api")] pub use client::Client; +#[cfg(feature = "completions")] pub use completion::Completions; +#[cfg(feature = "container")] pub use containers::*; +#[cfg(feature = "embedding")] pub use embedding::Embeddings; +#[cfg(feature = "evals")] pub use evals::*; +#[cfg(feature = "file")] pub use file::Files; +#[cfg(feature = "finetuning")] pub use fine_tuning::FineTuning; +#[cfg(feature = "image")] pub use image::Images; +#[cfg(feature = "model")] pub use model::Models; +#[cfg(feature = "moderation")] pub use moderation::Moderations; #[cfg(feature = "realtime")] pub use realtime::Realtime; +#[cfg(feature = "_api")] pub use request_options::RequestOptions; +#[cfg(feature = "responses")] pub use responses::*; +#[cfg(feature = "upload")] pub use uploads::Uploads; +#[cfg(feature = "vectorstore")] pub use vectorstores::*; +#[cfg(feature = "video")] pub use video::Videos; From 0b8a51c0222df1fc3b0f9df566b4d53c688f0f21 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:22:32 -0800 Subject: [PATCH 28/36] github workflow to build all features --- .github/workflows/pr-checks.yml | 95 +++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 232720d1..53095952 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -5,8 +5,8 @@ on: types: [opened, synchronize, reopened] jobs: - build: - name: Build Workspace + format: + name: Check Formatting runs-on: ubuntu-latest steps: @@ -17,7 +17,80 @@ jobs: uses: actions-rs/toolchain@v1 with: toolchain: stable - components: rustfmt, clippy + components: rustfmt + override: true + + - name: Check formatting + run: cargo fmt --all -- --check + + build-features: + name: Build Feature - ${{ matrix.feature }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + feature: + [ + rustls, + rustls-webpki-roots, + native-tls, + native-tls-vendored, + byot, + responses, + webhook, + audio, + video, + image, + embedding, + evals, + finetuning, + grader, + batch, + file, + upload, + model, + moderation, + vectorstore, + chatkit, + container, + realtime, + chat-completion, + assistant, + administration, + completions, + response-types, + webhook-types, + audio-types, + video-types, + image-types, + embedding-types, + eval-types, + finetuning-types, + grader-types, + batch-types, + file-types, + upload-types, + model-types, + moderation-types, + vectorstore-types, + chatkit-types, + container-types, + realtime-types, + chat-completion-types, + assistant-types, + administration-types, + completion-types, + ] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy override: true - name: Cache cargo registry @@ -27,15 +100,15 @@ jobs: ~/.cargo/registry ~/.cargo/git target - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.feature }} restore-keys: | + ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}- ${{ runner.os }}-cargo- - - name: Build workspace - run: cargo build --workspace --verbose - - - name: Check formatting - run: cargo fmt --all -- --check + - name: Build with feature ${{ matrix.feature }} + env: + RUSTFLAGS: "-D warnings" + run: cargo build --no-default-features --features ${{ matrix.feature }} --verbose - # - name: Run clippy - # run: cargo clippy --workspace -- -D warnings + - name: Run clippy with feature ${{ matrix.feature }} + run: cargo clippy --no-default-features --features ${{ matrix.feature }} -- -D warnings From c808600393495954582c0143bfe27d1d094dd364 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:31:39 -0800 Subject: [PATCH 29/36] add types in feature list --- .github/workflows/pr-checks.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 53095952..489160c0 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -80,6 +80,7 @@ jobs: assistant-types, administration-types, completion-types, + types, ] steps: From c07a863499955cb996fb93e218a5cad5c6790f31 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:33:03 -0800 Subject: [PATCH 30/36] add feature flag docs in readme --- async-openai/README.md | 44 +++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/async-openai/README.md b/async-openai/README.md index 288bb1b4..77807856 100644 --- a/async-openai/README.md +++ b/async-openai/README.md @@ -21,19 +21,19 @@ `async-openai` is an unofficial Rust library for OpenAI, based on [OpenAI OpenAPI spec](https://github.com/openai/openai-openapi). It implements all APIs from the spec: -| Features | APIs | -|---|---| -| **Responses API** | Responses, Conversations, Streaming events | -| **Webhooks** | Webhook Events | -| **Platform APIs** | Audio, Audio Streaming, Videos, Images, Image Streaming, Embeddings, Evals, Fine-tuning, Graders, Batch, Files, Uploads, Models, Moderations | -| **Vector stores** | Vector stores, Vector store files, Vector store file batches | -| **ChatKit** (Beta) | ChatKit | -| **Containers** | Containers, Container Files | -| **Realtime** | Realtime Calls, Client secrets, Client events, Server events | -| **Chat Completions** | Chat Completions, Streaming | -| **Assistants** (Beta) | Assistants, Threads, Messages, Runs, Run steps, Streaming | -| **Administration** | Admin API Keys, Invites, Users, Groups, Roles, Role assignments, Projects, Project users, Project groups, Project service accounts, Project API keys, Project rate limits, Audit logs, Usage, Certificates | -| **Legacy** | Completions | +| What | APIs | Crate Feature Flags | +|---|---|---| +| **Responses API** | Responses, Conversations, Streaming events | `responses` | +| **Webhooks** | Webhook Events | `webhook` | +| **Platform APIs** | Audio, Audio Streaming, Videos, Images, Image Streaming, Embeddings, Evals, Fine-tuning, Graders, Batch, Files, Uploads, Models, Moderations | `audio`, `video`, `image`, `embedding`, `evals`, `finetuning`, `grader`, `batch`, `file`, `upload`, `model`, `moderation` | +| **Vector stores** | Vector stores, Vector store files, Vector store file batches | `vectorstore` | +| **ChatKit** (Beta) | ChatKit | `chatkit` | +| **Containers** | Containers, Container Files | `container` | +| **Realtime** | Realtime Calls, Client secrets, Client events, Server events | `realtime` | +| **Chat Completions** | Chat Completions, Streaming | `chat-completion` | +| **Assistants** (Beta) | Assistants, Threads, Messages, Runs, Run steps, Streaming | `assistant` | +| **Administration** | Admin API Keys, Invites, Users, Groups, Roles, Role assignments, Projects, Project users, Project groups, Project service accounts, Project API keys, Project rate limits, Audit logs, Usage, Certificates | `administration` | +| **Legacy** | Completions | `completions` | Features that makes `async-openai` unique: - Bring your own custom types for Request or Response objects. @@ -41,6 +41,7 @@ Features that makes `async-openai` unique: - Customize path, query and headers per request; customize path and headers globally (for all requests). - Requests (except SSE streaming) including form submissions are retried with exponential backoff when [rate limited](https://platform.openai.com/docs/guides/rate-limits). - Ergonomic builder pattern for all request objects. +- Granular feature flags to enable any types or apis: good for faster compilation and crate reuse. - Microsoft Azure OpenAI Service (only for APIs matching OpenAI spec). ## Usage @@ -62,13 +63,6 @@ Other official environment variables supported are: `OPENAI_ADMIN_KEY`, `OPENAI_ - Visit [examples](https://github.com/64bit/async-openai/tree/main/examples) directory on how to use `async-openai`. - Visit [docs.rs/async-openai](https://docs.rs/async-openai) for docs. -## Realtime - -Realtime types and APIs can be enabled with feature flag `realtime`. - -## Webhooks - -Support for webhook event types, signature verification, and building webhook events from payloads can be enabled by using the `webhook` feature flag. ## Image Generation Example @@ -114,6 +108,10 @@ async fn main() -> Result<(), Box> { Scaled up for README, actual size 256x256 +## Webhooks + +Support for webhook event types, signature verification, and building webhook events from payloads can be enabled by using the `webhook` feature flag. + ## Bring Your Own Types Enable methods whose input and outputs are generics with `byot` feature. It creates a new method with same name and `_byot` suffix. @@ -152,6 +150,12 @@ This can be useful in many scenarios: Visit [examples/bring-your-own-type](https://github.com/64bit/async-openai/tree/main/examples/bring-your-own-type) directory to learn more. +## Rust Types + +To only use Rust types from the crate - use feature flag `types`. + +There are granular feature flags like `response-types`, `chat-completion-types`, etc. + ## Dynamic Dispatch for OpenAI-compatible Providers This allows you to use same code (say a `fn`) to call APIs on different OpenAI-compatible providers. From c098c62fd14532d764b4d8ec402e2a9cef7709e5 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:40:57 -0800 Subject: [PATCH 31/36] updated README --- async-openai/README.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/async-openai/README.md b/async-openai/README.md index 77807856..007dd74e 100644 --- a/async-openai/README.md +++ b/async-openai/README.md @@ -156,7 +156,25 @@ To only use Rust types from the crate - use feature flag `types`. There are granular feature flags like `response-types`, `chat-completion-types`, etc. -## Dynamic Dispatch for OpenAI-compatible Providers +## OpenAI-compatible Providers + +### Configurable Request + +To change path, query or headers of individual request use the `.path()`, `.query()`, `.header()`, `.headers()` method on the API group. + +For example: + +``` +client + .chat() + .path("/v1/messages")? + .query(&[("role", "user")])? + .header("key", "value")? + .create(request) + .await? +``` + +### Dynamic Dispatch This allows you to use same code (say a `fn`) to call APIs on different OpenAI-compatible providers. From 5099b5a13ba91ebc4d85d88e8cdebffd6d8cf4f7 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:46:10 -0800 Subject: [PATCH 32/36] webhook clippy fix: module has the same name as its containing module --- async-openai/src/types/webhooks/mod.rs | 4 ++-- async-openai/src/types/webhooks/{webhooks.rs => webhooks_.rs} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename async-openai/src/types/webhooks/{webhooks.rs => webhooks_.rs} (100%) diff --git a/async-openai/src/types/webhooks/mod.rs b/async-openai/src/types/webhooks/mod.rs index 73f94904..43b5ee06 100644 --- a/async-openai/src/types/webhooks/mod.rs +++ b/async-openai/src/types/webhooks/mod.rs @@ -1,3 +1,3 @@ -mod webhooks; +mod webhooks_; -pub use webhooks::*; +pub use webhooks_::*; diff --git a/async-openai/src/types/webhooks/webhooks.rs b/async-openai/src/types/webhooks/webhooks_.rs similarity index 100% rename from async-openai/src/types/webhooks/webhooks.rs rename to async-openai/src/types/webhooks/webhooks_.rs From 726929bd5179a3a2cfb55845dd8a846adc9ed4ac Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:50:05 -0800 Subject: [PATCH 33/36] clippy: image feature: derive default on ImageInput instead of manually impl --- async-openai/src/types/impls.rs | 9 --------- async-openai/src/types/shared/image_input.rs | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/async-openai/src/types/impls.rs b/async-openai/src/types/impls.rs index 7c9bf446..c3d8e567 100644 --- a/async-openai/src/types/impls.rs +++ b/async-openai/src/types/impls.rs @@ -139,15 +139,6 @@ impl Default for InputSource { } } -#[cfg(any(feature = "image-types", feature = "video-types"))] -impl Default for ImageInput { - fn default() -> Self { - Self { - source: InputSource::default(), - } - } -} - /// for `impl_input!(Struct)` where /// ```text /// Struct { diff --git a/async-openai/src/types/shared/image_input.rs b/async-openai/src/types/shared/image_input.rs index 38fd4819..48a96600 100644 --- a/async-openai/src/types/shared/image_input.rs +++ b/async-openai/src/types/shared/image_input.rs @@ -1,6 +1,6 @@ use crate::types::InputSource; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct ImageInput { pub source: InputSource, } From f08556d0bf2f24be1adead4d92042cf72477caa1 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:53:04 -0800 Subject: [PATCH 34/36] clippy: realtime feature: box variant to reduce enum size --- async-openai/src/types/realtime/session.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/async-openai/src/types/realtime/session.rs b/async-openai/src/types/realtime/session.rs index 21c3e33e..039970bb 100644 --- a/async-openai/src/types/realtime/session.rs +++ b/async-openai/src/types/realtime/session.rs @@ -301,9 +301,12 @@ pub struct TokenLimits { #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "type")] pub enum Session { + // Boxed as per clippy suggestion: + // https://rust-lang.github.io/rust -clippy/rust-1.91.0/index.html#large_enum_variant + // the largest variant contains at least 600 bytes, the second-largest variant contains at least 144 bytes /// The type of session to create. Always `realtime` for the Realtime API. #[serde(rename = "realtime")] - RealtimeSession(RealtimeSession), + RealtimeSession(Box), /// The type of session to create. Always `transcription` for transcription sessions. #[serde(rename = "transcription")] RealtimeTranscriptionSession(RealtimeTranscriptionSession), From 83282dff2460c8e5c385ec60b5065c7953f81eae Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 17:55:20 -0800 Subject: [PATCH 35/36] remove tls feature flags for reqwest from the pr checks --- .github/workflows/pr-checks.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 489160c0..62b121f2 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -31,10 +31,6 @@ jobs: matrix: feature: [ - rustls, - rustls-webpki-roots, - native-tls, - native-tls-vendored, byot, responses, webhook, From 543be86b07259831b21d510e2c490e5cc00518d6 Mon Sep 17 00:00:00 2001 From: Himanshu Neema Date: Tue, 25 Nov 2025 18:01:32 -0800 Subject: [PATCH 36/36] move default implementation for InputSource in its own file --- async-openai/src/types/impls.rs | 13 ------------- async-openai/src/types/input_source.rs | 8 ++++++++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/async-openai/src/types/impls.rs b/async-openai/src/types/impls.rs index c3d8e567..56c87eb0 100644 --- a/async-openai/src/types/impls.rs +++ b/async-openai/src/types/impls.rs @@ -126,19 +126,6 @@ impl_default!(ModerationInput); #[cfg(feature = "embedding-types")] impl_default!(EmbeddingInput); -#[cfg(any( - feature = "audio-types", - feature = "file-types", - feature = "image-types" -))] -impl Default for InputSource { - fn default() -> Self { - InputSource::Path { - path: std::path::PathBuf::new(), - } - } -} - /// for `impl_input!(Struct)` where /// ```text /// Struct { diff --git a/async-openai/src/types/input_source.rs b/async-openai/src/types/input_source.rs index 44704056..87cfda67 100644 --- a/async-openai/src/types/input_source.rs +++ b/async-openai/src/types/input_source.rs @@ -12,3 +12,11 @@ pub enum InputSource { vec: Vec, }, } + +impl Default for InputSource { + fn default() -> Self { + InputSource::Path { + path: std::path::PathBuf::new(), + } + } +}