1818
1919import static com .google .common .base .Preconditions .checkArgument ;
2020import static com .google .common .base .Strings .isNullOrEmpty ;
21+ import static com .google .common .base .Strings .nullToEmpty ;
2122import static com .google .common .collect .ImmutableList .toImmutableList ;
2223import static java .lang .String .format ;
2324
2425import com .google .adk .agents .Callbacks .AfterAgentCallback ;
2526import com .google .adk .agents .Callbacks .BeforeAgentCallback ;
27+ import com .google .adk .annotations .Experimental ;
2628import com .google .adk .events .Event ;
2729import com .google .adk .events .EventActions ;
2830import com .google .adk .plugins .Plugin ;
2931import com .google .adk .telemetry .Instrumentation ;
3032import com .google .adk .telemetry .Instrumentation .AgentInvocation ;
3133import com .google .adk .telemetry .Tracing ;
3234import com .google .adk .utils .AgentEnums .AgentOrigin ;
35+ import com .google .adk .workflow .BaseNode ;
3336import com .google .common .collect .ImmutableList ;
3437import com .google .errorprone .annotations .CanIgnoreReturnValue ;
3538import com .google .errorprone .annotations .DoNotCall ;
4952import org .jspecify .annotations .Nullable ;
5053
5154/** Base class for all agents. */
52- public abstract class BaseAgent {
55+ public abstract class BaseAgent extends BaseNode {
5356
5457 // Pattern for valid agent names.
5558 private static final String IDENTIFIER_REGEX = "^_?[a-zA-Z0-9]*([. _-][a-zA-Z0-9]+)*$" ;
5659 private static final Pattern IDENTIFIER_PATTERN = Pattern .compile (IDENTIFIER_REGEX );
5760
58- /** The agent's name. Must be a unique identifier within the agent tree. */
59- private final String name ;
60-
61- /**
62- * One line description about the agent's capability. The system can use this for decision-making
63- * when delegating control to different agents.
64- */
65- private final String description ;
66-
6761 /**
6862 * The parent agent in the agent tree. Note that one agent cannot be added to two different
6963 * parents' sub-agents lists.
@@ -79,7 +73,7 @@ public abstract class BaseAgent {
7973 * Creates a new BaseAgent.
8074 *
8175 * @param name Unique agent name. Cannot be "user" (reserved).
82- * @param description Agent purpose.
76+ * @param description Agent purpose; null is treated as an empty string .
8377 * @param subAgents Agents managed by this agent.
8478 * @param beforeAgentCallback Callbacks before agent execution. Invoked in order until one doesn't
8579 * return null.
@@ -88,16 +82,14 @@ public abstract class BaseAgent {
8882 */
8983 public BaseAgent (
9084 String name ,
91- String description ,
85+ @ Nullable String description ,
9286 @ Nullable List <? extends BaseAgent > subAgents ,
9387 @ Nullable List <? extends BeforeAgentCallback > beforeAgentCallback ,
9488 @ Nullable List <? extends AfterAgentCallback > afterAgentCallback ) {
95- validateAgentName (name );
96- this .name = name ;
97- this .description = description ;
89+ super (validateAgentName (name ), nullToEmpty (description ));
9890 this .parentAgent = null ;
9991 this .subAgents = (subAgents != null ) ? ImmutableList .copyOf (subAgents ) : ImmutableList .of ();
100- validateSubAgents (this . name , this .subAgents );
92+ validateSubAgents (name , this .subAgents );
10193 this .beforeAgentCallback =
10294 (beforeAgentCallback != null )
10395 ? ImmutableList .copyOf (beforeAgentCallback )
@@ -128,10 +120,12 @@ public Completable close() {
128120 * Validates the agent name.
129121 *
130122 * @param name The agent name to validate.
123+ * @return the validated name.
131124 * @throws IllegalArgumentException if the agent name is null, empty, or does not match the
132125 * identifier pattern.
133126 */
134- private static void validateAgentName (String name ) {
127+ @ CanIgnoreReturnValue
128+ private static String validateAgentName (String name ) {
135129 if (isNullOrEmpty (name )) {
136130 throw new IllegalArgumentException ("Agent name cannot be null or empty." );
137131 }
@@ -141,6 +135,7 @@ private static void validateAgentName(String name) {
141135 }
142136 checkArgument (
143137 !name .equals (Role .USER ), "Agent name cannot be 'user'; reserved for end-user input." );
138+ return name ;
144139 }
145140
146141 /**
@@ -173,24 +168,6 @@ private static void validateSubAgents(
173168 }
174169 }
175170
176- /**
177- * Gets the agent's unique name.
178- *
179- * @return the unique name of the agent.
180- */
181- public final String name () {
182- return name ;
183- }
184-
185- /**
186- * Gets the one-line description of the agent's capability.
187- *
188- * @return the description of the agent.
189- */
190- public final String description () {
191- return description ;
192- }
193-
194171 /**
195172 * Retrieves the parent agent in the agent tree.
196173 *
@@ -312,7 +289,7 @@ private InvocationContext createInvocationContext(InvocationContext parentContex
312289 * @return stream of agent-generated events.
313290 */
314291 public Flowable <Event > runAsync (InvocationContext parentContext ) {
315- return run (parentContext , this ::runAsyncImpl );
292+ return runWithCallbacks (parentContext , this ::runAsyncImpl );
316293 }
317294
318295 /**
@@ -322,7 +299,7 @@ public Flowable<Event> runAsync(InvocationContext parentContext) {
322299 * @param runImplementation The agent-specific logic to run.
323300 * @return stream of agent-generated events.
324301 */
325- private Flowable <Event > run (
302+ private Flowable <Event > runWithCallbacks (
326303 InvocationContext parentContext ,
327304 Function <InvocationContext , Flowable <Event >> runImplementation ) {
328305 return Flowable .using (
@@ -468,7 +445,7 @@ private Maybe<Event> callCallback(
468445 * @return stream of agent-generated events.
469446 */
470447 public Flowable <Event > runLive (InvocationContext parentContext ) {
471- return run (parentContext , this ::runLiveImpl );
448+ return runWithCallbacks (parentContext , this ::runLiveImpl );
472449 }
473450
474451 /**
@@ -510,6 +487,17 @@ private Event checkpointEvent(InvocationContext context, EventActions actions) {
510487 .build ();
511488 }
512489
490+ /**
491+ * Runs this agent as a workflow node through its {@link #runAsync} lifecycle, including its
492+ * callbacks. The node input is not used.
493+ */
494+ @ Experimental
495+ @ Override
496+ public Flowable <Event > runNode (
497+ com .google .adk .agents .Context context , @ Nullable Object nodeInput ) {
498+ return runAsync (context .invocationContext ());
499+ }
500+
513501 /**
514502 * Agent-specific asynchronous logic.
515503 *
0 commit comments