Skip to content

Commit fb9274e

Browse files
kvmiloscopybara-github
authored andcommitted
feat: add avatar config support to the live streaming flow
PiperOrigin-RevId: 931042630
1 parent bfee8be commit fb9274e

4 files changed

Lines changed: 69 additions & 0 deletions

File tree

core/src/main/java/com/google/adk/agents/RunConfig.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.common.collect.ImmutableList;
2121
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2222
import com.google.genai.types.AudioTranscriptionConfig;
23+
import com.google.genai.types.AvatarConfig;
2324
import com.google.genai.types.Modality;
2425
import com.google.genai.types.SpeechConfig;
2526
import org.jspecify.annotations.Nullable;
@@ -67,6 +68,8 @@ public enum ToolExecutionMode {
6768

6869
public abstract ImmutableList<Modality> responseModalities();
6970

71+
public abstract @Nullable AvatarConfig avatarConfig();
72+
7073
public abstract boolean saveInputBlobsAsArtifacts();
7174

7275
public abstract StreamingMode streamingMode();
@@ -101,6 +104,7 @@ public static Builder builder(RunConfig runConfig) {
101104
.maxLlmCalls(runConfig.maxLlmCalls())
102105
.responseModalities(runConfig.responseModalities())
103106
.speechConfig(runConfig.speechConfig())
107+
.avatarConfig(runConfig.avatarConfig())
104108
.outputAudioTranscription(runConfig.outputAudioTranscription())
105109
.inputAudioTranscription(runConfig.inputAudioTranscription())
106110
.autoCreateSession(runConfig.autoCreateSession());
@@ -128,6 +132,9 @@ public final Builder setResponseModalities(Iterable<Modality> responseModalities
128132
@CanIgnoreReturnValue
129133
public abstract Builder responseModalities(Iterable<Modality> responseModalities);
130134

135+
@CanIgnoreReturnValue
136+
public abstract Builder avatarConfig(@Nullable AvatarConfig avatarConfig);
137+
131138
@Deprecated
132139
@CanIgnoreReturnValue
133140
public final Builder setSaveInputBlobsAsArtifacts(boolean saveInputBlobsAsArtifacts) {

core/src/main/java/com/google/adk/flows/llmflows/Basic.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public Single<RequestProcessor.RequestProcessingResult> processRequest(
4747
LiveConnectConfig.builder().responseModalities(context.runConfig().responseModalities());
4848
Optional.ofNullable(context.runConfig().speechConfig())
4949
.ifPresent(liveConnectConfigBuilder::speechConfig);
50+
Optional.ofNullable(context.runConfig().avatarConfig())
51+
.ifPresent(liveConnectConfigBuilder::avatarConfig);
5052
Optional.ofNullable(context.runConfig().outputAudioTranscription())
5153
.ifPresent(liveConnectConfigBuilder::outputAudioTranscription);
5254
Optional.ofNullable(context.runConfig().inputAudioTranscription())

core/src/test/java/com/google/adk/agents/RunConfigTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import com.google.common.collect.ImmutableList;
2323
import com.google.genai.types.AudioTranscriptionConfig;
24+
import com.google.genai.types.AvatarConfig;
25+
import com.google.genai.types.CustomizedAvatar;
2426
import com.google.genai.types.Modality;
2527
import com.google.genai.types.SpeechConfig;
2628
import org.junit.Test;
@@ -61,6 +63,7 @@ public void testBuilderDefaults() {
6163

6264
assertThat(runConfig.speechConfig()).isNull();
6365
assertThat(runConfig.responseModalities()).isEmpty();
66+
assertThat(runConfig.avatarConfig()).isNull();
6467
assertThat(runConfig.saveInputBlobsAsArtifacts()).isFalse();
6568
assertThat(runConfig.streamingMode()).isEqualTo(RunConfig.StreamingMode.NONE);
6669
assertThat(runConfig.outputAudioTranscription()).isNull();
@@ -122,4 +125,32 @@ public void testMaxLlmCalls_integerMaxValue_throwsIllegalArgumentException() {
122125
IllegalArgumentException.class,
123126
() -> RunConfig.builder().setMaxLlmCalls(Integer.MAX_VALUE).build());
124127
}
128+
129+
@Test
130+
public void testAvatarConfig_withName() {
131+
AvatarConfig avatarConfig = AvatarConfig.builder().avatarName("test_avatar").build();
132+
133+
RunConfig runConfig = RunConfig.builder().avatarConfig(avatarConfig).build();
134+
135+
assertThat(runConfig.avatarConfig()).isEqualTo(avatarConfig);
136+
assertThat(runConfig.avatarConfig().avatarName()).hasValue("test_avatar");
137+
assertThat(runConfig.avatarConfig().customizedAvatar()).isEmpty();
138+
}
139+
140+
@Test
141+
public void testAvatarConfig_withCustomizedAvatar() {
142+
CustomizedAvatar customizedAvatar =
143+
CustomizedAvatar.builder()
144+
.imageMimeType("image/jpeg")
145+
.imageData(new byte[] {1, 2, 3})
146+
.build();
147+
AvatarConfig avatarConfig = AvatarConfig.builder().customizedAvatar(customizedAvatar).build();
148+
149+
RunConfig runConfig = RunConfig.builder().avatarConfig(avatarConfig).build();
150+
151+
assertThat(runConfig.avatarConfig()).isEqualTo(avatarConfig);
152+
assertThat(runConfig.avatarConfig().customizedAvatar()).hasValue(customizedAvatar);
153+
assertThat(runConfig.avatarConfig().customizedAvatar().get().imageMimeType())
154+
.hasValue("image/jpeg");
155+
}
125156
}

core/src/test/java/com/google/adk/flows/llmflows/BasicTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import com.google.adk.testing.TestLlm;
3434
import com.google.common.collect.ImmutableList;
3535
import com.google.genai.types.AudioTranscriptionConfig;
36+
import com.google.genai.types.AvatarConfig;
37+
import com.google.genai.types.CustomizedAvatar;
3638
import com.google.genai.types.GenerateContentConfig;
3739
import com.google.genai.types.Modality;
3840
import com.google.genai.types.Schema;
@@ -60,6 +62,15 @@ public final class BasicTest {
6062
.build();
6163
private static final AudioTranscriptionConfig TEST_AUDIO_TRANSCRIPTION_CONFIG =
6264
AudioTranscriptionConfig.builder().build();
65+
private static final AvatarConfig TEST_AVATAR_CONFIG =
66+
AvatarConfig.builder()
67+
.avatarName("test-avatar")
68+
.customizedAvatar(
69+
CustomizedAvatar.builder()
70+
.imageMimeType("image/jpeg")
71+
.imageData(new byte[] {1, 2, 3})
72+
.build())
73+
.build();
6374

6475
private Basic basicProcessor;
6576
private TestLlm testLlm;
@@ -201,6 +212,22 @@ public void processRequest_buildsLiveConnectConfigFromRunConfig_speechConfig() {
201212
assertThat(result.events()).isEmpty();
202213
}
203214

215+
@Test
216+
public void processRequest_buildsLiveConnectConfigFromRunConfig_avatarConfig() {
217+
RunConfig runConfig = RunConfig.builder().avatarConfig(TEST_AVATAR_CONFIG).build();
218+
LlmAgent agentWithConfig = LlmAgent.builder().name("agentWithConfig").model(testLlm).build();
219+
InvocationContext contextWithRunConfig = createInvocationContext(agentWithConfig, runConfig);
220+
221+
RequestProcessingResult result =
222+
basicProcessor.processRequest(contextWithRunConfig, initialRequest).blockingGet();
223+
224+
LlmRequest updatedRequest = result.updatedRequest();
225+
assertThat(updatedRequest.liveConnectConfig()).isNotNull();
226+
assertThat(updatedRequest.liveConnectConfig().responseModalities().get()).isEmpty();
227+
assertThat(updatedRequest.liveConnectConfig().avatarConfig()).hasValue(TEST_AVATAR_CONFIG);
228+
assertThat(result.events()).isEmpty();
229+
}
230+
204231
@Test
205232
public void processRequest_buildsLiveConnectConfigFromRunConfig_outputAudioTranscription() {
206233
RunConfig runConfig =
@@ -245,6 +272,7 @@ public void processRequest_buildsLiveConnectConfigFromRunConfig_allFields() {
245272
RunConfig.builder()
246273
.setResponseModalities(ImmutableList.of(new Modality(Modality.Known.AUDIO)))
247274
.setSpeechConfig(TEST_SPEECH_CONFIG)
275+
.avatarConfig(TEST_AVATAR_CONFIG)
248276
.setOutputAudioTranscription(TEST_AUDIO_TRANSCRIPTION_CONFIG)
249277
.setInputAudioTranscription(TEST_AUDIO_TRANSCRIPTION_CONFIG)
250278
.build();
@@ -259,6 +287,7 @@ public void processRequest_buildsLiveConnectConfigFromRunConfig_allFields() {
259287
assertThat(updatedRequest.liveConnectConfig().responseModalities().get())
260288
.containsExactly(new Modality(Modality.Known.AUDIO));
261289
assertThat(updatedRequest.liveConnectConfig().speechConfig()).hasValue(TEST_SPEECH_CONFIG);
290+
assertThat(updatedRequest.liveConnectConfig().avatarConfig()).hasValue(TEST_AVATAR_CONFIG);
262291
assertThat(updatedRequest.liveConnectConfig().outputAudioTranscription())
263292
.hasValue(TEST_AUDIO_TRANSCRIPTION_CONFIG);
264293
assertThat(updatedRequest.liveConnectConfig().inputAudioTranscription())

0 commit comments

Comments
 (0)