7405b96d82
## Issue Closes #6100 ## Change `OpenAiResponsesChatModel` and `OpenAiResponsesStreamingChatModel` had no way to set custom HTTP headers, so they could not be used behind an authenticated proxy or a gateway that requires extra headers. This PR adds the two overloads that `OpenAiChatModel` and `OpenAiStreamingChatModel` already have, bringing the Responses API models to parity: ```java ChatModel model = OpenAiResponsesChatModel.builder() .apiKey(System.getenv("OPENAI_API_KEY")) .modelName("gpt-4o-mini") .customHeaders(Map.of("Proxy-Authorization", "Basic dXNlcjpwYXNz")) .build(); ``` ```java ChatModel model = OpenAiResponsesChatModel.builder() .apiKey(System.getenv("OPENAI_API_KEY")) .modelName("gpt-4o-mini") .customHeaders(() -> Map.of("Authorization", "Bearer " + tokenProvider.currentToken())) .build(); ``` Details: - `customHeaders(Map<String, String>)` and `customHeaders(Supplier<Map<String, String>>)` were added to both builders. The `Supplier` is invoked before every request, so dynamic values such as expiring OAuth2 tokens are supported. - The headers are plumbed through `OpenAiResponsesClient`, which builds its requests itself rather than going through `DefaultOpenAiClient`. The default is `Map::of`, following the same pattern as `DefaultOpenAiClient`. - Custom headers are applied after the built-in ones (`Authorization`, `OpenAI-Organization`, `Content-Type`, `Accept`), so they can deliberately override them. This matches the precedence in `DefaultOpenAiClient#buildRequestHeaders` and is what the authenticated-proxy use case needs. - A `null` or empty map returned by the supplier is a no-op. - No masking work was needed: `HttpRequestLogger` masks by header-name keyword, so credential-carrying custom headers are already masked when `logRequests` is enabled. Tests: `OpenAiResponsesCustomHeadersTest` captures the outgoing `HttpRequest` through a stub `HttpClient` and asserts the headers that are actually sent, covering the static map, the supplier being called before each request, overriding a default header, the streaming model, and the negative cases (no custom headers configured, supplier returning `null`). Documentation: a "Custom HTTP headers" section was added to `docs/docs/integrations/language-models/open-ai.md`, under the OpenAI Responses API section. ## General checklist - [X] There are no breaking changes (API, behaviour) - [X] I have added unit and/or integration tests for my change - [X] The tests cover both positive and negative cases - [ ] I have manually run all the unit and integration tests in the module I have added/changed, and they are all green - [X] I have manually run all the unit and integration tests in the [core](https://github.com/langchain4j/langchain4j/tree/main/langchain4j-core) and [main](https://github.com/langchain4j/langchain4j/tree/main/langchain4j) modules, and they are all green - [X] I have added/updated the [documentation](https://github.com/langchain4j/langchain4j/tree/main/docs/docs) - [ ] I have added an example in the [examples repo](https://github.com/langchain4j/langchain4j-examples) (only for "big" features) - [ ] I have added/updated [Spring Boot starter(s)](https://github.com/langchain4j/langchain4j-spring) (if applicable)