Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions dev/src/main/java/com/google/adk/web/AdkWebServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
Expand Down Expand Up @@ -87,10 +89,25 @@ public BaseMemoryService memoryService() {
* @return Configured ObjectMapper instance
*/
@Bean
@Primary
public ObjectMapper objectMapper() {
return JsonBaseModel.getMapper();
}

/**
* Configures the message converter to use the custom ADK ObjectMapper. This ensures that Spring
* Web uses the correct JSON serialization settings (like omitting absent optional fields) and
* prevents double-serialization issues, particularly for Server-Sent Events (SSE).
*
* @param objectMapper The primary ObjectMapper configured for the ADK.
* @return A configured MappingJackson2HttpMessageConverter.
*/
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
ObjectMapper objectMapper) {
return new MappingJackson2HttpMessageConverter(objectMapper);
}

/**
* Configures resource handlers for serving static content (like the Dev UI). Maps requests
* starting with "/dev-ui/" to the directory specified by the 'adk.web.ui.dir' system property.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ public List<Event> agentRun(@RequestBody AgentRunRequest request) {
RunConfig runConfig = RunConfig.builder().setStreamingMode(StreamingMode.NONE).build();
Flowable<Event> eventStream =
runner.runAsync(
request.userId, request.sessionId, request.newMessage, runConfig, request.stateDelta);
request.userId,
request.sessionId,
request.getNewMessage(),
runConfig,
request.stateDelta);

List<Event> events = Lists.newArrayList(eventStream.blockingIterable());
log.info("Agent run for session {} generated {} events.", request.sessionId, events.size());
Expand Down Expand Up @@ -155,7 +159,7 @@ public SseEmitter agentRunSse(@RequestBody AgentRunRequest request) {
runner.runAsync(
request.userId,
request.sessionId,
request.newMessage,
request.getNewMessage(),
runConfig,
request.stateDelta);

Expand All @@ -167,7 +171,7 @@ public SseEmitter agentRunSse(@RequestBody AgentRunRequest request) {
try {
log.debug(
"SseEmitter: Sending event {} for session {}", event.id(), sessionId);
emitter.send(SseEmitter.event().data(event.toJson()));
emitter.send(SseEmitter.event().data(event));
} catch (IOException e) {
log.error(
"SseEmitter: IOException sending event for session {}: {}",
Expand Down
15 changes: 13 additions & 2 deletions dev/src/main/java/com/google/adk/web/dto/AgentRunRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.adk.web.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.adk.JsonBaseModel;
import com.google.genai.types.Content;
import java.util.Map;
import javax.annotation.Nullable;
Expand All @@ -36,7 +37,7 @@ public class AgentRunRequest {
public String sessionId;

@JsonProperty("newMessage")
public Content newMessage;
public Object newMessage;

@JsonProperty("streaming")
public boolean streaming = false;
Expand Down Expand Up @@ -65,7 +66,17 @@ public String getSessionId() {
}

public Content getNewMessage() {
return newMessage;
if (newMessage instanceof Content) {
return (Content) newMessage;
}
if (newMessage != null) {
try {
return JsonBaseModel.getMapper().convertValue(newMessage, Content.class);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Failed to parse newMessage into Content", e);
}
}
return null;
}

public boolean getStreaming() {
Expand Down