langgraph-agent-toolkit 0.9.0__tar.gz → 0.9.2__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 (199) hide show
  1. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.dockerignore +13 -0
  2. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.env.example +13 -0
  3. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/CHANGELOG.md +78 -0
  4. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/CLAUDE.md +31 -7
  5. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/PKG-INFO +3 -1
  6. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/README.md +2 -0
  7. langgraph_agent_toolkit-0.9.2/docker/api/Dockerfile +69 -0
  8. langgraph_agent_toolkit-0.9.2/docker/app/Dockerfile +45 -0
  9. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/usage.rst +11 -1
  10. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/agent_executor.py +86 -13
  11. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/create_agent/agent.py +91 -0
  12. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/create_agent_structured/agent.py +76 -0
  13. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/hitl_agent/agent.py +67 -0
  14. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/__init__.py +18 -0
  15. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/_history.py +39 -0
  16. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/clear_intermediate_tool_calls.py +157 -0
  17. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/immediate_generation.py +80 -0
  18. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/sanitize_history.py +33 -0
  19. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/token_trim.py +81 -0
  20. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/trim_messages.py +62 -0
  21. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/_base_settings.py +39 -4
  22. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/utils.py +37 -20
  23. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/run_api.py +3 -4
  24. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/run_app.py +18 -0
  25. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/schema.py +59 -4
  26. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/__init__.py +1 -0
  27. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/components/__init__.py +1 -0
  28. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/components/draw_message.py +179 -0
  29. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/components/side_panel.py +92 -0
  30. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/main_page.py +143 -0
  31. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/utils/__init__.py +1 -0
  32. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/utils/constants.py +7 -0
  33. langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/utils/message.py +102 -0
  34. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/pyproject.toml +1 -1
  35. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_agent_executor.py +150 -1
  36. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_blueprints.py +5 -4
  37. langgraph_agent_toolkit-0.9.2/tests/agents/test_create_agent_stack.py +107 -0
  38. langgraph_agent_toolkit-0.9.2/tests/agents/test_hitl_agent.py +147 -0
  39. langgraph_agent_toolkit-0.9.2/tests/agents/test_middlewares.py +401 -0
  40. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/helper/test_create_ai_message.py +8 -9
  41. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/helper/test_helper_utils.py +35 -0
  42. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_service.py +2 -1
  43. langgraph_agent_toolkit-0.9.2/tests/ui/test_draw_messages.py +58 -0
  44. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/uv.lock +113 -112
  45. langgraph_agent_toolkit-0.9.0/.github/workflows/deploy.yml +0 -71
  46. langgraph_agent_toolkit-0.9.0/docker/api/Dockerfile +0 -69
  47. langgraph_agent_toolkit-0.9.0/docker/app/Dockerfile +0 -31
  48. langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_new/agent.py +0 -61
  49. langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_old/agent.py +0 -76
  50. langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_so/agent.py +0 -71
  51. langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_so_old/agent.py +0 -86
  52. langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/run_app.py +0 -414
  53. langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/service/__init__.py +0 -0
  54. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.claude/settings.json +0 -0
  55. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.coveragerc +0 -0
  56. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  57. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  58. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  59. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/RELEASE_TEMPLATE/release-template.md +0 -0
  60. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/codecov.yml +0 -0
  61. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/dependabot.yml +0 -0
  62. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/scripts/tag_from_pyproject.sh +0 -0
  63. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/workflows/release.yml +0 -0
  64. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/workflows/sphinx.yml +0 -0
  65. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/workflows/test.yml +0 -0
  66. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.gitignore +0 -0
  67. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.pre-commit-config.yaml +0 -0
  68. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.project-root +0 -0
  69. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/CONTRIBUTING.md +0 -0
  70. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/LICENSE +0 -0
  71. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/Makefile +0 -0
  72. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/clickhouse/.clickhouse.env.example +0 -0
  73. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/langfuse/.langfuse.env.example +0 -0
  74. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/litellm/.litellm.env.example +0 -0
  75. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/litellm/config.example.yaml +0 -0
  76. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/minio/.minio.env.example +0 -0
  77. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/postgres/.postgres.env.example +0 -0
  78. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/redis/.redis.env.example +0 -0
  79. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docker-compose.yaml +0 -0
  80. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/.gitignore +0 -0
  81. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/Makefile +0 -0
  82. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_static/custom.css +0 -0
  83. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_templates/class.rst +0 -0
  84. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_templates/layout.html +0 -0
  85. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_templates/module.rst +0 -0
  86. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/conf.py +0 -0
  87. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/contributing.rst +0 -0
  88. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/environment_setup.rst +0 -0
  89. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/index.rst +0 -0
  90. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/installation.rst +0 -0
  91. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/make.bat +0 -0
  92. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/agent_architecture.excalidraw +0 -0
  93. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/agent_architecture.png +0 -0
  94. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/agent_diagram.png +0 -0
  95. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/logo.svg +0 -0
  96. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph.json +0 -0
  97. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/__init__.py +0 -0
  98. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/__init__.py +0 -0
  99. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/agent.py +0 -0
  100. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/__init__.py +0 -0
  101. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/__init__.py +0 -0
  102. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/agent.py +0 -0
  103. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/task.py +0 -0
  104. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/utils.py +0 -0
  105. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/chatbot/__init__.py +0 -0
  106. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/chatbot/agent.py +0 -0
  107. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/command_agent/__init__.py +0 -0
  108. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/command_agent/agent.py +0 -0
  109. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/interrupt_agent → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/create_agent}/__init__.py +0 -0
  110. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/knowledge_base_agent → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/create_agent_structured}/__init__.py +0 -0
  111. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/hitl_agent}/__init__.py +0 -0
  112. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_new → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/interrupt_agent}/__init__.py +0 -0
  113. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/interrupt_agent/agent.py +0 -0
  114. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_old → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/knowledge_base_agent}/__init__.py +0 -0
  115. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/knowledge_base_agent/agent.py +0 -0
  116. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_so → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/react}/__init__.py +0 -0
  117. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/react/agent.py +0 -0
  118. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_so_old → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/supervisor_agent}/__init__.py +0 -0
  119. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/supervisor_agent/agent.py +0 -0
  120. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/supervisor_agent → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components}/__init__.py +0 -0
  121. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/components → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/checkpoint}/__init__.py +0 -0
  122. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/checkpoint/empty.py +0 -0
  123. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/creators/__init__.py +0 -0
  124. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/creators/create_react_agent.py +0 -0
  125. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/tools.py +0 -0
  126. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/utils.py +0 -0
  127. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/client/__init__.py +0 -0
  128. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/client/client.py +0 -0
  129. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/__init__.py +0 -0
  130. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/components/checkpoint → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/core/memory}/__init__.py +0 -0
  131. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/base.py +0 -0
  132. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/factory.py +0 -0
  133. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/postgres.py +0 -0
  134. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/sqlite.py +0 -0
  135. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/types.py +0 -0
  136. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/__init__.py +0 -0
  137. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/chat_openai.py +0 -0
  138. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/factory.py +0 -0
  139. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/fake.py +0 -0
  140. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/core/memory → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/core/observability}/__init__.py +0 -0
  141. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/base.py +0 -0
  142. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/empty.py +0 -0
  143. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/factory.py +0 -0
  144. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/langfuse.py +0 -0
  145. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/langsmith.py +0 -0
  146. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/types.py +0 -0
  147. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/core/observability → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/core/prompts}/__init__.py +0 -0
  148. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/prompts/chat_prompt_template.py +0 -0
  149. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/prompts/prompt_manager.py +0 -0
  150. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/settings.py +0 -0
  151. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/core/prompts → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/helper}/__init__.py +0 -0
  152. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/constants.py +0 -0
  153. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/exceptions.py +0 -0
  154. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/logging.py +0 -0
  155. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/types.py +0 -0
  156. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/__init__.py +0 -0
  157. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/models.py +0 -0
  158. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/task_data.py +0 -0
  159. {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/helper → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/service}/__init__.py +0 -0
  160. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/exception_handlers.py +0 -0
  161. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/factory.py +0 -0
  162. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/handler.py +0 -0
  163. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/middleware.py +0 -0
  164. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/routes.py +0 -0
  165. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/types.py +0 -0
  166. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/utils.py +0 -0
  167. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/postgres-init/create_databases.sql +0 -0
  168. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/postgres-init/create_schema.sql +0 -0
  169. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/01-invoke-proxy.py +0 -0
  170. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/02-test-local-pm.py +0 -0
  171. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/03-test-langfuse-pm.py +0 -0
  172. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/04-test-langsmith-pm.py +0 -0
  173. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/05-test-prompt-types.py +0 -0
  174. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/06-test-custom-chat-prompt-template.py +0 -0
  175. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/07-test-get-chat-history.py +0 -0
  176. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/08-test-update-chat-history.py +0 -0
  177. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/09-test-clear-chat-history.py +0 -0
  178. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/098-cls-example.py +0 -0
  179. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/099-t.py +0 -0
  180. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_checkpoint_empty.py +0 -0
  181. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_components_utils.py +0 -0
  182. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_tools.py +0 -0
  183. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/client/conftest.py +0 -0
  184. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/client/test_client.py +0 -0
  185. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/conftest.py +0 -0
  186. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_llm.py +0 -0
  187. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_memory.py +0 -0
  188. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_observability.py +0 -0
  189. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_prompt_manager.py +0 -0
  190. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_prompts.py +0 -0
  191. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_settings.py +0 -0
  192. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/integration/test_docker_e2e.py +0 -0
  193. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/conftest.py +0 -0
  194. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_auth.py +0 -0
  195. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_exception_handlers.py +0 -0
  196. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_factory.py +0 -0
  197. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_handler.py +0 -0
  198. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_middleware.py +0 -0
  199. {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_service_e2e.py +0 -0
@@ -164,3 +164,16 @@ venv
164
164
 
165
165
  # langgraph
166
166
  .langgraph_api
167
+
168
+ # Build context trimming — the images only COPY pyproject.toml, uv.lock and
169
+ # langgraph_agent_toolkit/, so exclude everything else from the build context.
170
+ tests/
171
+ docs/
172
+ scripts/
173
+ configs/
174
+ .github/
175
+ data/
176
+ *.md
177
+ Makefile
178
+ docker-compose*.yaml
179
+ .pre-commit-config.yaml
@@ -113,4 +113,17 @@ MODEL_CONFIGS_PATH=
113
113
  # Amazon Bedrock Knowledge Base ID
114
114
  AWS_KB_ID=
115
115
 
116
+ # Detect/resume interrupted runs (human-in-the-loop). Default true; set false to skip the per-request
117
+ # checkpointer read when no agent uses interrupt().
116
118
  CHECK_INTERRUPTS=
119
+
120
+ # Max non-text attachments (image/file/audio/video) per message. Empty = no toolkit limit
121
+ # (the model provider still enforces its own per-model caps).
122
+ MULTIMODAL_MAX_ATTACHMENTS=
123
+
124
+ # Defaults for ClearIntermediateToolCallsMiddleware (opt-in token reduction). Global kill switch,
125
+ # dedup key ("name_args" = collapse only identical repeat calls; "name" = collapse all repeats of a
126
+ # tool), and how many most-recent results to keep per key in previous turns.
127
+ CLEAR_INTERMEDIATE_TOOL_CALLS=
128
+ CLEAR_INTERMEDIATE_TOOL_CALLS_BY=
129
+ CLEAR_INTERMEDIATE_TOOL_CALLS_KEEP_LAST_N=
@@ -6,6 +6,84 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.9.2]
10
+
11
+ ### Fixed
12
+
13
+ - `TrimMessagesMiddleware` / `TokenTrimMiddleware` no longer silently destroy
14
+ the model's view when the **latest turn does not fit the budget**.
15
+ `trim_messages` (`strategy="last"`, `start_on="human"`) returns `[]` whenever
16
+ the current turn exceeds the budget — e.g. a single user message larger than
17
+ the token budget, or a turn with more tool calls than the message budget —
18
+ which invoked the model with the system prompt only and made it answer with
19
+ the user's question dropped. Both middlewares now floor to the latest turn
20
+ (kept verbatim, over budget but answerable) rather than emptying it.
21
+ Regression tests cover an oversize user message, an oversize tool result, and
22
+ a 6+ tool-call burst.
23
+
24
+ ### Added
25
+
26
+ - `TokenTrimMiddleware` — bounds the model's message view by a **token** budget
27
+ (the token-counting companion to `TrimMessagesMiddleware`, which bounds by
28
+ message count). View-only, so the full history stays in state and the system
29
+ prompt is preserved. The token counter is configurable (`token_counter`,
30
+ default `count_tokens_approximately` — no extra dependency; pass a
31
+ `tiktoken`-backed counter or the model for an exact count), and the budget
32
+ defaults to the new `DEFAULT_MAX_TOKENS_HISTORY_LENGTH` setting (unset by
33
+ default, since a sensible budget is model-specific). Compose it after
34
+ `TrimMessagesMiddleware` to cap both message count and token size.
35
+
36
+ ## [0.9.1]
37
+
38
+ ### Added
39
+
40
+ - Reusable `create_agent` middleware that brings the custom `create_react_agent`
41
+ history features to native LangChain `create_agent`, using only public API:
42
+ `ImmediateGenerationMiddleware` (graceful model-call budget — on the last
43
+ allowed call it strips tools and asks the model to synthesize a direct answer
44
+ instead of stalling), `SanitizeHistoryMiddleware` (repair broken
45
+ tool-call/result pairing before the model call), and
46
+ `ClearIntermediateToolCallsMiddleware` (token reduction — keep only the most
47
+ recent result(s) per tool from earlier turns; configurable via constructor or
48
+ `CLEAR_INTERMEDIATE_TOOL_CALLS*` settings, with a safe `name_args` dedup key
49
+ that collapses only identical repeat calls by default), and
50
+ `TrimMessagesMiddleware` (view-only window bound — trims the model's input to
51
+ the last `DEFAULT_MAX_MESSAGE_HISTORY_LENGTH` messages while keeping full
52
+ state). Demonstrated in the `create_agent` blueprint
53
+ - `hitl_agent` blueprint: human-in-the-loop tool approval on native
54
+ `create_agent` via `HumanInTheLoopMiddleware`. The executor bridges the resume
55
+ (`build_resume_command`): replying `approve` / `reject: <reason>` / free text
56
+ maps to the middleware's decision format, with custom `interrupt()` blueprints
57
+ unchanged
58
+ - Multimodal input: `UserComplexInput.message` accepts LangChain content blocks
59
+ (text / image / file / audio / video, via URL or base64), with a configurable
60
+ per-message attachment cap (`MULTIMODAL_MAX_ATTACHMENTS`), and the Streamlit
61
+ chat supports file/image uploads
62
+
63
+ ### Changed
64
+
65
+ - Dockerfiles (`docker/api`, `docker/app`) are now multi-stage with uv cache
66
+ mounts and dependency-before-source layering: faster rebuilds (a code change
67
+ no longer reinstalls dependencies), smaller images, and a trimmed build
68
+ context
69
+ - Renamed and de-duplicated the ReAct example blueprints: `react_new` →
70
+ `create_agent`, `react_so` → `create_agent_structured`; removed `react_old` (a
71
+ duplicate of `react`) and `react_so_old`. Examples are now grouped by builder
72
+ (toolkit `create_react_agent` vs native `create_agent`)
73
+ - `sanitize_chat_history` is now bidirectional: in addition to stripping
74
+ unanswered tool calls, it drops orphaned ToolMessages (a tool result whose
75
+ requesting tool call is gone, e.g. after trimming/summarization). Both the
76
+ custom `create_react_agent` and `SanitizeHistoryMiddleware` benefit
77
+ - Refactored the Streamlit UI from a single `run_app.py` into a `ui/` package
78
+ (`main_page`, `components/`, `utils/`); `run_app.py` is now a thin entry point
79
+
80
+ ### Fixed
81
+
82
+ - Human-in-the-loop interrupts now resume by default (`CHECK_INTERRUPTS`
83
+ defaults to `True`); previously the resume was silently skipped
84
+ - Streaming now surfaces an agent's `structured_response` (`response_format`),
85
+ matching `invoke`
86
+
9
87
  ## [0.9.0]
10
88
 
11
89
  ### Added
@@ -60,8 +60,8 @@ langgraph_agent_toolkit/ # The package (all importable code)
60
60
  agents/
61
61
  agent.py # Agent dataclass (wraps a compiled LangGraph Pregel)
62
62
  agent_executor.py # Loads agents from "module:obj" strings; invoke/stream
63
- components/ # checkpoint/, creators/ (custom create_react_agent), tools, utils
64
- blueprints/ # Example agent graphs: chatbot, react*, supervisor, etc.
63
+ components/ # checkpoint/, creators/ (custom create_react_agent), middlewares/, tools, utils
64
+ blueprints/ # Example agent graphs: react, create_agent*, chatbot, supervisor, etc.
65
65
  service/ # FastAPI HTTP layer (factory, routes, handler, middleware, auth)
66
66
  client/client.py # AgentClient SDK (httpx; sync + async)
67
67
  core/ # Cross-cutting factories + settings
@@ -77,7 +77,7 @@ scripts/
77
77
  python/ # 01–09 runnable usage examples (proxy, prompts, history)
78
78
  tests/ # pytest suite (unit / in-process e2e / docker e2e)
79
79
  docs/ # Sphinx docs (published to GitHub Pages)
80
- .github/workflows/ # CI/CD: test.yml, release.yml, deploy.yml, sphinx.yml
80
+ .github/workflows/ # CI/CD: test.yml, release.yml, sphinx.yml
81
81
  pyproject.toml # Project + tool config (ruff, pytest, extras)
82
82
  Makefile # uv / pre-commit / docker shortcuts
83
83
  langgraph.json # LangGraph CLI deploy config
@@ -151,7 +151,7 @@ loaded from the nearest `.env`.
151
151
  points `load_dotenv()` the `.env` so those vars are present at runtime.
152
152
  - Notable defaults: `ENV_MODE=production`, `HOST/PORT=0.0.0.0/8080`,
153
153
  `MEMORY_BACKEND` unset (→ no persistence), `OBSERVABILITY_BACKEND` unset (→
154
- `EMPTY` at runtime), `DEFAULT_AGENT=react-agent`, `CHECK_INTERRUPTS=False`,
154
+ `EMPTY` at runtime), `DEFAULT_AGENT=create-agent`, `CHECK_INTERRUPTS=True`,
155
155
  `CORS_ENABLED=False`, `AUTH_SECRET=None` (→ auth disabled).
156
156
 
157
157
  ## Architecture & core patterns
@@ -181,9 +181,33 @@ create `agents/blueprints/<name>/agent.py` exposing a compiled graph or `Agent`,
181
181
  then register its path in `AGENT_PATHS` (default list in `_base_settings.py`).
182
182
  ⚠️ `run_api.py` **hard-codes its own `AGENT_PATHS`** list, overriding the
183
183
  settings default — update it there too if the service entry point must load your
184
- agent. Several `react*` blueprints (`react_old`, `react_so_old`) are legacy
185
- near-duplicates of `react` / `react_so`; confirm which variant is actually wired
186
- before editing one.
184
+ agent.
185
+
186
+ **ReAct example blueprints — two builders.** The toolkit ships two ways to build
187
+ a tool-calling ReAct agent, shown side by side:
188
+
189
+ - **`react`** — built with the toolkit's **custom `create_react_agent`**
190
+ (`components/creators/`), a fork of LangGraph's prebuilt agent that adds an
191
+ `immediate_generation` router, `sanitize_chat_history`, and an always-on
192
+ `pre_model_hook`. It pushes a Langfuse prompt at import (needs `LANGFUSE_*`).
193
+ - **`create_agent`** (flagship) and **`create_agent_structured`** — built with
194
+ **LangChain's native `create_agent`** composed with middleware. The toolkit's
195
+ `components/middlewares/` reproduce the custom-agent features on the supported
196
+ path (all view-only `wrap_model_call`, so the full history stays in state):
197
+ `ImmediateGenerationMiddleware`, `SanitizeHistoryMiddleware`,
198
+ `ClearIntermediateToolCallsMiddleware` (token reduction, tunable via
199
+ `CLEAR_INTERMEDIATE_TOOL_CALLS*` settings), and `TrimMessagesMiddleware`
200
+ (view-only window bound, reuses `DEFAULT_MAX_MESSAGE_HISTORY_LENGTH`). The
201
+ flagship stack also uses the built-in `ContextEditingMiddleware` (window) and
202
+ `ToolRetryMiddleware` (resilience). `create_agent_structured` adds a
203
+ `response_format`. **This is the recommended pattern for new agents, and
204
+ `create-agent` is the default (`DEFAULT_AGENT=create-agent`).**
205
+ - **`hitl_agent`** — human-in-the-loop tool approval on `create_agent` via
206
+ `HumanInTheLoopMiddleware`. Its resume goes through
207
+ `agent_executor.build_resume_command`, which maps an `approve` /
208
+ `reject: <reason>` / free-text reply to the middleware's decision format; raw
209
+ `interrupt()` blueprints (`interrupt_agent`) are unaffected (they still get
210
+ `Command(resume=<input>)`).
187
211
 
188
212
  **Service.** `service/handler.py:create_app()` is the FastAPI factory; an async
189
213
  `lifespan` boots observability + memory checkpointer + `AgentExecutor` onto
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-agent-toolkit
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Full toolkit for running an AI agent service built with LangGraph, FastAPI and Streamlit
5
5
  Project-URL: documentation, https://kryvokhyzha.github.io/langgraph-agent-toolkit
6
6
  Project-URL: repository, https://github.com/kryvokhyzha/langgraph-agent-toolkit
@@ -226,6 +226,8 @@ For detailed installation instructions and available extras, see the
226
226
 
227
227
  - FastAPI with streaming and non-streaming endpoints
228
228
  - Streaming over Server-Sent Events (SSE) or JSON Lines (NDJSON)
229
+ - Multimodal input (images, files/PDF, audio, video) via LangChain content
230
+ blocks
229
231
  - Support for both token-based and message-based streaming
230
232
  - Multiple agent support with URL path routing
231
233
  - Available agents and models listed at `/info` endpoint
@@ -130,6 +130,8 @@ For detailed installation instructions and available extras, see the
130
130
 
131
131
  - FastAPI with streaming and non-streaming endpoints
132
132
  - Streaming over Server-Sent Events (SSE) or JSON Lines (NDJSON)
133
+ - Multimodal input (images, files/PDF, audio, video) via LangChain content
134
+ blocks
133
135
  - Support for both token-based and message-based streaming
134
136
  - Multiple agent support with URL path routing
135
137
  - Available agents and models listed at `/info` endpoint
@@ -0,0 +1,69 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ # ---------------------------------------------------------------------------
4
+ # Builder: resolve + install dependencies into an isolated venv. Kept out of
5
+ # the final image so the uv binary and build cache never ship to production.
6
+ # ---------------------------------------------------------------------------
7
+ FROM python:3.13-slim AS builder
8
+
9
+ ENV UV_COMPILE_BYTECODE=1 \
10
+ UV_LINK_MODE=copy \
11
+ UV_PYTHON_DOWNLOADS=0 \
12
+ UV_PROJECT_ENVIRONMENT=/opt/venv
13
+
14
+ COPY --from=ghcr.io/astral-sh/uv:0.11 /uv /bin/uv
15
+
16
+ WORKDIR /app
17
+
18
+ # Only the manifest + lockfile are needed to install dependencies. Copying them
19
+ # before the source keeps this expensive layer cached across code changes; the
20
+ # cache mount reuses uv's download/wheel cache across builds.
21
+ COPY pyproject.toml uv.lock ./
22
+ RUN --mount=type=cache,target=/root/.cache/uv \
23
+ uv sync --frozen --no-install-project --no-dev \
24
+ --extra gunicorn-backend --extra all-observability --extra openai
25
+
26
+ # ---------------------------------------------------------------------------
27
+ # Runtime: minimal image with just the venv + application source.
28
+ # ---------------------------------------------------------------------------
29
+ FROM python:3.13-slim AS runtime
30
+
31
+ ENV PYTHONPATH=/app \
32
+ PYTHONUNBUFFERED=1 \
33
+ PATH=/opt/venv/bin:$PATH
34
+
35
+ # curl is used by the container healthcheck (GET /health/ready).
36
+ RUN apt-get update && apt-get install -y --no-install-recommends curl \
37
+ && rm -rf /var/lib/apt/lists/*
38
+
39
+ WORKDIR /app
40
+ COPY --from=builder /opt/venv /opt/venv
41
+ COPY langgraph_agent_toolkit/ ./langgraph_agent_toolkit/
42
+
43
+ # Run as a non-root user.
44
+ RUN useradd --create-home --shell /bin/bash appuser && chown -R appuser:appuser /app
45
+ USER appuser
46
+
47
+ EXPOSE 8080
48
+
49
+ # Gunicorn worker management (see run_api.py):
50
+ # --workers N worker processes (recommend 2-4 per CPU core)
51
+ # --preload_app load the app once before forking — faster worker startup,
52
+ # shared memory, agents initialized once (best for prod)
53
+ # --timeout kill workers that don't respond in N s (> slowest request)
54
+ # --graceful_timeout time for in-flight requests to finish before a worker is killed
55
+ # --max_requests[_jitter] recycle workers after N requests to bound memory growth
56
+ CMD ["python", "langgraph_agent_toolkit/run_api.py", "run_api", \
57
+ "--runner_type", "gunicorn", \
58
+ "--workers", "1", \
59
+ "--preload_app", \
60
+ "--timeout", "120", \
61
+ "--graceful_timeout", "30"]
62
+
63
+ # ====================================================
64
+ # Health check endpoints for Kubernetes:
65
+ # - /health/live - Liveness probe (is process alive?)
66
+ # - /health/ready - Readiness probe (can accept traffic?)
67
+ # - /health/startup - Startup probe (has initialization completed?)
68
+ # - /health/db - Database pool health (for monitoring)
69
+ # ====================================================
@@ -0,0 +1,45 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ # ---------------------------------------------------------------------------
4
+ # Builder: install the minimal Streamlit client deps into an isolated venv.
5
+ # ---------------------------------------------------------------------------
6
+ FROM python:3.13-slim AS builder
7
+
8
+ ENV UV_COMPILE_BYTECODE=1 \
9
+ UV_LINK_MODE=copy \
10
+ UV_PYTHON_DOWNLOADS=0 \
11
+ UV_PROJECT_ENVIRONMENT=/opt/venv
12
+
13
+ COPY --from=ghcr.io/astral-sh/uv:0.11 /uv /bin/uv
14
+
15
+ WORKDIR /app
16
+
17
+ COPY pyproject.toml uv.lock ./
18
+ RUN --mount=type=cache,target=/root/.cache/uv \
19
+ uv sync --frozen --no-install-project --only-group client
20
+
21
+ # ---------------------------------------------------------------------------
22
+ # Runtime: minimal image with just the venv + application source.
23
+ # ---------------------------------------------------------------------------
24
+ FROM python:3.13-slim AS runtime
25
+
26
+ ENV PYTHONPATH=/app \
27
+ PYTHONUNBUFFERED=1 \
28
+ PATH=/opt/venv/bin:$PATH
29
+
30
+ WORKDIR /app
31
+ COPY --from=builder /opt/venv /opt/venv
32
+ COPY langgraph_agent_toolkit/ ./langgraph_agent_toolkit/
33
+
34
+ # Run as a non-root user.
35
+ RUN useradd --create-home --shell /bin/bash appuser && chown -R appuser:appuser /app
36
+ USER appuser
37
+
38
+ EXPOSE 8501
39
+
40
+ CMD ["streamlit", "run", "langgraph_agent_toolkit/run_app.py", \
41
+ "--server.headless=true", \
42
+ "--server.address=0.0.0.0", \
43
+ "--server.port=8501", \
44
+ "--server.fileWatcherType=none", \
45
+ "--browser.gatherUsageStats=false"]
@@ -22,7 +22,8 @@ To customize the agent:
22
22
 
23
23
  1. Add your agent to ``langgraph_agent_toolkit/agents/blueprints/``
24
24
  2. Register it in ``AGENT_PATHS`` list in ``langgraph_agent_toolkit/core/settings.py``
25
- 3. Optionally customize the Streamlit interface in ``run_app.py``
25
+ 3. Optionally customize the Streamlit interface under ``langgraph_agent_toolkit/ui/``
26
+ (``main_page.py``, ``components/``, ``utils/``); ``run_app.py`` is just the entry point
26
27
 
27
28
  Docker Setup
28
29
  ------------
@@ -91,6 +92,14 @@ The toolkit includes ``AgentClient`` for interacting with the agent service:
91
92
  for chunk in client.stream_jsonl({"message": "Tell me a brief joke?"}):
92
93
  print(chunk)
93
94
 
95
+ # Multimodal input: ``message`` can be a list of LangChain content blocks
96
+ # (text / image / file / audio / video, by URL or base64). The chosen model must
97
+ # support the modality; LangChain translates blocks to the provider's format.
98
+ client.invoke({"message": [
99
+ {"type": "text", "text": "Describe this image."},
100
+ {"type": "image", "url": "https://example.com/image.jpg"},
101
+ ]})
102
+
94
103
  See ``langgraph_agent_toolkit/run_client.py`` for more examples.
95
104
 
96
105
  Development with LangGraph Studio
@@ -143,6 +152,7 @@ Key Features
143
152
 
144
153
  - FastAPI with streaming and non-streaming endpoints
145
154
  - Streaming over Server-Sent Events (SSE) or JSON Lines (NDJSON)
155
+ - Multimodal input (images, files/PDF, audio, video) via LangChain content blocks
146
156
  - Support for both token-based and message-based streaming
147
157
  - Multiple agent support with URL path routing
148
158
  - Available agents and models listed at ``/info`` endpoint
@@ -28,6 +28,64 @@ from langgraph_agent_toolkit.helper.utils import (
28
28
  from langgraph_agent_toolkit.schema import AgentInfo, ChatMessage
29
29
 
30
30
 
31
+ _HITL_APPROVE = {"approve", "yes", "y", "ok", "accept", "approved"}
32
+ _HITL_REJECT = {"reject", "no", "n", "deny", "rejected"}
33
+
34
+
35
+ def interrupt_value_to_content(value: Any) -> Any:
36
+ """Render an interrupt payload as valid ``AIMessage`` content (a string).
37
+
38
+ Custom ``interrupt()`` blueprints pass a string (used as-is). ``HumanInTheLoopMiddleware`` passes
39
+ a request dict (``{"action_requests": [...]}``); its per-action ``description`` already holds a
40
+ readable approval prompt, so join those and append a hint on how to reply. This keeps the dict
41
+ out of ``AIMessage(content=...)``, which only accepts a string or content-block list.
42
+ """
43
+ if isinstance(value, (str, list)):
44
+ return value
45
+ if isinstance(value, dict) and value.get("action_requests"):
46
+ lines = []
47
+ for req in value["action_requests"]:
48
+ description = req.get("description")
49
+ lines.append(
50
+ str(description) if description else f"Approve `{req.get('name')}` with args {req.get('args')}?"
51
+ )
52
+ lines.append("\nReply 'approve' to proceed, 'reject: <reason>' to decline, or send other instructions.")
53
+ return "\n".join(lines)
54
+ return str(value)
55
+
56
+
57
+ def build_resume_command(interrupted_tasks: list, user_input: Dict[str, Any]) -> Command:
58
+ """Build the ``Command(resume=...)`` for an interrupted run.
59
+
60
+ ``HumanInTheLoopMiddleware`` expects ``{"decisions": [...]}``; other interrupts (custom
61
+ ``interrupt()`` blueprints) read the raw input dict (e.g. ``resume_value["message"]``). When the
62
+ pending interrupt is a HITL tool-approval request, translate the user's reply into one decision
63
+ per pending tool call: ``approve``/``yes`` -> approve, ``reject[: reason]``/``no`` -> reject, any
64
+ other text -> respond (sent to the model). Otherwise resume with the raw input unchanged.
65
+ """
66
+ interrupt_value = None
67
+ try:
68
+ interrupt_value = interrupted_tasks[0].interrupts[0].value
69
+ except (IndexError, AttributeError, TypeError):
70
+ pass
71
+
72
+ if isinstance(interrupt_value, dict) and interrupt_value.get("action_requests"):
73
+ count = len(interrupt_value["action_requests"]) or 1
74
+ raw = user_input.get("message")
75
+ message = raw.strip() if isinstance(raw, str) else ""
76
+ lowered = message.lower()
77
+ if lowered in _HITL_APPROVE:
78
+ decision: Dict[str, Any] = {"type": "approve"}
79
+ elif lowered in _HITL_REJECT or lowered.startswith("reject"):
80
+ reason = message.split(":", 1)[1].strip() if ":" in message else "User rejected the action."
81
+ decision = {"type": "reject", "message": reason}
82
+ else:
83
+ decision = {"type": "respond", "message": message}
84
+ return Command(resume={"decisions": [decision] * count})
85
+
86
+ return Command(resume=user_input)
87
+
88
+
31
89
  T = TypeVar("T")
32
90
 
33
91
 
@@ -276,8 +334,10 @@ class AgentExecutor:
276
334
  pass
277
335
 
278
336
  if interrupted_tasks:
279
- # User input is a response to resume agent execution from interrupt
280
- input_data = Command(resume=_input)
337
+ # User input resumes an interrupted run. For HumanInTheLoopMiddleware the reply is mapped
338
+ # to a decision; custom interrupt() blueprints receive the raw input dict and read the
339
+ # field they need (e.g. resume_value["message"]).
340
+ input_data = build_resume_command(interrupted_tasks, _input)
281
341
  else:
282
342
  if "message" in _input:
283
343
  message = _input.pop("message", "") or ""
@@ -360,13 +420,11 @@ class AgentExecutor:
360
420
  # Normal response, the agent completed successfully
361
421
  output = langchain_to_chat_message(generated_message)
362
422
  elif response_type == "values" and "__interrupt__" in response:
363
- # The last thing to occur was an interrupt
364
- # Return the value of the first interrupt as an AIMessage
365
- output = langchain_to_chat_message(AIMessage(content=response["__interrupt__"][0].value))
366
- elif response_type == "updates" and "__interrupt__" in response:
367
- # The last thing to occur was an interrupt
368
- # Return the value of the first interrupt as an AIMessage
369
- output = langchain_to_chat_message(AIMessage(content=response["__interrupt__"][0].value))
423
+ # The agent paused on an interrupt. ainvoke(stream_mode=["values"]) surfaces it in the
424
+ # final values event; return the first interrupt's value as an AIMessage.
425
+ output = langchain_to_chat_message(
426
+ AIMessage(content=interrupt_value_to_content(response["__interrupt__"][0].value))
427
+ )
370
428
  else:
371
429
  raise ValueError(f"Unexpected response type: {response_type}")
372
430
 
@@ -445,7 +503,7 @@ class AgentExecutor:
445
503
  if node == "__interrupt__":
446
504
  interrupt: Interrupt
447
505
  for interrupt in updates:
448
- new_messages.append(AIMessage(content=interrupt.value))
506
+ new_messages.append(AIMessage(content=interrupt_value_to_content(interrupt.value)))
449
507
  continue
450
508
 
451
509
  update_messages = (updates or {}).get("messages", [])
@@ -469,6 +527,12 @@ class AgentExecutor:
469
527
  update_messages = [msg]
470
528
  new_messages.extend(update_messages)
471
529
 
530
+ # Surface structured output (response_format) so streaming matches invoke,
531
+ # which returns structured_response. Yielded as a ChatMessage with dict content.
532
+ structured_response = (updates or {}).get("structured_response")
533
+ if structured_response is not None:
534
+ new_messages.append(structured_response)
535
+
472
536
  elif stream_mode == "custom":
473
537
  new_messages = [event]
474
538
 
@@ -510,12 +574,21 @@ class AgentExecutor:
510
574
  try:
511
575
  chat_message = langchain_to_chat_message(msg)
512
576
  chat_message.run_id = str(run_id)
513
- # Skip the input message if it's repeated by LangGraph
514
- if chat_message.type == "human" and chat_message.content == msg:
577
+ # Don't echo human messages back in the response stream: the client already
578
+ # has its input, and LangGraph can re-surface it. (The previous
579
+ # `content == msg` check compared a str to a message object and never matched.)
580
+ if chat_message.type == "human":
515
581
  continue
516
582
  # Track the latest AI message to record as the trace output
517
583
  if chat_message.type == "ai" and chat_message.content:
518
- final_output = convert_message_content_to_string(chat_message.content)
584
+ _content = chat_message.content
585
+ final_output = (
586
+ _content
587
+ if isinstance(_content, str)
588
+ else convert_message_content_to_string(_content)
589
+ if isinstance(_content, list)
590
+ else str(_content) # structured-output dict, etc.
591
+ )
519
592
  yield chat_message
520
593
  except Exception as e:
521
594
  logger.error(f"Error parsing message: {e}")
@@ -0,0 +1,91 @@
1
+ """Example agent built with LangChain's native ``create_agent`` (the recommended modern pattern).
2
+
3
+ A ``create_agent`` tool-calling loop composed with middleware. It reproduces the toolkit's custom
4
+ ``create_react_agent`` behavior using only public LangChain middleware:
5
+
6
+ - ``ContextEditingMiddleware`` — bound the context window non-destructively: once tokens pass the
7
+ trigger, clear OLD tool outputs (keeping the most recent), reclaiming tokens while keeping the
8
+ conversation text. Chosen over ``SummarizationMiddleware`` (which destructively replaces history
9
+ with a summary).
10
+ - ``ImmediateGenerationMiddleware`` — the graceful loop bound: near the recursion limit, drop tools
11
+ and ask the model to answer from what it already gathered, instead of stalling or erroring (ports
12
+ the custom router's ``immediate_generation``). This is the loop bound — a separate hard tool-call
13
+ cap is intentionally omitted, since it would end abruptly and preempt this graceful synthesis.
14
+ - ``ClearIntermediateToolCallsMiddleware`` — token reduction: keep only the latest result per tool
15
+ from earlier turns (configurable via the ``CLEAR_INTERMEDIATE_TOOL_CALLS*`` settings).
16
+ - ``SanitizeHistoryMiddleware`` — repair broken tool-call/result pairing (interrupted runs, post
17
+ trim/clear orphans).
18
+ - ``ToolRetryMiddleware`` — resilience: retry a failed tool call with backoff, and after retries are
19
+ exhausted return the error as a ToolMessage so a single flaky tool (e.g. a search timeout) doesn't
20
+ abort the whole run.
21
+
22
+ Compare with ``blueprints/react``: the same agent built with the toolkit's ``create_react_agent``.
23
+ """
24
+
25
+ from langchain.agents import AgentState, create_agent
26
+ from langchain.agents.middleware import ClearToolUsesEdit, ContextEditingMiddleware, ToolRetryMiddleware
27
+ from langchain_community.tools import DuckDuckGoSearchResults
28
+ from langgraph.checkpoint.memory import MemorySaver
29
+
30
+ from langgraph_agent_toolkit.agents.agent import Agent
31
+ from langgraph_agent_toolkit.agents.components.middlewares import (
32
+ ClearIntermediateToolCallsMiddleware,
33
+ ImmediateGenerationMiddleware,
34
+ SanitizeHistoryMiddleware,
35
+ )
36
+ from langgraph_agent_toolkit.agents.components.tools import add, multiply
37
+ from langgraph_agent_toolkit.core import settings
38
+ from langgraph_agent_toolkit.core.models.factory import CompletionModelFactory
39
+ from langgraph_agent_toolkit.schema.models import ModelProvider
40
+
41
+
42
+ model = CompletionModelFactory.create(
43
+ model_provider=ModelProvider.OPENAI,
44
+ model_name=settings.OPENAI_MODEL_NAME,
45
+ config_prefix="",
46
+ configurable_fields=(),
47
+ model_parameter_values=(("temperature", 0.2), ("top_p", 0.95), ("streaming", False)),
48
+ openai_api_base=settings.OPENAI_API_BASE_URL,
49
+ openai_api_key=settings.OPENAI_API_KEY,
50
+ )
51
+
52
+ react_agent = Agent(
53
+ name="create-agent",
54
+ description="A tool-calling ReAct agent built with LangChain's native create_agent + middleware.",
55
+ graph=create_agent(
56
+ model=model,
57
+ tools=[add, multiply, DuckDuckGoSearchResults()],
58
+ # Middleware compose in list order. The wrap_model_call-based ones (Immediate /
59
+ # ClearIntermediate / Sanitize) wrap the model node rather than adding graph nodes;
60
+ # SanitizeHistory is placed last so it cleans the final request sent to the model.
61
+ middleware=[
62
+ # Bound the context window without summarizing: once the conversation passes the token
63
+ # trigger, clear OLD tool outputs (keeping the most recent `keep`), reclaiming tokens
64
+ # while preserving conversation text. Tune `trigger` to the model's context window.
65
+ ContextEditingMiddleware(edits=[ClearToolUsesEdit(trigger=100_000, keep=3)]),
66
+ # Graceful loop bound near the recursion limit: on the last allowed model call, strip
67
+ # tools and ask the model to answer from what it already gathered (ports the custom
68
+ # create_react_agent's immediate_generation router). Default budget ~= recursion_limit/2.
69
+ # No separate hard tool-call cap — it would end abruptly and preempt this synthesis.
70
+ ImmediateGenerationMiddleware(),
71
+ # Token reduction: keep only the latest result per tool from earlier turns (current turn
72
+ # untouched). Defaults from CLEAR_INTERMEDIATE_TOOL_CALLS* settings (safe name_args key).
73
+ ClearIntermediateToolCallsMiddleware(),
74
+ # Repair broken tool-call/result pairing before the model call (interrupted runs, post
75
+ # trim/summarize orphans).
76
+ SanitizeHistoryMiddleware(),
77
+ # Resilience: retry a failed tool call (backoff), then on_failure="continue" (the default)
78
+ # returns the error as a ToolMessage so one flaky search timeout doesn't abort the run.
79
+ ToolRetryMiddleware(max_retries=2),
80
+ ],
81
+ system_prompt=(
82
+ "You are a team support agent that can perform calculations and search the web. "
83
+ "You can use the tools provided to help you with your tasks. "
84
+ "You can also ask clarifying questions to the user. "
85
+ ),
86
+ state_schema=AgentState,
87
+ checkpointer=MemorySaver(),
88
+ ),
89
+ )
90
+
91
+ __all__ = ["react_agent"]