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.
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.dockerignore +13 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.env.example +13 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/CHANGELOG.md +78 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/CLAUDE.md +31 -7
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/PKG-INFO +3 -1
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/README.md +2 -0
- langgraph_agent_toolkit-0.9.2/docker/api/Dockerfile +69 -0
- langgraph_agent_toolkit-0.9.2/docker/app/Dockerfile +45 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/usage.rst +11 -1
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/agent_executor.py +86 -13
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/create_agent/agent.py +91 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/create_agent_structured/agent.py +76 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/blueprints/hitl_agent/agent.py +67 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/__init__.py +18 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/_history.py +39 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/clear_intermediate_tool_calls.py +157 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/immediate_generation.py +80 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/sanitize_history.py +33 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/token_trim.py +81 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/agents/components/middlewares/trim_messages.py +62 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/_base_settings.py +39 -4
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/utils.py +37 -20
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/run_api.py +3 -4
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/run_app.py +18 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/schema.py +59 -4
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/__init__.py +1 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/components/__init__.py +1 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/components/draw_message.py +179 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/components/side_panel.py +92 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/main_page.py +143 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/utils/__init__.py +1 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/utils/constants.py +7 -0
- langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/ui/utils/message.py +102 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/pyproject.toml +1 -1
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_agent_executor.py +150 -1
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_blueprints.py +5 -4
- langgraph_agent_toolkit-0.9.2/tests/agents/test_create_agent_stack.py +107 -0
- langgraph_agent_toolkit-0.9.2/tests/agents/test_hitl_agent.py +147 -0
- langgraph_agent_toolkit-0.9.2/tests/agents/test_middlewares.py +401 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/helper/test_create_ai_message.py +8 -9
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/helper/test_helper_utils.py +35 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_service.py +2 -1
- langgraph_agent_toolkit-0.9.2/tests/ui/test_draw_messages.py +58 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/uv.lock +113 -112
- langgraph_agent_toolkit-0.9.0/.github/workflows/deploy.yml +0 -71
- langgraph_agent_toolkit-0.9.0/docker/api/Dockerfile +0 -69
- langgraph_agent_toolkit-0.9.0/docker/app/Dockerfile +0 -31
- langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_new/agent.py +0 -61
- langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_old/agent.py +0 -76
- langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_so/agent.py +0 -71
- langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/agents/blueprints/react_so_old/agent.py +0 -86
- langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/run_app.py +0 -414
- langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/service/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.claude/settings.json +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.coveragerc +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/RELEASE_TEMPLATE/release-template.md +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/codecov.yml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/dependabot.yml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/scripts/tag_from_pyproject.sh +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/workflows/release.yml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/workflows/sphinx.yml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.github/workflows/test.yml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.gitignore +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.pre-commit-config.yaml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/.project-root +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/CONTRIBUTING.md +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/LICENSE +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/Makefile +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/clickhouse/.clickhouse.env.example +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/langfuse/.langfuse.env.example +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/litellm/.litellm.env.example +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/litellm/config.example.yaml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/minio/.minio.env.example +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/postgres/.postgres.env.example +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/configs/redis/.redis.env.example +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docker-compose.yaml +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/.gitignore +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/Makefile +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_static/custom.css +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_templates/class.rst +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_templates/layout.html +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/_templates/module.rst +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/conf.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/contributing.rst +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/environment_setup.rst +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/index.rst +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/installation.rst +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/make.bat +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/agent_architecture.excalidraw +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/agent_architecture.png +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/agent_diagram.png +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/docs/media/logo.svg +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph.json +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/agent.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/agent.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/task.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/bg_task_agent/utils.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/chatbot/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/chatbot/agent.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/command_agent/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/command_agent/agent.py +0 -0
- {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
- {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
- {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
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/interrupt_agent/agent.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/knowledge_base_agent/agent.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/react/agent.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/blueprints/supervisor_agent/agent.py +0 -0
- {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
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/checkpoint/empty.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/creators/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/creators/create_react_agent.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/tools.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/agents/components/utils.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/client/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/client/client.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/__init__.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/base.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/factory.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/postgres.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/sqlite.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/memory/types.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/chat_openai.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/factory.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/models/fake.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/base.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/empty.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/factory.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/langfuse.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/langsmith.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/observability/types.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/prompts/chat_prompt_template.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/prompts/prompt_manager.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/core/settings.py +0 -0
- {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
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/constants.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/exceptions.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/logging.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/helper/types.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/models.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/schema/task_data.py +0 -0
- {langgraph_agent_toolkit-0.9.0/langgraph_agent_toolkit/helper → langgraph_agent_toolkit-0.9.2/langgraph_agent_toolkit/service}/__init__.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/exception_handlers.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/factory.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/handler.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/middleware.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/routes.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/types.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/langgraph_agent_toolkit/service/utils.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/postgres-init/create_databases.sql +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/postgres-init/create_schema.sql +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/01-invoke-proxy.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/02-test-local-pm.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/03-test-langfuse-pm.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/04-test-langsmith-pm.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/05-test-prompt-types.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/06-test-custom-chat-prompt-template.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/07-test-get-chat-history.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/08-test-update-chat-history.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/09-test-clear-chat-history.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/098-cls-example.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/scripts/python/099-t.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_checkpoint_empty.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_components_utils.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/agents/test_tools.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/client/conftest.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/client/test_client.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/conftest.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_llm.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_memory.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_observability.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_prompt_manager.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_prompts.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/core/test_settings.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/integration/test_docker_e2e.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/conftest.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_auth.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_exception_handlers.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_factory.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_handler.py +0 -0
- {langgraph_agent_toolkit-0.9.0 → langgraph_agent_toolkit-0.9.2}/tests/service/test_middleware.py +0 -0
- {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:
|
|
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,
|
|
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=
|
|
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.
|
|
185
|
-
|
|
186
|
-
|
|
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.
|
|
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
|
|
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
|
|
280
|
-
|
|
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
|
|
364
|
-
#
|
|
365
|
-
output = langchain_to_chat_message(
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
#
|
|
514
|
-
|
|
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
|
-
|
|
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"]
|