Skip to content

Commit 5ebfc33

Browse files
feat: [vertexai] allow setting ToolConfig and SystemInstruction in ChatSession (#10953)
PiperOrigin-RevId: 641987014 Co-authored-by: Jaycee Li <jayceeli@google.com>
1 parent 0801812 commit 5ebfc33

2 files changed

Lines changed: 86 additions & 36 deletions

File tree

java-vertexai/google-cloud-vertexai/src/main/java/com/google/cloud/vertexai/generativeai/ChatSession.java

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.google.cloud.vertexai.api.GenerationConfig;
3030
import com.google.cloud.vertexai.api.SafetySetting;
3131
import com.google.cloud.vertexai.api.Tool;
32+
import com.google.cloud.vertexai.api.ToolConfig;
3233
import com.google.common.collect.ImmutableList;
3334
import java.io.IOException;
3435
import java.util.ArrayList;
@@ -40,8 +41,8 @@ public final class ChatSession {
4041
private final GenerativeModel model;
4142
private final Optional<ChatSession> rootChatSession;
4243
private final Optional<AutomaticFunctionCallingResponder> automaticFunctionCallingResponder;
43-
private List<Content> history = new ArrayList<>();
44-
private int previousHistorySize = 0;
44+
private List<Content> history;
45+
private int previousHistorySize;
4546
private Optional<ResponseStream<GenerateContentResponse>> currentResponseStream;
4647
private Optional<GenerateContentResponse> currentResponse;
4748

@@ -50,14 +51,17 @@ public final class ChatSession {
5051
* GenerationConfig) inherits from the model.
5152
*/
5253
public ChatSession(GenerativeModel model) {
53-
this(model, Optional.empty(), Optional.empty());
54+
this(model, new ArrayList<>(), 0, Optional.empty(), Optional.empty());
5455
}
5556

5657
/**
5758
* Creates a new chat session given a GenerativeModel instance and a root chat session.
5859
* Configurations of the chat (e.g., GenerationConfig) inherits from the model.
5960
*
6061
* @param model a {@link GenerativeModel} instance that generates contents in the chat.
62+
* @param history a list of {@link Content} containing interleaving conversation between "user"
63+
* and "model".
64+
* @param previousHistorySize the size of the previous history.
6165
* @param rootChatSession a root {@link ChatSession} instance. All the chat history in the current
6266
* chat session will be merged to the root chat session.
6367
* @param automaticFunctionCallingResponder an {@link AutomaticFunctionCallingResponder} instance
@@ -66,10 +70,14 @@ public ChatSession(GenerativeModel model) {
6670
*/
6771
private ChatSession(
6872
GenerativeModel model,
73+
List<Content> history,
74+
int previousHistorySize,
6975
Optional<ChatSession> rootChatSession,
7076
Optional<AutomaticFunctionCallingResponder> automaticFunctionCallingResponder) {
7177
checkNotNull(model, "model should not be null");
7278
this.model = model;
79+
this.history = history;
80+
this.previousHistorySize = previousHistorySize;
7381
this.rootChatSession = rootChatSession;
7482
this.automaticFunctionCallingResponder = automaticFunctionCallingResponder;
7583
currentResponseStream = Optional.empty();
@@ -84,15 +92,12 @@ private ChatSession(
8492
* @return a new {@link ChatSession} instance with the specified GenerationConfig.
8593
*/
8694
public ChatSession withGenerationConfig(GenerationConfig generationConfig) {
87-
ChatSession rootChat = rootChatSession.orElse(this);
88-
ChatSession newChatSession =
89-
new ChatSession(
90-
model.withGenerationConfig(generationConfig),
91-
Optional.of(rootChat),
92-
automaticFunctionCallingResponder);
93-
newChatSession.history = history;
94-
newChatSession.previousHistorySize = previousHistorySize;
95-
return newChatSession;
95+
return new ChatSession(
96+
model.withGenerationConfig(generationConfig),
97+
history,
98+
previousHistorySize,
99+
Optional.of(rootChatSession.orElse(this)),
100+
automaticFunctionCallingResponder);
96101
}
97102

98103
/**
@@ -103,15 +108,12 @@ public ChatSession withGenerationConfig(GenerationConfig generationConfig) {
103108
* @return a new {@link ChatSession} instance with the specified SafetySettings.
104109
*/
105110
public ChatSession withSafetySettings(List<SafetySetting> safetySettings) {
106-
ChatSession rootChat = rootChatSession.orElse(this);
107-
ChatSession newChatSession =
108-
new ChatSession(
109-
model.withSafetySettings(safetySettings),
110-
Optional.of(rootChat),
111-
automaticFunctionCallingResponder);
112-
newChatSession.history = history;
113-
newChatSession.previousHistorySize = previousHistorySize;
114-
return newChatSession;
111+
return new ChatSession(
112+
model.withSafetySettings(safetySettings),
113+
history,
114+
previousHistorySize,
115+
Optional.of(rootChatSession.orElse(this)),
116+
automaticFunctionCallingResponder);
115117
}
116118

117119
/**
@@ -122,13 +124,44 @@ public ChatSession withSafetySettings(List<SafetySetting> safetySettings) {
122124
* @return a new {@link ChatSession} instance with the specified Tools.
123125
*/
124126
public ChatSession withTools(List<Tool> tools) {
125-
ChatSession rootChat = rootChatSession.orElse(this);
126-
ChatSession newChatSession =
127-
new ChatSession(
128-
model.withTools(tools), Optional.of(rootChat), automaticFunctionCallingResponder);
129-
newChatSession.history = history;
130-
newChatSession.previousHistorySize = previousHistorySize;
131-
return newChatSession;
127+
return new ChatSession(
128+
model.withTools(tools),
129+
history,
130+
previousHistorySize,
131+
Optional.of(rootChatSession.orElse(this)),
132+
automaticFunctionCallingResponder);
133+
}
134+
135+
/**
136+
* Creates a copy of the current ChatSession with updated ToolConfig.
137+
*
138+
* @param toolConfig a {@link com.google.cloud.vertexai.api.ToolConfig} that will be used in the
139+
* new ChatSession.
140+
* @return a new {@link ChatSession} instance with the specified ToolConfigs.
141+
*/
142+
public ChatSession withToolConfig(ToolConfig toolConfig) {
143+
return new ChatSession(
144+
model.withToolConfig(toolConfig),
145+
history,
146+
previousHistorySize,
147+
Optional.of(rootChatSession.orElse(this)),
148+
automaticFunctionCallingResponder);
149+
}
150+
151+
/**
152+
* Creates a copy of the current ChatSession with updated SystemInstruction.
153+
*
154+
* @param systemInstruction a {@link com.google.cloud.vertexai.api.Content} containing system
155+
* instructions.
156+
* @return a new {@link ChatSession} instance with the specified ToolConfigs.
157+
*/
158+
public ChatSession withSystemInstruction(Content systemInstruction) {
159+
return new ChatSession(
160+
model.withSystemInstruction(systemInstruction),
161+
history,
162+
previousHistorySize,
163+
Optional.of(rootChatSession.orElse(this)),
164+
automaticFunctionCallingResponder);
132165
}
133166

134167
/**
@@ -141,13 +174,12 @@ public ChatSession withTools(List<Tool> tools) {
141174
*/
142175
public ChatSession withAutomaticFunctionCallingResponder(
143176
AutomaticFunctionCallingResponder automaticFunctionCallingResponder) {
144-
ChatSession rootChat = rootChatSession.orElse(this);
145-
ChatSession newChatSession =
146-
new ChatSession(
147-
model, Optional.of(rootChat), Optional.of(automaticFunctionCallingResponder));
148-
newChatSession.history = history;
149-
newChatSession.previousHistorySize = previousHistorySize;
150-
return newChatSession;
177+
return new ChatSession(
178+
model,
179+
history,
180+
previousHistorySize,
181+
Optional.of(rootChatSession.orElse(this)),
182+
Optional.of(automaticFunctionCallingResponder));
151183
}
152184

153185
/**

java-vertexai/google-cloud-vertexai/src/test/java/com/google/cloud/vertexai/generativeai/ChatSessionTest.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import com.google.cloud.vertexai.api.Candidate.FinishReason;
3030
import com.google.cloud.vertexai.api.Content;
3131
import com.google.cloud.vertexai.api.FunctionCall;
32+
import com.google.cloud.vertexai.api.FunctionCallingConfig;
3233
import com.google.cloud.vertexai.api.FunctionDeclaration;
3334
import com.google.cloud.vertexai.api.GenerateContentRequest;
3435
import com.google.cloud.vertexai.api.GenerateContentResponse;
@@ -40,6 +41,7 @@
4041
import com.google.cloud.vertexai.api.SafetySetting.HarmBlockThreshold;
4142
import com.google.cloud.vertexai.api.Schema;
4243
import com.google.cloud.vertexai.api.Tool;
44+
import com.google.cloud.vertexai.api.ToolConfig;
4345
import com.google.cloud.vertexai.api.Type;
4446
import com.google.protobuf.Struct;
4547
import com.google.protobuf.Value;
@@ -174,6 +176,16 @@ public final class ChatSessionTest {
174176
.build())
175177
.addRequired("location")))
176178
.build();
179+
private static final ToolConfig TOOL_CONFIG =
180+
ToolConfig.newBuilder()
181+
.setFunctionCallingConfig(
182+
FunctionCallingConfig.newBuilder()
183+
.setMode(FunctionCallingConfig.Mode.ANY)
184+
.addAllowedFunctionNames("getCurrentWeather"))
185+
.build();
186+
private static final Content SYSTEM_INSTRUCTION =
187+
ContentMaker.fromString(
188+
"You're a helpful assistant that starts all its answers with: \"COOL\"");
177189

178190
@Rule public final MockitoRule mocksRule = MockitoJUnit.rule();
179191

@@ -518,7 +530,9 @@ public void testChatSessionMergeHistoryToRootChatSession() throws Exception {
518530
rootChat
519531
.withGenerationConfig(GENERATION_CONFIG)
520532
.withSafetySettings(Arrays.asList(SAFETY_SETTING))
521-
.withTools(Arrays.asList(TOOL));
533+
.withTools(Arrays.asList(TOOL))
534+
.withToolConfig(TOOL_CONFIG)
535+
.withSystemInstruction(SYSTEM_INSTRUCTION);
522536
response = childChat.sendMessage(SAMPLE_MESSAGE_2);
523537

524538
// (Assert) root chat history should contain all 4 contents
@@ -532,8 +546,12 @@ public void testChatSessionMergeHistoryToRootChatSession() throws Exception {
532546
ArgumentCaptor<GenerateContentRequest> request =
533547
ArgumentCaptor.forClass(GenerateContentRequest.class);
534548
verify(mockUnaryCallable, times(2)).call(request.capture());
549+
Content expectedSystemInstruction = SYSTEM_INSTRUCTION.toBuilder().clearRole().build();
535550
assertThat(request.getAllValues().get(1).getGenerationConfig()).isEqualTo(GENERATION_CONFIG);
536551
assertThat(request.getAllValues().get(1).getSafetySettings(0)).isEqualTo(SAFETY_SETTING);
537552
assertThat(request.getAllValues().get(1).getTools(0)).isEqualTo(TOOL);
553+
assertThat(request.getAllValues().get(1).getToolConfig()).isEqualTo(TOOL_CONFIG);
554+
assertThat(request.getAllValues().get(1).getSystemInstruction())
555+
.isEqualTo(expectedSystemInstruction);
538556
}
539557
}

0 commit comments

Comments
 (0)