Dynamic input Function Wrappers after milestone 1

Issue with Adding Function Wrappers in ChatClient for Dynamic Variables in Spring AI

Context:
I’m trying to implement a feature similar to the booking example provided by the Spring AI team on GitHub. However, the documentation seems outdated, and I am encountering errors when modifying their implementation. Any help or guidance would be greatly appreciated!

Problem:
There is no clear example or documentation (currently outdated) on how to add function wrappers that can dynamically accept these variables and use them in function callbacks during chat prompt execution. Are function wrappers deprecated?

Example Scenario:
Here’s a simplified version of what I am trying to achieve, focusing on modifying booking dates:

The customer, before entering the chat session, will provide the booking ID in a form (no AI involved). The static data, like the IP address of the customer, is passed by the calling application:

Final request = Static data + AI input params

@Service
public class CustomerSupportAssistant {

    private final ChatClient chatClient;
    private final BookingService bookingService;

    @Autowired
    public CustomerSupportAssistant(
            ChatClient.Builder modelBuilder, 
            VectorStore vectorStore, 
            ChatMemory chatMemory, 
            BookingService bookingService
    ) {
        this.bookingService = bookingService;

        this.chatClient = modelBuilder
                .defaultSystem("""
                        You are a customer chat support agent of an airline named "Funnair".
                        Respond in a friendly, helpful, and joyful manner.
                        You are interacting with customers through an online chat system.
                        Use the provided functions to change bookings.
                        Today is {current_date}.
                    """)
                .defaultAdvisors(
                        new PromptChatMemoryAdvisor(chatMemory),
                        new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults()))
                // removed the default functions to add dynamic input functions
                .build();
    }

    public Flux<String> chat(
            String chatId, 
            String userMessageContent, 
            Booking booking, // is now passed by the calling application / code
            String ipAddress // cannot be expected to be passed by customer in chat so is now passed by the calling application / code
    ) {
        var dynamicChatOptions = OpenAiChatOptions.builder()
                .withModel("gpt-3.5-turbo")
                .withMaxTokens(100)
                .withFunctionCallbacks(
                        List.of(
                                FunctionCallbackWrapper.builder(
                                        (ChangeBookingDatesRequest request) -> {
                                            bookingService.changeBooking(
                                                    booking.id(),
                                                    request.from(), // for validation if invalid dates are provided
                                                    request.to(), 
                                                    request.ipAddress() // security check or audit log
                                            );
                                            return "Booking dates changed successfully";
                                        })
                                        .withName("changeBooking")
                                        .withDescription("Change booking dates with additional parameters")
                                        .build()))
                .build();

        return this.chatClient.prompt()
                .withOptions(dynamicChatOptions)
                .system(s -> s.param("current_date", LocalDate.now().toString()))
                .user(userMessageContent)
                .advisors(a -> a
                        .param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100))
                .stream().content();
    }
}

Error:
When I try to implement the above approach, I’m getting the following error:

The code works and there is no error till I add the dynamicChatOptions to the chatClient.prompt() method.

My Setup:

spring:
  ai:
    openai:
      api-key: ${OPEN_AI_KEY}
      chat:
        options:
          model: gpt-3.5-turbo-0125

Error Details:

{
  "error": {
    "message": "You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY), or as the password field (with blank username) if you're accessing the API from your browser and are prompted for a username and password. You can obtain an API key from https://platform.openai.com/account/api-keys.",
    "type": "invalid_request_error",
    "param": null,
    "code": null
  }
}
org.springframework.web.reactive.function.client.WebClientResponseException$BadRequest: 400 Bad Request from POST https://api.openai.com/v1/chat/completions
	at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:307)
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ 400 BAD_REQUEST from POST https://api.openai.com/v1/chat/completions [DefaultWebClient]
Original Stack Trace:

Link to Repo:
For reference, here is the link to the repository: tzolov/playground-flight-booking

Any guidance or examples on how to resolve this issue would be greatly appreciated. Thank you!

Its not allowing me to post links so just search for : gitbub dot com slash
tzolov/playground-flight-booking