google-adk-extras 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google_adk_extras/__init__.py +1 -1
- google_adk_extras/adk_builder.py +1 -0
- google_adk_extras/auth/attach.py +8 -3
- google_adk_extras/auth/jwt_utils.py +12 -3
- google_adk_extras/enhanced_fastapi.py +47 -13
- {google_adk_extras-0.3.0.dist-info → google_adk_extras-0.3.1.dist-info}/METADATA +1 -1
- {google_adk_extras-0.3.0.dist-info → google_adk_extras-0.3.1.dist-info}/RECORD +10 -10
- {google_adk_extras-0.3.0.dist-info → google_adk_extras-0.3.1.dist-info}/WHEEL +0 -0
- {google_adk_extras-0.3.0.dist-info → google_adk_extras-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {google_adk_extras-0.3.0.dist-info → google_adk_extras-0.3.1.dist-info}/top_level.txt +0 -0
google_adk_extras/__init__.py
CHANGED
google_adk_extras/adk_builder.py
CHANGED
@@ -683,6 +683,7 @@ class AdkBuilder:
|
|
683
683
|
eval_storage_uri=self._eval_storage_uri,
|
684
684
|
allow_origins=self._allow_origins,
|
685
685
|
web=self._web_ui,
|
686
|
+
# Expose future override via builder when needed
|
686
687
|
a2a=self._a2a,
|
687
688
|
programmatic_a2a=self._a2a_expose_programmatic,
|
688
689
|
programmatic_a2a_mount_base=self._a2a_programmatic_mount_base,
|
google_adk_extras/auth/attach.py
CHANGED
@@ -9,7 +9,7 @@ from starlette.middleware.base import BaseHTTPMiddleware
|
|
9
9
|
|
10
10
|
from .config import AuthConfig, JwtIssuerConfig, JwtValidatorConfig
|
11
11
|
from .jwt_utils import decode_jwt, encode_jwt, now_ts
|
12
|
-
from
|
12
|
+
from typing import Any
|
13
13
|
|
14
14
|
|
15
15
|
def attach_auth(app: FastAPI, cfg: Optional[AuthConfig]) -> None:
|
@@ -25,9 +25,14 @@ def attach_auth(app: FastAPI, cfg: Optional[AuthConfig]) -> None:
|
|
25
25
|
issuer_cfg = cfg.jwt_issuer
|
26
26
|
api_keys = set(cfg.api_keys or [])
|
27
27
|
basic_users = cfg.basic_users or {}
|
28
|
-
auth_store: Optional[
|
28
|
+
auth_store: Optional[Any] = None
|
29
29
|
if issuer_cfg and issuer_cfg.database_url:
|
30
|
-
|
30
|
+
try:
|
31
|
+
from .sql_store import AuthStore # type: ignore
|
32
|
+
auth_store = AuthStore(issuer_cfg.database_url)
|
33
|
+
except Exception:
|
34
|
+
# SQL store not available; API key issuance and password grants will be unavailable.
|
35
|
+
auth_store = None
|
31
36
|
|
32
37
|
# Security helpers
|
33
38
|
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
|
@@ -5,8 +5,16 @@ import json
|
|
5
5
|
import time
|
6
6
|
from typing import Any, Dict, Optional
|
7
7
|
|
8
|
-
import
|
9
|
-
|
8
|
+
# Lazy import PyJWT to keep this optional when auth is not used.
|
9
|
+
def _import_pyjwt():
|
10
|
+
try:
|
11
|
+
import jwt # type: ignore
|
12
|
+
from jwt import PyJWKClient # type: ignore
|
13
|
+
return jwt, PyJWKClient
|
14
|
+
except Exception as e:
|
15
|
+
raise ImportError(
|
16
|
+
"PyJWT is required for JWT encode/decode. Install with: pip install PyJWT"
|
17
|
+
) from e
|
10
18
|
|
11
19
|
|
12
20
|
def _b64url(data: bytes) -> str:
|
@@ -14,11 +22,13 @@ def _b64url(data: bytes) -> str:
|
|
14
22
|
|
15
23
|
|
16
24
|
def encode_jwt(payload: Dict[str, Any], *, algorithm: str, key: str, headers: Optional[Dict[str, Any]] = None) -> str:
|
25
|
+
jwt, _PyJWKClient = _import_pyjwt()
|
17
26
|
return jwt.encode(payload, key, algorithm=algorithm, headers=headers)
|
18
27
|
|
19
28
|
|
20
29
|
def decode_jwt(token: str, *, issuer: Optional[str] = None, audience: Optional[str] = None,
|
21
30
|
jwks_url: Optional[str] = None, hs256_secret: Optional[str] = None) -> Dict[str, Any]:
|
31
|
+
jwt, PyJWKClient = _import_pyjwt()
|
22
32
|
options = {"verify_signature": True, "verify_exp": True, "verify_nbf": True}
|
23
33
|
if jwks_url:
|
24
34
|
jwk_client = PyJWKClient(jwks_url)
|
@@ -33,4 +43,3 @@ def decode_jwt(token: str, *, issuer: Optional[str] = None, audience: Optional[s
|
|
33
43
|
def now_ts() -> int:
|
34
44
|
return int(time.time())
|
35
45
|
|
36
|
-
|
@@ -10,7 +10,7 @@ import logging
|
|
10
10
|
import os
|
11
11
|
from pathlib import Path
|
12
12
|
import shutil
|
13
|
-
from typing import Any, Mapping, Optional, List, Callable, Dict
|
13
|
+
from typing import Any, Mapping, Optional, List, Callable, Dict, Union
|
14
14
|
|
15
15
|
import click
|
16
16
|
from fastapi import FastAPI
|
@@ -57,6 +57,7 @@ def get_enhanced_fast_api_app(
|
|
57
57
|
eval_storage_uri: Optional[str] = None,
|
58
58
|
allow_origins: Optional[List[str]] = None,
|
59
59
|
web: bool = True,
|
60
|
+
web_assets_dir: Optional[Union[str, Path]] = None,
|
60
61
|
a2a: bool = False,
|
61
62
|
programmatic_a2a: bool = False,
|
62
63
|
programmatic_a2a_mount_base: str = "/a2a",
|
@@ -305,20 +306,53 @@ def get_enhanced_fast_api_app(
|
|
305
306
|
tear_down_observer=tear_down_observer,
|
306
307
|
)
|
307
308
|
|
308
|
-
|
309
|
+
def _auto_find_web_assets() -> Optional[Path]:
|
309
310
|
try:
|
310
|
-
#
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
311
|
+
# Prefer importlib.resources so this works across ADK versions
|
312
|
+
import importlib.resources as r
|
313
|
+
try:
|
314
|
+
import google.adk.cli.fast_api as fast_api_pkg # type: ignore
|
315
|
+
base = r.files(fast_api_pkg)
|
316
|
+
candidates = [
|
317
|
+
base / "browser",
|
318
|
+
base / "static" / "browser",
|
319
|
+
]
|
320
|
+
except Exception:
|
321
|
+
import google.adk.cli as cli_pkg # type: ignore
|
322
|
+
base = r.files(cli_pkg) / "fast_api"
|
323
|
+
candidates = [
|
324
|
+
base / "browser",
|
325
|
+
base / "static" / "browser",
|
326
|
+
]
|
327
|
+
for p in candidates:
|
328
|
+
if p.exists() and (p / "index.html").exists():
|
329
|
+
# Convert to real filesystem Path if possible
|
330
|
+
try:
|
331
|
+
return Path(str(p))
|
332
|
+
except Exception:
|
333
|
+
continue
|
334
|
+
except Exception:
|
335
|
+
pass
|
336
|
+
# Fallback to local relative path (for dev builds of this package)
|
337
|
+
local = Path(__file__).parent / "browser"
|
338
|
+
if local.exists() and (local / "index.html").exists():
|
339
|
+
return local
|
340
|
+
return None
|
341
|
+
|
342
|
+
if web:
|
343
|
+
chosen: Optional[Path] = None
|
344
|
+
if web_assets_dir is not None:
|
345
|
+
p = Path(web_assets_dir)
|
346
|
+
if p.exists():
|
347
|
+
chosen = p
|
348
|
+
if chosen is None:
|
349
|
+
chosen = _auto_find_web_assets()
|
350
|
+
if chosen is not None:
|
351
|
+
extra_fast_api_args.update(web_assets_dir=chosen)
|
320
352
|
else:
|
321
|
-
logger.warning(
|
353
|
+
logger.warning(
|
354
|
+
"Web UI assets not found; set web_assets_dir or install an ADK build that ships fast_api/browser"
|
355
|
+
)
|
322
356
|
|
323
357
|
# Create FastAPI app
|
324
358
|
app = adk_web_server.get_fast_api_app(
|
@@ -1,8 +1,8 @@
|
|
1
|
-
google_adk_extras/__init__.py,sha256=
|
2
|
-
google_adk_extras/adk_builder.py,sha256=
|
1
|
+
google_adk_extras/__init__.py,sha256=GbBnzocuEjf2RphvKaL9-DoDtsq0FVz2QO0uVTe66sQ,851
|
2
|
+
google_adk_extras/adk_builder.py,sha256=OR8ZSgaZJwjVpbfoTHOjgIisO_2sPUxegS0_ngCAco4,30129
|
3
3
|
google_adk_extras/custom_agent_loader.py,sha256=e_sgA58RmDzCUHCySAi3Hruxumtozw3UScZV2vxlCbw,5991
|
4
4
|
google_adk_extras/enhanced_adk_web_server.py,sha256=4QxTADlQv6oXaAEVMQc7-bpf84jCrTkN6pJC6R2jmww,5348
|
5
|
-
google_adk_extras/enhanced_fastapi.py,sha256=
|
5
|
+
google_adk_extras/enhanced_fastapi.py,sha256=8JCkGOtzUaQM68BanhPaii1xBziPelXAYIbyUeUMEO0,29748
|
6
6
|
google_adk_extras/enhanced_runner.py,sha256=b7O1a9-4S49LduILOEDs6IxjCI4w_E39sc-Hs4y3Rys,1410
|
7
7
|
google_adk_extras/artifacts/__init__.py,sha256=_IsKDgf6wanWR0HXvSpK9SiLa3n5URKLtazkKyH1P-o,931
|
8
8
|
google_adk_extras/artifacts/base_custom_artifact_service.py,sha256=O9rkc250B3yDRYbyDI0EvTrCKvnih5_DQas5OF-hRMY,9721
|
@@ -11,9 +11,9 @@ google_adk_extras/artifacts/mongo_artifact_service.py,sha256=K46Ycl7gkzCbCweVL0G
|
|
11
11
|
google_adk_extras/artifacts/s3_artifact_service.py,sha256=inIc2KL3OdIQGkCA_HYJE0ZfGFQ3YcX_SFZEFVUb0T8,15655
|
12
12
|
google_adk_extras/artifacts/sql_artifact_service.py,sha256=OovKSzM0nib2c-pzkv7NYyiHi8kFK-k3SFOMi92U4Mk,11980
|
13
13
|
google_adk_extras/auth/__init__.py,sha256=PQQmFAjOPrt9tAGHOtQC-_U7fpRd8Dt_vh973b2pSnc,202
|
14
|
-
google_adk_extras/auth/attach.py,sha256=
|
14
|
+
google_adk_extras/auth/attach.py,sha256=wSb2jKziGXqhRzu8XCBVuoHXyJa7T6CrGGbRhsfp_50,10235
|
15
15
|
google_adk_extras/auth/config.py,sha256=JGJefyExVG3QFjmAkgTT-yaMivCvkOs4E7HwMlqVES0,1573
|
16
|
-
google_adk_extras/auth/jwt_utils.py,sha256=
|
16
|
+
google_adk_extras/auth/jwt_utils.py,sha256=B3Iyu0GRqDU0EstGxfMUKm_w58z4l6WQGRAQvlcwvYk,1701
|
17
17
|
google_adk_extras/auth/sql_store.py,sha256=-LouLrcT4gBBGrwG4kqbMyjVo1W1BbugPCKZUUFklWs,6693
|
18
18
|
google_adk_extras/credentials/base_custom_credential_service.py,sha256=iYHacJAsZmDfpxLOPYx4tQpbtWTbwC75tRp6hlZFoSg,4014
|
19
19
|
google_adk_extras/memory/__init__.py,sha256=2FFJXw9CZHctKXmCuc-lrdETeQ5xqdivy3oarHJz5gs,994
|
@@ -30,8 +30,8 @@ google_adk_extras/sessions/sql_session_service.py,sha256=TaOeEVWnwQ_8nvDZBW7e3qh
|
|
30
30
|
google_adk_extras/sessions/yaml_file_session_service.py,sha256=g65ptJWAMVN4XQmCxQ0UwnSC2GU1NJ6QRvrwfzSK_xo,11797
|
31
31
|
google_adk_extras/streaming/__init__.py,sha256=rcjmlCJHTlvUiCrx6qNGw5ObCnEtfENkGTvzfEiGL0M,461
|
32
32
|
google_adk_extras/streaming/streaming_controller.py,sha256=Z72k5QgvWBIU2YP8iXlc3D3oWxDYWJo9eygj_KzALYA,10489
|
33
|
-
google_adk_extras-0.3.
|
34
|
-
google_adk_extras-0.3.
|
35
|
-
google_adk_extras-0.3.
|
36
|
-
google_adk_extras-0.3.
|
37
|
-
google_adk_extras-0.3.
|
33
|
+
google_adk_extras-0.3.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
34
|
+
google_adk_extras-0.3.1.dist-info/METADATA,sha256=jN02PjbEwa6Lm-2rEpLV-bCBhRmNM9U3bd7u9RpxsS8,12867
|
35
|
+
google_adk_extras-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
36
|
+
google_adk_extras-0.3.1.dist-info/top_level.txt,sha256=DDWgVkz8G8ihPzznxAWyKa2jgJW3F6Fwy__qMddoKTs,18
|
37
|
+
google_adk_extras-0.3.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|