kagent-adk 0.6.2__py3-none-any.whl → 0.6.4__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.

Potentially problematic release.


This version of kagent-adk might be problematic. Click here for more details.

kagent_adk/_token.py ADDED
@@ -0,0 +1,78 @@
1
+ import logging # noqa: I001
2
+ import asyncio
3
+ from contextlib import asynccontextmanager
4
+ from typing import Any, Optional
5
+
6
+ KAGENT_TOKEN_PATH = "/var/run/secrets/tokens/kagent-token"
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class KAgentTokenService:
11
+ """Reads a k8s token from a file, and reloads it
12
+ periodically.
13
+ """
14
+
15
+ def __init__(self, app_name: str):
16
+ self.token = None
17
+ self.update_lock = asyncio.Lock()
18
+ self.update_task = None
19
+ self.app_name = app_name
20
+
21
+ def lifespan(self):
22
+ """Returns an async context manager to start the token update loop"""
23
+
24
+ @asynccontextmanager
25
+ async def _lifespan(app: Any):
26
+ await self._update_token_loop()
27
+ yield
28
+ self._drain()
29
+
30
+ return _lifespan
31
+
32
+ def event_hooks(self):
33
+ """Returns a dictionary of event hooks for the application
34
+ to use when creating the httpx.AsyncClient.
35
+ """
36
+ return {"request": [self._add_bearer_token]}
37
+
38
+ async def _update_token_loop(self) -> None:
39
+ self.token = await self._read_kagent_token()
40
+ # keep it updated - launch a background task to refresh it periodically
41
+ self.update_task = asyncio.create_task(self._refresh_token())
42
+
43
+ def _drain(self):
44
+ if self.update_task:
45
+ self.update_task.cancel()
46
+
47
+ async def _get_token(self) -> str | None:
48
+ async with self.update_lock:
49
+ return self.token
50
+
51
+ async def _read_kagent_token(self) -> str | None:
52
+ return await asyncio.to_thread(read_token)
53
+
54
+ async def _refresh_token(self):
55
+ while True:
56
+ await asyncio.sleep(60) # Wait for 60 seconds before refreshing
57
+ token = await self._read_kagent_token()
58
+ if token is not None and token != self.token:
59
+ async with self.update_lock:
60
+ self.token = token
61
+
62
+ async def _add_bearer_token(self, request):
63
+ # Your function to generate headers dynamically
64
+ token = await self._get_token()
65
+ headers = {"X-Agent-Name": self.app_name}
66
+ if token:
67
+ headers["Authorization"] = f"Bearer {token}"
68
+ request.headers.update(headers)
69
+
70
+
71
+ def read_token() -> str | None:
72
+ try:
73
+ with open(KAGENT_TOKEN_PATH, "r", encoding="utf-8") as f:
74
+ token = f.read()
75
+ return token.strip()
76
+ except OSError as e:
77
+ logger.error(f"Error reading token from {KAGENT_TOKEN_PATH}: {e}")
78
+ return None
kagent_adk/a2a.py CHANGED
@@ -25,9 +25,7 @@ from google.genai import types
25
25
  from ._agent_executor import A2aAgentExecutor
26
26
  from ._session_service import KAgentSessionService
27
27
  from ._task_store import KAgentTaskStore
28
-
29
- # --- Constants ---
30
- USER_ID = "admin@kagent.dev"
28
+ from ._token import KAgentTokenService
31
29
 
32
30
  # --- Configure Logging ---
33
31
  logger = logging.getLogger(__name__)
@@ -39,7 +37,7 @@ class KAgentUser(User):
39
37
 
40
38
  @property
41
39
  def is_authenticated(self) -> bool:
42
- return False
40
+ return True
43
41
 
44
42
  @property
45
43
  def user_name(self) -> str:
@@ -51,9 +49,8 @@ class KAgentRequestContextBuilder(SimpleRequestContextBuilder):
51
49
  A request context builder that will be used to hack in the user_id for now.
52
50
  """
53
51
 
54
- def __init__(self, user_id: str, task_store: TaskStore):
52
+ def __init__(self, task_store: TaskStore):
55
53
  super().__init__(task_store=task_store)
56
- self.user_id = user_id
57
54
 
58
55
  async def build(
59
56
  self,
@@ -63,10 +60,12 @@ class KAgentRequestContextBuilder(SimpleRequestContextBuilder):
63
60
  task: Task | None = None,
64
61
  context: ServerCallContext | None = None,
65
62
  ) -> RequestContext:
66
- if not context:
67
- context = ServerCallContext(user=KAgentUser(user_id=self.user_id))
68
- else:
69
- context.user = KAgentUser(user_id=self.user_id)
63
+ if context:
64
+ # grab the user id from the header
65
+ headers = context.state.get("headers", {})
66
+ user_id = headers.get("x-user-id", None)
67
+ if user_id:
68
+ context.user = KAgentUser(user_id=user_id)
70
69
  request_context = await super().build(params, task_id, context_id, task, context)
71
70
  return request_context
72
71
 
@@ -101,7 +100,10 @@ class KAgentApp:
101
100
  self.agent_card = agent_card
102
101
 
103
102
  def build(self) -> FastAPI:
104
- http_client = httpx.AsyncClient(base_url=kagent_url_override or self.kagent_url)
103
+ token_service = KAgentTokenService(self.app_name)
104
+ http_client = httpx.AsyncClient( # TODO: add user and agent headers
105
+ base_url=kagent_url_override or self.kagent_url, event_hooks=token_service.event_hooks()
106
+ )
105
107
  session_service = KAgentSessionService(http_client)
106
108
 
107
109
  def create_runner() -> Runner:
@@ -117,7 +119,7 @@ class KAgentApp:
117
119
 
118
120
  kagent_task_store = KAgentTaskStore(http_client)
119
121
 
120
- request_context_builder = KAgentRequestContextBuilder(user_id=USER_ID, task_store=kagent_task_store)
122
+ request_context_builder = KAgentRequestContextBuilder(task_store=kagent_task_store)
121
123
  request_handler = DefaultRequestHandler(
122
124
  agent_executor=agent_executor,
123
125
  task_store=kagent_task_store,
@@ -130,7 +132,7 @@ class KAgentApp:
130
132
  )
131
133
 
132
134
  faulthandler.enable()
133
- app = FastAPI()
135
+ app = FastAPI(lifespan=token_service.lifespan())
134
136
 
135
137
  # Health check/readiness probe
136
138
  app.add_route("/health", methods=["GET"], route=health_check)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kagent-adk
3
- Version: 0.6.2
3
+ Version: 0.6.4
4
4
  Summary: kagent-adk is an sdk for integrating adk agents with kagent
5
5
  Requires-Python: >=3.12.11
6
6
  Requires-Dist: a2a-sdk>=0.2.16
@@ -2,10 +2,11 @@ kagent_adk/__init__.py,sha256=3oB8gbSzsvVmqV8w-BGKkRlH3JPfK6o27AfOD6wAd8o,182
2
2
  kagent_adk/_agent_executor.py,sha256=VJn3uQ3EITouzqiIzcN7MZgZ8ozannZIIqjVVyYO57k,10388
3
3
  kagent_adk/_session_service.py,sha256=A47gsfDVp8jITzeW987AHTJLEhcU_mU3ik_SFptFGIc,5815
4
4
  kagent_adk/_task_store.py,sha256=3ApKbFfcDZmcEnwef6bCDhBhoGY9ZYwwyP671B1DHFo,889
5
- kagent_adk/a2a.py,sha256=HBEdGq4gPr78AD88GhygsPhntnctY5dw5pt-BN7FpaI,5647
5
+ kagent_adk/_token.py,sha256=M9TOxxC4RAWPup_MIYuLIYoklnfllJS0yV3dQOfr5ng,2486
6
+ kagent_adk/a2a.py,sha256=r8GgDkeKoZJx_qZmLfoaA0zSrP7t0Hn_VqEc-m0xIc8,5845
6
7
  kagent_adk/cli.py,sha256=MSdd38T1vsFEhpj3MEAg4IdQhlrcumnSbRi-8xUKXVE,6977
7
8
  kagent_adk/models.py,sha256=ZR1Hbc6fjA82fGdgrfa5-HyWOkXQTrjX2FiS57_O8i4,4411
8
- kagent_adk-0.6.2.dist-info/METADATA,sha256=3kiPEkmM4DI2SSLtHZp_zxcuDOLA4CxqFeGW-dC2Dkc,1242
9
- kagent_adk-0.6.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
- kagent_adk-0.6.2.dist-info/entry_points.txt,sha256=bmqHEc9zPYkbRoK57wF3wi5ohHTMB6yHTslKfvuVpc4,50
11
- kagent_adk-0.6.2.dist-info/RECORD,,
9
+ kagent_adk-0.6.4.dist-info/METADATA,sha256=iPOqZIFpxKM4896jCQaUaScSvcZnxb_FwZHCVoc-rYU,1242
10
+ kagent_adk-0.6.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ kagent_adk-0.6.4.dist-info/entry_points.txt,sha256=bmqHEc9zPYkbRoK57wF3wi5ohHTMB6yHTslKfvuVpc4,50
12
+ kagent_adk-0.6.4.dist-info/RECORD,,