Skip to content

Commit a2653a6

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: Setting up data structures for pause/resume/rewind
PiperOrigin-RevId: 860852195
1 parent 1da942f commit a2653a6

File tree

6 files changed

+260
-17
lines changed

6 files changed

+260
-17
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.agents;
18+
19+
import com.google.adk.JsonBaseModel;
20+
21+
/** Base class for all agent states. */
22+
public class BaseAgentState extends JsonBaseModel {
23+
24+
protected BaseAgentState() {}
25+
26+
/** Returns a new {@link Builder} for creating {@link BaseAgentState} instances. */
27+
public static Builder builder() {
28+
return new Builder();
29+
}
30+
31+
/** Builder for {@link BaseAgentState}. */
32+
public static class Builder {
33+
private Builder() {}
34+
35+
public BaseAgentState build() {
36+
return new BaseAgentState();
37+
}
38+
}
39+
}

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ public class InvocationContext {
5050
private final Session session;
5151
private final Optional<Content> userContent;
5252
private final RunConfig runConfig;
53+
private final Map<String, BaseAgentState> agentStates;
54+
private final Map<String, Boolean> endOfAgents;
5355
private final ResumabilityConfig resumabilityConfig;
5456
private final InvocationCostManager invocationCostManager;
5557

@@ -71,6 +73,8 @@ protected InvocationContext(Builder builder) {
7173
this.userContent = builder.userContent;
7274
this.runConfig = builder.runConfig;
7375
this.endInvocation = builder.endInvocation;
76+
this.agentStates = builder.agentStates;
77+
this.endOfAgents = builder.endOfAgents;
7478
this.resumabilityConfig = builder.resumabilityConfig;
7579
this.invocationCostManager = builder.invocationCostManager;
7680
}
@@ -299,6 +303,16 @@ public RunConfig runConfig() {
299303
return runConfig;
300304
}
301305

306+
/** Returns agent-specific state saved within this invocation. */
307+
public Map<String, BaseAgentState> agentStates() {
308+
return agentStates;
309+
}
310+
311+
/** Returns map of agents that ended during this invocation. */
312+
public Map<String, Boolean> endOfAgents() {
313+
return endOfAgents;
314+
}
315+
302316
/**
303317
* Returns whether this invocation should be ended, e.g., due to reaching a terminal state or
304318
* error.
@@ -410,6 +424,8 @@ private Builder(InvocationContext context) {
410424
this.userContent = context.userContent;
411425
this.runConfig = context.runConfig;
412426
this.endInvocation = context.endInvocation;
427+
this.agentStates = new ConcurrentHashMap<>(context.agentStates);
428+
this.endOfAgents = new ConcurrentHashMap<>(context.endOfAgents);
413429
this.resumabilityConfig = context.resumabilityConfig;
414430
this.invocationCostManager = context.invocationCostManager;
415431
}
@@ -427,6 +443,8 @@ private Builder(InvocationContext context) {
427443
private Optional<Content> userContent = Optional.empty();
428444
private RunConfig runConfig = RunConfig.builder().build();
429445
private boolean endInvocation = false;
446+
private Map<String, BaseAgentState> agentStates = new ConcurrentHashMap<>();
447+
private Map<String, Boolean> endOfAgents = new ConcurrentHashMap<>();
430448
private ResumabilityConfig resumabilityConfig = new ResumabilityConfig();
431449
private InvocationCostManager invocationCostManager = new InvocationCostManager();
432450

@@ -616,6 +634,30 @@ public Builder endInvocation(boolean endInvocation) {
616634
return this;
617635
}
618636

637+
/**
638+
* Sets agent-specific state saved within this invocation.
639+
*
640+
* @param agentStates agent-specific state saved within this invocation.
641+
* @return this builder instance for chaining.
642+
*/
643+
@CanIgnoreReturnValue
644+
public Builder agentStates(Map<String, BaseAgentState> agentStates) {
645+
this.agentStates = agentStates;
646+
return this;
647+
}
648+
649+
/**
650+
* Sets agent end-of-invocation status.
651+
*
652+
* @param endOfAgents agent end-of-invocation status.
653+
* @return this builder instance for chaining.
654+
*/
655+
@CanIgnoreReturnValue
656+
public Builder endOfAgents(Map<String, Boolean> endOfAgents) {
657+
this.endOfAgents = endOfAgents;
658+
return this;
659+
}
660+
619661
/**
620662
* Sets the resumability configuration for the current agent run.
621663
*
@@ -660,6 +702,8 @@ public boolean equals(Object o) {
660702
&& Objects.equals(session, that.session)
661703
&& Objects.equals(userContent, that.userContent)
662704
&& Objects.equals(runConfig, that.runConfig)
705+
&& Objects.equals(agentStates, that.agentStates)
706+
&& Objects.equals(endOfAgents, that.endOfAgents)
663707
&& Objects.equals(resumabilityConfig, that.resumabilityConfig)
664708
&& Objects.equals(invocationCostManager, that.invocationCostManager);
665709
}
@@ -680,6 +724,8 @@ public int hashCode() {
680724
userContent,
681725
runConfig,
682726
endInvocation,
727+
agentStates,
728+
endOfAgents,
683729
resumabilityConfig,
684730
invocationCostManager);
685731
}

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -704,16 +704,7 @@ private static boolean isThought(Part part) {
704704

705705
@Override
706706
protected Flowable<Event> runAsyncImpl(InvocationContext invocationContext) {
707-
return llmFlow
708-
.run(invocationContext)
709-
.concatMap(
710-
event -> {
711-
this.maybeSaveOutputToState(event);
712-
if (invocationContext.shouldPauseInvocation(event)) {
713-
return Flowable.just(event).concatWith(Flowable.empty());
714-
}
715-
return Flowable.just(event);
716-
});
707+
return llmFlow.run(invocationContext).doOnNext(this::maybeSaveOutputToState);
717708
}
718709

719710
@Override

core/src/main/java/com/google/adk/events/EventActions.java

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.fasterxml.jackson.annotation.JsonProperty;
1919
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
20+
import com.google.adk.agents.BaseAgentState;
2021
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2122
import com.google.genai.types.Part;
2223
import java.util.Objects;
@@ -37,8 +38,12 @@ public class EventActions {
3738
private Optional<Boolean> escalate;
3839
private ConcurrentMap<String, ConcurrentMap<String, Object>> requestedAuthConfigs;
3940
private ConcurrentMap<String, ToolConfirmation> requestedToolConfirmations;
41+
private boolean endOfAgent;
42+
private ConcurrentMap<String, BaseAgentState> agentStates;
43+
private boolean pauseInvocation;
4044
private Optional<Boolean> endInvocation;
4145
private Optional<EventCompaction> compaction;
46+
private Optional<String> rewindBeforeInvocationId;
4247

4348
/** Default constructor for Jackson. */
4449
public EventActions() {
@@ -49,8 +54,12 @@ public EventActions() {
4954
this.escalate = Optional.empty();
5055
this.requestedAuthConfigs = new ConcurrentHashMap<>();
5156
this.requestedToolConfirmations = new ConcurrentHashMap<>();
57+
this.endOfAgent = false;
58+
this.pauseInvocation = false;
5259
this.endInvocation = Optional.empty();
5360
this.compaction = Optional.empty();
61+
this.agentStates = new ConcurrentHashMap<>();
62+
this.rewindBeforeInvocationId = Optional.empty();
5463
}
5564

5665
private EventActions(Builder builder) {
@@ -61,8 +70,12 @@ private EventActions(Builder builder) {
6170
this.escalate = builder.escalate;
6271
this.requestedAuthConfigs = builder.requestedAuthConfigs;
6372
this.requestedToolConfirmations = builder.requestedToolConfirmations;
73+
this.endOfAgent = builder.endOfAgent;
74+
this.pauseInvocation = builder.pauseInvocation;
6475
this.endInvocation = builder.endInvocation;
6576
this.compaction = builder.compaction;
77+
this.agentStates = builder.agentStates;
78+
this.rewindBeforeInvocationId = builder.rewindBeforeInvocationId;
6679
}
6780

6881
@JsonProperty("skipSummarization")
@@ -146,6 +159,24 @@ public void setRequestedToolConfirmations(
146159
this.requestedToolConfirmations = requestedToolConfirmations;
147160
}
148161

162+
@JsonProperty("endOfAgent")
163+
public boolean endOfAgent() {
164+
return endOfAgent;
165+
}
166+
167+
public void setEndOfAgent(boolean endOfAgent) {
168+
this.endOfAgent = endOfAgent;
169+
}
170+
171+
@JsonProperty("pauseInvocation")
172+
public boolean pauseInvocation() {
173+
return pauseInvocation;
174+
}
175+
176+
public void setPauseInvocation(boolean pauseInvocation) {
177+
this.pauseInvocation = pauseInvocation;
178+
}
179+
149180
@JsonProperty("endInvocation")
150181
public Optional<Boolean> endInvocation() {
151182
return endInvocation;
@@ -168,6 +199,24 @@ public void setCompaction(Optional<EventCompaction> compaction) {
168199
this.compaction = compaction;
169200
}
170201

202+
@JsonProperty("agentStates")
203+
public ConcurrentMap<String, BaseAgentState> agentStates() {
204+
return agentStates;
205+
}
206+
207+
public void setAgentStates(ConcurrentMap<String, BaseAgentState> agentStates) {
208+
this.agentStates = agentStates;
209+
}
210+
211+
@JsonProperty("rewindBeforeInvocationId")
212+
public Optional<String> rewindBeforeInvocationId() {
213+
return rewindBeforeInvocationId;
214+
}
215+
216+
public void setRewindBeforeInvocationId(@Nullable String rewindBeforeInvocationId) {
217+
this.rewindBeforeInvocationId = Optional.ofNullable(rewindBeforeInvocationId);
218+
}
219+
171220
public static Builder builder() {
172221
return new Builder();
173222
}
@@ -191,8 +240,12 @@ public boolean equals(Object o) {
191240
&& Objects.equals(escalate, that.escalate)
192241
&& Objects.equals(requestedAuthConfigs, that.requestedAuthConfigs)
193242
&& Objects.equals(requestedToolConfirmations, that.requestedToolConfirmations)
243+
&& (endOfAgent == that.endOfAgent)
244+
&& (pauseInvocation == that.pauseInvocation)
194245
&& Objects.equals(endInvocation, that.endInvocation)
195-
&& Objects.equals(compaction, that.compaction);
246+
&& Objects.equals(compaction, that.compaction)
247+
&& Objects.equals(agentStates, that.agentStates)
248+
&& Objects.equals(rewindBeforeInvocationId, that.rewindBeforeInvocationId);
196249
}
197250

198251
@Override
@@ -205,8 +258,12 @@ public int hashCode() {
205258
escalate,
206259
requestedAuthConfigs,
207260
requestedToolConfirmations,
261+
endOfAgent,
262+
pauseInvocation,
208263
endInvocation,
209-
compaction);
264+
compaction,
265+
agentStates,
266+
rewindBeforeInvocationId);
210267
}
211268

212269
/** Builder for {@link EventActions}. */
@@ -218,8 +275,12 @@ public static class Builder {
218275
private Optional<Boolean> escalate;
219276
private ConcurrentMap<String, ConcurrentMap<String, Object>> requestedAuthConfigs;
220277
private ConcurrentMap<String, ToolConfirmation> requestedToolConfirmations;
278+
private boolean endOfAgent = false;
279+
private boolean pauseInvocation = false;
221280
private Optional<Boolean> endInvocation;
222281
private Optional<EventCompaction> compaction;
282+
private ConcurrentMap<String, BaseAgentState> agentStates;
283+
private Optional<String> rewindBeforeInvocationId;
223284

224285
public Builder() {
225286
this.skipSummarization = Optional.empty();
@@ -231,6 +292,8 @@ public Builder() {
231292
this.requestedToolConfirmations = new ConcurrentHashMap<>();
232293
this.endInvocation = Optional.empty();
233294
this.compaction = Optional.empty();
295+
this.agentStates = new ConcurrentHashMap<>();
296+
this.rewindBeforeInvocationId = Optional.empty();
234297
}
235298

236299
private Builder(EventActions eventActions) {
@@ -242,8 +305,12 @@ private Builder(EventActions eventActions) {
242305
this.requestedAuthConfigs = new ConcurrentHashMap<>(eventActions.requestedAuthConfigs());
243306
this.requestedToolConfirmations =
244307
new ConcurrentHashMap<>(eventActions.requestedToolConfirmations());
308+
this.endOfAgent = eventActions.endOfAgent();
309+
this.pauseInvocation = eventActions.pauseInvocation();
245310
this.endInvocation = eventActions.endInvocation();
246311
this.compaction = eventActions.compaction();
312+
this.agentStates = new ConcurrentHashMap<>(eventActions.agentStates());
313+
this.rewindBeforeInvocationId = eventActions.rewindBeforeInvocationId();
247314
}
248315

249316
@CanIgnoreReturnValue
@@ -296,6 +363,20 @@ public Builder requestedToolConfirmations(ConcurrentMap<String, ToolConfirmation
296363
return this;
297364
}
298365

366+
@CanIgnoreReturnValue
367+
@JsonProperty("endOfAgent")
368+
public Builder endOfAgent(boolean endOfAgent) {
369+
this.endOfAgent = endOfAgent;
370+
return this;
371+
}
372+
373+
@CanIgnoreReturnValue
374+
@JsonProperty("pauseInvocation")
375+
public Builder pauseInvocation(boolean pauseInvocation) {
376+
this.pauseInvocation = pauseInvocation;
377+
return this;
378+
}
379+
299380
@CanIgnoreReturnValue
300381
@JsonProperty("endInvocation")
301382
public Builder endInvocation(boolean endInvocation) {
@@ -310,6 +391,20 @@ public Builder compaction(EventCompaction value) {
310391
return this;
311392
}
312393

394+
@CanIgnoreReturnValue
395+
@JsonProperty("agentStates")
396+
public Builder agentStates(ConcurrentMap<String, BaseAgentState> agentStates) {
397+
this.agentStates = agentStates;
398+
return this;
399+
}
400+
401+
@CanIgnoreReturnValue
402+
@JsonProperty("rewindBeforeInvocationId")
403+
public Builder rewindBeforeInvocationId(String rewindBeforeInvocationId) {
404+
this.rewindBeforeInvocationId = Optional.ofNullable(rewindBeforeInvocationId);
405+
return this;
406+
}
407+
313408
@CanIgnoreReturnValue
314409
public Builder merge(EventActions other) {
315410
other.skipSummarization().ifPresent(this::skipSummarization);
@@ -319,8 +414,12 @@ public Builder merge(EventActions other) {
319414
other.escalate().ifPresent(this::escalate);
320415
this.requestedAuthConfigs.putAll(other.requestedAuthConfigs());
321416
this.requestedToolConfirmations.putAll(other.requestedToolConfirmations());
417+
this.endOfAgent = other.endOfAgent();
418+
this.pauseInvocation = other.pauseInvocation();
322419
other.endInvocation().ifPresent(this::endInvocation);
323420
other.compaction().ifPresent(this::compaction);
421+
this.agentStates.putAll(other.agentStates());
422+
other.rewindBeforeInvocationId().ifPresent(this::rewindBeforeInvocationId);
324423
return this;
325424
}
326425

0 commit comments

Comments
 (0)