Skip to content

Commit a1b277a

Browse files
committed
feat: support invoke adk webserver app
(cherry picked from commit f392a4a0376477922ed49de94a64509bd186fbcd)
1 parent eb061a7 commit a1b277a

File tree

6 files changed

+446
-30
lines changed

6 files changed

+446
-30
lines changed

agentkit/apps/agent_server_app/agent_server_app.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
from typing import override
1616

1717
import uvicorn
18+
import json
19+
from fastapi import Request
20+
from fastapi import HTTPException
21+
from fastapi.responses import StreamingResponse
1822
from google.adk.agents.base_agent import BaseAgent
1923
from google.adk.artifacts.in_memory_artifact_service import (
2024
InMemoryArtifactService,
@@ -30,6 +34,9 @@
3034
from google.adk.evaluation.local_eval_sets_manager import LocalEvalSetsManager
3135
from google.adk.memory.in_memory_memory_service import InMemoryMemoryService
3236
from google.adk.sessions.base_session_service import BaseSessionService
37+
from google.adk.agents.run_config import RunConfig, StreamingMode
38+
from google.adk.utils.context_utils import Aclosing
39+
from google.genai import types
3340
from veadk import Agent
3441
from veadk.memory.short_term_memory import ShortTermMemory
3542

@@ -80,6 +87,89 @@ def __init__(
8087

8188
self.app = self.server.get_fast_api_app()
8289

90+
async def _invoke_compat(request: Request):
91+
# Extract headers (fallback keys supported)
92+
headers = request.headers
93+
user_id = (
94+
headers.get("user_id") or headers.get("x-user-id") or "agentkit_user"
95+
)
96+
session_id = (
97+
headers.get("session_id")
98+
or headers.get("x-session-id")
99+
or "agentkit_sample_session"
100+
)
101+
102+
# Determine app_name from loader
103+
app_names = self.server.agent_loader.list_agents()
104+
if not app_names:
105+
raise HTTPException(status_code=404, detail="No agents configured")
106+
app_name = app_names[0]
107+
108+
# Parse payload and convert to ADK Content
109+
try:
110+
payload = await request.json()
111+
except Exception:
112+
payload = None
113+
114+
text = payload.get("prompt") if isinstance(payload, dict) else None
115+
if text is None:
116+
if payload is not None:
117+
try:
118+
text = json.dumps(payload, ensure_ascii=False)
119+
except Exception:
120+
text = ""
121+
else:
122+
try:
123+
body_bytes = await request.body()
124+
text = body_bytes.decode("utf-8")
125+
except Exception:
126+
text = ""
127+
content = types.UserContent(parts=[types.Part(text=text or "")])
128+
129+
# Ensure session exists
130+
session = await self.server.session_service.get_session(
131+
app_name=app_name, user_id=user_id, session_id=session_id
132+
)
133+
if not session:
134+
await self.server.session_service.create_session(
135+
app_name=app_name, user_id=user_id, session_id=session_id
136+
)
137+
138+
async def event_generator():
139+
try:
140+
runner = await self.server.get_runner_async(app_name)
141+
async with Aclosing(
142+
runner.run_async(
143+
user_id=user_id,
144+
session_id=session_id,
145+
new_message=content,
146+
run_config=RunConfig(streaming_mode=StreamingMode.SSE),
147+
)
148+
) as agen:
149+
async for event in agen:
150+
yield (
151+
"data: "
152+
+ event.model_dump_json(
153+
exclude_none=True, by_alias=True
154+
)
155+
+ "\n\n"
156+
)
157+
except Exception as e:
158+
yield f'data: {{"error": "{str(e)}"}}\n\n'
159+
160+
return StreamingResponse(
161+
event_generator(),
162+
media_type="text/event-stream",
163+
headers={
164+
"Cache-Control": "no-cache",
165+
"Connection": "keep-alive",
166+
"X-Accel-Buffering": "no",
167+
},
168+
)
169+
170+
# Compatibility route for AgentKit CLI invoke
171+
self.app.add_api_route("/invoke", _invoke_compat, methods=["POST"])
172+
83173
def run(self, host: str, port: int = 8000) -> None:
84174
"""Run the app with Uvicorn server."""
85175
uvicorn.run(self.app, host=host, port=port)

0 commit comments

Comments
 (0)