|
16 | 16 |
|
17 | 17 | package com.google.adk.agents; |
18 | 18 |
|
| 19 | +import static com.google.common.base.Preconditions.checkArgument; |
19 | 20 | import static com.google.common.base.Strings.isNullOrEmpty; |
20 | 21 | import static com.google.common.collect.ImmutableList.toImmutableList; |
21 | 22 | import static java.lang.String.format; |
22 | 23 |
|
23 | 24 | import com.google.adk.agents.Callbacks.AfterAgentCallback; |
24 | 25 | import com.google.adk.agents.Callbacks.BeforeAgentCallback; |
25 | 26 | import com.google.adk.events.Event; |
| 27 | +import com.google.adk.events.EventActions; |
26 | 28 | import com.google.adk.plugins.Plugin; |
27 | 29 | import com.google.adk.telemetry.Instrumentation; |
28 | 30 | import com.google.adk.telemetry.Instrumentation.AgentInvocation; |
|
39 | 41 | import java.util.ArrayList; |
40 | 42 | import java.util.HashSet; |
41 | 43 | import java.util.List; |
| 44 | +import java.util.Map; |
42 | 45 | import java.util.Optional; |
43 | 46 | import java.util.function.Function; |
44 | 47 | import java.util.regex.Pattern; |
@@ -136,10 +139,8 @@ private static void validateAgentName(String name) { |
136 | 139 | throw new IllegalArgumentException( |
137 | 140 | format("Agent name '%s' does not match regex '%s'.", name, IDENTIFIER_REGEX)); |
138 | 141 | } |
139 | | - if (name.equals(Role.USER)) { |
140 | | - throw new IllegalArgumentException( |
141 | | - "Agent name cannot be 'user'; reserved for end-user input."); |
142 | | - } |
| 142 | + checkArgument( |
| 143 | + !name.equals(Role.USER), "Agent name cannot be 'user'; reserved for end-user input."); |
143 | 144 | } |
144 | 145 |
|
145 | 146 | /** |
@@ -468,6 +469,44 @@ public Flowable<Event> runLive(InvocationContext parentContext) { |
468 | 469 | return run(parentContext, this::runLiveImpl); |
469 | 470 | } |
470 | 471 |
|
| 472 | + /** |
| 473 | + * Records this agent's end-of-agent checkpoint and returns it as a single-event stream. The |
| 474 | + * recorded state is cleared and the agent marked finished, so a later run skips it. |
| 475 | + * |
| 476 | + * @param context Current invocation context. |
| 477 | + * @return stream of the single {@code endOfAgent = true} checkpoint event. |
| 478 | + */ |
| 479 | + final Flowable<Event> endOfAgentAndRecord(InvocationContext context) { |
| 480 | + context.setAgentState(name(), /* agentState= */ null, /* endOfAgent= */ true); |
| 481 | + return Flowable.just(checkpointEvent(context, EventActions.builder().endOfAgent(true).build())); |
| 482 | + } |
| 483 | + |
| 484 | + /** |
| 485 | + * Records {@code agentState} for this agent and returns the matching checkpoint event as a |
| 486 | + * single-event stream. The agent is left unfinished, so a later run resumes from this checkpoint. |
| 487 | + * |
| 488 | + * @param context Current invocation context. |
| 489 | + * @param agentState The serialized agent state to persist. |
| 490 | + * @return stream of the single checkpoint event carrying {@code agentState}. |
| 491 | + */ |
| 492 | + final Flowable<Event> checkpointAndRecord( |
| 493 | + InvocationContext context, Map<String, Object> agentState) { |
| 494 | + context.setAgentState(name(), agentState, /* endOfAgent= */ false); |
| 495 | + return Flowable.just( |
| 496 | + checkpointEvent(context, EventActions.builder().agentState(agentState).build())); |
| 497 | + } |
| 498 | + |
| 499 | + /** Builds a resumability checkpoint event authored by this agent carrying {@code actions}. */ |
| 500 | + private Event checkpointEvent(InvocationContext context, EventActions actions) { |
| 501 | + return Event.builder() |
| 502 | + .id(Event.generateEventId()) |
| 503 | + .invocationId(context.invocationId()) |
| 504 | + .author(name()) |
| 505 | + .branch(context.branch().orElse(null)) |
| 506 | + .actions(actions) |
| 507 | + .build(); |
| 508 | + } |
| 509 | + |
471 | 510 | /** |
472 | 511 | * Agent-specific asynchronous logic. |
473 | 512 | * |
|
0 commit comments