39
39
import org .springframework .ai .chat .prompt .Prompt ;
40
40
import org .springframework .ai .chat .prompt .PromptTemplate ;
41
41
import org .springframework .ai .converter .BeanOutputConverter ;
42
+ import org .springframework .ai .converter .StructuredOutputConverter ;
42
43
import org .springframework .ai .model .function .FunctionCallback ;
43
44
import org .springframework .ai .model .function .FunctionCallbackWrapper ;
44
45
import org .springframework .ai .model .function .FunctionCallingOptions ;
@@ -74,6 +75,12 @@ static Builder builder(ChatModel chatModel) {
74
75
75
76
ChatClientPromptRequest prompt (Prompt prompt );
76
77
78
+ /**
79
+ * Return a {@link ChatClient.Builder} to create a new {@link ChatClient} whose
80
+ * settings are replicated from the default {@link ChatClientRequest} of this client.
81
+ */
82
+ Builder mutate ();
83
+
77
84
interface PromptSpec <T > {
78
85
79
86
T text (String text );
@@ -223,6 +230,26 @@ class ChatClientRequest {
223
230
224
231
private final Map <String , Object > systemParams = new HashMap <>();
225
232
233
+ /**
234
+ * Return a {@code ChatClient.Builder} to create a new {@code ChatClient} whose
235
+ * settings are replicated from this {@code ChatClientRequest}.
236
+ */
237
+ public Builder mutate () {
238
+ Builder builder = ChatClient .builder (chatModel )
239
+ .defaultSystem (s -> s .text (this .systemText ).params (this .systemParams ))
240
+ .defaultUser (u -> u .text (this .userText )
241
+ .params (this .userParams )
242
+ .media (this .media .toArray (new Media [this .media .size ()])))
243
+ .defaultOptions (this .chatOptions )
244
+ .defaultFunctions (StringUtils .toStringArray (this .functionNames ));
245
+
246
+ // workaround to set the missing fields.
247
+ builder .defaultRequest .messages .addAll (this .messages );
248
+ builder .defaultRequest .functionCallbacks .addAll (this .functionCallbacks );
249
+
250
+ return builder ;
251
+ }
252
+
226
253
/* copy constructor */
227
254
ChatClientRequest (ChatClientRequest ccr ) {
228
255
this (ccr .chatModel , ccr .userText , ccr .userParams , ccr .systemText , ccr .systemParams , ccr .functionCallbacks ,
@@ -411,7 +438,11 @@ public <T> T entity(ParameterizedTypeReference<T> type) {
411
438
return doSingleWithBeanOutputConverter (new BeanOutputConverter <T >(type ));
412
439
}
413
440
414
- private <T > T doSingleWithBeanOutputConverter (BeanOutputConverter <T > boc ) {
441
+ public <T > T entity (StructuredOutputConverter <T > structuredOutputConverter ) {
442
+ return doSingleWithBeanOutputConverter (structuredOutputConverter );
443
+ }
444
+
445
+ private <T > T doSingleWithBeanOutputConverter (StructuredOutputConverter <T > boc ) {
415
446
var processedUserText = this .request .userText + System .lineSeparator () + System .lineSeparator ()
416
447
+ "{format}" ;
417
448
var chatResponse = doGetChatResponse (processedUserText , boc .getFormat ());
@@ -435,13 +466,15 @@ private ChatResponse doGetChatResponse(String processedUserText, String formatPa
435
466
userParams .put ("format" , formatParam );
436
467
}
437
468
438
- var messages = new ArrayList <Message >();
469
+ var messages = new ArrayList <Message >(this . request . messages );
439
470
var textsAreValid = (StringUtils .hasText (processedUserText )
440
471
|| StringUtils .hasText (this .request .systemText ));
441
- var messagesAreValid = !this .request .messages .isEmpty ();
442
- Assert .state (!(messagesAreValid && textsAreValid ), "you must specify either " + Message .class .getName ()
443
- + " instances or user/system texts, but not both" );
444
472
if (textsAreValid ) {
473
+ if (StringUtils .hasText (this .request .systemText ) || !this .request .systemParams .isEmpty ()) {
474
+ var systemMessage = new SystemMessage (
475
+ new PromptTemplate (this .request .systemText , this .request .systemParams ).render ());
476
+ messages .add (systemMessage );
477
+ }
445
478
UserMessage userMessage = null ;
446
479
if (!CollectionUtils .isEmpty (userParams )) {
447
480
userMessage = new UserMessage (new PromptTemplate (processedUserText , userParams ).render (),
@@ -450,16 +483,8 @@ private ChatResponse doGetChatResponse(String processedUserText, String formatPa
450
483
else {
451
484
userMessage = new UserMessage (processedUserText , this .request .media );
452
485
}
453
- if (StringUtils .hasText (this .request .systemText ) || !this .request .systemParams .isEmpty ()) {
454
- var systemMessage = new SystemMessage (
455
- new PromptTemplate (this .request .systemText , this .request .systemParams ).render ());
456
- messages .add (systemMessage );
457
- }
458
486
messages .add (userMessage );
459
487
}
460
- else {
461
- messages .addAll (this .request .messages );
462
- }
463
488
if (this .request .chatOptions instanceof FunctionCallingOptions functionCallingOptions ) {
464
489
// if (this.request.chatOptions instanceof
465
490
// FunctionCallingOptionsBuilder.PortableFunctionCallingOptions
0 commit comments