Skip to content

Commit ce82089

Browse files
feat: add agentic_generative_ui agent
1 parent 7bf05b7 commit ce82089

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

integrations/adk-middleware/python/examples/server/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from .api import (
2121
agentic_chat_app,
22+
agentic_generative_ui_app,
2223
tool_based_generative_ui_app,
2324
human_in_the_loop_app,
2425
shared_state_app,
@@ -30,6 +31,7 @@
3031

3132
# Include routers instead of mounting apps to show routes in docs
3233
app.include_router(agentic_chat_app.router, prefix='/chat', tags=['Agentic Chat'])
34+
app.include_router(agentic_generative_ui_app.router, prefix='/adk-agentic-generative-ui', tags=['Agentic Generative UI'])
3335
app.include_router(tool_based_generative_ui_app.router, prefix='/adk-tool-based-generative-ui', tags=['Tool Based Generative UI'])
3436
app.include_router(human_in_the_loop_app.router, prefix='/adk-human-in-loop-agent', tags=['Human in the Loop'])
3537
app.include_router(shared_state_app.router, prefix='/adk-shared-state-agent', tags=['Shared State'])
@@ -43,6 +45,7 @@ async def root():
4345
"message": "ADK Middleware is running!",
4446
"endpoints": {
4547
"chat": "/chat",
48+
"agentic_generative_ui": "/adk-agentic-generative-ui",
4649
"tool_based_generative_ui": "/adk-tool-based-generative-ui",
4750
"human_in_the_loop": "/adk-human-in-loop-agent",
4851
"shared_state": "/adk-shared-state-agent",
@@ -83,6 +86,7 @@ def main():
8386
print("Starting ADK Middleware server...")
8487
print(f"Available endpoints:")
8588
print(f" • Chat: http://localhost:{port}/chat")
89+
print(f" • Agentic Generative UI: http://localhost:{port}/adk-agentic-generative-ui")
8690
print(f" • Tool Based Generative UI: http://localhost:{port}/adk-tool-based-generative-ui")
8791
print(f" • Human in the Loop: http://localhost:{port}/adk-human-in-loop-agent")
8892
print(f" • Shared State: http://localhost:{port}/adk-shared-state-agent")

integrations/adk-middleware/python/examples/server/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""API modules for ADK middleware examples."""
22

33
from .agentic_chat import app as agentic_chat_app
4+
from .agentic_generative_ui import app as agentic_generative_ui_app
45
from .tool_based_generative_ui import app as tool_based_generative_ui_app
56
from .human_in_the_loop import app as human_in_the_loop_app
67
from .shared_state import app as shared_state_app
@@ -9,6 +10,7 @@
910

1011
__all__ = [
1112
"agentic_chat_app",
13+
"agentic_generative_ui_app",
1214
"tool_based_generative_ui_app",
1315
"human_in_the_loop_app",
1416
"shared_state_app",
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
"""Agentic Generative UI feature."""
2+
3+
from __future__ import annotations
4+
5+
from textwrap import dedent
6+
from typing import Any, Literal
7+
8+
from fastapi import FastAPI
9+
from pydantic import BaseModel, Field
10+
11+
from ag_ui.core import EventType, StateDeltaEvent, StateSnapshotEvent
12+
from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint
13+
from google.adk.agents import LlmAgent
14+
15+
StepStatus = Literal['pending', 'completed']
16+
17+
18+
class Step(BaseModel):
19+
"""Represents a step in a plan."""
20+
21+
description: str = Field(description='The description of the step')
22+
status: StepStatus = Field(
23+
default='pending',
24+
description='The status of the step (e.g., pending, completed)',
25+
)
26+
27+
28+
class Plan(BaseModel):
29+
"""Represents a plan with multiple steps."""
30+
31+
steps: list[Step] = Field(default_factory=list, description='The steps in the plan')
32+
33+
34+
class JSONPatchOp(BaseModel):
35+
"""A class representing a JSON Patch operation (RFC 6902)."""
36+
37+
op: Literal['add', 'remove', 'replace', 'move', 'copy', 'test'] = Field(
38+
description='The operation to perform: add, remove, replace, move, copy, or test',
39+
)
40+
path: str = Field(description='JSON Pointer (RFC 6901) to the target location')
41+
value: Any = Field(
42+
default=None,
43+
description='The value to apply (for add, replace operations)',
44+
)
45+
from_: str | None = Field(
46+
default=None,
47+
alias='from',
48+
description='Source path (for move, copy operations)',
49+
)
50+
51+
52+
async def create_plan(steps: list[str]) -> StateSnapshotEvent:
53+
"""Create a plan with multiple steps.
54+
55+
Args:
56+
steps (list[str]): List of step descriptions to create the plan.
57+
58+
Returns:
59+
StateSnapshotEvent: Event containing the initial state of the steps.
60+
"""
61+
plan: Plan = Plan(
62+
steps=[Step(description=step) for step in steps],
63+
)
64+
return StateSnapshotEvent(
65+
type=EventType.STATE_SNAPSHOT,
66+
snapshot=plan.model_dump(),
67+
)
68+
69+
70+
async def update_plan_step(
71+
index: int, description: str | None = None, status: StepStatus | None = None
72+
) -> StateDeltaEvent:
73+
"""Update the plan with new steps or changes.
74+
75+
Args:
76+
index (int): The index of the step to update.
77+
description (str | None): The new description for the step.
78+
status (StepStatus | None): The new status for the step.
79+
80+
Returns:
81+
StateDeltaEvent: Event containing the changes made to the plan.
82+
"""
83+
changes: list[JSONPatchOp] = []
84+
if description is not None:
85+
changes.append(
86+
JSONPatchOp(
87+
op='replace', path=f'/steps/{index}/description', value=description
88+
)
89+
)
90+
if status is not None:
91+
changes.append(
92+
JSONPatchOp(op='replace', path=f'/steps/{index}/status', value=status)
93+
)
94+
return StateDeltaEvent(
95+
type=EventType.STATE_DELTA,
96+
delta=changes,
97+
)
98+
99+
100+
# Create the ADK agent
101+
agent = LlmAgent(
102+
name="planner",
103+
model="gemini-2.0-flash",
104+
instruction=dedent(
105+
"""
106+
When planning use tools only, without any other messages.
107+
IMPORTANT:
108+
- Use the `create_plan` tool to set the initial state of the steps
109+
- Use the `update_plan_step` tool to update the status of each step
110+
- Do NOT repeat the plan or summarise it in a message
111+
- Do NOT confirm the creation or updates in a message
112+
- Do NOT ask the user for additional information or next steps
113+
- Do NOT leave a plan hanging, always complete the plan via `update_plan_step` if one is ongoing.
114+
115+
Only one plan can be active at a time, so do not call the `create_plan` tool
116+
again until all the steps in current plan are completed.
117+
"""
118+
),
119+
tools=[create_plan, update_plan_step],
120+
)
121+
122+
# Create ADK middleware agent instance
123+
adk_agent = ADKAgent(
124+
adk_agent=agent,
125+
app_name="demo_app",
126+
user_id="demo_user",
127+
session_timeout_seconds=3600,
128+
use_in_memory_services=True,
129+
)
130+
131+
# Create FastAPI app
132+
app = FastAPI(title="ADK Middleware Agentic Generative UI")
133+
134+
# Add the ADK endpoint
135+
add_adk_fastapi_endpoint(app, adk_agent, path="/")

0 commit comments

Comments
 (0)