agentbyte 0.7.0__tar.gz → 0.8.0__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 (288) hide show
  1. {agentbyte-0.7.0 → agentbyte-0.8.0}/CHANGELOG.md +21 -0
  2. {agentbyte-0.7.0 → agentbyte-0.8.0}/PKG-INFO +16 -3
  3. {agentbyte-0.7.0 → agentbyte-0.8.0}/README.md +11 -2
  4. {agentbyte-0.7.0 → agentbyte-0.8.0}/pyproject.toml +8 -0
  5. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/__about__.py +1 -1
  6. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/agents/agent.py +3 -0
  7. agentbyte-0.8.0/src/agentbyte/middleware/sql_usage.py +140 -0
  8. agentbyte-0.8.0/src/agentbyte/middleware/usage_logger.py +177 -0
  9. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/presets/workflow.py +53 -6
  10. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/__init__.py +4 -1
  11. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/execution.py +29 -3
  12. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/index.html +1 -1
  13. agentbyte-0.8.0/src/agentbyte/webui/frontend/package-lock.json +4893 -0
  14. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/package.json +4 -2
  15. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/App.tsx +22 -48
  16. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/agent/agent-view.tsx +21 -4
  17. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/orchestrator/orchestrator-view.tsx +32 -5
  18. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/app-header.tsx +4 -7
  19. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/chat-base.tsx +26 -6
  20. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/debug-panel.tsx +55 -11
  21. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/entity-selector.tsx +2 -24
  22. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/session-switcher.tsx +7 -3
  23. agentbyte-0.8.0/src/agentbyte/webui/frontend/src/components/workflow/workflow-result-renderer.tsx +508 -0
  24. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/workflow/workflow-view.tsx +97 -33
  25. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/hooks/messageHandlers.ts +41 -10
  26. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/hooks/useEntityExecution.ts +125 -24
  27. agentbyte-0.8.0/src/agentbyte/webui/frontend/src/lib/format-utils.ts +3 -0
  28. agentbyte-0.8.0/src/agentbyte/webui/frontend/src/lib/user-id.ts +23 -0
  29. agentbyte-0.8.0/src/agentbyte/webui/frontend/src/lib/utils.ts +6 -0
  30. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/services/api.ts +99 -26
  31. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/types/index.ts +2 -2
  32. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/types/picoagents.ts +19 -11
  33. agentbyte-0.8.0/src/agentbyte/webui/frontend/yarn.lock +2401 -0
  34. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/models.py +13 -0
  35. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/server.py +100 -48
  36. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/sessions.py +69 -4
  37. agentbyte-0.8.0/src/agentbyte/webui/ui/assets/index-CPLl1y5f.js +82 -0
  38. agentbyte-0.8.0/src/agentbyte/webui/ui/assets/index-DLCk-jRl.css +1 -0
  39. {agentbyte-0.7.0/src/agentbyte/webui/agent_framework_devui → agentbyte-0.8.0/src/agentbyte/webui}/ui/index.html +3 -3
  40. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/core/models.py +1 -0
  41. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/core/runner.py +11 -0
  42. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/agentbyte_agent.py +20 -3
  43. agentbyte-0.8.0/tests/middleware/test_sql_usage.py +245 -0
  44. agentbyte-0.8.0/tests/middleware/test_usage_logger.py +221 -0
  45. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/presets/test_orchestration.py +38 -0
  46. agentbyte-0.8.0/tests/presets/test_workflow.py +96 -0
  47. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_source.py +1 -1
  48. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/webui/test_execution.py +32 -1
  49. agentbyte-0.8.0/tests/webui/test_server.py +185 -0
  50. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/webui/test_sessions.py +51 -1
  51. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_models.py +21 -0
  52. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_runner.py +15 -0
  53. agentbyte-0.7.0/src/agentbyte/webui/agent_framework_devui/ui/assets/index-BzhEszHZ.css +0 -1
  54. agentbyte-0.7.0/src/agentbyte/webui/agent_framework_devui/ui/assets/index-DByFJNGD.js +0 -245
  55. agentbyte-0.7.0/src/agentbyte/webui/frontend/src/components/shared/examples-gallery.tsx +0 -268
  56. agentbyte-0.7.0/src/agentbyte/webui/frontend/yarn.lock +0 -2282
  57. agentbyte-0.7.0/src/agentbyte/webui/ui/assets/index-CWk64UM3.js +0 -359
  58. agentbyte-0.7.0/src/agentbyte/webui/ui/assets/index-vt1cujlT.css +0 -1
  59. agentbyte-0.7.0/src/agentbyte/webui/ui/index.html +0 -14
  60. agentbyte-0.7.0/src/agentbyte/webui/ui/vite.svg +0 -1
  61. agentbyte-0.7.0/tests/presets/test_workflow.py +0 -30
  62. agentbyte-0.7.0/tests/webui/test_server.py +0 -54
  63. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-agent-as-tool/SKILL.md +0 -0
  64. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-ai-driven-orchestration/SKILL.md +0 -0
  65. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-dataset/SKILL.md +0 -0
  66. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-fastapi-sse-streaming/SKILL.md +0 -0
  67. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-function-tools/SKILL.md +0 -0
  68. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-handoff-orchestration/SKILL.md +0 -0
  69. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-list-memory/SKILL.md +0 -0
  70. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-llm-client/SKILL.md +0 -0
  71. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-memory-tool/SKILL.md +0 -0
  72. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-middleware/SKILL.md +0 -0
  73. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-multi-turn-context/SKILL.md +0 -0
  74. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-otel-tracing/SKILL.md +0 -0
  75. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-plan-based-orchestration/SKILL.md +0 -0
  76. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-round-robin-orchestration/SKILL.md +0 -0
  77. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-simple-agent/SKILL.md +0 -0
  78. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-tool-approval/SKILL.md +0 -0
  79. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/agentbyte-workflow/SKILL.md +0 -0
  80. {agentbyte-0.7.0 → agentbyte-0.8.0}/.github/skills/skill-authoring/SKILL.md +0 -0
  81. {agentbyte-0.7.0 → agentbyte-0.8.0}/.gitignore +0 -0
  82. {agentbyte-0.7.0 → agentbyte-0.8.0}/LICENSE +0 -0
  83. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/__init__.py +0 -0
  84. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/agents/__init__.py +0 -0
  85. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/agents/agent_as_tool.py +0 -0
  86. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/agents/base.py +0 -0
  87. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/agents/types.py +0 -0
  88. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/cancellation_token.py +0 -0
  89. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/cli/__init__.py +0 -0
  90. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/cli/main.py +0 -0
  91. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/component.py +0 -0
  92. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/context.py +0 -0
  93. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/__init__.py +0 -0
  94. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/base.py +0 -0
  95. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/config.py +0 -0
  96. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/json.py +0 -0
  97. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/loader.py +0 -0
  98. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/loaders.py +0 -0
  99. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/sources.py +0 -0
  100. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/dataset/sqlite.py +0 -0
  101. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/entity.py +0 -0
  102. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/__init__.py +0 -0
  103. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/_retry_observability.py +0 -0
  104. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/auth.py +0 -0
  105. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure/__init__.py +0 -0
  106. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure/auth.py +0 -0
  107. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure/chat.py +0 -0
  108. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure/embedding.py +0 -0
  109. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure/settings.py +0 -0
  110. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure_openai.py +0 -0
  111. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/azure_openai_embedding.py +0 -0
  112. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/base.py +0 -0
  113. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/embeddings_base.py +0 -0
  114. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/openai/__init__.py +0 -0
  115. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/openai/chat.py +0 -0
  116. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/openai/embedding.py +0 -0
  117. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/openai/settings.py +0 -0
  118. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/openai.py +0 -0
  119. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/openai_embedding.py +0 -0
  120. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/pricing.py +0 -0
  121. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/retry_policy.py +0 -0
  122. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/settings.py +0 -0
  123. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/llm/types.py +0 -0
  124. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/memory/__init__.py +0 -0
  125. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/memory/base.py +0 -0
  126. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/messages.py +0 -0
  127. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/microwebui/__init__.py +0 -0
  128. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/microwebui/server.py +0 -0
  129. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/microwebui/ui/index.html +0 -0
  130. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/middleware/__init__.py +0 -0
  131. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/middleware/base.py +0 -0
  132. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/middleware/otel.py +0 -0
  133. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/middleware/retry.py +0 -0
  134. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/notebook.py +0 -0
  135. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/__init__.py +0 -0
  136. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/ai.py +0 -0
  137. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/base.py +0 -0
  138. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/handoff.py +0 -0
  139. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/plan.py +0 -0
  140. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/policies.py +0 -0
  141. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/orchestration/round_robin.py +0 -0
  142. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/presets/__init__.py +0 -0
  143. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/presets/agents.py +0 -0
  144. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/presets/clients.py +0 -0
  145. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/presets/orchestration.py +0 -0
  146. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/session_store.py +0 -0
  147. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/__init__.py +0 -0
  148. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/base.py +0 -0
  149. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/cancellation.py +0 -0
  150. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/composite.py +0 -0
  151. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/consecutive_agent.py +0 -0
  152. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/external.py +0 -0
  153. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/function_call.py +0 -0
  154. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/handoff.py +0 -0
  155. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/max_message.py +0 -0
  156. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/predicate.py +0 -0
  157. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/source.py +0 -0
  158. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/text_mention.py +0 -0
  159. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/timeout.py +0 -0
  160. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/termination/token_usage.py +0 -0
  161. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/tools/__init__.py +0 -0
  162. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/tools/base.py +0 -0
  163. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/tools/core_tools.py +0 -0
  164. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/tools/decorator.py +0 -0
  165. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/tools/memory_tool.py +0 -0
  166. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/types.py +0 -0
  167. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/discovery.py +0 -0
  168. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/.gitignore +0 -0
  169. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/README.md +0 -0
  170. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/components.json +0 -0
  171. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/eslint.config.js +0 -0
  172. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/plan.md +0 -0
  173. {agentbyte-0.7.0/src/agentbyte/webui/agent_framework_devui/ui → agentbyte-0.8.0/src/agentbyte/webui/frontend/public}/vite.svg +0 -0
  174. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/App.css +0 -0
  175. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/assets/react.svg +0 -0
  176. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/message_renderer/ContentRenderer.tsx +0 -0
  177. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/message_renderer/MessageRenderer.tsx +0 -0
  178. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/message_renderer/index.ts +0 -0
  179. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/message_renderer/types.ts +0 -0
  180. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/mode-toggle.tsx +0 -0
  181. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/context-inspector.tsx +0 -0
  182. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/example-tasks-display.tsx +0 -0
  183. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/shared/tool-approval-banner.tsx +0 -0
  184. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/theme-provider.tsx +0 -0
  185. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/attachment-gallery.tsx +0 -0
  186. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/badge.tsx +0 -0
  187. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/button.tsx +0 -0
  188. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/card.tsx +0 -0
  189. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/dialog.tsx +0 -0
  190. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/dropdown-menu.tsx +0 -0
  191. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/file-upload.tsx +0 -0
  192. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/input.tsx +0 -0
  193. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/label.tsx +0 -0
  194. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/loading-spinner.tsx +0 -0
  195. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/loading-state.tsx +0 -0
  196. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/message-input.tsx +0 -0
  197. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/scroll-area.tsx +0 -0
  198. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/slider.tsx +0 -0
  199. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/tabs.tsx +0 -0
  200. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/components/ui/textarea.tsx +0 -0
  201. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/index.css +0 -0
  202. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/main.tsx +0 -0
  203. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/utils/message-utils.ts +0 -0
  204. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/src/vite-env.d.ts +0 -0
  205. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/tsconfig.app.json +0 -0
  206. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/tsconfig.json +0 -0
  207. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/tsconfig.node.json +0 -0
  208. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/frontend/vite.config.ts +0 -0
  209. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/registry.py +0 -0
  210. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/webui/session_store.py +0 -0
  211. {agentbyte-0.7.0/src/agentbyte/webui/frontend/public → agentbyte-0.8.0/src/agentbyte/webui/ui}/vite.svg +0 -0
  212. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/__init__.py +0 -0
  213. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/agent.py +0 -0
  214. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/core/__init__.py +0 -0
  215. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/core/_structure_hash.py +0 -0
  216. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/core/checkpoint.py +0 -0
  217. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/core/workflow.py +0 -0
  218. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/defaults.py +0 -0
  219. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/loader.py +0 -0
  220. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/schema.py +0 -0
  221. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/schema_utils.py +0 -0
  222. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/__init__.py +0 -0
  223. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/echo.py +0 -0
  224. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/function.py +0 -0
  225. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/http.py +0 -0
  226. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/step.py +0 -0
  227. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/subworkflow.py +0 -0
  228. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/steps/transform.py +0 -0
  229. {agentbyte-0.7.0 → agentbyte-0.8.0}/src/agentbyte/workflow/visualizer.py +0 -0
  230. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_as_tool.py +0 -0
  231. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_basic.py +0 -0
  232. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_event_types.py +0 -0
  233. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_memory_integration.py +0 -0
  234. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_middleware_integration.py +0 -0
  235. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_retry_middleware.py +0 -0
  236. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_agent_stream_events.py +0 -0
  237. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/agents/test_tool_approval.py +0 -0
  238. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/cli/test_create_skills.py +0 -0
  239. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/dataset/test_loader.py +0 -0
  240. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_azure_client.py +0 -0
  241. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_azure_embedding_client.py +0 -0
  242. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_llm_types.py +0 -0
  243. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_openai_client.py +0 -0
  244. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_openai_embedding_client.py +0 -0
  245. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_retry_observability.py +0 -0
  246. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/llm/test_retry_policy_api.py +0 -0
  247. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/memory/test_memory.py +0 -0
  248. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/middleware/test_middleware_chain.py +0 -0
  249. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/middleware/test_otel.py +0 -0
  250. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/middleware/test_retry_middleware.py +0 -0
  251. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/orchestration/test_ai_orchestrator.py +0 -0
  252. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/orchestration/test_base_orchestrator.py +0 -0
  253. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/orchestration/test_handoff_orchestrator.py +0 -0
  254. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/orchestration/test_plan_orchestrator.py +0 -0
  255. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/orchestration/test_round_robin.py +0 -0
  256. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/presets/test_agents.py +0 -0
  257. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/presets/test_clients.py +0 -0
  258. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_base.py +0 -0
  259. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_cancellation.py +0 -0
  260. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_composite.py +0 -0
  261. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_consecutive_agent.py +0 -0
  262. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_external.py +0 -0
  263. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_function_call.py +0 -0
  264. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_handoff.py +0 -0
  265. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_max_message.py +0 -0
  266. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_predicate.py +0 -0
  267. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_text_mention.py +0 -0
  268. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_timeout.py +0 -0
  269. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/termination/test_token_usage.py +0 -0
  270. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/test_cancellation_token.py +0 -0
  271. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/test_context.py +0 -0
  272. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/test_messages.py +0 -0
  273. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/test_package_api.py +0 -0
  274. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/test_session_store.py +0 -0
  275. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/test_types.py +0 -0
  276. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/tools/test_memory_tool.py +0 -0
  277. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/tools/test_tools.py +0 -0
  278. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/webui/__init__.py +0 -0
  279. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/webui/helpers.py +0 -0
  280. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/webui/test_package_api.py +0 -0
  281. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/webui/test_registry.py +0 -0
  282. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_checkpoint.py +0 -0
  283. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_subworkflow_step.py +0 -0
  284. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_agent.py +0 -0
  285. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_class.py +0 -0
  286. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_schema.py +0 -0
  287. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_steps.py +0 -0
  288. {agentbyte-0.7.0 → agentbyte-0.8.0}/tests/workflow/test_workflow_visualizer.py +0 -0
@@ -4,6 +4,27 @@ All notable changes to Agentbyte are documented in this file.
4
4
 
5
5
  The format follows Keep a Changelog principles and semantic versioning.
6
6
 
7
+ ## [0.8.0] - 2026-04-13
8
+
9
+ ### Added
10
+
11
+ - Added SQL-backed usage logging middleware with a typed persistence contract plus SQLModel-backed storage for LLM usage records.
12
+ - Added `examples/webui/in_memory.py` and `examples/webui/presets_webui.py` as concrete launchers for the packaged AgentByte WebUI.
13
+ - Added plan-based orchestration to the preset-backed WebUI catalog so round-robin, AI-driven, and plan-based teams are all selectable from the same real-entities launcher.
14
+
15
+ ### Changed
16
+
17
+ - Completed the `agentbyte.webui` session contract: WebUI sessions now support `user_id`, stricter session/entity binding, and injected durable session stores for persisted `AgentContext` reload across restarts.
18
+ - Rebased and adapted the packaged WebUI frontend to AgentByte's backend contracts, including fixed session query handling, stable post-stream message refresh, richer workflow result rendering, cleaner orchestration event classification, and improved debug-panel payload inspection.
19
+ - Extended agent and orchestrator WebUI usage surfaces to show both token counts and cost estimates when providers supply pricing data.
20
+ - Removed the unused bundled examples-gallery flow and other stale picoagents-only frontend assumptions from the packaged WebUI.
21
+
22
+ ### Fixed
23
+
24
+ - Fixed agent stream completion handling in the WebUI so final agent state events no longer fall through to `unknown`, immediate UI finalization works again, and post-stream session refresh reliably recalculates session totals.
25
+ - Fixed round-robin and other orchestrator debug events so lifecycle payloads render as labeled orchestration events instead of opaque `unknown` entries.
26
+ - Fixed workflow completion rendering so the WebUI shows terminal workflow outputs directly instead of dumping the raw completion envelope.
27
+
7
28
  ## [0.7.0] - 2026-04-09
8
29
 
9
30
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentbyte
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: A toolkit for designing multiagent systems
5
5
  Project-URL: Homepage, https://gitlab.com/pyninja/aiengineering/agentbyte
6
6
  Project-URL: Repository, https://gitlab.com/pyninja/aiengineering/agentbyte
@@ -42,6 +42,10 @@ Provides-Extra: otel
42
42
  Requires-Dist: opentelemetry-api>=1.39.1; extra == 'otel'
43
43
  Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.39.1; extra == 'otel'
44
44
  Requires-Dist: opentelemetry-sdk>=1.39.1; extra == 'otel'
45
+ Provides-Extra: sql
46
+ Requires-Dist: aiosqlite>=0.22.1; extra == 'sql'
47
+ Requires-Dist: asyncpg>=0.31.0; extra == 'sql'
48
+ Requires-Dist: sqlmodel>=0.0.38; extra == 'sql'
45
49
  Provides-Extra: test
46
50
  Requires-Dist: pytest-asyncio>=1.3.0; extra == 'test'
47
51
  Requires-Dist: pytest-cov>=7.0.0; extra == 'test'
@@ -55,17 +59,26 @@ Requires-Dist: uvicorn[standard]>=0.44.0; extra == 'webui'
55
59
  Description-Content-Type: text/markdown
56
60
 
57
61
  <p align="center">
58
- <img src="https://gitlab.com/pyninja/aiengineering/agentbyte/-/raw/v0.7.0/logo/agent-byte-avatar-low.png" alt="Agentbyte" width="200"/>
62
+ <img src="https://gitlab.com/pyninja/aiengineering/agentbyte/-/raw/v0.8.0/logo/agent-byte-avatar-low.png" alt="Agentbyte" width="200"/>
59
63
  </p>
60
64
 
61
65
  # Agentbyte
62
66
 
63
67
  Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
64
68
 
65
- Current release: **0.7.0**
69
+ Current release: **0.8.0**
66
70
 
67
71
  Repository: [gitlab.com/pyninja/aiengineering/agentbyte](https://gitlab.com/pyninja/aiengineering/agentbyte)
68
72
 
73
+ ## What's New in 0.8.0
74
+
75
+ **WebUI maturity + preset expansion + SQL usage logging**
76
+
77
+ - Completed the server-side WebUI session contract with user-scoped sessions, stricter `session_id` binding to `entity_id`, and injectable session stores for durable context reload.
78
+ - Rebased and adopted the bundled WebUI frontend to AgentByte's backend contract, including fixed session lookup, post-stream session refresh, richer workflow result rendering, improved debug panel behavior, and visible usage cost for agent and orchestrator sessions.
79
+ - Added real-entity WebUI launchers under `examples/webui/`, including preset-backed agents, workflows, and all three top-level orchestration patterns: round-robin, AI-driven, and plan-based.
80
+ - Added SQL-backed usage logging middleware so provider usage records can be persisted through a typed backend contract instead of staying in-memory only.
81
+
69
82
  ## What's New in 0.7.0
70
83
 
71
84
  **MicroWebUI streaming polish + bundled SSE skill**
@@ -1,15 +1,24 @@
1
1
  <p align="center">
2
- <img src="https://gitlab.com/pyninja/aiengineering/agentbyte/-/raw/v0.7.0/logo/agent-byte-avatar-low.png" alt="Agentbyte" width="200"/>
2
+ <img src="https://gitlab.com/pyninja/aiengineering/agentbyte/-/raw/v0.8.0/logo/agent-byte-avatar-low.png" alt="Agentbyte" width="200"/>
3
3
  </p>
4
4
 
5
5
  # Agentbyte
6
6
 
7
7
  Agentbyte is an observability-first agentic AI framework for building and studying multiagent systems with a learning-first, implementation-oriented workflow.
8
8
 
9
- Current release: **0.7.0**
9
+ Current release: **0.8.0**
10
10
 
11
11
  Repository: [gitlab.com/pyninja/aiengineering/agentbyte](https://gitlab.com/pyninja/aiengineering/agentbyte)
12
12
 
13
+ ## What's New in 0.8.0
14
+
15
+ **WebUI maturity + preset expansion + SQL usage logging**
16
+
17
+ - Completed the server-side WebUI session contract with user-scoped sessions, stricter `session_id` binding to `entity_id`, and injectable session stores for durable context reload.
18
+ - Rebased and adopted the bundled WebUI frontend to AgentByte's backend contract, including fixed session lookup, post-stream session refresh, richer workflow result rendering, improved debug panel behavior, and visible usage cost for agent and orchestrator sessions.
19
+ - Added real-entity WebUI launchers under `examples/webui/`, including preset-backed agents, workflows, and all three top-level orchestration patterns: round-robin, AI-driven, and plan-based.
20
+ - Added SQL-backed usage logging middleware so provider usage records can be persisted through a typed backend contract instead of staying in-memory only.
21
+
13
22
  ## What's New in 0.7.0
14
23
 
15
24
  **MicroWebUI streaming polish + bundled SSE skill**
@@ -44,6 +44,11 @@ webui = [
44
44
  "fastapi>=0.135.2",
45
45
  "uvicorn[standard]>=0.44.0",
46
46
  ]
47
+ sql = [
48
+ "sqlmodel>=0.0.38",
49
+ "asyncpg>=0.31.0",
50
+ "aiosqlite>=0.22.1",
51
+ ]
47
52
  viz = [
48
53
  "graphviz>=0.21",
49
54
  ]
@@ -120,6 +125,9 @@ test = [
120
125
  "pytest-asyncio>=1.3.0",
121
126
  "pytest-cov>=7.0.0",
122
127
  "ruff>=0.15.0",
128
+ "aiosqlite>=0.22.1",
129
+ "sqlmodel>=0.0.38",
130
+ "greenlet>=3.0.0",
123
131
  ]
124
132
  viz = [
125
133
  "graphviz>=0.21",
@@ -1,2 +1,2 @@
1
- __version__ = "0.7.0"
1
+ __version__ = "0.8.0"
2
2
  VERSION = __version__
@@ -5,6 +5,7 @@ Concrete Agent implementation with core execution loop.
5
5
  import asyncio
6
6
  import os
7
7
  import time
8
+ import uuid
8
9
  import warnings
9
10
  from collections.abc import AsyncGenerator
10
11
  from typing import List, Optional, Union
@@ -74,6 +75,8 @@ class Agent(BaseAgent):
74
75
  cancellation_token: Optional[CancellationToken] = None,
75
76
  ) -> AgentResponse:
76
77
  working_context = context if context is not None else AgentContext()
78
+ if "run_id" not in working_context.metadata:
79
+ working_context.metadata["run_id"] = str(uuid.uuid4())
77
80
  if not task and working_context.is_empty:
78
81
  raise AgentConfigurationError(
79
82
  "Either 'task' must be provided or 'context' must be non-empty."
@@ -0,0 +1,140 @@
1
+ """SQL backend for UsageLoggerMiddleware.
2
+
3
+ Persists :class:`~agentbyte.middleware.usage_logger.UsageEvent` rows to any
4
+ SQLAlchemy-supported database using SQLModel for table definitions and
5
+ SQLAlchemy's async session for writes.
6
+
7
+ Requires the ``sql`` optional extra::
8
+
9
+ uv sync --extra sql
10
+
11
+ Supports both PostgreSQL (via asyncpg) and SQLite (via aiosqlite).
12
+
13
+ Usage::
14
+
15
+ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
16
+ from sqlalchemy.orm import sessionmaker
17
+ from agentbyte.middleware.sql_usage import SqlUsageBackend, create_usage_tables
18
+
19
+ engine = create_async_engine("postgresql+asyncpg://user:pass@host/db")
20
+ AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
21
+
22
+ async def get_session():
23
+ async with AsyncSessionLocal() as session:
24
+ yield session
25
+
26
+ await create_usage_tables(engine)
27
+ backend = SqlUsageBackend(session_factory=get_session)
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ from collections.abc import AsyncGenerator, Callable
33
+ from datetime import datetime, timezone
34
+ from typing import Optional
35
+
36
+ from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
37
+ from sqlmodel import Field, SQLModel
38
+
39
+ from .usage_logger import UsageEvent, UsagePersistenceBackend
40
+
41
+
42
+ class LlmUsageEvent(SQLModel, table=True):
43
+ """SQLModel table that stores one row per LLM call.
44
+
45
+ This class is internal to :class:`SqlUsageBackend`. Callers who need
46
+ direct DB access can import it for read-only queries.
47
+ """
48
+
49
+ __tablename__ = "llm_usage_events"
50
+
51
+ id: Optional[int] = Field(default=None, primary_key=True)
52
+ run_id: Optional[str] = Field(default=None, index=True)
53
+ session_id: Optional[str] = Field(default=None, index=True)
54
+ user_id: Optional[str] = Field(default=None)
55
+ identifier: Optional[str] = Field(default=None, index=True)
56
+ agent_name: str
57
+ model: str
58
+ duration_ms: int = Field(default=0)
59
+ llm_calls: int = Field(default=0)
60
+ tokens_input: int = Field(default=0)
61
+ tokens_output: int = Field(default=0)
62
+ tool_calls: int = Field(default=0)
63
+ memory_operations: int = Field(default=0)
64
+ cost_estimate: Optional[float] = Field(default=None)
65
+ recorded_at: datetime = Field(
66
+ default_factory=lambda: datetime.now(timezone.utc),
67
+ )
68
+
69
+
70
+ async def create_usage_tables(engine: AsyncEngine) -> None:
71
+ """Create the ``llm_usage_events`` table if it does not exist.
72
+
73
+ Call this once at application startup before any agents run::
74
+
75
+ await create_usage_tables(engine)
76
+ """
77
+ async with engine.begin() as conn:
78
+ await conn.run_sync(SQLModel.metadata.create_all)
79
+
80
+
81
+ class SqlUsageBackend(UsagePersistenceBackend):
82
+ """Persists :class:`~agentbyte.middleware.usage_logger.UsageEvent` rows
83
+ to a SQL database via an async SQLAlchemy session.
84
+
85
+ The caller is responsible for creating the engine and session factory.
86
+ This backend holds only a reference to the factory — it does not own the
87
+ connection pool.
88
+
89
+ Args:
90
+ session_factory: Zero-argument async generator factory that yields one
91
+ :class:`~sqlalchemy.ext.asyncio.AsyncSession` per call. The
92
+ factory should handle its own cleanup (e.g. via ``async with``).
93
+
94
+ Example::
95
+
96
+ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
97
+ from sqlalchemy.orm import sessionmaker
98
+
99
+ engine = create_async_engine("postgresql+asyncpg://user:pass@host/db")
100
+ AsyncSessionLocal = sessionmaker(
101
+ engine, class_=AsyncSession, expire_on_commit=False
102
+ )
103
+
104
+ async def get_session():
105
+ async with AsyncSessionLocal() as session:
106
+ yield session
107
+
108
+ backend = SqlUsageBackend(session_factory=get_session)
109
+ """
110
+
111
+ def __init__(
112
+ self,
113
+ session_factory: Callable[[], AsyncGenerator[AsyncSession, None]],
114
+ ) -> None:
115
+ self._session_factory = session_factory
116
+
117
+ async def write(self, event: UsageEvent) -> None:
118
+ gen = self._session_factory()
119
+ session: AsyncSession = await gen.__anext__()
120
+ try:
121
+ row = LlmUsageEvent(
122
+ run_id=event.run_id,
123
+ session_id=event.session_id,
124
+ user_id=event.user_id,
125
+ identifier=event.identifier,
126
+ agent_name=event.agent_name,
127
+ model=event.model,
128
+ duration_ms=event.duration_ms,
129
+ llm_calls=event.llm_calls,
130
+ tokens_input=event.tokens_input,
131
+ tokens_output=event.tokens_output,
132
+ tool_calls=event.tool_calls,
133
+ memory_operations=event.memory_operations,
134
+ cost_estimate=event.cost_estimate,
135
+ recorded_at=event.recorded_at,
136
+ )
137
+ session.add(row)
138
+ await session.commit()
139
+ finally:
140
+ await gen.aclose()
@@ -0,0 +1,177 @@
1
+ """Usage logging middleware with a pluggable persistence backend.
2
+
3
+ Writes one :class:`UsageEvent` per LLM ``MODEL_CALL`` to whatever
4
+ :class:`UsagePersistenceBackend` the caller supplies. The first concrete
5
+ backend is :class:`~agentbyte.middleware.sql_usage.SqlUsageBackend`; future
6
+ backends (CosmosDB, DynamoDB, …) implement the same interface.
7
+
8
+ Usage::
9
+
10
+ from agentbyte.middleware.usage_logger import UsageLoggerMiddleware
11
+ from agentbyte.middleware.sql_usage import SqlUsageBackend, create_usage_tables
12
+
13
+ backend = SqlUsageBackend(session_factory=get_session)
14
+ mw = UsageLoggerMiddleware(backend=backend, identifier="my-app")
15
+ agent = Agent(..., middlewares=[mw])
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import asyncio
21
+ import warnings
22
+ from abc import ABC, abstractmethod
23
+ from datetime import datetime, timezone
24
+ from typing import Any, Optional
25
+
26
+ from pydantic import BaseModel, Field
27
+
28
+ from .base import BaseMiddleware, MiddlewareContext, OperationType
29
+
30
+
31
+ class UsageEvent(BaseModel):
32
+ """Data contract passed to every :class:`UsagePersistenceBackend`.
33
+
34
+ All fields are derived from the :class:`~agentbyte.middleware.base.MiddlewareContext`
35
+ and the :class:`~agentbyte.llm.types.ChatCompletionResult` returned by a
36
+ ``MODEL_CALL`` operation. Backends receive this object and persist it in
37
+ whatever form suits their storage technology.
38
+ """
39
+
40
+ run_id: Optional[str] = Field(
41
+ default=None,
42
+ description="Groups all LLM calls that belong to one agent.run() invocation",
43
+ )
44
+ session_id: Optional[str] = Field(
45
+ default=None,
46
+ description="Session identifier from AgentContext",
47
+ )
48
+ user_id: Optional[str] = Field(
49
+ default=None,
50
+ description="User identifier from AgentContext",
51
+ )
52
+ identifier: Optional[str] = Field(
53
+ default=None,
54
+ description="Application or service label set at middleware init",
55
+ )
56
+ agent_name: str = Field(description="Name of the agent that made the call")
57
+ model: str = Field(description="Model name used for the call")
58
+ # Full Usage fields
59
+ duration_ms: int = Field(default=0, description="Wall-clock time in milliseconds")
60
+ llm_calls: int = Field(default=0, description="LLM call count (typically 1 per event)")
61
+ tokens_input: int = Field(default=0, description="Prompt tokens consumed")
62
+ tokens_output: int = Field(default=0, description="Completion tokens generated")
63
+ tool_calls: int = Field(default=0, description="Tool invocations in Usage")
64
+ memory_operations: int = Field(default=0, description="Memory operations in Usage")
65
+ cost_estimate: Optional[float] = Field(
66
+ default=None,
67
+ description="Estimated USD cost (None when provider does not supply pricing)",
68
+ )
69
+ recorded_at: datetime = Field(
70
+ default_factory=lambda: datetime.now(timezone.utc),
71
+ description="UTC timestamp when the event was created",
72
+ )
73
+
74
+
75
+ class UsagePersistenceBackend(ABC):
76
+ """Interface that all usage storage backends must satisfy.
77
+
78
+ Implement :meth:`write` to persist a :class:`UsageEvent`. The optional
79
+ :meth:`setup` and :meth:`close` hooks let backends manage connection
80
+ lifecycle when the caller needs explicit control.
81
+
82
+ Example — minimal custom backend::
83
+
84
+ class PrintBackend(UsagePersistenceBackend):
85
+ async def write(self, event: UsageEvent) -> None:
86
+ print(event.model_dump_json())
87
+ """
88
+
89
+ @abstractmethod
90
+ async def write(self, event: UsageEvent) -> None:
91
+ """Persist one usage event. Must not raise — errors should be handled internally."""
92
+
93
+ async def setup(self) -> None:
94
+ """Optional: initialise connections, create tables, etc."""
95
+
96
+ async def close(self) -> None:
97
+ """Optional: clean up connections and flush buffers."""
98
+
99
+
100
+ class UsageLoggerMiddleware(BaseMiddleware):
101
+ """Middleware that writes one :class:`UsageEvent` per LLM call to a backend.
102
+
103
+ Writes are fire-and-forget (``asyncio.create_task``). Backend failures are
104
+ swallowed as ``RuntimeWarning`` and never interrupt agent execution.
105
+
106
+ Args:
107
+ backend: Any :class:`UsagePersistenceBackend` implementation.
108
+ identifier: Optional application/service label stored on every event.
109
+ """
110
+
111
+ def __init__(
112
+ self,
113
+ backend: UsagePersistenceBackend,
114
+ identifier: Optional[str] = None,
115
+ ) -> None:
116
+ self._backend = backend
117
+ self._identifier = identifier
118
+
119
+ async def _write(self, event: UsageEvent) -> None:
120
+ try:
121
+ await self._backend.write(event)
122
+ except Exception as exc:
123
+ warnings.warn(
124
+ f"UsageLoggerMiddleware: backend write failed: {exc}",
125
+ RuntimeWarning,
126
+ stacklevel=2,
127
+ )
128
+
129
+ async def process_request(self, context: MiddlewareContext) -> MiddlewareContext:
130
+ return context
131
+
132
+ async def process_response(
133
+ self,
134
+ context: MiddlewareContext,
135
+ result: Any,
136
+ ) -> Any:
137
+ if context.operation != OperationType.MODEL_CALL:
138
+ return result
139
+
140
+ usage = getattr(result, "usage", None)
141
+ if usage is None:
142
+ return result
143
+
144
+ agent_ctx = context.agent_context
145
+ run_id: Optional[str] = None
146
+ if agent_ctx is not None:
147
+ raw = agent_ctx.metadata.get("run_id")
148
+ if raw is not None:
149
+ run_id = str(raw)
150
+
151
+ model: str = context.metadata.get("model") or getattr(result, "model", "unknown")
152
+
153
+ event = UsageEvent(
154
+ run_id=run_id,
155
+ session_id=agent_ctx.session_id if agent_ctx is not None else None,
156
+ user_id=agent_ctx.user_id if agent_ctx is not None else None,
157
+ identifier=self._identifier,
158
+ agent_name=context.agent_name,
159
+ model=model,
160
+ duration_ms=usage.duration_ms,
161
+ llm_calls=usage.llm_calls,
162
+ tokens_input=usage.tokens_input,
163
+ tokens_output=usage.tokens_output,
164
+ tool_calls=usage.tool_calls,
165
+ memory_operations=usage.memory_operations,
166
+ cost_estimate=usage.cost_estimate,
167
+ )
168
+
169
+ asyncio.create_task(self._write(event))
170
+ return result
171
+
172
+ async def process_error(
173
+ self,
174
+ context: MiddlewareContext,
175
+ error: Exception,
176
+ ) -> Optional[Any]:
177
+ return None
@@ -6,7 +6,7 @@ from typing import Any
6
6
 
7
7
  from agentbyte.llm import BaseChatCompletionClient
8
8
  from agentbyte.workflow import Workflow, WorkflowConfig
9
- from agentbyte.workflow.core.models import StepMetadata
9
+ from agentbyte.workflow.core.models import StepMetadata, WorkflowContext
10
10
  from agentbyte.workflow.steps import AgentStep, FunctionStep
11
11
  from agentbyte.workflow.steps.agentbyte_agent import (
12
12
  AgentbyteAgentInput,
@@ -17,6 +17,42 @@ from .agents import get_researcher, get_reviewer, get_writer
17
17
  from .clients import build_chat_client
18
18
 
19
19
 
20
+ def _writer_to_reviewer_fn(
21
+ output: AgentbyteAgentOutput, context: WorkflowContext
22
+ ) -> dict:
23
+ """Transform writer output into reviewer input; store draft for later retrieval."""
24
+ context.set("writer_draft", output.response or "")
25
+ return {
26
+ "task": output.response or "",
27
+ "additional_context": {"messages": output.messages, "usage": output.usage},
28
+ }
29
+
30
+
31
+ def _reviewer_to_writer_fn(
32
+ output: AgentbyteAgentOutput, context: WorkflowContext
33
+ ) -> dict:
34
+ """Transform reviewer output into writer_final input.
35
+
36
+ Passes the original draft plus reviewer feedback so the writer can
37
+ produce an improved final version. If the reviewer approved, the writer
38
+ is asked to confirm and present the polished version.
39
+ """
40
+ draft = context.get("writer_draft") or ""
41
+ feedback = (output.response or "").strip()
42
+ approved = feedback.upper() == "APPROVED"
43
+ if approved:
44
+ task = f"Your draft was approved by the reviewer. Output the final polished version:\n\n{draft}"
45
+ else:
46
+ task = (
47
+ f"Revise your draft based on the reviewer's feedback.\n\n"
48
+ f"Your draft:\n{draft}\n\nReviewer feedback:\n{feedback}"
49
+ )
50
+ return {
51
+ "task": task,
52
+ "additional_context": {"messages": output.messages, "usage": output.usage},
53
+ }
54
+
55
+
20
56
  def _create_linear_research_writer_reviewer_workflow(
21
57
  *,
22
58
  name: str,
@@ -25,7 +61,7 @@ def _create_linear_research_writer_reviewer_workflow(
25
61
  writer,
26
62
  reviewer,
27
63
  ) -> Workflow:
28
- """Create the default researcher -> writer -> reviewer workflow."""
64
+ """Create the default researcher -> writer -> reviewer -> writer_final workflow."""
29
65
  workflow = Workflow(WorkflowConfig(name=name, description=description))
30
66
  researcher_step = AgentStep(
31
67
  step_id="researcher",
@@ -57,10 +93,19 @@ def _create_linear_research_writer_reviewer_workflow(
57
93
  metadata=StepMetadata(name="writer_to_reviewer"),
58
94
  input_type=AgentbyteAgentOutput,
59
95
  output_type=AgentbyteAgentInput,
60
- func=lambda output, _context: {
61
- "task": output.response or "",
62
- "additional_context": {"messages": output.messages, "usage": output.usage},
63
- },
96
+ func=_writer_to_reviewer_fn,
97
+ )
98
+ reviewer_to_writer = FunctionStep(
99
+ step_id="reviewer_to_writer",
100
+ metadata=StepMetadata(name="reviewer_to_writer"),
101
+ input_type=AgentbyteAgentOutput,
102
+ output_type=AgentbyteAgentInput,
103
+ func=_reviewer_to_writer_fn,
104
+ )
105
+ writer_final_step = AgentStep(
106
+ step_id="writer_final",
107
+ metadata=StepMetadata(name="writer_final"),
108
+ agent=writer,
64
109
  )
65
110
  workflow.chain(
66
111
  researcher_step,
@@ -68,6 +113,8 @@ def _create_linear_research_writer_reviewer_workflow(
68
113
  writer_step,
69
114
  writer_to_reviewer,
70
115
  reviewer_step,
116
+ reviewer_to_writer,
117
+ writer_final_step,
71
118
  )
72
119
  return workflow
73
120
 
@@ -4,6 +4,7 @@ from agentbyte.webui.discovery import AgentbyteScanner
4
4
  from agentbyte.webui.execution import ExecutionEngine
5
5
  from agentbyte.webui.models import (
6
6
  AgentInfo,
7
+ CreateSessionRequest,
7
8
  Entity,
8
9
  EntityInfo,
9
10
  HealthResponse,
@@ -29,12 +30,13 @@ from agentbyte.webui.session_store import (
29
30
  InMemorySessionStore,
30
31
  SessionStore,
31
32
  )
32
- from agentbyte.webui.sessions import SessionManager
33
+ from agentbyte.webui.sessions import SessionBindingError, SessionManager
33
34
 
34
35
  __all__ = [
35
36
  "AgentInfo",
36
37
  "AgentbyteScanner",
37
38
  "AgentbyteWebUIServer",
39
+ "CreateSessionRequest",
38
40
  "Entity",
39
41
  "EntityInfo",
40
42
  "EntityRegistry",
@@ -46,6 +48,7 @@ __all__ = [
46
48
  "OrchestratorInfo",
47
49
  "RunEntityRequest",
48
50
  "SessionInfo",
51
+ "SessionBindingError",
49
52
  "SessionManager",
50
53
  "SessionStore",
51
54
  "StatsResponse",