agentkernel 0.6.0__tar.gz → 0.6.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 (177) hide show
  1. {agentkernel-0.6.0 → agentkernel-0.6.1}/PKG-INFO +8 -8
  2. {agentkernel-0.6.0 → agentkernel-0.6.1}/pyproject.toml +9 -9
  3. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/handler.py +21 -5
  4. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/http.py +4 -1
  5. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/__init__.py +1 -0
  6. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/base.py +12 -1
  7. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/chat_service.py +151 -39
  8. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/config.py +1 -1
  9. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/hooks.py +14 -0
  10. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/model.py +6 -0
  11. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/dynamodb.py +4 -0
  12. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/redis.py +2 -1
  13. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/session_cache.py +4 -0
  14. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/runtime.py +80 -19
  15. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/service.py +17 -1
  16. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/util/config_yaml_util.py +8 -2
  17. agentkernel-0.6.1/src/agentkernel/deployment/aws/serverless/__init__.py +13 -0
  18. agentkernel-0.6.1/src/agentkernel/deployment/aws/serverless/akagentrunner.py +279 -0
  19. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/aklambda.py +2 -1
  20. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/akresponsehandler.py +48 -24
  21. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/core/router/rest_lambda.py +11 -4
  22. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/core/router/ws_lambda.py +109 -32
  23. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/adk/adk.py +115 -58
  24. agentkernel-0.6.1/src/agentkernel/framework/crewai/crewai.py +502 -0
  25. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/langgraph/langgraph.py +86 -24
  26. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/openai/openai.py +101 -56
  27. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/smolagents/smolagents.py +9 -0
  28. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-add-capabilities/SKILL.md +26 -18
  29. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-add-capabilities/evals/evals.json +1 -1
  30. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-add-integration/SKILL.md +8 -8
  31. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-add-integration/evals/evals.json +1 -1
  32. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-build/SKILL.md +1 -1
  33. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-build/evals/evals.json +1 -1
  34. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-cloud-deploy/SKILL.md +79 -20
  35. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-cloud-deploy/evals/evals.json +18 -1
  36. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-init/SKILL.md +2 -2
  37. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-init/evals/evals.json +2 -2
  38. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-test/SKILL.md +2 -2
  39. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/ak-test/evals/evals.json +1 -1
  40. agentkernel-0.6.0/src/agentkernel/deployment/aws/serverless/__init__.py +0 -5
  41. agentkernel-0.6.0/src/agentkernel/deployment/aws/serverless/akagentrunner.py +0 -137
  42. agentkernel-0.6.0/src/agentkernel/framework/crewai/crewai.py +0 -306
  43. {agentkernel-0.6.0 → agentkernel-0.6.1}/README.md +0 -0
  44. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/__init__.py +0 -0
  45. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/adk.py +0 -0
  46. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/__init__.py +0 -0
  47. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/a2a/__init__.py +0 -0
  48. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/a2a/a2a.py +0 -0
  49. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/a2a/handler.py +0 -0
  50. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/mcp/__init__.py +0 -0
  51. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/api/mcp/akmcp.py +0 -0
  52. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/auth/__init__.py +0 -0
  53. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/auth/handler.py +0 -0
  54. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/auth.py +0 -0
  55. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/aws.py +0 -0
  56. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/azure.py +0 -0
  57. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/cli/__init__.py +0 -0
  58. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/cli/ak.py +0 -0
  59. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/cli/cli.py +0 -0
  60. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/builder.py +0 -0
  61. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/logger.py +0 -0
  62. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/module.py +0 -0
  63. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/__init__.py +0 -0
  64. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/factory.py +0 -0
  65. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/hooks.py +0 -0
  66. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/__init__.py +0 -0
  67. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/base.py +0 -0
  68. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/in_memory.py +0 -0
  69. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/storage/storage_manager.py +0 -0
  70. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/multimodal/tools.py +0 -0
  71. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/__init__.py +0 -0
  72. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/base.py +0 -0
  73. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/cosmosdb.py +0 -0
  74. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/dynamodb.py +0 -0
  75. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/firestore.py +0 -0
  76. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/in_memory.py +0 -0
  77. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/redis.py +0 -0
  78. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/session/serde.py +0 -0
  79. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/tool.py +0 -0
  80. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/util/error_util.py +0 -0
  81. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/core/util/key_value_cache.py +0 -0
  82. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/crewai.py +0 -0
  83. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/__init__.py +0 -0
  84. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/__init__.py +0 -0
  85. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/__init__.py +0 -0
  86. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/response_store/__init__.py +0 -0
  87. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/response_store/dynamodb.py +0 -0
  88. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/response_store/handler.py +0 -0
  89. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/response_store/redis.py +0 -0
  90. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/sqs_handler.py +0 -0
  91. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/core/websocket_service.py +0 -0
  92. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/akauthorizer.py +0 -0
  93. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/akwsconnectionhandler.py +0 -0
  94. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/core/__init__.py +0 -0
  95. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/core/router/__init__.py +0 -0
  96. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/core/router/common.py +0 -0
  97. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/aws/serverless/core/sqs_consumer.py +0 -0
  98. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/azure/__init__.py +0 -0
  99. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/azure/akfunction.py +0 -0
  100. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/common/__init__.py +0 -0
  101. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/common/response_store.py +0 -0
  102. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/common/websocket_connection_store.py +0 -0
  103. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/gcp/__init__.py +0 -0
  104. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/gcp/akauthorizer.py +0 -0
  105. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/deployment/gcp/akcloudrun.py +0 -0
  106. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/__init__.py +0 -0
  107. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/adk/__init__.py +0 -0
  108. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/crewai/__init__.py +0 -0
  109. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/langgraph/__init__.py +0 -0
  110. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/openai/__init__.py +0 -0
  111. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/framework/smolagents/__init__.py +0 -0
  112. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/gcp.py +0 -0
  113. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/gmail.py +0 -0
  114. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/guardrail/__init__.py +0 -0
  115. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/guardrail/bedrock.py +0 -0
  116. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/guardrail/guardrail.py +0 -0
  117. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/guardrail/openai.py +0 -0
  118. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/guardrail/walledai.py +0 -0
  119. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/instagram.py +0 -0
  120. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/__init__.py +0 -0
  121. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/gmail/README.md +0 -0
  122. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/gmail/__init__.py +0 -0
  123. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/gmail/gmail_chat.py +0 -0
  124. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/instagram/README.md +0 -0
  125. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/instagram/__init__.py +0 -0
  126. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/instagram/instagram_chat.py +0 -0
  127. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/messenger/README.md +0 -0
  128. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/messenger/__init__.py +0 -0
  129. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/messenger/messenger_chat.py +0 -0
  130. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/slack/README.md +0 -0
  131. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/slack/__init__.py +0 -0
  132. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/slack/slack_chat.py +0 -0
  133. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/teams/README.md +0 -0
  134. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/teams/__init__.py +0 -0
  135. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/teams/teams_chat.py +0 -0
  136. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/telegram/README.md +0 -0
  137. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/telegram/__init__.py +0 -0
  138. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/telegram/telegram_chat.py +0 -0
  139. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/whatsapp/README.md +0 -0
  140. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/whatsapp/__init__.py +0 -0
  141. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/integration/whatsapp/whatsapp_chat.py +0 -0
  142. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/knowledgebase/__init__.py +0 -0
  143. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/knowledgebase/base.py +0 -0
  144. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/knowledgebase/chroma.py +0 -0
  145. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/knowledgebase/knowledgebuilder.py +0 -0
  146. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/knowledgebase/neo4j.py +0 -0
  147. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/knowledgebase/starburst.py +0 -0
  148. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/langgraph.py +0 -0
  149. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/mcp.py +0 -0
  150. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/messenger.py +0 -0
  151. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/openai.py +0 -0
  152. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/__init__.py +0 -0
  153. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/skills/skills.py +0 -0
  154. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/slack.py +0 -0
  155. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/smolagents.py +0 -0
  156. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/teams.py +0 -0
  157. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/telegram.py +0 -0
  158. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/test/__init__.py +0 -0
  159. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/test/test.py +0 -0
  160. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/__init__.py +0 -0
  161. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/base.py +0 -0
  162. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/__init__.py +0 -0
  163. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/adk.py +0 -0
  164. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/crewai.py +0 -0
  165. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/langfuse.py +0 -0
  166. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/langgraph.py +0 -0
  167. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/openai.py +0 -0
  168. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/langfuse/smolagents.py +0 -0
  169. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/__init__.py +0 -0
  170. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/adk.py +0 -0
  171. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/crewai.py +0 -0
  172. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/langgraph.py +0 -0
  173. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/openai.py +0 -0
  174. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/openllmetry.py +0 -0
  175. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/openllmetry/smolagents.py +0 -0
  176. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/trace/trace.py +0 -0
  177. {agentkernel-0.6.0 → agentkernel-0.6.1}/src/agentkernel/whatsapp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: agentkernel
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: Agent Kernel - Unified AI Agents Runtime
5
5
  Author: Yaala Labs
6
6
  Author-email: Yaala Labs <agentkernel@yaalalabs.com>
@@ -12,18 +12,18 @@ Requires-Dist: pyyaml>=6.0.2
12
12
  Requires-Dist: singleton-type>=0.0.5
13
13
  Requires-Dist: a2a-sdk[http-server]>=0.3.6 ; extra == 'a2a'
14
14
  Requires-Dist: google-adk>=1.14.1 ; extra == 'adk'
15
- Requires-Dist: litellm~=1.74.3 ; extra == 'adk'
15
+ Requires-Dist: litellm~=1.89.2 ; extra == 'adk'
16
16
  Requires-Dist: openinference-instrumentation-google-adk>=0.1.6 ; extra == 'adk'
17
17
  Requires-Dist: fastapi>=0.118.0 ; extra == 'api'
18
18
  Requires-Dist: uvicorn>=0.37.0 ; extra == 'api'
19
19
  Requires-Dist: gunicorn>=23.0.0 ; extra == 'api'
20
- Requires-Dist: pyjwt>=2.0.0 ; extra == 'auth'
20
+ Requires-Dist: pyjwt>=2.13.0 ; extra == 'auth'
21
21
  Requires-Dist: boto3>=1.41.4 ; extra == 'aws'
22
22
  Requires-Dist: azure-functions>=1.24.0 ; extra == 'azure'
23
23
  Requires-Dist: azure-data-tables>=12.4.0 ; extra == 'azure'
24
24
  Requires-Dist: azure-core>=1.26.0 ; extra == 'azure'
25
25
  Requires-Dist: chromadb>=0.4.0 ; extra == 'chromadb'
26
- Requires-Dist: crewai>=0.150.0 ; extra == 'crewai'
26
+ Requires-Dist: crewai>=1.15.0 ; extra == 'crewai'
27
27
  Requires-Dist: openinference-instrumentation-crewai>=0.1.16 ; extra == 'crewai'
28
28
  Requires-Dist: openinference-instrumentation-litellm>=0.1.28 ; extra == 'crewai'
29
29
  Requires-Dist: google-cloud-firestore>=2.19.0 ; extra == 'gcp'
@@ -36,15 +36,15 @@ Requires-Dist: langfuse>=4.2.0 ; extra == 'langfuse'
36
36
  Requires-Dist: nest-asyncio>=1.6.0 ; extra == 'langfuse'
37
37
  Requires-Dist: langgraph~=1.0.5 ; extra == 'langgraph'
38
38
  Requires-Dist: langchain~=1.2.3 ; extra == 'langgraph'
39
- Requires-Dist: langchain-community~=0.4.1 ; extra == 'langgraph'
40
- Requires-Dist: litellm~=1.74.9 ; extra == 'langgraph'
39
+ Requires-Dist: langchain-community==0.4.1 ; extra == 'langgraph'
40
+ Requires-Dist: litellm~=1.89.2 ; extra == 'langgraph'
41
41
  Requires-Dist: fastmcp>=2.14.2,<3.0.0 ; extra == 'mcp'
42
42
  Requires-Dist: httpx>=0.27.0 ; extra == 'messenger'
43
43
  Requires-Dist: neo4j>=5.0.0 ; extra == 'neo4j'
44
44
  Requires-Dist: openai-agents>=0.6.5 ; extra == 'openai'
45
45
  Requires-Dist: openinference-instrumentation-openai-agents>=1.4.0 ; extra == 'openai'
46
46
  Requires-Dist: openai-guardrails>=0.2.1 ; extra == 'openai'
47
- Requires-Dist: traceloop-sdk>=0.48.0 ; extra == 'openllmetry'
47
+ Requires-Dist: traceloop-sdk>=0.61.0 ; extra == 'openllmetry'
48
48
  Requires-Dist: redis>=7.1.0 ; extra == 'redis'
49
49
  Requires-Dist: slack-bolt==1.22.0 ; extra == 'slack'
50
50
  Requires-Dist: httpx>=0.27.0 ; extra == 'slack'
@@ -63,7 +63,7 @@ Requires-Dist: rapidfuzz>=3.14.1 ; extra == 'test'
63
63
  Requires-Dist: ragas>=0.4.1 ; extra == 'test'
64
64
  Requires-Dist: datasets>=2.14.0 ; extra == 'test'
65
65
  Requires-Dist: pandas>=2.0.0 ; extra == 'test'
66
- Requires-Dist: litellm>=1.74.9 ; extra == 'test'
66
+ Requires-Dist: litellm>=1.89.2 ; extra == 'test'
67
67
  Requires-Dist: trino>=0.337.0 ; extra == 'trino'
68
68
  Requires-Dist: walledai>=4.9.3 ; extra == 'walledai'
69
69
  Requires-Dist: httpx>=0.27.0 ; extra == 'whatsapp'
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "agentkernel"
7
- version = "0.6.0"
7
+ version = "0.6.1"
8
8
  description = "Agent Kernel - Unified AI Agents Runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12,<3.14"
@@ -22,25 +22,25 @@ dependencies = [
22
22
 
23
23
  [project.optional-dependencies]
24
24
  auth = [
25
- "PyJWT>=2.0.0",
25
+ "PyJWT>=2.13.0",
26
26
  ]
27
27
  langfuse = [
28
28
  "langfuse>=4.2.0",
29
29
  "nest-asyncio>=1.6.0",
30
30
  ]
31
31
  openllmetry = [
32
- "traceloop-sdk>=0.48.0",
32
+ "traceloop-sdk>=0.61.0",
33
33
  ]
34
34
  crewai = [
35
- "crewai>=0.150.0",
35
+ "crewai>=1.15.0",
36
36
  "openinference-instrumentation-crewai>=0.1.16",
37
37
  "openinference-instrumentation-litellm>=0.1.28",
38
38
  ]
39
39
  langgraph = [
40
40
  "langgraph~=1.0.5",
41
41
  "langchain~=1.2.3",
42
- "langchain_community~=0.4.1",
43
- "litellm~=1.74.9"
42
+ "langchain_community==0.4.1",
43
+ "litellm~=1.89.2"
44
44
  ]
45
45
  smolagents = [
46
46
  "smolagents>=1.0.0",
@@ -78,7 +78,7 @@ openai = [
78
78
  ]
79
79
  adk = [
80
80
  "google-adk>=1.14.1",
81
- "litellm~=1.74.3",
81
+ "litellm~=1.89.2",
82
82
  "openinference-instrumentation-google-adk>=0.1.6",
83
83
  ]
84
84
  walledai = [
@@ -130,7 +130,7 @@ test = [
130
130
  "ragas>=0.4.1",
131
131
  "datasets>=2.14.0",
132
132
  "pandas>=2.0.0",
133
- "litellm>=1.74.9",
133
+ "litellm>=1.89.2",
134
134
  ]
135
135
  a2a = [
136
136
  "a2a-sdk[http-server]>=0.3.6",
@@ -144,7 +144,7 @@ ak = "agentkernel.cli.ak:main"
144
144
 
145
145
  [dependency-groups]
146
146
  dev = [
147
- "black>=23.0.0",
147
+ "black==26.5.1",
148
148
  "isort>=5.0.0",
149
149
  "mypy>=1.0.0",
150
150
  ]
@@ -2,12 +2,13 @@ import logging
2
2
  from abc import ABC, abstractmethod
3
3
  from typing import List, Optional
4
4
 
5
- from fastapi import APIRouter, File, Form, UploadFile
5
+ from fastapi import APIRouter, File, Form, HTTPException, UploadFile
6
+ from fastapi.responses import StreamingResponse
6
7
  from pydantic import ConfigDict
7
8
 
8
9
  from ..core import Config
9
10
  from ..core.chat_service import ChatService
10
- from ..core.model import BaseChatRequest, BaseRunRequest
11
+ from ..core.model import BaseChatRequest, BaseRunRequest, ExecutionMode
11
12
  from ..core.runtime import Runtime
12
13
 
13
14
 
@@ -35,8 +36,8 @@ class AgentRESTRequestHandler(RESTRequestHandler):
35
36
  API routers that expose endpoints to interact with Agent Kernel.
36
37
  Endpoints:
37
38
  - GET /api/v1/agents: List available agents
38
- - POST /api/v1/chat: Run an agent with a prompt
39
- Payload JSON: { "prompt": str, "agent": str | null, "session_id": str | null }
39
+ - POST /api/v1/chat: Run an agent (streams SSE when execution.mode=stream, otherwise returns JSON)
40
+ - POST /api/v1/chat-multipart: Same as /api/v1/chat but accepts multipart form data with file/image uploads
40
41
  """
41
42
 
42
43
  class BaseMultimodalRunRequest(BaseChatRequest):
@@ -64,6 +65,14 @@ class AgentRESTRequestHandler(RESTRequestHandler):
64
65
 
65
66
  @router.post("/api/v1/chat")
66
67
  async def run(body: BaseRunRequest):
68
+ if Config.get().execution.mode == ExecutionMode.STREAM:
69
+ try:
70
+ gen = await self.chat_service.process_stream_chat_async(req=body, sse_format=True)
71
+ return StreamingResponse(gen, media_type="text/event-stream")
72
+ except ValueError as e:
73
+ raise HTTPException(status_code=400, detail=str(e))
74
+ except Exception as e:
75
+ raise HTTPException(status_code=500, detail=f"Streaming failed: {str(e)}")
67
76
  return await self.chat_service.process_async_chat_request(req=body)
68
77
 
69
78
  @router.post("/api/v1/chat-multipart")
@@ -74,7 +83,6 @@ class AgentRESTRequestHandler(RESTRequestHandler):
74
83
  files: Optional[List[UploadFile]] = File(None),
75
84
  images: Optional[List[UploadFile]] = File(None),
76
85
  ):
77
- # Construct BaseMultimodalRunRequest from form parameters
78
86
  req = AgentRESTRequestHandler.BaseMultimodalRunRequest(
79
87
  prompt=prompt,
80
88
  agent=agent,
@@ -82,6 +90,14 @@ class AgentRESTRequestHandler(RESTRequestHandler):
82
90
  files=files,
83
91
  images=images,
84
92
  )
93
+ if Config.get().execution.mode == ExecutionMode.STREAM:
94
+ try:
95
+ gen = await self.chat_service.process_stream_chat_async(req=req, sse_format=True)
96
+ return StreamingResponse(gen, media_type="text/event-stream")
97
+ except ValueError as e:
98
+ raise HTTPException(status_code=400, detail=str(e))
99
+ except Exception as e:
100
+ raise HTTPException(status_code=500, detail=f"Streaming failed: {str(e)}")
85
101
  return await self.chat_service.process_async_chat_request(req=req)
86
102
 
87
103
  return router
@@ -72,7 +72,10 @@ class RESTAPI:
72
72
  """
73
73
  cls._log.debug(f"Adding custom router")
74
74
  for route in router.routes:
75
- cls._log.debug(f"Route: {route.path} [{route.methods}]")
75
+ route_path = getattr(route, "path", None)
76
+ route_methods = getattr(route, "methods", None)
77
+ if route_path is not None:
78
+ cls._log.debug(f"Route: {route_path} [{route_methods}]")
76
79
  cls._custom_routers.append(router)
77
80
 
78
81
  @classmethod
@@ -21,6 +21,7 @@ from .model import (
21
21
  AgentReply,
22
22
  AgentReplyText,
23
23
  AgentReplyImage,
24
+ StreamChunk,
24
25
  )
25
26
  from .config import AKConfig as Config
26
27
  from .module import Module
@@ -2,7 +2,7 @@ import asyncio
2
2
  import contextvars
3
3
  import logging
4
4
  from abc import ABC, abstractmethod
5
- from collections.abc import Iterator
5
+ from collections.abc import AsyncGenerator, Iterator
6
6
  from enum import Enum
7
7
  from typing import Any, ClassVar, Self, cast
8
8
 
@@ -231,6 +231,17 @@ class Runner(ABC):
231
231
  """
232
232
  raise NotImplementedError()
233
233
 
234
+ @abstractmethod
235
+ async def stream(self, agent: Any, session: Session, requests: list[AgentRequest]) -> AsyncGenerator[str, None]:
236
+ """
237
+ Streams the agent response token by token.
238
+ :param agent: The agent to run.
239
+ :param session: The session to use for the agent.
240
+ :param requests: The list of requests to provide to the agent.
241
+ :return: An async generator yielding string token deltas.
242
+ """
243
+ raise NotImplementedError()
244
+
234
245
 
235
246
  class Agent(ABC):
236
247
  """
@@ -1,6 +1,8 @@
1
1
  import asyncio
2
2
  import base64
3
+ import json
3
4
  import logging
5
+ from collections.abc import AsyncGenerator, Generator
4
6
  from typing import Any, Dict, List, Optional, Union
5
7
 
6
8
  from .config import AKConfig
@@ -13,6 +15,7 @@ from .model import (
13
15
  AgentRequestText,
14
16
  BaseChatRequest,
15
17
  BaseRunRequest,
18
+ StreamChunk,
16
19
  )
17
20
  from .service import AgentService
18
21
 
@@ -194,21 +197,30 @@ class AgentHandler:
194
197
  if not self.service.agent:
195
198
  raise ValueError("No agent available")
196
199
 
197
- def run_sync(self, requests: List[Any]) -> Any:
198
- """Run agent requests synchronously.
200
+ @staticmethod
201
+ def _run_async_sync(coro) -> Any:
202
+ """Run an async coroutine from sync code, handling event loop state.
199
203
 
200
- :param requests: List of AgentRequest objects to process
201
- :return: Agent execution result
204
+ :param coro: Coroutine to execute
205
+ :return: Result of the coroutine
202
206
  """
203
207
  try:
204
208
  loop = asyncio.get_event_loop()
205
209
  if loop.is_closed():
206
210
  asyncio.set_event_loop(asyncio.new_event_loop())
207
- return asyncio.run(self.service.run_multi(requests=requests))
211
+ return asyncio.run(coro)
208
212
  else:
209
- return loop.run_until_complete(self.service.run_multi(requests=requests))
213
+ return loop.run_until_complete(coro)
210
214
  except RuntimeError:
211
- return asyncio.run(self.service.run_multi(requests=requests))
215
+ return asyncio.run(coro)
216
+
217
+ def run_sync(self, requests: List[Any]) -> Any:
218
+ """Run agent requests synchronously.
219
+
220
+ :param requests: List of AgentRequest objects to process
221
+ :return: Agent execution result
222
+ """
223
+ return AgentHandler._run_async_sync(self.service.run_multi(requests=requests))
212
224
 
213
225
  async def run_async(self, requests: List[Any]) -> Any:
214
226
  """Run agent requests asynchronously.
@@ -218,6 +230,32 @@ class AgentHandler:
218
230
  """
219
231
  return await self.service.run_multi(requests=requests)
220
232
 
233
+ def run_stream_sync(self, requests: List[Any]) -> List[Any]:
234
+ """Run agent streaming requests synchronously.
235
+
236
+ Manages event loop lifecycle internally and returns all chunks as a list.
237
+
238
+ :param requests: List of AgentRequest objects to process
239
+ :return: List of StreamChunk objects
240
+ """
241
+
242
+ async def _collect():
243
+ chunks = []
244
+ async for chunk in self.service.stream_multi(requests=requests):
245
+ chunks.append(chunk)
246
+ return chunks
247
+
248
+ return AgentHandler._run_async_sync(_collect())
249
+
250
+ async def run_stream_async(self, requests: List[Any]) -> AsyncGenerator[Any, None]:
251
+ """Run agent streaming requests asynchronously.
252
+
253
+ :param requests: List of AgentRequest objects to process
254
+ :return: AsyncGenerator yielding StreamChunk objects
255
+ """
256
+ async for chunk in self.service.stream_multi(requests=requests):
257
+ yield chunk
258
+
221
259
  def get_response_session_id(self, session_id: Optional[str]) -> Optional[str]:
222
260
  """Get the session ID for the response.
223
261
 
@@ -231,40 +269,44 @@ class ResponseBuilder:
231
269
  """Formats agent results and errors into response dicts."""
232
270
 
233
271
  @staticmethod
234
- def success(status_code: int, result: Any, session_id: str, rest_api_mode: bool):
235
- """Build success response from agent result.
272
+ def build_response(status_code: int, session_id: Optional[str], rest_api_mode: bool, result: Any = None, error: Optional[Exception] = None):
273
+ """Build response from agent result or error.
236
274
 
237
- :param status_code: HTTP status code for success
238
- :param result: Agent execution result
275
+ :param status_code: HTTP status code
239
276
  :param session_id: Session identifier for the response
240
- :param rest_api_mode: If True, return dict only; if False, return tuple
241
- :return: Response dict or (status_code, response_dict) tuple
277
+ :param rest_api_mode: If True, return dict only on success or raise HTTPException on error; if False, return tuple
278
+ :param result: Agent execution result (mutually exclusive with error)
279
+ :param error: Exception that occurred (mutually exclusive with result)
280
+ :return: Response dict or (status_code, response_dict) tuple; raises HTTPException if error in rest_api_mode
242
281
  """
243
- response_dict = {
244
- "result": str(result) if isinstance(result, (AgentReplyText, AgentReplyImage)) else "Non textual result received",
245
- "session_id": session_id,
246
- }
247
- return response_dict if rest_api_mode else (status_code, response_dict)
282
+ if error:
283
+ response_dict = {"error": str(error)}
284
+ else:
285
+ response_dict = {"result": str(result) if isinstance(result, (AgentReplyText, AgentReplyImage)) else "Non textual result received"}
248
286
 
249
- @staticmethod
250
- def error(status_code: int, error: Exception, session_id: Optional[str], rest_api_mode: bool):
251
- """Build error response from exception.
287
+ if session_id:
288
+ response_dict["session_id"] = session_id
252
289
 
253
- :param status_code: HTTP status code for error
254
- :param error: Exception that occurred
255
- :param session_id: Session identifier for the response
256
- :param rest_api_mode: If True, raise HTTPException; if False, return tuple
257
- :return: (status_code, response_dict) tuple or raises HTTPException
258
- """
259
- response_dict = {
260
- "error": str(error),
261
- "session_id": session_id,
262
- }
263
- if rest_api_mode:
290
+ if error and rest_api_mode:
264
291
  from fastapi import HTTPException
265
292
 
266
293
  raise HTTPException(status_code=status_code, detail=response_dict)
267
- return (status_code, response_dict)
294
+
295
+ return response_dict if rest_api_mode else (status_code, response_dict)
296
+
297
+ @staticmethod
298
+ def stream_chunk(chunk: StreamChunk, session_id: str, sse_format: bool = False) -> str:
299
+ """Format a StreamChunk as JSON or SSE.
300
+
301
+ :param chunk: StreamChunk to format
302
+ :param session_id: Session identifier to include in the payload
303
+ :param sse_format: When True, wrap the JSON payload as an SSE frame.
304
+ :return: JSON string or SSE-formatted string with excluded None values
305
+ """
306
+ payload_dict = chunk.model_dump(exclude_none=True)
307
+ payload_dict["session_id"] = session_id
308
+ payload = json.dumps(payload_dict)
309
+ return f"data: {payload}\n\n" if sse_format else payload
268
310
 
269
311
 
270
312
  class ChatService:
@@ -291,13 +333,13 @@ class ChatService:
291
333
  requests = RequestBuilder.from_base_request_sync(req)
292
334
  handler.initialize(session_id, req.agent)
293
335
  result = handler.run_sync(requests)
294
- return ResponseBuilder.success(200, result, handler.get_response_session_id(session_id), self.rest_api_mode)
336
+ return ResponseBuilder.build_response(200, handler.get_response_session_id(session_id), self.rest_api_mode, result=result)
295
337
  except ValueError as ve:
296
338
  self._log.error(f"ValueError processing request: {ve}")
297
- return ResponseBuilder.error(400, ve, handler.get_response_session_id(session_id), self.rest_api_mode)
339
+ return ResponseBuilder.build_response(400, handler.get_response_session_id(session_id), self.rest_api_mode, error=ve)
298
340
  except Exception as e:
299
341
  self._log.error(f"Error processing request: {e}")
300
- return ResponseBuilder.error(500, e, handler.get_response_session_id(None), self.rest_api_mode)
342
+ return ResponseBuilder.build_response(500, handler.get_response_session_id(None), self.rest_api_mode, error=e)
301
343
 
302
344
  async def process_async_chat_request(self, req: BaseChatRequest) -> Union[tuple[int, Dict[str, Any]], Dict[str, Any]]:
303
345
  """Process a chat request asynchronously.
@@ -317,13 +359,83 @@ class ChatService:
317
359
  requests = await RequestBuilder.from_base_request_async(req)
318
360
  handler.initialize(session_id, req.agent)
319
361
  result = await handler.run_async(requests)
320
- return ResponseBuilder.success(200, result, handler.get_response_session_id(session_id), self.rest_api_mode)
362
+ return ResponseBuilder.build_response(200, handler.get_response_session_id(session_id), self.rest_api_mode, result=result)
321
363
  except ValueError as ve:
322
364
  self._log.error(f"ValueError processing request: {ve}")
323
- return ResponseBuilder.error(400, ve, handler.get_response_session_id(session_id), self.rest_api_mode)
365
+ return ResponseBuilder.build_response(400, handler.get_response_session_id(session_id), self.rest_api_mode, error=ve)
324
366
  except Exception as e:
325
367
  self._log.error(f"Error processing request: {e}")
326
- return ResponseBuilder.error(500, e, handler.get_response_session_id(session_id), self.rest_api_mode)
368
+ return ResponseBuilder.build_response(500, handler.get_response_session_id(session_id), self.rest_api_mode, error=e)
369
+
370
+ async def process_stream_chat_async(
371
+ self,
372
+ req: BaseChatRequest,
373
+ sse_format: bool = False,
374
+ ) -> AsyncGenerator[str, None]:
375
+ """Process a streaming chat request asynchronously.
376
+
377
+ Validate, initialize, and return a streaming chat response generator.
378
+
379
+ :param req: Base chat request with prompt, session_id, agent, and optional attachments
380
+ :param sse_format: When True, yield Server-Sent Events formatted frames.
381
+ When False, yield raw StreamChunk JSON payloads.
382
+ :return: Async generator yielding StreamChunk payloads as JSON or SSE-formatted strings
383
+ :raises ValueError: If session_id or prompt is missing, or no agent is available
384
+ """
385
+ session_id = req.session_id
386
+ if not session_id:
387
+ raise ValueError("No session_id is provided in the request")
388
+ if not req.prompt:
389
+ raise ValueError("No prompt provided in the request")
390
+ requests = await RequestBuilder.from_base_request_async(req)
391
+ handler = AgentHandler()
392
+ handler.initialize(session_id, req.agent)
393
+
394
+ async def _stream() -> AsyncGenerator[str, None]:
395
+ try:
396
+ async for chunk in handler.run_stream_async(requests):
397
+ yield ResponseBuilder.stream_chunk(chunk, session_id, sse_format=sse_format)
398
+ except Exception as e:
399
+ error_chunk = StreamChunk(error=str(e), done=True)
400
+ yield ResponseBuilder.stream_chunk(error_chunk, session_id, sse_format=sse_format)
401
+
402
+ return _stream()
403
+
404
+ def process_stream_chat_sync(
405
+ self,
406
+ req: BaseRunRequest,
407
+ sse_format: bool = False,
408
+ ) -> Generator[str, None, None]:
409
+ """Process a streaming chat request synchronously.
410
+
411
+ Validates and initializes eagerly (before returning the generator), then
412
+ yields formatted streaming chunks. Mirrors the async version's pattern so
413
+ ValueError is raised at call time, not deferred until the first iteration.
414
+
415
+ :param req: Base run request with prompt, session_id, agent, and attachments
416
+ :param sse_format: When True, yield Server-Sent Events formatted frames.
417
+ When False, yield raw StreamChunk JSON payloads.
418
+ :return: Generator yielding StreamChunk payloads as JSON or SSE-formatted strings
419
+ :raises ValueError: If session_id or prompt is missing, or no agent is available
420
+ """
421
+ session_id = req.session_id
422
+ if not session_id:
423
+ raise ValueError("No session_id is provided in the request")
424
+ if not req.prompt:
425
+ raise ValueError("No prompt provided in the request")
426
+ requests = RequestBuilder.from_base_request_sync(req)
427
+ handler = AgentHandler()
428
+ handler.initialize(session_id, req.agent)
429
+
430
+ def _stream() -> Generator[str, None, None]:
431
+ try:
432
+ for chunk in handler.run_stream_sync(requests):
433
+ yield ResponseBuilder.stream_chunk(chunk, session_id, sse_format=sse_format)
434
+ except Exception as e:
435
+ error_chunk = StreamChunk(error=str(e), done=True)
436
+ yield ResponseBuilder.stream_chunk(error_chunk, session_id, sse_format=sse_format)
437
+
438
+ return _stream()
327
439
 
328
440
  @staticmethod
329
441
  def _validate(req: BaseRunRequest):
@@ -286,7 +286,7 @@ class _LoggingConfig(BaseModel):
286
286
  class _ExecutionConfig(BaseModel):
287
287
  mode: Optional[ExecutionMode] = Field(
288
288
  default=None,
289
- description="Execution mode: rest_sync for synchronous REST, rest_async for asynchronous REST",
289
+ description="Execution mode: rest_sync for synchronous REST, rest_async for asynchronous REST, stream for token streaming (WebSocket serverless or containerized direct streaming)",
290
290
  )
291
291
  queues: Optional[_QueuesConfig] = Field(default_factory=_QueuesConfig, description="Queue URLs for async execution mode")
292
292
  response_store: Optional[_ResponseStoreConfig] = Field(
@@ -67,6 +67,20 @@ class PostHook(ABC):
67
67
  """
68
68
  raise NotImplementedError
69
69
 
70
+ async def on_stream_chunk(
71
+ self,
72
+ session: "Session",
73
+ requests: list[AgentRequest],
74
+ agent: "Agent",
75
+ delta: str,
76
+ ) -> str | None:
77
+ """
78
+ Called for each streaming token delta before it is sent to the client.
79
+ Return the (optionally modified) delta string, or None to drop the token.
80
+ Default implementation passes the delta through unchanged.
81
+ """
82
+ return delta
83
+
70
84
  @abstractmethod
71
85
  def name(self) -> str:
72
86
  """
@@ -119,6 +119,12 @@ class ExecutionMode(str, Enum):
119
119
  ASYNC = "async"
120
120
 
121
121
 
122
+ class StreamChunk(BaseModel):
123
+ delta: str | None = None
124
+ done: bool = False
125
+ error: str | None = None
126
+
127
+
122
128
  class SystemTool(BaseModel):
123
129
  name: str
124
130
  description: str
@@ -183,4 +183,8 @@ class DynamoDBAttachmentStore(AttachmentStore):
183
183
  :param attachment_id: Attachment ID.
184
184
  """
185
185
  self._driver.delete(self._session_id, attachment_id)
186
+ index_ids = self._driver.get(self._session_id, "_index") or []
187
+ if attachment_id in index_ids:
188
+ index_ids.remove(attachment_id)
189
+ self._driver.put(self._session_id, "_index", index_ids)
186
190
  self._log.debug(f"Deleted attachment: {attachment_id}")
@@ -97,8 +97,9 @@ class RedisAttachmentDriver:
97
97
  return None
98
98
 
99
99
  def delete(self, session_id: str, attachment_id: str) -> None:
100
- """Delete a single attachment."""
100
+ """Delete a single attachment and remove its ID from the session index."""
101
101
  self.client.delete(self.key(session_id, attachment_id))
102
+ self.client.lrem(self.index_key(session_id), 0, attachment_id)
102
103
 
103
104
  def append_index(self, session_id: str, attachment_id: str) -> None:
104
105
  """Append an attachment ID to the session index."""
@@ -72,3 +72,7 @@ class SessionNonVolatileCacheAttachmentStore(AttachmentStore):
72
72
 
73
73
  def delete(self, attachment_id: str) -> None:
74
74
  self._cache.delete(f"{ATTACHMENT_KEY_PREFIX}{attachment_id}")
75
+ index = self._cache.get(ATTACHMENT_INDEX_KEY)
76
+ if index and attachment_id in index["ids"]:
77
+ index["ids"].remove(attachment_id)
78
+ self._cache.set(ATTACHMENT_INDEX_KEY, index)