18
18
from contextlib import asynccontextmanager
19
19
import logging
20
20
import os
21
+ from pathlib import Path
21
22
import time
22
23
import traceback
23
24
import typing
31
32
from fastapi import HTTPException
32
33
from fastapi import Query
33
34
from fastapi .middleware .cors import CORSMiddleware
35
+ from fastapi .responses import JSONResponse
34
36
from fastapi .responses import RedirectResponse
35
37
from fastapi .responses import StreamingResponse
36
38
from fastapi .staticfiles import StaticFiles
44
46
from opentelemetry .sdk .trace import TracerProvider
45
47
from pydantic import Field
46
48
from pydantic import ValidationError
49
+ from starlette .responses import Response
47
50
from starlette .types import Lifespan
48
51
from typing_extensions import override
49
52
from watchdog .observers import Observer
@@ -193,6 +196,28 @@ class GetEventGraphResult(common.BaseModel):
193
196
dot_src : str
194
197
195
198
199
+ class ConfigInjectingStaticFiles (StaticFiles ):
200
+ """
201
+ Custom StaticFiles that injects config.json for dev-ui.
202
+ Fixes https://github.com/google/adk-python/issues/2072
203
+ """
204
+
205
+ def __init__ (self , * , directory , base_url : Optional [str ], ** kwargs ):
206
+ super ().__init__ (directory = directory , ** kwargs )
207
+ if base_url is None :
208
+ base_url = ""
209
+ self .base_url = base_url
210
+
211
+ async def get_response (self , path : str , scope ) -> Response :
212
+ # Check if the request is for config.json
213
+ if Path (path ).as_posix () == "assets/config/runtime-config.json" :
214
+ config = {"backendUrl" : self .base_url }
215
+ return JSONResponse (content = config )
216
+
217
+ # Otherwise, serve static files normally
218
+ return await super ().get_response (path , scope )
219
+
220
+
196
221
class AdkWebServer :
197
222
"""Helper class for setting up and running the ADK web server on FastAPI.
198
223
@@ -284,6 +309,7 @@ def get_fast_api_app(
284
309
[Observer , "AdkWebServer" ], None
285
310
] = lambda o , s : None ,
286
311
register_processors : Callable [[TracerProvider ], None ] = lambda o : None ,
312
+ base_url : Optional [str ] = None ,
287
313
):
288
314
"""Creates a FastAPI app for the ADK web server.
289
315
@@ -300,6 +326,8 @@ def get_fast_api_app(
300
326
tear_down_observer: Callback for cleaning up the file system observer.
301
327
register_processors: Callback for additional Span processors to be added
302
328
to the TracerProvider.
329
+ base_url: The base URL for the web-ui, useful if fastapi app is mounted as
330
+ a sub-application. If none is provided, the host is used in the frontend.
303
331
304
332
Returns:
305
333
A FastAPI app instance.
@@ -996,7 +1024,12 @@ async def redirect_dev_ui_add_slash():
996
1024
997
1025
app .mount (
998
1026
"/dev-ui/" ,
999
- StaticFiles (directory = web_assets_dir , html = True , follow_symlink = True ),
1027
+ ConfigInjectingStaticFiles (
1028
+ directory = web_assets_dir ,
1029
+ base_url = base_url ,
1030
+ html = True ,
1031
+ follow_symlink = True ,
1032
+ ),
1000
1033
name = "static" ,
1001
1034
)
1002
1035
0 commit comments