Describe the bug
Depends.__call__ (in kagenti_adk/server/dependencies.py, around line 48) invokes the dependency callable synchronously and passes its return value directly to the handler. If the callable is an async def, the handler receives an unawaited coroutine object instead of the resolved value.
Steps to Reproduce
from kagenti_adk.server.dependencies import Depends
async def get_my_service():
service = await SomeAsyncFactory.create()
return service
@server.agent()
async def my_agent(
input: Message,
context: RunContext,
svc: Annotated[MyService, Depends(get_my_service)],
):
# svc is a coroutine object, not a MyService instance
await svc.do_something() # AttributeError: 'coroutine' object has no attribute 'do_something'
Root Cause
In dependencies.py, the dependency callable is invoked with a plain function call:
result = self._callable(message, context, request_context)
When self._callable is async def, result is a coroutine that needs to be awaited. The existing extension servers avoid this because they're BaseExtensionServer subclasses with a lifespan() method, not plain async callables.
Expected Behavior
Depends.__call__ should detect when the callable returns a coroutine and await it:
result = self._callable(message, context, request_context)
if inspect.isawaitable(result):
result = await result
Workaround
Use a synchronous callable that returns a lazy-initializing proxy. The proxy defers the async initialization to the first method call:
class _LazyProxy:
def __init__(self, factory, context_id):
self._factory = factory
self._instance = None
async def _resolve(self):
if self._instance is None:
self._instance = await self._factory.create()
return self._instance
async def do_something(self, *args, **kwargs):
inst = await self._resolve()
return await inst.do_something(*args, **kwargs)
def create_dependency(factory):
def provider(message, context, request_context):
return _LazyProxy(factory, context.context_id) # sync return
return provider
Additional Context
- Found while implementing a
MemoryStore extension for the ADK that requires async initialization (connecting to an external service)
- The workaround is functional but adds boilerplate that wouldn't be needed if
Depends handled async callables natively
- ADK version: 0.8.2
Describe the bug
Depends.__call__(inkagenti_adk/server/dependencies.py, around line 48) invokes the dependency callable synchronously and passes its return value directly to the handler. If the callable is anasync def, the handler receives an unawaited coroutine object instead of the resolved value.Steps to Reproduce
Root Cause
In
dependencies.py, the dependency callable is invoked with a plain function call:When
self._callableisasync def,resultis a coroutine that needs to be awaited. The existing extension servers avoid this because they'reBaseExtensionServersubclasses with alifespan()method, not plain async callables.Expected Behavior
Depends.__call__should detect when the callable returns a coroutine and await it:Workaround
Use a synchronous callable that returns a lazy-initializing proxy. The proxy defers the async initialization to the first method call:
Additional Context
MemoryStoreextension for the ADK that requires async initialization (connecting to an external service)Dependshandled async callables natively