Bug description OpenAiChatOptions does not have a topK parameter, but the generic ChatOptions rsp. ToolCallingChatOptions builders do.

Specifying that parameter via one of these leads to a NotWritablePropertyException upon executing a query, as ModelOptionsUtils.copyToTarget() can't map the property and fails.

Environment The problem occurs in the current Spring AI 1.0.0-SNAPSHOT using Spring Boot 3.4.5, but is reproducible in earlier releases too. We don't use the OpenAiChatOptions directly, but the generic builders instead, talking to the together.ai OpenAI-compatible API (but the issue is not related to OpenAI itself, but the mapping before the actual call).

Steps to reproduce

Example:

var chatOptions = ToolCallingChatOptions.builder()
            .temperature(settings.getTemperature())
            .topK(settings.getTopK()) // does not work with OpenAI ChatOptions
            .topP(settings.getTopP())
            .frequencyPenalty(settings.getFrequencyPenalty())
            .presencePenalty(settings.getPresencePenalty())
            .build();

and then execute an arbitrary ChatClientcall with these options, using OpenAI.

Stack trace:

java.lang.RuntimeException: Failed to convert the org.springframework.ai.model.tool.ToolCallingChatOptions into org.springframework.ai.openai.OpenAiChatOptions
    at org.springframework.ai.model.ModelOptionsUtils.copyToTarget(ModelOptionsUtils.java:296) ~[spring-ai-model-1.0.0-20250430.052125-121.jar:1.0.0-SNAPSHOT]
    at org.springframework.ai.openai.OpenAiChatModel.buildRequestPrompt(OpenAiChatModel.java:490) ~[spring-ai-openai-1.0.0-20250430.052125-1423.jar:1.0.0-SNAPSHOT]
    at org.springframework.ai.openai.OpenAiChatModel.call(OpenAiChatModel.java:178) ~[spring-ai-openai-1.0.0-20250430.052125-1423.jar:1.0.0-SNAPSHOT]
(...rest omitted for sake of brevity...)
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'topK' of bean class [org.springframework.ai.openai.OpenAiChatOptions]: Bean property 'topK' is not writable or has an invalid setter method. Did you mean 'stop', or 'topP'?
    at org.springframework.beans.BeanWrapperImpl.createNotWritablePropertyException(BeanWrapperImpl.java:209) ~[spring-beans-6.2.6.jar:6.2.6]
    at org.springframework.beans.AbstractNestablePropertyAccessor.processLocalProperty(AbstractNestablePropertyAccessor.java:429) ~[spring-beans-6.2.6.jar:6.2.6]
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:278) ~[spring-beans-6.2.6.jar:6.2.6]
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:246) ~[spring-beans-6.2.6.jar:6.2.6]
    at org.springframework.ai.model.ModelOptionsUtils.mergeBeans(ModelOptionsUtils.java:338) ~[spring-ai-model-1.0.0-20250430.052125-121.jar:1.0.0-SNAPSHOT]
    at org.springframework.ai.model.ModelOptionsUtils.copyToTarget(ModelOptionsUtils.java:290) ~[spring-ai-model-1.0.0-20250430.052125-121.jar:1.0.0-SNAPSHOT]
    ... 54 common frames omitted

Expected behavior I would suggest an unsupported property on the target options class should better be silently ignored in this case.

Comment From: jingbio

事实上这个问题在最新RC1上依然存在。

Comment From: cbollmeyer

The issue remains also in Spring AI 1.0.1, you cannot programmatically set topK in one of the high level Options builders unless you want to get an exception.