agentkernel 0.8.0__tar.gz → 0.8.1__tar.gz

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.
Files changed (245) hide show
  1. {agentkernel-0.8.0 → agentkernel-0.8.1}/PKG-INFO +1 -1
  2. {agentkernel-0.8.0 → agentkernel-0.8.1}/pyproject.toml +1 -1
  3. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/cli/cli.py +28 -2
  4. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/base.py +134 -1
  5. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/adk/adk.py +89 -36
  6. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/crewai/crewai.py +8 -6
  7. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/langgraph/langgraph.py +33 -2
  8. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/openai/openai.py +20 -8
  9. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/pydanticai/pydanticai.py +20 -2
  10. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/smolagents/smolagents.py +14 -1
  11. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-add-capabilities/SKILL.md +58 -23
  12. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-add-capabilities/evals/evals.json +16 -1
  13. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-add-integration/SKILL.md +8 -8
  14. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-add-integration/evals/evals.json +1 -1
  15. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-build/SKILL.md +1 -1
  16. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-build/evals/evals.json +1 -1
  17. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-cloud-deploy/SKILL.md +19 -19
  18. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-cloud-deploy/evals/evals.json +1 -1
  19. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-init/SKILL.md +2 -2
  20. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-init/evals/evals.json +2 -2
  21. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-test/SKILL.md +2 -2
  22. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/ak-test/evals/evals.json +1 -1
  23. agentkernel-0.8.1/src/agentkernel/trace/langfuse/langgraph.py +49 -0
  24. agentkernel-0.8.0/src/agentkernel/trace/langfuse/langgraph.py +0 -70
  25. {agentkernel-0.8.0 → agentkernel-0.8.1}/README.md +0 -0
  26. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/__init__.py +0 -0
  27. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/adk.py +0 -0
  28. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/__init__.py +0 -0
  29. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/a2a/__init__.py +0 -0
  30. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/a2a/a2a.py +0 -0
  31. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/a2a/handler.py +0 -0
  32. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/handler.py +0 -0
  33. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/http.py +0 -0
  34. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/mcp/__init__.py +0 -0
  35. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/mcp/akmcp.py +0 -0
  36. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/api/thread.py +0 -0
  37. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/auth/__init__.py +0 -0
  38. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/auth/handler.py +0 -0
  39. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/auth.py +0 -0
  40. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/aws.py +0 -0
  41. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/azure.py +0 -0
  42. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/cli/__init__.py +0 -0
  43. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/cli/ak.py +0 -0
  44. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/__init__.py +0 -0
  45. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/builder.py +0 -0
  46. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/chat_service.py +0 -0
  47. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/config.py +0 -0
  48. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/hooks.py +0 -0
  49. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/logger.py +0 -0
  50. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/model.py +0 -0
  51. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/module.py +0 -0
  52. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/__init__.py +0 -0
  53. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/factory.py +0 -0
  54. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/hooks.py +0 -0
  55. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/__init__.py +0 -0
  56. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/base.py +0 -0
  57. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/dynamodb.py +0 -0
  58. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/in_memory.py +0 -0
  59. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/redis.py +0 -0
  60. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/session_cache.py +0 -0
  61. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/storage/storage_manager.py +0 -0
  62. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/multimodal/tools.py +0 -0
  63. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/runtime.py +0 -0
  64. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/service.py +0 -0
  65. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/__init__.py +0 -0
  66. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/base.py +0 -0
  67. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/cosmosdb.py +0 -0
  68. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/dynamodb.py +0 -0
  69. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/firestore.py +0 -0
  70. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/in_memory.py +0 -0
  71. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/redis.py +0 -0
  72. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/serde.py +0 -0
  73. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/session/valkey.py +0 -0
  74. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/__init__.py +0 -0
  75. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/authoriser.py +0 -0
  76. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/manager.py +0 -0
  77. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/model.py +0 -0
  78. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/naming.py +0 -0
  79. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/__init__.py +0 -0
  80. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/base.py +0 -0
  81. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/cosmosdb.py +0 -0
  82. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/dynamodb.py +0 -0
  83. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/firestore.py +0 -0
  84. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/in_memory.py +0 -0
  85. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/thread/store/redis.py +0 -0
  86. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/tool.py +0 -0
  87. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/config_yaml_util.py +0 -0
  88. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/__init__.py +0 -0
  89. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/base.py +0 -0
  90. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/cosmosdb.py +0 -0
  91. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/dynamodb.py +0 -0
  92. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/firestore.py +0 -0
  93. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/redis.py +0 -0
  94. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/redis_like.py +0 -0
  95. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/driver/valkey.py +0 -0
  96. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/error_util.py +0 -0
  97. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/factory.py +0 -0
  98. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/core/util/key_value_cache.py +0 -0
  99. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/crewai.py +0 -0
  100. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/__init__.py +0 -0
  101. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/__init__.py +0 -0
  102. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/__init__.py +0 -0
  103. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/akagentrunner.py +0 -0
  104. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/akoutputconsumer.py +0 -0
  105. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/core/__init__.py +0 -0
  106. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/core/sqs_consumer.py +0 -0
  107. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/ecs_io_handler.py +0 -0
  108. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/containerized/ecs_queue_handler.py +0 -0
  109. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/__init__.py +0 -0
  110. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/response_store/__init__.py +0 -0
  111. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/response_store/dynamodb.py +0 -0
  112. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/response_store/handler.py +0 -0
  113. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/response_store/redis.py +0 -0
  114. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/response_store/valkey.py +0 -0
  115. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/sqs_handler.py +0 -0
  116. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/core/websocket_service.py +0 -0
  117. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/__init__.py +0 -0
  118. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/akagentrunner.py +0 -0
  119. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/akauthorizer.py +0 -0
  120. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/aklambda.py +0 -0
  121. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/akresponsehandler.py +0 -0
  122. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/akwsconnectionhandler.py +0 -0
  123. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/core/__init__.py +0 -0
  124. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/core/router/__init__.py +0 -0
  125. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/core/router/common.py +0 -0
  126. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/core/router/rest_lambda.py +0 -0
  127. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/core/router/ws_lambda.py +0 -0
  128. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/aws/serverless/core/sqs_consumer.py +0 -0
  129. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/azure/__init__.py +0 -0
  130. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/azure/akfunction.py +0 -0
  131. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/__init__.py +0 -0
  132. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/queue_consumer.py +0 -0
  133. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/queue_handler.py +0 -0
  134. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/queue_request_handler.py +0 -0
  135. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/response_store.py +0 -0
  136. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/thread_runner.py +0 -0
  137. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/common/websocket_connection_store.py +0 -0
  138. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/gcp/__init__.py +0 -0
  139. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/gcp/akauthorizer.py +0 -0
  140. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/deployment/gcp/akcloudrun.py +0 -0
  141. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/__init__.py +0 -0
  142. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/adk/__init__.py +0 -0
  143. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/crewai/__init__.py +0 -0
  144. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/langgraph/__init__.py +0 -0
  145. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/openai/__init__.py +0 -0
  146. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/pydanticai/__init__.py +0 -0
  147. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/framework/smolagents/__init__.py +0 -0
  148. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/gcp.py +0 -0
  149. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/gmail.py +0 -0
  150. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/guardrail/__init__.py +0 -0
  151. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/guardrail/bedrock.py +0 -0
  152. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/guardrail/guardrail.py +0 -0
  153. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/guardrail/openai.py +0 -0
  154. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/guardrail/walledai.py +0 -0
  155. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/instagram.py +0 -0
  156. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/__init__.py +0 -0
  157. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/gmail/README.md +0 -0
  158. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/gmail/__init__.py +0 -0
  159. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/gmail/gmail_chat.py +0 -0
  160. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/instagram/README.md +0 -0
  161. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/instagram/__init__.py +0 -0
  162. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/instagram/instagram_chat.py +0 -0
  163. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/messenger/README.md +0 -0
  164. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/messenger/__init__.py +0 -0
  165. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/messenger/messenger_chat.py +0 -0
  166. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/slack/README.md +0 -0
  167. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/slack/__init__.py +0 -0
  168. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/slack/slack_chat.py +0 -0
  169. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/teams/README.md +0 -0
  170. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/teams/__init__.py +0 -0
  171. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/teams/teams_chat.py +0 -0
  172. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/telegram/README.md +0 -0
  173. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/telegram/__init__.py +0 -0
  174. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/telegram/telegram_chat.py +0 -0
  175. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/whatsapp/README.md +0 -0
  176. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/whatsapp/__init__.py +0 -0
  177. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/integration/whatsapp/whatsapp_chat.py +0 -0
  178. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/knowledgebase/__init__.py +0 -0
  179. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/knowledgebase/base.py +0 -0
  180. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/knowledgebase/chroma.py +0 -0
  181. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/knowledgebase/knowledgebuilder.py +0 -0
  182. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/knowledgebase/neo4j.py +0 -0
  183. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/knowledgebase/starburst.py +0 -0
  184. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/langgraph.py +0 -0
  185. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/mcp.py +0 -0
  186. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/messenger.py +0 -0
  187. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/openai.py +0 -0
  188. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/pydanticai.py +0 -0
  189. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/__init__.py +0 -0
  190. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/base.py +0 -0
  191. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/broker/__init__.py +0 -0
  192. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/broker/base.py +0 -0
  193. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/broker/embedded.py +0 -0
  194. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/broker/thread.py +0 -0
  195. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/broker/worker.py +0 -0
  196. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/errors.py +0 -0
  197. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/factory.py +0 -0
  198. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/hooks.py +0 -0
  199. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/manager.py +0 -0
  200. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/model.py +0 -0
  201. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/principal.py +0 -0
  202. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/providers/__init__.py +0 -0
  203. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/providers/daytona.py +0 -0
  204. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/providers/docker.py +0 -0
  205. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/providers/e2b.py +0 -0
  206. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/providers/ec2_ssm.py +0 -0
  207. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/providers/local_subprocess.py +0 -0
  208. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/testing.py +0 -0
  209. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/sandbox/tools.py +0 -0
  210. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/__init__.py +0 -0
  211. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/skills/skills.py +0 -0
  212. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/slack.py +0 -0
  213. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/smolagents.py +0 -0
  214. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/teams.py +0 -0
  215. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/telegram.py +0 -0
  216. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/test/__init__.py +0 -0
  217. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/test/config.py +0 -0
  218. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/test/test.py +0 -0
  219. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/__init__.py +0 -0
  220. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/base.py +0 -0
  221. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/__init__.py +0 -0
  222. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/adk.py +0 -0
  223. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/crewai.py +0 -0
  224. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/langfuse.py +0 -0
  225. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/openai.py +0 -0
  226. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/pydanticai.py +0 -0
  227. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/langfuse/smolagents.py +0 -0
  228. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/__init__.py +0 -0
  229. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/adk.py +0 -0
  230. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/crewai.py +0 -0
  231. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/langgraph.py +0 -0
  232. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/logfire.py +0 -0
  233. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/openai.py +0 -0
  234. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/pydanticai.py +0 -0
  235. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/logfire/smolagents.py +0 -0
  236. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/__init__.py +0 -0
  237. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/adk.py +0 -0
  238. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/crewai.py +0 -0
  239. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/langgraph.py +0 -0
  240. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/openai.py +0 -0
  241. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/openllmetry.py +0 -0
  242. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/pydanticai.py +0 -0
  243. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/openllmetry/smolagents.py +0 -0
  244. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/trace/trace.py +0 -0
  245. {agentkernel-0.8.0 → agentkernel-0.8.1}/src/agentkernel/whatsapp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: agentkernel
3
- Version: 0.8.0
3
+ Version: 0.8.1
4
4
  Summary: Agent Kernel - Unified AI Agents Runtime
5
5
  Author: Yaala Labs
6
6
  Author-email: Yaala Labs <agentkernel@yaalalabs.com>
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "agentkernel"
7
- version = "0.8.0"
7
+ version = "0.8.1"
8
8
  description = "Agent Kernel - Unified AI Agents Runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12,<3.14"
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
2
  import logging
3
3
  import readline # Enables line editing and history features for input() in the CLI
4
+ import threading
4
5
 
5
6
  from ..core import AgentService
6
- from ..core.config import AKConfig
7
7
 
8
8
  ak_cli_logger = logging.getLogger("ak.cli")
9
9
 
@@ -47,6 +47,32 @@ class CLI:
47
47
  self._print(f" {agent.name}")
48
48
  self._print()
49
49
 
50
+ @staticmethod
51
+ async def _ainput(prompt: str) -> str:
52
+ """
53
+ Reads a line of input without blocking the event loop, so background tasks keep running between turns.
54
+ The reader is a daemon thread, so Ctrl+C exits instead of waiting on a thread parked in `input()`.
55
+ :param prompt: The prompt to display to the user.
56
+ :return: The line entered by the user.
57
+ """
58
+ loop = asyncio.get_running_loop()
59
+ future: asyncio.Future[str] = loop.create_future()
60
+
61
+ def resolve(setter, value):
62
+ if not future.done():
63
+ setter(value)
64
+
65
+ def read():
66
+ try:
67
+ line = input(prompt)
68
+ except BaseException as e: # noqa: BLE001 - relayed to the awaiting caller
69
+ loop.call_soon_threadsafe(resolve, future.set_exception, e)
70
+ else:
71
+ loop.call_soon_threadsafe(resolve, future.set_result, line)
72
+
73
+ threading.Thread(target=read, daemon=True, name="ak-cli-input").start()
74
+ return await future
75
+
50
76
  async def run(self):
51
77
  self._print("AgentKernel CLI (type !help for commands or !quit to exit):")
52
78
  self._service.select()
@@ -57,7 +83,7 @@ class CLI:
57
83
  while True:
58
84
  try:
59
85
  name = self._service.agent.name if self._service.agent else "none"
60
- prompt = input(f"({name}) >> ")
86
+ prompt = await self._ainput(f"({name}) >> ")
61
87
  if not prompt.strip():
62
88
  continue
63
89
  if prompt.startswith("!"):
@@ -1,8 +1,10 @@
1
1
  import asyncio
2
2
  import contextvars
3
+ import copy
3
4
  import logging
5
+ import pickle
4
6
  from abc import ABC, abstractmethod
5
- from collections.abc import AsyncGenerator, Iterator
7
+ from collections.abc import AsyncGenerator, Iterator, Mapping
6
8
  from enum import Enum
7
9
  from typing import Any, ClassVar, Self, cast
8
10
 
@@ -10,6 +12,8 @@ from .hooks import PostHook, PreHook
10
12
  from .model import AgentReply, AgentRequest
11
13
  from .util.key_value_cache import KeyValueCache
12
14
 
15
+ _log = logging.getLogger("ak.core.runner")
16
+
13
17
 
14
18
  class Session:
15
19
  """
@@ -39,6 +43,7 @@ class Session:
39
43
 
40
44
  VOLATILE_CACHE = "v_cache"
41
45
  NON_VOLATILE_CACHE = "nv_cache"
46
+ FRAMEWORK_CONTEXT = "framework_context"
42
47
 
43
48
  current_session: ClassVar[contextvars.ContextVar[Self | None]] = contextvars.ContextVar("current_session", default=None)
44
49
 
@@ -157,6 +162,35 @@ class Session:
157
162
  """
158
163
  return cast(KeyValueCache, self.get(Session.Keys.NON_VOLATILE_CACHE.value))
159
164
 
165
+ def get_framework_context(self) -> dict | None:
166
+ """
167
+ Returns the live per-run framework context dict, so hooks can edit it in place.
168
+ Never auto-creates the key: absent means "nothing injected", {} means "injected but empty".
169
+ :return: The stored framework context dict, or None when the key is absent.
170
+ """
171
+ return self.get(Session.Keys.FRAMEWORK_CONTEXT.value)
172
+
173
+ def set_framework_context(self, context: dict) -> dict:
174
+ """
175
+ Seeds or replaces the per-run framework context carried across turns.
176
+ :param context: The context dict to store. Must be picklable, since sessions are persisted with pickle.
177
+ :return: The stored context dict.
178
+ :raises TypeError: If context is not a dict.
179
+ """
180
+ if not isinstance(context, dict):
181
+ raise TypeError(
182
+ f"Session '{self._id}' framework_context must be a dict, got "
183
+ f"{type(context).__name__}. The reserved framework_context key carries a "
184
+ f"per-run context/state dict; wrap the value in a dict before setting it."
185
+ )
186
+ return self.set(Session.Keys.FRAMEWORK_CONTEXT.value, context)
187
+
188
+ def clear_framework_context(self) -> None:
189
+ """
190
+ Deletes the per-run framework context, so nothing is injected on the next turn.
191
+ """
192
+ self.delete(Session.Keys.FRAMEWORK_CONTEXT.value)
193
+
160
194
  def set(self, key: str, value: Any) -> Any:
161
195
  """
162
196
  Sets a session data object for the specified key.
@@ -220,6 +254,92 @@ class Runner(ABC):
220
254
  """
221
255
  return self._name
222
256
 
257
+ def _load_framework_context(self, session: Session | None) -> dict | None:
258
+ """
259
+ Loads the per-run framework context to inject into this run.
260
+ Returns a deep copy, so a failed run leaves the stored context intact.
261
+ :param session: The session to read the framework context from, or None.
262
+ :return: A deep copy of the stored dict, or None when nothing is stored.
263
+ :raises TypeError: If the stored value is not a dict.
264
+ """
265
+ if session is None:
266
+ return None
267
+ stored = session.get_framework_context()
268
+ if stored is None:
269
+ return None
270
+ if not isinstance(stored, dict):
271
+ raise TypeError(
272
+ f"Session '{session.id}' framework_context must be a dict, got "
273
+ f"{type(stored).__name__}. The reserved framework_context key carries a "
274
+ f"per-run context/state dict; wrap the value in a dict before setting it."
275
+ )
276
+ return copy.deepcopy(stored)
277
+
278
+ def _store_framework_context(self, session: Session | None, incoming: dict | None, produced: Mapping[str, Any] | None) -> None:
279
+ """
280
+ Merges the framework's post-run state over the context loaded this turn and stores the result.
281
+ Keys the framework touched win; untouched caller keys are preserved. No-op when nothing was loaded.
282
+ :param session: The session to write the merged context back to, or None.
283
+ :param incoming: The context loaded this turn, or None when nothing was stored.
284
+ :param produced: The framework's post-run state, or None.
285
+ """
286
+ if session is None or incoming is None:
287
+ return
288
+ merged = dict(incoming)
289
+ if produced:
290
+ merged.update(produced)
291
+ self._ensure_framework_context_picklable(session, merged)
292
+ session.set_framework_context(merged)
293
+
294
+ @staticmethod
295
+ def _not_picklable(value: Any) -> bool:
296
+ """
297
+ Checks whether the given value can be pickled.
298
+ :param value: The value to test.
299
+ :return: True if the value cannot be pickled.
300
+ """
301
+ try:
302
+ pickle.dumps(value)
303
+ return False
304
+ except Exception:
305
+ return True
306
+
307
+ @classmethod
308
+ def _ensure_framework_context_picklable(cls, session: Session, ctx: Mapping[str, Any]) -> None:
309
+ """
310
+ Fails fast if the context cannot be pickled, before it can break the session store.
311
+ :param session: The session whose id is named in the error.
312
+ :param ctx: The framework context to validate.
313
+ :raises TypeError: If any value in ctx is not pickle-serializable.
314
+ """
315
+ try:
316
+ pickle.dumps(ctx)
317
+ except Exception as exc:
318
+ offender = next(
319
+ (f"{k!r} ({type(v).__name__})" for k, v in ctx.items() if cls._not_picklable(v)),
320
+ "<unknown key>",
321
+ )
322
+ raise TypeError(
323
+ f"Session '{session.id}' framework_context is not picklable; "
324
+ f"offending entry: {offender}. framework_context values must be "
325
+ f"pickle-serializable so the session can be persisted."
326
+ ) from exc
327
+
328
+ @staticmethod
329
+ def _log_framework_context_stream_failure(session: Session | None, error: Exception) -> None:
330
+ """
331
+ Logs a framework context write-back failure at the end of a streamed run instead of raising it.
332
+ Raising here would surface as a transport error and skip the turn's session store.
333
+ :param session: The session whose write-back failed.
334
+ :param error: The exception raised while producing or storing the context.
335
+ """
336
+ session_id = session.id if session is not None else "<none>"
337
+ _log.error(
338
+ f"Session '{session_id}': framework_context write-back was skipped at the end of a "
339
+ f"streamed run; the previously stored context is left intact. Error: {error}",
340
+ exc_info=error,
341
+ )
342
+
223
343
  @abstractmethod
224
344
  async def run(self, agent: Any, session: Session, requests: list[AgentRequest]) -> AgentReply:
225
345
  """
@@ -351,3 +471,16 @@ class Agent(ABC):
351
471
 
352
472
  for tool in SystemToolFactory.get_all(self.name):
353
473
  self.attach_tool(tool.func)
474
+
475
+ @staticmethod
476
+ def _append_tools(agent: Any, wrapped: list[Any]) -> None:
477
+ """
478
+ Appends already-wrapped tools to a framework agent's list-based `tools` attribute, skipping duplicates.
479
+ :param agent: The framework-native agent holding the `tools` attribute.
480
+ :param wrapped: The wrapped tools to attach.
481
+ """
482
+ for w in wrapped:
483
+ if not hasattr(agent, "tools") or agent.tools is None:
484
+ agent.tools = []
485
+ if w not in agent.tools:
486
+ agent.tools.append(w)
@@ -13,7 +13,7 @@ from google.adk.agents import BaseAgent
13
13
  from google.adk.agents.run_config import RunConfig, StreamingMode
14
14
  from google.adk.events import Event, EventActions
15
15
  from google.adk.runners import Runner
16
- from google.adk.sessions import BaseSessionService, InMemorySessionService
16
+ from google.adk.sessions import BaseSessionService, InMemorySessionService, State
17
17
  from google.adk.tools import FunctionTool, ToolContext
18
18
  from google.genai import types
19
19
  from pydantic import ValidationError
@@ -76,6 +76,21 @@ class GoogleADKSession:
76
76
  )
77
77
  await self._session_service.append_event(self._session, event)
78
78
 
79
+ async def get_state(self) -> dict:
80
+ """
81
+ Returns the caller-visible ADK session state, stripping the AK-internal ``ak_tool_context`` id and the
82
+ ``app:`` / ``user:`` / ``temp:`` prefixed keys that are not session-scoped.
83
+ :return: The accumulated session state, or an empty dict when no session exists.
84
+ """
85
+ if self._session is None:
86
+ return {}
87
+ refreshed = await self._session_service.get_session(
88
+ app_name=self._session.app_name, user_id=self._session.user_id, session_id=self._session.id
89
+ )
90
+ state = dict(getattr(refreshed, "state", {}) or {})
91
+ state.pop("ak_tool_context", None)
92
+ return {k: v for k, v in state.items() if not k.startswith((State.APP_PREFIX, State.USER_PREFIX, State.TEMP_PREFIX))}
93
+
79
94
 
80
95
  class GoogleADKRunner(BaseRunner):
81
96
  def __init__(self):
@@ -131,7 +146,7 @@ class GoogleADKRunner(BaseRunner):
131
146
  parts.append(types.Part(file_data=types.FileData(file_uri=base64_data)))
132
147
  continue
133
148
 
134
- if base64_data.startswith(("data:")):
149
+ if base64_data.startswith("data:"):
135
150
  mime_type = base64_data.split(";")[0][5:]
136
151
  else:
137
152
  if not req.mime_type:
@@ -143,15 +158,19 @@ class GoogleADKRunner(BaseRunner):
143
158
 
144
159
  return prompt, parts
145
160
 
146
- async def _setup_session_context(self, agent: Any, session: Session, requests: list[AgentRequest]) -> tuple[str, Runner, AKToolContext]:
161
+ async def _setup_session_context(
162
+ self, agent: Any, session: Session, requests: list[AgentRequest], injected: dict | None = None
163
+ ) -> tuple[str, Runner, AKToolContext, GoogleADKSession]:
147
164
  """
148
165
  Setup ADK session and tool context.
149
166
  :param agent: The ADK agent.
150
167
  :param session: The AgentKernel session.
151
168
  :param requests: The requests.
152
- :return: Tuple of (user_id, runner, tool_context). The caller is responsible for entering/exiting
153
- the returned tool_context around the runner's actual execution, since tools invoked by
154
- the agent look up this context by id from the cache while the agent is running.
169
+ :param injected: The per-run framework context to seed into the ADK session state, or None.
170
+ :return: Tuple of (user_id, runner, tool_context, adk_session). The caller is responsible for
171
+ entering/exiting the returned tool_context around the runner's actual execution, since
172
+ tools invoked by the agent look up this context by id from the cache while the agent is
173
+ running. The returned adk_session lets the caller read state back without re-fetching.
155
174
  """
156
175
  app_name = "AgentKernel"
157
176
  user_id = "AgentKernel"
@@ -159,10 +178,13 @@ class GoogleADKRunner(BaseRunner):
159
178
 
160
179
  ctx: AKToolContext = AKToolContext(Runtime.current(), agent, session, requests)
161
180
  await adk_session.create_session(app_name=app_name, user_id=user_id, session_id=session.id)
162
- await adk_session.update_session_state(ctx.id, agent.name, {"ak_tool_context": ctx.id})
181
+ # Assigned last so a caller key of the same name cannot replace the id tools resolve their context by.
182
+ state = dict(injected or {})
183
+ state["ak_tool_context"] = ctx.id
184
+ await adk_session.update_session_state(ctx.id, agent.name, state)
163
185
 
164
186
  runner = Runner(agent=agent.agent, app_name=app_name, session_service=adk_session.session_service)
165
- return user_id, runner, ctx
187
+ return user_id, runner, ctx, adk_session
166
188
 
167
189
  @staticmethod
168
190
  async def get_response(runner: Runner, user_id: str, session_id: str, parts: list[types.Part]) -> str:
@@ -178,15 +200,12 @@ class GoogleADKRunner(BaseRunner):
178
200
  response_text = ""
179
201
 
180
202
  if hasattr(runner, "run_async"):
181
- events = runner.run_async(user_id=user_id, session_id=session_id, new_message=new_message)
182
- try:
183
- async for event in events:
184
- if event.is_final_response() and event.content and event.content.parts:
185
- text_parts = [p.text for p in event.content.parts if hasattr(p, "text") and p.text]
186
- response_text = " ".join(text_parts) if text_parts else ""
187
- break
188
- finally:
189
- await events.aclose()
203
+ # Drain the stream instead of breaking early: stopping early cancels ADK's still-running root agent
204
+ # task, and with sub-agents the last final response is the one to return.
205
+ async for event in runner.run_async(user_id=user_id, session_id=session_id, new_message=new_message):
206
+ if event.is_final_response() and event.content and event.content.parts:
207
+ text_parts = [p.text for p in event.content.parts if hasattr(p, "text") and p.text]
208
+ response_text = " ".join(text_parts) if text_parts else ""
190
209
  else:
191
210
  for event in runner.run(user_id=user_id, session_id=session_id, new_message=new_message):
192
211
  if event.is_final_response() and event.content and event.content.parts:
@@ -203,16 +222,24 @@ class GoogleADKRunner(BaseRunner):
203
222
  :param requests: The requests to the agent.
204
223
  :return: The result of the agent's execution.
205
224
  """
225
+ prompt = ""
206
226
  try:
207
227
  prompt, parts = self._process_requests(requests)
208
228
 
209
229
  if not parts:
210
230
  return AgentReplyText(response="Sorry. No valid content found in the requests")
211
231
 
212
- user_id, runner, ctx = await self._setup_session_context(agent, session, requests)
232
+ incoming = self._load_framework_context(session)
233
+ user_id, runner, ctx, adk_session = await self._setup_session_context(agent, session, requests, incoming)
213
234
  with ctx:
214
235
  reply = await self.get_response(runner=runner, session_id=session.id, parts=parts, user_id=user_id)
215
236
 
237
+ # Write back the full ADK state, so keys a tool added during the run also round-trip. Done after
238
+ # the run, so a framework error leaves the stored context intact.
239
+ if incoming is not None:
240
+ produced = await adk_session.get_state()
241
+ self._store_framework_context(session, incoming, produced)
242
+
216
243
  output_schema = getattr(agent.agent, "output_schema", None)
217
244
  if output_schema is not None:
218
245
  try:
@@ -237,7 +264,8 @@ class GoogleADKRunner(BaseRunner):
237
264
  if not parts:
238
265
  return
239
266
 
240
- user_id, runner, ctx = await self._setup_session_context(agent, session, requests)
267
+ incoming = self._load_framework_context(session)
268
+ user_id, runner, ctx, adk_session = await self._setup_session_context(agent, session, requests, incoming)
241
269
  new_message = types.Content(role="user", parts=parts)
242
270
  run_config = RunConfig(streaming_mode=StreamingMode.SSE)
243
271
 
@@ -257,6 +285,15 @@ class GoogleADKRunner(BaseRunner):
257
285
  if chunk:
258
286
  yield chunk
259
287
 
288
+ # Only after the stream drains normally, so a disconnect or mid-stream error leaves the stored
289
+ # context intact. Deliberately not in a finally.
290
+ if incoming is not None:
291
+ try:
292
+ produced = await adk_session.get_state()
293
+ self._store_framework_context(session, incoming, produced)
294
+ except Exception as e:
295
+ self._log_framework_context_stream_failure(session, e)
296
+
260
297
 
261
298
  class GoogleADKAgent(AKBaseAgent):
262
299
  """
@@ -293,9 +330,8 @@ class GoogleADKAgent(AKBaseAgent):
293
330
  Appends the given prompt text to the ADK agent's description.
294
331
  Called by the base Agent._setup_system_prompt() at init when multimodal is enabled.
295
332
  """
296
- if hasattr(self._agent, "description") and self._agent.description:
297
- if prompt not in self._agent.description:
298
- self._agent.description += "\n" + prompt
333
+ if hasattr(self._agent, "description") and self._agent.description and prompt not in self._agent.description:
334
+ self._agent.description += "\n" + prompt
299
335
 
300
336
  def attach_tool(self, tool: Any) -> None:
301
337
  """
@@ -304,12 +340,7 @@ class GoogleADKAgent(AKBaseAgent):
304
340
  :param tool: Raw Python callable or already-wrapped ADK FunctionTool.
305
341
  """
306
342
  # Delegate to the tool builder to handle binding
307
- wrapped = GoogleADKToolBuilder.bind([tool])
308
- for w in wrapped:
309
- if not hasattr(self._agent, "tools") or self._agent.tools is None:
310
- self._agent.tools = []
311
- if w not in self._agent.tools:
312
- self._agent.tools.append(w)
343
+ self._append_tools(self._agent, GoogleADKToolBuilder.bind([tool]))
313
344
 
314
345
  def get_a2a_card(self):
315
346
  """
@@ -410,15 +441,40 @@ class GoogleADKToolBuilder(ToolBuilder):
410
441
  if not callable(func):
411
442
  raise TypeError(f"Expected a callable, got {type(func).__name__}")
412
443
 
444
+ signature = inspect.signature(func)
445
+ parameters = list(signature.parameters.values())
446
+
447
+ # ADK-aware tools declare `tool_context` themselves and expect the live ADK
448
+ # context to reach them, so it has to be forwarded. Generic tools do not, and
449
+ # for those the parameter is consumed here purely to activate the AK context.
450
+ declares_tool_context = "tool_context" in signature.parameters
451
+ tool_context_position = list(signature.parameters).index("tool_context") if declares_tool_context else -1
452
+
453
+ def forwarded_kwargs(args: tuple[Any, ...], kwargs: dict[str, Any], tool_context: ToolContext | None) -> dict[str, Any]:
454
+ """
455
+ Builds the keyword arguments for the wrapped function.
456
+
457
+ :param args: Positional arguments the wrapper was called with.
458
+ :param kwargs: Keyword arguments the wrapper was called with.
459
+ :param tool_context: The ADK tool context supplied to the wrapper.
460
+ :return: The keyword arguments to pass to the wrapped function.
461
+ """
462
+ if not declares_tool_context or "tool_context" in kwargs:
463
+ return kwargs
464
+ # The caller already bound tool_context positionally; do not bind it twice.
465
+ if len(args) > tool_context_position:
466
+ return kwargs
467
+ return {**kwargs, "tool_context": tool_context}
468
+
413
469
  if asyncio.iscoroutinefunction(func):
414
470
 
415
471
  @functools.wraps(func)
416
- async def wrapper(*args: Any, tool_context: ToolContext, **kwargs: Any) -> Any:
472
+ async def wrapper(*args: Any, tool_context: ToolContext | None = None, **kwargs: Any) -> Any:
417
473
  tctx: AKToolContext | None = None
418
474
  try:
419
475
  if tool_context and tool_context.state and tool_context.state.get("ak_tool_context"):
420
476
  tctx = AKToolContext.fetch(tool_context.state["ak_tool_context"]).set()
421
- return await func(*args, **kwargs)
477
+ return await func(*args, **forwarded_kwargs(args, kwargs, tool_context))
422
478
  finally:
423
479
  if tctx:
424
480
  tctx.reset()
@@ -426,23 +482,20 @@ class GoogleADKToolBuilder(ToolBuilder):
426
482
  else:
427
483
 
428
484
  @functools.wraps(func)
429
- def wrapper(*args: Any, tool_context: ToolContext, **kwargs: Any) -> Any:
485
+ def wrapper(*args: Any, tool_context: ToolContext | None = None, **kwargs: Any) -> Any:
430
486
  tctx: AKToolContext | None = None
431
487
  try:
432
488
  if tool_context and tool_context.state and tool_context.state.get("ak_tool_context"):
433
489
  tctx = AKToolContext.fetch(tool_context.state["ak_tool_context"]).set()
434
- return func(*args, **kwargs)
490
+ return func(*args, **forwarded_kwargs(args, kwargs, tool_context))
435
491
  finally:
436
492
  if tctx:
437
493
  tctx.reset()
438
494
 
439
- signature = inspect.signature(func)
440
- parameters = list(signature.parameters.values())
441
-
442
495
  # Only add a tool_context parameter if the original function does not already
443
496
  # declare one, and insert it before any **kwargs (VAR_KEYWORD) parameter to
444
497
  # maintain a valid inspect.Signature ordering.
445
- if "tool_context" not in signature.parameters:
498
+ if not declares_tool_context:
446
499
  tool_context_param = inspect.Parameter(
447
500
  "tool_context",
448
501
  kind=inspect.Parameter.KEYWORD_ONLY,
@@ -273,6 +273,8 @@ class CrewAIRunner(Runner):
273
273
  """
274
274
  super().__init__(FRAMEWORK)
275
275
  self._log = logging.getLogger("ak.crewai.runner")
276
+ self._context_warned = False
277
+ """Whether the unsupported-framework_context warning was already logged."""
276
278
 
277
279
  def _transcript(self, session: Session) -> list[str] | None:
278
280
  """
@@ -375,6 +377,11 @@ class CrewAIRunner(Runner):
375
377
  verbose=False,
376
378
  memory=memory,
377
379
  )
380
+ # CrewAI's kickoff(inputs=...) are template-interpolation variables, not a context/state object, so
381
+ # there is no per-run caller-state slot. Warn once, and leave the stored context untouched.
382
+ if not self._context_warned and session is not None and session.get_framework_context():
383
+ self._log.warning("framework_context is set but CrewAI does not support per-run caller context/state; ignoring it.")
384
+ self._context_warned = True
378
385
  reply = await crew.kickoff_async(inputs={})
379
386
  if isinstance(getattr(reply, "pydantic", None), BaseModel):
380
387
  agent_reply: AgentReply = AgentReplyAny(content=reply.pydantic.model_dump(mode="json"), prompt=prompt)
@@ -510,12 +517,7 @@ class CrewAIAgent(BaseAgent):
510
517
  :param tool: Raw Python callable or already-wrapped CrewAI tool.
511
518
  """
512
519
  # Delegate to the tool builder to handle binding
513
- wrapped = CrewAIToolBuilder.bind([tool])
514
- for w in wrapped:
515
- if not hasattr(self.agent, "tools") or self.agent.tools is None:
516
- self.agent.tools = []
517
- if w not in self.agent.tools:
518
- self.agent.tools.append(w)
520
+ self._append_tools(self.agent, CrewAIToolBuilder.bind([tool]))
519
521
 
520
522
  def override_system_prompt(self, prompt: str) -> None:
521
523
  """
@@ -371,6 +371,7 @@ class LangGraphRunner(BaseRunner):
371
371
  :param requests: The requests to the agent.
372
372
  :return: The result of the agent's execution.
373
373
  """
374
+ prompt = ""
374
375
  context: ToolContext | None = None
375
376
  try:
376
377
  context = ToolContext(Runtime.current(), agent, session, requests).set()
@@ -387,10 +388,24 @@ class LangGraphRunner(BaseRunner):
387
388
 
388
389
  config, messages = self._prepare_session_and_messages(agent, session, prompt)
389
390
 
391
+ # Spread the context's top-level keys into the input state so they map onto the graph's state
392
+ # channels. `messages` is written last so a caller key cannot replace it.
393
+ incoming = self._load_framework_context(session)
394
+ input_state: dict[str, Any] = {}
395
+ if incoming:
396
+ input_state.update(incoming)
397
+ input_state["messages"] = messages
398
+
390
399
  result = await agent.agent.ainvoke(
391
- input={"messages": messages},
400
+ input=input_state,
392
401
  config=config,
393
402
  )
403
+
404
+ # Only keys the graph declares as state channels come back on `result`; the rest keep their value.
405
+ if incoming is not None:
406
+ produced = {k: result[k] for k in incoming if k in result}
407
+ self._store_framework_context(session, incoming, produced)
408
+
394
409
  structured = AgentReplyAny.from_output(result.get("structured_response"), prompt)
395
410
  if structured is not None:
396
411
  return structured
@@ -423,8 +438,14 @@ class LangGraphRunner(BaseRunner):
423
438
 
424
439
  config, messages = self._prepare_session_and_messages(agent, session, prompt)
425
440
 
441
+ incoming = self._load_framework_context(session)
442
+ input_state: dict[str, Any] = {}
443
+ if incoming:
444
+ input_state.update(incoming)
445
+ input_state["messages"] = messages
446
+
426
447
  async for event in agent.agent.astream_events(
427
- input={"messages": messages},
448
+ input=input_state,
428
449
  config=config,
429
450
  version="v2",
430
451
  ):
@@ -436,6 +457,16 @@ class LangGraphRunner(BaseRunner):
436
457
  for item in content:
437
458
  if isinstance(item, dict) and item.get("text"):
438
459
  yield item["text"]
460
+
461
+ # astream_events yields events, not a final state, so read the state back once the stream drains
462
+ # normally. A disconnect or mid-stream error unwinds first, leaving the stored context intact.
463
+ if incoming is not None:
464
+ try:
465
+ state = await agent.agent.aget_state(config)
466
+ produced = {k: state.values[k] for k in incoming if k in state.values}
467
+ self._store_framework_context(session, incoming, produced)
468
+ except Exception as e:
469
+ self._log_framework_context_stream_failure(session, e)
439
470
  finally:
440
471
  if context is not None:
441
472
  context.reset()
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import copy
3
4
  from collections.abc import AsyncGenerator
4
5
  from typing import Any, Callable, List
5
6
 
@@ -171,6 +172,7 @@ class OpenAIRunner(BaseRunner):
171
172
  :param requests: The requests to the agent.
172
173
  :return: The result of the agent's execution.
173
174
  """
175
+ prompt = ""
174
176
  context: ToolContext | None = None
175
177
  try:
176
178
  context = ToolContext(Runtime.current(), agent, session, requests).set()
@@ -180,7 +182,13 @@ class OpenAIRunner(BaseRunner):
180
182
  return AgentReplyText(response="Sorry. No valid content found in the requests")
181
183
 
182
184
  input_data, session_to_use = self._get_run_input(agent, session, prompt, message_content)
183
- reply = (await Runner.run(agent.agent, input_data, session=session_to_use)).final_output
185
+ # Injected as the run context, so tools read and write it via RunContextWrapper.context.
186
+ # A deep copy is passed in so tools mutating it in place don't also mutate `incoming`.
187
+ incoming = self._load_framework_context(session)
188
+ produced = copy.deepcopy(incoming)
189
+ reply = (await Runner.run(agent.agent, input_data, session=session_to_use, context=produced)).final_output
190
+
191
+ self._store_framework_context(session, incoming, produced)
184
192
 
185
193
  structured = AgentReplyAny.from_output(reply, prompt)
186
194
  if structured is not None:
@@ -211,12 +219,21 @@ class OpenAIRunner(BaseRunner):
211
219
  return
212
220
 
213
221
  input_data, session_to_use = self._get_run_input(agent, session, prompt, message_content)
214
- result = Runner.run_streamed(agent.agent, input_data, session=session_to_use)
222
+ incoming = self._load_framework_context(session)
223
+ produced = copy.deepcopy(incoming)
224
+ result = Runner.run_streamed(agent.agent, input_data, session=session_to_use, context=produced)
215
225
 
216
226
  async for event in result.stream_events():
217
227
  if event.type == "raw_response_event" and isinstance(event.data, ResponseTextDeltaEvent):
218
228
  if event.data.delta:
219
229
  yield event.data.delta
230
+
231
+ # Only after the stream drains normally, so a disconnect or framework error leaves the stored
232
+ # context intact. Deliberately not in a finally.
233
+ try:
234
+ self._store_framework_context(session, incoming, produced)
235
+ except Exception as e:
236
+ self._log_framework_context_stream_failure(session, e)
220
237
  finally:
221
238
  if context is not None:
222
239
  context.reset()
@@ -268,12 +285,7 @@ class OpenAIAgent(BaseAgent):
268
285
  :param tool: Raw Python callable or already-wrapped OpenAI function_tool.
269
286
  """
270
287
  # Delegate to the tool builder to handle binding
271
- wrapped = OpenAIToolBuilder.bind([tool])
272
- for w in wrapped:
273
- if not hasattr(self._agent, "tools") or self._agent.tools is None:
274
- self._agent.tools = []
275
- if w not in self._agent.tools:
276
- self._agent.tools.append(w)
288
+ self._append_tools(self._agent, OpenAIToolBuilder.bind([tool]))
277
289
 
278
290
  def get_a2a_card(self):
279
291
  """