diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index ec17db77c..b86c38ec8 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -38,12 +38,13 @@ jobs: with: filter: "docs/docs/**" - run-changed-notebooks: - needs: get-changed-files - uses: ./.github/workflows/run_notebooks.yml - secrets: inherit - with: - changed-files: ${{ needs.get-changed-files.outputs.changed-files }} + # TODO: Uncomment this to run on PRs + # run-changed-notebooks: + # needs: get-changed-files + # uses: ./.github/workflows/run_notebooks.yml + # secrets: inherit + # with: + # changed-files: ${{ needs.get-changed-files.outputs.changed-files }} deploy: # needs: run-changed-notebooks @@ -98,6 +99,7 @@ jobs: - name: Check links in notebooks env: LANGCHAIN_API_KEY: test + if: github.event_name == 'schedule' run: | if [ "${{ github.event_name }}" == "schedule" ]; then echo "Running link check on all HTML files matching notebooks in docs directory..." diff --git a/README.md b/README.md index 799ab4b9a..ae8f0084f 100644 --- a/README.md +++ b/README.md @@ -16,48 +16,41 @@ > [!NOTE] > Looking for the JS version? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://langchain-ai.github.io/langgraphjs/). -LangGraph — used by Replit, Uber, LinkedIn, GitLab and more — is a low-level orchestration framework for building controllable agents. While langchain provides integrations and composable components to streamline LLM application development, the LangGraph library enables agent orchestration — offering customizable architectures, long-term memory, and human-in-the-loop to reliably handle complex tasks. +LangGraph is a low-level orchestration framework for building controllable agents. While [LangChain](https://python.langchain.com/docs/introduction/) provides integrations and composable components to streamline LLM application development, the LangGraph library enables agent orchestration — offering customizable architectures, long-term memory, and human-in-the-loop to reliably handle complex tasks. -```bash +## Get started + +First, install LangGraph: + +``` pip install -U langgraph ``` -To learn more about how to use LangGraph, check out [the docs](https://langchain-ai.github.io/langgraph/). We show a simple example below of how to create a ReAct agent. +There are two ways to get started with LangGraph: -```python -# This code depends on pip install langchain[anthropic] -from langgraph.prebuilt import create_react_agent +- [Use prebuilt components](https://langchain-ai.github.io/langgraph/agents/agents/): Construct agentic systems quickly and reliably without the need to implement orchestration, memory, or human feedback handling from scratch. +- [Use LangGraph](https://langchain-ai.github.io/langgraph/tutorials/introduction/): Customize your architectures, use long-term memory, and implement human-in-the-loop to reliably handle complex tasks. -def search(query: str): - """Call to surf the web.""" - if "sf" in query.lower() or "san francisco" in query.lower(): - return "It's 60 degrees and foggy." - return "It's 90 degrees and sunny." +Once you have a LangGraph application and are ready to move into production, use [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/quick_start/) to test, debug, and deploy your application. -agent = create_react_agent("anthropic:claude-3-7-sonnet-latest", tools=[search]) -agent.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]} -) -``` +## What LangGraph provides -> [!TIP] -> Check out [this guide](https://langchain-ai.github.io/langgraph/tutorials/workflows/) that walks through implementing common patterns (workflows and agents) in LangGraph. +LangGraph provides low-level supporting infrastructure that sits underneath *any* workflow or agent. It does not abstract prompts or architecture, and provides three central benefits: -## Why use LangGraph? +### Persistence -LangGraph is built for developers who want to build powerful, adaptable AI agents. Developers choose LangGraph for: +LangGraph has a [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), which offers a number of benefits: -- **Reliability and controllability.** Steer agent actions with moderation checks and human-in-the-loop approvals. LangGraph persists context for long-running workflows, keeping your agents on course. -- **Low-level and extensible.** Build custom agents with fully descriptive, low-level primitives – free from rigid abstractions that limit customization. Design scalable multi-agent systems, with each agent serving a specific role tailored to your use case. -- **First-class streaming support.** With token-by-token streaming and streaming of intermediate steps, LangGraph gives users clear visibility into agent reasoning and actions as they unfold in real time. +- [Memory](https://langchain-ai.github.io/langgraph/concepts/memory/): LangGraph persists arbitrary aspects of your application's state, supporting memory of conversations and other updates within and across user interactions; +- [Human-in-the-loop](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): Because state is checkpointed, execution can be interrupted and resumed, allowing for decisions, validation, and corrections via human input. -LangGraph is trusted in production and powering agents for companies like: +### Streaming -- [Klarna](https://blog.langchain.dev/customers-klarna/): Customer support bot for 85 million active users -- [Elastic](https://www.elastic.co/blog/elastic-security-generative-ai-features): Security AI assistant for threat detection -- [Uber](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/): Automated unit test generation -- [Replit](https://www.langchain.com/breakoutagents/replit): Code generation -- And many more ([see list here](https://www.langchain.com/built-with-langgraph)) +LangGraph provides support for [streaming](https://langchain-ai.github.io/langgraph/concepts/streaming/) workflow / agent state to the user (or developer) over the course of execution. LangGraph supports streaming of both events ([such as feedback from a tool call](https://langchain-ai.github.io/langgraph/how-tos/streaming.ipynb#updates)) and [tokens from LLM calls](https://langchain-ai.github.io/langgraph/how-tos/streaming-tokens.ipynb) embedded in an application. + +### Debugging and deployment + +LangGraph provides an easy onramp for testing, debugging, and deploying applications via [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). This includes [Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/), an IDE that enables visualization, interaction, and debugging of workflows or agents. This also includes numerous [options](https://langchain-ai.github.io/langgraph/tutorials/deployment/) for deployment. ## LangGraph’s ecosystem @@ -66,24 +59,14 @@ While LangGraph can be used standalone, it also integrates seamlessly with any L - [LangSmith](http://www.langchain.com/langsmith) — Helpful for agent evals and observability. Debug poor-performing LLM app runs, evaluate agent trajectories, gain visibility in production, and improve performance over time. - [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform) — Deploy and scale agents effortlessly with a purpose-built deployment platform for long running, stateful workflows. Discover, reuse, configure, and share agents across teams — and iterate quickly with visual prototyping in [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/). -## Pairing with LangGraph Platform - -While LangGraph is our open-source agent orchestration framework, enterprises that need scalable agent deployment can benefit from [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). - -LangGraph Platform can help engineering teams: - -- **Accelerate agent development**: Quickly create agent UXs with configurable templates and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/) for visualizing and debugging agent interactions. -- **Deploy seamlessly**: We handle the complexity of deploying your agent. LangGraph Platform includes robust APIs for memory, threads, and cron jobs plus auto-scaling task queues & servers. -- **Centralize agent management & reusability**: Discover, reuse, and manage agents across the organization. Business users can also modify agents without coding. - ## Additional resources +- [Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.). +- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components. +- [Examples](https://langchain-ai.github.io/langgraph/tutorials/): Guided examples on getting started with LangGraph. - [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course. -- [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Simple walkthroughs with guided examples on getting started with LangGraph. - [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted. -- [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.). -- [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components. -- [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. +- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. ## Acknowledgements diff --git a/docs/_scripts/generate_llms_text.py b/docs/_scripts/generate_llms_text.py index 65ef80355..a3c220641 100644 --- a/docs/_scripts/generate_llms_text.py +++ b/docs/_scripts/generate_llms_text.py @@ -20,15 +20,8 @@ def _make_llms_text(output_file: str) -> str: output_file: Path to output the consolidated text file """ # Collect all markdown and notebook files - relative_paths = [ - # Files relative to docs/docs/ - "tutorials/introduction.ipynb", - ] - all_files = [os.path.join(SOURCE_DIR, path) for path in relative_paths] + all_files = glob.glob(os.path.join(SOURCE_DIR, "how-tos/*.md"), recursive=True) - all_files.extend( - glob.glob(os.path.join(SOURCE_DIR, "how-tos/*.md"), recursive=True) - ) all_files.extend( glob.glob(os.path.join(SOURCE_DIR, "how-tos/*.ipynb"), recursive=True) ) diff --git a/docs/_scripts/notebook_convert_templates/mdoutput/index.md.j2 b/docs/_scripts/notebook_convert_templates/mdoutput/index.md.j2 index 05cbef99a..2e84ff7f6 100644 --- a/docs/_scripts/notebook_convert_templates/mdoutput/index.md.j2 +++ b/docs/_scripts/notebook_convert_templates/mdoutput/index.md.j2 @@ -38,9 +38,13 @@ {%- endblock data_html -%} {%- block data_jpg scoped -%} -![](data:image/jpg;base64,{{ output.data['image/jpeg'] }}) +

+ +

{%- endblock data_jpg -%} {%- block data_png scoped -%} -![](data:image/png;base64,{{ output.data['image/png'] }}) +

+ +

{%- endblock data_png -%} diff --git a/docs/_scripts/notebook_hooks.py b/docs/_scripts/notebook_hooks.py index 20955dbab..b106cc4a7 100644 --- a/docs/_scripts/notebook_hooks.py +++ b/docs/_scripts/notebook_hooks.py @@ -18,28 +18,84 @@ DISABLED = os.getenv("DISABLE_NOTEBOOK_CONVERT") in ("1", "true", "True") REDIRECT_MAP = { # lib redirects - "how-tos/stream-values.ipynb": "how-tos/streaming.ipynb#values", - "how-tos/stream-updates.ipynb": "how-tos/streaming.ipynb#updates", - "how-tos/streaming-content.ipynb": "how-tos/streaming.ipynb#custom", - "how-tos/stream-multiple.ipynb": "how-tos/streaming.ipynb#multiple", - "how-tos/streaming-tokens-without-langchain.ipynb": "how-tos/streaming-tokens.ipynb#example-without-langchain", + "how-tos/stream-values.ipynb": "how-tos/streaming.md#stream-graph-state", + "how-tos/stream-updates.ipynb": "how-tos/streaming.md#stream-graph-state", + "how-tos/streaming-content.ipynb": "how-tos/streaming.md", + "how-tos/stream-multiple.ipynb": "how-tos/streaming.md#stream-multiple-nodes", + "how-tos/streaming-tokens-without-langchain.ipynb": "how-tos/streaming.md#use-with-any-llm", "how-tos/streaming-from-final-node.ipynb": "how-tos/streaming-specific-nodes.ipynb", "how-tos/streaming-events-from-within-tools-without-langchain.ipynb": "how-tos/streaming-events-from-within-tools.ipynb#example-without-langchain", + # graph-api + "how-tos/state-reducers.ipynb": "how-tos/graph-api#define-and-update-state", + "how-tos/sequence.ipynb": "how-tos/graph-api#create-a-sequence-of-steps", + "how-tos/branching.ipynb": "how-tos/graph-api#create-branches", + "how-tos/recursion-limit.ipynb": "how-tos/graph-api#create-and-control-loops", + "how-tos/visualization.ipynb": "how-tos/graph-api#visualize-your-graph", + "how-tos/input_output_schema.ipynb": "how-tos/graph-api#define-input-and-output-schemas", + "how-tos/pass_private_state.ipynb": "how-tos/graph-api#pass-private-state-between-nodes", + "how-tos/state-model.ipynb": "how-tos/graph-api#use-pydantic-models-for-graph-state", + "how-tos/map-reduce.ipynb": "how-tos/graph-api/#map-reduce-and-the-send-api", + "how-tos/command.ipynb": "how-tos/graph-api/#combine-control-flow-and-state-updates-with-command", + "how-tos/configuration.ipynb": "how-tos/graph-api/#add-runtime-configuration", + "how-tos/node-retries.ipynb": "how-tos/graph-api/#add-retry-policies", + "how-tos/return-when-recursion-limit-hits.ipynb": "how-tos/graph-api/#impose-a-recursion-limit", + # memory how-tos + "how-tos/memory/manage-conversation-history.ipynb": "how-tos/memory.ipynb", + "how-tos/memory/delete-messages.ipynb": "how-tos/memory.ipynb#delete-messages", + "how-tos/memory/add-summary-conversation-history.ipynb": "how-tos/memory.ipynb#summarize-messages", + # subgraph how-tos + "how-tos/subgraph-transform-state.ipynb": "how-tos/subgraph.ipynb#different-state-schemas", + "how-tos/subgraphs-manage-state.ipynb": "how-tos/subgraph.ipynb#add-persistence", + # persistence how-tos + "how-tos/persistence_postgres.ipynb": "how-tos/persistence.ipynb#use-in-production", + "how-tos/persistence_mongodb.ipynb": "how-tos/persistence.ipynb#use-in-production", + "how-tos/persistence_redis.ipynb": "how-tos/persistence.ipynb#use-in-production", + "how-tos/subgraph-persistence.ipynb": "how-tos/persistence.ipynb#use-with-subgraphs", + "how-tos/cross-thread-persistence.ipynb": "how-tos/persistence.ipynb#add-long-term-memory", + # tool calling how-tos + "how-tos/tool-calling-errors.ipynb": "how-tos/tool-calling.ipynb#handle-errors", + "how-tos/pass-config-to-tools.ipynb": "how-tos/tool-calling.ipynb#access-config", + "how-tos/pass-run-time-values-to-tools.ipynb": "how-tos/tool-calling.ipynb#read-state", + "how-tos/update-state-from-tools.ipynb": "how-tos/tool-calling.ipynb#update-state", + # multi-agent how-tos + "how-tos/agent-handoffs.ipynb": "how-tos/multi_agent.ipynb#handoffs", + "how-tos/multi-agent-network.ipynb": "how-tos/multi_agent.ipynb#use-in-a-multi-agent-system", + "how-tos/multi-agent-multi-turn-convo.ipynb": "how-tos/multi_agent.ipynb#multi-turn-conversation", # cloud redirects - "cloud/index.md": "concepts/index.md#langgraph-platform", - "cloud/how-tos/index.md": "how-tos/index.md#langgraph-platform", + "cloud/index.md": "index.md", + "cloud/how-tos/index.md": "concepts/langgraph_platform", "cloud/concepts/api.md": "concepts/langgraph_server.md", "cloud/concepts/cloud.md": "concepts/langgraph_cloud.md", "cloud/faq/studio.md": "concepts/langgraph_studio.md#studio-faqs", + # cloud streaming redirects + "cloud/how-tos/stream_values.md": "cloud/how-tos/streaming.md#stream-graph-state", + "cloud/how-tos/stream_updates.md": "cloud/how-tos/streaming.md#stream-graph-state", + "cloud/how-tos/stream_messages.md": "cloud/how-tos/streaming.md#messages", + "cloud/how-tos/stream_events.md": "cloud/how-tos/streaming.md#stream-events", + "cloud/how-tos/stream_debug.md": "cloud/how-tos/streaming.md#debug", + "cloud/how-tos/stream_multiple.md": "cloud/how-tos/streaming.md#stream-multiple-modes", # prebuit redirects "how-tos/create-react-agent.ipynb": "agents/agents.md#basic-configuration", "how-tos/create-react-agent-memory.ipynb": "agents/memory.md", "how-tos/create-react-agent-system-prompt.ipynb": "agents/context.md#prompts", "how-tos/create-react-agent-hitl.ipynb": "agents/human-in-the-loop.md", "how-tos/create-react-agent-structured-output.ipynb": "agents/agents.md#structured-output", + # Time-travel + "how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.ipynb", + # breakpoints + "how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.ipynb", # misc "prebuilt.md": "agents/prebuilt.md", - "reference/prebuilt.md": "reference/agents.md" + "reference/prebuilt.md": "reference/agents.md", + "concepts/high_level.md": "index.md", + "concepts/index.md": "index.md", + "concepts/v0-human-in-the-loop.md": "concepts/human-in-the-loop.md", + "how-tos/index.md": "index.md", + "tutorials/introduction.ipynb": "concepts/why-langgraph.md", + # deployment redirects + "how-tos/deploy-self-hosted.md": "cloud/deployment/self_hosted_data_plane.md", + "concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md" + } diff --git a/docs/cassettes/add-summary-conversation-history_048805a4-3d97-4e76-ac45-8d80d4364c46.msgpack.zlib b/docs/cassettes/add-summary-conversation-history_048805a4-3d97-4e76-ac45-8d80d4364c46.msgpack.zlib deleted file mode 100644 index c8992ccdd..000000000 --- a/docs/cassettes/add-summary-conversation-history_048805a4-3d97-4e76-ac45-8d80d4364c46.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/add-summary-conversation-history_0a1a0fda-5309-45f0-9465-9f3dff604d74.msgpack.zlib b/docs/cassettes/add-summary-conversation-history_0a1a0fda-5309-45f0-9465-9f3dff604d74.msgpack.zlib deleted file mode 100644 index 105e33c74..000000000 --- a/docs/cassettes/add-summary-conversation-history_0a1a0fda-5309-45f0-9465-9f3dff604d74.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/add-summary-conversation-history_40e5db8e-9db9-4ac7-9d76-a99fd4034bf3.msgpack.zlib b/docs/cassettes/add-summary-conversation-history_40e5db8e-9db9-4ac7-9d76-a99fd4034bf3.msgpack.zlib deleted file mode 100644 index e2ee9d9db..000000000 --- a/docs/cassettes/add-summary-conversation-history_40e5db8e-9db9-4ac7-9d76-a99fd4034bf3.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNqNVg1sFMcV5q8OAZLShqgoDXjiNFglt+f78Z2x0wbZJgTzj30JcQHRud3Z2/Ht7Sw7u7aPKJWASIkSEnQRCSoqUMHZDicDdqGBNKQUCE1QqJI2EQlN1KIqiVpShUJ/wG2i9M3s3WHzI4Fkcbuz8973vve9b2Z9XydxOGXW6H5qucTBqgsPPLe+zyFrPMLdJ3szxDWYll+6pC2xy3PomfsM17V5Q00NtmkQW67hMJuqQZVlajrDNRnCOU4Rnk8yLfvH8S88XpXB3atdliYWr2pA4VCkNoCqSl/BmxWPVznMJPCryuPEqYJVlQEUyxWvKDJpmiCDdaGMpxrINUgWdVGr6okAurIRc065C1iu2p0wsFvNkWdpUCSsazhpkntQwiComZguVTkycCdBSUIsxCyCmC4yoAzjLuKeqgJM3TOR7mBLNSgnHFELLW5qRPDgMicbRG0sQ1AaQOlAHUc4yTxXxigmqBZoLWqlkOtgjQp2G1ZaKy1FoMj66buYhTByiMocDYXrZALVwBlbtMKgNg9cQQUIsZVFLsGZoAhBHWRieO9S1yRIxYAGIEZCoVnBq9NksEZkINvEWabrspi6MBKIIWxdHHGCOaREnFqq/6lJcMoDhJgjnQkeNbEpXF8bHxlegwJ8TqiKHM8SAcPhkVXIndFyEngSGcL1sRDwZmkoHoJCTciQzMJ/KWJp3O9+EzVN1OpxTkwzgJpYEjUzj2cDctd8ZlhoHu40qUrSRVAtlmATRICyBDs+fdlqoMAhGUwtItDaxCHQGGwiXzAgkQBQlJatuoqkcKSkDMn1sCIEgnKDZTc02knFQKF66AnoHGkwNHIVg6ZsbEmMLUKXKYfAO5eB/gCQjiVrWPYWgrqGkKABL7jrMIhQymMTjcJWEhwu5GqQHjWpmxXxoCIxEECAmYWHjE1cAv1zfJVwyQrCOsy7/5MCSqJTi7oENmCUpJAFO26xaqgK+PHLwLZNsBkcOX/XGdwuf/QyWWSBJmff3Ly2Mw/gmxoCFQMukwJAyVuWeY4MJKCCAAKIs2te3hwotHjuQp9iTYaABNRKoxYpNcC5StgT04gpNqgm9jSiRBUD07SnRMC9QtFQnQjLs0BwRnzU5mUy2MkKsiCX8FMsxrxUQQOaB1ITGKGTVz4V4Ed8DhXp2JHmIHgAO3aY5qkgVlEoaB+0IeuUouOYygWEnWHiERJtApuAcCWDS2KeJm4Swwj5ptEidAeCKG6HWFhNW6wLJi8FL2/Ed9ESZFdFGrkqItgO66RgDMEScliF4rttB9xzWMBrnbyMEZQtcMEGm0mPAQcwaMow4c8VquPCZYv1lQVPMzIFFQ5aHI2iLcuqyn4bQBZzyyPo3rztyjA3PiBGTNkNT4uig5YODEGSGFtxZNgMmsxlB8sk+e0sESPa2mUwMXWAk2KX8OJAXuUJfhW+I7aUW+LzJgeg24XQwsElfqEE6KMJIRR5MEqS/RJ8ebnY9bgQ3LCqgSAx0qJ2rApbMSk3IMuVgmV5c5hECcopyR2+9hwszUXFtus5/uEivLhEwvUmwrOFmclI8qvZaCFxhTcIuSKqS8K6mAeGIbUFK8L8TOxQHWbMESIUxYg+W1kx5ynwiD6DYHEf2JQ3oJLc4DXXmH0Al9iuQiyVCWJye1JrqR0QFmlCEQXAaBF5T8oV0oTYCjZBg73+rtwA9ArOIllBTQccEv1FA1LcrE2uXS4In1LgMmS5uYONJRw1SwEv4A4Fo7XByEC36BK1wLu5YmKA1GvL9deGL9gwxxBHKd7ocr3+5r3Dv2E817MIq0vaRoTEjmrkerCTidfuH/4eDnJxhuX6mpdem664eCVdNBgOB+sHRwTmWUvN9ejY5GSwTHJ5SwEMNaqE4koovLfEkkmslGvk8hG4ZLzsOwInG3p9Qa7PQ0vIqbf6ihfInUsWlNq5MT8HmpN7PWF4ARSJozZiI+HXcFo3ROMNtVH08KJEf3MxS+K6vRhMgJK5Dv14qNT7PtXwrDTRCs3X7XqheE1WqJY7DL9Xh8Ix6i1rTmhOVH1sWXRu9/yuhR38R+2/7FZUk3maArakEqU4k7kzqK42MiteHwlFk7EYiSVxRNVj9bP0iI7r62pnxWK7OinOFcLBMEoxljLJvua5SjNWDaK0SUpyfXPaFzcuamnuf0xpZUnmciWBU7m8BYPb20Yc4DpXkKlBvQ7phe2tje25A7PU+iiu1XEM16u10VpdeWh560CJnnL5eSF9eZdfBy0QN4AToz+pfHb8KPlvrNn6+47vhid/+SJZ/aUTfv6Ouw69OaV1TM8TxgI6P3yRvtO656PXO5Z3PnfhyHe2bZux+cFbH43uj947LbzWXPPu7zrWfPVp9NI3Vx3+84ufbv3gfNPQzNk7tg80PrAxsSx/Lv7kbXqLdzaxa6t6vOKWC5sHTgRf/cvfzn0289AhZfnbJy52rtl/6HjFA/jeuHmkcsedz/1k+RfugcuLJlz+a1YPTV4xpeLNWybm6s6ebp109/Gnnrr0408qBs5Our0VnVBiPx+z6WzPCxs++tbkBWfGPf3xgukff08fs82u/OFgz1hzwu5jD74RPPzyo0fvsdYf3fqbxvNT8zuO9701bd3mlXd2bv53/9SfNdWsWnYRrTz5auvhSe8uqJg47tLOGZPY99v/PuX04oNaessfDuwbSq89/2Hh+NHM7s/cApn6zn0Lz1RfOMdPvd8244t5uFJZGcSnfvHsr1+KPfLPmUN3T//fhJ8O7e7/1dwNb//ryD/a3ygMVUxPjR1X9/xTz1xa9trOtS/tXXF/9+2VytI/PdwzYcmt7ycP7rnc8Z9jQ9XH+B1btk/o+++kmtHjK06O237qRJ7/4Ctj6aLfPjKj79iHVYOr209u3DKxZ3XP6XXKls13Bd6ryWyamg28Ejnz7ftfOdh18Lb5gx/s//zzur73KqGdX389dtTTq+LTvjF21Kj/A+ZUWo4= \ No newline at end of file diff --git a/docs/cassettes/add-summary-conversation-history_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib b/docs/cassettes/add-summary-conversation-history_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib deleted file mode 100644 index 7a7d6b2b1..000000000 --- a/docs/cassettes/add-summary-conversation-history_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/add-summary-conversation-history_7094c5ab-66f8-42ff-b1c3-90c8a9468e62.msgpack.zlib b/docs/cassettes/add-summary-conversation-history_7094c5ab-66f8-42ff-b1c3-90c8a9468e62.msgpack.zlib deleted file mode 100644 index de43698e6..000000000 --- a/docs/cassettes/add-summary-conversation-history_7094c5ab-66f8-42ff-b1c3-90c8a9468e62.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/agent-handoffs_62ba5113-e972-41e6-8392-cc970d4eea72.msgpack.zlib b/docs/cassettes/agent-handoffs_62ba5113-e972-41e6-8392-cc970d4eea72.msgpack.zlib deleted file mode 100644 index 4bd93ef2e..000000000 --- a/docs/cassettes/agent-handoffs_62ba5113-e972-41e6-8392-cc970d4eea72.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/agent-handoffs_637d188c-e0d0-4c05-bb41-f007b4e17fb7.msgpack.zlib b/docs/cassettes/agent-handoffs_637d188c-e0d0-4c05-bb41-f007b4e17fb7.msgpack.zlib deleted file mode 100644 index 220e60417..000000000 --- a/docs/cassettes/agent-handoffs_637d188c-e0d0-4c05-bb41-f007b4e17fb7.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/agent-handoffs_c4ccd402-a90d-4c94-906d-6d364c274192.msgpack.zlib b/docs/cassettes/agent-handoffs_c4ccd402-a90d-4c94-906d-6d364c274192.msgpack.zlib deleted file mode 100644 index 4b0efc892..000000000 --- a/docs/cassettes/agent-handoffs_c4ccd402-a90d-4c94-906d-6d364c274192.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/agent-handoffs_f39f99b0-95c7-422f-96a6-e612fde186df.msgpack.zlib b/docs/cassettes/agent-handoffs_f39f99b0-95c7-422f-96a6-e612fde186df.msgpack.zlib deleted file mode 100644 index 7593980a3..000000000 --- a/docs/cassettes/agent-handoffs_f39f99b0-95c7-422f-96a6-e612fde186df.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/cross-thread-persistence-functional_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib b/docs/cassettes/cross-thread-persistence-functional_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib deleted file mode 100644 index 6528a965f..000000000 --- a/docs/cassettes/cross-thread-persistence-functional_c871a073-a466-46ad-aafe-2b870831057e.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/cross-thread-persistence-functional_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib b/docs/cassettes/cross-thread-persistence-functional_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib deleted file mode 100644 index 2e32efdaa..000000000 --- a/docs/cassettes/cross-thread-persistence-functional_d362350b-d730-48bd-9652-983812fd7811.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/cross-thread-persistence-functional_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib b/docs/cassettes/cross-thread-persistence-functional_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib deleted file mode 100644 index 4772c550c..000000000 --- a/docs/cassettes/cross-thread-persistence-functional_d862be40-1f8a-4057-81c4-b7bf073dc4c1.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/delete-messages_3975f34c-c243-40ea-b9d2-424d50a48dc9.msgpack.zlib b/docs/cassettes/delete-messages_3975f34c-c243-40ea-b9d2-424d50a48dc9.msgpack.zlib deleted file mode 100644 index 3a03a970c..000000000 --- a/docs/cassettes/delete-messages_3975f34c-c243-40ea-b9d2-424d50a48dc9.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/delete-messages_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib b/docs/cassettes/delete-messages_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib deleted file mode 100644 index 19a5b7835..000000000 --- a/docs/cassettes/delete-messages_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNrtVH1sE2UY35wgBkTQZQRh46xDCOzaXtu13SLMrWNStrqtnWgFxLd3b3u3tnfH3XWsQyCU8TGHzJsONyEat67VZsAWUIJjY3OQKUGMQY0DYtAwNChIwiYfAefbfcAW8A8T/UPj/fXe8/08v+f5BcIlUBAZjo1tYlgJCoCU0I9YHQgLcJUPilJ5yAslmqOCBfm2ogafwPTMpiWJF9NVKsAzSsBKtMDxDKkkOa+qhFB5oSgCFxSDDo7y9whrFF5QulLi3JAVFekYodboUjDFiBGSLFujEDgPRC+FT4SCAmlJDlXCSlERzTyOmed4MQfnUKxdEfXkKOiJakgP8FEQ1+I0YNw+XIMCq7Vqg2JtmIaAQj1VBWlOlOSWu6rcC0gS8hIOWZKjGNYl73aVMXwKRkGnB0gwgtKzcHAMcsQNIY8DD1MCQ0NecjPgeQ9DgqheVSxybNNwubjk5+Hd6ki0Kxw1y0rygcyROlQFfjRUFlMrtTqlprkUFyXAsB40FtwDUEkhflDfOlrBA9KN4uDDgMmhIec9o204UW60ADLfNiYkEEhabgSCV6/bN1ou+FiJ8UI5bCq4O92w8k46rZIglGktYwKLfpaUG53AI8KW20O+7RJBqGhxtR5XE3tGpuSBrEui5QaC0L0vQJFHywY3hlBIyScGgggRePzT8PB+1OfnjqC5LZiNsJHbimhfCqbRYzbIY1HMMUKbrjWkq3XYM5aiJtNwkqJ7QtFSJABWdCI4Fo1AHyZpH+uGVMR0T9Ajw0eAM5R8CL1Xqoms7FKryc35AWmhsrJ9VpeQWpZLfFiKkx7OR+ESuiCIDzZbKsk9mEanh4TekZZmBEadg9AYtUYCOgzQQekJvdqpayhhgBwhlATm4jiXB+415eAmQNIQtw2ORA5n25/NtJhNTS/gVs7BSSJeBFxykOVYGLJBAY1ajgymRssrwBByt2ba5f1GMk0LUg1OAwU0evTAFz1vbR4Zz+32g9HNH7zUDQgCAYmOXJ9VOSFm8IvLqyrM7Xp6SvnAsTRV+/LZlk0X2iYEvg3Ed04rTF4u5s4o69l9cIH7oeu/VkfOnuw4oN2XV/Vkx3uWnZHahbP6KtpfSjrdvOLzrv7uW103WN+4iQsuMVLhknWm5p+St3eEv0rub2qmZxeUmxLXTtbVWT5q7+k1299862hTbVd9wlLHpjUXBx6rWdj9i3lmQnxD7TL7u3WN78zpslhyju7PLt5erTqeNTn0m2fH+R/7F7+25HL3jElcghmu9J17Qz1zq6nxIHkz6ZE21w9vnzV203K+e3nV5qv2+TWJqwI7dyRU92fMqwTXxsfEDAzExXzWkv7N/NiYmL+H8k7Fjvs7OS8Fu2MLRJFBh4Ksxjoshh4Ph2VxDuQnzRExliEhJnGYF0IJ83M+JbaYW42RgMXM2FCMqBRZUMCfMTbFPcpZTYNoUK8fY4EXZvxPw/8pGtboiX8lDRN5Rrup0MHbeGgo03MOv4vKA0v/lIZ1iG6h1ml0Oim1AWgIrT5VnWZwUEa106iFqY5/loaNBGHUqP8SDfePpuHMKA1vGjimmaaaYT8ZaDactnXavty4tTx1emtudZ1Ou8ya9XtrcF5p2eXvriYdmm6NSypLe+4SyMi7mLu99VbfjV26I1d6r0mv3D+xLJFvLEjeNSVl25ndOVPM9RviU/rOvPxA0gXlufGVlqmmYrHwY+FnPbvig7p4c+fhL9ZXvnryVFvFFsOJnKzi4zVX6Ll9dHVt4voXn/Doxrc92jB1ff3Giu8D5yu7aw5v6e0KzH34662ZtR1xVhuT9OC6uE4xJzL1qd49+17nuJuTKjY31QiVyWcPnLjPdYurYe3tsUMU3Gf6ZFKUgv8AZIo4lA== \ No newline at end of file diff --git a/docs/cassettes/manage-conversation-history_52468ebb-4b23-45ac-a98e-b4439f37740a.msgpack.zlib b/docs/cassettes/manage-conversation-history_52468ebb-4b23-45ac-a98e-b4439f37740a.msgpack.zlib deleted file mode 100644 index 1827ef0c9..000000000 --- a/docs/cassettes/manage-conversation-history_52468ebb-4b23-45ac-a98e-b4439f37740a.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/manage-conversation-history_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib b/docs/cassettes/manage-conversation-history_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib deleted file mode 100644 index 325f25c47..000000000 --- a/docs/cassettes/manage-conversation-history_57b27553-21be-43e5-ac48-d1d0a3aa0dca.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/multi-agent-multi-turn-convo-functional_2b6fde57-86e3-440e-a7bf-f1e9b5ed9ff2.msgpack.zlib b/docs/cassettes/multi-agent-multi-turn-convo-functional_2b6fde57-86e3-440e-a7bf-f1e9b5ed9ff2.msgpack.zlib deleted file mode 100644 index 0c836d93e..000000000 --- a/docs/cassettes/multi-agent-multi-turn-convo-functional_2b6fde57-86e3-440e-a7bf-f1e9b5ed9ff2.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/multi-agent-multi-turn-convo_161e0cf1-d13a-4026-8f89-bdab67d1ad4d.msgpack.zlib b/docs/cassettes/multi-agent-multi-turn-convo_161e0cf1-d13a-4026-8f89-bdab67d1ad4d.msgpack.zlib deleted file mode 100644 index 4e2e0614d..000000000 --- a/docs/cassettes/multi-agent-multi-turn-convo_161e0cf1-d13a-4026-8f89-bdab67d1ad4d.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/multi-agent-network-functional_29b47c57-ad05-4f10-83bf-c3ff6ff8eb93.msgpack.zlib b/docs/cassettes/multi-agent-network-functional_29b47c57-ad05-4f10-83bf-c3ff6ff8eb93.msgpack.zlib deleted file mode 100644 index 0c8672f04..000000000 --- a/docs/cassettes/multi-agent-network-functional_29b47c57-ad05-4f10-83bf-c3ff6ff8eb93.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNrtWnlAE9f2RsGnVESLC60bY0AQISGEzeBShSIKIsiihKU4ZG7IyGQmzkxY64qoqFVSsEWp1SqLRdqCqLVSUNyrYrW2BWoVaMUNsVoVtSq+O0MQFLTan/5e3yv8Q2bmnnu/c849d873JQtzYwDN4BTZJR8nWUCjchZeMOkLc2kwWwMYdlGOCrBKCsvy8w0I3KSh8arhSpZVM652dqgaF6Ekq6QpNS4XySmVXYy9nQowDBoFmKxICov/Sd8gUaBC4yJYKhqQjMAVsRdLHG0RQcsoeCc0UUBTBICfBBoG0AL4VE5BKCTL3cKRWJQkUSSKQhhKBWKVgAbwFq1CcBJhlQCRozQeGQlQUoRAFNEIRQIEg7hxEuU8QVASQ6LwGICoAKKkWEAgNIBQVYDE+AGMYE44B4jCAMEtKCdQDQaEDkInIUORJGCFBMrC+ThcTDzDAhU3SkZpEBQigcAACaNGICyNxsDJQZwa0CxEhrIQGtm6WMuANtgYZAQQRYkQOaUhWRoHjC0ix1n+P2Dl1iJksgKJhwuRAGAdY7dFUCYaseKfRaBYDM5QtBWioGhECQi1COFg+gQFBMJgyQnoFqLUqFBSSAMUQyMJAKdj1HAagEQCaAQ4jCSjADSNk1EIS8HgUTDGNAJTRbIiLgQsRRG6rJGois9aFGAjmp2LeDK00AD6K6dxNXfNDfYE7BNO8HA7CA5njJNqDRvByJVAhULrRIEa7jUYX5zfOYlzOEDxah4FFTkLyFnBHHivFVqLP3D/RTwWpA6QTYCRbA6ybkyz163R/KuAwufkKmHAYZmtylJSDKstbFc4X6ByOVCzQkDKKQzGXvtZVAKutoXxUHC7L0/O7US+MrV50QCohSgBt3ROs5W2AFWrCVzOh81uFty1+boCEnJY2j/O4+pMyHun/XJCCw47v3hY5yQiFjk4iiQFcUKGRXGSgIUKKwBCylHzz4vbPlCj8mg4j1B3hmhzmo0/bzuGYrTZPqjcN+CxKVFartRmwzp2dixqe5+GpYCrgDbX3a/9crqHrcs5iOztRdLCxyZm4km5NluBEgwofBTkRyZ5ErHEQSh2FortP2+JEgHIKFap3eTiItncUhFJOXBKVsMszIIZAccO5+pOrI2+3i3ZPKtnmvU2zI62ZAbAbBGJBPGCBQ/nd0IkDq4ODq5OUsTTJzDfXbdMYIfJKAzU7VGhR0vyc+VKDRkNsDz3DtNeJWh1i4brE7gKZ4W64xomi7vUZjmKxeIqy2eOpOEmxkluxSwHqVT6J/PCyABWu43zDwZPKJEE6rx0Cel4Hb5WhM0nvw5VDocK4hr5p+NbsbXYWD6HzVMQSkOqrDqypjRsO4jZo/jVbP58fCtEnY3V89g8HSLSkfkT4WteyOIZI9sGrnk08szRT8WTp8u8EMe0X8PPEWL7QIYK8tOQ9gp0ogbFgx2lSixONnVTDI5q8+xF9vAlTUUR4Av3iUJ3FB6RwgC+hLS5b8umTvCZ7J4fLPSnIim4lwJRuOdI+KrOCQA0LE1tnpygNBg87GiQA839J8i026RiZwcn1F6OYmJnuYNDpNBjhn9BSzE9KpYs7qTkm40FsGS5F9eBLvFmy3vo8X/6mNbX92dxnwO7jyhFJdi095M/XzuoZ2Bejf+t8VsW2lJjqnrVH7Nt3FmQ//sZm+7DmtbZfpv42+1z17skLullPFt1JG9XU8zJ8vUD3gr6zddVGkH6PiSibf1ujz4iWnbyc8OeRr/c2HOw0nN7fnANsnKMc2VC5uDy80Vpsn6K72ThPx4KkkX52eTvX1Zeva9n4CX7Q7mbyswivl7S6+6QK8MnVBTp9+ztbKRWuO8O0QJ1v+1RW0rEwTEbBkUGp7mlL5hp7jW063aJ0X5yq8dFC+yXk72qr/W3NjIIN9tYev6s/1vZSUaI9fx/3Vs1ZtSWGGA+pDb463Fv78/sdyMhZ935RAm49eBq/f1Lpg9Kf4o4eKoBaHaEvVMxZMDhmMNfOX0af35t75I1+4uzKgcfvL5jz+atDguIfnOrXQy1V/vO9q5U/166x/FBEBOneGO1cPb+83GFIwq2NyyeMkg5UvLbkLrlQw/v+natxZzRsvRf75jp6T18qK+30WaSdmJXPb2X1DZ26/Jf0DZyjUYLBJRhcPjCINnHcUCQLIjjEU22Igi+j+BbOgUO50ebEbm3QGkHAAIlYYPJ8j50DINvT+CMojAyjJwCh8KBCpxm2Fa7trO2s6YpFUJpWhswlEUjUQY093q6ToZ3gXf30R3YBUbAsHOjnq8N5A/qlhYJx1om0cBTZeIsZ4eEABA8Jd6bmRDtbe/u5jZDooBt+WMRbp/k0CfwwLNMQzyRAAGroaMZPphyFJdTTEsPy6GPeC4cHF4mAvbEsGt0Rfi+AkLr5AydnKGTM/zjOUOWvWSU/UskDY6uYsk/gjRIXzFpcHCx/7+QBpgHx785aeC2yqsgDU72f4008Hg6IA3S2V7RmgAPOROZEBgX6xIdw8TIJzGvljRIXBSog+SFSENXZStp0OOaWizAZ9UgF6MHNvmikhWmjTnRG8a5eiwUeGgNQhGlv9FOk4aTIe6uFnWyqNqH7yidl1s0pJi8NdTs1uZDqQGVi042PqA1N+bOmXp73oHqcxWn9pm+E7V9d3Wpcfi1G9qQAWtqP3YzDfRiNsicPRtPJE8zWV1gWDjTZ1tc4U5ZhjjN7vMPK3bnf1BR8UnPaZUpY4lx48YluY7d9nsVsXfAeyY99sny3ARHvQr6dltkqFn04ea7V1emhh5z2BRVazy3e/aIXyd9VLPjcpmetMz72LQrVjuHbC0bgt76eku3HWvHntabmlfl8W1qL2Pbvt+u2zooY8b5Y4kZi69sK1gc4/lG963GGz8uL7SNHBZ4LW/9Fsw848TkzzJD1xtqPvGXjr3+cY85SMnCimXamcujKp3HHDaigqZKXz+0Ijlfm7K3AU0p+WiCtne6nmft2DvjxSkf3GQyD99f80P/n40Nql6jJalnVva7OMzfer8xPWZZQt2VNcTQ73LGrFxze8gby4duPnYh3bfowJodaQu3u9XXBOd1Wehf1t2r+pv545YN6e6/64/96+/4rnEdcU7sn7nQOiHNJOeKvuPk7rNHzr+U7tMvbKavsaX5giHW58NXzi+cbI3/2JhZcONWyoN5w0tf+/DqabeU9NKQ0FPxX54uaTz6w5KRZu+cWX/2XGx9psvdVfcadoaX/GGya8+o45plxOjvzmavlzVGyJyRcdN7Zx46WrdelHG0cIZb36bCM4PFf4SlmCf3qvDf5XfBrij+3b0Xw433D3B2qTcNX+pTPG5kedGttxS263/1ymgyS7tcnTi9vq7udzu9Zo5085v3px3Xf2kcybBrJ0fq5Eh/Z470Ysl3gyHF4B7jMkVzCcHhduQy96wtYItMbkOXAh854s47MgwJVOIMJCqohsUVGgJxoyFXYpQIy9EVlqLjEfg4mqRimxkFzjIIw2pI7k2IxCpxFggZbjY4AXwzcVSLhmwOJYRyAqBwP2jo2RoKZ7iqgTNyzAoOjoePhDSkZ1gz7liAcnxIhHjSqBwgbmg84sbNx1WZH03F4Bjs4HEUNqIcGBgaLlAwOkQ8Aps82NEhqIriqBWsyFiKJjArziO4eXWoRNBJAE1hw40xCKWAXSFklHJAEBwTodRqioYu8RyRd5KJxVUq6KAtwpAUHQ1f7dxnDI/h/6M8bOgNwnCG0Cc1oYExhVEm0DiAtUkDyqooRs2dGnxhTaVibRGiubp03IMv41icVfLl8zhRgkzxUfUxaiDHFbgcgeQEppLCnlKI0OzJFP+FInwmwXtGDQZrqOCJs2K88WnOTt74lFluKjf7iQkvqQYDNJCXMQzcpDDvjyg1jDeM02OBe0ZxPgXgKxAwmhE9qVuom3fzMw5hlH9fPFbBTygW3OHPvWx4MaE9wdeJF7oztL168f8mXjRvnOfTLl4sHs8hGQgIqpkM8heA1HDpCRWgtCYS5TE/eaCHtymS5n6XFz0EXCMCj1mMN380afiLSCSPp+IpGokuk50iyT9TJJE4iJ1frkji+L8vkjTz+1crkkid/vdFEsdXIZK4OP1lkcSxI5HEycdd4qFgWK/p6inB/nJPqaf79ATpqxVJHFCnURLpi32z6tXmm9XUCN+94n4Hdnsx64uxKX2uZJbtNx0+6+2kg47ZxYPSmt6sF77+TWlxVQ+Tm59eGnuh6Th+268O2bPYPyfp9JeEffFd0eXfmeLMH0+/6fPxefOa8cUDR5su3uBlYPyey5nxyX7d/FfOT7olHdhnw3vLpJam34wwPCvNsvAuqkXKJTUbSsxZg1/mzFtkMldT/2BYjXGKDBtu0vOsIDTebd/A78+GsF9tPFK857XqgguV+foBoqiAINzMYNt9g1tnD7+xK+/BvV2J6ZdqNFu/Mtu9YuiS5ZFVtg0/nPsDfefcnjLr0w2rJ21dlT5PMDp1i/mCyqTru8xifq422WXXRXWvbFjqFyBp5OAxuaKSPuq+J3GD2o32gyMf5kbO65F6ruJi16XX61KTpick+7tUdj/CeCZ8Pyjw7rxyT9cL2xt662SAzTtDs692eWkywGtlnTJApwzQKQN0ygCdMkCnDPDCMsCLFafu1HyOc/bJBLn+tVPyqTT7UYLacuH2R1j79M0YNdvHZbrTNEeZIpKOVElHTfALUmAvKX2hYYLW8nYnNJFhcECYwN3XxxfxQ2HoWRiO+DBB+DPS9xSAnSpOp4rTqeJ0qjj/QRXHxcnh5ao4Lv8IFcfx7/37eC4Pf38Vx+Xv9Pt4Hk8HKo6L0j/EHXPyVk/0CgkCMnqKBx7jNOPVqjiOjijm7PhiP3VZ1EbFSTuz8vREo+SI5IzoqoJ12OnLOeNXNH3S633LnhbjA974fmnI60O1l1PlXxRWxtpNrO/m3LBa733m/EfU5iV75ij3YbFLyhtv+f42rvSu/P6No71X3IlvOrN78LzSqsWWd0COq4cizvMTQ1mAcMObmZvilHuzxmafWJxRcHNbwvaEIkn/YRENzsUVp8tJ07V9gj7a736vYl/R5lNzxpa++9M1G9D1mMHc6RvuTbLWjlpxOX18VFR//QE7hXeV87/bN1Satz2ibgtRcc374KRrA+wKfLOja2OwpMCr3qXjLU9d8es58OSn3ftf09bkS29t6WIlbHSrFaKDK65lJhnrA/0pOEhepyf/Hv9uqKl7rynDpd+m7Dk+xsc2VrzFMlqvTEEM2DTR6kjGhqhP9SvE0TuHXErevumibOYJoys7+gSfFy+YNm52lkf08TGvsz/UpAbdt359S77NkjMDG3+rLlnSO6PI9cp1utuE2/b9f+0btKCva5fQvISKe19IbdIGKkMsz62pDljqMQHUSvokfIMFHf+oblZK/leS9wzLa6ZYG64pm6/tOzqtyx9ph3zNp55ZalhrHm9508Z23aGRd29OLSwoPDFPhq7ADoYLLormX5tVtDZ4WV92mfGaxIXD6g3Mtn680yplRQqB3pR5X67d2M3EzNCy3MA54NwC8wKjtbndRszMPbCg0vPIBvdk+er1x9M/tFhbe/+zjIof1gWsDhsQWxXcL9yiMeOr+h7dEvKOfRA612jVPJeysAvulo6rT/zr/aaa4d47nVc0WVto3WyGZ1um10UQZl2Pht2vSbAoPDF3HnNqUXBEbR8b3+nSd0cXxl+N2tv0cKywaevWB+SNO3dafgYzPqRiqZWBnt6/AXIQa2I= \ No newline at end of file diff --git a/docs/cassettes/multi-agent-network_26a0d4df-ff99-40f0-92a8-0b3f2c591040.msgpack.zlib b/docs/cassettes/multi-agent-network_26a0d4df-ff99-40f0-92a8-0b3f2c591040.msgpack.zlib deleted file mode 100644 index e225c1250..000000000 --- a/docs/cassettes/multi-agent-network_26a0d4df-ff99-40f0-92a8-0b3f2c591040.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/multi-agent-network_29b47c57-ad05-4f10-83bf-c3ff6ff8eb93.msgpack.zlib b/docs/cassettes/multi-agent-network_29b47c57-ad05-4f10-83bf-c3ff6ff8eb93.msgpack.zlib deleted file mode 100644 index b0d9e9264..000000000 --- a/docs/cassettes/multi-agent-network_29b47c57-ad05-4f10-83bf-c3ff6ff8eb93.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/multi-agent-network_68a547d4-0a15-43bd-aeed-c9ba1dfe388f.msgpack.zlib b/docs/cassettes/multi-agent-network_68a547d4-0a15-43bd-aeed-c9ba1dfe388f.msgpack.zlib deleted file mode 100644 index a10bdaf46..000000000 --- a/docs/cassettes/multi-agent-network_68a547d4-0a15-43bd-aeed-c9ba1dfe388f.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/pass-config-to-tools_14.msgpack.zlib b/docs/cassettes/pass-config-to-tools_14.msgpack.zlib deleted file mode 100644 index 3362c58b5..000000000 --- a/docs/cassettes/pass-config-to-tools_14.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/pass-config-to-tools_15.msgpack.zlib b/docs/cassettes/pass-config-to-tools_15.msgpack.zlib deleted file mode 100644 index cc9ce3d38..000000000 --- a/docs/cassettes/pass-config-to-tools_15.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/pass-config-to-tools_16.msgpack.zlib b/docs/cassettes/pass-config-to-tools_16.msgpack.zlib deleted file mode 100644 index a630974f8..000000000 --- a/docs/cassettes/pass-config-to-tools_16.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/pass-run-time-values-to-tools_2e3fd1e2-cc19-4023-8ffa-b0fc13da9e09.msgpack.zlib b/docs/cassettes/pass-run-time-values-to-tools_2e3fd1e2-cc19-4023-8ffa-b0fc13da9e09.msgpack.zlib deleted file mode 100644 index 9f2ff8fbb..000000000 --- a/docs/cassettes/pass-run-time-values-to-tools_2e3fd1e2-cc19-4023-8ffa-b0fc13da9e09.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNrtVnlwE9cZN5BylHFKw5EEEliUMKbglXd1WqZukC9ssJHxBQg7YrX7JC1e7a73sCUbwYTYMRBKWAihgXAbG4wxR8wZIDRcBh+QTGvCkQBJGww0QElIIIXQt7IM9pB00hn6R9vsjLR67/u9736ffrOqCoEg0hzbpYZmJSAQpAQX4sJZVQIokIEolVZ6geThqIp0W2bWWlmgT4/wSBIvxkRFETyt5XjAErSW5LxRhXgU6SGkKPibZ0BQTYWTo/xnupSXaLxAFAk3EDUxyJQSDclBW6wEF5oieCRCRCQPQBhCggYRFhSJCOHkZAlJ4rg4QtBEIhqBY4AKl0UgaAJ5cMfLUYBRt9y8hBo4FcTCJQ7foiQAwgsXLoIRAdyQgJeHsUmyoCrBtJi6x3FMyB3JzweVu2Q2GL6q68HvGKREwxLeIMANJEfQd5+kYiggkgLNh2CaMUBCBMCAQoKVkBAMcXECQrBiERBo1h0MM5hWeESrquAJAeqGiReDhngBJlSQaNC2bIcGF+1ewuigKk0goKYFFokWAKXG8RCtpqcdzTmnAVKC6EBeoMoDCAqa+jSsT4WHEyWltnMJNxMkCWA2AUtyFLShbHIX03wkQgGXWptqGBMLgllRqvMB4FGCoQtBZdspZQvB8wxNEqo8aprIsTWhMqOqL4+Kq9VaorApWEmps0EnrClR6X7YayyCa42YFt/iQ0WJoFkG9g7KENCfSj4of6+jgCfIfKgEDfWxUtl2uLYjhhOVdWkEacvspJIQSI+yjhC8JsO7HfcFmZVoL1Cq4tMfNRcSPjSn1+K41rK1k2LRz5LKumD37ex0GEiCHyU5qENZjVWSHJdPA+X0TYeDdDmc3lhPZqYn2WHV+T2cP4EqYBx+X463wOwcp/U7xkTHTy6m7TY5LS0jqTgfxc26aMxs1Fv0KK6FAWtxVHTqJ6a6ea6AK84WxGnFOTkp8SaGMOlkMm2ygS10S6LOPX6S0zA2dVym11rE0zJmdmhTcVcWqYtOZfKTMwqyaf80q99niEvPxlyZXLK1aBQCvZMLaSrWaPelJxXYOHKaz0lhObZsz8QcyhWdjQvpcobe4/IlStGeOB2GJ2Ed3NOZDSgW8tCEGaIx9alt7w0GsG7Jo6zVW/D1AhB5ODXAq5UwZZIszqqAfQga66tC02ONbdzDFu5fkQB7UtmXJNCRCGZAbKSE6DCdAX7FGE0xehMyJi2rJj5kJusHW3BrlgDvpgu2YWJ7y1eRHpnNB1R1/A82+z612WElVffhTEKBj+dEgIa8UmomoRltcxNNSXi37WahnOAmWLo4aFbZoDYynJM0WxcSwzuvqoTGUa+orDWYsdqQpL3HqmFcMKMYiuG71dtPwiulOs5zgoSKgIRTWfIrpyO9hE+9T7F63Kg3wSSPQmiWZGQKZMrOBM4LbYqjEB6OKI6g9vhQOBABQ3tpWITgd2jiw7uCqyXa9ShC4vIBKyrr9Vjbs78jRACqBTWMB4oqLPDZ+8Ogdl06FWMx6/d0homgg0NrTV5x16PykIo1mFjjawejNKWcfhEuHC4LriMpl4kALtLgwgxOEtPhGOUymy0W+DZujk9C4wnSA9DMYLcpVQmTx1vTUuJ3TEI7tg1qC054KGc5kaVdrspMIMDSKNUkw8kUHI0CqIS6MqyTlbpokorGDUajCegNmIvQo4kTM7a0a3vQZBXqXA3+Ob5S2TbOD3c5M+T1nmHBpxv83L/PZDSwZ7E+e6+OnB07pexuek1rC9I81DOhLnyuQR6a/qcrRGZFXO2CJ167H3vy4MLPJvWY9fGHjX9rvnkB657YdWg3RXwKDPtk87K8bSV1M69du4cMWPb+UufdwHYHN9jRcp5owaS98daIlqdXN4zV9LfLW7D6XoP+fKf41778mf4vd47e0PfNcHRjfR5ddBHNqX1616fZtkZ56Mm4+u8t8/BCz4nKxMUXRpY2Lls+Ypi9QV/K356DY3ZT/wstA97apfnD71ednJtuzNtoP95rtL0hmf/NmM+vjUq9Ro7PPV5/9vwp26ebAs1DVpiOHYw6cXf4+5dX/mOOI+Jezvbwddufiv9d3+nry92uea98BhqaFqzZ8e3EmLX67ucoec7cpS0Xt5RdGuh9YVcZ33thX7vzl47Iz7fWzvmEDhxsGjD/hrW1NXfP/ZUUhW1ClwR8gXvRTPyVGl3MDvfFOPv6D75QrOzZoVWTR0XsbOlx5VdXS4+3blsz++vB2S9cjRo14ZkhZ3s2vzr4xbTc+bduTS+0omMX+D5kS3xTZ73+3CLlsmVRl5dKXl7Y+lpk1jcphy8vPrB/8ge6sb0Xr96Q+uH+pOSNPQO5eSeWPBP5R0vM9WABu4Vdvbvuq7dgNR8nmer60eMmU5FIRx2szDAdIAQcTHAYs0G+o1ImB0kw/4o30SoX0aggB5Y/VrZjCWKBJ8ueSGVlYILNm8pNyP+p9IoQ3LIXeqVa05TkPuA3uXCdq/mxAHM1AY1KdjqHpWkTImo+CdaPFBEipGYySwEKDkn4n4FbOmZGjbRTxI6fEtfPvPRnXvozL/3f4qVmne6x8lID/t/JSyuMBr35/5CYmh4/MdWRgDKbMRNhMhIGgw4jcb3RZDFbjEYdpqcs0f9JYmrBLdG6f4+YLn9ITJkJ1jZO2n/KinWjF3456Rv0FxmrYiuWDLb3KzuQPvJt02Gwu1/uCzfO9z4+96/I7hvYwbeXnw6khJWyhwaUnjm2qti9rfxoQLw9oT5i+kfnTx0NGGtmzBBnDpmZ3f+l2YYRrf43RuytvtbvVvPUk1RU3c3h3ZJOOfNy7hRv//jcGwm28KXDr+bWv/XmYv/uxpsjGq5HXJxfFzdgyu3lYWF753HzPIPuRuxYULU5+Y3GbfFb983o2mdFakIp1fJcRbhmeUqiadXzmTOHfhcZe+jcRysuDH/WPpB5NdzTG7zMXLuQ3zti4AGN6eSiMVPLx+60d/HfWH+y+xbfX/q9Yz3Ws3u3r3v2GHfUtlOM3dGtYdLZJ4+k3r5jP5R+6bexXx1y/D1nStN7Z9ZS23BDD8FJneh1YGUBcXDZ8z0vbSha/aQ0elD4xivOiC96N1G7l9aPti59Nmpu4nev5H0ydcGZG01HyhZOK2+KbFq0jL1ePoMquFzl/bZ52NvvPLEyeqpj55nC1uWnlgzaUXukv9Z8uOvGsuTmYzND3PJG2fcjGruGhf0TwS28Tw== \ No newline at end of file diff --git a/docs/cassettes/pass-run-time-values-to-tools_c0858273-10f2-45c4-a922-b11321ac3fae.msgpack.zlib b/docs/cassettes/pass-run-time-values-to-tools_c0858273-10f2-45c4-a922-b11321ac3fae.msgpack.zlib deleted file mode 100644 index 5cf7c3901..000000000 --- a/docs/cassettes/pass-run-time-values-to-tools_c0858273-10f2-45c4-a922-b11321ac3fae.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/pass-run-time-values-to-tools_d683986f-faf4-4724-a13f-bac39ea9bafe.msgpack.zlib b/docs/cassettes/pass-run-time-values-to-tools_d683986f-faf4-4724-a13f-bac39ea9bafe.msgpack.zlib deleted file mode 100644 index 339d0b1ad..000000000 --- a/docs/cassettes/pass-run-time-values-to-tools_d683986f-faf4-4724-a13f-bac39ea9bafe.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib b/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib deleted file mode 100644 index 615498036..000000000 --- a/docs/cassettes/persistence_08ae8246-11d5-40e1-8567-361e5bef8917.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNqFVF1sFFUUbukLiUSxYHzTy4ISsXd3Zn9adok2sFRoa3/srvIXbO7euduZ7sy9w8ydtluCxEWURE0zPhAh8YVud2Wt0KYoEktCtIk/ISH481Ax1mBC0Gqij5KYeme7S0EanKeZe75zzne+78zNFQeIZWuM1o5rlBMLYS4+bDdXtMgBh9j8tYJBuMqUfHdXIjnqWNrsEyrnph0LBJCp+RHlqsVMDfsxMwIDcsAgto36iJ1PMSX7Q+2ugz4DDfVyliHU9sWALAXDDcBXRYmTfQd9FtOJePM5NrF8IoqZoEK5d6Rq60DrRgOkWMp3qAEsYZFtazYX7f+TsJPoOgPbWErk8Y02oBomgDNgEMJBljl+sJMNAowoaAWLNbxTgVBQthm02oCrxCIA0SxXNdoHbJNgLa1hD7VRAbqWKZfDKuIApZjDAbM8NCir5WlXrqeiAdJ8N+NlphsUVQRHIwsoMjz8fk8bphDdi2IdOQqBIRiBNqOUcBgU6kmNQcl3qKgSpAjnRvIqs7k7eY8XZxHGxOSQUMwUMYj7Yd+wZjYAhaR1xEkJexXLZrulDCEmRLo2QAqLWe4EMk1dw8iLB/pF9/EKa8izJrk3XPKGg8JRyt3zW6s8At1CREaB5A+F/cGJISgM06guvIc6EpQKZjn+6Z0BE+GMqAMra+kWFpPP3IlhtjvWgXBX4q6SyMKqO4YsozE8dee55VCuGcQtxrvvbVcJLrUL+WXZH528q7CdpdgdSyPdJpO3Rb6dUhKuhKDUCCX5TFUlndA+rrqjoXDofYvYplgLcqQgSnLHzuWFI+Tyl8XKT3Cqq73q5k819fntwh33YlJ1GoAUAl2YA891IEdjITkmXnZ0JMfjlTbJZc2YTFqI2mlhSEvV/CJWHZohSim+rO2zvqWxLNFf1wyNw8oNIMzyPt18WJKk2Sfvi7SIIVTzOuZD0Wj0f+oKZQh3z3nzQVmCUii5OGUkvHcWLJe5eI1U+BQ8PoLRhvsgl/hU0eC+6OX5BMN7SxXSUFPcafHeK8md0eQLmWRkIMl3tynb2ox+pTPe0v/REMQ6cxTIxV1KYHkhhrg7C4JNJBVRpFRjWsLiSQUlWUqhSDooNwXDBKdHBzTklmS/DPoY69PJ2fhzMI6wSmCivDZucfuezq0drfHx3bCHpZjQL4mEzpRRUkgQS6yjWyq3Fj+4RQoivWfrHvfcZozTERRMESUSltLRKGzZ1TNRXaDbC5L3bofynf2qWFNLHM38+fibK2vKT93zI+3tM9Laowttm+eTMeexd97LTZnrph5e69Zfm1/dwWIXmn7uvjU3diT3Qd1c9tKJ1cObV1n6/Pd/fPvrhS2/06GmZ7+mhz956O255kvbrqyHT9X/tSPX0nmg9uUNx4Zf2r3qdHHlG/5b3ySc/cam1sv5FxNN88PXvpu4Wf/05GcXOw+Pts21/+N7MHBa+fwVsGbmx7HBzPS79qYbU8dOXjqZ6I399ujxo9e/eORG0wNXwx+fmN7wet2Buf6v3uqN30we25L7pX605cK0uWbFSMu+jt6ZFedn9+ZPLVztf+ZKsxhtYaGuJnz9+N/ra2tq/gUe9MBC \ No newline at end of file diff --git a/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib b/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib deleted file mode 100644 index 0d1358369..000000000 --- a/docs/cassettes/persistence_273d56a8-f40f-4a51-a27f-7c6bb2bda0ba.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNqFVH1sE2UcLrBMFCKCDqdGOI4pCLv2rtd1vRFdujIRWNnoytcQxrvr2/bY9e64u3bdGEw2iEQwcBEMLirOdS3UCvsA0eDix1SMkQASDGXLkCVgjDMBxUlExLddy0dY8P567/f5/J7n976NkQCUFU4URsU4QYUyYFX0o2iNERmu80NF3Rz2QdUrukJlpeXOVr/MxZ/xqqqkFBgMQOL0QFC9sihxrJ4VfYYAZfBBRQEeqISqRFdtvH497gPBSlWshoKCF2AUaTTlYng6CFlWrsdlkYfohPsVKOPIy4oIiaAmTDVeoM5QME7BfLWYAHywEN+wKlFAdEE+EcDywO+CBE3kEYooCFAljKgFaTaS+IaIFwIXmm5HyCsqqtZxD96DgGWhpBJQYEUXJ3i0Dz11nJSLuaCbByqMsomKSUK0aDWEEgF4LgDDw1laO5AknmNBwm9Yi7rHUsAJtVaC97qjifkINLagakesaRyGslpEr4CRetqkN7YHCUUFnMAjgggeIEhhKek/eqdDAmw1qkOkpNPCw8kH7owRFa3NDtjS8rtKApn1am1A9plNXXfaZb+gcj6oRWxl97ZLOW+3o/UUpWc67iqs1Aqs1uYGvAI7bpF8KyWKVKEJ0kyQ1IE0SzwUPKpXa6WMpn0yVCS0drApjEqqfqUxhBSB338bSW3K+6UL02r26yaF5iJ1tG6n15+LkTRWyqpYQnWMYgpoqsBoxubZnTFbqo1zRDE6nDIQFDcSpDgtfoT1+oVq6IraRpQ9jt8eS0b9ec7HqUTqliCxEr9ayESSZPzZ+0bK0IdYS3QM0QzD/E9dxAxUtUOJ+QiKJEjaOTxlnqkijo2UOXzXUnjCCTwIUc59Im/jSUdj940eGY/RXBFNgSY4l/YpOleSFEU7A3Vw4TpOXLTA5mAsRUyANZsPBwmWF/0uQkXvDSSSCxFUtThGUab8qiqKNrnNbqMpn2bcbjqftsAqi4lmjKyrNcABLUrpKcwjih4eHrS9SNgA64VEeXJttMjcFYus9vm22HLCIVaJiD8nQDwLogDD5VBG66hFk63RBZdhGKU7rCu0QxaWdecBI7RYXBTpZhiieJmjPb1AtxYklHgdku/aJrSmMjJ9Papz6raxuuQ3pt5hF3vJ8TdmZxi6Z1qbheILK8dd3dkr9BrHb8JPfVT2llo8a//jVz+bEChYc3Rw7ta6qfUZhj242eKtOdu38VREPBYZ+jXnutDQ37DjL1D3zskW+/TjMx1/Pt3Sg9cKwTOhS/GTFzDNaM7uPKgtrfngxOwsd+eZQNeNQ5+cF06CR8xVPZeOXdyx71RvSeWCpjmXW12//GCQpVjmnK1f5md2F0689shLWSWf/5ExPStr6IlJRxyZ4vzsfxZHv8g5Yx3YWV3Sd/zE6MEHKnpaGz3BPutQ35LzE3Objja8Hptx+diuN+xdK1/76s1zD4ZeaX7s7701A3sWPbd0b8usrFU9XROez7jwaFY3XrPsqbzKkhYi1N2kdG6cvKeL2FbXFZfes36X4dNGfVMUyVkyrWPxFTD5dN7gOWbAvvnt1WMzmz0HFvxknffQfjuYP+Hnd7Prt29xFg4NTHZPs5Q/LLc9eXH8uL7e3cElU8cddv547d/TLc3bXy1avaXDOhBsr8gufGHX6tnrMP7jS4Pt+prTL5NXlv+25vei2Nm+fmbX2oYjU6b0n28Yo9PdvDlGV00XXN89Wqf7D0/81FI= \ No newline at end of file diff --git a/docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib b/docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib deleted file mode 100644 index 678bb17e5..000000000 --- a/docs/cassettes/persistence_6fa9a5e3-7101-43ab-a811-592e222b9580.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib b/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib deleted file mode 100644 index 18e97c77b..000000000 --- a/docs/cassettes/persistence_cfd140f0-a5a6-4697-8115-322242f197b5.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNqFVH9MG1UcL8Ml2xKTiWYxS8hujQymvPauV6AlGFcLG6QyKjSboBt7vXttT653591rBSZ/DIhmLnNelihm6nQt7WzKoNKxBUeGQaPRRROXLDYxaKbL/GPJVGZiWCK+lhZYIHh/vfv+/Hw/n+97/fEwUjVBloqSgoSRCjlMfjS9P66iV0JIw4OxIMIBmY+6W9o8kZAqZMoCGCtardkMFcEEJRxQZUXgTJwcNIcZcxBpGvQjLeqV+Z5M6KgxCLs7sdyFJM1YSzG0xVpJGQtBxPLiUaMqi4icjCENqUbi5WSCRMJZU0DYSTWVBymv7DX2HcpmyjwSsx5OhCEeARZUAU2WJISBhdSmqy20sS8eQJAnY52KBmQN66lVQEchxyEFAyRxMi9Ifn3E3ysolRSPfCLEKMFlK+aY0BNdCCkAikIYxRaz9DGoKKLAwazf/DLpnswjBrhHQavdiexggMwrYf2So4DD7O4hvEoUbWKtJstYN9AwFCSRMANESCDFlJz/s5UOBXJdpA7Ia6bHFpMvrIyRNX24GXItbQ+UhCoX0IehGqy2jq+0qyEJC0Gkx53u1e3yzuV2rIlhTPbUA4W1HonTh31Q1FBqieSllARRhQV0NaCZCwWWRCT5cUCPMEzNeRVpCtk3NBAjJXFI648SRdC1r+P5FTnX4iqoOWsoidYTdfQpTyBUSdEs1cJhKqs6xdhrWaaWHPY1e5LOfBvPmmKkPCqUNB8RpKEgfpwLhKQuxCeca8qeMS6PpZL+ohAUMMhfDyJW9lePWmmazuxaN1JFQcJatmOUtdvt/1OXMIOwns7OBxga0Kxnccoqa0eGWitz8ZLl8cSyeAiiJ9aJXMZTiKbWjV4bj8XakciDBgKvXyHnTprZC19t7e3oZS0+t2LrsDe7WVe4K3SxG3CiHOIBJg8NArmF6MZ6hvLyVi9kLTS0evkqK0LIx9RAZKuppq12xmKzRcIC1BOMiaH8suwX0ahzL3BCLoBAW25t9Hh9+35Hc5Mz+QJolb0y4c8DCc+SLKFYG1LJOuqJXGtywVUUI+mtjnY9beM4XxW02Bg7D2mf3Q4aDraOFRZoaUGi2dch96AdI2uqEtOXRU/uOLHJkPuKn3u72TWzZ+vrC9/Y3j1c0tT2jLa7orH39LNPV5RMnEm1T77XND5+wz3/c9nzn1+fZr+/Unx386GTGyfgQTR3cfbvW66ehXuXZ9O+uZ/udp66VLbrvHNfpGHnUCnsn/rnkaGtL7ln3tw80Xr6qw0jNakY1g/HHUNN1+u+Hf30TN3MQyNjJU9tk+NX3cOjf762feM7v01ND4jmI8PjhjuVx7ak67cMfOGquLXpBp385fb9Rsdw9UzJgaL0xx9O//HRyV9LB99K3lfCaV9V96WzN0XusWsHzvXfizz8RqPjA2Xor+1zTa66q+WPeyYT5Y8OpvbcnPzhR/Zf04ZSY6qs0tZ79sj787v3/375RMcnd44Xb5urcxyf3wGk727LhJSFhWJDJF5S2VdkMPwHIYKQ/g== \ No newline at end of file diff --git a/docs/cassettes/persistence_mongodb_2e65b3b2-8e3e-4d96-8db4-4846a3bc2eac.msgpack.zlib b/docs/cassettes/persistence_mongodb_2e65b3b2-8e3e-4d96-8db4-4846a3bc2eac.msgpack.zlib deleted file mode 100644 index d331f38dc..000000000 --- a/docs/cassettes/persistence_mongodb_2e65b3b2-8e3e-4d96-8db4-4846a3bc2eac.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_mongodb_623b81ea-9415-4c49-9ded-9c7830a3ef6b.msgpack.zlib b/docs/cassettes/persistence_mongodb_623b81ea-9415-4c49-9ded-9c7830a3ef6b.msgpack.zlib deleted file mode 100644 index c1ea230c2..000000000 --- a/docs/cassettes/persistence_mongodb_623b81ea-9415-4c49-9ded-9c7830a3ef6b.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_mongodb_e3a9889d-7a60-455f-96d6-95a8a2e7dbf6.msgpack.zlib b/docs/cassettes/persistence_mongodb_e3a9889d-7a60-455f-96d6-95a8a2e7dbf6.msgpack.zlib deleted file mode 100644 index f5647be04..000000000 --- a/docs/cassettes/persistence_mongodb_e3a9889d-7a60-455f-96d6-95a8a2e7dbf6.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_mongodb_f7aaec32-1755-4ae4-a40b-ade58491a5bb.msgpack.zlib b/docs/cassettes/persistence_mongodb_f7aaec32-1755-4ae4-a40b-ade58491a5bb.msgpack.zlib deleted file mode 100644 index 0d507d7f2..000000000 --- a/docs/cassettes/persistence_mongodb_f7aaec32-1755-4ae4-a40b-ade58491a5bb.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_postgres_180d6daf-8fa7-4608-bd2e-bfbf44ed5836.msgpack.zlib b/docs/cassettes/persistence_postgres_180d6daf-8fa7-4608-bd2e-bfbf44ed5836.msgpack.zlib deleted file mode 100644 index 2023370c6..000000000 --- a/docs/cassettes/persistence_postgres_180d6daf-8fa7-4608-bd2e-bfbf44ed5836.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_postgres_386b78bc-2f73-49ba-a2a4-47bce6fc49b7.msgpack.zlib b/docs/cassettes/persistence_postgres_386b78bc-2f73-49ba-a2a4-47bce6fc49b7.msgpack.zlib deleted file mode 100644 index 45b9eded4..000000000 --- a/docs/cassettes/persistence_postgres_386b78bc-2f73-49ba-a2a4-47bce6fc49b7.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_postgres_4faf6087-73cc-4957-9a4f-f3509a32a740.msgpack.zlib b/docs/cassettes/persistence_postgres_4faf6087-73cc-4957-9a4f-f3509a32a740.msgpack.zlib deleted file mode 100644 index f8e85ea6d..000000000 --- a/docs/cassettes/persistence_postgres_4faf6087-73cc-4957-9a4f-f3509a32a740.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_postgres_5fe54e79-9eaf-44e2-b2d9-1e0284b984d0.msgpack.zlib b/docs/cassettes/persistence_postgres_5fe54e79-9eaf-44e2-b2d9-1e0284b984d0.msgpack.zlib deleted file mode 100644 index 23711ae2e..000000000 --- a/docs/cassettes/persistence_postgres_5fe54e79-9eaf-44e2-b2d9-1e0284b984d0.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_postgres_6a39d1ff-ca37-4457-8b52-07d33b59c36e.msgpack.zlib b/docs/cassettes/persistence_postgres_6a39d1ff-ca37-4457-8b52-07d33b59c36e.msgpack.zlib deleted file mode 100644 index d257dd069..000000000 --- a/docs/cassettes/persistence_postgres_6a39d1ff-ca37-4457-8b52-07d33b59c36e.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_postgres_bd235fc7-1e5c-4db6-a90b-ea75462ccf7d.msgpack.zlib b/docs/cassettes/persistence_postgres_bd235fc7-1e5c-4db6-a90b-ea75462ccf7d.msgpack.zlib deleted file mode 100644 index f3545a443..000000000 --- a/docs/cassettes/persistence_postgres_bd235fc7-1e5c-4db6-a90b-ea75462ccf7d.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_redis_5fe54e79-9eaf-44e2-b2d9-1e0284b984d0.msgpack.zlib b/docs/cassettes/persistence_redis_5fe54e79-9eaf-44e2-b2d9-1e0284b984d0.msgpack.zlib deleted file mode 100644 index ac7e10fb3..000000000 --- a/docs/cassettes/persistence_redis_5fe54e79-9eaf-44e2-b2d9-1e0284b984d0.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/persistence_redis_6a39d1ff-ca37-4457-8b52-07d33b59c36e.msgpack.zlib b/docs/cassettes/persistence_redis_6a39d1ff-ca37-4457-8b52-07d33b59c36e.msgpack.zlib deleted file mode 100644 index f4504d61b..000000000 --- a/docs/cassettes/persistence_redis_6a39d1ff-ca37-4457-8b52-07d33b59c36e.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_12.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_12.msgpack.zlib deleted file mode 100644 index 42a9a79a6..000000000 --- a/docs/cassettes/subgraphs-manage-state_12.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_14.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_14.msgpack.zlib deleted file mode 100644 index 8150dcb53..000000000 --- a/docs/cassettes/subgraphs-manage-state_14.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_16.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_16.msgpack.zlib deleted file mode 100644 index 9085b559e..000000000 --- a/docs/cassettes/subgraphs-manage-state_16.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_31.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_31.msgpack.zlib deleted file mode 100644 index 9dc665f8d..000000000 --- a/docs/cassettes/subgraphs-manage-state_31.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_34.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_34.msgpack.zlib deleted file mode 100644 index b3d6bfd82..000000000 --- a/docs/cassettes/subgraphs-manage-state_34.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_41.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_41.msgpack.zlib deleted file mode 100644 index 758b01e8c..000000000 --- a/docs/cassettes/subgraphs-manage-state_41.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_43.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_43.msgpack.zlib deleted file mode 100644 index 3c9829c44..000000000 --- a/docs/cassettes/subgraphs-manage-state_43.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/subgraphs-manage-state_49.msgpack.zlib b/docs/cassettes/subgraphs-manage-state_49.msgpack.zlib deleted file mode 100644 index 8062d3291..000000000 --- a/docs/cassettes/subgraphs-manage-state_49.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling-errors_11.msgpack.zlib b/docs/cassettes/tool-calling-errors_11.msgpack.zlib deleted file mode 100644 index c1951b14a..000000000 --- a/docs/cassettes/tool-calling-errors_11.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNrtWHtUFNcZBx8hTUyNVWv12DrdoJJ2d9nZ92IiLgtGRBTZRcRIyGXm7u7I7MwwD2BBYsDHkZpIVhuTCBoQXBRR4USkaqhStb7QmJcWjeX4qDam2ir1WI0cemddFDTmJCcmpzl1/9nZud/j9z3u9/vOFtfkQF6gWCa0jmJEyANCRD+E5cU1PMyWoCAu8Hug6GbJ6qRpdkeVxFNto92iyAlRkZGAo9SAEd08y1GEmmA9kTl4pAcKAnBBoTqTJb0nQmGBwgPyMkQ2CzKCIgrDNVq9ElN0S6E3LxYoeJaG6EkhCZBXoFOCRVAYUX6V6wYiRgmY6IZYLgToi8coBhMAgzl5wBCUQLDRisJ02SZLQlrWIWggkVClU7kBlSWptMilRqcxyZZF6OFQkKLEyw41ao38jmXpIBAGeAJAXFDMCHqTtUgoEDzFyZmRT22ApjGRxZBUABch8TyC241PLatQDCeJGQLhhh6AdAoUHMoS5EUqEHOBgmYJELRXoBC9XMCtIPIU41IUFiIDcvopHpIysLvScpzd0mzmHEiISDq9sMYNAYnqWFrtZgXR13BfZTYDgoCcqIIMwZLIh2+jK5/ilBgJnTQQYS3KOAMDpffVZkHIqQBN5UD/bS1fPeA4mroNIXKOwDJ1wQqpZCz3H9fKhVSh+jKir8najSMyyYsaiUFZ1+nV2vo8lSACiqFRJ6hogCD5ucD5jp4HHCCykB1VsEl9/tvKm3rKsIJvbSIgptl7mQQ84fatBbzHqH+v53teYkTKA301tqT73QUP77rTqXFcbWnoZVjwMoRvrRPQAmy4k+Q7KrWo3XQqjVGlwTd1Z4mGjEt0+6p0BtM6HgocumBwvh+ZFCWhuBpVBLburwleiTXTErqr+Vp1LKqNr9nhlpSY1ojZIYfJzYzhuig9HqXTYy8kOupsQSeOryxFgwPdEsGJyhHXXfoawi0xWZCstX1l0WuDF19Fkb730XOGBjfEEFOy83U6rzWJcgB3JpU4MS12RmOeiqBZiVSJaGpAVSDYPNHXhukNBqPBYoBkpkGvs+hIqDeSGmDBgdlCOM2ZmVU5FPDV4mocc7Gsi4abbRNVNoCuisoeSImvJjZtqjUx3lY3U5XMZrKioHIAl6+aYRnot0MepdpXG3CNmpeHfqSebE3zbTETFh0gcIPTqTHrdZkWVVxqcn13eu6EXy13fmA6FflvX7i9oWGjljweEvj0nVKakbB7wtN7dv6utaP/Mn/XH5rWqIoLkx1J4bOXG0q2fdbY9vzoBXNz42P/fvbIkVs5ORPSJ1T9Tbtk+ZdXN84SuqTsMCE3r23ohqs3SiqxznfGDMPLllUc9Y77yaJtTnxqxdGbxUo9nxVjnT4ixc/EbFk87JD5dVPS/ubBfJ/O8bcG7y0o67/6DaGU+mlaefgX5HuXrp86Sx2nSz1dndxnO/8a0/JOzsE3w9sGDl+/rmzN5ZH98l+9ts13Ypy7Ptv07qps7+Ft+8yvRNT/RzjmO93GSfkvadL7bCuvSK+f8evWzRdPl64uYffj4kr/E+P3N26dtfRsJIq4q6tvSMKBJyviQ0NCHtLU73Puh5n6SuyuFSAIFLpRSL+XqRfvTld5zmcgZ7LAAwZ9YGrfO58VvdzKXhUU2W1QQtcDN+ImszeOT860ZpmneLw5CVPiUm2IlHoBvD/Me7Gh0SDR9+BXxPE8y0dhMwAtwcBzxNh4GSWG6sQjNsE8kiBimRC7TTAYw0qMMPbZ2QyWREMgQMxJ5WFeVuIxj5yfLCgE+Kk7GRnfKBQ5ZCEDyu6RdGD0oegeke4j0v3fJ12TXvMwSdfwQ5HudK3Dwk/XcVSq3c17pk9k7Y40t+uBpGvS6kkjSZgtFieJZ+osBosON2vMBo0OQgAI4/dMusBAIJ7/VqSb0oN0kz6cMxIfcGtolSujrXncX8406cOHrDxXmfhk5e/j/lFbcNmrOr6sIH5p5/UzHtvVcP3K4fHCY9HF89P8f6R2nNr9VO7Api8vXPq841rH278a3TiqpXj86Frlz1pKdsWcTwodcmXNL4YqW59LDgmz7dJ+5GyyVESvOLy17XJZ+sdFC4uqkh1c+weRSyeXpuz4ediwkr7TVu8ZsXmMZtTefvPCq8IOklMjHqu6oljYeuCLyjPnY2fu+21zde75RZ+0kvro4c9XjCg/ui81/2B5RNm75S5H2JLC5oWWf8ddLMga0xhZ+PErO1Ye2nxF297eWTnw5rOnmk7tPf7LmYvNqadiT3RFr5lM/OaJywOKwhwfDBo5t8W9SffnlkO76pXRysX8RV1l3QLThuNFR/8Zk41xDQterqxr2NERff2lG5Om77p08kifYYVLmtvVhzKCFD52xPmyTx8ehffb/ojC/w8o/BumH40YWcLKsTTrQoiVGCViNMtmCRhNZUG5yDwqMxAwlGdKECT0gxLdvYovi0ucGpuCCNyDVHgvOkY9AlxoyN8VD+bAyfIeIEYpelBvAEUA8XduBzuCOfFr2mFGnEeaQ9p4x9QcGCMmcA7cZE3RPaR2iBfHCphRg9YAFw+hnDIShetyeb+uqg9A9Ggxe7SY/UgXs2pci/84NzOH3ZhiZI2pXktirsNrT7Pn6vFk/QM3M2CwmIy4AUBoACZgNpmdwKQjzU6Nk4QaMzB8v5uZVoMTgPw2m9meGz3/DUlP2KN5Oq5r8tsXHNtPSlKH8uaZ5aPqIpJjtP62nLEGnfWtj7rU6UPmbucun/7TKixfw507emxDpyTsPN15qIWxz+vIv/6vkbesE+aXT5ytJLeGWm1Td/dRCmTDFvO+c9khfZn6vcSnjlWvF64/di3fbro21M2V9Ivf9X7ivCXF7Rc6Rw94Tlo3+8Dw+E+Gzfpcs2HSxQ+XbT+8Yjb5loNs3PjmvjcGpaVdvfjMQm77qzfS+yaMOPnaisFFoeHtkw/029n/rMvKP77ooMYdccHkLJ5E+GYkl+55WZ067qn1++dtPXG4Y2BweRozKMWqRMvTfwGuq9+W \ No newline at end of file diff --git a/docs/cassettes/tool-calling-errors_13.msgpack.zlib b/docs/cassettes/tool-calling-errors_13.msgpack.zlib deleted file mode 100644 index 0713e07ef..000000000 --- a/docs/cassettes/tool-calling-errors_13.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling-errors_17.msgpack.zlib b/docs/cassettes/tool-calling-errors_17.msgpack.zlib deleted file mode 100644 index 1514190a1..000000000 --- a/docs/cassettes/tool-calling-errors_17.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling-errors_19.msgpack.zlib b/docs/cassettes/tool-calling-errors_19.msgpack.zlib deleted file mode 100644 index d7ba79229..000000000 --- a/docs/cassettes/tool-calling-errors_19.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling-errors_9.msgpack.zlib b/docs/cassettes/tool-calling-errors_9.msgpack.zlib deleted file mode 100644 index 475c1673c..000000000 --- a/docs/cassettes/tool-calling-errors_9.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling_17.msgpack.zlib b/docs/cassettes/tool-calling_17.msgpack.zlib deleted file mode 100644 index 6afa8c456..000000000 --- a/docs/cassettes/tool-calling_17.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNqFVFtsFFUY3solNTGmKYkaH2QyAeuF2e6teykPsi7LJU2hdlewStOcPXN2Z+jsnOmcM+2WpqVWDAo0ZtCgiZqQdrsLa4U21SIqxtRIsPqmptIY9AFDClUqNYLBgGemu1xSEudlZs5/+b7//7//9OXbkU5krJYNyypFOoCU/RCzL6+jNgMRuieXRlTCYrZhayw+aOjy2dUSpRqpra4GmuwEKpV0rMnQCXG6ut1dnUaEgBQi2QQWO6fLznXxaZBpobgVqYSv5dwuj28Nx5e82MlLXbyOFcS+eIMgnWdWiBkVlVpHHRKgVYSjEuI6EGAvnZNVjiSf4bubrTxYRIrlBxVgiEjwChKQWw3Bw2BcXlfAykZRWmOFUUO3QFxOl3WGsVIEV0HaBk8h2lKEsKJERKAua1Y3LGsEKApHMce8bDLQ0HVGsUTKaYXIqmbQFgIllAYspovXWGeQTmW7zi5ewRAU83XxtFOzYQnVZTXFd3ezBFbLZR2JFrHb3ladJW+c2Ikgtb3vZg5ZQWxaLVC24RYXsJERB5wiE8rhJFd05267/w/57nuRaO7OSwiITEBvZCVMqDm6SBLHAYRIowJSIRZZoeaHqV2ytoYTUVIBFBXYqFVka84stCKkCUCR21FuIcocAZqmyAt9qN5JsDpclIZgcVlsLlgKEpiwVGqeCJd4VDd0MgWrbPRen9MzkhEIBbLK6ieCAhilnGbbP7vToAHYyvIIxe0wcwvBx+70wcQcqgdwa+yulECHkjkE9LTfN3bnuW6oVE4jMx9pWAxXNN6G8zrdbmdo9K7EpFOF5lASKASN3mryrZAC07xXcPkFl/tYqUsKUlNUMgd9geARHRGNbTZ6JcdSUoP0ZdlE0Hdn8sVdHNhaV5rmgex6NhvzVFwy1nAePxdDGmdtFOf21vrctTUhbmN9fDhSBInfcxSjcR2oJMnGES2NPg8lQ21FYiFyz6EXijeOIIvm5+y7xeX2+eo764Lk+WAdxBKsb+jYuK0tuv7jjAAVbIgCZdcVEuxiM9Q8y8GE3ycm/MgfCIQ8oAagZDCYrEkkUAi6azwB32C7DMyC2+nmUhinFHQ8skGIACZ5IWa3xMyvb9oSrt8cGX5BaMQJTIkQBykzq2IV5WJIZ602CzY0E6+Ociy8MdxkfhSEIS+ACW8C1dT4PAlRiG5vHCm151b5WUv59rX4cm5h678ue2rl/nKH/SyJN/xS95Wr4sb2yVPXDoanNgeu+CuWgeBzgWh2z6wU+b5uasfFDTM3nUf3zc98cvmLlR2B3lDvntNvR2t3z2y/TlZIJy+OTc7+8djlC5emhPJfyX7z1XMfVIbXXVCWvnX19Bi/vKx/7eFl908XtC/PJrY9GdvbdCg5NcM39zl+f8185Pz1uUtnMvumj27KHPmxadVD/0xWffpsc9UOcOX1fU/PVka+eXPg/Hgs2z+1ZeKJGwfeG4vOtZ2YOfzTXv59PN+ze378wfz47Lv90+mf5//exPXGVxir9T9XVAz9sHx5qNd4cbRtaeUNNBHsKZ+bnR6I/FY1Ef3LN5d5YNOj4caRbeve6Xl8L77a19x/Puw8dNLx8LXKb+fb/r3P4bh5c4lj19rZVQfLHI7/ANrmpzc= \ No newline at end of file diff --git a/docs/cassettes/tool-calling_19.msgpack.zlib b/docs/cassettes/tool-calling_19.msgpack.zlib deleted file mode 100644 index d74c6182d..000000000 --- a/docs/cassettes/tool-calling_19.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNqFVGtsFFUUbkOMjxCakJjor46jWJTO7s7utt1tjFiXtiDWLt2NpUrT3r1zd2e6s3OHuXf6oGywpT8K1MgQEqOxibHbXV0LtBEsUSQBYlMTMT4atZjU1y9N0KRiooSCd6a7LaQk7p+9c8/j+84537mDuW5kEAVrpROKRpEBIGUfxBrMGWiviQgdyqYQlbGUCTdHomOmocxvkinVSa3bDXTFBTQqG1hXoAvilLtbdKcQISCBSCaGpb4rpQv9fAr0dlCcRBrhaznR4/VXcnzRi9283M8bWEXsxJsEGTyzQsyoaNS+6pEBrSAclRHXgwD7MzhF40h8K59ut/NgCam2H1SBKSHBJ8hASZqCl8F4fJ4aOxtFKZ0VRk3DBvG4PPYdxmoBXAMpBzyBaEcBwo6SEIGGotvdsK0hoKocxRzzcshA0zAYxSIplx2iaLpJOwiUUQqwmH5eZ51BBlWcOvt5FUNQyNfP0z7dgSXUULQEn06zBHbLFQNJNrFVb7vOojeOdSFIHe87mUNWEJtWB1QcuLUFNDLigFMVQjkc5wru3Kr7/5BP341EezonIyAxAb2WkTGh1tQaSZwCECKdCkiDWGKFWicS+xS9kpNQXAUU5dmoNeRozsonEdIFoCrdKLscZU0CXVeV5T64uwjWJgrSEGwua815W0ECE5ZGrem6Ig93uI8pWGOj9/ld3slegVCgaKx+IqiAUcrqjv3j2w06gEmWRyhsh5VdDj55uw8m1ngTgM2RO1ICA8rWODBS1f4Pbr83TI0qKWTlQuG1cAXjKpzPJYqu4NQdiUmfBq3xOFAJmlpp8kpInmneJ3iqBY94stglFWkJKltj/prAuwYiOttsdDDLUlKTDGbYRNDns7nCLr7TvLM4zZHMNjYb65OobFZy3mougnTO3ihO9NX6vbUeD9fYFJ0IFUCidx3FVNQAGomzcdQXR5+DsqklkZQP3XXo+cKLIyiSdY6dOzyiHzY8v7NqV0BPRPyN++rrYCxKe1480ytAFZuSQNlzhQSn2F5qzXNxXyAYF8UqwHY/UFWNPEiKVyPRz07QVxOIj3UrwMqLLpFLYJxQ0alQgxACTPJCxGmJldvW9kJd047QxG6hBccwJUIUJKyMhjWUjSCDtdrKO9BMvAbKsvCWujbrdAAGfQDGAgCJyO+NSUJ9a8tksT0r5Wds5TvP4kB2ees/La0sP3JfifNbFw3vTF7yrL+5peH19j3byzMnsHD62mTjtEbpyE9B/v69V13H5p+bPVD+RfW3o0NPp8t2CNHg5kCLtenS5ZvxXU+5Fn8+/PXiv5O/Lv2wBDZs/Gf/xdln+XZuu3zu1Vcezw+fgUf1a8GXwp0TG4IbZg62tJoPjRz76rGHKyJHO89Buv738SVTujFy5fzms+//3fbAkf31F4/LXRc2HS6b2xN79MmK7iuHzLHR92Z77xm94VtciA/8oi3VTZW1eff8eLLL+Kup7/vrny1eBx+m33QnuAu/wbkHZ+ebnzn+UaQzLOzG/taFgcEDb3xpnto4vPREMhxpPjv8x71Df5aO1oVdu7c8cm1r5Op0/8z5hsa3Z76JDpbtPzSufJcuLSm5dWtdyeW39s4dY+f/AMGeoWY= \ No newline at end of file diff --git a/docs/cassettes/tool-calling_23.msgpack.zlib b/docs/cassettes/tool-calling_23.msgpack.zlib deleted file mode 100644 index 146c6a43d..000000000 --- a/docs/cassettes/tool-calling_23.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling_25.msgpack.zlib b/docs/cassettes/tool-calling_25.msgpack.zlib deleted file mode 100644 index 773d10656..000000000 --- a/docs/cassettes/tool-calling_25.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/tool-calling_26.msgpack.zlib b/docs/cassettes/tool-calling_26.msgpack.zlib deleted file mode 100644 index 7bb8a34b7..000000000 --- a/docs/cassettes/tool-calling_26.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/cassettes/update-state-from-tools_9d71af94-572a-4961-88a7-665e792cf96a.msgpack.zlib b/docs/cassettes/update-state-from-tools_9d71af94-572a-4961-88a7-665e792cf96a.msgpack.zlib deleted file mode 100644 index b4e5cd250..000000000 --- a/docs/cassettes/update-state-from-tools_9d71af94-572a-4961-88a7-665e792cf96a.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -eNrtV2lQFGcaFtQoQUSjokk82hEQlR7mZkYgCgOiIpcDAiIOTXfPTMN096S7BxgQFVQwGI+JMVESY0QOQQQEZBVFMSSK962Qy4t4BF0t8Yob1v16xAQ3qdRurT82Vekqprq/9/ne63v67Yec0lScYQmasqsgKA5nEJQDD+wHOaUM/q4ZZ7mlJSTOGWisKCJcE7XFzBBtEw0cZ2Ine3khJkJIm3AKIYQoTXqlir1QA8J5gXuTEbe5KUqiMcvXdjGZAhJnWUSPs4LJUHymAKVBLIoDDwID4QmlgW0Qa6DNRgwiIIyGOAPBQmk4noJT2BSBJyRgaCPOo80szgiyEsAKSWO4kV/SmzhYRvMglmNwhARrOsTI4mCBo2ljd0TOYrI50JkpW4U8/pf7yVCmgEJIG8BI0ylmk5YPpCUonc0xhrMoQ5i6sYJoFn+eIUdDPBwymyAeD/F4hkR4HG9LwjnQUQhhWYLlwA6chNIIzsDfEQxk6y7fJCEfwoQwIAEAZ23ZmBjQWIYjbA3LzOJr6S6ATkrGUU6QlZWVkFVqwBEMbPm+16AiA81y1sqXj6QKQVEctAenUBojKL11uz6DMHlCGK4zIhxeDo6Bwm0tsJan4LgJRoxEKl7yfJe1GjGZjARqK8crmaWpiu5jg/lcfmsu53sAg0OmOGtdOEjCf4ZXhAVwh4LEQrlK6F2dDrMcQlBGwAXYiIB8Skw2+56eBhOCpgAncDcvrSXPN1f2xNCstTgUQcM1L7lEGNRgLUYYUiGr7bnOmCmOIHFrqTrit+G6jb+GkwrFYqFqx0uOWQuFWotttPrbS5txjrHAKA18WDeLSlBABgK3tt3XalGdNon0i9IF0HPl5gyZOdIyi52uCYuaE0n6W8KjU0Nk4WxETCATGR2aok5TBcTBYm+pQqkUK1VSWCwUCcVCMSyd7T9HFy1Nz8CYOWmxuCxWF6mRmmOVMdIUjclbbuFiIt7VREQZMKlEEqDE4qSxyRmKEMkcqZC1aLWkPl0cLlWqFYx4jiw4Rjxnxru6WLM8zQcC2ZlTCcwP86cyyLmR5IyIpGSFtwRN0kdJydCguGnJ2nAmXCsKSw1RB4FDNUrRHukpJBJY1J2hQiRTivir8gU3jDil5wzWLVKZdCuDsyZAcHxJCWgZZ2ZzigAP8WMtpd3ToDA85FcKuxQFAk5aG6PM4NUVy6CZCAVJRBI5JFZNFosnS1VQcGhUhbo7TNTvUnBHFINQrA7QMOgF5UtRg5lKwbFy9e+SvZEnOzhJPn0wZGA83USzONydlbUiFp79fA7CMwJrn79ZMM3oEYrIsIW1lvFEBnOPoOq6zeDd5V2C4DDJWreoFNLKbssLjpWDukSwWASLxA3pMAPKNhIkAXpn++0evIDiYr6zu36L4GgwGFnrVqno+bWvJ4TBSZAMH/0XR0UqcO39fdALXxIeo/KWNrwMY/EeCW1RkOyu39q7XRSK2Ir0F2CYwKxtruBBm4RgCrFMJwK/IrlUp1LJklAclcoVuBIBS+LdYGwTKPDCH52JZjiYxVHwneEs1jZPEknnJ4qfVCyXKkClPmDGokYzhmvMSYE0XwPrA5kY3EgjWJV6GqxGUAMOa2xss5YGxoX5h85Q18fCPWkDh9smObBTNEsROl2JBmfA0VjLUSNtxsBoZPAS4Gu2f5y1TiUS63AcU6CoXCKToAo4KGZ29Qtvv5CsiJ+rpYgR5J6KWmsNUj/BZJlMKvCBSMRPqZCJRLYvYXYJXyul/8ru72NW9O9lu3qDv2fP3teErv5ENKixc1KFKi9/TdOZb+vLG/yifzy0+evympGZ0Im3vqkJ3RP54bP5dg7uxMR1vWuuH9+7wSJlZ/W3m5CoXnw39vL26FtbyPSyTi9tzKb9nV1n65V7U4oXeS66Vn8EOR28/s5oy67AxislO19fIstYulvtUq1PeKfiSPncOfQ2O8PKqefz5IqilLXX4/aF1U48foS9fGL6qtGK9uCA/mMPXbn08da++77IxVasKA66G7ekesOn/e30UbTd9cYH2bd6rejPbOn9477k7ybIe+eI85mSqFm+Cw+1+fz45YeFJ+vvbbsx/pi28cmjW1mNVQ+Df17jXbtg3MMDA/ue33h97TvSBTU09cFg+4Kd6grJ9eLaus6bW8/t3H0F6rM+pcHFfLMj75pD5T0Nc7eLvbC/uaFz1sZlqm/C1545IruwYfv+wQOTy4ovReYdc3Y6Zp4lbMv1PZWw8vUK6XYn2frh5/zIyFVFg4ZPyDn6w5sD3EXD7vzQfHXg28NGrB/proKd9QvyBNMOuiVtXKN7zbX2xDPh9dGPWxvPHX92KngxW2fXd+fAZe0XnYK987o2dB0lz6R7jPBt0H4wzumNhClO2fKOc+l2l53fSQxJKXubu3D4yoDP6+talEO2CZrlrqXtzrZD7d3ryylDZzr36dXrVaop+0t/oKaieRnCSxkIyJMoxGKkGUiTRug4IWQz8SOPBe8QFIADxhst0HTCaGQ9IbV/T5XFWlgOJwVAdvzPUu1lF5TZaOwBea6MEGDqFmtaFDH+kWIjMH6FB2nnmuSsdG4wLklnsaiwQF2yjpqOT5Po/ythhzB6MwlS40MKMrMEvKj6t6I1ZtsHQgcyt9jUHo79nt7rWTlfyUsVaf+TvP9StX+p2r9U7f+5qvWWyl+pqpXJ/pyqtkjmLVL8eWStzPuVy1oU0FOFKhCxApWjSgQVYd6ITieSeSdJ5TIlgvwpZK1OguHoq5O1fcb+KmvfXxdKf6MclHv3p2GaBPs+qWuqJoc9Ohf6dtHUbBeiPjZxj+hg+/SCAsHO9pb6ue37vXJnJ/W7Y595OrvZcimv+crNQ3ZTD9Tvyv3inEcJ8d2D0PgNR+9zfv9Y+NPpD+92eA0/Tz65NmqR8lnrP+NmycZ57rdaSyvQIQUXrKZ76tbAgLHRfo2+m47fKO3ctm2kIcetlIiedHaFyM9HtWf9Z8dKx9eKdww0egy7eO+iXa+m1T9HB9JE/Lzmw+1E8eYPqwuvPrUMmTp4ydl19pqrrjeL19/OcU8fu6ns7ojR1Wlj9+X45PcZ4TDb0L/1DXcPdZ+ythiHp6eyHTbWJi6pdGsdtL0lPtF5/9mCwo4rqzaGXNR2xSzKGBAcrFXuaMqqHnqZbJePGpXQvIfsCHBdU5A4pLD27BufnHKbbjbEPxrm+l6gxO5RPTuszF+X79oSNmRcfVefgKVOmW8rVHLHBuqboDk78ZtLn93yGDXpxIarvpfze10Zyw0OcPBuN7wZl7HL0ckNz9y6KT/CbDycs1To3iSvaS7WGIaKbvpHhaTkiLnv91U0BWYrXlv72bQdyfKIcGnG/RZz5bzH7SZHj8X3dn91bHPWlvti6yR/eyjwu+Icl8zvRvqWXXW81txoX+TSb7Xjw9aqpyuG7nIMEGqPFfiayurzrE39sl1bV+uXy9o6st+6OPdI7qlbcqi1ZWFxbLJovmH7kcXf2/9Eb+73UR/5eAerU2It9iBXcjUlaO+1dRmbm8jA/cztK69ljfFd8MWuI0vj3B/nBN96UL53WT4WuwUOan4vsU3tt3xCqKS9bXEg9nFi8+zmD6qHCH36pZQcjyhpq0QXCc984rGpozpy+WO36pHuW3eQh53d91wUuTh0pV8fkOu08GTwihqHd/t+pOmoHr+tKGfV3jXnPca/mShk/eta6LbMfHXatzXjd5W6tgY9KJR5iVNmfX4hXh0WfYBb5XfwneHZC3sPWZAUEuklenym9mlrWPOo6IdR2tQF9W9tvT7TrFkbdyAv8dQPH1kbPz5rinb0nJE1IGjGkM/J4yEXrOvvr5BvJiZXVa1i7s8f1VxwVeRy8LBkb/23pqPZJxwnRJXsdmMipgmyxpQMHEtMedAQnjxT1gDvNPR3I+8r1R4+U+A2VU34tKpHpWhRTcjW5ra0Eys7Vp+8dmFZ+Upkw8EnnRmHP9M0Ll86IX3U9hkB8e03r9k1XbJUpHm5m08fPFVXs6ZaUJUTU9Vvd9LjMW19T+o6xRP9T92xv1HbedjrgYti9dG6x6jHgIKC20Lz4+EHTjCtjiNvb3yq/1RLOI/Xa7vG/JTQNCJ52e3ClVjbXt/7VLxr18l/Xqy/MVF/WRA5r3bzMlFQo0OIWyr1pK9LWXjA8UJMG2kc5/zsQE3CvGOVYeGVYaaFcSN9R//s+Pw/oZZx8+FBYDb8C2sICug= \ No newline at end of file diff --git a/docs/cassettes/update-state-from-tools_de34a58b-1765-4b63-a232-d46790aff884.msgpack.zlib b/docs/cassettes/update-state-from-tools_de34a58b-1765-4b63-a232-d46790aff884.msgpack.zlib deleted file mode 100644 index 0b5e7422f..000000000 --- a/docs/cassettes/update-state-from-tools_de34a58b-1765-4b63-a232-d46790aff884.msgpack.zlib +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/docs/docs/adopters.md b/docs/docs/adopters.md index c8dd97286..91142d44f 100644 --- a/docs/docs/adopters.md +++ b/docs/docs/adopters.md @@ -1,4 +1,4 @@ -# 🦜🕸️ Companies using LangGraph +# 🦜🕸️ Case studies This list of companies using LangGraph and their success stories is compiled from public sources. If your company uses LangGraph, we'd love for you to share your story and add it to the list. You’re also welcome to contribute updates based on publicly available information from other companies, such as blog posts or press releases. diff --git a/docs/docs/agents/agents.md b/docs/docs/agents/agents.md index 2cbd089f8..03ba00dde 100644 --- a/docs/docs/agents/agents.md +++ b/docs/docs/agents/agents.md @@ -7,22 +7,31 @@ hide: - tags --- -# Agents +# LangGraph quickstart -## What is an agent? +This guide shows you how to set up and use LangGraph's **prebuilt**, **reusable** components, which are designed to help you construct agentic systems quickly and reliably. -An *agent* consists of three components: a **large language model (LLM)**, a set of **tools** it can use, and a **prompt** that provides instructions. +## Prerequisites -The LLM operates in a loop. In each iteration, it selects a tool to invoke, provides input, receives the result (an observation), and uses that observation to inform the next action. The loop continues until a stopping condition is met — typically when the agent has gathered enough information to respond to the user. +Before you start this tutorial, ensure you have the following: -
-![image](./assets/agent.png){: style="max-height:400px"} -
Agent loop: the LLM selects tools and uses their outputs to fulfill a user request.
-
+- An [Anthropic](https://console.anthropic.com/settings/admin-keys) API key -## Basic configuration +## 1. Install dependencies -Use [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] to instantiate an agent: +If you haven't already, install LangGraph and LangChain: + +``` +pip install -U langgraph "langchain[anthropic]" +``` + +!!! info + + LangChain is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/). + +## 2. Create an agent + +To create an agent, use [`create_react_agent`](langgraph.prebuilt.chat_agent_executor.create_react_agent): ```python from langgraph.prebuilt import create_react_agent @@ -48,10 +57,9 @@ agent.invoke( 3. Provide a list of tools for the model to use. 4. Provide a system prompt (instructions) to the language model used by the agent. -## LLM configuration +## 3. Configure an LLM -Use [init_chat_model](https://python.langchain.com/api_reference/langchain/chat_models/langchain.chat_models.base.init_chat_model.html) to configure an LLM with specific parameters, -such as temperature: +To configure an LLM with specific parameters, such as temperature, use [init_chat_model](https://python.langchain.com/api_reference/langchain/chat_models/langchain.chat_models.base.init_chat_model.html): ```python from langchain.chat_models import init_chat_model @@ -71,77 +79,77 @@ agent = create_react_agent( ) ``` -See the [models](./models.md) page for more information on how to configure LLMs. +For more information on how to configure LLMs, see [Models](./models.md). -## Custom Prompts +## 4. Add a custom prompt -Prompts instruct the LLM how to behave. They can be: +Prompts instruct the LLM how to behave. Add one of the following types of prompts: -* **Static**: A string is interpreted as a **system message** -* **Dynamic**: a list of messages generated at **runtime** based on input or configuration +* **Static**: A string is interpreted as a **system message**. +* **Dynamic**: A list of messages generated at **runtime**, based on input or configuration. -### Static prompts +=== "Static prompt" -Define a fixed prompt string or list of messages. + Define a fixed prompt string or list of messages: -```python -from langgraph.prebuilt import create_react_agent + ```python + from langgraph.prebuilt import create_react_agent + + agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_weather], + # A static prompt that never changes + # highlight-next-line + prompt="Never answer questions about the weather." + ) + + agent.invoke( + {"messages": [{"role": "user", "content": "what is the weather in sf"}]} + ) + ``` + +=== "Dynamic prompt" + + Define a function that returns a message list based on the agent's state and configuration: + + ```python + from langchain_core.messages import AnyMessage + from langchain_core.runnables import RunnableConfig + from langgraph.prebuilt.chat_agent_executor import AgentState + from langgraph.prebuilt import create_react_agent -agent = create_react_agent( - model="anthropic:claude-3-7-sonnet-latest", - tools=[get_weather], - # A static prompt that never changes # highlight-next-line - prompt="Never answer questions about the weather." -) + def prompt(state: AgentState, config: RunnableConfig) -> list[AnyMessage]: # (1)! + user_name = config["configurable"].get("user_name") + system_msg = f"You are a helpful assistant. Address the user as {user_name}." + return [{"role": "system", "content": system_msg}] + state["messages"] -agent.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]} -) -``` + agent = create_react_agent( + model="anthropic:claude-3-7-sonnet-latest", + tools=[get_weather], + # highlight-next-line + prompt=prompt + ) -### Dynamic prompts + agent.invoke( + {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, + # highlight-next-line + config={"configurable": {"user_name": "John Smith"}} + ) + ``` -Define a function that returns a message list based on the agent's state and configuration: + 1. Dynamic prompts allow including non-message [context](./context.md) when constructing an input to the LLM, such as: -```python -from langchain_core.messages import AnyMessage -from langchain_core.runnables import RunnableConfig -from langgraph.prebuilt.chat_agent_executor import AgentState -from langgraph.prebuilt import create_react_agent + - Information passed at runtime, like a `user_id` or API credentials (using `config`). + - Internal agent state updated during a multi-step reasoning process (using `state`). -# highlight-next-line -def prompt(state: AgentState, config: RunnableConfig) -> list[AnyMessage]: # (1)! - user_name = config["configurable"].get("user_name") - system_msg = f"You are a helpful assistant. Address the user as {user_name}." - return [{"role": "system", "content": system_msg}] + state["messages"] + Dynamic prompts can be defined as functions that take `state` and `config` and return a list of messages to send to the LLM. -agent = create_react_agent( - model="anthropic:claude-3-7-sonnet-latest", - tools=[get_weather], - # highlight-next-line - prompt=prompt -) +For more information, see [Context](./context.md). -agent.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]}, - # highlight-next-line - config={"configurable": {"user_name": "John Smith"}} -) -``` +## 5. Add memory -1. Dynamic prompts allow including non-message [context](./context.md) when constructing an input to the LLM, such as: - - - Information passed at runtime, like a `user_id` or API credentials (using `config`). - - Internal agent state updated during a multi-step reasoning process (using `state`). - - Dynamic prompts can be defined as functions that take `state` and `config` and return a list of messages to send to the LLM. - -See the [context](./context.md) page for more information. - -## Memory - -To allow multi-turn conversations with an agent, you need to enable [persistence](../concepts/persistence.md) by providing a `checkpointer` when creating an agent. At runtime you need to provide a config containing `thread_id` — a unique identifier for the conversation (session): +To allow multi-turn conversations with an agent, you need to enable [persistence](../concepts/persistence.md) by providing a `checkpointer` when creating an agent. At runtime, you need to provide a config containing `thread_id` — a unique identifier for the conversation (session): ```python from langgraph.prebuilt import create_react_agent @@ -179,10 +187,9 @@ When you enable the checkpointer, it stores agent state at every step in the pro Note that in the above example, when the agent is invoked the second time with the same `thread_id`, the original message history from the first conversation is automatically included, together with the new user input. -Please see the [memory guide](./memory.md) for more details on how to work with memory. +For more information, see [Memory](./memory.md). - -## Structured output +## 6. Configure structured output To produce structured responses conforming to a schema, use the `response_format` parameter. The schema can be defined with a `Pydantic` model or `TypedDict`. The result will be accessible via the `structured_response` field. @@ -216,3 +223,8 @@ response["structured_response"] Structured output requires an additional call to the LLM to format the response according to the schema. +## Next steps + +- [Deploy your agent locally](../tutorials/langgraph-platform/local-server.md) +- [Learn more about prebuilt agents](../agents/overview.md) +- [LangGraph Platform quickstart](../cloud/quick_start.md) diff --git a/docs/docs/agents/overview.md b/docs/docs/agents/overview.md index 5f85bcd55..22f39ccb9 100644 --- a/docs/docs/agents/overview.md +++ b/docs/docs/agents/overview.md @@ -12,6 +12,17 @@ hide: **LangGraph** provides both low-level primitives and high-level prebuilt components for building agent-based applications. This section focuses on the **prebuilt**, **reusable** components designed to help you construct agentic systems quickly and reliably—without the need to implement orchestration, memory, or human feedback handling from scratch. +## What is an agent? + +An *agent* consists of three components: a **large language model (LLM)**, a set of **tools** it can use, and a **prompt** that provides instructions. + +The LLM operates in a loop. In each iteration, it selects a tool to invoke, provides input, receives the result (an observation), and uses that observation to inform the next action. The loop continues until a stopping condition is met — typically when the agent has gathered enough information to respond to the user. + +
+![image](./assets/agent.png){: style="max-height:400px"} +
Agent loop: the LLM selects tools and uses their outputs to fulfill a user request.
+
+ ## Key features LangGraph includes several capabilities essential for building robust, production-ready agentic systems: diff --git a/docs/docs/agents/prebuilt.md b/docs/docs/agents/prebuilt.md index be05edd04..8ebd5c17b 100644 --- a/docs/docs/agents/prebuilt.md +++ b/docs/docs/agents/prebuilt.md @@ -1,14 +1,44 @@ ---- -tags: - - agent -hide: - - tags ---- - +[//]: # (This file is automatically generated using a script in docs/_scripts. Do not edit this file directly!) # Community Agents +If you’re looking for other prebuilt libraries, explore the community-built options +below. These libraries can extend LangGraph's functionality in various ways. + +## 📚 Available Libraries + +[//]: # (This file is automatically generated using a script in docs/_scripts. Do not edit this file directly!) +| Name | GitHub URL | Description | Weekly Downloads | Stars | +| --- | --- | --- | --- | --- | +| **trustcall** | [hinthornw/trustcall](https://github.com/hinthornw/trustcall) | Tenacious tool calling built on LangGraph. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/hinthornw/trustcall?style=social) +| **breeze-agent** | [andrestorres123/breeze-agent](https://github.com/andrestorres123/breeze-agent) | A streamlined research system built inspired on STORM and built on LangGraph. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/andrestorres123/breeze-agent?style=social) +| **langgraph-supervisor** | [langchain-ai/langgraph-supervisor-py](https://github.com/langchain-ai/langgraph-supervisor-py) | Build supervisor multi-agent systems with LangGraph. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langgraph-supervisor-py?style=social) +| **langmem** | [langchain-ai/langmem](https://github.com/langchain-ai/langmem) | Build agents that learn and adapt from interactions over time. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langmem?style=social) +| **langchain-mcp-adapters** | [langchain-ai/langchain-mcp-adapters](https://github.com/langchain-ai/langchain-mcp-adapters) | Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langchain-mcp-adapters?style=social) +| **open-deep-research** | [langchain-ai/open_deep_research](https://github.com/langchain-ai/open_deep_research) | Open source assistant for iterative web research and report writing. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/open_deep_research?style=social) +| **langgraph-swarm** | [langchain-ai/langgraph-swarm-py](https://github.com/langchain-ai/langgraph-swarm-py) | Build swarm-style multi-agent systems using LangGraph. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langgraph-swarm-py?style=social) +| **delve-taxonomy-generator** | [andrestorres123/delve](https://github.com/andrestorres123/delve) | A taxonomy generator for unstructured data | -12345 | ![GitHub stars](https://img.shields.io/github/stars/andrestorres123/delve?style=social) +| **nodeology** | [xyin-anl/Nodeology](https://github.com/xyin-anl/Nodeology) | Enable researcher to build scientific workflows easily with simplified interface. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/xyin-anl/Nodeology?style=social) +| **langgraph-bigtool** | [langchain-ai/langgraph-bigtool](https://github.com/langchain-ai/langgraph-bigtool) | Build LangGraph agents with large numbers of tools. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langgraph-bigtool?style=social) +| **ai-data-science-team** | [business-science/ai-data-science-team](https://github.com/business-science/ai-data-science-team) | An AI-powered data science team of agents to help you perform common data science tasks 10X faster. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/business-science/ai-data-science-team?style=social) +| **langgraph-reflection** | [langchain-ai/langgraph-reflection](https://github.com/langchain-ai/langgraph-reflection) | LangGraph agent that runs a reflection step. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langgraph-reflection?style=social) +| **langgraph-codeact** | [langchain-ai/langgraph-codeact](https://github.com/langchain-ai/langgraph-codeact) | LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling. | -12345 | ![GitHub stars](https://img.shields.io/github/stars/langchain-ai/langgraph-codeact?style=social) + +## ✨ Contributing Your Library + +Have you built an awesome open-source library using LangGraph? We'd love to feature +your project on the official LangGraph documentation pages! 🏆 + To share your project, simply open a Pull Request adding an entry for your package in our [packages.yml](https://github.com/langchain-ai/langgraph/blob/main/docs/_scripts/third_party_page/packages.yml) file. -[//]: # (This file is stub. Do not edit this file directly!) -[//]: # (1. Update the `packages.yml` file in the `docs/_scripts/third_party_page` directory.) -[//]: # (2. From the /docs directory, run `make build-prebuilt` to generate an updated version of this file for testing locally.) +**Guidelines** + +- Your repo must be distributed as an installable package (e.g., PyPI for Python, npm + for JavaScript/TypeScript, etc.) 📦 +- The repo should either use the Graph API (exposing a `StateGraph` instance) or + the Functional API (exposing an `entrypoint`). +- The package must include documentation (e.g., a `README.md` or docs site) + explaining how to use it. + +We'll review your contribution and merge it in! + +Thanks for contributing! 🚀 diff --git a/docs/docs/agents/run_agents.md b/docs/docs/agents/run_agents.md index 874be6249..0d32708de 100644 --- a/docs/docs/agents/run_agents.md +++ b/docs/docs/agents/run_agents.md @@ -72,7 +72,7 @@ more about [LangChain messages](https://python.langchain.com/docs/concepts/messa Agent output is a dictionary containing: - `messages`: A list of all messages exchanged during execution (user input, assistant replies, tool invocations). -- Optionally, `structured_response` if [structured output](./agents.md#structured-output) is configured. +- Optionally, `structured_response` if [structured output](./agents.md#6-configure-structured-output) is configured. - If using a custom `state_schema`, additional keys corresponding to your defined fields may also be present in the output. These can hold updated state values from tool execution or prompt logic. See the [context guide](./context.md) for more details on working with custom state schemas and accessing context. diff --git a/docs/docs/agents/tools.md b/docs/docs/agents/tools.md index 71279f5cb..8ca986e05 100644 --- a/docs/docs/agents/tools.md +++ b/docs/docs/agents/tools.md @@ -65,7 +65,7 @@ class MultiplyInputSchema(BaseModel): # highlight-next-line @tool("multiply_tool", args_schema=MultiplyInputSchema) def multiply(a: int, b: int) -> int: - return a * b + return a * b ``` For additional customization, refer to the [custom tools guide](https://python.langchain.com/docs/how_to/custom_tools/). diff --git a/docs/docs/cloud/concepts/cron_jobs.md b/docs/docs/cloud/concepts/cron_jobs.md new file mode 100644 index 000000000..9431ed8b2 --- /dev/null +++ b/docs/docs/cloud/concepts/cron_jobs.md @@ -0,0 +1,15 @@ +## Cron jobs + +There are many situations in which it is useful to run an assistant on a schedule. + +For example, say that you're building an assistant that runs daily and sends an email summary +of the day's news. You could use a cron job to run the assistant every day at 8:00 PM. + +LangGraph Cloud supports cron jobs, which run on a user-defined schedule. The user specifies a schedule, an assistant, and some input. After that, on the specified schedule, the server will: + +- Create a new thread with the specified assistant +- Send the specified input to that thread + +Note that this sends the same input to the thread every time. See the [how-to guide](../../cloud/how-tos/cron_jobs.md) for creating cron jobs. + +The LangGraph Cloud API provides several endpoints for creating and managing cron jobs. See the [API reference](../../cloud/reference/api/api_ref.html#tag/runscreate/POST/threads/{thread_id}/runs/crons) for more details. \ No newline at end of file diff --git a/docs/docs/cloud/concepts/runs.md b/docs/docs/cloud/concepts/runs.md new file mode 100644 index 000000000..b1764f7f4 --- /dev/null +++ b/docs/docs/cloud/concepts/runs.md @@ -0,0 +1,5 @@ +# Runs + +A run is an invocation of an [assistant](../../concepts/assistants.md). Each run may have its own input, configuration, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](./threads.md). + +The LangGraph Cloud API provides several endpoints for creating and managing runs. See the [API reference](../../cloud/reference/api/api_ref.html#tag/thread-runs/) for more details. \ No newline at end of file diff --git a/docs/docs/cloud/concepts/streaming.md b/docs/docs/cloud/concepts/streaming.md new file mode 100644 index 000000000..8654bda58 --- /dev/null +++ b/docs/docs/cloud/concepts/streaming.md @@ -0,0 +1,138 @@ +# Streaming + +Streaming is critical for making LLM applications feel responsive to end users. +When creating a streaming run, the **streaming mode** determines what kinds of data are streamed back to the API client. + +## Supported streaming modes + +LangGraph Platform supports the following streaming modes: + +| Mode | Description | LangGraph Library Method | +|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| **`values`** | Stream the full graph state after each [super-step](https://langchain-ai.github.io/langgraph/concepts/low_level/#graphs). [Guide](../how-tos/streaming.md#stream-graph-state) | `.stream()` / `.astream()` with `stream_mode="values"` | +| **`updates`** | Stream only the updates to the graph state after each node. [Guide](../how-tos/streaming.md#stream-graph-state) | `.stream()` / `.astream()` with `stream_mode="updates"` | +| **`messages-tuple`** | Stream LLM tokens for any messages generated inside the graph (useful for chat apps). [Guide](../how-tos/streaming.md#messages) | `.stream()` / `.astream()` with `stream_mode="messages"` | +| **`debug`** | Stream debug information throughout graph execution. [Guide](../how-tos/streaming.md#debug) | `.stream()` / `.astream()` with `stream_mode="debug"` | +| **`custom`** | Stream custom data. [Guide](../../how-tos/streaming.md#stream-custom-data) | `.stream()` / `.astream()` with `stream_mode="custom"` | +| **`events`** | Stream all events (including the state of the graph); mainly useful when migrating large LCEL apps. [Guide](../how-tos/streaming.md#stream-events) | `.astream_events()` | + +✅ You can also **combine multiple modes** at the same time. See the [how-to guide](../how-tos/streaming.md#stream-multiple-modes) for configuration details. + +## Stateless runs + +If you don't want to **persist the outputs** of a streaming run in the [checkpointer](../../concepts/persistence.md) DB, you can create a stateless run without creating a thread: + +=== "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=, api_key=) + + async for chunk in client.runs.stream( + # highlight-next-line + None, # (1)! + assistant_id, + input=inputs, + stream_mode="updates" + ): + print(chunk.data) + ``` + + 1. We are passing `None` instead of a `thread_id` UUID. + +=== "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: , apiKey: }); + + // create a streaming run + // highlight-next-line + const streamResponse = client.runs.stream( + // highlight-next-line + null, // (1)! + assistantID, + { + input, + streamMode: "updates" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + + 1. We are passing `None` instead of a `thread_id` UUID. + +=== "cURL" + + ```bash + curl --request POST \ + --url /runs/stream \ + --header 'Content-Type: application/json' \ + --header 'x-api-key: ' + --data "{ + \"assistant_id\": \"agent\", + \"input\": , + \"stream_mode\": \"updates\" + }" + ``` + +## Join and stream + +LangGraph Platform allows you to join an active [background run](../how-tos/background_run.md) and stream outputs from it. To do so, you can use [LangGraph SDK's](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) `client.runs.join_stream` method: + +=== "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=, api_key=) + + # highlight-next-line + async for chunk in client.runs.join_stream( + thread_id, + # highlight-next-line + run_id, # (1)! + ): + print(chunk) + ``` + + 1. This is the `run_id` of an existing run you want to join. + + +=== "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: , apiKey: }); + + // highlight-next-line + const streamResponse = client.runs.joinStream( + threadID, + // highlight-next-line + runId // (1)! + ); + for await (const chunk of streamResponse) { + console.log(chunk); + } + ``` + + 1. This is the `run_id` of an existing run you want to join. + +=== "cURL" + + ```bash + curl --request GET \ + --url /threads//runs//stream \ + --header 'Content-Type: application/json' \ + --header 'x-api-key: ' + ``` + +!!! warning "Outputs not buffered" + + When you use `.join_stream`, output is not buffered, so any output produced before joining will not be received. + +## API Reference + +For API usage and implementation, refer to the [API reference](../reference/api/api_ref.html#tag/thread-runs/POST/threads/{thread_id}/runs/stream). + diff --git a/docs/docs/cloud/concepts/threads.md b/docs/docs/cloud/concepts/threads.md new file mode 100644 index 000000000..0d4fc5965 --- /dev/null +++ b/docs/docs/cloud/concepts/threads.md @@ -0,0 +1,11 @@ +# Threads + +A thread contains the accumulated state of a sequence of [runs](./runs.md). If a run is executed on a thread, then the [state](../../concepts/low_level.md#state) of the underlying graph of the assistant will be persisted to the thread. + +A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run. + +The state of a thread at a particular point in time is called a [checkpoint](../../concepts/persistence.md#checkpoints). Checkpoints can be used to restore the state of a thread at a later time. + +For more on threads and checkpoints, see this section of the [LangGraph conceptual guide](../../concepts/persistence.md). + +The LangGraph Cloud API provides several endpoints for creating and managing threads and thread state. See the [API reference](../../cloud/reference/api/api_ref.html#tag/threads) for more details. \ No newline at end of file diff --git a/docs/docs/cloud/concepts/webhooks.md b/docs/docs/cloud/concepts/webhooks.md new file mode 100644 index 000000000..206b97006 --- /dev/null +++ b/docs/docs/cloud/concepts/webhooks.md @@ -0,0 +1,7 @@ +# Webhooks + +Webhooks enable event-driven communication from your LangGraph Cloud application to external services. For example, you may want to issue an update to a separate service once an API call to LangGraph Cloud has finished running. + +Many LangGraph Cloud endpoints accept a `webhook` parameter. If this parameter is specified by a an endpoint that can accept POST requests, LangGraph Cloud will send a request at the completion of a run. + +See the corresponding [how-to guide](../../cloud/how-tos/webhooks.md) for more detail. \ No newline at end of file diff --git a/docs/docs/cloud/deployment/cloud.md b/docs/docs/cloud/deployment/cloud.md index e5cd9ce0b..aba1122d8 100644 --- a/docs/docs/cloud/deployment/cloud.md +++ b/docs/docs/cloud/deployment/cloud.md @@ -1,11 +1,11 @@ -# How to Deploy to Cloud SaaS (Beta) +# How to Deploy to Cloud SaaS Before deploying, review the [conceptual guide for the Cloud SaaS](../../concepts/langgraph_cloud.md) deployment option. ## Prerequisites 1. LangGraph Cloud applications are deployed from GitHub repositories. Configure and upload a LangGraph Cloud application to a GitHub repository in order to deploy it to LangGraph Cloud. -1. [Verify that the LangGraph API runs locally](test_locally.md). If the API does not run successfully (i.e. `langgraph dev`), deploying to LangGraph Cloud will fail as well. +1. [Verify that the LangGraph API runs locally](../../tutorials/langgraph-platform/local-server.md). If the API does not run successfully (i.e. `langgraph dev`), deploying to LangGraph Cloud will fail as well. ## Create New Deployment diff --git a/docs/docs/cloud/deployment/img/01_login.png b/docs/docs/cloud/deployment/img/01_login.png deleted file mode 100644 index e0487b935..000000000 Binary files a/docs/docs/cloud/deployment/img/01_login.png and /dev/null differ diff --git a/docs/docs/cloud/deployment/img/02_langgraph_platform.png b/docs/docs/cloud/deployment/img/02_langgraph_platform.png deleted file mode 100644 index 6b7a6d1f6..000000000 Binary files a/docs/docs/cloud/deployment/img/02_langgraph_platform.png and /dev/null differ diff --git a/docs/docs/cloud/deployment/img/03_deployments_page.png b/docs/docs/cloud/deployment/img/03_deployments_page.png deleted file mode 100644 index cbb1b23f4..000000000 Binary files a/docs/docs/cloud/deployment/img/03_deployments_page.png and /dev/null differ diff --git a/docs/docs/cloud/deployment/img/04_create_new_deployment.png b/docs/docs/cloud/deployment/img/04_create_new_deployment.png deleted file mode 100644 index 369d54c7c..000000000 Binary files a/docs/docs/cloud/deployment/img/04_create_new_deployment.png and /dev/null differ diff --git a/docs/docs/cloud/deployment/img/05_configure_deployment.png b/docs/docs/cloud/deployment/img/05_configure_deployment.png deleted file mode 100644 index 897762f25..000000000 Binary files a/docs/docs/cloud/deployment/img/05_configure_deployment.png and /dev/null differ diff --git a/docs/docs/cloud/deployment/self_hosted_control_plane.md b/docs/docs/cloud/deployment/self_hosted_control_plane.md index 737ce31c0..23a3530fa 100644 --- a/docs/docs/cloud/deployment/self_hosted_control_plane.md +++ b/docs/docs/cloud/deployment/self_hosted_control_plane.md @@ -1,4 +1,4 @@ -# How to Deploy Self-Hosted Control Plane (Beta) +# How to Deploy Self-Hosted Control Plane Before deploying, review the [conceptual guide for the Self-Hosted Control Plane](../../concepts/langgraph_self_hosted_control_plane.md) deployment option. @@ -6,7 +6,7 @@ Before deploying, review the [conceptual guide for the Self-Hosted Control Plane 1. You are using Kubernetes. 1. You have self-hosted LangSmith deployed. -1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](./test_locally.md). +1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](../../tutorials/langgraph-platform/local-server.md). 1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to build a Docker image (i.e. `langgraph build`) and push it to a registry your Kubernetes cluster has access to. 1. `KEDA` is installed on your cluster. @@ -46,4 +46,4 @@ Before deploying, review the [conceptual guide for the Self-Hosted Control Plane 1. In your `values.yaml` file, configure the `hostBackendImage` and `operatorImage` options (if you need to mirror images) 1. You can also configure base templates for your agents by overriding the base templates [here](https://github.com/langchain-ai/helm/blob/main/charts/langsmith/values.yaml#L898). -1. You create a deployment from the [Control Plane UI](../../concepts/langgraph_control_plane.md#control-plane-ui). +1. You create a deployment from the [control plane UI](../../concepts/langgraph_control_plane.md#control-plane-ui). diff --git a/docs/docs/cloud/deployment/self_hosted_data_plane.md b/docs/docs/cloud/deployment/self_hosted_data_plane.md index c9512eb10..ed75266fb 100644 --- a/docs/docs/cloud/deployment/self_hosted_data_plane.md +++ b/docs/docs/cloud/deployment/self_hosted_data_plane.md @@ -1,10 +1,10 @@ -# How to Deploy Self-Hosted Data Plane (Beta) +# How to Deploy Self-Hosted Data Plane Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](../../concepts/langgraph_self_hosted_data_plane.md) deployment option. ## Prerequisites -1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](./test_locally.md). +1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](../../tutorials/langgraph-platform/local-server.md). 1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to build a Docker image (i.e. `langgraph build`) and push it to a registry your Kubernetes cluster or Amazon ECS cluster has access to. ## Kubernetes @@ -46,7 +46,7 @@ Before deploying, review the [conceptual guide for the Self-Hosted Data Plane](. langgraph-dataplane-listener-7fccd788-wn2dx 0/1 Running 0 9s langgraph-dataplane-redis-0 0/1 ContainerCreating 0 9s -1. You create a deployment from the [Control Plane UI](../../concepts/langgraph_control_plane.md#control-plane-ui). +1. You create a deployment from the [control plane UI](../../concepts/langgraph_control_plane.md#control-plane-ui). ## Amazon ECS diff --git a/docs/docs/cloud/deployment/setup.md b/docs/docs/cloud/deployment/setup.md index ceb7834b0..766e6bfab 100644 --- a/docs/docs/cloud/deployment/setup.md +++ b/docs/docs/cloud/deployment/setup.md @@ -1,6 +1,6 @@ -# How to Set Up a LangGraph Application for Deployment +# How to Set Up a LangGraph Application with requirements.txt -A LangGraph application must be configured with a [LangGraph API configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Cloud (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph application for deployment using `requirements.txt` to specify project dependencies. +A LangGraph application must be configured with a [LangGraph configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Cloud (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph application for deployment using `requirements.txt` to specify project dependencies. This walkthrough is based on [this repository](https://github.com/langchain-ai/langgraph-example), which you can play around with to learn more about how to setup your LangGraph application for deployment. @@ -8,9 +8,9 @@ This walkthrough is based on [this repository](https://github.com/langchain-ai/l If you prefer using poetry for dependency management, check out [this how-to guide](./setup_pyproject.md) on using `pyproject.toml` for LangGraph Cloud. !!! tip "Setup with a Monorepo" - If you are interested in deploying a graph located inside a monorepo, take a look at [this](https://github.com/langchain-ai/langgraph-example-monorepo) repository for an example of how to do so. + If you are interested in deploying a graph located inside a monorepo, take a look at [this repository](https://github.com/langchain-ai/langgraph-example-monorepo) for an example of how to do so. -The final repo structure will look something like this: +The final repository structure will look something like this: ```bash my-app/ @@ -31,17 +31,17 @@ After each step, an example file directory is provided to demonstrate how code c ## Specify Dependencies -Dependencies can optionally be specified in one of the following files: `pyproject.toml`, `setup.py`, or `requirements.txt`. If none of these files is created, then dependencies can be specified later in the [LangGraph API configuration file](#create-langgraph-api-config). +Dependencies can optionally be specified in one of the following files: `pyproject.toml`, `setup.py`, or `requirements.txt`. If none of these files is created, then dependencies can be specified later in the [LangGraph configuration file](#create-langgraph-api-config). The dependencies below will be included in the image, you can also use them in your code, as long as with a compatible version range: ``` -langgraph>=0.2.56,<0.4.0 -langgraph-sdk>=0.1.53 -langgraph-checkpoint>=2.0.15,<3.0 -langchain-core>=0.2.38,<0.4.0 +langgraph>=0.3.27 +langgraph-sdk>=0.1.66 +langgraph-checkpoint>=2.0.23 +langchain-core>=0.2.38 langsmith>=0.1.63 -orjson>=3.9.7 +orjson>=3.9.7,<3.10.17 httpx>=0.25.0 tenacity>=8.0.0 uvicorn>=0.26.0 @@ -49,7 +49,8 @@ sse-starlette>=2.1.0,<2.2.0 uvloop>=0.18.0 httptools>=0.5.0 jsonschema-rs>=0.20.0 -structlog>=23.1.0 +structlog>=24.1.0 +cloudpickle>=3.0.0 ``` Example `requirements.txt` file: @@ -94,9 +95,9 @@ my-app/ ## Define Graphs -Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][langgraph.graph.graph.CompiledGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph API configuration file](../reference/cli.md#configuration-file). +Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][langgraph.graph.graph.CompiledGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file). -Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repo](https://github.com/langchain-ai/langgraph-example) to see their implementation): +Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example) to see their implementation): ```python # my_agent/agent.py @@ -147,9 +148,9 @@ my-app/ └── .env # environment variables ``` -## Create LangGraph API Config +## Create LangGraph Configuration File -Create a [LangGraph API configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph CLI reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file. +Create a [LangGraph configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph configuration file reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file. Example `langgraph.json` file: @@ -165,8 +166,8 @@ Example `langgraph.json` file: Note that the variable name of the `CompiledGraph` appears at the end of the value of each subkey in the top-level `graphs` key (i.e. `:`). -!!! warning "Configuration Location" - The LangGraph API configuration file must be placed in a directory that is at the same level or higher than the Python files that contain compiled graphs and associated dependencies. +!!! warning "Configuration File Location" + The LangGraph configuration file must be placed in a directory that is at the same level or higher than the Python files that contain compiled graphs and associated dependencies. Example file directory: @@ -187,4 +188,4 @@ my-app/ ## Next -After you setup your project and place it in a github repo, it's time to [deploy your app](./cloud.md). +After you setup your project and place it in a GitHub repository, it's time to [deploy your app](./cloud.md). diff --git a/docs/docs/cloud/deployment/setup_javascript.md b/docs/docs/cloud/deployment/setup_javascript.md index b3de67bea..aefc7bdb5 100644 --- a/docs/docs/cloud/deployment/setup_javascript.md +++ b/docs/docs/cloud/deployment/setup_javascript.md @@ -1,10 +1,10 @@ -# How to Set Up a LangGraph.js Application for Deployment +# How to Set Up a LangGraph.js Application -A [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) application must be configured with a [LangGraph API configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Cloud (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph.js application for deployment using `package.json` to specify project dependencies. +A [LangGraph.js](https://langchain-ai.github.io/langgraphjs/) application must be configured with a [LangGraph configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Cloud (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph.js application for deployment using `package.json` to specify project dependencies. This walkthrough is based on [this repository](https://github.com/langchain-ai/langgraphjs-studio-starter), which you can play around with to learn more about how to setup your LangGraph application for deployment. -The final repo structure will look something like this: +The final repository structure will look something like this: ```bash my-app/ @@ -23,7 +23,7 @@ After each step, an example file directory is provided to demonstrate how code c ## Specify Dependencies -Dependencies can be specified in a `package.json`. If none of these files is created, then dependencies can be specified later in the [LangGraph API configuration file](#create-langgraph-api-config). +Dependencies can be specified in a `package.json`. If none of these files is created, then dependencies can be specified later in the [LangGraph configuration file](#create-langgraph-api-config). Example `package.json` file: @@ -78,7 +78,7 @@ my-app/ ## Define Graphs -Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each compiled graph to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph API configuration file](../reference/cli.md#configuration-file). +Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each compiled graph to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file). Here is an example `agent.ts`: @@ -176,7 +176,7 @@ my-app/ ## Create LangGraph API Config -Create a [LangGraph API configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph CLI reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file. +Create a [LangGraph configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph configuration file reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file. Example `langgraph.json` file: @@ -196,8 +196,8 @@ Note that the variable name of the `CompiledGraph` appears at the end of the val !!! info "Configuration Location" - The LangGraph API configuration file must be placed in a directory that is at the same level or higher than the TypeScript files that contain compiled graphs and associated dependencies. + The LangGraph configuration file must be placed in a directory that is at the same level or higher than the TypeScript files that contain compiled graphs and associated dependencies. ## Next -After you setup your project and place it in a github repo, it's time to [deploy your app](./cloud.md). +After you setup your project and place it in a GitHub repository, it's time to [deploy your app](./cloud.md). diff --git a/docs/docs/cloud/deployment/setup_pyproject.md b/docs/docs/cloud/deployment/setup_pyproject.md index 9af697611..28dda13bf 100644 --- a/docs/docs/cloud/deployment/setup_pyproject.md +++ b/docs/docs/cloud/deployment/setup_pyproject.md @@ -1,6 +1,6 @@ -# How to Set Up a LangGraph Application for Deployment +# How to Set Up a LangGraph Application with pyproject.toml -A LangGraph application must be configured with a [LangGraph API configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Cloud (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph application for deployment using `pyproject.toml` to define your package's dependencies. +A LangGraph application must be configured with a [LangGraph configuration file](../reference/cli.md#configuration-file) in order to be deployed to LangGraph Cloud (or to be self-hosted). This how-to guide discusses the basic steps to setup a LangGraph application for deployment using `pyproject.toml` to define your package's dependencies. This walkthrough is based on [this repository](https://github.com/langchain-ai/langgraph-example-pyproject), which you can play around with to learn more about how to setup your LangGraph application for deployment. @@ -10,7 +10,7 @@ This walkthrough is based on [this repository](https://github.com/langchain-ai/l !!! tip "Setup with a Monorepo" If you are interested in deploying a graph located inside a monorepo, take a look at [this](https://github.com/langchain-ai/langgraph-example-monorepo) repository for an example of how to do so. -The final repo structure will look something like this: +The final repository structure will look something like this: ```bash my-app/ @@ -31,17 +31,17 @@ After each step, an example file directory is provided to demonstrate how code c ## Specify Dependencies -Dependencies can optionally be specified in one of the following files: `pyproject.toml`, `setup.py`, or `requirements.txt`. If none of these files is created, then dependencies can be specified later in the [LangGraph API configuration file](#create-langgraph-api-config). +Dependencies can optionally be specified in one of the following files: `pyproject.toml`, `setup.py`, or `requirements.txt`. If none of these files is created, then dependencies can be specified later in the [LangGraph configuration file](#create-langgraph-api-config). The dependencies below will be included in the image, you can also use them in your code, as long as with a compatible version range: ``` -langgraph>=0.2.56,<0.4.0 -langgraph-sdk>=0.1.53 -langgraph-checkpoint>=2.0.15,<3.0 -langchain-core>=0.2.38,<0.4.0 +langgraph>=0.3.27 +langgraph-sdk>=0.1.66 +langgraph-checkpoint>=2.0.23 +langchain-core>=0.2.38 langsmith>=0.1.63 -orjson>=3.9.7 +orjson>=3.9.7,<3.10.17 httpx>=0.25.0 tenacity>=8.0.0 uvicorn>=0.26.0 @@ -49,7 +49,8 @@ sse-starlette>=2.1.0,<2.2.0 uvloop>=0.18.0 httptools>=0.5.0 jsonschema-rs>=0.20.0 -structlog>=23.1.0 +structlog>=24.1.0 +cloudpickle>=3.0.0 ``` Example `pyproject.toml` file: @@ -68,7 +69,6 @@ python = ">=3.9" langgraph = "^0.2.0" langchain-fireworks = "^0.1.3" - [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" @@ -97,15 +97,15 @@ Example file directory: ```bash my-app/ -├── .env # file with environment variables +├── .env # file with environment variables └── pyproject.toml ``` ## Define Graphs -Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][langgraph.graph.graph.CompiledGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph API configuration file](../reference/cli.md#configuration-file). +Implement your graphs! Graphs can be defined in a single file or multiple files. Make note of the variable names of each [CompiledGraph][langgraph.graph.graph.CompiledGraph] to be included in the LangGraph application. The variable names will be used later when creating the [LangGraph configuration file](../reference/cli.md#configuration-file). -Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repo](https://github.com/langchain-ai/langgraph-example-pyproject) to see their implementation): +Example `agent.py` file, which shows how to import from other modules you define (code for the modules is not shown here, please see [this repository](https://github.com/langchain-ai/langgraph-example-pyproject) to see their implementation): ```python # my_agent/agent.py @@ -156,9 +156,9 @@ my-app/ └── pyproject.toml ``` -## Create LangGraph API Config +## Create LangGraph Configuration File -Create a [LangGraph API configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph CLI reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file. +Create a [LangGraph configuration file](../reference/cli.md#configuration-file) called `langgraph.json`. See the [LangGraph configuration file reference](../reference/cli.md#configuration-file) for detailed explanations of each key in the JSON object of the configuration file. Example `langgraph.json` file: @@ -174,8 +174,8 @@ Example `langgraph.json` file: Note that the variable name of the `CompiledGraph` appears at the end of the value of each subkey in the top-level `graphs` key (i.e. `:`). -!!! warning "Configuration Location" - The LangGraph API configuration file must be placed in a directory that is at the same level or higher than the Python files that contain compiled graphs and associated dependencies. +!!! warning "Configuration File Location" + The LangGraph configuration file must be placed in a directory that is at the same level or higher than the Python files that contain compiled graphs and associated dependencies. Example file directory: @@ -196,4 +196,4 @@ my-app/ ## Next -After you setup your project and place it in a github repo, it's time to [deploy your app](./cloud.md). +After you setup your project and place it in a GitHub repository, it's time to [deploy your app](./cloud.md). diff --git a/docs/docs/cloud/deployment/standalone_container.md b/docs/docs/cloud/deployment/standalone_container.md index de1315522..57ab6c706 100644 --- a/docs/docs/cloud/deployment/standalone_container.md +++ b/docs/docs/cloud/deployment/standalone_container.md @@ -4,7 +4,7 @@ Before deploying, review the [conceptual guide for the Standalone Container](../ ## Prerequisites -1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](./test_locally.md). +1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to [test your application locally](../../tutorials/langgraph-platform/local-server.md). 1. Use the [LangGraph CLI](../../concepts/langgraph_cli.md) to build a Docker image (i.e. `langgraph build`). 1. The following environment variables are needed for a standalone container deployment. 1. `REDIS_URI`: Connection details to a Redis instance. Redis will be used as a pub-sub broker to enable streaming real time output from background runs. The value of `REDIS_URI` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url). @@ -21,7 +21,7 @@ Before deploying, review the [conceptual guide for the Standalone Container](../ `` and `database_name_2` are different databases within the same instance, but `` is shared. **The same database cannot be used for separate deployments**. - 1. `LANGSMITH_API_KEY`: (if using [Lite](../../concepts/langgraph_data_plane.md#lite-vs-enterprise)) LangSmith API key. This will be used to authenticate ONCE at server start up. + 1. `LANGSMITH_API_KEY`: (if using [Lite](../../concepts/langgraph_server.md#server-versions)) LangSmith API key. This will be used to authenticate ONCE at server start up. 1. `LANGGRAPH_CLOUD_LICENSE_KEY`: (if using [Enterprise](../../concepts/langgraph_data_plane.md#lite-vs-enterprise)) LangGraph Platform license key. This will be used to authenticate ONCE at server start up. 1. `LANGSMITH_ENDPOINT`: To send traces to a [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) instance, set `LANGSMITH_ENDPOINT` to the hostname of the self-hosted LangSmith instance. diff --git a/docs/docs/cloud/deployment/test_locally.md b/docs/docs/cloud/deployment/test_locally.md deleted file mode 100644 index fb037e47b..000000000 --- a/docs/docs/cloud/deployment/test_locally.md +++ /dev/null @@ -1,196 +0,0 @@ -# How to test a LangGraph app locally - -This guide assumes you have a LangGraph app correctly set up with a proper configuration file and a corresponding compiled graph, and that you have a proper LangChain API key. - -Testing locally ensures that there are no errors or conflicts with Python dependencies and confirms that the configuration file is specified correctly. - -## Setup - -Install the LangGraph CLI package: - -```bash -pip install -U "langgraph-cli[inmem]" -``` - -Ensure you have an API key, which you can create from the [LangSmith UI](https://smith.langchain.com) (Settings > API Keys). This is required to authenticate that you have LangGraph Cloud access. After you have saved the key to a safe place, place the following line in your `.env` file: - -```python -LANGSMITH_API_KEY = ********* -``` - -## Start the API server - -Once you have installed the CLI, you can run the following command to start the API server for local testing: - -```shell -langgraph dev -``` - -This will start up the LangGraph API server locally. If this runs successfully, you should see something like: - -> Ready! -> -> - API: [http://localhost:2024](http://localhost:2024/) -> -> - Docs: http://localhost:2024/docs -> -> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 - -!!! note "In-Memory Mode" - - The `langgraph dev` command starts LangGraph Server in an in-memory mode. This mode is suitable for development and testing purposes. For production use, you should deploy LangGraph Server with access to a persistent storage backend. - - If you want to test your application with a persistent storage backend, you can use the `langgraph up` command instead of `langgraph dev`. You will - need to have `docker` installed on your machine to use this command. - - -### Interact with the server - -We can now interact with the API server using the LangGraph SDK. First, we need to start our client, select our assistant (in this case a graph we called "agent", make sure to select the proper assistant you wish to test). - -You can either initialize by passing authentication or by setting an environment variable. - -#### Initialize with authentication - -=== "Python" - - ```python - from langgraph_sdk import get_client - - # only pass the url argument to get_client() if you changed the default port when calling langgraph dev - client = get_client(url=,api_key=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - thread = await client.threads.create() - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - // only set the apiUrl if you changed the default port when calling langgraph dev - const client = new Client({ apiUrl: , apiKey: }); - // Using the graph deployed with the name "agent" - const assistantId = "agent"; - const thread = await client.threads.create(); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' - --header 'x-api-key: ' - ``` - - -#### Initialize with environment variables - -If you have a `LANGSMITH_API_KEY` set in your environment, you do not need to explicitly pass authentication to the client - -=== "Python" - - ```python - from langgraph_sdk import get_client - - # only pass the url argument to get_client() if you changed the default port when calling langgraph dev - client = get_client() - # Using the graph deployed with the name "agent" - assistant_id = "agent" - thread = await client.threads.create() - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - // only set the apiUrl if you changed the default port when calling langgraph dev - const client = new Client(); - // Using the graph deployed with the name "agent" - const assistantId = "agent"; - const thread = await client.threads.create(); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' - ``` - -Now we can invoke our graph to ensure it is working. Make sure to change the input to match the proper schema for your graph. - -=== "Python" - - ```python - input = {"messages": [{"role": "user", "content": "what's the weather in sf"}]} - async for chunk in client.runs.stream( - thread["thread_id"], - assistant_id, - input=input, - stream_mode="updates", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` -=== "Javascript" - - ```js - const input = { "messages": [{ "role": "user", "content": "what's the weather in sf"}] } - - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantId, - { - input: input, - streamMode: "updates", - } - ); - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what's the weather in sf\"}]}, - \"stream_mode\": [ - \"events\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - -If your graph works correctly, you should see your graph output displayed in the console. Of course, there are many more ways you might need to test your graph, for a full list of commands you can send with the SDK, see the [Python](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) and [JS/TS](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/js_ts_sdk_ref/) references. diff --git a/docs/docs/cloud/how-tos/assistant_versioning.md b/docs/docs/cloud/how-tos/assistant_versioning.md index 9b1fccc37..085371daa 100644 --- a/docs/docs/cloud/how-tos/assistant_versioning.md +++ b/docs/docs/cloud/how-tos/assistant_versioning.md @@ -1,6 +1,11 @@ -# How to version assistants +# How to version Assistants -In this how-to guide we will walk through how you can create and manage different assistant versions. If you haven't already, you can read [this](../../concepts/assistants.md#versioning-assistants) conceptual guide to gain a better understanding of what assistant versioning is. This how-to assumes you have a graph that is configurable, which means you have defined a config schema and passed it to your graph as follows: +!!! info "Prerequisites" + + - [Assistants Overview](../../concepts/assistants.md) + - [How to create an Assistant](./configuration_cloud.md) + +In this guide we will show you how to create, manage and use multiple versions of an assistant. If you have not already, please first see [this](./configuration_cloud.md) guide on creating an assistant. For this example, assume you have a graph with the following configuration schema: === "Python" @@ -9,7 +14,7 @@ In this how-to guide we will walk through how you can create and manage differen model_name: Literal["anthropic", "openai"] = "anthropic" system_prompt: str - agent = StateGraph(State, config_schema=Config) + builder = StateGraph(State, config_schema=Config) ``` === "Javascript" @@ -24,96 +29,63 @@ In this how-to guide we will walk through how you can create and manage differen // the rest of your code - const agent = new StateGraph(StateAnnotation, ConfigAnnotation); + const builder = new StateGraph(StateAnnotation, ConfigAnnotation); ``` -## Setup +And that you have the following assistant already created: -First let's set up our client and thread. If you are using the Studio, just open the application to the graph called "agent". If using cURL, you don't need to do anything except copy down your deployment URL and the name of the graph you want to use. - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - graph_name = "agent" - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const graphName = "agent"; - ``` - -## Create an assistant - -For this example, we will create an assistant by modifying the model name that is used in our graph. We can create a new assistant called "openai_assistant" for this: - -=== "Python" - - ```python - openai_assistant = await client.assistants.create(graph_name, config={"configurable": {"model_name": "openai"}}, name="openai_assistant") - ``` - -=== "Javascript" - - ```js - const openaiAssistant = await client.assistants.create({graphId: graphName, config: { configurable: {"modelName": "openai"}}, name: "openaiAssistant"}); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /assistants \ - --header 'Content-Type: application/json' \ - --data '{ - "graph_id": "agent", - "config": {"model_name": "openai"}, - "name": "openai_assistant" - }' - ``` - -### Using the studio - -To create an assistant using the studio do the following steps: - -1. Click on the "Create New Assistant" button: - - ![click create](./img/click_create_assistant.png) - -1. Use the create assistant pane to enter info for the assistant you wish to create, and then click create: - - ![create](./img/create_assistant.png) - -1. See that your assistant was created and is displayed in the Studio - - ![view create](./img/create_assistant_view.png) - -1. Click on the edit button next to the selected assistant to manage your created assistant: - - ![create edit](./img/edit_created_assistant.png) + { + "assistant_id": "62e209ca-9154-432a-b9e9-2d75c7a9219b", + "graph_id": "agent", + "name": "Open AI Assistant" + "config": { + "configurable": { + "model_name": "openai", + "system_prompt": "You are a helpful assistant." + } + }, + "metadata": {} + "created_at": "2024-08-31T03:09:10.230718+00:00", + "updated_at": "2024-08-31T03:09:10.230718+00:00", + } ## Create a new version for your assistant -Let's now say we wanted to add a system prompt to our assistant. We can do this by using the `update` endpoint as follows. Please note that you must pass in the ENTIRE config (and metadata if you are using it). The update endpoint creates new versions completely from scratch and does not rely on previously entered config. In this case, we need to continue telling the assistant to use "openai" as the model. +### LangGraph SDK +To edit the assistant, use the `update` method. This will create a new version of the assistant with the provided edits. See the [Python](../reference/sdk/python_sdk_ref.md#langgraph_sdk.client.AssistantsClient.update) and [JS](../reference/sdk/js_ts_sdk_ref.md#update) SDK reference docs for more information. + +!!! note "Note" + You must pass in the ENTIRE config (and metadata if you are using it). The update endpoint creates new versions completely from scratch and does not rely on previously versions. + +For example, to update your assistant's system prompt: === "Python" ```python - openai_assistant_v2 = await client.assistants.update(openai_assistant['assistant_id'], config={"configurable": {"model_name": "openai", "system_prompt": "You are a helpful assistant!"}}) + openai_assistant_v2 = await client.assistants.update( + openai_assistant["assistant_id"], + config={ + "configurable": { + "model_name": "openai", + "system_prompt": "You are an unhelpful assistant!", + } + }, + ) ``` === "Javascript" ```js - const openaiAssistantV2 = await client.assistants.update(openaiAssistant['assistant_id'], {config: { configurable: {"modelName": "openai", "systemPrompt": "You are a helpful assistant!"}}}); + const openaiAssistantV2 = await client.assistants.update( + openai_assistant["assistant_id"], + { + config: { + configurable: { + model_name: 'openai', + system_prompt: 'You are an unhelpful assistant!', + }, + }, + }); ``` === "CURL" @@ -123,27 +95,29 @@ Let's now say we wanted to add a system prompt to our assistant. We can do this --url /assistants/ \ --header 'Content-Type: application/json' \ --data '{ - "config": {"model_name": "openai", "system_prompt": "You are a helpful assistant!"} + "config": {"model_name": "openai", "system_prompt": "You are an unhelpful assistant!"} }' ``` -### Using the studio +This will create a new version of the assistant with the updated parameters and set this as the active version of your assistant. If you now run your graph and pass in this assistant id, it will use this latest version. -1. First, click on the edit button next to the `openai_assistant`. Then, add a system prompt and click "Save New Version": +### LangGraph Platform UI - ![create new version](./img/create_new_version.png) +You can also edit assistants from the LangGraph Platform UI. -1. Then you can see it is selected in the assistant dropdown: +Inside your deployment, select the "Assistants" tab. This will load a table of all of the assistants in your deployment, across all graphs. - ![see version dropdown](./img/see_new_version.png) +To edit an existing assistant, select the "Edit" button for the specified assistant. This will open a form where you can edit the assistant's name, description, and configuration. -1. And you can see all the version history in the edit pane for the assistant: +Additionally, if using LangGraph Studio, you can edit the assistants and create new versions via the "Manage Assistants" button. - ![see versions](./img/see_version_history.png) +## Use a previous assistant version -## Point your assistant to a different version +### LangGraph SDK -After having created multiple versions, we can change the version our assistant points to both by using the SDK and also the Studio. In this case we will be resetting the `openai_assistant` we just created two versions for to point back to the first version. When you create a new version (by using the `update` endpoint) the assistant automatically points to the newly created version, so following the code above our `openai_assistant` is pointing to the second version. Here we will change it to point to the first version: +You can also change the active version of your assistant. To do so, use the `setLatest` method. + +In the example above, to rollback to the first version of the assistant: === "Python" @@ -168,16 +142,11 @@ After having created multiple versions, we can change the version our assistant }' ``` +If you now run your graph and pass in this assistant id, it will use the first version of the assistant. -### Using the studio +### LangGraph Platform UI -To change the version, all you have to do is click into the edit pane for an assistant, select the version you want to change to, and then click the "Set As Current Version" button - -![set version](./img/select_different_version.png) - -## Using your assistant versions - -Whether you are a business user iterating without writing code, or a developer using the SDK - assistant versioning allows you to quickly test different agents in a controlled environment, making it easy to iterate fast. You can use any of the assistant versions just how you would a normal assistant, and can read more about how to stream output from these assistants by reading [these guides](https://langchain-ai.github.io/langgraph/cloud/how-tos/#streaming) or [this one](https://langchain-ai.github.io/langgraph/cloud/how-tos/invoke_studio/) if you are using the Studio. +If using LangGraph Studio, to set the active version of your asssistant, click the "Manage Assistants" button and locate the assistant you would like to use. Select the assistant and the version, and then click the "Active" toggle. This will update the assistant to make the selected version active. !!! warning "Deleting Assistants" - Deleting as assistant will delete ALL of it's versions, since they all point to the same assistant ID. There is currently no way to just delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use. \ No newline at end of file + Deleting as assistant will delete ALL of it's versions. There is currently no way to delete a single version, but by pointing your assistant to the correct version you can skip any versions that you don't wish to use. diff --git a/docs/docs/cloud/how-tos/configurable_headers.md b/docs/docs/cloud/how-tos/configurable_headers.md index 7a61dff0e..1a65f34e8 100644 --- a/docs/docs/cloud/how-tos/configurable_headers.md +++ b/docs/docs/cloud/how-tos/configurable_headers.md @@ -1,6 +1,6 @@ # Configurable Headers -LangGraph allows runtime configuration to modify agent behavior and permissions dynamically. When using the [LangGraph Platform](../quick_start.md), you can pass this configuration in the request body (`config`) or specific request headers. This enables adjustments based on user identity or other request data (see the [configuration how-to](../../how-tos/configuration.ipynb) for more details on how to access within your graph). +LangGraph allows runtime configuration to modify agent behavior and permissions dynamically. When using the [LangGraph Platform](../quick_start.md), you can pass this configuration in the request body (`config`) or specific request headers. This enables adjustments based on user identity or other request data. For privacy, control which headers are passed to the runtime configuration via the `http.configurable_headers` section in your `langgraph.json` file. @@ -65,8 +65,6 @@ async def generate_agent(config): } ``` -For more examples on how to use runtime configuration, check out the [configuration how-to](../../how-tos/configuration.ipynb). - ### Opt-out of configurable headers If you'd like to opt-out of configurable headers, you can simply set a wildcard pattern in the `exclude` list: diff --git a/docs/docs/cloud/how-tos/configuration_cloud.md b/docs/docs/cloud/how-tos/configuration_cloud.md index 8954d966f..dd38ece29 100644 --- a/docs/docs/cloud/how-tos/configuration_cloud.md +++ b/docs/docs/cloud/how-tos/configuration_cloud.md @@ -1,19 +1,23 @@ -# How to create agents with configuration +# How to create Assistants -One of the benefits of LangGraph API is that it lets you create agents with different configurations. -This is useful when you want to: +!!! info "Prerequisites" -- Define a cognitive architecture once as a LangGraph -- Let that LangGraph be configurable across some attributes (for example, system message or LLM to use) -- Let users create agents with arbitrary configurations, save them, and then use them in the future + - [Assistants Overview](../../concepts/assistants.md) + - [Configuration](../../concepts/low_level.md#configuration) -In this guide we will show how to do that for the default agent we have built in. +In this guide we will show how to create and configure an assistant. -If you look at the agent we defined, you can see that inside the `call_model` node we have created the model based on some configuration. That node looks like: +First, as a brief refresher on the concept of configurations, consider the following simple `call_model` node and configuration schema. Observe that this node tries to read and use the `model_name` as defined by the `config` object's `configurable`. === "Python" ```python + + class ConfigSchema(TypedDict): + model_name: str + + builder = StateGraph(AgentState, config_schema=ConfigSchema) + def call_model(state, config): messages = state["messages"] model_name = config.get('configurable', {}).get("model_name", "anthropic") @@ -26,6 +30,15 @@ If you look at the agent we defined, you can see that inside the `call_model` no === "Javascript" ```js + import { Annotation } from "@langchain/langgraph"; + + const ConfigSchema = Annotation.Root({ + model_name: Annotation, + system_prompt: + }); + + const builder = new StateGraph(AgentState, ConfigSchema) + function callModel(state: State, config: RunnableConfig) { const messages = state.messages; const modelName = config.configurable?.model_name ?? "anthropic"; @@ -36,9 +49,15 @@ If you look at the agent we defined, you can see that inside the `call_model` no } ``` -We are looking inside the config for a `model_name` parameter (which defaults to `anthropic` if none is found). That means that by default we are using Anthropic as our model provider. In this example we will see an example of how to create an example agent that is configured to use OpenAI. +For more information on configurations, [see here](../../concepts/low_level.md#configuration). -First let's set up our client and thread: +## Creating an Assistant + +### LangGraph SDK + +To create an assistant, use the [LangGraph SDK](../../concepts/sdk.md) `create` method. See the [Python](../reference/sdk/python_sdk_ref.md#langgraph_sdk.client.AssistantsClient.create) and [JS](../reference/sdk/js_ts_sdk_ref.md#create) SDK reference docs for more information. + +This example uses the same configuration schema as above, and creates an assistant with `model_name` set to `openai`. === "Python" @@ -46,84 +65,9 @@ First let's set up our client and thread: from langgraph_sdk import get_client client = get_client(url=) - # Select an assistant that is not configured - assistants = await client.assistants.search() - assistant = [a for a in assistants if not a["config"]][0] - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Select an assistant that is not configured - const assistants = await client.assistants.search(); - const assistant = assistants.find(a => !a.config); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /assistants/search \ - --header 'Content-Type: application/json' \ - --data '{ - "limit": 10, - "offset": 0 - }' | jq -c 'map(select(.config == null or .config == {})) | .[0]' - ``` - -We can now call `.get_schemas` to get schemas associated with this graph: - -=== "Python" - - ```python - schemas = await client.assistants.get_schemas( - assistant_id=assistant["assistant_id"] - ) - # There are multiple types of schemas - # We can get the `config_schema` to look at the configurable parameters - print(schemas["config_schema"]) - ``` - -=== "Javascript" - - ```js - const schemas = await client.assistants.getSchemas( - assistant["assistant_id"] - ); - // There are multiple types of schemas - // We can get the `config_schema` to look at the configurable parameters - console.log(schemas.config_schema); - ``` - -=== "CURL" - - ```bash - curl --request GET \ - --url /assistants//schemas | jq -r '.config_schema' - ``` - -Output: - - { - 'model_name': - { - 'title': 'Model Name', - 'enum': ['anthropic', 'openai'], - 'type': 'string' - } - } - -Now we can initialize an assistant with config: - -=== "Python" - - ```python openai_assistant = await client.assistants.create( # "agent" is the name of a graph we deployed - "agent", config={"configurable": {"model_name": "openai"}} + "agent", config={"configurable": {"model_name": "openai"}}, name="Open AI Assistant" ) print(openai_assistant) @@ -132,10 +76,14 @@ Now we can initialize an assistant with config: === "Javascript" ```js - let openAIAssistant = await client.assistants.create( - // "agent" is the name of a graph we deployed - "agent", { "configurable": { "model_name": "openai" } } - ); + import { Client } from "@langchain/langgraph-sdk"; + + const client = new Client({ apiUrl: }); + let openAIAssistant = await client.assistants.create({ + graphId: 'agent', + name: "Open AI Assistant", + config: { "configurable": { "model_name": "openai" } }, + }); console.log(openAIAssistant); ``` @@ -146,7 +94,7 @@ Now we can initialize an assistant with config: curl --request POST \ --url /assistants \ --header 'Content-Type: application/json' \ - --data '{"graph_id":"agent","config":{"configurable":{"model_name":"open_ai"}}}' + --data '{"graph_id":"agent", "config":{"configurable":{"model_name":"openai"}}, "name": "Open AI Assistant"}' ``` Output: @@ -154,17 +102,32 @@ Output: { "assistant_id": "62e209ca-9154-432a-b9e9-2d75c7a9219b", "graph_id": "agent", - "created_at": "2024-08-31T03:09:10.230718+00:00", - "updated_at": "2024-08-31T03:09:10.230718+00:00", + "name": "Open AI Assistant" "config": { "configurable": { - "model_name": "open_ai" + "model_name": "openai" } }, "metadata": {} + "created_at": "2024-08-31T03:09:10.230718+00:00", + "updated_at": "2024-08-31T03:09:10.230718+00:00", } -We can verify the config is indeed taking effect: +### LangGraph Platform UI + +You can also create assistants from the LangGraph Platform UI. + +Inside your deployment, select the "Assistants" tab. This will load a table of all of the assistants in your deployment, across all graphs. + +To create a new assistant, select the "+ New assistant" button. This will open a form where you can specify the graph this assistant is for, as well as provide a name, description, and the desired configuration for the assistant based on the configuration schema for that graph. + +To confirm, click "Create assistant". This will take you to [LangGraph Studio](../../concepts/langgraph_studio.md) where you can test the assistant. If you go back to the "Assistants" tab in the deployment, you will see the newly created assistant in the table. + +## Using an Assistant + +### LangGraph SDK + +We have now created an assistant called "Open AI Assistant" that has `model_name` defined as `openai`. We can now use this assistant with this configuration: === "Python" @@ -173,6 +136,7 @@ We can verify the config is indeed taking effect: input = {"messages": [{"role": "user", "content": "who made you?"}]} async for event in client.runs.stream( thread["thread_id"], + # this is where we specify the assistant id to use openai_assistant["assistant_id"], input=input, stream_mode="updates", @@ -190,6 +154,7 @@ We can verify the config is indeed taking effect: const streamResponse = client.runs.stream( thread["thread_id"], + // this is where we specify the assistant id to use openAIAssistant["assistant_id"], { input, @@ -260,5 +225,6 @@ Output: Receiving event of type: updates {'agent': {'messages': [{'content': 'I was created by OpenAI, a research organization focused on developing and advancing artificial intelligence technology.', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_157b3831f5'}, 'type': 'ai', 'name': None, 'id': 'run-e1a6b25c-8416-41f2-9981-f9cfe043f414', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}} +### LangGraph Platform UI - +Inside your deployment, select the "Assistants" tab. For the assistant you would like to use, click the "Studio" button. This will open LangGraph Studio with the selected assistant. When you submit an input (either in Graph or Chat mode), the selected assistant and its configuration will be used. diff --git a/docs/docs/cloud/how-tos/copy_threads.md b/docs/docs/cloud/how-tos/copy_threads.md index 2e83ae0e4..e26cdfe52 100644 --- a/docs/docs/cloud/how-tos/copy_threads.md +++ b/docs/docs/cloud/how-tos/copy_threads.md @@ -4,7 +4,9 @@ You may wish to copy (i.e. "fork") an existing thread in order to keep the exist ## Setup -This code assumes you already have a thread to copy. You can read about what a thread is [here](../../concepts/langgraph_server.md#threads) and learn how to stream a run on a thread in [these how-to guides](../../how-tos/index.md#streaming_1). +This code assumes you already have a thread to copy. + +For more information, see these guides on [Threads](../../cloud/concepts/threads.md) and [Streaming](../../concepts/streaming.md). ### SDK initialization diff --git a/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md b/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md index 0e684e59b..996347597 100644 --- a/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md +++ b/docs/docs/cloud/how-tos/human_in_the_loop_breakpoint.md @@ -8,9 +8,9 @@ * [LangGraph Glossary](../../concepts/low_level.md) -Human-in-the-loop (HIL) interactions are crucial for [agentic systems](../../concepts/agentic_concepts.md#human-in-the-loop). [Breakpoints](../../concepts/low_level.md#breakpoints) are a common HIL interaction pattern, allowing the graph to stop at specific steps and seek human approval before proceeding (e.g., for sensitive actions). +Human-in-the-loop (HIL) interactions are crucial for [agentic systems](../../concepts/agentic_concepts.md#human-in-the-loop). [Breakpoints](../../concepts/breakpoints.md) are a common HIL interaction pattern, allowing the graph to stop at specific steps and seek human approval before proceeding (e.g., for sensitive actions). -Breakpoints are built on top of LangGraph [checkpoints](../../concepts/low_level.md#persistence), which save the graph's state after each node execution. Checkpoints are saved in [threads](../../concepts/low_level.md#threads) that preserve graph state and can be accessed after a graph has finished execution. This allows for graph execution to pause at specific points, await human approval, and then resume execution from the last checkpoint. +Breakpoints are built on top of LangGraph [checkpoints](../../concepts/persistence.md#checkpoints), which save the graph's state after each node execution. Checkpoints are saved in [threads](../../concepts/persistence.md#threads) that preserve graph state and can be accessed after a graph has finished execution. This allows for graph execution to pause at specific points, await human approval, and then resume execution from the last checkpoint. ## Setup diff --git a/docs/docs/cloud/how-tos/human_in_the_loop_edit_state.md b/docs/docs/cloud/how-tos/human_in_the_loop_edit_state.md index 983d27d09..d1a2d8bb4 100644 --- a/docs/docs/cloud/how-tos/human_in_the_loop_edit_state.md +++ b/docs/docs/cloud/how-tos/human_in_the_loop_edit_state.md @@ -6,7 +6,7 @@ This can be in several ways, but the primary supported way is to add an "interru ## Setup -We are not going to show the full code for the graph we are hosting, but you can see it [here](../../how-tos/human_in_the_loop/edit-graph-state.ipynb#agent) if you want to. Once this graph is hosted, we are ready to invoke it and wait for user input. +We are not going to show the full code for the graph we are hosting, but you can see it [here](../../how-tos/human_in_the_loop/time-travel.ipynb) if you want to. Once this graph is hosted, we are ready to invoke it and wait for user input. ### SDK initialization diff --git a/docs/docs/cloud/how-tos/stream_debug.md b/docs/docs/cloud/how-tos/stream_debug.md deleted file mode 100644 index 0dee6a7cd..000000000 --- a/docs/docs/cloud/how-tos/stream_debug.md +++ /dev/null @@ -1,235 +0,0 @@ -# How to stream debug events - -!!! info "Prerequisites" - * [Streaming](../../concepts/streaming.md) - -This guide covers how to stream debug events from your graph (`stream_mode="debug"`). Streaming debug events produces responses containing `type` and `timestamp` keys. Debug events correspond to different steps in the graph's execution, and there are three different types of steps that will get streamed back to you: - -- `checkpoint`: These events will get streamed anytime the graph saves its state, which occurs after every super-step. Read more about checkpoints [here](https://langchain-ai.github.io/langgraph/concepts/low_level/#checkpointer) -- `task`: These events will get streamed before each super-step, and will contain information about a single task. Each super-step works by executing a list of tasks, where each task is scoped to a specific node and input. Below we will discuss the format of these tasks in more detail. -- `task_result`: After each `task` event, you will see a corresponding `task_result` event which as the name suggests contains information on the results of the task executed in the super-step. Scroll more to learn about the exact structure of these events. - -## Setup - -First let's set up our client and thread: - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - # create thread - thread = await client.threads.create() - print(thread) - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - // create thread - const thread = await client.threads.create(); - console.log(thread); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - - -Output: - - { - 'thread_id': 'd0cbe9ad-f11c-443a-9f6f-dca0ae5a0dd3', - 'created_at': '2024-06-21T22:10:27.696862+00:00', - 'updated_at': '2024-06-21T22:10:27.696862+00:00', - 'metadata': {}, - 'status': 'idle', - 'config': {}, - 'values': None - } - -## Stream graph in debug mode - -=== "Python" - - ```python - # create input - input = { - "messages": [ - { - "role": "user", - "content": "What's the weather in SF?", - } - ] - } - - # stream debug - async for chunk in client.runs.stream( - thread_id=thread["thread_id"], - assistant_id=assistant_id, - input=input, - stream_mode="debug", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` - -=== "Javascript" - - ```js - // create input - const input = { - messages: [ - { - role: "human", - content: "What's the weather in SF?", - } - ] - }; - - // stream debug - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - streamMode: "debug" - } - ); - - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"What's the weather in SF?\"}]}, - \"stream_mode\": [ - \"debug\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - - -Output: - - Receiving new event of type: metadata... - {'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2'} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-08-28T23:16:28.134680+00:00', 'step': -1, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'checkpoint_id': '1ef65938-d8f3-6b25-bfff-30a8ed6460bd', 'checkpoint_ns': ''}, 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2'}, 'values': {'messages': [], 'search_results': []}, 'metadata': {'source': 'input', 'writes': {'messages': [{'role': 'human', 'content': "What's the weather in SF?"}]}, 'step': -1}, 'next': ['__start__'], 'tasks': [{'id': 'b40d2c90-dc1e-52db-82d6-08751b769c55', 'name': '__start__', 'interrupts': []}]}} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-08-28T23:16:28.139821+00:00', 'step': 0, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'checkpoint_id': '1ef65938-d900-63f1-8000-70fe53e0da5c', 'checkpoint_ns': ''}, 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2'}, 'values': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}], 'search_results': []}, 'metadata': {'source': 'loop', 'writes': None, 'step': 0}, 'next': ['call_model'], 'tasks': [{'id': '685d89f6-542b-5e11-8cff-2963e7f4ea63', 'name': 'call_model', 'interrupts': []}]}} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-08-28T23:16:28.139928+00:00', 'step': 1, 'payload': {'id': '600a6ff3-7ff1-570a-b626-f887e9a70f1c', 'name': 'call_model', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}], 'search_results': [], 'final_answer': None}, 'triggers': ['start:call_model']}} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-08-28T23:16:28.584833+00:00', 'step': 1, 'payload': {'id': '600a6ff3-7ff1-570a-b626-f887e9a70f1c', 'name': 'call_model', 'error': None, 'result': [['messages', {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]], 'interrupts': []}} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-08-28T23:16:28.584991+00:00', 'step': 1, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'checkpoint_id': '1ef65938-dd3f-616f-8001-ce1c6f31e130', 'checkpoint_ns': ''}, 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2'}, 'values': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}, {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'search_results': []}, 'metadata': {'source': 'loop', 'writes': {'call_model': {'messages': {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}}}, 'step': 1}, 'next': ['exa_search', 'tavily_search'], 'tasks': [{'id': '43865935-be38-5f6e-8d38-d44ef369c278', 'name': 'exa_search', 'interrupts': []}, {'id': 'dc220677-2720-56c7-a524-caaff60fce2c', 'name': 'tavily_search', 'interrupts': []}]}} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-08-28T23:16:28.585219+00:00', 'step': 2, 'payload': {'id': '870b5854-2f84-533d-8e7d-87158ee948fc', 'name': 'exa_search', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}, {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'search_results': [], 'final_answer': None}, 'triggers': ['call_model']}} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-08-28T23:16:28.585219+00:00', 'step': 2, 'payload': {'id': '7589abfc-04df-58c6-8835-be172f84a7ff', 'name': 'tavily_search', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}, {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'search_results': [], 'final_answer': None}, 'triggers': ['call_model']}} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-08-28T23:16:32.422243+00:00', 'step': 2, 'payload': {'id': '7589abfc-04df-58c6-8835-be172f84a7ff', 'name': 'tavily_search', 'error': None, 'result': [['search_results', ["{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724886988, 'localtime': '2024-08-28 16:16'}, 'current': {'last_updated_epoch': 1724886900, 'last_updated': '2024-08-28 16:15', 'temp_c': 22.2, 'temp_f': 72.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 16.1, 'wind_kph': 25.9, 'wind_degree': 300, 'wind_dir': 'WNW', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 61, 'cloud': 25, 'feelslike_c': 24.6, 'feelslike_f': 76.4, 'windchill_c': 19.6, 'windchill_f': 67.2, 'heatindex_c': 19.7, 'heatindex_f': 67.4, 'dewpoint_c': 13.0, 'dewpoint_f': 55.5, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 18.7, 'gust_kph': 30.0}}"]]], 'interrupts': []}} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-08-28T23:16:34.750124+00:00', 'step': 2, 'payload': {'id': '870b5854-2f84-533d-8e7d-87158ee948fc', 'name': 'exa_search', 'error': None, 'result': [['search_results', ['The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.']]], 'interrupts': []}} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-08-28T23:16:34.750266+00:00', 'step': 2, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'checkpoint_id': '1ef65939-180b-6087-8002-f969296f8e3d', 'checkpoint_ns': ''}, 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2'}, 'values': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}, {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'search_results': ['The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.', "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724886988, 'localtime': '2024-08-28 16:16'}, 'current': {'last_updated_epoch': 1724886900, 'last_updated': '2024-08-28 16:15', 'temp_c': 22.2, 'temp_f': 72.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 16.1, 'wind_kph': 25.9, 'wind_degree': 300, 'wind_dir': 'WNW', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 61, 'cloud': 25, 'feelslike_c': 24.6, 'feelslike_f': 76.4, 'windchill_c': 19.6, 'windchill_f': 67.2, 'heatindex_c': 19.7, 'heatindex_f': 67.4, 'dewpoint_c': 13.0, 'dewpoint_f': 55.5, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 18.7, 'gust_kph': 30.0}}"]}, 'metadata': {'source': 'loop', 'writes': {'exa_search': {'search_results': ['The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.']}, 'tavily_search': {'search_results': ["{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724886988, 'localtime': '2024-08-28 16:16'}, 'current': {'last_updated_epoch': 1724886900, 'last_updated': '2024-08-28 16:15', 'temp_c': 22.2, 'temp_f': 72.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 16.1, 'wind_kph': 25.9, 'wind_degree': 300, 'wind_dir': 'WNW', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 61, 'cloud': 25, 'feelslike_c': 24.6, 'feelslike_f': 76.4, 'windchill_c': 19.6, 'windchill_f': 67.2, 'heatindex_c': 19.7, 'heatindex_f': 67.4, 'dewpoint_c': 13.0, 'dewpoint_f': 55.5, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 18.7, 'gust_kph': 30.0}}"]}}, 'step': 2}, 'next': ['summarize_search_results'], 'tasks': [{'id': '7263c738-516d-5708-b318-2c8ef54d4a33', 'name': 'summarize_search_results', 'interrupts': []}]}} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-08-28T23:16:34.750394+00:00', 'step': 3, 'payload': {'id': '5beaa05d-57d4-5acd-95c1-c7093990910f', 'name': 'summarize_search_results', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}, {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'search_results': ['The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.', "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724886988, 'localtime': '2024-08-28 16:16'}, 'current': {'last_updated_epoch': 1724886900, 'last_updated': '2024-08-28 16:15', 'temp_c': 22.2, 'temp_f': 72.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 16.1, 'wind_kph': 25.9, 'wind_degree': 300, 'wind_dir': 'WNW', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 61, 'cloud': 25, 'feelslike_c': 24.6, 'feelslike_f': 76.4, 'windchill_c': 19.6, 'windchill_f': 67.2, 'heatindex_c': 19.7, 'heatindex_f': 67.4, 'dewpoint_c': 13.0, 'dewpoint_f': 55.5, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 18.7, 'gust_kph': 30.0}}"], 'final_answer': None}, 'triggers': ['exa_search', 'tavily_search']}} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-08-28T23:16:35.851058+00:00', 'step': 3, 'payload': {'id': '5beaa05d-57d4-5acd-95c1-c7093990910f', 'name': 'summarize_search_results', 'error': None, 'result': [['final_answer', {'content': "The provided data details various twilight periods based on the sun's position relative to the horizon, alongside current weather information for San Francisco, California, as of August 28, 2024. The weather is partly cloudy with a temperature of 22.2°C (72.0°F), moderate wind from the WNW at 16.1 mph, and the UV index is 5.", 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_157b3831f5'}, 'type': 'ai', 'name': None, 'id': 'run-928c997b-9d85-4664-bd20-97ade4cc655e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]], 'interrupts': []}} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-08-28T23:16:35.851194+00:00', 'step': 3, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'be4fd54d-ff22-4e9e-8876-d5cccc0e8048', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'checkpoint_id': '1ef65939-228a-6d93-8003-8b06d7483024', 'checkpoint_ns': ''}, 'run_id': '1ef65938-d7c7-68db-b786-011aa1cb3cd2'}, 'values': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '4123a12c-46cb-4815-bdcc-32537af0cb5b', 'example': False}, {'content': 'Current weather in San Francisco', 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_a2ff031fb5'}, 'type': 'ai', 'name': None, 'id': 'run-0407bff9-3692-4ab5-9e57-2e9f396a3ee4', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'search_results': ['The time period when the sun is no more than 6 degrees below the horizon at either sunrise or sunset. The horizon should be clearly defined and the brightest stars should be visible under good atmospheric conditions (i.e. no moonlight, or other lights). One still should be able to carry on ordinary outdoor activities. The time period when the sun is between 6 and 12 degrees below the horizon at either sunrise or sunset. The horizon is well defined and the outline of objects might be visible without artificial light. Ordinary outdoor activities are not possible at this time without extra illumination. The time period when the sun is between 12 and 18 degrees below the horizon at either sunrise or sunset. The sun does not contribute to the illumination of the sky before this time in the morning, or after this time in the evening. In the beginning of morning astronomical twilight and at the end of astronomical twilight in the evening, sky illumination is very faint, and might be undetectable. The time of Civil Sunset minus the time of Civil Sunrise. The time of Actual Sunset minus the time of Actual Sunrise. The change in length of daylight between today and tomorrow is also listed when available.', "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.78, 'lon': -122.42, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1724886988, 'localtime': '2024-08-28 16:16'}, 'current': {'last_updated_epoch': 1724886900, 'last_updated': '2024-08-28 16:15', 'temp_c': 22.2, 'temp_f': 72.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 16.1, 'wind_kph': 25.9, 'wind_degree': 300, 'wind_dir': 'WNW', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 61, 'cloud': 25, 'feelslike_c': 24.6, 'feelslike_f': 76.4, 'windchill_c': 19.6, 'windchill_f': 67.2, 'heatindex_c': 19.7, 'heatindex_f': 67.4, 'dewpoint_c': 13.0, 'dewpoint_f': 55.5, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 5.0, 'gust_mph': 18.7, 'gust_kph': 30.0}}"], 'final_answer': {'content': "The provided data details various twilight periods based on the sun's position relative to the horizon, alongside current weather information for San Francisco, California, as of August 28, 2024. The weather is partly cloudy with a temperature of 22.2°C (72.0°F), moderate wind from the WNW at 16.1 mph, and the UV index is 5.", 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_157b3831f5'}, 'type': 'ai', 'name': None, 'id': 'run-928c997b-9d85-4664-bd20-97ade4cc655e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}}, 'metadata': {'source': 'loop', 'writes': {'summarize_search_results': {'final_answer': {'content': "The provided data details various twilight periods based on the sun's position relative to the horizon, alongside current weather information for San Francisco, California, as of August 28, 2024. The weather is partly cloudy with a temperature of 22.2°C (72.0°F), moderate wind from the WNW at 16.1 mph, and the UV index is 5.", 'additional_kwargs': {}, 'response_metadata': {'finish_reason': 'stop', 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_157b3831f5'}, 'type': 'ai', 'name': None, 'id': 'run-928c997b-9d85-4664-bd20-97ade4cc655e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}}}, 'step': 3}, 'next': [], 'tasks': []}} - - - -We see that our debug events start with two `checkpoint` events at step 0 and 1, which represent checkpointing before the graph is created and after it has been created. We then see a single `task` and corresponding `task_result` which corresponds to our first node, `call_model`, being triggered. After it has finished, the entire super-step is over so the graph saves another checkpoint and we see the corresponding `checkpoint` event. - -The next super-step executed two search nodes [in parallel](https://langchain-ai.github.io/langgraph/how-tos/branching/) - specifically one node will execute an Exa search, while the other will use Tavily. Executing these nodes in parallel in the same super-step creates 2 `task` events and two corresponding `task_result` events. After we receive both of those `task_result` events, we see another `checkpoint` event as we would expect. - -Lastly, we see a final `task` and `task_result` pair corresponding to the `summarize_search_results` node, which is the last node in our graph. As soon as this super-step is done we see one final `checkpoint` event corresponding to the final checkpoint of this run. - - diff --git a/docs/docs/cloud/how-tos/stream_events.md b/docs/docs/cloud/how-tos/stream_events.md deleted file mode 100644 index 83898a049..000000000 --- a/docs/docs/cloud/how-tos/stream_events.md +++ /dev/null @@ -1,295 +0,0 @@ -# How to stream events - -!!! info "Prerequisites" - * [Streaming](../../concepts/streaming.md#streaming-graph-outputs-stream-and-astream) - -This guide covers how to stream events from your graph (`stream_mode="events"`). Depending on the use case and user experience of your LangGraph application, your application may process event types differently. - -## Setup - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - # create thread - thread = await client.threads.create() - print(thread) - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - // create thread - const thread = await client.threads.create(); - console.log(thread); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - -Output: - - - { - 'thread_id': '3f4c64e0-f792-4a5e-aa07-a4404e06e0bd', - 'created_at': '2024-06-24T22:16:29.301522+00:00', - 'updated_at': '2024-06-24T22:16:29.301522+00:00', - 'metadata': {}, - 'status': 'idle', - 'config': {}, - 'values': None - } - -## Stream graph in events mode - -Streaming events produces responses containing an `event` key (in addition to other keys such as `data`). See the LangChain [`Runnable.astream_events()` reference](https://api.python.langchain.com/en/latest/runnables/langchain_core.runnables.base.Runnable.html#langchain_core.runnables.base.Runnable.astream_events) for all event types. - - -=== "Python" - - ```python - # create input - input = { - "messages": [ - { - "role": "user", - "content": "What's the weather in SF?", - } - ] - } - - # stream events - async for chunk in client.runs.stream( - thread_id=thread["thread_id"], - assistant_id=assistant_id, - input=input, - stream_mode="events", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` - -=== "Javascript" - - ```js - // create input - const input = { - "messages": [ - { - "role": "user", - "content": "What's the weather in SF?", - } - ] - } - - // stream events - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - streamMode: "events" - } - ); - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"What's the weather in sf\"}]}, - \"stream_mode\": [ - \"events\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - -Output: - - Receiving new event of type: metadata... - {'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8'} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {'input': {'messages': [{'role': 'human', 'content': "What's the weather in SF?"}]}}, 'name': 'LangGraph', 'tags': [], 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {}, 'name': 'agent', 'tags': ['graph:step:6'], 'run_id': '7bb08493-d507-4e28-b9e6-4a5eda9d04f0', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_start', 'data': {'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}]]}}, 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'b', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'e', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'g', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'i', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'n', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_end', 'data': {'output': {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, 'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}]]}}, 'run_id': 'cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'name': 'should_continue', 'tags': ['seq:step:3'], 'run_id': 'c7fe4d2d-3fb8-4e53-946d-03de13527853', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': 'tool', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'run_id': 'c7fe4d2d-3fb8-4e53-946d-03de13527853', 'name': 'should_continue', 'tags': ['seq:step:3'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '7bb08493-d507-4e28-b9e6-4a5eda9d04f0']} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '7bb08493-d507-4e28-b9e6-4a5eda9d04f0', 'name': 'agent', 'tags': ['graph:step:6'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'data': {'chunk': {'messages': [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'messages': [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}, 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}], 'sleep': None}}, 'run_id': '7bb08493-d507-4e28-b9e6-4a5eda9d04f0', 'name': 'agent', 'tags': ['graph:step:6'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 6, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {}, 'name': 'tool', 'tags': ['graph:step:7'], 'run_id': 'f044fd3d-7271-488f-b8aa-e01572ff9112', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 7, 'langgraph_node': 'tool', 'langgraph_triggers': ['branch:agent:should_continue:tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': 'f044fd3d-7271-488f-b8aa-e01572ff9112', 'name': 'tool', 'tags': ['graph:step:7'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 7, 'langgraph_node': 'tool', 'langgraph_triggers': ['branch:agent:should_continue:tool'], 'langgraph_task_idx': 0}, 'data': {'chunk': {'messages': [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': None, 'tool_call_id': 'tool_call_id'}]}}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'messages': [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}]}, 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'sleep': None}}, 'run_id': 'f044fd3d-7271-488f-b8aa-e01572ff9112', 'name': 'tool', 'tags': ['graph:step:7'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 7, 'langgraph_node': 'tool', 'langgraph_triggers': ['branch:agent:should_continue:tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {}, 'name': 'agent', 'tags': ['graph:step:8'], 'run_id': '1f4f95d0-0ce1-4061-85d4-946446bbd3e5', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_start', 'data': {'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}]]}}, 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'run_id': '028a68fb-6435-4b46-a156-c3326f73985c', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'e', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '028a68fb-6435-4b46-a156-c3326f73985c', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'n', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '028a68fb-6435-4b46-a156-c3326f73985c', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'd', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '028a68fb-6435-4b46-a156-c3326f73985c', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_end', 'data': {'output': {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, 'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}]]}}, 'run_id': '028a68fb-6435-4b46-a156-c3326f73985c', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'name': 'should_continue', 'tags': ['seq:step:3'], 'run_id': 'f2b2dfaf-475d-422b-8bf5-02a31bcc7d1a', 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': '__end__', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'run_id': 'f2b2dfaf-475d-422b-8bf5-02a31bcc7d1a', 'name': 'should_continue', 'tags': ['seq:step:3'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8', '1f4f95d0-0ce1-4061-85d4-946446bbd3e5']} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1f4f95d0-0ce1-4061-85d4-946446bbd3e5', 'name': 'agent', 'tags': ['graph:step:8'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'data': {'chunk': {'messages': [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'messages': [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}, 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}], 'sleep': None}}, 'run_id': '1f4f95d0-0ce1-4061-85d4-946446bbd3e5', 'name': 'agent', 'tags': ['graph:step:8'], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 8, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef301a5-b867-67de-9e9e-a32e53c5b1f8']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '51f2874d-f8c7-4040-8b3b-8f15429a56ae', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-5f556aa0-26ea-42e2-b9e4-7ece3a00974e', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1faf5dd0-ae97-4235-963f-5075083a027a', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-ae383611-6a42-475a-912a-09d5972e9e94', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': 'c67e08e6-e7af-4c4a-aa5e-50c8340ae341', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-cb1b98c1-c9e2-4a30-9d7a-38fa1f6224bd', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '1c9a16d2-5f0a-4eba-a0d2-240484a4ce7e', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-028a68fb-6435-4b46-a156-c3326f73985c', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}, 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'name': 'LangGraph', 'tags': [], 'metadata': {'graph_id': 'agent', 'created_by': 'system', 'run_id': '1ef301a5-b867-67de-9e9e-a32e53c5b1f8', 'user_id': '', 'thread_id': '7196a3aa-763c-4a8d-bfda-12fbfe1cd727', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'parent_ids': []} - - - - Receiving new event of type: end... - None \ No newline at end of file diff --git a/docs/docs/cloud/how-tos/stream_messages.md b/docs/docs/cloud/how-tos/stream_messages.md deleted file mode 100644 index a359956a3..000000000 --- a/docs/docs/cloud/how-tos/stream_messages.md +++ /dev/null @@ -1,331 +0,0 @@ -# How to stream messages from your graph - -!!! info "Prerequisites" - * [Streaming](../../concepts/streaming.md) - -This guide covers how to stream messages from your graph. With `stream_mode="messages-tuple"`, messages (i.e. individual LLM tokens) from any chat model invocations inside your graph nodes will be streamed back. - -## Setup - -First let's set up our client and thread: - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - # create thread - thread = await client.threads.create() - print(thread) - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - // create thread - const thread = await client.threads.create(); - console.log(thread); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - -Output: - - { - 'thread_id': 'e1431c95-e241-4d1d-a252-27eceb1e5c86', - 'created_at': '2024-06-21T15:48:59.808924+00:00', - 'updated_at': '2024-06-21T15:48:59.808924+00:00', - 'metadata': {}, - 'status': 'idle', - 'config': {}, - 'values': None - } - -## Stream graph in messages mode - -Now we can stream LLM tokens for any messages generated inside a node in the form of tuples `(message, metadata)`. Metadata contains additional information that can be useful for filtering the streamed outputs to a specific node or LLM. - -=== "Python" - - ```python - input = {"messages": [{"role": "user", "content": "what's the weather in sf"}]} - config = {"configurable": {"model_name": "openai"}} - - async for chunk in client.runs.stream( - thread["thread_id"], - assistant_id=assistant_id, - input=input, - config=config, - stream_mode="messages-tuple", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` - -=== "Javascript" - - ```js - const input = { - messages: [ - { - role: "human", - content: "What's the weather in sf", - } - ] - }; - const config = { configurable: { model_name: "openai" } }; - - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - config, - streamMode: "messages-tuple" - } - ); - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what's the weather in la\"}]}, - \"stream_mode\": [ - \"messages-tuple\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - - -Output: - - Receiving new event of type: metadata... - {"run_id": "1ef971e0-9a84-6154-9047-247b4ce89c4d", "attempt": 1} - - ... - - Receiving new event of type: messages... - [ - { - "type": "AIMessageChunk", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "weat" - }, - "id": "toolu_0114XKXdNtHQEa3ozmY1uDdM", - "type": "tool_call" - } - ], - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - - - Receiving new event of type: messages... - [ - { - "type": "AIMessageChunk", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "her in san " - }, - "id": "toolu_0114XKXdNtHQEa3ozmY1uDdM", - "type": "tool_call" - } - ], - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - ... - - Receiving new event of type: messages... - [ - { - "type": "AIMessageChunk", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "francisco" - }, - "id": "toolu_0114XKXdNtHQEa3ozmY1uDdM", - "type": "tool_call" - } - ], - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - ... - - Receiving new event of type: messages... - [ - { - "content": "[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1730475777, 'localtime': '2024-11-01 08:42'}, 'current': {'last_updated_epoch': 1730475000, 'last_updated': '2024-11-01 08:30', 'temp_c': 11.1, 'temp_f': 52.0, 'is_day': 1, 'condition': {'text': 'Partly cloudy', 'icon': '//cdn.weatherapi.com/weather/64x64/day/116.png', 'code': 1003}, 'wind_mph': 2.2, 'wind_kph': 3.6, 'wind_degree': 192, 'wind_dir': 'SSW', 'pressure_mb': 1018.0, 'pressure_in': 30.07, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 89, 'cloud': 75, 'feelslike_c': 11.5, 'feelslike_f': 52.6, 'windchill_c': 10.0, 'windchill_f': 50.1, 'heatindex_c': 10.4, 'heatindex_f': 50.7, 'dewpoint_c': 9.1, 'dewpoint_f': 48.5, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 3.0, 'gust_mph': 6.7, 'gust_kph': 10.8}}\"}]", - "type": "tool", - "tool_call_id": "toolu_0114XKXdNtHQEa3ozmY1uDdM", - ... - }, - { - "graph_id": "agent", - "langgraph_node": "action", - ... - } - ] - - ... - - Receiving new event of type: messages... - [ - { - "content": [ - { - "text": "\n\nThe search", - "type": "text", - "index": 0 - } - ], - "type": "AIMessageChunk", - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - - - Receiving new event of type: messages... - [ - { - "content": [ - { - "text": " results provide", - "type": "text", - "index": 0 - } - ], - "type": "AIMessageChunk", - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - - - Receiving new event of type: messages... - [ - { - "content": [ - { - "text": " the current weather conditions", - "type": "text", - "index": 0 - } - ], - "type": "AIMessageChunk", - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - - - Receiving new event of type: messages... - [ - { - "content": [ - { - "text": " in San Francisco.", - "type": "text", - "index": 0 - } - ], - "type": "AIMessageChunk", - ... - }, - { - "graph_id": "agent", - "langgraph_node": "agent", - ... - } - ] - - ... \ No newline at end of file diff --git a/docs/docs/cloud/how-tos/stream_multiple.md b/docs/docs/cloud/how-tos/stream_multiple.md deleted file mode 100644 index 20a05468c..000000000 --- a/docs/docs/cloud/how-tos/stream_multiple.md +++ /dev/null @@ -1,485 +0,0 @@ -# How to configure multiple streaming modes at the same time - -!!! info "Prerequisites" - * [Streaming](../../concepts/streaming.md) - -This guide covers how to configure multiple streaming modes at the same time. - -## Setup - -First let's set up our client and thread: - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - # create thread - thread = await client.threads.create() - print(thread) - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - // create thread - const thread = await client.threads.create(); - console.log(thread); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - -Output: - - { - 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', - 'created_at': '2024-06-24T21:30:07.980789+00:00', - 'updated_at': '2024-06-24T21:30:07.980789+00:00', - 'metadata': {}, - 'status': 'idle', - 'config': {}, - 'values': None - } - -## Stream graph with multiple modes - -When configuring multiple streaming modes for a run, responses for each respective mode will be produced. In the following example, note that a `list` of modes (`messages`, `events`, `debug`) is passed to the `stream_mode` parameter and the response contains `events`, `debug`, `messages/complete`, `messages/metadata`, and `messages/partial` event types. - -=== "Python" - - ```python - # create input - input = { - "messages": [ - { - "role": "user", - "content": "What's the weather in SF?", - } - ] - } - - # stream events with multiple streaming modes - async for chunk in client.runs.stream( - thread_id=thread["thread_id"], - assistant_id=assistant_id, - input=input, - stream_mode=["messages", "events", "debug"], - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` - -=== "Javascript" - - ```js - // create input - const input = { - messages: [ - { - role: "human", - content: "What's the weather in SF?", - } - ] - }; - - // stream events with multiple streaming modes - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - streamMode: ["messages", "events", "debug"] - } - ); - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"What's the weather in SF?\"}]}, - \"stream_mode\": [ - \"messages\", - \"events\", - \"debug\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - -Output: - - Receiving new event of type: metadata... - {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {'input': {'messages': [{'role': 'human', 'content': "What's the weather in SF?"}]}}, 'name': 'LangGraph', 'tags': [], 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.116009+00:00', 'step': -1, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc7c-6daa-bfff-6b9027c1a50e', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'messages': []}, 'metadata': {'source': 'input', 'step': -1, 'writes': {'messages': [{'role': 'human', 'content': "What's the weather in SF?"}]}}}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.116009+00:00', 'step': -1, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc7c-6daa-bfff-6b9027c1a50e', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'messages': []}, 'metadata': {'source': 'input', 'step': -1, 'writes': {'messages': [{'role': 'human', 'content': "What's the weather in SF?"}]}}}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['values', {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}]}]}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.117924+00:00', 'step': 0, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc81-68c8-8000-4e18ae7d67a5', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}]}, 'metadata': {'source': 'loop', 'step': 0, 'writes': None}}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.117924+00:00', 'step': 0, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc81-68c8-8000-4e18ae7d67a5', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}]}, 'metadata': {'source': 'loop', 'step': 0, 'writes': None}}}]}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-06-24T21:34:06.118042+00:00', 'step': 1, 'payload': {'id': '212ed9c2-a454-50c5-a202-12066bbbe7b8', 'name': 'agent', 'input': {'some_bytes': None, 'some_byte_array': None, 'dict_with_bytes': None, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}], 'sleep': None}, 'triggers': ['start:agent']}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'task', 'timestamp': '2024-06-24T21:34:06.118042+00:00', 'step': 1, 'payload': {'id': '212ed9c2-a454-50c5-a202-12066bbbe7b8', 'name': 'agent', 'input': {'some_bytes': None, 'some_byte_array': None, 'dict_with_bytes': None, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}], 'sleep': None}, 'triggers': ['start:agent']}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {}, 'name': 'agent', 'tags': ['graph:step:1'], 'run_id': '72b74d24-5792-48da-a887-102100d6e2c0', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_start', 'data': {'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}]]}}, 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'b', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: messages/metadata... - {'run-2424dd6d-5cf5-4244-8d98-357640ce6e12': {'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}}} - - - - Receiving new event of type: messages/partial... - [{'content': 'b', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'e', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: messages/partial... - [{'content': 'be', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'g', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: messages/partial... - [{'content': 'beg', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'i', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: messages/partial... - [{'content': 'begi', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'n', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: messages/partial... - [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_end', 'data': {'output': {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, 'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}]]}}, 'run_id': '2424dd6d-5cf5-4244-8d98-357640ce6e12', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'name': 'should_continue', 'tags': ['seq:step:3'], 'run_id': '227afb0f-f909-4d54-a042-556ca6d98a69', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': 'tool', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'run_id': '227afb0f-f909-4d54-a042-556ca6d98a69', 'name': 'should_continue', 'tags': ['seq:step:3'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', '72b74d24-5792-48da-a887-102100d6e2c0']} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '72b74d24-5792-48da-a887-102100d6e2c0', 'name': 'agent', 'tags': ['graph:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'data': {'chunk': {'messages': [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'messages': [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}, 'input': {'some_bytes': None, 'some_byte_array': None, 'dict_with_bytes': None, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}], 'sleep': None}}, 'run_id': '72b74d24-5792-48da-a887-102100d6e2c0', 'name': 'agent', 'tags': ['graph:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 1, 'langgraph_node': 'agent', 'langgraph_triggers': ['start:agent'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-06-24T21:34:06.124350+00:00', 'step': 1, 'payload': {'id': '212ed9c2-a454-50c5-a202-12066bbbe7b8', 'name': 'agent', 'result': [['some_bytes', 'c29tZV9ieXRlcw=='], ['some_byte_array', 'c29tZV9ieXRlX2FycmF5'], ['dict_with_bytes', {'more_bytes': 'bW9yZV9ieXRlcw=='}], ['messages', [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]]]}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'task_result', 'timestamp': '2024-06-24T21:34:06.124350+00:00', 'step': 1, 'payload': {'id': '212ed9c2-a454-50c5-a202-12066bbbe7b8', 'name': 'agent', 'result': [['some_bytes', 'c29tZV9ieXRlcw=='], ['some_byte_array', 'c29tZV9ieXRlX2FycmF5'], ['dict_with_bytes', {'more_bytes': 'bW9yZV9ieXRlcw=='}], ['messages', [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]]]}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['values', {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}]}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.124510+00:00', 'step': 1, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc91-6a34-8001-26353c117c25', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}, 'metadata': {'source': 'loop', 'step': 1, 'writes': {'agent': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}}}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.124510+00:00', 'step': 1, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc91-6a34-8001-26353c117c25', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}, 'metadata': {'source': 'loop', 'step': 1, 'writes': {'agent': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}}}}]}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-06-24T21:34:06.124572+00:00', 'step': 2, 'payload': {'id': '44139125-a1be-57c2-9cb2-19eb62bbaf2f', 'name': 'tool', 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'sleep': None}, 'triggers': ['branch:agent:should_continue:tool']}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'task', 'timestamp': '2024-06-24T21:34:06.124572+00:00', 'step': 2, 'payload': {'id': '44139125-a1be-57c2-9cb2-19eb62bbaf2f', 'name': 'tool', 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'sleep': None}, 'triggers': ['branch:agent:should_continue:tool']}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {}, 'name': 'tool', 'tags': ['graph:step:2'], 'run_id': '91575720-886e-485e-ae2d-d6817e5346bf', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 2, 'langgraph_node': 'tool', 'langgraph_triggers': ['branch:agent:should_continue:tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '91575720-886e-485e-ae2d-d6817e5346bf', 'name': 'tool', 'tags': ['graph:step:2'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 2, 'langgraph_node': 'tool', 'langgraph_triggers': ['branch:agent:should_continue:tool'], 'langgraph_task_idx': 0}, 'data': {'chunk': {'messages': [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': None, 'tool_call_id': 'tool_call_id'}]}}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'messages': [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]}, 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'sleep': None}}, 'run_id': '91575720-886e-485e-ae2d-d6817e5346bf', 'name': 'tool', 'tags': ['graph:step:2'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 2, 'langgraph_node': 'tool', 'langgraph_triggers': ['branch:agent:should_continue:tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-06-24T21:34:06.126828+00:00', 'step': 2, 'payload': {'id': '44139125-a1be-57c2-9cb2-19eb62bbaf2f', 'name': 'tool', 'result': [['messages', [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]]]}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'task_result', 'timestamp': '2024-06-24T21:34:06.126828+00:00', 'step': 2, 'payload': {'id': '44139125-a1be-57c2-9cb2-19eb62bbaf2f', 'name': 'tool', 'result': [['messages', [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]]]}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['values', {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]}]}, 'parent_ids': []} - - - - Receiving new event of type: messages/complete... - [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}] - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.126966+00:00', 'step': 2, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc97-6a06-8002-8e9ffc1ea75a', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]}, 'metadata': {'source': 'loop', 'step': 2, 'writes': {'tool': {'messages': [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]}}}}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.126966+00:00', 'step': 2, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bc97-6a06-8002-8e9ffc1ea75a', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]}, 'metadata': {'source': 'loop', 'step': 2, 'writes': {'tool': {'messages': [{'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]}}}}}]}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'task', 'timestamp': '2024-06-24T21:34:06.127034+00:00', 'step': 3, 'payload': {'id': 'f1ccf371-63b3-5268-a837-7f360a93c4ec', 'name': 'agent', 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}], 'sleep': None}, 'triggers': ['tool']}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'task', 'timestamp': '2024-06-24T21:34:06.127034+00:00', 'step': 3, 'payload': {'id': 'f1ccf371-63b3-5268-a837-7f360a93c4ec', 'name': 'agent', 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}], 'sleep': None}, 'triggers': ['tool']}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {}, 'name': 'agent', 'tags': ['graph:step:3'], 'run_id': 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_start', 'data': {'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]]}}, 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'run_id': '0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'e', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: messages/metadata... - {'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575': {'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}}} - - - - Receiving new event of type: messages/partial... - [{'content': 'e', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'n', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: messages/partial... - [{'content': 'en', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_stream', 'data': {'chunk': {'content': 'd', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'AIMessageChunk', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None, 'tool_call_chunks': []}}, 'run_id': '0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: messages/partial... - [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}] - - - - Receiving new event of type: events... - {'event': 'on_chat_model_end', 'data': {'output': {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, 'input': {'messages': [[{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}]]}}, 'run_id': '0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'name': 'FakeListChatModel', 'tags': ['seq:step:1'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0, 'ls_model_type': 'chat'}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: events... - {'event': 'on_chain_start', 'data': {'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'name': 'should_continue', 'tags': ['seq:step:3'], 'run_id': '8af814e9-8136-4aab-acbc-dffc5bcafdfd', 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': '__end__', 'input': {'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'run_id': '8af814e9-8136-4aab-acbc-dffc5bcafdfd', 'name': 'should_continue', 'tags': ['seq:step:3'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25', 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e']} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e', 'name': 'agent', 'tags': ['graph:step:3'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'data': {'chunk': {'messages': [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'messages': [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}], 'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}}, 'input': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}], 'sleep': None}}, 'run_id': 'b7d0900c-bfc2-43e4-b760-99bbc5bad84e', 'name': 'agent', 'tags': ['graph:step:3'], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca', 'langgraph_step': 3, 'langgraph_node': 'agent', 'langgraph_triggers': ['tool'], 'langgraph_task_idx': 0}, 'parent_ids': ['1ef32717-bc30-6cf2-8a26-33f63567bc25']} - - - - Receiving new event of type: debug... - {'type': 'task_result', 'timestamp': '2024-06-24T21:34:06.133991+00:00', 'step': 3, 'payload': {'id': 'f1ccf371-63b3-5268-a837-7f360a93c4ec', 'name': 'agent', 'result': [['some_bytes', 'c29tZV9ieXRlcw=='], ['some_byte_array', 'c29tZV9ieXRlX2FycmF5'], ['dict_with_bytes', {'more_bytes': 'bW9yZV9ieXRlcw=='}], ['messages', [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]]]}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'task_result', 'timestamp': '2024-06-24T21:34:06.133991+00:00', 'step': 3, 'payload': {'id': 'f1ccf371-63b3-5268-a837-7f360a93c4ec', 'name': 'agent', 'result': [['some_bytes', 'c29tZV9ieXRlcw=='], ['some_byte_array', 'c29tZV9ieXRlX2FycmF5'], ['dict_with_bytes', {'more_bytes': 'bW9yZV9ieXRlcw=='}], ['messages', [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]]]}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['values', {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}]}, 'parent_ids': []} - - - - Receiving new event of type: debug... - {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.134190+00:00', 'step': 3, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bca9-6418-8003-8d0d0b06845c', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}, 'metadata': {'source': 'loop', 'step': 3, 'writes': {'agent': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}}}} - - - - Receiving new event of type: events... - {'event': 'on_chain_stream', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'data': {'chunk': ['debug', {'type': 'checkpoint', 'timestamp': '2024-06-24T21:34:06.134190+00:00', 'step': 3, 'payload': {'config': {'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'callbacks': [None], 'recursion_limit': 25, 'configurable': {'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'thread_ts': '1ef32717-bca9-6418-8003-8d0d0b06845c', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25'}, 'values': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}, 'metadata': {'source': 'loop', 'step': 3, 'writes': {'agent': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}}}}]}, 'parent_ids': []} - - - - Receiving new event of type: events... - {'event': 'on_chain_end', 'data': {'output': {'some_bytes': 'c29tZV9ieXRlcw==', 'some_byte_array': 'c29tZV9ieXRlX2FycmF5', 'dict_with_bytes': {'more_bytes': 'bW9yZV9ieXRlcw=='}, 'messages': [{'content': "What's the weather in SF?", 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'human', 'name': None, 'id': '7da1bafa-f53c-4df8-ba63-8dd517140b9f', 'example': False}, {'content': 'begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-2424dd6d-5cf5-4244-8d98-357640ce6e12', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}, {'content': 'tool_call__begin', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'tool', 'name': None, 'id': '639ca779-403d-4915-a066-327e1f634c8b', 'tool_call_id': 'tool_call_id'}, {'content': 'end', 'additional_kwargs': {}, 'response_metadata': {}, 'type': 'ai', 'name': None, 'id': 'run-0f2ef0a1-0fc7-445c-9df4-55e8bb284575', 'example': False, 'tool_calls': [], 'invalid_tool_calls': [], 'usage_metadata': None}]}}, 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'name': 'LangGraph', 'tags': [], 'metadata': {'created_by': 'system', 'run_id': '1ef32717-bc30-6cf2-8a26-33f63567bc25', 'user_id': '', 'graph_id': 'agent', 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', 'assistant_id': 'fe096781-5601-53d2-b2f6-0d3403f7e9ca'}, 'parent_ids': []} - - - - Receiving new event of type: end... - None - - - diff --git a/docs/docs/cloud/how-tos/stream_updates.md b/docs/docs/cloud/how-tos/stream_updates.md deleted file mode 100644 index 1c08b5e80..000000000 --- a/docs/docs/cloud/how-tos/stream_updates.md +++ /dev/null @@ -1,217 +0,0 @@ -# How to stream state updates of your graph - -!!! info "Prerequisites" - * [Streaming](../../concepts/streaming.md) - -This guide covers how to use `stream_mode="updates"` for your graph, which will stream the updates to the graph state that are made after each node is executed. This differs from using `stream_mode="values"`: instead of streaming the entire value of the state at each superstep, it only streams the updates from each of the nodes that made an update to the state at that superstep. - -## Setup - -First let's set up our client and thread: - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - # create thread - thread = await client.threads.create() - print(thread) - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - // create thread - const thread = await client.threads.create(); - console.log(thread); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - -Output: - - { - 'thread_id': '979e3c89-a702-4882-87c2-7a59a250ce16', - 'created_at': '2024-06-21T15:22:07.453100+00:00', - 'updated_at': '2024-06-21T15:22:07.453100+00:00', - 'metadata': {}, - 'status': 'idle', - 'config': {}, - 'values': None - } - -## Stream graph in updates mode - -Now we can stream by updates, which outputs updates made to the state by each node after it has executed: - - -=== "Python" - - ```python - input = { - "messages": [ - { - "role": "user", - "content": "what's the weather in la" - } - ] - } - async for chunk in client.runs.stream( - thread["thread_id"], - assistant_id, - input=input, - stream_mode="updates", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` - -=== "Javascript" - - ```js - const input = { - messages: [ - { - role: "human", - content: "What's the weather in la" - } - ] - }; - - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - streamMode: "updates" - } - ); - - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"What's the weather in la\"}]}, - \"stream_mode\": [ - \"updates\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - -Output: - - Receiving new event of type: metadata... - {"run_id": "cfc96c16-ed9a-44bd-b5bb-c30e3c0725f0"} - - - - Receiving new event of type: updates... - { - "agent": { - "messages": [ - { - "type": "ai", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "weather in los angeles" - }, - "id": "toolu_0148tMmDK51iLQfG1yaNwRHM" - } - ], - ... - } - ] - } - } - - - - Receiving new event of type: updates... - { - "action": { - "messages": [ - { - "content": [ - { - "url": "https://www.weatherapi.com/", - "content": "{\"location\": {\"name\": \"Los Angeles\", \"region\": \"California\", \"country\": \"United States of America\", \"lat\": 34.05, \"lon\": -118.24, \"tz_id\": \"America/Los_Angeles\", \"localtime_epoch\": 1716062239, \"localtime\": \"2024-05-18 12:57\"}, \"current\": {\"last_updated_epoch\": 1716061500, \"last_updated\": \"2024-05-18 12:45\", \"temp_c\": 18.9, \"temp_f\": 66.0, \"is_day\": 1, \"condition\": {\"text\": \"Overcast\", \"icon\": \"//cdn.weatherapi.com/weather/64x64/day/122.png\", \"code\": 1009}, \"wind_mph\": 2.2, \"wind_kph\": 3.6, \"wind_degree\": 10, \"wind_dir\": \"N\", \"pressure_mb\": 1017.0, \"pressure_in\": 30.02, \"precip_mm\": 0.0, \"precip_in\": 0.0, \"humidity\": 65, \"cloud\": 100, \"feelslike_c\": 18.9, \"feelslike_f\": 66.0, \"vis_km\": 16.0, \"vis_miles\": 9.0, \"uv\": 6.0, \"gust_mph\": 7.5, \"gust_kph\": 12.0}}" - } - ], - "type": "tool", - "name": "tavily_search_results_json", - "tool_call_id": "toolu_0148tMmDK51iLQfG1yaNwRHM", - ... - } - ] - } - } - - - - Receiving new event of type: updates... - { - "agent": { - "messages": [ - { - "content": "The weather in Los Angeles is currently overcast with a temperature of around 66°F (18.9°C). There are light winds from the north at around 2-3 mph. The humidity is 65% and visibility is good at 9 miles. Overall, mild spring weather conditions in LA.", - "type": "ai", - ... - } - ] - } - } - - - - Receiving new event of type: end... - None \ No newline at end of file diff --git a/docs/docs/cloud/how-tos/stream_values.md b/docs/docs/cloud/how-tos/stream_values.md deleted file mode 100644 index 17e186027..000000000 --- a/docs/docs/cloud/how-tos/stream_values.md +++ /dev/null @@ -1,335 +0,0 @@ -# How to stream full state of your graph - -!!! info "Prerequisites" - * [Streaming](../../concepts/streaming.md) - -This guide covers how to use `stream_mode="values"`, which streams the value of the state at each superstep. This differs from using `stream_mode="updates"`: instead of streaming just the updates to the state from each node, it streams the entire graph state at that superstep. - -## Setup - -First let's set up our client and thread: - -=== "Python" - - ```python - from langgraph_sdk import get_client - - client = get_client(url=) - # Using the graph deployed with the name "agent" - assistant_id = "agent" - # create thread - thread = await client.threads.create() - print(thread) - ``` - -=== "Javascript" - - ```js - import { Client } from "@langchain/langgraph-sdk"; - - const client = new Client({ apiUrl: }); - // Using the graph deployed with the name "agent" - const assistantID = "agent"; - // create thread - const thread = await client.threads.create(); - console.log(thread); - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads \ - --header 'Content-Type: application/json' \ - --data '{}' - ``` - -Output: - - { - 'thread_id': 'bfc68029-1f7b-400f-beab-6f9032a52da4', - 'created_at': '2024-06-24T21:30:07.980789+00:00', - 'updated_at': '2024-06-24T21:30:07.980789+00:00', - 'metadata': {}, - 'status': 'idle', - 'config': {}, - 'values': None - } - -## Stream graph in values mode - -Now we can stream by values, which streams the full state of the graph after each node has finished executing: - -=== "Python" - - ```python - input = {"messages": [{"role": "user", "content": "what's the weather in la"}]} - - # stream values - async for chunk in client.runs.stream( - thread["thread_id"], - assistant_id, - input=input, - stream_mode="values" - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` - -=== "Javascript" - - ```js - const input = {"messages": [{"role": "user", "content": "what's the weather in la"}]} - - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - streamMode: "values" - } - ); - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(chunk.data); - console.log("\n\n"); - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what's the weather in la\"}]}, - \"stream_mode\": [ - \"values\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^event:/ { - if (data_content != "") { - print data_content "\n" - } - sub(/^event: /, "Receiving event of type: ", $0) - printf "%s...\n", $0 - data_content = "" - } - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content "\n" - } - } - ' - ``` - - -Output: - - Receiving new event of type: metadata... - {"run_id": "f08791ce-0a3d-44e0-836c-ff62cd2e2786"} - - - - Receiving new event of type: values... - { - "messages": [ - { - "role": "human", - "content": "what's the weather in la" - } - ] - } - - - - Receiving new event of type: values... - { - "messages": [ - { - "content": "what's the weather in la", - "type": "human", - ... - }, - { - "content": "", - "type": "ai", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "weather in los angeles" - }, - "id": "toolu_01E5mSaZWm5rWJnCqmt63v4g" - } - ], - ... - } - ] - } - - ... - - Receiving new event of type: values... - { - "messages": [ - { - "content": "what's the weather in la", - "type": "human", - ... - }, - { - "content": "", - "type": "ai", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "weather in los angeles" - }, - "id": "toolu_01E5mSaZWm5rWJnCqmt63v4g" - } - ], - ... - } - { - "content": [ - { - "url": "https://www.weatherapi.com/", - "content": "{\"location\": {\"name\": \"Los Angeles\", \"region\": \"California\", \"country\": \"United States of America\", \"lat\": 34.05, \"lon\": -118.24, \"tz_id\": \"America/Los_Angeles\", \"localtime_epoch\": 1716310320, \"localtime\": \"2024-05-21 9:52\"}, \"current\": {\"last_updated_epoch\": 1716309900, \"last_updated\": \"2024-05-21 09:45\", \"temp_c\": 16.7, \"temp_f\": 62.1, \"is_day\": 1, \"condition\": {\"text\": \"Overcast\", \"icon\": \"//cdn.weatherapi.com/weather/64x64/day/122.png\", \"code\": 1009}, \"wind_mph\": 8.1, \"wind_kph\": 13.0, \"wind_degree\": 250, \"wind_dir\": \"WSW\", \"pressure_mb\": 1015.0, \"pressure_in\": 29.97, \"precip_mm\": 0.0, \"precip_in\": 0.0, \"humidity\": 65, \"cloud\": 100, \"feelslike_c\": 16.7, \"feelslike_f\": 62.1, \"vis_km\": 16.0, \"vis_miles\": 9.0, \"uv\": 5.0, \"gust_mph\": 12.5, \"gust_kph\": 20.2}}" - } - ], - "type": "tool", - "name": "tavily_search_results_json", - "tool_call_id": "toolu_01E5mSaZWm5rWJnCqmt63v4g" - ... - }, - { - "content": "Based on the weather API results, the current weather in Los Angeles is overcast with a temperature of around 62°F (17°C). There are light winds from the west-southwest around 8-13 mph. The humidity is 65% and visibility is good at 9 miles. Overall, mild spring weather conditions in LA.", - "type": "ai", - ... - } - ] - } - - - - Receiving new event of type: end... - None - - - - - -If we want to just get the final result, we can use this endpoint and just keep track of the last value we received - - -=== "Python" - - ```python - final_answer = None - async for chunk in client.runs.stream( - thread["thread_id"], - assistant_id, - input=input, - stream_mode="values" - ): - if chunk.event == "values": - final_answer = chunk.data - ``` - -=== "Javascript" - - ```js - let finalAnswer; - const streamResponse = client.runs.stream( - thread["thread_id"], - assistantID, - { - input, - streamMode: "values" - } - ); - for await (const chunk of streamResponse) { - finalAnswer = chunk.data; - } - ``` - -=== "CURL" - - ```bash - curl --request POST \ - --url /threads//runs/stream \ - --header 'Content-Type: application/json' \ - --data "{ - \"assistant_id\": \"agent\", - \"input\": {\"messages\": [{\"role\": \"human\", \"content\": \"what's the weather in la\"}]}, - \"stream_mode\": [ - \"values\" - ] - }" | \ - sed 's/\r$//' | \ - awk ' - /^data:/ { - sub(/^data: /, "", $0) - data_content = $0 - } - END { - if (data_content != "") { - print data_content - } - } - ' - ``` - - -Output: - - { - "messages": [ - { - "content": "what's the weather in la", - "type": "human", - ... - }, - { - "type": "ai", - "tool_calls": [ - { - "name": "tavily_search_results_json", - "args": { - "query": "weather in los angeles" - }, - "id": "toolu_01E5mSaZWm5rWJnCqmt63v4g" - } - ], - ... - } - { - "content": [ - { - "url": "https://www.weatherapi.com/", - "content": "{\"location\": {\"name\": \"Los Angeles\", \"region\": \"California\", \"country\": \"United States of America\", \"lat\": 34.05, \"lon\": -118.24, \"tz_id\": \"America/Los_Angeles\", \"localtime_epoch\": 1716310320, \"localtime\": \"2024-05-21 9:52\"}, \"current\": {\"last_updated_epoch\": 1716309900, \"last_updated\": \"2024-05-21 09:45\", \"temp_c\": 16.7, \"temp_f\": 62.1, \"is_day\": 1, \"condition\": {\"text\": \"Overcast\", \"icon\": \"//cdn.weatherapi.com/weather/64x64/day/122.png\", \"code\": 1009}, \"wind_mph\": 8.1, \"wind_kph\": 13.0, \"wind_degree\": 250, \"wind_dir\": \"WSW\", \"pressure_mb\": 1015.0, \"pressure_in\": 29.97, \"precip_mm\": 0.0, \"precip_in\": 0.0, \"humidity\": 65, \"cloud\": 100, \"feelslike_c\": 16.7, \"feelslike_f\": 62.1, \"vis_km\": 16.0, \"vis_miles\": 9.0, \"uv\": 5.0, \"gust_mph\": 12.5, \"gust_kph\": 20.2}}" - } - ], - "type": "tool", - "name": "tavily_search_results_json", - "tool_call_id": "toolu_01E5mSaZWm5rWJnCqmt63v4g" - ... - }, - { - "content": "Based on the weather API results, the current weather in Los Angeles is overcast with a temperature of around 62°F (17°C). There are light winds from the west-southwest around 8-13 mph. The humidity is 65% and visibility is good at 9 miles. Overall, mild spring weather conditions in LA.", - "type": "ai", - ... - } - ] - } \ No newline at end of file diff --git a/docs/docs/cloud/how-tos/streaming.md b/docs/docs/cloud/how-tos/streaming.md new file mode 100644 index 000000000..9ccf5d6be --- /dev/null +++ b/docs/docs/cloud/how-tos/streaming.md @@ -0,0 +1,879 @@ +# Stream outputs + +## Streaming API + +[LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) allows you to stream outputs from the LangGraph API server. + +Basic usage example: + +=== "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=, api_key=) + + # Using the graph deployed with the name "agent" + assistant_id = "agent" + + # create a thread + thread = await client.threads.create() + thread_id = thread["thread_id"] + + # create a streaming run + # highlight-next-line + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input=inputs, + stream_mode="updates" + ): + print(chunk.data) + ``` + +=== "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: , apiKey: }); + + // Using the graph deployed with the name "agent" + const assistantID = "agent"; + + // create a thread + const thread = await client.threads.create(); + const threadID = thread["thread_id"]; + + // create a streaming run + // highlight-next-line + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input, + streamMode: "updates" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + +=== "cURL" + + Create a thread: + + ```bash + curl --request POST \ + --url /threads \ + --header 'Content-Type: application/json' \ + --data '{}' + ``` + + Create a streaming run: + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --header 'x-api-key: ' + --data "{ + \"assistant_id\": \"agent\", + \"input\": , + \"stream_mode\": \"updates\" + }" + ``` + +??? example "Extended example: streaming updates" + + This is an example graph you can run in the LangGraph API server. + See [LangGraph Platform quickstart](../quick_start.md) for more details. + + ```python + # graph.py + from typing import TypedDict + from langgraph.graph import StateGraph, START, END + + class State(TypedDict): + topic: str + joke: str + + def refine_topic(state: State): + return {"topic": state["topic"] + " and cats"} + + def generate_joke(state: State): + return {"joke": f"This is a joke about {state['topic']}"} + + graph = ( + StateGraph(State) + .add_node(refine_topic) + .add_node(generate_joke) + .add_edge(START, "refine_topic") + .add_edge("refine_topic", "generate_joke") + .add_edge("generate_joke", END) + .compile() + ) + ``` + + Once you have a running LangGraph API server, you can interact with it using + [LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) + + === "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=) + + # Using the graph deployed with the name "agent" + assistant_id = "agent" + + # create a thread + thread = await client.threads.create() + thread_id = thread["thread_id"] + + # create a streaming run + # highlight-next-line + async for chunk in client.runs.stream( # (1)! + thread_id, + assistant_id, + input={"topic": "ice cream"}, + # highlight-next-line + stream_mode="updates" # (2)! + ): + print(chunk.data) + ``` + + 1. The `client.runs.stream()` method returns an iterator that yields streamed outputs. + 2. Set `stream_mode="updates"` to stream only the updates to the graph state after each node. Other stream modes are also available. See [supported stream modes](#supported-stream-modes) for details. + + === "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: }); + + // Using the graph deployed with the name "agent" + const assistantID = "agent"; + + // create a thread + const thread = await client.threads.create(); + const threadID = thread["thread_id"]; + + // create a streaming run + // highlight-next-line + const streamResponse = client.runs.stream( // (1)! + threadID, + assistantID, + { + input: { topic: "ice cream" }, + // highlight-next-line + streamMode: "updates" // (2)! + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + + 1. The `client.runs.stream()` method returns an iterator that yields streamed outputs. + 2. Set `streamMode: "updates"` to stream only the updates to the graph state after each node. Other stream modes are also available. See [supported stream modes](#supported-stream-modes) for details. + + === "cURL" + + Create a thread: + + ```bash + curl --request POST \ + --url /threads \ + --header 'Content-Type: application/json' \ + --data '{}' + ``` + + Create a streaming run: + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"topic\": \"ice cream\"}, + \"stream_mode\": \"updates\" + }" + ``` + + ```output + {'run_id': '1f02c2b3-3cef-68de-b720-eec2a4a8e920', 'attempt': 1} + {'refine_topic': {'topic': 'ice cream and cats'}} + {'generate_joke': {'joke': 'This is a joke about ice cream and cats'}} + ``` + + +### Supported stream modes + +| Mode | Description | LangGraph Library Method | +|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| [`values`](#stream-graph-state) | Stream the full graph state after each [super-step](../../concepts/low_level.md#graphs). | `.stream()` / `.astream()` with [`stream_mode="values"`](../../how-tos/streaming.md#stream-graph-state) | +| [`updates`](#stream-graph-state) | Streams the updates to the state after each step of the graph. If multiple updates are made in the same step (e.g., multiple nodes are run), those updates are streamed separately. | `.stream()` / `.astream()` with [`stream_mode="updates"`](../../how-tos/streaming.md#stream-graph-state) | +| [`messages-tuple`](#messages) | Streams LLM tokens and metadata for the graph node where the LLM is invoked (useful for chat apps). | `.stream()` / `.astream()` with [`stream_mode="messages"`](../../how-tos/streaming.md#messages) | +| [`debug`](#debug) | Streams as much information as possible throughout the execution of the graph. | `.stream()` / `.astream()` with [`stream_mode="debug"`](../../how-tos/streaming.md#stream-graph-state) | +| [`custom`](#stream-custom-data) | Streams custom data from inside your graph | `.stream()` / `.astream()` with [`stream_mode="custom"`](../../how-tos/streaming.md#stream-custom-data) | +| [`events`](#stream-events) | Stream all events (including the state of the graph); mainly useful when migrating large LCEL apps. | `.astream_events()` + +### Stream multiple modes + +You can pass a list as the `stream_mode` parameter to stream multiple modes at once. + +The streamed outputs will be tuples of `(mode, chunk)` where `mode` is the name of the stream mode and `chunk` is the data streamed by that mode. + +=== "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input=inputs, + stream_mode=["updates", "custom"] + ): + print(chunk) + ``` + +=== "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input, + streamMode: ["updates", "custom"] + } + ); + for await (const chunk of streamResponse) { + console.log(chunk); + } + ``` + +=== "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": , + \"stream_mode\": [ + \"updates\" + \"custom\" + ] + }" + ``` + +## Stream graph state + +Use the stream modes `updates` and `values` to stream the state of the graph as it executes. + +* `updates` streams the **updates** to the state after each step of the graph. +* `values` streams the **full value** of the state after each step of the graph. + +??? example "Example graph" + + ```python + from typing import TypedDict + from langgraph.graph import StateGraph, START, END + + class State(TypedDict): + topic: str + joke: str + + def refine_topic(state: State): + return {"topic": state["topic"] + " and cats"} + + def generate_joke(state: State): + return {"joke": f"This is a joke about {state['topic']}"} + + graph = ( + StateGraph(State) + .add_node(refine_topic) + .add_node(generate_joke) + .add_edge(START, "refine_topic") + .add_edge("refine_topic", "generate_joke") + .add_edge("generate_joke", END) + .compile() + ) + ``` + +!!! note "Stateful runs" + + Examples below assume that you want to **persist the outputs** of a streaming run in the [checkpointer](../../concepts/persistence.md) DB and have created a thread. To create a thread: + + === "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=) + + # Using the graph deployed with the name "agent" + assistant_id = "agent" + # create a thread + thread = await client.threads.create() + thread_id = thread["thread_id"] + ``` + + === "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: }); + + // Using the graph deployed with the name "agent" + const assistantID = "agent"; + // create a thread + const thread = await client.threads.create(); + const threadID = thread["thread_id"] + ``` + + === "cURL" + + ```bash + curl --request POST \ + --url /threads \ + --header 'Content-Type: application/json' \ + --data '{}' + ``` + + If you don't need to persist the outputs of a run, you can pass `None` instead of `thread_id` when streaming. + +=== "updates" + + Use this to stream only the **state updates** returned by the nodes after each step. The streamed outputs include the name of the node as well as the update. + + === "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"topic": "ice cream"}, + # highlight-next-line + stream_mode="updates" + ): + print(chunk.data) + ``` + + === "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { topic: "ice cream" }, + // highlight-next-line + streamMode: "updates" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + + === "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"topic\": \"ice cream\"}, + \"stream_mode\": \"updates\" + }" + ``` + +=== "values" + + Use this to stream the **full state** of the graph after each step. + + === "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"topic": "ice cream"}, + # highlight-next-line + stream_mode="values" + ): + print(chunk.data) + ``` + + === "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { topic: "ice cream" }, + // highlight-next-line + streamMode: "values" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + + === "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"topic\": \"ice cream\"}, + \"stream_mode\": \"values\" + }" + ``` + + +## Subgraphs + +To include outputs from [subgraphs](../../concepts/subgraphs.md) in the streamed outputs, you can set `subgraphs=True` in the `.stream()` method of the parent graph. This will stream outputs from both the parent graph and any subgraphs. + +```python +for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"foo": "foo"}, + # highlight-next-line + stream_subgraphs=True, # (1)! + stream_mode="updates", +): + print(chunk) +``` + +1. Set `stream_subgraphs=True` to stream outputs from subgraphs. + +??? example "Extended example: streaming from subgraphs" + + This is an example graph you can run in the LangGraph API server. + See [LangGraph Platform quickstart](../quick_start.md) for more details. + + ```python + # graph.py + from langgraph.graph import START, StateGraph + from typing import TypedDict + + # Define subgraph + class SubgraphState(TypedDict): + foo: str # note that this key is shared with the parent graph state + bar: str + + def subgraph_node_1(state: SubgraphState): + return {"bar": "bar"} + + def subgraph_node_2(state: SubgraphState): + return {"foo": state["foo"] + state["bar"]} + + subgraph_builder = StateGraph(SubgraphState) + subgraph_builder.add_node(subgraph_node_1) + subgraph_builder.add_node(subgraph_node_2) + subgraph_builder.add_edge(START, "subgraph_node_1") + subgraph_builder.add_edge("subgraph_node_1", "subgraph_node_2") + subgraph = subgraph_builder.compile() + + # Define parent graph + class ParentState(TypedDict): + foo: str + + def node_1(state: ParentState): + return {"foo": "hi! " + state["foo"]} + + builder = StateGraph(ParentState) + builder.add_node("node_1", node_1) + builder.add_node("node_2", subgraph) + builder.add_edge(START, "node_1") + builder.add_edge("node_1", "node_2") + graph = builder.compile() + ``` + + Once you have a running LangGraph API server, you can interact with it using + [LangGraph SDK](https://langchain-ai.github.io/langgraph/cloud/reference/sdk/python_sdk_ref/) + + === "Python" + + ```python + from langgraph_sdk import get_client + client = get_client(url=) + + # Using the graph deployed with the name "agent" + assistant_id = "agent" + + # create a thread + thread = await client.threads.create() + thread_id = thread["thread_id"] + + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"foo": "foo"}, + # highlight-next-line + stream_subgraphs=True, # (1)! + stream_mode="updates", + ): + print(chunk) + ``` + + 1. Set `stream_subgraphs=True` to stream outputs from subgraphs. + + === "JavaScript" + + ```js + import { Client } from "@langchain/langgraph-sdk"; + const client = new Client({ apiUrl: }); + + // Using the graph deployed with the name "agent" + const assistantID = "agent"; + + // create a thread + const thread = await client.threads.create(); + const threadID = thread["thread_id"]; + + // create a streaming run + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { foo: "foo" }, + // highlight-next-line + streamSubgraphs: true, // (1)! + streamMode: "updates" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk); + } + ``` + + 1. Set `streamSubgraphs: true` to stream outputs from subgraphs. + + === "cURL" + + Create a thread: + + ```bash + curl --request POST \ + --url /threads \ + --header 'Content-Type: application/json' \ + --data '{}' + ``` + + Create a streaming run: + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"foo\": \"foo\"}, + \"stream_subgraphs\": true, + \"stream_mode\": [ + \"updates\" + ] + }" + ``` + + **Note** that we are receiving not just the node updates, but we also the namespaces which tell us what graph (or subgraph) we are streaming from. + +## Debugging {#debug} + +Use the `debug` streaming mode to stream as much information as possible throughout the execution of the graph. The streamed outputs include the name of the node as well as the full state. + +=== "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"topic": "ice cream"}, + # highlight-next-line + stream_mode="debug" + ): + print(chunk.data) + ``` + +=== "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { topic: "ice cream" }, + // highlight-next-line + streamMode: "debug" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + +=== "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"topic\": \"ice cream\"}, + \"stream_mode\": \"debug\" + }" + ``` + +## LLM tokens {#messages} + +Use the `messages-tuple` streaming mode to stream Large Language Model (LLM) outputs **token by token** from any part of your graph, including nodes, tools, subgraphs, or tasks. + +The streamed output from [`messages-tuple` mode](#supported-stream-modes) is a tuple `(message_chunk, metadata)` where: + +- `message_chunk`: the token or message segment from the LLM. +- `metadata`: a dictionary containing details about the graph node and LLM invocation. + +> If your LLM is not available as a LangChain integration, you can stream its outputs using `custom` mode instead. See [use with any LLM](#use-with-any-llm) for details. + +!!! warning "Manual config required for async in Python < 3.11" + + When using Python < 3.11 with async code in your graph, you must explicitly pass `RunnableConfig` to `ainvoke()` to enable proper streaming. See [Async with Python < 3.11](#async) for details or upgrade to Python 3.11+. + +??? example "Example graph" + + ```python + from dataclasses import dataclass + + from langchain.chat_models import init_chat_model + from langgraph.graph import StateGraph, START + + @dataclass + class MyState: + topic: str + joke: str = "" + + llm = init_chat_model(model="openai:gpt-4o-mini") + + def call_model(state: MyState): + """Call the LLM to generate a joke about a topic""" + # highlight-next-line + llm_response = llm.invoke( # (1)! + [ + {"role": "user", "content": f"Generate a joke about {state.topic}"} + ] + ) + return {"joke": llm_response.content} + + graph = ( + StateGraph(MyState) + .add_node(call_model) + .add_edge(START, "call_model") + .compile() + ) + ``` + + 1. Note that the message events are emitted even when the LLM is run using `.invoke` rather than `.stream`. + +=== "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"topic": "ice cream"}, + # highlight-next-line + stream_mode="messages-tuple", + ): + if chunk.event != "messages": + continue + + message_chunk, metadata = chunk.data # (1)! + if message_chunk["content"]: + print(message_chunk["content"], end="|", flush=True) + ``` + + 1. The "messages-tuple" stream mode returns an iterator of tuples `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information. + +=== "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { topic: "ice cream" }, + // highlight-next-line + streamMode: "messages-tuple" + } + ); + for await (const chunk of streamResponse) { + if (chunk.event !== "messages") { + continue; + } + console.log(chunk.data[0]["content"]); // (1)! + } + ``` + + 1. The "messages-tuple" stream mode returns an iterator of tuples `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information. + +=== "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"topic\": \"ice cream\"}, + \"stream_mode\": \"messages-tuple\" + }" + ``` + +### Filter LLM tokens + +* To filter the streamed tokens by LLM invocation, you can [associate `tags` with LLM invocations](../../how-tos/streaming.md#filter-by-llm-invocation). +* To stream tokens only from specific nodes, use `stream_mode="messages"` and [filter the outputs by the `langgraph_node` field](../../how-tos/streaming.md#filter-by-node) in the streamed metadata. + +## Stream custom data + +To send **custom user-defined data** from inside a LangGraph node or tool, follow these steps: + +1. Use `get_stream_writer()` to access the stream writer and emit custom data. +2. Set `stream_mode="custom"` when calling `.stream()` or `.astream()` to get the custom data in the stream. You can combine multiple modes (e.g., `["updates", "custom"]`), but at least one must be `"custom"`. + +!!! warning "No `get_stream_writer()` in async for Python < 3.11" + + In async code running on Python < 3.11, `get_stream_writer()` will not work. + Instead, add a `writer` parameter to your node or tool and pass it manually. + See [Async with Python < 3.11](#async) for usage examples. + +??? example "Example graph" + + ```python + from typing import TypedDict + from langgraph.config import get_stream_writer + from langgraph.graph import StateGraph, START + + class State(TypedDict): + query: str + answer: str + + def node(state: State): + writer = get_stream_writer() # (1)! + writer({"custom_key": "Generating custom data inside node"}) # (2)! + return {"answer": "some data"} + + graph = ( + StateGraph(State) + .add_node(node) + .add_edge(START, "node") + .compile() + ) + ``` + + 1. Get the stream writer to send custom data. + 2. Emit a custom key-value pair (e.g., progress update). + +=== "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"query": "example"}, + # highlight-next-line + stream_mode="custom" + ): + print(chunk.data) + ``` + +=== "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { query: "example" }, + // highlight-next-line + streamMode: "custom" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + +=== "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"query\": \"example\"}, + \"stream_mode\": \"custom\" + }" + ``` + +See [this guide](../../how-tos/streaming.md#stream-custom-data) for more examples. + +## Stream events + +To stream all events, including the state of the graph: + +=== "Python" + + ```python + async for chunk in client.runs.stream( + thread_id, + assistant_id, + input={"topic": "ice cream"}, + # highlight-next-line + stream_mode="events" + ): + print(chunk.data) + ``` + +=== "JavaScript" + + ```js + const streamResponse = client.runs.stream( + threadID, + assistantID, + { + input: { topic: "ice cream" }, + // highlight-next-line + streamMode: "events" + } + ); + for await (const chunk of streamResponse) { + console.log(chunk.data); + } + ``` + +=== "cURL" + + ```bash + curl --request POST \ + --url /threads//runs/stream \ + --header 'Content-Type: application/json' \ + --data "{ + \"assistant_id\": \"agent\", + \"input\": {\"topic\": \"ice cream\"}, + \"stream_mode\": \"events\" + }" + ``` diff --git a/docs/docs/cloud/how-tos/studio/quick_start.md b/docs/docs/cloud/how-tos/studio/quick_start.md new file mode 100644 index 000000000..d196d8ed3 --- /dev/null +++ b/docs/docs/cloud/how-tos/studio/quick_start.md @@ -0,0 +1,88 @@ +!!! info "Prerequisites" + + - [LangGraph Studio Overview](../../../concepts/langgraph_studio.md) + +LangGraph Studio supports connecting to two types of graphs: + +- Graphs deployed on [LangGraph Platform](../../../cloud/quick_start.md) +- Graphs running locally via the [LangGraph Server](../../../tutorials/langgraph-platform/local-server.md). + +## Deployed Application + +For applications that are deployed on LangGraph Platform, you can access Studio as part of that deployment. To do so, navigate to the deployment in LangGraph Platform within the LangSmith UI and click the "LangGraph Studio" button. + +This will load the Studio UI connected to your live deployment, allowing you to create, read, and update the [threads](../../concepts/threads.md), [assistants](../../../concepts/assistants.md), and [memory](../../../concepts//memory.md) in that deployment. + +## Local Development Server + +To test your locally running application using LangGraph Studio, ensure your application is set up following [this guide](https://langchain-ai.github.io/langgraph/cloud/deployment/setup/). + +Next, install the [LangGraph CLI](../../../concepts/langgraph_cli.md): + +``` +pip install -U "langgraph-cli[inmem]" +``` + +and run: + +``` +langgraph dev +``` + +!!! warning "Browser Compatibility" + Safari blocks `localhost` connections to Studio. To work around this, run the above command with `--tunnel` to access Studio via a secure tunnel. + +This will start the LangGraph Server locally, running in-memory. The server will run in watch mode, listening for and automatically restarting on code changes. Read this [reference](https://langchain-ai.github.io/langgraph/cloud/reference/cli/#dev) to learn about all the options for starting the API server. + +If successful, you will see the following logs: + +> Ready! +> +> - API: [http://localhost:2024](http://localhost:2024/) +> +> - Docs: http://localhost:2024/docs +> +> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 + +Once running, you will automatically be directed to LangGraph Studio. You can manually access Studio by navigating to the following URL: `https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024`. If running your server at a different host or port, simply update the `baseUrl` to match. + +### (Optional) Attach a debugger + +For step-by-step debugging with breakpoints and variable inspection: + +```bash +# Install debugpy package +pip install debugpy + +# Start server with debugging enabled +langgraph dev --debug-port 5678 +``` + +Then attach your preferred debugger: + +=== "VS Code" +Add this configuration to `launch.json`: +`json + { + "name": "Attach to LangGraph", + "type": "debugpy", + "request": "attach", + "connect": { + "host": "0.0.0.0", + "port": 5678 + } + } + ` +Specify the port number you chose in the previous step. + +=== "PyCharm" 1. Go to Run → Edit Configurations 2. Click + and select "Python Debug Server" 3. Set IDE host name: `localhost` 4. Set port: `5678` (or the port number you chose in the previous step) 5. Click "OK" and start debugging + +## Next steps + +See the following how-tos for more information on how to use Studio: + +- [How to manage Assistants](../invoke_studio.md) +- [How to manage Threads](../threads_studio.md) +- [How to create datasets](../datasets_studio.md) +- [How to prompt engineer](../iterate_graph_studio.md) +- [How to locally debug remote traces](../clone_traces_studio.md) diff --git a/docs/docs/cloud/how-tos/test_deployment.md b/docs/docs/cloud/how-tos/test_deployment.md deleted file mode 100644 index b35bf5e13..000000000 --- a/docs/docs/cloud/how-tos/test_deployment.md +++ /dev/null @@ -1,16 +0,0 @@ -# Test LangGraph Platform Deployment - -The LangGraph Studio UI connects directly to LangGraph Platform deployments. - -Starting from the LangSmith UI... - -1. In the left-hand navigation panel, select `LangGraph Platform`. The `LangGraph Platform` view contains a list of existing LangGraph Platform deployments. -1. Select an existing deployment to test with LangGraph Studio. -1. In the top-right corner, select `Open LangGraph Studio`. -1. [Invoke an assistant](./invoke_studio.md) or [view an existing thread](./threads_studio.md). - -The following video shows these exact steps being carried out: - - diff --git a/docs/docs/cloud/how-tos/test_local_deployment.md b/docs/docs/cloud/how-tos/test_local_deployment.md deleted file mode 100644 index 1b7b0cfe1..000000000 --- a/docs/docs/cloud/how-tos/test_local_deployment.md +++ /dev/null @@ -1,32 +0,0 @@ -# LangGraph Studio With Local Deployment - -!!! warning "Browser Compatibility" - Safari blocks `localhost` connections to Studio. To work around this, start the server with `--tunnel` and you’ll be able to access Studio from Safari via a secure tunnel. - -## Setup - -Make sure you have setup your app correctly, by creating a compiled graph, a `.env` file with any environment variables, and a `langgraph.json` config file that points to your environment file and compiled graph. See [here](https://langchain-ai.github.io/langgraph/cloud/deployment/setup/) for more detailed instructions. - -After you have your app setup, head into the directory with your `langgraph.json` file and call `langgraph dev` to start the API server in watch mode which means it will restart on code changes, which is ideal for local testing. If the API server start correctly you should see logs that look something like this: - -> Ready! -> -> - API: [http://localhost:2024](http://localhost:2024/) -> -> - Docs: http://localhost:2024/docs -> -> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 - -Read this [reference](https://langchain-ai.github.io/langgraph/cloud/reference/cli/#up) to learn about all the options for starting the API server. - -## Access Studio - -Once you have successfully started the API server, you can access the studio by going to the following URL: `https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024` (see warning above if using Safari). - -If everything is working correctly you should see the studio show up looking something like this (with your graph diagram on the left hand side): - -![LangGraph Studio](./img/studio_screenshot.png) - -## Use the Studio for Testing - -To learn about how to use the studio for testing, read the [LangGraph Studio how-tos](https://langchain-ai.github.io/langgraph/cloud/how-tos/#langgraph-studio). \ No newline at end of file diff --git a/docs/docs/cloud/how-tos/webhooks.md b/docs/docs/cloud/how-tos/webhooks.md index 7bae74001..f8d7809a3 100644 --- a/docs/docs/cloud/how-tos/webhooks.md +++ b/docs/docs/cloud/how-tos/webhooks.md @@ -121,7 +121,7 @@ curl --request POST \ ## Webhook Payload -LangGraph Cloud sends webhook notifications in the format of a [Run](../../concepts/langgraph_server.md/#runs). See the [API Reference](https://langchain-ai.github.io/langgraph/cloud/reference/api/api_ref.html#model/run) for details. The request payload includes run input, configuration, and other metadata in the `kwargs` field. +LangGraph Cloud sends webhook notifications in the format of a [Run](../../cloud/concepts/runs.md). See the [API Reference](https://langchain-ai.github.io/langgraph/cloud/reference/api/api_ref.html#model/run) for details. The request payload includes run input, configuration, and other metadata in the `kwargs` field. ## Securing Webhooks diff --git a/docs/docs/cloud/quick_start.md b/docs/docs/cloud/quick_start.md index ea4cb11b6..87967e147 100644 --- a/docs/docs/cloud/quick_start.md +++ b/docs/docs/cloud/quick_start.md @@ -1,234 +1,164 @@ -# Quickstart: Deploy on LangGraph Cloud +# Deployment quickstart -!!! note "Prerequisites" +This guide shows you how to set up and use LangGraph Platform for a cloud deployment. - Before you begin, ensure you have the following: +## Prerequisites - - [GitHub account](https://github.com/) - - [LangSmith account](https://smith.langchain.com/) +Before you begin, ensure you have the following: -## Create a repository on GitHub +- A [GitHub account](https://github.com/) +- A [LangSmith account](https://smith.langchain.com/) – free to sign up -To deploy a LangGraph application to **LangGraph Cloud**, your application code must reside in a GitHub repository. Both public and private repositories are supported. +This quickstart uses the [pre-built Python ReAct agent template](https://github.com/langchain-ai/react-agent), which requires the following: -You can deploy any [LangGraph Application](../concepts/application_structure.md) to LangGraph Cloud. +- An API key for [Anthropic](https://console.anthropic.com/) +- An API key for [Tavily](https://app.tavily.com/) -For this guide, we'll use the pre-built Python [**ReAct Agent**](https://github.com/langchain-ai/react-agent) template. - -??? note "Get Required API Keys for the ReAct Agent template" - - This **ReAct Agent** application requires an API key from [Anthropic](https://console.anthropic.com/) and [Tavily](https://app.tavily.com/). You can get these API keys by signing up on their respective websites. - - **Alternative**: If you'd prefer a scaffold application that doesn't require API keys, use the [**New LangGraph Project**](https://github.com/langchain-ai/new-langgraph-project) template instead of the **ReAct Agent** template. +## 1. Create a repository on GitHub +To deploy a LangGraph application to **LangGraph Cloud**, your application code must reside in a GitHub repository. Both public and private repositories are supported. For this quickstart, use the [pre-built Python ReAct agent template](https://github.com/langchain-ai/react-agent) for your application: 1. Go to the [ReAct Agent](https://github.com/langchain-ai/react-agent) repository. -2. Fork the repository to your GitHub account by clicking the `Fork` button in the top right corner. +1. Click the `Fork` button in the top right corner to fork the repository to your GitHub account. +1. Click **Create fork**. -## Deploy to LangGraph Cloud +## 2. Deploy to LangGraph Platform -??? note "1. Log in to [LangSmith](https://smith.langchain.com/)" +1. Log in to [LangSmith](https://smith.langchain.com/). +1. In the left sidebar, select **LangGraph Platform**. +1. Click the **+ New Deployment** button. A modal will open where you can fill in the required fields. +1. If you are a first time user or adding a private repository that has not been previously connected, click the **Import from GitHub** button and follow the instructions to connect your GitHub account. +1. Select your ReAct Agent repository. +1. In the **Environment Variables** section, set the following secrets: + + - **ANTHROPIC_API_KEY**: Get an API key from [Anthropic](https://console.anthropic.com/). + - **TAVILY_API_KEY**: Get an API key on the [Tavily website](https://app.tavily.com/). + +1. Click **Submit** to deploy. + + This may take about 15 minutes to complete. You can check the status in the **Deployment details** view. + +## 3. Test your application in LangGraph Studio + +Once your application is deployed: + +1. Select the deployment you just created to view more details. +1. Click the **LangGraph Studio** button in the top right corner. + + LangGraph Studio will open to display your graph.
- [![Login to LangSmith](deployment/img/01_login.png){: style="max-height:300px"}](deployment/img/01_login.png) + [![image](deployment/img/09_langgraph_studio.png){: style="max-height:400px"}](deployment/img/09_langgraph_studio.png)
- Go to [LangSmith](https://smith.langchain.com/) and log in. If you don't have an account, you can sign up for free. + Sample graph run in LangGraph Studio.
+## 4. Get the API URL for your deployment -??? note "2. Click on LangGraph Platform (the left sidebar)" +1. In the **Deployment details** view in LangGraph, click the **API URL** to copy it to your clipboard. +1. Click the `URL` to copy it to the clipboard. -
- [![Login to LangSmith](deployment/img/02_langgraph_platform.png){: style="max-height:300px"}](deployment/img/02_langgraph_platform.png) -
- Select **LangGraph Platform** from the left sidebar. -
-
+## 5. Test the API -??? note "3. Click on + New Deployment (top right corner)" - -
- [![Login to LangSmith](deployment/img/03_deployments_page.png){: style="max-height:300px"}](deployment/img/03_deployments_page.png) -
- Click on **+ New Deployment** to create a new deployment. This button is located in the top right corner. - It'll open a new modal where you can fill out the required fields. -
-
- -??? note "4. Click on Import from GitHub (first time users)" - -
- [![image](deployment/img/04_create_new_deployment.png)](deployment/img/04_create_new_deployment.png) -
- Click on **Import from GitHub** and follow the instructions to connect your GitHub account. This step is needed for **first-time users** or to add private repositories that haven't been connected before.
-
- -??? note "5. Select the repository, configure ENV vars etc" - -
- [![image](deployment/img/05_configure_deployment.png){: style="max-height:300px"}](deployment/img/05_configure_deployment.png) -
- Select the repository, add env variables and secrets, and set other configuration options. -
-
- - - **Repository**: Select the repository you forked earlier (or any other repository you want to deploy). - - Set the secrets and environment variables required by your application. For the **ReAct Agent** template, you need to set the following secrets: - - **ANTHROPIC_API_KEY**: Get an API key from [Anthropic](https://console.anthropic.com/). - - **TAVILY_API_KEY**: Get an API key on the [Tavily website](https://app.tavily.com/). - -??? note "6. Click Submit to Deploy!" - - -
- [![image](deployment/img/05_configure_deployment.png){: style="max-height:300px"}](deployment/img/05_configure_deployment.png) -
- Please note that this step may ~15 minutes to complete. You can check the status of your deployment in the **Deployments** view. - Click the Submit button at the top right corner to deploy your application. -
-
- - -## LangGraph Studio Web UI - -Once your application is deployed, you can test it in **LangGraph Studio**. - -??? note "1. Click on an existing deployment" - -
- [![image](deployment/img/07_deployments_page.png){: style="max-height:300px"}](deployment/img/07_deployments_page.png) -
- Click on the deployment you just created to view more details. -
-
- -??? note "2. Click on LangGraph Studio" - -
- [![image](deployment/img/08_deployment_view.png){: style="max-height:300px"}](deployment/img/08_deployment_view.png) -
- Click on the LangGraph Studio button to open LangGraph Studio. -
-
- -
-[![image](deployment/img/09_langgraph_studio.png){: style="max-height:400px"}](deployment/img/09_langgraph_studio.png) -
- Sample graph run in LangGraph Studio. -
-
- -## Test the API - -!!! note - - The API calls below are for the **ReAct Agent** template. If you're deploying a different application, you may need to adjust the API calls accordingly. - -Before using, you need to get the `URL` of your LangGraph deployment. You can find this in the `Deployment` view. Click the `URL` to copy it to the clipboard. - -You also need to make sure you have set up your API key properly, so you can authenticate with LangGraph Cloud. - -```shell -export LANGSMITH_API_KEY=... -``` +You can now test the API: === "Python SDK (Async)" - **Install the LangGraph Python SDK** + 1. Install the LangGraph Python SDK: - ```shell - pip install langgraph-sdk - ``` + ```shell + pip install langgraph-sdk + ``` - **Send a message to the assistant (threadless run)** + 1. Send a message to the assistant (threadless run): - ```python - from langgraph_sdk import get_client + ```python + from langgraph_sdk import get_client - client = get_client(url="your-deployment-url", api_key="your-langsmith-api-key") + client = get_client(url="your-deployment-url", api_key="your-langsmith-api-key") - async for chunk in client.runs.stream( - None, # Threadless run - "agent", # Name of assistant. Defined in langgraph.json. - input={ - "messages": [{ - "role": "human", - "content": "What is LangGraph?", - }], - }, - stream_mode="updates", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` + async for chunk in client.runs.stream( + None, # Threadless run + "agent", # Name of assistant. Defined in langgraph.json. + input={ + "messages": [{ + "role": "human", + "content": "What is LangGraph?", + }], + }, + stream_mode="updates", + ): + print(f"Receiving new event of type: {chunk.event}...") + print(chunk.data) + print("\n\n") + ``` === "Python SDK (Sync)" - **Install the LangGraph Python SDK** + 1. Install the LangGraph Python SDK: - ```shell - pip install langgraph-sdk - ``` + ```shell + pip install langgraph-sdk + ``` - **Send a message to the assistant (threadless run)** + 1. Send a message to the assistant (threadless run): - ```python - from langgraph_sdk import get_sync_client + ```python + from langgraph_sdk import get_sync_client - client = get_sync_client(url="your-deployment-url", api_key="your-langsmith-api-key") + client = get_sync_client(url="your-deployment-url", api_key="your-langsmith-api-key") - for chunk in client.runs.stream( - None, # Threadless run - "agent", # Name of assistant. Defined in langgraph.json. - input={ - "messages": [{ - "role": "human", - "content": "What is LangGraph?", - }], - }, - stream_mode="updates", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` + for chunk in client.runs.stream( + None, # Threadless run + "agent", # Name of assistant. Defined in langgraph.json. + input={ + "messages": [{ + "role": "human", + "content": "What is LangGraph?", + }], + }, + stream_mode="updates", + ): + print(f"Receiving new event of type: {chunk.event}...") + print(chunk.data) + print("\n\n") + ``` === "Javascript SDK" - **Install the LangGraph JS SDK** + 1. Install the LangGraph JS SDK - ```shell - npm install @langchain/langgraph-sdk - ``` + ```shell + npm install @langchain/langgraph-sdk + ``` - **Send a message to the assistant (threadless run)** + 1. Send a message to the assistant (threadless run): - ```js - const { Client } = await import("@langchain/langgraph-sdk"); + ```js + const { Client } = await import("@langchain/langgraph-sdk"); - const client = new Client({ apiUrl: "your-deployment-url", apiKey: "your-langsmith-api-key" }); + const client = new Client({ apiUrl: "your-deployment-url", apiKey: "your-langsmith-api-key" }); - const streamResponse = client.runs.stream( - null, // Threadless run - "agent", // Assistant ID - { - input: { - "messages": [ - { "role": "user", "content": "What is LangGraph?"} - ] - }, - streamMode: "messages", + const streamResponse = client.runs.stream( + null, // Threadless run + "agent", // Assistant ID + { + input: { + "messages": [ + { "role": "user", "content": "What is LangGraph?"} + ] + }, + streamMode: "messages", + } + ); + + for await (const chunk of streamResponse) { + console.log(`Receiving new event of type: ${chunk.event}...`); + console.log(JSON.stringify(chunk.data)); + console.log("\n\n"); } - ); - - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(JSON.stringify(chunk.data)); - console.log("\n\n"); - } - ``` + ``` === "Rest API" @@ -253,20 +183,11 @@ export LANGSMITH_API_KEY=... ## Next Steps -Congratulations! If you've worked your way through this tutorial you are well on your way to becoming a LangGraph Cloud expert. Here are some other resources to check out to help you out on the path to expertise: +Congratulations! You have deployed an application using LangGraph Platform. -### LangGraph Framework +Here are some other resources to check out: -- **[LangGraph Tutorial](../tutorials/introduction.ipynb)**: Get started with LangGraph framework. -- **[LangGraph Concepts](../concepts/index.md)**: Learn the foundational concepts of LangGraph. -- **[LangGraph How-to Guides](../how-tos/index.md)**: Guides for common tasks with LangGraph. - -### 📚 Learn More about LangGraph Platform - -Expand your knowledge with these resources: - -- **[LangGraph Platform Concepts](../concepts/index.md#langgraph-platform)**: Understand the foundational concepts of the LangGraph Platform. -- **[LangGraph Platform How-to Guides](../how-tos/index.md#langgraph-platform)**: Discover step-by-step guides to build and deploy applications. -- **[Launch Local LangGraph Server](../tutorials/langgraph-platform/local-server.md)**: This quick start guide shows how to start a LangGraph Server locally for the **ReAct Agent** template. The steps are similar for other templates. +- [LangGraph Platform overview](../concepts/langgraph_platform.md) +- [Deployment options](../concepts/deployment_options.md) diff --git a/docs/docs/cloud/reference/env_var.md b/docs/docs/cloud/reference/env_var.md index 659459219..e25ef72ca 100644 --- a/docs/docs/cloud/reference/env_var.md +++ b/docs/docs/cloud/reference/env_var.md @@ -18,6 +18,10 @@ A background run can execute for longer than 1 hour, but a client must reconnect Defaults to `3600`. +## `BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS` + +Specifies, in seconds, how long the server will wait for background jobs to finish after the queue receives a shutdown signal. After this period, the server will force termination. Defaults to `3600` seconds. Set this to ensure jobs have enough time to complete cleanly during shutdown. Added in `langgraph-api==0.2.16`. + ## `DD_API_KEY` Specify `DD_API_KEY` (your [Datadog API Key](https://docs.datadoghq.com/account_management/api-app-keys/)) to automatically enable Datadog tracing for the deployment. Specify other [`DD_*` environment variables](https://ddtrace.readthedocs.io/en/stable/configuration.html) to configure the tracing instrumentation. @@ -38,11 +42,11 @@ For deployments to LangGraph Cloud, this environment variable is set automatical ## `LANGSMITH_RUNS_ENDPOINTS` -For [Bring Your Own Cloud (BYOC)](../../concepts/bring_your_own_cloud.md) deployments with [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) only. +For deployments with [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) only. -Set this environment variable to have a BYOC deployment send traces to a self-hosted LangSmith instance. The value of `LANGSMITH_RUNS_ENDPOINTS` is a JSON string: `{"":""}`. +Set this environment variable to have a deployment send traces to a self-hosted LangSmith instance. The value of `LANGSMITH_RUNS_ENDPOINTS` is a JSON string: `{"":""}`. -`SELF_HOSTED_LANGSMITH_HOSTNAME` is the hostname of the self-hosted LangSmith instance. It must be accessible to the BYOC deployment. `LANGSMITH_API_KEY` is a LangSmith API generated from the self-hosted LangSmith instance. +`SELF_HOSTED_LANGSMITH_HOSTNAME` is the hostname of the self-hosted LangSmith instance. It must be accessible to the deployment. `LANGSMITH_API_KEY` is a LangSmith API generated from the self-hosted LangSmith instance. ## `LANGSMITH_TRACING` diff --git a/docs/docs/concepts/agentic_concepts.md b/docs/docs/concepts/agentic_concepts.md index 336633e95..ed1a811f9 100644 --- a/docs/docs/concepts/agentic_concepts.md +++ b/docs/docs/concepts/agentic_concepts.md @@ -31,7 +31,7 @@ Structured outputs with LLMs work by providing a specific format or schema that Structured outputs are crucial for routing as they ensure the LLM's decision can be reliably interpreted and acted upon by the system. Learn more about [structured outputs in this how-to guide](https://python.langchain.com/docs/how_to/structured_output/). -## Tool calling agent +## Tool-calling agent While a router allows an LLM to make a single decision, more complex agent architectures expand the LLM's control in two key ways: @@ -40,11 +40,13 @@ While a router allows an LLM to make a single decision, more complex agent archi [ReAct](https://arxiv.org/abs/2210.03629) is a popular general purpose agent architecture that combines these expansions, integrating three core concepts. -1. `Tool calling`: Allowing the LLM to select and use various tools as needed. -2. `Memory`: Enabling the agent to retain and use information from previous steps. -3. `Planning`: Empowering the LLM to create and follow multi-step plans to achieve goals. +1. [Tool calling](#tool-calling): Allowing the LLM to select and use various tools as needed. +2. [Memory](#memory): Enabling the agent to retain and use information from previous steps. +3. [Planning](#planning): Empowering the LLM to create and follow multi-step plans to achieve goals. -This architecture allows for more complex and flexible agent behaviors, going beyond simple routing to enable dynamic problem-solving with multiple steps. You can use it with [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]. +This architecture allows for more complex and flexible agent behaviors, going beyond simple routing to enable dynamic problem-solving with multiple steps. Unlike the original [paper](https://arxiv.org/abs/2210.03629), today's agents rely on LLMs' [tool calling](#tool-calling) capabilities and operate on a list of [messages](./low_level.md#why-use-messages). + +In LangGraph, you can use the prebuilt [agent](../agent/overview.md) to get started with tool-calling agents. ### Tool calling @@ -56,33 +58,24 @@ Tools are useful whenever you want an agent to interact with external systems. E ### Memory -Memory is crucial for agents, enabling them to retain and utilize information across multiple steps of problem-solving. It operates on different scales: +[Memory](./memory.md) is crucial for agents, enabling them to retain and utilize information across multiple steps of problem-solving. It operates on different scales: -1. Short-term memory: Allows the agent to access information acquired during earlier steps in a sequence. -2. Long-term memory: Enables the agent to recall information from previous interactions, such as past messages in a conversation. +1. [Short-term memory](./memory.md#short-term-memory): Allows the agent to access information acquired during earlier steps in a sequence. +2. [Long-term memory](./memory.md#long-term-memory): Enables the agent to recall information from previous interactions, such as past messages in a conversation. LangGraph provides full control over memory implementation: - [`State`](./low_level.md#state): User-defined schema specifying the exact structure of memory to retain. -- [`Checkpointers`](./persistence.md): Mechanism to store state at every step across different interactions. +- [`Checkpointer`](./persistence.md#checkpoints): Mechanism to store state at every step across different interactions within a session. +- [`Store`](./persistence.md#memory-store): Mechanism to store user-specific or application-level data across sessions. This flexible approach allows you to tailor the memory system to your specific agent architecture needs. For a practical guide on adding memory to your graph, see [this tutorial](../how-tos/persistence.ipynb). -Effective memory management enhances an agent's ability to maintain context, learn from past experiences, and make more informed decisions over time. +Effective [memory management](../how-tos/memory.ipynb) enhances an agent's ability to maintain context, learn from past experiences, and make more informed decisions over time. ### Planning -In the ReAct architecture, an LLM is called repeatedly in a while-loop. At each step the agent decides which tools to call, and what the inputs to those tools should be. Those tools are then executed, and the outputs are fed back into the LLM as observations. The while-loop terminates when the agent decides it has enough information to solve the user request and it is not worth calling any more tools. - -### ReAct implementation - -There are several differences between [this](https://arxiv.org/abs/2210.03629) paper and the pre-built [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] implementation: - -- First, we use [tool-calling](#tool-calling) to have LLMs call tools, whereas the paper used prompting + parsing of raw output. This is because tool calling did not exist when the paper was written, but is generally better and more reliable. -- Second, we use messages to prompt the LLM, whereas the paper used string formatting. This is because at the time of writing, LLMs didn't even expose a message-based interface, whereas now that's the only interface they expose. -- Third, the paper required all inputs to the tools to be a single string. This was largely due to LLMs not being super capable at the time, and only really being able to generate a single input. Our implementation allows for using tools that require multiple inputs. -- Fourth, the paper only looks at calling a single tool at the time, largely due to limitations in LLMs performance at the time. Our implementation allows for calling multiple tools at a time. -- Finally, the paper asked the LLM to explicitly generate a "Thought" step before deciding which tools to call. This is the "Reasoning" part of "ReAct". Our implementation does not do this by default, largely because LLMs have gotten much better and that is not as necessary. Of course, if you wish to prompt it do so, you certainly can. +In a tool-calling [agent](../agent/overview.md), an LLM is called repeatedly in a while-loop. At each step the agent decides which tools to call, and what the inputs to those tools should be. Those tools are then executed, and the outputs are fed back into the LLM as observations. The while-loop terminates when the agent decides it has enough information to solve the user request and it is not worth calling any more tools. ## Custom agent architectures @@ -110,7 +103,7 @@ For practical implementation, see our [map-reduce tutorial](../how-tos/map-reduc ### Subgraphs -[Subgraphs](./low_level.md#subgraphs) are essential for managing complex agent architectures, particularly in [multi-agent systems](./multi_agent.md). They allow: +[Subgraphs](./subgraphs.md) are essential for managing complex agent architectures, particularly in [multi-agent systems](./multi_agent.md). They allow: - Isolated state management for individual agents - Hierarchical organization of agent teams diff --git a/docs/docs/concepts/application_structure.md b/docs/docs/concepts/application_structure.md index e938dff31..47b03c6d7 100644 --- a/docs/docs/concepts/application_structure.md +++ b/docs/docs/concepts/application_structure.md @@ -5,25 +5,20 @@ search: # Application Structure -!!! info "Prerequisites" - - - [LangGraph Server](./langgraph_server.md) - - [LangGraph Glossary](./low_level.md) - ## Overview -A LangGraph application consists of one or more graphs, a LangGraph API Configuration file (`langgraph.json`), a file that specifies dependencies, and an optional .env file that specifies environment variables. +A LangGraph application consists of one or more graphs, a configuration file (`langgraph.json`), a file that specifies dependencies, and an optional `.env` file that specifies environment variables. -This guide shows a typical structure for a LangGraph application and shows how the required information to deploy a LangGraph application using the LangGraph Platform is specified. +This guide shows a typical structure of an application and shows how the required information to deploy an application using the LangGraph Platform is specified. ## Key Concepts To deploy using the LangGraph Platform, the following information should be provided: -1. A [LangGraph API Configuration file](#configuration-file-concepts) (`langgraph.json`) that specifies the dependencies, graphs, environment variables to use for the application. +1. A [LangGraph configuration file](#configuration-file-concepts) (`langgraph.json`) that specifies the dependencies, graphs, and environment variables to use for the application. 2. The [graphs](#graphs) that implement the logic of the application. 3. A file that specifies [dependencies](#dependencies) required to run the application. -4. [Environment variable](#environment-variables) that are required for the application to run. +4. [Environment variables](#environment-variables) that are required for the application to run. ## File Structure @@ -81,26 +76,15 @@ Below are examples of directory structures for Python and JavaScript application The directory structure of a LangGraph application can vary depending on the programming language and the package manager used. - ## Configuration File {#configuration-file-concepts} The `langgraph.json` file is a JSON file that specifies the dependencies, graphs, environment variables, and other settings required to deploy a LangGraph application. -The file supports specification of the following information: +See the [LangGraph configuration file reference](../cloud/reference/cli.md#configuration-file) for details on all supported keys in the JSON file. - -| Key | Description | -|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `dependencies` | **Required**. Array of dependencies for LangGraph API server. Dependencies can be one of the following: (1) `"."`, which will look for local Python packages, (2) `pyproject.toml`, `setup.py` or `requirements.txt` in the app directory `"./local_package"`, or (3) a package name. | -| `graphs` | **Required**. Mapping from graph ID to path where the compiled graph or a function that makes a graph is defined. Example:
  • `./your_package/your_file.py:variable`, where `variable` is an instance of `langgraph.graph.state.CompiledStateGraph`
  • `./your_package/your_file.py:make_graph`, where `make_graph` is a function that takes a config dictionary (`langchain_core.runnables.RunnableConfig`) and creates an instance of `langgraph.graph.state.StateGraph` / `langgraph.graph.state.CompiledStateGraph`.
| -| `env` | Path to `.env` file or a mapping from environment variable to its value. | -| `python_version` | `3.11` or `3.12`. Defaults to `3.11`. | -| `pip_config_file` | Path to `pip` config file. | -| `dockerfile_lines` | Array of additional lines to add to Dockerfile following the import from parent image. | !!! tip - The LangGraph CLI defaults to using the configuration file **langgraph.json** in the current directory. - + The [LangGraph CLI](./langgraph_cli.md) defaults to using the configuration file `langgraph.json` in the current directory. ### Examples @@ -149,7 +133,7 @@ A LangGraph application may depend on other Python packages or JavaScript librar You will generally need to specify the following information for dependencies to be set up correctly: -1. A file in the directory that specifies the dependencies (e.g., `requirements.txt`, `pyproject.toml`, or `package.json`). +1. A file in the directory that specifies the dependencies (e.g. `requirements.txt`, `pyproject.toml`, or `package.json`). 2. A `dependencies` key in the [LangGraph configuration file](#configuration-file-concepts) that specifies the dependencies required to run the LangGraph application. 3. Any additional binaries or system libraries can be specified using `dockerfile_lines` key in the [LangGraph configuration file](#configuration-file-concepts). @@ -164,9 +148,3 @@ You can specify one or more graphs in the configuration file. Each graph is iden If you're working with a deployed LangGraph application locally, you can configure environment variables in the `env` key of the [LangGraph configuration file](#configuration-file-concepts). For a production deployment, you will typically want to configure the environment variables in the deployment environment. - -## Related - -Please see the following resources for more information: - -- How-to guides for [Application Structure](../how-tos/index.md#application-structure). diff --git a/docs/docs/concepts/assistants.md b/docs/docs/concepts/assistants.md index ef8986201..58c669223 100644 --- a/docs/docs/concepts/assistants.md +++ b/docs/docs/concepts/assistants.md @@ -1,42 +1,25 @@ ---- -search: - boost: 2 ---- - # Assistants !!! info "Prerequisites" - [LangGraph Server](./langgraph_server.md) + - [Configuration](./low_level.md#configuration) -When building agents, it is fairly common to make rapid changes that *do not* alter the graph logic. For example, simply changing prompts or the LLM selection can have significant impacts on the behavior of the agents. Assistants offer an easy way to make and save these types of changes to agent configuration. This can have at least two use-cases: +When building agents, it is common to make rapid changes that _do not_ alter the graph logic. For example, simply changing prompts or the LLM selection can have significant impacts on the behavior of the agent but does not require updating your graph's architecture. Assistants offer a straightforward way to manage these configurations separately from your graph's core logic. -* Assistants give developers a quick and easy way to modify and version agents for experimentation. -* Assistants can be modified via LangGraph Studio, offering a no-code way to configure agents (e.g., for business users). - -Assistants build off the concept of ["configuration"](low_level.md#configuration). -While ["configuration"](low_level.md#configuration) is available in the open source LangGraph library as well, assistants are only present in [LangGraph Platform](langgraph_platform.md). -This is because Assistants are tightly coupled to your deployed graph, and so we can only make them available when we are also deploying the graphs. - -## Configuring Assistants - -In practice, an assistant is just an *instance* of a graph with a specific configuration. Because of this, multiple assistants can reference the same graph but can contain different configurations, such as prompts, models, and other graph configuration options. The LangGraph Cloud API provides several endpoints for creating and managing assistants. See the [API reference](../cloud/reference/api/api_ref.html) and [this how-to](../cloud/how-tos/configuration_cloud.md) for more details on how to create assistants. - -## Versioning Assistants - -Once you've created an assistant, you can save and version it to track changes to the configuration over time. You can think about this at three levels: - -1) The graph lays out the general agent application logic -2) The agent configuration options represent parameters that can be changed -3) Assistant versions save and track specific settings of the agent configuration options - -For example, let's imagine you have a general writing agent. You have created a general graph architecture that works well for writing. However, there are different types of writing, e.g. blogs vs tweets. In order to get the best performance on each use case, you need to make some minor changes to the models and prompts used. In this setup, you could create an assistant for each use case - one for blog writing and one for tweeting. These would share the same graph structure, but they may use different models and different prompts. Read [this how-to](../cloud/how-tos/assistant_versioning.md) to learn how you can use assistant versioning through both the [Studio](../concepts/langgraph_studio.md) and the SDK. +Imagine a general-purpose writing agent built on a common graph architecture. While the structure remains the same, different writing styles—such as blog posts and tweets—require tailored configurations to optimize performance. To support these variations, you can create multiple assistants (e.g., one for blogs and another for tweets) that share the underlying graph but differ in model selection and system prompt. ![assistant versions](img/assistants.png) +## Configuring Assistants -## Resources +Assistants build on the LangGraph open source concept of [configuration](low_level.md#configuration). +While configuration is available in the open source LangGraph library, assistants are only present in [LangGraph Platform](langgraph_platform.md). +This is due to the fact that Assistants are tightly coupled to your deployed graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default configuration settings. -For more information on assistants, see the following resources: +In practice, an assistant is just an _instance_ of a graph with a specific configuration. Therefore, multiple assistants can reference the same graph but can contain different configurations (e.g. prompts, models, tools). The LangGraph Server API provides several endpoints for creating and managing assistants. See the [API reference](../cloud/reference/api/api_ref.html) and [this how-to](../cloud/how-tos/configuration_cloud.md) for more details on how to create assistants. -- [Assistants how-to guides](../how-tos/index.md#assistants) \ No newline at end of file +## Versioning Assistants + +Assistants support versioning to track changes over time. +Once you've created an assistant, subsequent edits to that assistant will create new versions. See [this how-to](../cloud/how-tos/assistant_versioning.md) for more details on how to manage assistant versions. diff --git a/docs/docs/concepts/auth.md b/docs/docs/concepts/auth.md index 7e3f98399..41b56df06 100644 --- a/docs/docs/concepts/auth.md +++ b/docs/docs/concepts/auth.md @@ -38,8 +38,8 @@ LangGraph Platform provides different security defaults: - You control all aspects of authentication and authorization !!! note "Custom auth" - Custom auth is supported for **Enterprise** self-hosted plans. - Self-hosted lite plans do not support custom auth natively. + Custom auth is supported for **Enterprise** self-hosted deployments. + Self-hosted lite deployments do not support custom auth natively. ## System Architecture diff --git a/docs/docs/concepts/breakpoints.md b/docs/docs/concepts/breakpoints.md index 3454f9de7..e373543f1 100644 --- a/docs/docs/concepts/breakpoints.md +++ b/docs/docs/concepts/breakpoints.md @@ -5,133 +5,10 @@ search: # Breakpoints -Breakpoints pause graph execution at specific points and enable stepping through execution step by step. Breakpoints are powered by LangGraph's [**persistence layer**](./persistence.md), which saves the state after each graph step. Breakpoints can also be used to enable [**human-in-the-loop**](./human_in_the_loop.md) workflows, though we recommend using the [`interrupt` function](./human_in_the_loop.md#interrupt) for this purpose. +Breakpoints pause graph execution at defined points and let you step through each stage. They use LangGraph's [**persistence layer**](./persistence.md), which saves the graph state after each step. -## Requirements +With breakpoints, you can inspect the graph's state and node inputs at any point. Execution pauses **indefinitely** until you resume, as the checkpointer preserves the state. -To use breakpoints, you will need to: - -1. [**Specify a checkpointer**](persistence.md#checkpoints) to save the graph state after each step. -2. [**Set breakpoints**](#setting-breakpoints) to specify where execution should pause. -3. **Run the graph** with a [**thread ID**](./persistence.md#threads) to pause execution at the breakpoint. -4. **Resume execution** using `invoke`/`ainvoke`/`stream`/`astream` (see [**The `Command` primitive**](./human_in_the_loop.md#the-command-primitive)). - -## Setting breakpoints - -There are two places where you can set breakpoints: - -1. **Before** or **after** a node executes by setting breakpoints at **compile time** or **run time**. We call these [**static breakpoints**](#static-breakpoints). -2. **Inside** a node using the [`NodeInterrupt` exception](#nodeinterrupt-exception). - -### Static breakpoints - -Static breakpoints are triggered either **before** or **after** a node executes. You can set static breakpoints by specifying `interrupt_before` and `interrupt_after` at **"compile" time** or **run time**. - -=== "Compile time" - - ```python - graph = graph_builder.compile( - interrupt_before=["node_a"], - interrupt_after=["node_b", "node_c"], - checkpointer=..., # Specify a checkpointer - ) - - thread_config = { - "configurable": { - "thread_id": "some_thread" - } - } - - # Run the graph until the breakpoint - graph.invoke(inputs, config=thread_config) - - # Optionally update the graph state based on user input - graph.update_state(update, config=thread_config) - - # Resume the graph - graph.invoke(None, config=thread_config) - ``` - -=== "Run time" - - ```python - graph.invoke( - inputs, - config={"configurable": {"thread_id": "some_thread"}}, - interrupt_before=["node_a"], - interrupt_after=["node_b", "node_c"] - ) - - thread_config = { - "configurable": { - "thread_id": "some_thread" - } - } - - # Run the graph until the breakpoint - graph.invoke(inputs, config=thread_config) - - # Optionally update the graph state based on user input - graph.update_state(update, config=thread_config) - - # Resume the graph - graph.invoke(None, config=thread_config) - ``` - - !!! note - - You cannot set static breakpoints at runtime for **sub-graphs**. - If you have a sub-graph, you must set the breakpoints at compilation time. - -Static breakpoints can be especially useful for debugging if you want to step through the graph execution one -node at a time or if you want to pause the graph execution at specific nodes. - -### `NodeInterrupt` exception - -We recommend that you [**use the `interrupt` function instead**][langgraph.types.interrupt] of the `NodeInterrupt` exception if you're trying to implement -[human-in-the-loop](./human_in_the_loop.md) workflows. The `interrupt` function is easier to use and more flexible. - -??? node "`NodeInterrupt` exception" - - The developer can define some *condition* that must be met for a breakpoint to be triggered. This concept of _dynamic breakpoints_ is useful when the developer wants to halt the graph under *a particular condition*. This uses a `NodeInterrupt`, which is a special type of exception that can be raised from within a node based upon some condition. As an example, we can define a dynamic breakpoint that triggers when the `input` is longer than 5 characters. - - ```python - def my_node(state: State) -> State: - if len(state['input']) > 5: - raise NodeInterrupt(f"Received input that is longer than 5 characters: {state['input']}") - - return state - ``` - - - Let's assume we run the graph with an input that triggers the dynamic breakpoint and then attempt to resume the graph execution simply by passing in `None` for the input. - - ```python - # Attempt to continue the graph execution with no change to state after we hit the dynamic breakpoint - for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) - ``` - - The graph will *interrupt* again because this node will be *re-run* with the same graph state. We need to change the graph state such that the condition that triggers the dynamic breakpoint is no longer met. So, we can simply edit the graph state to an input that meets the condition of our dynamic breakpoint (< 5 characters) and re-run the node. - - ```python - # Update the state to pass the dynamic breakpoint - graph.update_state(config=thread_config, values={"input": "foo"}) - for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) - ``` - - Alternatively, what if we want to keep our current input and skip the node (`my_node`) that performs the check? To do this, we can simply perform the graph update with `as_node="my_node"` and pass in `None` for the values. This will make no update the graph state, but run the update as `my_node`, effectively skipping the node and bypassing the dynamic breakpoint. - - ```python - # This update will skip the node `my_node` altogether - graph.update_state(config=thread_config, values=None, as_node="my_node") - for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) - ``` - -## Additional Resources 📚 - -- [**Conceptual Guide: Persistence**](persistence.md): Read the persistence guide for more context about persistence. -- [**Conceptual Guide: Human-in-the-loop**](human_in_the_loop.md): Read the human-in-the-loop guide for more context on integrating human feedback into LangGraph applications using breakpoints. -- [**How to View and Update Past Graph State**](../how-tos/human_in_the_loop/time-travel.ipynb): Step-by-step instructions for working with graph state that demonstrate the **replay** and **fork** actions. \ No newline at end of file +
+![image](img/breakpoints.png){: style="max-height:400px"} +
An example graph consisting of 3 sequential steps with a breakpoint before step_3.
diff --git a/docs/docs/concepts/bring_your_own_cloud.md b/docs/docs/concepts/bring_your_own_cloud.md deleted file mode 100644 index 4a8e4c473..000000000 --- a/docs/docs/concepts/bring_your_own_cloud.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -search: - boost: 2 ---- - -# Bring Your Own Cloud (BYOC) - -!!! note Prerequisites - - - [LangGraph Platform](./langgraph_platform.md) - - [Deployment Options](./deployment_options.md) - -## Architecture - -Split control plane (hosted by us) and data plane (hosted by you, managed by us). - -| | Control Plane | Data Plane | -|-----------------------------|---------------------------------|-----------------------------------------------| -| What it does | Manages deployments, revisions. | Runs your LangGraph graphs, stores your data. | -| Where it is hosted | LangChain Cloud account | Your cloud account | -| Who provisions and monitors | LangChain | LangChain | - -LangChain has no direct access to the resources created in your cloud account, and can only interact with them via AWS APIs. Your data never leaves your cloud account / VPC at rest or in transit. - -![Architecture](img/byoc_architecture.png) - -## Requirements - -- You’re using AWS already. -- You use `langgraph-cli` and/or [LangGraph Studio](./langgraph_studio.md) app to test graph locally. -- You use `langgraph build` command to build image and then push it to your AWS ECR repository (`docker push`). - -## How it works - -- We provide you a [Terraform module](https://github.com/langchain-ai/terraform/tree/main/modules/langgraph_cloud_setup) which you run to set up our requirements - 1. Creates an AWS role (which our control plane will later assume to provision and monitor resources) - - https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonVPCReadOnlyAccess.html - - Read VPCS to find subnets - - https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonECS_FullAccess.html - - Used to create/delete ECS resources for your LangGraph Cloud instances - - https://docs.aws.amazon.com/aws-managed-policy/latest/reference/SecretsManagerReadWrite.html - - Create secrets for your ECS resources - - https://docs.aws.amazon.com/aws-managed-policy/latest/reference/CloudWatchReadOnlyAccess.html - - Read CloudWatch metrics/logs to monitor your instances/push deployment logs - - https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonRDSFullAccess.html - - Provision `RDS` instances for your LangGraph Cloud instances - - Alternatively, an externally managed Postgres instance can be used instead of the default `RDS` instance. LangChain does not monitor or manage the externally managed Postgres instance. See details for [`POSTGRES_URI_CUSTOM` environment variable](../cloud/reference/env_var.md#postgres_uri_custom). - 2. Either - - Tags an existing vpc / subnets as `langgraph-cloud-enabled` - - Creates a new vpc and subnets and tags them as `langgraph-cloud-enabled` -- You create a LangGraph Cloud Project in `smith.langchain.com` providing - - the ID of the AWS role created in the step above - - the AWS ECR repo to pull the service image from -- We provision the resources in your cloud account using the role above -- We monitor those resources to ensure uptime and recovery from errors - -Notes for customers using [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting): - -- Creation of new LangGraph Cloud projects and revisions currently needs to be done on `smith.langchain.com`. -- However, you can set up the project to trace to your self-hosted LangSmith instance if desired. See details for [`LANGSMITH_RUNS_ENDPOINTS` environment variable](../cloud/reference/env_var.md#langsmith_runs_endpoints). diff --git a/docs/docs/concepts/deployment_options.md b/docs/docs/concepts/deployment_options.md index 8934e147b..31a53e945 100644 --- a/docs/docs/concepts/deployment_options.md +++ b/docs/docs/concepts/deployment_options.md @@ -5,33 +5,33 @@ search: # Deployment Options -!!! info "Prerequisites" - - - [LangGraph Platform](./langgraph_platform.md) - - [LangGraph Server](./langgraph_server.md) - - [LangGraph Platform Plans](./plans.md) - -## Overview - There are 4 main options for deploying with the LangGraph Platform: -1. **Cloud SaaS(Beta)**: Available for **Plus** and **Enterprise** plans. +1. [Cloud SaaS](#cloud-saas) -1. **Self-Hosted Data Plane(Beta)**: Available for the **Enterprise** plan. +1. [Self-Hosted Data Plane(Beta)](#self-hosted-data-plane) -1. **Self-Hosted Control Plane(Beta)**: Available for the **Enterprise** plan. +1. [Self-Hosted Control Plane(Beta)](#self-hosted-control-plane) -1. **[Standalone Container](#standalone-container)**: Available for all plans. +1. [Standalone Container](#standalone-container) -Please see the [LangGraph Platform Plans](./plans.md) for more information on the different plans. -The guide below will explain the differences between the deployment options. +A quick comparison: + +| | **Cloud SaaS** | **Self-Hosted Data Plane** | **Self-Hosted Control Plane** | **Standalone Container** | **Self-Hosted Lite** | +|----------------------|----------------|----------------------------|-------------------------------|--------------------------| ---------------------| +| **[Control plane UI/API](../concepts/langgraph_control_plane.md)** | Yes | Yes | Yes | No | No | +| **CI/CD** | Managed internally by platform | Managed externally by you | Managed externally by you | Managed externally by you | Managed externally by you | +| **Data/compute residency** | LangChain’s cloud | Your cloud | Your cloud | Your cloud | Your cloud | +| **LangSmith compatibility** | Trace to LangSmith SaaS | Trace to LangSmith SaaS | Trace to Self-Hosted LangSmith | Optional tracing | Optional tracing | +| **[Server version compatibility](../concepts/langgraph_server.md#server-versions)** | Enterprise | Enterprise | Enterprise | Lite, Enterprise | Lite | +| **[Pricing](https://www.langchain.com/pricing-langgraph-platform)** | Plus | Enterprise | Enterprise | Developer | Free with LangSmith | ## Cloud SaaS The [Cloud SaaS](./langgraph_cloud.md) deployment option is a fully managed model for deployment where we manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in our cloud. This option provides a simple way to deploy and manage your LangGraph Servers. -Connect your GitHub repositories to the platform and deploy your LangGraph Servers from the [Control Plane UI](./langgraph_control_plane.md#control-plane-ui). The build process (i.e. CI/CD) is managed internally by the platform. +Connect your GitHub repositories to the platform and deploy your LangGraph Servers from the [control plane UI](./langgraph_control_plane.md#control-plane-ui). The build process (i.e. CI/CD) is managed internally by the platform. For more information, please see: @@ -42,7 +42,7 @@ For more information, please see: The [Self-Hosted Data Plane](./langgraph_self_hosted_data_plane.md) deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. This option provides a way to securely manage your data plane infrastructure, while offloading control plane management to us. -Build a Docker image using the [LangGraph CLI](./langgraph_cli.md) and deploy your LangGraph Server from the [Control Plane UI](./langgraph_control_plane.md#control-plane-ui). +Build a Docker image using the [LangGraph CLI](./langgraph_cli.md) and deploy your LangGraph Server from the [control plane UI](./langgraph_control_plane.md#control-plane-ui). Supported Compute Platforms: [Kubernetes](https://kubernetes.io/), [Amazon ECS](https://aws.amazon.com/ecs/) (coming soon!) @@ -55,7 +55,7 @@ For more information, please see: The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option give you full control and responsibility of the control plane and data plane infrastructure. -Build a Docker image using the [LangGraph CLI](./langgraph_cli.md) and deploy your LangGraph Server from the [Control Plane UI](./langgraph_control_plane.md#control-plane-ui). +Build a Docker image using the [LangGraph CLI](./langgraph_cli.md) and deploy your LangGraph Server from the [control plane UI](./langgraph_control_plane.md#control-plane-ui). Supported Compute Platforms: [Kubernetes](https://kubernetes.io/) @@ -66,13 +66,13 @@ For more information, please see: ## Standalone Container -The [Standalone Container](./langgraph_standalone_container.md) deployment option is the least restrictive model for deployment. Deploy standalone instances of a LangGraph Server in your cloud. +The [Standalone Container](./langgraph_standalone_container.md) deployment option is the least restrictive model for deployment. Deploy standalone instances of a LangGraph Server in your cloud, using any of the [available](./plans.md) license options. Build a Docker image using the [LangGraph CLI](./langgraph_cli.md) and deploy your LangGraph Server using the container deployment tooling of your choice. Images can be deployed to any compute platform. For more information, please see: -* [Sandalone Container Conceptual Guide](./langgraph_standalone_container.md) +* [Standalone Container Conceptual Guide](./langgraph_standalone_container.md) * [How to deploy a Standalone Container](../cloud/deployment/standalone_container.md) ## Related @@ -81,4 +81,3 @@ For more information, please see: * [LangGraph Platform plans](./plans.md) * [LangGraph Platform pricing](https://www.langchain.com/langgraph-platform-pricing) -* [Deployment how-to guides](../how-tos/index.md#deployment) diff --git a/docs/docs/concepts/faq.md b/docs/docs/concepts/faq.md index 17d80f269..c274952b3 100644 --- a/docs/docs/concepts/faq.md +++ b/docs/docs/concepts/faq.md @@ -35,7 +35,7 @@ LangGraph is a stateful, orchestration framework that brings added control to ag | Streaming | Basic | Dedicated mode for token-by-token messages | | Checkpointer | Community contributed | Supported out-of-the-box | | Persistence Layer | Self-managed | Managed Postgres with efficient storage | -| Deployment | Self-managed | • Cloud SaaS
• Free self-hosted
• Enterprise (BYOC or paid self-hosted) | +| Deployment | Self-managed | • Cloud SaaS
• Free self-hosted
• Enterprise (paid self-hosted) | | Scalability | Self-managed | Auto-scaling of task queues and servers | | Fault-tolerance | Self-managed | Automated retries | | Concurrency Control | Simple threading | Supports double-texting | @@ -43,20 +43,11 @@ LangGraph is a stateful, orchestration framework that brings added control to ag | Monitoring | None | Integrated with LangSmith for observability | | IDE integration | LangGraph Studio | LangGraph Studio | -## What are my deployment options for LangGraph Platform? - -We currently have the following deployment options for LangGraph applications: - -- [‍Self-Hosted Lite](./deployment_options.md#self-hosted-lite): A free (up to 1M nodes executed), limited version of LangGraph Platform that you can run locally or in a self-hosted manner. This version requires a LangSmith API key and logs all usage to LangSmith. Fewer features are available than in paid plans. -- [Cloud SaaS](./deployment_options.md#cloud-saas): Fully managed and hosted as part of LangSmith, with automatic updates and zero maintenance. -- [‍Bring Your Own Cloud (BYOC)](./deployment_options.md#bring-your-own-cloud): Deploy LangGraph Platform within your VPC, provisioned and run as a service. Keep data in your environment while outsourcing the management of the service. -- [Self-Hosted Enterprise](./deployment_options.md#self-hosted-enterprise): Deploy LangGraph entirely on your own infrastructure. - ## Is LangGraph Platform open source? No. LangGraph Platform is proprietary software. -There is a free, self-hosted version of LangGraph Platform with access to basic features. The Cloud SaaS deployment option is free while in beta, but will eventually be a paid service. We will always give ample notice before charging for a service and reward our early adopters with preferential pricing. The Bring Your Own Cloud (BYOC) and Self-Hosted Enterprise options are also paid services. [Contact our sales team](https://www.langchain.com/contact-sales) to learn more. +There is a free, self-hosted version of LangGraph Platform with access to basic features. The Cloud SaaS deployment option is free while in beta, but will eventually be a paid service. We will always give ample notice before charging for a service and reward our early adopters with preferential pricing. The Self-Hosted deployment options are paid services. [Contact our sales team](https://www.langchain.com/contact-sales) to learn more. For more information, see our [LangGraph Platform pricing page](https://www.langchain.com/pricing-langgraph-platform). diff --git a/docs/docs/concepts/functional_api.md b/docs/docs/concepts/functional_api.md index c39aa8f64..61fbcbc22 100644 --- a/docs/docs/concepts/functional_api.md +++ b/docs/docs/concepts/functional_api.md @@ -3,11 +3,11 @@ search: boost: 2 --- -# Functional API +# Functional API concepts ## Overview -The **Functional API** allows you to add LangGraph's key features -- [persistence](./persistence.md), [memory](./memory.md), [human-in-the-loop](./human_in_the_loop.md), and [streaming](./streaming.md) — to your applications with minimal changes to your existing code. +The **Functional API** allows you to add LangGraph's key features — [persistence](./persistence.md), [memory](./memory.md), [human-in-the-loop](./human_in_the_loop.md), and [streaming](./streaming.md) — to your applications with minimal changes to your existing code. It is designed to integrate these features into existing code that may use standard language primitives for branching and control flow, such as `if` statements, `for` loops, and function calls. Unlike many data orchestration frameworks that require restructuring code into an explicit pipeline or DAG, the Functional API allows you to incorporate these capabilities without enforcing a rigid execution model. @@ -179,7 +179,7 @@ You will usually want to pass a **checkpointer** to the `@entrypoint` decorator The **inputs** and **outputs** of entrypoints must be JSON-serializable to support checkpointing. Please see the [serialization](#serialization) section for more details. -### Injectable Parameters +### Injectable parameters When declaring an `entrypoint`, you can request access to additional parameters that will be injected automatically at run time. These parameters include: @@ -394,7 +394,7 @@ This assumes that the underlying **error** has been resolved and execution can p print(chunk) ``` -### State Management +### Short-term memory When an `entrypoint` is defined with a `checkpointer`, it stores information between successive invocations on the same **thread id** in [checkpoints](persistence.md#checkpoints). @@ -524,7 +524,7 @@ Providing non-serializable inputs or outputs will result in a runtime error when To utilize features like **human-in-the-loop**, any randomness should be encapsulated inside of **tasks**. This guarantees that when execution is halted (e.g., for human in the loop) and then resumed, it will follow the same *sequence of steps*, even if **task** results are non-deterministic. -LangGraph achieves this behavior by persisting **task** and [**subgraph**](./low_level.md#subgraphs) results as they execute. A well-designed workflow ensures that resuming execution follows the *same sequence of steps*, allowing previously computed results to be retrieved correctly without having to re-execute them. This is particularly useful for long-running **tasks** or **tasks** with non-deterministic results, as it avoids repeating previously done work and allows resuming from essentially the same +LangGraph achieves this behavior by persisting **task** and [**subgraph**](./subgraphs.md) results as they execute. A well-designed workflow ensures that resuming execution follows the *same sequence of steps*, allowing previously computed results to be retrieved correctly without having to re-execute them. This is particularly useful for long-running **tasks** or **tasks** with non-deterministic results, as it avoids repeating previously done work and allows resuming from essentially the same. While different runs of a workflow can produce different results, resuming a **specific** run should always follow the same sequence of recorded steps. This allows LangGraph to efficiently look up **task** and **subgraph** results that were executed prior to the graph being interrupted and avoid recomputing them. @@ -537,7 +537,7 @@ Idempotency ensures that running the same operation multiple times produces the The **Functional API** and the [Graph APIs (StateGraph)](./low_level.md#stategraph) provide two different paradigms to create applications with LangGraph. Here are some key differences: - **Control flow**: The Functional API does not require thinking about graph structure. You can use standard Python constructs to define workflows. This will usually trim the amount of code you need to write. -- **State management**: The **GraphAPI** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `@entrypoint` and `@tasks` do not require explicit state management as their state is scoped to the function and is not shared across functions. +- **Short-term memory**: The **GraphAPI** requires declaring a [**State**](./low_level.md#state) and may require defining [**reducers**](./low_level.md#reducers) to manage updates to the graph state. `@entrypoint` and `@tasks` do not require explicit state management as their state is scoped to the function and is not shared across functions. - **Checkpointing**: Both APIs generate and use checkpoints. In the **Graph API** a new checkpoint is generated after every [superstep](./low_level.md). In the **Functional API**, when tasks are executed, their results are saved to an existing checkpoint associated with the given entrypoint instead of creating a new checkpoint. - **Visualization**: The Graph API makes it easy to visualize the workflow as a graph which can be useful for debugging, understanding the workflow, and sharing with others. The Functional API does not support visualization as the graph is dynamically generated during runtime. @@ -665,279 +665,3 @@ Please read the section on [determinism](#determinism) for more details. } ``` -## Patterns - -Below are a few simple patterns that show examples of **how to** use the **Functional API**. - -When defining an `entrypoint`, input is restricted to the first argument of the function. To pass multiple inputs, you can use a dictionary. - -```python -@entrypoint(checkpointer=checkpointer) -def my_workflow(inputs: dict) -> int: - value = inputs["value"] - another_value = inputs["another_value"] - ... - -my_workflow.invoke({"value": 1, "another_value": 2}) -``` - -### Parallel execution - -Tasks can be executed in parallel by invoking them concurrently and waiting for the results. This is useful for improving performance in IO bound tasks (e.g., calling APIs for LLMs). - -```python -@task -def add_one(number: int) -> int: - return number + 1 - -@entrypoint(checkpointer=checkpointer) -def graph(numbers: list[int]) -> list[str]: - futures = [add_one(i) for i in numbers] - return [f.result() for f in futures] -``` - -### Calling subgraphs - -The **Functional API** and the [**Graph API**](./low_level.md) can be used together in the same application as they share the same underlying runtime. - -```python -from langgraph.func import entrypoint -from langgraph.graph import StateGraph - -builder = StateGraph() -... -some_graph = builder.compile() - -@entrypoint() -def some_workflow(some_input: dict) -> int: - # Call a graph defined using the graph API - result_1 = some_graph.invoke(...) - # Call another graph defined using the graph API - result_2 = another_graph.invoke(...) - return { - "result_1": result_1, - "result_2": result_2 - } -``` - -### Calling other entrypoints - -You can call other **entrypoints** from within an **entrypoint** or a **task**. - -```python -@entrypoint() # Will automatically use the checkpointer from the parent entrypoint -def some_other_workflow(inputs: dict) -> int: - return inputs["value"] - -@entrypoint(checkpointer=checkpointer) -def my_workflow(inputs: dict) -> int: - value = some_other_workflow.invoke({"value": 1}) - return value -``` - -### Streaming custom data - -You can stream custom data from an **entrypoint** by using the `StreamWriter` type. This allows you to write custom data to the `custom` stream. - -```python -from langgraph.checkpoint.memory import MemorySaver -from langgraph.func import entrypoint, task -from langgraph.types import StreamWriter - -@task -def add_one(x): - return x + 1 - -@task -def add_two(x): - return x + 2 - -checkpointer = MemorySaver() - -@entrypoint(checkpointer=checkpointer) -def main(inputs, writer: StreamWriter) -> int: - """A simple workflow that adds one and two to a number.""" - writer("hello") # Write some data to the `custom` stream - add_one(inputs['number']).result() # Will write data to the `updates` stream - writer("world") # Write some more data to the `custom` stream - add_two(inputs['number']).result() # Will write data to the `updates` stream - return 5 - -config = { - "configurable": { - "thread_id": "1" - } -} - -for chunk in main.stream({"number": 1}, stream_mode=["custom", "updates"], config=config): - print(chunk) -``` - -```pycon -('updates', {'add_one': 2}) -('updates', {'add_two': 3}) -('custom', 'hello') -('custom', 'world') -('updates', {'main': 5}) -``` - -!!! important - - The `writer` parameter is automatically injected at run time. It will only be injected if the - parameter name appears in the function signature with that *exact* name. - - -### Retry policy - -```python -from langgraph.checkpoint.memory import MemorySaver -from langgraph.func import entrypoint, task -from langgraph.types import RetryPolicy - -attempts = 0 - -# Let's configure the RetryPolicy to retry on ValueError. -# The default RetryPolicy is optimized for retrying specific network errors. -retry_policy = RetryPolicy(retry_on=ValueError) - -@task(retry=retry_policy) -def get_info(): - global attempts - attempts += 1 - - if attempts < 2: - raise ValueError('Failure') - return "OK" - -checkpointer = MemorySaver() - -@entrypoint(checkpointer=checkpointer) -def main(inputs, writer): - return get_info().result() - -config = { - "configurable": { - "thread_id": "1" - } -} - -main.invoke({'any_input': 'foobar'}, config=config) -``` - -```pycon -'OK' -``` - -### Resuming after an error - -```python -import time -from langgraph.checkpoint.memory import MemorySaver -from langgraph.func import entrypoint, task -from langgraph.types import StreamWriter - -# This variable is just used for demonstration purposes to simulate a network failure. -# It's not something you will have in your actual code. -attempts = 0 - -@task() -def get_info(): - """ - Simulates a task that fails once before succeeding. - Raises an exception on the first attempt, then returns "OK" on subsequent tries. - """ - global attempts - attempts += 1 - - if attempts < 2: - raise ValueError("Failure") # Simulate a failure on the first attempt - return "OK" - -# Initialize an in-memory checkpointer for persistence -checkpointer = MemorySaver() - -@task -def slow_task(): - """ - Simulates a slow-running task by introducing a 1-second delay. - """ - time.sleep(1) - return "Ran slow task." - -@entrypoint(checkpointer=checkpointer) -def main(inputs, writer: StreamWriter): - """ - Main workflow function that runs the slow_task and get_info tasks sequentially. - - Parameters: - - inputs: Dictionary containing workflow input values. - - writer: StreamWriter for streaming custom data. - - The workflow first executes `slow_task` and then attempts to execute `get_info`, - which will fail on the first invocation. - """ - slow_task_result = slow_task().result() # Blocking call to slow_task - get_info().result() # Exception will be raised here on the first attempt - return slow_task_result - -# Workflow execution configuration with a unique thread identifier -config = { - "configurable": { - "thread_id": "1" # Unique identifier to track workflow execution - } -} - -# This invocation will take ~1 second due to the slow_task execution -try: - # First invocation will raise an exception due to the `get_info` task failing - main.invoke({'any_input': 'foobar'}, config=config) -except ValueError: - pass # Handle the failure gracefully -``` - -When we resume execution, we won't need to re-run the `slow_task` as its result is already saved in the checkpoint. - -```python -main.invoke(None, config=config) -``` - -```pycon -'Ran slow task.' -``` - -### Human-in-the-loop - -The functional API supports [human-in-the-loop](human_in_the_loop.md) workflows using the `interrupt` function and the `Command` primitive. - -Please see the following examples for more details: - -* [How to wait for user input (Functional API)](../how-tos/wait-user-input-functional.ipynb): Shows how to implement a simple human-in-the-loop workflow using the functional API. -* [How to review tool calls (Functional API)](../how-tos/review-tool-calls-functional.ipynb): Guide demonstrates how to implement human-in-the-loop workflows in a ReAct agent using the LangGraph Functional API. - -### Short-term memory - -[State management](#state-management) using the **previous** parameter and optionally using the `entrypoint.final` primitive can be used to implement [short term memory](memory.md). - -Please see the following how-to guides for more details: - -* [How to add thread-level persistence (functional API)](../how-tos/persistence-functional.ipynb): Shows how to add thread-level persistence to a functional API workflow and implements a simple chatbot. - -### Long-term memory - -[long-term memory](memory.md#long-term-memory) allows storing information across different **thread ids**. This could be useful for learning information -about a given user in one conversation and using it in another. - -Please see the following how-to guides for more details: - -* [How to add cross-thread persistence (functional API)](../how-tos/cross-thread-persistence-functional.ipynb): Shows how to add cross-thread persistence to a functional API workflow and implements a simple chatbot. - -### Workflows - -* [Workflows and agent](../tutorials/workflows/index.md) guide for more examples of how to build workflows using the Functional API. - -### Agents - -* [How to create a React agent from scratch (Functional API)](../how-tos/react-agent-from-scratch-functional.ipynb): Shows how to create a simple React agent from scratch using the functional API. -* [How to build a multi-agent network](../how-tos/multi-agent-network-functional.ipynb): Shows how to build a multi-agent network using the functional API. -* [How to add multi-turn conversation in a multi-agent application (functional API)](../how-tos/multi-agent-multi-turn-convo-functional.ipynb): allow an end-user to engage in a multi-turn conversation with one or more agents. - diff --git a/docs/docs/concepts/high_level.md b/docs/docs/concepts/high_level.md deleted file mode 100644 index 5ad24d841..000000000 --- a/docs/docs/concepts/high_level.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -search: - boost: 2 ---- - -# Why LangGraph? - -## LLM applications - -LLMs make it possible to embed intelligence into a new class of applications. There are many patterns for building applications that use LLMs. Workflows have scaffolding of predefined code paths around LLM calls. LLMs can direct the control flow through these predefined code paths, which some consider to be an "agentic system". In other cases, it's possible to remove this scaffolding, creating autonomous agents that can [plan](https://huyenchip.com/2025/01/07/agents.html), take actions via [tool calls](https://python.langchain.com/docs/concepts/tool_calling/), and directly respond [to the feedback from their own actions](https://research.google/blog/react-synergizing-reasoning-and-acting-in-language-models/) with further actions. - -![Agent Workflow](img/agent_workflow.png) - -## What LangGraph provides - -LangGraph provides low-level supporting infrastructure that sits underneath *any* workflow or agent. It does not abstract prompts or architecture, and provides three central benefits: - -### Persistence - -LangGraph has a [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), which offers a number of benefits: - -- [Memory](https://langchain-ai.github.io/langgraph/concepts/memory/): LangGraph persists arbitrary aspects of your application's state, supporting memory of conversations and other updates within and across user interactions; -- [Human-in-the-loop](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): Because state is checkpointed, execution can be interrupted and resumed, allowing for decisions, validation, and corrections via human input. - -### Streaming - -LangGraph also provides support for [streaming](../how-tos/index.md#streaming) workflow / agent state to the user (or developer) over the course of execution. LangGraph supports streaming of both events ([such as feedback from a tool call](../how-tos/streaming.ipynb#updates)) and [tokens from LLM calls](../how-tos/streaming-tokens.ipynb) embedded in an application. - -### Debugging and Deployment - -LangGraph provides an easy onramp for testing, debugging, and deploying applications via [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). This includes [Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/), an IDE that enables visualization, interaction, and debugging of workflows or agents. This also includes numerous [options](https://langchain-ai.github.io/langgraph/tutorials/deployment/) for deployment. \ No newline at end of file diff --git a/docs/docs/concepts/human_in_the_loop.md b/docs/docs/concepts/human_in_the_loop.md index 0c6fc0bc3..4b2aa575e 100644 --- a/docs/docs/concepts/human_in_the_loop.md +++ b/docs/docs/concepts/human_in_the_loop.md @@ -4,720 +4,28 @@ search: tags: - human-in-the-loop - hil + - overview hide: - tags --- # Human-in-the-loop -!!! tip "This guide uses the new `interrupt` function." +LangGraph supports robust **human-in-the-loop (HIL)** workflows, enabling human intervention at any point in an automated process. This is especially useful in large language model (LLM)-driven applications where model output may require validation, correction, or additional context. - As of LangGraph 0.2.57, the recommended way to set breakpoints is using the [`interrupt` function][langgraph.types.interrupt] as it simplifies **human-in-the-loop** patterns. +## Key capabilities - If you're looking for the previous version of this conceptual guide, which relied on static breakpoints and `NodeInterrupt` exception, it is available [here](v0-human-in-the-loop.md). +* **Persistent execution state**: LangGraph checkpoints the graph state after each step, allowing execution to pause indefinitely at defined nodes. This supports asynchronous human review or input without time constraints. -A **human-in-the-loop** (or "on-the-loop") workflow integrates human input into automated processes, allowing for decisions, validation, or corrections at key stages. This is especially useful in **LLM-based applications**, where the underlying model may generate occasional inaccuracies. In low-error-tolerance scenarios like compliance, decision-making, or content generation, human involvement ensures reliability by enabling review, correction, or override of model outputs. +* **Flexible integration points**: HIL logic can be introduced at any point in the workflow. This allows targeted human involvement, such as approving API calls, correcting outputs, or guiding conversations. - -## Use cases - -Key use cases for **human-in-the-loop** workflows in LLM-based applications include: +## Typical use cases 1. [**🛠️ Reviewing tool calls**](#review-tool-calls): Humans can review, edit, or approve tool calls requested by the LLM before tool execution. 2. **✅ Validating LLM outputs**: Humans can review, edit, or approve content generated by the LLM. 3. **💡 Providing context**: Enable the LLM to explicitly request human input for clarification or additional details or to support multi-turn conversations. -## `interrupt` +## Implementation -The [`interrupt` function][langgraph.types.interrupt] in LangGraph enables human-in-the-loop workflows by pausing the graph at a specific node, presenting information to a human, and resuming the graph with their input. This function is useful for tasks like approvals, edits, or collecting additional input. The [`interrupt` function][langgraph.types.interrupt] is used in conjunction with the [`Command`](../reference/types.md#langgraph.types.Command) object to resume the graph with a value provided by the human. - -```python -from langgraph.types import interrupt - -def human_node(state: State): - value = interrupt( - # Any JSON serializable value to surface to the human. - # For example, a question or a piece of text or a set of keys in the state - { - "text_to_revise": state["some_text"] - } - ) - # Update the state with the human's input or route the graph based on the input. - return { - "some_text": value - } - -graph = graph_builder.compile( - checkpointer=checkpointer # Required for `interrupt` to work -) - -# Run the graph until the interrupt -thread_config = {"configurable": {"thread_id": "some_id"}} -graph.invoke(some_input, config=thread_config) - -# Resume the graph with the human's input -graph.invoke(Command(resume=value_from_human), config=thread_config) -``` - -```pycon -{'some_text': 'Edited text'} -``` - -!!! warning - Interrupts are both powerful and ergonomic. However, while they may resemble Python's input() function in terms of developer experience, it's important to note that they do not automatically resume execution from the interruption point. Instead, they rerun the entire node where the interrupt was used. - For this reason, interrupts are typically best placed at the start of a node or in a dedicated node. Please read the [resuming from an interrupt](#how-does-resuming-from-an-interrupt-work) section for more details. - -??? "Full Code" - - Here's a full example of how to use `interrupt` in a graph, if you'd like - to see the code in action. - - ```python - from typing import TypedDict - import uuid - - from langgraph.checkpoint.memory import MemorySaver - from langgraph.constants import START - from langgraph.graph import StateGraph - from langgraph.types import interrupt, Command - - class State(TypedDict): - """The graph state.""" - some_text: str - - def human_node(state: State): - value = interrupt( - # Any JSON serializable value to surface to the human. - # For example, a question or a piece of text or a set of keys in the state - { - "text_to_revise": state["some_text"] - } - ) - return { - # Update the state with the human's input - "some_text": value - } - - - # Build the graph - graph_builder = StateGraph(State) - # Add the human-node to the graph - graph_builder.add_node("human_node", human_node) - graph_builder.add_edge(START, "human_node") - - # A checkpointer is required for `interrupt` to work. - checkpointer = MemorySaver() - graph = graph_builder.compile( - checkpointer=checkpointer - ) - - # Pass a thread ID to the graph to run it. - thread_config = {"configurable": {"thread_id": uuid.uuid4()}} - - # Using stream() to directly surface the `__interrupt__` information. - for chunk in graph.stream({"some_text": "Original text"}, config=thread_config): - print(chunk) - - # Resume using Command - for chunk in graph.stream(Command(resume="Edited text"), config=thread_config): - print(chunk) - ``` - - ```pycon - {'__interrupt__': ( - Interrupt( - value={'question': 'Please revise the text', 'some_text': 'Original text'}, - resumable=True, - ns=['human_node:10fe492f-3688-c8c6-0d0a-ec61a43fecd6'], - when='during' - ), - ) - } - {'human_node': {'some_text': 'Edited text'}} - ``` - -## Requirements - -To use `interrupt` in your graph, you need to: - -1. [**Specify a checkpointer**](persistence.md#checkpoints) to save the graph state after each step. -2. **Call `interrupt()`** in the appropriate place. See the [Design Patterns](#design-patterns) section for examples. -3. **Run the graph** with a [**thread ID**](./persistence.md#threads) until the `interrupt` is hit. -4. **Resume execution** using `invoke`/`ainvoke`/`stream`/`astream` (see [**The `Command` primitive**](#the-command-primitive)). - -## Design Patterns - -There are typically three different **actions** that you can do with a human-in-the-loop workflow: - -1. **Approve or Reject**: Pause the graph before a critical step, such as an API call, to review and approve the action. If the action is rejected, you can prevent the graph from executing the step, and potentially take an alternative action. This pattern often involve **routing** the graph based on the human's input. -2. **Edit Graph State**: Pause the graph to review and edit the graph state. This is useful for correcting mistakes or updating the state with additional information. This pattern often involves **updating** the state with the human's input. -3. **Get Input**: Explicitly request human input at a particular step in the graph. This is useful for collecting additional information or context to inform the agent's decision-making process or for supporting **multi-turn conversations**. - -Below we show different design patterns that can be implemented using these **actions**. - -### Approve or Reject - -
-![image](img/human_in_the_loop/approve-or-reject.png){: style="max-height:400px"} -
Depending on the human's approval or rejection, the graph can proceed with the action or take an alternative path.
-
- -Pause the graph before a critical step, such as an API call, to review and approve the action. If the action is rejected, you can prevent the graph from executing the step, and potentially take an alternative action. - -```python - -from typing import Literal -from langgraph.types import interrupt, Command - -def human_approval(state: State) -> Command[Literal["some_node", "another_node"]]: - is_approved = interrupt( - { - "question": "Is this correct?", - # Surface the output that should be - # reviewed and approved by the human. - "llm_output": state["llm_output"] - } - ) - - if is_approved: - return Command(goto="some_node") - else: - return Command(goto="another_node") - -# Add the node to the graph in an appropriate location -# and connect it to the relevant nodes. -graph_builder.add_node("human_approval", human_approval) -graph = graph_builder.compile(checkpointer=checkpointer) - -# After running the graph and hitting the interrupt, the graph will pause. -# Resume it with either an approval or rejection. -thread_config = {"configurable": {"thread_id": "some_id"}} -graph.invoke(Command(resume=True), config=thread_config) -``` - -See [how to review tool calls](../how-tos/human_in_the_loop/review-tool-calls.ipynb) for a more detailed example. - -### Review & Edit State - -
-![image](img/human_in_the_loop/edit-graph-state-simple.png){: style="max-height:400px"} -
A human can review and edit the state of the graph. This is useful for correcting mistakes or updating the state with additional information. -
-
- -```python -from langgraph.types import interrupt - -def human_editing(state: State): - ... - result = interrupt( - # Interrupt information to surface to the client. - # Can be any JSON serializable value. - { - "task": "Review the output from the LLM and make any necessary edits.", - "llm_generated_summary": state["llm_generated_summary"] - } - ) - - # Update the state with the edited text - return { - "llm_generated_summary": result["edited_text"] - } - -# Add the node to the graph in an appropriate location -# and connect it to the relevant nodes. -graph_builder.add_node("human_editing", human_editing) -graph = graph_builder.compile(checkpointer=checkpointer) - -... - -# After running the graph and hitting the interrupt, the graph will pause. -# Resume it with the edited text. -thread_config = {"configurable": {"thread_id": "some_id"}} -graph.invoke( - Command(resume={"edited_text": "The edited text"}), - config=thread_config -) -``` - -See [How to wait for user input using interrupt](../how-tos/human_in_the_loop/wait-user-input.ipynb) for a more detailed example. - -### Review Tool Calls - -
-![image](img/human_in_the_loop/tool-call-review.png){: style="max-height:400px"} -
A human can review and edit the output from the LLM before proceeding. This is particularly -critical in applications where the tool calls requested by the LLM may be sensitive or require human oversight. -
-
- -```python -def human_review_node(state) -> Command[Literal["call_llm", "run_tool"]]: - # This is the value we'll be providing via Command(resume=) - human_review = interrupt( - { - "question": "Is this correct?", - # Surface tool calls for review - "tool_call": tool_call - } - ) - - review_action, review_data = human_review - - # Approve the tool call and continue - if review_action == "continue": - return Command(goto="run_tool") - - # Modify the tool call manually and then continue - elif review_action == "update": - ... - updated_msg = get_updated_msg(review_data) - # Remember that to modify an existing message you will need - # to pass the message with a matching ID. - return Command(goto="run_tool", update={"messages": [updated_message]}) - - # Give natural language feedback, and then pass that back to the agent - elif review_action == "feedback": - ... - feedback_msg = get_feedback_msg(review_data) - return Command(goto="call_llm", update={"messages": [feedback_msg]}) -``` - -See [how to review tool calls](../how-tos/human_in_the_loop/review-tool-calls.ipynb) for a more detailed example. - -### Multi-turn conversation - -
-![image](img/human_in_the_loop/multi-turn-conversation.png){: style="max-height:400px"} -
A multi-turn conversation architecture where an agent and human node cycle back and forth until the agent decides to hand off the conversation to another agent or another part of the system. -
-
- -A **multi-turn conversation** involves multiple back-and-forth interactions between an agent and a human, which can allow the agent to gather additional information from the human in a conversational manner. - -This design pattern is useful in an LLM application consisting of [multiple agents](./multi_agent.md). One or more agents may need to carry out multi-turn conversations with a human, where the human provides input or feedback at different stages of the conversation. For simplicity, the agent implementation below is illustrated as a single node, but in reality -it may be part of a larger graph consisting of multiple nodes and include a conditional edge. - -=== "Using a human node per agent" - - In this pattern, each agent has its own human node for collecting user input. - This can be achieved by either naming the human nodes with unique names (e.g., "human for agent 1", "human for agent 2") or by - using subgraphs where a subgraph contains a human node and an agent node. - - ```python - from langgraph.types import interrupt - - def human_input(state: State): - human_message = interrupt("human_input") - return { - "messages": [ - { - "role": "human", - "content": human_message - } - ] - } - - def agent(state: State): - # Agent logic - ... - - graph_builder.add_node("human_input", human_input) - graph_builder.add_edge("human_input", "agent") - graph = graph_builder.compile(checkpointer=checkpointer) - - # After running the graph and hitting the interrupt, the graph will pause. - # Resume it with the human's input. - graph.invoke( - Command(resume="hello!"), - config=thread_config - ) - ``` - - -=== "Sharing human node across multiple agents" - - In this pattern, a single human node is used to collect user input for multiple agents. The active agent is determined from the state, so after human input is collected, the graph can route to the correct agent. - - ```python - from langgraph.types import interrupt - - def human_node(state: MessagesState) -> Command[Literal["agent_1", "agent_2", ...]]: - """A node for collecting user input.""" - user_input = interrupt(value="Ready for user input.") - - # Determine the **active agent** from the state, so - # we can route to the correct agent after collecting input. - # For example, add a field to the state or use the last active agent. - # or fill in `name` attribute of AI messages generated by the agents. - active_agent = ... - - return Command( - update={ - "messages": [{ - "role": "human", - "content": user_input, - }] - }, - goto=active_agent, - ) - ``` - -See [how to implement multi-turn conversations](../how-tos/multi-agent-multi-turn-convo.ipynb) for a more detailed example. - -### Validating human input - -If you need to validate the input provided by the human within the graph itself (rather than on the client side), you can achieve this by using multiple interrupt calls within a single node. - -```python -from langgraph.types import interrupt - -def human_node(state: State): - """Human node with validation.""" - question = "What is your age?" - - while True: - answer = interrupt(question) - - # Validate answer, if the answer isn't valid ask for input again. - if not isinstance(answer, int) or answer < 0: - question = f"'{answer} is not a valid age. What is your age?" - answer = None - continue - else: - # If the answer is valid, we can proceed. - break - - print(f"The human in the loop is {answer} years old.") - return { - "age": answer - } -``` - -## The `Command` primitive - -When using the `interrupt` function, the graph will pause at the interrupt and wait for user input. - -Graph execution can be resumed using the [Command](../reference/types.md#langgraph.types.Command) primitive which can be passed through the `invoke`, `ainvoke`, `stream` or `astream` methods. - -The `Command` primitive provides a way to **pass a value** (such as user's input) to the `interrupt` via `Command(resume=value)`. Execution resumes from the beginning of the node where the `interrupt` was used, however, this time the `interrupt(...)` call will return the value passed in the `Command(resume=value)` instead of pausing the graph. - -```python -# Resume graph execution with the user's input. -graph.invoke(Command(resume={"age": "25"}), thread_config) -``` - -By leveraging `Command`, you can resume graph execution and handle user inputs. - -## How does resuming from an interrupt work? - -!!! warning - - Resuming from an `interrupt` is **different** from Python's `input()` function, where execution resumes from the exact point where the `input()` function was called. - -A critical aspect of using `interrupt` is understanding how resuming works. When you resume execution after an `interrupt`, graph execution starts from the **beginning** of the **graph node** where the last `interrupt` was triggered. - -**All** code from the beginning of the node to the `interrupt` will be re-executed. - -```python -counter = 0 -def node(state: State): - # All the code from the beginning of the node to the interrupt will be re-executed - # when the graph resumes. - global counter - counter += 1 - print(f"> Entered the node: {counter} # of times") - # Pause the graph and wait for user input. - answer = interrupt() - print("The value of counter is:", counter) - ... -``` - -Upon **resuming** the graph, the counter will be incremented a second time, resulting in the following output: - -```pycon -> Entered the node: 2 # of times -The value of counter is: 2 -``` - -### Resuming multiple interrupts with one invocation - -If you have multiple interrupts in the task queue, you can use `Command.resume` with a dictionary mapping -of interrupt ids to resume values to resume multiple interrupts with a single `invoke` / `stream` call. - -For example, once your graph has been interrupted (multiple times, theoretically) and is stalled: - -```python -resume_map = { - i.interrupt_id: f"human input for prompt {i.value}" - for i in parent.get_state(thread_config).interrupts -} - -parent_graph.invoke(Command(resume=resume_map), config=thread_config) -``` - -## Common Pitfalls - -### Side-effects - -Place code with side effects, such as API calls, **after** the `interrupt` to avoid duplication, as these are re-triggered every time the node is resumed. - -=== "Side effects before interrupt (BAD)" - - This code will re-execute the API call another time when the node is resumed from - the `interrupt`. - - This can be problematic if the API call is not idempotent or is just expensive. - - ```python - from langgraph.types import interrupt - - def human_node(state: State): - """Human node with validation.""" - api_call(...) # This code will be re-executed when the node is resumed. - answer = interrupt(question) - ``` - -=== "Side effects after interrupt (OK)" - - ```python - from langgraph.types import interrupt - - def human_node(state: State): - """Human node with validation.""" - - answer = interrupt(question) - - api_call(answer) # OK as it's after the interrupt - ``` - -=== "Side effects in a separate node (OK)" - - ```python - from langgraph.types import interrupt - - def human_node(state: State): - """Human node with validation.""" - - answer = interrupt(question) - - return { - "answer": answer - } - - def api_call_node(state: State): - api_call(...) # OK as it's in a separate node - ``` - -### Subgraphs called as functions - -When invoking a subgraph [as a function](low_level.md#as-a-function), the **parent graph** will resume execution from the **beginning of the node** where the subgraph was invoked (and where an `interrupt` was triggered). Similarly, the **subgraph**, will resume from the **beginning of the node** where the `interrupt()` function was called. - -For example, - -```python -def node_in_parent_graph(state: State): - some_code() # <-- This will re-execute when the subgraph is resumed. - # Invoke a subgraph as a function. - # The subgraph contains an `interrupt` call. - subgraph_result = subgraph.invoke(some_input) - ... -``` - -??? "**Example: Parent and Subgraph Execution Flow**" - - Say we have a parent graph with 3 nodes: - - **Parent Graph**: `node_1` → `node_2` (subgraph call) → `node_3` - - And the subgraph has 3 nodes, where the second node contains an `interrupt`: - - **Subgraph**: `sub_node_1` → `sub_node_2` (`interrupt`) → `sub_node_3` - - When resuming the graph, the execution will proceed as follows: - - 1. **Skip `node_1`** in the parent graph (already executed, graph state was saved in snapshot). - 2. **Re-execute `node_2`** in the parent graph from the start. - 3. **Skip `sub_node_1`** in the subgraph (already executed, graph state was saved in snapshot). - 4. **Re-execute `sub_node_2`** in the subgraph from the beginning. - 5. Continue with `sub_node_3` and subsequent nodes. - - Here is abbreviated example code that you can use to understand how subgraphs work with interrupts. - It counts the number of times each node is entered and prints the count. - - ```python - import uuid - from typing import TypedDict - - from langgraph.graph import StateGraph - from langgraph.constants import START - from langgraph.types import interrupt, Command - from langgraph.checkpoint.memory import MemorySaver - - - class State(TypedDict): - """The graph state.""" - state_counter: int - - - counter_node_in_subgraph = 0 - - def node_in_subgraph(state: State): - """A node in the sub-graph.""" - global counter_node_in_subgraph - counter_node_in_subgraph += 1 # This code will **NOT** run again! - print(f"Entered `node_in_subgraph` a total of {counter_node_in_subgraph} times") - - counter_human_node = 0 - - def human_node(state: State): - global counter_human_node - counter_human_node += 1 # This code will run again! - print(f"Entered human_node in sub-graph a total of {counter_human_node} times") - answer = interrupt("what is your name?") - print(f"Got an answer of {answer}") - - - checkpointer = MemorySaver() - - subgraph_builder = StateGraph(State) - subgraph_builder.add_node("some_node", node_in_subgraph) - subgraph_builder.add_node("human_node", human_node) - subgraph_builder.add_edge(START, "some_node") - subgraph_builder.add_edge("some_node", "human_node") - subgraph = subgraph_builder.compile(checkpointer=checkpointer) - - - counter_parent_node = 0 - - def parent_node(state: State): - """This parent node will invoke the subgraph.""" - global counter_parent_node - - counter_parent_node += 1 # This code will run again on resuming! - print(f"Entered `parent_node` a total of {counter_parent_node} times") - - # Please note that we're intentionally incrementing the state counter - # in the graph state as well to demonstrate that the subgraph update - # of the same key will not conflict with the parent graph (until - subgraph_state = subgraph.invoke(state) - return subgraph_state - - - builder = StateGraph(State) - builder.add_node("parent_node", parent_node) - builder.add_edge(START, "parent_node") - - # A checkpointer must be enabled for interrupts to work! - checkpointer = MemorySaver() - graph = builder.compile(checkpointer=checkpointer) - - config = { - "configurable": { - "thread_id": uuid.uuid4(), - } - } - - for chunk in graph.stream({"state_counter": 1}, config): - print(chunk) - - print('--- Resuming ---') - - for chunk in graph.stream(Command(resume="35"), config): - print(chunk) - ``` - - This will print out - - ```pycon - Entered `parent_node` a total of 1 times - Entered `node_in_subgraph` a total of 1 times - Entered human_node in sub-graph a total of 1 times - {'__interrupt__': (Interrupt(value='what is your name?', resumable=True, ns=['parent_node:4c3a0248-21f0-1287-eacf-3002bc304db4', 'human_node:2fe86d52-6f70-2a3f-6b2f-b1eededd6348'], when='during'),)} - --- Resuming --- - Entered `parent_node` a total of 2 times - Entered human_node in sub-graph a total of 2 times - Got an answer of 35 - {'parent_node': {'state_counter': 1}} - ``` - - - -### Using multiple interrupts - -Using multiple interrupts within a **single** node can be helpful for patterns like [validating human input](#validating-human-input). However, using multiple interrupts in the same node can lead to unexpected behavior if not handled carefully. - -When a node contains multiple interrupt calls, LangGraph keeps a list of resume values specific to the task executing the node. Whenever execution resumes, it starts at the beginning of the node. For each interrupt encountered, LangGraph checks if a matching value exists in the task's resume list. Matching is **strictly index-based**, so the order of interrupt calls within the node is critical. - -To avoid issues, refrain from dynamically changing the node's structure between executions. This includes adding, removing, or reordering interrupt calls, as such changes can result in mismatched indices. These problems often arise from unconventional patterns, such as mutating state via `Command(resume=..., update=SOME_STATE_MUTATION)` or relying on global variables to modify the node’s structure dynamically. - -??? "Example of incorrect code" - - ```python - import uuid - from typing import TypedDict, Optional - - from langgraph.graph import StateGraph - from langgraph.constants import START - from langgraph.types import interrupt, Command - from langgraph.checkpoint.memory import MemorySaver - - - class State(TypedDict): - """The graph state.""" - - age: Optional[str] - name: Optional[str] - - - def human_node(state: State): - if not state.get('name'): - name = interrupt("what is your name?") - else: - name = "N/A" - - if not state.get('age'): - age = interrupt("what is your age?") - else: - age = "N/A" - - print(f"Name: {name}. Age: {age}") - - return { - "age": age, - "name": name, - } - - - builder = StateGraph(State) - builder.add_node("human_node", human_node) - builder.add_edge(START, "human_node") - - # A checkpointer must be enabled for interrupts to work! - checkpointer = MemorySaver() - graph = builder.compile(checkpointer=checkpointer) - - config = { - "configurable": { - "thread_id": uuid.uuid4(), - } - } - - for chunk in graph.stream({"age": None, "name": None}, config): - print(chunk) - - for chunk in graph.stream(Command(resume="John", update={"name": "foo"}), config): - print(chunk) - ``` - - ```pycon - {'__interrupt__': (Interrupt(value='what is your name?', resumable=True, ns=['human_node:3a007ef9-c30d-c357-1ec1-86a1a70d8fba'], when='during'),)} - Name: N/A. Age: John - {'human_node': {'age': 'John', 'name': 'N/A'}} - ``` - -## Additional Resources 📚 - -- [**Conceptual Guide: Persistence**](persistence.md#replay): Read the persistence guide for more context on replaying. -- [**How to Guides: Human-in-the-loop**](../how-tos/index.md#human-in-the-loop): Learn how to implement human-in-the-loop workflows in LangGraph. -- [**How to implement multi-turn conversations**](../how-tos/multi-agent-multi-turn-convo.ipynb): Learn how to implement multi-turn conversations in LangGraph. +* `interrupt` function: Pauses execution at a specific point, presents information for human review. +* `Command` primitive: Used to resume execution with a value provided by the human. diff --git a/docs/docs/concepts/img/breakpoints.png b/docs/docs/concepts/img/breakpoints.png new file mode 100644 index 000000000..0fb5aabea Binary files /dev/null and b/docs/docs/concepts/img/breakpoints.png differ diff --git a/docs/docs/concepts/img/lg_studio.png b/docs/docs/concepts/img/lg_studio.png index 5d41830fc..91fcc447c 100644 Binary files a/docs/docs/concepts/img/lg_studio.png and b/docs/docs/concepts/img/lg_studio.png differ diff --git a/docs/docs/concepts/img/subgraph.png b/docs/docs/concepts/img/subgraph.png new file mode 100644 index 000000000..29401933c Binary files /dev/null and b/docs/docs/concepts/img/subgraph.png differ diff --git a/docs/docs/concepts/index.md b/docs/docs/concepts/index.md deleted file mode 100644 index 1852592a5..000000000 --- a/docs/docs/concepts/index.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: Concepts -description: Conceptual Guide for LangGraph -search: - boost: 0.5 ---- - -# Conceptual Guide - -This guide provides explanations of the key concepts behind the LangGraph framework and AI applications more broadly. - -We recommend that you go through at least the [Quickstart](../tutorials/introduction.ipynb) before diving into the conceptual guide. This will provide practical context that will make it easier to understand the concepts discussed here. - -The conceptual guide does not cover step-by-step instructions or specific implementation examples — those are found in the [Tutorials](../tutorials/index.md) and [How-to guides](../how-tos/index.md). For detailed reference material, please see the [API reference](../reference/index.md). - -## LangGraph - -### High Level - -- [Why LangGraph?](high_level.md): A high-level overview of LangGraph and its goals. - -### Concepts - -- [LangGraph Glossary](low_level.md): LangGraph workflows are designed as graphs, with nodes representing different components and edges representing the flow of information between them. This guide provides an overview of the key concepts associated with LangGraph graph primitives. -- [Common Agentic Patterns](agentic_concepts.md): An agent uses an LLM to pick its own control flow to solve more complex problems! Agents are a key building block in many LLM applications. This guide explains the different types of agent architectures and how they can be used to control the flow of an application. -- [Multi-Agent Systems](multi_agent.md): Complex LLM applications can often be broken down into multiple agents, each responsible for a different part of the application. This guide explains common patterns for building multi-agent systems. -- [Breakpoints](breakpoints.md): Breakpoints allow pausing the execution of a graph at specific points. Breakpoints allow stepping through graph execution for debugging purposes. -- [Human-in-the-Loop](human_in_the_loop.md): Explains different ways of integrating human feedback into a LangGraph application. -- [Time Travel](time-travel.md): Time travel allows you to replay past actions in your LangGraph application to explore alternative paths and debug issues. -- [Persistence](persistence.md): LangGraph has a built-in persistence layer, implemented through checkpointers. This persistence layer helps to support powerful capabilities like human-in-the-loop, memory, time travel, and fault-tolerance. -- [Memory](memory.md): Memory in AI applications refers to the ability to process, store, and effectively recall information from past interactions. With memory, your agents can learn from feedback and adapt to users' preferences. -- [Streaming](streaming.md): Streaming is crucial for enhancing the responsiveness of applications built on LLMs. By displaying output progressively, even before a complete response is ready, streaming significantly improves user experience (UX), particularly when dealing with the latency of LLMs. -- [Functional API](functional_api.md): `@entrypoint` and `@task` decorators that allow you to add LangGraph functionality to an existing codebase. -- [Durable Execution](durable_execution.md): LangGraph's built-in [persistence](./persistence.md) layer provides durable execution for workflows, ensuring that the state of each execution step is saved to a durable store. -- [Pregel](pregel.md): Pregel is LangGraph's runtime, which is responsible for managing the execution of LangGraph applications. -- [FAQ](faq.md): Frequently asked questions about LangGraph. - -## LangGraph Platform - -LangGraph Platform is a commercial solution for deploying agentic applications in production, built on the open-source LangGraph framework. - -The LangGraph Platform offers a few different deployment options described in the [deployment options guide](./deployment_options.md). - -!!! tip - - * LangGraph is an MIT-licensed open-source library, which we are committed to maintaining and growing for the community. - * You can always deploy LangGraph applications on your own infrastructure using the open-source LangGraph project without using LangGraph Platform. - -### High Level - -- [Why LangGraph Platform?](./langgraph_platform.md): The LangGraph platform is an opinionated way to deploy and manage LangGraph applications. This guide provides an overview of the key features and concepts behind LangGraph Platform. -- [Platform Architecture](./platform_architecture.md): A high-level overview of the architecture of the LangGraph Platform. -- [Scalability and Resilience](./scalability_and_resilience.md): LangGraph Platform is designed to be scalable and resilient. This document explains how the platform achieves this. -- [Deployment Options](./deployment_options.md): LangGraph Platform offers four deployment options: [Cloud SaaS](./langgraph_cloud.md), [Self-Hosted Data Plane](./langgraph_self_hosted_data_plane.md), [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md), and [Standalone Container](./langgraph_standalone_container.md). This guide explains the differences between these options, and which Plans they are available on. -- [Plans](./plans.md): LangGraph Platforms offer three different plans: Developer, Plus, Enterprise. This guide explains the differences between these options, what deployment options are available for each, and how to sign up for each one. -- [Template Applications](./template_applications.md): Reference applications designed to help you get started quickly when building with LangGraph. - -### Components - -The LangGraph Platform comprises several components that work together to support the deployment and management of LangGraph applications: - -- [LangGraph Server](./langgraph_server.md): The LangGraph Server is designed to support a wide range of agentic application use cases, from background processing to real-time interactions. -- [LangGraph Studio](./langgraph_studio.md): LangGraph Studio is a specialized IDE that can connect to a LangGraph Server to enable visualization, interaction, and debugging of the application locally. -- [LangGraph CLI](./langgraph_cli.md): LangGraph CLI is a command-line interface that helps to interact with a local LangGraph -- [Python/JS SDK](./sdk.md): The Python/JS SDK provides a programmatic way to interact with deployed LangGraph Applications. -- [Remote Graph](../how-tos/use-remote-graph.md): A RemoteGraph allows you to interact with any deployed LangGraph application as though it were running locally. -- [LangGraph Control Plane](./langgraph_control_plane.md): The LangGraph Control Plane refers to the Control Plane UI where users create and update LangGraph Servers and the Control Plane APIs that support the UI experience. -- [LangGraph Data Plane](./langgraph_data_plane.md): The LangGraph Data Plane refers to LangGraph Servers, the corresponding infrastructure for each server, and the "listener" application that continuously polls for updates from the LangGraph Control Plane. - -### LangGraph Server - -- [Application Structure](./application_structure.md): A LangGraph application consists of one or more graphs, a LangGraph API Configuration file (`langgraph.json`), a file that specifies dependencies, and environment variables. -- [Assistants](./assistants.md): Assistants are a way to save and manage different configurations of your LangGraph applications. -- [Web-hooks](./langgraph_server.md#webhooks): Webhooks allow your running LangGraph application to send data to external services on specific events. -- [Cron Jobs](./langgraph_server.md#cron-jobs): Cron jobs are a way to schedule tasks to run at specific times in your LangGraph application. -- [Double Texting](./double_texting.md): Double texting is a common issue in LLM applications where users may send multiple messages before the graph has finished running. This guide explains how to handle double texting with LangGraph Deploy. -- [Authentication & Access Control](./auth.md): Learn about options for authentication and access control when deploying the LangGraph Platform. -- [MCP Endpoint](./server-mcp.md): Expose your LangGraph agents as MCP tools using an MCP endpoint. - -### Deployment Options - -- Cloud SaaS(Beta): Connect to your GitHub repositories and deploy LangGraph Servers to LangChain's cloud. We manage everything. -- Self-Hosted Data Plane(Beta): Create deployments from the [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to your cloud. We manage the [control plane](../concepts/langgraph_control_plane.md), you manage the deployments. -- Self-Hosted Control Plane(Beta): Create deployments from a self-hosted [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to your cloud. You manage everything. -- [Standalone Container](../concepts/langgraph_standalone_container.md): Deploy LangGraph Server Docker images however you like. diff --git a/docs/docs/concepts/langgraph_cli.md b/docs/docs/concepts/langgraph_cli.md index feff59db6..91cf50b9f 100644 --- a/docs/docs/concepts/langgraph_cli.md +++ b/docs/docs/concepts/langgraph_cli.md @@ -5,20 +5,11 @@ search: # LangGraph CLI -!!! info "Prerequisites" - - [LangGraph Platform](./langgraph_platform.md) - - [LangGraph Server](./langgraph_server.md) - -The LangGraph CLI is a multi-platform command-line tool for building and running the [LangGraph API server](./langgraph_server.md) locally. The resulting server includes all API endpoints for your graph's runs, threads, assistants, etc. as well as the other services required to run your agent, including a managed database for checkpointing and storage. +**LangGraph CLI** is a multi-platform command-line tool for building and running the [LangGraph API server](./langgraph_server.md) locally. The resulting server includes all API endpoints for your graph's runs, threads, assistants, etc. as well as the other services required to run your agent, including a managed database for checkpointing and storage. ## Installation -The LangGraph CLI can be installed via Homebrew (on macOS) or pip: - -=== "Homebrew" - ```bash - brew install langgraph-cli - ``` +The LangGraph CLI can be installed via pip: === "pip" ```bash @@ -27,49 +18,13 @@ The LangGraph CLI can be installed via Homebrew (on macOS) or pip: ## Commands -The CLI provides the following core functionality: +LangGraph CLI provides the following core functionality: -### `build` +| Command | Description | +| -------- | -------| +| [`langgraph build`](../cloud/reference/cli.md#build) | Builds a Docker image for the [LangGraph API server](./langgraph_server.md) that can be directly deployed. | +| [`langgraph dev`](../cloud/reference/cli.md#dev) | Starts a lightweight development server that requires no Docker installation. This server is ideal for rapid development and testing. This is available in version 0.1.55 and up. +| [`langgraph dockerfile`](../cloud/reference/cli.md#dockerfile) | Generates a [Dockerfile](https://docs.docker.com/reference/dockerfile/) that can be used to build images for and deploy instances of the [LangGraph API server](./langgraph_server.md). This is useful if you want to further customize the dockerfile or deploy in a more custom way. | +| [`langgraph up`](../cloud/reference/cli.md#up) | Starts an instance of the [LangGraph API server](./langgraph_server.md) locally in a docker container. This requires the docker server to be running locally. It also requires a LangSmith API key for local development or a license key for production use. | -The `langgraph build` command builds a Docker image for the [LangGraph API server](./langgraph_server.md) that can be directly deployed. - -### `dev` - -!!! note "New in version 0.1.55" - The `langgraph dev` command was introduced in langgraph-cli version 0.1.55. - -!!! note "Python only" - - Currently, the CLI only supports Python >= 3.11. - JS support is coming soon. - -The `langgraph dev` command starts a lightweight development server that requires no Docker installation. This server is ideal for rapid development and testing, with features like: - -- Hot reloading: Changes to your code are automatically detected and reloaded -- Debugger support: Attach your IDE's debugger for line-by-line debugging -- In-memory state with local persistence: Server state is stored in memory for speed but persisted locally between restarts - -To use this command, you need to install the CLI with the "inmem" extra: - -```bash -pip install -U "langgraph-cli[inmem]" -``` - -**Note**: This command is intended for local development and testing only. It is not recommended for production use. Since it does not use Docker, we recommend using virtual environments to manage your project's dependencies. - -### `up` - -The `langgraph up` command starts an instance of the [LangGraph API server](./langgraph_server.md) locally in a docker container. This requires the docker server to be running locally. It also requires a LangSmith API key for local development or a license key for production use. - -The server includes all API endpoints for your graph's runs, threads, assistants, etc. as well as the other services required to run your agent, including a managed database for checkpointing and storage. - -### `dockerfile` - -The `langgraph dockerfile` command generates a [Dockerfile](https://docs.docker.com/reference/dockerfile/) that can be used to build images for and deploy instances of the [LangGraph API server](./langgraph_server.md). This is useful if you want to further customize the dockerfile or deploy in a more custom way. - -??? note "Updating your langgraph.json file" - The `langgraph dockerfile` command translates all the configuration in your `langgraph.json` file into Dockerfile commands. When using this command, you will have to re-run it whenever you update your `langgraph.json` file. Otherwise, your changes will not be reflected when you build or run the dockerfile. - -## Related - -- [LangGraph CLI API Reference](../cloud/reference/cli.md) +For more information, see the [LangGraph CLI Reference](../cloud/reference/cli.md). diff --git a/docs/docs/concepts/langgraph_cloud.md b/docs/docs/concepts/langgraph_cloud.md index f83d676e9..b9c835913 100644 --- a/docs/docs/concepts/langgraph_cloud.md +++ b/docs/docs/concepts/langgraph_cloud.md @@ -3,7 +3,7 @@ search: boost: 2 --- -# Cloud SaaS (Beta) +# Cloud SaaS To deploy a [LangGraph Server](../concepts/langgraph_server.md), follow the how-to guide for [how to deploy to Cloud SaaS](../cloud/deployment/cloud.md). @@ -11,9 +11,9 @@ To deploy a [LangGraph Server](../concepts/langgraph_server.md), follow the how- The Cloud SaaS deployment option is a fully managed model for deployment where we manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in our cloud. -| | [Control Plane](../concepts/langgraph_control_plane.md) | [Data Plane](../concepts/langgraph_data_plane.md) | +| | [Control plane](../concepts/langgraph_control_plane.md) | [Data plane](../concepts/langgraph_data_plane.md) | |-------------------|-------------------|------------| -| **What is it?** |
  • Control Plane UI for creating deployments and revisions
  • Control Plane APIs for creating deployments and revisions
|
  • Data plane "listener" for reconciling deployments with control plane state
  • LangGraph Servers
  • Postgres, Redis, etc
| +| **What is it?** |
  • Control plane UI for creating deployments and revisions
  • Control plane APIs for creating deployments and revisions
|
  • Data plane "listener" for reconciling deployments with control plane state
  • LangGraph Servers
  • Postgres, Redis, etc
| | **Where is it hosted?** | LangChain's cloud | LangChain's cloud | | **Who provisions and manages it?** | LangChain | LangChain | diff --git a/docs/docs/concepts/langgraph_components.md b/docs/docs/concepts/langgraph_components.md new file mode 100644 index 000000000..78b9e7c8d --- /dev/null +++ b/docs/docs/concepts/langgraph_components.md @@ -0,0 +1,13 @@ +## Components + +The LangGraph Platform consists of components that work together to support the development, deployment, debugging, and monitoring of LangGraph applications: + +- [LangGraph Server](./langgraph_server.md): The server defines an opinionated API and architecture that incorporates best practices for deploying agentic applications, allowing you to focus on building your agent logic rather than developing server infrastructure. +- [LangGraph CLI](./langgraph_cli.md): LangGraph CLI is a command-line interface that helps to interact with a local LangGraph +- [LangGraph Studio](./langgraph_studio.md): LangGraph Studio is a specialized IDE that can connect to a LangGraph Server to enable visualization, interaction, and debugging of the application locally. +- [Python/JS SDK](./sdk.md): The Python/JS SDK provides a programmatic way to interact with deployed LangGraph Applications. +- [Remote Graph](../how-tos/use-remote-graph.md): A RemoteGraph allows you to interact with any deployed LangGraph application as though it were running locally. +- [LangGraph control plane](./langgraph_control_plane.md): The LangGraph Control Plane refers to the Control Plane UI where users create and update LangGraph Servers and the Control Plane APIs that support the UI experience. +- [LangGraph data plane](./langgraph_data_plane.md): The LangGraph Data Plane refers to LangGraph Servers, the corresponding infrastructure for each server, and the "listener" application that continuously polls for updates from the LangGraph Control Plane. + +![LangGraph components](img/lg_platform.png) \ No newline at end of file diff --git a/docs/docs/concepts/langgraph_control_plane.md b/docs/docs/concepts/langgraph_control_plane.md index 85143f811..918921639 100644 --- a/docs/docs/concepts/langgraph_control_plane.md +++ b/docs/docs/concepts/langgraph_control_plane.md @@ -5,13 +5,13 @@ search: # LangGraph Control Plane -The term "control plane" is used broadly to refer to the Control Plane UI where users create and update [LangGraph Servers](./langgraph_server.md) (deployments) and the Control Plane APIs that support the UI experience. +The term "control plane" is used broadly to refer to the control plane UI where users create and update [LangGraph Servers](./langgraph_server.md) (deployments) and the control plane APIs that support the UI experience. -When a user makes an update through the Control Plane UI, the update is stored in the control plane state. The [LangGraph Data Plane](./langgraph_data_plane.md) "listener" application polls for these updates by calling the Control Plane APIs. +When a user makes an update through the control plane UI, the update is stored in the control plane state. The [LangGraph Data Plane](./langgraph_data_plane.md) "listener" application polls for these updates by calling the control plane APIs. ## Control Plane UI -From the Control Plane UI, you can: +From the control plane UI, you can: - View a list of outstanding deployments. - View details of an individual deployment. @@ -25,7 +25,7 @@ The Control Plane UI is embedded in [LangSmith](https://docs.smith.langchain.com ## Control Plane API -This section describes data model of the LangGraph Control Plane API. Control Plane API is used to create, update, and delete deployments. However, they are not publicly accessible. +This section describes data model of the control plane API. The API is used to create, update, and delete deployments. However, they are not publicly accessible. ### Deployment @@ -57,8 +57,8 @@ CPU and memory resources are per container. !!! info "For [Cloud SaaS](../concepts/langgraph_cloud.md)" For `Production` type deployments, resources can be manually increased on a case-by-case basis depending on use case and capacity constraints. Contact support@langchain.dev to request an increase in resources. -!!! info "For [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md)" - Resources for [Self-Hosted Data Plane](../concepts/langgraph_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_control_plane.md) deployments can be fully customized. +!!! info + Resources for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments can be fully customized. ### Database Provisioning @@ -70,8 +70,8 @@ There is no direct access to the database. All access to the database occurs thr The database is never deleted until the deployment itself is deleted. See [Automatic Deletion](#automatic-deletion) for additional details. -!!! info "For [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md)" - A custom Postgres instance can be configured for [Self-Hosted Data Plane](../concepts/langgraph_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_control_plane.md) deployments. +!!! info + A custom Postgres instance can be configured for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments. ### Asynchronous Deployment @@ -83,19 +83,6 @@ Infrastructure for deployments and revisions are provisioned and deployed asynch The control plane and [LangGraph Data Plane](./langgraph_data_plane.md) "listener" application coordinate to achieve asynchronous deployments. -### Automatic Deletion - -!!! info "Only for [Cloud SaaS](../concepts/langgraph_cloud.md)" - Automatic deletion of deployments is only available for [Cloud SaaS](../concepts/langgraph_cloud.md). - -The control plane automatically deletes deployments after 28 consecutive days of non-use (it is in an unused state). A deployment is in an unused state if there are no traces emitted to LangSmith from the deployment after 28 consecutive days. On any given day, if a deployment emits a trace to LangSmith, the counter for consecutive days of non-use is reset. - -- An email notification is sent after 7 consecutive days of non-use. -- A deployment is deleted after 28 consecutive days of non-use. - -!!! danger "Data Cannot Be Recovered" - After a deployment is deleted, the data (e.g. Postgres) from the deployment cannot be recovered. - ### LangSmith Integration A [LangSmith](https://docs.smith.langchain.com/) tracing project is automatically created for each deployment. The tracing project has the same name as the deployment. When creating a deployment, the `LANGCHAIN_TRACING` and `LANGSMITH_API_KEY`/`LANGCHAIN_API_KEY` environment variables do not need to be specified; they are set automatically by the control plane. diff --git a/docs/docs/concepts/langgraph_data_plane.md b/docs/docs/concepts/langgraph_data_plane.md index 9d47b7e77..47195a8ce 100644 --- a/docs/docs/concepts/langgraph_data_plane.md +++ b/docs/docs/concepts/langgraph_data_plane.md @@ -11,16 +11,14 @@ The term "data plane" is used broadly to refer to [LangGraph Servers](./langgrap In addition to the [LangGraph Server](./langgraph_server.md) itself, the following infrastructure for each server are also included in the broad definition of "data plane": -- [Postgres](../concepts/platform_architecture.md#how-we-use-postgres) -- [Redis](../concepts/platform_architecture.md#how-we-use-redis) +- Postgres +- Redis - Secrets store - Autoscalers -See [LangGraph Platform Architecture](../concepts/platform_architecture.md) for more details. - ## "Listener" Application -The data plane "listener" application periodically calls [Control Plane APIs](../concepts/langgraph_control_plane.md#control-plane-api) to: +The data plane "listener" application periodically calls [control plane APIs](../concepts/langgraph_control_plane.md#control-plane-api) to: - Determine if new deployments should be created. - Determine if existing deployments should be updated (i.e. new revisions). @@ -28,32 +26,37 @@ The data plane "listener" application periodically calls [Control Plane APIs](.. In other words, the data plane "listener" reads the latest state of the control plane (desired state) and takes action to reconcile outstanding deployments (current state) to match the latest state. +## Postgres + +Postgres is the persistence layer for all user, run, and long-term memory data in a LangGraph Server. This stores both checkpoints (see more info [here](./persistence.md)), server resources (threads, runs, assistants and crons), as well as items saved in the long-term memory store (see more info [here](./persistence.md#memory-store)). + +## Redis + +Redis is used in each LangGraph Server as a way for server and queue workers to communicate, and to store ephemeral metadata. No user or run data is stored in Redis. + +### Communication + +All runs in a LangGraph Server are executed by a pool of background workers that are part of each deployment. In order to enable some features for those runs (such as cancellation and output streaming) we need a channel for two-way communication between the server and the worker handling a particular run. We use Redis to organize that communication. + +1. A Redis list is used as a mechanism to wake up a worker as soon as a new run is created. Only a sentinel value is stored in this list, no actual run information. The run information is then retrieved from Postgres by the worker. +2. A combination of a Redis string and Redis PubSub channel is used for the server to communicate a run cancellation request to the appropriate worker. +3. A Redis PubSub channel is used by the worker to broadcast streaming output from an agent while the run is being handled. Any open `/stream` request in the server will subscribe to that channel and forward any events to the response as they arrive. No events are stored in Redis at any time. + +### Ephemeral metadata + +Runs in a LangGraph Server may be retried for specific failures (currently only for transient Postgres errors encountered during the run). In order to limit the number of retries (currently limited to 3 attempts per run) we record the attempt number in a Redis string when is picked up. This contains no run-specific info other than its ID, and expires after a short delay. + ## Data Plane Features This section describes various features of the data plane. -### Lite vs Enterprise - -There are two versions of the LangGraph Server: `Lite` and `Enterprise`. - -The `Lite` version is a limited version of the LangGraph Server that you can run locally or in a self-hosted manner (up to 1 million nodes executed per year). `Lite` is only available for the [Standalone Container](../concepts/langgraph_standalone_container.md) deployment option. - -The `Enterprise` version is the full version of the LangGraph Server. To use the `Enterprise` version, you must acquire a license key that you will need to specify when running the Docker image. To acquire a license key, please email sales@langchain.dev. `Enterprise` is available for [Cloud SaaS](../concepts/langgraph_cloud.md), [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md), and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployment options. - -Feature Differences: - -| | Lite | Enterprise | -|-------|------------|------------| -| [Cron Jobs](../concepts/langgraph_server.md#cron-jobs) |❌|✅| -| [Custom Authentication](../concepts/auth.md) |❌|✅| - ### Autoscaling [`Production` type](../concepts/langgraph_control_plane.md#deployment-types) deployments automatically scale up to 10 containers. Scaling is based on 3 metrics: 1. CPU utilization 1. Memory utilization -1. Number of pending (in progress) [runs](../concepts/langgraph_server.md#runs) +1. Number of pending (in progress) [runs](../cloud/concepts/runs.md) For CPU utilization, the autoscaler targets 75% utilization. This means the autoscaler will scale the number of containers up or down to ensure that CPU utilization is at or near 75%. For memory utilization, the autoscaler targets 75% utilization as well. @@ -83,7 +86,7 @@ All traffic from deployments created after January 6th 2025 will come through a ### Custom Postgres -!!! info "Only for Self-Hosted Data Plane and Self-Hosted Control Plane" +!!! info Custom Postgres instances are only available for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments. A custom Postgres instance can be used instead of the [one automatically created by the control plane](./langgraph_control_plane.md#database-provisioning). Specify the [`POSTGRES_URI_CUSTOM`](../cloud/reference/env_var.md#postgres_uri_custom) environment variable to use a custom Postgres instance. @@ -92,8 +95,8 @@ Multiple deployments can share the same Postgres instance. For example, for `Dep ### Custom Redis -!!! info "Only for Self-Hosted Data Plane and Self-Hosted Control Plane" - Custom Redis instances are only available for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_data_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments. +!!! info + Custom Redis instances are only available for [Self-Hosted Data Plane](../concepts/langgraph_self_hosted_control_plane.md) and [Self-Hosted Control Plane](../concepts/langgraph_self_hosted_control_plane.md) deployments. A custom Redis instance can be used instead of the one automatically created by the control plane. Specify the [REDIS_URI_CUSTOM](../cloud/reference/env_var.md#redis_uri_custom) environment variable to use a custom Redis instance. diff --git a/docs/docs/concepts/langgraph_platform.md b/docs/docs/concepts/langgraph_platform.md index 77d3f7c06..2b1890506 100644 --- a/docs/docs/concepts/langgraph_platform.md +++ b/docs/docs/concepts/langgraph_platform.md @@ -5,44 +5,35 @@ search: # LangGraph Platform -Watch this 4-minute overview of LangGraph Platform to see how it helps you build, deploy, and evaluate agentic applications. +**LangGraph Platform** is a commercial solution for deploying agentic applications to production, built on the open-source [LangGraph framework](../index.md). - +
-## Overview +!!! tip "Get started with LangGraph Platform" -LangGraph Platform is a commercial solution for deploying agentic applications to production, built on the open-source [LangGraph framework](./high_level.md). + Check out the [LangGraph Platform quickstart](../cloud/quick_start.md) for instructions on how to set up and use LangGraph Platform to do a cloud deployment. -The LangGraph Platform consists of several components that work together to support the development, deployment, debugging, and monitoring of LangGraph applications: -- [LangGraph Server](./langgraph_server.md): The server defines an opinionated API and architecture that incorporates best practices for deploying agentic applications, allowing you to focus on building your agent logic rather than developing server infrastructure. -- [LangGraph Studio](./langgraph_studio.md): LangGraph Studio is a specialized IDE that can connect to a LangGraph Server to enable visualization, interaction, and debugging of the application locally. -- [LangGraph CLI](./langgraph_cli.md): LangGraph CLI is a command-line interface that helps to interact with a local LangGraph -- [Python/JS SDK](./sdk.md): The Python/JS SDK provides a programmatic way to interact with deployed LangGraph Applications. -- [Remote Graph](../how-tos/use-remote-graph.md): A RemoteGraph allows you to interact with any deployed LangGraph application as though it were running locally. -- [LangGraph Control Plane](./langgraph_control_plane.md): The LangGraph Control Plane refers to the Control Plane UI where users create and update LangGraph Servers and the Control Plane APIs that support the UI experience. -- [LangGraph Data Plane](./langgraph_data_plane.md): The LangGraph Data Plane refers to LangGraph Servers, the corresponding infrastructure for each server, and the "listener" application that continuously polls for updates from the LangGraph Control Plane. +## Why use LangGraph Platform? -![](img/lg_platform.png) +LangGraph Platform handles common issues that arise when deploying LLM applications to production, allowing you to focus on agent logic instead of managing server infrastructure. -The LangGraph Platform offers a few different deployment options described in the [deployment options guide](./deployment_options.md). +- **[Streaming Support](../cloud/concepts/streaming.md)**: As agents grow more sophisticated, they often benefit from streaming both token outputs and intermediate states back to the user. Without this, users are left waiting for potentially long operations with no feedback. LangGraph Server provides multiple streaming modes optimized for various application needs. -## Why Use LangGraph Platform? - -**LangGraph Platform** handles common issues that arise when deploying LLM applications to production, allowing you to focus on agent logic instead of managing server infrastructure. - -- **[Streaming Support](streaming.md)**: As agents grow more sophisticated, they often benefit from streaming both token outputs and intermediate states back to the user. Without this, users are left waiting for potentially long operations with no feedback. LangGraph Server provides [multiple streaming modes](streaming.md) optimized for various application needs. - -- **Background Runs**: For agents that take longer to process (e.g., hours), maintaining an open connection can be impractical. The LangGraph Server supports launching agent runs in the background and provides both polling endpoints and webhooks to monitor run status effectively. +- **[Background Runs](../cloud/how-tos/background_run.md)**: For agents that take longer to process (e.g., hours), maintaining an open connection can be impractical. The LangGraph Server supports launching agent runs in the background and provides both polling endpoints and webhooks to monitor run status effectively. -- **Support for long runs**: Vanilla server setups often encounter timeouts or disruptions when handling requests that take a long time to complete. LangGraph Server’s API provides robust support for these tasks by sending regular heartbeat signals, preventing unexpected connection closures during prolonged processes. +- **Support for long runs**: Regular server setups often encounter timeouts or disruptions when handling requests that take a long time to complete. LangGraph Server’s API provides robust support for these tasks by sending regular heartbeat signals, preventing unexpected connection closures during prolonged processes. - **Handling Burstiness**: Certain applications, especially those with real-time user interaction, may experience "bursty" request loads where numerous requests hit the server simultaneously. LangGraph Server includes a task queue, ensuring requests are handled consistently without loss, even under heavy loads. -- **[Double Texting](double_texting.md)**: In user-driven applications, it’s common for users to send multiple messages rapidly. This “double texting” can disrupt agent flows if not handled properly. LangGraph Server offers built-in strategies to address and manage such interactions. +- **[Double-texting](../cloud/how-tos/interrupt_concurrent.md)**: In user-driven applications, it’s common for users to send multiple messages rapidly. This “double texting” can disrupt agent flows if not handled properly. LangGraph Server offers built-in strategies to address and manage such interactions. -- **[Checkpointers and Memory Management](persistence.md#checkpoints)**: For agents needing persistence (e.g., conversation memory), deploying a robust storage solution can be complex. LangGraph Platform includes optimized [checkpointers](persistence.md#checkpoints) and a [memory store](persistence.md#memory-store), managing state across sessions without the need for custom solutions. +- **[Checkpointers and memory management](persistence.md#checkpoints)**: For agents needing persistence (e.g., conversation memory), deploying a robust storage solution can be complex. LangGraph Platform includes optimized [checkpointers](persistence.md#checkpoints) and a [memory store](persistence.md#memory-store), managing state across sessions without the need for custom solutions. -- **[Human-in-the-loop Support](human_in_the_loop.md)**: In many applications, users require a way to intervene in agent processes. LangGraph Server provides specialized endpoints for human-in-the-loop scenarios, simplifying the integration of manual oversight into agent workflows. +- **[Human-in-the-loop support](../cloud/how-tos/human_in_the_loop_breakpoint.md)**: In many applications, users require a way to intervene in agent processes. LangGraph Server provides specialized endpoints for human-in-the-loop scenarios, simplifying the integration of manual oversight into agent workflows. By using LangGraph Platform, you gain access to a robust, scalable deployment solution that mitigates these challenges, saving you the effort of implementing and maintaining them manually. This allows you to focus more on building effective agent behavior and less on solving deployment infrastructure issues. + +## Deployment + +There are several ways to deploy on LangGraph Platform. For more information, see [Deployment options](./deployment_options.md). diff --git a/docs/docs/concepts/langgraph_self_hosted_control_plane.md b/docs/docs/concepts/langgraph_self_hosted_control_plane.md index dc0ee0322..e15fbe86d 100644 --- a/docs/docs/concepts/langgraph_self_hosted_control_plane.md +++ b/docs/docs/concepts/langgraph_self_hosted_control_plane.md @@ -1,28 +1,29 @@ ---- -search: - boost: 2 ---- +# Self-Hosted Control Plane -# Self-Hosted Control Plane (Beta) +There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane). -To deploy a [LangGraph Server](../concepts/langgraph_server.md), follow the how-to guide for [how to deploy the Self-Hosted Control Plane](../cloud/deployment/self_hosted_control_plane.md). +## Requirements -## Overview +- You use `langgraph-cli` and/or [LangGraph Studio](./langgraph_studio.md) app to test graph locally. +- You use `langgraph build` command to build image. -The Self-Hosted Control Plane deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud (this option implies that the data plane is self-hosted). +## Self-Hosted Control Plane (Beta) -| | [Control Plane](../concepts/langgraph_control_plane.md) | [Data Plane](../concepts/langgraph_data_plane.md) | +The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option give you full control and responsibility of the control plane and data plane infrastructure. + +| | [Control plane](../concepts/langgraph_control_plane.md) | [Data plane](../concepts/langgraph_data_plane.md) | |-------------------|-------------------|------------| -| **What is it?** |
  • Control Plane UI for creating deployments and revisions
  • Control Plane APIs for creating deployments and revisions
|
  • Data plane "listener" for reconciling deployments with control plane state
  • LangGraph Servers
  • Postgres, Redis, etc
| +| **What is it?** |
  • Control plane UI for creating deployments and revisions
  • Control plane APIs for creating deployments and revisions
|
  • Data plane "listener" for reconciling deployments with control plane state
  • LangGraph Servers
  • Postgres, Redis, etc
| | **Where is it hosted?** | Your cloud | Your cloud | | **Who provisions and manages it?** | You | You | -## Architecture +### Architecture ![Self-Hosted Control Plane Architecture](./img/self_hosted_control_plane_architecture.png) -## Compute Platforms +### Compute Platforms -### Kubernetes + - **Kubernetes**: The Self-Hosted Control Plane deployment option supports deploying control plane and data plane infrastructure to any Kubernetes cluster. -The Self-Hosted Control Plane deployment option supports deploying control plane and data plane infrastructure to any Kubernetes cluster. +!!! tip + If you would like to deploy to Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md). \ No newline at end of file diff --git a/docs/docs/concepts/langgraph_self_hosted_data_plane.md b/docs/docs/concepts/langgraph_self_hosted_data_plane.md index ba10e5d75..c9db23015 100644 --- a/docs/docs/concepts/langgraph_self_hosted_data_plane.md +++ b/docs/docs/concepts/langgraph_self_hosted_data_plane.md @@ -3,30 +3,35 @@ search: boost: 2 --- -# Self-Hosted Data Plane (Beta) +# Self-Hosted Data Plane -To deploy a [LangGraph Server](../concepts/langgraph_server.md), follow the how-to guide for [how to deploy the Self-Hosted Data Plane](../cloud/deployment/self_hosted_data_plane.md). +There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane). -## Overview +## Requirements -LangGraph Platform's Self-Hosted Data Plane deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. +- You use `langgraph-cli` and/or [LangGraph Studio](./langgraph_studio.md) app to test graph locally. +- You use `langgraph build` command to build image. -| | [Control Plane](../concepts/langgraph_control_plane.md) | [Data Plane](../concepts/langgraph_data_plane.md) | +## Self-Hosted Data Plane (Beta) + +The [Self-Hosted Data Plane](./self_hosted.md.md) deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. This option provides a way to securely manage your data plane infrastructure, while offloading control plane management to us. When using the Self-Hosted Data Plane version, you authenticate with a [LangSmith](https://smith.langchain.com/) API key. + +| | [Control plane](../concepts/langgraph_control_plane.md) | [Data plane](../concepts/langgraph_data_plane.md) | |-------------------|-------------------|------------| -| **What is it?** |
  • Control Plane UI for creating deployments and revisions
  • Control Plane APIs for creating deployments and revisions
|
  • Data plane "listener" for reconciling deployments with control plane state
  • LangGraph Servers
  • Postgres, Redis, etc
| +| **What is it?** |
  • Control plane UI for creating deployments and revisions
  • Control plane APIs for creating deployments and revisions
|
  • Data plane "listener" for reconciling deployments with control plane state
  • LangGraph Servers
  • Postgres, Redis, etc
| | **Where is it hosted?** | LangChain's cloud | Your cloud | | **Who provisions and manages it?** | LangChain | You | -## Architecture +For information on how to deploy a [LangGraph Server](../concepts/langgraph_server.md) to Self-Hosted Data Plane, see [Deploy to Self-Hosted Data Plane](../cloud/deployment/self_hosted_data_plane.md) + +### Architecture ![Self-Hosted Data Plane Architecture](./img/self_hosted_data_plane_architecture.png) -## Compute Platforms +### Compute Platforms -### Kubernetes +- **Kubernetes**: The Self-Hosted Data Plane deployment option supports deploying data plane infrastructure to any Kubernetes cluster. +- **Amazon ECS**: Coming soon! -The Self-Hosted Data Plane deployment option supports deploying data plane infrastructure to any Kubernetes cluster. - -### Amazon ECS - -Coming soon... +!!! tip + If you would like to deploy to Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md). \ No newline at end of file diff --git a/docs/docs/concepts/langgraph_server.md b/docs/docs/concepts/langgraph_server.md index 97ecb9657..9dead2ca3 100644 --- a/docs/docs/concepts/langgraph_server.md +++ b/docs/docs/concepts/langgraph_server.md @@ -5,34 +5,38 @@ search: # LangGraph Server -!!! info "Prerequisites" - - [LangGraph Platform](./langgraph_platform.md) - - [LangGraph Glossary](low_level.md) +**LangGraph Server** offers an API for creating and managing agent-based applications. It is built on the concept of [assistants](assistants.md), which are agents configured for specific tasks, and includes built-in [persistence](persistence.md#memory-store) and a **task queue**. This versatile API supports a wide range of agentic application use cases, from background processing to real-time interactions. -## Overview +Use LangGraph Serverto create and manage [assistants](assistants.md), [threads](../cloud/concepts/threads.md), [runs](../cloud/concepts/runs.md), [cron jobs](../cloud/concepts/cron_jobs.md), [webhooks](../cloud/concepts/webhooks.md), and more. -LangGraph Server offers an API for creating and managing agent-based applications. It is built on the concept of [assistants](assistants.md), which are agents configured for specific tasks, and includes built-in [persistence](persistence.md#memory-store) and a **task queue**. This versatile API supports a wide range of agentic application use cases, from background processing to real-time interactions. +!!! tip "API reference" + + For detailed information on the API endpoints and data models, see [LangGraph Platform API reference docs](../cloud/reference/api/api_ref.html). -## Key Features +## Server versions -The LangGraph Platform incorporates best practices for agent deployment, so you can focus on building your agent logic. +There are two versions of LangGraph Server: -* **Streaming endpoints**: Endpoints that expose [multiple different streaming modes](streaming.md). We've made these work even for long-running agents that may go minutes between consecutive stream events. -* **Background runs**: The LangGraph Server supports launching assistants in the background with endpoints for polling the status of the assistant's run and webhooks to monitor run status effectively. -- **Support for long runs**: Our blocking endpoints for running assistants send regular heartbeat signals, preventing unexpected connection closures when handling requests that take a long time to complete. -* **Task queue**: We've added a task queue to make sure we don't drop any requests if they arrive in a bursty nature. -* **Horizontally scalable infrastructure**: LangGraph Server is designed to be horizontally scalable, allowing you to scale up and down your usage as needed. -* **Double texting support**: Many times users might interact with your graph in unintended ways. For instance, a user may send one message and before the graph has finished running send a second message. We call this ["double texting"](double_texting.md) and have added four different ways to handle this. -* **Optimized checkpointer**: LangGraph Platform comes with a built-in [checkpointer](./persistence.md#checkpoints) optimized for LangGraph applications. -* **Human-in-the-loop endpoints**: We've exposed all endpoints needed to support [human-in-the-loop](human_in_the_loop.md) features. -* **Memory**: In addition to thread-level persistence (covered above by [checkpointers](./persistence.md#checkpoints)), LangGraph Platform also comes with a built-in [memory store](persistence.md#memory-store). -* **Cron jobs**: Built-in support for scheduling tasks, enabling you to automate regular actions like data clean-up or batch processing within your applications. -* **Webhooks**: Allows your application to send real-time notifications and data updates to external systems, making it easy to integrate with third-party services and trigger actions based on specific events. -* **Monitoring**: LangGraph Server integrates seamlessly with the [LangSmith](https://docs.smith.langchain.com/) monitoring platform, providing real-time insights into your application's performance and health. +- `Lite` is a limited version of the LangGraph Server that you can run locally or in a self-hosted manner (up to 1 million nodes executed per year). +- `Enterprise` is the full version of the LangGraph Server. To use the `Enterprise` version, you must acquire a license key that you will need to specify when running the Docker image. To acquire a license key, please email sales@langchain.dev. -## What are you deploying? +Feature Differences: -When you deploy a LangGraph Server, you are deploying one or more [graphs](#graphs), a database for [persistence](persistence.md), and a task queue. +| | Lite | Enterprise | +|-------|------------|------------| +| [Cron Jobs](../clouds/concepts/cron-jobs.md) |❌|✅| +| [Custom Authentication](../concepts/auth.md) |❌|✅| +| [Deployment options](../concepts/deployment_options.md) | Standalone container | Cloud Saas, Self-Hosted Data Plane, Self-Hosted Control Plane, Standalone container + +## Application structure + +To deploy a LangGraph Server application, you need to specify the graph(s) you want to deploy, as well as any relevant configuration settings, such as dependencies and environment variables. + +Read the [application structure](./application_structure.md) guide to learn how to structure your LangGraph application for deployment. + +## Parts of a deployment + +When you deploy LangGraph Server, you are deploying one or more [graphs](#graphs), a database for [persistence](persistence.md), and a task queue. ### Graphs @@ -43,16 +47,14 @@ that can be served by the same graph. Upon deployment, LangGraph Server will automatically create a default assistant for each graph using the graph's default configuration settings. -You can interact with assistants through the [LangGraph Server API](#langgraph-server-api). - !!! note We often think of a graph as implementing an [agent](agentic_concepts.md), but a graph does not necessarily need to implement an agent. For example, a graph could implement a simple chatbot that only supports back-and-forth conversation, without the ability to influence any application control flow. In reality, as applications get more complex, a graph will often implement a more complex flow that may use [multiple agents](./multi_agent.md) working in tandem. -### Persistence and Task Queue +### Persistence and task queue -The LangGraph Server leverages a database for [persistence](persistence.md) and a task queue. +LangGraph Server leverages a database for [persistence](persistence.md) and a task queue. Currently, only [Postgres](https://www.postgresql.org/) is supported as a database for LangGraph Server and [Redis](https://redis.io/) as the task queue. @@ -60,76 +62,7 @@ If you're deploying using [LangGraph Cloud](./langgraph_cloud.md), these compone Please review the [deployment options](./deployment_options.md) guide for more information on how these components are set up and managed. -## Application Structure - -To deploy a LangGraph Server application, you need to specify the graph(s) you want to deploy, as well as any relevant configuration settings, such as dependencies and environment variables. - -Read the [application structure](./application_structure.md) guide to learn how to structure your LangGraph application for deployment. - -## LangGraph Server API - -The LangGraph Server API allows you to create and manage [assistants](assistants.md), [threads](#threads), [runs](#runs), [cron jobs](#cron-jobs), and more. - -The [LangGraph Cloud API Reference](../cloud/reference/api/api_ref.html) provides detailed information on the API endpoints and data models. - -### Assistants - -An [Assistant](assistants.md) refers to a [graph](#graphs) plus specific [configuration](low_level.md#configuration) settings for that graph. - -You can think of an assistant as a saved configuration of an [agent](agentic_concepts.md). - -When building agents, it is fairly common to make rapid changes that *do not* alter the graph logic. For example, simply changing prompts or the LLM selection can have significant impacts on the behavior of the agents. Assistants offer an easy way to make and save these types of changes to agent configuration. - -### Threads - -A thread contains the accumulated state of a sequence of [runs](#runs). If a run is executed on a thread, then the [state](low_level.md#state) of the underlying graph of the assistant will be persisted to the thread. - -A thread's current and historical state can be retrieved. To persist state, a thread must be created prior to executing a run. - -The state of a thread at a particular point in time is called a [checkpoint](persistence.md#checkpoints). Checkpoints can be used to restore the state of a thread at a later time. - -For more on threads and checkpoints, see this section of the [LangGraph conceptual guide](low_level.md#persistence). - -The LangGraph Cloud API provides several endpoints for creating and managing threads and thread state. See the [API reference](../cloud/reference/api/api_ref.html#tag/threads) for more details. - -### Runs - -A run is an invocation of an [assistant](#assistants). Each run may have its own input, configuration, and metadata, which may affect execution and output of the underlying graph. A run can optionally be executed on a [thread](#threads). - -The LangGraph Cloud API provides several endpoints for creating and managing runs. See the [API reference](../cloud/reference/api/api_ref.html#tag/thread-runs/) for more details. - -### Store - -Store is an API for managing persistent [key-value store](./persistence.md#memory-store) that is available from any [thread](#threads). - -Stores are useful for implementing [memory](./memory.md) in your LangGraph application. - -### Cron Jobs - -There are many situations in which it is useful to run an assistant on a schedule. - -For example, say that you're building an assistant that runs daily and sends an email summary -of the day's news. You could use a cron job to run the assistant every day at 8:00 PM. - -LangGraph Cloud supports cron jobs, which run on a user-defined schedule. The user specifies a schedule, an assistant, and some input. After that, on the specified schedule, the server will: - -- Create a new thread with the specified assistant -- Send the specified input to that thread - -Note that this sends the same input to the thread every time. See the [how-to guide](../cloud/how-tos/cron_jobs.md) for creating cron jobs. - -The LangGraph Cloud API provides several endpoints for creating and managing cron jobs. See the [API reference](../cloud/reference/api/api_ref.html#tag/runscreate/POST/threads/{thread_id}/runs/crons) for more details. - -### Webhooks - -Webhooks enable event-driven communication from your LangGraph Cloud application to external services. For example, you may want to issue an update to a separate service once an API call to LangGraph Cloud has finished running. - -Many LangGraph Cloud endpoints accept a `webhook` parameter. If this parameter is specified by a an endpoint that can accept POST requests, LangGraph Cloud will send a request at the completion of a run. - -See the corresponding [how-to guide](../cloud/how-tos/webhooks.md) for more detail. - -## Related +## Learn more * LangGraph [Application Structure](./application_structure.md) guide explains how to structure your LangGraph application for deployment. -* [How-to guides for the LangGraph Platform](../how-tos/index.md). * The [LangGraph Cloud API Reference](../cloud/reference/api/api_ref.html) provides detailed information on the API endpoints and data models. diff --git a/docs/docs/concepts/langgraph_standalone_container.md b/docs/docs/concepts/langgraph_standalone_container.md index 5b6fd7324..99b895c21 100644 --- a/docs/docs/concepts/langgraph_standalone_container.md +++ b/docs/docs/concepts/langgraph_standalone_container.md @@ -11,7 +11,7 @@ To deploy a [LangGraph Server](../concepts/langgraph_server.md), follow the how- The Standalone Container deployment option is the least restrictive model for deployment. There is no [control plane](./langgraph_control_plane.md). [Data plane](./langgraph_data_plane.md) infrastructure is managed by you. -| | [Control Plane](../concepts/langgraph_control_plane.md) | [Data Plane](../concepts/langgraph_data_plane.md) | +| | [Control plane](../concepts/langgraph_control_plane.md) | [Data plane](../concepts/langgraph_data_plane.md) | |-------------------|-------------------|------------| | **What is it?** | n/a |
  • LangGraph Servers
  • Postgres, Redis, etc
| | **Where is it hosted?** | n/a | Your cloud | diff --git a/docs/docs/concepts/langgraph_studio.md b/docs/docs/concepts/langgraph_studio.md index fdfb6ff3c..fbd013dd9 100644 --- a/docs/docs/concepts/langgraph_studio.md +++ b/docs/docs/concepts/langgraph_studio.md @@ -9,10 +9,9 @@ search: - [LangGraph Platform](./langgraph_platform.md) - [LangGraph Server](./langgraph_server.md) + - [LangGraph CLI](./langgraph_cli.md) -LangGraph Studio offers a new way to develop LLM applications by providing a specialized agent IDE that enables visualization, interaction, and debugging of complex agentic applications. - -With visual graphs and the ability to edit state, you can better understand agent workflows and iterate faster. LangGraph Studio integrates with LangSmith allowing you to collaborate with teammates to debug failure modes. +LangGraph Studio is a specialized agent IDE that enables visualization, interaction, and debugging of agentic systems that implement the LangGraph Server API protocol. Studio also integrates with LangSmith to enable tracing, evaluation, and prompt engineering. ![](img/lg_studio.png) @@ -20,44 +19,17 @@ With visual graphs and the ability to edit state, you can better understand agen The key features of LangGraph Studio are: -- Visualize your graphs -- Test your graph by running it from the UI -- Debug your agent by [modifying its state and rerunning](human_in_the_loop.md) +- Visualize your graph architecture +- Run and interact with your graph in a GUI - Create and manage [assistants](assistants.md) -- View and manage [threads](persistence.md#threads) +- View and manage [threads](../cloud/concepts/threads.md) - View and manage [long term memory](memory.md) -- Add node input/outputs to [LangSmith](https://smith.langchain.com/) datasets for testing +- Debug agent state via [time travel](time-travel.md) -## Getting started -There are two ways to connect your LangGraph app with the studio: +LangGraph Studio works for graphs that are deployed on [LangGraph Platform](../cloud/quick_start.md) or for graphs that are running locally via the [LangGraph Server](../tutorials/langgraph-platform/local-server.md). -### Deployed Application -If you have deployed your LangGraph application on LangGraph Platform, you can access the studio as part of that deployment. To do so, navigate to the deployment in LangGraph Platform within the LangSmith UI and click the "LangGraph Studio" button. - -### Local Development Server - -If you have a LangGraph application that is [running locally in-memory](../tutorials/langgraph-platform/local-server.md), you can connect it to LangGraph Studio in the browser within LangSmith. - -By default, starting the local server with `langgraph dev` will run the server at `http://127.0.0.1:2024` and automatically open Studio in your browser. However, you can also manually connect to Studio by either: - -1. In LangGraph Platform, clicking the "LangGraph Studio" button and entering the server URL in the dialog that appears. - - or - -2. Navigating to the URL in your browser: - -``` -https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 -``` - -## Related - -For more information please see the following: - -- [LangGraph Studio how-to guides](../how-tos/index.md#langgraph-studio) -- [LangGraph CLI Documentation](../cloud/reference/cli.md) ## LangGraph Studio FAQs @@ -105,35 +77,6 @@ def routing_function(state: GraphState) -> Literal["node_b","node_c"]: return "node_c" ``` -### Studio Desktop FAQs - -!!! warning "Deprecation Warning" - In order to support a wider range of platforms and users, we now recommend following the above instructions to connect to LangGraph Studio using the development server instead of the desktop app. - -The LangGraph Studio Desktop App is a standalone application that allows you to connect to your LangGraph application and visualize and interact with your graph. It is available for MacOS only and requires Docker to be installed. - -#### Why is my project failing to start? - -In addition to the reasons listed above, for the desktop app there are a few more reasons that your project might fail to start: - -!!! Important "Note " - - LangGraph Studio Desktop automatically populates `LANGCHAIN_*` environment variables for license verification and tracing, regardless of the contents of the `.env` file. All other environment variables defined in `.env` will be read as normal. - -##### Docker issues - -LangGraph Studio (desktop) requires Docker Desktop version 4.24 or higher. Please make sure you have a version of Docker installed that satisfies that requirement and also make sure you have the Docker Desktop app up and running before trying to use LangGraph Studio. In addition, make sure you have docker-compose updated to version 2.22.0 or higher. - -##### Incorrect data region - -If you receive a license verification error when attempting to start the LangGraph Server, you may be logged into the incorrect LangSmith data region. Ensure that you're logged into the correct LangSmith data region and ensure that the LangSmith account has access to LangGraph platform. - -1. In the top right-hand corner, click the user icon and select `Logout`. -1. At the login screen, click the `Data Region` dropdown menu and select the appropriate data region. Then click `Login to LangSmith`. - -### How do I reload the app? - -If you would like to reload the app, don't use Command+R as you might normally do. Instead, close and reopen the app for a full refresh. ### How does automatic rebuilding work? diff --git a/docs/docs/concepts/low_level.md b/docs/docs/concepts/low_level.md index d652bed3e..852682b97 100644 --- a/docs/docs/concepts/low_level.md +++ b/docs/docs/concepts/low_level.md @@ -3,7 +3,7 @@ search: boost: 2 --- -# LangGraph Glossary +# Graph API concepts ## Graphs @@ -17,7 +17,7 @@ At its core, LangGraph models agent workflows as graphs. You define the behavior By composing `Nodes` and `Edges`, you can create complex, looping workflows that evolve the `State` over time. The real power, though, comes from how LangGraph manages that `State`. To emphasize: `Nodes` and `Edges` are nothing more than Python functions - they can contain an LLM or just good ol' Python code. -In short: _nodes do the work. edges tell what to do next_. +In short: _nodes do the work, edges tell what to do next_. LangGraph's underlying graph algorithm uses [message passing](https://en.wikipedia.org/wiki/Message_passing) to define a general program. When a Node completes its operation, it sends messages along one or more edges to other node(s). These recipient nodes then execute their functions, pass the resulting messages to the next set of nodes, and the process continues. Inspired by Google's [Pregel](https://research.google/pubs/pregel-a-system-for-large-scale-graph-processing/) system, the program proceeds in discrete "super-steps." @@ -31,7 +31,7 @@ The `StateGraph` class is the main graph class to use. This is parameterized by To build your graph, you first define the [state](#state), you then add [nodes](#nodes) and [edges](#edges), and then you compile it. What exactly is compiling your graph and why is it needed? -Compiling is a pretty simple step. It provides a few basic checks on the structure of your graph (no orphaned nodes, etc). It is also where you can specify runtime args like [checkpointers](./persistence.md) and [breakpoints](#breakpoints). You compile your graph by just calling the `.compile` method: +Compiling is a pretty simple step. It provides a few basic checks on the structure of your graph (no orphaned nodes, etc). It is also where you can specify runtime args like [checkpointers](./persistence.md) and breakpoints. You compile your graph by just calling the `.compile` method: ```python graph = graph_builder.compile(...) @@ -383,47 +383,18 @@ def my_node(state: State) -> Command[Literal["other_subgraph"]]: This is particularly useful when implementing [multi-agent handoffs](./multi_agent.md#handoffs). +Check out [this guide](../how-tos/graph-api.ipynb#navigate-to-a-node-in-a-parent-graph) for detail. + ### Using inside tools -A common use case is updating graph state from inside a tool. For example, in a customer support application you might want to look up customer information based on their account number or ID in the beginning of the conversation. To update the graph state from the tool, you can return `Command(update={"my_custom_key": "foo", "messages": [...]})` from the tool: +A common use case is updating graph state from inside a tool. For example, in a customer support application you might want to look up customer information based on their account number or ID in the beginning of the conversation. -```python -@tool -def lookup_user_info(tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig): - """Use this to look up user information to better assist them with their questions.""" - user_info = get_user_info(config.get("configurable", {}).get("user_id")) - return Command( - update={ - # update the state keys - "user_info": user_info, - # update the message history - "messages": [ToolMessage("Successfully looked up user information", tool_call_id=tool_call_id)] - } - ) -``` - -!!! important - You MUST include `messages` (or any state key used for the message history) in `Command.update` when returning `Command` from a tool and the list of messages in `messages` MUST contain a `ToolMessage`. This is necessary for the resulting message history to be valid (LLM providers require AI messages with tool calls to be followed by the tool result messages). - -If you are using tools that update state via `Command`, we recommend using prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] which automatically handles tools returning `Command` objects and propagates them to the graph state. If you're writing a custom node that calls tools, you would need to manually propagate `Command` objects returned by the tools as the update from the node. +Refer to [this guide](../how-tos/graph-api.ipynb#use-inside-tools) for detail. ### Human-in-the-loop `Command` is an important part of human-in-the-loop workflows: when using `interrupt()` to collect user input, `Command` is then used to supply the input and resume execution via `Command(resume="User input")`. Check out [this conceptual guide](./human_in_the_loop.md) for more information. -## Persistence - -LangGraph provides built-in persistence for your agent's state using [checkpointers][langgraph.checkpoint.base.BaseCheckpointSaver]. Checkpointers save snapshots of the graph state at every superstep, allowing resumption at any time. This enables features like human-in-the-loop interactions, memory management, and fault-tolerance. You can even directly manipulate a graph's state after its execution using the -appropriate `get` and `update` methods. For more details, see the [persistence conceptual guide](./persistence.md). - -## Threads - -Threads in LangGraph represent individual sessions or conversations between your graph and a user. When using checkpointing, turns in a single conversation (and even steps within a single graph execution) are organized by a unique thread ID. - -## Storage - -LangGraph provides built-in document storage through the [BaseStore][langgraph.store.base.BaseStore] interface. Unlike checkpointers, which save state by thread ID, stores use custom namespaces for organizing data. This enables cross-thread persistence, allowing agents to maintain long-term memories, learn from past interactions, and accumulate knowledge over time. Common use cases include storing user profiles, building knowledge bases, and managing global preferences across all threads. - ## Graph Migrations LangGraph can easily handle migrations of graph definitions (nodes, edges, and state) even when using a checkpointer to track state. @@ -455,7 +426,7 @@ config = {"configurable": {"llm": "anthropic"}} graph.invoke(inputs, config=config) ``` -You can then access and use this configuration inside a node: +You can then access and use this configuration inside a node or conditional edge: ```python def node_a(state, config): @@ -476,139 +447,6 @@ graph.invoke(inputs, config={"recursion_limit": 5, "configurable":{"llm": "anthr Read [this how-to](https://langchain-ai.github.io/langgraph/how-tos/recursion-limit/) to learn more about how the recursion limit works. -## `interrupt` - -Use the [interrupt](../reference/types.md/#langgraph.types.interrupt) function to **pause** the graph at specific points to collect user input. The `interrupt` function surfaces interrupt information to the client, allowing the developer to collect user input, validate the graph state, or make decisions before resuming execution. - -```python -from langgraph.types import interrupt - -def human_approval_node(state: State): - ... - answer = interrupt( - # This value will be sent to the client. - # It can be any JSON serializable value. - {"question": "is it ok to continue?"}, - ) - ... -``` - -Resuming the graph is done by passing a [`Command`](#command) object to the graph with the `resume` key set to the value returned by the `interrupt` function. - -Read more about how the `interrupt` is used for **human-in-the-loop** workflows in the [Human-in-the-loop conceptual guide](./human_in_the_loop.md). - -## Breakpoints - -Breakpoints pause graph execution at specific points and enable stepping through execution step by step. Breakpoints are powered by LangGraph's [**persistence layer**](./persistence.md), which saves the state after each graph step. Breakpoints can also be used to enable [**human-in-the-loop**](./human_in_the_loop.md) workflows, though we recommend using the [`interrupt` function](#interrupt) for this purpose. - -Read more about breakpoints in the [Breakpoints conceptual guide](./breakpoints.md). - -## Subgraphs - -A subgraph is a [graph](#graphs) that is used as a [node](#nodes) in another graph. This is nothing more than the age-old concept of encapsulation, applied to LangGraph. Some reasons for using subgraphs are: - -- building [multi-agent systems](./multi_agent.md) - -- when you want to reuse a set of nodes in multiple graphs, which maybe share some state, you can define them once in a subgraph and then use them in multiple parent graphs - -- when you want different teams to work on different parts of the graph independently, you can define each part as a subgraph, and as long as the subgraph interface (the input and output schemas) is respected, the parent graph can be built without knowing any details of the subgraph - -There are two ways to add subgraphs to a parent graph: - -- add a node with the compiled subgraph: this is useful when the parent graph and the subgraph share state keys and you don't need to transform state on the way in or out - -```python -builder.add_node("subgraph", subgraph_builder.compile()) -``` - -- add a node with a function that invokes the subgraph: this is useful when the parent graph and the subgraph have different state schemas and you need to transform state before or after calling the subgraph - -```python -subgraph = subgraph_builder.compile() - -def call_subgraph(state: State): - return subgraph.invoke({"subgraph_key": state["parent_key"]}) - -builder.add_node("subgraph", call_subgraph) -``` - -Let's take a look at examples for each. - -### As a compiled graph - -The simplest way to create subgraph nodes is by using a [compiled subgraph](#compiling-your-graph) directly. When doing so, it is **important** that the parent graph and the subgraph [state schemas](#state) share at least one key which they can use to communicate. If your graph and subgraph do not share any keys, you should write a function [invoking the subgraph](#as-a-function) instead. - -!!! Note - If you pass extra keys to the subgraph node (i.e., in addition to the shared keys), they will be ignored by the subgraph node. Similarly, if you return extra keys from the subgraph, they will be ignored by the parent graph. - -```python -from langgraph.graph import StateGraph -from typing import TypedDict - -class State(TypedDict): - foo: str - -class SubgraphState(TypedDict): - foo: str # note that this key is shared with the parent graph state - bar: str - -# Define subgraph -def subgraph_node(state: SubgraphState): - # note that this subgraph node can communicate with the parent graph via the shared "foo" key - return {"foo": state["foo"] + "bar"} - -subgraph_builder = StateGraph(SubgraphState) -subgraph_builder.add_node(subgraph_node) -... -subgraph = subgraph_builder.compile() - -# Define parent graph -builder = StateGraph(State) -builder.add_node("subgraph", subgraph) -... -graph = builder.compile() -``` - -### As a function - -You might want to define a subgraph with a completely different schema. In this case, you can create a node function that invokes the subgraph. This function will need to [transform](../how-tos/subgraph-transform-state.ipynb) the input (parent) state to the subgraph state before invoking the subgraph, and transform the results back to the parent state before returning the state update from the node. - -```python -class State(TypedDict): - foo: str - -class SubgraphState(TypedDict): - # note that none of these keys are shared with the parent graph state - bar: str - baz: str - -# Define subgraph -def subgraph_node(state: SubgraphState): - return {"bar": state["bar"] + "baz"} - -subgraph_builder = StateGraph(SubgraphState) -subgraph_builder.add_node(subgraph_node) -... -subgraph = subgraph_builder.compile() - -# Define parent graph -def node(state: State): - # transform the state to the subgraph state - response = subgraph.invoke({"bar": state["foo"]}) - # transform response back to the parent state - return {"foo": response["bar"]} - -builder = StateGraph(State) -# note that we are using `node` function instead of a compiled subgraph -builder.add_node(node) -... -graph = builder.compile() -``` - ## Visualization It's often nice to be able to visualize graphs, especially as they get more complex. LangGraph comes with several built-in ways to visualize graphs. See [this how-to guide](../how-tos/visualization.ipynb) for more info. - -## Streaming - -LangGraph is built with first class support for streaming, including streaming updates from graph nodes during the execution, streaming tokens from LLM calls and more. See this [conceptual guide](./streaming.md) for more information. diff --git a/docs/docs/concepts/multi_agent.md b/docs/docs/concepts/multi_agent.md index 401fab8be..6f7cc5f43 100644 --- a/docs/docs/concepts/multi_agent.md +++ b/docs/docs/concepts/multi_agent.md @@ -3,7 +3,7 @@ search: boost: 2 --- -# Multi-agent Systems +# Multi-agent systems An [agent](./agentic_concepts.md#agent-architectures) is _a system that uses an LLM to decide the control flow of an application_. As you develop these systems, they might grow more complex over time, making them harder to manage and scale. For example, you might run into the following problems: @@ -33,7 +33,7 @@ There are several ways to connect agents in a multi-agent system: ### Handoffs -In multi-agent architectures, agents can be represented as graph nodes. Each agent node executes its step(s) and decides whether to finish execution or route to another agent, including potentially routing to itself (e.g., running in a loop). A common pattern in multi-agent interactions is handoffs, where one agent hands off control to another. Handoffs allow you to specify: +In multi-agent architectures, agents can be represented as graph nodes. Each agent node executes its step(s) and decides whether to finish execution or route to another agent, including potentially routing to itself (e.g., running in a loop). A common pattern in multi-agent interactions is **handoffs**, where one agent *hands off* control to another. Handoffs allow you to specify: - __destination__: target agent to navigate to (e.g., name of the node to go to) - __payload__: [information to pass to that agent](#communication-between-agents) (e.g., state update) @@ -82,14 +82,20 @@ def some_node_inside_alice(state): #### Handoffs as tools -One of the most common agent types is a ReAct-style tool-calling agents. For those types of agents, a common pattern is wrapping a handoff in a tool call, e.g.: +One of the most common agent types is a [tool-calling agent](../agents/overview.md). For those types of agents, a common pattern is wrapping a handoff in a tool call, e.g.: ```python -def transfer_to_bob(state): +from langchain_core.tools import tool + +def transfer_to_bob(): """Transfer to bob.""" return Command( + # name of the agent (node) to go to goto="bob", + # data to send to the agent update={"my_state_key": "my_state_value"}, + # indicate to LangGraph that we need to navigate to + # agent node in a parent graph graph=Command.PARENT, ) ``` @@ -342,45 +348,70 @@ builder.add_edge(START, "agent_1") builder.add_edge("agent_1", "agent_2") ``` -## Communication between agents +## Communication and state management -The most important thing when building multi-agent systems is figuring out how the agents communicate. There are a few different considerations: +The most important thing when building multi-agent systems is figuring out how the agents communicate. -- Do agents communicate [**via graph state or via tool calls**](#graph-state-vs-tool-calls)? -- What if two agents have [**different state schemas**](#different-state-schemas)? -- How to communicate over a [**shared message list**](#shared-message-list)? +A common, generic way for agents to communicate is via a list of messages. This opens up the following questions: -### Graph state vs tool calls +- Do agents communicate [**via handoffs or via tool calls**](#handoffs-vs-tool-calls)? +- What messages are [**passed from one agent to the next**](#message-passing-between-agents)? +- How are [**handoffs represented in the list of messages**](#representing-handoffs-in-message-history)? +- How do you [**manage state for subagents**](#state-management-for-subagents)? -What is the "payload" that is being passed around between agents? In most of the architectures discussed above the agents communicate via the [graph state](./low_level.md#state). In the case of the [supervisor with tool-calling](#supervisor-tool-calling), the payloads are tool call arguments. +Additionally, if you are dealing with more complex agents or wish to keep individual agent state separate from the multi-agent system state, you may need to use [**different state schemas**](#using-different-state-schemas). + +### Handoffs vs tool calls + +What is the "payload" that is being passed around between agents? In most of the architectures discussed above, the agents communicate via [handoffs](#handoffs) and pass the [graph state](./low_level.md#state) as part of the handoff payload. Specifically, agents pass around lists of messages as part of the graph state. In the case of the [supervisor with tool-calling](#supervisor-tool-calling), the payloads are tool call arguments. ![](./img/multi_agent/request.png) -#### Graph state +### Message passing between agents -To communicate via graph state, individual agents need to be defined as [graph nodes](./low_level.md#nodes). These can be added as functions or as entire [subgraphs](./low_level.md#subgraphs). At each step of the graph execution, agent node receives the current state of the graph, executes the agent code and then passes the updated state to the next nodes. - -Typically agent nodes share a single [state schema](./low_level.md#schema). However, you might want to design agent nodes with [different state schemas](#different-state-schemas). - -### Different state schemas - -An agent might need to have a different state schema from the rest of the agents. For example, a search agent might only need to keep track of queries and retrieved documents. There are two ways to achieve this in LangGraph: - -- Define [subgraph](./low_level.md#subgraphs) agents with a separate state schema. If there are no shared state keys (channels) between the subgraph and the parent graph, it’s important to [add input / output transformations](https://langchain-ai.github.io/langgraph/how-tos/subgraph-transform-state/) so that the parent graph knows how to communicate with the subgraphs. -- Define agent node functions with a [private input state schema](https://langchain-ai.github.io/langgraph/how-tos/pass_private_state/) that is distinct from the overall graph state schema. This allows passing information that is only needed for executing that particular agent. - -### Shared message list - -The most common way for the agents to communicate is via a shared state channel, typically a list of messages. This assumes that there is always at least a single channel (key) in the state that is shared by the agents. When communicating via a shared message list there is an additional consideration: should the agents [share the full history](#share-full-history) of their thought process or only [the final result](#share-final-result)? +The most common way for agents to communicate is via a shared state channel, typically a list of messages. This assumes that there is always at least a single channel (key) in the state that is shared by the agents (e.g., `messages`). When communicating via a shared message list, there is an additional consideration: should the agents [share the full history](#sharing-full-thought-process) of their thought process or only [the final result](#sharing-only-final-results)? ![](./img/multi_agent/response.png) -#### Share full history +#### Sharing full thought process -Agents can **share the full history** of their thought process (i.e. "scratchpad") with all other agents. This "scratchpad" would typically look like a [list of messages](./low_level.md#why-use-messages). The benefit of sharing full thought process is that it might help other agents make better decisions and improve reasoning ability for the system as a whole. The downside is that as the number of agents and their complexity grows, the "scratchpad" will grow quickly and might require additional strategies for [memory management](./memory.md/#managing-long-conversation-history). +Agents can **share the full history** of their thought process (i.e., "scratchpad") with all other agents. This "scratchpad" would typically look like a [list of messages](./low_level.md#why-use-messages). The benefit of sharing the full thought process is that it might help other agents make better decisions and improve reasoning ability for the system as a whole. The downside is that as the number of agents and their complexity grows, the "scratchpad" will grow quickly and might require additional strategies for [memory management](./memory.md/#managing-long-conversation-history). -#### Share final result +#### Sharing only final results -Agents can have their own private "scratchpad" and only **share the final result** with the rest of the agents. This approach might work better for systems with many agents or agents that are more complex. In this case, you would need to define agents with [different state schemas](#different-state-schemas) +Agents can have their own private "scratchpad" and only **share the final result** with the rest of the agents. This approach might work better for systems with many agents or agents that are more complex. In this case, you would need to define agents with [different state schemas](#using-different-state-schemas). -For agents called as tools, the supervisor determines the inputs based on the tool schema. Additionally, LangGraph allows [passing state](https://langchain-ai.github.io/langgraph/how-tos/pass-run-time-values-to-tools/#pass-graph-state-to-tools) to individual tools at runtime, so subordinate agents can access parent state, if needed. +For agents called as tools, the supervisor determines the inputs based on the tool schema. Additionally, LangGraph allows [passing state](../how-tos/tool-calling.ipynb#read-state) to individual tools at runtime, so subordinate agents can access parent state, if needed. + +#### Indicating agent name in messages + +It can be helpful to indicate which agent a particular AI message is from, especially for long message histories. Some LLM providers (like OpenAI) support adding a `name` parameter to messages — you can use that to attach the agent name to the message. If that is not supported, you can consider manually injecting the agent name into the message content, e.g., `alicemessage from alice`. + +### Representing handoffs in message history + +Handoffs are typically done via the LLM calling a dedicated [handoff tool](#handoffs-as-tools). This is represented as an [AI message](https://python.langchain.com/docs/concepts/messages/#aimessage) with tool calls that is passed to the next agent (LLM). Most LLM providers don't support receiving AI messages with tool calls **without** corresponding tool messages. + +You therefore have two options: + +1. Add an extra [tool message](https://python.langchain.com/docs/concepts/messages/#toolmessage) to the message list, e.g., "Successfully transferred to agent X" +2. Remove the AI message with the tool calls + +In practice, we see that most developers opt for option (1). + +### State management for subagents + +A common practice is to have multiple agents communicating on a shared message list, but only [adding their final messages to the list](#sharing-only-final-results). This means that any intermediate messages (e.g., tool calls) are not saved in this list. + +What if you __do__ want to save these messages so that if this particular subagent is invoked in the future you can pass those back in? + +There are two high-level approaches to achieve that: + +1. Store these messages in the shared message list, but filter the list before passing it to the subagent LLM. For example, you can choose to filter out all tool calls from **other** agents. +2. Store a separate message list for each agent (e.g., `alice_messages`) in the subagent's graph state. This would be their "view" of what the message history looks like. + +### Using different state schemas + +An agent might need to have a different state schema from the rest of the agents. For example, a search agent might only need to keep track of queries and retrieved documents. There are two ways to achieve this in LangGraph: + +- Define [subgraph](./low_level.md#subgraphs) agents with a separate state schema. If there are no shared state keys (channels) between the subgraph and the parent graph, it’s important to [add input / output transformations](../how-tos/subgraph.ipynb#different-state-schemas) so that the parent graph knows how to communicate with the subgraphs. +- Define agent node functions with a [private input state schema](../how-tos/graph-api.ipynb/#pass-private-state-between-nodes) that is distinct from the overall graph state schema. This allows passing information that is only needed for executing that particular agent. \ No newline at end of file diff --git a/docs/docs/concepts/persistence.md b/docs/docs/concepts/persistence.md index 28ef4a96b..d1381b5c5 100644 --- a/docs/docs/concepts/persistence.md +++ b/docs/docs/concepts/persistence.md @@ -232,7 +232,7 @@ But, what if we want to retain some information *across threads*? Consider the c With checkpointers alone, we cannot share information across threads. This motivates the need for the [`Store`](../reference/store.md#langgraph.store.base.BaseStore) interface. As an illustration, we can define an `InMemoryStore` to store information about a user across threads. We simply compile our graph with a checkpointer, as before, and with our new `in_memory_store` variable. -!!! info "LangGraph API handles stores automatically" +!!! info "LangGraph API handles stores automatically" When using the LangGraph API, you don't need to implement or configure stores manually. The API handles all storage infrastructure for you behind the scenes. diff --git a/docs/docs/concepts/plans.md b/docs/docs/concepts/plans.md index 883477155..2831fd5df 100644 --- a/docs/docs/concepts/plans.md +++ b/docs/docs/concepts/plans.md @@ -10,9 +10,9 @@ search: LangGraph Platform is a commercial solution for deploying agentic applications in production. There are three different plans for using it. -- **Developer**: All [LangSmith](https://smith.langchain.com/) users have access to this plan. You can sign up for this plan simply by creating a LangSmith account. This gives you access to the [Self-Hosted Lite](./deployment_options.md#self-hosted-lite) deployment option. +- **Developer**: All [LangSmith](https://smith.langchain.com/) users have access to this plan. You can sign up for this plan simply by creating a LangSmith account. This gives you access to the [Self-Hosted Lite](./deployment_options.md) deployment option. - **Plus**: All [LangSmith](https://smith.langchain.com/) users with a [Plus account](https://docs.smith.langchain.com/administration/pricing) have access to this plan. You can sign up for this plan simply by upgrading your LangSmith account to the Plus plan type. This gives you access to the [Cloud](./deployment_options.md#cloud-saas) deployment option. -- **Enterprise**: This is separate from LangSmith plans. You can sign up for this plan by contacting sales@langchain.dev. This gives you access to all deployment options: [Cloud](./deployment_options.md#cloud-saas), [Bring-Your-Own-Cloud](./deployment_options.md#bring-your-own-cloud), and [Self Hosted Enterprise](./deployment_options.md#self-hosted-enterprise) +- **Enterprise**: This is separate from LangSmith plans. You can sign up for this plan by contacting sales@langchain.dev. This gives you access to all [deployment options](./deployment_options.md). ## Plan Details @@ -20,7 +20,7 @@ There are three different plans for using it. | | Developer | Plus | Enterprise | |------------------------------------------------------------------|---------------------------------------------|-------------------------------------------------------|-----------------------------------------------------| | Deployment Options | Self-Hosted Lite | Cloud | Self-Hosted Enterprise, Cloud, Bring-Your-Own-Cloud | -| Usage | Free, limited to 1M nodes executed per year | Free while in Beta, will be charged per node executed | Custom | +| Usage | Free, limited to 1M nodes executed per year | Free while in Beta, will be charged per node executed | Custom | | APIs for retrieving and updating state and conversational history | ✅ | ✅ | ✅ | | APIs for retrieving and updating long-term memory | ✅ | ✅ | ✅ | | Horizontally scalable task queues and servers | ✅ | ✅ | ✅ | diff --git a/docs/docs/concepts/platform_architecture.md b/docs/docs/concepts/platform_architecture.md deleted file mode 100644 index 3b7e9f95d..000000000 --- a/docs/docs/concepts/platform_architecture.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -search: - boost: 2 ---- - -# LangGraph Platform Architecture - -![](img/langgraph_platform_deployment_architecture.png) - -## How we use Postgres - -Postgres is the persistence layer for all user, run, and long-term memory data in LGP. This stores both checkpoints (see more info [here](./persistence.md)), server resources (threads, runs, assistants and crons), as well as items saved in the long-term memory store (see more info [here](./persistence.md#memory-store)). - -## How we use Redis - -Redis is used in each LGP deployment as a way for server and queue workers to communicate, and to store ephemeral metadata, more details on both below. No user/run data is stored in Redis. - -### Communication - -All runs in LGP are executed by the pool of background workers that are part of each deployment. In order to enable some features for those runs (such as cancellation and output streaming) we need a channel for two-way communication between the server and the worker handling a particular run. We use Redis to organize that communication. - -1. A Redis list is used as a mechanism to wake up a worker as soon as a new run is created. Only a sentinel value is stored in this list, no actual run info. The run information is then retrieved from Postgres by the worker. -2. A combination of a Redis string and Redis PubSub channel is used for the server to communicate a run cancellation request to the appropriate worker. -3. A Redis PubSub channel is used by the worker to broadcast streaming output from an agent while the run is being handled. Any open `/stream` request in the server will subscribe to that channel and forward any events to the response as they arrive. No events are stored in Redis at any time. - -### Ephemeral metadata - -Runs in an LGP deployment may be retried for specific failures (currently only for transient Postgres errors encountered during the run). In order to limit the number of retries (currently limited to 3 attempts per run) we record the attempt number in a Redis string when is picked up. This contains no run-specific info other than its ID, and expires after a short delay. diff --git a/docs/docs/concepts/pregel.md b/docs/docs/concepts/pregel.md index 039ba1226..9ff2a855e 100644 --- a/docs/docs/concepts/pregel.md +++ b/docs/docs/concepts/pregel.md @@ -33,14 +33,8 @@ An **actor** is a `PregelNode`. It subscribes to channels, reads data from them, Channels are used to communicate between actors (PregelNodes). Each channel has a value type, an update type, and an update function – which takes a sequence of updates and modifies the stored value. Channels can be used to send data from one chain to another, or to send data from a chain to itself in a future step. LangGraph provides a number of built-in channels: -### Basic channels: LastValue and Topic - - [LastValue][langgraph.channels.LastValue]: The default channel, stores the last value sent to the channel, useful for input and output values, or for sending data from one step to the next. - [Topic][langgraph.channels.Topic]: A configurable PubSub Topic, useful for sending multiple values between **actors**, or for accumulating output. Can be configured to deduplicate values or to accumulate values over the course of multiple steps. - -### Advanced channels: Context and BinaryOperatorAggregate - -- `Context`: exposes the value of a context manager, managing its lifecycle. Useful for accessing external resources that require setup and/or teardown; e.g., `client = Context(httpx.Client)`. - [BinaryOperatorAggregate][langgraph.channels.BinaryOperatorAggregate]: stores a persistent value, updated by applying a binary operator to the current value and each update sent to the channel, useful for computing aggregates over multiple steps; e.g.,`total = BinaryOperatorAggregate(int, operator.add)` ## Examples diff --git a/docs/docs/concepts/scalability_and_resilience.md b/docs/docs/concepts/scalability_and_resilience.md index 089f63e34..76a035bb8 100644 --- a/docs/docs/concepts/scalability_and_resilience.md +++ b/docs/docs/concepts/scalability_and_resilience.md @@ -3,7 +3,7 @@ search: boost: 2 --- -# LangGraph Platform: Scalability & Resilience +# Scalability & Resilience LangGraph Platform is designed to scale horizontally with your workload. Each instance of the service is stateless, and keeps no resources in memory. The service is designed to gracefully handle new instances being added or removed, including hard shutdown cases. @@ -25,16 +25,16 @@ When a graceful shutdown request is received (SIGINT) an instance enters shutdow - gives any in-progress runs a limited number of seconds to finish (if not finished it will be put back in the queue) - stops the instance from picking up more runs from the queue -If a hard shutdown occurs, eg. due to a server crash, or an infra failure, any runs that were in progress will be picked up by a periodic sweeper task that looks for in-progress runs that have breached their heartbeat window, which will put them back in the queue for another instance to pick them up. +If a hard shutdown occurs due to a server crash or an infrastructure failure, any runs that were in progress will be picked up by a internal sweeper task that looks for in-progress runs that have breached their heartbeat window. The sweeper runs every 2 minutes and will put the runs back in the queue for another instance to pick them up. ## Postgres resilience -For deployment modalities where we manage the Postgres database we have periodic backups, continuously replicated standby replicas for automatic failover. Optionally, on request, we can also setup read replicas as well as other advanced failover capabilities. +For deployment modalities where we manage the Postgres database, we have periodic backups and continuously replicated standby replicas for automatic failover. This Postgres configuration is available in the [Cloud SaaS deployment option](../concepts/langgraph_cloud.md) for [`Production` deployment types](../concepts/langgraph_control_plane.md#deployment-types) only. -All communication with Postgres implements retries for retry-able errors. If Postgres is momentarily unavailable, such as during a database restart, most/all traffic should continue to succeed. Prolonged failure of the Postgres instance will switch traffic to the failover replica. If the failover replica also fails before the primary is brought back online the service would become unavailable. +All communication with Postgres implements retries for retry-able errors. If Postgres is momentarily unavailable, such as during a database restart, most/all traffic should continue to succeed. Prolonged failure of Postgres will render the LangGraph Server unavailable. ## Redis resilience -All data that requires durable storage is stored in Postgres, not Redis. Redis is used only for ephemeral metadata, and communication between instances. Refer to the [architecture](./platform_architecture.md) page for more details on how we use Redis. Therefore we place no durability requirements on Redis. +All data that requires durable storage is stored in Postgres, not Redis. Redis is used only for ephemeral metadata, and communication between instances. Therefore we place no durability requirements on Redis. -All communication with Redis implements retries for retry-able errors. If Redis is momentarily unavailable, such as during a database restart, most/all traffic should continue to succeed. Prolonged failure of Redis will render the LGP service unavailable. +All communication with Redis implements retries for retry-able errors. If Redis is momentarily unavailable, such as during a database restart, most/all traffic should continue to succeed. Prolonged failure of Redis will render the LangGraph Server unavailable. diff --git a/docs/docs/concepts/sdk.md b/docs/docs/concepts/sdk.md index f97699bb7..221fcccde 100644 --- a/docs/docs/concepts/sdk.md +++ b/docs/docs/concepts/sdk.md @@ -5,15 +5,15 @@ search: # LangGraph SDK -!!! info "Prerequisites" - - [LangGraph Platform](./langgraph_platform.md) - - [LangGraph Server](./langgraph_server.md) +LangGraph Platform provides both a Python SDK for interacting with [LangGraph Server](./langgraph_server.md). -The LangGraph Platform provides both a Python and JS SDK for interacting with the [LangGraph Server API](./langgraph_server.md). +!!! tip "Python SDK reference" + + For detailed information about the Python SDK, see [Python SDK reference docs](../cloud/reference/sdk/python_sdk_ref.md). ## Installation -You can install the packages using the appropriate package manager for your language. +You can install the packages using the appropriate package manager for your language: === "Python" ```bash @@ -25,25 +25,9 @@ You can install the packages using the appropriate package manager for your lang yarn add @langchain/langgraph-sdk ``` +## Python sync vs. async -## API Reference - -You can find the API reference for the SDKs here: - -- [Python SDK Reference](../cloud/reference/sdk/python_sdk_ref.md) -- [JS/TS SDK Reference](../cloud/reference/sdk/js_ts_sdk_ref.md) - -## Python Sync vs. Async - -The Python SDK provides both synchronous (`get_sync_client`) and asynchronous (`get_client`) clients for interacting with the LangGraph Server API. - -=== "Async" - ```python - from langgraph_sdk import get_client - - client = get_client(url=..., api_key=...) - await client.assistants.search() - ``` +The Python SDK provides both synchronous (`get_sync_client`) and asynchronous (`get_client`) clients for interacting with LangGraph Server: === "Sync" @@ -54,8 +38,17 @@ The Python SDK provides both synchronous (`get_sync_client`) and asynchronous (` client.assistants.search() ``` -## Related +=== "Async" + ```python + from langgraph_sdk import get_client + + client = get_client(url=..., api_key=...) + await client.assistants.search() + ``` + + +## Learn more -- [LangGraph CLI API Reference](../cloud/reference/cli.md) - [Python SDK Reference](../cloud/reference/sdk/python_sdk_ref.md) +- [LangGraph CLI API Reference](../cloud/reference/cli.md) - [JS/TS SDK Reference](../cloud/reference/sdk/js_ts_sdk_ref.md) \ No newline at end of file diff --git a/docs/docs/concepts/self_hosted.md b/docs/docs/concepts/self_hosted.md deleted file mode 100644 index e6338e267..000000000 --- a/docs/docs/concepts/self_hosted.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -search: - boost: 2 ---- - -# Self-Hosted - -!!! note Prerequisites - - - [LangGraph Platform](./langgraph_platform.md) - - [Deployment Options](./deployment_options.md) - -## Versions - -There are two versions of the self-hosted deployment: [Self-Hosted Data Plane](./deployment_options.md#self-hosted-data-plane) and [Self-Hosted Control Plane](./deployment_options.md#self-hosted-control-plane). - -### Self-Hosted Data Plane - -The [Self-Hosted Data Plane](./langgraph_self_hosted_data_plane.md) deployment option is a "hybrid" model for deployment where we manage the [control plane](./langgraph_control_plane.md) in our cloud and you manage the [data plane](./langgraph_data_plane.md) in your cloud. This option provides a way to securely manage your data plane infrastructure, while offloading control plane management to us. - -When using the Self-Hosted Data Plane version, you authenticate with a [LangSmith](https://smith.langchain.com/) API key. - -### Self-Hosted Control Plane - -The [Self-Hosted Control Plane](./langgraph_self_hosted_control_plane.md) deployment option is a fully self-hosted model for deployment where you manage the [control plane](./langgraph_control_plane.md) and [data plane](./langgraph_data_plane.md) in your cloud. This option give you full control and responsibility of the control plane and data plane infrastructure. - -## Requirements - -- You use `langgraph-cli` and/or [LangGraph Studio](./langgraph_studio.md) app to test graph locally. -- You use `langgraph build` command to build image. - -## How it works - -- Deploy Redis and Postgres instances on your own infrastructure. -- Build the docker image for [LangGraph Server](./langgraph_server.md) using the [LangGraph CLI](./langgraph_cli.md). -- Deploy a web server that will run the docker image and pass in the necessary environment variables. - -!!! warning "Note" - - The LangGraph Platform Deployments view is optionally available for Self-Hosted LangGraph deployments. With one click, self-hosted LangGraph deployments can be deployed in the same Kubernetes cluster where a self-hosted LangSmith instance is deployed. - -For step-by-step instructions, see [How to set up a self-hosted deployment of LangGraph](../how-tos/deploy-self-hosted.md). - -## Helm Chart - -If you would like to deploy LangGraph Cloud on Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md). - -## Related - -- [How to set up a self-hosted deployment of LangGraph](../how-tos/deploy-self-hosted.md). diff --git a/docs/docs/concepts/streaming.md b/docs/docs/concepts/streaming.md index be1a0eeb6..71bcf4f0a 100644 --- a/docs/docs/concepts/streaming.md +++ b/docs/docs/concepts/streaming.md @@ -1,66 +1,23 @@ --- search: - boost: 2 +boost: 2 --- # Streaming -Building a responsive app for end-users? Real-time updates are key to keeping users engaged as your app progresses. +LangGraph implements a streaming system to surface real-time updates, allowing for responsive and transparent user experiences. -There are three main types of data you’ll want to stream: +LangGraph’s streaming system lets you surface live feedback from graph runs to your app. +There are three main categories of data you can stream: -1. Workflow progress (e.g., get state updates after each graph node is executed). -2. LLM tokens as they’re generated. -3. Custom updates (e.g., "Fetched 10/100 records"). +1. **Workflow progress** — get state updates after each graph node is executed. +2. **LLM tokens** — stream language model tokens as they’re generated. +3. **Custom updates** — emit user-defined signals (e.g., “Fetched 10/100 records”). -## Streaming graph outputs (`.stream` and `.astream`) +## What’s possible with LangGraph streaming -`.stream` and `.astream` are sync and async methods for streaming back outputs from a graph run. -There are several different modes you can specify when calling these methods (e.g. `graph.stream(..., mode="...")): - -- [`"values"`](../how-tos/streaming.ipynb#values): This streams the full value of the state after each step of the graph. -- [`"updates"`](../how-tos/streaming.ipynb#updates): This streams the updates to the state after each step of the graph. If multiple updates are made in the same step (e.g. multiple nodes are run) then those updates are streamed separately. -- [`"custom"`](../how-tos/streaming.ipynb#custom): This streams custom data from inside your graph nodes. -- [`"messages"`](../how-tos/streaming-tokens.ipynb): This streams LLM tokens and metadata for the graph node where LLM is invoked. -- [`"debug"`](../how-tos/streaming.ipynb#debug): This streams as much information as possible throughout the execution of the graph. - -You can also specify multiple streaming modes at the same time by passing them as a list. When you do this, the streamed outputs will be tuples `(stream_mode, data)`. For example: - -```python -graph.stream(..., stream_mode=["updates", "messages"]) -``` - -``` -... -('messages', (AIMessageChunk(content='Hi'), {'langgraph_step': 3, 'langgraph_node': 'agent', ...})) -... -('updates', {'agent': {'messages': [AIMessage(content="Hi, how can I help you?")]}}) -``` - -The below visualization shows the difference between the `values` and `updates` modes: - -![values vs updates](../static/values_vs_updates.png) - - -## LangGraph Platform - -Streaming is critical for making LLM applications feel responsive to end users. When creating a streaming run, the streaming mode determines what data is streamed back to the API client. LangGraph Platform supports five streaming modes: - -- `values`: Stream the full state of the graph after each [super-step](https://langchain-ai.github.io/langgraph/concepts/low_level/#graphs) is executed. See the [how-to guide](../cloud/how-tos/stream_values.md) for streaming values. -- `messages-tuple`: Stream LLM tokens for any messages generated inside a node. This mode is primarily meant for powering chat applications. See the [how-to guide](../cloud/how-tos/stream_messages.md) for streaming messages. -- `updates`: Streams updates to the state of the graph after each node is executed. See the [how-to guide](../cloud/how-tos/stream_updates.md) for streaming updates. -- `debug`: Stream debug events throughout graph execution. See the [how-to guide](../cloud/how-tos/stream_debug.md) for streaming debug events. -- `events`: Stream all events (including the state of the graph) that occur during graph execution. See the [how-to guide](../cloud/how-tos/stream_events.md) for streaming events. This mode is only useful for users migrating large LCEL applications to LangGraph. Generally, this mode is not necessary for most applications. - -You can also specify multiple streaming modes at the same time. See the [how-to guide](../cloud/how-tos/stream_multiple.md) for configuring multiple streaming modes at the same time. - -See the [API reference](../cloud/reference/api/api_ref.html#tag/threads-runs/POST/threads/{thread_id}/runs/stream) for how to create streaming runs. - -Streaming modes `values`, `updates`, `messages-tuple` and `debug` are very similar to modes available in the LangGraph library - for a deeper conceptual explanation of those, you can see the [previous section](#streaming-graph-outputs-stream-and-astream). - -Streaming mode `events` is the same as using `.astream_events` in the LangGraph library - for a deeper conceptual explanation of this, you can see the [previous section](#streaming-graph-outputs-stream-and-astream). - -All events emitted have two attributes: - -- `event`: This is the name of the event -- `data`: This is data associated with the event \ No newline at end of file +- [**Stream LLM tokens**](../how-tos/streaming.md#llm-tokens-messages) — capture token streams from anywhere: inside nodes, subgraphs, or tools. +- [**Emit progress notifications from tools**](../how-tos/streaming.md#stream-custom-data) — send custom updates or progress signals directly from tool functions. +- [**Stream from subgraphs**](../how-tos/streaming.md#subgraphs) — include outputs from both the parent graph and any nested subgraphs. +- [**Use any LLM**](../how-tos/streaming.md#use-with-any-llm) — stream tokens from any LLM, even if it's not a LangChain model using the `custom` streaming mode. +- [**Use multiple streaming modes**](../how-tos/streaming.md#stream-multiple-modes) — choose from `values` (full state), `updates` (state deltas), `messages` (LLM tokens + metadata), `custom` (arbitrary user data), or `debug` (detailed traces). \ No newline at end of file diff --git a/docs/docs/concepts/subgraphs.md b/docs/docs/concepts/subgraphs.md new file mode 100644 index 000000000..092cb9bb0 --- /dev/null +++ b/docs/docs/concepts/subgraphs.md @@ -0,0 +1,81 @@ +# Subgraphs + +A subgraph is a [graph](./low_level.md#graphs) that is used as a [node](./low_level.md#nodes) in another graph — this is the concept of encapsulation applied to LangGraph. Subgraphs allow you to build complex systems with multiple components that are themselves graphs. + +![Subgraph](./img/subgraph.png) + +Some reasons for using subgraphs are: + +- building [multi-agent systems](./multi_agent.md) +- when you want to reuse a set of nodes in multiple graphs +- when you want different teams to work on different parts of the graph independently, you can define each part as a subgraph, and as long as the subgraph interface (the input and output schemas) is respected, the parent graph can be built without knowing any details of the subgraph + +The main question when adding subgraphs is how the parent graph and subgraph communicate, i.e. how they pass the [state](./low_level.md#state) between each other during the graph execution. There are two scenarios: + +* parent and subgraph have **shared state keys** in their state [schemas](./low_level.md#state). In this case, you can [include the subgraph as a node in the parent graph](../how-tos/subgraph.ipynb#shared-state-schemas) + + ```python + from langgraph.graph import StateGraph, MessagesState, START + + # Subgraph + + def call_model(state: MessagesState): + response = model.invoke(state["messages"]) + return {"messages": response} + + subgraph_builder = StateGraph(State) + subgraph_builder.add_node(call_model) + ... + # highlight-next-line + subgraph = subgraph_builder.compile() + + # Parent graph + + builder = StateGraph(State) + # highlight-next-line + builder.add_node("subgraph_node", subgraph) + builder.add_edge(START, "subgraph_node") + graph = builder.compile() + ... + graph.invoke({"messages": [{"role": "user", "content": "hi!"}]}) + ``` + +* parent graph and subgraph have **different schemas** (no shared state keys in their state [schemas](./low_level.md#state)). In this case, you have to [call the subgraph from inside a node in the parent graph](../how-tos/subgraph.ipynb#different-state-schemas): this is useful when the parent graph and the subgraph have different state schemas and you need to transform state before or after calling the subgraph + + ```python + from typing_extensions import TypedDict, Annotated + from langchain_core.messages import AnyMessage + from langgraph.graph import StateGraph, MessagesState, START + from langgraph.graph.message import add_messages + + class SubgraphMessagesState(TypedDict): + # highlight-next-line + subgraph_messages: Annotated[list[AnyMessage], add_messages] + + # Subgraph + + # highlight-next-line + def call_model(state: SubgraphMessagesState): + response = model.invoke(state["subgraph_messages"]) + return {"subgraph_messages": response} + + subgraph_builder = StateGraph(State) + subgraph_builder.add_node(call_model) + ... + # highlight-next-line + subgraph = subgraph_builder.compile() + + # Parent graph + + def call_subgraph(state: MessagesState): + response = subgraph.invoke({"subgraph_messages": state["messages"]}) + return {"messages": response["subgraph_messages"]} + + builder = StateGraph(State) + # highlight-next-line + builder.add_node("subgraph_node", call_subgraph) + builder.add_edge(START, "subgraph_node") + graph = builder.compile() + ... + graph.invoke({"messages": [{"role": "user", "content": "hi!"}]}) + ``` diff --git a/docs/docs/concepts/template_applications.md b/docs/docs/concepts/template_applications.md index c0518912d..1f6ede360 100644 --- a/docs/docs/concepts/template_applications.md +++ b/docs/docs/concepts/template_applications.md @@ -16,9 +16,23 @@ You can create an application from a template using the LangGraph CLI. ## Install the LangGraph CLI -```bash -pip install "langgraph-cli[inmem]" --upgrade -``` +=== "Python" + + ```bash + pip install "langgraph-cli[inmem]" --upgrade + ``` + + Or via [`uv`](https://docs.astral.sh/uv/getting-started/installation/) (recommended): + + ```bash + uvx --from "langgraph-cli[inmem]" langgraph dev --help + ``` + +=== "JS" + + ```bash + npx @langchain/langgraph-cli --help + ``` ## Available Templates @@ -35,9 +49,23 @@ pip install "langgraph-cli[inmem]" --upgrade To create a new app from a template, use the `langgraph new` command. -```bash -langgraph new -``` +=== "Python" + + ```bash + langgraph new + ``` + + Or via [`uv`](https://docs.astral.sh/uv/getting-started/installation/) (recommended): + + ```bash + uvx --from "langgraph-cli[inmem]" langgraph new + ``` + +=== "JS" + + ```bash + npx @langchain/langgraph-cli new + ``` ## Next Steps @@ -45,23 +73,28 @@ Review the `README.md` file in the root of your new LangGraph app for more infor After configuring the app properly and adding your API keys, you can start the app using the LangGraph CLI: -```bash -langgraph dev -``` +=== "Python" + + ```bash + langgraph dev + ``` + + Or via [`uv`](https://docs.astral.sh/uv/getting-started/installation/) (recommended): + + ```bash + uvx --from "langgraph-cli[inmem]" --with-editable . langgraph dev + ``` + + ??? info "Missing Local Package?" + If you are not using `uv` and run into a "`ModuleNotFoundError`" or "`ImportError`", even after installing the local package (`pip install -e .`), it is likely the case that you need to install the CLI into your local virtual environment to make the CLI "aware" of the local package. You can do this by running `python -m pip install "langgraph-cli[inmem]"` and re-activating your virtual environment before running `langgraph dev`. + +=== "JS" + + ```bash + npx @langchain/langgraph-cli dev + ``` See the following guides for more information on how to deploy your app: - **[Launch Local LangGraph Server](../tutorials/langgraph-platform/local-server.md)**: This quick start guide shows how to start a LangGraph Server locally for the **ReAct Agent** template. The steps are similar for other templates. - **[Deploy to LangGraph Cloud](../cloud/quick_start.md)**: Deploy your LangGraph app using LangGraph Cloud. - -### LangGraph Framework - -- **[LangGraph Concepts](../concepts/index.md)**: Learn the foundational concepts of LangGraph. -- **[LangGraph How-to Guides](../how-tos/index.md)**: Guides for common tasks with LangGraph. - -### 📚 Learn More about LangGraph Platform - -Expand your knowledge with these resources: - -- **[LangGraph Platform Concepts](../concepts/index.md#langgraph-platform)**: Understand the foundational concepts of the LangGraph Platform. -- **[LangGraph Platform How-to Guides](../how-tos/index.md#langgraph-platform)**: Discover step-by-step guides to build and deploy applications. diff --git a/docs/docs/concepts/time-travel.md b/docs/docs/concepts/time-travel.md index f58023eca..04867f8a5 100644 --- a/docs/docs/concepts/time-travel.md +++ b/docs/docs/concepts/time-travel.md @@ -5,65 +5,11 @@ search: # Time Travel ⏱️ -!!! note "Prerequisites" - - This guide assumes that you are familiar with LangGraph's checkpoints and states. If not, please review the [persistence](./persistence.md) concept first. - - When working with non-deterministic systems that make model-based decisions (e.g., agents powered by LLMs), it can be useful to examine their decision-making process in detail: 1. 🤔 **Understand Reasoning**: Analyze the steps that led to a successful result. 2. 🐞 **Debug Mistakes**: Identify where and why errors occurred. 3. 🔍 **Explore Alternatives**: Test different paths to uncover better solutions. -We call these debugging techniques **Time Travel**, composed of two key actions: [**Replaying**](#replaying) 🔁 and [**Forking**](#forking) 🔀 . -## Replaying - -![](./img/human_in_the_loop/replay.png) - -Replaying allows us to revisit and reproduce an agent's past actions, up to and including a specific step (checkpoint). - -To replay actions before a specific checkpoint, start by retrieving all checkpoints for the thread: - -```python -all_checkpoints = [] -for state in graph.get_state_history(thread): - all_checkpoints.append(state) -``` - -Each checkpoint has a unique ID. After identifying the desired checkpoint, for instance, `xyz`, include its ID in the configuration: - -```python -config = {'configurable': {'thread_id': '1', 'checkpoint_id': 'xyz'}} -for event in graph.stream(None, config, stream_mode="values"): - print(event) -``` - -The graph replays previously executed steps _before_ the provided `checkpoint_id` and executes the steps _after_ `checkpoint_id` (i.e., a new fork), even if they have been executed previously. - -## Forking - -![](./img/human_in_the_loop/forking.png) - -Forking allows you to revisit an agent's past actions and explore alternative paths within the graph. - -To edit a specific checkpoint, such as `xyz`, provide its `checkpoint_id` when updating the graph's state: - -```python -config = {"configurable": {"thread_id": "1", "checkpoint_id": "xyz"}} -graph.update_state(config, {"state": "updated state"}) -``` - -This creates a new forked checkpoint, xyz-fork, from which you can continue running the graph: - -```python -config = {'configurable': {'thread_id': '1', 'checkpoint_id': 'xyz-fork'}} -for event in graph.stream(None, config, stream_mode="values"): - print(event) -``` - -## Additional Resources 📚 - -- [**Conceptual Guide: Persistence**](https://langchain-ai.github.io/langgraph/concepts/persistence/#replay): Read the persistence guide for more context on replaying. -- [**How to View and Update Past Graph State**](../how-tos/human_in_the_loop/time-travel.ipynb): Step-by-step instructions for working with graph state that demonstrate the **replay** and **fork** actions. +LangGraph provides **time travel** functionality to support these use cases. Specifically, you can **resume execution from a prior checkpoint** — either replaying the same state or modifying it to explore alternatives. In all cases, resuming past execution produces a **new fork** in the history. diff --git a/docs/docs/concepts/tools.md b/docs/docs/concepts/tools.md new file mode 100644 index 000000000..311c505ba --- /dev/null +++ b/docs/docs/concepts/tools.md @@ -0,0 +1,62 @@ +# Tools + +Many AI applications interact directly with humans. In these cases, it is appropriate for models to respond in natural language. +But what about cases where we want a model to also interact *directly* with systems, such as databases or an API? +These systems often have a particular input schema; for example, APIs frequently have a required payload structure. You can use [tool calling](https://platform.openai.com/docs/guides/function-calling/example-use-cases) to request model responses that match a particular schema. + +[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs. + +**Tools** can be passed to [chat models](https://python.langchain.com/docs/concepts/chat_models) that support [tool calling](https://python.langchain.com/docs/concepts/tool_calling) allowing the model to request the execution of a specific function with specific inputs. + +You can [create custom tools](https://python.langchain.com/docs/how_to/custom_tools/) or use [prebuilt](#prebuilt-tools) tools. + +## Tool calling + +![Diagram of a tool call by a model](./img/tool_call.png) + +A key principle of tool calling is that the model decides when to use a tool based on the input's relevance. The model doesn't always need to call a tool. +For example, given an input that is *irrelevant to the tool*, the model would not call the tool: + +```python +result = llm_with_tools.invoke("Hello world!") +``` + +The result would be an `AIMessage` containing the model's response in natural language (e.g., "Hello!"). +However, if we pass an input *relevant to the tool*, the model should choose to call it: + +```python +result = llm_with_tools.invoke("What is 2 multiplied by 3?") +``` + +As before, the output `result` will be an `AIMessage`. +But, if the tool was called, `result` will have a `tool_calls` attribute. +This attribute includes everything needed to execute the tool, including the tool name and input arguments: + +``` +result.tool_calls +{'name': 'multiply', 'args': {'a': 2, 'b': 3}, 'id': 'xxx', 'type': 'tool_call'} +``` + +For more details on usage, see the [how-to guide](../how-tos/tool-calling.ipynb). + +## Execute tools + +LangGraph offers pre-built components — [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] and [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] — that invoke the tools on behalf of the user. + +See this [how-to guide](../how-tos/tool-calling.ipynb#use-prebuilt-toolnode) on tool calling. + +## Prebuilt tools + +LangChain supports a wide range of prebuilt tool integrations for interacting with APIs, databases, file systems, web data, and more. These tools extend the functionality of agents and enable rapid development. + +You can browse the full list of available integrations in the [LangChain integrations directory](https://python.langchain.com/docs/integrations/tools/). + +Some commonly used tool categories include: + +- **Search**: Bing, SerpAPI, Tavily +- **Code interpreters**: Python REPL, Node.js REPL +- **Databases**: SQL, MongoDB, Redis +- **Web data**: Web scraping and browsing +- **APIs**: OpenWeatherMap, NewsAPI, and others + +These integrations can be configured and added to your agents using the same `tools` parameter shown in the examples above. \ No newline at end of file diff --git a/docs/docs/concepts/v0-human-in-the-loop.md b/docs/docs/concepts/v0-human-in-the-loop.md deleted file mode 100644 index 801d94be8..000000000 --- a/docs/docs/concepts/v0-human-in-the-loop.md +++ /dev/null @@ -1,334 +0,0 @@ ---- -search: - exclude: true ---- - -# Human-in-the-loop - -!!! note "Use the `interrupt` function instead." - - As of LangGraph 0.2.57, the recommended way to set breakpoints is using the [`interrupt` function][langgraph.types.interrupt] as it simplifies **human-in-the-loop** patterns. - - Please see the revised [human-in-the-loop guide](./human_in_the_loop.md) for the latest version that uses the `interrupt` function. - - -Human-in-the-loop (or "on-the-loop") enhances agent capabilities through several common user interaction patterns. - -Common interaction patterns include: - -(1) `Approval` - We can interrupt our agent, surface the current state to a user, and allow the user to accept an action. - -(2) `Editing` - We can interrupt our agent, surface the current state to a user, and allow the user to edit the agent state. - -(3) `Input` - We can explicitly create a graph node to collect human input and pass that input directly to the agent state. - -Use-cases for these interaction patterns include: - -(1) `Reviewing tool calls` - We can interrupt an agent to review and edit the results of tool calls. - -(2) `Time Travel` - We can manually re-play and / or fork past actions of an agent. - -## Persistence - -All of these interaction patterns are enabled by LangGraph's built-in [persistence](./persistence.md) layer, which will write a checkpoint of the graph state at each step. Persistence allows the graph to stop so that a human can review and / or edit the current state of the graph and then resume with the human's input. - -### Breakpoints - -Adding a [breakpoint](./breakpoints.md) a specific location in the graph flow is one way to enable human-in-the-loop. In this case, the developer knows *where* in the workflow human input is needed and simply places a breakpoint prior to or following that particular graph node. - -Here, we compile our graph with a checkpointer and a breakpoint at the node we want to interrupt before, `step_for_human_in_the_loop`. We then perform one of the above interaction patterns, which will create a new checkpoint if a human edits the graph state. The new checkpoint is saved to the `thread` and we can resume the graph execution from there by passing in `None` as the input. - -```python -# Compile our graph with a checkpointer and a breakpoint before "step_for_human_in_the_loop" -graph = builder.compile(checkpointer=checkpointer, interrupt_before=["step_for_human_in_the_loop"]) - -# Run the graph up to the breakpoint -thread_config = {"configurable": {"thread_id": "1"}} -for event in graph.stream(inputs, thread_config, stream_mode="values"): - print(event) - -# Perform some action that requires human in the loop - -# Continue the graph execution from the current checkpoint -for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) -``` - -### Dynamic Breakpoints - -Alternatively, the developer can define some *condition* that must be met for a breakpoint to be triggered. This concept of [dynamic breakpoints](./breakpoints.md) is useful when the developer wants to halt the graph under *a particular condition*. This uses a `NodeInterrupt`, which is a special type of exception that can be raised from within a node based upon some condition. As an example, we can define a dynamic breakpoint that triggers when the `input` is longer than 5 characters. - -```python -def my_node(state: State) -> State: - if len(state['input']) > 5: - raise NodeInterrupt(f"Received input that is longer than 5 characters: {state['input']}") - return state -``` - -Let's assume we run the graph with an input that triggers the dynamic breakpoint and then attempt to resume the graph execution simply by passing in `None` for the input. - -```python -# Attempt to continue the graph execution with no change to state after we hit the dynamic breakpoint -for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) -``` - -The graph will *interrupt* again because this node will be *re-run* with the same graph state. We need to change the graph state such that the condition that triggers the dynamic breakpoint is no longer met. So, we can simply edit the graph state to an input that meets the condition of our dynamic breakpoint (< 5 characters) and re-run the node. - -```python -# Update the state to pass the dynamic breakpoint -graph.update_state(config=thread_config, values={"input": "foo"}) -for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) -``` - -Alternatively, what if we want to keep our current input and skip the node (`my_node`) that performs the check? To do this, we can simply perform the graph update with `as_node="my_node"` and pass in `None` for the values. This will make no update the graph state, but run the update as `my_node`, effectively skipping the node and bypassing the dynamic breakpoint. - -```python -# This update will skip the node `my_node` altogether -graph.update_state(config=thread_config, values=None, as_node="my_node") -for event in graph.stream(None, thread_config, stream_mode="values"): - print(event) -``` - -See [our guide](../how-tos/human_in_the_loop/dynamic_breakpoints.ipynb) for a detailed how-to on doing this! - -## Interaction Patterns - -### Approval - -![](./img/human_in_the_loop/approval.png) - -Sometimes we want to approve certain steps in our agent's execution. - -We can interrupt our agent at a [breakpoint](./breakpoints.md) prior to the step that we want to approve. - -This is generally recommend for sensitive actions (e.g., using external APIs or writing to a database). - -With persistence, we can surface the current agent state as well as the next step to a user for review and approval. - -If approved, the graph resumes execution from the last saved checkpoint, which is saved to the `thread`: - -```python -# Compile our graph with a checkpointer and a breakpoint before the step to approve -graph = builder.compile(checkpointer=checkpointer, interrupt_before=["node_2"]) - -# Run the graph up to the breakpoint -for event in graph.stream(inputs, thread, stream_mode="values"): - print(event) - -# ... Get human approval ... - -# If approved, continue the graph execution from the last saved checkpoint -for event in graph.stream(None, thread, stream_mode="values"): - print(event) -``` - -See [our guide](../how-tos/human_in_the_loop/breakpoints.ipynb) for a detailed how-to on doing this! - -### Editing - -![](./img/human_in_the_loop/edit_graph_state.png) - -Sometimes we want to review and edit the agent's state. - -As with approval, we can interrupt our agent at a [breakpoint](./breakpoints.md) prior to the step we want to check. - -We can surface the current state to a user and allow the user to edit the agent state. - -This can, for example, be used to correct the agent if it made a mistake (e.g., see the section on tool calling below). - -We can edit the graph state by forking the current checkpoint, which is saved to the `thread`. - -We can then proceed with the graph from our forked checkpoint as done before. - -```python -# Compile our graph with a checkpointer and a breakpoint before the step to review -graph = builder.compile(checkpointer=checkpointer, interrupt_before=["node_2"]) - -# Run the graph up to the breakpoint -for event in graph.stream(inputs, thread, stream_mode="values"): - print(event) - -# Review the state, decide to edit it, and create a forked checkpoint with the new state -graph.update_state(thread, {"state": "new state"}) - -# Continue the graph execution from the forked checkpoint -for event in graph.stream(None, thread, stream_mode="values"): - print(event) -``` - -See [this guide](../how-tos/human_in_the_loop/edit-graph-state.ipynb) for a detailed how-to on doing this! - -### Input - -![](./img/human_in_the_loop/wait_for_input.png) - -Sometimes we want to explicitly get human input at a particular step in the graph. - -We can create a graph node designated for this (e.g., `human_input` in our example diagram). - -As with approval and editing, we can interrupt our agent at a [breakpoint](./breakpoints.md) prior to this node. - -We can then perform a state update that includes the human input, just as we did with editing state. - -But, we add one thing: - -We can use `as_node=human_input` with the state update to specify that the state update *should be treated as a node*. - -The is subtle, but important: - -With editing, the user makes a decision about whether or not to edit the graph state. - -With input, we explicitly define a node in our graph for collecting human input! - -The state update with the human input then runs *as this node*. - -```python -# Compile our graph with a checkpointer and a breakpoint before the step to to collect human input -graph = builder.compile(checkpointer=checkpointer, interrupt_before=["human_input"]) - -# Run the graph up to the breakpoint -for event in graph.stream(inputs, thread, stream_mode="values"): - print(event) - -# Update the state with the user input as if it was the human_input node -graph.update_state(thread, {"user_input": user_input}, as_node="human_input") - -# Continue the graph execution from the checkpoint created by the human_input node -for event in graph.stream(None, thread, stream_mode="values"): - print(event) -``` - -See [this guide](../how-tos/human_in_the_loop/wait-user-input.ipynb) for a detailed how-to on doing this! - -## Use-cases - -### Reviewing Tool Calls - -Some user interaction patterns combine the above ideas. - -For example, many agents use [tool calling](https://python.langchain.com/docs/how_to/tool_calling/) to make decisions. - -Tool calling presents a challenge because the agent must get two things right: - -(1) The name of the tool to call - -(2) The arguments to pass to the tool - -Even if the tool call is correct, we may also want to apply discretion: - -(3) The tool call may be a sensitive operation that we want to approve - -With these points in mind, we can combine the above ideas to create a human-in-the-loop review of a tool call. - -```python -# Compile our graph with a checkpointer and a breakpoint before the step to to review the tool call from the LLM -graph = builder.compile(checkpointer=checkpointer, interrupt_before=["human_review"]) - -# Run the graph up to the breakpoint -for event in graph.stream(inputs, thread, stream_mode="values"): - print(event) - -# Review the tool call and update it, if needed, as the human_review node -graph.update_state(thread, {"tool_call": "updated tool call"}, as_node="human_review") - -# Otherwise, approve the tool call and proceed with the graph execution with no edits - -# Continue the graph execution from either: -# (1) the forked checkpoint created by human_review or -# (2) the checkpoint saved when the tool call was originally made (no edits in human_review) -for event in graph.stream(None, thread, stream_mode="values"): - print(event) -``` - -See [this guide](../how-tos/human_in_the_loop/review-tool-calls.ipynb) for a detailed how-to on doing this! - -### Time Travel - -When working with agents, we often want closely examine their decision making process: - -(1) Even when they arrive a desired final result, the reasoning that led to that result is often important to examine. - -(2) When agents make mistakes, it is often valuable to understand why. - -(3) In either of the above cases, it is useful to manually explore alternative decision making paths. - -Collectively, we call these debugging concepts `time-travel` and they are composed of `replaying` and `forking`. - -#### Replaying - -![](./img/human_in_the_loop/replay.png) - -Sometimes we want to simply replay past actions of an agent. - -Above, we showed the case of executing an agent from the current state (or checkpoint) of the graph. - -We by simply passing in `None` for the input with a `thread`. - -``` -thread = {"configurable": {"thread_id": "1"}} -for event in graph.stream(None, thread, stream_mode="values"): - print(event) -``` - -Now, we can modify this to replay past actions from a *specific* checkpoint by passing in the checkpoint ID. - -To get a specific checkpoint ID, we can easily get all of the checkpoints in the thread and filter to the one we want. - -```python -all_checkpoints = [] -for state in app.get_state_history(thread): - all_checkpoints.append(state) -``` - -Each checkpoint has a unique ID, which we can use to replay from a specific checkpoint. - -Assume from reviewing the checkpoints that we want to replay from one, `xxx`. - -We just pass in the checkpoint ID when we run the graph. - -```python -config = {'configurable': {'thread_id': '1', 'checkpoint_id': 'xxx'}} -for event in graph.stream(None, config, stream_mode="values"): - print(event) -``` - -Importantly, the graph knows which checkpoints have been previously executed. - -So, it will re-play any previously executed nodes rather than re-executing them. - -See [this additional conceptual guide](https://langchain-ai.github.io/langgraph/concepts/persistence/#replay) for related context on replaying. - -See see [this guide](../how-tos/human_in_the_loop/time-travel.ipynb) for a detailed how-to on doing time-travel! - -#### Forking - -![](./img/human_in_the_loop/forking.png) - -Sometimes we want to fork past actions of an agent, and explore different paths through the graph. - -`Editing`, as discussed above, is *exactly* how we do this for the *current* state of the graph! - -But, what if we want to fork *past* states of the graph? - -For example, let's say we want to edit a particular checkpoint, `xxx`. - -We pass this `checkpoint_id` when we update the state of the graph. - -```python -config = {"configurable": {"thread_id": "1", "checkpoint_id": "xxx"}} -graph.update_state(config, {"state": "updated state"}, ) -``` - -This creates a new forked checkpoint, `xxx-fork`, which we can then run the graph from. - -```python -config = {'configurable': {'thread_id': '1', 'checkpoint_id': 'xxx-fork'}} -for event in graph.stream(None, config, stream_mode="values"): - print(event) -``` - -See [this additional conceptual guide](https://langchain-ai.github.io/langgraph/concepts/persistence/#update-state) for related context on forking. - -See [this guide](../how-tos/human_in_the_loop/time-travel.ipynb) for a detailed how-to on doing time-travel! diff --git a/docs/docs/concepts/why-langgraph.md b/docs/docs/concepts/why-langgraph.md new file mode 100644 index 000000000..1d27c28a1 --- /dev/null +++ b/docs/docs/concepts/why-langgraph.md @@ -0,0 +1,26 @@ +# Overview + +LangGraph is built for developers who want to build powerful, adaptable AI agents. Developers choose LangGraph for: + +- **Reliability and controllability.** Steer agent actions with moderation checks and human-in-the-loop approvals. LangGraph persists context for long-running workflows, keeping your agents on course. +- **Low-level and extensible.** Build custom agents with fully descriptive, low-level primitives free from rigid abstractions that limit customization. Design scalable multi-agent systems, with each agent serving a specific role tailored to your use case. +- **First-class streaming support.** With token-by-token streaming and streaming of intermediate steps, LangGraph gives users clear visibility into agent reasoning and actions as they unfold in real time. + +## Learn LangGraph basics + +To get acquainted with LangGraph's key concepts and features, complete the following LangGraph basics tutorials series: + +1. [Build a basic chatbot](../tutorials/get-started/1-build-basic-chatbot.md) +2. [Add tools](../tutorials/get-started/2-add-tools.md) +3. [Add memory](../tutorials/get-started/3-add-memory.md) +4. [Add human-in-the-loop controls](../tutorials/get-started/4-human-in-the-loop.md) +5. [Customize state](../tutorials/get-started/5-customize-state.md) +6. [Time travel](../tutorials/get-started/6-time-travel.md) + +In completing this series of tutorials, you will build a support chatbot in LangGraph that can: + +✅ **Answer common questions** by searching the web +✅ **Maintain conversation state** across calls +✅ **Route complex queries** to a human for review +✅ **Use custom state** to control its behavior +✅ **Rewind and explore** alternative conversation paths diff --git a/docs/docs/how-tos/agent-handoffs.ipynb b/docs/docs/how-tos/agent-handoffs.ipynb deleted file mode 100644 index 039dc6ec0..000000000 --- a/docs/docs/how-tos/agent-handoffs.ipynb +++ /dev/null @@ -1,1033 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "34d3d54e-9a2b-481e-bccd-74aca7a53f9a", - "metadata": {}, - "source": [ - "# How to implement handoffs between agents" - ] - }, - { - "cell_type": "markdown", - "id": "ef16392a-56de-4cda-9ae8-dff078b2ed87", - "metadata": {}, - "source": [ - "!!! info \"Prerequisites\"\n", - " This guide assumes familiarity with the following:\n", - "\n", - " - [Multi-agent systems](../../concepts/multi_agent)\n", - " - [Command](../../concepts/low_level/#command)\n", - " - [LangGraph Glossary](../../concepts/low_level/)\n", - " \n", - "\n", - "In multi-agent architectures, agents can be represented as graph nodes. Each agent node executes its step(s) and decides whether to finish execution or route to another agent, including potentially routing to itself (e.g., running in a loop). A natural pattern in multi-agent interactions is [handoffs](../../concepts/multi_agent#handoffs), where one agent hands off control to another. Handoffs allow you to specify:\n", - "\n", - "- **destination**: target agent to navigate to - node name in LangGraph\n", - "- **payload**: information to pass to that agent - state update in LangGraph\n", - "\n", - "To implement handoffs in LangGraph, agent nodes can return `Command` object that allows you to [combine both control flow and state updates](../command):\n", - "\n", - "```python\n", - "def agent(state) -> Command[Literal[\"agent\", \"another_agent\"]]:\n", - " # the condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.\n", - " goto = get_next_agent(...) # 'agent' / 'another_agent'\n", - " return Command(\n", - " # Specify which agent to call next\n", - " goto=goto,\n", - " # Update the graph state\n", - " update={\"my_state_key\": \"my_state_value\"}\n", - " )\n", - "```\n", - "\n", - "One of the most common agent types is a tool-calling agent. For those types of agents, one pattern is wrapping a handoff in a tool call, e.g.:\n", - "\n", - "```python\n", - "@tool\n", - "def transfer_to_bob(state):\n", - " \"\"\"Transfer to bob.\"\"\"\n", - " return Command(\n", - " goto=\"bob\",\n", - " update={\"my_state_key\": \"my_state_value\"},\n", - " # Each tool-calling agent is implemented as a subgraph.\n", - " # As a result, to navigate to another agent (a sibling sub-graph), \n", - " # we need to specify that navigation is w/ respect to the parent graph.\n", - " graph=Command.PARENT,\n", - " )\n", - "```\n", - "\n", - "This guide shows how you can:\n", - "\n", - "- implement handoffs using `Command`: agent node makes a decision on who to hand off to (usually LLM-based), and explicitly returns a handoff via `Command`. These are useful when you need fine-grained control over how an agent routes to another agent. It could be well suited for implementing a supervisor agent in a supervisor architecture.\n", - "- implement handoffs using tools: a tool-calling agent has access to tools that can return a handoff via `Command`. The tool-executing node in the agent recognizes `Command` objects returned by the tools and routes accordingly. Handoff tool a general-purpose primitive that is useful in any multi-agent systems that contain tool-calling agents." - ] - }, - { - "cell_type": "markdown", - "id": "7a4274c8-204f-41e4-b7ef-c8d1bb8de02e", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "e060e7a2-e339-49a6-bfd0-071dba8a3131", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain-anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b4864843-00a1-4c88-9a7c-c34e6c31c548", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "230aec8a-ed82-4b97-a52e-2131f6c295ed", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "4157f016-ccce-4f3a-877c-d3b3cfd77ffe", - "metadata": {}, - "source": [ - "## Implement handoffs using `Command`" - ] - }, - { - "cell_type": "markdown", - "id": "43a75f43-cf79-4e5d-b2b2-fc8982bc84a8", - "metadata": {}, - "source": [ - "Let's implement a system with two agents:\n", - "\n", - "- an addition expert (can only add numbers)\n", - "- a multiplication expert (can only multiply numbers).\n", - "\n", - "In this example the agents will be relying on the LLM for doing math. In a more realistic [follow-up example](#using-with-a-custom-agent), we will give the agents tools for doing math.\n", - "\n", - "When the addition expert needs help with multiplication, it hands off to the multiplication expert and vice-versa. This is an example of a simple multi-agent network.\n", - "\n", - "Each agent will have a corresponding node function that can conditionally return a `Command` object (e.g. our handoff). The node function will use an LLM with a system prompt and a tool that lets it signal when it needs to hand off to another agent. If the LLM responds with the tool calls, we will return a `Command(goto=)`.\n", - "\n", - "> **Note**: while we're using tools for the LLM to signal that it needs a handoff, the condition for the handoff can be anything: a specific response text from the LLM, structured output from the LLM, any other custom logic, etc." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "4e184beb-b9b2-4bd0-ac35-0356a8da46bc", - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import Literal\n", - "from langchain_core.messages import ToolMessage\n", - "from langchain_core.tools import tool\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langgraph.graph import MessagesState, StateGraph, START\n", - "from langgraph.types import Command\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-latest\")\n", - "\n", - "\n", - "@tool\n", - "def transfer_to_multiplication_expert():\n", - " \"\"\"Ask multiplication agent for help.\"\"\"\n", - " # This tool is not returning anything: we're just using it\n", - " # as a way for LLM to signal that it needs to hand off to another agent\n", - " # (See the paragraph above)\n", - " return\n", - "\n", - "\n", - "@tool\n", - "def transfer_to_addition_expert():\n", - " \"\"\"Ask addition agent for help.\"\"\"\n", - " return\n", - "\n", - "\n", - "def addition_expert(\n", - " state: MessagesState,\n", - ") -> Command[Literal[\"multiplication_expert\", \"__end__\"]]:\n", - " system_prompt = (\n", - " \"You are an addition expert, you can ask the multiplication expert for help with multiplication. \"\n", - " \"Always do your portion of calculation before the handoff.\"\n", - " )\n", - " messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n", - " ai_msg = model.bind_tools([transfer_to_multiplication_expert]).invoke(messages)\n", - " # If there are tool calls, the LLM needs to hand off to another agent\n", - " if len(ai_msg.tool_calls) > 0:\n", - " tool_call_id = ai_msg.tool_calls[-1][\"id\"]\n", - " # NOTE: it's important to insert a tool message here because LLM providers are expecting\n", - " # all AI messages to be followed by a corresponding tool result message\n", - " tool_msg = {\n", - " \"role\": \"tool\",\n", - " \"content\": \"Successfully transferred\",\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(\n", - " goto=\"multiplication_expert\", update={\"messages\": [ai_msg, tool_msg]}\n", - " )\n", - "\n", - " # If the expert has an answer, return it directly to the user\n", - " return {\"messages\": [ai_msg]}\n", - "\n", - "\n", - "def multiplication_expert(\n", - " state: MessagesState,\n", - ") -> Command[Literal[\"addition_expert\", \"__end__\"]]:\n", - " system_prompt = (\n", - " \"You are a multiplication expert, you can ask an addition expert for help with addition. \"\n", - " \"Always do your portion of calculation before the handoff.\"\n", - " )\n", - " messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n", - " ai_msg = model.bind_tools([transfer_to_addition_expert]).invoke(messages)\n", - " if len(ai_msg.tool_calls) > 0:\n", - " tool_call_id = ai_msg.tool_calls[-1][\"id\"]\n", - " tool_msg = {\n", - " \"role\": \"tool\",\n", - " \"content\": \"Successfully transferred\",\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(goto=\"addition_expert\", update={\"messages\": [ai_msg, tool_msg]})\n", - "\n", - " return {\"messages\": [ai_msg]}" - ] - }, - { - "cell_type": "markdown", - "id": "921dc7bb-0c5b-410e-b143-601a549d529d", - "metadata": {}, - "source": [ - "Let's now combine both of these nodes into a single graph. Note that there are no edges between the agents! If the expert has an answer, it will return it directly to the user, otherwise it will route to the other expert for help." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "f56b6617-4226-4a7f-8234-59ebeaf53447", - "metadata": {}, - "outputs": [], - "source": [ - "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"addition_expert\", addition_expert)\n", - "builder.add_node(\"multiplication_expert\", multiplication_expert)\n", - "# we'll always start with the addition expert\n", - "builder.add_edge(START, \"addition_expert\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "d36574f3-7990-4ef2-b556-3bbd3625ec17", - "metadata": {}, - "source": [ - "Finally, let's define a helper function to render the streamed outputs nicely:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "3f8e4b2b-c761-445c-909b-3d206ac475c7", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import convert_to_messages\n", - "\n", - "\n", - "def pretty_print_messages(update):\n", - " if isinstance(update, tuple):\n", - " ns, update = update\n", - " # skip parent graph updates in the printouts\n", - " if len(ns) == 0:\n", - " return\n", - "\n", - " graph_id = ns[-1].split(\":\")[0]\n", - " print(f\"Update from subgraph {graph_id}:\")\n", - " print(\"\\n\")\n", - "\n", - " for node_name, node_update in update.items():\n", - " print(f\"Update from node {node_name}:\")\n", - " print(\"\\n\")\n", - "\n", - " for m in convert_to_messages(node_update[\"messages\"]):\n", - " m.pretty_print()\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "01ff98c2-81ea-4679-8569-fed4750d5954", - "metadata": {}, - "source": [ - "Let's run the graph with an expression that requires both addition and multiplication:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "62ba5113-e972-41e6-8392-cc970d4eea72", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from node addition_expert:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Let me help break this down:\\n\\nFirst, I'll handle the addition part since I'm the addition expert:\\n3 + 5 = 8\\n\\nNow, for the multiplication of 8 * 12, I'll need to ask the multiplication expert for help.\", 'type': 'text'}, {'id': 'toolu_015LCrsomHbeoQPtCzuff78Y', 'input': {}, 'name': 'transfer_to_multiplication_expert', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_multiplication_expert (toolu_015LCrsomHbeoQPtCzuff78Y)\n", - " Call ID: toolu_015LCrsomHbeoQPtCzuff78Y\n", - " Args:\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "\n", - "Successfully transferred\n", - "\n", - "\n", - "Update from node multiplication_expert:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'I see there was an error in my approach. I am actually the multiplication expert, and I need to ask the addition expert for help with (3 + 5) first.', 'type': 'text'}, {'id': 'toolu_01HFcB8WesPfDyrdgxoXApZk', 'input': {}, 'name': 'transfer_to_addition_expert', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_addition_expert (toolu_01HFcB8WesPfDyrdgxoXApZk)\n", - " Call ID: toolu_01HFcB8WesPfDyrdgxoXApZk\n", - " Args:\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "\n", - "Successfully transferred\n", - "\n", - "\n", - "Update from node addition_expert:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Now that I have the result of 3 + 5 = 8 from the addition expert, I can multiply 8 * 12:\n", - "\n", - "8 * 12 = 96\n", - "\n", - "So, (3 + 5) * 12 = 96\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"messages\": [(\"user\", \"what's (3 + 5) * 12\")]},\n", - "):\n", - " pretty_print_messages(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "0088d791-1e03-49fb-b640-0ea01a7ef61d", - "metadata": {}, - "source": [ - "You can see that the addition expert first handled the expression in the parentheses, and then handed off to the multiplication expert to finish the calculation.\n", - "\n", - "Now let's see how we can implement this same system using special handoff tools and give our agents actual math tools." - ] - }, - { - "cell_type": "markdown", - "id": "c7a5d161-9f74-47a2-83ce-0cbe6073edcc", - "metadata": {}, - "source": [ - "## Implement handoffs using tools" - ] - }, - { - "cell_type": "markdown", - "id": "6ccfbd12-0a27-4e34-b6f7-701c2e7a6ffb", - "metadata": {}, - "source": [ - "### Implement a handoff tool" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "acaed37a-ddd3-4bf9-ac30-a9c5cc1ea3fe", - "metadata": {}, - "source": [ - "In the previous example we explicitly defined custom handoffs in each of the agent nodes. Another pattern is to create special **handoff tools** that directly return `Command` objects. When an agent calls a tool like this, it hands the control off to a different agent. Specifically, the tool-executing node in the agent recognizes the `Command` objects returned by the tools and routes control flow accordingly. **Note**: unlike the previous example, a tool-calling agent is not a single node but another graph that can be added to the multi-agent graph as a subgraph node.\n", - "\n", - "There are a few important considerations when implementing handoff tools:\n", - "\n", - "- since each agent is a __subgraph__ node in another graph, and the tools will be called in one of the agent subgraph nodes (e.g. tool executor), we need to specify `graph=Command.PARENT` in the `Command`, so that LangGraph knows to navigate outside of the agent subgraph\n", - "- we can optionally specify a state update that will be applied to the parent graph state before the next agent is called\n", - " - these state updates can be used to control [how much of the chat message history](../../concepts/multi_agent#shared-message-list) the target agent sees. For example, you might choose to just share the last AI messages from the current agent, or its full internal chat history, etc. In the examples below we'll be sharing the full internal chat history.\n", - "\n", - "- we can optionally provide the following to the tool (in the tool function signature):\n", - " - graph state (using [`InjectedState`][langgraph.prebuilt.tool_node.InjectedState])\n", - " - graph long-term memory (using [`InjectedStore`][langgraph.prebuilt.tool_node.InjectedStore])\n", - " - the current tool call ID (using [`InjectedToolCallId`](https://python.langchain.com/api_reference/core/tools/langchain_core.tools.base.InjectedToolCallId.html))\n", - " \n", - " These are not necessary but are useful for creating the state update passed to the next agent." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "d022072b-39bf-4133-aa62-e20f22bb4b17", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from langchain_core.tools import tool\n", - "from langchain_core.tools.base import InjectedToolCallId\n", - "from langgraph.prebuilt import InjectedState\n", - "\n", - "\n", - "def make_handoff_tool(*, agent_name: str):\n", - " \"\"\"Create a tool that can return handoff via a Command\"\"\"\n", - " tool_name = f\"transfer_to_{agent_name}\"\n", - "\n", - " @tool(tool_name)\n", - " def handoff_to_agent(\n", - " # # optionally pass current graph state to the tool (will be ignored by the LLM)\n", - " state: Annotated[dict, InjectedState],\n", - " # optionally pass the current tool call ID (will be ignored by the LLM)\n", - " tool_call_id: Annotated[str, InjectedToolCallId],\n", - " ):\n", - " \"\"\"Ask another agent for help.\"\"\"\n", - " tool_message = {\n", - " \"role\": \"tool\",\n", - " \"content\": f\"Successfully transferred to {agent_name}\",\n", - " \"name\": tool_name,\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(\n", - " # navigate to another agent node in the PARENT graph\n", - " goto=agent_name,\n", - " graph=Command.PARENT,\n", - " # This is the state update that the agent `agent_name` will see when it is invoked.\n", - " # We're passing agent's FULL internal message history AND adding a tool message to make sure\n", - " # the resulting chat history is valid. See the paragraph above for more information.\n", - " update={\"messages\": state[\"messages\"] + [tool_message]},\n", - " )\n", - "\n", - " return handoff_to_agent" - ] - }, - { - "cell_type": "markdown", - "id": "ba83e85a-576a-4e3f-8086-ce5e2c149c60", - "metadata": {}, - "source": [ - "### Using with a custom agent" - ] - }, - { - "cell_type": "markdown", - "id": "4d263776-3b2d-4ab0-9cc8-c7cbef22e2d5", - "metadata": {}, - "source": [ - "To demonstrate how to use handoff tools, let's first implement a simple version of the prebuilt [create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]. This is useful in case you want to have a custom tool-calling agent implementation and want to leverage handoff tools." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "e5cd13c5-7dac-4dd7-9ffc-9f3467e28a44", - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import Literal\n", - "from langchain_core.messages import ToolMessage\n", - "from langchain_core.tools import tool\n", - "from langgraph.graph import MessagesState, StateGraph, START\n", - "from langgraph.types import Command\n", - "\n", - "\n", - "def make_agent(model, tools, system_prompt=None):\n", - " model_with_tools = model.bind_tools(tools)\n", - " tools_by_name = {tool.name: tool for tool in tools}\n", - "\n", - " def call_model(state: MessagesState) -> Command[Literal[\"call_tools\", \"__end__\"]]:\n", - " messages = state[\"messages\"]\n", - " if system_prompt:\n", - " messages = [{\"role\": \"system\", \"content\": system_prompt}] + messages\n", - "\n", - " response = model_with_tools.invoke(messages)\n", - " if len(response.tool_calls) > 0:\n", - " return Command(goto=\"call_tools\", update={\"messages\": [response]})\n", - "\n", - " return {\"messages\": [response]}\n", - "\n", - " # NOTE: this is a simplified version of the prebuilt ToolNode\n", - " # If you want to have a tool node that has full feature parity, please refer to the source code\n", - " def call_tools(state: MessagesState) -> Command[Literal[\"call_model\"]]:\n", - " tool_calls = state[\"messages\"][-1].tool_calls\n", - " results = []\n", - " for tool_call in tool_calls:\n", - " tool_ = tools_by_name[tool_call[\"name\"]]\n", - " tool_input_fields = tool_.get_input_schema().model_json_schema()[\n", - " \"properties\"\n", - " ]\n", - "\n", - " # this is simplified for demonstration purposes and\n", - " # is different from the ToolNode implementation\n", - " if \"state\" in tool_input_fields:\n", - " # inject state\n", - " tool_call = {**tool_call, \"args\": {**tool_call[\"args\"], \"state\": state}}\n", - "\n", - " tool_response = tool_.invoke(tool_call)\n", - " if isinstance(tool_response, ToolMessage):\n", - " results.append(Command(update={\"messages\": [tool_response]}))\n", - "\n", - " # handle tools that return Command directly\n", - " elif isinstance(tool_response, Command):\n", - " results.append(tool_response)\n", - "\n", - " # NOTE: nodes in LangGraph allow you to return list of updates, including Command objects\n", - " return results\n", - "\n", - " graph = StateGraph(MessagesState)\n", - " graph.add_node(call_model)\n", - " graph.add_node(call_tools)\n", - " graph.add_edge(START, \"call_model\")\n", - " graph.add_edge(\"call_tools\", \"call_model\")\n", - "\n", - " return graph.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "8b7231d5-1e01-41a7-b260-d0495323d552", - "metadata": {}, - "source": [ - "Let's also define math tools that we'll give our agents:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "b9f8e553-8894-4d59-a069-1baa05d23289", - "metadata": {}, - "outputs": [], - "source": [ - "@tool\n", - "def add(a: int, b: int) -> int:\n", - " \"\"\"Adds two numbers.\"\"\"\n", - " return a + b\n", - "\n", - "\n", - "@tool\n", - "def multiply(a: int, b: int) -> int:\n", - " \"\"\"Multiplies two numbers.\"\"\"\n", - " return a * b" - ] - }, - { - "cell_type": "markdown", - "id": "e3f76999-2364-4e08-90be-62d4d138a8f4", - "metadata": {}, - "source": [ - "Let's test the agent implementation out to make sure it's working as expected:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "f39f99b0-95c7-422f-96a6-e612fde186df", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help break this down into two steps:\\n1. First calculate 3 + 5\\n2. Then multiply that result by 12\\n\\nLet me make these calculations:\\n\\n1. Adding 3 and 5:\", 'type': 'text'}, {'id': 'toolu_01DUAzgWFqq6XZtj1hzHTka9', 'input': {'a': 3, 'b': 5}, 'name': 'add', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " add (toolu_01DUAzgWFqq6XZtj1hzHTka9)\n", - " Call ID: toolu_01DUAzgWFqq6XZtj1hzHTka9\n", - " Args:\n", - " a: 3\n", - " b: 5\n", - "\n", - "\n", - "Update from node call_tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: add\n", - "\n", - "8\n", - "\n", - "\n", - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': '2. Multiplying the result (8) by 12:', 'type': 'text'}, {'id': 'toolu_01QXi1prSN4etgJ1QCuFJsgN', 'input': {'a': 8, 'b': 12}, 'name': 'multiply', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " multiply (toolu_01QXi1prSN4etgJ1QCuFJsgN)\n", - " Call ID: toolu_01QXi1prSN4etgJ1QCuFJsgN\n", - " Args:\n", - " a: 8\n", - " b: 12\n", - "\n", - "\n", - "Update from node call_tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: multiply\n", - "\n", - "96\n", - "\n", - "\n", - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The result of (3 + 5) * 12 = 96\n", - "\n", - "\n" - ] - } - ], - "source": [ - "agent = make_agent(model, [add, multiply])\n", - "\n", - "for chunk in agent.stream({\"messages\": [(\"user\", \"what's (3 + 5) * 12\")]}):\n", - " pretty_print_messages(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "09689fde-7a54-4725-859f-b9e7d2725434", - "metadata": {}, - "source": [ - "Now, we can implement our multi-agent system with the multiplication and addition expert agents. This time we'll give them the tools for doing math, as well as our special handoff tools:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "af9e540a-e847-4ee3-b896-2b4dd93ecb34", - "metadata": {}, - "outputs": [], - "source": [ - "addition_expert = make_agent(\n", - " model,\n", - " [add, make_handoff_tool(agent_name=\"multiplication_expert\")],\n", - " system_prompt=\"You are an addition expert, you can ask the multiplication expert for help with multiplication.\",\n", - ")\n", - "multiplication_expert = make_agent(\n", - " model,\n", - " [multiply, make_handoff_tool(agent_name=\"addition_expert\")],\n", - " system_prompt=\"You are a multiplication expert, you can ask an addition expert for help with addition.\",\n", - ")\n", - "\n", - "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"addition_expert\", addition_expert)\n", - "builder.add_node(\"multiplication_expert\", multiplication_expert)\n", - "builder.add_edge(START, \"addition_expert\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "039ff31e-6559-437b-a500-f739b29c003b", - "metadata": {}, - "source": [ - "Let's run the graph with the same multi-step calculation input as before:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "c4ccd402-a90d-4c94-906d-6d364c274192", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I can help with the addition part (3 + 5), but I'll need to ask the multiplication expert for help with multiplying the result by 12. Let me break this down:\\n\\n1. First, let me calculate 3 + 5:\", 'type': 'text'}, {'id': 'toolu_01McaW4XWczLGKaetg88fxQ5', 'input': {'a': 3, 'b': 5}, 'name': 'add', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " add (toolu_01McaW4XWczLGKaetg88fxQ5)\n", - " Call ID: toolu_01McaW4XWczLGKaetg88fxQ5\n", - " Args:\n", - " a: 3\n", - " b: 5\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node call_tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: add\n", - "\n", - "8\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Now that we have 8, we need to multiply it by 12. I'll ask the multiplication expert for help with this:\", 'type': 'text'}, {'id': 'toolu_01KpdUhHuyrmha62z5SduKRc', 'input': {}, 'name': 'transfer_to_multiplication_expert', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_multiplication_expert (toolu_01KpdUhHuyrmha62z5SduKRc)\n", - " Call ID: toolu_01KpdUhHuyrmha62z5SduKRc\n", - " Args:\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'Now that we have 8 as the result of the addition, I can help with the multiplication by 12:', 'type': 'text'}, {'id': 'toolu_01Vnp4k3TE87siad3BNJgRKb', 'input': {'a': 8, 'b': 12}, 'name': 'multiply', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " multiply (toolu_01Vnp4k3TE87siad3BNJgRKb)\n", - " Call ID: toolu_01Vnp4k3TE87siad3BNJgRKb\n", - " Args:\n", - " a: 8\n", - " b: 12\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node call_tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: multiply\n", - "\n", - "96\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node call_model:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The final result is 96.\n", - "\n", - "To break down the steps:\n", - "1. 3 + 5 = 8\n", - "2. 8 * 12 = 96\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"messages\": [(\"user\", \"what's (3 + 5) * 12\")]}, subgraphs=True\n", - "):\n", - " pretty_print_messages(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "dd98eeae-5abd-45d9-aae7-4e714b7999dc", - "metadata": {}, - "source": [ - "We can see that after the addition expert is done with the first part of the calculation (after calling the `add` tool), it decides to hand off to the multiplication expert, which computes the final result." - ] - }, - { - "cell_type": "markdown", - "id": "102b116d-62f1-4570-afba-be9a96ce721f", - "metadata": {}, - "source": [ - "## Using with a prebuilt ReAct agent" - ] - }, - { - "cell_type": "markdown", - "id": "c46194ad-768d-4f29-85ce-91869a220107", - "metadata": {}, - "source": [ - "If you don't need extra customization, you can use the prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent], which includes built-in support for handoff tools through [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode]." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "fe91541c-4c6f-42ef-858a-336bbbb96728", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.prebuilt import create_react_agent\n", - "\n", - "addition_expert = create_react_agent(\n", - " model,\n", - " [add, make_handoff_tool(agent_name=\"multiplication_expert\")],\n", - " prompt=\"You are an addition expert, you can ask the multiplication expert for help with multiplication.\",\n", - ")\n", - "\n", - "multiplication_expert = create_react_agent(\n", - " model,\n", - " [multiply, make_handoff_tool(agent_name=\"addition_expert\")],\n", - " prompt=\"You are a multiplication expert, you can ask an addition expert for help with addition.\",\n", - ")\n", - "\n", - "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"addition_expert\", addition_expert)\n", - "builder.add_node(\"multiplication_expert\", multiplication_expert)\n", - "builder.add_edge(START, \"addition_expert\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "762fbd94-0e54-45cd-84fb-05a241bae679", - "metadata": {}, - "source": [ - "We can now verify that the prebuilt ReAct agent works exactly the same as the custom agent above:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "637d188c-e0d0-4c05-bb41-f007b4e17fb7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I can help with the addition part of this calculation (3 + 5), and then I'll need to ask the multiplication expert for help with multiplying the result by 12.\\n\\nLet me first calculate 3 + 5:\", 'type': 'text'}, {'id': 'toolu_01GUasumGGJVXDV7TJEqEfmY', 'input': {'a': 3, 'b': 5}, 'name': 'add', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " add (toolu_01GUasumGGJVXDV7TJEqEfmY)\n", - " Call ID: toolu_01GUasumGGJVXDV7TJEqEfmY\n", - " Args:\n", - " a: 3\n", - " b: 5\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: add\n", - "\n", - "8\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Now that we have 8, we need to multiply it by 12. Since I'm an addition expert, I'll transfer this to the multiplication expert to complete the calculation:\", 'type': 'text'}, {'id': 'toolu_014HEbwiH2jVno8r1Pc6t9Qh', 'input': {}, 'name': 'transfer_to_multiplication_expert', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_multiplication_expert (toolu_014HEbwiH2jVno8r1Pc6t9Qh)\n", - " Call ID: toolu_014HEbwiH2jVno8r1Pc6t9Qh\n", - " Args:\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'I notice I made a mistake - I actually don\\'t have access to the \"add\" function or \"transfer_to_multiplication_expert\". Instead, I am the multiplication expert and I should ask the addition expert for help with the first part. Let me correct this:', 'type': 'text'}, {'id': 'toolu_01VAGpmr4ysHjvvuZp3q5Dzj', 'input': {}, 'name': 'transfer_to_addition_expert', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_addition_expert (toolu_01VAGpmr4ysHjvvuZp3q5Dzj)\n", - " Call ID: toolu_01VAGpmr4ysHjvvuZp3q5Dzj\n", - " Args:\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you with the addition part of (3 + 5) * 12. First, let me calculate 3 + 5:\", 'type': 'text'}, {'id': 'toolu_01RE16cRGVo4CC4wwHFB6gaE', 'input': {'a': 3, 'b': 5}, 'name': 'add', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " add (toolu_01RE16cRGVo4CC4wwHFB6gaE)\n", - " Call ID: toolu_01RE16cRGVo4CC4wwHFB6gaE\n", - " Args:\n", - " a: 3\n", - " b: 5\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: add\n", - "\n", - "8\n", - "\n", - "\n", - "Update from subgraph addition_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Now that we have 8, we need to multiply it by 12. Since I'm an addition expert, I'll need to transfer this to the multiplication expert to complete the calculation:\", 'type': 'text'}, {'id': 'toolu_01HBDRh64SzGcCp7EX1u3MFa', 'input': {}, 'name': 'transfer_to_multiplication_expert', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_multiplication_expert (toolu_01HBDRh64SzGcCp7EX1u3MFa)\n", - " Call ID: toolu_01HBDRh64SzGcCp7EX1u3MFa\n", - " Args:\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'Now that I have the result of 3 + 5 = 8, I can help with multiplying by 12:', 'type': 'text'}, {'id': 'toolu_014Ay95rsKvvbWWJV4CcZSPY', 'input': {'a': 8, 'b': 12}, 'name': 'multiply', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " multiply (toolu_014Ay95rsKvvbWWJV4CcZSPY)\n", - " Call ID: toolu_014Ay95rsKvvbWWJV4CcZSPY\n", - " Args:\n", - " a: 8\n", - " b: 12\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: multiply\n", - "\n", - "96\n", - "\n", - "\n", - "Update from subgraph multiplication_expert:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The final result is 96. Here's the complete calculation:\n", - "(3 + 5) * 12 = 8 * 12 = 96\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"messages\": [(\"user\", \"what's (3 + 5) * 12\")]}, subgraphs=True\n", - "):\n", - " pretty_print_messages(chunk)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/auth/custom_auth.md b/docs/docs/how-tos/auth/custom_auth.md index 826383887..0bf19307d 100644 --- a/docs/docs/how-tos/auth/custom_auth.md +++ b/docs/docs/how-tos/auth/custom_auth.md @@ -5,7 +5,7 @@ This guide assumes familiarity with the following concepts: * [**Authentication & Access Control**](../../concepts/auth.md) - * [**LangGraph Platform**](../../concepts/index.md#langgraph-platform) + * [**LangGraph Platform**](../../concepts/langgraph_platform.md) For a more guided walkthrough, see [**setting up custom authentication**](../../tutorials/auth/getting_started.md) tutorial. @@ -13,7 +13,7 @@ Custom auth is supported for all deployments in the **managed LangGraph Cloud**, as well as **Enterprise** self-hosted plans. It is not supported for **Lite** self-hosted plans. -This guide shows how to add custom authentication to your LangGraph Platform application. This guide applies to both LangGraph Cloud, BYOC, and self-hosted deployments. It does not apply to isolated usage of the LangGraph open source library in your own custom server. +This guide shows how to add custom authentication to your LangGraph Platform application. This guide applies to both LangGraph Cloud and self-hosted deployments. It does not apply to isolated usage of the LangGraph open source library in your own custom server. ## 1. Implement authentication diff --git a/docs/docs/how-tos/auth/openapi_security.md b/docs/docs/how-tos/auth/openapi_security.md index 87e1e0229..d74afbc76 100644 --- a/docs/docs/how-tos/auth/openapi_security.md +++ b/docs/docs/how-tos/auth/openapi_security.md @@ -5,7 +5,7 @@ This guide shows how to customize the OpenAPI security schema for your LangGraph !!! note "Implementation vs Documentation" This guide only covers how to document your security requirements in OpenAPI. To implement the actual authentication logic, see [How to add custom authentication](./custom_auth.md). -This guide applies to all LangGraph Platform deployments (Cloud, BYOC, and self-hosted). It does not apply to usage of the LangGraph open source library if you are not using LangGraph Platform. +This guide applies to all LangGraph Platform deployments (Cloud and self-hosted). It does not apply to usage of the LangGraph open source library if you are not using LangGraph Platform. ## Default Schema diff --git a/docs/docs/how-tos/branching.ipynb b/docs/docs/how-tos/branching.ipynb deleted file mode 100644 index d1d6dd494..000000000 --- a/docs/docs/how-tos/branching.ipynb +++ /dev/null @@ -1,541 +0,0 @@ -{ - "cells": [ - { - "attachments": { - "51f122de-b2ce-4c21-a5a7-c3be70c28a91.png": { - "image/png": "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LyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj41NDI8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+OTA0PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ClCweXwAAAAcaURPVAAAAAIAAAAAAAABDwAAACgAAAEPAAABDwAARV8dcCWfAABAAElEQVR4AezdB3wURfvA8UcgdAgdqaElNAEVFBSk96agf1REFJSiooAFRXxtiAooShHEBkhRULEjRTpIB0MTCC0JJEBooZcA/5mJt97mLqSQS+4uv30/8XZnd2dnvjcvnzyZ2ZmbrqlN2BBAAAEEEEAAAQQQQAABBDK9wE0EiJm+DQCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIICARwXOnDkjW7ZssT2jWrVqEhgYaEvjAAEEEEAAAQQyXoAAMeO/A0qAAAII+LVA+/btXQJEXeHy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Ujl++pycOH1eTkSfl7PnzsvFC+cl5qL5MZ8XL56TwsUjpFSZslK2TBkpXz5C8uUQyZczixTKncV82llyggACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAApaKqg4AAAVzSURBVAgggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuC/w/OsDdHSiHP+MAAAAASUVORK5CYII=" - } - }, - "cell_type": "markdown", - "id": "710dc4f0-1c88-4386-9e9d-fec3de6bb774", - "metadata": {}, - "source": [ - "# How to create branches for parallel node execution\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "Parallel execution of nodes is essential to speed up overall graph operation. LangGraph offers native support for parallel execution of nodes, which can significantly enhance the performance of graph-based workflows. This parallelization is achieved through fan-out and fan-in mechanisms, utilizing both standard edges and [conditional_edges](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.MessageGraph.add_conditional_edges). Below are some examples showing how to add create branching dataflows that work for you. \n", - "\n", - "![Screenshot 2024-07-09 at 2.55.56 PM.png](attachment:51f122de-b2ce-4c21-a5a7-c3be70c28a91.png)" - ] - }, - { - "cell_type": "markdown", - "id": "66b6b42d", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "bb54e2d0", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "73bac559", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "d6c05fc4-ecd8-483f-a9fd-b1a055f922d9", - "metadata": {}, - "source": [ - "## How to run graph nodes in parallel\n", - "\n", - "In this example, we fan out from `Node A` to `B and C` and then fan in to `D`. With our state, [we specify the reducer add operation](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers). This will combine or accumulate values for the specific key in the State, rather than simply overwriting the existing value. For lists, this means concatenating the new list with the existing list. See [this guide](../../how-tos/state-reducers) for more detail on updating state with reducers." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "09372b8b-edea-4b9d-9ec3-3d93ce1ba819", - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing import Annotated, Any\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "\n", - "\n", - "class State(TypedDict):\n", - " # The operator.add reducer fn makes this append-only\n", - " aggregate: Annotated[list, operator.add]\n", - "\n", - "\n", - "def a(state: State):\n", - " print(f'Adding \"A\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"A\"]}\n", - "\n", - "\n", - "def b(state: State):\n", - " print(f'Adding \"B\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"B\"]}\n", - "\n", - "\n", - "def c(state: State):\n", - " print(f'Adding \"C\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"C\"]}\n", - "\n", - "\n", - "def d(state: State):\n", - " print(f'Adding \"D\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"D\"]}\n", - "\n", - "\n", - "builder = StateGraph(State)\n", - "builder.add_node(a)\n", - "builder.add_node(b)\n", - "builder.add_node(c)\n", - "builder.add_node(d)\n", - "builder.add_edge(START, \"a\")\n", - "builder.add_edge(\"a\", \"b\")\n", - "builder.add_edge(\"a\", \"c\")\n", - "builder.add_edge(\"b\", \"d\")\n", - "builder.add_edge(\"c\", \"d\")\n", - "builder.add_edge(\"d\", END)\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "66f52a20", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "74dd577b-0474-44c4-b4bc-9113090e3121", - "metadata": {}, - "source": [ - "With the reducer, you can see that the values added in each node are accumulated." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "81646784-5e7d-4096-980d-9fdfafd6e7a3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adding \"A\" to []\n", - "Adding \"B\" to ['A']\n", - "Adding \"C\" to ['A']\n", - "Adding \"D\" to ['A', 'B', 'C']\n" - ] - }, - { - "data": { - "text/plain": [ - "{'aggregate': ['A', 'B', 'C', 'D']}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"aggregate\": []}, {\"configurable\": {\"thread_id\": \"foo\"}})" - ] - }, - { - "cell_type": "markdown", - "id": "ea5495cf-9564-40c6-bc2d-0b2a8f72a5df", - "metadata": {}, - "source": [ - "!!! note\n", - "\n", - " In the above example, nodes `\"b\"` and `\"c\"` are executed concurrently in the same [superstep](../../concepts/low_level/#graphs). Because they are in the same step, node `\"d\"` executes after both `\"b\"` and `\"c\"` are finished.\n", - "\n", - " Importantly, updates from a parallel superstep may not be ordered consistently. If you need a consistent, predetermined ordering of updates from a parallel superstep, you should write the outputs to a separate field in the state together with a value with which to order them." - ] - }, - { - "cell_type": "markdown", - "id": "c392b3d2", - "metadata": {}, - "source": [ - "
Exception handling?\n", - "

LangGraph executes nodes within \"supersteps\", meaning that while parallel branches are executed in parallel, the entire superstep is transactional. If any of these branches raises an exception, none of the updates are applied to the state (the entire superstep errors).

\n", - "

Importantly, when using a checkpointer, results from successful nodes within a superstep are saved, and don't repeat when resumed.

\n", - " If you have error-prone (perhaps want to handle flakey API calls), LangGraph provides two ways to address this:
\n", - "
    \n", - "
  1. You can write regular python code within your node to catch and handle exceptions.
  2. \n", - "
  3. You can set a retry_policy to direct the graph to retry nodes that raise certain types of exceptions. Only failing branches are retried, so you needn't worry about performing redundant work.
  4. \n", - "

\n", - "Together, these let you perform parallel execution and fully control exception handling.\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "08d8162e-1785-4ae1-993f-6d2ed48c22ae", - "metadata": {}, - "source": [ - "## Parallel node fan-out and fan-in with extra steps\n", - "\n", - "The above example showed how to fan-out and fan-in when each path was only one step. But what if one path had more than one step? Let's add a node `b_2` in the \"b\" branch:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "259a7704-5aa0-4e4c-aeef-cca04e8be0ff", - "metadata": {}, - "outputs": [], - "source": [ - "def b_2(state: State):\n", - " print(f'Adding \"B_2\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"B_2\"]}\n", - "\n", - "\n", - "builder = StateGraph(State)\n", - "builder.add_node(a)\n", - "builder.add_node(b)\n", - "builder.add_node(b_2)\n", - "builder.add_node(c)\n", - "builder.add_node(d)\n", - "builder.add_edge(START, \"a\")\n", - "builder.add_edge(\"a\", \"b\")\n", - "builder.add_edge(\"a\", \"c\")\n", - "builder.add_edge(\"b\", \"b_2\")\n", - "# highlight-next-line\n", - "builder.add_edge([\"b_2\", \"c\"], \"d\")\n", - "builder.add_edge(\"d\", END)\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "83320227-8ab3-44c0-b6cf-064a7a425b9f", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "2b8659a9-bacd-4620-a160-8a08d10f7192", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adding \"A\" to []\n", - "Adding \"B\" to ['A']\n", - "Adding \"C\" to ['A']\n", - "Adding \"B_2\" to ['A', 'B', 'C']\n", - "Adding \"D\" to ['A', 'B', 'C', 'B_2']\n" - ] - }, - { - "data": { - "text/plain": [ - "{'aggregate': ['A', 'B', 'C', 'B_2', 'D']}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"aggregate\": []})" - ] - }, - { - "cell_type": "markdown", - "id": "00d33cb0-5a47-4057-bc55-0fc14c6034fc", - "metadata": {}, - "source": [ - "!!! note\n", - "\n", - "

In the above example, nodes `\"b\"` and `\"c\"` are executed concurrently in the same [superstep](../../concepts/low_level/#graphs). What happens in the next step?

\n", - "

We use `add_edge([\"b_2\", \"c\"], \"d\")` here to force node `\"d\"` to only run when both nodes `\"b_2\"` and `\"c\"` have finished execution. If we added two separate edges,\n", - " node `\"d\"` would run twice: after node `b2` finishes and once again after node `c` (in whichever order those nodes finish).

" - ] - }, - { - "cell_type": "markdown", - "id": "d45f4477", - "metadata": {}, - "source": [ - "## Conditional Branching\n", - "\n", - "If your fan-out is not deterministic, you can use [add_conditional_edges](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph.add_conditional_edges) directly." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "95f5e026", - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing import Annotated, Sequence\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "\n", - "\n", - "class State(TypedDict):\n", - " aggregate: Annotated[list, operator.add]\n", - " # Add a key to the state. We will set this key to determine\n", - " # how we branch.\n", - " which: str\n", - "\n", - "\n", - "def a(state: State):\n", - " print(f'Adding \"A\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"A\"]}\n", - "\n", - "\n", - "def b(state: State):\n", - " print(f'Adding \"B\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"B\"]}\n", - "\n", - "\n", - "def c(state: State):\n", - " print(f'Adding \"C\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"C\"]}\n", - "\n", - "\n", - "def d(state: State):\n", - " print(f'Adding \"D\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"D\"]}\n", - "\n", - "\n", - "def e(state: State):\n", - " print(f'Adding \"E\" to {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"E\"]}\n", - "\n", - "\n", - "builder = StateGraph(State)\n", - "builder.add_node(a)\n", - "builder.add_node(b)\n", - "builder.add_node(c)\n", - "builder.add_node(d)\n", - "builder.add_node(e)\n", - "builder.add_edge(START, \"a\")\n", - "\n", - "\n", - "def route_bc_or_cd(state: State) -> Sequence[str]:\n", - " if state[\"which\"] == \"cd\":\n", - " return [\"c\", \"d\"]\n", - " return [\"b\", \"c\"]\n", - "\n", - "\n", - "intermediates = [\"b\", \"c\", \"d\"]\n", - "builder.add_conditional_edges(\n", - " \"a\",\n", - " route_bc_or_cd,\n", - " intermediates,\n", - ")\n", - "for node in intermediates:\n", - " builder.add_edge(node, \"e\")\n", - "\n", - "builder.add_edge(\"e\", END)\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "264da3f8-f5de-499b-8287-73797c1e3511", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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Uv3www8zZ850Op1UbhcJP7nke/LkyQ0bNlB/eZ/qM+QKhSIvL++pp55i/IUJf7jku2vXrm+//XbZsmXUbxrBpZ2AgICioqLXX3/92LFj1G8dI8uaNWtOnz793XffIdk6smuS+fn527Zt++GHH1AVABuz7/J9++23eTzeu+++i6oAlBfTP//88+rqagqusiDB1Lv02FTFAAARpElEQVR8jUbj3Llz+/TpM2PGDIRlIJ4FMm/evPT09OHDh9fVUbf6OfbQjhw5MmLEiFdffRX52SH0j3fJyspKTU3Nzc196aWXsrKyUJdDGubNDluxYsXt27d/++031IUA9D2uR3h4+O7du4uKit577z3UtZCGSbPDrFbr1KlTQ0NDfWe+lE8E12Pp0qVdunSZO3duWVkZ6lpIEBQUxIyDs3379r322mtvvfVWTk4O6lr+gn6ocKfRo0f36NHjtddeGzRoENqx/6NrbGxkwMHZggUL2Gz26tWrURdyNx/qcT0iIyO3bt3qcDhycnJofcQmk8m4XN/qFx7I8ePHn3zyyQEDBrz//vuoa2mFj+7Z2bNn9+vXLzc3d9q0adRMkyOd0Wik75Xt5cuX19fXHz161GevWvtcj9uiQ4cOu3fvrqysfO211+jY9UokEjpOazx58uScOXM6duy4cuVKn02t7/a4Ld58880LFy7k5uaOHz9++vTpqMt5AGazmXbTGhcvXqzVapctWxYQEIC6ljb4bo/bIiUlZffu3WazecKECTR6wIRKpRIKYT1+kXS//PJLWlpaenr6qlWrfD+1NOhxW7zyyivDhg1btGhRWlravHnzUJfTNo1GExsbi7qKthkMhoULF8pkstOnT9PoBk9vnyzpOzZt2vTrr79OmzatT58+qGtpxdixYysrK1vu8iUIgiCITp06UTzP2ksbNmw4c+ZMdnb2U089hbqWB0ODocJdpkyZ8vHHH//000/z5s1rbKTuYd5e6tu3L4vFaum6WCyWUql8/vnnUdd1t3Pnzo0dO1an061cuZJ2qaVlj9uisLBw2bJl2dnZubm5qGv5S319/UsvveTpdD26d+/+1VdfIS3qfzgcjvfee6+2tnbhwoW0GMy0in49bovMzMz9+/fbbLYRI0acPXsWdTl/Cg0NvXMpY4VC8cwzzyCt6H/s2rWrd+/e6enp33zzDX1TS+/gerz00ktfffXV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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "ffe8e4aa-55c1-43b4-ba64-74583359a35b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adding \"A\" to []\n", - "Adding \"B\" to ['A']\n", - "Adding \"C\" to ['A']\n", - "Adding \"E\" to ['A', 'B', 'C']\n" - ] - }, - { - "data": { - "text/plain": [ - "{'aggregate': ['A', 'B', 'C', 'E'], 'which': 'bc'}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"aggregate\": [], \"which\": \"bc\"})" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "3bc6b3b4-a0c8-471a-9029-ddf2472c385c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Adding \"A\" to []\n", - "Adding \"C\" to ['A']\n", - "Adding \"D\" to ['A']\n", - "Adding \"E\" to ['A', 'C', 'D']\n" - ] - }, - { - "data": { - "text/plain": [ - "{'aggregate': ['A', 'C', 'D', 'E'], 'which': 'cd'}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"aggregate\": [], \"which\": \"cd\"})" - ] - }, - { - "cell_type": "markdown", - "id": "639a3653-0fa3-4b6d-bf53-63479c6b00fe", - "metadata": {}, - "source": [ - "## Next steps\n", - "\n", - "- Continue with the [Graph API Basics](../../how-tos/#graph-api-basics) guides.\n", - "- Learn how to create [map-reduce](../../how-tos/map-reduce/) branches in which different states can be distributed to multiple instances of a node." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/command.ipynb b/docs/docs/how-tos/command.ipynb deleted file mode 100644 index cf0b01ae9..000000000 --- a/docs/docs/how-tos/command.ipynb +++ /dev/null @@ -1,397 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d33ecddc-6818-41a3-9d0d-b1b1cbcd286d", - "metadata": {}, - "source": [ - "# How to combine control flow and state updates with Command" - ] - }, - { - "cell_type": "markdown", - "id": "7c0a8d03-80b4-47fd-9b17-e26aa9b081f3", - "metadata": {}, - "source": [ - "!!! info \"Prerequisites\"\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [State](../../concepts/low_level#state)\n", - " - [Nodes](../../concepts/low_level#nodes)\n", - " - [Edges](../../concepts/low_level#edges)\n", - " - [Command](../../concepts/low_level#command)\n", - "\n", - "It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a `Command` object from node functions:\n", - "\n", - "```python\n", - "def my_node(state: State) -> Command[Literal[\"my_other_node\"]]:\n", - " return Command(\n", - " # state update\n", - " update={\"foo\": \"bar\"},\n", - " # control flow\n", - " goto=\"my_other_node\"\n", - " )\n", - "```\n", - "\n", - "If you are using [subgraphs](#subgraphs), you might want to navigate from a node within a subgraph to a different subgraph (i.e. a different node in the parent graph). To do so, you can specify `graph=Command.PARENT` in `Command`:\n", - "\n", - "```python\n", - "def my_node(state: State) -> Command[Literal[\"my_other_node\"]]:\n", - " return Command(\n", - " update={\"foo\": \"bar\"},\n", - " goto=\"other_subgraph\", # where `other_subgraph` is a node in the parent graph\n", - " graph=Command.PARENT\n", - " )\n", - "```\n", - "\n", - "!!! important \"State updates with `Command.PARENT`\"\n", - "\n", - " When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](../../concepts/low_level#schema), you **must** define a [reducer](../../concepts/low_level#reducers) for the key you're updating in the parent graph state. See this [example](#navigating-to-a-node-in-a-parent-graph) below.\n", - "\n", - "This guide shows how you can do use `Command` to add dynamic control flow in your LangGraph app." - ] - }, - { - "cell_type": "markdown", - "id": "d1c3f866-8c20-40c7-a201-35f6c9f4b680", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "6999c7fe-31bb-4c19-946a-85c2edc57da7", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "0f131c92-4744-431c-a89c-7c382a15b79f", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "f22c228f-6882-4757-8e7e-1ca51328af4a", - "metadata": {}, - "source": [ - "Let's create a simple graph with 3 nodes: A, B and C. We will first execute node A, and then decide whether to go to Node B or Node C next based on the output of node A." - ] - }, - { - "cell_type": "markdown", - "id": "6a08d957-b3d2-4538-bf4a-68ef90a51b98", - "metadata": {}, - "source": [ - "## Basic usage" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "4539b81b-09e9-4660-ac55-1b1775e13892", - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "from typing_extensions import TypedDict, Literal\n", - "\n", - "from langgraph.graph import StateGraph, START\n", - "from langgraph.types import Command\n", - "\n", - "\n", - "# Define graph state\n", - "class State(TypedDict):\n", - " foo: str\n", - "\n", - "\n", - "# Define the nodes\n", - "\n", - "\n", - "def node_a(state: State) -> Command[Literal[\"node_b\", \"node_c\"]]:\n", - " print(\"Called A\")\n", - " value = random.choice([\"a\", \"b\"])\n", - " # this is a replacement for a conditional edge function\n", - " if value == \"a\":\n", - " goto = \"node_b\"\n", - " else:\n", - " goto = \"node_c\"\n", - "\n", - " # note how Command allows you to BOTH update the graph state AND route to the next node\n", - " return Command(\n", - " # this is the state update\n", - " update={\"foo\": value},\n", - " # this is a replacement for an edge\n", - " goto=goto,\n", - " )\n", - "\n", - "\n", - "def node_b(state: State):\n", - " print(\"Called B\")\n", - " return {\"foo\": state[\"foo\"] + \"b\"}\n", - "\n", - "\n", - "def node_c(state: State):\n", - " print(\"Called C\")\n", - " return {\"foo\": state[\"foo\"] + \"c\"}" - ] - }, - { - "cell_type": "markdown", - "id": "badc25eb-4876-482e-bb10-d763023cdaad", - "metadata": {}, - "source": [ - "We can now create the `StateGraph` with the above nodes. Notice that the graph doesn't have [conditional edges](../../concepts/low_level#conditional-edges) for routing! This is because control flow is defined with `Command` inside `node_a`." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "d6711650-4380-4551-a007-2805f49ab2d8", - "metadata": {}, - "outputs": [], - "source": [ - "builder = StateGraph(State)\n", - "builder.add_edge(START, \"node_a\")\n", - "builder.add_node(node_a)\n", - "builder.add_node(node_b)\n", - "builder.add_node(node_c)\n", - "# NOTE: there are no edges between nodes A, B and C!\n", - "\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "0ab344c5-d634-4d7d-b3b4-edf4fa875311", - "metadata": {}, - "source": [ - "!!! important\n", - "\n", - " You might have noticed that we used `Command` as a return type annotation, e.g. `Command[Literal[\"node_b\", \"node_c\"]]`. This is necessary for the graph rendering and tells LangGraph that `node_a` can navigate to `node_b` and `node_c`." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "eeb810e5-8822-4c09-8d53-c55cd0f5d42e", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import display, Image\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "58fb6c32-e6fb-4c94-8182-e351ed52a45d", - "metadata": {}, - "source": [ - "If we run the graph multiple times, we'd see it take different paths (A -> B or A -> C) based on the random choice in node A." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "d88a5d9b-ee08-4ed4-9c65-6e868210bfac", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Called A\n", - "Called C\n" - ] - }, - { - "data": { - "text/plain": [ - "{'foo': 'bc'}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"foo\": \"\"})" - ] - }, - { - "cell_type": "markdown", - "id": "68986cc4-97ec-43a1-b95d-5273d7ffc25a", - "metadata": {}, - "source": [ - "## Navigating to a node in a parent graph" - ] - }, - { - "cell_type": "markdown", - "id": "02ccddf2-978c-41bf-b2eb-2d0c4b3f5d81", - "metadata": {}, - "source": [ - "Now let's demonstrate how you can navigate from inside a subgraph to a different node in a parent graph. We'll do so by changing `node_a` in the above example into a single-node graph that we'll add as a subgraph to our parent graph." - ] - }, - { - "cell_type": "markdown", - "id": "6be0aeb9-e138-4adc-a1df-5d743a8eb348", - "metadata": {}, - "source": [ - "!!! important \"State updates with `Command.PARENT`\"\n", - "\n", - " When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](../../concepts/low_level#schema), you **must** define a [reducer](../../concepts/low_level#reducers) for the key you're updating in the parent graph state." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "91351541-67af-4c73-9437-426599dcf81e", - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing_extensions import Annotated\n", - "\n", - "\n", - "class State(TypedDict):\n", - " # NOTE: we define a reducer here\n", - " # highlight-next-line\n", - " foo: Annotated[str, operator.add]\n", - "\n", - "\n", - "def node_a(state: State):\n", - " print(\"Called A\")\n", - " value = random.choice([\"a\", \"b\"])\n", - " # this is a replacement for a conditional edge function\n", - " if value == \"a\":\n", - " goto = \"node_b\"\n", - " else:\n", - " goto = \"node_c\"\n", - "\n", - " # note how Command allows you to BOTH update the graph state AND route to the next node\n", - " return Command(\n", - " update={\"foo\": value},\n", - " goto=goto,\n", - " # this tells LangGraph to navigate to node_b or node_c in the parent graph\n", - " # NOTE: this will navigate to the closest parent graph relative to the subgraph\n", - " # highlight-next-line\n", - " graph=Command.PARENT,\n", - " )\n", - "\n", - "\n", - "subgraph = StateGraph(State).add_node(node_a).add_edge(START, \"node_a\").compile()\n", - "\n", - "\n", - "def node_b(state: State):\n", - " print(\"Called B\")\n", - " # NOTE: since we've defined a reducer, we don't need to manually append\n", - " # new characters to existing 'foo' value. instead, reducer will append these\n", - " # automatically (via operator.add)\n", - " # highlight-next-line\n", - " return {\"foo\": \"b\"}\n", - "\n", - "\n", - "def node_c(state: State):\n", - " print(\"Called C\")\n", - " # highlight-next-line\n", - " return {\"foo\": \"c\"}" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "beb61d02-c868-4c2b-b83f-1dfd280f1c8e", - "metadata": {}, - "outputs": [], - "source": [ - "builder = StateGraph(State)\n", - "builder.add_edge(START, \"subgraph\")\n", - "builder.add_node(\"subgraph\", subgraph)\n", - "builder.add_node(node_b)\n", - "builder.add_node(node_c)\n", - "\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "3f07b704-1fe2-48a3-ad40-c9bc7698cb1c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Called A\n", - "Called C\n" - ] - }, - { - "data": { - "text/plain": [ - "{'foo': 'bc'}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"foo\": \"\"})" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/configuration.ipynb b/docs/docs/how-tos/configuration.ipynb deleted file mode 100644 index 589131b95..000000000 --- a/docs/docs/how-tos/configuration.ipynb +++ /dev/null @@ -1,353 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "6e6a0a39-9a4c-47ae-a238-1a3a847eea5b", - "metadata": {}, - "source": [ - "# How to add runtime configuration to your graph\n", - "\n", - "Sometimes you want to be able to configure your agent when calling it. \n", - "Examples of this include configuring which LLM to use.\n", - "Below we walk through an example of doing so.\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "03df6e04", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "a00c45e0", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "55e8be3b", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "df1ff9cf-f8d2-4109-adf9-2adec83f5a95", - "metadata": {}, - "source": [ - "## Define graph\n", - "\n", - "First, let's create a very simple graph" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "816523d0-0b59-47cf-9f4c-4838024efe22", - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing import Annotated, Sequence\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.messages import BaseMessage, HumanMessage\n", - "\n", - "from langgraph.graph import END, StateGraph, START\n", - "\n", - "model = ChatAnthropic(model_name=\"claude-2.1\")\n", - "\n", - "\n", - "class AgentState(TypedDict):\n", - " messages: Annotated[Sequence[BaseMessage], operator.add]\n", - "\n", - "\n", - "def _call_model(state):\n", - " state[\"messages\"]\n", - " response = model.invoke(state[\"messages\"])\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Define a new graph\n", - "builder = StateGraph(AgentState)\n", - "builder.add_node(\"model\", _call_model)\n", - "builder.add_edge(START, \"model\")\n", - "builder.add_edge(\"model\", END)\n", - "\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "69a1dd47-c5b3-4e04-af56-45682f74d61f", - "metadata": {}, - "source": [ - "## Configure the graph\n", - "\n", - "Great! Now let's suppose that we want to extend this example so the user is able to choose from multiple llms.\n", - "We can easily do that by passing in a config. Any configuration information needs to be passed inside `configurable` key as shown below.\n", - "This config is meant to contain things are not part of the input (and therefore that we don't want to track as part of the state)." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "c01f1e7c-8e8b-4e26-98f7-56ac225077b4", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_openai import ChatOpenAI\n", - "from typing import Optional\n", - "from langchain_core.runnables.config import RunnableConfig\n", - "\n", - "openai_model = ChatOpenAI()\n", - "\n", - "models = {\n", - " \"anthropic\": model,\n", - " \"openai\": openai_model,\n", - "}\n", - "\n", - "\n", - "def _call_model(state: AgentState, config: RunnableConfig):\n", - " # Access the config through the configurable key\n", - " model_name = config[\"configurable\"].get(\"model\", \"anthropic\")\n", - " model = models[model_name]\n", - " response = model.invoke(state[\"messages\"])\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Define a new graph\n", - "builder = StateGraph(AgentState)\n", - "builder.add_node(\"model\", _call_model)\n", - "builder.add_edge(START, \"model\")\n", - "builder.add_edge(\"model\", END)\n", - "\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "7741b75c-55ba-4c78-bbb1-5dc20a210f11", - "metadata": {}, - "source": [ - "If we call it with no configuration, it will use the default as we defined it (Anthropic)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "ef50f048-fc43-40c0-b713-346408fcf052", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='hi', additional_kwargs={}, response_metadata={}),\n", - " AIMessage(content='Hello!', additional_kwargs={}, response_metadata={'id': 'msg_01WFXkfgK8AvSckLvYYrHshi', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 10, 'output_tokens': 6}}, id='run-ece54b16-f8fc-4201-8405-b97122edf8d8-0', usage_metadata={'input_tokens': 10, 'output_tokens': 6, 'total_tokens': 16})]}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"messages\": [HumanMessage(content=\"hi\")]})" - ] - }, - { - "cell_type": "markdown", - "id": "f6896b32-9b25-4342-bfd0-29a3d329a06a", - "metadata": {}, - "source": [ - "We can also call it with a config to get it to use a different model." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "f2f7c74b-9fb0-41c6-9728-dcf9d8a3c397", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='hi', additional_kwargs={}, response_metadata={}),\n", - " AIMessage(content='Hello! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 8, 'total_tokens': 17, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-f8331964-d811-4b44-afb8-56c30ade7c15-0', usage_metadata={'input_tokens': 8, 'output_tokens': 9, 'total_tokens': 17})]}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "config = {\"configurable\": {\"model\": \"openai\"}}\n", - "graph.invoke({\"messages\": [HumanMessage(content=\"hi\")]}, config=config)" - ] - }, - { - "cell_type": "markdown", - "id": "b4c7eaf1-4ee0-42b3-971d-273a108f205f", - "metadata": {}, - "source": [ - "We can also adapt our graph to take in more configuration! Like a system message for example." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "f0393a43-9fbe-4056-972f-3e91ea329041", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import SystemMessage\n", - "\n", - "\n", - "# We can define a config schema to specify the configuration options for the graph\n", - "# A config schema is useful for indicating which fields are available in the configurable dict inside the config\n", - "class ConfigSchema(TypedDict):\n", - " model: Optional[str]\n", - " system_message: Optional[str]\n", - "\n", - "\n", - "def _call_model(state: AgentState, config: RunnableConfig):\n", - " # Access the config through the configurable key\n", - " model_name = config[\"configurable\"].get(\"model\", \"anthropic\")\n", - " model = models[model_name]\n", - " messages = state[\"messages\"]\n", - " if \"system_message\" in config[\"configurable\"]:\n", - " messages = [\n", - " SystemMessage(content=config[\"configurable\"][\"system_message\"])\n", - " ] + messages\n", - " response = model.invoke(messages)\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Define a new graph - note that we pass in the configuration schema here, but it is not necessary\n", - "workflow = StateGraph(AgentState, ConfigSchema)\n", - "workflow.add_node(\"model\", _call_model)\n", - "workflow.add_edge(START, \"model\")\n", - "workflow.add_edge(\"model\", END)\n", - "\n", - "graph = workflow.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "718685f7-4cdd-4181-9fc8-e7762d584727", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='hi', additional_kwargs={}, response_metadata={}),\n", - " AIMessage(content='Hello!', additional_kwargs={}, response_metadata={'id': 'msg_01VgCANVHr14PsHJSXyKkLVh', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 10, 'output_tokens': 6}}, id='run-f8c5f18c-be58-4e44-9a4e-d43692d7eed1-0', usage_metadata={'input_tokens': 10, 'output_tokens': 6, 'total_tokens': 16})]}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"messages\": [HumanMessage(content=\"hi\")]})" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "e043a719-f197-46ef-9d45-84740a39aeb0", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='hi', additional_kwargs={}, response_metadata={}),\n", - " AIMessage(content='Ciao!', additional_kwargs={}, response_metadata={'id': 'msg_011YuCYQk1Rzc8PEhVCpQGr6', 'model': 'claude-2.1', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 14, 'output_tokens': 7}}, id='run-a583341e-5868-4e8c-a536-881338f21252-0', usage_metadata={'input_tokens': 14, 'output_tokens': 7, 'total_tokens': 21})]}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "config = {\"configurable\": {\"system_message\": \"respond in italian\"}}\n", - "graph.invoke({\"messages\": [HumanMessage(content=\"hi\")]}, config=config)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.1" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/cross-thread-persistence.ipynb b/docs/docs/how-tos/cross-thread-persistence.ipynb deleted file mode 100644 index f1c2b33fd..000000000 --- a/docs/docs/how-tos/cross-thread-persistence.ipynb +++ /dev/null @@ -1,357 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "d2eecb96-cf0e-47ed-8116-88a7eaa4236d", - "metadata": {}, - "source": [ - "# How to add cross-thread persistence to your graph\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "In the [previous guide](https://langchain-ai.github.io/langgraph/how-tos/persistence/) you learned how to persist graph state across multiple interactions on a single [thread](). LangGraph also allows you to persist data across **multiple threads**. For instance, you can store information about users (their names or preferences) in a shared memory and reuse them in the new conversational threads.\n", - "\n", - "In this guide, we will show how to construct and use a graph that has a shared memory implemented using the [Store](https://langchain-ai.github.io/langgraph/reference/store/#langgraph.store.base.BaseStore) interface.\n", - "\n", - "
\n", - "

Note

\n", - "

\n", - " Support for the Store API that is used in this guide was added in LangGraph v0.2.32.\n", - "

\n", - "

\n", - " Support for index and query arguments of the Store API that is used in this guide was added in LangGraph v0.2.54.\n", - "

\n", - "
\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "3457aadf", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langchain_openai langgraph" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "aa2c64a7", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "51b6817d", - "metadata": {}, - "source": [ - "!!! tip \"Set up [LangSmith](https://smith.langchain.com) for LangGraph development\"\n", - "\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started [here](https://docs.smith.langchain.com)" - ] - }, - { - "cell_type": "markdown", - "id": "c4c550b5-1954-496b-8b9d-800361af17dc", - "metadata": {}, - "source": [ - "## Define store\n", - "\n", - "In this example we will create a graph that will be able to retrieve information about a user's preferences. We will do so by defining an `InMemoryStore` - an object that can store data in memory and query that data. We will then pass the store object when compiling the graph. This allows each node in the graph to access the store: when you define node functions, you can define `store` keyword argument, and LangGraph will automatically pass the store object you compiled the graph with.\n", - "\n", - "When storing objects using the `Store` interface you define two things:\n", - "\n", - "* the namespace for the object, a tuple (similar to directories)\n", - "* the object key (similar to filenames)\n", - "\n", - "In our example, we'll be using `(\"memories\", )` as namespace and random UUID as key for each new memory.\n", - "\n", - "Importantly, to determine the user, we will be passing `user_id` via the config keyword argument of the node function.\n", - "\n", - "Let's first define an `InMemoryStore` already populated with some memories about the users." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "a7f303d6-612e-4e34-bf36-29d4ed25d802", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.store.memory import InMemoryStore\n", - "from langchain_openai import OpenAIEmbeddings\n", - "\n", - "in_memory_store = InMemoryStore(\n", - " index={\n", - " \"embed\": OpenAIEmbeddings(model=\"text-embedding-3-small\"),\n", - " \"dims\": 1536,\n", - " }\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "3389c9f4-226d-40c7-8bfc-ee8aac24f79d", - "metadata": {}, - "source": [ - "## Create graph" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "2a30a362-528c-45ee-9df6-630d2d843588", - "metadata": {}, - "outputs": [], - "source": [ - "import uuid\n", - "from typing import Annotated\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langgraph.graph import StateGraph, MessagesState, START\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.store.base import BaseStore\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", - "\n", - "\n", - "# NOTE: we're passing the Store param to the node --\n", - "# this is the Store we compile the graph with\n", - "def call_model(state: MessagesState, config: RunnableConfig, *, store: BaseStore):\n", - " user_id = config[\"configurable\"][\"user_id\"]\n", - " namespace = (\"memories\", user_id)\n", - " memories = store.search(namespace, query=str(state[\"messages\"][-1].content))\n", - " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", - " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", - "\n", - " # Store new memories if the user asks the model to remember\n", - " last_message = state[\"messages\"][-1]\n", - " if \"remember\" in last_message.content.lower():\n", - " memory = \"User name is Bob\"\n", - " store.put(namespace, str(uuid.uuid4()), {\"data\": memory})\n", - "\n", - " response = model.invoke(\n", - " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", - " )\n", - " return {\"messages\": response}\n", - "\n", - "\n", - "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"call_model\", call_model)\n", - "builder.add_edge(START, \"call_model\")\n", - "\n", - "# NOTE: we're passing the store object here when compiling the graph\n", - "graph = builder.compile(checkpointer=MemorySaver(), store=in_memory_store)\n", - "# If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass the store or checkpointer when compiling the graph, since it's done automatically." - ] - }, - { - "cell_type": "markdown", - "id": "f22a4a18-67e4-4f0b-b655-a29bbe202e1c", - "metadata": {}, - "source": [ - "
\n", - "

Note

\n", - "

\n", - " If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass store when compiling the graph, since it's done automatically.\n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "552d4e33-556d-4fa5-8094-2a076bc21529", - "metadata": {}, - "source": [ - "## Run the graph!" - ] - }, - { - "cell_type": "markdown", - "id": "1842c626-6cd9-4f58-b549-58978e478098", - "metadata": {}, - "source": [ - "Now let's specify a user ID in the config and tell the model our name:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c871a073-a466-46ad-aafe-2b870831057e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Hi! Remember: my name is Bob\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Hello Bob! It's nice to meet you. I'll remember that your name is Bob. How can I assist you today?\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\", \"user_id\": \"1\"}}\n", - "input_message = {\"role\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "d862be40-1f8a-4057-81c4-b7bf073dc4c1", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what is my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Your name is Bob.\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"2\", \"user_id\": \"1\"}}\n", - "input_message = {\"role\": \"user\", \"content\": \"what is my name?\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "80fd01ec-f135-4811-8743-daff8daea422", - "metadata": {}, - "source": [ - "We can now inspect our in-memory store and verify that we have in fact saved the memories for the user:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "76cde493-89cf-4709-a339-207d2b7e9ea7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'data': 'User name is Bob'}\n" - ] - } - ], - "source": [ - "for memory in in_memory_store.search((\"memories\", \"1\")):\n", - " print(memory.value)" - ] - }, - { - "cell_type": "markdown", - "id": "23f5d7eb-af23-4131-b8fd-2a69e74e6e55", - "metadata": {}, - "source": [ - "Let's now run the graph for another user to verify that the memories about the first user are self contained:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "d362350b-d730-48bd-9652-983812fd7811", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what is my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I apologize, but I don't have any information about your name. As an AI assistant, I don't have access to personal information about users unless it has been specifically shared in our conversation. If you'd like, you can tell me your name and I'll be happy to use it in our discussion.\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"3\", \"user_id\": \"2\"}}\n", - "input_message = {\"role\": \"user\", \"content\": \"what is my name?\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/deploy-self-hosted.md b/docs/docs/how-tos/deploy-self-hosted.md deleted file mode 100644 index 29a6b9e7b..000000000 --- a/docs/docs/how-tos/deploy-self-hosted.md +++ /dev/null @@ -1,154 +0,0 @@ -# How to do a Self-hosted deployment of LangGraph - -!!! info "Prerequisites" - - - [Application Structure](../concepts/application_structure.md) - - [Deployment Options](../concepts/deployment_options.md) - -This how-to guide will walk you through how to create a docker image from an existing LangGraph application, so you can deploy it on your own infrastructure. - -## How it works - -With the self-hosted deployment option, you are responsible for managing the infrastructure, including setting up and maintaining necessary databases, Redis instances, and other services. - -You will need to do the following: - -1. Deploy Redis and Postgres instances on your own infrastructure. -2. Build a docker image with the [LangGraph Server](../concepts/langgraph_server.md) using the [LangGraph CLI](../concepts/langgraph_cli.md). -3. Deploy a web server that will run the docker image and pass in the necessary environment variables. - -## Helm Chart - -If you would like to deploy LangGraph Cloud on Kubernetes, you can use this [Helm chart](https://github.com/langchain-ai/helm/blob/main/charts/langgraph-cloud/README.md). - -## Environment Variables - -You will eventually need to pass in the following environment variables to the LangGraph Deploy server: - -- `REDIS_URI`: Connection details to a Redis instance. Redis will be used as a pub-sub broker to enable streaming real time output from background runs. The value of `REDIS_URI` must be a valid [Redis connection URI](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis.from_url). - - !!! Note "Shared Redis Instance" - Multiple self-hosted deployments can share the same Redis instance. For example, for `Deployment A`, `REDIS_URI` can be set to `redis://:/1` and for `Deployment B`, `REDIS_URI` can be set to `redis://:/2`. - - `1` and `2` are different database numbers within the same instance, but `` is shared. **The same database number cannot be used for separate deployments**. - -- `DATABASE_URI`: Postgres connection details. Postgres will be used to store assistants, threads, runs, persist thread state and long term memory, and to manage the state of the background task queue with 'exactly once' semantics. The value of `DATABASE_URI` must be a valid [Postgres connection URI](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-URIS). - - !!! Note "Shared Postgres Instance" - Multiple self-hosted deployments can share the same Postgres instance. For example, for `Deployment A`, `DATABASE_URI` can be set to `postgres://:@/?host=` and for `Deployment B`, `DATABASE_URI` can be set to `postgres://:@/?host=`. - - `` and `database_name_2` are different databases within the same instance, but `` is shared. **The same database cannot be used for separate deployments**. - -- `LANGSMITH_API_KEY`: (If using [Self-Hosted Data Plane](../concepts/deployment_options.md#self-hosted-data-plane)) LangSmith API key. This will be used to authenticate ONCE at server start up. -- `LANGGRAPH_CLOUD_LICENSE_KEY`: (If using [Self-Hosted Enterprise](../concepts/deployment_options.md#self-hosted-enterprise)) LangGraph Platform license key. This will be used to authenticate ONCE at server start up. -- `LANGCHAIN_ENDPOINT`: To send traces to a [self-hosted LangSmith](https://docs.smith.langchain.com/self_hosting) instance, set `LANGCHAIN_ENDPOINT` to the hostname of the self-hosted LangSmith instance. - - -## Build the Docker Image - -Please read the [Application Structure](../concepts/application_structure.md) guide to understand how to structure your LangGraph application. - -If the application is structured correctly, you can build a docker image with the LangGraph Deploy server. - -To build the docker image, you first need to install the CLI: - -```shell -pip install -U langgraph-cli -``` - -You can then use: - -``` -langgraph build -t my-image -``` - -This will build a docker image with the LangGraph Deploy server. The `-t my-image` is used to tag the image with a name. - -When running this server, you need to pass three environment variables: - -## Running the application locally - -### Using Docker - -```shell -docker run \ - --env-file .env \ - -p 8123:8000 \ - -e REDIS_URI="foo" \ - -e DATABASE_URI="bar" \ - -e LANGSMITH_API_KEY="baz" \ - my-image -``` - -If you want to run this quickly without setting up a separate Redis and Postgres instance, you can use this docker compose file. - -!!! note - - * You need to replace `my-image` with the name of the image you built in the previous step (from `langgraph build`). - and you should provide appropriate values for `REDIS_URI`, `DATABASE_URI`, and `LANGSMITH_API_KEY`. - * If your application requires additional environment variables, you can pass them in a similar way. - * If using [Self-Hosted Enterprise](../concepts/deployment_options.md#self-hosted-enterprise), you must provide `LANGGRAPH_CLOUD_LICENSE_KEY` as an additional environment variable. - - -### Using Docker Compose - -```yml -volumes: - langgraph-data: - driver: local -services: - langgraph-redis: - image: redis:6 - healthcheck: - test: redis-cli ping - interval: 5s - timeout: 1s - retries: 5 - langgraph-postgres: - image: postgres:16 - ports: - - "5433:5432" - environment: - POSTGRES_DB: postgres - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - volumes: - - langgraph-data:/var/lib/postgresql/data - healthcheck: - test: pg_isready -U postgres - start_period: 10s - timeout: 1s - retries: 5 - interval: 5s - langgraph-api: - image: ${IMAGE_NAME} - ports: - - "8123:8000" - depends_on: - langgraph-redis: - condition: service_healthy - langgraph-postgres: - condition: service_healthy - env_file: - - .env - environment: - REDIS_URI: redis://langgraph-redis:6379 - LANGSMITH_API_KEY: ${LANGSMITH_API_KEY} - POSTGRES_URI: postgres://postgres:postgres@langgraph-postgres:5432/postgres?sslmode=disable -``` - -You can then run `docker compose up` with this Docker compose file in the same folder. - -This will spin up LangGraph Deploy on port `8123` (if you want to change this, you can change this by changing the ports in the `langgraph-api` volume). - -You can test that the application is up by checking: - -```shell -curl --request GET --url 0.0.0.0:8123/ok -``` -Assuming everything is running correctly, you should see a response like: - -```shell -{"ok":true} -``` - diff --git a/docs/docs/how-tos/graph-api.ipynb b/docs/docs/how-tos/graph-api.ipynb new file mode 100644 index 000000000..740ef4453 --- /dev/null +++ b/docs/docs/how-tos/graph-api.ipynb @@ -0,0 +1,3385 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9c19faa1-795c-451e-95e4-7aa40a19aa20", + "metadata": {}, + "source": [ + "# How to use the graph API\n", + "\n", + "This guide demonstrates the basics of LangGraph's Graph API. It walks through [state](#define-and-update-state), as well as composing common graph structures such as [sequences](#create-a-sequence-of-steps), [branches](#create-branches), and [loops](#create-and-control-loops). It also covers LangGraph's control features, including the [Send API](#map-reduce-and-the-send-api) for map-reduce workflows and the [Command API](#combine-control-flow-and-state-updates-with-command) for combining state updates with \"hops\" across nodes." + ] + }, + { + "cell_type": "markdown", + "id": "f6fcda61-9c21-43de-af0d-0d9efb063c40", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "Install `langgraph`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f031bc56-26f5-4ece-b27e-3c87b3b34f0a", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install -qU langgraph" + ] + }, + { + "cell_type": "markdown", + "id": "55c22136-74cc-495a-94ab-82ccac247cef", + "metadata": {}, + "source": [ + "
\n", + "

Set up LangSmith for better debugging

\n", + "

\n", + " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM aps built with LangGraph — read more about how to get started in the docs. \n", + "

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "b462f26d-8795-4dc2-9420-722d3e21656c", + "metadata": {}, + "source": [ + "## Define and update state\n", + "\n", + "Here we show how to define and update [state](../../concepts/low_level/#state) in LangGraph. We will demonstrate:\n", + "\n", + "1. How to use state to define a graph's [schema](../../concepts/low_level/#schema)\n", + "2. How to use [reducers](../../concepts/low_level/#reducers) to control how state updates are processed." + ] + }, + { + "cell_type": "markdown", + "id": "ca7ac66a-a3ae-43c6-bb9d-7ee2bd0030f0", + "metadata": {}, + "source": [ + "### Define state\n", + "\n", + "[State](../../concepts/low_level/#state) in LangGraph can be a `TypedDict`, `Pydantic` model, or dataclass. Below we will use `TypedDict`. See [this section](#use-pydantic-models-for-graph-state) for detail on using Pydantic.\n", + "\n", + "By default, graphs will have the same input and output schema, and the state determines that schema. See [this section](#define-input-and-output-schemas) for how to define distinct input and output schemas.\n", + "\n", + "Let's consider a simple example using [messages](../../concepts/low_level/#messagesstate). This represents a versatile formulation of state for many LLM applications. See our [concepts page](../../concepts/low_level/#working-with-messages-in-graph-state) for more detail." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e7c3b392-50fb-4af3-bf2d-7b769f47efc6", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.messages import AnyMessage\n", + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "class State(TypedDict):\n", + " messages: list[AnyMessage]\n", + " extra_field: int" + ] + }, + { + "cell_type": "markdown", + "id": "c3555791-9dc9-4593-923e-9aa599d4c547", + "metadata": {}, + "source": [ + "This state tracks a list of [message](https://python.langchain.com/docs/concepts/messages/) objects, as well as an extra integer field.\n", + "\n", + "### Update state\n", + "\n", + "Let's build an example graph with a single node. Our [node](../../concepts/low_level/#nodes) is just a Python function that reads our graph's state and makes updates to it. The first argument to this function will always be the state:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "f5db493b-c977-4f15-a06f-27b460cd7e4c", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.messages import AIMessage\n", + "\n", + "\n", + "def node(state: State):\n", + " messages = state[\"messages\"]\n", + " new_message = AIMessage(\"Hello!\")\n", + "\n", + " return {\"messages\": messages + [new_message], \"extra_field\": 10}" + ] + }, + { + "cell_type": "markdown", + "id": "9f6cef5d-2635-45bc-a415-b422bb571685", + "metadata": {}, + "source": [ + "This node simply appends a message to our message list, and populates an extra field.\n", + "\n", + "!!! important\n", + "\n", + " Nodes should return updates to the state directly, instead of mutating the state.\n", + "\n", + "Let's next define a simple graph containing this node. We use [StateGraph](../../concepts/low_level/#stategraph) to define a graph that operates on this state. We then use [add_node](../../concepts/low_level/#nodes) populate our graph." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "92402ca2-9e46-4ad9-8378-83f98f597c00", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import StateGraph\n", + "\n", + "builder = StateGraph(State)\n", + "builder.add_node(node)\n", + "builder.set_entry_point(\"node\")\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "markdown", + "id": "f765d37d-3793-4ac9-90e5-fe28c6142202", + "metadata": {}, + "source": [ + "LangGraph provides built-in utilities for visualizing your graph. Let's inspect our graph. See [this section](#visualize-your-graph) for detail on visualization." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "263470d0-a9fa-48bc-86b1-c5a28b242aec", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGsAAACGCAIAAABVB+MHAAAAAXNSR0IArs4c6QAADyxJREFUeJztnX9UE1e+wG8yk1+TXyQEEuQ3DxEURFt0qdIKK9ouRShH+2wtfeqrnrpl23PW/tofdm1Pz7o9bHfrtn2v+LZsz2n1PLX7+kqzulb7LFuBomDf2qAgP4IoIUh+kUkmyUxmkv0jLnUlv0gmZHDz+c/MnTtfP9yZufO9d+6wvF4vSBAF7HgHsOBJGIyWhMFoSRiMloTBaEkYjBY4yv1tZrfV5HbYKAdKkW6vx7MA+kYQDGCYjUggRAzLVBxEFJUEVmT9QZMeH/kWG9VgXIQFvCxEDCESSCCEPdQCMAhzWHaUdKCUw0biTg+Hy84rEeaXiiTJnAhqm7NB+zTZpTZ6AUhScHJLhKkZ/AiOyij0o06tBrPcJEQyeE2tgsuf25VtbgZ7Tpv7uqxrNimW3Cuee6hMR9Nh7fqTsfzh5NL7k8Lfaw4G297T5a8ULSuXRhrhwuDiF2bTJLGxURVm+XBbbOsroyu/L7vr9QEA7q2WZxcK297ThbuDNwze36c1TrjCKXnXMPRX29E3r4dTMvRZ3PaebuX3ZVlLEBr+vguK/vOoTuusflwZvFgIg71nzAIRtOy+u//k9UvvF2aBMMR/P9h10D5Najqt/7T6AABl1fIvjxuClwlmsEttXLNJQXdUC4z7apO71MYgBQIaNOlxLwB3Zb9vTty7XmacwF0YGahAQIMj32JJikieciKjr68Px/F47R4coQTW9jkCbQ1ocFSD5ZYIYxTTHajV6h07djidzrjsHpK8EpFWYw+01b9B1OzmIex5e+aNuPn4OhKxa30+couFdgsZKO0UwKDJHaMhvLGxsT179lRUVNTU1Bw4cMDj8ajV6jfeeAMAUF1dXVZWplarAQA3b97cv39/dXV1eXn51q1bT5065dt9enq6rKzso48+2rdvX0VFxe7du/3uTjuk22s1uv1u8p8ac9goRAzFIpTXX3/92rVrzz//PIZhvb29bDZ77dq1jY2Nhw8fPnjwoEgkysrKAgCQJHn58uUtW7YkJSWdPXt23759mZmZy5Yt81XS2tr66KOPtrS0QBCkVCpn7047iARyoJQs1c+mAAZRCpHExODExERhYWFDQwMAoLGxEQAgl8szMjIAAMXFxUlJt5Ii6enpH3/8MYvFAgDU19dXV1e3t7fPGCwpKWlqapqpc/butCOUwBjq/3Yc8E7C4cZkAKCmpqa7u7u5udlsNgcvOTg4uHfv3oceeqihoYGiKJPJNLNp9erVsYgtCFw+O9DDm39NfCHbZgnYA4qGpqamvXv3nj59uq6u7vjx44GK9fT0bN++nSCI/fv3Nzc3S6VSj8czs1UgEMQitiBYjW5E7P989f8rIoYdtpgYZLFY27Ztq6+vP3DgQHNzc0FBwYoVK3ybbv8jv//++xkZGQcPHoRhOExlMZ2+EuTG4L8NimQQTxCTs9jX8xAKhXv27AEADAwMzAgyGL57Ap2eni4oKPDpIwjC4XDc3gbvYPbutCOUQmKZ/+cL/21QruQZxolpA5GUwqU3lJdfflkkEpWXl3d0dAAAioqKAAClpaUQBL355pt1dXU4jm/evNnXL2lra5NKpUeOHEFRdGRkJFArm707vTHrhp0eEgQaP4FeffVVvxtsFhKzkmm5NF9xxsfHOzo6Tp065XQ6n3322crKSgCARCJRKpVnzpw5d+4ciqK1tbWlpaVarfbo0aO9vb0bNmzYunXr559/XlhYmJyc/OGHH1ZUVCxdunSmztm70xvzpb9MK3P4qhz/zxcB84MTWmf/eXR9qPziPwMnWvUV9QppgCxBwMHmRXmCC6fMNwYdmQX+s9MoitbV1fndlJGRMT4+Pvv3devWvfbaa2FHHiG7du0aHh6e/XtRUVF/f//s34uLi999991AtfVfQHkCdiB9IXLUUzdcXx43bH0+0+9Wj8czOTnpv1KW/2oFAoFMJgt0OLowGAxut58nsEBRcblchSJgGrT1ldHHX8oM1JUJneX/6n8NWQVIzrJ5StIwjcvdVgdKrdooD1ImRJflgYaUv3xiQE3+H6rvbiZGnAM9tuD6QDijnbiLanlpmI4RxIWEE3Mf+slIOCXDGi8mcOrQT4ftVnfUgS0MpsZdrb/QkqQnnMLhzvpw2qn/br7+4L8p0/Pv8oHj4Uu23tOWx14MN0s2t5lHXx6bQi3utZsUinRepBEyF92I82u1SZnNu78hJfy95jz77fqAo1NtzCpElJn83GIhBLPmHiqzIFwebZ998prLrCfu25ScljO3x7AIZ2COfGsf/MY22octuVfM4bGFElgohfgItBCmsAKIzXLYSAwlMZSyW93jg868YlFBmSi7MJJOW4QGZ7g+4LBMERhKYlbK4/GSBJ0KKYrSaDQz6S+64CFsX9pZKIGS07hRXtmjNRhT7HZ7bW1te3t7vAMJRmIuf7QkDEYL0w36UrBMhukG/eajGAXTDcZuCJgumG5weno63iGEgOkGFy1aFO8QQsB0gxMTE/EOIQRMN1hSUhLvEELAdIMajSbeIYSA6QaZD9MNBhlFYwhMN2g0BnsTgQkw3WBKyhzSxXGB6QZjOiOLFphukPkw3WB+fn68QwgB0w36nUPEKJhukPkw3eDtMy2ZCdMNXrlyJd4hhIDpBpkP0w0mcjPRksjN3P0w3WBitDNaEqOddz9MN5gYL46WxHhxtCxevDjeIYSA6QaHhobiHUIImG6Q+TDdoEoV7lqU8YLpBgO9/MgcmG6wuLg43iGEgOkG+/r64h1CCJhuMNEGoyXRBqMlM9P/G/bMgYlv5OzevXtiYgKGYY/HYzQaFQoFm812u90nT56Md2h+YGIbfOKJJ1AU1el0er3e7Xbr9XqdTgdBMVlJLXqYaLCysvKOx2Gv18vYARMmGgQAPPnkkwjy3QuDaWlpjz32WFwjCghDDVZVVeXm5s5co0tLS5cvXx7voPzDUIMAgJ07d/rSqwqFgrENkNEGKysr8/LyfEPGjL0I0vCdpgggXB6HjXSgFIEHWRIPAAAe2fg0bjlWU7lT24cFKQaxAVfARiQwImRz+PN9y56//qBu2Dl8yT7W78BQkiuAuDxYIOUQTir6mnkIjFlwN05RpIcvhPOXC/OWC1XZ87QU9HwYvHrR9tevUNzpReSIJAXhIjFcat1lI2wGh8Pi4AvZqzcm5cZ+vavYGtSPuc4cnoL5nJR/kXN483rFcGGEccQMw96aHcrIPgIWJjE0qOm09nVjskwZX0zzQprhg1lchhHTAw3yvGJRjA4RK4MXTlu0V3DVEka8y6DTTJatl8ToOxcxMfj1ScvYEKEqYNDrSPr+qWWrhcsrJLTXTH9/sK/Len0IZ5Q+AEBaUaqm0zbWH6xXFBk0G5wcc/Z1Y8oCRpy8d5C+XNXxmcU2TfNaijQbPHPEkJQR83VCI0aySHrm8BS9ddJpcKAXhfmcON55QyJWIHbUqxum81swdBq89JVNkRdqzc14o8iTXTxrobFC2gzqhp0E7p2HbvP53rYXXvkeikb41iwi5RtuEIE+1xIBtBkc0dgFsoWxPKZQgYz2Bfzu0lyhzeDYgFOSsjAMihSI9nLAb3/NFXpOOjfhsZndmWGkDPb9cv3mTS/39bdfudop4IvKVzVsrNrl24SiRvWp3/UPdXkoMie7dNODz6Wpbr3YqZu4+unJ397QXZGIFSnJ/7BC6rD24skz/zkxOSgWyfNzy36w4YcScYiuqEDM1Wlo+zgWPW3QgVI8QbiJuaOfvLZIVfDMUy33lP7g9NnfX7naCQAgCFfLB01D2p6HN/5oc91PUNTY8kGT02kDANw0XHvvDz9EUUPNhmfWrdmm01+dqWpopOf3Hz6nTM3910d+/sCabdpr/9/yQRNBuIIHAHEgyu2hSHoexuhpgxhKwrxwDa6+p279uh0AgEWqggsX2waHu5cuWXvx0p+njNee3vkfi/PKAAC52St+9VbDue5jG6t2nfj8HRaL/ezTrSKhDADAYrM/UTf7qvr0xG/Kyxoaal/w/bMg/3u/fnvr4MiF4qIHgsfARWAMJSVyGnI2NJ3FuIcnDLcbyOXeWioWgiCpJNWKGgAA2tFv+HyRTx8AQC5LS1XkjOv6CcJ1dbj7vlWbffoAABD7Vsxmi/6mYdRovtHd++nt9VvR0H1mYRIXd1IAMMYgIoZdaCRXFjYb9ngoAIATt884ulUnIkVtRtRmpChSLkubva/NbgIAbKjatXxp1e2/i0NdBwEAqNElktKTNKTJoAQiXFHl66WS1Os3/mGSkc1uSpIqfVrtdj99YAFfDABwu/HUlJw5Hcvr9bpxj0BEz4gKPXcSRAyJkqL6Y+Rkljic6NjfJU5MDhlNN3KzV/D5QkVy5qXL/0eSd/aBUxRZSVJVzzdqnLj1lEZR5OxisyFxSpVLW8eLHoMsFosnYNuMkXey7il9KCU566NjP+vu/fT8xc8+OPKiSChbs3ozAGBj1S6Tefyd/9rV2f1x14X/ae88MnPQ+pofozbjO4ee6jz/x3NfH3v70FNdF/4Y8lg2o1Mio+3ZibYe9eKVQswUuUEIgndvfzsjvUj959+1nfhNqiL7madaxCK5T27Dwy84nNY/nX7nwkV1duZ3czJLllb+e+NvIYjz2cm3vmj/g0ymystZGfJYmBlbvIK2ESjactQ2i7vt0GRGKdMXXAQAjJ6/sf0X2Ww2Pevh09YGxTKOXMmxTtL2vBkjTGPT+StFdOmjObt1/yPJhpEQX+OMO/qrloq6ZBorpNOgWMYpXCWe1ttorJNeTNcta+uSfZ+kpQuas/wV9Qp0wuqyE/RWSwt2k8OL4yuraB6EoH+srvGnWSNf62ivNkpInNL3G7c8l057zTEZL3Y5qONv6dJLVBCHEZOfcYwwDBkffzEjFt+jicn8QT4CbXlu0XDXuBMNkWiaB+wmbLJ/attLMdEX85lHJ1r1DgcrKVM2z9OOfOAYYblukaWwH3wyhi+Ixnz220AP2tFmSs4S8yWIQDpP38fCLC6Hxe60uCrqk/NKYjXnyMc8zcDs67R+24liVlKiEnL4HJgHc3gQzKXpKukFboIicZIkKMKOT0865CpuSYWkaBX9s2RmM6/vNGFWcvQyNjmG+z6OzOFCdjrmYIgVXLeLEklhqQJWZvFyi4V8ZP7uYEx8K2xhwdy5/AuFhMFoSRiMloTBaEkYjJaEwWj5G9cmpR4/Ig13AAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "ca3cd1a1-38b1-4cbb-9301-5aec62659e70", + "metadata": {}, + "source": [ + "In this case, our graph just executes a single node. Let's proceed with a simple invocation:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7d932703-932f-48cb-842c-c372f82510f9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'messages': [HumanMessage(content='Hi', additional_kwargs={}, response_metadata={}),\n", + " AIMessage(content='Hello!', additional_kwargs={}, response_metadata={})],\n", + " 'extra_field': 10}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain_core.messages import HumanMessage\n", + "\n", + "result = graph.invoke({\"messages\": [HumanMessage(\"Hi\")]})\n", + "result" + ] + }, + { + "cell_type": "markdown", + "id": "e5918e84-49ac-4ab1-80bb-863a2e5461e2", + "metadata": {}, + "source": [ + "Note that:\n", + "\n", + "- We kicked off invocation by updating a single key of the state.\n", + "- We receive the entire state in the invocation result.\n", + "\n", + "For convenience, we frequently inspect the content of [message objects](https://python.langchain.com/docs/concepts/messages/) via pretty-print:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "5009dbb2-77c3-47de-9d9d-3fc6e5b649b9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Hi\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Hello!\n" + ] + } + ], + "source": [ + "for message in result[\"messages\"]:\n", + " message.pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "4c4da6ff-a677-41bf-b51e-f2826fc51926", + "metadata": {}, + "source": [ + "### Process state updates with reducers\n", + "\n", + "Each key in the state can have its own independent [reducer](../../concepts/low_level/#reducers) function, which controls how updates from nodes are applied. If no reducer function is explicitly specified then it is assumed that all updates to the key should override it.\n", + "\n", + "For `TypedDict` state schemas, we can define reducers by annotating the corresponding field of the state with a reducer function.\n", + "\n", + "In the earlier example, our node updated the `\"messages\"` key in the state by appending a message to it. Below, we add a reducer to this key, such that updates are automatically appended:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "35db8bfc-8747-423f-858a-b4f069d6199f", + "metadata": {}, + "outputs": [], + "source": [ + "from typing_extensions import Annotated\n", + "\n", + "\n", + "def add(left, right):\n", + " \"\"\"Can also import `add` from the `operator` built-in.\"\"\"\n", + " return left + right\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # highlight-next-line\n", + " messages: Annotated[list[AnyMessage], add]\n", + " extra_field: int" + ] + }, + { + "cell_type": "markdown", + "id": "4979a906-fff3-48de-9215-8a12b9bc4acf", + "metadata": {}, + "source": [ + "Now our node can be simplified:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f24f8d3f-973f-468e-8895-8c4cf01951dd", + "metadata": {}, + "outputs": [], + "source": [ + "def node(state: State):\n", + " new_message = AIMessage(\"Hello!\")\n", + " # highlight-next-line\n", + " return {\"messages\": [new_message], \"extra_field\": 10}" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "6ef429ed-a0fa-4c00-a88c-bb61df59f578", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Hi\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Hello!\n" + ] + } + ], + "source": [ + "from langgraph.graph import START\n", + "\n", + "\n", + "graph = StateGraph(State).add_node(node).add_edge(START, \"node\").compile()\n", + "\n", + "result = graph.invoke({\"messages\": [HumanMessage(\"Hi\")]})\n", + "\n", + "for message in result[\"messages\"]:\n", + " message.pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "7827723b-64aa-4d8b-b17a-5a3bcd8206f7", + "metadata": {}, + "source": [ + "#### MessagesState\n", + "\n", + "In practice, there are additional considerations for updating lists of messages:\n", + "\n", + "- We may wish to update an existing message in the state.\n", + "- We may want to accept short-hands for [message formats](../../concepts/low_level/#using-messages-in-your-graph), such as [OpenAI format](https://python.langchain.com/docs/concepts/messages/#openai-format).\n", + "\n", + "LangGraph includes a built-in reducer `add_messages` that handles these considerations:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "89880b92-5d00-421f-83c3-46382c1d1c17", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph.message import add_messages\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # highlight-next-line\n", + " messages: Annotated[list[AnyMessage], add_messages]\n", + " extra_field: int\n", + "\n", + "\n", + "def node(state: State):\n", + " new_message = AIMessage(\"Hello!\")\n", + " return {\"messages\": [new_message], \"extra_field\": 10}\n", + "\n", + "\n", + "graph = StateGraph(State).add_node(node).set_entry_point(\"node\").compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "51aeb731-e7f0-4d28-a096-436ef7fe004a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "Hi\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Hello!\n" + ] + } + ], + "source": [ + "# highlight-next-line\n", + "input_message = {\"role\": \"user\", \"content\": \"Hi\"}\n", + "\n", + "result = graph.invoke({\"messages\": [input_message]})\n", + "\n", + "for message in result[\"messages\"]:\n", + " message.pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "17583dde-2520-464c-a962-eae511d0928e", + "metadata": {}, + "source": [ + "This is a versatile representation of state for applications involving [chat models](https://python.langchain.com/docs/concepts/chat_models/). LangGraph includes a pre-built `MessagesState` for convenience, so that we can have:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "05956122-5ba0-4b4c-8b66-6362982227f2", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import MessagesState\n", + "\n", + "\n", + "class State(MessagesState):\n", + " extra_field: int" + ] + }, + { + "cell_type": "markdown", + "id": "f262985e-e973-4a27-9c9e-dbb3a06a35b7", + "metadata": {}, + "source": [ + "### Define input and output schemas\n", + "\n", + "By default, `StateGraph` operates with a single schema, and all nodes are expected to communicate using that schema. However, it's also possible to define distinct input and output schemas for a graph.\n", + "\n", + "When distinct schemas are specified, an internal schema will still be used for communication between nodes. The input schema ensures that the provided input matches the expected structure, while the output schema filters the internal data to return only the relevant information according to the defined output schema.\n", + "\n", + "Below, we'll see how to define distinct input and output schema." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6ec0eb77-874e-443e-8c73-93125b515106", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'answer': 'bye'}\n" + ] + } + ], + "source": [ + "from langgraph.graph import StateGraph, START, END\n", + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "# Define the schema for the input\n", + "class InputState(TypedDict):\n", + " question: str\n", + "\n", + "\n", + "# Define the schema for the output\n", + "class OutputState(TypedDict):\n", + " answer: str\n", + "\n", + "\n", + "# Define the overall schema, combining both input and output\n", + "class OverallState(InputState, OutputState):\n", + " pass\n", + "\n", + "\n", + "# Define the node that processes the input and generates an answer\n", + "def answer_node(state: InputState):\n", + " # Example answer and an extra key\n", + " return {\"answer\": \"bye\", \"question\": state[\"question\"]}\n", + "\n", + "\n", + "# Build the graph with input and output schemas specified\n", + "builder = StateGraph(OverallState, input=InputState, output=OutputState)\n", + "builder.add_node(answer_node) # Add the answer node\n", + "builder.add_edge(START, \"answer_node\") # Define the starting edge\n", + "builder.add_edge(\"answer_node\", END) # Define the ending edge\n", + "graph = builder.compile() # Compile the graph\n", + "\n", + "# Invoke the graph with an input and print the result\n", + "print(graph.invoke({\"question\": \"hi\"}))" + ] + }, + { + "cell_type": "markdown", + "id": "6a68836f-98e1-4684-a8a6-c1473c73460c", + "metadata": {}, + "source": [ + "Notice that the output of invoke only includes the output schema." + ] + }, + { + "cell_type": "markdown", + "id": "47ed5db3-bda5-49e1-bf75-23e08c9a3af0", + "metadata": {}, + "source": [ + "### Pass private state between nodes\n", + "\n", + "In some cases, you may want nodes to exchange information that is crucial for intermediate logic but doesn’t need to be part of the main schema of the graph. This private data is not relevant to the overall input/output of the graph and should only be shared between certain nodes.\n", + "\n", + "Below, we'll create an example sequential graph consisting of three nodes (node_1, node_2 and node_3), where private data is passed between the first two steps (node_1 and node_2), while the third step (node_3) only has access to the public overall state." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "ce5b944d-4597-4af9-a7b5-15a00325f3e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Entered node `node_1`:\n", + "\tInput: {'a': 'set at start'}.\n", + "\tReturned: {'private_data': 'set by node_1'}\n", + "Entered node `node_2`:\n", + "\tInput: {'private_data': 'set by node_1'}.\n", + "\tReturned: {'a': 'set by node_2'}\n", + "Entered node `node_3`:\n", + "\tInput: {'a': 'set by node_2'}.\n", + "\tReturned: {'a': 'set by node_3'}\n", + "\n", + "Output of graph invocation: {'a': 'set by node_3'}\n" + ] + } + ], + "source": [ + "from langgraph.graph import StateGraph, START, END\n", + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "# The overall state of the graph (this is the public state shared across nodes)\n", + "class OverallState(TypedDict):\n", + " a: str\n", + "\n", + "\n", + "# Output from node_1 contains private data that is not part of the overall state\n", + "class Node1Output(TypedDict):\n", + " private_data: str\n", + "\n", + "\n", + "# The private data is only shared between node_1 and node_2\n", + "def node_1(state: OverallState) -> Node1Output:\n", + " output = {\"private_data\": \"set by node_1\"}\n", + " print(f\"Entered node `node_1`:\\n\\tInput: {state}.\\n\\tReturned: {output}\")\n", + " return output\n", + "\n", + "\n", + "# Node 2 input only requests the private data available after node_1\n", + "class Node2Input(TypedDict):\n", + " private_data: str\n", + "\n", + "\n", + "def node_2(state: Node2Input) -> OverallState:\n", + " output = {\"a\": \"set by node_2\"}\n", + " print(f\"Entered node `node_2`:\\n\\tInput: {state}.\\n\\tReturned: {output}\")\n", + " return output\n", + "\n", + "\n", + "# Node 3 only has access to the overall state (no access to private data from node_1)\n", + "def node_3(state: OverallState) -> OverallState:\n", + " output = {\"a\": \"set by node_3\"}\n", + " print(f\"Entered node `node_3`:\\n\\tInput: {state}.\\n\\tReturned: {output}\")\n", + " return output\n", + "\n", + "\n", + "# Connect nodes in a sequence\n", + "# node_2 accepts private data from node_1, whereas\n", + "# node_3 does not see the private data.\n", + "builder = StateGraph(OverallState).add_sequence([node_1, node_2, node_3])\n", + "builder.add_edge(START, \"node_1\")\n", + "graph = builder.compile()\n", + "\n", + "# Invoke the graph with the initial state\n", + "response = graph.invoke(\n", + " {\n", + " \"a\": \"set at start\",\n", + " }\n", + ")\n", + "\n", + "print()\n", + "print(f\"Output of graph invocation: {response}\")" + ] + }, + { + "cell_type": "markdown", + "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", + "metadata": {}, + "source": [ + "### Use Pydantic models for graph state\n", + "\n", + "A [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph) accepts a `state_schema` argument on initialization that specifies the \"shape\" of the state that the nodes in the graph can access and update.\n", + "\n", + "In our examples, we typically use a python-native `TypedDict` for `state_schema`, but `state_schema` can be any [type](https://docs.python.org/3/library/stdtypes.html#type-objects).\n", + "\n", + "Here, we'll see how a [Pydantic BaseModel](https://docs.pydantic.dev/latest/api/base_model/). can be used for `state_schema` to add run time validation on **inputs**.\n", + "\n", + "\n", + "
\n", + "

Known Limitations

\n", + "

\n", + "

    \n", + "
  • \n", + " Currently, the output of the graph will NOT be an instance of a pydantic model.\n", + "
  • \n", + "
  • \n", + " Run-time validation only occurs on inputs into nodes, not on the outputs.\n", + "
  • \n", + "
  • \n", + " The validation error trace from pydantic does not show which node the error arises in.\n", + "
  • \n", + "
\n", + "

\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "efc46b36-425c-49c3-9f9e-d9785c70b034", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'a': 'goodbye'}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langgraph.graph import StateGraph, START, END\n", + "from typing_extensions import TypedDict\n", + "\n", + "from pydantic import BaseModel\n", + "\n", + "\n", + "# The overall state of the graph (this is the public state shared across nodes)\n", + "class OverallState(BaseModel):\n", + " a: str\n", + "\n", + "\n", + "def node(state: OverallState):\n", + " return {\"a\": \"goodbye\"}\n", + "\n", + "\n", + "# Build the state graph\n", + "builder = StateGraph(OverallState)\n", + "builder.add_node(node) # node_1 is the first node\n", + "builder.add_edge(START, \"node\") # Start the graph with node_1\n", + "builder.add_edge(\"node\", END) # End the graph after node_1\n", + "graph = builder.compile()\n", + "\n", + "# Test the graph with a valid input\n", + "graph.invoke({\"a\": \"hello\"})" + ] + }, + { + "cell_type": "markdown", + "id": "25b594c2-8198-4f76-9606-ea47151ff9d1", + "metadata": {}, + "source": [ + "Invoke the graph with an **invalid** input" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "05d7d43b-0b71-4e25-af6f-61d1560a46cb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "An exception was raised because `a` is an integer rather than a string.\n", + "1 validation error for OverallState\n", + "a\n", + " Input should be a valid string [type=string_type, input_value=123, input_type=int]\n", + " For further information visit https://errors.pydantic.dev/2.9/v/string_type\n" + ] + } + ], + "source": [ + "try:\n", + " graph.invoke({\"a\": 123}) # Should be a string\n", + "except Exception as e:\n", + " print(\"An exception was raised because `a` is an integer rather than a string.\")\n", + " print(e)" + ] + }, + { + "cell_type": "markdown", + "id": "572ee9f1-45d2-428e-9b70-e7befaf2da80", + "metadata": {}, + "source": [ + "See below for additional features of Pydantic model state:\n", + "\n", + "
\n", + "Serialization Behavior\n", + "\n", + "When using Pydantic models as state schemas, it's important to understand how serialization works, especially when:\n", + "
    \n", + "
  • Passing Pydantic objects as inputs
  • \n", + "
  • Receiving outputs from the graph
  • \n", + "
  • Working with nested Pydantic models
  • \n", + "
\n", + "Let's see these behaviors in action.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e919cdc", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import StateGraph, START, END\n", + "from pydantic import BaseModel\n", + "\n", + "\n", + "class NestedModel(BaseModel):\n", + " value: str\n", + "\n", + "\n", + "class ComplexState(BaseModel):\n", + " text: str\n", + " count: int\n", + " nested: NestedModel\n", + "\n", + "\n", + "def process_node(state: ComplexState):\n", + " # Node receives a validated Pydantic object\n", + " print(f\"Input state type: {type(state)}\")\n", + " print(f\"Nested type: {type(state.nested)}\")\n", + "\n", + " # Return a dictionary update\n", + " return {\"text\": state.text + \" processed\", \"count\": state.count + 1}\n", + "\n", + "\n", + "# Build the graph\n", + "builder = StateGraph(ComplexState)\n", + "builder.add_node(\"process\", process_node)\n", + "builder.add_edge(START, \"process\")\n", + "builder.add_edge(\"process\", END)\n", + "graph = builder.compile()\n", + "\n", + "# Create a Pydantic instance for input\n", + "input_state = ComplexState(text=\"hello\", count=0, nested=NestedModel(value=\"test\"))\n", + "print(f\"Input object type: {type(input_state)}\")\n", + "\n", + "# Invoke graph with a Pydantic instance\n", + "result = graph.invoke(input_state)\n", + "print(f\"Output type: {type(result)}\")\n", + "print(f\"Output content: {result}\")\n", + "\n", + "# Convert back to Pydantic model if needed\n", + "output_model = ComplexState(**result)\n", + "print(f\"Converted back to Pydantic: {type(output_model)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f13f28ce", + "metadata": {}, + "source": [ + "
\n", + "\n", + "
Runtime Type Coercion\n", + "\n", + "Pydantic performs runtime type coercion for certain data types. This can be helpful but also lead to unexpected behavior if you're not aware of it.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "faf59316", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import StateGraph, START, END\n", + "from pydantic import BaseModel\n", + "\n", + "\n", + "class CoercionExample(BaseModel):\n", + " # Pydantic will coerce string numbers to integers\n", + " number: int\n", + " # Pydantic will parse string booleans to bool\n", + " flag: bool\n", + "\n", + "\n", + "def inspect_node(state: CoercionExample):\n", + " print(f\"number: {state.number} (type: {type(state.number)})\")\n", + " print(f\"flag: {state.flag} (type: {type(state.flag)})\")\n", + " return {}\n", + "\n", + "\n", + "builder = StateGraph(CoercionExample)\n", + "builder.add_node(\"inspect\", inspect_node)\n", + "builder.add_edge(START, \"inspect\")\n", + "builder.add_edge(\"inspect\", END)\n", + "graph = builder.compile()\n", + "\n", + "# Demonstrate coercion with string inputs that will be converted\n", + "result = graph.invoke({\"number\": \"42\", \"flag\": \"true\"})\n", + "\n", + "# This would fail with a validation error\n", + "try:\n", + " graph.invoke({\"number\": \"not-a-number\", \"flag\": \"true\"})\n", + "except Exception as e:\n", + " print(f\"\\nExpected validation error: {e}\")" + ] + }, + { + "cell_type": "markdown", + "id": "2844475b", + "metadata": {}, + "source": [ + "
\n", + "\n", + "
Working with Message Models\n", + "\n", + "When working with LangChain message types in your state schema, there are important considerations for serialization. You should use AnyMessage (rather than BaseMessage) for proper serialization/deserialization when using message objects over the wire.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd0734b0", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import StateGraph, START, END\n", + "from pydantic import BaseModel\n", + "from langchain_core.messages import HumanMessage, AIMessage, AnyMessage\n", + "from typing import List\n", + "\n", + "\n", + "class ChatState(BaseModel):\n", + " messages: List[AnyMessage]\n", + " context: str\n", + "\n", + "\n", + "def add_message(state: ChatState):\n", + " return {\"messages\": state.messages + [AIMessage(content=\"Hello there!\")]}\n", + "\n", + "\n", + "builder = StateGraph(ChatState)\n", + "builder.add_node(\"add_message\", add_message)\n", + "builder.add_edge(START, \"add_message\")\n", + "builder.add_edge(\"add_message\", END)\n", + "graph = builder.compile()\n", + "\n", + "# Create input with a message\n", + "initial_state = ChatState(\n", + " messages=[HumanMessage(content=\"Hi\")], context=\"Customer support chat\"\n", + ")\n", + "\n", + "result = graph.invoke(initial_state)\n", + "print(f\"Output: {result}\")\n", + "\n", + "# Convert back to Pydantic model to see message types\n", + "output_model = ChatState(**result)\n", + "for i, msg in enumerate(output_model.messages):\n", + " print(f\"Message {i}: {type(msg).__name__} - {msg.content}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c2e52e1f-c07a-4ebf-b28e-c370c8f50550", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "6e6a0a39-9a4c-47ae-a238-1a3a847eea5b", + "metadata": {}, + "source": [ + "## Add runtime configuration\n", + "\n", + "Sometimes you want to be able to configure your graph when calling it. For example, you might want to be able to specify what LLM or system prompt to use at runtime, *without polluting the graph state with these parameters*.\n", + "\n", + "To add runtime configuration:\n", + "\n", + "1. Specify a schema for your configuration\n", + "2. Add the configuration to the function signature for nodes or conditional edges\n", + "3. Pass the configuration into the graph.\n", + "\n", + "See below for a simple example:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "97fc508b-1011-402e-8769-573ac3acb53a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'my_state_value': 1}\n", + "{'my_state_value': 2}\n" + ] + } + ], + "source": [ + "from langchain_core.runnables import RunnableConfig\n", + "from langgraph.graph import END, StateGraph, START\n", + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "# 1. Specify config schema\n", + "class ConfigSchema(TypedDict):\n", + " my_runtime_value: str\n", + "\n", + "\n", + "# 2. Define a graph that accesses the config in a node\n", + "class State(TypedDict):\n", + " my_state_value: str\n", + "\n", + "\n", + "# highlight-next-line\n", + "def node(state: State, config: RunnableConfig):\n", + " # highlight-next-line\n", + " if config[\"configurable\"][\"my_runtime_value\"] == \"a\":\n", + " return {\"my_state_value\": 1}\n", + " # highlight-next-line\n", + " elif config[\"configurable\"][\"my_runtime_value\"] == \"b\":\n", + " return {\"my_state_value\": 2}\n", + " else:\n", + " raise ValueError(\"Unknown values.\")\n", + "\n", + "\n", + "# highlight-next-line\n", + "builder = StateGraph(State, config_schema=ConfigSchema)\n", + "builder.add_node(node)\n", + "builder.add_edge(START, \"node\")\n", + "builder.add_edge(\"node\", END)\n", + "\n", + "graph = builder.compile()\n", + "\n", + "# 3. Pass in configuration at runtime:\n", + "# highlight-next-line\n", + "print(graph.invoke({}, {\"configurable\": {\"my_runtime_value\": \"a\"}}))\n", + "# highlight-next-line\n", + "print(graph.invoke({}, {\"configurable\": {\"my_runtime_value\": \"b\"}}))" + ] + }, + { + "cell_type": "markdown", + "id": "f080f50b-cec1-4dba-81e0-63cf40c990ee", + "metadata": {}, + "source": [ + "
Extended example: specifying LLM at runtime\n", + "\n", + "Below we demonstrate a practical example in which we configure what LLM to use at runtime. We will use both OpenAI and Anthropic models.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff4c1453-8cff-4679-9574-8602c530144e", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langgraph \"langchain[anthropic,openai]\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c031a059-7279-4e75-9164-58325d76242f", + "metadata": {}, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"ANTHROPIC_API_KEY\")\n", + "_set_env(\"OPENAI_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "id": "75ebea6f-e75f-42d4-9d32-68b37150bdde", + "metadata": {}, + "source": [ + "Build the graph:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a6033c2a-3b56-46f5-9c3f-79310e31e545", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "claude-3-5-haiku-20241022\n", + "gpt-4.1-mini-2025-04-14\n" + ] + } + ], + "source": [ + "from langchain.chat_models import init_chat_model\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langgraph.graph import MessagesState\n", + "from langgraph.graph import END, StateGraph, START\n", + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "class ConfigSchema(TypedDict):\n", + " model: str\n", + "\n", + "\n", + "MODELS = {\n", + " \"anthropic\": init_chat_model(\"anthropic:claude-3-5-haiku-latest\"),\n", + " \"openai\": init_chat_model(\"openai:gpt-4.1-mini\"),\n", + "}\n", + "\n", + "\n", + "def call_model(state: MessagesState, config: RunnableConfig):\n", + " model = config[\"configurable\"].get(\"model\", \"anthropic\")\n", + " model = MODELS[model]\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "builder = StateGraph(MessagesState, config_schema=ConfigSchema)\n", + "builder.add_node(\"model\", call_model)\n", + "builder.add_edge(START, \"model\")\n", + "builder.add_edge(\"model\", END)\n", + "\n", + "graph = builder.compile()\n", + "\n", + "# Usage\n", + "input_message = {\"role\": \"user\", \"content\": \"hi\"}\n", + "# With no configuration, uses default (Anthropic)\n", + "response_1 = graph.invoke({\"messages\": [input_message]})[\"messages\"][-1]\n", + "# Or, can set OpenAI\n", + "config = {\"configurable\": {\"model\": \"openai\"}}\n", + "response_2 = graph.invoke({\"messages\": [input_message]}, config=config)[\"messages\"][-1]\n", + "\n", + "print(response_1.response_metadata[\"model_name\"])\n", + "print(response_2.response_metadata[\"model_name\"])" + ] + }, + { + "cell_type": "markdown", + "id": "bd1ac2bc-9e3e-42c4-a68f-238c841e58d1", + "metadata": {}, + "source": [ + "
\n", + "\n", + "
Extended example: specifying model and system message at runtime\n", + "\n", + "Below we demonstrate a practical example in which we configure two parameters: the LLM and system message to use at runtime.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "367bcedd-047c-4150-a059-0a7630ab2663", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install -U langgraph \"langchain[anthropic,openai]\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5d0dd7d-9564-4a5f-aa2e-2f7be20e1647", + "metadata": {}, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"ANTHROPIC_API_KEY\")\n", + "_set_env(\"OPENAI_API_KEY\")" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "04924627-9326-438b-aa52-91cea76f4477", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "hi\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Ciao! Come posso aiutarti oggi?\n" + ] + } + ], + "source": [ + "from typing import Optional\n", + "\n", + "from langchain.chat_models import init_chat_model\n", + "from langchain_core.messages import SystemMessage\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langgraph.graph import END, MessagesState, StateGraph, START\n", + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "class ConfigSchema(TypedDict):\n", + " model: Optional[str]\n", + " system_message: Optional[str]\n", + "\n", + "\n", + "MODELS = {\n", + " \"anthropic\": init_chat_model(\"anthropic:claude-3-5-haiku-latest\"),\n", + " \"openai\": init_chat_model(\"openai:gpt-4.1-mini\"),\n", + "}\n", + "\n", + "\n", + "def call_model(state: MessagesState, config: RunnableConfig):\n", + " model = config[\"configurable\"].get(\"model\", \"anthropic\")\n", + " model = MODELS[model]\n", + " messages = state[\"messages\"]\n", + " if system_message := config[\"configurable\"].get(\"system_message\"):\n", + " messages = [SystemMessage(system_message)] + messages\n", + " response = model.invoke(messages)\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "builder = StateGraph(MessagesState, config_schema=ConfigSchema)\n", + "builder.add_node(\"model\", call_model)\n", + "builder.add_edge(START, \"model\")\n", + "builder.add_edge(\"model\", END)\n", + "\n", + "graph = builder.compile()\n", + "\n", + "# Usage\n", + "input_message = {\"role\": \"user\", \"content\": \"hi\"}\n", + "config = {\"configurable\": {\"model\": \"openai\", \"system_message\": \"Respond in Italian.\"}}\n", + "response = graph.invoke({\"messages\": [input_message]}, config)\n", + "for message in response[\"messages\"]:\n", + " message.pretty_print()" + ] + }, + { + "cell_type": "markdown", + "id": "03eac38a-fca6-4baf-9ccf-94bf16321235", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "94715e3d-e98b-4be0-ae5f-1169cb795ce5", + "metadata": {}, + "source": [ + "## Add retry policies\n", + "\n", + "There are many use cases where you may wish for your node to have a custom retry policy, for example if you are calling an API, querying a database, or calling an LLM, etc. LangGraph lets you add retry policies to nodes.\n", + "\n", + "To configure a retry policy, pass the `retry` parameter to the [add_node](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph.add_node). The `retry` parameter takes in a `RetryPolicy` named tuple object. Below we instantiate a `RetryPolicy` object with the default parameters and associate it with a node:\n", + "\n", + "```python\n", + "from langgraph.pregel import RetryPolicy\n", + "\n", + "builder.add_node(\n", + " \"node_name\",\n", + " node_function,\n", + " retry=RetryPolicy(),\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "af144b8f-761a-4456-a356-ce0812e92577", + "metadata": {}, + "source": [ + "By default, the `retry_on` parameter uses the `default_retry_on` function, which retries on any exception except for the following:\n", + "\n", + "* `ValueError`\n", + "* `TypeError`\n", + "* `ArithmeticError`\n", + "* `ImportError`\n", + "* `LookupError`\n", + "* `NameError`\n", + "* `SyntaxError`\n", + "* `RuntimeError`\n", + "* `ReferenceError`\n", + "* `StopIteration`\n", + "* `StopAsyncIteration`\n", + "* `OSError`\n", + "\n", + "In addition, for exceptions from popular http request libraries such as `requests` and `httpx` it only retries on 5xx status codes.\n", + "\n", + "
Extended example: customizing retry policies\n", + "\n", + "Consider an example in which we are reading from a SQL database. Below we pass two different retry policies to nodes:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "ad92598c-b688-42fa-aae0-9de36273d584", + "metadata": {}, + "outputs": [], + "source": [ + "import sqlite3\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langchain.chat_models import init_chat_model\n", + "\n", + "from langgraph.graph import END, MessagesState, StateGraph, START\n", + "from langgraph.pregel import RetryPolicy\n", + "from langchain_community.utilities import SQLDatabase\n", + "from langchain_core.messages import AIMessage\n", + "\n", + "db = SQLDatabase.from_uri(\"sqlite:///:memory:\")\n", + "\n", + "model = init_chat_model(\"anthropic:claude-3-5-haiku-latest\")\n", + "\n", + "\n", + "def query_database(state: MessagesState):\n", + " query_result = db.run(\"SELECT * FROM Artist LIMIT 10;\")\n", + " return {\"messages\": [AIMessage(content=query_result)]}\n", + "\n", + "\n", + "def call_model(state: MessagesState):\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": [response]}\n", + "\n", + "\n", + "# Define a new graph\n", + "builder = StateGraph(MessagesState)\n", + "builder.add_node(\n", + " \"query_database\",\n", + " query_database,\n", + " retry=RetryPolicy(retry_on=sqlite3.OperationalError),\n", + ")\n", + "builder.add_node(\"model\", call_model, retry=RetryPolicy(max_attempts=5))\n", + "builder.add_edge(START, \"model\")\n", + "builder.add_edge(\"model\", \"query_database\")\n", + "builder.add_edge(\"query_database\", END)\n", + "\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "markdown", + "id": "4eeb895c-adca-40ab-b289-93ee56e18661", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "e1a0213e-282f-4fad-b048-5f7465edfccb", + "metadata": {}, + "source": [ + "## Create a sequence of steps\n", + "\n", + "!!! info \"Prerequisites\"\n", + " This guide assumes familiarity with the above section on [state](#define-and-update-state).\n", + "\n", + "Here we demonstrate how to construct a simple sequence of steps. We will show:\n", + "\n", + "1. How to build a sequential graph\n", + "2. Built-in short-hand for constructing similar graphs.\n", + "\n", + "\n", + "To add a sequence of nodes, we use the `.add_node` and `.add_edge` methods of our [graph](../../concepts/low_level/#stategraph):\n", + "```python\n", + "from langgraph.graph import START, StateGraph\n", + "\n", + "builder = StateGraph(State)\n", + "\n", + "# Add nodes\n", + "builder.add_node(step_1)\n", + "builder.add_node(step_2)\n", + "builder.add_node(step_3)\n", + "\n", + "# Add edges\n", + "builder.add_edge(START, \"step_1\")\n", + "builder.add_edge(\"step_1\", \"step_2\")\n", + "builder.add_edge(\"step_2\", \"step_3\")\n", + "```\n", + "\n", + "We can also use the built-in shorthand `.add_sequence`:\n", + "```python\n", + "builder = StateGraph(State).add_sequence([step_1, step_2, step_3])\n", + "builder.add_edge(START, \"step_1\")\n", + "```\n", + "\n", + "\n", + "
\n", + "Why split application steps into a sequence with LangGraph?\n", + "\n", + "LangGraph makes it easy to add an underlying persistence layer to your application.\n", + "This allows state to be checkpointed in between the execution of nodes, so your LangGraph nodes govern:\n", + "\n", + "
    \n", + "
  • How state updates are [checkpointed](../../concepts/persistence/)
  • \n", + "
  • How interruptions are resumed in [human-in-the-loop](../../concepts/human_in_the_loop/) workflows
  • \n", + "
  • How we can \"rewind\" and branch-off executions using LangGraph's [time travel](../../concepts/time-travel/) features
  • \n", + "
\n", + "\n", + "They also determine how execution steps are [streamed](../../concepts/streaming/), and how your application is visualized\n", + "and debugged using [LangGraph Studio](../../concepts/langgraph_studio/).\n", + "\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "518cb5d1-c60f-44d7-b348-e03b6e487098", + "metadata": {}, + "source": [ + "Let's demonstrate an end-to-end example. We will create a sequence of three steps:\n", + "\n", + "1. Populate a value in a key of the state\n", + "2. Update the same value\n", + "3. Populate a different value\n", + "\n", + "Let's first define our [state](../../concepts/low_level/#state). This governs the [schema of the graph](../../concepts/low_level/#schema), and can also specify how to apply updates. See [this section](#process-state-updates-with-reducers) for more detail.\n", + "\n", + "In our case, we will just keep track of two values:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "aa1b04c6-2653-4ad4-a720-facc1f2906a7", + "metadata": {}, + "outputs": [], + "source": [ + "from typing_extensions import TypedDict\n", + "\n", + "\n", + "class State(TypedDict):\n", + " value_1: str\n", + " value_2: int" + ] + }, + { + "cell_type": "markdown", + "id": "6d4a8554-bc19-4bbe-a8c2-20adcfca8273", + "metadata": {}, + "source": [ + "Our [nodes](../../concepts/low_level/#nodes) are just Python functions that read our graph's state and make updates to it. The first argument to this function will always be the state:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c7db921a-dbfb-4039-a93b-8b2264143a3f", + "metadata": {}, + "outputs": [], + "source": [ + "def step_1(state: State):\n", + " return {\"value_1\": \"a\"}\n", + "\n", + "\n", + "def step_2(state: State):\n", + " current_value_1 = state[\"value_1\"]\n", + " return {\"value_1\": f\"{current_value_1} b\"}\n", + "\n", + "\n", + "def step_3(state: State):\n", + " return {\"value_2\": 10}" + ] + }, + { + "cell_type": "markdown", + "id": "2b454eb0-19c1-418e-a912-dc44c0c045e2", + "metadata": {}, + "source": [ + "!!! note\n", + "\n", + " Note that when issuing updates to the state, each node can just specify the value of the key it wishes to update.\n", + "\n", + "By default, this will **overwrite** the value of the corresponding key. You can also use [reducers](../../concepts/low_level/#reducers) to control how updates are processed— for example, you can append successive updates to a key instead. See [this section](#process-state-updates-with-reducers) for more detail.\n", + "\n", + "Finally, we define the graph. We use [StateGraph](../../concepts/low_level/#stategraph) to define a graph that operates on this state.\n", + "\n", + "We will then use [add_node](../../concepts/low_level/#messagesstate) and [add_edge](../../concepts/low_level/#edges) to populate our graph and define its control flow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b02bdbcf-2bbb-4f08-b177-1a45b2a8bc6d", + "metadata": {}, + "outputs": [], + "source": [ + "from langgraph.graph import START, StateGraph\n", + "\n", + "builder = StateGraph(State)\n", + "\n", + "# Add nodes\n", + "builder.add_node(step_1)\n", + "builder.add_node(step_2)\n", + "builder.add_node(step_3)\n", + "\n", + "# Add edges\n", + "builder.add_edge(START, \"step_1\")\n", + "builder.add_edge(\"step_1\", \"step_2\")\n", + "builder.add_edge(\"step_2\", \"step_3\")" + ] + }, + { + "cell_type": "markdown", + "id": "79a696b2-ef9b-4f8d-ae83-ea674a16bab0", + "metadata": {}, + "source": [ + "!!! tip \"Specifying custom names\"\n", + "\n", + " You can specify custom names for nodes using `.add_node`:\n", + "\n", + " ```python\n", + " builder.add_node(\"my_node\", step_1)\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "7452c5ea-cf1b-47a5-8da0-32479c142dce", + "metadata": {}, + "source": [ + "Note that:\n", + "\n", + "- `.add_edge` takes the names of nodes, which for functions defaults to `node.__name__`.\n", + "- We must specify the entry point of the graph. For this we add an edge with the [START node](../../concepts/low_level/#start-node).\n", + "- The graph halts when there are no more nodes to execute.\n", + "\n", + "We next [compile](../../concepts/low_level/#compiling-your-graph) our graph. This provides a few basic checks on the structure of the graph (e.g., identifying orphaned nodes). If we were adding persistence to our application via a [checkpointer](../../concepts/persistence/), it would also be passed in here." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7aa2828c-0903-4775-b4ea-d62647f3bf0a", + "metadata": {}, + "outputs": [], + "source": [ + "graph = builder.compile()" + ] + }, + { + "cell_type": "markdown", + "id": "4c85772e-788c-49df-9327-11cb92f02c6a", + "metadata": {}, + "source": [ + "LangGraph provides built-in utilities for visualizing your graph. Let's inspect our sequence. See [this guide](../../how-tos/visualization) for detail on visualization." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4162bc81-cbfd-49e3-b79f-8a97b9f417c2", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "9406b427-c28c-4cd0-9f01-e5bc1f089f4c", + "metadata": {}, + "source": [ + "Let's proceed with a simple invocation:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3f7012ae-4f8f-4dd3-9f99-ebd179ff5fe9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'value_1': 'a b', 'value_2': 10}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"value_1\": \"c\"})" + ] + }, + { + "cell_type": "markdown", + "id": "648421de-e43a-4242-8e62-afd84bc91b7e", + "metadata": {}, + "source": [ + "Note that:\n", + "\n", + "- We kicked off invocation by providing a value for a single state key. We must always provide a value for at least one key.\n", + "- The value we passed in was overwritten by the first node.\n", + "- The second node updated the value.\n", + "- The third node populated a different value." + ] + }, + { + "cell_type": "markdown", + "id": "1acdf7f1-d2f8-4863-a7f3-d5de4cc0ef28", + "metadata": {}, + "source": [ + "!!! tip \"Built-in shorthand\"\n", + "\n", + " `langgraph>=0.2.46` includes a built-in short-hand `add_sequence` for adding node sequences. You can compile the same graph as follows:\n", + "\n", + " ```python\n", + " # highlight-next-line\n", + " builder = StateGraph(State).add_sequence([step_1, step_2, step_3])\n", + " builder.add_edge(START, \"step_1\")\n", + " \n", + " graph = builder.compile()\n", + " \n", + " graph.invoke({\"value_1\": \"c\"}) \n", + " ```" + ] + }, + { + "attachments": { + "51f122de-b2ce-4c21-a5a7-c3be70c28a91.png": { + "image/png": "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LyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj41NDI8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+OTA0PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+ClCweXwAAAAcaURPVAAAAAIAAAAAAAABDwAAACgAAAEPAAABDwAARV8dcCWfAABAAElEQVR4AezdB3wURfvA8UcgdAgdqaElNAEVFBSk96agf1REFJSiooAFRXxtiAooShHEBkhRULEjRTpIB0MTCC0JJEBooZcA/5mJt97mLqSQS+4uv30/8XZnd2dnvjcvnzyZ2ZmbrqlN2BBAAAEEEEAAAQQQQAABBDK9wE0EiJm+DQCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIIAAAggggAACCCCAgBEgQKQhIIAAAggggAACCCCAAAIIGAECRBoCAggggAACCCCAAAIIIICAESBApCEggAACCCCAAAIIIIAAAggYAQJEGgICCCCAAAIIIIAAAggggIARIECkISCAAAIIIIAAAggggAACCBgBAkQaAgIIIICARwXOnDkjW7ZssT2jWrVqEhgYaEvjAAEEEEAAAQQyXoAAMeO/A0qAAAII+LVA+/btXQJEXeHy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Ujl++pycOH1eTkSfl7PnzsvFC+cl5qL5MZ8XL56TwsUjpFSZslK2TBkpXz5C8uUQyZczixTKncV82llyggACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAApaKqg4AAAVzSURBVAgggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuCxAgugxOcQgggAACCCCAAAIIIICAVwUIEL36ZqgXAggggAACCCCAAAIIIOCyAAGiy+AUhwACCCCAAAIIIIAAAgh4VYAA0atvhnohgAACCCCAAAIIIIAAAi4LECC6DE5xCCCAAAIIIIAAAggggIBXBQgQvfpmqBcCCCCAAAIIIIAAAggg4LIAAaLL4BSHAAIIIIAAAggggAACCHhVgADRq2+GeiGAAAIIIIAAAggggAACLgsQILoMTnEIIIAAAggggAACCCCAgFcFCBC9+maoFwIIIIAAAggggAACCCDgsgABosvgFIcAAggggAACCCCAAAIIeFWAANGrb4Z6IYAAAggggAACCCCAAAIuC/w/OsDdHSiHP+MAAAAASUVORK5CYII=" + } + }, + "cell_type": "markdown", + "id": "710dc4f0-1c88-4386-9e9d-fec3de6bb774", + "metadata": {}, + "source": [ + "## Create branches\n", + "\n", + "Parallel execution of nodes is essential to speed up overall graph operation. LangGraph offers native support for parallel execution of nodes, which can significantly enhance the performance of graph-based workflows. This parallelization is achieved through fan-out and fan-in mechanisms, utilizing both standard edges and [conditional_edges](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.MessageGraph.add_conditional_edges). Below are some examples showing how to add create branching dataflows that work for you. \n", + "\n", + "![Screenshot 2024-07-09 at 2.55.56 PM.png](attachment:51f122de-b2ce-4c21-a5a7-c3be70c28a91.png)" + ] + }, + { + "cell_type": "markdown", + "id": "d6c05fc4-ecd8-483f-a9fd-b1a055f922d9", + "metadata": {}, + "source": [ + "### Run graph nodes in parallel\n", + "\n", + "In this example, we fan out from `Node A` to `B and C` and then fan in to `D`. With our state, [we specify the reducer add operation](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers). This will combine or accumulate values for the specific key in the State, rather than simply overwriting the existing value. For lists, this means concatenating the new list with the existing list. See the above section on [state reducers](#process-state-updates-with-reducers) for more detail on updating state with reducers." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "09372b8b-edea-4b9d-9ec3-3d93ce1ba819", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated, Any\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # The operator.add reducer fn makes this append-only\n", + " aggregate: Annotated[list, operator.add]\n", + "\n", + "\n", + "def a(state: State):\n", + " print(f'Adding \"A\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"A\"]}\n", + "\n", + "\n", + "def b(state: State):\n", + " print(f'Adding \"B\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B\"]}\n", + "\n", + "\n", + "def c(state: State):\n", + " print(f'Adding \"C\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"C\"]}\n", + "\n", + "\n", + "def d(state: State):\n", + " print(f'Adding \"D\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"D\"]}\n", + "\n", + "\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "builder.add_node(c)\n", + "builder.add_node(d)\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_edge(\"a\", \"b\")\n", + "builder.add_edge(\"a\", \"c\")\n", + "builder.add_edge(\"b\", \"d\")\n", + "builder.add_edge(\"c\", \"d\")\n", + "builder.add_edge(\"d\", END)\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "66f52a20", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "74dd577b-0474-44c4-b4bc-9113090e3121", + "metadata": {}, + "source": [ + "With the reducer, you can see that the values added in each node are accumulated." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "81646784-5e7d-4096-980d-9fdfafd6e7a3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding \"A\" to []\n", + "Adding \"B\" to ['A']\n", + "Adding \"C\" to ['A']\n", + "Adding \"D\" to ['A', 'B', 'C']\n" + ] + }, + { + "data": { + "text/plain": [ + "{'aggregate': ['A', 'B', 'C', 'D']}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"aggregate\": []}, {\"configurable\": {\"thread_id\": \"foo\"}})" + ] + }, + { + "cell_type": "markdown", + "id": "ea5495cf-9564-40c6-bc2d-0b2a8f72a5df", + "metadata": {}, + "source": [ + "!!! note\n", + "\n", + " In the above example, nodes `\"b\"` and `\"c\"` are executed concurrently in the same [superstep](../../concepts/low_level/#graphs). Because they are in the same step, node `\"d\"` executes after both `\"b\"` and `\"c\"` are finished.\n", + "\n", + " Importantly, updates from a parallel superstep may not be ordered consistently. If you need a consistent, predetermined ordering of updates from a parallel superstep, you should write the outputs to a separate field in the state together with a value with which to order them." + ] + }, + { + "cell_type": "markdown", + "id": "c392b3d2", + "metadata": {}, + "source": [ + "
Exception handling?\n", + "

LangGraph executes nodes within \"supersteps\", meaning that while parallel branches are executed in parallel, the entire superstep is transactional. If any of these branches raises an exception, none of the updates are applied to the state (the entire superstep errors).

\n", + "

Importantly, when using a checkpointer, results from successful nodes within a superstep are saved, and don't repeat when resumed.

\n", + " If you have error-prone (perhaps want to handle flakey API calls), LangGraph provides two ways to address this:
\n", + "
    \n", + "
  1. You can write regular python code within your node to catch and handle exceptions.
  2. \n", + "
  3. You can set a retry_policy to direct the graph to retry nodes that raise certain types of exceptions. Only failing branches are retried, so you needn't worry about performing redundant work.
  4. \n", + "

\n", + "Together, these let you perform parallel execution and fully control exception handling.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "205ff836-0f97-4ee8-9830-6bd8368e48c9", + "metadata": {}, + "source": [ + "
Extended example: unequal length branches\n", + "\n", + "The above example showed how to fan-out and fan-in when each path was only one step. But what if one path had more than one step? Let's add a node b_2 in the \"b\" branch:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "3890af2f-fb14-4569-b48d-a91db2d3f026", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated, Any\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # The operator.add reducer fn makes this append-only\n", + " aggregate: Annotated[list, operator.add]\n", + "\n", + "\n", + "def a(state: State):\n", + " print(f'Adding \"A\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"A\"]}\n", + "\n", + "\n", + "def b(state: State):\n", + " print(f'Adding \"B\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B\"]}\n", + "\n", + "\n", + "def b_2(state: State):\n", + " print(f'Adding \"B_2\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B_2\"]}\n", + "\n", + "\n", + "def c(state: State):\n", + " print(f'Adding \"C\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"C\"]}\n", + "\n", + "\n", + "def d(state: State):\n", + " print(f'Adding \"D\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"D\"]}\n", + "\n", + "\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "builder.add_node(b_2)\n", + "builder.add_node(c)\n", + "builder.add_node(d)\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_edge(\"a\", \"b\")\n", + "builder.add_edge(\"a\", \"c\")\n", + "builder.add_edge(\"b\", \"b_2\")\n", + "# highlight-next-line\n", + "builder.add_edge([\"b_2\", \"c\"], \"d\")\n", + "builder.add_edge(\"d\", END)\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1a3508e6-bcaf-448e-bdc8-bf5701589d42", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b510379a-b82a-4658-973e-df56caf5cd01", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding \"A\" to []\n", + "Adding \"B\" to ['A']\n", + "Adding \"C\" to ['A']\n", + "Adding \"B_2\" to ['A', 'B', 'C']\n", + "Adding \"D\" to ['A', 'B', 'C', 'B_2']\n" + ] + }, + { + "data": { + "text/plain": [ + "{'aggregate': ['A', 'B', 'C', 'B_2', 'D']}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"aggregate\": []})" + ] + }, + { + "cell_type": "markdown", + "id": "903f0da5-8c2c-4a7e-96fb-0b16b4756eff", + "metadata": {}, + "source": [ + "
\n", + "

Note

\n", + "

In the above example, nodes \"b\" and \"c\" are executed concurrently in the same [superstep](../../concepts/low_level/#graphs). What happens in the next step?

\n", + "

We use add_edge([\"b_2\", \"c\"], \"d\") here to force node \"d\" to only run when both nodes \"b_2\" and \"c\" have finished execution. If we added two separate edges,\n", + " node \"d\" would run twice: after node b2 finishes and once again after node c (in whichever order those nodes finish).

\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "c1653341-3215-4ca0-b0e7-9be22f0adaa1", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "1a940eec-f36f-4236-9cc8-8d5dfd5cc860", + "metadata": {}, + "source": [ + "### Conditional branching\n", + "\n", + "If your fan-out should vary at runtime based on the state, you can use [add_conditional_edges](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph.add_conditional_edges) to select one or more paths using the graph state. See example below, where node `a` generates a state update that determines the following node." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "8b270199-f07d-4831-9674-f18715fa26de", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated, Literal, Sequence\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "class State(TypedDict):\n", + " aggregate: Annotated[list, operator.add]\n", + " # Add a key to the state. We will set this key to determine\n", + " # how we branch.\n", + " which: str\n", + "\n", + "\n", + "def a(state: State):\n", + " print(f'Adding \"A\" to {state[\"aggregate\"]}')\n", + " # highlight-next-line\n", + " return {\"aggregate\": [\"A\"], \"which\": \"c\"}\n", + "\n", + "\n", + "def b(state: State):\n", + " print(f'Adding \"B\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B\"]}\n", + "\n", + "\n", + "def c(state: State):\n", + " print(f'Adding \"C\" to {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"C\"]}\n", + "\n", + "\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "builder.add_node(c)\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_edge(\"b\", END)\n", + "builder.add_edge(\"c\", END)\n", + "\n", + "\n", + "def conditional_edge(state: State) -> Literal[\"b\", \"c\"]:\n", + " # Fill in arbitrary logic here that uses the state\n", + " # to determine the next node\n", + " return state[\"which\"]\n", + "\n", + "\n", + "# highlight-next-line\n", + "builder.add_conditional_edges(\"a\", conditional_edge)\n", + "\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "43999312-0198-49e4-86a9-4f71e343ed64", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "c6e92bf6-5ee8-4a5a-8693-a0e028b73e3b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding \"A\" to []\n", + "Adding \"C\" to ['A']\n", + "{'aggregate': ['A', 'C'], 'which': 'c'}\n" + ] + } + ], + "source": [ + "result = graph.invoke({\"aggregate\": []})\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "id": "b1c54e61-393d-4359-88e2-6117a6022ce3", + "metadata": {}, + "source": [ + "!!! tip\n", + "\n", + " Your conditional edges can route to multiple destination nodes. For example:\n", + "\n", + " ```python\n", + " def route_bc_or_cd(state: State) -> Sequence[str]:\n", + " if state[\"which\"] == \"cd\":\n", + " return [\"c\", \"d\"]\n", + " return [\"b\", \"c\"]\n", + " ```" + ] + }, + { + "attachments": { + "f0038a5c-08d9-4eff-a1cb-d1ee4dde4fe5.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABXIAAAExCAYAAADRMVpJAAABXWlDQ1BJQ0MgUHJvZmlsZQAAKJF1kD1Lw3AQxp9oS0EDFnUQ6hDoJFQpbcRBCtZaXyBDaC21gkOa1lboy98kIm7i4hcQv4BQ3B3q4ODkLAgKguDqLARBS7x/o6ZVvON4fjzcHccBA6LGWM0HoN6wjMzKorRR2JQCL/BTBillTTdZUlUVasG39od9D4Hr3TTfpa2ehd4ux+ZCN+JTdjd89Le/L4ZKZVMn/aCSdWZYgBAlVvctxvmQeNygo4hPOFdcPudcdPmq27OeSRHfEgf1qlYifiaOFHv8Sg/Xa3v61w38erHcyGVJJ6gmsYQ0FEoJOcQhI4ZZ5JH+Z0buzqTQBMMBDOyggiosmk6Sw1BDmXgNDeiYQYQ4hijfyX/9+4eed0yayBMseJ5SAC6awGjL88JbwMg8cL3MNEP7+axg+8zteMzl4TbgP3WcV9oXmAI6D47z3nacTgsYfKRZ+xN5zGEwOHUGjgAAAFZlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA5KGAAcAAAASAAAARKACAAQAAAABAAAFcqADAAQAAAABAAABMQAAAABBU0NJSQAAAFNjcmVlbnNob3S9u+miAAAB12lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4zMDU8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTM5NDwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PlNjcmVlbnNob3Q8L2V4aWY6VXNlckNvbW1lbnQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgqn9EX7AABAAElEQVR4AeydB4BVxfnFz/beCyxLWXqXJihYwB4xdqNGjcYaY0xMYokaW9QY/zExRZMYE02MGrvYS1CkSJPey9J3l+299//55vGWB1IWWHB3OQO77+0tc2d+d+69M+d+831+zUxQEgEREAEREAEREAEREAEREAEREAEREAEREAEREAERaLcE/NttyVQwERABERABERABERABERABERABERABERABERABERABR0BCrhqCCIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAREQAREQAREQAREQAREQAREQAREQAREQEKu2oAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAItHMCEnLb+QlS8URABERABERABERABERABERABERABERABERABERAQq7agAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAi0cwISctv5CVLxREAEREAEREAEREAEREAEREAEREAEREAEREAEREBCrtqACIiACIiACIiACIiACIiACIiACIiACIiACIiACLRzAhJy2/kJUvFEQAREQAQOH4H60lKULFqA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iIAIiEDHJCAht2OeN5VaBERABNoPAYq5jbQu3fz0H1G1KR3D//ws/IJswkdrLFbbTzUOa0nIyKyXze1EU00N+QQxIFrQfl0zHNYyKXMREAEREAEREAEREAEREAEREIEORUBCboc6XSqsCIiACLRfAs1NTQxO1kCB0gKYKYmACIiACIiACIhAxyOwOacSm7IrMXZgPKLD5Ymw451BlVgEREAEOjcBzXvt3OdXtRMBERCBI0bAz99fIu4Ro60DiYAIiIAIiIAItDWB+oYm/OXtdXjw74vdZyODliqJgAiIgAiIQHsiICG3PZ0NlUUEREAEREAEREAEREAEREAEROAbIWBCbnpGORobGcw1qwIScr+R06CDioAIiIAI7IOAhNx9wNEqERABERABERABERABERABERCBzk/AbG9NuC0uqYV9r6OoqyQCIiACIiAC7Y2AhNz2dkZUHhEQAREQAREQAREQAREQAREQgSNLgOrt1rxqirkeAbemttFilCqJgAiIgAiIQLsiICG3XZ0OFUYEREAEREAEREAEREAEREAEROBIE2imHe6MFfnOGteOXVldTyFXSu6RPg86ngiIgAiIwL4JSMjdNx+tFQEREAEREAEREAEREAEREAER6OwEqNl+tbqgRbwNCPSHn19nr7TqJwIiIAIi0NEISMjtaGdM5RUBERABERABERABERABERABEWhzArl5VS3uFCLDguDHf0oiIAIiIAIi0J4IBLanwqgsIiACIiACIiACIiACIiACIiACRzcB82hgrg48Mirl1COgp5oThaqaBgfejhcbSSH3CBz36D7Tqr0IiIAIiMCBEpCQe6DEtL0IiIAIiIAIiIAIiIAIiIAIiECbEzABt7a+EQs2lGBrbiWC6d6gb0oEhvaMRkhQwF6FVa/w2+LglgKsWdMeqBDb2OAJdGYV6xoXCn//tlNyD7aMB7tfm58cZSgCIiACItAuCEjIbRenQYUQAREQAREQAREQAREQAREQgaObwLrMctz796XIzqvYBURMdAiuO6cfzhyXgtiIoF3WNVHpXLy+GG/NysTaraVmyothfWJx1tgUTBiasFcxtoaCcRN127DgnQJxU7NHyPWjAty/RzT8dyjBJqbmldQghNvGhB+4pW5VbSP97xbikwXZWLK+CMFB/hjUKwbfP6s3BqftPM4uFeMf9RSWV20pw9tf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" + } + }, + "cell_type": "markdown", + "id": "931a0f15-b8d2-4ff6-8772-fd99f708a099", + "metadata": {}, + "source": [ + "### Map-reduce and the `Send` API\n", + "\n", + "By default, `Nodes` and `Edges` are defined ahead of time and operate on the same shared state. However, there can be cases where the exact edges are not known ahead of time and/or you may want different versions of state to exist at the same time. A common example of this is with map-reduce design patterns. In this design pattern, a first node may generate a list of objects, and you may want to apply some other node to all those objects. The number of objects may be unknown ahead of time (meaning the number of edges may not be known) and the input state to the downstream `Node` should be different (one for each generated object).\n", + "\n", + "To support this design pattern, LangGraph supports returning [Send](/langgraph/reference/types/#langgraph.types.Send) objects from conditional edges. `Send` takes two arguments: first is the name of the node, and second is the state to pass to that node.\n", + "\n", + "```python\n", + "def continue_to_jokes(state: OverallState):\n", + " return [Send(\"generate_joke\", {\"subject\": s}) for s in state['subjects']]\n", + "\n", + "graph.add_conditional_edges(\"node_a\", continue_to_jokes)\n", + "```\n", + "\n", + "Below we implement a simple example, where we simulate using LLMs to (1) generate a list of subjects (the length of which is unknown ahead of time), (2) generate jokes in parallel, and (3) select a \"best\" joke. Importantly, the input state to the fan-out nodes is different than the graph's overall state.\n", + "\n", + "![Screenshot 2025-05-05 at 4.21.35 PM.png](attachment:f0038a5c-08d9-4eff-a1cb-d1ee4dde4fe5.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8b971a9c-337a-4899-bcf7-080193832935", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.types import Send\n", + "from langgraph.graph import END, StateGraph, START\n", + "\n", + "\n", + "# This will be the overall state of the main graph.\n", + "# It will contain a topic (which we expect the user to provide)\n", + "# and then will generate a list of subjects, and then a joke for\n", + "# each subject\n", + "class OverallState(TypedDict):\n", + " topic: str\n", + " subjects: list\n", + " # Notice here we use the operator.add\n", + " # This is because we want combine all the jokes we generate\n", + " # from individual nodes back into one list - this is essentially\n", + " # the \"reduce\" part\n", + " jokes: Annotated[list, operator.add]\n", + " best_selected_joke: str\n", + "\n", + "\n", + "# This will be the state of the node that we will \"map\" all\n", + "# subjects to in order to generate a joke\n", + "class JokeState(TypedDict):\n", + " subject: str\n", + "\n", + "\n", + "# This is the function we will use to generate the subjects of the jokes.\n", + "# In general the length of the list generated by this node could vary each run.\n", + "def generate_topics(state: OverallState):\n", + " # Simulate a LLM.\n", + " return {\"subjects\": [\"lions\", \"elephants\", \"penguins\"]}\n", + "\n", + "\n", + "# Here we generate a joke, given a subject\n", + "def generate_joke(state: JokeState):\n", + " # Simulate a LLM.\n", + " joke_map = {\n", + " \"lions\": \"Why don't lions like fast food? Because they can't catch it!\",\n", + " \"elephants\": \"Why don't elephants use computers? They're afraid of the mouse!\",\n", + " \"penguins\": (\n", + " \"Why don’t penguins like talking to strangers at parties? \"\n", + " \"Because they find it hard to break the ice.\"\n", + " ),\n", + " }\n", + " return {\"jokes\": [joke_map[state[\"subject\"]]]}\n", + "\n", + "\n", + "# Here we define the logic to map out over the generated subjects\n", + "# We will use this as an edge in the graph\n", + "def continue_to_jokes(state: OverallState):\n", + " # We will return a list of `Send` objects\n", + " # Each `Send` object consists of the name of a node in the graph\n", + " # as well as the state to send to that node\n", + " return [Send(\"generate_joke\", {\"subject\": s}) for s in state[\"subjects\"]]\n", + "\n", + "\n", + "# Here we will judge the best joke\n", + "def best_joke(state: OverallState):\n", + " return {\"best_selected_joke\": \"penguins\"}\n", + "\n", + "\n", + "# Construct the graph: here we put everything together to construct our graph\n", + "builder = StateGraph(OverallState)\n", + "builder.add_node(\"generate_topics\", generate_topics)\n", + "builder.add_node(\"generate_joke\", generate_joke)\n", + "builder.add_node(\"best_joke\", best_joke)\n", + "builder.add_edge(START, \"generate_topics\")\n", + "builder.add_conditional_edges(\"generate_topics\", continue_to_jokes, [\"generate_joke\"])\n", + "builder.add_edge(\"generate_joke\", \"best_joke\")\n", + "builder.add_edge(\"best_joke\", END)\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2760846f-a297-455c-a07c-155743f5e55f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "cd91131a-b640-4604-9b48-b6cb5207be31", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'generate_topics': {'subjects': ['lions', 'elephants', 'penguins']}}\n", + "{'generate_joke': {'jokes': [\"Why don't lions like fast food? Because they can't catch it!\"]}}\n", + "{'generate_joke': {'jokes': [\"Why don't elephants use computers? They're afraid of the mouse!\"]}}\n", + "{'generate_joke': {'jokes': ['Why don’t penguins like talking to strangers at parties? Because they find it hard to break the ice.']}}\n", + "{'best_joke': {'best_selected_joke': 'penguins'}}\n" + ] + } + ], + "source": [ + "# Call the graph: here we call it to generate a list of jokes\n", + "for step in graph.stream({\"topic\": \"animals\"}):\n", + " print(step)" + ] + }, + { + "cell_type": "markdown", + "id": "4c505843-5449-4e9b-8ad4-27b88a987cc4", + "metadata": {}, + "source": [ + "## Create and control loops\n", + "\n", + "When creating a graph with a loop, we require a mechanism for terminating execution. This is most commonly done by adding a [conditional edge](../../concepts/low_level/#conditional-edges) that routes to the [END](../../concepts/low_level/#end-node) node once we reach some termination condition.\n", + "\n", + "You can also set the graph recursion limit when invoking or streaming the graph. The recursion limit sets the number of [supersteps](../../concepts/low_level/#graphs) that the graph is allowed to execute before it raises an error. Read more about the concept of recursion limits [here](../../concepts/low_level/#recursion-limit). \n", + "\n", + "Let's consider a simple graph with a loop to better understand how these mechanisms work.\n", + "\n", + "!!! tip\n", + "\n", + " To return the last value of your state instead of receiving a recursion limit error, see the [next section](#impose-a-recursion-limit).\n", + "\n", + "When creating a loop, you can include a conditional edge that specifies a termination condition:\n", + "```python\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "\n", + "def route(state: State) -> Literal[\"b\", END]:\n", + " if termination_condition(state):\n", + " return END\n", + " else:\n", + " return \"a\"\n", + "\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_conditional_edges(\"a\", route)\n", + "builder.add_edge(\"b\", \"a\")\n", + "graph = builder.compile()\n", + "```\n", + "\n", + "To control the recursion limit, specify `\"recursion_limit\"` in the config. This will raise a `GraphRecursionError`, which you can catch and handle:\n", + "```python\n", + "from langgraph.errors import GraphRecursionError\n", + "\n", + "try:\n", + " graph.invoke(inputs, {\"recursion_limit\": 3})\n", + "except GraphRecursionError:\n", + " print(\"Recursion Error\")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "2de7cdff-3811-4d19-b93b-7b8dfbbdb4f1", + "metadata": {}, + "source": [ + "Let's define a graph with a simple loop. Note that we use a conditional edge to implement a termination condition." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "f087c028-b115-42a0-a85d-f53d96223720", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated, Literal\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # The operator.add reducer fn makes this append-only\n", + " aggregate: Annotated[list, operator.add]\n", + "\n", + "\n", + "def a(state: State):\n", + " print(f'Node A sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"A\"]}\n", + "\n", + "\n", + "def b(state: State):\n", + " print(f'Node B sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B\"]}\n", + "\n", + "\n", + "# Define nodes\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "\n", + "\n", + "# Define edges\n", + "def route(state: State) -> Literal[\"b\", END]:\n", + " if len(state[\"aggregate\"]) < 7:\n", + " return \"b\"\n", + " else:\n", + " return END\n", + "\n", + "\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_conditional_edges(\"a\", route)\n", + "builder.add_edge(\"b\", \"a\")\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c468e5b2-a1dd-4fac-84a9-9eb212a09752", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "255d288a-6e17-4f34-babe-0c6cf1e09a6f", + "metadata": {}, + "source": [ + "This architecture is similar to a [ReAct agent](../../agents/overview) in which node `\"a\"` is a tool-calling model, and node `\"b\"` represents the tools.\n", + "\n", + "In our `route` conditional edge, we specify that we should end after the `\"aggregate\"` list in the state passes a threshold length.\n", + "\n", + "Invoking the graph, we see that we alternate between nodes `\"a\"` and `\"b\"` before terminating once we reach the termination condition." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "83c759be-9bb7-4f96-8b79-028fe1ebb45f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Node A sees []\n", + "Node B sees ['A']\n", + "Node A sees ['A', 'B']\n", + "Node B sees ['A', 'B', 'A']\n", + "Node A sees ['A', 'B', 'A', 'B']\n", + "Node B sees ['A', 'B', 'A', 'B', 'A']\n", + "Node A sees ['A', 'B', 'A', 'B', 'A', 'B']\n" + ] + }, + { + "data": { + "text/plain": [ + "{'aggregate': ['A', 'B', 'A', 'B', 'A', 'B', 'A']}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"aggregate\": []})" + ] + }, + { + "cell_type": "markdown", + "id": "8c596264-9a36-4c52-ba7d-9fa5dcb3467d", + "metadata": {}, + "source": [ + "### Impose a recursion limit\n", + "\n", + "In some applications, we may not have a guarantee that we will reach a given termination condition. In these cases, we can set the graph's [recursion limit](../../concepts/low_level/#recursion-limit). This will raise a `GraphRecursionError` after a given number of [supersteps](../../concepts/low_level/#graphs). We can then catch and handle this exception:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f7526e3c-357c-4eba-b101-751418523672", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Node A sees []\n", + "Node B sees ['A']\n", + "Node A sees ['A', 'B']\n", + "Node B sees ['A', 'B', 'A']\n", + "Recursion Error\n" + ] + } + ], + "source": [ + "from langgraph.errors import GraphRecursionError\n", + "\n", + "try:\n", + " graph.invoke({\"aggregate\": []}, {\"recursion_limit\": 4})\n", + "except GraphRecursionError:\n", + " print(\"Recursion Error\")" + ] + }, + { + "cell_type": "markdown", + "id": "0793b71a-fd92-4284-8d58-cc10f49872f6", + "metadata": {}, + "source": [ + "Note that this time we terminate after the fourth step. The default recursion limit is 25.\n", + "\n", + "
Extended example: return state on hitting recursion limit\n", + "\n", + "Instead of raising GraphRecursionError, we can introduce a new key to the state that keeps track of the number of steps remaining until reaching the recursion limit. We can then use this key to determine if we should end the run.\n", + "\n", + "LangGraph implements a special RemainingSteps annotation. Under the hood, it creates a ManagedValue channel -- a state channel that will exist for the duration of our graph run and no longer.\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "7fe57f1a-ab55-45ed-b229-8f29fc3da05b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Node A sees []\n", + "Node B sees ['A']\n", + "Node A sees ['A', 'B']\n", + "{'aggregate': ['A', 'B', 'A']}\n" + ] + } + ], + "source": [ + "import operator\n", + "from typing import Annotated, Literal\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "# highlight-next-line\n", + "from langgraph.managed.is_last_step import RemainingSteps\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # The operator.add reducer fn makes this append-only\n", + " aggregate: Annotated[list, operator.add]\n", + " # highlight-next-line\n", + " remaining_steps: RemainingSteps\n", + "\n", + "\n", + "def a(state: State):\n", + " print(f'Node A sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"A\"]}\n", + "\n", + "\n", + "def b(state: State):\n", + " print(f'Node B sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B\"]}\n", + "\n", + "\n", + "# Define nodes\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "\n", + "\n", + "# Define edges\n", + "def route(state: State) -> Literal[\"b\", END]:\n", + " # highlight-next-line\n", + " if state[\"remaining_steps\"] <= 2:\n", + " return END\n", + " else:\n", + " return \"b\"\n", + "\n", + "\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_conditional_edges(\"a\", route)\n", + "builder.add_edge(\"b\", \"a\")\n", + "graph = builder.compile()\n", + "\n", + "# Test it out\n", + "result = graph.invoke({\"aggregate\": []}, {\"recursion_limit\": 4})\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "id": "6c9e1818-079a-41bb-aed0-2bf993ca943f", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "308d93f4-6e78-411d-82de-78eac230e44d", + "metadata": {}, + "source": [ + "
Extended example: loops with branches\n", + "\n", + "To better understand how the recursion limit works, let's consider a more complex example. Below we implement a loop, but one step fans out into two nodes:\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "258d8613-8572-407a-941a-2ac50b8f1c3e", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing import Annotated, Literal\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "\n", + "\n", + "class State(TypedDict):\n", + " aggregate: Annotated[list, operator.add]\n", + "\n", + "\n", + "def a(state: State):\n", + " print(f'Node A sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"A\"]}\n", + "\n", + "\n", + "def b(state: State):\n", + " print(f'Node B sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"B\"]}\n", + "\n", + "\n", + "def c(state: State):\n", + " print(f'Node C sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"C\"]}\n", + "\n", + "\n", + "def d(state: State):\n", + " print(f'Node D sees {state[\"aggregate\"]}')\n", + " return {\"aggregate\": [\"D\"]}\n", + "\n", + "\n", + "# Define nodes\n", + "builder = StateGraph(State)\n", + "builder.add_node(a)\n", + "builder.add_node(b)\n", + "builder.add_node(c)\n", + "builder.add_node(d)\n", + "\n", + "\n", + "# Define edges\n", + "def route(state: State) -> Literal[\"b\", END]:\n", + " if len(state[\"aggregate\"]) < 7:\n", + " return \"b\"\n", + " else:\n", + " return END\n", + "\n", + "\n", + "builder.add_edge(START, \"a\")\n", + "builder.add_conditional_edges(\"a\", route)\n", + "builder.add_edge(\"b\", \"c\")\n", + "builder.add_edge(\"b\", \"d\")\n", + "builder.add_edge([\"c\", \"d\"], \"a\")\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "bdb2a545-3f1f-408b-8aa3-3702d37eedf8", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "a1d4cc42-590c-4de9-9e51-0bb8a79db86f", + "metadata": {}, + "source": [ + "This graph looks complex, but can be conceptualized as loop of [supersteps](../../concepts/low_level/#graphs):\n", + "\n", + "1. Node A\n", + "2. Node B\n", + "3. Nodes C and D\n", + "4. Node A\n", + "5. ...\n", + "\n", + "We have a loop of four supersteps, where nodes C and D are executed concurrently.\n", + "\n", + "Invoking the graph as before, we see that we complete two full \"laps\" before hitting the termination condition:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "d5c692d0-9a69-4743-bd47-e462adab8700", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Node A sees []\n", + "Node B sees ['A']\n", + "Node D sees ['A', 'B']\n", + "Node C sees ['A', 'B']\n", + "Node A sees ['A', 'B', 'C', 'D']\n", + "Node B sees ['A', 'B', 'C', 'D', 'A']\n", + "Node D sees ['A', 'B', 'C', 'D', 'A', 'B']\n", + "Node C sees ['A', 'B', 'C', 'D', 'A', 'B']\n", + "Node A sees ['A', 'B', 'C', 'D', 'A', 'B', 'C', 'D']\n" + ] + } + ], + "source": [ + "result = graph.invoke({\"aggregate\": []})" + ] + }, + { + "cell_type": "markdown", + "id": "42cb9253-93a9-4a33-b4fb-a235aa41d655", + "metadata": {}, + "source": [ + "However, if we set the recursion limit to four, we only complete one lap because each lap is four supersteps:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "d0ff64b3-eb78-48a4-aab5-bb78499f92df", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Node A sees []\n", + "Node B sees ['A']\n", + "Node C sees ['A', 'B']\n", + "Node D sees ['A', 'B']\n", + "Node A sees ['A', 'B', 'C', 'D']\n", + "Recursion Error\n" + ] + } + ], + "source": [ + "from langgraph.errors import GraphRecursionError\n", + "\n", + "try:\n", + " result = graph.invoke({\"aggregate\": []}, {\"recursion_limit\": 4})\n", + "except GraphRecursionError:\n", + " print(\"Recursion Error\")" + ] + }, + { + "cell_type": "markdown", + "id": "13579366-69fb-4aa4-9d95-a9865c1d5799", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "d33ecddc-6818-41a3-9d0d-b1b1cbcd286d", + "metadata": {}, + "source": [ + "## Combine control flow and state updates with `Command`" + ] + }, + { + "cell_type": "markdown", + "id": "7c0a8d03-80b4-47fd-9b17-e26aa9b081f3", + "metadata": {}, + "source": [ + "It can be useful to combine control flow (edges) and state updates (nodes). For example, you might want to BOTH perform state updates AND decide which node to go to next in the SAME node. LangGraph provides a way to do so by returning a [Command](/langgraph/reference/types/#langgraph.types.Command) object from node functions:\n", + "\n", + "```python\n", + "def my_node(state: State) -> Command[Literal[\"my_other_node\"]]:\n", + " return Command(\n", + " # state update\n", + " update={\"foo\": \"bar\"},\n", + " # control flow\n", + " goto=\"my_other_node\"\n", + " )\n", + "```\n", + "\n", + "We show an end-to-end example below. Let's create a simple graph with 3 nodes: A, B and C. We will first execute node A, and then decide whether to go to Node B or Node C next based on the output of node A." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "4539b81b-09e9-4660-ac55-1b1775e13892", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from typing_extensions import TypedDict, Literal\n", + "\n", + "from langgraph.graph import StateGraph, START\n", + "from langgraph.types import Command\n", + "\n", + "\n", + "# Define graph state\n", + "class State(TypedDict):\n", + " foo: str\n", + "\n", + "\n", + "# Define the nodes\n", + "\n", + "\n", + "def node_a(state: State) -> Command[Literal[\"node_b\", \"node_c\"]]:\n", + " print(\"Called A\")\n", + " value = random.choice([\"a\", \"b\"])\n", + " # this is a replacement for a conditional edge function\n", + " if value == \"a\":\n", + " goto = \"node_b\"\n", + " else:\n", + " goto = \"node_c\"\n", + "\n", + " # note how Command allows you to BOTH update the graph state AND route to the next node\n", + " return Command(\n", + " # this is the state update\n", + " update={\"foo\": value},\n", + " # this is a replacement for an edge\n", + " goto=goto,\n", + " )\n", + "\n", + "\n", + "def node_b(state: State):\n", + " print(\"Called B\")\n", + " return {\"foo\": state[\"foo\"] + \"b\"}\n", + "\n", + "\n", + "def node_c(state: State):\n", + " print(\"Called C\")\n", + " return {\"foo\": state[\"foo\"] + \"c\"}" + ] + }, + { + "cell_type": "markdown", + "id": "badc25eb-4876-482e-bb10-d763023cdaad", + "metadata": {}, + "source": [ + "We can now create the `StateGraph` with the above nodes. Notice that the graph doesn't have [conditional edges](../../concepts/low_level#conditional-edges) for routing! This is because control flow is defined with `Command` inside `node_a`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d6711650-4380-4551-a007-2805f49ab2d8", + "metadata": {}, + "outputs": [], + "source": [ + "builder = StateGraph(State)\n", + "builder.add_edge(START, \"node_a\")\n", + "builder.add_node(node_a)\n", + "builder.add_node(node_b)\n", + "builder.add_node(node_c)\n", + "# NOTE: there are no edges between nodes A, B and C!\n", + "\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "markdown", + "id": "0ab344c5-d634-4d7d-b3b4-edf4fa875311", + "metadata": {}, + "source": [ + "!!! important\n", + "\n", + " You might have noticed that we used `Command` as a return type annotation, e.g. `Command[Literal[\"node_b\", \"node_c\"]]`. This is necessary for the graph rendering and tells LangGraph that `node_a` can navigate to `node_b` and `node_c`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eeb810e5-8822-4c09-8d53-c55cd0f5d42e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import display, Image\n", + "\n", + "display(Image(graph.get_graph().draw_mermaid_png()))" + ] + }, + { + "cell_type": "markdown", + "id": "58fb6c32-e6fb-4c94-8182-e351ed52a45d", + "metadata": {}, + "source": [ + "If we run the graph multiple times, we'd see it take different paths (A -> B or A -> C) based on the random choice in node A." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d88a5d9b-ee08-4ed4-9c65-6e868210bfac", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Called A\n", + "Called C\n" + ] + }, + { + "data": { + "text/plain": [ + "{'foo': 'bc'}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"foo\": \"\"})" + ] + }, + { + "cell_type": "markdown", + "id": "68986cc4-97ec-43a1-b95d-5273d7ffc25a", + "metadata": {}, + "source": [ + "### Navigate to a node in a parent graph\n", + "\n", + "If you are using [subgraphs](../../concepts/subgraphs), you might want to navigate from a node within a subgraph to a different subgraph (i.e. a different node in the parent graph). To do so, you can specify `graph=Command.PARENT` in `Command`:\n", + "\n", + "```python\n", + "def my_node(state: State) -> Command[Literal[\"my_other_node\"]]:\n", + " return Command(\n", + " update={\"foo\": \"bar\"},\n", + " goto=\"other_subgraph\", # where `other_subgraph` is a node in the parent graph\n", + " graph=Command.PARENT\n", + " )\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "02ccddf2-978c-41bf-b2eb-2d0c4b3f5d81", + "metadata": {}, + "source": [ + "Let's demonstrate this using the above example. We'll do so by changing `node_a` in the above example into a single-node graph that we'll add as a subgraph to our parent graph.\n", + "\n", + "!!! important \"State updates with `Command.PARENT`\"\n", + "\n", + " When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](../../concepts/low_level#schema), you **must** define a [reducer](../../concepts/low_level#reducers) for the key you're updating in the parent graph state. See the example below." + ] + }, + { + "cell_type": "markdown", + "id": "6be0aeb9-e138-4adc-a1df-5d743a8eb348", + "metadata": {}, + "source": [ + "!!! important \"State updates with `Command.PARENT`\"\n", + "\n", + " When you send updates from a subgraph node to a parent graph node for a key that's shared by both parent and subgraph [state schemas](../../concepts/low_level#schema), you **must** define a [reducer](../../concepts/low_level#reducers) for the key you're updating in the parent graph state." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "91351541-67af-4c73-9437-426599dcf81e", + "metadata": {}, + "outputs": [], + "source": [ + "import operator\n", + "from typing_extensions import Annotated\n", + "\n", + "\n", + "class State(TypedDict):\n", + " # NOTE: we define a reducer here\n", + " # highlight-next-line\n", + " foo: Annotated[str, operator.add]\n", + "\n", + "\n", + "def node_a(state: State):\n", + " print(\"Called A\")\n", + " value = random.choice([\"a\", \"b\"])\n", + " # this is a replacement for a conditional edge function\n", + " if value == \"a\":\n", + " goto = \"node_b\"\n", + " else:\n", + " goto = \"node_c\"\n", + "\n", + " # note how Command allows you to BOTH update the graph state AND route to the next node\n", + " return Command(\n", + " update={\"foo\": value},\n", + " goto=goto,\n", + " # this tells LangGraph to navigate to node_b or node_c in the parent graph\n", + " # NOTE: this will navigate to the closest parent graph relative to the subgraph\n", + " # highlight-next-line\n", + " graph=Command.PARENT,\n", + " )\n", + "\n", + "\n", + "subgraph = StateGraph(State).add_node(node_a).add_edge(START, \"node_a\").compile()\n", + "\n", + "\n", + "def node_b(state: State):\n", + " print(\"Called B\")\n", + " # NOTE: since we've defined a reducer, we don't need to manually append\n", + " # new characters to existing 'foo' value. instead, reducer will append these\n", + " # automatically (via operator.add)\n", + " # highlight-next-line\n", + " return {\"foo\": \"b\"}\n", + "\n", + "\n", + "def node_c(state: State):\n", + " print(\"Called C\")\n", + " # highlight-next-line\n", + " return {\"foo\": \"c\"}" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "beb61d02-c868-4c2b-b83f-1dfd280f1c8e", + "metadata": {}, + "outputs": [], + "source": [ + "builder = StateGraph(State)\n", + "builder.add_edge(START, \"subgraph\")\n", + "builder.add_node(\"subgraph\", subgraph)\n", + "builder.add_node(node_b)\n", + "builder.add_node(node_c)\n", + "\n", + "graph = builder.compile()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "3f07b704-1fe2-48a3-ad40-c9bc7698cb1c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Called A\n", + "Called C\n" + ] + }, + { + "data": { + "text/plain": [ + "{'foo': 'bc'}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graph.invoke({\"foo\": \"\"})" + ] + }, + { + "cell_type": "markdown", + "id": "bcd31ceb-f96f-4325-878d-ae1dea8cde8a", + "metadata": {}, + "source": [ + "### Use inside tools\n", + "\n", + "A common use case is updating graph state from inside a tool. For example, in a customer support application you might want to look up customer information based on their account number or ID in the beginning of the conversation. To update the graph state from the tool, you can return `Command(update={\"my_custom_key\": \"foo\", \"messages\": [...]})` from the tool:\n", + "\n", + "```python\n", + "@tool\n", + "def lookup_user_info(tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig):\n", + " \"\"\"Use this to look up user information to better assist them with their questions.\"\"\"\n", + " user_info = get_user_info(config.get(\"configurable\", {}).get(\"user_id\"))\n", + " return Command(\n", + " update={\n", + " # update the state keys\n", + " \"user_info\": user_info,\n", + " # update the message history\n", + " \"messages\": [ToolMessage(\"Successfully looked up user information\", tool_call_id=tool_call_id)]\n", + " }\n", + " )\n", + "```\n", + "\n", + "!!! important\n", + " You MUST include `messages` (or any state key used for the message history) in `Command.update` when returning `Command` from a tool and the list of messages in `messages` MUST contain a `ToolMessage`. This is necessary for the resulting message history to be valid (LLM providers require AI messages with tool calls to be followed by the tool result messages).\n", + "\n", + "If you are using tools that update state via `Command`, we recommend using prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] which automatically handles tools returning `Command` objects and propagates them to the graph state. If you're writing a custom node that calls tools, you would need to manually propagate `Command` objects returned by the tools as the update from the node." + ] + }, + { + "cell_type": "markdown", + "id": "8bcd1a3d-7c50-4f58-be4e-1ed654aa33be", + "metadata": {}, + "source": [ + "## Visualize your graph\n", + "\n", + "Here we demonstrate how to visualize the graphs you create." + ] + }, + { + "cell_type": "markdown", + "id": "e130cf70-a30e-47d7-8fd5-464f1a92e374", + "metadata": {}, + "source": [ + "You can visualize any arbitrary [Graph](https://langchain-ai.github.io/langgraph/reference/graphs/), including [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph). Let's have some fun by drawing fractals :)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6d604311", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from typing import Annotated, Literal\n", + "\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import StateGraph, START, END\n", + "from langgraph.graph.message import add_messages\n", + "\n", + "\n", + "class State(TypedDict):\n", + " messages: Annotated[list, add_messages]\n", + "\n", + "\n", + "class MyNode:\n", + " def __init__(self, name: str):\n", + " self.name = name\n", + "\n", + " def __call__(self, state: State):\n", + " return {\"messages\": [(\"assistant\", f\"Called node {self.name}\")]}\n", + "\n", + "\n", + "def route(state) -> Literal[\"entry_node\", \"__end__\"]:\n", + " if len(state[\"messages\"]) > 10:\n", + " return \"__end__\"\n", + " return \"entry_node\"\n", + "\n", + "\n", + "def add_fractal_nodes(builder, current_node, level, max_level):\n", + " if level > max_level:\n", + " return\n", + "\n", + " # Number of nodes to create at this level\n", + " num_nodes = random.randint(1, 3) # Adjust randomness as needed\n", + " for i in range(num_nodes):\n", + " nm = [\"A\", \"B\", \"C\"][i]\n", + " node_name = f\"node_{current_node}_{nm}\"\n", + " builder.add_node(node_name, MyNode(node_name))\n", + " builder.add_edge(current_node, node_name)\n", + "\n", + " # Recursively add more nodes\n", + " r = random.random()\n", + " if r > 0.2 and level + 1 < max_level:\n", + " add_fractal_nodes(builder, node_name, level + 1, max_level)\n", + " elif r > 0.05:\n", + " builder.add_conditional_edges(node_name, route, node_name)\n", + " else:\n", + " # End\n", + " builder.add_edge(node_name, \"__end__\")\n", + "\n", + "\n", + "def build_fractal_graph(max_level: int):\n", + " builder = StateGraph(State)\n", + " entry_point = \"entry_node\"\n", + " builder.add_node(entry_point, MyNode(entry_point))\n", + " builder.add_edge(START, entry_point)\n", + "\n", + " add_fractal_nodes(builder, entry_point, 1, max_level)\n", + "\n", + " # Optional: set a finish point if required\n", + " builder.add_edge(entry_point, END) # or any specific node\n", + "\n", + " return builder.compile()\n", + "\n", + "\n", + "app = build_fractal_graph(3)" + ] + }, + { + "cell_type": "markdown", + "id": "edcd9ad2", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-18T12:18:30.629307Z", + "start_time": "2024-04-18T12:18:30.609323Z" + } + }, + "source": [ + "### Mermaid\n", + "\n", + "We can also convert a graph class into Mermaid syntax." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "66007b2d", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-19T11:25:38.733126Z", + "start_time": "2024-04-19T11:25:38.726838Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "%%{init: {'flowchart': {'curve': 'linear'}}}%%\n", + "graph TD;\n", + "\t__start__([

__start__

]):::first\n", + "\tentry_node(entry_node)\n", + "\tnode_entry_node_A(node_entry_node_A)\n", + "\tnode_entry_node_B(node_entry_node_B)\n", + "\tnode_node_entry_node_B_A(node_node_entry_node_B_A)\n", + "\tnode_node_entry_node_B_B(node_node_entry_node_B_B)\n", + "\tnode_node_entry_node_B_C(node_node_entry_node_B_C)\n", + "\t__end__([

__end__

]):::last\n", + "\t__start__ --> entry_node;\n", + "\tentry_node --> __end__;\n", + "\tentry_node --> node_entry_node_A;\n", + "\tentry_node --> node_entry_node_B;\n", + "\tnode_entry_node_B --> node_node_entry_node_B_A;\n", + "\tnode_entry_node_B --> node_node_entry_node_B_B;\n", + "\tnode_entry_node_B --> node_node_entry_node_B_C;\n", + "\tnode_entry_node_A -.-> entry_node;\n", + "\tnode_entry_node_A -.-> __end__;\n", + "\tnode_node_entry_node_B_A -.-> entry_node;\n", + "\tnode_node_entry_node_B_A -.-> __end__;\n", + "\tnode_node_entry_node_B_B -.-> entry_node;\n", + "\tnode_node_entry_node_B_B -.-> __end__;\n", + "\tnode_node_entry_node_B_C -.-> entry_node;\n", + "\tnode_node_entry_node_B_C -.-> __end__;\n", + "\tclassDef default fill:#f2f0ff,line-height:1.2\n", + "\tclassDef first fill-opacity:0\n", + "\tclassDef last fill:#bfb6fc\n", + "\n" + ] + } + ], + "source": [ + "print(app.get_graph().draw_mermaid())" + ] + }, + { + "cell_type": "markdown", + "id": "8f77ad75", + "metadata": {}, + "source": [ + "### PNG\n", + "\n", + "If preferred, we could render the Graph into a `.png`. Here we could use three options:\n", + "\n", + "- Using Mermaid.ink API (does not require additional packages)\n", + "- Using Mermaid + Pyppeteer (requires `pip install pyppeteer`)\n", + "- Using graphviz (which requires `pip install graphviz`)\n", + "\n", + "\n", + "**Using Mermaid.Ink**\n", + "\n", + "By default, `draw_mermaid_png()` uses Mermaid.Ink's API to generate the diagram." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "967f116d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/jpeg": "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IgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIC17waINTV+xJ/958l3/8Aa/nWwlr3g1v5Jq/fb+s+S7tv879CDYSIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIC15wZG1TWHUH/3oyXcP/nLYa15wZ28k1ht7UZLw2/tkGw0REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEUzmdU3GZGbH4alDcs1w3yma1M6KGEkAhm4a4ufykO2AAAI3I3G+O8+6w/0DB+9zfVrqp6NXVF+yPWYWy3RRHn3WH+gYP3ub6tPPusP9Awfvc31a1utecawWW6KI8+6w/0DB+9zfVp591h/oGD97m+rTda841gs+3GHXd3hhwz1BqvH4N+pLGJr+VOxsc/YOlja4dq4P5XbcrOd/cd+Xbx3XmD4G3wvbXGbX+X0tR0LJSq2rd3OXMm7JB7abJHbtZyCFvOS8tbvuO8nw2XpafLasswyQzYzAyxSNLHxvsyua5pGxBBi6grU3wfeA1r4OsOpWafp4id2avutOkntS80MI37KAHs+rWczuvjum615xrBZ6TRRHn3WH+gYP3ub6tPPusP9Awfvc31abrXnGsFluiiPPusP9Awfvc31aefdYf6Bg/e5vq03WvONYLLdFEefdYf6Bg/e5vq1+2ai1VBvJPicXZjb1MVW69sjht+LzxhpPqBIHXqQm615xrBZaIupicpWzeOgvVHl9eZvM0uaWuHgQQeoIIIIPUEELtrkmJpm0oIiKAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIggNPnfNasJ7/Ox6/8A+vAs4sHp/wD6a1Z+lj/w8Kzi+vicY9I+kLPEREXmgi6NzOY/H5HH0LN2CC9kHPZUrSSASTljC9/I3vdytBJ27gu8gIiICIiAi6uVylbCYu5kbsvY06cL7E8vKXckbGlzjsASdgD0A3X4weap6kwuPy+Om8ox9+vHarTcrm9pE9ocx2zgCNwQdiAfWoO6iIqOtwxO+mJ/oyuSAAHcBenVYpLhh/Vix+lsn/x06rVy9J+PX6z9WquMiIi5mRERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEX5kkbExz3uDGNG5c47ABRuZ408P9PTdjktbafp2CdhXlycIlcfUGc3MT9ACC0Ra6dx60vO0nG19Q5vpuHYzTt6aI/8AfdiIh+t4UXmvhb4bHWvJIsDYbcPyYchl8bXkd+aFtl8//wBpBdaf/wCmtWfpY/8ADwrOKF4Salm1hjc5mJ6Xm6W1lHuNbeQ8m0UQHWSON3UAHqwd/TcbE3S+vicY9I+kLPF5d1bPr7ihxk1/hcNYsw0tMGpVqQU9VS4V0RmrNl7d7I6svb8znOA5zygR7cu+5PfxWB1dq7izR0prLVuXp2a2haVu/HprJy1IZr3ldiN07XMDXAkAEgcodsA4ENaBtjW/A3RHEXMsy2ewgs5JsPkzrVe1PWfLDvv2chie3tGdT6L9x1PRZ6lofCY7Uoz9aiIcsMdHiRO2R+wqxvc9kYZvyjZznHfbfrtvsufZm/ajyphq1ji5N8G/I6jzOY85XoMtVsW8fk56UkjoYJAJAYnt5Xu5PSc3YuG4O46LZun9PXdccfuJ1bI6o1FFh8JLifIcXQy09aFj31Gve48jgSCQN278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1J98f3FpEez2Dxe3drfEhLOsXw+WCHT+auOrW2VC2Ku1na83fKwyPaHRt8Xb/mBVEiCctaky7BeFbSeQmdXtMgiMlmqxtqM/KmYRKSGN9Tw158GnvXNrJ6m5rramAov7O1HHXdayZibNAflynlheWub12Zseb1tVEiCdnk1ZIbIhr4aANusEDpJ5Zeer+O54DG8svqaC5vrKS09VymcMy2IrDy9r4j5tlkIpj5UTvv4++n/OD0R+QVRIgnZMHnp+231M6EHINsR+T0YgWVh/1Y8/Nzb+MnR3q2XEmlL0/bCTVWZIfkBdYGCtH2UY/wCqtLYQTF6+bmkP5fgqNEE7LoitY7cT5TNSCW+3IANyc0XI4d0TTG5p7L1x9WnxBXE3D/CWRYE8Fmy2e83JPbPenkAnb8ktDnnkaPyG7M/1VRognpeHel7BtGfT2Ms+U3W5Gbt6jJOe035Mx5gfTHg7vHgsjHp7FRPsPZjKbH2JhYmc2uwGSUd0junV30nqsgiDgADuGy5REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBhtaaVqa70dndNZB80VDM0J8dYfXcGytjmjdG4sJBAds47EgjfwK0Fjvgd8KeBWkMnnMHp039QY6tJPUy2WlNieKYDeORoOzGua7YhzWgghellitVYUak0zlcUXBnltWWuHn8UuaQD+ondeuDNNOJTNfC8XWOLzXBC2tBHEwbMjaGNH0AbBftfKrJJJCBMwxWGExzRHvjkaS17T9IcCP1LCag1Rdwl1kFbS+YzbHRh5sY81hG07kcp7WZjt+m/QbdR179v6jVVFMXliVAoHizxJm0HHhqdGFs2Vy9h8MDpa09iOFrGF75HRwNdI/YAANaB1duSACV3PjAym39QNTfm5qH2pY7O4C1xOioXW1MtonOYS15Rj712OvMd3MLXgsjleHMc0kOBLT3bFc+JXNVExhcfSf1427hJt41aobhJ98RWfkY8xQx0FuxRt0qltll/Ju1kzRIxzDuD8sDoeu+yyd/i9mdGs1hU1DUo5HJ4aGnNTOMa+GO2bT3RxRlr3PLCJG7E7kbHfbpsqDIcO8xn8HQqZvUzchcq5mrlRZZj2ws5YZGPELWB/QHlPpFziC4942C+WquD9XV+S1RYuZCWOLN0KlRrIY+V9aSvI+RkrX79TzOadth8nvO65tjpEReme39Mp9e+3/AFxNYIapHHvD/dQ7EPsnTdt0fmlkrWNHlFfma7tCSdunpDbf1BbmWsaeidRac1LDq7L5qfWV2njpMdHQx2NhqySNklicXgumDdxybncgEd222xzrdfZRx2OgdSt6E7l1D1d3/Ol7YM9XeK4ntm+f0uLFFKUNbZK7dggk0TqGlHK8MdYsOpdnECflO5bLnbD6AT9Cq3ODWlziAANyT4LrpqirgjRvwg/gza8494dmQ0jSwt9uBlkp9hKeyyMgftYIbI70DGDO7ZhIIJceu422p/7P7hbrnRnArVOGzT8porIzZx7q0NvGtbNBtFBzzM7VpbI14HKDsWgscQSe70NwUwz8ZooWpWlkuUsPv8p/IcGsjP642MP61fL+cdPmmrpWJNPC/wD9/d6TxTmR0peyPnhp1Vmasd9sLYWVhWZ5Bybcxhd2JcTJt6XaF+2/o8iZLRFfLeeG2MpmhFk2wtfHWyc1fsBHtt2DonNdEXbekWkF3j06KjRcCJzJcP8ACZjzyLsFm0zLiEW4pL05jcItuQMZz8sfd15A3mPV26/WR4d6XzDswchp7GZAZnsPOLblRkzbfY7dj2jXAh3JsC3fuI3CoUQY52ncS+e7M7GU3TXTG61Ia7OacsGzC87ekWgADffbwWQAAJ2AG/U/SuUQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREGsOJHDCfJW5M1gmB9143s0C4NFggdHsJ2DX+B3IDum5BG51BcvRYyya2QLsbaHfBeaYX/qDttx9I3C9XL5z1orUZjmiZMw/iyNDh/4FfoOifxfE6PRGHiU7URw7bT917J4vKfneiP8Artf/ABW/xXHnej/ptf8AxW/xXp/7msR81Uvd2fwT7msR81Uvd2fwX0fx3D/xzr/pLQ8wed6P+m1/8Vv8U870f9Nr/wCK3+K9P/c1iPmql7uz+Cfc1iPmql7uz+CfjuH/AI51/wBFoeYPO9H/AE2v/it/innej/ptf/Fb/Fen/uaxHzVS93Z/BPuaxHzVS93Z/BPx3D/xzr/otDy/55omRsbLUUsrzs2KJ3O9x9Qa3cn9QWwtDcLruoLEdzOVJMfiWEObUnHLNa+h7e9jPWDs49xAHfuirj6tEEVq0NcHv7KMN/3LsLj6T/Gq8SmaMGnZv33vP6cLHZHBwAGgADYDuAXKIvzQIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIP/Z", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.display import Image, display\n", + "from langchain_core.runnables.graph import CurveStyle, MermaidDrawMethod, NodeStyles\n", + "\n", + "display(\n", + " Image(\n", + " app.get_graph().draw_mermaid_png(\n", + " draw_method=MermaidDrawMethod.API,\n", + " )\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "b9e767fc", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-18T12:18:30.873950Z", + "start_time": "2024-04-18T12:18:30.871750Z" + } + }, + "source": [ + "**Using Mermaid + Pyppeteer**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d403e1e7", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-19T11:25:44.798703Z", + "start_time": "2024-04-19T11:25:44.793438Z" + } + }, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install --quiet pyppeteer\n", + "%pip install --quiet nest_asyncio" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "058546ee", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-19T11:25:47.412695Z", + "start_time": "2024-04-19T11:25:45.405158Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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AAAAJpWJUwAAwEHt2zUw+nHjDG8hflVPT0++8IW/O2C9tbUt5557YXbs2J5HH30k3d37kiSXXnplqqurR89bsuS4XHDBpdm1a0ceffSRMde44IJLD7ju3Lnzxxy3t8/JZZe9Kffcc9eY9cbGpixbdnx27hyZCvWrPve5/5WPf/xPDutz/OY37xj9eNGipTn99Feno2NLfvrTH+f6629MfX19Zs5sG817//33jnn+2Wefd0BZ7MQTTzmse5dRY0ttsqk3e5/32gMAAAAAYOL5rgcAAHBQfb1DSZLaegNrx/OLX6wYLUXt9/GP/0kuvfSNo8c9PT25/fYv5J/+6dM5//xfG3PueeddlPPOuygbNz6T97//raPrS5celz/8wz87rAzvfOfNo8WpD3/4Y7nkkjfmmGNmjj6+efOz+Yu/+OMsX/6T0bV77/123vKWd+bUU1912J/r7/7u7+Xqq68fPV6z5qm0t89JkixYsGg07zve8cYxW/197GN/lLa2WYd9n7KrrRt5re1/7QEAAAAAMDkUpwAAgIPq/2V5o6ZWcWo8u3fvOmDt4ovfMOa4oaEhN974m3nTm64bU2iaKMuWHZ+PfeyTOeusc0eLTM83f/7C/NEf/WXe+95rxxSaVq1aedjFqf/0n/4gb3rTm8esHXfciS8vOOPaX1LsV5wCAAAAAJhUvvMBAAAc1P6pN3UmTo1rzpx5B6z94hc/H/fc9vbZqa2tnZQcr3/9VeOWpvZraGjI2972njFr423hN57jjjsxV1xxzcvKx+GrrR/ZytHEKQAAAACAyeU7HwAAwEH19/1yq766SsFJpqalS487YO2P/uijWbHi4QLSjLVz54488cRjeeCB+7J27dNZvHjpmMcPtzh13XW/kerq6smIyDj2b9W3/7UHAAAAAMDksFUfAABwUJXKSGFquOAcU1Vz84zcfPPv5B/+4W9H13bs6MpHP/rbueKKa3L99Tce0S3tHn74gXzxi/+YVatWprt730HP3bz58IpTS5YcOxHROEy/fMll2IsOAAAAAGBSKU4BAAAHtX/S1GC/FscLeetbb8zTT6/K97//nTHrd9/99dx999dz3nkX5eabPzSpBapVq1bm7/7uf2bFip8e9nMGBwcP67x58xa81Fi8BM9NeTMkGgAAAABgMvkqLAAAcFC19bYNO5S6urr83u/9t9x002+N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DgAAAAAAAABA76NVHwAAAIBeUVS0QTfccHnA0FQgL7/8rG644XLV1m7qcu2zzz6km266xi801dGiRR/rgQfu7NbzH6gVK/4dMDTV5txzLzUqZbX57LOPujxvXd1WU2hKkk444bT92+Q+euWVv+ruu//LLzTVUVHRBs2Y8Qs1NDQEXbNu3Wpdd91FAUNTHXm9bt1887WaPfsF+Xy+oOv27Nmjp5/+n4Chqf21bVud7rrr5oChqUA++2yerrrqPK1c+W2P7QEAAAAAAAAAEBpUnAIAAAAQcjt31uvuu/9LXq/bNG+12pWfP1oWS4y8XrfWrPnO9HhFRZmefPJ+3XffUwoLCwt6/u++W2oaH3bYWGVlOVVZ6TJVA5Kk5cu/0YYNa02VnYYOTdRPfrK3fds33ywxrZ8w4WhZLDGmueHDR3RxxXurLrVJSEjU+PFHS5IWL16gww4bq7y8kWppaTZVP1q06GNdd93vZLFYgp63Y9BowoSjZbMld7mfnuD1uk2fw/T0LB1++Hht3bpZ3377lWltY2ODPv74PV144RV+59m82aubb77Wbz4ry6lx446SxWJRQcGPWr16henx11//X2VlOXX88acG3N/99//R7/Mn7f06Gz36CEnSmjXf+bVj7MwTT9znd20xMbEaPfoIJSQMU339DhUUrDWds7GxQffcc5teffWfGjo0oeMpAQAAAAAAAAD9BMEpAAAAACE3a9ZzfqGpGTNu05lnnq9BgwYZc9u21em55x7V4sULjLnvvluqzz6bp9NPP7vL57nggst16aVXa8iQocbcqlXLdffdtxjt5iTp3Xff0J13/qcqUWpquu6662FJ0iWXnG4Kwdx22z1KTBy2D1drNmXKuZox4w9Gy8HrrvudsZeRI8coK8upiooySXsDN//+97900klnBD3f4sWfmMannDJ1v/e2v8aOnajf//5OpaVlGHObNlXrvvtuV1HRBmNu9uwXdN55lyoiwvyj5+uv/6/fOW+88Vadc87FprnS0iLdcceNps/Hyy8/o2OOOcGvheOyZV/7haYSEhJ1992PatSow405n8+n1157Xm+++XKX1/nll4v8znnOORfrqqt+bWr32NzcrHfeeU2zZj1nzDU2NuiFF57ULbfc1eXzAAAAAAAAAAD6Bq36AAAAAITU2rWr9MEHfzfNPfXULJ199kWm0JQkDR2a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379qGHV1dZo7d67mzp0rr9drzFssFk2bNk2XXXYZbfyAQ1Rtba2ee+45I1xVX1+vCy+8ULfffrtp3RNPPKHZs2cbY7vdrvvvv1/jxo3r7S0DPaKpqUlut9sIWG3ZskU///nPTWvWrFmj6dOnm+YuueQS3Xrrraa5++67T++//74kKS4uTna7XY888oiysrJM69avXy+bzSar1RqCKwIAAAAAdIbgFABgwNu9e7epelTbv5WVlWppaQl6XHx8vF/1qJycHKWkpAzYKkjbt283wlEbNmxQQUGBysvL1draGnC9xWLR8OHDTa328vLyTH/JC+DAtLb4tPKLzfp2oVe7mwL/twjg0JNgjdSE45OUP3aIYuIOvMpcc3OzFi1apDlz5uiHH34wPTZp0iRdeumlOu644wbsayBgIPB6vWppaVFysrnl50033aQvv/zSNPf2228rNzfXNDdt2jRZrVZlZ2fL4XAoPz9fP/3pT0O+byBUtmzZIrfbrc2bN6umpkY5OTkaP368aU37tn9tFixYYApI7dixQyeddJIxttvtOvHEE3XbbbeZjnO73WpoaFBKSgo/MwMAAABADyI4BQAYMNraUZSVlamkpMQISVVVVamzb4eJiYnKyckxhaOcTueA/0vQmpoaUxWpgoIC1dTUBF0/ZMgQo3pU283hcCg8PLwXdw0MXL+dcZMifamKDx+ulj2RptZbnfH5fEYQov39uLg45efnh2y/OHBbt2412swkJSUpOzu7j3eEUBocP0hDk6I0NClKw+xRSs8ZHLLnKigo0BtvvKFPP/3UVIUzIyNDF110kc477zwNHhy65wfQvzQ2Npra/pWWlv5/9u48Lup6+x/4i0U2kU1AcB3WGTZFBMR9QyX1uqQVopZL3TYzu9atzG5a3ntb7GplV7uZ4m5qRaWlaLngQkKKMOwgg4DADCAgwoAIvz/88vn5ccByYT4sr+fjMQ+d9+eM94A3kJnXnIN//vOforVkV69exfjx40WP8/DwwO7du0Vnly5dQnJysrD2jytBqSPIz88XVgNqNBrMnTtXdD0rKwvh4eGis7CwMKxevVp09t///hebN28GAFhYWMDR0RFvv/02BgwYIKrLyMiAtbW1TsiRiIiIiIiImsfgFBERdTharVY0OaopJFVQUHDXgJSDg4MoGOXq6go3NzdYWVnpsfu2p76+HtnZ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4OnpKTpLT0/HsmXLUFRUJJw98sgjeO+990R1O3bswLp164Q1gzKZDHPnzoVCodBL70REREQPisEpIhLJz8+HUqlEYmIikpKSWgzrGBsbw8PDA35+fujfvz9X7j2g6upqJCYmCpOklEolysvLdeoMDQ3h6uoqCqe5urrC0NBQgq6JiKi2thZbt27F1q1b0adPH+zevRsGBgZSt0VERG1QSUkJtmzZgu+++w51dXUAbq3RnDdvHmbNmgUzMzOJOyQiIildunQJubm56NKlC4YPHy669uGHH2Lv3r3CfVNTU7z11luYNGmSvtskok4qNTUVly9fRvfu3REYGCi69v7772P//v2is40bN+rUrVixAqampnB0dISjoyNkMhkGDhzY6r0TERER/REGp4g6sbq6OqSkpCAxMRGJiYm4ePEirl692mytg4MD/Pz8hJu3tzdMTEz03HHH0NjYCJVKJYTTEhMTkZOTg+a+HNvZ2cHPzw++vr7Cr3xBhYiobYiOjsbatWuh0WgAAGZmZoiMjOTUKSIiuqvS0lJs374d+/fvh1arBXBreu+cOXPw+OOPo2vXrhJ3SEREbc2ePXsQHR2NtLQ0IXzbXChh/fr16NKlC7y9vdG/f39YW1tL0S4RdTLp6elIT0+HRqOBWq2GRqPB8uXLYW9vL9Rcv34do0aNEj0uMDAQGzduFJ0lJSUhLy8Pffv2hbu7O58LJyIiIr1gcIqoEykpKcHFixeFkFRaWlqz06RMTEygUCiEkJSvry/3kz+AqqoqKJVKISSVlJSEqqoqnTpjY2MoFAohJOXn54eePXtK0DEREf0ZixYtwsWLFwEAU6ZMwZIlS7gqldqcL774AgAwduxYrnQhamMqKiqwfft27N27F9XV1QCAbt26ITw8HHPmzOHacyIialZaWhpSU1MxceJEWFhYiK6NHDlS+J4CAD179sQPP/yg7xaJiHRcvXoVn332GXJycpCTk4Oqqio8+uijWL58uahuzZo12LNnj3DfwcEBq1atQnBwsL5bJiIiok6EwSmiDurmzZvIzMwUTZMqLCxsttbe3h4DBgxA//79MWDAACgUChgbG+u5444jJydHCEglJSXh0qVLzU6TcnJyEk3xUigU6NKliwQdExHR/VCpVFi5ciVeffVV+Pr6St0OkQ6tViuseVm1ahUmT54scUdE1Jyqqirs3LkTu3fvFt5g0bVrV0RERDBARUREf9q1a9ewatUqxMfHC99PPD09sWvXLlFdUlISjh49iqCgIAQGBnKaCxFJoqSkBPX19Tpv2F66dClOnTolOouMjNR53uXRRx+FpaUl+vXrB5lMBrlcrrPmlIiIiOjPYnCKqIPQarVISkpCQkICEhISkJiYiJqaGp06Q0NDeHp6on///kJQytnZWYKOO4ba2loolUrRJK9r167p1JmYmMDLywt+fn7o378//P39OZWEiKidqK6uxpYtW7Bw4UKYm5tL3Q7Rn8bgFFH7cv36dXz99dfYtWsXysvLAdyaQDVv3jyEh4frTBUhIiJqiVKpRHx8PLp06YI5c+aIrm3atEm0GisgIACvvPIKvLy89N0mEZEOrVaLS5cuQaVS4fLly8jJycHy5ctFq0erq6sxcuRI0eOaC4qmp6cjMzMTrq6ucHFx4XM6RERE1CKOlCFqpyoqKnD+/HkhKJWWloabN2/q1HXr1k0UkvL19eU7yR5ASUmJKJyWnp7e7Oe9R48eQkiqf//+nOJFRNROHTp0COvWrUNJSQnMzc2xcOFCqVsiIqIOqmvXrli4cCEiIiKwe/dubN++HZWVlfjvf/+LXbt24cknn8Tjjz/On+eIiOgP+fr6tjgVt6KiQnT//PnzzU5AP3DgAIYNGwZbW9tW6ZGIqDlmZmbw9vaGt7d3izWGhoZ49913oVKpkJOTA5VKBU9PT526Y8eOYdOmTcJ9R0dHfPzxxwyKEhERkQ6+ik/UTuTn5yMhIQEXLlxAQkICcnNzm62TyWSioJSLi4ueO+04GhsbkZ2dLQSlWlp3aGRkBE9PTwwYMAADBgyAv78/HBwcJOiYiIgelpKSErz55pu4cOGCcKZUKiXsiIiIOgszMzMsWLAAjz32GHbv3o2dO3eivLwcn376KXbs2IEFCxZg5syZMDExkbpVIiJqh5YtW4bFixcjNTUVSUlJSE1Nhbu7u6gmMTERK1euBADI5XIEBQVh6tSpcHV1laJlIiIRMzMzTJo06Q/ramtrYW5uLmzmUKvVzW6BGDt2LPr27QuZTCas/RsyZMhD75uIiIjaLq7qI2qDGhoakJGRIQR2EhISUFJSolNnbGwMhUIBf39/+Pv7IyAgAFZWVhJ03DHU1dUJ6w6bVu9VVVXp1HXr1g1+fn5CUIpTvIiIOp66ujrMmDEDxcXFcHV1xeLFi3XGwBMREenDtWvXsGPHDuzevRvV1dUAAAcHByxatAjTp0/nZFsiInroDhw4IASnmrz77rs6QYX8/Hz07t1bn60REd2z4uJiYTJVeHi46FpeXh5mzJghOvP29sa2bdtEZ1lZWVCpVPD19YWTk1Or90xERET6xeAUURtw8+ZNpKSk4PfffxfW7zU9IX47c3Nz+Pn5YeDAgfD390f//v1hamoqQccdw/Xr14UJXufPn0dKSgrq6+t16nr27ClMkhowYADc3NxgYGAgQcdERKRPp06dwtWrV/GXv/xF6laIiIhQUVGBbdu24euvv4ZWqwVw62eVF154ARMnTuTPKERE9FBVV1fj3LlzOHv2LGJjY7F582Z0795duF5fX4/Ro0fDwsICwcHBCA4OxpAhQziFnYjalfz8fGzatAkqlQoqlQpVVVWYNGkS3n33XVHdV199hQ0bNgAAunfvDh8fHzz77LOQy+VStE1EREQPGYNTRBKor6+HUqnE+fPnhaBU0xPft7O1tRWmSQ0cOBByuRxGRkYSdNwxVFRUCOG0CxcuICMjA3d+CTQ0NISnp6cQkho4cCDs7e0l6piIiFpbcXExtm3bhsrKSrz33ntSt0NERPSHysvLsWXLFuzfvx+1tbUAbq1ReumllxASEiJxd0RE1FlcvHgRixYtEp15eXlh+/btEnVERPTgSkpKUF9frzNVasWKFTh06JDoLDIyEr6+vqKz1157TVj55+LiAldXV26rICIiagcYnCLSgxs3biAxMRHnz5/H77//jqSkJOEJ7tvZ29tj0KBBCAgIwKBBgyCTySTotuNQqVRISEhAYmIiLl68iNzcXJ2apqBUYGAgAgMDERAQAAsLCwm6JSIifcrLy8OWLVvw008/CdMGd+zYAYVCIXFnREREf45Go8HGjRvx448/oqGhAQAQEBCAZcuW8Z3vRESkFwkJCTh37hx+++03XLx4EfPnz8fixYtFNd9//z3UajUGDx6M/v37S9QpEdGD0Wq1UKlUyMnJEdb+vffee6KNILm5uZg5c6bocWFhYVi9erW+2yUiIqJ7xOAUUSuor69HcnIy4uLiEB8fj8TERNTV1enU9ejRQwhJBQQEoG/fvhJ023E0Te9KTExEQkICqqqqmq2Ty+UICAhAUFAQAgICYGlpqedOiYhIap988onwTmgTExOE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y5cvV3BwsObNm6e0tDQ5OzurY8eOWrp0qT7++GN17NiRoikHVatWLbVr106StGjRIh05csRwIgBAUTp8+LD+/e9/W4umJCk7O9tgIgAAgBtTp04dSdLvv/9uOAkAAI4lLS1NY8aM0Z49e/Too48qKirKdCQAwF/k10Hmvffe0759+/TCCy+ob9+++v777w0kAwD8GStOlXBZWVkKCwvTwoULlZiYaB3v1KmTRo4cqZo1axpMh+KUmJiohx56SBcvXpSfn5+WLl0qT09P07EAADfphx9+UKNGjfJcGdq3b19JUo8ePdSzZ0/atAIAALs0b948LViwQBUrVlR4eLjpOAAAOJStW7fqpZdeksVikYuLi5599ln169fPdCwAwFXs2bNHy5cv17fffmsdmzdvnlq2bGkwFQCUbq6mAyB/OTk52rhxo+bNm6fjx49bx4OCgjRq1CjVrVvXYDqYULVqVT3//POaPn26YmNjNWnSJM2ePdt0LADADTh16pRWr16tr776SqdPn9bYsWP1z3/+0+aYDz74QFWrVjWUEICjmDdvniSpQ4cOqlevnuE0AEqj3At+LBaL4SQAADieDh06yM/PT88++6wSEhIUHR1tOhIA4BoCAgIUEBCgw4cP64033tDly5cpmgIAw1hxqgT69ttv9cEHH9i0Y2vRooXGjh2rxo0bG0yGkuC1117Tl19+KUnq3r27pk6dajgRAOB67Ny5UyNHjrQZa9Omjd5//31DiQA4KovFoqCgIEnStGnT1K1bN8OJAJRGoaGhmjFjhiQpMjLScBoAABxTamqqlixZkud8AwCg5EtJScnTbeDgwYO69dZb83QpAAAUDVacKkGioqL01ltv6eDBg9axxo0b66mnnlKbNm0MJkNJMmnSJMXFxSkyMlJr166Vt7e3xo4dazoWAKCAWrRoIQ8PD126dEn33nuvevbsqbvvvtt0LAAAgCLx5xbzFotF7u7uBtMAAOCYvLy8KJoCADv116IpSZo4caLOnTunESNG6NFHHzWQCgBKF2fTASBFR0dr5MiRGjJkiLVoqnbt2po5c6aWLl1K0RTyeOedd9SgQQNJ0ieffELLPgAoYY4cOaKFCxeqX79++vXXX232lS1bVq+//rq+/vprzZw5U0FBQXJxcTGUFAAAoGi5ublZb1+8eNFgEgAASpecnByNHz+eFR8BwM78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DvYhqYCAALy9vQ3UitQ8q1evBqBhw4b27UBERKqLzp07a3BKRERqvUaNGjFkyBD76rGZmZlXrNx88OBBioqKKCwsZN++fezbt4/FixdjsVho3749PXr0ICAggMDAwHLbTu/ll19m+/btbNy4kVWrVpXLzxQRkdrp0qVLvPnmmwC88847hISEGC4SEfltGpwSERERkWuy2WwcOXLEPiSVmJhIWlraVec5OTnRuXNn+1OwAQEBuLi4GCgWqflsNht169Zl1KhRODg4mM4RESkTX19foqKiOHLkCIWFhdqmV0REBPDw8KB///70798fAKvVyvfff2//Pfz777/HarXaf0c/cuQIy5YtA6BFixYEBAQQEBBAjx49aN68eZn/+19//TXbt28HYOjQoeX3xkREpFbKycmxf12vXj2DJSIi1093qEREREQE+Peg1O7du+3b712+fPmq81xcXOjatSsBAQF0796drl27UrduXQPFIrXPyy+/TG5uLkVFRaZTRETKzM/PD4CioiL2799P9+7dDReJiIhUPS4uLgQHBxMcHAyU/Lt58OBBEhMT2bNnD0lJSfbf1VNSUkhJSWHNmjUANG7c+IqHmtq1a/er/62MjAxee+01ANq2bcvDDz9cge9MRERqg+zsbPvXbm5uBktERK6fBqdERMrgnnvuITU11X7DX0SkOrPZbBw7doyEhAQSEhJITEwkIyPjqvPc3d3tW+716NEDPz8/6tSpY6BYRABcXV1NJ4iI3JDOnTvj5OREQUEBcXFxGpwSERG5DnXq1MHf3x9/f38eeugh++/ye/bssQ9SpaamAnDhwgU2btzIxo0bAfDy8rIPUQUEBNChQwcsFov9Z1+8eBEPDw8yMzOZNWuWVoMUEZGb9ssVpzQ4JSLVhcVms9lMR1yP0NBQCgoKmDJlCpGRkaZzRERERKql48ePk5CQwO7du9m9ezfp6elXnePt7W1/QrVHjx5X3VgVERERuVGTJk1ix44d+Pv78/HHH5vOERERqRFOnz5tX5EqMTGRM2fOXPO80gejAgMDCQgIoFOnTtSpU4edO3fSq1evSq4WEZGaKDk52T7AO27cOFxcXAwXiYj8Nj0+ICIiIlKDnT9/nri4OOLj49m1axdpaWlXnePl5UVAQABBQUEEBQX95lL+IlL5fv75Zxo2bGg6Q0TkpvXu3ZsdO3awf/9+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Z4mIiFRJsbGx/N///R/z58+nS5cupnOMadSoEXfffTd33303NpuNH3/8kbi4OHbu3ElSUhL5+fmcOXOG5cuXs3z5chwdHenatat9kKpjx45YLBbTb0NEpEa4dOkSAD4+Pvq7VUSqFQ1OiYiUga+vL25ubrRu3dp0iohUkOPHj7NkyRKioqLIz8+3Hw8KCuKBBx6gX79+ODg4GCwUkZrkk08+ISwsjLZt21dsP9kAACAASURBVJpOERExrnHjxrz++us8/vjjJCcn88ILLzBnzhzTWSIiIlXOihUrePXVVwF46qmnWLdunYaNAYvFQseOHenYsSPjxo0jLy+P3bt3ExcXx44dOzhx4gSFhYXs2bOHPXv2MH/+fLy8vAgJCSE0NJTevXvToEED029DRKTaKl1xSqupi0h1Y7HZbDbTEdcjNDSUgoICpkyZQmRkpOkcERERqWGOHj3KO++8Q2xsrP2Yi4sLd911F5GRkbRp08ZgnYjURLGxsUyePBmAhQsXEhQUZLhIRKRqeO+99/j73/8OwNNPP82YMWMMF4mIiFQdn332GW+88QYAjo6OzJ49m/DwcMNV1UNqaiqxsbH2FakuX7581TmdOnWiT58+9OnTB39/fz08JyJSBlFRUcTFxeHj48MTTzxhOkdE5LppcEpERERqteTkZBYsWMDmzZvtxzw8PHjggQeIjIykfv36ButEpKY6d+4cY8eOJSMjg44dO/Lpp5+aThIRqTJsNhuPP/44u3fvpk6dOvz973+na9euprNERESqhPnz57No0SIaNmzIG2+8QefOnU0nVUvFxcX88MMP7Nixgx07dvDDDz9QXFx8xTmenp6EhobSp08fevfujaenp6FaEREREalIGpwSERGRWikrK4t3332X5cuX22+MNWzYkDFjxnDffffh6upquFBEaiqr1cr48eM5evQozs7OfPbZZ9oGWETkP6SnpxMZGcnFixfx9PTko48+0t+VIiIi/7Jw4UJGjx5Nw4YNTafUGFlZWezYsYPvvvuO7du327ebKmWxWOjcuTN9+vShb9++dOrUCYvFYqhWRERERMqTBqdERESk1lm7di1vv/02ly5dAqBp06Y89NBDjBw5krp16xquE5GarqCggFmzZrF+/XpmzJhBRESE6SQRkSrp2LFjPPLII2RlZeHj48MHH3xAixYtTGeJiIhIDWez2Th06BDfffcd33333TVXo/L29qZv376EhYUREhKiB/BEREREqjENTomIlMGKFStITU3Fz8+PsLAw0zkiUkZHjhzh1VdfZd++fQC4uLjwyCOP8NBDD+Ho6Gi4TkRqm/j4eIKDg01niIhUaT/88AN/+MMfyMvLo0mTJnz88cc0atTIdJaIiEiliI6OJioqijlz5uDg4GA6p9bKzMy8YjWq9PT0K153dHQkKCiIvn37MmDAAJo2bWqoVERERERuhAanRETKYOzYsRw+fJiRI0fy/PPPm84RkTL49NNPefvttykqKgIgPDycqVOn4uPjY7hMRERERH7N7t27+eMf/0hhYSGtWrXigw8+wNvb23SWiIhIhcnNzeVvf/sby5YtA+DRRx/lscceM1wlULIa1Q8//MC2bdvYtm0bP/7441Xn3HLLLfTv35/+/fvj5+enLf1EpFY4e/Ys8+bNo1GjRowfP15DpCJSrWhpBREREanRcnNzef755/n2228BaNmyJS+++CLdu3c3XCYitUlGRgaenp6mM0REqqXAwEDmzp3L008/zalTp/j973/PwoULadasmek0ERGRcnfo0CGmTp3KuXPnAAgKCuL+++83XCWlLBYL/v7++Pv7M3HiRFJTU9m6dSuxsbHEx8eTl5fHsWPHOHbsGB999BE+Pj6EhYXRv39/evXqhZOTk+m3ICJSIc6cOUNMTAwADzzwgOEaEZGy0dquIiIiUmOdOnWKMWPG2Iemhg4dyrJlyzQ0JSKV6vLlyzz88MM8++yz5OXlmc4REamWwsLCeOGFF4CSG/IPPfQQBw4cMFwlIiJS/ho1akRWVhYAEyZMYOHChXh5eRmukv/Gx8eHUaNG8dZbb7F582b++te/cvfdd9OgQQMAUlNTWblyJZMnT2bgwIFMnTqVdevWkZGRYbhcRKR8Xbhwwf61VpsSkepGK06JiIhIjXT27FnGjRvH5cuXqVOnDk8//bSe0BQRIyZPnszJkyc5efIkQ4cOpX///qaTRESqpWHDhmGxWJg5cybp6ek8+uijzJkzhz59+phOExERKTcNGzZk1qxZODo6EhoaajpHysDFxcW+RZ/NZuP7778nJiaGmJgYkpOTsVqtbN26la1bt2KxWOjevTsDBgxg4MCB/M///I/pfBGRm1I6OFWvXj1cXFwM14iIlI0Gp0REyuCee+4hNTUVPz8/0yki8isyMzOZOHEily9fxmKx8MorrzBo0CDTWSJSyxQVFTFlyhT27t0LwMSJEzU0JSJykyIiIvD09OTPf/4zeXl5TJ48menTpzN8+HDTaSIiIjfku+++u2oIOCwszFCNlBeLxULXrl3p2rUrkyZN4syZM3zzzTfExMSwd+9eiouLSUxMJDExkTfffJNbb72VgQMHMnDgQG699VbT+SIiZXbx4kUAGjdubLhERKTsLDabzWY64nqEhoZSUFDAlClTiIyMNJ0jIiIiVdjEiROJj48H4LnnnuPee+81XCQitdGZM2cYO3YsWVlZREREMGPGDNNJIiI1RlJSEpMnT7ZvZTR+/HieeOIJw1UiIiLX7+jRo8yYMYNDhw4xf/58evXqZTpJKklGRgYxMTFs2bKF2NjYq15v1qwZ4eHhDBo0CH9/fwOFIiI35uzZs+Tk5HDLLbeYThERKRMNTomIiEiNkpSUxIQJEwB49NFHeeyxxwwXiUhtduzYMd58803eeustHB214K+ISHk6evQoEydO5NKlSwCEhITw6quvUr9+fcNlIiIiv+6f//wnc+fOtf85PDyc1157zWCRmJKTk8N3333HN998Q2xsLDk5OVe8XjpENXjwYHx9fQ1VioiIiNRsGpwSERGRGmXKlCnExMTg4eHB119/rUEFERERkRrsp59+4n//939JSUkBSj5cnDdvHh07djRcJiIicm3JycmMGjUKAFdXV5588klGjx5tuEqqitjYWL755huio6PJzs6+4rUmTZowZMgQwsPDNUQlIiIiUo40OCUiIiI1St++fbFarYwdO5annnrKdI6I1DJZWVm4u7ubzhARqVWysrKYPn26fasbJycnZs6cyeDBgw2XiYiIXNubb77Jrl27mDt3Li1atDCdI1VQYWEhO3fuZNOmTWzdutW+PXGpli1bMmTIEIYOHUrLli0NVYqIiIjUDBqcEhEpg9mzZ3Pq1Cn69evHgw8+aDpHRP5DYWEhISEhAEybNs3+BKeISGXYunUrs2fPZuHChbRv3950johIrfPRRx+xYMECSm913X333fz5z3/GxcXFcJmIiNRmGRkZeHp6XnHMarXq3ye5boWFhezYsYOvv/6ab7/99qqVqPz8/Ljzzju544478Pb2NlQpIrVZTk4OKSkpNG7cGC8vL9M5IiJl5mA6QESkOjl48CB79uzh5MmTplNE5Bq0LZ+ImBIbG8vUqVNJT0/XanciIoY8/PDDvPvuu/aV/9asWcP999/PwYMHDZeJiEhtlJOTw5w5c7jrrrs4f/78Fa9paErKwtHRkbCwMGbNmkV0dDTz5s3jjjvuwNXVFYADBw7w17/+lSFDhvDHP/6RdevWkZOTY7haRGqTH374gTFjxhAeHk5ycrLpHBGRMtPglIiIiNQofn5+AMTHxxsuEZHaIj4+nqlTpwLg6urKnDlzDBeJiNRewcHBLF26lG7dugFw5swZfv/737N48WKqyaLrIiJSA0RFRTFixAiWLVuG1WplwYIFppOkhnBycmLAgAG8/PLLREdH88orr9C3b1/q1KlDcXExO3fuZMaMGYSHhzNt2jS2bt1KQUGB6WwRqeHOnDlj/7pp06YGS0REbowGp0RERKRG6dChA1CyZdbFixcN14hIbbBs2TIKCwtxcXHh3XffxdfX13SSiEit1rRpU/7+978zceJE6tSpQ2FhIX/729/4wx/+wNmzZ03niYhIDRcbG8v06dNJS0sDYNSoUfYHLUTKk7OzM4MHD+att97i66+/5tlnn6VLly4A5OfnEx0dzdSpU7njjjt4/fXXOXDggOFiEampfvrpJwAaNGigVRVFpFrS4JSIiIjUKPfccw8ARUVFLFq0yHCNiNQGs2bNonfv3rz77rv2m9QiImKWg4MDjzzyCB9//DHNmjUDIDExkfvvv59Vq1YZrhMRkZqsd+/etG/fniZNmrBo0SKmTZtm30ZWpKJ4enoyevRoFi1axOrVq3n88cdp1aoVAJmZmXzxxRf87ne/Y/To0XzyySf2wT4RkfJQOjhV+ruXiEh1Y7FVk3XKQ0NDKSgoYMqUKURGRprOERERkSrstddeY/ny5QC8/vrrDBo0yHCRiIiIiJiSk5PDG2+8ccXAVGhoKC+++CI+Pj4Gy0REpCZIT0/Hy8vrimOHDh2iRYsWGpgS4/bv38+6devYuHEjly9fth93cHAgJCSEiIgIBgwYQN26dQ1Wikh1t2zZMqKiomjZsiUzZ840nSMiUmYanBIREZEax2q18uCDD5KcnIyjoyMLFy6ke/fuprNEpIbYuXMnvXr1Mp0hIiJltH37dmbOnMnPP/8MgIeHB9OmTWPw4MGGy0REpDpKTk7mtddeIz09nc8//xyLxWI6SeS/KigoICYmhnXr1rF9+3aKi4vtr7m7uzN48GCGDRumVZRFRESkVtLglIiIiNRIycnJPPzww2RmZuLq6sqiRYto37696SwRqcaKioqYOXMm69ev1+8lIiLV1OXLl3nppZf45ptv7Mf69OnDiy++iLe3t8EyERGpLpKTk1m0aBFfffWV/dicOXO47bbbDFaJXL/09HTWrVvHunXrOHr06BWvtWnThuHDhzNs2LCrVlITERERqak0OCUiIiI11pEjR5gwYQLZ2dm4uroyZ84cQkNDTWeJSDWUlZXF1KlTSUhIAMDf35+PP/7YcJWIiNyojRs38tprr9m3rKlfvz5TpkwhIiLCcJmIiFR1f/3rX/n8888BaNCgAZMmTWLYsGFacUqqpUOHDrFu3TqioqJIT0+3H69Tpw5hYWGMGDGC0NBQ6tSpY7BSREREpGJpcEpEpAwOHjxIdnY2jRo1onXr1qZzROQ6HDp0iD/96U/2LVkmT57Mgw8+aLhKRKqbxx9/3D40dfvtt/Pqq68aLhIRkZv1888/M3PmTLZv324/FhgYyEsvvUSTJk0MlomISFWWnp7OsGHDGDFiBI8//jhubm6mk0RuWmFhITExMaxatYq4uDh++dGhj48PERERjBgxghYtWhisFBEREakYGpwSESmDsWPHcvjwYUaOHMnzzz9vOkdErtOlS5d45plnSEpKAuC2227jpZdewsXFxXCZiFQX33//PRMmTOD2229n1qxZeppcRKQGiYqKYu7cuWRkZADg6urKE088wX333ae/70VEarGcnBw++eQThg8fTrNmza54LTMzEw8PD0NlIhXrwoULrF69mtWrV3Pu3LkrXgsICGD48OEMGjRI99VEBIDo6Gg2b95Mq1atmDhxoukcEZEb4mA6QERERKSiNWjQgA8++IDbb78dgC1btjBu3DiSk5MNl4lIddGlSxfef/99Zs+erQ/RRURqmCFDhrB8+XIGDhwIQG5uLnPnzuWRRx7h1KlThutERKSyWa1WPvnkE4YNG8YHH3xwzS26NTQlNVnjxo159NFHWbduHW+//TaDBg2yv7Znzx5efPFF+0NF+/fvN1gqIlVBQkICmzZtYsuWLaZTRERumAanREREpNZ45ZVXGDFiBADHjh3jwQcfZNu2bYarRKQqunz58lXHunXrZqBEREQqQ4MGDZg7dy6vvfYaXl5eAOzbt4/7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IlLzZGVlXXVs6NChdOrUiaeeeooNGzbwpz/9iUaNGhmoE5GyaNasGZMmTWL9+vW8/vrrhISEYLFYKCoqIiYmhsmTJzNs2DDef/99Lly4YDpXRP7l2LFj9q+12pSIVHcanBIRERH5FR06dOCzzz4jKCgIgCNHjhAZGcmOHTsMl4lIWUVERDB//nz+8pe/ULduXdM5IiJSw3h4eDBjxgwWLlxI06ZNAdi/fz/3338/H330EUVFRYYLRUSqv5SUFObOncudd95JVFTUVa8vWbKEsWPHamVZkWrI0dGRQYMG8c4777B27VoeeeQRfHx8ADh//jzvv/8+ERERTJ48mZiYGF1biRh29OhRAFxcXOy//4iIVFcWWzVZMzw0NJSCggKmTJlCZGSk6RwRERGpZYqLi5k/fz6LFy8GwGKx8NhjjzFhwoQy/ZygoCASEhIqIlFEfuGLL77A19cXf39/0ykiIlILWa1W3nvvPT799FP71jK33HILL730Eh07djRcJyJS/Rw/fpx33nmHb7/91n6sW7du9q24RaRmKioqYtu2baxatYrvvvvuim2QfXx8GD58OCNHjtTQhogBGzZsYOXKlTg5OTF//nzTOSIiN0WDUyIiIiJlsGXLFl544QWsVisAffv2Zfbs2bi7u//m95auWuXk5KQVq0QqyE8//cT06dPZt28fLVu2ZOnSpTg7O5vOEhGRWurw4cO88MIL9m0sHBwcePDBB3n88cdvaPVDDeGLSG118uRJ7r33XqBkhb8777yTkSNHamsgkVrkwoULrFq1itWrV3P+/Hn7cYvFQq9evbjnnnvo168fjo6OBitFRESkOqozY8aMGaYjrseHH35IcXExvXv3pkuXLqZzREREpJZq27Ytt912Gzt37iQjI4NTp06xadMmQkND8fLy+q/fFxQUZH8qrri4mIKCAnr27FlZ2SK1wubNm3nyySdJSUkBoEmTJvTr14/69esbLhMRkdrKx8eHe+65B1dXV/bu3UthYSF79+4lKioKf39/mjRpct0/q3QI//3338fb2xs/P7+KyhYRMSouLg53d3dcXFzsx7y8vCgqKuLee+9l1qxZ9OnTB29vb4OVIlLZ3NzcCAwMJDIyks6dO5Obm0tKSgrFxcWkpKSwadMmvvzySzIyMmjZsqXuBYiIiMh104pTIiIiIjcgNzeX5557jtjYWKBk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Wrvh5FwyhnTmRK7hmuvnaDpARKQ6+fTTT00n1Chp5/MBcPN0sm99IyIiIlJVOdRxoElLN84mZ5N2Ps90jlSAtAv//v+1eTs3gyUiIiIiv635LfU5kpRBUYGNrPQC6jfQ/bWa5tK/fu9o0d7dcImIiIjIb7M4WGjaxo3Thy9Xq/unWnFKRESMycoseZrf3VM3dURERKR6qO9V8vxRdmah4RKpCKXXp6BrVBEREan63Dz+/Wx89i+uY6TmyPrX7x31dG0qIiIi1YS7Z+n90+pzfarBKRERMcaaXQSAs2sdwyUiIiIi16duvZJf/HOyigyXSEUovT4FcK6nRbpFRESkaqvn/u9hmpxsXZ/WRNacYgBc6+n+qYiIyP9n787Doqr+P4C/URQGFwbFBdlBFMXEfd9x18wtK5fU0qTUXHL7luWeS2mWmZpL5ZZbpua+b6louIUKoqAoYgiCKIsywO8PfozcubMBs13m/XqenriHO3c+cmfOvefczzmHpKFMudx71HQJ3Z8ycYqIiMwmJyf3/yV4NSIiIiKJKFHSBgCQk51j5kjIGPLuT2Fj1jCIiIiI9GKTr08tWzrPpUhf+ZscNrxBJSIiIon4/9uW7GzzhlEQHD5JRFQAt27dQmpqKipVqgRPT09zh0NERERERERERERERERERESFxDk+iIgKYO7cuQgODsbGjRvNHQoREREREREREREREREREREVAROniIiIiIiIiIiIiIiIiIiIiIjI6jBxioiIiIiIiIiIiIiIiIiIiIiIrA4Tp4iIiIiIiIiIiIiIiIiIiIiIyOrYmjsAIiIp6du3LxISElC7dm1zh0JERERERERERERERERERERFwMQpIqIC6Nevn7lDICIiIiIiIiIiIiIiIiIiIgPgUn1ERERERERERERERERERERERGR1mDhFRERERERERERERERERERERERWh4lTRERERERERERERERERERERERkdWzNHQARkZTMnTsXMTExaNOmDQYPHmzucIiIiIiIiIiIiIiIiIiIiKiQmDhFRFQAt27dQkREBDw9Pc0dChERERERERERERERERERERUBl+ojIiIiIiIiIiIiIiIiIiIiIiKrw8QpIiIiIiIiIiIiIiIiIiIiIiKyOkycIiIiIiIiIiIiIiIiIiIiIiIiq2Nr7gCIiKRk+vTpSE1NRaVKlcwdChERERERERERERERERERERUBE6eIiAqgVq1a5g6BiIiIiIiIiIiIiIiIiIiIDIBL9RERERERERERERERERERERERkdVh4hQREREREREREREREREREREREVkdJk4REREREREREREREREREREREZHVsTV3AEREUjJ37lzExMSgTZs2GDx4sLnDISIiIiIiIiIiIiIiIiIiokJi4hQRUQHcunULERER8PT0NHcoREREREREREREREREREREVARcqo+IiIiIiIiIiIiIiIiIiIiIiKwOE6eIiIiIiIiIiIiIiIiIiIiIiMjqMHGKiIiIiIiIiIiIiIiIiIiIiIisjq25AyAikpJNmzaZOwQiIiIiIiIiIiIiIiIiIiIyAM44RUREREREREREREREREREREREVoeJU0REREREREREREREREREREREZHWYOEVERERERERERERERERERERERFbH1twBEBFJya1bt5CamopKlSrB09PT3OEQERERERERERERERERERFRIXHGKSKiApg7dy6Cg4OxceNGc4dCRERERERERERERERERERERcDEKSIiIiIiIiIiIiIiIiIiIiIisjpMnCIiIiIiIiIiIiIiIiIiIiIiIqvDxCkiIiIiIiIiIiIiIiIiIiIiIrI6tuYOgIhISvr27YuEhATUrl3b3KEQERERERERERERERERERFRETBxioioAPr162fuEIiIiIiIiIiIiIiIiIiIiMgAmDhFRERkZWbOnISUlGQAQMmStpgzZyns7e3NHBXl2bRpDUJDLyi3g4M/Q40atcwYEVHxEBJyFlu3/qrc7tz5TXTt+pYZIyoahUKBly8zkJGRAYUiEwqFAtnZWShZ0hYVK1aCnZ2duUPUKisrC6GhF1Ctmjvc3DzMHQ4RmVlxq6OLG54fIuMpTu3znJwcvHz5Ei9fZiAz8xUyMzOhUGQiOzsbMpkDKlashJIlS5o7TGRlZeHVq1d4+TIDr169hEKhQFaWAjk5OShfXg653MncIRKRmcXHP8aCBdOV297efhg7dqoZIyJVxen6SWRJituzifz3fJmZmcjKykJWlgIymQOcnCrC1tayU2UePXqIhIR4PH2agOzsLDg6OkEurwC53AmOjk4WH7/U8K9JRERkZa5evYT09DTldlaWwozRkKp79+7ixo1ryu3k5KdmjIao+Hjy5LHguxUQEGjG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c4dFRMWYZBKn7OzsAHDGKSIyryVLlpg7BCIiKgZmz+b1hIiIiIgsx8CBH2LgwA/NHQYRERERERo0aIoGDZqaOwwisiIlzB2AvjjjFBERERERERERERERERERERERGQoTp4iIiIiIiIiIiIiIiIiIiIiIyOpIJnEqb6m+9PR0M0dCRERERERERERERERERERERERSZ2vuAPQlk8kAAKmpqWaOhIisWUxMDOLj41GmTBnUqlXL3OEQERERERERERERERERERFRIUkmcapMmTIAgLS0NDNHQkTWbOvWrdi6dSt8fHywbds2c4dDREREREREREREREREREREhSSZpfqYOEVElqB06dIAgMzMTDNHQkREREREREREREREREREREUhmcQpBwcH5c/p6elmjISIrBkTp4iIiIiIiIiIiIiIiIiIiIoHySROlS1bVvlzamqqGSMhImuWlzj16tUrM0dCRERERERERERERERERERERWFr7gD0Vb58eeXPKSkpcHZ2NmM0RGStGjVqhJEjR8Le3t7coRAREREREREREREREREREVERSCZxqkKFCsqfExIS4OPjY8ZoiMhaBQYGIjAw0NxhEBERERERERERERERERERURFJZqm+/DNMPX361IyREBERERERERERERERERERERGR1Ekmcaps2bKwtc2dICshIcHM0RARERERERERERERERERERERkZRJJnEKeD3rVGJiopkjISIiIiIiIiIiIiIiIiIiIiIiKZNk4hSX6iMic4mLi8OCBQvw2Wef4fHjx+YOh4iIiIiIiIiIiIiIiIiIiApJUolTFSpUAMAZp4jIfJ4+fYodO3bg1KlTSE5ONnc4REREREREREREREREREREVEiSSpyqWLEiACZOEZH5lClTRvlzamqqGSMhIiIiIiIiIiIiIiIiIiKiopBk4lRcXJyZIyEia5U/cSotLc2MkRAREREREREREREREREREVFRSCpxqmrVqgCAFy9e4NmzZ2aOhoiskYODg/JnzjhFREREREREREREREREREQkXbbmDqAgPDw8lD8/fPgQjo6OZoyGiP6PvTuPrqo82z9+hYRAJgiQSQYzAgHCaBgUEApRVKJSRKUOVBGLUxUp/gSHNq0T+mrFVl5wZBBb8aWCGgQlzKCAAYIkJDGQQUjICAmZTubfH+hpt6GtIMmTk3w/a53l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xXQMAAAAAAAAAAAAwK6srMx0BABocZxjYmJiTIdoau7u7vLy8tKXX36poqIi2Ww2XX755aZjAWiF7r33Xr3xxhs6c+aMfdodAKD5bdu2TZ9//rlOnDih8PBw03EAAADQhr344ot64403VFJSoqFDh5qOAwAAgDZs6dKlevLJJ1VdXa1hw4aZjgMALUKbmDglSbfeeqvGjBkjSXr//fe1d+9ew4kAtEYDBw6UJO3cuZPpdgBg0LZt2/TWW29p3bp1pqMAAACgjfvqq6+UnJysrKws01EAAADQhhUVFWn16tUqLi7W8ePHTccBgBajzTROSdKf/vQndevWTZL05JNPqri42HAiAK3NxIkTJUlVVVXatGmT4TQAAAAAAMCknJwcnThxQpIUGRlpOA0AAADaqoaGBj355JOqqqqSi4uLHnzwQdORAKDFaFONU506ddILL7wgSSouLtYTTzyhhoYGw6kAtCYDBgxQz549JUlbtmwxnAYAAAAAAJj0w7WBdu3a6corrzScBgAAAG3V4cOHFR8fL0m699575efnZzgRALQcbapxSpKGDRumO++8U5K0b98+rVy50nAiAK3NPffco2eeeUYvv/yy6SgAAAAAAMAgFxcXde7cWcOHD1enTp1MxwEAAEAbNWjQIC1ZskSXX3657r77btNxAKBFcWpogyOXamtr9etf/1qpqalq166d/vKXv2jUqFGmYwEAAAAAAABohQoKCuTr62s6BgAAAAAA+JE22TglSdnZ2br11ltls9nUsWNHLVu2TL179zYdCwAAAAAAAAAAAAAAAEAzaHNb9f2gR48eWrhwoZycnGSz2fTQQw8pLy/PdCwAAAAAAAAAAAAAAC7YkSNHNGvWLJWWlpqOAgAtXpttnJKkMWPGaMGCBZKkoqIiPfjggyorKzOcCkBrkpCQoMWLF5uOAQAAAAAAmtGOHTtMRwAAAEAbFRsbqxkzZighIUFz5841HQcAWrw23TglSVOnTtXMmTMlSZmZmZo7d65qa2sNpwLQGqxfv16zZs3SsmXLlJycbDoOAAAAAABoBtu3b9fcuXN11113KTc313QcAAAAtCEPP/ywYmJiJEne3t767W9/azgRALR8bb5xSpIeeOABRUdHS5IOHDhg/8cEAH6O8ePHq2PHjpKk5cuXG04DAG1LTEyMIiMjddddd5mOAgAAgDaksrJS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XJxqa2u1ceNGbdy4UWFhYZo8ebImT57MFCqglXFxcdH8+fPVv39//elPf1Jtba327NlD4xQAAAAAwCEUFRWpW7dullppaan9eVBQkKKiolRXV9fc0QAAANqU3NxcdejQQV26dLHUY2JiFBcXZ6ldf/31lsapjh076oYbbpC3t7eCg4MVEhKikJCQRr8Hk6UAAC0ZE6dakVOnTmnNmjX66KOPVFhYaK87OTlp5MiRmjx5sn7xi1+oY8eOBlMCuNiOHj2q559/XosWLVKnTp1MxwGAFoGJUwAAAC3P9u3btWnTJu3YsUPXXnutFixYYDn+xRdf6Pjx45o4caKCgoIMpQQAAGjdCgoKtHjxYqWnpysjI0OVlZV69NFHdfvtt1vWvfnmm3rzzTfl6uqq0NBQ9erVS7/61a80cOBAQ8kBAGgaNE61QrW1tfryyy+1fv167dixQzU1NfZjbm5umjhxoqKjo3XZZZfJycnJYFIATc1ms9EsCaBNWrFihXbv3q2QkBDNnz/fdBwAAIA27cyZM7ruuutks9nstUsuuUSffvqpwVQAAACtT0pKig4cOKDMzExlZWUpPT1db731lqUp/fTp07rqqqss75syZYqeeuopS62wsFC1tbUKCAholuwAAJhC41QrV1ZWps8//1yxsbE6fPiw5Zi/v7+uvfZaXX/99QoMDDSUEEBTWbx4sTZs2KCYmBhFRkaajgMAAAAAaOXKy8u1d+9e9e/fv9EXbNOnT9fRo0fl6empyMhIjRgxQrfccouhpAAAAI7JZrPp2LFjOn78uPz9/TV06FDL8ZdfflkffPCBpbZo0SKNGTPGUluwYIF69uyp4OBg+4ObsAEAbRWNU21Idna2Pv30U61fv14nT560HAsLC1NUVJSuvvpqXXrppYYSArhYsrOzdeONN9pfX3PNNZo3b568vb0NpgIAAAAAtDa5ubn65JNP9NVXX9lv2ps/f76mTZtmWbd371517NhRgwcPNhETAADAYaSlpal3796W2r59+/SHP/xBBQUF9toNN9yg3//+95Z1H3zwgV5++WV16NBBQUFBCgoK0m233aYBAwY0S3YAABwRjVNtUENDgw4ePKj169crLi5O5eXlluPBwcGaOHGioqKiFBYWZiglgJ/ryy+/1DPPPGP/QWrs2LF69dVXDacCAAAAALQm33zzjWbOnGmpRUVF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AAAAms6HH36ojRs36ptvvrHXhg8fbpmK3bdvX/n5+alPnz6KiIhQREQEW9UAAACdOXNGBQUF6tatW6MtfJ988knt379fhYWF9lp8fLxlTUVFhdasWWOp5eXlNfp9RowYoW7dutkbovz8/NShQ4dG637c6A0AANBW0EUCh+Ph4WG5q6G6ulpJSUk6ePCgDhw4oG+++UYVFRUqKyvT7t27tXv3bkmSq6urwsPDNXDgQPvD39/f5KkArYKvr68eeughPfTQQ8rNzW10fNu2bZo3b56uuuoq3XjjjRo1apSBlAAAAABw/mw2m44dO6asrCz17NlTgwYNshzPzMy0NE1J0rfffmtpnJKkzz77rMmzAgCAliMnJ0dVVVUKDg621P/xj39o5cqVKigosE/JjomJUXR0tGVdUVGRpWlKOrudno+Pj/21n5+frrzySsu2eT+eSiVJd91118U6LQAAgFaJxik4PFdXV/tUqZkzZ6q+vl7ffvutfWu/hIQEnTp1StXV1frmm28sFzR9fHw0aNAgeyNVv379znmnBYCfJiAgoFHtk08+kSRt2rRJmzZtkp+fn55//nkNGTKkueMBaEOCg4M1bNgwhYSEmI4CAAAc0K5du/Tss89avrCcMmVKo8apyy+/XBUVFQoKClJISIgCAwPPua0NAABwbGVlZSovL1dFRYXKy8sVGBjYaML+jBkzlJOTo+LiYknSwIEDtWzZMssam82m7OxsS62oqKjR7zd8+HD5+fnJz8/PPiXK09PTsqZz587685//fDFODwAAoE1zamhoaDAdAmhq6enpSkpKUlJSkhISEnT06NF/uzY8PFzh4eHq37+/+vfvf847NAD8dMePH9fatWsVGxurU6dOSZI2bNggX19fw8kAAAAAtEU2m03p6enKyMhQRkaGsrKy9D//8z+WNd98841mzpxpqU2aNEnPPfdcc0YFAABNrKSkRAUFBSosLFReXp68vLw0YcIEy5q33npLb7zxhqX26quvauzYsZbaddddp/z8fPvrgIAAxcbGWtbs2bNHa9eula+vr/0xcOBA9erV6yKfGQAAAH4qGqfQJtlsNiUmJioxMVGHDx/W4cOH7Q0dP+bq6qq+fftqwIAB9maqwMBAOTk5NXNqwPFt3bpVqampuu+++yz13Nxcvffee5o4caKGDRtmKB0AAACAtuDpp5/Whg0b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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import nest_asyncio\n", + "\n", + "nest_asyncio.apply() # Required for Jupyter Notebook to run async functions\n", + "\n", + "display(\n", + " Image(\n", + " app.get_graph().draw_mermaid_png(\n", + " curve_style=CurveStyle.LINEAR,\n", + " node_colors=NodeStyles(first=\"#ffdfba\", last=\"#baffc9\", default=\"#fad7de\"),\n", + " wrap_label_n_words=9,\n", + " output_file_path=None,\n", + " draw_method=MermaidDrawMethod.PYPPETEER,\n", + " background_color=\"white\",\n", + " padding=10,\n", + " )\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d821b2f6", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-18T12:18:30.629629Z", + "start_time": "2024-04-18T12:18:30.620092Z" + } + }, + "source": [ + "**Using Graphviz**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4234400-75cd-4b13-aeff-828f7fb68ab1", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-19T11:25:42.057704Z", + "start_time": "2024-04-19T11:25:42.019017Z" + } + }, + "outputs": [], + "source": [ + "%%capture --no-stderr\n", + "%pip install pygraphviz" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ee026342-f560-4ce0-ab43-1718bd19a366", + "metadata": { + "ExecuteTime": { + "end_time": "2024-04-19T11:25:42.631675Z", + "start_time": "2024-04-19T11:25:42.452377Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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P87s2bNZt24dDz/8MP/85z8xGAxahyWEEGesrKyMPXv2OBWn0tLSUBSlSXHq/PPPJzQ0VOuQRQdw8OBBbDYb/fr10zoUIYToSFq3EFVYWMiQIUOYOHEiq1ataq3ZCKGJJUuWoNPpmDdvntahCCGEaCNJSUksWrSItWvXMmLECObNm8f1118vB2mFEC5FURRefPFFEhMTGTFiBKtWrSIqKkrrsIQQ4pyVlpayd+9ep+LU/v37AZoUpy644AK5zbJo4u6772bFihVccsklrF69msDAQK1DEkKIjqB1C1EA33zzDVOnTuXVV1/lr3/9a2vOSgghhBCixdlsNr766iueeOIJkpOTiYuLIzExkWnTpmkdmhBCtKrU1FSuu+46fv/9d15++WWuu+46rUMSQogWV1JSwr59+9iyZQtJSUmkpKSQm5sLNC1OxcfHExwcrHHEQks2m401a9bwzTff8Morr2gdjhBCdBStX4gCeOihh3jhhRf46aefiI2Nbe3ZCSGEEEKcs5qaGv7zn//wr3/9i0OHDjFlyhQeffRRRo8erXVoQgjRZsxmM4mJiSxbtowbbriBFStW4Ofnp3VYQgjRqnJycpyumtq+fTt5eXkYDAb69+/vVJwaMWIEPj4+WocshBBCtGdtU4iyWq1MnjyZw4cPk5ycLJetCiGEEKLdKisr46233uLZZ5+lsLCQa665hkceeUTuAy+EcGv//e9/ue222/D392fVqlWMHTtW65CEEKJNnVic2rZtG/n5+RiNRvr16+dUnBo5ciTe3t5ahyw0lJubS5cuXeQW3kIIoWqbQhRAXl4esbGxxMfH89FHH7XFLIUQQgghTlteXh4vv/wyS5cuxWq1csstt5CYmEh4eLjWoQkhRLuQl5fHLbfcwvr163n44Yd59NFH0ev1WoclhBCaObE49fPPP1NYWNhscWr06NF4enpqHbJoIwkJCWRnZ3PnnXdy7733ah2OEEJore0KUQA//PADF198MUuXLuXOO+9sq9kKIYQQ7daRI0dQFIXu3btrHYrbyszMZOnSpaxcuZKAgAD+/ve/M3/+fIKCgrQOTQgh2h1FUXjxxRe5//77iYuL47333iMiIkLrsIQQot04sTi1ZcsWiouLMZlM9O3b16k4dd555+Hh4aF1yKIV/Prrr6xYsYK8vDw++OADrcMRQgittW0hCuCJJ57g6aef5ocffpDbOQghhHB7c+bM4eDBg/zvf//TOhS3s2vXLp5//nk++OADevbsydy5c7n99tvlNipCCHEaUlJSmDlzJsePH+eVV17h2muv1TqkDmPr1q1s3bqV+fPnax2KEKINWK1W0tPTnYpTO3fupKqqqqE4FR8fT1xcHCNHjmTgwIFytakQQghX0/aFKJvNxowZM/jll1/Ytm0bPXv2bMvZCyGEEO3KFVdcgYeHB6tXr9Y6FLeRlJTEokWLWLt2LcOGDWPBggXMnDkTo9GodWhCCNGhVFdX88ADD/Diiy9y44038vLLL+Pr66t1WO3e/fffz3fffceuXbu0DkUIoZHmilM7duyguroaPz8/hg0b5nTllBSnXJfFYpH9ECGEO2j7QhRARUUFcXFxWCwWfvrpJwIDA9s6BCHOWUpKCgUFBUyePFnrUIQQHdjq1avx9PTk8ssv1zoUl2az2fjqq6946qmn2LZtG3FxcSQmJjJ16lR0Op3W4QkhRIf2+eefc9tttxEaGsoHH3xAbGys1iG1axdeeCHR0dG8/vrrWocihGhHLBYLGRkZTsWplJQUzGYz/v7+DB061Kk4FRMTI/3YDs5mszFkyBBGjRrF3LlzGTlypNYhCSFEa9GmEAVw+PBhxowZw4gRI1izZg0Gg0GLMIQ4a3feeSepqan8+OOPWocihBDiJGpra1m9ejXPPPMMBw4cYMqUKTz88MOcf/75WocmhBAuJTs7m5tuuoktW7bw0EMP8eijj8rZ+ydRVFREVVUVkZGRWocihGjn6urqOHDggFNhavv27dTW1hIYGMjgwYOlONWBWSwW3n77bV566SXGjBnDq6++qnVIQgjRWrQrRAH89NNPXHjhhcybN49FixZpFYYQZ2XBggX8/PPP/Pzzz1qHIoQQ4gQVFRW88cYbLF68mOPHj3Pttdfy4IMPMnDgQK1DE0IIl6UoCi+++CL3338/48aN49133yU8PFzrsIQQwqU0Lk5t2bKFpKQkMjIysFqtBAUFMWjQoIbCVHx8PNHR0VqHLE5DdXW1PKtWCOHKtC1EAbz33nvcfPPNvPnmm8yaNUvLUIQ4I3v27KGsrIz4+HitQxFCCFEvPz+f5cuXs2zZMmpra5k9ezb33XefnHUuhBBtKDk5mZkzZ1JSUsLrr7/O9OnTtQ5JCCFcWkVFBbt27XK6cio9PR2bzUZYWJjTVVOjR4+mW7duWocshBDCvWhfiAJ46KGHeO6551izZg2XXHKJ1uEIIYQQooP57bffeOGFF3j99dfx9fXljjvuYO7cuXTq1Enr0IQQwi2Vl5dz7733snLlSm688UZeeeUVfHx8tA5LCCHcRnl5Obt373YqTqWlpaEoSpPi1JgxY+jSpYvWIYuTqKysZNq0adx4441cd911eHl5aR2SEEKcqfZRiFIUhVtvvZX//Oc/rF+/ngsuuEDrkIQQQgjRAezdu5d///vffPjhh0RGRjJ//nxuu+02OdgphBDtxKeffsrtt99O165d+eCDDxg+fLjWIQkhhNsqKytjz549p1WcGjt2LJ07d9Y6ZAHk5uZy77338sknn/D444/z4IMPah2SEEKcqfZRiAKwWq1cffXVbNq0ic2bN8szHIQQQghxUklJSSxatIivvvqKwYMHc++99zJz5kyMRqPWoQkhhDjB77//zo033sgvv/zC448/zn333Yder9c6LCGEEEBJSQn79u1zKk7t378foElxKi4uTu44oKFjx47h6elJcHCw1qEIIcSZaj+FKFAfzHfJJZeQlZXFli1b6Nmzp9YhCSGEEKKdUBSFtWvXsnDhQn766Sfi4uJITExk6tSp6HQ6rcMTQghxClarlcWLF/PPf/6TCRMm8M477xAWFqZ1WEIIIZqRm5tLcnJyQ2EqOTmZY8eOAY7iVHx8PHFxccTGxuLr66txxEIIIdq59lWIAigtLWX8+PFUVVWRlJQk96gVQgjhsr7//ntSUlK47777tA6lXaurq+PDDz/k2WefZf/+/Vx22WU88MADxMXFaR2aEEKIM/TLL79w/fXXU1payptvvsnUqVObHc9qtfLxxx/zl7/8pY0jbD0lJSX4+/tjMBi0DkUIIc5YTk6O01VTv/zyC8ePH8dgMNC/f3+nK6dGjhyJt7e31iG7naNHj7J8+XLuvPNOIiIitA5HCCEaa3+FKFA3nHFxcYSFhfHdd9/h7++vdUhCCCFEi3vkkUdYs2YNu3fv1jqUdqmyspLXX3+d559/niNHjnDllVfy2GOPMWjQIK1DE0IIcQ7Kysq46667eP/997ntttt44YUXmjzb78knn+Txxx/nxx9/ZNy4cRpF2rJuu+02fv/9d9atW6d1KEII0SJOLE5t3bqVgoICjEYj/fr1cypMjRo1Ci8vL61Ddmk//PAD119/PQUFBXz77bdceOGFWockhBB27bMQBZCRkcH48ePp27cv33zzDX5+flqHJIQQQrSoOXPmcOjQITZs2KB1KK2uoqLitHN5WVkZb731FgsXLqS4uJhrrrmGRx99lD59+rRylEIIIdrSxx9/zJw5cwgPD+eDDz5g6NChAPz888/Ex8ejKArh4eGkpqYSGBiocbTnLiYmhhkzZvD0009rHYoQQrSaE4tTP/30E0VFRc0Wp0aPHo2np6fWIbuU2tpaPvnkE6644gop/Akh2pP2W4gCtRg1ceJEoqOj+fbbb6UYJdoVm83Gn//8Z+6//36XOUtTCNG2SktLqaqqcvlnZCxdupTvv/+eL7744pTjHTt2jFdeeYUlS5agKAqzZs3igQcecPnfRwgh3Nnhw4e54YYbSE5OZuHChcyePZuhQ4dy5MgRLBYLJpOJa665hvfff1/rUM+JoigkJiYyffp04uPjtQ5HCCHalL04tWXLFpKSkti1axeVlZWYTCb69u3rVJw677zz8PDw0DpkIYQQLat9F6IA0tPTmThxIn369JEro0S7ExgYyHPPPcdf//pXrUMRQoh2afHixdx3333odDr27dtHTExMk3EOHjzIsmXLWLlyJUFBQcyZM4d//OMfLnH2uxBCiD9msVh44oknePrpp+nWrRvHjx+nrq7OaZwPP/zQpZ4XJYQQ7sxqtZKenu505dTOnTupqqrC19eX4cOHOxWnBg4ciF6v1zpsl3Ho0CGqq6sZPHiw1qEIIdxH+y9EgaMY1bdvX77++mspRol2IyYmhr///e/cfffdWocihBDtzrPPPktiYiIAJpOJv/zlL7z77rsNn+/YsYMlS5bwwQcf0KtXL+6++27mzJkjt5AQQgg39cQTT/DYY481Ga7T6fD19SU1NZUePXpoEJkQQojWZrFYyMjIcCpOpaSkYDab8ff3Z+jQoVKcaiH3338/ixcvZtKkSaxevZqQkBCtQxJCuL6OUYgC2LNnD5MmTSImJoavv/4aX19frUMSQgghxEksWrSIBx54wGmYwWDg0KFDZGdns2jRItauXUtsbCzz58/n+uuvx2AwaBStEEIIrWVlZTFkyBCqqqpobhfVZDJx3nnnsWnTJjnwKIQQbqK54lRycjI1NTUEBAQwZMgQp+JUTEwMOp1O67DbPUVRWLduHZ999hmv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5BNcvHgR0dHReOqppzB9+nS4ubkJHe+OKC0thbe3t9AxiIiI6BYYDAacOXMGiYmJcHFxwfPPPy90JCKyAnq9Hrm5ufD29oajo2Or44YPH47y8nIMGDAAH3/8sRkTEhEREVEHUCEWOgFRR+Tp6Ym//e1vuHDhAk6ePIl7770XL730Evz8/DB16lTs378fHbnHe+LECchkMmzatEnoKERERHSLxo4di1WrVqGoqEjoKERkBb744gs4Ojqia9euSElJaXPsgQMHcPr0aTahiIiIiOiGeEUU0R2iUCiwdetWrF+/vvGmun/5y1/wl7/8pcMtfaPX67Fo0SIsX74cJ06cQExMjNCRiIiI6CZyc3MRFBQEkUgkdBQislAGgwFr1qxBZmYmgoKCsHDhwlbHZmRk4OjRo+jWrRt69erF++MSERER0R/FpfmI2kNaWho2b96MDRs2QKlUYvz48Zg5cyYefPBB2NjYCB3vlqWmpvL+V0RERAJSKBRISEjADz/8gEcffRTjxo0TOhIRWSiNRoPs7GyEhoZCIpG0Oq5nz55wdnbGgw8+iNdff92MCYmIiIiok+LSfETtISoqCkuXLkV+fj6++OILVFRUYPz48ejatSv+8Y9/ICcnR+iIt4RNKKI7LzExEatWrRI6BhF1EEVFRZg9ezYKCws71GQWIjKv9957D46OjoiIiMDly5fbHHv+/HkcPXqUTSgiIiIiMhteEUVkJunp6di4cSM2btyIa9euYdiwYXj66acxYcIESKVSoeMRkZksXrwYiYmJSE1NFToKEXUQSqWSS2IRdUJKpRLr1q2DXC7HgAED8OSTT7Y69vTp08jIyEB4eDh69uwJOzs78wUlIiIiImobr4giMpeIiAgsXboUV69exZYtWwAAjz76KLp27YpXX331pjMXiYiIyHqcP38eixYtQnR0NPLz89scyyYUkfWpra3FxYsX2xxjY2ODDz74ABcuXEBdXV2bY/v27Ytp06YhJiaGTSgiIiIisji8IopIQHl5efjyyy+xdu1a5OTkICYmBjNnzsTMmTPh6ekpdLw2ffvtt7j33nsRHBwsdBSiDqW2thYajQaurq5CRyEiAf3vf//De++9hzFjxuDll19mPSXqRObNm4f169cDAFQqFRwcHARORERERETUrirYiCKyAHq9HklJSdi0aRN27twJvV6P+Ph4zJw5E2PHjm3zZsNC0Ol06NevH/Ly8rB582aMHj1a6EhEREQdil6vh1jMxQmIrEVhYSE+++wzyOVyTJgwAfHx8a2OPXz4MK5du4Zu3bohMjKSvwuIiIiIyNpxaT4iSyAWizFixAhs2rQJBQUFWLduHSoqKjB+/Hh07doVCxYswLlz54SO2cjGxgaHDh3C6NGjIZfLhY5DRERkMb788kuMHz8effr0aXMcTzwTdRxVVVVIT09vc4xSqcT69etx9epVaDSaNsfed999mDhxInr27MnfBURERETUKfCKKCILlp6ejq+++gqbNm1CdnZ249J9M2bMQJcuXYSOR0RERNeZP38+cnNzMWbMGDz11FOwsbEROhIR/QljxozBjz/+CF9fXxQVFQkdh4iIiIioI+LSfEQdgV6vxy+//ILNmzdjy5Yt0Gg0GDlyJGbNmoWJEyda3NJ9RERE1qq2tpb3cyHq4DIyMrBlyxbI5XK88MILGDBgQKtjf/zxR+j1eoSHh6Nbt25mTElEREREZDW4NB9RRyAWixEbG4t169YhPz8f69evh1qtxrRp0xASEoIFCxbgzJkzQsckIiKySvX19Xj++ecRHh6OefPmCR2HiNpQUlKCzMzMNsfk5eVh69atqKysvOkyeqNHj8bYsWPZhCIiIiIi+hN4RRRRB5abm4stW7Zgw4YNuHz5MiIjIzFr1izMnj0b3t7eQsfDb7/9hl69egkdg4iI6E+bOHEiIiMjMX78ePTv31/oOER0AxEREcjIyEC/fv1w/PhxoeMQEREREZERl+YjsgbNl+776quvUFdXh1GjRmHKlCmYNGkSnJyczJ7p2LFjGDRoEObNm4fly5cLkoGIiOhWVFdXQywWs1YRWaATJ07gm2++gVwux7///W/IZLJWx3733XdwdnZGREQEgoKCzJiSiIiIiIjawKX5iKxB86X7CgoKsGHDBmg0GsyePRsBAQH4y1/+gv3790On05kt04ABA/Dll19ix44dOH36tNl+LpGle+uttzB06FChYxARjFfuPvDAA/Dy8sKWLVuEjkPUqRgMBuTm5iI7O7vNcRcvXsT3338PvV4PtVrd5tjx48dj+PDhbEIREREREVkYXhFFZMXKy8vx9ddfY9OmTfjll1/g6emJSZMmYebMmRgyZAhEIlG7Z1AqlXB2dm73n0PUUSxevBiJiYlITU0VOgpRp1dYWIhXXnkFY8aMwejRo+Hl5SV0JKJOob6+Hh4eHqipqcGUKVOwfft2oSMREREREVH74dJ8RJ1FTk4Otm7dio0bNyI9PR1du3bFtGnTMGfOHN58mciMPv30U5w8eRJr164VOgqRVdPr9Th37hzuueceoaMQdRr79+/HDz/8ALlcji1btrS53OW2bdsQGBiI7t27o0uXLmZMSUREREREZsZGFFFnlJaWhs2bN+Pzzz9HUVERIiMjMWvWLDzxxBPw8/MTOh4REdGf8umnn2Lx4sUoKSnBxYsX0b17d6EjEXVoWq0WOTk5sLOza3PZu2XLluHrr79GeHg4Vq5cCR8fHzOmJCIiIiIiC8VGFFFnptfr8csvv2Dz5s3YunUrVCoVBg4ciFmzZuGxxx6Di4tLu/58rVaL5ORkDB8+vF1/DhERdS7Jyck4evQoxowZg969e5tlKVoia5WdnY2IiAhoNBosXLgQy5cvFzoSERERERF1LGxEEZFRbW0tvvvuO2zZsgWJiYmwtbXF+PHjMX36dIwaNQpSqfSO/8xdu3Zh4sSJmDx5MlatWgV/f/87/jOIiMi6FBcXIzMzE7GxsUJHIerQtm/fjkOHDqG0tBTbtm1rdZxGo8GOHTsQHh6OiIgIuLm5mTElERERERFZgQqx0AmIyDI4ODjg0Ucfxe7du1FcXIw1a9agpKQE8fHx8PX1xaxZs5CQkACNRnPHfuaECRPw448/IisrC+yJExHRzUyZMgUBAQGYPn260FGILFZdXR0uXryI4uLiNscdOXIEZ8+ehaOjI3Q6XavjpFIppk+fjv79+7MJRUREREREfwiviCKiNuXk5GD79u3Ytm0bTp06BR8fH0yaNAlTp05FXFwcxGL2s4mIyDx27NgBe3t7DBs2DE5OTkLHIbI4hw4dwgMPPAC9Xo8PP/wQzz//vNCRiIiIiIiIuDQfEd26nJwc7Nq1Czt27MCRI0fQpUsXjB07FrNmzcKwYcPYlCIioj9Eo9HgyJEjcHR0RP/+/YWOQ2RxPv74Y5w6dQo2Njb4+OOPWx1XUVGBpKQkhIeHo1u3bnB0dDRjSiIiIiIiohtiI4qI/pjs7Gzs3r0bmzZtQmpqKoKCgvDII49gypQpGDJkCG8MT0REt0ShUCAkJARVVVWYN28e1q5dK3QkIrOprq6GXC5HWFgYXF1dWx336KOPorS0FNHR0Vi+fLkZExIREREREf1pbEQR0Z+XlpaGHTt2YNu2bbh06RKCg4MxceLEO9KUMt2nasmSJRg7duwdTE0kDLlcjrKyMgwYMEDoKEQW46uvvkL//v0RFhYmdBQis9m8eTNmzZoFANi9ezfi4+MFTkRERERERNQu2IgiojvL1JTasmULMjMzcdddd2H8+PGYMmUKYmNjb/v98vPz8dxzz+G7777Dtm3bMHXq1HZITWQ+ixcvRmJiIlJTU4WOQtTusrKykJiYiLFjx0Imkwkdh8gs/vWvfyEjIwPBwcF45513Wh139epVnDt3Dt26dYNMJoOtra0ZUxIREREREZlNhUToBERkXaKiohAVFYUlS5bg+PHj2L59O3bs2IFVq1ahe/fumDp1KiZNmoTevXvf0vsFBgZi165dSEpKwuDBg9s5PRER3Sl79+7FuHHj4OLigsDAQDaiqMMrKyuDXC5H375922wa7d+/Hw4ODujVq1eb7xcSEoKQkJA7HZOIiIiIiMji8IooImp3BoMBv/76K7Zt24ZvvvkGeXl56NatGx555BFMnjwZMTExvKcUdRrJycnIzs7Gk08+KXQUonZVXV2NU6dOYciQIZBKpULHIfpT3n77bbz++usAgDNnzqBPnz4CJyIiIiIiIuowuDQfEZmfafm+r776qnHpmokTJyI+Ph5Dhw6FRMKLNYmILJVKpUJSUhIOHjyIFStWQCwWCx2J6A9RKpVYunQp5HI5Bg0ahAULFrQ6Nj09HTk5OejWrRtCQkJgY2NjxqREREREREQdWgXPHBCR2ZmW7ktPT8f58+cxe/Zs7Nu3DyNHjoS/vz9mzZqFhIQEaDSaW37P9957D3v27GnH1EREBACvvvoqJkyYgEOHDqG4uFjoOEQ3VFBQgCNHjrQ5xs7ODgkJCairq4Obm1ubYyMiIjBq1CjIZDI2oYiIiIiIiG4Tr4giIouRlpaGPXv2ICEhAUeOHIGnpyceeughTJkyBaNHj271fgwGgwFTp07Fzp078eijj2LLli1mTk5E1HkUFBRAIpHAx8dH6ChENzR79mxs3LgRAFBZWXnTJhMRERERERG1Ky7NR0SW6cqVK/juu++wY8cO/PLLL3Bzc8PIkSMxbtw4TJo0CU5OTr97zcmTJ6FQKDBs2DABEhMRdWxnz57FDz/8AJVKhbffflvoOEQt5OfnY+XKlZDL5ZgyZQoee+yxVseeOXMGVVVVCA8PR2BgoBlTEhERERER0Q2wEUVEli8nJwc7d+7Ezp07cfToUTg6OuKhhx7CI488grFjx8LFxUXoiEREHV6/fv2Qm5uLSZMmYfXq1ULHoU5Cp9Ph6tWrKC4uxsCBA1sdl5ubiwkTJiA8PByPP/444uPjzZiSiIiIiIiI/gQ2ooioYykoKMC3336LnTt34tChQ5BIJBg2bBgmTJiAhx9+GH5+fkJHJCLqkIqLi+Hj4wORSCR0FOpEhg8fjqSkJLi5uaGyslLoOERERERERHTnsRFFRB1XeXk5Dhw4gISEBOzatQvV1dWIjIzElClTMHXqVERGRrYYf/r0abzzzjt488030bNnT4FSExGZT01NDb799lskJiYiLi4Oc+fOFToSdQIXLlzAxx9/DLlcjoULF7a5ZO7Ro0chEokQHh4OLy8vM6YkIiIiIiIiM6kQC52AiOiP8vT0xJQpU7Bp0yaUlJRg3759GDFiBNatW4eoqCiEhYVhwYIFSElJgV6vh1qtxuXLl9GnTx+kpqYKHZ86qcTERKxatUroGNRJaLVaPPPMM8jPz4e7u7vQcaiDq6+vR3p6Ok6ePNnmOIVCgZMnT6JLly5wcHBoc+zAgQMxYMAANqGIiIiIiIisGK+IIiKro9fr8csvv2DPnj3YtWsX0tPT4e3tjTFjxmDy5MkQi8UYN26c0DGpk1q8eDESExPZDCWzUavVsLe3FzoGWYGwsDBkZWWhd+/eOHv2rNBxiIiIiIiIqGPgFVFEZH3EYjFiY2OxdOlSXLp0CefPn8ff//53ZGVlYcKECZg2bRri4+OxadMmVFVVCR2XiOi2ZWZmYvHixYiOjsbx48fbHMsmFLXlyJEjmDdvHkaMGIGLFy+2OXbjxo1ITU1FSkqKmdIRERERERGRNWAjioisXlRUFF555RWkpKTgypUrWLp0KWprazFnzhz4+Phg9OjRWLNmDa5evQoAyM7OhkqlEjg1WavXXnsNP//8s9AxqIO7cuUKtm/fjsGDB8PNzU3oOGSBampqcO7cOfz2229tjispKUF6ejpkMhnE4rYPDeLi4tC3b1+4uLjcyahERERERERk5bg0HxF1WhUVFdi7dy++++47/Pjjj6iurkafPn2gUChQUVGBF198Ea+//jpEIpHQUYmok9Hr9TdtChC1RqfTwcHBARqNBvHx8di9e7fQkYiIiIiIiKjzqmAjiogIgFarxdGjR7Fnzx7s3LkTcrkcdnZ2ePjhhzFu3DhMmDABrq6uQsekDuann37C1KlTodPp2hwnFovxzDPP4N///reZkpGl2rVrFz777DMcPXoUOTk5sLOzEzoSWRBTjbp8+TJ2794Nd3f3Vsfu27cPAQEBCAsL4/KMREREREREJCTeI4qICAAkEknjfaUyMzNx+fJlLFu2DBUVFZgzZ9C8pkQAACAASURBVA68vLwQGxuLZcuWISMjQ+i41EEMHToUer0eSqWyzU2hUCA+Pl7ouGQB0tPTAQBLliy5aQOTrEdFRQVOnjx50/qSl5eHgoIC9OrVC/X19W2OHTlyJKKiotiEIiIiIiIiIsHxiigiopsoKytDUlISEhISsHv3blRVVSE0NBQPPfQQHn74YQwdOhQSiUTomGSh5s6di88//xwajabVMX5+fsjPz+dSbJ2AUqmEs7Oz0DHIgly9ehV33XUXAOCFF17AqlWrBE5EREREREREdEdxaT4iottRV1eH5ORkJCQkYP369aivr4enpyfGjx+PcePGYdSoUTzJTC0cPHgQw4YNa/X7tv/f3r2HRVnn/x9/zjAzHATPIHhAJDQRPEVWaHkgPGe2bmWrlZWuv2q72i7Nas1yc6vd0nY72zfL3M2OtulGmqJ5tlITxQA1OagoCYhyGBEYZub3x2yoq5SHgRvx9biuueae+/7c97w+6HXR1dv352Oz8cgjj/DCCy/UYyqpb1OmTOGLL74gPDyc1atXGx1H6sGCBQtITk4mLy+PtWvX1jrO5XKRnJxMVFQUHTt2xGq11l9IERERERERkbp3TP+EX0TkPPj6+jJkyBAGDhxI586defnll2nTpg25ubmMHTsWgGuvvZZRo0aRmJhIXFycwYnFaAMGDCAkJISCgoKzXq+qquJ3v/tdPaeS+lZRUcHtt9/OyJEjjY4iFyk/P5+9e/cSHh5OeHh4reNycnKw2+3ExcVRVVWFzWY76ziz2cywYcPqKq6IiIiIiIiI4dQRJSJyEdxuN3a7naCgIAoLC1m+fDnLli0jOTmZo0ePEhkZyfDhwxkxYgSDBg3C39/f6MhigClTpvD666+fdXm+yMhIsrKyDEgl3lJWVkZVVRWtWrUyOorUsfXr1zNgwAAA5syZw9SpUw1OJCIiIiIiItLgaWk+EZG64HQ62bFjB6tWrSIpKYlvvvkGX19frr/+ehITE7n55puJjo42OqbUk61bt3LNNdeccd5qtfL0008zY8YMA1LJxcrNzWXChAls3LiRJ554glmzZhkdSS7QnDlz+O677zCZTCxatKjWcXa7na1btxIVFUX79u0xmUz1mFJERERERETkkqRClIhIXSovLycuLo4hQ4YQFRXF1q1bSUpKori4mMjISBITE2v2lvL19TU6rtShyMhIcnJyzjj/448/0rlzZwMSycWqrKzk/vvvZ/DgwQwePJjg4GCjI8kp3G43ubm5ZGZm0qNHD1q3bl3r2D/84Q8UFBQQGxvLzJkz6zGliIiIiIiISKOnQpSISF0qKSnhpZdeYsGCBUyaNImnn34ah8PBxo0b+eqrr1i2bBnp6ekEBgZy4403MmLECIYPH06HDh2Mji5eNnPmTP7617/WLM9nMpno2bMn27dvNziZnI3b7Wb79u3ExMSoSHyJWrhwIXfddRcAixYt4tZbbzU4kYiIiIiIiMhlSYUoEZH64HK5qKioICAg4Ixr+fn5rFixgi+//JIVK1ZQWlpa0y2VmJjI8OHDCQwMNCC1eNPu3btPW47RYrEwe/ZsHnnkEQNTydksXryYBx54gPz8fFauXEliYqLRkeQUjz/+OBkZGYSHh/PGG2/UOi4/P5/MzEw6d+5MSEhIPSYUERERERERkVOoECUi0lAUFhYSFBTEhg0bWL58OStWrCA9PR1/f38GDBjA0KFDGTZsGF27djU6qlyg7t27k56ejtvtxmQykZubS7t27YyOJf8jPT2dpKQkhg0bRs+ePbUPUD1wOBzs27ePrKws+vfvf9ai/c9uu+02bDYb/fr148EHH6zHlCIiIiIiIiJyAVSIEhFpCH766SfCw8OJj4/n8ccfZ+TIkYDnX/SvX7+epKQkli5dytGjRwkNDWXw4MGMGjWKxMREWrRoYXB6OVezZ89m+vTpuFwubrjhBtauXWt0pMtOQUEBKSkpDBs2zOgocornnnuOGTNmALBlyxb69OljcCIRERERERER8RIVokREGoKqqipWrFjBhx9+yMiRI7nzzjvPGON0OtmxYwerVq1i1apVrFu3DpfLRa9evWqW8Rs4cCAWi8WAGci5yM3NpWPHjrjdbubNm8ekSZOMjnRZeeCBB3j77bcJCAigoKAAf39/oyM1asePH2fatGlkZWXRr18/nn766VrHHjhwgIKCAqKiomjevHk9phQRERERERGROqZClIjIpaqoqIhVq1axYsUKVqxYQV5eHq1bt2bw4MEMHTqUxMRELfvWAPXr14+tW7eSn5+vbrZ69vXXX1NeXk5CQgJNmjQxOs4lq6KigszMTLKyshg9enSt41wuF4MHD6Zjx44MHTqUsWPH1mNKEREREREREWkgVIgSEbnUzJw5k4EDB9K/f398fHxqzu/cubOmKLVx40YqKyuJjo4+rVuqadOmBiYXgLfeeovly5ezZMkSo6M0CAUFBYSEhFzUMxwOB5s2baKqqoohQ4Z4KZnUZvLkycybNw/w7G3XunVrgxOJiIiIiIiISAOmQpSIyKWkqKiIhIQEdu7cyf3338/cuXPPOu7EiRNs2rSpZhm/7du3YzKZTlvG74YbbsDX17eeZ9D4lZeXY7fbsdvtNefsdjsOhwOA0tJSUlJSGDhwYM31UzujfH19CQoKavRFw8rKSmbMmMFXX31FWlraBT/H5XLRoUMH8vLyGDNmDP/+97+9mPLycejQIWbOnElmZibjxo1j8uTJtY7du3cvFRUVREVFaXlDEREREREREfk1KkSJiFyK9u7di9vtpkuXLuc0/siRI6xZs6amMJWdnU1AQAB9+/atKUz17t0bs9nslXwul8trzzJSUVEReXl5HD58mPz8fAoLC8nPz/ccFxzm2NEjlJWVUlZWRklJGaX2cpxOl9e+v1nTJgQFNiEoMJDAoEBatGxNcEgYwcHBtGnThtDQ0Jrjtm3bEhYWhslk8tr315X09HTGjh1LRkYGbrebAwcO0KFDhwt+3tKlS4mOjiYyMtKLKRuH0tJSMjMzyc/PZ/jw4bWOKygoYPz48URFRTFmzBgGDx5cjylFREREREREpBFTIUpEpLHasmULXbt2PWtnTXZ2Nhs3bmTTpk18+eWX5OXlERwczMCBA0lMTGTIkCFERERc0PdmZWVx1113MX/+fLp27XqRs6hbTqeT7Oxsdu3aRU5OjueVncW+nL3s259LaVl5zVirxUxIcwshTU2ENq0mJMhJiyYQ5A+BftA8AIL8PMdB/p7jn/nbwM969gzVTiirOPn5RBXYKzznisuh7ITns70SjtqhsMxMod3C4RIT+ceqKa901tzra7PSMbwtEZ2uIKJTFBEREXTq1IkuXboQHR1tePeK2+1m3rx5PPzwwzidTqqrq7FYLMydO5dJkyadMT4rK4vly5dz3XXXERcXZ0DiS9/QoUNJTk4mKCiIkpKSS6JQKSIiIiIiIiKNigpRIiKNkdvtpn379hQVFXHffffx5ptv/uL47Ozsmm6p5cuXU1ZWRmRkZE231I033kjLli3P6bvfffddJk2ahM1m49lnn2XKlCmn7WVllP3797Nt2zZ27dpFWtoP7M7Yya7dmVRWeZbMC21pI6I1RLSqolMwRARDp2Bo3xJCmkGrQIMnUIvjlXC4GH4qhpxCyCmAfUdgX5GVnEITB484qHa6MZtNdOrYjpjYXnSLiaVbt2707NmTmJiYevnzyc/PZ8KECaxcuRKX62TXmI+PD6NGjWLx4sWnjd++fTtXXXUVTZs25e9//zsTJ06s84yXirS0NF544QUyMzOZPn06o0aNqnVseno6VquViIgIbDZbPaYUEREREREREQFUiBIRabyOHTtGUlISTqeTe++995zvq66uJjU1taYwtW7dOpxOJ717964pTF1//fX4+flRWVmJ1Wo9bRm+8ePH8+mnn1JdXY3ZbKZXr168//77dOvWrS6meValpaXs3LmTbdu2sWnjetavW0t+4VEAwlpaiWnnpFtbFzHtoVs76NXR08nUGFU74UARpB+EjEOQfshExk82dh2sprzCSZMAP3r17EFcH0/XUVxcHN26dfNq58znn3/OfffdR3l5ec1eWacKCAiguLgYq/Vk25jL5WLDhg307dv3tPON2ZEjR8jMzKS8vJyEhIRax6WmpjJ9+nSioqK46667uPrqq+sxpYiIiIiIiIjIeVEhSkTkcpednU3z5s1r7Xiy2+189913NYWplJQU/Pz86NevH6GhoezYsYOPP/6YmJgYAEJCQigsLKy532Kx4Ha7efTRR5k1a1addGWUlJSwfv16vv76a9Z8vYIf0vfgdrvpFGrjmk4O+kS6ueYKuCoCmvh6/esvSdVOSD8EW7NgcxZs3Wcj/YCne6p92xASEoeSkHAjCQkJF7x/U1lZGVOmTOGdd97BbDaf1gn1v9atW0f//v0vdDqNQteuXdmzZw+xsbH88MMPRscREREREREREfEGFaJERC53Y8aMISkpiX79+pGcnPyrhaLc3NyaotSSJUsoL/fsoxQbG8uYMWOYNWvW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4MTxEh64sZo/DoXQ5kYnk4tR4YB/roc5X1k5cMTNw398hBkzZtCsWTOjo4mIiIiIiIiISP3SHlEiImK8srIyXn/9dV59+SWOHSvm7hvcTB3h4sowo5PJ+Th2HOaugleTLRSXw90TJvD443/iiiuuMDqaiIiIiIiIiIgYQ4UoERFpOKqqqvj444/52/Oz2LUni7hIHyYPcjKuLwT6GZ1Ozsblhm9+hPc3mflgkwkfqy/33DuJxx57TEvwiYiIiIiIiIiIClEiItLwuFwuli9fzvx33yEpKQlfK9x+jYs7r3dxw5Xgox0ODZdxCD79DhZstLK/wEH8tVdz78TJ3HHHHQQFBRkdT0REREREREREGgYVokREpGE7cuQIH3zwAQvmz2PHznRaNbUyqlc1t1ztZkh38LcZnfDy4HLD5kxY8j0s2W7jx0NVhLVpzZ1338u9995LdHS00RFFRERERERERKThUSFKREQuHZmZmSxevJglny/iuy3f42czk9ANEro5SYiBHh3AZDI6ZeORWwSrM2B1uonkNAuHjzmIigznljG3c8sttxAfH4/ZrPY0ERERERERERGplQpRIiJyaTp8+DBffPEFyckrWLvma4qOltC6mZVB0U4GdnUR3xliO4DVx+ikl47MfNiSBet2wZrdVvbmOfDztRJ/3bUkDhnOzTffTGxsrNExRURERERERETk0qFClIiIXPpcLhepqamsWbOG1V+vZP36dZTZT+Dv60OvCDPXdHLQJxKujoSoNtpjCuDQMUjJga3ZsDXHhy1ZJo6WVWO1+HB1XG8SEoeSkJBAfHw8/v7+RscVEREREREREZFLkwpRIiLS+LhcLnbv3s2WLVvYunUrW77bSOrOdBzVTnytZqLbW4kOqyK2vZtu7SCmPXRsDTaL0cm9y+32FJx250H6Qcg4BGmHrGQcclNsr8ZkMtH5inD6XNuPa665lj59+tC7d2/8/PyMji4iIiIiIiIiIo2DClEiInJ5qKys5IcffiA9PZ2MjAzS03aSkf4D+w7k4Xa7MZtNtG1pJSLYTadWDiKCISIY2reE0GYQ0hSCmzasbqqjdsgvgcIyOHgU9hX+91VkYd8RHw4UOqh0uABo3bIZsbGxRMf0oHv37kRHR9OrVy+aN29u8CxERERERERERKQRUyFKREQub3a7nT179pCTk8O+ffs8r5wscrL3sm//QcpPVNaMNZtNBDezEtzURGgzFy38HTQLgEBfCPSDIH9oHgBBfmDx8exPFXhKc5G/DfysnmOnC0pPnLxW6YDyKs/xseNgr/C8yio840rKwV7lw+ESC4dL3BSWVFP13yITgNXiQ/t2oUREdCIisjMRERF06tSJiIgIunbtSnBwcF3+GEVERERERERERM5GhSgREZFfcuzYMQ4fPkxhYSGHDx8mPz+/5ri4uJiS4iLsZaWUlZVSVlZGSUkZpfZynE7Xrz+8Fs2aNiEosAmBTZoQ1DSIZs1a0KxFKwIDgwgJCSEsLIzg4GDatGlDaGgowcHBhISEYDY3oHYtERERERERERERFaJERETqTkVFBSdOnGx7stvtOByOms8tWrSoObZYL2SkjgAAAF9JREFULAQFBdVrPhERERERERERkTqmQpSIiIiIiIiIiIiIiIjUiWNaw0dERERERERERERERETqhApRIiIiIiIiIiIiIiIiUicswDajQ4iIiIiIiIiIiIiIiEijU/r/ARN5/xGPrsbJAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "try:\n", + " display(Image(app.get_graph().draw_png()))\n", + "except ImportError:\n", + " print(\n", + " \"You likely need to install dependencies for pygraphviz, see more here https://github.com/pygraphviz/pygraphviz/blob/main/INSTALL.txt\"\n", + " )" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/how-tos/http/custom_lifespan.md b/docs/docs/how-tos/http/custom_lifespan.md index a7b2d7d48..a804f4748 100644 --- a/docs/docs/how-tos/http/custom_lifespan.md +++ b/docs/docs/how-tos/http/custom_lifespan.md @@ -1,8 +1,8 @@ # How to add custom lifespan events -When deploying agents on the LangGraph platform, you often need to initialize resources like database connections when your server starts up, and ensure they're properly closed when it shuts down. Lifespan events let you hook into your server's startup and shutdown sequence to handle these critical setup and teardown tasks. +When deploying agents to LangGraph Platform, you often need to initialize resources like database connections when your server starts up, and ensure they're properly closed when it shuts down. Lifespan events let you hook into your server's startup and shutdown sequence to handle these critical setup and teardown tasks. -This works the same way as [adding custom routes](./custom_routes.md) - you just need to provide your own [`Starlette`](https://www.starlette.io/applications/) app (including [`FastAPI`](https://fastapi.tiangolo.com/), [`FastHTML`](https://fastht.ml/) and other compatible apps). +This works the same way as [adding custom routes](./custom_routes.md). You just need to provide your own [`Starlette`](https://www.starlette.io/applications/) app (including [`FastAPI`](https://fastapi.tiangolo.com/), [`FastHTML`](https://fastht.ml/) and other compatible apps). Below is an example using FastAPI. @@ -47,7 +47,7 @@ app = FastAPI(lifespan=lifespan) ## Configure `langgraph.json` -Add the following to your `langgraph.json` file. Make sure the path points to the `webapp.py` file you created above. +Add the following to your `langgraph.json` configuration file. Make sure the path points to the `webapp.py` file you created above. ```json { @@ -71,11 +71,11 @@ Test the server out locally: langgraph dev --no-browser ``` -You should see your startup message printed when the server starts, and your cleanup message when you stop it with Ctrl+C. +You should see your startup message printed when the server starts, and your cleanup message when you stop it with `Ctrl+C`. ## Deploying -You can deploy your app as-is to the managed langgraph cloud or to your self-hosted platform. +You can deploy your app as-is to LangGraph Cloud or to your self-hosted platform. ## Next steps diff --git a/docs/docs/how-tos/http/custom_middleware.md b/docs/docs/how-tos/http/custom_middleware.md index 2626e289a..ec18491d8 100644 --- a/docs/docs/how-tos/http/custom_middleware.md +++ b/docs/docs/how-tos/http/custom_middleware.md @@ -1,6 +1,6 @@ # How to add custom middleware -When deploying agents on the LangGraph platform, you can add custom middleware to your server to handle cross-cutting concerns like logging request metrics, injecting or checking headers, and enforcing security policies without modifying core server logic. This works the same way as [adding custom routes](./custom_routes.md) - you just need to provide your own [`Starlette`](https://www.starlette.io/applications/) app (including [`FastAPI`](https://fastapi.tiangolo.com/), [`FastHTML`](https://fastht.ml/) and other compatible apps). +When deploying agents to LangGraph Platform, you can add custom middleware to your server to handle concerns like logging request metrics, injecting or checking headers, and enforcing security policies without modifying core server logic. This works the same way as [adding custom routes](./custom_routes.md). You just need to provide your own [`Starlette`](https://www.starlette.io/applications/) app (including [`FastAPI`](https://fastapi.tiangolo.com/), [`FastHTML`](https://fastht.ml/) and other compatible apps). Adding middleware lets you intercept and modify requests and responses globally across your deployment, whether they're hitting your custom endpoints or the built-in LangGraph Platform APIs. @@ -40,7 +40,7 @@ app.add_middleware(CustomHeaderMiddleware) ## Configure `langgraph.json` -Add the following to your `langgraph.json` file. Make sure the path points to the `webapp.py` file you created above. +Add the following to your `langgraph.json` configuration file. Make sure the path points to the `webapp.py` file you created above. ```json { @@ -68,7 +68,7 @@ Now any request to your server will include the custom header `X-Custom-Header` ## Deploying -You can deploy this app as-is to the managed langgraph cloud or to your self-hosted platform. +You can deploy this app as-is to LangGraph Cloud or to your self-hosted platform. ## Next steps diff --git a/docs/docs/how-tos/http/custom_routes.md b/docs/docs/how-tos/http/custom_routes.md index e5d5ed5d6..19a3abb63 100644 --- a/docs/docs/how-tos/http/custom_routes.md +++ b/docs/docs/how-tos/http/custom_routes.md @@ -1,10 +1,10 @@ # How to add custom routes -When deploying agents on the LangGraph platform, your server automatically exposes routes for creating runs and threads, interacting with the long-term memory store, managing configurable assistants, and other core functionality ([see all default API endpoints](../../cloud/reference/api/api_ref.md)). +When deploying agents to LangGraph platform, your server automatically exposes routes for creating runs and threads, interacting with the long-term memory store, managing configurable assistants, and other core functionality ([see all default API endpoints](../../cloud/reference/api/api_ref.md)). -You can add custom routes by providing your own [`Starlette`](https://www.starlette.io/applications/) app (including [`FastAPI`](https://fastapi.tiangolo.com/), [`FastHTML`](https://fastht.ml/) and other compatible apps). You make LangGraph Platform aware of this by providing a path to the app in your `langgraph.json` configuration file. (`"http": {"app": "path/to/app.py:app"}`). +You can add custom routes by providing your own [`Starlette`](https://www.starlette.io/applications/) app (including [`FastAPI`](https://fastapi.tiangolo.com/), [`FastHTML`](https://fastht.ml/) and other compatible apps). You make LangGraph Platform aware of this by providing a path to the app in your `langgraph.json` configuration file. -Defining a custom app object lets you add any routes you'd like, so you can do anything from adding a `/login` endpoint to writing an entire full-stack web-app, all deployed in a single LangGraph deployment. +Defining a custom app object lets you add any routes you'd like, so you can do anything from adding a `/login` endpoint to writing an entire full-stack web-app, all deployed in a single LangGraph Server. Below is an example using FastAPI. @@ -34,7 +34,7 @@ def read_root(): ## Configure `langgraph.json` -Add the following to your `langgraph.json` file. Make sure the path points to the `app.py` file you created above. +Add the following to your `langgraph.json` configuration file. Make sure the path points to the `app.py` file you created above. ```json { @@ -58,7 +58,7 @@ Test the server out locally: langgraph dev --no-browser ``` -If you navigate to `localhost:2024/hello` in your browser (2024 is the default development port), you should see the `hello` endpoint returning `{"Hello": "World"}`. +If you navigate to `localhost:2024/hello` in your browser (`2024` is the default development port), you should see the `/hello` endpoint returning `{"Hello": "World"}`. !!! note "Shadowing default endpoints" @@ -67,7 +67,7 @@ If you navigate to `localhost:2024/hello` in your browser (2024 is the default d ## Deploying -You can deploy this app as-is to the managed langgraph cloud or to your self-hosted platform. +You can deploy this app as-is to LangGraph Cloud or to your self-hosted platform. ## Next steps diff --git a/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md b/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md new file mode 100644 index 000000000..51508ec46 --- /dev/null +++ b/docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md @@ -0,0 +1,848 @@ +--- +search: + boost: 2 +tags: + - human-in-the-loop + - hil + - interrupt +hide: + - tags +--- + +# Add human-in-the-loop + +## `interrupt` + +The [`interrupt` function][langgraph.types.interrupt] in LangGraph enables human-in-the-loop workflows by pausing the graph at a specific node, presenting information to a human, and resuming the graph with their input. It's useful for tasks like approvals, edits, or gathering additional context. + +The graph is resumed using a [`Command`](../reference/types.md#langgraph.types.Command) object that provides the human's response. + +```python +# highlight-next-line +from langgraph.types import interrupt, Command + +def human_node(state: State): + # highlight-next-line + value = interrupt( # (1)! + { + "text_to_revise": state["some_text"] # (2)! + } + ) + return { + "some_text": value # (3)! + } + + +graph = graph_builder.compile(checkpointer=checkpointer) # (4)! + +# Run the graph until the interrupt is hit. +config = {"configurable": {"thread_id": "some_id"}} +result = graph.invoke({"some_text": "original text"}, config=config) # (5)! +print(result['__interrupt__']) # (6)! +# > [ +# > Interrupt( +# > value={'text_to_revise': 'original text'}, +# > resumable=True, +# > ns=['human_node:6ce9e64f-edef-fe5d-f7dc-511fa9526960'] +# > ) +# > ] + +# highlight-next-line +print(graph.invoke(Command(resume="Edited text"), config=config)) # (7)! +# > {'some_text': 'Edited text'} +``` + +1. `interrupt(...)` pauses execution at `human_node`, surfacing the given payload to a human. +2. Any JSON serializable value can be passed to the `interrupt` function. Here, a dict containing the text to revise. +3. Once resumed, the return value of `interrupt(...)` is the human-provided input, which is used to update the state. +4. A checkpointer is required to persist graph state. In production, this should be durable (e.g., backed by a database). +5. The graph is invoked with some initial state. +6. When the graph hits the interrupt, it returns an `Interrupt` object with the payload and metadata. +7. The graph is resumed with a `Command(resume=...)`, injecting the human's input and continuing execution. + +??? example "Extended example: using `interrupt`" + + ```python + from typing import TypedDict + import uuid + + from langgraph.checkpoint.memory import InMemorySaver + from langgraph.constants import START + from langgraph.graph import StateGraph + # highlight-next-line + from langgraph.types import interrupt, Command + + class State(TypedDict): + some_text: str + + def human_node(state: State): + # highlight-next-line + value = interrupt( # (1)! + { + "text_to_revise": state["some_text"] # (2)! + } + ) + return { + "some_text": value # (3)! + } + + + # Build the graph + graph_builder = StateGraph(State) + graph_builder.add_node("human_node", human_node) + graph_builder.add_edge(START, "human_node") + + checkpointer = InMemorySaver() # (4)! + + graph = graph_builder.compile(checkpointer=checkpointer) + + # Pass a thread ID to the graph to run it. + config = {"configurable": {"thread_id": uuid.uuid4()}} + + # Run the graph until the interrupt is hit. + result = graph.invoke({"some_text": "original text"}, config=config) # (5)! + + print(result['__interrupt__']) # (6)! + # > [ + # > Interrupt( + # > value={'text_to_revise': 'original text'}, + # > resumable=True, + # > ns=['human_node:6ce9e64f-edef-fe5d-f7dc-511fa9526960'] + # > ) + # > ] + + # highlight-next-line + print(graph.invoke(Command(resume="Edited text"), config=config)) # (7)! + # > {'some_text': 'Edited text'} + ``` + + 1. `interrupt(...)` pauses execution at `human_node`, surfacing the given payload to a human. + 2. Any JSON serializable value can be passed to the `interrupt` function. Here, a dict containing the text to revise. + 3. Once resumed, the return value of `interrupt(...)` is the human-provided input, which is used to update the state. + 4. A checkpointer is required to persist graph state. In production, this should be durable (e.g., backed by a database). + 5. The graph is invoked with some initial state. + 6. When the graph hits the interrupt, it returns an `Interrupt` object with the payload and metadata. + 7. The graph is resumed with a `Command(resume=...)`, injecting the human's input and continuing execution. + + + +!!! tip "New in 0.4.0" + + `__interrupt__` is a special key that will be returned when running the graph if the graph is interrupted. Support for `__interrupt__` in `invoke` and `ainvoke` has been added in version 0.4.0. If you're on an older version, you will only see `__interrupt__` in the result if you use `stream` or `astream`. You can also use `graph.get_state(thread_id)` to get the interrupt value. + +!!! warning + + Interrupts are both powerful and ergonomic. However, while they may resemble Python's input() function in terms of developer experience, it's important to note that they do not automatically resume execution from the interruption point. Instead, they rerun the entire node where the interrupt was used. + For this reason, interrupts are typically best placed at the start of a node or in a dedicated node. Please read the [resuming from an interrupt](#how-does-resuming-from-an-interrupt-work) section for more details. + +## Requirements + +To use `interrupt` in your graph, you need to: + +1. [**Specify a checkpointer**](../../concepts/persistence.md#checkpoints) to save the graph state after each step. +2. **Call `interrupt()`** in the appropriate place. See the [Design Patterns](#design-patterns) section for examples. +3. **Run the graph** with a [**thread ID**](../../concepts/persistence.md#threads) until the `interrupt` is hit. +4. **Resume execution** using `invoke`/`ainvoke`/`stream`/`astream` (see [**The `Command` primitive**](#the-command-primitive)). + +## Design patterns + +There are typically three different **actions** that you can do with a human-in-the-loop workflow: + +1. **Approve or Reject**: Pause the graph before a critical step, such as an API call, to review and approve the action. If the action is rejected, you can prevent the graph from executing the step, and potentially take an alternative action. This pattern often involve **routing** the graph based on the human's input. +2. **Edit Graph State**: Pause the graph to review and edit the graph state. This is useful for correcting mistakes or updating the state with additional information. This pattern often involves **updating** the state with the human's input. +3. **Get Input**: Explicitly request human input at a particular step in the graph. This is useful for collecting additional information or context to inform the agent's decision-making process. + +Below we show different design patterns that can be implemented using these **actions**. + +### Approve or reject + +
+![image](../../concepts/img/human_in_the_loop/approve-or-reject.png){: style="max-height:400px"} +
Depending on the human's approval or rejection, the graph can proceed with the action or take an alternative path.
+
+ +Pause the graph before a critical step, such as an API call, to review and approve the action. If the action is rejected, you can prevent the graph from executing the step, and potentially take an alternative action. + +```python +from typing import Literal +from langgraph.types import interrupt, Command + +def human_approval(state: State) -> Command[Literal["some_node", "another_node"]]: + is_approved = interrupt( + { + "question": "Is this correct?", + # Surface the output that should be + # reviewed and approved by the human. + "llm_output": state["llm_output"] + } + ) + + if is_approved: + return Command(goto="some_node") + else: + return Command(goto="another_node") + +# Add the node to the graph in an appropriate location +# and connect it to the relevant nodes. +graph_builder.add_node("human_approval", human_approval) +graph = graph_builder.compile(checkpointer=checkpointer) + +# After running the graph and hitting the interrupt, the graph will pause. +# Resume it with either an approval or rejection. +thread_config = {"configurable": {"thread_id": "some_id"}} +graph.invoke(Command(resume=True), config=thread_config) +``` + +??? example "Extended example: approve or reject with interrupt" + + ```python + from typing import Literal, TypedDict + import uuid + + from langgraph.constants import START, END + from langgraph.graph import StateGraph + from langgraph.types import interrupt, Command + from langgraph.checkpoint.memory import MemorySaver + + # Define the shared graph state + class State(TypedDict): + llm_output: str + decision: str + + # Simulate an LLM output node + def generate_llm_output(state: State) -> State: + return {"llm_output": "This is the generated output."} + + # Human approval node + def human_approval(state: State) -> Command[Literal["approved_path", "rejected_path"]]: + decision = interrupt({ + "question": "Do you approve the following output?", + "llm_output": state["llm_output"] + }) + + if decision == "approve": + return Command(goto="approved_path", update={"decision": "approved"}) + else: + return Command(goto="rejected_path", update={"decision": "rejected"}) + + # Next steps after approval + def approved_node(state: State) -> State: + print("✅ Approved path taken.") + return state + + # Alternative path after rejection + def rejected_node(state: State) -> State: + print("❌ Rejected path taken.") + return state + + # Build the graph + builder = StateGraph(State) + builder.add_node("generate_llm_output", generate_llm_output) + builder.add_node("human_approval", human_approval) + builder.add_node("approved_path", approved_node) + builder.add_node("rejected_path", rejected_node) + + builder.set_entry_point("generate_llm_output") + builder.add_edge("generate_llm_output", "human_approval") + builder.add_edge("approved_path", END) + builder.add_edge("rejected_path", END) + + checkpointer = MemorySaver() + graph = builder.compile(checkpointer=checkpointer) + + # Run until interrupt + config = {"configurable": {"thread_id": uuid.uuid4()}} + result = graph.invoke({}, config=config) + print(result["__interrupt__"]) + # Output: + # Interrupt(value={'question': 'Do you approve the following output?', 'llm_output': 'This is the generated output.'}, ...) + + # Simulate resuming with human input + # To test rejection, replace resume="approve" with resume="reject" + final_result = graph.invoke(Command(resume="approve"), config=config) + print(final_result) + ``` + +See [how to review tool calls](./review-tool-calls.ipynb) for a more detailed example. + +### Review & edit state + +
+![image](../../concepts/img/human_in_the_loop/edit-graph-state-simple.png){: style="max-height:400px"} +
A human can review and edit the state of the graph. This is useful for correcting mistakes or updating the state with additional information. +
+
+ +```python +from langgraph.types import interrupt + +def human_editing(state: State): + ... + result = interrupt( + # Interrupt information to surface to the client. + # Can be any JSON serializable value. + { + "task": "Review the output from the LLM and make any necessary edits.", + "llm_generated_summary": state["llm_generated_summary"] + } + ) + + # Update the state with the edited text + return { + "llm_generated_summary": result["edited_text"] + } + +# Add the node to the graph in an appropriate location +# and connect it to the relevant nodes. +graph_builder.add_node("human_editing", human_editing) +graph = graph_builder.compile(checkpointer=checkpointer) + +... + +# After running the graph and hitting the interrupt, the graph will pause. +# Resume it with the edited text. +thread_config = {"configurable": {"thread_id": "some_id"}} +graph.invoke( + Command(resume={"edited_text": "The edited text"}), + config=thread_config +) +``` + +??? example "Extended example: edit state with interrupt" + + ```python + from typing import TypedDict + import uuid + + from langgraph.constants import START, END + from langgraph.graph import StateGraph + from langgraph.types import interrupt, Command + from langgraph.checkpoint.memory import MemorySaver + + # Define the graph state + class State(TypedDict): + summary: str + + # Simulate an LLM summary generation + def generate_summary(state: State) -> State: + return { + "summary": "The cat sat on the mat and looked at the stars." + } + + # Human editing node + def human_review_edit(state: State) -> State: + result = interrupt({ + "task": "Please review and edit the generated summary if necessary.", + "generated_summary": state["summary"] + }) + return { + "summary": result["edited_summary"] + } + + # Simulate downstream use of the edited summary + def downstream_use(state: State) -> State: + print(f"✅ Using edited summary: {state['summary']}") + return state + + # Build the graph + builder = StateGraph(State) + builder.add_node("generate_summary", generate_summary) + builder.add_node("human_review_edit", human_review_edit) + builder.add_node("downstream_use", downstream_use) + + builder.set_entry_point("generate_summary") + builder.add_edge("generate_summary", "human_review_edit") + builder.add_edge("human_review_edit", "downstream_use") + builder.add_edge("downstream_use", END) + + # Set up in-memory checkpointing for interrupt support + checkpointer = MemorySaver() + graph = builder.compile(checkpointer=checkpointer) + + # Invoke the graph until it hits the interrupt + config = {"configurable": {"thread_id": uuid.uuid4()}} + result = graph.invoke({}, config=config) + + # Output interrupt payload + print(result["__interrupt__"]) + # Example output: + # Interrupt( + # value={ + # 'task': 'Please review and edit the generated summary if necessary.', + # 'generated_summary': 'The cat sat on the mat and looked at the stars.' + # }, + # resumable=True, + # ... + # ) + + # Resume the graph with human-edited input + edited_summary = "The cat lay on the rug, gazing peacefully at the night sky." + resumed_result = graph.invoke( + Command(resume={"edited_summary": edited_summary}), + config=config + ) + print(resumed_result) + ``` + +### Review tool calls + +
+![image](../../concepts/img/human_in_the_loop/tool-call-review.png){: style="max-height:400px"} +
A human can review and edit the output from the LLM before proceeding. This is particularly +critical in applications where the tool calls requested by the LLM may be sensitive or require human oversight. +
+
+ +```python +def human_review_node(state) -> Command[Literal["call_llm", "run_tool"]]: + # This is the value we'll be providing via Command(resume=) + human_review = interrupt( + { + "question": "Is this correct?", + # Surface tool calls for review + "tool_call": tool_call + } + ) + + review_action, review_data = human_review + + # Approve the tool call and continue + if review_action == "continue": + return Command(goto="run_tool") + + # Modify the tool call manually and then continue + elif review_action == "update": + ... + updated_msg = get_updated_msg(review_data) + # Remember that to modify an existing message you will need + # to pass the message with a matching ID. + return Command(goto="run_tool", update={"messages": [updated_message]}) + + # Give natural language feedback, and then pass that back to the agent + elif review_action == "feedback": + ... + feedback_msg = get_feedback_msg(review_data) + return Command(goto="call_llm", update={"messages": [feedback_msg]}) +``` + +See [how to review tool calls](./review-tool-calls.ipynb) for a more detailed example. + +### Validating human input + +If you need to validate the input provided by the human within the graph itself (rather than on the client side), you can achieve this by using multiple interrupt calls within a single node. + +```python +from langgraph.types import interrupt + +def human_node(state: State): + """Human node with validation.""" + question = "What is your age?" + + while True: + answer = interrupt(question) + + # Validate answer, if the answer isn't valid ask for input again. + if not isinstance(answer, int) or answer < 0: + question = f"'{answer} is not a valid age. What is your age?" + answer = None + continue + else: + # If the answer is valid, we can proceed. + break + + print(f"The human in the loop is {answer} years old.") + return { + "age": answer + } +``` + +??? example "Extended example: validating user input" + + ```python + from typing import TypedDict + import uuid + + from langgraph.constants import START, END + from langgraph.graph import StateGraph + from langgraph.types import interrupt, Command + from langgraph.checkpoint.memory import MemorySaver + + # Define graph state + class State(TypedDict): + age: int + + # Node that asks for human input and validates it + def get_valid_age(state: State) -> State: + prompt = "Please enter your age (must be a non-negative integer)." + + while True: + user_input = interrupt(prompt) + + # Validate the input + try: + age = int(user_input) + if age < 0: + raise ValueError("Age must be non-negative.") + break # Valid input received + except (ValueError, TypeError): + prompt = f"'{user_input}' is not valid. Please enter a non-negative integer for age." + + return {"age": age} + + # Node that uses the valid input + def report_age(state: State) -> State: + print(f"✅ Human is {state['age']} years old.") + return state + + # Build the graph + builder = StateGraph(State) + builder.add_node("get_valid_age", get_valid_age) + builder.add_node("report_age", report_age) + + builder.set_entry_point("get_valid_age") + builder.add_edge("get_valid_age", "report_age") + builder.add_edge("report_age", END) + + # Create the graph with a memory checkpointer + checkpointer = MemorySaver() + graph = builder.compile(checkpointer=checkpointer) + + # Run the graph until the first interrupt + config = {"configurable": {"thread_id": uuid.uuid4()}} + result = graph.invoke({}, config=config) + print(result["__interrupt__"]) # First prompt: "Please enter your age..." + + # Simulate an invalid input (e.g., string instead of integer) + result = graph.invoke(Command(resume="not a number"), config=config) + print(result["__interrupt__"]) # Follow-up prompt with validation message + + # Simulate a second invalid input (e.g., negative number) + result = graph.invoke(Command(resume="-10"), config=config) + print(result["__interrupt__"]) # Another retry + + # Provide valid input + final_result = graph.invoke(Command(resume="25"), config=config) + print(final_result) # Should include the valid age + ``` + + +## Resume using the `Command` primitive + +When the `interrupt` function is used within a graph, execution pauses at that point and awaits user input. + +To resume execution, use the [`Command`](../reference/types.md#langgraph.types.Command) primitive, which can be supplied via the `invoke`, `ainvoke`, `stream`, or `astream` methods. + +**Providing a response to the `interrupt`:** +To continue execution, pass the user's input using `Command(resume=value)`. The graph resumes execution from the beginning of the node where `interrupt(...)` was initially called. This time, the `interrupt` function will return the value provided in `Command(resume=value)` rather than pausing again. + +```python +# Resume graph execution by providing the user's input. +graph.invoke(Command(resume={"age": "25"}), thread_config) +``` + +## How does resuming from an interrupt work? + +!!! warning + + Resuming from an `interrupt` is **different** from Python's `input()` function, where execution resumes from the exact point where the `input()` function was called. + +A critical aspect of using `interrupt` is understanding how resuming works. When you resume execution after an `interrupt`, graph execution starts from the **beginning** of the **graph node** where the last `interrupt` was triggered. + +**All** code from the beginning of the node to the `interrupt` will be re-executed. + +```python +counter = 0 +def node(state: State): + # All the code from the beginning of the node to the interrupt will be re-executed + # when the graph resumes. + global counter + counter += 1 + print(f"> Entered the node: {counter} # of times") + # Pause the graph and wait for user input. + answer = interrupt() + print("The value of counter is:", counter) + ... +``` + +Upon **resuming** the graph, the counter will be incremented a second time, resulting in the following output: + +```pycon +> Entered the node: 2 # of times +The value of counter is: 2 +``` + +### Resuming multiple interrupts with one invocation + +If you have multiple interrupts in the task queue, you can use `Command.resume` with a dictionary mapping +of interrupt ids to resume values to resume multiple interrupts with a single `invoke` / `stream` call. + +For example, once your graph has been interrupted (multiple times, theoretically) and is stalled: + +```python +resume_map = { + i.interrupt_id: f"human input for prompt {i.value}" + for i in parent.get_state(thread_config).interrupts +} + +parent_graph.invoke(Command(resume=resume_map), config=thread_config) +``` + +## Common pitfalls + +### Side-effects + +Place code with side effects, such as API calls, **after** the `interrupt` to avoid duplication, as these are re-triggered every time the node is resumed. + +=== "Side effects before interrupt (BAD)" + + This code will re-execute the API call another time when the node is resumed from + the `interrupt`. + + This can be problematic if the API call is not idempotent or is just expensive. + + ```python + from langgraph.types import interrupt + + def human_node(state: State): + """Human node with validation.""" + api_call(...) # This code will be re-executed when the node is resumed. + answer = interrupt(question) + ``` + +=== "Side effects after interrupt (OK)" + + ```python + from langgraph.types import interrupt + + def human_node(state: State): + """Human node with validation.""" + + answer = interrupt(question) + + api_call(answer) # OK as it's after the interrupt + ``` + +=== "Side effects in a separate node (OK)" + + ```python + from langgraph.types import interrupt + + def human_node(state: State): + """Human node with validation.""" + + answer = interrupt(question) + + return { + "answer": answer + } + + def api_call_node(state: State): + api_call(...) # OK as it's in a separate node + ``` + +### Subgraphs called as functions + +When invoking a subgraph [as a function](low_level.md#as-a-function), the **parent graph** will resume execution from the **beginning of the node** where the subgraph was invoked (and where an `interrupt` was triggered). Similarly, the **subgraph**, will resume from the **beginning of the node** where the `interrupt()` function was called. + +For example, + +```python +def node_in_parent_graph(state: State): + some_code() # <-- This will re-execute when the subgraph is resumed. + # Invoke a subgraph as a function. + # The subgraph contains an `interrupt` call. + subgraph_result = subgraph.invoke(some_input) + ... +``` + +??? example "Extended example: parent and subgraph execution flow" + + Say we have a parent graph with 3 nodes: + + **Parent Graph**: `node_1` → `node_2` (subgraph call) → `node_3` + + And the subgraph has 3 nodes, where the second node contains an `interrupt`: + + **Subgraph**: `sub_node_1` → `sub_node_2` (`interrupt`) → `sub_node_3` + + When resuming the graph, the execution will proceed as follows: + + 1. **Skip `node_1`** in the parent graph (already executed, graph state was saved in snapshot). + 2. **Re-execute `node_2`** in the parent graph from the start. + 3. **Skip `sub_node_1`** in the subgraph (already executed, graph state was saved in snapshot). + 4. **Re-execute `sub_node_2`** in the subgraph from the beginning. + 5. Continue with `sub_node_3` and subsequent nodes. + + Here is abbreviated example code that you can use to understand how subgraphs work with interrupts. + It counts the number of times each node is entered and prints the count. + + ```python + import uuid + from typing import TypedDict + + from langgraph.graph import StateGraph + from langgraph.constants import START + from langgraph.types import interrupt, Command + from langgraph.checkpoint.memory import MemorySaver + + + class State(TypedDict): + """The graph state.""" + state_counter: int + + + counter_node_in_subgraph = 0 + + def node_in_subgraph(state: State): + """A node in the sub-graph.""" + global counter_node_in_subgraph + counter_node_in_subgraph += 1 # This code will **NOT** run again! + print(f"Entered `node_in_subgraph` a total of {counter_node_in_subgraph} times") + + counter_human_node = 0 + + def human_node(state: State): + global counter_human_node + counter_human_node += 1 # This code will run again! + print(f"Entered human_node in sub-graph a total of {counter_human_node} times") + answer = interrupt("what is your name?") + print(f"Got an answer of {answer}") + + + checkpointer = MemorySaver() + + subgraph_builder = StateGraph(State) + subgraph_builder.add_node("some_node", node_in_subgraph) + subgraph_builder.add_node("human_node", human_node) + subgraph_builder.add_edge(START, "some_node") + subgraph_builder.add_edge("some_node", "human_node") + subgraph = subgraph_builder.compile(checkpointer=checkpointer) + + + counter_parent_node = 0 + + def parent_node(state: State): + """This parent node will invoke the subgraph.""" + global counter_parent_node + + counter_parent_node += 1 # This code will run again on resuming! + print(f"Entered `parent_node` a total of {counter_parent_node} times") + + # Please note that we're intentionally incrementing the state counter + # in the graph state as well to demonstrate that the subgraph update + # of the same key will not conflict with the parent graph (until + subgraph_state = subgraph.invoke(state) + return subgraph_state + + + builder = StateGraph(State) + builder.add_node("parent_node", parent_node) + builder.add_edge(START, "parent_node") + + # A checkpointer must be enabled for interrupts to work! + checkpointer = MemorySaver() + graph = builder.compile(checkpointer=checkpointer) + + config = { + "configurable": { + "thread_id": uuid.uuid4(), + } + } + + for chunk in graph.stream({"state_counter": 1}, config): + print(chunk) + + print('--- Resuming ---') + + for chunk in graph.stream(Command(resume="35"), config): + print(chunk) + ``` + + This will print out + + ```pycon + Entered `parent_node` a total of 1 times + Entered `node_in_subgraph` a total of 1 times + Entered human_node in sub-graph a total of 1 times + {'__interrupt__': (Interrupt(value='what is your name?', resumable=True, ns=['parent_node:4c3a0248-21f0-1287-eacf-3002bc304db4', 'human_node:2fe86d52-6f70-2a3f-6b2f-b1eededd6348'], when='during'),)} + --- Resuming --- + Entered `parent_node` a total of 2 times + Entered human_node in sub-graph a total of 2 times + Got an answer of 35 + {'parent_node': {'state_counter': 1}} + ``` + + + +### Using multiple interrupts + +Using multiple interrupts within a **single** node can be helpful for patterns like [validating human input](#validating-human-input). However, using multiple interrupts in the same node can lead to unexpected behavior if not handled carefully. + +When a node contains multiple interrupt calls, LangGraph keeps a list of resume values specific to the task executing the node. Whenever execution resumes, it starts at the beginning of the node. For each interrupt encountered, LangGraph checks if a matching value exists in the task's resume list. Matching is **strictly index-based**, so the order of interrupt calls within the node is critical. + +To avoid issues, refrain from dynamically changing the node's structure between executions. This includes adding, removing, or reordering interrupt calls, as such changes can result in mismatched indices. These problems often arise from unconventional patterns, such as mutating state via `Command(resume=..., update=SOME_STATE_MUTATION)` or relying on global variables to modify the node’s structure dynamically. + +??? example "Extended example: incorrect code that introduces non-determinism" + + ```python + import uuid + from typing import TypedDict, Optional + + from langgraph.graph import StateGraph + from langgraph.constants import START + from langgraph.types import interrupt, Command + from langgraph.checkpoint.memory import MemorySaver + + + class State(TypedDict): + """The graph state.""" + + age: Optional[str] + name: Optional[str] + + + def human_node(state: State): + if not state.get('name'): + name = interrupt("what is your name?") + else: + name = "N/A" + + if not state.get('age'): + age = interrupt("what is your age?") + else: + age = "N/A" + + print(f"Name: {name}. Age: {age}") + + return { + "age": age, + "name": name, + } + + + builder = StateGraph(State) + builder.add_node("human_node", human_node) + builder.add_edge(START, "human_node") + + # A checkpointer must be enabled for interrupts to work! + checkpointer = MemorySaver() + graph = builder.compile(checkpointer=checkpointer) + + config = { + "configurable": { + "thread_id": uuid.uuid4(), + } + } + + for chunk in graph.stream({"age": None, "name": None}, config): + print(chunk) + + for chunk in graph.stream(Command(resume="John", update={"name": "foo"}), config): + print(chunk) + ``` + + ```pycon + {'__interrupt__': (Interrupt(value='what is your name?', resumable=True, ns=['human_node:3a007ef9-c30d-c357-1ec1-86a1a70d8fba'], when='during'),)} + Name: N/A. Age: John + {'human_node': {'age': 'John', 'name': 'N/A'}} + ``` \ No newline at end of file diff --git a/docs/docs/how-tos/human_in_the_loop/breakpoints.ipynb b/docs/docs/how-tos/human_in_the_loop/breakpoints.ipynb index 7d52f25c9..9520d97ae 100644 --- a/docs/docs/how-tos/human_in_the_loop/breakpoints.ipynb +++ b/docs/docs/how-tos/human_in_the_loop/breakpoints.ipynb @@ -1,126 +1,214 @@ { "cells": [ { - "attachments": { - "e47c6871-a603-43b7-a8b0-1c75d2348747.png": { - "image/png": "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mmvklltusROkpaVJo0aNzFQyb731ljz66KO8QBBAAAEEEEAAAQQQQAABBBBAAIFCL0CIo9AfQnYAAQQQQAABBLxdQMMODRs2lJMnT5qhvv/++9KyZUvz/0OHDjUl4N9++21p06aNeUwvVukyS5cuNRembO3hhx+Wp556Suo63Nn+888/y7p16yQuLk5atWol119/van6oXdl33HHHea/1nb06FF57bXX0lXR0OdzWoreFhgZMGCACXLQEECgeAvEr18vx599VvzCw6XaypXFGyOf9t7bPme2bNkir776quzbt88uoIFBDWLUrFnTYyoaUrRNF/bVV1/Jtdde67G+6QgBBBBAAAEEEEAAAQQQQAABBBAoKAFCHAUlz3YRQAABBBBAoNgI6MUsDWDY2uDBg+WZZ54RvUv5uuuuk3PnzsmmTZukSpUqosv27NnTHvjQdfSilFbMsLXx48fb+5syZYroz9b2+eefy0cffSSLFy8W27Zsz0dGRpp1Dx48aB7S0MeePXtk//79ZkoXLUlvLVPvykEaNGiQfPzxxyYY0r17d1dWYRkEECjCAvHffy/Hn3tOfENCpPr69UV4T71n17zpc0Y/zx555BGDExISIs2aNTNVp/Szrm3btjJp0iSPwY0aNUqmTZtmtrNr1y7x8/PzWN90hAACCCCAAAIIIIAAAggggAACCBSUACGOgpJnuwgggAACCCBQbARef/11mTNnjn1/9YLWzJkzTZn5Tp06mTLzq1atMs9rEEIDGNpq164ts2bNkho1apgpVTSUoRU2tGmljqCgIOncubP5+Z577jEl5n///XdTsn7kyJHmgtlLL70kffv2Ncto2XmdtkWDGrpNHVN4eLj89ttv9sog27dvN2EOd1r//v1FgyO6zSeeeMKdVVkWAQSKoMD5devkxIABhDjy8dh6y+eMVpxq0qSJPbAxZswYCQwMNJ9lw4YNM59rGujwRDty5IjceuutpquBAwdK7969PdEtfSCAAAIIIIAAAggggAACCCCAAAIFLkCIo8APAQNAAAEEEEAAgaIsYK22MX/+fHn88cfN7moJ+Oeee85MaaIXtp5++mnzuN6hrFOraJDi22+/ldDQ0HQ8y5cvl379+pmLZElJSbJ582ZT1UPDHz4+PmZZaxBEp1b57LPPzOMrVqyQXr162furV6+eVK9eXb788kvzWE4v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M2faggUL7Mt5C2z+/Pn29cIF1qhxY9ti2062XcdOtu0221inbbe2jttubY0aNaqU3aOfCCCAAAIIIIAAAggggAACCCCAQKoECHGk6nDQGQQQQAABBBBAoDiBFStWBANpGlQL/6v/VxnqDh06WPv27YtbIUsjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBAjQkQ4qgxejaMAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgj8T4AQB2cDAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAANXyPYkAACAASURBVAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAKBAhxpOAg0AUEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIAQB+cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQAgFCHCk4CHQBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAgxME5gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIpECAEEcKDgJdQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHFwDiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAikQIMSRgoNAFxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAUIcnAMIIIAAAggggAAC1SKwatUqmz9/fmZbzZo1syZNmlTLtqt7I6tXr7avvvoqs9n69evbRhttVN3dSMX2Zs+ebS+88ILttttu1qVLl1T0iU4ggAACCCCAAAIIIIAAAggggAACCCCAAAJpFSDEkdYjQ78QQAABBBBAAIEKEPjhhx9s8eLF1rJlS1tnnXXy9njChAk2ZMiQzDKjRo2y4447rgL2svgufvPNN9axY8fMC7fbbjt77rnnil9Rhb9i3LhxNnTo0MxeHHvssXb55ZdX+F7RfQQQQAABBBBAAAEEEEAAAQQQQAABBBBAoHwChDjKZ8uaEUAAAQQQQACBWifwwQcf2Kuvvmrvv/++vffee/bxxx9n9rFr1662ww47mAILBx98sDVq1Chr///0pz/ZBRdckPk3Qhy17vTI2iFVI9l7773t008/zfr3d955xzbYYIMa2fklS5bYsmXLgm3Xq1fP2rZtWyP9YKMIIIAAAggggAACCCCAAAIIIIAAAggggEAuAUIcnBsIIIAAAggggAACBQU0Fcof/vAHu+qqqwouqwVat25to0ePtl122SWzPCGOulWJQ+eMQj2qSuK2SZMm1Vh44pprrrE77rgj051HHnnEevToEeucZiEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQKA6BAhxVIcy20AAAQQQQAABBCpYYO7cuXbuuefaG2+8UdReNGnSxJ555hlr37598DpCHHUrxKFjfvPNN9stt9ySOW969eplDzzwQFHnUZIL+yGO+++/33r37p3kJlgXAggggAACCCCAAAIIIIAAAggggAACCCBQJQFCHFXi48UIIIAAAggggEDtFli5cqXtt99+a02JoYDGXnvtZZ07d7aNN97Y3n33XXv55Zfts88+y4D89Kc/tccff5wQh1kwxcxzz9W9EMcPP/wQ7LfOjZ122skOPfRQa968eY390hDiqDF6NowAAggggAACCCCAAAIIIIAAAggggAACMQUIccSEYjEEEEAAAQQQQKAuCowdO9bOP//8rF3v1q2b3XrrrdaqVausf1fg46KLLrJx48aZAhyPPfaYbbnllpllqMRR90IcafudIcSRtiNCfxBAAAEEEEAAAQQQQAABBBBAAAEEEEDAFyDEwTmBAAIIIIAAAgggECmwfPly22OPPezrr7/O/PyYY46xkSNH2nrrrRf5mh9//NHuuece22effbICHFo4X4hjxYoVNm/ePFPlhs0228zq169f8lFRmGTOnDnWsGFD22STTaxevXolryt84TfffGOaVkYVSDbaaCNr0KBB3nVq+Y4dO2aWKWclDpkvXLjQVq1aZRtssIGtv/76Je+v1rF48eJgXaqwksa2ZMkSW7BggW244YZBWKiYRoijGC2WRQABBBBAAAEEEEAAAQQQQAABBBBAAIGaECDEURPqbBMBBBBAAAEEEKgAgdtvv92uvfbaTE8VYJg6dao1bdq0pN5HhTh69epl1113nT399NNZ61To4ZxzzrFf/OIXsba1aNEi+/3vf29vv/12MLVL2NRnrUvTeCiAss4668Ran0Il9913n73++uv23nvvZQVZtIJtttnG+vXrZ/37948MEhQb4lAFE20rbFdeeWUwXU3YFKQZMGCAff/998E/XXjhhbbvvvvabbfdFoRmtL2wbb/99tazZ087++yzrVGjRgX399tvv7XRo0cH2//73/+eZbfz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FC9hO+2000whkDgtqRCH3KKmcPn000/t5z//eaYrhDjiHBWWQQABBBBAAAEEEEAAAQQQQAABBBBAAIE0CxDiSPPRoW8IIIAAAggggEANCSxdutR22GGHzNY19cnbb79dpd74IQ5Ne6HpL6JaoRDHrFmzrFevXiX359JLL7UTTzwx8/rHH388K1ByxBFHZE03UuyG/BBHnNergoRCCFHND3EUCiu8/vrrdvTRR2dWpX3VPodNVUdUfSRsWn6zzTaL3LYCNO5UJgcffLCNHj06zi5ZUiGO2bNnR26PEEesw8BCCCCAAAIIIIAAAggggAACCCCAAAIIIFBBAoQ4Kuhg0VUEEEAAAQQQQKA6BTp27Jg11Ueuaghx+5SmEMcVV1xhv/nNbzJdV5WR8847L/P3vn372q233hp319ZartgQR6FQRrEhjjfffNMOP/zwTL+OOeYYu/LKKzN/90MckydPtjZt2kTu78SJE23w4MGZnx1wwAFBVZE4jRBHHCWWQQABBBBAAAEEEEAAAQQQQAABBBBAAAEE/idAiIOzAQEEEEAAAQQQQCBSQEGGd999N/Ozyy+/3I499tiStZIMcaxcudK22mqrrL506dIldt/OPPNM23fffTPL+6GH7bff3p5++unY6/MXLDbEode/+OKLts0220Rus9gQhx+8UEDljDPOyKxbAQ/tc9ieeOIJ23HHHSO3/cc//jGrisdJJ51kF198cSwbQhyxmFgIAQQQQAABBBBAAAEEEEAAAQQQQAABBBDICBDi4GRAAAEEEEAAAQQQiBQ4//zzbezYsZmfaUoVTbvRuHHjksSSDHGoAwphfPzxx5m+vP/++yX3bf78+bbbbrtl7ddbb71lG220UUn76oc4WrdubZdccomtu+66JsemTZta//79syqddOvWzWRUr169tbZZbIjjvvvus+HDh2fWc/PNN9thhx2W+btCHao+Ejb/524Hhg0bZvfff3/mn/wqJvmA0hbiuOmmm+x3v/tdpss33HBDcBxoCCCAAAIIIIAAAggggAACCCCAAAIIIIBAWgQIcaTlSNAPBBBAAAEEEEAgZQKffvqp/fznP8/q1emnnx5MOxIVNCjU/aRDHKeddpr95S9/yWzWrzZRqD/uz1evXm3t27fPesmvf/1ru+aaa4pZTWZZP8Sx3Xbb2XPPPZe1rocfftguuuiirH9T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1FJVZcL2CHbddVejNGr33HNPVVm17Qc/+EEQ3r5omzx5chBO35qctW5qMokO4hze4n3EEUdUNfOPf/xjkM7M2qBBg4I01RdffLH5+c9/XlVWDuHDDz/cHHfccYmOV10o5/7UqVONGP/2t781aq81cdtpp53MqFGjzMorr1w0usj677vvPqM5rvmoUOCuiaUiKx988MFm44037laHRAb63Nq2224bmeL73nvvNRdccEGl7Lhx44xSbrv27W9/OxBD+HbkkUeao48+OhhrpaRTuiHXdF+l7nafk5dfftkMHz48tN8aX13z0ksvGbVj3rx5VeW++c1vGqWyk4M9ypQa8JJLLjG/+c1vgrG1pjmodigateZKnIBA7VM7ZZp3Z2BMbtcAACAASURBVJ55prnuuuuM5rk/r/fee+/g8zAhge6zcOHCSht0rTvXNI5xghyl6thqq60aOgc13/Rs6H9ffPHFbvc+4IADzODBg4NnJMzCRBwSvmh+uOOha3feeWfzox/9yGyyySap+qg2KV39Cy+8UPVMiOMWW2xhjjnmmMh2hd1A46H61C6lAnHHRuW/9rWvBc/R/vvvHyqKyyLi8L9XNtxwwyC9pGsab/sMqU/6DnvmmWeMxD9PPvlk1VzecccdzbBhw0z//v1TsXvzzTeD+avn4g9/+EPlGq2dW265pfnOd76TyE589txzz8T7jRw50hxyyCGx5cReqT/l/JWddtppQZT4rOt7Ud+1iZ1MWaCI95Q812PbjTK+90gMqu8B17K8R8V977n9rmdNyWsep5xOqYs14rnIY01J3aGUBcs4j1M2nWJ1EEDEUQc8LoUABOongIijfobUAAEIQAACEIAABCAAAQhAAAKtR+Dmm28OHD/WbrnllooYQ87TX//615XP5Kju169f8O8xY8YEqY6t3X///VWO8LBUxGH05GD7yle+EgpWG8lpnF1xoyLHfZKIQ0IDOf3clM1+nY1I4SzxxKxZs2qeZCeffLI54YQTqq4PE3GowOzZsyPvo/HQvNAJ8yiTE0iO5meffTa2vXJuSgyw/fbb19yvWi7UWI4dO9bMmTMn1eUq64siFD3BFSbJGS0uYXbFFVcEDnZr6rOEDq717t079Fo59CWC0lx3HcN+4dtuu81ss802wZ/lLJfwIcwkRlJbowQCukbO7Yceeig0gsDcuXPN97///Sqh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/fY1dV3iHkW2dE2imv3337+m+nwRh7+m6/mSOOLPf/5zpf6459pnJ3GNmxLFbeTDDz9sjjzyyMqfxMRNFaMPrIDRFjrxxBODNGO+Pf3000ZOSteUplPRRNNY2UQceXzXpul32jJFvqeUXcSR91j4IoLf/va3ZtVVV007FEG5PNeUvN9TMnUkY+E8xqJRa0rGriUWL8P7e2IjKVAzAUQcNaPjQghAAAIQgAAEINC8BOREGzp0aHB6etSoUYlpRZq3p7QcAhCAAATKRMCmidEmmU7HxqVwKVO7aQsEeoqAH15bJ7V1ElUnoW1qK6VnOvfcc82XvvSlwGFvox3IeSonalqrdxNYzvGJEydWbidhw5133mmWXXbZtE0wzSLikFhmo402quqX0tjss88+qfuat3PkzTffNEpn5toBBxxgzj///LqiNqTuUEJBzQVfePCtb33LnHPOOUHEv6zmO7sUpWaXXXapqsZPL6EPm1HEoagBEsG4psgrShWy1FJLZUXXzcm3cOHC0Dqyijh0QEC/MV3L++R81s6qb/68UIQKiRuypC6x981bxOFH0NF9JIbZYYcdsnY1SL0jEYebgkTfFZdddpn5+te/nrm+JBGHKgybm1HfPT67fffdN2jbEkssUdW2f/7zn0HEKUWYsqa1Q+Il1+x3n/2b+nrrrbcaffdYU3Sqo446ykjIYS1rlKqyiTjy+K7NPBliLijyPaXsIo68x0Lrpxv5UEImrRFZLM81Je/3lCz9yFo2j7Fo1JqStW9J5cvw/p7URj6vnQAijtrZcSUEIAABCEAAAhBoSgKugEMdGDZsmBk3blxT9oVGQwACEIBAcxGQc0EnRWU6KSaHL1E5mmsMaW3jCbjpGOzdt91228BZJbv//vvN0Ucf3a1hV111lRk0aFDV35UCyXXwuR9q41+nPq3J+b/JJptUXb/66qubPn36hEJ48MEHg/dK1xQhQeksdM1qq61mPv74Y6Nw3xIc7L777mb99devKt8sIg412l3PbCckUJOzVKkGlMJAvN9+++3g44MPPriqr0U4R3SyXQI51+TYHD58uPnKV74SjMHKK69sdIJep+flpN9yyy1N//79C5/Y//73vwPHrJz6rilkvBxVcqivu+66RmkU1L533nkniNyktCFqv28SMPh1ycmryBty3CoyihsZxl4voc3AgQODuS1n72uvvWb++te/VqqXIEpRbqzJyax5bG299dYLxjfKnn/++SAijjU3AoDGQpEhXOvXr59ZYYUVEvn7kUx0gYRbevY32GCDQBSpej788EPzpz/9yShajO6t9vqWJkKErskq4hDHsBQ+OjSg1BhrrLFGIDR49913g/mnqA077bRTYt/rLaAxlCDBNzn3JejQOiQxjObde++9Z9544w2jlD2KbOOLZPIWcWi8JDLRuuja1772tSDShNKaat7Y9USiFI2v5rovftD1Ej6EpbDRd4FYa67YNUDPicZBz9khhxwSjIdraUQcKv/tb3+7EgHKXv/444+bddZZp6o+n50+VKQprQsSxSkqz8svv2wmTZpUJbpQuWeeecbo+8c1jZfWLpedWJ1wwglBP/V3PW/2vdNeG5ZqSuuO+9y791HqMonErKm9fnST5ZZbLpjj1opY323deXzX1vtM+dfn9Z6S93qsdpb9vcdlqfeun//851V4FYVGkdX0PaTvQz23eq/QGqXvRl8om+eaUuQ8znsO5vFc5Lmm5N2/ZprHefe93etDxNHuM4D+QwACEIAABCDQVgR0YlOnoLVRIxs8eHDVicm2gkFnIQABCECg4QQkJBwzZkwQQl8mp5McjmEOh4Y3jhtCoKQE5OTyhRcSBFin5O9///vAKe2bnNjuiWR9/qtf/SpwmNVqcadC5aSXI9A9RRp3nwkTJnR79ptJxBEWdSCqv2G57YtwjshBfuCBB1aJcZLGWo7s8ePHJxXL5XNfFJCmUgkVfLGGrnv00UfNYYcdlljFN7/5zSAijG9WCCVHvVLRpDU52eLuq2g5crKnNYmwNt5448Ticthljc5w5ZVXmr322qtb3UWJOHQjRbiwKZ+SOtWo36KffPJJILqyUYqS2mU/1zPuCnj097xFHKrzl7/8pVHEgSymyBISxYSZUtoomkcWu/TSS42eFdfSijgkvNhjjz2qrpVoREJC18JEHGnaqP2LM888M7TozTffbE477bQ01QRl9H2qNFO++SmaUlf4n4ISwDz00EOVy4pY323leXzXZu1fUvm83lPyXo/V7rK/97hsJXCT2MpNARbHPio1VF5rSpHzOGlOZf08r+cirzUla/uTyjfTPE7qC59nI4CIIxsvSkMAAhCAAAQgAIGmJeBH4GjUplnTAqPhEIAABCBQGAGdspw8eXKl/lmzZhGRozDa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IEGSiiiwi4AJEMN5/hXRC3oG9PT0TJyYUYISl6gILEtGogoSlxw35508nf+v77eqentm08DMBnY+dbfMTHf1r6re1Tu8fPXD82VDAAEEEEBgUwv8/ve/V9TCscsuu2jmzJmb+pQ4PgIIIIAAAggggAACCCCAAAIIILDJBAhxbDJ6DowAAggggAACCGxcAfsvnO2/dLbNmjhuueWWjXsCHA0BBBBAAIF+ArX/bpo0aZIHOAgZ8jZBAAEEEEAAAQQQQAABBBBAAIHhLECIYzjffa4dAQQQQAABBIadwDnnnKNrrrnGr3vatGn60Y9+NOwMuGAEEEAAgU0v0N7e7u0b0QiVpqYmzZgxg3Ffm/7WcAYIIIAAAggggAACCCCAAAIIILCJBQhxbOIbwOERQAABBBBAAIGNLXDMMcfomWee8cMeffTRHuTgv3re2HeB4yGAAALDV2D27NmyUKF9tY0Ax/B9L3DlCCCAAAIIIIAAAggggAACCCCwugAhDt4VCCCAAAIIIIDAMBOw//p5+vTp1SCHjVa54IILNHny5GEmweUigAACCGwKgd1331327yLb9t9/f/93EGHCTXEnOCYCCCCAAAIIIIAAAggggAACCGyOAoQ4Nse7wjkhgAACCCCAAAIbWMA+PLP/CnrWrFl+JAtw3H///Rv4qCyPAAIIIICAFDVCfeMb39CZZ54JCQIIIIAAAggggAACCCCAAAIIIIBAjQAhDt4OCCCAAAIIIIDAMBY499xzdeGFF2rSpEl64IEHhrEEl44AAgggsLEELEhof2iA2ljiHAcBBBBAAAEEEEAAAQQQQAABBN5KAoQ43kp3i3NFAAEEEEAAAQQ2gMDs2bO9xp4P0zYALksigAACW7iA/Ttk7ty5sq/25+mnn/Z/n1x11VVb+JVzeQgggAACCCCAAAIIIIAAAggggMCGESDEsWFcWRUBBBBAAAEEENiiBL797W/7B3O77rqrBz7WtD344IM6+uijdcYZZ6z12u2/vLa15syZs06fAw44QF/84hcHvY6dr9X1r22z8/nyl7+stra2Ne5iH0jaPnZdv/3tb9e5zsknn+wfYK5rW9869kHoWWedtd513va2t+mWW25Z66EGus76zseufSiuy070U5/6lG699dZB+QzV+UT3vf/57L///n3Or6WlZZ33Pbqutb1/osW22mor/ehHP1rn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AQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgYEJEOIYmBN7IYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACG1SAEMcG5WVxBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEBgYAKEOAbmxF4IIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggMAGFSDEsUF5WRwBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEBiYACGOgTmxFwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggsEEFCHFsUF4WRwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEBiZAiGNgTuyFAAIIIIAAAggggAACCGwSgUqlolgsJvs61Juty4YAAggggAACCCCAAAIIIIAAAggggAACm48AIY7N515wJggggAACCCCAAAIIIIBAH4ENGeDoT02ggzcfAggggAACCCCAAAIIIIAAAggggAACm16AEMemvwecAQIIIIAAAggggAACCCBQFejfuGE/259SqahCoahisah8Ia9ioahyuayK/ZFkpRrBvuFSYclGIh5XLBaXfU0kk0qlUkqmUkolk0omk97yYZv9M1gn+DkKkHBrEEAAAQQQQAABBBBAAAEEEEAAAQQQQGDjCRDi2HjWHAkBBBBAAAEEEEAAAQQQcIF1jUbxkEY+r97eXvX29Kg316vOjk4tX7FcK5YtV1tbm5avWKHOzk7lcjkVC4U+quWKBTsqHvCwZEcU1sjWZdXU1KyW1la1trRozOjRGjFypBobG1VXV6e6+jr/mkym1niXaOrgzYsAAggggAACCCCAAAIIIIAAAggggMCGFyDEseGNOQICCCCAAAIIIIAAAggg4AL9x6PYzxbasDBGrrdXXd3dWrp0qRYuWKC5c+Zozpw5WjBvnpYsWaKVbW3q6elRsVTycEYikfCARjyeUDwRVzwW8yYNa+YolUq+bin8vlAoqFIqVZs2Mum0WlpaNGrUKI0bO1bbbruttt9hB22z3XYaP3GCmhoala2rUzqdrjZzRLeQMAdvZgQQQAABBBBAAAEEEEAAAQQQQAABBDacACGODWfLyggggAACCCCAAAII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Ir/6Rb6LR2SHipi0aVUs8yUugY1lskM4LoU+vyrFkiypknC5gBdJRZ5fVgf8slaiEonGpGN1XLYPi0QgcoE3BiqfJOhAbgKHjihKtYRjUhGvkCUDT5E2f7tMYu+9I/LwE1IVCsmHAy4wRBylLVQ5FYg2BIIZnygRhx/uI7Go+AJByS/IN4QYJgjlQ2KUeTGcOJRNikRjUQlXV0owHpYT999O9u3ZISkMqe3xweVIgARIgARIgARIgARIgARIgARIgARIgARIoKERoIijoe0RjocESIAESIAESIAESIAESMAzAqaIY9GKDTL3l7VSXh2XYCgkfr/hxKGEBVBxQJ2QEG+oEixwf1CjiCuHiHC42hAiQFagRBwi8SgcO1DmIy7hqipZ/uW7snLRDxIMQ77hk4jEJQLRgxJ+GK4cbX1+OSKYL50lIGXo29BsqNUbxVwMVw6UVoE7xabCAlldXS1tqsLSOu6T3/MCsikak+KAyGbxSfO4SIeoSCgWk8qCkPzmi0thVVhKCwpkJTarqkpaR0XyLUSNURsR8PkkGvRLJBiQynhcNkXCUhCOS2vVwJBQwB3DkFL86U6Cki/Y7up4RNb02keKjzhcovN+EP/770s4GJKfdh4g0mE7ad68QG2H4XpicFaOHBCsxOLiDwUkEAwqCD58mCChdkdit0hCNAPBTCQSFolFpFe3VrLjNqVG6ZWEk4lnBw07IgESIAESIAESIAESIAESIAESIAESIAESIIEtSIAiji0In6smARIgARIgARIgARIgARKoXwKmeMGQIziPpDlHpkX+tPDI2LHbdTsf5RZsCSGFZfsNDYizLXXWyti22u6/LUiGqyYBEiABEiABEiABEiABEiABEiABEiABEiABVwQo4nCFi41JgARIgARIgARIgARIgAQaKwGHGos6bJ4jqYfq32L84Xh9mZYxhRDOR+B4tc4aaiKOPxdyI9FwtirFLzfdOh8AW5IACZAACZAACZAACZAACZAACZAACZAACZBAjghQxJEjsOyWBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEhgyxIoKyuTcDgsLVu23LID4drrncDatWtVmd8WLVoYpZUbSVDE0Uh2FIdJAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiSQmcC8efNk6tSp8vbbb8uCBQuSjb/66itp1aoV8W1FBI4++mj54Ycf1BZ37NhRDjroIDnmmGOkf//+EgwGGywJijga7K7hwEiABEiABEiABEiABEiABEiABEiABEiABEjAWwIVFRWyfv36ZKdt27Zt0C8vvd36pt3bhg0bpLy8XG2kz+eTDh06NO0N5taRAAls1QRWr14tkUhEMSgoKJDS0tKtmgc3ngRIwCCAa8Odd94pr7/+ui2ShQsXNuln35UrV0osFuPzoGXv/+Uvf5EPP/ywxvHQvXt3ue+++2TvvfdukKcPRRwNcrdwUCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiTgPYFrrrlGXnrppWTHU6ZMkV133dX7FbHHeifQt29fWb58eXK9ixcvrvcxcIUkQAIkUB8ElixZIgceeGByVUcddZQ89dRT9bFqroMESKABE/j555/lxBNPFJROsYvWrVvLl19+2YC3oO5D22WXXVK2v6k8D0ajUVm3bp0S77Vp08aVEOfmm2+W8ePHp4V7//33y6BBg+oO3+MeKOLwGCi7IwESIAESIAESIAESIAESIAESIAESIAESIIG6EhgxYoQgSWXGK6+84vhl5fz58+Xqq69OLnv66afLkCFD1M9/+9vfUmYmUsRR1z3VcJZvqi/tGw5hjoQESMALAnCEWrNmTbKrdu3aSX5+vquuMZP+0EMPTS5DEYcrfI2mMRwFqqur1XhxjOBYaaoBl7RNmzapzYObVqdOnZrqpuZsu3777Tc5+eST5Y8//qixjoMPPlj23XdfgeC1T58+Nb6fOHGiPP/88ymfP/TQQ9KlSxfb8UIU8M0336jvDjjgALn22mtztl1uO25Kz4MQ5bz55pvyxhtvyC+//JKCAu4ZvXr1kgsvvDCr+9yiRYvko48+ktmzZ8uMGTNsj5HHH39cjj32WLe4c9qeIo6c4mXnJEACJEACJEACJEACJEACJEACJEACJEACJOCewJlnnimffvppckG8dHSavIBdMGyDzYBw48orr1Q/UsThfl80liWa0kv7xsKc4yQBEnBPQL9HXX755TJy5EhXHVHE4QpXo2183HHHyXfffZcc/w8//CDNmzdvtNuTaeB///vfBUlkM1588UXp169fk9zWXGxUPB6XM844Q2bOnJnS/fHHHy8PPPBAVqHYY489JqNGjUpZdtiwYXL99dfbDtf6nA5xyKRJk3KxWbXqsyk8D27cuFHgjvHcc885YoCSKKeddpqjtmgEwc5NN91Uo72b37ccr6wODSniqAM8LkoCJEACJEACJEACJEACJEACJEACJEACJEACuSAAJ40JEyYku3777bdl5513drQqLGd14rj33ntl8ODBalmKOBwhbJSNmsJL+0YJnoMmARJwRUAXcVx88cVy3XXXueqDIg5XuBptY13EAUFHcXFxo92eTAPXRRxIXh9yyCFNcltzsVFwarj00ktTuh46dKjcdtttEggEsq7STsRRWFioSq8UFBTUWJ4ijqxIa90ATioDBw6s4byRrUMIaSCocRqTJ0+W4cOHpzQ/9dRTZfTo0U67yHk7ijhyjpgrIAESIAESIAESIAESIAESIAESIAESIAESIAF3BB588MGUl4iYMda/f39HnTzyyCNq9poZ//rXv5K28xRxOELYKBtRxNEodxsHTQJbHQGKOLa6XV7rDaaIgyIOpwfP4YcfLgsWLEg2hwjgn//8p9PFxU7EgYVRUgUlWvSgiMMxWtcNzzrrLPn4449rLId9jLI4zZo1k6+//lpeeOGFlDa77babKrviRLRjLmgn/oET4rbbbut63LlYgCKOXFBlnyRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRQBwIvvfSSXHPNNckeMCsMs8OcxC233JJiPzxlyhQ3uWjxAAAgAElEQVTZdddd1aIUcTgh2DjbUMTROPcbR00CWxsBiji2tj1e++2liIMiDidHD8rsHH300SlN3333XenZs6eTxVWbdCKOdKVSKOJwjNZ1w1mzZsmgQYOSyx111FFK2A5nFGvMmTOnxu9G77//vnTv3t3xOiORiBx44IGyfPny5DIooYNSOg0hKOJoCHuBYyABEiABEiABEiABEiABEiABEiABEiABEiABC4Hp06fLOeeck/zkhhtukIsuusgRI7x4nDp1arItrKBbt26tfs4k4igrK5NVq1ZJXl6edOzYUfx+v6P12TXCS9GlS5eqGuQdOnQQn89X677MBdevXy+rV6+WVq1aJbenzp267AA118PhsGKDmX5ebJfLIaRtnknE0RDY6QMHy5UrV0ppaWmNWvW//fab+qx9+/Zpt7e+9oWX50Vd9jWOOxxvuTzusA7zGoDzzM1sVrtt87o/6zo2b96ski5t27aVli1b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nSukx0TkePfFjUKuRo0aydSpU4WUh2pKQAkoASWgBJSAElACSkAJKAEloASUgBJQAukJqIhDZ4cSSJDAunXrTLSA//73v6lab7zxRunbt2+CZ9lYFalDjj/+eEGMYI1IC0RciGOkfyENjGvz588XBCiFMEQk7BIkDYxrRAP585//nDE1DAxq164dOI4oHldeeWXqM/oxadKkQIqWNWvWyIABAwLsiAjiRq6wFeRLxPHjjz/K9ttvH2g7Oct79uyZCPZiEHEMGTJEHn/88VR/zjrrLDnvvPMC/QsT06QTcRAZZPz48YHjH3nkEenSpUsizLQSJaAESpeAijiKb+xSIo6ddpKJTqq54muptkgJVC4CpFskbcmLL75oOnbsRbdK+317VWgnbz79UPnq4/mmDYWIVFihndWTKwElUJQEli9fLrx7wNhks+WWWxZlO7VRVZMAc5M5am2zzTaTBg0aVEoYCExJe8wPttVWW5kfBJ5bb711pexzqXdq1apVsnbtWtMN0lU3adKk1Luk7VcClZrAzz//bMT81urVq1cwP0+hwW7YsEGWLFmSOu2mm24qDRsWNvpkofuc7nyff/65PPPMM9K5c2fp0KFDsTRL25EAARVxJABRq1ACLoHhw4fLQw89lPqIRXPy5MlSvXr1yKAuvvhiIzAgGkW7du2kcePGZucaxk2Y73D4u2IRvsNBjqM8qq1fv16OPvroQOSK3//+90J6lUKaH8HEnhuRAwKP7bbbTtq0aWMeOFasWCFEGyFqBS+nX3vttcAfEAg7unXrFogswnFnnnmmqYOII6TvIMS0a4gNdt999zLdzpeIgxPRN78dRBI54IADzB+v1apVE/5Ysg9eRx11VKB9fOeLX2wBBA9uFIyrrrpKdthhh8DxPNS0atUq9VnS6VRuvfVWue666wLnPOaYY1Khvd9++21B5OTbzjvvLCeccIJpG5E24IB999130r1798DY8vlee+0lcCONEGNtufHw8sUXX5jrgj801ZSAEqi8BFTEUXxjGxBxIOjzRJfF12JtkRKoHARuueUWGT16tOlMx4P6Sf/zf02ZWFE9XLn8S7ntzD6y5tvlJurdlClTZNttt62o5lSZ85JyU6OeVJnh1o5mILBw4ULZe++9UyUOPvhgufPOO5WZEigaAqT5Jd2vtco2RxGpsOGKFNT+e0zbZzY08Z5T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rVs3EwVATQkoASWgBJSAElACSkAJKAEloASUgBJQAkogeQIq4kieqdaoBJSAElACSkAJKAEloASUgBJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAElACSkAJKIHYBFTEERuZHqAElIASUAJKQAkoASWgBJSAElACSkAJKAEloASUgBJQAkpACSgBJaAElIASUAJKQAkogeQJqIgjeaZaoxJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAElACSkAJKAEloASUgBJQAkpACSgBJaAEYhNQEUdsZHqAElACSkAJKAEloASUgBJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAElACSkAJKAEloASSJ6AijuSZao1KQAkoASWgBJSAElACSkAJKAEloASUgBJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAEohNQEUcsZHpAUpACSgBJaAElIASUAJKQAkoASWgBJSAElACSkAJKAEloASUgBJQAkpACSgBJaAElIASSJ6AijiSZ6o1KgEloASUgBJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAElACSkAJKAEloASUgBJQAkogNgEVccRGpgcoASWgBJSAElACSkAJKAEloASUgBJQAkpACSgBJaAElIASUAJKQAkoASWgBJSAElACSiB5Av8POSQ0hKDx8iYAAAAASUVORK5CYII=" - } - }, + "attachments": {}, "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", + "id": "ed746260-7027-4399-bbab-a0cdb1e53ec2", "metadata": {}, "source": [ - "# How to add breakpoints\n", + "# Use breakpoints\n", "\n", - "!!! tip \"Prerequisites\"\n", + "## Requirements\n", "\n", - " This guide assumes familiarity with the following concepts:\n", + "To use breakpoints, you will need to:\n", "\n", - " * [Breakpoints](../../../concepts/breakpoints)\n", - " * [LangGraph Glossary](../../../concepts/low_level)\n", + "1. [**Specify a checkpointer**](../../../concepts/persistence#checkpoints) to save the graph state after each step.\n", + "2. [**Set breakpoints**](#setting-breakpoints) to specify where execution should pause.\n", + "3. **Run the graph** with a [**thread ID**](../../../concepts/persistence#threads) to pause execution at the breakpoint.\n", + "4. **Resume execution** using `invoke`/`ainvoke`/`stream`/`astream` passing a `None` as the argument for the inputs.\n", + "\n", + "## Setting breakpoints\n", + "\n", + "There are two places where you can set breakpoints:\n", + "\n", + "1. **Before** or **after** a node executes by setting breakpoints at **compile time** or **run time**. We call these [**static breakpoints**](#static-breakpoints).\n", + "2. **Inside** a node using the `NodeInterrupt` exception. We call these [**dynamic breakpoints**](#dynamic-breakpoints).\n", + "\n", + "## Static breakpoints\n", + "\n", + "Static breakpoints are triggered either **before** or **after** a node executes. You can set static breakpoints by specifying `interrupt_before` and `interrupt_after` at **\"compile\" time** or **run time**.\n", + "\n", + "Static breakpoints can be especially useful for debugging if you want to step through the graph execution one\n", + "node at a time or if you want to pause the graph execution at specific nodes.\n", + "\n", + "=== \"Compile time\"\n", + "\n", + " ```python\n", + " # highlight-next-line\n", + " graph = graph_builder.compile( # (1)!\n", + " # highlight-next-line\n", + " interrupt_before=[\"node_a\"], # (2)!\n", + " # highlight-next-line\n", + " interrupt_after=[\"node_b\", \"node_c\"], # (3)!\n", + " checkpointer=checkpointer, # (4)!\n", + " )\n", + "\n", + " config = {\n", + " \"configurable\": {\n", + " \"thread_id\": \"some_thread\"\n", + " }\n", + " }\n", + "\n", + " # Run the graph until the breakpoint\n", + " graph.invoke(inputs, config=thread_config) # (5)!\n", + "\n", + " # Resume the graph\n", + " graph.invoke(None, config=thread_config) # (6)!\n", + " ```\n", + "\n", + " 1. The breakpoints are set during `compile` time.\n", + " 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.\n", + " 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.\n", + " 4. A checkpointer is required to enable breakpoints.\n", + " 5. The graph is run until the first breakpoint is hit.\n", + " 6. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit.\n", + "\n", + "=== \"Run time\"\n", + "\n", + " ```python\n", + " # highlight-next-line\n", + " graph.invoke( # (1)!\n", + " inputs, \n", + " # highlight-next-line\n", + " interrupt_before=[\"node_a\"], # (2)!\n", + " # highlight-next-line\n", + " interrupt_after=[\"node_b\", \"node_c\"] # (3)!\n", + " config={\n", + " \"configurable\": {\"thread_id\": \"some_thread\"}\n", + " }, \n", + " )\n", + "\n", + " config = {\n", + " \"configurable\": {\n", + " \"thread_id\": \"some_thread\"\n", + " }\n", + " }\n", + "\n", + " # Run the graph until the breakpoint\n", + " graph.invoke(inputs, config=config) # (4)!\n", + "\n", + " # Resume the graph\n", + " graph.invoke(None, config=config) # (5)!\n", + " ```\n", + "\n", + " 1. `graph.invoke` is called with the `interrupt_before` and `interrupt_after` parameters. This is a run-time configuration and can be changed for every invocation.\n", + " 2. `interrupt_before` specifies the nodes where execution should pause before the node is executed.\n", + " 3. `interrupt_after` specifies the nodes where execution should pause after the node is executed.\n", + " 4. The graph is run until the first breakpoint is hit.\n", + " 5. The graph is resumed by passing in `None` for the input. This will run the graph until the next breakpoint is hit.\n", + "\n", + " !!! note\n", + "\n", + " You cannot set static breakpoints at runtime for **sub-graphs**.\n", + " If you have a sub-graph, you must set the breakpoints at compilation time.\n", + "\n", + "??? example \"Setting static breakpoints\"\n", + "\n", + " ```python\n", + " from IPython.display import Image, display\n", + " from typing_extensions import TypedDict\n", " \n", - "\n", - "Human-in-the-loop (HIL) interactions are crucial for [agentic systems](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#human-in-the-loop). [Breakpoints](https://langchain-ai.github.io/langgraph/concepts/low_level/#breakpoints) are a common HIL interaction pattern, allowing the graph to stop at specific steps and seek human approval before proceeding (e.g., for sensitive actions). \n", - "\n", - "Breakpoints are built on top of LangGraph [checkpoints](https://langchain-ai.github.io/langgraph/concepts/low_level/#checkpointer), which save the graph's state after each node execution. Checkpoints are saved in [threads](https://langchain-ai.github.io/langgraph/concepts/low_level/#threads) that preserve graph state and can be accessed after a graph has finished execution. This allows for graph execution to pause at specific points, await human approval, and then resume execution from the last checkpoint.\n", - "\n", - "![approval.png](attachment:e47c6871-a603-43b7-a8b0-1c75d2348747.png)" + " from langgraph.checkpoint.memory import InMemorySaver \n", + " from langgraph.graph import StateGraph, START, END\n", + " \n", + " \n", + " class State(TypedDict):\n", + " input: str\n", + " \n", + " \n", + " def step_1(state):\n", + " print(\"---Step 1---\")\n", + " pass\n", + " \n", + " \n", + " def step_2(state):\n", + " print(\"---Step 2---\")\n", + " pass\n", + " \n", + " \n", + " def step_3(state):\n", + " print(\"---Step 3---\")\n", + " pass\n", + " \n", + " \n", + " builder = StateGraph(State)\n", + " builder.add_node(\"step_1\", step_1)\n", + " builder.add_node(\"step_2\", step_2)\n", + " builder.add_node(\"step_3\", step_3)\n", + " builder.add_edge(START, \"step_1\")\n", + " builder.add_edge(\"step_1\", \"step_2\")\n", + " builder.add_edge(\"step_2\", \"step_3\")\n", + " builder.add_edge(\"step_3\", END)\n", + " \n", + " # Set up a checkpointer \n", + " checkpointer = InMemorySaver() # (1)!\n", + " \n", + " graph = builder.compile(\n", + " checkpointer=checkpointer, # (2)!\n", + " interrupt_before=[\"step_3\"] # (3)!\n", + " )\n", + " \n", + " # View\n", + " display(Image(graph.get_graph().draw_mermaid_png()))\n", + " \n", + " \n", + " # Input\n", + " initial_input = {\"input\": \"hello world\"}\n", + " \n", + " # Thread\n", + " thread = {\"configurable\": {\"thread_id\": \"1\"}}\n", + " \n", + " # Run the graph until the first interruption\n", + " for event in graph.stream(initial_input, thread, stream_mode=\"values\"):\n", + " print(event)\n", + " \n", + " # This will run until the breakpoint\n", + " # You can get the state of the graph at this point\n", + " print(graph.get_state(config))\n", + " \n", + " # You can continue the graph execution by passing in `None` for the input\n", + " for event in graph.stream(None, thread, stream_mode=\"values\"):\n", + " print(event)\n", + " ```" ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", + "id": "b7d5f6a5-9e59-43e4-a4b6-8ada6dace691", "metadata": {}, "source": [ - "## Setup\n", + "## Dynamic breakpoints\n", "\n", - "First we need to install the packages required" + "Use dynamic breakpoints if you need to interrupt the graph from inside a given node based on a condition.\n", + "\n", + "```python\n", + "from langgraph.errors import NodeInterrupt\n", + "\n", + "def step_2(state: State) -> State:\n", + " # highlight-next-line\n", + " if len(state[\"input\"]) > 5:\n", + " # highlight-next-line\n", + " raise NodeInterrupt( # (1)!\n", + " f\"Received input that is longer than 5 characters: {state['foo']}\"\n", + " )\n", + " return state\n", + "```\n", + "\n", + "1. raise NodeInterrupt exception based on a some condition. In this example, we create a dynamic breakpoint if the length of the attribute `input` is longer than 5 characters.\n", + "\n", + "
Using dynamic breakpoints" ] }, { "cell_type": "code", - "execution_count": 1, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API keys for Anthropic (the LLM we will use)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ANTHROPIC_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "131fd44d-c0f8-473a-ae80-4b4668ad7f47", - "metadata": {}, - "source": [ - "## Simple Usage\n", - "\n", - "Let's look at very basic usage of this.\n", - "\n", - "Below, we do two things:\n", - "\n", - "1) We specify the [breakpoint](https://langchain-ai.github.io/langgraph/concepts/low_level/#breakpoints) using `interrupt_before` the specified step.\n", - "\n", - "2) We set up a [checkpointer](https://langchain-ai.github.io/langgraph/concepts/low_level/#checkpointer) to save the state of the graph." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "9b53f191-1e86-4881-a667-d46a3d66958b", + "execution_count": 16, + "id": "9a14c8b2-5c25-4201-93ea-e5358ee99bcb", "metadata": {}, "outputs": [ { "data": { - "image/jpeg": "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", + "image/png": "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", "text/plain": [ "" ] @@ -131,28 +219,36 @@ ], "source": [ "from typing_extensions import TypedDict\n", + "from IPython.display import Image, display\n", + "\n", "from langgraph.graph import StateGraph, START, END\n", "from langgraph.checkpoint.memory import MemorySaver\n", - "from IPython.display import Image, display\n", + "from langgraph.errors import NodeInterrupt\n", "\n", "\n", "class State(TypedDict):\n", " input: str\n", "\n", "\n", - "def step_1(state):\n", + "def step_1(state: State) -> State:\n", " print(\"---Step 1---\")\n", - " pass\n", + " return state\n", "\n", "\n", - "def step_2(state):\n", + "def step_2(state: State) -> State:\n", + " # Let's optionally raise a NodeInterrupt\n", + " # if the length of the input is longer than 5 characters\n", + " if len(state[\"input\"]) > 5:\n", + " raise NodeInterrupt(\n", + " f\"Received input that is longer than 5 characters: {state['input']}\"\n", + " )\n", " print(\"---Step 2---\")\n", - " pass\n", + " return state\n", "\n", "\n", - "def step_3(state):\n", + "def step_3(state: State) -> State:\n", " print(\"---Step 3---\")\n", - " pass\n", + " return state\n", "\n", "\n", "builder = StateGraph(State)\n", @@ -167,29 +263,92 @@ "# Set up memory\n", "memory = MemorySaver()\n", "\n", - "# Add\n", - "graph = builder.compile(checkpointer=memory, interrupt_before=[\"step_3\"])\n", + "# Compile the graph with memory\n", + "graph = builder.compile(checkpointer=memory)\n", "\n", "# View\n", "display(Image(graph.get_graph().draw_mermaid_png()))" ] }, { + "attachments": {}, "cell_type": "markdown", - "id": "d7d5f80f-9d8c-4a39-b198-24fe94132b41", + "id": "ef321c80-2677-4bb7-86a4-d2bd2439b4fb", "metadata": {}, "source": [ - "We create a [thread ID](https://langchain-ai.github.io/langgraph/concepts/low_level/#threads) for the checkpointer.\n", - "\n", - "We run until step 3, as defined with `interrupt_before`. \n", - "\n", - "After the user input / approval, [we resume execution](https://langchain-ai.github.io/langgraph/concepts/low_level/#breakpoints) by invoking the graph with `None`. " + "First, let's run the graph with an input that <= 5 characters long. This should safely ignore the interrupt condition we defined and return the original input at the end of the graph execution." ] }, { "cell_type": "code", - "execution_count": 7, - "id": "dfe04a7f-988e-4a36-8ce8-2c49fab0130a", + "execution_count": 17, + "id": "b2d281f1-3349-4378-8918-7665fa7a7457", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'input': 'hello'}\n", + "---Step 1---\n", + "{'input': 'hello'}\n", + "---Step 2---\n", + "{'input': 'hello'}\n", + "---Step 3---\n", + "{'input': 'hello'}\n" + ] + } + ], + "source": [ + "initial_input = {\"input\": \"hello\"}\n", + "thread_config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + "\n", + "for event in graph.stream(initial_input, thread_config, stream_mode=\"values\"):\n", + " print(event)" + ] + }, + { + "cell_type": "markdown", + "id": "2b66b926-47eb-401b-b37b-d80269d7214c", + "metadata": {}, + "source": [ + "If we inspect the graph at this point, we can see that there are no more tasks left to run and that the graph indeed finished execution." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "4eac1455-e7ef-4a32-8c14-0d5789409689", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "()\n", + "()\n" + ] + } + ], + "source": [ + "state = graph.get_state(thread_config)\n", + "print(state.next)\n", + "print(state.tasks)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "f8e03817-2135-4fb3-b881-fd6d2c378ccf", + "metadata": {}, + "source": [ + "Now, let's run the graph with an input that's longer than 5 characters. This should trigger the dynamic interrupt we defined via raising a `NodeInterrupt` error inside the `step_2` node." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "c06192ad-13a4-4d2e-8e30-f1c08578fe77", "metadata": {}, "outputs": [ { @@ -198,264 +357,193 @@ "text": [ "{'input': 'hello world'}\n", "---Step 1---\n", - "---Step 2---\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Do you want to go to Step 3? (yes/no): yes\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "---Step 3---\n" + "{'input': 'hello world'}\n", + "{'__interrupt__': (Interrupt(value='Received input that is longer than 5 characters: hello world', resumable=False, ns=None),)}\n" ] } ], "source": [ - "# Input\n", "initial_input = {\"input\": \"hello world\"}\n", - "\n", - "# Thread\n", - "thread = {\"configurable\": {\"thread_id\": \"1\"}}\n", + "thread_config = {\"configurable\": {\"thread_id\": \"2\"}}\n", "\n", "# Run the graph until the first interruption\n", - "for event in graph.stream(initial_input, thread, stream_mode=\"values\"):\n", - " print(event)\n", - "\n", - "try:\n", - " user_approval = input(\"Do you want to go to Step 3? (yes/no): \")\n", - "except:\n", - " user_approval = \"yes\"\n", - "\n", - "if user_approval.lower() == \"yes\":\n", - " # If approved, continue the graph execution\n", - " for event in graph.stream(None, thread, stream_mode=\"values\"):\n", - " print(event)\n", - "else:\n", - " print(\"Operation cancelled by user.\")" + "for event in graph.stream(initial_input, thread_config, stream_mode=\"values\"):\n", + " print(event)" ] }, { "cell_type": "markdown", - "id": "3333b771", + "id": "173fd4f1-db97-44bb-a9e5-435ed042e3a3", "metadata": {}, "source": [ - "## Agent\n", - "\n", - "In the context of agents, breakpoints are useful to manually approve certain agent actions.\n", - " \n", - "To show this, we will build a relatively simple ReAct-style agent that does tool calling. \n", - "\n", - "We'll add a breakpoint before the `action` node is called. " + "We can see that the graph now stopped while executing `step_2`. If we inspect the graph state at this point, we can see the information on what node is set to execute next (`step_2`), as well as what node raised the interrupt (also `step_2`), and additional information about the interrupt." ] }, { "cell_type": "code", - "execution_count": 2, - "id": "6098e5cb", + "execution_count": 20, + "id": "2058593c-178e-4a23-a4c4-860d4a9c2198", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('step_2',)\n", + "(PregelTask(id='bfc767e3-a6c4-c5af-dbbf-0d20ea64501e', name='step_2', path=('__pregel_pull', 'step_2'), error=None, interrupts=(Interrupt(value='Received input that is longer than 5 characters: hello world', resumable=False, ns=None),), state=None, result=None),)\n" + ] + } + ], + "source": [ + "state = graph.get_state(thread_config)\n", + "print(state.next)\n", + "print(state.tasks)" + ] + }, + { + "cell_type": "markdown", + "id": "fc36d1be-ae2e-49c8-a17f-2b27be09618a", + "metadata": {}, + "source": [ + "If we try to resume the graph from the breakpoint, we will simply interrupt again as our inputs & graph state haven't changed." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "872e7a69-9784-4f81-90c6-6b6af2fa6480", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'input': 'hello world'}\n", + "{'__interrupt__': (Interrupt(value='Received input that is longer than 5 characters: hello world', resumable=False, ns=None),)}\n" + ] + } + ], + "source": [ + "# NOTE: to resume the graph from a dynamic interrupt we use the same syntax as with regular interrupts -- we pass None as the input\n", + "for event in graph.stream(None, thread_config, stream_mode=\"values\"):\n", + " print(event)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "3275f899-7039-4029-8814-0bb5c33fabfe", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('step_2',)\n", + "(PregelTask(id='bfc767e3-a6c4-c5af-dbbf-0d20ea64501e', name='step_2', path=('__pregel_pull', 'step_2'), error=None, interrupts=(Interrupt(value='Received input that is longer than 5 characters: hello world', resumable=False, ns=None),), state=None, result=None),)\n" + ] + } + ], + "source": [ + "state = graph.get_state(thread_config)\n", + "print(state.next)\n", + "print(state.tasks)" + ] + }, + { + "cell_type": "markdown", + "id": "f2000f6c-029e-4c0a-8db5-7504dc185d01", + "metadata": {}, + "source": [ + "
" + ] + }, + { + "cell_type": "markdown", + "id": "4eb3ebb1-cf26-4082-977e-796eadb6f654", + "metadata": {}, + "source": [ + "## Use with subgraphs\n", + "\n", + "To add breakpoints to subgraph either:\n", + "\n", + "* Define [static breakpoints](#static-breakpoints) by specifying them when **compiling** the subgraph.\n", + "* Define [dynamic breakpoints](#dynamic-breakpoints).\n", + "\n", + "\n", + "
Add breakpoints to subgraphs" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "3c3edfe3-4633-46d2-9723-db7f7be28830", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StateSnapshot(values={'foo': ''}, next=('subgraph_node_1',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': 'node_1:dfc321bb-7c91-ccfe-23b8-c2374ae3f1cc', 'checkpoint_id': '1f02a8d1-985a-6e2c-8000-77034088c0ce', 'checkpoint_map': {'': '1f02a8d1-9856-6264-8000-ed1534455427', 'node_1:dfc321bb-7c91-ccfe-23b8-c2374ae3f1cc': '1f02a8d1-985a-6e2c-8000-77034088c0ce'}}}, metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {'': '1f02a8d1-9856-6264-8000-ed1534455427'}, 'thread_id': '1', 'langgraph_step': 1, 'langgraph_node': 'node_1', 'langgraph_triggers': ['branch:to:node_1'], 'langgraph_path': ['__pregel_pull', 'node_1'], 'langgraph_checkpoint_ns': 'node_1:dfc321bb-7c91-ccfe-23b8-c2374ae3f1cc'}, created_at='2025-05-06T15:16:35.543192+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': 'node_1:dfc321bb-7c91-ccfe-23b8-c2374ae3f1cc', 'checkpoint_id': '1f02a8d1-9859-6d41-bfff-872b2e8f4db6', 'checkpoint_map': {'': '1f02a8d1-9856-6264-8000-ed1534455427', 'node_1:dfc321bb-7c91-ccfe-23b8-c2374ae3f1cc': '1f02a8d1-9859-6d41-bfff-872b2e8f4db6'}}}, tasks=(PregelTask(id='33218e09-8747-5161-12b1-5dc705d30b51', name='subgraph_node_1', path=('__pregel_pull', 'subgraph_node_1'), error=None, interrupts=(), state=None, result=None),), interrupts=())\n" + ] + }, { "data": { - "image/jpeg": "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", "text/plain": [ - "" + "{'foo': ''}" ] }, + "execution_count": 21, "metadata": {}, - "output_type": "display_data" + "output_type": "execute_result" } ], "source": [ - "# Set up the tool\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.tools import tool\n", - "from langgraph.graph import MessagesState, START\n", - "from langgraph.prebuilt import ToolNode\n", - "from langgraph.graph import END, StateGraph\n", - "from langgraph.checkpoint.memory import MemorySaver\n", + "from typing_extensions import TypedDict\n", + "\n", + "from langgraph.graph import START, StateGraph\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "from langgraph.types import interrupt\n", "\n", "\n", - "@tool\n", - "def search(query: str):\n", - " \"\"\"Call to surf the web.\"\"\"\n", - " # This is a placeholder for the actual implementation\n", - " # Don't let the LLM know this though 😊\n", - " return [\n", - " \"It's sunny in San Francisco, but you better look out if you're a Gemini 😈.\"\n", - " ]\n", + "class State(TypedDict):\n", + " foo: str\n", "\n", "\n", - "tools = [search]\n", - "tool_node = ToolNode(tools)\n", - "\n", - "# Set up the model\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", - "model = model.bind_tools(tools)\n", + "def subgraph_node_1(state: State):\n", + " return {\"foo\": state[\"foo\"]}\n", "\n", "\n", - "# Define nodes and conditional edges\n", + "subgraph_builder = StateGraph(State)\n", + "subgraph_builder.add_node(subgraph_node_1)\n", + "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", "\n", + "subgraph = subgraph_builder.compile(interrupt_before=[\"subgraph_node_1\"])\n", "\n", - "# Define the function that determines whether to continue or not\n", - "def should_continue(state):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return \"end\"\n", - " # Otherwise if there is, we continue\n", - " else:\n", - " return \"continue\"\n", + "builder = StateGraph(State)\n", + "builder.add_node(\"node_1\", subgraph) # directly include subgraph as a node\n", + "builder.add_edge(START, \"node_1\")\n", "\n", + "checkpointer = InMemorySaver()\n", + "graph = builder.compile(checkpointer=checkpointer)\n", "\n", - "# Define the function that calls the model\n", - "def call_model(state):\n", - " messages = state[\"messages\"]\n", - " response = model.invoke(messages)\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": [response]}\n", + "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", "\n", + "graph.invoke({\"foo\": \"\"}, config)\n", "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", + "# Fetch state including subgraph state.\n", + "print(graph.get_state(config, subgraphs=True).tasks[0].state)\n", "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " # Finally we pass in a mapping.\n", - " # The keys are strings, and the values are other nodes.\n", - " # END is a special node marking that the graph should finish.\n", - " # What will happen is we will call `should_continue`, and then the output of that\n", - " # will be matched against the keys in this mapping.\n", - " # Based on which one it matches, that node will then be called.\n", - " {\n", - " # If `tools`, then we call the tool node.\n", - " \"continue\": \"action\",\n", - " # Otherwise we finish.\n", - " \"end\": END,\n", - " },\n", - ")\n", - "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")\n", - "\n", - "# Set up memory\n", - "memory = MemorySaver()\n", - "\n", - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", - "\n", - "# We add in `interrupt_before=[\"action\"]`\n", - "# This will add a breakpoint before the `action` node is called\n", - "app = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])\n", - "\n", - "display(Image(app.get_graph().draw_mermaid_png()))" + "# resume the subgraph\n", + "graph.invoke(None, config)" ] }, { "cell_type": "markdown", - "id": "2a1b56c5-bd61-4192-8bdb-458a1e9f0159", + "id": "e509da54-8805-4a54-a07c-1b7805fa6b95", "metadata": {}, "source": [ - "## Interacting with the Agent\n", - "\n", - "We can now interact with the agent.\n", - "\n", - "We see that it stops before calling a tool, because `interrupt_before` is set before the `action` node." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "cfd140f0-a5a6-4697-8115-322242f197b5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "search for the weather in sf now\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'll search for the current weather in San Francisco for you. Let me use the search function to find this information.\", 'type': 'text'}, {'text': None, 'type': 'tool_use', 'id': 'toolu_011ezBx5hKKjVJwqnECNPyyC', 'name': 'search', 'input': {'query': 'current weather in San Francisco'}}]\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "thread = {\"configurable\": {\"thread_id\": \"3\"}}\n", - "inputs = [HumanMessage(content=\"search for the weather in sf now\")]\n", - "for event in app.stream({\"messages\": inputs}, thread, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "1bca3814-db08-4b0b-8c0c-95b6c5440c81", - "metadata": {}, - "source": [ - "**Resume**\n", - "\n", - "We can now call the agent again with no inputs to continue.\n", - "\n", - "This will run the tool as requested.\n", - "\n", - "Running an interrupted graph with `None` in the inputs means to `proceed as if the interruption didn't occur.`" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "51923913-20f7-4ee1-b9ba-d01f5fb2869b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: search\n", - "\n", - "[\"It's sunny in San Francisco, but you better look out if you're a Gemini \\ud83d\\ude08.\"]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Based on the search results, I can provide you with information about the current weather in San Francisco:\n", - "\n", - "The weather in San Francisco right now is sunny. \n", - "\n", - "It's worth noting that the search result includes a playful reference to astrology, suggesting that Geminis should \"look out.\" However, this is likely just a humorous addition and not related to the actual weather conditions.\n", - "\n", - "Is there anything else you'd like to know about the weather in San Francisco or any other location?\n" - ] - } - ], - "source": [ - "for event in app.stream(None, thread, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" + "
" ] } ], diff --git a/docs/docs/how-tos/human_in_the_loop/dynamic_breakpoints.ipynb b/docs/docs/how-tos/human_in_the_loop/dynamic_breakpoints.ipynb deleted file mode 100644 index 28893dda7..000000000 --- a/docs/docs/how-tos/human_in_the_loop/dynamic_breakpoints.ipynb +++ /dev/null @@ -1,446 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "b7d5f6a5-9e59-43e4-a4b6-8ada6dace691", - "metadata": {}, - "source": [ - "# How to add dynamic breakpoints with `NodeInterrupt`\n", - "\n", - "!!! note\n", - "\n", - " For **human-in-the-loop** workflows use the new [`interrupt()`](../../../reference/types/#langgraph.types.interrupt) function for **human-in-the-loop** workflows. Please review the [Human-in-the-loop conceptual guide](../../../concepts/human_in_the_loop) for more information about design patterns with `interrupt`.\n", - "\n", - "!!! tip \"Prerequisites\"\n", - "\n", - " This guide assumes familiarity with the following concepts:\n", - "\n", - " * [Breakpoints](../../../concepts/breakpoints)\n", - " * [LangGraph Glossary](../../../concepts/low_level)\n", - " \n", - "\n", - "Human-in-the-loop (HIL) interactions are crucial for [agentic systems](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#human-in-the-loop). [Breakpoints](https://langchain-ai.github.io/langgraph/concepts/low_level/#breakpoints) are a common HIL interaction pattern, allowing the graph to stop at specific steps and seek human approval before proceeding (e.g., for sensitive actions).\n", - "\n", - "In LangGraph you can add breakpoints before / after a node is executed. But oftentimes it may be helpful to **dynamically** interrupt the graph from inside a given node based on some condition. When doing so, it may also be helpful to include information about **why** that interrupt was raised.\n", - "\n", - "This guide shows how you can dynamically interrupt the graph using `NodeInterrupt` -- a special exception that can be raised from inside a node. Let's see it in action!\n", - "\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "2013d058-c245-498e-ba05-5af99b9b8a1b", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "d9f9574b", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "e9aa244f-1dd9-450e-9526-b1a28b30f84f", - "metadata": {}, - "source": [ - "## Define the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "9a14c8b2-5c25-4201-93ea-e5358ee99bcb", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from typing_extensions import TypedDict\n", - "from IPython.display import Image, display\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.errors import NodeInterrupt\n", - "\n", - "\n", - "class State(TypedDict):\n", - " input: str\n", - "\n", - "\n", - "def step_1(state: State) -> State:\n", - " print(\"---Step 1---\")\n", - " return state\n", - "\n", - "\n", - "def step_2(state: State) -> State:\n", - " # Let's optionally raise a NodeInterrupt\n", - " # if the length of the input is longer than 5 characters\n", - " if len(state[\"input\"]) > 5:\n", - " raise NodeInterrupt(\n", - " f\"Received input that is longer than 5 characters: {state['input']}\"\n", - " )\n", - "\n", - " print(\"---Step 2---\")\n", - " return state\n", - "\n", - "\n", - "def step_3(state: State) -> State:\n", - " print(\"---Step 3---\")\n", - " return state\n", - "\n", - "\n", - "builder = StateGraph(State)\n", - "builder.add_node(\"step_1\", step_1)\n", - "builder.add_node(\"step_2\", step_2)\n", - "builder.add_node(\"step_3\", step_3)\n", - "builder.add_edge(START, \"step_1\")\n", - "builder.add_edge(\"step_1\", \"step_2\")\n", - "builder.add_edge(\"step_2\", \"step_3\")\n", - "builder.add_edge(\"step_3\", END)\n", - "\n", - "# Set up memory\n", - "memory = MemorySaver()\n", - "\n", - "# Compile the graph with memory\n", - "graph = builder.compile(checkpointer=memory)\n", - "\n", - "# View\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "ad5521e1-0e58-42c5-9282-ff96f24ee6f6", - "metadata": {}, - "source": [ - "## Run the graph with dynamic interrupt" - ] - }, - { - "cell_type": "markdown", - "id": "83692c63-5c65-4562-9c65-5ad1935e339f", - "metadata": {}, - "source": [ - "First, let's run the graph with an input that <= 5 characters long. This should safely ignore the interrupt condition we defined and return the original input at the end of the graph execution." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "b2d281f1-3349-4378-8918-7665fa7a7457", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'input': 'hello'}\n", - "---Step 1---\n", - "{'input': 'hello'}\n", - "---Step 2---\n", - "{'input': 'hello'}\n", - "---Step 3---\n", - "{'input': 'hello'}\n" - ] - } - ], - "source": [ - "initial_input = {\"input\": \"hello\"}\n", - "thread_config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "\n", - "for event in graph.stream(initial_input, thread_config, stream_mode=\"values\"):\n", - " print(event)" - ] - }, - { - "cell_type": "markdown", - "id": "2b66b926-47eb-401b-b37b-d80269d7214c", - "metadata": {}, - "source": [ - "If we inspect the graph at this point, we can see that there are no more tasks left to run and that the graph indeed finished execution." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "4eac1455-e7ef-4a32-8c14-0d5789409689", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "()\n", - "()\n" - ] - } - ], - "source": [ - "state = graph.get_state(thread_config)\n", - "print(state.next)\n", - "print(state.tasks)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "f8e03817-2135-4fb3-b881-fd6d2c378ccf", - "metadata": {}, - "source": [ - "Now, let's run the graph with an input that's longer than 5 characters. This should trigger the dynamic interrupt we defined via raising a `NodeInterrupt` error inside the `step_2` node." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c06192ad-13a4-4d2e-8e30-f1c08578fe77", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'input': 'hello world'}\n", - "---Step 1---\n", - "{'input': 'hello world'}\n" - ] - } - ], - "source": [ - "initial_input = {\"input\": \"hello world\"}\n", - "thread_config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "\n", - "# Run the graph until the first interruption\n", - "for event in graph.stream(initial_input, thread_config, stream_mode=\"values\"):\n", - " print(event)" - ] - }, - { - "cell_type": "markdown", - "id": "173fd4f1-db97-44bb-a9e5-435ed042e3a3", - "metadata": {}, - "source": [ - "We can see that the graph now stopped while executing `step_2`. If we inspect the graph state at this point, we can see the information on what node is set to execute next (`step_2`), as well as what node raised the interrupt (also `step_2`), and additional information about the interrupt." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "2058593c-178e-4a23-a4c4-860d4a9c2198", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "('step_2',)\n", - "(PregelTask(id='365d4518-bcff-5abd-8ef5-8a0de7f510b0', name='step_2', error=None, interrupts=(Interrupt(value='Received input that is longer than 5 characters: hello world', when='during'),)),)\n" - ] - } - ], - "source": [ - "state = graph.get_state(thread_config)\n", - "print(state.next)\n", - "print(state.tasks)" - ] - }, - { - "cell_type": "markdown", - "id": "fc36d1be-ae2e-49c8-a17f-2b27be09618a", - "metadata": {}, - "source": [ - "If we try to resume the graph from the breakpoint, we will simply interrupt again as our inputs & graph state haven't changed." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "872e7a69-9784-4f81-90c6-6b6af2fa6480", - "metadata": {}, - "outputs": [], - "source": [ - "# NOTE: to resume the graph from a dynamic interrupt we use the same syntax as with regular interrupts -- we pass None as the input\n", - "for event in graph.stream(None, thread_config, stream_mode=\"values\"):\n", - " print(event)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "3275f899-7039-4029-8814-0bb5c33fabfe", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "('step_2',)\n", - "(PregelTask(id='365d4518-bcff-5abd-8ef5-8a0de7f510b0', name='step_2', error=None, interrupts=(Interrupt(value='Received input that is longer than 5 characters: hello world', when='during'),)),)\n" - ] - } - ], - "source": [ - "state = graph.get_state(thread_config)\n", - "print(state.next)\n", - "print(state.tasks)" - ] - }, - { - "cell_type": "markdown", - "id": "a5862dea-2af2-48cb-9889-979b6c6af6aa", - "metadata": {}, - "source": [ - "## Update the graph state" - ] - }, - { - "cell_type": "markdown", - "id": "c8724ef6-877a-44b9-b96a-ae81efa2d9e4", - "metadata": {}, - "source": [ - "To get around it, we can do several things. \n", - "\n", - "First, we could simply run the graph on a different thread with a shorter input, like we did in the beginning. Alternatively, if we want to resume the graph execution from the breakpoint, we can update the state to have an input that's shorter than 5 characters (the condition for our interrupt)." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "2ba8dc8d-b90e-45f5-92cd-2192fc66f270", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "---Step 2---\n", - "{'input': 'foo'}\n", - "---Step 3---\n", - "{'input': 'foo'}\n", - "()\n", - "{'input': 'foo'}\n" - ] - } - ], - "source": [ - "# NOTE: this update will be applied as of the last successful node before the interrupt, i.e. `step_1`, right before the node with an interrupt\n", - "graph.update_state(config=thread_config, values={\"input\": \"foo\"})\n", - "for event in graph.stream(None, thread_config, stream_mode=\"values\"):\n", - " print(event)\n", - "\n", - "state = graph.get_state(thread_config)\n", - "print(state.next)\n", - "print(state.values)" - ] - }, - { - "cell_type": "markdown", - "id": "6f16980e-aef4-45c9-85eb-955568a93c5b", - "metadata": {}, - "source": [ - "You can also update the state **as node `step_2`** (interrupted node) which would skip over that node altogether" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "9a48e564-d979-4ac2-b815-c667345a9f07", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'input': 'hello world'}\n", - "---Step 1---\n", - "{'input': 'hello world'}\n" - ] - } - ], - "source": [ - "initial_input = {\"input\": \"hello world\"}\n", - "thread_config = {\"configurable\": {\"thread_id\": \"3\"}}\n", - "\n", - "# Run the graph until the first interruption\n", - "for event in graph.stream(initial_input, thread_config, stream_mode=\"values\"):\n", - " print(event)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "17f973ab-00ce-4f16-a452-641e76625fde", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "---Step 3---\n", - "{'input': 'hello world'}\n", - "()\n", - "{'input': 'hello world'}\n" - ] - } - ], - "source": [ - "# NOTE: this update will skip the node `step_2` altogether\n", - "graph.update_state(config=thread_config, values=None, as_node=\"step_2\")\n", - "for event in graph.stream(None, thread_config, stream_mode=\"values\"):\n", - " print(event)\n", - "\n", - "state = graph.get_state(thread_config)\n", - "print(state.next)\n", - "print(state.values)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/human_in_the_loop/edit-graph-state.ipynb b/docs/docs/how-tos/human_in_the_loop/edit-graph-state.ipynb deleted file mode 100644 index 35b5f6c41..000000000 --- a/docs/docs/how-tos/human_in_the_loop/edit-graph-state.ipynb +++ /dev/null @@ -1,568 +0,0 @@ -{ - "cells": [ - { - "attachments": { - "1a5388fe-fa93-4607-a009-d71fe2223f5a.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAB8cAAAWwCAYAAADAIUCbAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQmcTeUbx58x+zAztkEopVBJQqEsbeYv2SJS1uypECktlKIkW1LZtyylRFFUiEgohRKVlCJjxjbGmBnGzPw/v5dzO/fMufu5M3dmfs/nM5+Zufc97/J9zz33nPf3Ps8TlJOTkyM0EiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEijEBIIojhfi2eXQSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEFAGK4zwRSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAECj0BiuOFfoo5QBIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAYrjPAdIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAQKPQGK44V+ijlAEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABiuM8B0iABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABAo9AYrjhX6KOUASIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAGK4zwHSIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAECj0BiuOFfoo5QBIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAYrjPAdIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIgAQKPQGK44V+ijlAEiABEiABEiABEghMAud27pRz+/ZJaOXKEnbDDRJcunRgdpS9ckkgdeVKOT1rlgSFhEhMz55SolUrkWLFXB7HAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiSQlwQojuclbbZFAiRAAiRAAiRAAiRgI3B85Eg5+9lndkTCataUsBo1JKxaNYmoX19Cr7qKxAKcQOaBA3KkY0e7XkbFx0vZ0aMlKCwswHvP7pEACZAACZAACZAACZAACZAACZAACZAACRQl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S3rsMZXXW2/YpFAeXu6GfOfuTDXCpmcdO+Y4B7wH40saPFjSN2+WUkOGSEy3bu40zzIFkMAjjzwia9askQ8//FDq169vyQjy8nvG2OGcnBzJysqyTOi3BAgrIQESIAESIAESIAESIAESIAESIAESyEWA4jhPChIgARIgARIggVwEXnjhBVmwYIH07dtXRlzKl+wrpoULF9rq+vLLL6VGjRq+Vml6PMLqQnT54osvZPDgwTJ06FC/tMNKfSMAj/CkRx+VzL//dllRVHy8xDz4oITXqWMrC/EUonjEpXDsZpVooc/xHo5F7m0I2ReOHBGIxqgDBs9veIAj1HnO+fMSHBdn3qesLCXMh9WoIUEREaqsUZjHuDL375eI226ToJAQm+d4+VmzJAIbNbKzlde4ErodiNDYEJCTlqY8utGOI8tOTpZiJUu65AdPcWw20BsE+MRevdTmA3icl7jvPineqpUKO++NgQU2GxSLiXF5uKvxYVzIO168bVu1UYFWOAnceeed8ueff8rs2bMlPj7ekkHm1feM1tkTJ07IrFmz5OOPP5aEhAT1crVq1aRfv37ywAMPWDImVkICJEACJEACJEACJEACJEACJEACJGAtAYrj1vJkbSRAAiRAAiRQYAhgIf/xxx+Xrl27Srt27ez6jYV9iMsQyO+44w5LxjR69GglgsA+//xzue666yyp11jJ1KlTZcKECepliuN+QWxppRBKIYbmpKdLdnq6+h0UGSnBsbFSDD/R0V55MqtO5uRIysKFcuqNNxz2GXmySz7xhMoj7g/TwqpXmDPHTtz3R1ue1olc70qEj4319FCWJwG3CMCTe/LkyTJq1CipVauW3TFVqlRR///0008Sa9E5mFffM+g3wsJ369bNJoobgTz99NPy2GOPucWJhUiABEiABEiABEiABEiABEiABEiABPKOAMXxvGPNlkiABEiABEggoAgglC3CphcvXlz27t1r17cmTZrIP//8Y6lo0aNHD9m4caNqZ/v27VKhQgXLeWzbtk06depkq5fiuOWIC2SFWadOSdq6dZL5119KDEYY89Bq1ZQntzuezr4MOvmtt+T03LlSbvJkibz9dl+q4rEkUOAIPPnkk7Js2TJp2bKlvPPOO7b+JyYmqlDq2CSFzVJWWV58z2h97dixo0oRAhszZow0atRIzp07J6+99prtu2737t1S0p3oDlYBYD0kQAIkQAIkQAIkQAIkQAIkQAIkQAIuCVAcd4mIBUiABEiABEigcBLQ8opjdD/++KOUQZ5nETl+/LjK043/8bpV1qZNG4FQADtw4IBf8rL27NlTvvrqK1uXKY5bNXusx1sCZz74QE6+9pqUfu45ie7QwdtqeBwJFEgCjz76qHz22Wcq1Pi6detsY4Ag3r9/f+nQoYNMnDjRsrHlxfeM1llNHO/du7cgFYlmaWlptsgo/oySYhk0VkQCJEACJEACJEACJEACJEACJEACRYwAxfEiNuEcLgmQAAmQAAloBJ555hl577331L8rV66U2rVrq78hYGCx30y0QD7vgwcPSmhoqFx22WUeCdz33HOP7Nu3T7WD9ox24cIF2bRpkxw+fFgJCzfddJNqxxPLysqS1NRUmT9/vkyaNIlh1T2Bx7J+IZC+ZYskDRwoEQ0bSnmd56xfGmOlJBBgBBo2bGgLO/7XX39JsWLFVA/haY1c3UiBAZFZb4H+PaP1Fd+FEP5bt24tV1xxhW0Ihw4dksaNG6v/169fL9dcc02AzQq7QwIkQAIkQAIkQAIkQAIkQAIkQAJFmwDF8aI9/xw9CZAACZBAESUAEfmWW26REydOKALTpk2Te++9V/2N3LDz5s2TN954w5aLHCHWkTcWecjPnj2rysGz/MEHH5Tu3bvbhUjPyclRgsD333+vQra3b99eKleuLFqo9meffVYeeeQRO/IITfvcc8+pHK6aQXxfunSpaHlpPZkqTXgZOnSoEshpJJBfBHIyMuSf225TzVdauVJCKlfOr66wXRLIUwJ//vmn3HnnnbY28Z1Qrlw59T9ex/tbtmxR3w+wgvY94wjm7NmzBbnP8f2HfOohISF5yp2NkQAJkAAJkAAJkAAJkAAJkAAJkAAJOCdAcZxnCAmQAAmQAAkUQQIQo/XeeiNGjJC+ffsKvLdvvPFGJYBv3bpVKlasKPrw60CFBX+8rgnZEMkXLFggtWrVUvlWEUZXHz4X5Xfs2KE86SDG673UUR/agciu1d2sWTN1PPoAYR2ivKcGAX7JkiXy/PPPS79+/Tw9nOVJwFICx0eMkLOrV0v52bMlom5dS+tmZSQQqASmTp2qPMM1++STT1REEEQQQSQRbIDatm2bersgfs+YccfmsFatWsmePXty5VkP1Hliv0iABEiABEiABEiABEiABEiABEigqBGgOF7UZpzjJQESIAESIAERlR8VgrZmEKTnzJmjwpp369ZNhTVHrlSY5vGNv7HoP378eImKipKkpCR55513lJc5DB6ACxculOnTp6v/4R1eokQJlV8cgsiLL76oXl+2bJnyWodBLEf9mhA+btw4CQsLk7lz58pLL72UK0+tu5M3aNAggRDzyiuvSNeuXd09jOVIwC8EslNSJH3rVikeHy9yKay0XxpipSQQQAQ073CtSyNHjpQ+ffqo75C33npLbcjCxqyC+j1jhnr16tUyYMAA9dby5culXr16ATQj7AoJkAAJkAAJkAAJkAAJkAAJkAAJkAAIUBzneUACJEACJEACRYyA3jt88eLF0qVLF0UA4V+feOIJ+eqrr5Qw/fDDD6vX77//fuX5/b///U9mzJhhyxmrYYN39qJFi2TIkCE2L++ZM2dK8+bNVRG0Fx8fr0LowgYOHCjDhg1Tf+tFeniY161bV+UZRx9gEFIgqHhqEF2+/PJL03y2ntbF8iRAAiRAAp4R+OWXX1SqjmrVqkmPHj2UCF67dm1577331IYobIyCkFyzZs0C+z1z+vRp+eijj+SHH36Q1NRUNQ6EjsdmrxtuuEFt0GJIdc/OG5YmARIgARIgARIgARIgARIgARIggbwgQHE8LyizDRIgARIgARIIIALbt2+XBx54QOrXry8ffvihLfcrhIvdu3ernmKxv2zZsnaiBbzEW7ZsmWskmpc2PLQhkletWlU2bNigymVnZyvvbeRg1eyKK66Qr7/+Wr139dVXq5c7deqk8ovrDWHf4W0eHR3tMT30ZfPmzXZ50z2uhAeQAAmQAAl4RUALqT506FCVNgPfNzDtewaiuT79hrYJq6B8zyQnJ6txIUS8I0PKkWeeeUalMAkKCvKKIw8iARIgARIgARIgARIgARIgARIgARKwngDFceuZskYSIAESIAESCGgCCHs+duxYefnll5VH35tvvikTJ0609Rke4rNmzbL9/9hjj8mnn36qBHWEPS92KSz08ePHleg9bdo0gQiAOpHfGx5zKJ+RkSFPPvmkfPbZZ6ouhJh99dVXlRc6hHCEXIfYfvPNNyvvu8TERJV/Fl53derUUaHdvTVNaEHo3tatW3tbDY8jARIgARLwgkD37t3VJijNOxwboLT84qhOH50E/xe07xl9jnRsAECOcUQrMTOk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bdVCWTt/gqSdSVbC+LvvvisV+TmylDErIwESIAESIAESIAESIAESIAESIIFAI+B3cfzChQuSkpIiJUqUkLCwML+P/9y5c3LmzBnVHsLk0UiABEiABEiABHwnMHv2bBk9erStooply8ojbdtKj3vu8b1ykxr2Hz6sBPI127apdy+//HKZNGmS1K9f3y/tsVIS8IVA6vLlcuKSKF6ibVsp8+KLvlTn9NjMgwclsX9/yTp2zFYuomFDKf/OO35rkxWTQF4S6N6jh3x9KYLIFdfVlcb395FaTVv6rQsJB/bK4jED5MS/B6VBgwYCj/XwcPfCtPutU6yYBEiABEiABEiABEiABEiABEiABEjAbwQsF8dTU1Nl3bp18tlnn8kPP/xg8y7r27evjBgxwm8D0Speu3at9OnTR/1bvHhxqV69urRs2VLuuecetbBOIwESIAESIAES8IwAvPfgxacZBHEI4xDI/W2vL1kib18K4R4VFSWTJ09W3+k0Egg0AnqBPLpDByn93HOWdzHnwgVJeOABgUCuWXCZMlJ57VrL22KFJJDXBM6fPy/3tGgpB/74XUqWqyi3dxogDVt3z5NuIBf5whf7SMqJRLnn3lYyY9rbedIuGyEBEiABEiABEiABEiABEiABEiABEsh7ApaK4xDER44caRduVRvSsGHDZODAgX4f4e7du6VNmzam7aD9xx57TCIjI/3ej/xu4PTp07J69WqJi4uTO+64Q0JCQvK7S4W6/fT0dEm+FP4XAwV3MndvyhFZ4uzZs7bCpUqVKrJRH7ChaNeuXUr4q1SpknsAWYoE/Ezgq6++kt69e0t2drZUq1xZXuzZU5rceKOfW7Wvftg778iHGzaoFytXrixLly5Vv2kkEGgEzn76qRx/4QXVreiHHpLSTz1laRePdu8u5/bssdUZFBkpV2zZYmkbrIwE8oPA/v375dFHH5Xff/9dYuMuk+4vz5GKV9fM0678+dM2WfhiX8k4myJde/SUV14elaftszESIIGiR+DYsWOCaIswRD7EszCNBEjAOgJZWVmSlJRkqzAmJkY5UtFcE0Bk1pMnT9oKghv4FUXjWp3zWS8Ma+JYmz548KD6geNnmTJlbD9XXXVVUTztOWYnBBITE9UaKSwoKEgqVKhAXgWUgCXieE5OjowaNUrmz5/vEANyhXbs2NHvmHByOgu5et1116lF9djYWL/3Jb8a+PXXX6V58+a25qtWraq8+YODg/OrS4W+3aefflqdV5phY0LNmnm7oFdQIY8fP17eeustW/fnzp0rd999d0Edjtf9HjJkiCxfvtx2PPI6O9ro43UjPJAEPCSAzRp9eveWY8ePK2H8naFDpXo+RGHJys6WnmPHyte7dqkRdOjQQSZOnOjhaFicBPKGQOrKlXJi1EVRrdSgQRLz8MOWNJz46KOScSnNACoMqVRJKq1aZUndrIQE8puAlmM8LLK4dH9ptlx902350qVft38li17qJ1kXMmXs2LHSuXPnfOkHGyWBwkQgLS1N8FM2DyIOFSRuhw4dksaNG9u6jDWcmTNnFqQhsK8kEPAEVqxYIU888YStny+//LL06NEj4PsdCB3ctGmTdOvWzdaV/v37y3N+iIwVCGN11geu1bmeoYK8Jo4IxHD0TEhIMB0oNoXs3bvXNQSWKFIErr/+ejtHv7///rtQjD8zM1M5PcPhs6jct1sijr/++uvy9tu5Q89BlEXetnr16imxq3Tp0i5PFAi7q1atki1btth2YOCgJUuWqDzirgy7AiEE79y5U7Zt26Z+G61OnTqqPoRnzUuDAPjll1+qJkuWLCkQAZ15F+PiDE942NVXX61CybpjOO7dd9+1K7pgwQLlQe6OYefLv//+ayuKjQRFdXegO7xQZtCgQfLJJ5/YilMcd5ecCMVxUTdhDRs2tINWu3ZtWblypfsgLS6JjUYIbwpD3s1y5cpZ3AKrC3QC2Cnevn172bNnjwqfvuC55/JFGNc4/XvsmPR67TX59Z9/1EsQxyGS00ggEAmkLFokpyZNUl0rO3q0FG/pW77kY08/LWnr1tmGGl6rllRYsCAQh84+uUEgbe1ayfzzT4lo1EjCb7jBjSMKd5GNGzfaFqq7jJwmNzS5N18HvOPzpfLRpKflyurXy6qPlvI5KF9ng40XRAI//fSTbN68WS0m4+9/Lt27YYG5bt26ggVFbCS/9957JTQ0tCAO0ZI+HzhwQO666y5bXUVFHOd6kyWnT0BWAu/R48eP2/qGNQSsJeSnvf/++zJ8+HBbFyiOuz8bFMe5Vufu2VIQ18QRcRf6iX4t32y8cLL8/PPP3UXBck4IfPjhh7Jw4UK7ElOmTBFHnvl6XaxRo0Z21/L8Bl1YxHE4PG/fvl1psWvWrLGLBq7dt992223Ss2fPQhuJ22dxHAJ0p06dcp2T8KI1ij2OTlwIQwjJvmzZMtm3b59pMYjEEJQ9NYTP6d69e656BwwYIM8884yn1flUHu299957tjowVmcC/UMPPSTffvutKu/JTiWEjv/0009zXWzuu+8+t/qPUCK1atWylb355psF+WZpjgkUxBuBQJlPiuOiQojGx8fbTclll12mNvjkl7Vs2VKJopq5ul7lVz/Zrv8IYEMXPp+wl3v3FuQZz2/75JtvZNCUKaobDK+e37PB9l0RSJ42TU7PmqWKlZ8+XSLq13d1iOn7p6ZMkRSdEB5x881Snp5lXrEMlINOjhsnZy5FHCoWGyuREMnr1JGI2rUl9JprAqWbedYPeHBBIL/5nk5y/9DX86xdZw29+0Jv2bdtnXTs1ksmjHkxIPpUmDuBtQBs7sZzJ8RCLETm9Ub2wsw3r8aG8OCIfvXGG2+41eQVV1whb775psB5oShaURXHud5UeM92pOPCArpm8LjVe23nx8gpjntPneI41+rcPXsK4pr4888/L4sWLXI5xKKycc0lCAsKvPPOOzJu3Di7mh555BF59tlnTWvX62KBpk0VBnH8zz//FHwONO3R2RTjnh3393CALmzmkziOhx/kxkWOOM0g4mIniLshpR2J60bQ3orjqAc333379s0lNK1fv16uycMFqLwSx+F1rw8BiDlBfhR3c60bH1ZuuOEGtXmB5phAQbwRCJT5pDh+cSbuv/9+2bFjh21acHOAm4T8MqM4DqE8Ojo6v7rDdvOYAG6S2rVrJ8nJySq/+KKRI/O4B46bGzBxoqy+tHEEm99Gjx4dMH1jR0jASODk66/LmfffVy9D0Iaw7Ymd+egjOfnKK7ZDKIx7Qi9wy2afOSNnV6+W9G3bJGPrVsm5FKkFPQ6/8UaJvPVWCa9XTyIgGBXytEjYgIuQ6lExpeSRyR9J3OVXB8TE/bptvSx4oZfqy8yZs6R58/8FRL8KaycQIc0oqGLxpWnTpir62U033VRYh15oxoUQ4RDB9M8z7gwOaxXY2I+og0XNKI5fnHGuNxWeM98ojueHU5KRJsVx788viuMX2XGtzvU5VNDWxP/4449c6Twh/j355JNSo0YNFTkTkRQRXhrRL6pXr+4aAku4JGAmjuM+8Mcff5SIiIhcx1Mcd4nU6wKItO2uE63WCOZq69athS5VtU/i+BdffCH9+vWzmwjcDCEEuLumD6Pn7BhfxHHUm5GRoSZd75mOD9lrr73mbld9LpdX4jhCInz33XcqJDNCoj/44IOCi7y7RnHcXVL/lStoNwKej9B/R1Acv8j21KlTKkLDL7/8Iv/73/+UJ7mztAv+m5GLNVMc9zfhwK4fmzOQfgQGYRwCeaDYzv375f4RIwR5yMuUKSPffPMNvcsCZXLYD1MCx0eOlLOXNhl6IpBnbN8uiQMG2OqkMF44T7CspCRJ37pV5ZPH7+yUFNtAg+PiJAIief366iekYsVCB6FVq1by888/S4s+z0rTB/JvU6AZWM17/Lob68rnq1YUOi3oGvMAACAASURBVPaBNiCkH4NIbpbXEeL4nXfeSaE80CbtUn+QnxAe/1r4dK2bWETDvEH8xEIz1nQ2bNhgVw73csuXL5crr7wyQEfnv25RHL/IluK4/86xvK6Z4nheE/dvexTHL/LlWp3r86ygrYkbI+7CK3n+/Pl0CHI91T6VMBPHUSFCq5sJtRTHfcLt8OCzZ8/KLbfcYpczHYVx346UR0iRjc0ha9euVdHd9NanTx+VjqAwmU/iOIRxCOSaYXHDLPe4M2BGcbxFixbSpk0bFcoVnmuaIVcVhF5fDB7tw4YNs6sCOc7d9aj2pW0cm1fiuK/9pDjuOcGCdiPg+Qj9dwTFcf+x9aVmiuO+0CvYx+ofgts3bSqTBw4MuAG9tnixTPv4Y9WvV155Rbp27RpwfWSHSEBP4NiTT0rahg3qJXcEcuSjPtKhg60KCuNF43zKPn1a0rdskfRvv1W/8b/NgoIkokEDibwklIddf32Bh4LNvB07dpS4y6+RoXPWB9x49N7jiHaGlDc0/xLAcygE8rlz5zpsCIs52EiKn6IoqPp3BryrHfkjR4wYYXdws2bNZNKkSbnWcBB9EOsiWJuBMI7UekXRaxywKI5fPGUojnv3uQvEoyiOB+KseN8niuPes/PnkYG4VlfQ1sTr1q1rl1sZjkoQyGn+JeBIHHcUMp3iuP/mY9asWTJmzBhbA08//bQg2kuxYsXsGp0+fbqMHTvW9ponaZ/913tra/ZaHE9NTc0VOv2DDz5Quws8MXhyw3u7bdu2KqSFJoBDIMfOYs2sEMfT09NVbHzskNBs9uzZuXL9etJ/T8pSHPeElnlZ7EoPCgqS4OBg9TtQzNmNAMISHzt2TO2W93WDh3G8+BwmJCRIXFyclCxZ0mMc+Ez8+++/UrZsWY+Pt2ou8lIcT0tLkzNnzihO5cuX95iX/gAs3qE+cDcL/+JT5RYcnJWVpW72Tp8+LRUrVlQ7wDyxQLzh9qT/LOs9Af131dtDhkir227zvjI/Hbn/8GFpNmSIqr1hw4ay9FLuXj81x2pJwBICSQMHKsFTfQfNmqU8gs0MguihO++0vUVh3BL8Ba4Sp0K5iITVqKHEcniURwbgddod4G+99ZbaEH3Hg49J815Pu3NInpeZ0u9/cvTgbzLujXfkwXYt87z9otqgMy9yjQkiLGkiOX57eq9bVNlaPW4z7xOkhho+fHiuBTat7ezsbJkzZ45a//FWGD9//rx6jsVzWIUKFZyuDeC5CG1iwQ/rCP4yPHfh+TAqKsqt535n4rivz3L+GqNWLzY54HkYY8bfMTEx6scdxxN/O2NY/ZyOc+f48eOCOSlVqpTPz/6+sLNyXv3xuSho4jiuX4mJier7w9f1IePc5OdaHc4xGK55RqHDk3MoL8VxrC8mJSVJWFiYlC5d2qdrNTwe4e2N65HVa7Ce8HNU1tfreyCu1eXVmrgva9jafKCOa6+91jY9uA9BVBtfDfOK8w6/rb6eoG/5eU3xlY12vCNxHO9//vnnct1119k15a04buVc4D4Hugt0E/xo5kvOcSvOYyvmBPfiL7/8skAox7OUmeH7BFGg9NGhrNBorei/VXV4LY4jlxTybmhWrVo15W5vlWBpFMd9Dauu9XPcuHGCD6NmuIAjp0RemD/EcWxImDp1qtPuY+HA2YUeN7AvvviiXR3GkGjOwrJjhw92+OeFGS8+aBNeHAi1h40PjRs3znUxzYt+md0I/P3332p3jZ4l+oodagjhUrNmTdOurV+/XkaNGmX6HhaKcIOHzxouYPq6sfMe+Xcff/xxp+G4sSFl2rRpKoSlPjoDjq9Vq5b07dtXcXRlVs2FJ+I4+q5P5XDNNdfIvHnz7LqKhVZNKMOYPv74Y/nhhx/UJhx4KGmGB6Bbb71VevXqJY0aNXI1XPU+jocny65du9SXo/76h3Nw4MCBUqVKFad14QHsnnvucdkezhGkRHBmEL87deqkwp3AcI1BXkaEpJkxY4bdoTj34F2LxSpjuHbk2+nZs6fX1wAciCgg/lxscgmMBSwjgJD+v//+u0SGh8uuuXMlIizMsrqtrCh+6FD5/dAhVSUe3F199qxsm3WRgLcEEvv1k4wdO9ThjgTyv+vWtVVPYdxb0oXrOCWUb96sog9oEQj0IwyrWVOKx8dLVLNmBSr0Ou5h4JE94I0VcsX1/533gTR7H7/5vGz/dJG07Nhd3pkwOpC6Vuj7AoHr3XffVWmH9M8sZgPHfS4WdRAKEJvmaHlHAGsREyZMsDWI569vv/3WKwER95+9e/c27TzWG7DugMh/WLvAtUNvWD/C8zHES6OZebbjWRDPkohEULt2beUw4Y6wi/6hn7DmzZsrj3mco2+88YbdsznWT9DfoUOHyuWXX246JjNxHOP09FkuL2YbGxEQNfKzzz5TqQr1DifG9rE2uG7dOtvLebHe5OtzutlzNaIfYG0Bi8f68cLTHesHQ4YMceuc8YWdP+fWis8Fznuc/5qBE1hqhs8ZrgmODGs73bp18+cwxSznOD6bWHMzrg/hddybQHw0s4KyVvfoo4+qz6reMA9Yw8O6KX6aNGnicv3eE3Ecm0jwPaytTaHtVatW2TnhIB0a0rdptnjxYrU2hTVBpNfQG77LMQ84P9zRGY4cOaKuw8hdvH//fltVuD+48cYb1Vqpq3VOrtV5/1G0ck3c2Aur1rC1enFPCbFPM1zrcZ33xiByIoIyzm3kcNZf+7D2j88E1mEdbVIpKNcUb9iYHWMUx3Fd0r4zevTooe7j9OaJOO7rXOjbxXr/xIkTZfv27bl0l6eeekrQL0/FcavPY6vmBA6E0dHRTqszpiHA9wvuhQqLeS2OG2+knnjiCXVzaJX5SxyHSNa+fXtbN5EbyyiuWTUGYz3+EMch+EHodGUQah0ZFh18yRdw2223yXvvveeqCz6/j13Yxl1EZpVifrFTHTvI88qMNwLPP/+8CvXrzDB3uKAaDXlOjJsVtDLY5IALKm52HZmjcxo3q5hrR3Xr63v44YeV0OpogcDKufBEHDemRjBL5WCcC+w+cyVGv/TSS4IxOzLslMKXOL4cXRkWiHD9cmT44nHnSwTnkH4jgFl9xgUVzBluyPTpLozH1alTR31e9XOLc8oVI1fjxg0mxXFXlAL/fXxXNG3aVHX0viZNZMqgQQHb6eHTp8v76y+G4bX6HiRgB82OFQoCR7t3l3N79qixlJs6VSJ1G7TgMa6F0qYwXiim2/JBZP71lxLI0zdskHO//GJXf1BkpBRv1kyiIPK4sdHR8s55UOHJkycF9yQlSpaR5z/40YMj87boT19/Ku+98piUq1RFvv92U942ztYUASy0Q3zBwvn333/vkgqeTfGMgJ9A9BhzOYACVgCpEfQC0+jRo5UI4Y398ssvaoODmb3++uuCuXUmbmCRFc/LxnmHeO/KoQDHQixz9hyHfukXQ2+//XYVARECuCODOIj1JrMIi2biOOrx9FnOG9aeHGPcAOHqWKzZ4BlcM3+uN1n1nG72XI3XsP7gyPBMD28rRGlzZL6yc8Xal/et+Fxg4/2aNWu87gZEBjh3+NOM4jgW+fGaXsQ3tg9BFhtfjBECC8JaHcaC3L16oc6ML+7BcM2Dk4cj80QcP3jwoOCaqJlZ6F3jXEBXgBimF7ONfcH6LpyOnEVrhBMR1gOcbdpBvZh7XK+NziJam1yr8/6TaOWauNYLK9ew9SPbsmWLdO7c2faSmSjrDglslMPavLPzF/VgjR7XW7ONQgXlmuIOD3fKGMVxfB6RgkezvXv32kWCclcct2IutD7g2omNkM6+IxCOHNcl/TXHke7mr/PYHd5WlTFuuIITIr5DCot5LY6/8MILsmDBAhsHR0Kft6D8JY4fOnTI7oEKFyfsLMsLozjuG2XjzZaz2hAWZfXq1W7t5PWtVxePNt4IYKe40fverB085GNnqt6cfTnCaxkPEM4u0qjL7EJlFKFdjdvZDYKVc+GJOA5hH3w0w2cKOTH0ZpyLFi1auPXA5ixvsbFdV+yw41+/CUdf3p833Ljpws58VzZs2DDl5a4ZxXFXxIrO+7h2DB48WA142pNPyr0B7H21cssWGfjGG6qvXbp0kVdffbXoTBRHWuAJHOnYUTIPHFDjiBs/XqLuvlvlGEeucRiF8QI/xXkygIzvvrN5k2clJdm1CW/y6A4dpETbtnnSF08b+eSTT9T987UN7pIeo+2jAHlalz/Ln89IkxfbXAzxt2fPHpc76/3ZF9Z9UTSE6IYFe4Q5dmYIaamJ5PDeofmHgDFv52+//eaV1zh650wch4CGZ9BPP/3U6UDMNhjj2ceZyKmvEAvYEPwdmV4ch4c0Qne6imyAuszChRoFWaxhuFOX8VnOPzN7sVZEKsT6gycGj/qZM2faDvGnOG7Vc7rZRgVnmxS0wTmLlGAFO0+4e1rWis9FQRTH3V2ra9eunfJE1ltBWKtDf43XZWfnBqI84FpmZp6I49gkgfNBMwjl+OzrzSiOu7tWZ+YUo9VrbNfV5+CBBx5QnupmxrU6V/Qcv2/lmrjWipVr2PqeI+ol1rs1w5oy1pY9MUQEwYY9dw3XHazVhoaGFshrirvjdFXOKI5jo4I+kiuiPesjqLojjls1F+i7MaqAo/Hguz8jI8Mtcdxf57Er1la+j0ge+ui5iKZrFqnJyjbzsi6vxXHjhQ+7YSHMWGX+Esdx8taoUcOum868qq0aD+rxhziOHS1aWC99X+EJ684OFhyDBwGE2NYMoSj0XwwIQ+PsiwLhyNzxhPWVJQRhCDfIL6b9wOsEGx6wwcG4S9Db3V/e9NP4edDqwIUc4VqQlwILBW+++abdBQUX1K1bt0p4eLitWYS4xuIbDOemfhcVwrEsWrRIvQdxE2GfsFsau1r1FyrsdMVOJs0QYgghxPWGL2fUh4Uj5C5ByCNjeDrsvDfLA2flXLgrjmPhAWHv9BsDEIbJ6D3gai6wgxVfeHjQ0deFuUDIFOPNitlGAJTFTTUYYmcbdrzqzWxetfdzcnLUxg0w1xtSVeABWjNvPMe1Y9E+xEL0D3mbEObH+PnA4lOJEiXUIcihYky9gA1P+nMK/zuKJIC86wjnTiv4BLD4pZ2Hn7z6qtzk4EE5EEaanJoqtS+lA/hffLzMmj07ELrFPpCA2wT+bdVKLhw5osqHVq1KYdxtcixoJJB99qykffWVpK1fL+mb7L2bI+rWlehOnZQ3eSAZNoji/iS+x5NyV5fAjVICZrOe6iR/7t6m7ve06CqBxLIo9gVRrLBov3nzZvXj6nke96maUO5O6OyiyNSbMRvzduLZA/PhrSUnJ6tUTZppGzbxP+YPzyt4punQoYPKV46FOUTR+/rrr23HmPUB4g+e/xCFAHltcf7gOQfrINgkbDTUd+WVV5oOwyy1GApCaER4djybIxejMe0cPMyxFqA3oyCrvYe1lT59+qg+IB8yBHujZ5r+Wc5b3q6OcxQtDuI3PIawxoFna3hhgivmBuszWD/Q567013qTlc/pjuYCa2Fa6jSMD5scjOGfzRyFrGLnao58ed+KzwXWj44ePWrrBtax4E2vGdaIce47Miy4+zvio1GQ1fqCtrFeh7QHEFewtmRcD4NHsn79uCCs1WF8EKVxDmrrphB9Dx8+rDYg6dd4UBaRHlauXKlyfRvNE3EcntsrVqywVWGWwtTVXMTFxan1KzjiGT3fEX4aa896M8uFi/exzolrNebVLEqAcV61OrlW5/0VxdU6rCdr4uiF1WvY+pFZIY4//fTTtnSe+usdNoXgs4ew09q6vvY+nDmwTqu3gnJN8f7MsD/SKI7jHgyRjJctW6YKGiPPuCOOWzUXaN+o2+E1bM6EngIPcGhneIY1M7NnEX+ex1bNiat6cG+O+1vNzKKCuKoj0N/3WhxHflq9hyJ28CJfsVXmL3Ec/TM+0OBG2FFYFavGY/Yhw47kqKgoh02AqSbeeXryGXd1uFow0HcC+d30c4mHM2O+Giu5WFEXHsyxG9wYHh6h98qVK2dFE07rMLsRmD59umAnpN7w4IB513uVOws9h904+ocJnAd4KMPNol6MNIaFMe7SNO4KRr8QIhz1aYYLPV5DXi3NzB7iXcH0dC7cFceNY0Tfd+/enUvMdncu8DAN7269QG7m8W28yceCC8KSV65c2YYCD1HGCAAID6XfjeiKGx4k0JZm3orjWKjAZiX9Li6cd3gw1QvkrnKEIL+T/maO3lKuZrBwvI+NNXgIhq2dNEmqO8iRGCijvbZrV0k/d05uqlVLPnHhSRQofWY/SEBP4HCzZpJ18qTtJXqM+/H8yM4WLHpJdvbFn0t/217T/te9hzI5HpZH3cZ2VB26tnO1aeiXsbytH1o5J/3KSkyU8/v3S+Yff9idW8ViYyX6wQelZP/+foTsftVaFLJWA16URu16uX9gPpRc9FI/+WXLFyrFjqM8pPnQrSLdJBbEtUV/CJ4I6430aXj2My5G6kHh/hhrAfCSw0ItNt/q77+LNFQvBm8UFJHDVtvI7UV1uQ6pUqWK7TXtOdiYSsfM08+TdE/IYa6lptIac7bJ3riWhH5h47NRTMdaGdbM9GYU3c0EWTzjQ1zUC1VYn8H6jifPclbwxyIwNiVohrFijcps87wn7Vm13mTlc7rZXMARAesu2oZybYzwbMP3gWZYH8DGDf2aor/YecLZl7Kefi60toznvTcemb702+xYM0EWm0+w3qLPA4zvFITdhnCqGb7z9XOtr78grtVhzQ+5keHhrb+eYJORWUoLd8VxOFsgr7fezDQCd+cCa4q9evWSb7/91lalmcf30qVLBcKY3owbGbEZACG09VE5jNEtXJ1zXKtzRSh3NFUc4cuauFVr2EjzYrwvNHr8oq9mIc/xOpzdjOk1IWhjg57ejBFdcD3Bd5ReS0EbWNd2tEmzIF5TXJ8Z9iXMxHEI5PrIq/pIuK7EcSvnAtcK3GvpzewcxkYjbAA0OqCZ6W5WnceecrayPM5hfWpfq+/1reyrt3V5LY7ff//9Ak9HzfBACg9Uq8yf4jhy6+p3CGNnb17kIzPbgeIuL4rj7pGCl/WUKVNshSFiehLqxL1WcpcyCrJ4qNWnHdAfYQyv5ays8csR9eBG3rgJAAtEV199ta0ZPLBqnsDG93Au4QvZLAQGdnxDRNXEe192/7s7F+6I47ixwM26fsc8doOa5XX3ZC4Qph5RFjQz5ms3skM5hIjDzbTRNA8o7XWI1PhSd9esuuHGTvZ69erlahZi/Zw5c2yvO3oA0gpQHHd35gpXOSxgYIEP9u20aVKpbNmAHuAt/fpJ0qlTUqlCBfl2+/Z86Ss8fxP79ZMLCQkX2w8Kuvij/vzvb/3rtr+DgkSVtKicXV2X+mBWtzvlVN8d9U33njvl3OHgFi89U2f986acfqyGuh3OkbvldHUbeSEs9jld9J6Ihg0lvHbti+eFRZaDenQCr53wapEgbBSQc4m5esHYKEpfEo5dCchOhWqzOowCskU8C3I1IRUrSqUA2UiEHHPII33/k+Pl5uYPBDTWjyY+JTu++CDPxXEIt4g0hB8swOA37om9NdSHe33U4ew33vOXaaI2BG19NDD87clrWOC3wrBR3cxz2Iq6i0IdRu8rCBDIwag3s0Vo/fv4XixdurQpLr04jgLY1ABvV6Nhk7Le4xMbJbD5wV2DtzOikWkLnRBFcX0yM6M4/txzz0l/B5uO+vbtaye0IdobXtPMTJA1C7+O8ogKp/fIdfUs5+7YnZWDSKjvL7yosY4QHBzsU/VWiONWP6ebzYWjnJq4VuFZX78wjlQh+tzN/mLnE3gPD/bkc6FVXRDEcayHYf3auOkBYzALqetos01BXquDQK73YB0yZIjpRjF3xXFsNNBvjMI6Io61PfdcOkGM4rizuYCgadyQ+Ndff9ltaNALZ2jCbK0Urxu/q/AavvudOavpPy5cq3N98fBkHdbVmriVa9jGdU3XI7Ev0axZM7t1VLwLhzJ9aH5H9yanTp2y+17Asc6iUBXka4q7XM3EcXwOwVlb78c9nead7Uoct3IuMDe4T9PMmQhsli7GKI5beR67y9fqcoiCgPtjvVNhYdwsTnFcRIW9ojj+30fIiocVqz+Q7taHB2H9jiNnXtnu1ulOOeONgFkuca0eT8LPmX05Gh+8tHr79eunwrfAsJCgCcfG/Buudu8i3Lg+DJy3kRXcnQtX4jgWArGAasz5ZRZWCWP3ZC7wwIcHW830mwrwGnaE6fOfYKcfHqTMIk1gQwG+PDXzdEOLFTfc6B9SDJiZ8cvb1WeD4rg7n/zCV0YfVn33vHlS8lLo/UAd6Z2DB8ufR46oCBLYNZofBnE8adAgW0js/OgD2yQBEiABZwSKRUZKUFSUlBw4UEq0aRMQsHDfinu7LiOnyQ1N7g2IPjnqxOqZY2TzsllK9IP4lxf27LPPypIlS/KiqSLdBu7p8axD844Ansfg3aeZmWef8RnH2JKz5xejOG4Ul7W6EK4cz2gw3BPiedbT9R1svNaHhEeUMaOwg/qN4rijNGQoa+QDT/JRo0bZEBgFWSuf5bybUfujIB7BsURv2EyOfKB4RjYTF91p14r1Jquf041z4epZHuFxZ8yYYRsu/taz8hc7d/haWcbdz4XWZkEQx81yieuZGTfbOHIEK8hrddgEpw9R7siT2pU4jo1qSJGD1A96wxofvg+MZhTHXc2F0bHNuPHJGDF17dq1Ur169VztYnMgrln6kPKO1hPNPj9cq3N9VfFkHdbVmriVa9j+EMeNYbzNwqVrxPTra3jNLA2HVrYgX1NcnyEXSzgSx5HWApsNNdN0OlfiuJVzYYwK40wENstzbhTHrTyP3eVrdTmjEyA2guD53ddNklb309f6vBbHEWpKnw/KVYheTzvqT8/xQAmr7ihsh8ZKvzPD1c25kW9hDquOBw3sGEfuBvwgDxd2hlesWFHlgEB4dc1cCcGenpeOyhtvBBDWGg+Ojgwiqj60uru7UXEeIE+Q2YO6o7aQR1t/Y4rdlGYhk7TjscsZoUM0wyIBdn6amRVzYRTHsfAIkRpfhrg5wHXGGK7E0Y5Q9NE4F2Z5yfVjcfZZMYZLN4arNzIxLuAgH7k+dL2z882KG25nXg7GkFOuwr5THLfq6lCw6kEkBURUgP3x3nsSGhIS0ANo8+yzsvuPPyQ2JkZ+0nnf5ken09aulWPDh+dH02zTCgLwAi9WTIKKFVO/4XFv+/vSa+6+Z1ePvk5dvVnJyZJ5SZBBuOvwWrUk/ZtvbCMJveYaCata9WJftPYv9dH2v5vvqegBWlhveG1f+rF5art4zRYmXFfO0WvKu9tQztFrdq/r+mcXcjyQ+2vFeZdHdZQaNEhiHn44j1pzrxmIzPBA7DV2oVSr19S9g/Kp1OqZr8jmZTOVVxW8q/xpeCZAO0gdFEiGRZDw8HAV6ln/Y3zN1f9WLqZA2EZ9+NH/rf8fAifCA+OZ5dChQzakCGmJELAQ+fQbqwOJeUHoi1EARMQ2RG7Tm5XiuCdihpEfFuPXrFkjv/32m9oAjUVLbMLGGgJCoutT2uFYhMWOiYnJNQ3GtSScX45CpBoFXITh1Ht/GwVZK5/lrDh/ENEBoWP16xb6epGDEoITcnHecsstDjkY+2KFOG71c7pxLlxFgTOe1y+++KLdRhF/sbNiXvV1WPW50OosCOK4qzVCRGmEY4FmjiIImIVADqS1OuTuxnUNn19c77B2CpEYOdax3qZf83OUStMojmPjADZMwKsb49+6dWuu6wNyBkMfMPu+N4rjZnnJ9eenUfjS6w74jEGo0ZuzlBrapkytvDFVpbPPFtfqXF95rFwTt3ING59JfBfrDWvN+nSi+G7u0KGD6SChNRgjcxo30Di6RqBCnGdIJaUZUjcYUwFo7wX6NcX1WeC6hCNx3JgiR1uvdiWOWzkXxnPY2T2nWfQaozhu5Xnsmqz1Jcw2+Rk3Alrfav7U6LU4PnDgQFm5cqWt167EQE+H5y9xHCGQjDvJPMnH7ek49OWNYdVdhXHRXwQojosShbGTB7m63DVXN77u1uOqnPEiumrVqlw5d/R1eLsb1Zv879gsgDwX3pqZp7qVc2EUx131E4sGCHfiKASScS4QIrpmzZoOqzWmiMANiRZyHuH04LWumT68i1mFyEejz2XkaOeq2bFW3HA7y51EcdzVmcX3QQD5lOB9A/tp/nyJLV48oMG0fuYZ+enAAbnmqqtk/caN+dpXmzhuEFjdEUrtBFBfxVm074OIqheEc4nDunq9fc+Uh4N6VRvO3tO9bypkGwVvvchtIobn1QmUvnmzJA0erJrT5xjPPnNGDt1+u60bpYcPl+hOnfKqW2zHUwL5INxn/PijZHz/vfrJPn06V4+Dy5aViFtukYh69ST0qqtsGxXCr79egiIjPR2hX8tr98KdnpkiN911n1/b8rXyOc90kT9+/EZcRd3xtR0cr4nj2GDpTITGe96I1d4eZ6WobQUnZ3UgRyk21+KZEcKl3vBM0Lp1a2nbtq0SRWm+EUhOThYIpJqZpeSyUhz3JuIfFjCxmAfvRuOGa2ejd1ccd7aWZPSOg2iEsOmaGQVZK5/lfJvZ/46GCIaN6XqPS0d1P/zwwyovpat0i1aI41Y/p3syFxi/MSw1ws/rw7GijD/YWTWvVn8utH4VBHEc4jfOaUc2depUO09oR96DRiErUNbq4GSFFIf6MOeuzht3xXFX9cABDJ/Nq666yrSoURx35bBhTNU4e/ZsiY+PV3Xj2tu06X+bK5H2QZ9ew9gBbGCZP3++7WVn3r7GY7lW52rmczsp+bIm7o81bP0IjGH2PdUN6tataxdmGt8H2HRiZliPRv2atWrVSt2PmFmgXlNcz777JRyJ46gB36FY64dhAw++T7CZGvf1MLMNhFbOxX333Sc7d+60DQYblUuWLOlwcMbNksb7QX+fnQIaewAAIABJREFUx+5T97wkNJ+OHTva3TfDgQ6bSophTa2QmdfiuHE3HURL7Ly2yvwljhvDGjgLXWXVWLR6KI57T9Tsg+lObZ5+yblTp1kZTwVZ4/ntbqgmZ/nJHfXd1wsyQmZce+21tuqtngtPxXF8QerzqxvH7elcGEOFYfertlhmzIVjlkdP374+Twped5QzzmyueMPt7aePx1lJQO+F8dnrr8sNDh5srWzTl7qu79ZNzmZkSMP69WWpLmqIL3XyWBLwJwGImomXcpPqhXGtzaykJDmsC2FaZtSogAmD7U8urNsxgfP79knaxo2SvnGjnN+/37RgZOPGEhUfL8WbNQs4EdzRyLQwbY3a9ZJWA14M6FPg1QdvkTMnk1TIZUfRlAJ6AEWgc/BugxiOHy1noX7Y8ApC+FZn0bOKACa/DNEYOcuYkgs5YrWQ51oHli9fbhMxPAmr7ijUuaOBIaocPLT0keXchWCFOA4vTSzwambcPOCJIOvpRmd3x+lOOYRgxrMqRENHXuRaPXDqQOQ2feoyYxtWiONWP6d7MhcYz44dOwSb7DXDmoKW1k4/XqvZuTNfrsr443OhtVkQxHFXgqwxjKy74nggrNWdPn1asPkQjliemFXiuKtNhJ6K4xARtdzDGA+uQVhLheG7Bcw1cyWOY97nzJljK++qr3p+XKtzfTZ5ug7rbE3c6jVsY++tFsf1a8jGtrCejqgFmrVo0cIuaoO+vFEcD4RriuuZ96yEM3EcWoP+Ph33PVOmTPFIHPdlLozr+c4iA2HU/hbHjVqMZ6S9L430Fd2wznr2rK0SbEzAvV1ERIT3FQfwkV6L48b8tfCuHHzJC8aK8fpLHMcuEOwG0cybi42346M47i05UXOm38GDhy5sxsDDJrx88eCJ/NHY2YOHbc0CVRzXX0SdhUo3fjki1As8Oz0xY+5vtKfPL+SqLoRb0ntWWD0XnorjCH2oz4lu7L+nN2XGL0D9gg7CfepzSyJUPqJkODLjl6Mn3g284XZ1JvL9vCKg7b6cPmyYtGjQIK+a9bidvxIS5I5Bg9RxrVu1krcc7MD1uGIeQAJ+InBuzx452r27qt1MGNeazfz7bznSrp2tF3Hjxinhk1a0CKQuXy5n166VjO3bTQceUqmSRN19txSPj5cwJxFyApUawhs/8sgjUrV2Q+k7fmmgdlNOH0+Q1zo3lOiYWNnz808B28+i2DFs6MNGVCxyYpHczPDsBM8HpFGi+YeAMScsFjL16y1mrSLEKEKNwtwVx71xajCGBEZ7OBcQKhyhUhF9IS0tTYXcx7OYXvi1QhyHByfuqzVD21js1cwTQTY/xXH9HCK6BUKFwpMLIUfNvPEhUuFz6WgR1Qpx3OrndE/mAjyMggci9SG6pjOzgp0Vn2J/fC60fhUGcRxhjxGOXDNHDg+BuFaH3N8QkPWGSCkIC411U0QXQzoJnO/6FA9WiePYAIToiY4++56K40ZBG5tiGlxanzBG5sCYnW2gQlQLhGXXDKnk8F3gjnGtzjUlT9dhna2JW72Gbey9r+K4MfqoWbRVrU14QuujivTv398ut7a+b4F4TXE9856VcCaOoya9Foi/jx8/7lQct3IuevbsqbzVNXMmtKOMK3Hc3+exZ+TdK22MioOjoLvhGujMi9692gO3lNfiuDF2PsJp6cOs+zpkf4njCBerFxed5XvwdQzG4wuKOG68yfDmQdRKdsYHFYQjw8NhbGxsrmaMO40CURzHDRtyV2tmfEh29uWI3OEQkz0x40M58p17EmJJ35Y/5sIojuNmoVatWipXN0Ky4QbWGHYG8+9okcuTmzJsqkBb2kO98Vw3zhUe9LEQYBZGBDmdkGtNM09TIQTaDbfxJgOeOMjHRyv8BIYPHy54cH2+e3fp17p1wA74i+++k36Xroe4kR01alTA9pUdI4GMHTsk8dKucWfCuEbq/G+/ScJDD9nAlXvzTYF3MK3wE0hdtUpSP/xQsJkilwUHS9Rdd0nUnXeq30FhYQUWiLZgEBVTSkYu2xWw4/jzp20ya1gnuarq1bJxw38LJgHb4ULeMYTxhmiB5wMtzKJxyMgTrYniWLii+ZfAkCFD7DanYxFt3bp1pvlmtZ7klThufC6EcITNEmZmzEdrhThuXJswPst7IsgGijiuZwcPZORwhzeRFgpVe99ZSF0r1pusfk73ZC4wRoRnRphmzbB5H5v43TVv2blbv7Ny/vhcaO0ZF9bxecPnLj/NE0EW4eYbN25sl0YA0UiQksRoRiErv9fq0D+jWONI2Deug7krjsNZBOc5eJQrV06OHj2qNjrqzZnjnCdzgTqRruDLL7+0VW+M4GMMqewswo8xBaInXplcq3P9CfZkHdbVmriVa9hmPfdVHMdmKH1EGmfXf/39DvoyZswY5ZVrZoF4TXE9856VcCWOG1OmYMONtnHRLKy6lXNhnCs4XhrzzetH60oc9/d57Bl556WxURRpLPSbpnDE/9m7E3ibqv//4x8hYypCIiQUkiJDJCmR5sHUIENJoSJSyZCpQYkmkSj0/crQ5IuiSdM3mZOh6StKqWSe0sD/8d6/zvnvs++5955z79n37nPuaz0eHrh377XXfq59zz1nv/daS/mbZtwoX758Ig8XuLqyHI5rupbTTz894oQyW1MinrP3IxzXG50GDRpErA3x7LPP5tj0askSjqufvG8yMltrIZ6+jXdb79OnGU1/ozVo9P1QCWI47n3ToPWOtEyBX78co71J1i9y/SzEW/zoC2847n2CUx+e9UbWvc6ZbrroTXLBggXTnILXV6MS3NMtuXfwvimSiftNzh9//GHVqlWLOIY+/OsDk7d4p3yKd82poL3h9t7oiufJ2nivK7YPlkDo6dYL69e35/v3D1bjXK0Z/8Yb9tBLLzlfefjhh+1aV5AY2EbTsDwpEG8wHkI6uGqV/dy1a9is7IQJznrSlNQU2Pfmm7Zn9mw76FrrLHSmhWrXDgfiBSpWTAmAzZs3W5MmTZxzuWP8m1auSjBDzLWfvGUvDe3uPJTpHvGZEp2QRCehKYxDobgeSI1WdANNN+0VxlSoUCGJzi65m6rpezV63F0yCqG1XU6F41ofUes+q2Q0W5vuE3mX7Yo1HE9vOx1TSw/qRnCoeEOjeALZIIbj7j733r/ToBSNWE2vZPd+U6I/p3v7IrPP8t7zVeh39tlnZ+mHOV67LB3EtZMfPxeh6r1TXevGugLa3CzxBLLebXUvSA/7RCuJCLJUrzdgyeq9Ou+MDOpn9+uP+xw0w+FlrofgYw3Ho4161YwJ3oFy6Q2s8PpmdL92x44ddsYZZ0TQex9U0O9797Idms1Wr7Pe4l0GQd/X74ajjjoqpkuTe3WZM8UTjsdyTzxRPxfRWp7dcFwz5ChIDJVooa2+p0FYGkDlnmElo/vTQXtNybzX498is3Bc9/8VSEeblSaacyL7YsKECfbggw+GT+qmm25y3q9GK9FmrvCuOZ7I1/f4pWPfQzPx9O3bNyJz0d56fVW+VqRIkdgrS9ItsxyO63w7derkTJcUKlrbxL0eSHZM/AjHQ9P3udu1bt0654NSTpRkCsfVl5qqLlTU15rSJjeK9xdXek8i6oVI7XaHqEELx6OtnaI3kpp5IVpJ1C9H73REOpZ7SqJY+9WPvsgsHFfbvNOW6WsDBgwwvTn3Fu8brUs13fLTTztTSLnL77//7jyx534zrTf2evLMXbxTq+iDgwJy95QiepOuD//uX+D65aK2xFqC9obbO8uGPtjqWo321HSs58h2ySHgXnd81rBh1qBGjUA2vO3gwbZk/XorVrSorYtzXbVAnhCNSkmBrAbjIQz3/vpa6dGjnZCUkjoC+995xwnFf1+yJOKk8h97rDOdvkaIF87CA41BF1KwocBZT9Vf0n2QnXPNzYFs8oyH77RV773uzNykUWGUnBPYs2ePM0JcobhGg6VXdPNcMx7pT059rs85heQ4UrRwRJ/D9bmqQIECaU4ip8Jx7z0lBflFixZN0x7NLKjPPu4Sazie3iiwn376ybR8l/vzoR5APffcc8OHSZVwXD+rF154YcR9mPQeKA+dfCLuNyXyc7q3L9TO9EbdegcMaFvdt9G01fGWrNjFewzv9n78XISOEe2hhfTW7M7uecS6f6zhuAYE6WFr98+sBrFoMEu0ErR7dbqWdK8qVLwDP0JfV6ij+2gKsEMlO+G4Xuu8D4akt3ypty/0UJt+z2vGF2/Rw+8azBYqZ555pr3++usRm2mUo16DQ0XvATTyVPeuQkUunTt3NgXkoRLvA4/cq8v8py3WcDzWe+KJuocdreXZDce9P/s6hnf0uGYHGTp0qDPLiPv61FTd0WbBDf0ecT9UlpXZKFSPn3aZXwkZb5FZOK699TPtHcGsr0cLxxPZF8oGvLMLaRmSSpUqpTmpaNdxtHA8yH2hB6pkHe3hb2W7ep+WV0q2wnGtq+ANfzRFntZvirVo2h2tveMt+oFxh5wKlr0fdvVkePHixWM6lF6Y1LHuIEwvOt4PQTFVlsWNEh2Oa22sX375JWprdHPAXfQGwVtOOukkZ42vaEVPy+ipGXfRmyutv6yppfWhUm8y9OS+ptLREzV+hWY//vijNW7cOKItepPUsmVL58O2vq8XRL1x1Q02d9EbKE2rpzWz9eTZ8ccfn8Xey3g37xsBfRjUsfPnz29bt241hafqA/faRarRG97rw4Se4gyVr7/+2u67777w//Um072WlerXcTIrWldIH8S9PnINja7Qz5emC9esEHpR19QluqHhDpX96ItYwnGdnz6oeKdPjLYGiLcvtK9uTCgI15O/Gm0uV715cb9B1nbRXr+80+FpO41c1zVfunRpZ10jPa3m/hAlS73WeF+fNH3VyigjwlSn3ui7p6NTe73r9WldPE0DHyp+3lDRGnJdXSMWdUz97GutJk2vrg//mnpF15Q+EGm9Jr2mUFJDQK8Xeh1odsYZNvX++wN3UotWrbJOI0c67erUsaMNc30oDlxjaVCeFXAH2xr5e/w/66vGC+INyEsNHWrFA7zkQbznl1e33//BB7Z39mw78MknEQSadr9oixZOMK6APJWL3rtPnTrVTqrd0G4ZPTNwp/rzd1/aUz0utkN//225OYtW4GB8bpDeK4dCcff9AO9h9d5T9wP0ICwldwV0P0czfXmLAhd9Zj/11FOtatWqzmdj3b8YO3Zs+HOde1krfQ7W5+FQcd/T0OcrvV64S61atTIc0eK9/9KqVStnGR7dG9CD0grL9cD4v//97zRt1yxa+myjbTWKKbSslnc0m3bU50KNwtS2f/75p/N64b03IQvdC3B/tvbzs1wirogvv/zSxo8f79wY1mwM+uyrz7daT1h+um+gPtONVe/PamavmYm435TIz+nRwnFdc7q3oGtb9zj1uVc3yt0zFco52oAMP+2y27d+/Fy426SZJPSz5S6656QpubVsXuieU2gWEL8fPPMGsrrHpcE/un+p+2TffvutaeSc996wBrBoWt3QAz5Bv1cnb4W+7p9FvY5panJdy1qWRD+vunflvQ+m12EtOaqpc/W6d8oppzjd512fPr31kjUYxbv8o+4ne2cV8faFjqF7dDq27mtqJLfuQ86ePTvNUpAvvPCCcw25i4J+zULkvs+pc+3Vq5czG4i+rt8b3usx2nTJ3KvL3itLou6Jh1qRqHvY0c4qu+G46vQuxaKv6YEtvV84fPiwaWZl95IA+r5ee/X7IlSS4TUle1dF2r1jCceVn+gevrekN0I/EX3hft/pfn3U64ke1NGDuHrvo9dX9W208D5aOO7ndZzdvpk/f37E9RiqT1mprDMren/vV8aW2bET/f1shePRpjvWLzYFg3rTE0vp379/lqeo04eY0HR8GR1L02TpRcg9XbK2VxgVS7AYy3nEsk2iw3FvqBhLG9zbZPQE5/bt252po6NNZRHtOH6uR6xfLHoTFO0hCr1Qeduo6YN0Q8VbevfubXpz6EeJFshmdhwFrHoxck9RoRfa9NbSjlZfPOtaR3vCObM26peCPgSHih99EWs4rkBbT6S7i25wPPfccxFfy0pfqAJ9aBg4cGBUknjr1GgI3STxFl2r2Vn7UNfM+++/H67Wzxsq6usOHTpEzCCR0fWS2fSJmV1rfD9YAu43rYM7d7abLrkkUA286+mn7ZV/nnZ/++23rXr16oFqH41BwB1oFyhf3sr/5z/ZQvEG5CX797ejOnTIVp3snHsCuyZMsJ2uh1CPrFbNmTK/SPPmVrhevdxrWA4f2T1TyW1PvGYVa9TN4RZkfLh5E4bbx6887zysqJvJFH8F9Fldn+Hc73W9R9QNfI161B9Ny0wJjkBoWZ54W+QOx5s2bRpeWzKWejJ7D5jejb9o9xD0kIX3QfZQG7Sutm6KqkQLx2Npq5Z/836W9fOzXCxtymwbzRrmfjA/s+1D39e9GwVZGZVE3W9K1Of0aOF4rOe7dOlSZ/1ld/HTLtZ2pbedHz8X7mO5f7dn1lb3z39m22b1+9EC2Vjq0nTq7iX2gn6vTufkXTM3dJ7RXvM0iEghtLe4A6hYw3E9LKOBPO5gXn2rWV/cg9yy2hcaCa6ZYL2zQart06dPd+73x1oUumkNXW/hXl2sgtG3i/e1WLVEuyfurj0R97CjtTYR4Xi0+9MZCernQYND3bPXJMNrSvauirR7xxKOay/v7DL6WnrheCL6ItRS9dH1118f02mrT90P5kQLx1WRX9dxTI3MYKP03gvEWm9WlwCJtf6c3C5b4bgaqqmGvFMba3Shnh6NNvWA9+T8Dsf1S1ov0pqW2V2yOj1FdjonmcJxnaeehtETd7GUWB9UiKWuaNvoA6meSsmsKODU04bu9T9C+wQpHFdwqvVwvNOp+PnLUQ56IlYBcLQHDaLZRnuAJNF9EWs4rvbpKW3dWHAX75ot3jdlso725tddh56M0tNg0abZ03YaIT1kyBBnZEFmRSP9dR1qZIS3JNMbbrVdNwk0CiKWh2T8/PnKzJzvJ17A/QazZIkSpunVq5Yvn/gDZaHGDT/9ZC379rU///rLLm3Vyp7xPCCThSrZBYGECriD7HxFilhFz8jgrB7s988+s19cT5sf06OHHZ3OVI9ZPQb75YyAwvG9//mPHdWmjRU++2w78p8ROjlz9GAdJXTzo1n72+yim2K/uen3Wez85Ud7skdrO7BnlxOMe2fz8fv4ea1+zeik0cTRitZr1APxCsP1J9Y1QvOaYRDOV58T9RnXO0ovo7b5GY7ruFrqKloA5G6TwhvNihhtpJK2yygc1+xmCmcyKvr8ramZvcFO0MNx703sWK4xjbaVRyxLHCTiflOiPqd7+0LXgj4PaRRrekXnqAf1NajEW/y2i6UvMtom0T8X3mPp3ol7OuGM2uL++crueUXbP95AtlmzZs4MEwru3CUZ7tXpvo0e9Mnsfp9mkNR9fI2g95ashOOqI9pSiN5ZFbx9ccMNN6QZIe5tj4Jx/ZxpCvZoRYM6dE9Q11xmRff9Ro4cGfV9BPfqMtPL+PvxhuPp3RP3HiUR97C9dSYiHFedmtlUmYl3htZo17B+JyTja0r2roq0e8cajuthWc1a6i7pheOJ6Av3cTTbhGb/yajotVOzOSv4DpX0wnF934/rOLt9Qzj+/wWzHY6rqmgvgnqjqDeUunj1IVZTaUVbb8qPcFwXpKbZ1hTJevLc+4ZW4b1+0NKbUjy7F1h6+3vXGkhvzavQ/vploacVVaKNEH7qqadMozWzWmJZ+0fTWehmhX55ZBSQ5cRNo++++86Z6khT4HiL+lIfxDUVtYJQ97ozoW39DO9ieSOg6+700093Rq+718Bxn4ueoI5nNoN4Ro6HjqOp3vQktxwzu3ERbeoi1ZPIvvBexxk9aKGp27Sekfta1NO8oZ+TaK9HesFfs2aNc1PEvayCttUbbN2oiPahINrPlR4W0NRy0dz0WqcbHxn138GDB7M1wjWzkeNXXXVVujcWvctgxLqGiKbf0s+dzj2jN326MaQHDCipI6DXUz0trnLVuefa2NtvD8TJjZk508bOmuW0ZfLkyc6U/hQEgiLgHeFdacWKhDbtwMcf26933BGu85ju3e3o7t0TegwqQyAnBUI3IEqfeLLdNen/32DIyTZEO9Y708bYu9PGOtMka7TSMccck9tNSunj632qPgNoSleZh/4mDE++btdnTb0/0+hRTa2d3ucHfY7VMj4aZRyaVjnadMwZCWQ2clz7ahZBfe7Vw/PRpunXrHN33XWXM+17eoM7MgrHQ/dL1Bb92100lbpusKY3M5w3kPXjs1x2riA9sKJ7QbEUzeim9msK8tAo+1j2S9T9pux+To/2oILu3+lBft1T9F7HGiWrqeH1WhWt5IRdLL7pbZPon4tox1FooOUQvfdgvNtqpN6JJ56YndPJcN9YwnG9Hmn5Oi0rp2s5WkmWe3W6Z6Z7ounNeKOBHLp/qQDdvb5x6JzdAZR3Dd7M7qkq7NZocXdxz0YZbf13zcahe2xaMtG7VKGW1hgwYECGy2eEjqV7fhpMo9893qJ7hpp6OaMp/LlXl70fwUTdE4/WikTcw3bX6w3H9R5AeUJWym+//eas8a170t7MRBmAfsZUv5bI9JZkeU3Jikt6+8QajmvKeU1l7jbNKBzX8bLTF972Kk/UmvF6H+suuievWYCUZeqBnJdeein87YzCcW2U6Os4u/2S3XBcDzgq40qFkpBwXB2sXzTuJya8OApXov3iTTSi3rRmNMWaQlS9cU7vqbNEtydV6tP6K/rAoBdvrd+uN9MaZauRz7qBEcuTwYmy0HT++mCrvla7tMaB1sAKPXyhN4O7d+921hBy/9H3o03Dk4h2yUPHVZCoY+uNlWYtUJGP3uy7p09PxDETUYf6Uuu+bd682VnfTT5qp9qs6dRDa6uld6wg9oX3TZle8LUenYr6RGuT6brROkrekfuxmspKPw/qay0hof6NNlI81vqSZTtdJ/rZ0/Wu1329wdO6c7petAY5JbUENE2O1mQLlQEdO1r3yy/P1ZP8aPVqu2H4cKcNvXv2tD79++dqezg4Am4BbzBe4Z13LH/JkglH2v/ee7bV9bNJQJ5wYirMQQG9n9fNTz14eV6Hntaqa+6/rq//9G2bOuRmR0EP3OphMQoCCGRNQOstKoTRCF99ztRnzJIlS8YVoGbtyJF76XOvbpz++OOPzmd1fYZRsOn+DKMbmwULFnTuIbj/dg/y8E6r7r4ZqnsBCmj0MI3CmGg3wxNxLjlZhz736fOf7OSmz8Hy0B/Z6Y/ON9pAmHjamaj7TVn9nJ7ZKH5dNwrydR9RD1HE8tk/p+zicfZum6ifi4zaoHtGWtdb9050v0kjfXUvUa8Duo+gnzU/i46nY+/YscO5Z6d7QrqW1T96PVKfZvW+kJ/tzu69Op3fzz//7LzmyV0/p7pvGpotUT8r+tn23jdVf2R2HzCr5x0tHA8NVNFrgH7G9Fqjh5Wyupat3DSiU+deokQJZ7RuKrwWZ2ae2/fqcuqeeHZ/LjJzzM73t27d6gzO1M+P1rzX9RekEmS7RDslqi/0OqnXJf0e02uJfm+FivIx/T5RHqY/8bwPykt9kei+9aO+hITjapjeXOipwPSeLNXTXt7p1/04IY3o1BPH0YpGsusGh57eoSCAQGoKZBSOp+YZc1YI+CegJ2j1QFmoPHHHHXZl06b+HTCDmvcfPGhtBw2yNd99Z7WqV7f5b7+dK+3goAhEE/AG4yfMnGkFq1b1DWvfggX22333hesnIPeNmopzQECjLW67rYf98cdBu2HIc1arSfRRWznQFNv12xZ7+LpGzqE0AjLWaWFzom0cAwEEcl8go3A891tHC7IqkFk4ntV62Q8BBP6/QEbhOE4IIIAAAgjkhkDCwvFQ4/VEoKYv1s1097RVXbp0cdZt8bt4p8fQ8a6++mpn1LqmPqIggEBqCxCOp3b/cnY5L1CvXj3nCW6VggUK2LKJE+2Y4sVzvCGDnn/epi5Y4BxX072nN/VljjeMA+Z5gT/Wr7ct118fdig7caIVrlfPdxetWb3Ntb7ecSNGWLGLL/b9uBwAAT8ENHXt008/bccef6Ld+vhsK3Hc8X4cJtM6R3VsYjt+2exsN3PmTGvYsGGm+7ABAgjkHQHC8dTsa8Lx1OxXzipYAoTjweoPWoMAAgggYJbwcDyEqqlrdDNdfzR9jabLqVy5su/mmi5n9erVdtRRRzlT5OiP39P0+H5SHAABBGIWIByPmYoNEYhJYOnSpdamTZvwtseXKmWfjR8f076J2sgdjGe21lmijkk9CMQicGj3bvvB9fBlTgXjobbtffVV2zZiRLippR95xIpeeGEsTWcbBAIn0Lp1a1u3bp3VPvcSa9d/jBU4Mu36fH42+tk7r7Lv169wDqEZzzTzGQUBBBBwCxCOp+b1QDiemv3KWQVLgHA8WP1BaxBAAAEEfAzHwUUAAQRyQ4BwPDfUOWaqC2jJlLFjx4ZPs9ZJJ9nrDz5oRxYo4Oup//Tbb3b/xIn23or/CyvGjRtnl1xyia/HpHIEYhX4+5dfbHPr1uHNSz/2mBU9//xYd0/Ydnteftm2jxoVrq/83LlW4IQTElY/FSGQUwJaL7FJkybO4UoeX9E6jZhsZSpW8/3wu7ZusWd7X227tv7kHKtDhw72yCOP+H5cDoAAAsknQDiefH0WS4sJx2NRYhsEsidAOJ49P/ZGAAEEEEi8gG8jxxPfVGpEAAEEMhcgHM/ciC0QyIqAd9mSIoUK2bSBA63+qadmpbpM9/n3O+/YlDfftC+//97ZVkuzaIkWCgJBEXCvM15q0CArftVVuda03dOm2Y4xY5zjH929u2kNcgoCySiwceNGa9asmdP0YkeXtLZ3P26nNGju26l8+dl7NnNUbzuwZ5dzDL2P7Nu3r2/Ho2IEEEhuAcLx5O6/9Fr16hRHAAAgAElEQVRPOJ6a/cpZBUuAcDxY/UFrEEAAAQQYOc41gAACKSZAOJ5iHcrpBEpgyZIl1rVrV9uzZ0+4XQM7dbJul16asHYqFP/322/bFxs2OHUWLVLEnn7mGbvgggsSdgwqQiARAr9062a/L19ux95xh5Xo3DkRVWarjl2TJtnOZ55x6qj0z2wL2aqQnRHIJYH9+/fbbbfdZnooq0DBI+2ynkOtwcXXJbw1S9+cbm88Ncj+/utPp+6hQ4da5wD8LCf8RKkQAQQSJkA4njDKQFVEOB6o7qAxKSpAOJ6iHctpIYAAAkkswMjxJO48mo4AAmkFXnvtNVu7dm34G7169bJjjjkGKgQQSJCAfr7uuece++KLL8I1nlqxorVt3txuzmJI/u2PP9pHn39ur3zwQTgUV+X16ta1R0aNsmrV/J9WN0E8VJOHBPa99ZYd/vNPK37ZZYE5673/+Y+Z2nT11YFpEw1BIKsCCqsnT57s7F628inW+MrOCQnJVy/6j33y2uTw+uJVqp1ife7oZZdffnlWm8p+CCCQRwS01NC+ffucsy1RooQz2wQl+QV+++03Gz9+fPhETj/9dH4nJH+3cgYBE1i5cqXNmzcv3KrLLrvM6tSpE7BW0hwEEEAAgbwkQDiel3qbc0UAAQQQQCBBArNnz7aZM2faZ599Fq6xfOnSdl2LFtbsjDOsdpUqGR5p1Tff2KJVq+z9lStN/3aXE0880dq1a2fdu3e3QoUKJajFVIMAAgggkGwC+l2jG6nvvfee0/TCxY6ypm272wkn17JyVWrY0aXLxXRK27d8b9+u/NiWL5gVDsWPKXmcs1zHLTd3taJFi8ZUDxshgAACCCCAAAIIIIAAAggggEDyCxCOJ38fcgYIIIAAAgjkmsD8+fNt5vTp9v6HH0ZtQ41Klax4kSK298AB27N/f/jvvw8dSrN99erVnVC8ffv2zmgcCgIIIIAAAhJQQD5lypSIB7L09WLHlLKylapZmUrVrfjRpdJg7d72ixOKKxx3lxs7d3VCcT2MRUEAAQQQQAABBBBAAAEEEEAAgbwlQDiet/qbs0UAAQQQQMAXgW+//dZWrVplqz77zFZ9/rl98dVXMR2ndq1adkqNGla3bl0nGC9YsGBM+7ERAggggEDeE5g+fbp99NFHtmLFCtuyZUvMAFpip0mTJnbJJZfYmWeeaSeccELM+7IhAggggAACCCCAAAIIIIAAAgiklgDheGr1J2eDAAIIIIBAIAQOHjxoWlds//79ztqM+jv059hjj7VatWqZRooXKVIkEO2lEQgggAACySWwfv16W758ufPnp59+StN4zUCi3zVaO7Zp06Y8fJVc3UtrEUAAAQQQQAABBBBAAAEEEPBNgHDcN1oqRgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIigDheFB6gnYggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCPgmQDjuGy0VI4AAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggERYBwPCg9QTsQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBHwTIBz3jZaKEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSCIkA4HpSeoB0IIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAr4JEI77RkvFCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJBESAcD0pP0A4EEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAd8ECMd9o6ViBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGgCBCOB6UnaAcCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgG8ChOO+0VIxAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEBQBAjHg9ITtAMBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwDcBwnHfaKkYAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCAoAoTjQekJ2oEAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggg4JsA4bhvtFSMAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBAUAcLxoPQE7UAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQ8E2AcNw3WipGAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEAiKAOF4UHqCdiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAII+CZAOO4bLRUjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCARFgHA8KD1BOxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEfBMgHPeNlooRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBIIiQDgelJ6gHQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACvgkQjvtGS8UIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAkERIBwPSk/QDgQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAAB3wQIx32jpWIEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaAIEI4HpSdoBwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICAbwKE477RUjECCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQFAECMeD0hO0AwEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDANwHCcd9oqRgBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAICgChONB6QnagQACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgmwDhuG+0VIwAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggEBQBwvGg9ATtQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBDwTYBw3DdaKkYAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQCIoA4XhQeoJ2IIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgj4JkA47hstFSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIBEWAcDwoPUE7EEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQR8EyAc942WihFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEgiJAOB6UnqAdCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAK+CRCO+0ZLxQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACQREgHA9KT9AOBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAHfBAjHfaOlYgQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBoAgQjgelJ2gHAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIBvAoTjvtFSMQIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBAUAQIx4PSE7QDAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQMA3AcJx32ipGAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgKAKE40HpCdqBAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIOCbAOG4b7RUjAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCAQFAHC8aD0BO1AAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEPBNgHDcN1oqRgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIigDheFB6gnYggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCPgmQDjuGy0VI4AAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggERYBwPCg9QTsQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBHwTIBz3jZaKEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSCIkA4HpSeoB0IIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAr4JEI77RkvFCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJBESAcD0pP0A4EEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAd8ECMd9o6ViBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGgCBCOB6UnaAcCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgG8ChOO+0VIxAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEBQBAjHg9ITtAMBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwDcBwnHfaKkYAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCAoAoTjQekJ2oEAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggg4JsA4bhvtFSMAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBAUAcLxoPQE7UAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQ8E2AcNw3WipGAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEAiKAOF4UHqCdiCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAII+CZAOO4bLRUjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCARFgHA8KD1BOxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEfBMgHPeNlooRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBIIiQDgelJ6gHQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACvgkQjvtGS8UIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAkERIBwPSk/QDgQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAAB3wQIx32jpWIEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaAIEI4HpSdoBwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICAbwKE477RUjECCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQFAECMeD0hO0AwEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDANwHCcd9oqRgBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAICgChONB6QnagQACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgmwDhuG+0VIwAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggEBQBwvGg9ATtQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBDwTYBw3DdaKkYAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQCIoA4XhQeoJ2IIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgj4JkA47hstFSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIBEWAcDwoPUE7EEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQR8EyAc942WihFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEgiJAOB6UnqAdCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAK+CRCO+0ZLxQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACQREgHA9KT9AOBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAHfBAjHfaOlYgQQQAABBBAIusCBAwds586d4WaWLl3aChQoEPRmZ6l9Bw8etO3bt4f3LVasmJUoUSJLdSX7TsuXL7dVq1bZRRddZOXLl0/206H9CCCAAAIIIIAAAggggAACCCCAAAIIIBCjAOF4jFBshgACCCCAAALJIbB37177448/rGTJkpk2uH///jZjxozwdvPnz7datWplul8ybvDhhx9ax44dw03v3r27DRgwIBlPJVtt7tOnj7366qvhOp566im7/PLLs1UnOyOAAAIIIIAAAggggAACCCCAAAIIIIBAcggQjidHP9FKBBBAAAEEEEhHQKHvypUrbe3atbZ69WrbsmWLs2WpUqWsTp06VrNmTatXr541b97c8uXLF1HLHXfcYW+88Ub4a4TjqX2Z6dpo1KhRxEnqGpkzZ06unbhmLtizZ49zfF2fFSpUyLW2cGAEEEAAAQQQQAABBBBAAAEEEEAAAQRSXYBwPNV7mPNDAAEEEEAgRQUUKA4ePDhiFHBGp9qgQQN7+umnrWzZsuHNCMfz1sjxr7/+2i688MKIy6RcuXK2ePHiXPspefjhh+3ZZ58NH3/69OnWuHHjXGsPB0YAAQQQQAABBBBAAAEEEEAAAQQQQCCVBQjHU7l3OTcEEEAAAQRSVGDZsmXWq1ev8CjxWE/ztNNOc8L0QoUKObsQjuetcFx9fs0115iun1C577777NZbb431Ekr4dt5wfMqUKXbeeecl/DhUiAACCCCAAAIIIIAAAggggAACCCCAAAJmhONcBQgggAACCCCQVALff/+9NW3aNE2bNQL4nHPOsdNPP93y589vS5cutYULF9q+ffvC25511ln2r3/9ywoXLux8jXA874XjO3bssFdeecWZhr9ly5bOSPICBQrk2s8A4Xiu0XNgBBBAAAEEEEAAAQQQQAABBBBAAIE8KEA4ngc7nVNGAAEEEEAgmQV69+5tr732WsQpdOnSxQYMGGBHHnlkxNe3bdtmN954o61Zs8Y0rfqLL75oxYoVC29DOJ73wvGgXfuE40HrEdqDAAIIIIAAAggggAACCCCAAAIIIJDKAoTjqdy7nBsCCCCAAAIpJvDFF1/YpZdeGnFWjz/+uDNVdnpl7969NnHiRLvlllsignFtn1E4rhHnv/76qxO4a1T6EUcckWXNv/76yzZv3uxM53788cdbvnz5slxXaEe176effnLO6bjjjkvzYID3AB9++KF17Ngx/OXu3bs7DxT4Uf7888+wXcmSJZ2R/FktBw8eNI32LlKkiB199NFZrca3/f7++2/TQxi7du2yE044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uHBhuP6PPvrIFMCHSt26dW3btm3pft/dsObNm5vWJA8VrT/uDdfTQwpaOO6dbv6xxx4zLRlAQQABBBBAAAEEEEAAAQQQQAABBBBAAIHECxCOJ96UGhFAAAEEEEDAJwHvVOM6zJQpUyKm5I7n0IkOx3v27Glz584NN0HTot9+++3xNCm87eHDh61y5coR+1577bX28MMPZ6k+bzjevXt3GzBgQERdauucOXMivvbBBx+kaYc28Ibjt912m917771R27Zjxw4744wzIr6nhwgUzIeKAuElS5aE/3/nnXeawnlv8Y6o1/fXrFljRx11VEwuQQvHNYL+7rvvDrc9Wr/EdGJshAACCCCAAAIIIIAAAggggAACCCCAAAKZChCOZ0rEBggggAACCCAQFAFNXX7RRRdFjM5W2xRK9+7dOyJs9bZZU3cXKVIk4suJDsc1gvmWW26JOIamE7/hhhssf/78cTPef//99tJLL0Xsp6917drVChQoEFd9sYTjP/30k5199tkR9WotcD2A4C3ecFyjwOfNm2clSpRIs60C/WeffTb89TPPPNNef/31iO00A4DWXQ+VYsWK2SuvvBIxbf6ePXusc+fOpoA8VDSbwIwZM2K2CFo4vnjxYmvfvn1E+72j6mM+OTZEAAEEEEAAAQQQQAABBBBAAAEEEEAAgQwFCMe5QBBAAAEEEEAgqQTee+8969KlS5o2V6tWzQnOq1at6qz9rXD1t99+s//973+mtckXLVpkn332mR1//PHhfRMdjqtiheMKyd1FwfHNN9/stEvhsUJ6raH+/fff23fffeesLX7iiSemOaedO3da48aNbd++fRHf0/rjV1xxhVNf6dKl7eDBg842mhr9xx9/NIXPmjbdXWIJx7X9008/bY8++mjEvhMmTHBs3cUbjut76gM9qKDjayS3zm/27NlpAv4XXnghTfv08EKTJk0iplZXH/bq1cs5T025PnXqVNNU9e7y6quvWr169SK+9vfff9vKlSujXtcK5adNmxb+XseOHe3KK6+M2LZQoUJWu3bt8Nd0Dbk9W7VqZc8991zU+hXU9+/fP/w9PRzRqVOndH/GdI1626+N9bCH2qD+1UMh27dvd5YUqFKlip1zzjlJ9TNLYxFAAAEEEEAAAQQQQAABBBBAAAEEEAiKAOF4UHqCdiCAAAIIIIBAzAKjRo2yZ555Jubt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Qw8C6O89+/dHeDSqU8f69OhhjVq0MCtQIE9bcfIIIIAAAggggAACCCCAAAIIIIAAAghkV4BwPLuC7I8AAggggAACOS+wf7/Nfv55GzN1appR4hoZrtHgLRs0cP6uULp0zrePIyKQRQGF5WNmzjTvqPJGp51mE594wkpUrZrFmtkNAQQQQAABBBBAAAEEEEAAAQQQQAABBAjHuQYQQAABBBBAIKkE1n32mXXr2TNqKH7TJZeY/mgKcgoCySygkeST5s2z2YsWhU9D1/WMxx6zmppqvXjxZD492o4AAggggAACCCCAAAIIIIAAAggggECuCBCO5wo7B0UAAQQQQACBrAjMmjDB+j34YMSu5UuXtrbnnUconhVQ9gm8wOatW23oCy/YwqVLw219rFcva9u5sxmzIgS+/2ggAggggAACCCCAAAIIIIAAAggggECwBAjHg9UftAYBBBBAAAEEogjs3r3bhvXrZ7MWLIj47uDOnZ1QnIJAqgvMWrTICclDa5LrgZDHRo40q1Ah1U+d80MAAQQQQAABBBBAAAEEEEAAAQQQQCBhAoTjCaOkIgQQQAABBBDwQ2Dz5s3WrXNnW/fNN+HqNVr8+f79rWblyn4ckjoRCKSAplq/edQo+3HrVqd9vdu2tT49e5qddFIg20ujEEAAAQQQQAABBBBAAAEEEEAAAQQQCJoA4XjQeoT2IIAAAggggEBYQCPG27dpY+u++ir8tZb169vonj1ZV5zrJE8K7N63z7qNGmWL161zzv+5u++2VhdfbFalSp704KQRQAABBBBAAAEEEEAAAQQQQAABBBCIR4BwPB4ttkUAAQQQQACBHBXo16ePzXr11fAxnZGy7drlaBs4GAJBFLjo7rtt/caNzkMiMx54wGqed55ZmTJBbCptQgABBBBAAAEEEEAAAQQQQAABBBBAIDAChOOB6QoaggACCCCAAAJugUmTJtmwYcPCX2pz3nnOiHEKAgiYbd661S7q189Zg1zLC8wYMcJK1KtnVrQoPAgggAACCCCAAAIIIIAAAggggAACCCCQjgDhOJcGAggggAACCAROYN26dda6detwu2pUrmxvPfpo4NpJgxDITYHFa9da+wcecJrQqkEDe+6RR5hePTc7hGMjgAACCCCAAAIIIIAAAggggAACCARegHA88F1EAxFAAAEEEMhbAlpnvEmTJqa/VcqX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CCCAAAIIIIAAAggggAACCCCAAAIeAcJxLgkEEEAAAQQQyFUBwvFc5efgKSgw5s03bezkyYTjKdi3nBICCCCAAAIIIIAAAggggAACCCCAQPYECMez58feCCCAAAIIIJBNgVA43rJ+fZvYv382a2P3ZBY4dPiwXTt0qFUsW9Yeve22ZD6VXG37mIULbezEiYTjudoLHBwBBBBAAAEEEEAAAQQQQAABBBBAIIgChONB7BXahAACCCCAQB4SCIXjjWrWtBlDh+ahM+dUvQKbt261Jj16OF9eNXmyHXvUUSBlQWDMu+/a2PHjCcezYMcuCCCAAAIIIIAAAggggAACCCCAAAKpLUA4ntr9y9khgAACCCAQeAHC8ex10esffWTvLl9uY++4w/IfcUT2KsvlvT9evdquHz7cacWS556zsscem2MtOnz4sP196JAVyJ8/x47p14HGvP++jR03jnDcL2DqRQABBBBAAAEEEEAAAQQQQAABBBBIWgHC8aTtOhqOAAIIIIBAaggQjmevH7uNGmULly51Rt1r9H0yl2kLF9rAiROdU1g4erSdUrGir6ezbdcumzh3rukBgy3btjnHqlahgt1y2WXW7vzzfT22n5V3Gz/eFr77LuG4n8jUjQACCCCAAAIIIIAAAggggAACCCCQlAKE40nZbTQaAQQQQACB1BEgHM9eX970yCP2zrJlNqFfP7uoYcPsVZbLew+fMsWenzvXacVbjz1mNSpV8q1F32zebB1HjAiH4t4D9b/uOut51VW+Hd/Pits/9pgt/uwzwnE/kakbAQQQQAABBBBAAAEEEEAAAQQQQCApBQjHk7LbaDQCCCCAAAKpI0A4nvW+PHT4sF07dKgtXrvWzjr1VDuxTBn74ddfbd+BA3Z08eL25J135ujU5Fk/k//bs9ODD9qilSudf382YYIdX7JkdqtMd/+2gwfbkvXrne+P6NbNmpx2mh388097+F//Crfh8xdesGOKF/etDX5V3H70aFu8eDHhuF/A1IsAAggggAACCCCAAAIIIIAAAgggkLQChONJ23U0HAEEEEAAgdQQIByPrx9Xfv21PfvGG/brzp2mf6dXSh19tE0dMMBOq1IlvInW1A7yuuSX33efff7tt057//fyy76u/x0Kx2+65BIb3Llz2Gj/wYNW44YbnP/7PXo9vp6PcesCBaz9I48QjsfIxWYI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CEAAAhCAQEUR+PbbbyNRx9mOO+5oU6ZMSdTGG2+80c4555xM2fHjx1uvXr2i33OJ44sXL7Z58+aZwlWus846tuyyyyY6X1yh//73vzZ37lxbfvnlbc0117RmzZoVXZc78KuvvrLPPvvMVlttNVt99dVLri/NCpYsWWILFy40hZH97rvvopDoLVu2tJVWWilR38spji9atMi+/PJLW3HFFa1Vq1apdNv1U3nRS63z559/jsKj/vTTT7bqqqvaCiusUFIbP/nkE/vhhx+sbdu2tswyyxRdl/r48ccf269+9avonzPE1uRI0xqL5GesWzLXeBV7T9H9TbbUUktF/6rBKmEsxKka2enZ+Omnn9pyyy0XPX+WXnrpkoa8nGPxzTffRPet1q1b2yqrrFJUO/UM0/1PYrLux6pn5ZVXLrnfRTUmOEjzR+1S+/SznrP6p+dbPiu3OC7v+A8//DB6XhTLPuxDsfeobCwkIOufnrX6V8ozspzzON9Yxn2fljiu613vrLrO03h3LaYvhR5TzrFI456COF7oiFIeAhCAAAQgAAEIQAACEIAABCAAAQg0YQK+qLPJJpvYX//61wyNQYMG2cyZMzO/6zsJsbKLL744k2Ncv9999922xRZbRN/FieO//e1v7aKLLqqTe1PnPOWUU2z33XdPNArK93jFFVfYCy+8YC+//HLmGLVLdSmk6mGHHZZTTDrqqKPsn//8Z3SsBP2zzz7bJPZfdtll0YKuM9W51157Rd+ntQidqJO/FNIi++OPPx4x+8c//lGrbWE9EvKVQ75du3bRV2+//bYdccQRtYq9//77tX5fd911czZnxowZOYWKjz76KGKmsfjXv/6VqWuttdayLl26RPnrt9tuu5zniBuLO+64I6rXb6/aqvClmivaVBFnGruamhqTUC9TmP9dd93VrrrqKps4caJpM4gz5YHt2bOnDRw4MJHgIYFEdYiJ5p1fl+ad+jlgwIBI3MlnEpXGjh1rzz33XK0+agx1zSnVQTWL44oi8cgjj0QYJIzcc889GSTqmza0yDp06BAxdXbsscfaG2+8kfn9oYceMm2MCC3Nscg3Vkm/jxuvUu8pxx13XJ37peaIzqWw0fq3/fbb5xRWdC8eN25cphu6P+ZLnfH3v//dzjzzzMwx6623nt18882xKCpxLNTQNNglHftCyoVsb7nllkg4HDNmTHT/9q1Hjx5RbuM//vGPicSzUsfiscces+HDh8d25+GHH47uk7qudX3792bNSd3rTzjhhKwiqITAZ5991hRxRvdQ3QOzmZ67559/fvQsD033B90n8pk26+m+nNQkNut+o2etzuHf38M6NtpoI3v00UczH+sZPWzYsFrFCnnW6rl26aWX5myq2nTNNdfYq6++GoWQdyb2m222mR1zzDFFPWtLvUe5dujZq/bp2fj666/X4bftttva/vvvb/vtt1/eDZGlzuOkY15subTE8fCZofbo3Unv0bq3650i1xzW+9ehhx6a2Qj061//Onr3zie069q46aabMt3Xe+KRRx5Zlvt7Oe8pcQ1GHC92VnMcBCAAAQhAAAIQgAAEIAABCEAAAhBoggT22GOPjCClRek5c+ZkKGhx3l/EljjuFutOP/30KMenMwl98t6WheK4REOVzbUgrgW6bAvz7hxPP/20KS+6L2DHDZkWYiXer7322rEj6i9KSrTfeeed6yxu+wdqAVp9kphXXyYRRQufhdgrr7yS8bDWYrrGthTTInw270WJJRrXXCKCzn388cdHgnY2z7FwLCSIqHw20xy94YYbbOutt65T5N///nc0ls4kjuuz22+/PWt9EsknTJhgWljOZhI6TjrpJHvxxRdz4tTCtjZudO/ePWs51aENAbnm8LnnnhuJQz7b9957r5ShrNdjxUqbZZxpDDT+Ej3at29fqy3vvvtuZjFfeVwdl/Be5A5KcyzShBIKHSNGjCj5niIhKd+c69q1a3TfdBuTwj7pvqx0Gc7EVfeJXJ6c4b1d6TN0LYVWqWOhdqbBLs354eoKn40SqSQ2+5uLwvNKVNT9IFe0izTGYvLkyVnn7BNPPBG9J2jTQTbTvVf35tB0jasP+Z7b/nGTJk2yXXbZpU5dEtb79euXd2juuusu07WRxK688srofSGphZsIwyg6Setx5fS+ctttt8Uepognqj8U3+MKH3744dF1ms27vRzvPYpmc+edd0YbCPO9C6jNm2++ebRZLdvGvDTmcaH8Cy2fhjiuqAlJNm/ouhk8eHDm3dpvq6LgaIOf/16tjYXabJHL/Hd+lZs2bVrs+1QaY1Gue0q2/iGOFzqbKQ8BCEAAAhCAAAQgAAEIQAACEIAABJowAQl1vheUPI4V6lzet6EY7IdO1wK1FqqdOQFMv4cCwAYbbFDL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AIEILLVl1ettFo4vjvfAVDi+555lXWaOKwQIECBAgAABAgQIECBAgAABAgQILBkB4fiS6WoNJUCAAAECCy8gHN9j4TthiddgKhzfa6+y7uMfX+Iamk+AAAECBAgQIECAAAECBAgQIEBgaQkIx5dWf2stAQIECBBYUAHhuHB8QW/AUspUOH63u5V1H/vYQlfH9QkQGCOBbJWxbNmysnz58jGqtaoSIECAAAECBAgQIECAAAECdQHhuPuBAAECBAgQGJmAcFw4PrKbrceFpsLxu9+9rDv77IWujusTIDAmAps3by6rVq2qanvppZdWIblCgAABAgQIECBAgAABAgQIjJ+AcHz8+kyNCRAgQIDA2AoIx4XjC33zdsLxZdtvXy69/PKFro7rEyAwJgIbN24sBxxwQFXbdevWlZUrV45JzVWTAAECBAgQIECAAAECBAgQqAsIx90PBAgQIECAwMgEHvCAB5Srr766nHjiiWXNmjUju+5CXqgzIGDdcceVlXsIxxeyL3Ltte9+dzn9E5+oqnHVVVctdHVcnwCBMREQjo9JR6kmAQIECBAgQIAAAQIECBAYICAcd4sQIECAAAECIxPIsrT5ZynNuBOOj+z2GupCJ515Zjl5/frqWOH4UGQOIkCglCIcdxsQIECAAAECBAgQIECAAIHJEBCOT0Y/agUBAgQIECCwSAWE44urY4Tji6s/1IbAuAgIx8elp9STAAECBAgQIECAAAECBAj0FxCOu0MIECBAgAABAvMo0AnHLzjllLJ8553n8UpOPYzAaeecU44/44zqUDPHhxFzDAECERCOuw8IECBAgAABAgQIECBAgMBkCAjHJ6MftYIAAQIECBBYhAJbtmwpe+211x+D2D8t5b0Iq7mkqrTx8svLAccd98c+sef4kup7jSUwFwHh+Fz0vJYAAQIECBAgQIAAAQIECCweAeH44ukLNSFAgAABAgQmTKATpuyy887lwlNOmbDWjWdzNl15ZVn94hdXlReOj2cfqjWBhRAQji+EumsSIECAAAECBAgQIECAAIH2BYTj7Zs6IwECBAgQIECgEqjPHL/0jDPKsu22I7MIBHZbs6aqhXB8EXSGKhAYEwHh+Jh0lGoSIECAAAECBAgQIECAAIEBAsJxtwgBAgQIECBAYB4F9nvEI8oV3/lOOfXFLy773u9+83glpx5WQDg+rJTjCBDoCGzevLnst99+1f9edtllYAgQIECAAAECBAgQIECAAIExFRCOj2nHqTYBAgQIEBhHgYQLy5Ytq/5ZKuWIgw8uGz71qXLgox5Vjv2nf1oqzV7U7eyE4+vWrSsrV65c1HVVOQIECBAgQIAAAQIECBAgQIAAAQIE2hMQjrdn6UwECBAgQIBAH4FNmzaV1atXV0cspeWs159wQjnyrW8ty3feuVxg3/EFf49suf76stcznlHVQzi+4N2hAgQIECBAgAABAgQIECBAgAABAgRGKiAcHym3ixEgQIAAgaUrcN5555VDDz10yYWSWz7zmakwNuF4QnJl4QQ2XnVVOeDII6sKXHDBBWX58uULVxlXJkCAAAECBAgQIECAAAECBAgQIEBgpALC8ZFyuxgBAgQIEFi6AieddFI5+eSTK4ClNHO8XHxxOeQNbyjnf+lLllZfBLf/Ee95T9nw8Y8vvftwEdirAgECBAgQIECAAAECBAgQIECAAIGFFhCOL3QPuD4BAgQIEFgiAks5HF//2c+WI9/2tqqnzz3hhLJi992XSK8vrmZu/s1vyqqnPrWq1C677FIuvPDCxVVBtSFAgAABAgQIECBAgAABAgQIECBAYF4FhOPzyuvkBAgQIECAQEdgyYbj3/hGKVu2lD2f/vTyqxtuqILxBOTKiAVufOOy+uijy6b0RynlxBNPLGvWrBlxJVyOAAECBAgQIECAAAECBAgQIECAAIGFFBCOL6S+axMgQIAAgSUksGTD8WuuKeWHPywnnXlmOXn9+qrHj3nGM8pBj370Eur9hW3qluuvL8d/5CNl/dlnVxXZYYcdymWXXbawlXJ1AgQIECBAgAABAgQIECBAgAABAgRGLiAcHzm5CxIgQIAAgaUpcMQRR5QNGzYsvWDy+utLufzyqtP3e/GLyxVXXlmWbbddWXfccZZXH8FbYfPPflYOOemksumb36yulmD8zDPPLCtWrBjB1V2CAIFJEti8eXPZtGlT2WeffSapWdpCgAABAgQIECBAgAABAgSWlIBwfEl1t8YSIECAAIGFEzjggAPKxo0by8qVK8u6desWriILceWrrirlJz8pm6+9tux35JHV8uopx/7TP5UDH/WohajRxF8z1iefdVZZf95509p66qmnln333Xfi26+BBAi0L7DXXnuVLVu22JahfVpnJECAAAECBAgQIECAAAECIxMQjo+M2oUIECBAgMDSFljS4Xi6/k8BeZb43v+446oZ5CnLd965rHnYw8rKPfYoK0c8m3nTlVeWLX8K6hfq7myzzQnEz//Sl8p5X/5y2fj1r09rUgZlHHvssWaML1RHuy6BCRDYbbfdqlYcdthh5fDDD5+AFmkCAQIECBAgQIAAAQIECBBYegLC8aXX51pMgAABAgQWRGDJh+NRv+66Un70o1L++7/L2ne/u5z+iU9s1Rcrdt+9WnZ9j913LwnSf3jttQP7a/NPf1rNSp/ksvJe9yrlD38o5X//t5Tf/77671133rlqcow2/mnp+rpBllDPLPE1a9ZUKxYoBAgQmIuAcHwuel5LgAABAgQIECBAgAABAgQWh4BwfHH0g1oQIECAAIGJFxCO17o4s7W3bCkbv/jFctyb31yu+O53J77/R9HAhOF7ZAb+ypVl7733FoiPAt01CCwhAeH4EupsTSVAgAABAgQIECBAgACBiRUQjk9s12oYAQIECBBYXALC8d79bM3FFQAAIABJREFUsXnz5rJ+/frqgOxnu2zZsmkHr1ixotzylrdcXB06y9pcfvnlVRvbKrFKIB6jpltb13AeAgQIREA47j4gQIAAAQIECBAgQIAAAQLjLyAcH/8+1AICBAgQIDAWAsLxsegmlSRAgACBHgLCcbcGAQIECBAgQIAAAQIECBAYfwHh+Pj3oRYQIECAAIGxEFi7dm05/fTTq9m9l1566VjUWSUJECBAgEBHQDjuXiBAgAABAgQIECBAgAABAuMvIBwf/z7UAgIECBAgMBYCJ510Ujn55JOrul511VVjUWeVJECAAAECEdi0aVNZvXp1hXHqqaeWfffdFwwBAgQIECBAgAABAgQIECAwhgLC8THsNFUmQIAAAQLjKJA9tY888siq6ueee261R7RCgAABAgTGQWDjxo0l24OkrFu3rqxcuXIcqq2OBAgQIECAAAECBAgQIECAQENAOO6WIECAAAECBEYiIFgYCbOLECBAgMA8CNQ/wwzwmgdgpyRAgAABAgQIECBAgAABAiMSEI6PCNplCBAgQIDAUhfYvHlzWbVqVcVg1t1Svxu0nwABAuMlkGXV999//7Js2bJy4YUXjlfl1ZYAAQIECBAgQIAAAQIECBCYEhCOuxkIECBAgACBkQlkafWE5AcddFAVMCgECBAgQIAAAQIECBAgQIAAAQIECBAgQGBUAsLxUUm7DgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgsmIBwfMHoXZgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIERiUgHB+VtOsQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwIIJCMcXjN6FCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGBUAsLxUUm7DgECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgsmIBwfMHoXZgAAQIECBAgQIAAAQIEFrPAli1byrJlyxZzFdWNAAECBAgQIECAAAECBAgQmIGAcHwGWA4lQIAAAQIE2hNI4HD88ceX+9///mXNmjXtndiZCBAgQIBACwJHHnlkWb9+fTnmmGPKQQcd1MIZnYIAAQIECBAgQIAAAQIECBBYaAHh+EL3gOsTIECAAIElKnDaaadV4XjKiSeeKCBfoveBZhMgQGAxCtQ/ow488MBy7LHHLsZqqhMBAgQIECBAgAABAgQIECAwQwHh+AzBHE6AAAECBAi0I7B58+ay3377lV/96lfVCc8999yyYsWKdk7uLAQIECBAYJYCGzduLAcccED16l122aV88pOftLT6LC29jAABAgQIECBAgAABAgQILDYB4fhi6xH1IUCAAAECS0hg06ZNZf/9968C8uzpum7dOgH5Eup/TSVAgMBiE0gwfsghh5Rs/bHDDjuUM8880+fSYusk9SFAgAABAgQIECBAgAABAnMQEI7PAc9LCRAgQIAAgbkLZD/X7OvaKVm6NkvYKgQIECBAYJQCp59+elm7du3UJU899dSy7777jrIKrkWAAAECBAgQIECAAAECBAjMs4BwfJ6BnZ4AAQIECBAYLNAMyBNGZB/yzCZXCBAgQIDAfAtkkFY+i1IyYzwDtdasWTPfl3V+AgQIECBAgAABAgQIECBAYMQCwvERg7scAQIECBAg0F0gS6wffPDB5eqrr64O2Geffco73/lOXAQIECBAYF4FTjvttHL88cdX18ge4+9617sspT6v4k5OgAABAgQIECBAgAABAgQWTkA4vnD2rkyAAAECBAg0BLLH6xFHHFHOP/984bi7gwABAgRGIrB58+ay3377lT322KMalGXVkpGwuwgBAgQIECBAgAABAgQIEFgQAeH4grC7KAECBAgQINBPILPIly9fLqBwmxAgQIAAAQIECBAgQIAAAQIECBAgQIBAawLC8dYonYgAAQIECBAYlUBmmB9wwAFVeH7LW96yWv42YXr+Scn/m/k3qt5wHQIECCy8QD4XMrAqpfPfmRH+wx/+sGzcuLEcc8wx5aCDDlr4iqoBAQIECBAgQIAAAQIECBAgsKACwvEF5XdxAgQIECBAYDYCCToSjg9T9t1333Lqqaf2PHT9+vXVXrMJU3qVhO4JVnKuXuW8884rp59++sAqZS/1fgFNwpzU55e//GXfcx1++OFl5cqVPY+JUeoz6DwHHnhg33alPieffHIVMPUrT3jCE8qaNWt6HpLQKvXpd54MdEh9+rVrmPrkPI9//OP7tiv9nXZdfvnlPes8zHmGbdeg+gzTrlR0kPOw5xlVvw9bn7beF4vtPLmX817tVeKTrSQGlWHOc8ghh0yFw93OlwFD6fd+9cn9nPOkXv1KznPsscf2fb8Pc548M0488cQ5n2eQX34ew3Xr1g1zqGMIECBAgAABAgQIECBAgACBCRYQjk9w52oaAQIECBCYVIEEmwm1szd5wtarr766Z1N32GGHctlll/X8eYKpDRs2DKRK6Ja9aHuVYc+zyy67lAsvvLDneU466aQqtB1UBgU9w9Zn0HnifOSRRw6qThnUrrVr1w41eGBQfYb1SRB46aWX9qz3aaedVg1CGFTuete7lk9+8pNz7q9B5xm2PqnIVVddNe/1GdZ5UL8Pe/+01a5B9WnLedh2DXr+DFufcTtPWz7DnqfXGyL3w6677lqtJpJBSZ3VRQa97/2cAAECBAgQIECAAAECBAgQmFwB4fjk9q2WESBAgACBJSWQGY+d2d+ZDdz577333nvgTOQEMINKZo0nYOlVcv0EXf1mXCawzczffjPQ8/oEk4Nmbg4zczz16TcjPm0ZZgZxgu1B5xk0Yzcz2dOuQWXQzOg4pz6DyjAzbYeZsTuoXcPWZ9B50t/DOA/TrmHO01Z9hjnPMPdzW+cZdP8M+/4adJ68H9KuzjLeve7HNs4zzHMj9cn7fVDJM6zf86cz8GjQ+33Qc7XN82RVjkHPw7Q7TnvssccUQb8VKAY5+TkBAgQIECBAgAABAgQIECAwuQLC8cntWy0jQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgT8JCMfdCgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAw8QLC8YnvYg0kQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAeG4e4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEJl5AOD7xXayBBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQICAcdw8QIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwMQLCMcnvos1kAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSE4+4BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEJh4AeH4xHexBhIgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQICAcNw9QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQITLyAcn/gu1kACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQEI67BwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBg4gWE4xPfxRpIgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAsJx9wABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQITLyAcHziu1gDCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQEA47h4gQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgYkXEI5PfBdrIAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgIx90DBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDDxAsLxie9iDSRAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAAB4bh7gAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQmXkA4PvFdrIEECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgIBx3DxAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAxAsIxye+izWQAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBITj7gECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQmHgB4fjEd7EGEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgIBw3D1AgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAhMvIByf+C7WQAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAQjrsHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGDiBYTjE9/FGkiAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECwnH3AAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhMvIBwfOK7WAMJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAQDjuHiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBiRcQjk98F2sgAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECAjH3QMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMPECwvGJ72INJECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAHhuHuAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBCZeQDg+8V2sgQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAgHHcPECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMDECwjHJ76LNZAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEhOPuAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCYeAHh+MR3sQYSIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAgHDcPUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECEy8gHJ/4LtZAAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEBCOuwcIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAYOIFhOMT38UaSIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLCcfcAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECEy8gHB84rtYAwkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBAOO4eIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGJFxCOT3wXayABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQICMfdAwQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAw8QLC8YnvYg0kQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAeG4e4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEJl5AOD7xXayBBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQICAcdw8QIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAwMQLCMcnvos1kAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSE4+4BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEJh4AeH4xHexBhIgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQICAcNw9QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQITLyAcn/gu1kACBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQEI67BwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEBg4gWE4xPfxRpIgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAsJx9wABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQITLyAcHziu1gDCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQEA47h4gQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgYkXEI5PfBdrIAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgIx90DBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIDDxAsLxie9iDSRAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAAB4bh7gAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQmXkA4PvFdrIEECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgIBx3DxAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIDAxAsIxye+izWQAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBITj7gECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQmHgB4fjEd7EGEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgIBw3D1AgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAhMvIByf+C7WQAIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAQjrsHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQGDiBYTjE9/FGkiAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECwnH3AAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhMvIBwfOK7WAMJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAQDjuHiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBiRcQjk98F2sgAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECAjH3QMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgMPECwvGJ72INJECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAHhuHuAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBCZeQDg+8V2sgQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECAgHHcPECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgMDECwjHJ76LNZAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEhOPuAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCYeAHh+MR3sQYSIECAAIGlKfDLX/6y3HDDDVXjt9lmm/KXf/mXEwtx3XXXld/97ndT7bvNbW5TbnSjG01se3s1LAaf/vSny5YtW8qjHvWosv322y85Aw0mQIAAAQIECBAgQIAAAQIECBAgQKC3gHDc3UGAAAECBAiMjcDPfvazsu2225bttttuYJ1XrlxZrrnmmqnjrrrqqoGvGdcD/v7v/7587Wtfm6r+17/+9XLLW95yXJszq3onGH/Qgx40rc8/97nPld13331W5/MiAgQIECBAgAABAgQIECBAgAABAgQmT0A4Pnl9qkUECBAgQGAiBBJ2fvzjHy9XXHFF2bRpU7nkkkvK9ddfX7Xtdre7Xbnb3e5WVqxYUR7ykIeUPffcc6s252ed4/ND4fhE3BY9G3HOOeeU5zznOdN+nv8/6qijFqThv//978vVV189de0MVli2bNmC1MVFCRAgQIAAAQIECBAgQIAAAQIECBD4o4Bw3J1AgAABAgQILDqB733ve+X5z39+ueyyy4aq21Of+tSydu3acpOb3GTqeOH40po5/oEPfKAcffTR0+6XJz3pSeV1r3vdUPdQ2wdlafe99tpr6rT3uc99yoc//OG2L+N8BAgQIECAAAECBAgQIECAAAECBAjMQEA4PgMshxIgQIAAAQLzK/CHP/yhrFu3blazfZ/+9KeX448/fqqCwvGlFY5nj/msJlAvH/3oR8s973nP+b1pe5y9GY5ndYPMblcIECBAgAABAgQIECBAgAABAgQIEFg4AeH4wtm7MgECBAgQINAQOPvss6sZ482SYDEzb/fYY4/yi1/8olx00UXl//7f/zvtsGc961nlZS972dSfCceXVjiejs+KAxlc8V//9V/lH/7hH8q9733vBXuPCccXjN6FCRAgQIAAAQIECBAgQIAAAQIECPQUEI67OQgQIECAAIFFIfCb3/ym2j/8mmuumVafE088saxZs2arOn71q18tT37yk6t9xQ855JDy8pe/vGyzzTZTxwnHl144vihu5D9VQji+mHpDXQgQIECAAAECBAgQIECAAAECBAj8UUA47k4gQIAAAQIEFoXA6aefXu0b3inbbbddtUfzXe961571+853vlM++9nPloMPPnirY/qF45l9fu2115Zb3epW5S/+4i/m1P4s551z7bLLLuUWt7jFnM6VF//+978vP/7xj6vZzzvttFNZtmzZtNC/2wX+/u//vnzta1+b+tHXv/71cstbzk84fsMNN5Rf/epX1bVuc5vbzKm9CZBzvh133LFsu+22czrXfLz4d7/7XfnJT35Sfvvb35Zdd9213PSmNx36MsLxoakcSIAAAQIECBAgQIAAAQIECBAgQGBkAsLxkVG7EAECBAgQINBLIGHr/e9//2oWeKe89KUvLc9+9rNnjdYtHH/ve99bTj755PKzn/1s6rwJ4R/1qEeVV7ziFVVIO0z55Cc/WdavX1++8pWvTDvX7W53u2qP6xe96EVl9913H+ZU1TFXXHFFOe2006p/X3bZZVu97rGPfWx5whOeUB74wAd2PedMwvEzzzyzvOUtb5k6z/7777/VUvZvfetbq+XJUzJ4IHt3f/nLXy6ve93rysUX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AoTjicrNwxBAAAEEEEh6ApZwfOXYseLl+d9ZsM4uoVuVdwsMlF1HjsTa1WweHjKgZUsTfkctGqBfvXFDMmfIEK8h/n3lity7d0+ye3jE6z4qJx0B/cFG6PHjZsCsHE86885I7RM4cTlM+q//RPZdOGhzQ7qUaeXXd5ZK8mTJ7WuIWggggAACCCCAAAIIIIAAAggg4NYChONuPb0MDgEEEEAAgScvoGeO6/bqg1q3lnavv/7kOxSPHkRGRsqmfftk8/79EnbunGRIl0506/NKJUpI8YIFrVulx6NJqiLwSAKXr16VMq1bm3tLliwpq1ateqR2uAkBdxaIlEiZsfsbmy3WA18eIjUKVHXnYTM2BBBAAAEEEEAAAQQQQAABBBCIhwDheDywqIoAAggggAAC8RcICAiQwMBAm7Ov498KdyCQtAVWb94sHceONQht27aVwYMHJ20QRo/AAwTOXwuXBaFL5NXCNaVY1sJYIYAAAggggAACCCCAAAIIIIAAAlYBwnFeBgQQQAABBBBwqICuGtfV45nSp5c9s2Y59Fk0joC7CvSaOFEWBweb4X366afSuHFjdx0q40IAAQQQQAABBBBAAAEEEEAAAQQQQMBhAoTjDqOlYQQQQAABBBCwCLjquePMIALOIuDTpYuEnf8/e28CJ8ddnvk/XVV9z63RLfmU75PLlmQT2yFgjiRcEgnkgkDyd0KyCwGS7Gc3F9mTkCW7sJBNPsnGJgnBZgMkCwYCtjEYjLE5YluyjQ3WLY1Go5npu7uq6/953l9VqzWW5bEsWZrRU9B0T3cdv9+3alpC33red78N5/bbb8fFF198qgxN4xABERABERABERABERABERABERABERABERCBBUNAcnzBnCoNVAREQAREQAQWLoGF3Hd84VLXyBcLgS1PPolXve99Np3BwUE89NBDi2VqmocIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIPK8EJMefV9w6mAiIgAiIgAicngR6fcevvhp/+d73np4QNGsROEYCH7r1VvzZbbfZ1uvXr8cnP/nJY9yTNhMBERABERABERABERABERABERABERABERCB05uA5Pjpff41exEQAREQARF4Xghs2bIFr3rVq+xY93z0o1izdOnzclwdRAQWOoHZWg3XvPOd4DOX3//938fb3/72hT4tjV8EREAEREAEREAEREAEREAEREAEREAEREAETgoByfGTgl0HFQEREAEREIHTj8ArX/lKbN26FZte9jL86U03nX4ANGMROAYC/alxllT/xje+gaGhoWPYkzYRAREQAREQAREQAREQAREQAREQAREQAREQARGQHNc1IAIiIAIiIAIi8LwQuO222/DepKS60uPPC3IdZIETmJsa/+Vf/mX8wR/8wQKflYYvAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiePgOT4yWOvI4uACIiACIjAaUdg48aN2LVrF971lrfg3a9//Wk3f01YBJ4Ngdvuugvv/V//q7fJPffcgzVr1jybXWhdERABERABERABERABERABERABERABERABERCBPgKS47ocREAEREAEREAEnjcCaXp8aHAQ93z4wxgql5+3Y+tAIrCQCDA1/qr3vQ879++3YW/atAl/+qd/upCmoLGKgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIwClHQHL8lDslGpAIiIAIiIAILF4Cs7OzYHq8UqngxmuvxV/823+7eCermYnAcyDwq3/yJ/jifff19vDJT34S69evfw571KYiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAKS47oGREAEREAEREAEnlcC/b3H3/XmN+Pdb3jD83p8HUwETnUCH7r1VvzZbbf1hqnU+Kl+xo59fHEcH/vGz7BlJpM5YfvWjkVABERABERABERABERABERABERABERgoRKQHF+oZ07jFgEREAEREIEFTOA973kPPvWpT9kM/uJ978ONV121gGejoYvA8SPAtDhT4+ly0UUX4Qtf+MLxO4D2dNIIHE2EnyiR/XTHPFHHO2lwdWAREAEREAEREAEREAEREAEREAEREAERmCcByfF5gtJqIiACIiACIiACx5fAK1/5SmzduhXsP/7J3/99XHzWWcf3ANqbCCwwAluefBI/84d/CPYb5zI4OGhifM2aNQtsJhruXAJHktQuNB4jiiI0mg3Ua3U0m01Uq1U0Gg10Oh1EYdjbVYwYth/3XzAYHvgBfN9HLpdDoVhEqVRCMX0uFOAHgW1M9fpmAAAgAElEQVTjQuSHJ8klyHWdioAIiIAIiIAIiIAIiIAIiIAIiIAInI4EJMdPx7OuOYuACIiACIjAKUBg586doCBn/3EK8g/edJMS5KfAedEQTg4BJsbf+9GP9sQ4R6E+4yfnXDyXozoRnUns9eF74metVgszszOYOjCFyf37MXXgAA4kj5npg6hUa6jV6+i0WojiGHG3axac/+FOu8l7YRQBybF4vCAIUCgUUCyV7Pt06fg4xpcuxZIlS7Bs2TIsW74c40vHUSqV5w7KWXYtIiACIiACIiACIiACIiACIiACIiACInCaEJAcP01OtKYpAiIgAiIgAqcigXvvvRfveMc7TJBz2Xz99fj9t74VQ+U5AudUHLzGJALHiQD7i7PPeP/yrne9C+9+97uP0xG0m+eDwJHS4bV6DQf2T2Lfvr3Yu28Ce3bvxv6JCUxOTuLgwYOYmZ5GtVZDq9lEJwwtEe5lPPjZAIHnIeP58LyME+4Aut2uJc35SF8zYd7lz5Yqjy1JXiwULEVOUT4+Po7lK1Zgzdq1OOPMM3HG2rVYtXo1hoaH4XneYWiUJn8+rhQdQwREQAREQAREQAREQAREQAREQARE4GQSkBw/mfR1bBEQAREQAREQAWzZsgW/9Vu/ZSXWuVx87rn405tuUpl1XRuLngDLpzMtztR4//LBD34QmzdvXvTzX2wTTOU40+Hbtm3DI1u24Ec/+hFYJWNiYgJTBw/ajUBhp2Np7Ww2a2XPA9+3R8b3TWxbTjwR4hmz5SSVsfLoTJJTglOMc+GzvUdpztf8LBXnYYgwDE2k8/1CPo/R0VGsXr0a55xzDi655BKcf9GFWLNmLfL5vO0vleO9BPxiO0majwiIgAiIgAiIgAiIgAiIgAiIgAiIwGlPQHL8tL8EBEAEREAEREAETj6B2dlZ/NEf/RE+9alP9Qaz/pJL8O7Nm8FnLSKwmAhQin/qq1/FX33uc9g5MdGbGnuM33rrrbj44osX03QX5VyOlBLnRGu1Ku6//wF8+UtfwkMPPmgJ8Xang2wu5x6U4cnDRDgT4UyIJx3BPd+3kuzduGuf8WPKchPjmYwrs84C665huXt/zmuuQ1FOSZ6mzNm7nMl0PvNBMX/mGWfgsssvxwte+AJcdPEllizn2PoXJckX5eWrSYmACIiACIiACIiACIiACIiACIjAaU1Acvy0Pv2avAiIgAiIgAicWgT+6q/+Cu9///sPG9TFZ52Ft7/mNdh0/fWn1mA1GhF4lgQoxf/68583Kc7X/ctFF11kYnxoaOhZ7lWrnywCabqaqe1O2EHcjXH//ffjf3/sY3jg/vsxODIC3vDAVDalM0Vzmvz2KL49z8qa978+moxOk+M05nPl/GGCvC9J3o0oyiPwuduNTJqngrzTbiOOIutHvn79evzYDTfg/PPPt5/TcuuS4yfr6tJxRUAEREAEREAEREAEREAEREAEREAEThQByfETRVb7FQEREAEREAEROCYCLEH8oQ99CF/84hd7vci5ozVLl2LDJZdYkpwP/qxFBBYCgXu3bMGX7rsPt91111OkOOXp29/+dvUXXwgnMhljKsX5PHXgAB597DFs374d1WoV93z96/jOAw+gWCphdGzMlU73fRPgXJj3tu1ZLZ3vMzVuCfFDjyOiYLl028GhxLjJ9r7keLqdHcPKrbvy6ybHe4I8KcFuqfIQnU6IbhjafpcvX46NGzfi+h+/ARdcdHHvRo30OBLlC+gi1VBFQAREQAREQAREQAREQAREQAREQASeloDkuC4OERABERABERCBU5IAS60zSc4H+/TOXVJZ/oqrrjJRzoS5FhE4FQhsefJJfOnb38Y3t2zBvQ89dMQhse8zpTh7iystfiqctWceQ39au9lsYPu27SbDb7/9djy8ZQtmZmYslT00PIyVq1bZeWVi3OS45x0qf951JdOPJMeP1Ov7kATnGGN0Y+tAbgPuH9Pc16kktx7lSd9xk+VpuXX2JI9YZj2yPugcOyX+xRddhNe89rVYv2EDli5deij1TqmfSP5npqU1REAEREAEREAEREAEREAEREAEREAERODUJCA5fmqeF41KBERABERABESgj8Btt92GL33pS/jmN795RFGerkpJvmbZMlxy1lkYKpdNmPP5VF0oUeeW1z4ZY/3mww+fjMOekGMOJ+f9ue48vZaebj88bzx/XNg3fMfkpPWOvvdf//Woh6YUf/e7321SXMvCINCfFOeIJyb24b57v4Uv3n477vv2t7F3YgLNRtNEM0ulj42OYlUqx7PZnlw2Qc5Edxw7MU5BzveYIve8Hoy5JdP5GaV2+syy6hkmyOeUVz+stHqSUud6aSl3fs79OEEeOklOMR5F6CRynO8xRT42MoIN11yDl7/iFbj0sstQKpVsfJLjC+Oa1ShFQAREQAREQAREQAREQAREQAREQASenoDkuK4OERABERABERCBBUVgy5YtJsnT5127di2o8WuwpxcByvANGzZYT2c+r1mz5vQCsMBn2y+qKZVnpqfxpS9+EX9/y8exY+cO1FstVKpV1Op1k86B72N4eBir16zByMiIlVVnetx6i1OAJ2XRKbZ9yvEgcOlvJrKZzE7WoYTm/o4kpFmSnWnwI33WL8hT9Gnp9X45nkpyPjM1HoYssd5xkpzynM+dDq655hr87M//HC677HKUy+Ve+fcFflo1fBEQAREQAREQAREQAREQAREQAREQgdOYgOT4aXzyNXUREAEREAERWAwE2KOcDy47duzove5//7B5Uiody2MxwDrKHNgXW8tTCbAn+CWXXPKMaCi9+8V3KsIlw58R3Sm7wmFiPO5ix7bt+OdPfxqf//ztODB1ANl8HvVGA7v37EGVrR8ovH0fA6UyVq5eZSXJc7mcCfJUjvf372Zy3GR4XxI8hZEmtOemyPthWQI9SZyn6z1dsjsV5JThaZI8LbHOZ5PiUYR2u22vWYadZdYp8M86+2z87JvfjGuuvRYjo6O9Pumn7InTwERABERABERABERABERABERABERABETgKAQkx3V5iIAIiIAIiIAIiMB8CDDFSak+n+enW2eulOdx+9872s/PZt00nTqffTOxerRHIu+Ous6J2AeP+3SP+ZwvrSMCz4FAfwKb8njXrp34h7/9O3zh9tvRbLVQGhyAH2Sxd+9esHpFvV63VLXveSbDly9fjhUrV6JYLDpBnqTHTY4n40pFNp/TR5oipzh3v/KH9/me+/NcGX6oP7nbrn/9VJBzv4fKq0e910yPM0XeTpLkfG3rhSGWL1uKN7/l5/Cyl78cS8bH7SYAlVh/DheYNhUBERABERABERABERABERABERABEThpBCTHTxp6HVgEREAEREAEREAEREAEROBUJJDKcaaptz35JG75q7/CPd/4BmrNJoaGh5HN5Uwk79q5Ezt27kSj1QJ1NqUx09yjSd9xVh7I5/MmzNPP+qV1v7xOZbP1Ie+T4nMldz+v9DO+d5hg71upP4Xe2xdg5dMtSR7HlhpP5bj1IE8S5NaXPIoQR5GVid+0eTNefuONYLsAlouXID8Vr16NSQREQAREQAREQAREQAREQAREQARE4GgEJMd1fYiACIiACIiACIiACIiACIhAQqC/RzeT4X/zl3+JL37pSwijEMOjY8jl8yaVKZBNjjM53mw6Oe55JoxLpRJWrFhhkpxynI+Agjz5PJXUvT7kSfWFNDHe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3VK2bFl57LHHJH369E43//zzz+WNN96wf0Y47tu5CbTWYmJipG7duqIvdjiWrVu3iu7gkBIlKipKLl26ZG4dFhYmBQsWTIlucE8EEEAAAQQQQAABBBBAAAEEEEAAAYsLEI5bfIIZHgIIIIBAcAk88cQTsm3btkR3Wq/Nli1boq/354WE477R1i3RZ8yYISNGjPCowfz588t7770nlStXttcnHA+tleP6zOjLEo7HGujDsG7duhQLpUeNGiVTp061P5OfffaZ1KxZ06NnmkoIIIAAAggggAACCCCAAAIIIIAAAgh4KkA47qkU9RBAAAEEEPCDAOE426p785gdO3ZMevbsKevXr/fmMnOe+LJly6Ro0aLmOsLx0ArHdc7Hjx8vEyZMsD83Dz30kMyePdur58iXlV3D8Y8++khq167ty1vQFgIIIIAAAggggAACCCCAAAIIIIAAAkI4zkOAAAIIIIBAAAm4huMNGjTwqncadmnwGQyFleNJm6Xo6GipX79+rK2xdf4ffPBBqVChguTNm9fsRPDjjz/KoUOH7DfMmTOnLFy4kHBcREL1zHE9k/6bb74xz0alSpWkSZMmkjVr1qQ9lEm4mnA8CXhcigACCCCAAAIIIIAAAggggAACCCDgsQDhuMdUVEQAAQQQQCD5BRzD8cKFC8uaNWuS/6YpdAfC8aTBz507V15//XWnRu677z559913JU+ePE6fa5Det29fmTdvnmgwvmDBAilevLi9DivHQ2/leNKePt9fTTjue1NaRAABBBBAAAEEEEAAAQQQQAABBBCILUA4zlOBAAIIIIBAAAn4Kxy/ePGiXL161ZxPHhER4VMBPc/4xIkTcvPmTXN+cerUqd22769wXIPhI0eOSLp06SRfvnwSFhaW6PHquNSuQIEC9hX6+/btkzp16tjbbNiwoUyfPj3R9/DkQp27WrVqydmzZ+3V27RpI4MHD47T+/bt2zJz5kypV6+eUzCuDcQXjus8njx5UnSlcaFChSRNmjSedNFtHV/Ohe0Gem62bi+vK+Zz5coladOmjbd/P/30kzz77LP2Osm5clztTp06ZfqUI0cOSZUqVaLt9Hd1/vx50X/qjgCBWKKiouT06dNmrPoShjeFcNwbLeoigAACCCCAAAIIIIAAAggggAACCCRWgHA8sXJchwACCCCAQDIIJGc4vnHjRvnwww9l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AQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQsL0A4bvkpZoAIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAoTjPAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAApYXIBy3/BQzQAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABwnGeAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABywsQjlt+ihkgAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggADhOM8AAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIDlBQjHLT/FDBABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAgHCcZwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwPIChOOWn2IGiAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAOM4zgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBgeQHCcctPMQNEAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEECAc5xlAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEELC8AOG45aeYASKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIEI7zDCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIWF6AcNzyU8wAEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQIx3kGEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQsL0A4bvkpZoAIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAoTjPAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAApYXIBy3/BQzQAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABwnGeAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABywsQjlt+ihkgAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggADhOM8AAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIDlBQjHLT/FDBABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAgHCcZwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwPIChOOWn2IGiAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAOM4zgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBgeQHCcctPMQNEAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEECAc5xlAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEELC8AOG45aeYASKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIEI7zDCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIWF6AcNzyU8wAEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQIx3kGEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQsL0A4bvkpZoAIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAoTjPAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAApYXIBy3/BQzQAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABwnGeAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABywsQjlt+ihkgAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggADhOM8AAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIDlBQjHLT/FDBABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAgHCcZwABBBBAAAEEEEAAgQAQOH36tERHR5ueRERESPbs2QOgV9bqgvqqs62kS5dOcuTIYa1BMhoEEEAAAQQQQAABBBBAAAEEEEAAgTgFCMd5OBBAAAEEEEAAAQQQSGGBw4cPS61atey9aNiwoUyfPj2Fe2W92+/bt0/q1KmDs/WmlhEhgAACCCCAAAIIIIAAAggggAAC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ujds2JD+9Kc/pU022SR77njxM9X/8pe/pNe+9rUpZqbHv8d/KwQIECBAgAABAgQIECBAgAABAs0hIBxvjnHWSwIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECDS1gHC8qYdf5wkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQINAcAsLx5hhnvSRAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEBTCwjHm3r4dZ4AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQLNISAcb45x1ksCBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAg0tYBwvKmHX+cJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDQHALC8eYYZ70kQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAUwsIx5t6+HWeAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECzSEgHG+OcdZLAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQINLWAcLyph1/nCRAgQIAAAQLlBVavXp3iT0dlwIABaciQIWUrWr58edlthg8f3uk20Y6lS5em9evXd7jdwIED06hRo1K0q6PS0tKS1dNZif3Hjh3brXpuvvnm1qp32223NHHixE6NlixZkubPn99pe7beeut07rnnpuhfR6WSemLfKVOmpM6sFy5cmBYtWpSNe0djH+2I9owePbrD9syePTvrV7nxKlfPJZdckubMmdNpPTFeUc+4ceM6bE/UM2PGjLLjPnPmzLL9ivaUO3/KtSecoz2d+VTSr1Ln+H1s7/yfPn16p+dh/I5GXZ2VOA/jfO7s/Infrxj3zs7VOEb8fnW2Tenve0evNeVeN+JYhXO5I5uyL042IECAAAECBAgQIECAAAECBBpCQDjeEMOoEwQIECBAgEC9BAoBSyHojf//85//XPHhy4VTlYSJERBVI7yLRkc9nYWJ559/ftnQNuqZPHlyFrh2VKZOnZqFreVKhG5h1FEZM2ZMiuCtXIlQctKkSR1uNnLkyE4D/8KO5fo1YcKEVEnoX66eY445Jq1cubJct8o6V9qecs7VqmfEiBFpzZo1Pe7X6aefXvZmhjhIhK2zZs3q8HiV1lNuvCr1qVZ74maPefPmddivSttTrl+V+kQYvWDBgpo7V9qecs6V3BQRnSn3uhH1dHZTTdwIE2F//Ik2KQQIECBAgAABAgQIECBAgED+BITj+RsTLSJAgAABAgRyKDBt2rQUszx7WsqFU3kLSSsNp8qFrZWG4+XCqUrbE8FdZ7NJKwn9t9pqqyxo7WxmdIRlcUPDhg0b2pwapccud1NEudAtKo+bIqKecjPH4yaEcjO148aBzmb7xw0I0aYonR0vbqzo7Odx40DxLPr2fn+iX1FPZzP94yaUSn7/yrWnknry1p4wK9evGK9YNaBQ4v9Lz4EYp7iBpdx4xbh3dv7EMcqtPBBtid+Lzm74qOT3q5Lf02hPuXC80nrK3YRQ6c0e0aZyNx719L3E/gQIECBAgAABAgQIECBAgED3BITj3XOzFwECBAgQINBEAhE0xYzl9squu+6aYrZgJSVCqQg3OwsB6xkmRnsi+O2sPRGSVTJTu5JljcvNsC7MuKzE0jYECDSfQHuvR119rMOKFSvaDf+jnng97MnNJ1F34UaZcjfoNN/o6TEBAgQIECBAgAABAgQIEMiHgHA8H+OgFQQIECBAgEDOBWIWZAQzEZwMHTo0m3XbWaic8+5oHgECBAgQIECAAAECBAgQIECAAAECBJpOQDjedEOuwwQIECBAgECpQCy1HEG3sNu5QYAAAQK1FohHBMTjD8o9bqHW7VA/AQIECBAgQIAAAQIECBBoRgHheDOOuj4TIECAAAECrQIRUsTzxGMm+OLFi8kQIECAAIGaCkyYMCG6wcaSAAAgAElEQVQVHjPh2eQ1pVY5AQIECBAgQIAAAQIECBDYSEA47qQgQIAAAQIEmlYgQvEIx6NstdVW6e67725aCx0nQIAAgfoILFmyJJ1xxhmtBxOQ18fdUQgQIECAAAECBAgQIECAQAgIx50HBAgQIECAQNMJxLPDY+ZeS0tL1vddd901XXzxxdnscYUAAQIECNRaIN5/xo8fnzZs2JAd6txzz02TJk2q9WHVT4AAAQIECBAgQIAAAQIEml5AON70pwAAAgQIECDQXAKlwfjw4cPTvHnzPG+8uU4DvSVAgECvC5QG5PFoDzdp9fqwaAABAgQIECBAgAABAgQINLiAcLzBB1j3CBAgQIAAgbYCxUupjx07Ns2aNQsRAQIECBDoFYEIyMeMGZMde+DAgSkC8gEDBvRKWxyUAAECBAgQIECAAAECBAg0g4BwvBlGWR8JECBAgACBTOD8889P8+fPz/571KhR2YxxhQABAgQI9KbAJZdckmbMmJE1wU1bvTkSjk2AAAECBAgQIECAAAECzSAgHG+GUdZHAgQIECBAIMVy6sOGDcsk9tlnn3T55Zebnee8IECAAIFcCJx++ulp6dKlWVtWrVqVizZpBAECBAgQIECAAAECBAgQaEQB4Xgjjqo+ESBAgAABAu0KRPiwYsWKLBiP5WsVAgQIECCQB4G4gStWN4lVTUaPHp2HJmkDAQIECBAgQIAAAQIECBBoSAHheEMOq04RIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQLGAcNz5QIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQINLyAcb/gh1kECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQEI47BwgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECg4QWE4w0/xDpIgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAsJx5wABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQINLyAcLzhh1gHCRAgQIBA8wqsXr06LV++PI0aNSoNGDCgeSH0nAABAgT6lEC8dy1dujRNnDgxDRw4sE+1XWMJECBAgAABAgQIECBAgECeBYTjeR4dbSNAgAABAgR6JHD66ae3hgvTp0/vUV12JkCAAAEC9RIYM2ZMamlpycJx71/1UnccAgQIECBAgAABAgQIEGgGAeF4M4yyPhIgQIAAgSYVGDZsWFq/fn0aO3ZsmjVrVpMq6DYBAgQI9DWBCRMmZCufDB8+PC1YsKCvNV97CRAgQIAAAQIECBAgQIBAbgWE47kdGg0jQIAAAQIEeiowaNCgrIrJkyenKVOm9LQ6+xMgQIAAgboInH/++Wn+/PnZsVatWlWXYzoIAQIECBAgQIAAAQIECBBoBgHheDOMsj4SIECAAIEmFIjlaGNZ2ihz585No0ePbkIFXSZAgACBviiwcOHCNG3atKzpixcvTkOGDOmL3dBmAgQIECBAgAABAgQIECCQOwHheO6GRIMIECBAgACBagjEcrSxLG2UWJI2lqZVCBAgQIBAXxAofg9zg1dfGDFtJECAAAECBAgQIECAAIG+IiAc7ysjpZ0ECBAgQIBAlwSE413i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KvCyCQECBAgQIECAAAECBAgQqERAOF6Jkm0IECBAgACBPifQzOF4DNbq1avTMccckzZs2NA6dqMPPjhNPPZYIXmVz+aWhx5KU7/xjRR/R4lgfNSECdmz3yPcmjhxYpo+fXqVj6q6DS89m25Ze0cWlP/l2bUZyK1r7wTTRYEIwQuzwnfZcqd00E77pQN33s9M8S461mLz888/P82fPz8NHz48LViwoBaHUCcBAgQIECBAgAABAgQIEGg6AeF40w25DhMgQIAAgeYQKF5a/K677koDBgxojo4X9TKC2alTp6alS9vOsI2l1g8ZOjSNOvjgNHzIkKZzqUaHVz/+eFq+YkVa+vvfp5tXrEjrn3t1qe+J48enlocfzmZ7RolQa968eU15/lXDudZ1RLje18veb9gjbbXZln29G9rfjsCECROy1xLhuNODAAECBAgQIECAAAECBAhUT0A4Xj1LNREgQIAAAQI5EliyZEk644wzshYtW7asqZekDYuYfVgIbEuHaeD226eBO3T9+cpb9++fPdO8miXqq9bz0WMmdyG07m4bY/8V/zsjvFDH6sceSxGOlytmjJcT8nMCBDoTKNzkNXDgwOx9TCFAgAABAgQIECBAgAABAgR6LiAc77mhGggQIECAAIEcCjT7surtDUkstR5BeUtLS7r55pvTmjVrcjhyfb9JY8eOTVOmTGnqGzL6/ijqAYHeFyheAWXVqlW93yAtIECAAAECBAgQIECAAAECDSAgHG+AQdQFAgQIECBAYGMB4XhlZ0UE5vGnUNatW5eF55WWjmajV7p/HraLJYsrKUOGDElbb711dmNBe+WQQw7Jlj9WCBAgUA0B4Xg1FNVBgAABAgQIECBAgAABAgTaCgjHnREECBAgQIBAQxmUaLoAACAASURBVAoIxxtyWHWKAAECTSMgHG+aodZRAgQIECBAgAABAgQIEKijgHC8jtgORYAAAQIECNRPIGY/jxkzJjvg3Llz0+jRo+t3cEciQIAAAQI9FJg6dWpatGhR2nXXXdNNN93Uw9rsToAAAQIECBAgQIAAAQIECISAcNx5QIAAAQIECDSswKBBg7K+TZ48OXsGtEKAAAECBPqKwIQJE1KsghKPa1iwYEFfabZ2EiBAgAABAgQIECBAgACBXAsIx3M9PBpHgAABAgQI9ERgxIgRac2aNWns2LFp1qxZPanK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r3pi3CMIj1LpkvjN+h6p3wQIECBAgAABAgQIECBAIG8CwvG8jYj2ECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEDVBYTjVSdVIQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjkTUA4nrcR0R4CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqLqAcLzqpCokQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgbwJCMfzNiLaQ4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJVFxCOV51UhQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCQNwHheN5GRHsIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoOoCwvGqk6qQAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBPImIBzP24hoDwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUXUA4XnVSFRIgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA3gSE43kbEe0hQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgaoLCMerTqpCAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEMibgHA8byOiPQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQdQHheNVJVUiAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECeRMQjudtRLSHAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBKouIByvOqkKCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBvAsLxvI2I9hAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA1QWE41UnVSEBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI5E1AOJ63EdEeAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKi6gHC86qQqJECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIG8CQjH8zYi2kOAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECVRcQjledVIUECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkDcB4XjeRkR7CBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKDqAsLxqpOqkAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgTyJiAcz9uIaA8BAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIVF1AOF51UhUSIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQN4EhON5GxHtIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIGqCwjHq06qQgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIm4BwPG8joj0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUHUB4XjVSVVIgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAnkTEI7nbUS0hwABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgSqLiAcrzqpCgkQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgbwLC8byNiPYQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAQNUFhONVJ1UhAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECORNQDietxHRHgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBCouoBwvOqkKiRAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBvAkIx/M2ItpDgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAlUXEI5XnVSFBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIJA3AeF43kZEewgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECg6gLC8aqTqpAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8iYgHM/biGgPAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECFRdQDhedVIVEiBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEDeBITjeRsR7SFAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgACBqgsIx6tOqkICBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQyJuAcDxvI6I9BAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIFB1AeF41UlVSIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJ5ExCO521EtIcAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEqi4gHK86qQoJECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAIG8CwvG8jYj2ECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgEDVBYTjVSdVIQECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAjkTUA4nrcR0R4CBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQqLqAcLzqpCokQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgbwJCMfzNiLaQ4AAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJVFxCOV51UhQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECCQNwHheN5GRHsIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoOoCwvGqk6qQAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBPImIBzP24hoDwECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAhUXUA4XnVSFRIgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA3gSE43kbEe0hQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgaoLCMerTqpCAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEMibgHA8byOiPQQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQdQHheNVJVUiAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECeRMQjudtRLSHAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBKouIByvOqkKCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBvAsLxvI2I9hAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA1QWE41UnVSEBAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQI5E1AOJ63EdEeAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIEKi6gHC86qQqJECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAIG8CQjH8zYi2kOAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECVRcQjledVIUECBAgQIBAswjc89T96Za1d6YNLz27UZfvefL+dv+9Epu/PLs2/eXZRyvZtCrbbLXZlmnvN+xRlbo6qmTvN+6R4jiFkvVxw6Np3Usb0n1PPZD9c7Qhtjlw5/3SkbuPqHmbatphlRMgQIAAAQIECBAgQIAAAQIECBAgkDsB4XjuhkSDCBAgQIAAgTwL3LL2jnTpiitS/P3sS8/lual9vm0H7rRfOvudHxOS9/mR1AECBAgQIECAAAECBAgQIECAAAEC+RAQjudjHLSCAAECBAgQyLlAzBL/4m+/nm5be3drS7fZYkDaeZsd007b7JDz1ue3eWufeSy98LcXU/z94t/+2m5DZxx6djp+r1H57YSWESBAgAABAgQIECBAgAABAgQIECDQJwSE431imDSSAAECBAgQ6E2BCMYnLv50eu6l51O/TTdPh+x1YNp/0LC0Tf+te7NZDXfsR555LN226q70xzX3paefX9fav1hq/eIxM80gb7gR1yECBAgQIECAAAECBAgQIECAAAEC9RUQjtfX29EIECBAgACBPiYQy6eftnha1uqdtt4hTTri5CwgV2or8MeH70tX3b6kden6eB75ghMuqu1B1U6AAAECBAgQIECAAAECBAgQIECAQEMLCMcbenh1jgABAgQIEOiJwIaXnk0Trjoz/eXZR9M7Br0tnXjQcT2pzr5dFNju5W3T7F/NTfc+9UC2Z8wej+eQKwQINL7A448/nn7729+m3/3ud9mflStXZp0+4YQT0v7775/e+ta3puHDhzc+hB4SIECAAAECBAgQIECAAAECVRUQjleVU2UECBAgQIBAIwlc8NsL02UtV6Z4tvhZ75loxnidB/f1r+mX9nvdkPThn3wqPfLso+mf9hyVPn/Y2XVuhcMRIFAPgWeeeSb95je/Sbfeemu65ZZb0p133ln2sLvuums66aST0lFHHZXe/va3l93eBgQIECBAgAABAgQIECBAgAAB4bhzgAABAgQIECDQjkDMGj/ssvdnPzl5xIlpn1324tQLAntuNjg99/RzrUvb//qDV6Z4BrlCgEDfF4hA/MYbb0w33HBD9nf8f3ul35YD0pv3HZ5ablraYacjHD/iiCPSlClT+j6MHhAgQIAAAQIECBAgQIAAAQI1ExCO14xWxQQIECBAgEBfFrjotu+li27/fnr9pv3S/3fCv/blrvTptr92k9emQ7c4KJ3206nZ8uozDj07Hb/XqD7dJ40n0OwCd911V/rBD36Qfvaza9K6dRsH4ru+ZVja8+0j01sOPjJtt8vgNGC7nTKyNffdlZ5e++e07om1af0Ta9O6Jx5JT655KK2+9/9mmY8ceWiaOvXT6YADDmh2Zv0nQIAAAQIECBAgQIAAAQIE2hEQjjstGlLgH//4R1q/fn163etel/r371/zPv79739PTz/9dOrXr1/ackuz2WoO7gAECBCog8CkxVPTrWvvTAcM3je978AxdTiiQ3QkMHjTgemSZT9MNz58Uzpgp33TJWNmwSJAoA8K3Hvvvenb3/52FowXl+0Gvim9adjwNGjogWmv/Q9tDcMr7eJdv/pZuv36K1PLzddlu2y22eZZQH7mmWdWWoXtCBAgQIAAAQIECBAgQIAAgSYREI43yUA3ejdffvnldNNNN6XFixdnyzI+8sgjWZf32WefdO2119a8+xGMFz/n8M1vfnMaPXp0OuaYYzz/sOb6DkCAAIHaCLz92+/JKj7xwGPTOwYPq81B1FqRwGabbJr+dN+Dad7tl6W937BHWnDCRRXtZyMCBPIjcM8996RJkyalP//5z1mjdn3LvlkQvuf+h6U93j6iKg1dteKWtPzqS7OgPMrRRx+d/u3f/i295S1vqUr9KiFAgAABAgQIECBAgAABAgT6voBwvO+PYdP3YMWKFemcc85Jd99990YWI0aMSD/84Q9rbhQz1QcPHtzucSIknzFjRtppp1eXg1QaR+DWW29Nt99+e3YTxK677to4HdMTAgTSPU/dnyZc9eqMw48ffWraeZsdqPSywHOPPZe++KuvZ624/dRXZ4cqBAj0DYGrrroqfepTn8oau9Ob3pre/cFPpWHvOq5s41+zSUqv/KPsZhtt8IvLvpqu++6rK0zssede6RfX/7zrldiDAAECBAgQIECAAAECBAgQaEgB4XhDDmvzdOpnP/tZ+vjHP95hh8eNG5dmzpxZF5DDDjssPfzww+0eK5Z2X7hwYRo6dGhd2tLVg8Sy8E888UR6wxvekDbddNOu7t6U20+ZMiVdccUVrX3/2te+lo4//vimtNBpAo0ocMvaO9Jpi6dlXfv82H9rxC72uT498eST6Ss3XJy1Wzje54ZPg5tYIJZRP++88zKBCMRP/o8LK9bY/LUp/fXvFW/eZsP7b78pXf6lyWn9k4+mUWOOS/Muqvy43TuivQgQINA1gccffzzFKnhR4hFt2267bdcqsDWBGgs8+uij6ZVXXsmOsskmmzTspI/HHnssPfTQQ9mfKG984xuzPzvvvHPacccda6ys+u4IvPDCC+mZZ55p3XX77bfPHq3ZzKURzuOYfLZ27drWYYxr1Nttt12fHNY4P+M8LZS+eI6uW7cuPf/88w3/HhAdjFzkb3/7W+t4xWv/a17zmj557vWk0THm11xzTYrz9Ygjjmj411XheE/OFvv2qsAvfvGLdOqpp27UhvgAe8ghh6QDDjgg+yWOJc67W2JW+r//+7+37h7LMo4cObLd6mIWcSztfsstt6Qbb7xxo20iIL/66qt71J7u9qN0v3jBjyXoY3nLmHF/2223tW7ytre9LQvxhwwZks2I7qsz3uML3Jo1a1r7tfXWW6cBAwZUhTCW7R8+fHibuvbbb7/0k5/8pCr1q4QAgd4XKITj/TbdPH32hMm93yAtSA8+/nCa/8tXV4MRjjshCPQNgfnz56fzzz8/a+zeBx2RPjzjkvSa11Z+4bIn4XhB6OtnvTetue8uAXnfOGW0sgEF4qJq/OmrF7drNSTxiIlDDz20tfpYcW7u3Lm1Opx6CXRLIK4LPffcc637rlq1qlv15HGnuDFl3rx5KSY6FPexuK3HHXdcuvBCN9flcfxiBdEFCxa0Ni3CnLxOSKqlX6Odx/G7GK87hVKvx6XWYowmT56crrzy1Uc9RemL52hc+y48ujb60EjvAaVjHhPe7rjjjtZ/vvPOO1NkCc1U/vjHP2aPCS6UyNR+/vOfp9e+9rUNyyAcb9ihbeyOxTO+I6Qu/QD7uc99Lp122mkVdz6eR1547mHcqf2BD3ygzR0xv/vd71LMPi+Uz3/+8+nDH/5w2frjTqPPfOYzadGiRW22jQD1xz/+ca/eeRTBfcy27+jDf2nn/vu//zudfPLJZfuctw3Wr1+fhg37v2cEH3jggen//b//V5Vm3nvvvek973n1WcSFEncUL1++vCr1q4QAgd4XKITjg7ffLU06vO+9Bva+YPVbUAjHD9hp33TJmFeXS1YIEMivwH333ZfGjRufnn76qTRo6AHpQ+ddnPpv/YYuNbi7y6oXH+S5dU+m2acdnZ5b91QaPea4NNcM8i6NgY0JdFUgLib++te/Ti0tLSn+u7C6Wtwsvv/++2cXvSPAOPbYY5t61bL7778/vfvd727lFY539UyzfT0EGjUcj88oEVy193jGYtfTTz89/cd//Ec9qJvqGLEiwUsvvZT1efPNN0877ND1R5jF43risT2F0heDx54OeiOex8Lxnp4V1d2/Ud8D2lMSjqcUudr3vve9Njzf/e53s8mnvVFqOfGx0B/heG+MrGP2WOCzn/1suvTSS9vUM2fOnPT+97+/S3WXLoUeX1CLl+HpbjgejYhf4C984QvZnajF5YILLkjjx4/vUjursXEs5fKlL30pxdKWXS3f/OY3s4sXfamUhuMxIz6W4a9WOemkk7JVAgolVhg488xXn0+sECDQ9wWE4/kbQ+F4/sZEiwh0JvDJT34yW1Vnx8F7pw9Nn5veuOvgXgN74M7lad60Cdnxzz777PSJT3yi19riwAQaVSBmr8UMzPheXknZfffd01e/+tX0jne8o5LNG24b4XjDDWlDdqgRg5F4rYrJDg888EDZMZsxY0b6yEc+UnY7G3RNIGbkF9+YsHLlyrTFFlt0qZJmD8cb9TwWjnfp16DmGzfie0BHaMLxlM4666xs1ePi8pWvfCW9733vq/m51t4BajnxsXA84XivDK2D9kQgnssVs4CLS3cC50p+wXoSjhfaVxrkx0WAX/3qV9nzmupZ2ruhII4fNwjEjPY999wz+3IQd/kXL7Me21x88cUbzZSuZ9u7c6xah+OxekHMRI+l90eNGpX5NPvzjbozTvYhkFeBn9y3NJ37mwuSmeP5GSHheH7GQksIlBOIZS5jucsoJ029IB04uv43hpa2cflPv5eu+trnUr9+r0+LFi1ss8JQuf74OQECnQvEamwxC7P45uFKzPL06LFK2lvNbYTj1dRUV60EGjEYKf6MUnCL62If/ehHs+tiW221VbbSRguGiAAAIABJREFUYlx7HDhwoGeO1+DkKg3HIygP966UZg/HG/U8Fo535beg9ts24ntAR2rC8ZSWLVvWZvXg+JwejxF+/etfX/uTrZ0j1DrbiUMKx3tlaB20JwKxvEMs81Ao8Yzx3/72t11eku33v/99Gjt2bGs9kyZNSueee26bplUjHH/ooYfS4Ycf3qbeWFq9nnfIx1I7Rx99dJs2xDLgF110UXr729++0XD88Ic/zJaFj/Ktb30re/Z4Xyv1eAHtaybaS4BA5QIX3fa9dNHt3xeOV05W8y2ffPLpNOeGucmy6jWndgACPRJ44okn0gknnJBWr16d3jTsnemMWZf3qL5q7jz/309J99366zRq9DFp3txvVbNqdXUgEJ/J16xZk+KZkUpjCsQjxWJ58MLy6YVexgW1I488MsUKXrFkbjzH8YYbbmizXXyXv+KKK9Lgwb23skRvjYpwvLfkHbcrAo0WjMTr1Tvf+c705JNPtjLEtcCYTNLIz1TtypjXY1vheM+UG/k8Fo737Nyo9t6N9h7QmY9wPKV//OMfKbKwWP0tnrf+z//8zykmefZWqUe2IxzvrdF13G4LxFIOxTObp02blmLZxq6W0pB99uzZ6cQTT2xTTTXC8ajw1FNPTb/4xS9a6673c4vieEuXLm09fswU/853vpPe8IaOn/t43XXXZV8Oip+DVs447qyNF9KotxqzqOMDX+FZRLvttluXboCoxwtoOY+u/vyZZ57J7k4Ov7hQlKeydu3a9OKLL2Z3TldjbPPUN20h0J5AIRx/0/a7p4mHfwBSDgSeffq59KXrvy4cz8FYaEJbgfufWZWue/BXadj2b00jBx7U9Dzz589P559/fubwgc9+I+17+HtzY3Lbz69Il395Stae//7v/25zZ3xuGtlgDYkbdONG3QhH44bhkSNHpgMOOKBXL7Q0GHGvd+f73//+Rs/kjXH/n//5n+zCWnGJZWDjJuyFCxdm33cWLVqU3vzmN/d6H3qjAcLx3lB3zK4KNFowUjp5JW7iiet+W265ZVdpbN8DAeF4D/BSSo18HgvHe3ZuVHvvRnsP6MxHOF7ts6fn9dUj2xGO93yc1FBHgQhLY5mj4hIfZHfccccutyJC9fhSXijXXnvtRjMaqhWO33jjjW2eUxSzxmP2eD1KLH9RGvrH3flxUaqnJYLwyy+/PHuWdyyhFx9iCiUC+BEjRmQ3LsQXjo7Kb37zmxTP6y6Uyy67LHte+5e//OWNnhEeM04+/elPZ8uYl5a4+WD69Olt/rl09kJndzvFUv1xg0RpiT5VMnM+nssRd1SVK3FX8r333pttNnr06OxCUtyoEc/mK757OcziOe/x82222abdakv7fMYZZ6QPfehD7W77hS98IS1evLj1Z3EhqrPfm7hwdckll6Q4d2OWR/HYxjgceuih2dKJvkSWG3E/76sChXD8zdsPSqceXv53u6/2sy+1+6WnX0qfv362cLwvDVqTtPWi276fLrr9e1lvt+23TTpuj6PSIbsc0LRBeeFG1r0PPjJ99D+/k7uz4KtnHpMeeWBl2nXXXbPPRqXhXe4a3McbFJ/z47vCunXr2vQkVq+Kz98RmL/rXe/q471s3ubHd4SDDjqozXeFM888M/3bv/1bes1rXtMuTHzXi+8ZRx11VLeD8ZdeeilbkaBfv35pp5126vSRZX//+9+z75fRnlrODI1z/Pnnn8+em1vJ60pn4Xi0Ob4bRp277LJLp9+ne+Psi+syjz32WNpss82yG7ur6frss8+mRx55JG2//fYdfg/urM9xITXGIb5Dx/lRjRJjEX+23Xbb7E9Pbhav5k3n8Z09VmnZfPPNy/4elHOIcy3ct9tuu+xPofQ0GImxiLpjXGI8YlziGkI1z5lyfSv+eemSsfE88XiueLVLns7jeCRgvP6Vvi7FOR2v4fEa05Nzujt2tQ7Ho1+F16hYNbOj96NK2v7CCy9k7zfxe9HRtblK6qnmNrU6j+O9J86X+Ls719nL9bGS34t6huPx2hQTlOI7QU+Wjf7rX/+arYoTdcTvU+F8i2umV155ZSvLNddck4YOHVqOqWY/D9u//OUv2WeKOJ/jPbxc6ew9oJoTvKo1FoX+xOe+eL+N39/o64ABA8o+3rae4XhXPzN2Nk7VnqhY7pzo6s/zPvFRON7VEbV9rwr88Y9/zALFQokLKvHc5+6UwiyGwr5/+tOfNpqZXK1wPL607LHHHm2aGV+G6/EB9Gtf+1qaOXNm67FjJvi3v/3t7pC12SdeyOOiR3Hg2l6lEUjH8u0dfQD40Y9+lNVTKDHbKJa0ii9mHZWYiX/eeee1+XHpSgBd7WAE+bGcfGnZsGFDthRguRJtjnC6XCn+YBEXA2M8SkP94jpiRkUYveUtb9mo6p/+9KfpE5/4ROu/n3322W3+v3iHU045JXuefKHcfPPN2Ye29kp8qIvnN5U+e7502/iS8dWvfjUdfPDB5brt5wT6nMAFv70wXdZyZdpz+zeljxze+8/K7XOANWiwcLwGqKqsmsC371qQrn3ghnTPU/e31rn7gF2zgPzQXQ9umqD85z//eYobAaOc+OkvpYOOyd/NRb9eODddM++/sjZ+/etfT//0T/9UtfNARe0LPPXUU+n666/PVtKKP7EaUXF561vfmj0CKv7U89FTxqvnAqXfNeO7y0033dStUDJuIC68fpS2LG5iju/+cT0gvjstX768zSZxQTMCrgguS0t7M9vjwnDcdB/BftzU/Z73vKeiC+Pt3egc1yPiRufiG7PjO3C0N27sjhXQ2ivthePRz6985SvZo82KS3zviu9zceNBPa4hxLHbu4k9jn3BBRdkS+EXl+HDh6cIu+JG7U022WSj7sbvf+n398JGscJdBAqxcl2MYbFjnE8f/vCHs++4nfU7rtvEdYTbb7+9zXWEvfbaK3uMXNywP2jQoIpP+AgNv/nNb2Y3ia9YsaLNzR9RSVw7iAkIcTPYpptu2mm91b7pPF5P4zv4H/7wh6x9hRLndNzEHo81iXOlkjAwrrnMmjUre0xhqXtcW/jABz6QuhKOxwXwuM4QAVDcZN/ZNZ1ob6zgEu2tZyl9TnM8WrGj153SduX9PI6g/4EHHsiaHa9psVJL/L6uXLky+7e49hSvL6tWrcr+/Ze//GVrF2NyyoQJE2oyFHGtNa7hFZeuTGSJ/eJ8Kr2hor1njkdY96UvfanN70bsH8+Uj8dz7r333hX1McziNeCuu+5qNY0d4zVp2LBhKVbnjAkjvVV6ch6XtjnCw2984xvZa37xNcD4Hd1///2zyUmdvaZU+/eiq+F43IQZbS+U//qv/+r0psuYGBcT5aKvxROU4n07PoPG+3Ylj3qJQDxei+M6a/FrcbTjYx/7WPa+E9eJezMcj9fkWDU2fOJcLu5vtDPeI+Nxs+PGjetw9dL23gO6O8Gr9Nyr1lgU6o3f27j5Mv6+++67N/r1fP/735/1t6Pf3a6E4zFRMD4DF8r48eM3WtW4mp8ZiztTjYmKUV9pH9p7PYvPXvFIpHIl7xMfO2u/cLzc6Pp5rgRi1sHHP/7x1jbFB+l4M+pqibtXi597F1+I43kKpaVa4XjUG18Yi78cxBtoPZ7bUDpDPmZm9/RDXHzBi9nUsURipSVeTNtbMq80HI8P7MVL0HdUf3yYKQ5l+2I4Hh9ECndOdubYUXBfi3A87jiL0L54pni5Me4saC+3r58TyKvApMVT061r70x7bf/m9OHDx+W1mU3VrheefjF94fqvmDneVKPe9zr784d+na598IYUfxeXvbZ9Uzpy9xHpiEEj05A37tX3OlZhi+NCUOEz9eR516UdB218c1+FVdVss2effiJd8JFD00svvpBdCI4Lwkr9BOL7UHFQHhd4iksEioWgPD4rK/kWiAuq8Z25UD7/+c9nYWZ3SoSQsXJWeyV+T+M7UWffYyO0iO+cpbMj40bx4guY7dUf+0Z4GxdGOyulNzrH9Yi4kN5RiXAhbkyPZxyXlvbC8dhmyZIlHdYXF+7jhu6ezHCrdGxKv6fHTQYRXnd2DSAC4wg8S2dsx8X5jm4IjzGLC9nF13lK29jRDf5xXeLCCy/MAt5yJc6BcuMbr0cRZMTqbZV8H47rSHGTVUfXdap903nMFo332dKAo7Tv8bsS533MhuyoRDAUF+47q+s///M/s/Estohgtb0SyzzH+JdrW/G+cUNDrCBRzxKPe4iAuFAiAO3odae0XXk/j4snAMVrRYxFaQg9ZcqUFOdR8et2oZ8dXbPr6fjE73clqzF2dpwI/cuF43G+xu9uZ6Xc60DMNo1ri51NYCnU/9GPfjR7TEg9Xo9L+9ST87i4rrgpLV57y13bjdfgeE1p7/GP1f696Go4HgF+8etO3GjV3uSiqDce+xQ3FpQr8boXNwe1d7NX7BurEsTkqM4mFMUNYzEzu7fC8Whb3ORUbmyjPzGu8bsRN9SUltJwPAy7O8GrUHc1xyLqjBs8ov1xk0clJT67xueZWOmnuHQlHC/NWmK11g9+8INt6qvmZ8ZCxdWaqBj1ffGLX8xuAipXOnrfL94v7xMfO+ujcLzcGeDnuRKIL4Lx4aNQ4s7p4iW5K21s3FFcfIdqR0spVTMcP+mkk7Klxwslgv5KZiRX2qeOtis9bnwQjudG96TEm3ssD1Nc4maD9773vWmrrbbK7korfsZ5bBc/a++NqvQFtFBnfNGMD9CxlE9LS0u6+OKL2xwvgvHiZfHj4kLcCVco8eZYfK7E3fbF/1/a/5g50N54xBfkuPM5QuziEmMZd1kVSndmjhfXF+dgGMadfT/4wQ9a7+4tbBMf4OIGi+JSi3A87pz+7ne/2+Y4cQdceMfd5w8++OBGF5fizrtKLkj05JyzL4F6CxTC8b132COd8q6x9T6847Uj8NzTz6cvXv814bizo08IxAzymEl+3UO/Sqs3tF0N55277J/evfvIdPTgw9IbX7/xLMc+0cF2Gln8TLBtdxyYzvn+stx25RufPD6tvueObBWduMlP6R2BCFMKQXnxrJ9Ca+JibHyHiAuM1VoeuXd62rhHLb0ofc8993R7rDoLx2PmcJwvV199daeY7X0nK72A2VkFcfE/Lpp2VIovdMbNG7H0bGGmZmf1tvcIt9JwPG4kr6Su6E8EpLUupd/Tx4wZU3bVuGhTe9/7OwtPIiCNC/jlQtV4LF3pyhJxgT7qrrTEzPzSR84V7xvh2rx58yqtLtsuxi2uF5QGZNW+6bz0UX3lGhnnZ5x37c24j/PsyCOPLFdFFpjESh/lwvG46Slep8uNYekBe2OJ4dIwIG5eifeaSkrez+PS1TEr6VPxNjGz+rTTTuvqbmW3r1c4XslraNywFJ/7Onr0RcyojxteKi21Wpa/3PF7ch4X6o6l4uNGmkpL3AQUE5lKV8uo9u9FV8LxeJ2NmyqLS3urtMZ13Zg1XG51zOJ6OrpxJm7KitfP0htP2nOMa7yFlRvi5/V6zYvr8bG6QVdLfCYvfZRtaTge19Y7WxUkjtnRBK/4WTXHIuqL8Yj39dLZ++X6Hp/1ilfZje27Eo7HOVD8ma29x9dW8zNjoa/VmqgY9dUyHM/bxMfOzgfheLnfFj/PlUB8UYkvLIXSlSWQijtSGrLHB6AIAEtLNcPx4pk0cZz2ws5aYJe+kfV0Ofd4vls8F7D4zTA+hMcHyOIvhKVj1dEHgfbC8ZhtEF90i7/IxYew0qWY4gJJR3fyFV+gjWNH8B03JFSrlN4g0N1wPD6cx1J8xSsZxJt7BM7FH9zCY+LEiW2aX+1wPILvI444os0xYnwOOeSQNv/W3l3h7X2Iqpa1egj0hkAhHH/rDnulD77rxN5ogmOWCKx/akO64BcXCsedGX1K4OVXXk43PHxTuvHhm7K/n//bC63t32bzAVlAfvTgd6Xhu+zfp/rVXmOLg623v/uENOEzXV/dqV4Ii2ZOTbcuXZQd7qqrrsqW3VV6VyBC1UJQ/vvf/75NY+KCbARu8ac3n9XYu0L5O3rcjBxL4hdKjFPxY5y62uJYDjcCwEL513/919b/jrGPWY1x0Ty+J8Vs01hCPS5eFy8N3F4b4nEPcQEzlkCNG5FjFbn4Lhvfi4svWhcOFvV1tKRq6Xfrwj4RWMfN3fE97s4770wRwhaX9la8Kw3HC9vH99YIqKINjz76aHbxtnTmV7zexnOba1k6uok9btiOGXXxTPCYPRc3VpcGDqXfDWNZ5cISpzEDKWY9Fkos13vppZdm/xvXTCLoCMeYAVp8zSGWbC++FhTfSWPFs+ISYW5c14nzIG6wj9nupT+PYCye0V1aOro5I8YullGOGYAx0SBu5CmdVd7eignVvOm8o5X74qaRwup88aiB4pv3o38d3ewRkwZKHykXdcX3/pg5G5MOOlpVpb0ZZHGDQ8wmLC7RrhifCOnjXI0bnCIUid/DmPkWy8PHzPWYXFHP0pNQMe/ncWk4/i//8i9p6tSp2RLqxTd9RKAb50CMcfEjFyNMKzfzujtjFeNduixvjEPx73f8f0czsOM536XXqaIdpcuqF9oW53Ks1hH1xXXEWF2iuMRqH8XvL4WfxbOYS699xWtJvEbFpJ2YMBPX4Eof61GrGfedWffkPC7Ue84552w0izoCrfi9jffJuH5aujR1e7Njq/170ZVwvHR5+biBKm6kKi0RSsdS58Wl8DiQuFEi3mvj/aL08SjxXlb6XO6ov/T8ic8oEazG55L4vBETw9oLz+sRjodfPEag9Gal6G+E1jvssEP2nh2fjUq3iZucSn9f2vvcE9ex4zUkHlMQn6titYXSVW86yjyqORYxnu2tIhvti8+K8f4Trz/x2bT09zb2Lb1xsdJwvL0bzNr7XFbNz4zR3mpOVIz64jyI1SNKS7yfl7sprnSfvE987Oz1VDjenXd2+/SaQHzJjOd5FUq8aMeLd1dLBJmFL2Cxb0dvUNUMx0vvQq7HElKlHyriDq/23hC64hcXq+JNprjEv8UbbGkpfWOJL7tx4aC4lL6AxptYuLf3Zb/0w35Hx436+0o4Hh8oSj+kRfvjg0XxM8zbuyO12uF4XFyKD9mF0tmshLgrLpbkKpRyy1N15RyzLYE8CBTC8e37vzF9akz176DPQx/7WhueeeqZNOsX30p7v2GPtOCEi/pa87WXQHrs+SdaQ/Kb19zaRmS/HYa8GpQPelfaecuNP1P1Bb64wBAXYqMc/4kZ6ZDjP5LbZv960bx0zdxXb7iN1ZCKP9PkttFN1LAIF+OC5OLFi1OE5sVl9OjRrbPJS5dYbSKiXHS1NNyNi7HF37F72sjiZ0THd8T4blv6+7phw4aNVv9qb/ndjtoSzzCP72PF4W5nMwFLL3RGu+JaQmmY3t6N3aWhe3vheARAEWIVX4yP77VxUbv4QmU9VqFr70JnhPZxLaX4edZxk0TcxB3Pmi+UCKgjkGuvlK7iVxjbCNmLA7AIok8++eTWKiKwiYvghRLnQvFytRFiReBbvEpeXPsofY5yLKUaY1xcIhCOmWfF50FcO4nvx6Wz1Z9++uksLPv/2zsX8KuqOu8vLyAQIJIgYigI3vMKZmhqpGBS5iW8vDqW2jxvlr2amlF0kabXeibfispH0RzGx+vTjFli6YyJmopKYmgRaVSGIKCo4W2ynMn3+Wxcf9b/x9r77H3OPufsc/7f3zwM5Nl77bU+e+3b+v4uXjRC4GUOheesbKdznOnD9P0Izwg5NiOgnXc4C7BmEt4rESRtRrq5c+c6MgOEtmrVqqTWsHUEiInj55xzTq+sDqSbJgo5q058o/eHWvtzb7DOE+xjxSDmX1pmEtZDwjkYHrOK89iul3nh57777nM4l3jzWRjsf2espJNuhbGOGwqv/Luoo0RMHI8Jcnadi3kdyxBhs4xwTZAhkTnijXsF/y2MLq+33Gcezs2axwjatqSBXf8jMIr7bBhkxD2Fe3OaI0MZ10URcdxmSo0F0CHeIvqHYjX3bL5ZwmcZzg+kmA8d7qhff8opp/Q6/8yf0GGNZwD3uzBwC+cC/nv4XKSRVojjOL3YrK0xRyky38DBO1XxXGBd167t2/ce5gDv5ziMhEaQW8guFuBV5rng2LEMLTgAoBvZ/uH0xfuAf6bFmOQVx21ZA+691Dq3VuY7Y9mBiln3H1sWuJ606rTfCYGP9FPieJ6nkbapDIGyxHH7IoanTMx7uNPFcTyk9tlnn57zx0Psl7/8ZUPn03oqpaVL5yBWQI29NNqPbj5Krae97zBp9HkIe4ulp/O/dYo4TnTEuHHjNjknNvUUC4FXXXVVr+3KFsetBzkvD0OHDo3OF9Kr4SXojVR4eOjKRKBbCHhxnPF8dcbMbhlWR49j3QsvuO/es6HExmNn/qyjx6LOi8ATL/7e3bviQffgM4vdr9b9tgfIwC0HuPfueLA7eIeJ7pgJ0zoKVJg16OPfutmNfeeBle3/H3/1sPv+Z05O+oczImKPrJoEeN9nMZE/LKp5Gz9+fE80eay2ZDVH0129smmeY8KKTclsCbCYPHz48CiYUBxnAyKAiHSyxmJn6AD+6KOPum233TY3bCJYqWXuF0yJXEaMjJld6Jw1a1aPU5DdnijMsNQYEZlhmtOYOJ72fWsd7YvUSc4NwmxYxIkdYcsGLSAQh8KDb96KJ/x3RHfEhdCIluY694Yg7KNP7W9sw7cy38zWrFAQiyyMpX3OyvTHOguiEXMvVku5bKdzKzpQXo6yZzHjuzyMICdSnhIi3hDVw+jgLKeWWERebJGcTAKhCFSrPEG9c7LIfnYtrMi+ftusNONVnMdWHMf5BxGTc8M58oYDGtGy3CvDMgOdLo4jZuPoYQ2HljBDUHgv8dvaewqCOCIwkcDWrMDXaNaUrLnZrHmMuB86MKU9Xy07+so9hGyiMSvjusgrjs+fP3+TEiP2fkcf7TxHPKWUZSwLqXVswhHqkksu6Rkq15R9zvD8sLWr2SGWjaQV4rh9T0nLlEAfEcjJfML9gGC2mEOTbS+WKYW2qPUelmWIORqWeS44pn1Gcd1yvyPbRMw4J7xPIdyHmY/8tnnE8VjWmrRgsTLfGcsOVMy675QhjndK4CMcJI7X84akfdpGgA+e8MEU80Sq1TnSOIULKFnptssUx61XY7vSquPhZtPC1GIW/v7d7363V31par4jWqc9eKZPn97zE6nmeIEJzX50k54m9IoOt7Xe4VkvFp0ijvsPFsvPpmlphThuF5ZwbsgyvI/9IlJWdECR+aVtRaAqBCSOV+VMbOzHyudXu6vu3ZAesx3i+P2rFrnfrNs07VT1SHVAjzZ7023mNnebb7aZS/7vrb+T/538e/Pk7839b+Hv/rfovskevfeltaTdyG897W78rddxk3039CXWLm2mj+GtfYMx9Iwn+W8b913+56fc4rWPu0fWPOYef25ZzwkcsOVW7l3b7+9m7PZB9+7R+0fZVOls807IYhN27hV3uO3H71ml7vXqy1//8pqbfeyG/p122mmONJGy9hEgEouICP7wrRb7m2hHIlJYHLLiDCmP+aYjmidv7dj2jbZ7jkx0f1j2KfY9EEsBGRLIct624rgVl307fJ/y3Y5RC5WIobR6smn0WQAPU8Knle+yC51Z6XQtH0qEzZ49u6cLVhzPYmEXgNMWp8ucXfY7nXqtYRY/eyxE4jBNfZqTQkw8SStvgfMSEXgY88GvBRHVfMghh/R0AXbMgdjCPtGCCMDeWLAl5XpoNmubjVIvyrVsp/NwobpWuTgrhN58883uwAM3OqsRCRmmzc3KxhirSRwTxzlPYUpdGBOVyVoQ9WvTSuEV5Vpke7seVGRfv21Rcbzd89iK4z4IyM4JHwTRbeJ4llOGvXfbeWznOtkduY7TjHthGNTTaPnKtOM0ax7blOqxdOm+T9bhhmyTobNF2Pcy7u95xHGyZBCcE2a2SAu0smnQbZYSyz6MRre1s61TII5LPI/TzIqMzRbHyYxxwAEbS3VxL+a9Ocx+UPReaK+dtNIzeQK8yjwXjINMMGHEdlpm1rxjriWOs05PRoCw1jhZZmASC7gs852x7EDFLCZliOOdEvgIB4njea8QbVcJAiy4sfDmrdYLS6zT1nvLeoKF+5Qpjtt0L61IhcZYbJQ8qZPsQkORk2tTDfFSyIdyzKhBFn6IxT5E7Ud3LM2Zb7sbxfG09CTtEMd5ibJpxvLODRYiw3pVeffTdiJQVQJfuv9Sd9vv70y6p8jxapylp9Y97eb9/KakM+0Qx//xjs8kAqZMBKpE4EsHf9p9eLfiJYaaMYbQye4z19zn3j56p2YcprQ2v3zM7u6Nv/7FHXfcce473/lOae1WvSGiRIh6yvqDOO1/TxOrs4Tsor+FEeGN8CMCGedpUjOnRY000r727U3ALoTaRWS2LlMct3Wsi5wPUn/7NP0IqwghpFAlopaU6D/5yU96fQelZdCyC51pjs70zQq4NpWvFcezItZtXdWsb+YiXLK2td/pOPtTvzjNrNiStt4RS7vLGk0RAdWmS68lZtv1D8TxUCywkd5ZkXZ5+JbpdM79EYHZG5HvNso+7NPKlSt71cNFwAujg23QRtZ1FYvQj61fEKmOgBYzOJO+2de7jWXNy8O0nm1i9eFxFggzOiCwhdkWw+MQVJPW3yrO474ujrNeHDrNhOeylji+aNEih4OXNyJgw0AfO/+YQ2GUOs5VRJA3w5oxj+09yqfaj/UfMZl05d4oo8D9PmZlXBdWHCfSH9Y8b8l6gFNHWALD94PnAkKlNaJ6cZzwRtBdVnYZtvWZMKzTGqU7QqeJLEcBjmcd75otjluHFzKMkGmkEbPXDuWOYqUo8qxhl3kuGJPNqsJ7y+TJk+serhXHcXh6/vnnHe+EzLkwbXw4n2JZa/i9zHfGsgMVsyCVIY53SuAjHCSO133JaMd2EOADixog3uqp7cKDIax7TfoYUoPHjA/f7boiAAAgAElEQVQLXp694aU7derUJJ20rclUi4e9uaR5W9Vqp+jvtv5T1gtjnrapyRhGFHOD5jzEzHqtsY39mJI4viLKLs+LRZG06jbVWSzdUCPiOE4YoQd6nrmkbUSgygTmLrnWzX3sOjeo30D3+WPPrXJX+0zf2i2OEzn+X2/8xe3x9l3cwlWPuAee+UXyt0wE2kWg/xb93MyDzqmMOE4EKYvs2Bf+7VE3eFj+tMYxhlts5tz/vNk8upecPMm9+ud1SbRxrPZkmUe2i5Bltq224gSsICRO5RNYv369IzOYt1hq2TLFcZ8KuMhIEPeuvPLKpP6mrZ2c1U5ecTyrDiOCfJi2c4899nCkTfdmxfFYpjC/bRXE8VqCvK3BefXVVydrJ9aseFIrEjp2nmwNbu6xpE9PsylTpvSK9CL9a5hN0EZGNnr/aOS72jqdx1K4FrkGbMYFHMJCYenxxx/PdCaqJSrSlzfffDPJinDNNdfU7Br3DKLKbRr+mjuWtAFiFs4Q3nDwryfjSBXncV8Xx7OEx1rz2K4TF51uaVkDiraTd/tG57G9RyHAjxkzJnp4uBKY5i2rtGYZ14UVx/MwSSurwb42wCtPe+E24XOeevOsgXsjapnrLs2sM1KzxXFb2rSMDJ+1rh0/9jxr2GWeC45r53GjTipWHK81VyiVE5YpsdvnZcd+td4Zyw5UzBpbGeJ4pwQ+wkHieK2Zrt8rRcB6p9fjBcVLe6MRrlnpIWLASBVoPU6blXbHHt+mzUqrw5P3RNu672np7WjP1mOxCwJsI3G8NeK4/VCKiePWqzFc7Ko1P/AGxzNMJgLdQsCL43uO3NX9r8Pi2TG6ZaydMo52i+Oe04V3f8UtWPFAp2BTP7uYwBabbeEePWOj0NLuoVKrzpfP+afbnnT9thrQUJe23Ny5//57Q01k7vzNM9/rnn/mqSTKyKeDb9bRJI43i2y8XSJQ+cZgcUfWXAI2Itd+41K/06c89z1h8dbXCC+SVj0t1XnaCPkGJ7qtnqipMsRxsjQQ8ebNOg90mziOA0IoUKfV4LTiCZkeiEwsYjZSuVatZPstbGu720Xnr3/9644267VGxHHrdN6oOE59VcqheUurS5021iKL+4gjnPda5dk4FiIEIlORjAH1no9wv0ZFRd9WFeexxPHb3V577RWdJrXmcaPiOGUFYjWMy5izsTYancf2HhVbH/THtWUnstaUy7guiorjWY5ljKERQdZmPyWFOo5f3mqJ40Wyn5YxV+w85j7LPbkRq3Xt+LabLY7HMtHaeXzXXXc5AiDrtSLiOP3BaTNWzsUfPy87tq/1zlh2oGIWI4nj9c4g7ScCLSBg64VzSB6+22yzTe6jW0/Z3DsGGxYVx23ar1jt7Xr6kWefmLc+aeOozVeP2Ydtliea9TCMRRc3Sxy3XldZCy/1cLBcv/CFLzhqbdWyvA/HPC8WNnKclz4WpmNmjxt7+bX1WvionThxYq0h6XcR6EoCEserd1qrIo6TUWDxGqVXL2OGbKjljVGDO/n/Pf8O/hf/3FDze8M//L8cO721x6b70aBvMfm33e+tY4dthH1g+3C/Xv/2rb11hOg4NuwfjDAZY89Iev6dHGiTcfj91v3lBbfipVXJn/V/fbkH+9ZbDXXvHn2A++f3fqGMU1FKGzNnzkwESeyfbnvC9dtqYCntNquRy875gHtm+dJEAEEIabYRUUdaZ2oi9+/fP/k79iftt7L2yVrEaTaDRtsnTTUlovhDdAhpsb0NGTLEER3KH6IAlVa9Udr59rd1pilRwPd2lpGe1YuhecXxer7lmCehKEifWPDDqZeUqtSHpJ412eL4tqM2tbcyxHGbRY1jEwHurdvEcfstiYB90EEHbTIVrHgyY8YMRzReEVu4cGEv8bpWiS/7LWyzEFhh/+yzz+5Vzq9I39i2TKfzWGrzIk7sRC6GkY1nnnmmo16vtyxRjG3yrl+EjFiLoc4t62BEpBKdHjOcKXAea6U1Kir6vlZxHkscr18ct+moEb7Ccga15ihpvynT0SprdB7bsp9Zke/XXXddr+hYMj/MmjUrOtQyroui4jgdyRJFyXBJ0Jg3Uq+PHDky16ni3SMMriPTFA5H3rIyqbJNq8XxxYsXO86tt3oys1gweZ8BedawyzwXsWdtvZlA/JiLiOPsc+mll/Yqx1AvO/ar9c5YdqBi1gUgcTzX7UEbiUD7CNga2tRboh5MXiMt+8svb1xczNrvz3/+s1u6dGnPJnh74x1PGplTTjkl7yGdTW3+0Y9+1PHx2AqjRhUfi+HHPvXg5s2b5wYOLL5oaYV+xpCW4s5+FMZqxDdLHKdf1ousVsqwIuejCuL4vffe65hL3tLSydkXVLaPfQRff/31DpHfG178eEJ28iJqkXOqbUUgJCBxvHrzoSriePXIqEfdRuCZV9a4e55+MPnz6NpfbXwu73iwO2j7/d0h7zjQ7Th0h8oNOxRG/s/lt7vRE+LRO1Xp+PcvOtn98fGHE2G8kQjBqoynW/uByEJpLf7w7ks0sDe+ZfjO8aJ4Vg3JbuXT7nHZSBYipVmk3mKLLVK71ipx3KYzpY7oiSeeGO0XTs5Ex3krQxynjnZYs9Y6lXebOE560bCWc1p6U/ttWk/aVxtNjdhBjdjNN998k/P73HPPuQMPPLDnv8eiz6xTP4ICjuix9vJcc2U7nVvRk4yKgwYNytOVTbYJrz9+rOUQn1cYyerMSy+9lAjypN4P16UYF+sNrbRGRUXf1yrO404Sx604W0/ZySIpq2vNYytMHXrooY71sapao/PYRlNnlZKw9wybjSJkVMZ1YcVx7u+sU/JegVg9ePDg5FkelkpBzGNtOZaJwka+48wblmstco5tqddabbVaHLfPO8aG40cj78e1rh3PL484Xua54Lh2bjbq2GbFccRv3hm23nrrxKEC/clnPuL4/IYD2PDhw6PTKC87dq71zlh2oGLWvK+SON7swEc4KK16kbugtq0EAWqGfe1rX+vpC4I1CyVZH+D1dpwUcOEHNClUPvKRjxRq7tlnn3Wkfw+Nh/bkyZMLtdPIxvYBTlssXODllhVBTu0oovUHDNiYFpMXED4uwxcR6llfcsklvc5B7Jh4ytv0hs0Ux20KyzKdEqogjtuXDx7MXAuhFySe5ixUhN7hnP+YOL569epN5uXxxx+fXG/1fnw3Mm+1rwi0k4AXx/cYuYs79bAT2tkVHfstAhLHNRW6mcAb//OGu/vphe7uFQuTv/nf2LCthrr37zzFzdjtA27CNuMqjSCsw3fKrO+5fd/7oUr39/PTdkr610hGpUoPsMM7x7srqY+Jtg8dm4mg99Hh/L3ddtt1+Eg7u/u27BmjyRKh+b1V4njoVM93EguPsYXzWGRuXnE8bTvGacubXXDBBb3KUHWaOB5zdPezl6CC/fbbr9dkXr58eZIlw1oZ4snf/va3TVKn3nDDDe4973nPJsezUeGxSLrYPM6TBSHt6i3b6dwGW2RljKt1R7HraR/72MeSazJmdlGabcL6u7WOZX+3zv2IXqHQULS9erZvVFT0x6ziPO4kcdw6VhG8Q1aPIlamOM5xrZCFGGXXcov0r5nbNjqPub/hrOJt0qRJ7oc//OEmXY6t/5L5hUCamJVxXVhxPFaek3JIn//853t1Ie2e/eSTT7pp06b1bIvAzvtl3ujx8CBLlizplR2HFN44BKYZekJYWqbZNcdZwx87dmyv7rBez3yp1/IKvHnE8TLPBeO59tprE8E6tHocbfz+Vhy3gYC2/+yXxdeya+SdsexAxaz5UCVxnH42M/CR9iWO13t30H5tI/DMM884Ip9DazR1RtpgyhDHbeoLHsSkmGqGmJ82DiIsjjnmmF5R8H5bHtbcsEkZNGbMmCS1HII+ntcsFvKCHaaNSXsAEbVx7LHHJukheWEg3Uxohx9+ePLgstZMcRxRl4+/0Hi5JTqIDzEE31deecXhXbd27VrHh2H4AU/ND8YSsx//+MeO9ELeSNlnUwiSqs86H5T5YhFbFGBcLLzgNLJmzZokZWFsDHxg77PPPo6UbOzjje3txzGLSbDZf//9kxIGeGryoUz7vADRDvU6ZSLQTQTmL7/TffmBS93uIye40w7bmJqqm8bYaWORON5pZ0z9zUNgybNLewRxIsa97T1iDzdt3OHumAlTE4G8E4z3W9LjYkeefr474vRPV7bbz6/6o/vmWVOS9xoW8mTVIMC7Jd8f/AnPC99NPjqcv3fYoXqZE6pBsD29oKzT/Pnzex0cIRUBL5aBqlXiuF3kTIu2DR17/CDyiuNpEXQ4HfMdHTqU8+142GGH9XDqNHGc70sc4IcO3fSZZIUavhv5Xo5ZGeIJ7dr04IjeCORhSQUEetYowvNw4YUXOkS10HCQoEQA23vjG/iyyy5LslMUtbKdzm20Hf0hOp1MfUXXlewaF21RgoAMidZidZgbEcetkFFGyt+i56ZRUdEfr4rzuJPEcQJ1wnIKCKA8R2IONWnnuGxx3GZ84Lhp5SGKzruyt290HseyS9rocdaRv/KVrzjKAoX3RQJtiKRt1v09jzjOPZuMrjzXvbHWjgOOfUbFtkXU5n5UNBU+5XxYUw6fKaTUpw67NZ4nYUkLfm+2OM4xiLK3WQ/4b2eddVZdWUHLXMMu81wwVp5H4XsV/43nCo4SRcoi+HNXSxz3z16b8YT3Hd57rFl2jbwzlh2omHVPqpo43szARzhIHC/7CaX2WkKAFCh8mIUPaES9MF1WGR1pVBy/6aab3Oc+97leXfniF7+YRPK22p544gnHIgViZhGLefMSTY7YzQJWXiMtGSKqtWaK4y+++GLiPR6+uGT113qY1VPrJmyf6Px77rmn1yHLfLGgYbw9efDXsqOOOqpXqkC/PWl+8Nr1xsvKCSeckFoXLHacM844I3lplolANxFYvPZx9493fMbtOnK8O/2wDWKPrL0EJI63l7+OXh6BJ1/8g7t/5SJ336pF7lfPLetp+D3veJfjz4Hb7+fGD9t0kbq8HjSvJf8xTdQ40eNVtbuv/4772bXfSiJJrENnVfvczf0i/TKCOJmZ+M7wRmSST5uOMCerJgEbLeR7yQIl19juu++eLFIi4uGEPWfOnMQRGwtriROhg/Ovt7BuJkKldbTea6+9MsuE8R3O97g3vodmz56dLIa//vrryaI6wgcRaNb4Pho3blyy7cSJE3vSa9tvOfbDiRhHdLalpBmlvIhkIk1vyII5Hkaud5o4zlgQFHCyZhF4yJAhSYrsm2++eZOF+DB4gXPKufX2u9/9rlfEH9c5DhbemCexRWZ7jmwKUn7n+5vzMWLECEfqdb6Tw7UA5hFrPDh7W4uJxmzDvGFNYfz48T1O4jjYsxayatWqpNwex7VWttO5Tf3P8bgvUmKQviEIUWoC8Ybz8tRTTyW1ZwmAsGZTWsMFsY3of7IGMjbWb2LPx5g4TrYImCCwcx3QFwIRmO/whxNrLVwDobHugCDXSqtXVOyEedxJ4viCBQsSsS401h5Z6yXyFedFAne4j+JsQlQ59+TQyhbHuXYQ2sJ7N8cjOIugone84x1JGmXKLVAqgGuBaw1HsFhWkmbO63rncdin2D0FpyOeeUQgcw8IS2WwL89V1pW9NeO6yCOOc/zYPZv+85y3hsMbYro1zitzi7lHcBMOAZx/7p84ahAVbI13GHvfIoqdZxnPHtahEemvuOKKTeZSK8Tx9evXJ3PWroPzToazGM8L+sn7NtsQKEYQIs/dmDNY2WvYZZ4Lzg1ObKQ/t8Y6NWPmvsF7BQFeZLlhrIzZp+oP98sjjnPtkwk45ItzD8836xBa5jsj/YxFytcbqLhy5crknTxm4fs3v8eySsCVd3hvzdR2Gg18rHUvljhei5B+rySBmCcuHc1K71LPQBoRx3kQ2tQlfDTh9VvEG7KefqftwyIAHpqkFitiCxcuTF4EQ+NGyocxH/9Zxsvj5Zdfnpp2p5k3UPrFC92nPvWpXMNlYSSMgO4EcZw+4uUe1u6yg+UFlhckPBqtWXGc30ldyULC1VdfnYtbWlaAXDtrIxGoKAEvju8yYpz7yOEnVbSXfatbEsf71vnuttGueHnVBkF85cPuF2s2Riojgr9/5/e543d9v9t2YLxeWSexoH437xvbjBrjzr/6Ltev/8bSPFUax1dn7Ov+6+X1rsopM6vEqxl9ef7555PIUgTxpUuX9hyChSQicPiDECfrDAJEReMEXtRCcZwar1nfNLbtn/3sZ27XXXdNPaStI+035PvULhqzaG6FO789aTR9mbHYQmeeMfNdNXXq1F6bdqI4nmesLBJTDsGLRQittrRaVjuxmuBp21txrFb/yFqAeJ5mF110UeIwUcS+973vORbUrZXtdM5i/kEHHVSka8nzOBbRSI3U0047LVdbXKOhWBgTx4teuxyY88w1alMA5+pUAxvVKyp2wjzuJHEc8RXHkrxp9WPlOsoWx5lWlHRBYC1iixcvTsTGVlq98zjsI45K9rmUNQbuBdw7wpKLzbgu8orj9DX2DEgToP03St7zFAt2Yt9YGZG0Nu39sxXiOH255ZZbegVB5RkzmUgol2qtbHGc9ss6F7SFyM+aeNFAQO49YRZV2sojjrNdLBCSzBOUcg2tzHdGP9ayAhVxKMCxoF5D56F8kbdmajuNBj7WGqPE8VqE9HtlCcRqjNBZvLVIc4K3Gymteemu14qI43wwIBQ/+uijDjE5lsqaBxT9arfRT9Ks8KGfJW5zo4Mnf8c44hmP2M7Cll3IYHv2vfjiizNrAdob6De+8Q1HyoyY4Y0XevYTlR3z0rb7ks4Gzz6897KiyG2NGh6yWQsutc5jrcjxrA9/Wz6A2t94KMaMMVHTDucQa7NmzXIf//jHEwcFtrEWE8f9NkRTwI2Xfes9G7aTlTavFiP9LgJVJeDF8QkjxrqPHh6/J1W1793aL4nj3Xpmu3dcb/z9v91df7rfLVhxf/K3t6226O+m7HiwO2LsoW7q2I0pdruBRLjgftLMOW7/I46v3LAe/NG/utuu2BBVwvv68OGd75RQOcgZHSJiGKcERHEWxzEWWqdPn56IODYFZSeNra/3lW/L8847r1ea01pMmimOc2xSaBPZnGV8k916662pcy9LHCeqLIxOjx0HpwGie21kYaeJ4yyc21StdrwI41dddVUS0eytGeKJb5vIUtYb8gjarCWQwS8rDTlRkERLsyaR12bOnJlEu8asbKdzouEZL+saeYwxn3322dFNYxFodkMW+gmKQDD0ZsVxnACIRCxqtsxA0f3r3b5eUbET5nEnieOcP+6BZN3Ik+kxtm7VDHGcfrGey307r9iWllK53jmaZ79657Ftm3cygomy1vvYh3s7a4p2/bUZ10URcTwWOEfpSN4x7b2eexXrz0Sh5plzfo7GysMsWrQocaLIasdnzwlru7dKHKfv1FVnPbjWufVzAien2DO+GeJ4meeC/uNwi7CP5pLXYvpMXnE8lh6e46Ihbbfddj1dsOwaeWf0jZYVqNhJ4jhjbyTwsdackDhei5B+rzSBtPQZvtPUlsYjqRVmX0TtMZtVF73RsbEoRSoNUl0hdpMCi0WKbbfdtlA9ElIQIUKThoYo8/CB0Ggfy9qfGuK8gON1RD95oLEYR70c0n814khRVh8baYfx8LG6bt26ZCy8uPoxkfqFj3OyFoR/eNHLkwKKhQfaph0WDYieINUVNR9Dz9FG+q99RaBKBLw4vvOIndyZh59Spa712b5IHO+zp77jBr503RNuwYoH3F0r7ncrX17d0/9Jo/Z1U3Y62E3Z8RA3evDGD+eOG2CNDuMcSTrCPQ8+yp0++6rKDe+K845zT/92iWvld0LlILShQ4griJRhaaxJkyb1iOJF6z62YQg6ZA4CfE/OmzcviQbECTttUZZvFNLXkg7ypJM2ZOgh8iesH1rrcLUix9mf7yMWQFmcjpUEwwn8ggsuSNK+x2ou00aWOO6dsOlLWK+a/VgYJ716WtS0FceznKER78M62VkO5bW45f09FgXEQi/RyNSctenKScPJQjypvUPj2ztPmnS/T5HIcb8P4hT9is0f7jMIXUX6gAjNwjHjrCUskIIf4S7LynY6J9XxlVdemYw3S5wh099nP/vZ1K4R2EF5NBswwToCEaXsixgfCiZWHC8S0UWUHuIAgmieIIe8c7XIdlZUZJ6TIreWdcI8tsIO9xjWe3AEPO6443qGSMlFrlPOP6ntvZFVgewKrTQyHPqAm6xrjXljM3NacTwreCasoZvnHsOzjDVcnh+1nkvtWOutdx7Hzi3CIlGvd9111yb3E65ZUnHznCTtuLVmXBc2SIl7eCyts+8LmVGtQxNOTpR1iRnzjMAoSvpkOUAwT9gmTB0dtudTc8MtNLbn/QbnJET0sGxIK8Vx+sQ6PdcX7yi1nD24Rn7wgx9sgiwUeMsK8PIHKetc+PZw9uDckro969mYluGW+4wv+0Oby5YtS9UJHnnkETdjRu/yizhC8t7nzYrjjbwzhiemjEBFst6QkaNeqxU5XqXAx1pjlDhei5B+rzyB+fPnJ3VPYjc+Fudi0bTNGFTaxzQv/XyMF/kYa0b/1KYIiIAIiEB+Al4cZ4+vzpiZf0dt2TQCEsebhlYNl0DgTy+tcj9f+VDy55drf93T4ritxyRiOKL43iP2KOFI1W8izFZz3lV3ulFjd6tMp5c9+J/uutn/O+kPKZTJMiVrLgEyHyGIk77TG44JiCPURJR1NwEWZlmQxdEWMYbUs2Rr8GnKWzV6HKMRAMjOxcI7Nadx8sXZ1xuiX79+/RJH4vDvMGosK4IKkYcSAcOGDUtKAsSEhFaNt4zjZKXIxOmcRV6Y4lgwatSoMg7ZcBs4cSMI4hSOsz71trMixfMckHUmsuRxflmQ5rwyfxkz85n6w0WsbKdzUvwyd2mXec51RqADDkfM4zwGN84nNVlZvwozqiB+UZ4PMYE/sShKjgFzri9qj9MefeFawpGe64w/sVrvefrX17ZpxjzuBIYE7ODEhFOTv9aYM8zl8F7d6rEwl31AEeeG4BKuM/pVzz2g1f0vcjwCbbjfcV8jIwTBU91szDXmHePmXs+9fciQIYXmHPODe/Bzzz2XpOkOM6dwX+Yeyn2Q+2c73wsYK+eW5zb9Yqz0h/t9kedFs+ZDGeci7BvcOS881zhHjJXz0Mr7SSveGTshULHsOVN24KPE8bLPkNprCwE+CEjPh0d1WLMurUZI2Z3kAwDP8NBISYLnJh6a7aoxXvY41Z4IiIAI9BUCXhwfNmiou3D6J/rKsCs9TonjlT49fbpzoTMNILZ72wg3fef3uXePPsAdNPqAPseGhUMiIHknP+L0T7sjTz+/Egxee+lFd+UFM9y6lX9Q1HgLz4h3IN5vv/2Skktk25JTQgtPgA5VKoG86UVLPWibGitSP7JNXdRhRUAEREAEREAERKCSBPrSO2MlT0DOTkkczwlKm3UOAdI+4wnFHzyhqDfSbCM1Oak3OB4pVEaOHKlU082GrvZFQAREoIkEvNg1dsQY97HDT23ikdR0XgISx/OS0natJrDsheXu1PmfdP+w14fd9PFHuD3fvkuru1C541Hrz6eZPfGz33IHHPnhtvfx3/75027Jgh8l/VDUeOtOB+m1sbTU0q3riY4kAo0T6EsLnRLHG58vakEEREAEREAERKBvEuhL74ydfIYljnfy2VPfRUAEREAEREAEmkJA4nhTsDbUqBfHJ47ax/3L0d9sqC3tLAIi0HwC1F2jxt1Wgwa7z934sBswaEjzD5pyhAd//K/utstnJ79So/LCCy9sW190YBEQgc4l0JcWOiWOd+48Vc9FQAREQAREQATaS6AvvTO2l3RjR5c43hg/7S0CIiACIiACItCFBO55eqE7f8Fsp8jx6pzc365e7m588BYncbw650Q9EYEsAkQMn3zyyckm24/f0517xR1tAbZ88X1u3qzTk2Mj2H/pS19qSz90UBEQgc4n0JcWOiWOd/581QhEQAREQAREQATaQ6AvvTO2h3A5R5U4Xg5HtSICIiACIiACItBFBOYuudbNfew6ieMVOqd3L3vA3bNsocTxCp0TdUUEahGYM2eO+/a3v51s1o764wuum+Puum7D8Q859HB34/XX1uqyfhcBERCBVAJ9aaFT4rguBBEQAREQAREQARGoj0Bfemesj1A19pI4Xo3zoF6IgAiIgAiIgAhUiMCliy53Nyz7kcTxCp0TosaJHlfkeIVOiroiAjkIhAL55GPPcB865ys59mp8kx/N+Zz7xe03JQ0NHjzE/eY3SxtvVC2IgAj0aQJ9aaFT4nifnuoavAiIgAiIgAiIQAME+tI7YwOY2r6rxPG2nwJ1QAREQAREQAREoGoEPnbHhe7Rtb9KuvXVGTOr1r0+2Z9Lbp3jXn/jr+6YCdPcVw+9qE8y0KBFoFMJED2OSI4deOSx7uhP/l83cPDQpgzn5ReedXd8/xL32N23Ju2zMHHHHe1J6d6UAapRERCBthHgXvbaa68lxx86dKg799xz29aXZh94yZIl7qc//WnPYY455hi37777Nvuwal8EREAEREAEREAEOp5AX3pn7OSTJXG8k8+e+i4CIiACIiACItAUAqE4/skjz3TbDxvZlOOo0XwEnlr3tJv38w0RoBe96xPutL1OyLejthIBEagMgVAg3+Wd+7tDTjnP7fauKaX1D1H8F7ff6B65/SbHv7GzzjrLXXzxxaUdQw2JgAiIgAiIgAiIgAiIgAiIgAiIgAh0PgGJ451/DjUCERABERABERCBkgmE4viUPQ9x79vzPSUfQc0VIXD74wvcQ8sXJ7v84Ni5brfh44vsrm1FQAQqQmDevHlJDfKXX3456dHEKR90Ez/4ETdu74Pq7uGaP/7WLVv4H0kKdS+KEy1+/vnnu2nTptXdrnYUAREQAcTWn4MAAAYVSURBVBEQAREQAREQAREQAREQARHoTgISx7vzvGpUIiACIiACIiACDRCYu+RaN/ex65IWBvTbyl04/RPJ37LWE1j/2kvum3fMTQ48cdTe7l+O/lbrO6EjioAIlEZg2bJliUB+55139rT57qNPcvsddYobPWEv16//gJrHenHNCvfHxx92Sx/4D/fkL+7u2X7ChAnuhBNOcKeffnqS8lgmAiIgAiIgAiIgAiIgAiIgAiIgAiIgApaAxHHNCREQAREQAREQAREwBOYvv9N9+YFLe/7r/mP3didMmi5ObSBw44O3uN+uXp4c+eqj/5+bNEr1LttwGnRIESidgI0i5wADBw1yO07Yw+2wyzvd0FE7uUHbjHID3jYkiQh/6fm1bvXvl7pnfvdrt/65Z3r1Z++993annnqqO/HEE12/fv1K76saFAEREAEREAEREAEREAEREAEREAER6B4CEse751xqJCIgAiIgAiIgAiUReOVvr7pDbzi+V2sSyEuCW6CZJX/6tbtl8e3JHtPGH+6+cdgXC+ytTUVABKpOgCjy++67zy1atCj589prr+Xqcv/+/d3BBx/sdt99dzd16lQ3adKkXPtpIxEQAREQAREQAREQAREQAREQAREQARGQOK45IAIiIAIiIAIiIAIRAp9ecLG79+kH3cB+A92b7u/u9Tf+6saN2DGJIB/2tq3FrMkE7lm20N297IHkKGOG7eBu/MBlbkj/wU0+qpoXARFoJ4GHH37YPfTQQ0kXli9f7l544YWe7lBHnFTpEydOdJMnT1aEeDtPlI4tAiIgAiIgAiIgAiIgAiIgAiIgAh1MQOJ4B588dV0EREAEREAERKB5BIgeP/rf/8G9+rdNIxmJIn/fHodIJC8ZPw4IpFBHFKfWODZ62Ch3zdFz3MgBby/5aGpOBERABERABERABERABERABERABERABERABESgrxGQON7XzrjGKwIiIAIiIAIikJvAky/+wRFBvubVZ6P7bD9spNt/p73d2BE7Ov4tK07AC+JPrXvakUY9tIlj93GXHDrTjdpSbIuT1R4iIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAKWgMRxzQkREAEREAEREAERyCBABPkNv7nF3fr7O1NFcnYf0G+rJO369sO269XaqGEj3cB+A1rKGKE5zV5/43W3Zv1zdf9edCBwCZmQkn6bQVs7+kE/Y30ZO2KM+9A7j3LHjXm/G76FUtgXZa7tRUAEREAEREAEREAEREAEREAEREAEREAEREAE4gQkjmtmiIAIiIAIiIAIiEBOAkSS37NioXvixT84/p0WUZ6zOW0WEEBA33XEzu6wnd/tJo+c6EZv2dvJQLBEQAREQAREQAREQAREQAREQAREQAREQAREQAREoFECEscbJaj9RUAEREAEREAE+jSBxWsfT8a/+pVn3epX1/Zi8chbv+UFtPrVZ3sE912H7+yG9B+cd9eGtztw1L4Nt1G0gdGDR7nRQ7Zzuw0f39KxFu2nthcBERABERABERABERABERABERABERABERABEegOAhLHu+M8ahQiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIiIAIZBCSOa3qIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAh0PQGJ411/ijVAERABERABERABERABERABERABERABERABERABERABERABERABERABERABieOaAyIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAiIgAl1PQOJ4159iDVAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREDiuOaACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIhA1xOQON71p1gDFAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAEREAERkDiuOSACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACIiACItD1BP4/OrOMWDz8TRsAAAAASUVORK5CYII=" - } - }, - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to edit graph state\n", - "\n", - "!!! tip \"Prerequisites\"\n", - "\n", - " * [Human-in-the-loop](../../../concepts/human_in_the_loop)\n", - " * [Breakpoints](../../../concepts/breakpoints)\n", - " * [LangGraph Glossary](../../../concepts/low_level)\n", - "\n", - "Human-in-the-loop (HIL) interactions are crucial for [agentic systems](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#human-in-the-loop). Manually updating the graph state a common HIL interaction pattern, allowing the human to edit actions (e.g., what tool is being called or how it is being called).\n", - "\n", - "We can implement this in LangGraph using a [breakpoint](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/breakpoints/): breakpoints allow us to interrupt graph execution before a specific step. At this breakpoint, we can manually update the graph state and then resume from that spot to continue. \n", - "\n", - "![edit_graph_state.png](attachment:1a5388fe-fa93-4607-a009-d71fe2223f5a.png)" - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First we need to install the packages required" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API keys for Anthropic (the LLM we will use)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ANTHROPIC_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "035e567c-db5c-4085-ba4e-5b3814561c21", - "metadata": {}, - "source": [ - "## Simple Usage\n", - "\n", - "Let's look at very basic usage of this.\n", - "\n", - "Below, we do three things:\n", - "\n", - "1) We specify the [breakpoint](https://langchain-ai.github.io/langgraph/concepts/low_level/#breakpoints) using `interrupt_before` a specified step (node).\n", - "\n", - "2) We set up a [checkpointer](https://langchain-ai.github.io/langgraph/concepts/low_level/#checkpointer) to save the state of the graph up until this node.\n", - "\n", - "3) We use `.update_state` to update the state of the graph." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "85e452f8-f33a-4ead-bb4d-7386cdba8edc", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from typing_extensions import TypedDict\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from IPython.display import Image, display\n", - "\n", - "\n", - "class State(TypedDict):\n", - " input: str\n", - "\n", - "\n", - "def step_1(state):\n", - " print(\"---Step 1---\")\n", - " pass\n", - "\n", - "\n", - "def step_2(state):\n", - " print(\"---Step 2---\")\n", - " pass\n", - "\n", - "\n", - "def step_3(state):\n", - " print(\"---Step 3---\")\n", - " pass\n", - "\n", - "\n", - "builder = StateGraph(State)\n", - "builder.add_node(\"step_1\", step_1)\n", - "builder.add_node(\"step_2\", step_2)\n", - "builder.add_node(\"step_3\", step_3)\n", - "builder.add_edge(START, \"step_1\")\n", - "builder.add_edge(\"step_1\", \"step_2\")\n", - "builder.add_edge(\"step_2\", \"step_3\")\n", - "builder.add_edge(\"step_3\", END)\n", - "\n", - "# Set up memory\n", - "memory = MemorySaver()\n", - "\n", - "# Add\n", - "graph = builder.compile(checkpointer=memory, interrupt_before=[\"step_2\"])\n", - "\n", - "# View\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "1b3aa6fc-c7fb-4819-8d7f-ba6057cc4edf", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'input': 'hello world'}\n", - "---Step 1---\n" - ] - } - ], - "source": [ - "# Input\n", - "initial_input = {\"input\": \"hello world\"}\n", - "\n", - "# Thread\n", - "thread = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "\n", - "# Run the graph until the first interruption\n", - "for event in graph.stream(initial_input, thread, stream_mode=\"values\"):\n", - " print(event)" - ] - }, - { - "cell_type": "markdown", - "id": "4ab27716-e861-4ba3-9d7d-90694013e3c4", - "metadata": {}, - "source": [ - "Now, we can just manually update our graph state - " - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "49d61230-e5dc-4272-b8ab-09b0af30f088", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current state!\n", - "{'input': 'hello world'}\n", - "---\n", - "---\n", - "Updated state!\n", - "{'input': 'hello universe!'}\n" - ] - } - ], - "source": [ - "print(\"Current state!\")\n", - "print(graph.get_state(thread).values)\n", - "\n", - "graph.update_state(thread, {\"input\": \"hello universe!\"})\n", - "\n", - "print(\"---\\n---\\nUpdated state!\")\n", - "print(graph.get_state(thread).values)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "cf77f6eb-4cc0-4615-a095-eb5ae7027b7a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "---Step 2---\n", - "---Step 3---\n" - ] - } - ], - "source": [ - "# Continue the graph execution\n", - "for event in graph.stream(None, thread, stream_mode=\"values\"):\n", - " print(event)" - ] - }, - { - "cell_type": "markdown", - "id": "3333b771", - "metadata": {}, - "source": [ - "## Agent\n", - "\n", - "In the context of agents, updating state is useful for things like editing tool calls.\n", - " \n", - "To show this, we will build a relatively simple ReAct-style agent that does tool calling. \n", - "\n", - "We will use Anthropic's models and a fake tool (just for demo purposes)." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "6098e5cb", - "metadata": {}, - "outputs": [], - "source": [ - "# Set up the tool\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.tools import tool\n", - "from langgraph.graph import MessagesState, START, END, StateGraph\n", - "from langgraph.prebuilt import ToolNode\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "\n", - "@tool\n", - "def search(query: str):\n", - " \"\"\"Call to surf the web.\"\"\"\n", - " # This is a placeholder for the actual implementation\n", - " # Don't let the LLM know this though 😊\n", - " return [\n", - " \"It's sunny in San Francisco, but you better look out if you're a Gemini 😈.\"\n", - " ]\n", - "\n", - "\n", - "tools = [search]\n", - "tool_node = ToolNode(tools)\n", - "\n", - "# Set up the model\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", - "model = model.bind_tools(tools)\n", - "\n", - "\n", - "# Define nodes and conditional edges\n", - "\n", - "\n", - "# Define the function that determines whether to continue or not\n", - "def should_continue(state):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return \"end\"\n", - " # Otherwise if there is, we continue\n", - " else:\n", - " return \"continue\"\n", - "\n", - "\n", - "# Define the function that calls the model\n", - "def call_model(state):\n", - " messages = state[\"messages\"]\n", - " response = model.invoke(messages)\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " # Finally we pass in a mapping.\n", - " # The keys are strings, and the values are other nodes.\n", - " # END is a special node marking that the graph should finish.\n", - " # What will happen is we will call `should_continue`, and then the output of that\n", - " # will be matched against the keys in this mapping.\n", - " # Based on which one it matches, that node will then be called.\n", - " {\n", - " # If `tools`, then we call the tool node.\n", - " \"continue\": \"action\",\n", - " # Otherwise we finish.\n", - " \"end\": END,\n", - " },\n", - ")\n", - "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")\n", - "\n", - "# Set up memory\n", - "memory = MemorySaver()\n", - "\n", - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", - "\n", - "# We add in `interrupt_before=[\"action\"]`\n", - "# This will add a breakpoint before the `action` node is called\n", - "app = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])" - ] - }, - { - "cell_type": "markdown", - "id": "2a1b56c5-bd61-4192-8bdb-458a1e9f0159", - "metadata": {}, - "source": [ - "## Interacting with the Agent\n", - "\n", - "We can now interact with the agent and see that it stops before calling a tool.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "cfd140f0-a5a6-4697-8115-322242f197b5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "search for the weather in sf now\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'll search for the current weather in San Francisco for you. Let me use the search function to find this information.\", 'type': 'text'}, {'id': 'toolu_01DxRhkj4fAvaGWoBhVuvfeL', 'input': {'query': 'current weather in San Francisco'}, 'name': 'search', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " search (toolu_01DxRhkj4fAvaGWoBhVuvfeL)\n", - " Call ID: toolu_01DxRhkj4fAvaGWoBhVuvfeL\n", - " Args:\n", - " query: current weather in San Francisco\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "thread = {\"configurable\": {\"thread_id\": \"3\"}}\n", - "inputs = [HumanMessage(content=\"search for the weather in sf now\")]\n", - "for event in app.stream({\"messages\": inputs}, thread, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "78e3f5b9-9700-42b1-863f-c404861f8620", - "metadata": {}, - "source": [ - "**Edit**\n", - "\n", - "We can now update the state accordingly. Let's modify the tool call to have the query `\"current weather in SF\"`." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "1aa7b1b9-9322-4815-bc0d-eb083870ac15", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'configurable': {'thread_id': '3',\n", - " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1ef7830a-c688-6fc6-8002-824126081ba0'}}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# First, lets get the current state\n", - "current_state = app.get_state(thread)\n", - "\n", - "# Let's now get the last message in the state\n", - "# This is the one with the tool calls that we want to update\n", - "last_message = current_state.values[\"messages\"][-1]\n", - "\n", - "# Let's now update the args for that tool call\n", - "last_message.tool_calls[0][\"args\"] = {\"query\": \"current weather in SF\"}\n", - "\n", - "# Let's now call `update_state` to pass in this message in the `messages` key\n", - "# This will get treated as any other update to the state\n", - "# It will get passed to the reducer function for the `messages` key\n", - "# That reducer function will use the ID of the message to update it\n", - "# It's important that it has the right ID! Otherwise it would get appended\n", - "# as a new message\n", - "app.update_state(thread, {\"messages\": last_message})" - ] - }, - { - "cell_type": "markdown", - "id": "0dcc5457-1ba1-4cba-ac41-da5c67cc67e5", - "metadata": {}, - "source": [ - "Let's now check the current state of the app to make sure it got updated accordingly" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "a3fcf2bd-f881-49fe-b20e-ad16e6819bc6", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'name': 'search',\n", - " 'args': {'query': 'current weather in SF'},\n", - " 'id': 'toolu_01FSkinAVXR1C4D5kecrzAnj'}]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "current_state = app.get_state(thread).values[\"messages\"][-1].tool_calls\n", - "current_state" - ] - }, - { - "cell_type": "markdown", - "id": "1bca3814-db08-4b0b-8c0c-95b6c5440c81", - "metadata": {}, - "source": [ - "**Resume**\n", - "\n", - "We can now call the agent again with no inputs to continue, ie. run the tool as requested. We can see from the logs that it passes in the update args to the tool." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "51923913-20f7-4ee1-b9ba-d01f5fb2869b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: search\n", - "\n", - "[\"It's sunny in San Francisco, but you better look out if you're a Gemini \\ud83d\\ude08.\"]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Based on the search results, I can provide you with the current weather information for San Francisco:\n", - "\n", - "The weather in San Francisco is currently sunny. \n", - "\n", - "It's important to note that the search result also included a playful astrological reference, which isn't directly related to the weather. If you need more specific weather details like temperature, humidity, or forecast, please let me know, and I can perform another search to find that information for you.\n", - "\n", - "Is there anything else you'd like to know about the weather in San Francisco or any other location?\n" - ] - } - ], - "source": [ - "for event in app.stream(None, thread, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/human_in_the_loop/time-travel.ipynb b/docs/docs/how-tos/human_in_the_loop/time-travel.ipynb index 7e363b12d..62701c773 100644 --- a/docs/docs/how-tos/human_in_the_loop/time-travel.ipynb +++ b/docs/docs/how-tos/human_in_the_loop/time-travel.ipynb @@ -1,56 +1,38 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", + "id": "c23e0a59-759a-4226-997e-8a69f7661d32", "metadata": {}, "source": [ - "# How to view and update past graph state\n", + "# Use time-travel\n", "\n", - "!!! tip \"Prerequisites\"\n", + "To use time-travel in LangGraph:\n", "\n", - " This guide assumes familiarity with the following concepts:\n", + "1. **Identify a checkpoint in an existing thread**: Use the [`get_state_history()`][langgraph.graph.graph.CompiledGraph.get_state_history] method to retrieve the execution history for a specific `thread_id` and locate the desired `checkpoint_id`. \n", + " Alternatively, set a [breakpoint](../../../concepts/breakpoints/) before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that breakpoint.\n", + "2. **(Optional) modify the graph state**: Use the [`update_state`][langgraph.graph.graph.CompiledGraph.update_state] method to modify the graph’s state at the checkpoint and resume execution from alternative state.\n", + "3. **Resume execution from the checkpoint**: Use the `invoke` or `stream` APIs with an input of `None` and a configuration containing the appropriate `thread_id` and `checkpoint_id`.\n", "\n", - " * [Time Travel](../../../concepts/time-travel)\n", - " * [Breakpoints](../../../concepts/breakpoints)\n", - " * [LangGraph Glossary](../../../concepts/low_level)\n", + "## Example\n", "\n", + "This example builds a simple LangGraph workflow that generates a joke topic and writes a joke using an LLM. It demonstrates how to run the graph, retrieve past execution checkpoints, optionally modify the state, and resume execution from a chosen checkpoint to explore alternate outcomes.\n", "\n", - "Once you start [checkpointing](../../persistence) your graphs, you can easily **get** or **update** the state of the agent at any point in time. This permits a few things:\n", - "\n", - "1. You can surface a state during an interrupt to a user to let them accept an action.\n", - "2. You can **rewind** the graph to reproduce or avoid issues.\n", - "3. You can **modify** the state to embed your agent into a larger system, or to let the user better control its actions.\n", - "\n", - "The key methods used for this functionality are:\n", - "\n", - "- [get_state](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.graph.CompiledGraph.get_state): fetch the values from the target config\n", - "- [update_state](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.graph.CompiledGraph.update_state): apply the given values to the target state\n", - "\n", - "**Note:** this requires passing in a checkpointer.\n", - "\n", - "Below is a quick example." - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", + "### Setup\n", "\n", "First we need to install the packages required" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 38, "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", "metadata": {}, "outputs": [], "source": [ "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_openai" + "%pip install --quiet -U langgraph langchain_anthropic" ] }, { @@ -58,23 +40,15 @@ "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", "metadata": {}, "source": [ - "Next, we need to set API keys for OpenAI (the LLM we will use)" + "Next, we need to set API keys for Anthropic (the LLM we will use)" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ANTHROPIC_API_KEY: ········\n" - ] - } - ], + "outputs": [], "source": [ "import getpass\n", "import os\n", @@ -85,7 +59,7 @@ " os.environ[var] = getpass.getpass(f\"{var}: \")\n", "\n", "\n", - "_set_env(\"OPENAI_API_KEY\")" + "_set_env(\"ANTHROPIC_API_KEY\")" ] }, { @@ -101,484 +75,237 @@ "" ] }, - { - "cell_type": "markdown", - "id": "e36f89e5", - "metadata": {}, - "source": [ - "## Build the agent\n", - "\n", - "We can now build the agent. We will build a relatively simple ReAct-style agent that does tool calling. We will use Anthropic's models and fake tools (just for demo purposes)." - ] - }, { "cell_type": "code", - "execution_count": 42, - "id": "f5319e01", + "execution_count": 2, + "id": "4e1e9b07-4185-4d6c-8834-a0ae07dfdf4b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "# Set up the tool\n", - "from langchain_openai import ChatOpenAI\n", - "from langchain_core.tools import tool\n", - "from langgraph.graph import MessagesState, START\n", - "from langgraph.prebuilt import ToolNode\n", - "from langgraph.graph import END, StateGraph\n", - "from langgraph.checkpoint.memory import MemorySaver\n", + "import uuid\n", + "\n", + "from typing_extensions import TypedDict, NotRequired\n", + "from langgraph.graph import StateGraph, START, END\n", + "from langchain.chat_models import init_chat_model\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", "\n", "\n", - "@tool\n", - "def play_song_on_spotify(song: str):\n", - " \"\"\"Play a song on Spotify\"\"\"\n", - " # Call the spotify API ...\n", - " return f\"Successfully played {song} on Spotify!\"\n", + "class State(TypedDict):\n", + " topic: NotRequired[str]\n", + " joke: NotRequired[str]\n", "\n", "\n", - "@tool\n", - "def play_song_on_apple(song: str):\n", - " \"\"\"Play a song on Apple Music\"\"\"\n", - " # Call the apple music API ...\n", - " return f\"Successfully played {song} on Apple Music!\"\n", - "\n", - "\n", - "tools = [play_song_on_apple, play_song_on_spotify]\n", - "tool_node = ToolNode(tools)\n", - "\n", - "# Set up the model\n", - "\n", - "model = ChatOpenAI(model=\"gpt-4o-mini\")\n", - "model = model.bind_tools(tools, parallel_tool_calls=False)\n", - "\n", - "\n", - "# Define nodes and conditional edges\n", - "\n", - "\n", - "# Define the function that determines whether to continue or not\n", - "def should_continue(state):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return \"end\"\n", - " # Otherwise if there is, we continue\n", - " else:\n", - " return \"continue\"\n", - "\n", - "\n", - "# Define the function that calls the model\n", - "def call_model(state):\n", - " messages = state[\"messages\"]\n", - " response = model.invoke(messages)\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " # Finally we pass in a mapping.\n", - " # The keys are strings, and the values are other nodes.\n", - " # END is a special node marking that the graph should finish.\n", - " # What will happen is we will call `should_continue`, and then the output of that\n", - " # will be matched against the keys in this mapping.\n", - " # Based on which one it matches, that node will then be called.\n", - " {\n", - " # If `tools`, then we call the tool node.\n", - " \"continue\": \"action\",\n", - " # Otherwise we finish.\n", - " \"end\": END,\n", - " },\n", + "llm = init_chat_model(\n", + " \"anthropic:claude-3-7-sonnet-latest\",\n", + " temperature=0,\n", ")\n", "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")\n", "\n", - "# Set up memory\n", - "memory = MemorySaver()\n", + "def generate_topic(state: State):\n", + " \"\"\"LLM call to generate a topic for the joke\"\"\"\n", + " msg = llm.invoke(\"Give me a funny topic for a joke\")\n", + " return {\"topic\": msg.content}\n", "\n", - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", "\n", - "# We add in `interrupt_before=[\"action\"]`\n", - "# This will add a breakpoint before the `action` node is called\n", - "app = workflow.compile(checkpointer=memory)" + "def write_joke(state: State):\n", + " \"\"\"LLM call to write a joke based on the topic\"\"\"\n", + " msg = llm.invoke(f\"Write a short joke about {state['topic']}\")\n", + " return {\"joke\": msg.content}\n", + "\n", + "\n", + "# Build workflow\n", + "workflow = StateGraph(State)\n", + "\n", + "# Add nodes\n", + "workflow.add_node(\"generate_topic\", generate_topic)\n", + "workflow.add_node(\"write_joke\", write_joke)\n", + "\n", + "# Add edges to connect nodes\n", + "workflow.add_edge(START, \"generate_topic\")\n", + "workflow.add_edge(\"generate_topic\", \"write_joke\")\n", + "workflow.add_edge(\"write_joke\", END)\n", + "\n", + "# Compile\n", + "checkpointer = InMemorySaver()\n", + "graph = workflow.compile(checkpointer=checkpointer)\n", + "graph" ] }, { "cell_type": "markdown", - "id": "2a1b56c5-bd61-4192-8bdb-458a1e9f0159", + "id": "7ef76675-02e4-42ef-b707-0a9ce36ba0ac", "metadata": {}, "source": [ - "## Interacting with the Agent\n", - "\n", - "We can now interact with the agent. Let's ask it to play Taylor Swift's most popular song:\n" + "### Run the graph" ] }, { "cell_type": "code", - "execution_count": 43, - "id": "cfd140f0-a5a6-4697-8115-322242f197b5", + "execution_count": 3, + "id": "3199a8d0-17c0-4979-ac08-52d7007b7689", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", + "How about \"The Secret Life of Socks in the Dryer\"? You know, exploring the mysterious phenomenon of how socks go into the laundry as pairs but come out as singles. Where do they go? Are they starting new lives elsewhere? Is there a sock paradise we don't know about? There's a lot of comedic potential in the everyday mystery that unites us all!\n", "\n", - "Can you play Taylor Swift's most popular song?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " play_song_on_apple (call_uhGY6Fv6Mr4ZOhSokintuoD7)\n", - " Call ID: call_uhGY6Fv6Mr4ZOhSokintuoD7\n", - " Args:\n", - " song: Anti-Hero by Taylor Swift\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: play_song_on_apple\n", + "# The Secret Life of Socks in the Dryer\n", "\n", - "Succesfully played Anti-Hero by Taylor Swift on Apple Music!\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "I finally discovered where all my missing socks go after the dryer. Turns out they're not missing at all—they've just eloped with someone else's socks from the laundromat to start new lives together.\n", "\n", - "I've successfully played \"Anti-Hero\" by Taylor Swift on Apple Music! Enjoy the music!\n" + "My blue argyle is now living in Bermuda with a red polka dot, posting vacation photos on Sockstagram and sending me lint as alimony.\n" ] } ], "source": [ - "from langchain_core.messages import HumanMessage\n", + "config = {\n", + " \"configurable\": {\n", + " \"thread_id\": uuid.uuid4(),\n", + " }\n", + "}\n", + "state = graph.invoke({}, config)\n", "\n", - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "input_message = HumanMessage(content=\"Can you play Taylor Swift's most popular song?\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" + "print(state[\"topic\"])\n", + "print()\n", + "print(state[\"joke\"])" ] }, { "cell_type": "markdown", - "id": "1c38c505-6cee-427f-9dcd-493a2ade7ebb", + "id": "2fc0fc7f-5a7b-4b48-b1e2-d413ad4a51aa", "metadata": {}, "source": [ - "## Checking history\n", - "\n", - "Let's browse the history of this thread, from start to finish." + "### 1. Identify a checkpoint" ] }, { "cell_type": "code", - "execution_count": 44, - "id": "777538a5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'function': {'arguments': '{\"song\":\"Anti-Hero by Taylor Swift\"}', 'name': 'play_song_on_apple'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 80, 'total_tokens': 102}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0', tool_calls=[{'name': 'play_song_on_apple', 'args': {'song': 'Anti-Hero by Taylor Swift'}, 'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 80, 'output_tokens': 22, 'total_tokens': 102}),\n", - " ToolMessage(content='Succesfully played Anti-Hero by Taylor Swift on Apple Music!', name='play_song_on_apple', id='43a39ca7-326a-4033-8607-bf061615ed6b', tool_call_id='call_uhGY6Fv6Mr4ZOhSokintuoD7'),\n", - " AIMessage(content='I\\'ve successfully played \"Anti-Hero\" by Taylor Swift on Apple Music! Enjoy the music!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 126, 'total_tokens': 146}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'stop', 'logprobs': None}, id='run-bfee6b28-9f16-49cc-8d28-bfb5a5b9aea1-0', usage_metadata={'input_tokens': 126, 'output_tokens': 20, 'total_tokens': 146})]" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "app.get_state(config).values[\"messages\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "8578a66d-6489-4e03-8c23-fd0530278455", + "execution_count": 4, + "id": "e7f54f90-bff1-4810-8488-c8fce6b5a03f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "StateSnapshot(values={'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'function': {'arguments': '{\"song\":\"Anti-Hero by Taylor Swift\"}', 'name': 'play_song_on_apple'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 80, 'total_tokens': 102}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0', tool_calls=[{'name': 'play_song_on_apple', 'args': {'song': 'Anti-Hero by Taylor Swift'}, 'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 80, 'output_tokens': 22, 'total_tokens': 102}), ToolMessage(content='Succesfully played Anti-Hero by Taylor Swift on Apple Music!', name='play_song_on_apple', id='43a39ca7-326a-4033-8607-bf061615ed6b', tool_call_id='call_uhGY6Fv6Mr4ZOhSokintuoD7'), AIMessage(content='I\\'ve successfully played \"Anti-Hero\" by Taylor Swift on Apple Music! Enjoy the music!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 126, 'total_tokens': 146}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'stop', 'logprobs': None}, id='run-bfee6b28-9f16-49cc-8d28-bfb5a5b9aea1-0', usage_metadata={'input_tokens': 126, 'output_tokens': 20, 'total_tokens': 146})]}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-364f-6228-8003-dd67a426334e'}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='I\\'ve successfully played \"Anti-Hero\" by Taylor Swift on Apple Music! Enjoy the music!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 126, 'total_tokens': 146}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'stop', 'logprobs': None}, id='run-bfee6b28-9f16-49cc-8d28-bfb5a5b9aea1-0', usage_metadata={'input_tokens': 126, 'output_tokens': 20, 'total_tokens': 146})]}}, 'step': 3, 'parents': {}}, created_at='2024-09-05T21:37:39.955948+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-318f-6dc8-8002-dbdf9aaeac83'}}, tasks=())\n", - "--\n", - "StateSnapshot(values={'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'function': {'arguments': '{\"song\":\"Anti-Hero by Taylor Swift\"}', 'name': 'play_song_on_apple'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 80, 'total_tokens': 102}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0', tool_calls=[{'name': 'play_song_on_apple', 'args': {'song': 'Anti-Hero by Taylor Swift'}, 'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 80, 'output_tokens': 22, 'total_tokens': 102}), ToolMessage(content='Succesfully played Anti-Hero by Taylor Swift on Apple Music!', name='play_song_on_apple', id='43a39ca7-326a-4033-8607-bf061615ed6b', tool_call_id='call_uhGY6Fv6Mr4ZOhSokintuoD7')]}, next=('agent',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-318f-6dc8-8002-dbdf9aaeac83'}}, metadata={'source': 'loop', 'writes': {'action': {'messages': [ToolMessage(content='Succesfully played Anti-Hero by Taylor Swift on Apple Music!', name='play_song_on_apple', id='43a39ca7-326a-4033-8607-bf061615ed6b', tool_call_id='call_uhGY6Fv6Mr4ZOhSokintuoD7')]}}, 'step': 2, 'parents': {}}, created_at='2024-09-05T21:37:39.458185+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-3185-663e-8001-12b1ec3114b8'}}, tasks=(PregelTask(id='3a4c5ddb-14b2-5def-a766-02ddc32948ba', name='agent', error=None, interrupts=(), state=None),))\n", - "--\n", - "StateSnapshot(values={'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'function': {'arguments': '{\"song\":\"Anti-Hero by Taylor Swift\"}', 'name': 'play_song_on_apple'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 80, 'total_tokens': 102}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0', tool_calls=[{'name': 'play_song_on_apple', 'args': {'song': 'Anti-Hero by Taylor Swift'}, 'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 80, 'output_tokens': 22, 'total_tokens': 102})]}, next=('action',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-3185-663e-8001-12b1ec3114b8'}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'function': {'arguments': '{\"song\":\"Anti-Hero by Taylor Swift\"}', 'name': 'play_song_on_apple'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 80, 'total_tokens': 102}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0', tool_calls=[{'name': 'play_song_on_apple', 'args': {'song': 'Anti-Hero by Taylor Swift'}, 'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 80, 'output_tokens': 22, 'total_tokens': 102})]}}, 'step': 1, 'parents': {}}, created_at='2024-09-05T21:37:39.453898+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-29b8-6370-8000-f9f6e7ca1b06'}}, tasks=(PregelTask(id='01f1dc72-5a39-5876-97a6-abdc12f70c2a', name='action', error=None, interrupts=(), state=None),))\n", - "--\n", - "StateSnapshot(values={'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b')]}, next=('agent',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-29b8-6370-8000-f9f6e7ca1b06'}}, metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}}, created_at='2024-09-05T21:37:38.635849+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-29b3-6514-bfff-fe07fb36f14f'}}, tasks=(PregelTask(id='348e1ba7-95c6-5b89-80c9-1fc4720e35ef', name='agent', error=None, interrupts=(), state=None),))\n", - "--\n", - "StateSnapshot(values={'messages': []}, next=('__start__',), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef6bcf1-29b3-6514-bfff-fe07fb36f14f'}}, metadata={'source': 'input', 'writes': {'__start__': {'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\")]}}, 'step': -1, 'parents': {}}, created_at='2024-09-05T21:37:38.633849+00:00', parent_config=None, tasks=(PregelTask(id='f1cfbb8c-7792-5cf9-9d28-ae3ac7724cf3', name='__start__', error=None, interrupts=(), state=None),))\n", - "--\n" + "()\n", + "1f02ac4a-ec9f-6524-8002-8f7b0bbeed0e\n", + "\n", + "('write_joke',)\n", + "1f02ac4a-ce2a-6494-8001-cb2e2d651227\n", + "\n", + "('generate_topic',)\n", + "1f02ac4a-a4e0-630d-8000-b73c254ba748\n", + "\n", + "('__start__',)\n", + "1f02ac4a-a4dd-665e-bfff-e6c8c44315d9\n", + "\n" ] } ], "source": [ - "all_states = []\n", - "for state in app.get_state_history(config):\n", - " print(state)\n", - " all_states.append(state)\n", - " print(\"--\")" - ] - }, - { - "cell_type": "markdown", - "id": "0ec41c37-7c09-4cc7-8475-bf373fe66584", - "metadata": {}, - "source": [ - "## Replay a state\n", + "# The states are returned in reverse chronological order.\n", + "states = list(graph.get_state_history(config))\n", "\n", - "We can go back to any of these states and restart the agent from there! Let's go back to right before the tool call gets executed." + "for state in states:\n", + " print(state.next)\n", + " print(state.config[\"configurable\"][\"checkpoint_id\"])\n", + " print()" ] }, { "cell_type": "code", - "execution_count": 46, - "id": "02250602-8c4a-4fb5-bd6c-d0b9046e8699", - "metadata": {}, - "outputs": [], - "source": [ - "to_replay = all_states[2]" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "id": "21e7fc18-6fd9-4e11-a84b-e0325c9640c8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'function': {'arguments': '{\"song\":\"Anti-Hero by Taylor Swift\"}', 'name': 'play_song_on_apple'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 80, 'total_tokens': 102}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0', tool_calls=[{'name': 'play_song_on_apple', 'args': {'song': 'Anti-Hero by Taylor Swift'}, 'id': 'call_uhGY6Fv6Mr4ZOhSokintuoD7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 80, 'output_tokens': 22, 'total_tokens': 102})]}" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "to_replay.values" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "id": "d4b01634-0041-4632-8d1f-5464580e54f5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('action',)" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "to_replay.next" - ] - }, - { - "cell_type": "markdown", - "id": "29da43ea-9295-43e2-b164-0eb28d96749c", - "metadata": {}, - "source": [ - "To replay from this place we just need to pass its config back to the agent. Notice that it just resumes from right where it left all - making a tool call." - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "e986f94f-706f-4b6f-b3c4-f95483b9e9b8", + "execution_count": 5, + "id": "2f5d918d-0c1b-42b8-9d26-15b58aaaf058", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'messages': [ToolMessage(content='Succesfully played Anti-Hero by Taylor Swift on Apple Music!', name='play_song_on_apple', tool_call_id='call_uhGY6Fv6Mr4ZOhSokintuoD7')]}\n", - "{'messages': [AIMessage(content='I\\'ve started playing \"Anti-Hero\" by Taylor Swift on Apple Music! Enjoy the music!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 126, 'total_tokens': 146}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'stop', 'logprobs': None}, id='run-dc338bbd-d623-40bb-b824-5d2307954b57-0', usage_metadata={'input_tokens': 126, 'output_tokens': 20, 'total_tokens': 146})]}\n" + "('write_joke',)\n", + "{'topic': 'How about \"The Secret Life of Socks in the Dryer\"? You know, exploring the mysterious phenomenon of how socks go into the laundry as pairs but come out as singles. Where do they go? Are they starting new lives elsewhere? Is there a sock paradise we don\\'t know about? There\\'s a lot of comedic potential in the everyday mystery that unites us all!'}\n" ] } ], "source": [ - "for event in app.stream(None, to_replay.config):\n", - " for v in event.values():\n", - " print(v)" + "# This is the state before last (states are listed in chronological order)\n", + "selected_state = states[1]\n", + "print(selected_state.next)\n", + "print(selected_state.values)" ] }, { "cell_type": "markdown", - "id": "59910951-fae1-4475-8511-f622439b590d", + "id": "59d5ecb8-1291-4131-83b6-c666862a09fc", "metadata": {}, "source": [ - "## Branch off a past state\n", + "### 2. (Optional) update the state\n", "\n", - "Using LangGraph's checkpointing, you can do more than just replay past states. You can branch off previous locations to let the agent explore alternate trajectories or to let a user \"version control\" changes in a workflow.\n", - "\n", - "Let's show how to do this to edit the state at a particular point in time. Let's update the state to instead of playing the song on Apple to play it on Spotify:" + "`update_state` will create a new checkpoint. The new checkpoint will be associated with the same thread, but a new checkpoint ID." ] }, { "cell_type": "code", - "execution_count": 52, - "id": "fbd5ad3b-5363-4ab7-ac63-b04668bc998f", - "metadata": {}, - "outputs": [], - "source": [ - "# Let's now get the last message in the state\n", - "# This is the one with the tool calls that we want to update\n", - "last_message = to_replay.values[\"messages\"][-1]\n", - "\n", - "\n", - "# Let's now update the tool we are calling\n", - "last_message.tool_calls[0][\"name\"] = \"play_song_on_spotify\"\n", - "\n", - "branch_config = app.update_state(\n", - " to_replay.config,\n", - " {\"messages\": [last_message]},\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "bced65eb-2158-43e6-a9e3-3b047c8d418e", - "metadata": {}, - "source": [ - "We can then invoke with this new `branch_config` to resume running from here with changed state. We can see from the log that the tool was called with different input." - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "id": "9a92d3da-62e2-45a2-8545-e4f6a64e0ffe", + "execution_count": 6, + "id": "5ad78ce6-9a7f-4110-9e4a-8105f21cb90d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'messages': [ToolMessage(content='Succesfully played Anti-Hero by Taylor Swift on Spotify!', name='play_song_on_spotify', tool_call_id='call_uhGY6Fv6Mr4ZOhSokintuoD7')]}\n", - "{'messages': [AIMessage(content='I\\'ve started playing \"Anti-Hero\" by Taylor Swift on Spotify. Enjoy the music!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 19, 'prompt_tokens': 125, 'total_tokens': 144}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_483d39d857', 'finish_reason': 'stop', 'logprobs': None}, id='run-7d8d5094-7029-4da3-9e0e-ef9d18b63615-0', usage_metadata={'input_tokens': 125, 'output_tokens': 19, 'total_tokens': 144})]}\n" + "{'configurable': {'thread_id': 'c62e2e03-c27b-4cb6-8cea-ea9bfedae006', 'checkpoint_ns': '', 'checkpoint_id': '1f02ac4a-ecee-600b-8002-a1d21df32e4c'}}\n" ] } ], "source": [ - "for event in app.stream(None, branch_config):\n", - " for v in event.values():\n", - " print(v)" + "new_config = graph.update_state(selected_state.config, values={\"topic\": \"chickens\"})\n", + "print(new_config)" ] }, { "cell_type": "markdown", - "id": "511e319e-d10d-4b04-a4e0-fc4f3d87cb23", + "id": "db25cd11-7907-4c6f-9c97-b6b3458f246c", "metadata": {}, "source": [ - "Alternatively, we could update the state to not even call a tool!" + "### 3. Resume execution from the checkpoint" ] }, { "cell_type": "code", - "execution_count": 54, - "id": "01abb480-df55-4eba-a2be-cf9372b60b54", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import AIMessage\n", - "\n", - "# Let's now get the last message in the state\n", - "# This is the one with the tool calls that we want to update\n", - "last_message = to_replay.values[\"messages\"][-1]\n", - "\n", - "# Let's now get the ID for the last message, and create a new message with that ID.\n", - "new_message = AIMessage(\n", - " content=\"It's quiet hours so I can't play any music right now!\", id=last_message.id\n", - ")\n", - "\n", - "branch_config = app.update_state(\n", - " to_replay.config,\n", - " {\"messages\": [new_message]},\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "id": "1a7cfcd4-289e-419e-8b49-dfaef4f88641", - "metadata": {}, - "outputs": [], - "source": [ - "branch_state = app.get_state(branch_config)" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "id": "5198f9c1-d2d4-458a-993d-3caa55810b1e", + "execution_count": 7, + "id": "f0bab935-6d9b-4cfd-afe8-bfcf4638847e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'messages': [HumanMessage(content=\"Can you play Taylor Swift's most popular song?\", id='7e32f0f3-75f5-48e1-a4ae-d38ccc15973b'),\n", - " AIMessage(content=\"It's quiet hours so I can't play any music right now!\", id='run-af077bc4-f03c-4afe-8d92-78bdae394412-0')]}" + "{'topic': 'chickens',\n", + " 'joke': 'Why did the chicken join a band?\\n\\nBecause it had excellent drumsticks!'}" ] }, - "execution_count": 56, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "branch_state.values" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "id": "5d89d55d-db84-4c2d-828b-64a29a69947b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "()" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "branch_state.next" - ] - }, - { - "cell_type": "markdown", - "id": "cc168c90-a374-4280-a9a6-8bc232dbb006", - "metadata": {}, - "source": [ - "You can see the snapshot was updated and now correctly reflects that there is no next step." + "graph.invoke(None, new_config)" ] } ], diff --git a/docs/docs/how-tos/human_in_the_loop/wait-user-input.ipynb b/docs/docs/how-tos/human_in_the_loop/wait-user-input.ipynb index 562d6aad9..bbe14b4f1 100644 --- a/docs/docs/how-tos/human_in_the_loop/wait-user-input.ipynb +++ b/docs/docs/how-tos/human_in_the_loop/wait-user-input.ipynb @@ -597,7 +597,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.11.4" } }, "nbformat": 4, diff --git a/docs/docs/how-tos/index.md b/docs/docs/how-tos/index.md deleted file mode 100644 index 5b3816182..000000000 --- a/docs/docs/how-tos/index.md +++ /dev/null @@ -1,324 +0,0 @@ ---- -title: How-to Guides -description: How to accomplish common tasks in LangGraph -search: - boost: 0.5 ---- - -# How-to Guides - -Here you’ll find answers to “How do I...?” types of questions. These guides are **goal-oriented** and concrete; they're meant to help you complete a specific task. For conceptual explanations see the [Conceptual guide](../concepts/index.md). For end-to-end walk-throughs see [Tutorials](../tutorials/index.md). For comprehensive descriptions of every class and function see the [API Reference](../reference/index.md). - -## LangGraph - -### Graph API Basics - -- [How to update graph state from nodes](state-reducers.ipynb) -- [How to create a sequence of steps](sequence.ipynb) -- [How to create branches for parallel execution](branching.ipynb) -- [How to create and control loops with recursion limits](recursion-limit.ipynb) -- [How to visualize your graph](visualization.ipynb) - -### Fine-grained Control - -These guides demonstrate LangGraph features that grant fine-grained control over the -execution of your graph. - -- [How to create map-reduce branches for parallel execution](map-reduce.ipynb) -- [How to update state and jump to nodes in graphs and subgraphs](command.ipynb) -- [How to add runtime configuration to your graph](configuration.ipynb) -- [How to add node retries](node-retries.ipynb) -- [How to return state before hitting recursion limit](return-when-recursion-limit-hits.ipynb) - -### Persistence - -[LangGraph Persistence](../concepts/persistence.md) makes it easy to persist state across graph runs (per-thread persistence) and across threads (cross-thread persistence). These how-to guides show how to add persistence to your graph. - -- [How to add thread-level persistence to your graph](persistence.ipynb) -- [How to add thread-level persistence to a subgraph](subgraph-persistence.ipynb) -- [How to add cross-thread persistence to your graph](cross-thread-persistence.ipynb) -- [How to use Postgres checkpointer for persistence](persistence_postgres.ipynb) -- [How to use MongoDB checkpointer for persistence](persistence_mongodb.ipynb) -- [How to create a custom checkpointer using Redis](persistence_redis.ipynb) - -See the below guides for how-to add persistence to your workflow using the [Functional API](../concepts/functional_api.md): - -- [How to add thread-level persistence (functional API)](persistence-functional.ipynb) -- [How to add cross-thread persistence (functional API)](cross-thread-persistence-functional.ipynb) - -### Memory - -LangGraph makes it easy to manage conversation [memory](../concepts/memory.md) in your graph. These how-to guides show how to implement different strategies for that. - -- [How to manage conversation history](memory/manage-conversation-history.ipynb) -- [How to delete messages](memory/delete-messages.ipynb) -- [How to add summary conversation memory](memory/add-summary-conversation-history.ipynb) -- [How to add long-term memory (cross-thread)](cross-thread-persistence.ipynb) -- [How to use semantic search for long-term memory](memory/semantic-search.ipynb) - -### Human-in-the-loop - -[Human-in-the-loop](../concepts/human_in_the_loop.md) functionality allows -you to involve humans in the decision-making process of your graph. These how-to guides show how to implement human-in-the-loop workflows in your graph. - -Key workflows: - -- [How to wait for user input](human_in_the_loop/wait-user-input.ipynb): A basic example that shows how to implement a human-in-the-loop workflow in your graph using the `interrupt` function. -- [How to review tool calls](human_in_the_loop/review-tool-calls.ipynb): Incorporate human-in-the-loop for reviewing/editing/accepting tool call requests before they executed using the `interrupt` function. - -Other methods: - -- [How to add static breakpoints](human_in_the_loop/breakpoints.ipynb): Use for debugging purposes. For [**human-in-the-loop**](../concepts/human_in_the_loop.md) workflows, we recommend the [`interrupt` function][langgraph.types.interrupt] instead. -- [How to edit graph state](human_in_the_loop/edit-graph-state.ipynb): Edit graph state using `graph.update_state` method. Use this if implementing a **human-in-the-loop** workflow via **static breakpoints**. -- [How to add dynamic breakpoints with `NodeInterrupt`](human_in_the_loop/dynamic_breakpoints.ipynb): **Not recommended**: Use the [`interrupt` function](../concepts/human_in_the_loop.md) instead. - -See the below guides for how-to implement human-in-the-loop workflows with the -[Functional API](../concepts/functional_api.md): - -- [How to wait for user input (Functional API)](wait-user-input-functional.ipynb) -- [How to review tool calls (Functional API)](review-tool-calls-functional.ipynb) - -### Time Travel - -[Time travel](../concepts/time-travel.md) allows you to replay past actions in your LangGraph application to explore alternative paths and debug issues. These how-to guides show how to use time travel in your graph. - -- [How to view and update past graph state](human_in_the_loop/time-travel.ipynb) - -### Streaming - -[Streaming](../concepts/streaming.md) is crucial for enhancing the responsiveness of applications built on LLMs. By displaying output progressively, even before a complete response is ready, streaming significantly improves user experience (UX), particularly when dealing with the latency of LLMs. - -- [How to stream](streaming.ipynb) -- [How to stream LLM tokens](streaming-tokens.ipynb) -- [How to stream LLM tokens from specific nodes](streaming-specific-nodes.ipynb) -- [How to stream data from within a tool](streaming-events-from-within-tools.ipynb) -- [How to stream from subgraphs](streaming-subgraphs.ipynb) -- [How to disable streaming for models that don't support it](disable-streaming.ipynb) - -### Tool calling - -[Tool calling](https://python.langchain.com/docs/concepts/tool_calling/) is a type of -[chat model](https://python.langchain.com/docs/concepts/chat_models/) API that accepts -tool schemas, along with messages, as input and returns invocations of those tools as -part of the output message. - -These how-to guides show common patterns for tool calling with LangGraph: - -- [How to call tools using ToolNode](tool-calling.ipynb) -- [How to handle tool calling errors](tool-calling-errors.ipynb) -- [How to pass runtime values to tools](pass-run-time-values-to-tools.ipynb) -- [How to pass config to tools](pass-config-to-tools.ipynb) -- [How to update graph state from tools](update-state-from-tools.ipynb) -- [How to handle large numbers of tools](many-tools.ipynb) - -### Subgraphs - -[Subgraphs](../concepts/low_level.md#subgraphs) allow you to reuse an existing graph from another graph. These how-to guides show how to use subgraphs: - -- [How to use subgraphs](subgraph.ipynb) -- [How to view and update state in subgraphs](subgraphs-manage-state.ipynb) -- [How to transform inputs and outputs of a subgraph](subgraph-transform-state.ipynb) - -### Multi-agent - -[Multi-agent systems](../concepts/multi_agent.md) are useful to break down complex LLM applications into multiple agents, each responsible for a different part of the application. These how-to guides show how to implement multi-agent systems in LangGraph: - -- [How to implement handoffs between agents](agent-handoffs.ipynb) -- [How to build a multi-agent network](multi-agent-network.ipynb) -- [How to add multi-turn conversation in a multi-agent application](multi-agent-multi-turn-convo.ipynb) - -See the [multi-agent tutorials](../tutorials/index.md#multi-agent-systems) for implementations of other multi-agent architectures. - -See the below guides for how to implement multi-agent workflows with the [Functional API](../concepts/functional_api.md): - -- [How to build a multi-agent network (functional API)](multi-agent-network-functional.ipynb) -- [How to add multi-turn conversation in a multi-agent application (functional API)](multi-agent-multi-turn-convo-functional.ipynb) - -### State Management - -- [How to use Pydantic model as graph state](state-model.ipynb) -- [How to define input/output schema for your graph](input_output_schema.ipynb) -- [How to pass private state between nodes inside the graph](pass_private_state.ipynb) - -### Other - -- [How to run graph asynchronously](async.ipynb) -- [How to force tool-calling agent to structure output](react-agent-structured-output.ipynb) -- [How to pass custom LangSmith run ID for graph runs](run-id-langsmith.ipynb) -- [How to integrate LangGraph with AutoGen, CrewAI, and other frameworks](autogen-integration.ipynb) - -See the below guide for how to integrate with other frameworks using the [Functional API](../concepts/functional_api.md): - -- [How to integrate LangGraph (functional API) with AutoGen, CrewAI, and other frameworks](autogen-integration-functional.ipynb) - -### Prebuilt Agent - -LangGraph comes with a [prebuilt][langgraph.prebuilt.chat_agent_executor.create_react_agent] implementation of a [tool calling agent](../concepts/agentic_concepts.md#tool-calling-agent). See [Agents](../agents/overview.md) guides for more information. - -!!! tip - - One of the big benefits of LangGraph is that you can easily create your own agent architectures. So while it's fine to start here to build an agent quickly, we would strongly recommend learning how to build your own agent so that you can take full advantage of LangGraph. - -Interested in further customizing the ReAct agent? This guide provides an -overview of its underlying implementation to help you customize for your own needs: - -- [How to create prebuilt ReAct agent from scratch](react-agent-from-scratch.ipynb) - -See the below guide for how-to build ReAct agents with the [Functional API](../concepts/functional_api.md): - -- [How to create a ReAct agent from scratch (Functional API)](react-agent-from-scratch-functional.ipynb) - -## LangGraph Platform - -This section includes how-to guides for LangGraph Platform. - -LangGraph Platform is a commercial solution for deploying agentic applications in production, built on the open-source LangGraph framework. - -The LangGraph Platform offers a few different deployment options described in the [deployment options guide](../concepts/deployment_options.md). - -!!! tip - - * LangGraph is an MIT-licensed open-source library, which we are committed to maintaining and growing for the community. - * You can always deploy LangGraph applications on your own infrastructure using the open-source LangGraph project without using LangGraph Platform. - -### Application Structure - -Learn how to set up your app for deployment to LangGraph Platform: - -- [How to set up app for deployment (requirements.txt)](../cloud/deployment/setup.md) -- [How to set up app for deployment (pyproject.toml)](../cloud/deployment/setup_pyproject.md) -- [How to set up app for deployment (JavaScript)](../cloud/deployment/setup_javascript.md) -- [How to add semantic search](../cloud/deployment/semantic_search.md) -- [How to customize Dockerfile](../cloud/deployment/custom_docker.md) -- [How to test locally](../cloud/deployment/test_locally.md) -- [How to rebuild graph at runtime](../cloud/deployment/graph_rebuild.md) -- [How to use LangGraph Platform to deploy CrewAI, AutoGen, and other frameworks](autogen-langgraph-platform.ipynb) - -### Deployment - -LangGraph applications can be deployed using LangGraph Platform, which provides a range of services to help you deploy, manage, and scale your applications. - -- [How to deploy to Cloud SaaS](../cloud/deployment/cloud.md) -- [How to deploy the Self-Hosted Data Plane](../cloud/deployment/self_hosted_data_plane.md) -- [How to deploy the Self-Hosted Control Plane](../cloud/deployment/self_hosted_control_plane.md) -- [How to deploy a Standalone Container](../cloud/deployment/standalone_container.md) -- [How to interact with the deployment using RemoteGraph](./use-remote-graph.md) -- [How to add TTLs to your LangGraph application](./ttl/configure_ttl.md) - -### Authentication & Access Control - -- [How to add custom authentication](./auth/custom_auth.md) -- [How to update the security schema of your OpenAPI spec](./auth/openapi_security.md) - -### Modifying the API - -- [How to add custom routes](./http/custom_routes.md) -- [How to add custom middleware](./http/custom_middleware.md) -- [How to add custom lifespan events](./http/custom_lifespan.md) - -### Assistants - -[Assistants](../concepts/assistants.md) is a configured instance of a template. - -See [SDK Reference](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.client.AssistantsClient) -for supported endpoints and other details. - -- [How to configure agents](../cloud/how-tos/configuration_cloud.md) -- [How to version assistants](../cloud/how-tos/assistant_versioning.md) - -### Threads - -See [SDK Reference](../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.client.ThreadsClient) -for supported endpoints and other details. - -- [How to copy threads](../cloud/how-tos/copy_threads.md) -- [How to check status of your threads](../cloud/how-tos/check_thread_status.md) - -### Runs - -LangGraph Platform supports multiple types of runs besides streaming runs. - -- [How to run an agent in the background](../cloud/how-tos/background_run.md) -- [How to run multiple agents in the same thread](../cloud/how-tos/same-thread.md) -- [How to create cron jobs](../cloud/how-tos/cron_jobs.md) -- [How to create stateless runs](../cloud/how-tos/stateless_runs.md) -- [How to use headers as runtime configuration](../cloud/how-tos/configurable_headers.md) - -### Streaming {#streaming_1} - -Streaming the results of your LLM application is vital for ensuring a good user experience, especially when your graph may call multiple models and take a long time to fully complete a run. Read about how to stream values from your graph in these how to guides: - -- [How to stream values](../cloud/how-tos/stream_values.md) -- [How to stream updates](../cloud/how-tos/stream_updates.md) -- [How to stream messages](../cloud/how-tos/stream_messages.md) -- [How to stream events](../cloud/how-tos/stream_events.md) -- [How to stream in debug mode](../cloud/how-tos/stream_debug.md) -- [How to stream multiple modes](../cloud/how-tos/stream_multiple.md) - -### Frontend and Generative UI - -With LangGraph Platform you can integrate LangGraph agents into your React applications and colocate UI components with your agent code. - -- [How to integrate LangGraph into your React application](../cloud/how-tos/use_stream_react.md) -- [How to implement Generative User Interfaces with LangGraph](../cloud/how-tos/generative_ui_react.md) - -### Human-in-the-loop {#human-in-the-loop-1} - -[Human-in-the-loop](../concepts/human_in_the_loop.md) functionality allows -you to involve humans in the decision-making process of your graph. These how-to guides show how to implement human-in-the-loop workflows in your graph. - -- [How to wait for user input](../cloud/how-tos/human_in_the_loop_user_input.md) -- [How to review tool calls](../cloud/how-tos/human_in_the_loop_review_tool_calls.md) -- [How to add static breakpoints](../cloud/how-tos/human_in_the_loop_breakpoint.md) - -### Time Travel - -[Time travel](../concepts/time-travel.md) allows you to replay past actions in your LangGraph application to explore alternative paths and debug issues. These how-to guides show how to use time travel in your graph. - -- [How to edit graph state](../cloud/how-tos/human_in_the_loop_edit_state.md) -- [How to replay and branch from prior states](../cloud/how-tos/human_in_the_loop_time_travel.md) - -### Double-texting - -Graph execution can take a while, and sometimes users may change their mind about the input they wanted to send before their original input has finished running. For example, a user might notice a typo in their original request and will edit the prompt and resend it. Deciding what to do in these cases is important for ensuring a smooth user experience and preventing your graphs from behaving in unexpected ways. - -- [How to use the interrupt option](../cloud/how-tos/interrupt_concurrent.md) -- [How to use the rollback option](../cloud/how-tos/rollback_concurrent.md) -- [How to use the reject option](../cloud/how-tos/reject_concurrent.md) -- [How to use the enqueue option](../cloud/how-tos/enqueue_concurrent.md) - -### Webhooks - -- [How to integrate webhooks](../cloud/how-tos/webhooks.md) - -### Cron Jobs - -- [How to create cron jobs](../cloud/how-tos/cron_jobs.md) - -### LangGraph Studio - -LangGraph Studio is a built-in UI for visualizing, testing, and debugging your agents. - -- [How to connect to a LangGraph Platform deployment](../cloud/how-tos/test_deployment.md) -- [How to connect to a local dev server](../how-tos/local-studio.md) -- [How to connect to a local deployment (Docker)](../cloud/how-tos/test_local_deployment.md) -- [How to interact with threads in LangGraph Studio](../cloud/how-tos/threads_studio.md) -- [How to add nodes as dataset examples in LangGraph Studio](../cloud/how-tos/datasets_studio.md) -- [How to engineer prompts in LangGraph Studio](../cloud/how-tos/iterate_graph_studio.md) -- [How to test your agent against remote traces](../cloud/how-tos/clone_traces_studio.md) - -## Troubleshooting - -These are the guides for resolving common errors you may find while building with LangGraph. Errors referenced below will have an `lc_error_code` property corresponding to one of the below codes when they are thrown in code. - -- [GRAPH_RECURSION_LIMIT](../troubleshooting/errors/GRAPH_RECURSION_LIMIT.md) -- [INVALID_CONCURRENT_GRAPH_UPDATE](../troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md) -- [INVALID_GRAPH_NODE_RETURN_VALUE](../troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md) -- [MULTIPLE_SUBGRAPHS](../troubleshooting/errors/MULTIPLE_SUBGRAPHS.md) -- [INVALID_CHAT_HISTORY](../troubleshooting/errors/INVALID_CHAT_HISTORY.md) - -### LangGraph Platform Troubleshooting - -These guides provide troubleshooting information for errors that are specific to the LangGraph Platform. - -- [INVALID_LICENSE](../troubleshooting/errors/INVALID_LICENSE.md) diff --git a/docs/docs/how-tos/input_output_schema.ipynb b/docs/docs/how-tos/input_output_schema.ipynb deleted file mode 100644 index be19bee1d..000000000 --- a/docs/docs/how-tos/input_output_schema.ipynb +++ /dev/null @@ -1,153 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "f262985e-e973-4a27-9c9e-dbb3a06a35b7", - "metadata": {}, - "source": [ - "# How to define input/output schema for your graph\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "By default, `StateGraph` operates with a single schema, and all nodes are expected to communicate using that schema. However, it's also possible to define distinct input and output schemas for a graph.\n", - "\n", - "When distinct schemas are specified, an internal schema will still be used for communication between nodes. The input schema ensures that the provided input matches the expected structure, while the output schema filters the internal data to return only the relevant information according to the defined output schema.\n", - "\n", - "In this example, we'll see how to define distinct input and output schema.\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "678286f2", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "16aad512", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "72689b3d", - "metadata": {}, - "source": [ - "## Define and use the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "6ec0eb77-874e-443e-8c73-93125b515106", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'answer': 'bye'}\n" - ] - } - ], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from typing_extensions import TypedDict\n", - "\n", - "\n", - "# Define the schema for the input\n", - "class InputState(TypedDict):\n", - " question: str\n", - "\n", - "\n", - "# Define the schema for the output\n", - "class OutputState(TypedDict):\n", - " answer: str\n", - "\n", - "\n", - "# Define the overall schema, combining both input and output\n", - "class OverallState(InputState, OutputState):\n", - " pass\n", - "\n", - "\n", - "# Define the node that processes the input and generates an answer\n", - "def answer_node(state: InputState):\n", - " # Example answer and an extra key\n", - " return {\"answer\": \"bye\", \"question\": state[\"question\"]}\n", - "\n", - "\n", - "# Build the graph with input and output schemas specified\n", - "builder = StateGraph(OverallState, input=InputState, output=OutputState)\n", - "builder.add_node(answer_node) # Add the answer node\n", - "builder.add_edge(START, \"answer_node\") # Define the starting edge\n", - "builder.add_edge(\"answer_node\", END) # Define the ending edge\n", - "graph = builder.compile() # Compile the graph\n", - "\n", - "# Invoke the graph with an input and print the result\n", - "print(graph.invoke({\"question\": \"hi\"}))" - ] - }, - { - "cell_type": "markdown", - "id": "6a68836f-98e1-4684-a8a6-c1473c73460c", - "metadata": {}, - "source": [ - "Notice that the output of invoke only includes the output schema." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/local-studio.md b/docs/docs/how-tos/local-studio.md deleted file mode 100644 index 2f83f4c23..000000000 --- a/docs/docs/how-tos/local-studio.md +++ /dev/null @@ -1,82 +0,0 @@ -# How to connect a local agent to LangGraph Studio - -This guide shows you how to connect your local agent to [LangGraph Studio](../concepts/langgraph_studio.md) for visualization, interaction, and debugging using the development server. - -## Setup your application - -First, you will need to setup your application in the proper format. -This means defining a `langgraph.json` file which contains paths to your agent(s). -See [this guide](../concepts/application_structure.md) for information on how to do so. - -## Install langgraph-cli - -You will need to install [`langgraph-cli`](../cloud/reference/cli.md#langgraph-cli) (version `0.1.55` or higher). -You will need to make sure to install the `inmem` extras. - -???+ note "Minimum version" - -The minimum version to use the `inmem` extra with `langgraph-cli` is `0.1.55`. -Python 3.11 or higher is required. - -```shell -pip install -U "langgraph-cli[inmem]" -``` - -## Run the development server - -1. Navigate to your project directory (where `langgraph.json` is located) - -2. Start the server: - ```bash - langgraph dev - ``` - -This will look for the `langgraph.json` file in your current directory. -In there, it will find the paths to the graph(s), and start those up. -It will then automatically connect to the cloud-hosted studio. - -## Use the studio - -After connecting to the studio, a browser window should automatically pop up. -This will use the cloud hosted studio UI to connect to your local development server. -Your graph is still running locally, the UI is connecting to visualizing the agent and threads that are defined locally. - -The graph will always use the most up-to-date code, so you will be able to change the underlying code and have it automatically reflected in the studio. -This is useful for debugging workflows. -You can run your graph in the UI until it messes up, go in and change your code, and then rerun from the node that failed. - -# (Optional) Attach a debugger - -For step-by-step debugging with breakpoints and variable inspection: - -```bash -# Install debugpy package -pip install debugpy - -# Start server with debugging enabled -langgraph dev --debug-port 5678 -``` - -Then attach your preferred debugger: - -=== "VS Code" - Add this configuration to `launch.json`: - ```json - { - "name": "Attach to LangGraph", - "type": "debugpy", - "request": "attach", - "connect": { - "host": "0.0.0.0", - "port": 5678 - } - } - ``` - Specify the port number you chose in the previous step. - -=== "PyCharm" - 1. Go to Run → Edit Configurations - 2. Click + and select "Python Debug Server" - 3. Set IDE host name: `localhost` - 4. Set port: `5678` (or the port number you chose in the previous step) - 5. Click "OK" and start debugging diff --git a/docs/docs/how-tos/map-reduce.ipynb b/docs/docs/how-tos/map-reduce.ipynb deleted file mode 100644 index c059f9b9c..000000000 --- a/docs/docs/how-tos/map-reduce.ipynb +++ /dev/null @@ -1,317 +0,0 @@ -{ - "cells": [ - { - "attachments": { - "a108ffc8-6136-4cd7-a6f9-579e41a5a786.png": { - "image/png": "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gAACCCCAgBEgiIAbAQEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSMAEEE3AgIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggYAQIIuBGQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEjQBABNwICCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIGAGCCLgREEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQMAIEETAjYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACRoAgAm4EBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEDACBBFwIyCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICAESCIgBsBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBIwAQQTcCAgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBgBAgi4EZAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAASNAEAE3AgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggYAYIIuBEQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwAgQRMCNgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJGgCACbgQEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQMAIEEXAjIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIARIIiAGwEBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEjABBBNwICCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIGAECCLgRkAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABI0AQATcCAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCBgBggi4ERBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDACBBEwI2AAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAkaAIAJuBAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAwAgQRcCMggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgBEgiIAbAQEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSMAEEE3AgIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggYAQIIuBGQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEjQBABNwICCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIGAGCCLgREEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQMAIEETAjYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACRoAgAm4EBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEDACBBFwIyCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICAESCIgBsBAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBIwAQQTcCAgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBgBAgi4EZAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAASNAEAE3AgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggYAYIIuBEQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwAgQRMCNgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJGgCACbgQEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQMAIEEXAjIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIARIIiAGwEBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEjABBBNwICCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIGAECCLgRkAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABI0AQATcCAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCBgBggi4ERBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDACBBEwI2AAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAkaAIAJuBAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAwAgQRcCMggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgBEgiIAbAQEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSMAEEE3AgIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggYAQIIuBGQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEjQBABNwICCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIGAGCCLgREEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQMAIEETAjYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACRoAgAm4EBBBAAAEEEEAAgTYXSP/qC9k29xqpKipq87Y7U4NVhYVSumtnZ+oSfUEAAQQQQAABBBBAAAEEEEAAAQQQQAABBA5LgCCCw+LjYAQQQAABBBBAAIHGBPJ/XyKl8ZslZ/Evje3uNttS331btl01W4p37Og218SFIIAAAggggAACCCCAAAIIIIAAAggggEDPFiCIoGd//lw9AggggAACCCDQPgI11abdqry89mn/MFot2LBBtt/yNylJbIOBfzd305OizRsPo0ccigACCCCAAAIIIIAAAggggAACCCCAAAIIdB4B187TFXqCAAIIIIAAAggg0G0EquuCCAqWLhEnVzcpT90n1bm54myxiGXgIIn48zkddql5v/8qxevXyM67bpfBr7whrn5+re6LW0CgObY8aU+r2+BABBBAAAEEEEAAAQQQQAABBBBAAAEEEECgMwkQRNCZPg36ggAC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BBBAAAEEEEAAAQQQQAABBBBAAAEEEOhrAgQR9LUnzngRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIIRAeop5qBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAgQR9LEHznARQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAIJUAQQSgZ6hFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEOhjAv8PZqu/RV/yWTYAAAAASUVORK5CYII=" - } - }, - "cell_type": "markdown", - "id": "95a87145-34d0-4f97-b45f-5c9fd8532c8a", - "metadata": {}, - "source": [ - "# How to create map-reduce branches for parallel execution\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "\n", - "[Map-reduce](https://en.wikipedia.org/wiki/MapReduce) operations are essential for efficient task decomposition and parallel processing. This approach involves breaking a task into smaller sub-tasks, processing each sub-task in parallel, and aggregating the results across all of the completed sub-tasks. \n", - "\n", - "Consider this example: given a general topic from the user, generate a list of related subjects, generate a joke for each subject, and select the best joke from the resulting list. In this design pattern, a first node may generate a list of objects (e.g., related subjects) and we want to apply some other node (e.g., generate a joke) to all those objects (e.g., subjects). However, two main challenges arise.\n", - " \n", - "(1) the number of objects (e.g., subjects) may be unknown ahead of time (meaning the number of edges may not be known) when we lay out the graph and (2) the input State to the downstream Node should be different (one for each generated object).\n", - " \n", - "LangGraph addresses these challenges [through its `Send` API](https://langchain-ai.github.io/langgraph/concepts/low_level/#send). By utilizing conditional edges, `Send` can distribute different states (e.g., subjects) to multiple instances of a node (e.g., joke generation). Importantly, the sent state can differ from the core graph's state, allowing for flexible and dynamic workflow management. \n", - "\n", - "![Screenshot 2024-07-12 at 9.45.40 AM.png](attachment:a108ffc8-6136-4cd7-a6f9-579e41a5a786.png)" - ] - }, - { - "cell_type": "markdown", - "id": "66c58b5f", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "3eb04cd1", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langchain-anthropic langgraph" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "dc292321", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import getpass\n", - "\n", - "\n", - "def _set_env(name: str):\n", - " if not os.getenv(name):\n", - " os.environ[name] = getpass.getpass(f\"{name}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "b87911bb", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "b4e782a0", - "metadata": {}, - "source": [ - "## Define the graph" - ] - }, - { - "cell_type": "markdown", - "id": "66803b55", - "metadata": {}, - "source": [ - "
\n", - "

Using Pydantic with LangChain

\n", - "

\n", - " This notebook uses Pydantic v2 BaseModel, which requires langchain-core >= 0.3. Using langchain-core < 0.3 will result in errors due to mixing of Pydantic v1 and v2 BaseModels.\n", - "

\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "0f0f78e4-423d-4e2d-aa1a-01efaec4715f", - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing import Annotated\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "\n", - "from langgraph.types import Send\n", - "from langgraph.graph import END, StateGraph, START\n", - "\n", - "from pydantic import BaseModel, Field\n", - "\n", - "# Model and prompts\n", - "# Define model and prompts we will use\n", - "subjects_prompt = \"\"\"Generate a comma separated list of between 2 and 5 examples related to: {topic}.\"\"\"\n", - "joke_prompt = \"\"\"Generate a joke about {subject}\"\"\"\n", - "best_joke_prompt = \"\"\"Below are a bunch of jokes about {topic}. Select the best one! Return the ID of the best one.\n", - "\n", - "{jokes}\"\"\"\n", - "\n", - "\n", - "class Subjects(BaseModel):\n", - " subjects: list[str]\n", - "\n", - "\n", - "class Joke(BaseModel):\n", - " joke: str\n", - "\n", - "\n", - "class BestJoke(BaseModel):\n", - " id: int = Field(description=\"Index of the best joke, starting with 0\", ge=0)\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n", - "\n", - "# Graph components: define the components that will make up the graph\n", - "\n", - "\n", - "# This will be the overall state of the main graph.\n", - "# It will contain a topic (which we expect the user to provide)\n", - "# and then will generate a list of subjects, and then a joke for\n", - "# each subject\n", - "class OverallState(TypedDict):\n", - " topic: str\n", - " subjects: list\n", - " # Notice here we use the operator.add\n", - " # This is because we want combine all the jokes we generate\n", - " # from individual nodes back into one list - this is essentially\n", - " # the \"reduce\" part\n", - " jokes: Annotated[list, operator.add]\n", - " best_selected_joke: str\n", - "\n", - "\n", - "# This will be the state of the node that we will \"map\" all\n", - "# subjects to in order to generate a joke\n", - "class JokeState(TypedDict):\n", - " subject: str\n", - "\n", - "\n", - "# This is the function we will use to generate the subjects of the jokes\n", - "def generate_topics(state: OverallState):\n", - " prompt = subjects_prompt.format(topic=state[\"topic\"])\n", - " response = model.with_structured_output(Subjects).invoke(prompt)\n", - " return {\"subjects\": response.subjects}\n", - "\n", - "\n", - "# Here we generate a joke, given a subject\n", - "def generate_joke(state: JokeState):\n", - " prompt = joke_prompt.format(subject=state[\"subject\"])\n", - " response = model.with_structured_output(Joke).invoke(prompt)\n", - " return {\"jokes\": [response.joke]}\n", - "\n", - "\n", - "# Here we define the logic to map out over the generated subjects\n", - "# We will use this as an edge in the graph\n", - "def continue_to_jokes(state: OverallState):\n", - " # We will return a list of `Send` objects\n", - " # Each `Send` object consists of the name of a node in the graph\n", - " # as well as the state to send to that node\n", - " return [Send(\"generate_joke\", {\"subject\": s}) for s in state[\"subjects\"]]\n", - "\n", - "\n", - "# Here we will judge the best joke\n", - "def best_joke(state: OverallState):\n", - " jokes = \"\\n\\n\".join(state[\"jokes\"])\n", - " prompt = best_joke_prompt.format(topic=state[\"topic\"], jokes=jokes)\n", - " response = model.with_structured_output(BestJoke).invoke(prompt)\n", - " return {\"best_selected_joke\": state[\"jokes\"][response.id]}\n", - "\n", - "\n", - "# Construct the graph: here we put everything together to construct our graph\n", - "graph = StateGraph(OverallState)\n", - "graph.add_node(\"generate_topics\", generate_topics)\n", - "graph.add_node(\"generate_joke\", generate_joke)\n", - "graph.add_node(\"best_joke\", best_joke)\n", - "graph.add_edge(START, \"generate_topics\")\n", - "graph.add_conditional_edges(\"generate_topics\", continue_to_jokes, [\"generate_joke\"])\n", - "graph.add_edge(\"generate_joke\", \"best_joke\")\n", - "graph.add_edge(\"best_joke\", END)\n", - "app = graph.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "37ed1f71-63db-416f-b715-4617b33d4b7f", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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qjvOGqfWsc26VbZ+WewMe8zCXlHEta1p1cRoAFc49j1txOx0Nns9FFb7XRRNgp6WBujI2DoA9vWrRExI2Cx9lvxIof7Wo/fyLIWPst+JFD/a1H7+RWveYnvj0tJ6FWiIvNQ1eVfFi8fU5v2Cp7Gvi5avqkX7AVjUQR1UEkMrd+KRpY5p6wRoQoOGlv8AjNPDbm2Sa+U9OxsUNZR1ELXPYBo3lGyvZo/QcdCQenhruj0NHmJsTYrSa13zT1WjfFG9RaTna/epl17VRe/Tna/epl17VRe/XfU7UeKPco3aLSc7X71MuvaqL36c7X71MuvaqL36anajxR7lG7RaTna/epl17VRe/Tna/epl17VRe/TU7UeKPco3aLSc7X71MuvaqL36c7X71MuvaqL36anajxR7lG7RTFmyy7X60UVzo8NvJpKyFlRCZpKWJ5Y5oc3eY+YOadD8FwBHQQFmc7X71MuvaqL36anajxR7lG7RaTna/epl17VRe/Tna/epl17VRe/TU7UeKPco3aLSc7X71MuvaqL36c7X71MuvaqL36anajxR7lG7RaTna/epl17VRe/Tna/epl17VRe/TU7UeKPco3ax9lvxIof7Wo/fyLXNq8krTyUGMT0EjuAqLhVQGJn+8RFI9ztPMANejUdIq8es0ePWWjt0T3Stp2bpkf8ACe7pc4/OSSfzrjfzFm61KxWZid0xPCuHecIbFERecqIiICIiAiIgIiICIiCf2fTiqwTHZhPcaoSW+nfy94j5Otk1jad6dug3ZD0uGg0OqoFObN6gVez3GZ21dfcGyW2neKu6s3KubWNp35m9Uh6XDqJKo0BERAREQEREBERAREQEREBERAREQEREBERBObN6xlx2e4zVR19ZdI57bTyNrrjHydTUAxtIklb/AFXu6SOokqjU7s6recsAxur79rLly9up5e/LhCIaifWNp35WDQNeekt6iSFRICIiAiIgIiICIiAiIgIiICKan2l4lTSujlya0Me0kFprY9QegjpX5+NLDvWm0dtj9q0bPfT/AKTlKaTgqUUt40sO9abR22P2p40sO9abR22P2ps991JylOrOCpRS3jSw71ptHbY/anjSw71ptHbY/amz33UnKTVnBUrVZHldkw+ijrL9eLfZKSSQQsqLjVMp43PIJDA55ALtGuOnToD5lq/Glh3rTaO2x+1c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", - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "\n", - "Image(app.get_graph().draw_mermaid_png())" - ] - }, - { - "cell_type": "markdown", - "id": "4a0026d8", - "metadata": {}, - "source": [ - "## Use the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "fd90cace", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'generate_topics': {'subjects': ['Lions', 'Elephants', 'Penguins', 'Dolphins']}}\n", - "{'generate_joke': {'jokes': [\"Why don't elephants use computers? They're afraid of the mouse!\"]}}\n", - "{'generate_joke': {'jokes': [\"Why don't dolphins use smartphones? Because they're afraid of phishing!\"]}}\n", - "{'generate_joke': {'jokes': [\"Why don't you see penguins in Britain? Because they're afraid of Wales!\"]}}\n", - "{'generate_joke': {'jokes': [\"Why don't lions like fast food? Because they can't catch it!\"]}}\n", - "{'best_joke': {'best_selected_joke': \"Why don't dolphins use smartphones? Because they're afraid of phishing!\"}}\n" - ] - } - ], - "source": [ - "# Call the graph: here we call it to generate a list of jokes\n", - "for s in app.stream({\"topic\": \"animals\"}):\n", - " print(s)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/memory.ipynb b/docs/docs/how-tos/memory.ipynb new file mode 100644 index 000000000..5b4a29ec0 --- /dev/null +++ b/docs/docs/how-tos/memory.ipynb @@ -0,0 +1,447 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "15ed7413-c876-4d38-b080-79c71133549b", + "metadata": {}, + "source": [ + "# Manage memory\n", + "\n", + "Many AI applications need memory to share context across multiple interactions. LangGraph supports two types of memory essential for building conversational agents:\n", + "\n", + "- [Short-term memory](#add-short-term-memory): Tracks the ongoing conversation by maintaining message history within a session.\n", + "- [Long-term memory](#add-long-term-memory): Stores user-specific or application-level data across sessions.\n", + "\n", + "With [short-term memory](#add-short-term-memory) enabled, long conversations can exceed the LLM's context window. Common solutions are:\n", + "\n", + "* [Trimming](#trim-messages): Remove first or last N messages (before calling LLM)\n", + "* [Summarization](#summarize-messages): Summarize earlier messages in the history and replace them with a summary\n", + "* [Delete messages](#delete-messages) from LangGraph state permanently\n", + "* custom strategies (e.g., message filtering, etc.)\n", + "\n", + "This allows the agent to keep track of the conversation without exceeding the LLM's context window." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", + "metadata": {}, + "outputs": [], + "source": [ + "# hide-cell\n", + "%%capture --no-stderr\n", + "%pip install --quiet -U langgraph \"langchain[anthropic]\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", + "metadata": {}, + "outputs": [], + "source": [ + "# hide-cell\n", + "import getpass\n", + "import os\n", + "\n", + "\n", + "def _set_env(var: str):\n", + " if not os.environ.get(var):\n", + " os.environ[var] = getpass.getpass(f\"{var}: \")\n", + "\n", + "\n", + "_set_env(\"ANTHROPIC_API_KEY\")" + ] + }, + { + "cell_type": "markdown", + "id": "db38b03c-5609-49e3-9b93-bad0aab47ffb", + "metadata": {}, + "source": [ + "## Add short-term memory\n", + "\n", + "Short-term memory enables agents to track multi-turn conversations:\n", + "\n", + "```python\n", + "# highlight-next-line\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "from langgraph.graph import StateGraph\n", + "\n", + "# highlight-next-line\n", + "checkpointer = InMemorySaver()\n", + "\n", + "builder = StateGraph(...)\n", + "# highlight-next-line\n", + "graph = builder.compile(checkpointer=checkpointer)\n", + "\n", + "graph.invoke(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! i am Bob\"}]},\n", + " # highlight-next-line\n", + " {\"configurable\": {\"thread_id\": \"1\"}},\n", + ")\n", + "```\n", + "\n", + "See the [persistence](../persistence#add-short-term-memory) guide to learn more about working with short-term memory." + ] + }, + { + "cell_type": "markdown", + "id": "05bf55fd-b0b0-4fbf-9f15-aefac7f300bb", + "metadata": {}, + "source": [ + "## Add long-term memory\n", + "\n", + "Use long-term memory to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information.\n", + "\n", + "```python\n", + "# highlight-next-line\n", + "from langgraph.store.memory import InMemoryStore\n", + "from langgraph.graph import StateGraph\n", + "\n", + "# highlight-next-line\n", + "store = InMemoryStore()\n", + "\n", + "builder = StateGraph(...)\n", + "# highlight-next-line\n", + "graph = builder.compile(store=store)\n", + "```\n", + "\n", + "See the [persistence](../persistence#add-long-term-memory) guide to learn more about working with long-term memory." + ] + }, + { + "cell_type": "markdown", + "id": "e109c1b2-a44e-4ec0-8a11-1377e59315c6", + "metadata": {}, + "source": [ + "## Trim messages\n", + "\n", + "To trim message history, you can use [`trim_messages`](https://python.langchain.com/api_reference/core/messages/langchain_core.messages.utils.trim_messages.html) function:\n", + "\n", + "```python\n", + "# highlight-next-line\n", + "from langchain_core.messages.utils import (\n", + " # highlight-next-line\n", + " trim_messages,\n", + " # highlight-next-line\n", + " count_tokens_approximately\n", + "# highlight-next-line\n", + ")\n", + "\n", + "def call_model(state: MessagesState):\n", + " # highlight-next-line\n", + " messages = trim_messages(\n", + " state[\"messages\"],\n", + " strategy=\"last\",\n", + " token_counter=count_tokens_approximately,\n", + " max_tokens=128,\n", + " start_on=\"human\",\n", + " end_on=(\"human\", \"tool\"),\n", + " )\n", + " response = model.invoke(messages)\n", + " return {\"messages\": [response]}\n", + "\n", + "builder = StateGraph(MessagesState)\n", + "builder.add_node(call_model)\n", + "...\n", + "```\n", + "\n", + "??? example \"Full example: trim messages\"\n", + "\n", + " ```python\n", + " # highlight-next-line\n", + " from langchain_core.messages.utils import (\n", + " # highlight-next-line\n", + " trim_messages,\n", + " # highlight-next-line\n", + " count_tokens_approximately\n", + " # highlight-next-line\n", + " )\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, START, MessagesState\n", + " \n", + " model = init_chat_model(\"anthropic:claude-3-7-sonnet-latest\")\n", + " summarization_model = model.bind(max_tokens=128)\n", + " \n", + " def call_model(state: MessagesState):\n", + " # highlight-next-line\n", + " messages = trim_messages(\n", + " state[\"messages\"],\n", + " strategy=\"last\",\n", + " token_counter=count_tokens_approximately,\n", + " max_tokens=128,\n", + " start_on=\"human\",\n", + " end_on=(\"human\", \"tool\"),\n", + " )\n", + " response = model.invoke(messages)\n", + " return {\"messages\": [response]}\n", + " \n", + " checkpointer = InMemorySaver()\n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + " graph.invoke({\"messages\": \"hi, my name is bob\"}, config)\n", + " graph.invoke({\"messages\": \"write a short poem about cats\"}, config)\n", + " graph.invoke({\"messages\": \"now do the same but for dogs\"}, config)\n", + " final_response = graph.invoke({\"messages\": \"what's my name?\"}, config)\n", + "\n", + " final_response[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " ```\n", + " ================================== Ai Message ==================================\n", + " \n", + " Your name is Bob, as you mentioned when you first introduced yourself.\n", + " ```" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "6676cd03-3e97-4550-ad4a-72d04f2cee7c", + "metadata": {}, + "source": [ + "## Summarize messages\n", + "\n", + "An effective strategy for handling long conversation history is to summarize earlier messages once they reach a certain threshold:\n", + "\n", + "```python\n", + "from typing import Any, TypedDict\n", + "\n", + "from langchain_core.messages import AnyMessage\n", + "from langchain_core.messages.utils import count_tokens_approximately\n", + "# highlight-next-line\n", + "from langmem.short_term import SummarizationNode\n", + "from langgraph.graph import StateGraph, START, MessagesState\n", + "\n", + "class State(MessagesState):\n", + " # highlight-next-line\n", + " context: dict[str, Any] # (1)!\n", + "\n", + "class LLMInputState(TypedDict): # (2)!\n", + " summarized_messages: list[AnyMessage]\n", + " context: dict[str, Any]\n", + "\n", + "# highlight-next-line\n", + "summarization_node = SummarizationNode(\n", + " token_counter=count_tokens_approximately,\n", + " model=summarization_model,\n", + " max_tokens=512,\n", + " max_tokens_before_summary=256,\n", + " max_summary_tokens=256,\n", + ")\n", + "\n", + "# highlight-next-line\n", + "def call_model(state: LLMInputState): # (3)!\n", + " response = model.invoke(state[\"summarized_messages\"])\n", + " return {\"messages\": [response]}\n", + "\n", + "builder = StateGraph(State)\n", + "builder.add_node(call_model)\n", + "# highlight-next-line\n", + "builder.add_node(\"summarize\", summarization_node)\n", + "builder.add_edge(START, \"summarize\")\n", + "builder.add_edge(\"summarize\", \"call_model\")\n", + "...\n", + "```\n", + "\n", + "1. We will keep track of our running summary in the `context` field\n", + "(expected by the `SummarizationNode`).\n", + "2. Define private state that will be used only for filtering\n", + "the inputs to `call_model` node.\n", + "3. We're passing a private input state here to isolate the messages returned by the summarization node\n", + "\n", + "??? example \"Full example: summarize messages\"\n", + "\n", + " ```python\n", + " from typing import Any, TypedDict\n", + " \n", + " from langchain.chat_models import init_chat_model\n", + " from langchain_core.messages import AnyMessage\n", + " from langchain_core.messages.utils import count_tokens_approximately\n", + " from langgraph.graph import StateGraph, START, MessagesState\n", + " from langgraph.checkpoint.memory import InMemorySaver\n", + " # highlight-next-line\n", + " from langmem.short_term import SummarizationNode\n", + " \n", + " model = init_chat_model(\"anthropic:claude-3-7-sonnet-latest\")\n", + " summarization_model = model.bind(max_tokens=128)\n", + " \n", + " class State(MessagesState):\n", + " # highlight-next-line\n", + " context: dict[str, Any] # (1)!\n", + " \n", + " class LLMInputState(TypedDict): # (2)!\n", + " summarized_messages: list[AnyMessage]\n", + " context: dict[str, Any]\n", + " \n", + " # highlight-next-line\n", + " summarization_node = SummarizationNode(\n", + " token_counter=count_tokens_approximately,\n", + " model=summarization_model,\n", + " max_tokens=256,\n", + " max_tokens_before_summary=256,\n", + " max_summary_tokens=128,\n", + " )\n", + "\n", + " # highlight-next-line\n", + " def call_model(state: LLMInputState): # (3)!\n", + " response = model.invoke(state[\"summarized_messages\"])\n", + " return {\"messages\": [response]}\n", + " \n", + " checkpointer = InMemorySaver()\n", + " builder = StateGraph(State)\n", + " builder.add_node(call_model)\n", + " # highlight-next-line\n", + " builder.add_node(\"summarize\", summarization_node)\n", + " builder.add_edge(START, \"summarize\")\n", + " builder.add_edge(\"summarize\", \"call_model\")\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " # Invoke the graph\n", + " config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + " graph.invoke({\"messages\": \"hi, my name is bob\"}, config)\n", + " graph.invoke({\"messages\": \"write a short poem about cats\"}, config)\n", + " graph.invoke({\"messages\": \"now do the same but for dogs\"}, config)\n", + " final_response = graph.invoke({\"messages\": \"what's my name?\"}, config)\n", + "\n", + " final_response[\"messages\"][-1].pretty_print()\n", + " print(\"\\nSummary:\", final_response[\"context\"][\"running_summary\"].summary)\n", + " ```\n", + "\n", + " 1. We will keep track of our running summary in the `context` field\n", + " (expected by the `SummarizationNode`).\n", + " 2. Define private state that will be used only for filtering\n", + " the inputs to `call_model` node.\n", + " 3. We're passing a private input state here to isolate the messages returned by the summarization node\n", + "\n", + " ```\n", + " ================================== Ai Message ==================================\n", + "\n", + " From our conversation, I can see that you introduced yourself as Bob. That's the name you shared with me when we began talking.\n", + " \n", + " Summary: In this conversation, I was introduced to Bob, who then asked me to write a poem about cats. I composed a poem titled \"The Mystery of Cats\" that captured cats' graceful movements, independent nature, and their special relationship with humans. Bob then requested a similar poem about dogs, so I wrote \"The Joy of Dogs,\" which highlighted dogs' loyalty, enthusiasm, and loving companionship. Both poems were written in a similar style but emphasized the distinct characteristics that make each pet special.\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "361d880b-1258-4708-8f0e-5efc95031e78", + "metadata": {}, + "source": [ + "## Delete messages\n", + "\n", + "To delete messages from the graph state, you can use the `RemoveMessage`.\n", + "\n", + "* Remove specific messages:\n", + "\n", + " ```python\n", + " # highlight-next-line\n", + " from langchain_core.messages import RemoveMessage\n", + " \n", + " def delete_messages(state):\n", + " messages = state[\"messages\"]\n", + " if len(messages) > 2:\n", + " # remove the earliest two messages\n", + " # highlight-next-line\n", + " return {\"messages\": [RemoveMessage(id=m.id) for m in messages[:2]]}\n", + " ```\n", + "\n", + "* Remove **all** messages:\n", + " \n", + " ```python\n", + " # highlight-next-line\n", + " from langgraph.graph.message import REMOVE_ALL_MESSAGES\n", + " \n", + " def delete_messages(state):\n", + " # highlight-next-line\n", + " return {\"messages\": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]}\n", + " ```\n", + "\n", + "!!! important \"`add_messages` reducer\"\n", + "\n", + " For `RemoveMessage` to work, you need to use a state key with [`add_messages`][langgraph.graph.message.add_messages] [reducer](../../../concepts/low_level#reducers), like [`MessagesState`](../../../concepts/low_level#messagesstate)\n", + "\n", + "!!! warning \"Valid message history\"\n", + "\n", + " When deleting messages, **make sure** that the resulting message history is valid. Check the limitations of the LLM provider you're using. For example:\n", + " \n", + " * some providers expect message history to start with a `user` message\n", + " * most providers require `assistant` messages with tool calls to be followed by corresponding `tool` result messages.\n", + "\n", + "??? example \"Full example: delete messages\"\n", + "\n", + " ```python\n", + " # highlight-next-line\n", + " from langchain_core.messages import RemoveMessage\n", + " \n", + " def delete_messages(state):\n", + " messages = state[\"messages\"]\n", + " if len(messages) > 2:\n", + " # remove the earliest two messages\n", + " # highlight-next-line\n", + " return {\"messages\": [RemoveMessage(id=m.id) for m in messages[:2]]}\n", + " \n", + " def call_model(state: MessagesState):\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_sequence([call_model, delete_messages])\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " checkpointer = InMemorySaver()\n", + " app = builder.compile(checkpointer=checkpointer)\n", + " \n", + " for event in app.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " print([(message.type, message.content) for message in event[\"messages\"]])\n", + " \n", + " for event in app.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " print([(message.type, message.content) for message in event[\"messages\"]])\n", + " ```\n", + "\n", + " ```\n", + " [('human', \"hi! I'm bob\")]\n", + " [('human', \"hi! I'm bob\"), ('ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?')]\n", + " [('human', \"hi! I'm bob\"), ('ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?'), ('human', \"what's my name?\")]\n", + " [('human', \"hi! I'm bob\"), ('ai', 'Hi Bob! How are you doing today? Is there anything I can help you with?'), ('human', \"what's my name?\"), ('ai', 'Your name is Bob.')]\n", + " [('human', \"what's my name?\"), ('ai', 'Your name is Bob.')]\n", + " ```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "langgraph", + "language": "python", + "name": "langgraph" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb b/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb deleted file mode 100644 index f2f374534..000000000 --- a/docs/docs/how-tos/memory/add-summary-conversation-history.ipynb +++ /dev/null @@ -1,529 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to add summary of the conversation history\n", - "\n", - "One of the most common use cases for persistence is to use it to keep track of conversation history. This is great - it makes it easy to continue conversations. As conversations get longer and longer, however, this conversation history can build up and take up more and more of the context window. This can often be undesirable as it leads to more expensive and longer calls to the LLM, and potentially ones that error. One way to work around that is to create a summary of the conversation to date, and use that with the past N messages. This guide will go through an example of how to do that.\n", - "\n", - "This will involve a few steps:\n", - "\n", - "- Check if the conversation is too long (can be done by checking number of messages or length of messages)\n", - "- If yes, the create summary (will need a prompt for this)\n", - "- Then remove all except the last N messages\n", - "\n", - "A big part of this is deleting old messages. For an in depth guide on how to do that, see [this guide](../delete-messages)" - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's set up the packages we're going to want to use" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API keys for Anthropic (the LLM we will use)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "84835fdb-a5f3-4c90-85f3-0e6257650aba", - "metadata": {}, - "source": [ - "## Build the chatbot\n", - "\n", - "Let's now build the chatbot." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "378899a9-3b9a-4748-95b6-eb00e0828677", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.messages import SystemMessage, RemoveMessage, HumanMessage\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import MessagesState, StateGraph, START, END\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "# We will add a `summary` attribute (in addition to `messages` key,\n", - "# which MessagesState already has)\n", - "class State(MessagesState):\n", - " summary: str\n", - "\n", - "\n", - "# We will use this model for both the conversation and the summarization\n", - "model = ChatAnthropic(model_name=\"claude-3-haiku-20240307\")\n", - "\n", - "\n", - "# Define the logic to call the model\n", - "def call_model(state: State):\n", - " # If a summary exists, we add this in as a system message\n", - " summary = state.get(\"summary\", \"\")\n", - " if summary:\n", - " system_message = f\"Summary of conversation earlier: {summary}\"\n", - " messages = [SystemMessage(content=system_message)] + state[\"messages\"]\n", - " else:\n", - " messages = state[\"messages\"]\n", - " response = model.invoke(messages)\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# We now define the logic for determining whether to end or summarize the conversation\n", - "def should_continue(state: State) -> Literal[\"summarize_conversation\", END]:\n", - " \"\"\"Return the next node to execute.\"\"\"\n", - " messages = state[\"messages\"]\n", - " # If there are more than six messages, then we summarize the conversation\n", - " if len(messages) > 6:\n", - " return \"summarize_conversation\"\n", - " # Otherwise we can just end\n", - " return END\n", - "\n", - "\n", - "def summarize_conversation(state: State):\n", - " # First, we summarize the conversation\n", - " summary = state.get(\"summary\", \"\")\n", - " if summary:\n", - " # If a summary already exists, we use a different system prompt\n", - " # to summarize it than if one didn't\n", - " summary_message = (\n", - " f\"This is summary of the conversation to date: {summary}\\n\\n\"\n", - " \"Extend the summary by taking into account the new messages above:\"\n", - " )\n", - " else:\n", - " summary_message = \"Create a summary of the conversation above:\"\n", - "\n", - " messages = state[\"messages\"] + [HumanMessage(content=summary_message)]\n", - " response = model.invoke(messages)\n", - " # We now need to delete messages that we no longer want to show up\n", - " # I will delete all but the last two messages, but you can change this\n", - " delete_messages = [RemoveMessage(id=m.id) for m in state[\"messages\"][:-2]]\n", - " return {\"summary\": response.content, \"messages\": delete_messages}\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(State)\n", - "\n", - "# Define the conversation node and the summarize node\n", - "workflow.add_node(\"conversation\", call_model)\n", - "workflow.add_node(summarize_conversation)\n", - "\n", - "# Set the entrypoint as conversation\n", - "workflow.add_edge(START, \"conversation\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `conversation`.\n", - " # This means these are the edges taken after the `conversation` node is called.\n", - " \"conversation\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - ")\n", - "\n", - "# We now add a normal edge from `summarize_conversation` to END.\n", - "# This means that after `summarize_conversation` is called, we end.\n", - "workflow.add_edge(\"summarize_conversation\", END)\n", - "\n", - "# Finally, we compile it!\n", - "app = workflow.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "41c2872e-04b3-4c44-9e03-9e84a5230adf", - "metadata": {}, - "source": [ - "## Using the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "dc697132-8fa1-4bf5-9722-56a9859331ab", - "metadata": {}, - "outputs": [], - "source": [ - "def print_update(update):\n", - " for k, v in update.items():\n", - " for m in v[\"messages\"]:\n", - " m.pretty_print()\n", - " if \"summary\" in v:\n", - " print(v[\"summary\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "57b27553-21be-43e5-ac48-d1d0a3aa0dca", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "hi! I'm bob\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "It's nice to meet you, Bob! I'm an AI assistant created by Anthropic. How can I help you today?\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Your name is Bob, as you told me at the beginning of our conversation.\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "i like the celtics!\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "That's great, the Celtics are a fun team to follow! Basketball is an exciting sport. Do you have a favorite Celtics player or a favorite moment from a Celtics game you've watched? I'd be happy to discuss the team and the sport with you.\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "config = {\"configurable\": {\"thread_id\": \"4\"}}\n", - "input_message = HumanMessage(content=\"hi! I'm bob\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)\n", - "\n", - "input_message = HumanMessage(content=\"what's my name?\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)\n", - "\n", - "input_message = HumanMessage(content=\"i like the celtics!\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)" - ] - }, - { - "cell_type": "markdown", - "id": "9760e219-a7fc-4d81-b4e8-1334c5afc510", - "metadata": {}, - "source": [ - "We can see that so far no summarization has happened - this is because there are only six messages in the list." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "935265a0-d511-475a-8a0d-b3c3cc5e42a0", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content=\"hi! I'm bob\", id='6534853d-b8a7-44b9-837b-eb7abaf7ebf7'),\n", - " AIMessage(content=\"It's nice to meet you, Bob! I'm an AI assistant created by Anthropic. How can I help you today?\", response_metadata={'id': 'msg_015wCFew2vwMQJcpUh2VZ5ah', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 12, 'output_tokens': 30}}, id='run-0d33008b-1094-4f5e-94ce-293283fc3024-0'),\n", - " HumanMessage(content=\"what's my name?\", id='0a4f203a-b95a-42a9-b1c5-bb20f68b3251'),\n", - " AIMessage(content='Your name is Bob, as you told me at the beginning of our conversation.', response_metadata={'id': 'msg_01PLp8wg2xDsJbNR9uCtxcGz', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 50, 'output_tokens': 19}}, id='run-3815dd4d-ee0c-4fc2-9889-f6dd40325961-0'),\n", - " HumanMessage(content='i like the celtics!', id='ac128172-42d1-4390-b7cc-7bcb2d22ee48'),\n", - " AIMessage(content=\"That's great, the Celtics are a fun team to follow! Basketball is an exciting sport. Do you have a favorite Celtics player or a favorite moment from a Celtics game you've watched? I'd be happy to discuss the team and the sport with you.\", response_metadata={'id': 'msg_01CSg5avZEx6CKcZsSvSVXpr', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 78, 'output_tokens': 61}}, id='run-698faa28-0f72-495f-8ebe-e948664d2200-0')]}" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "values = app.get_state(config).values\n", - "values" - ] - }, - { - "cell_type": "markdown", - "id": "bb40eddb-9a31-4410-a4c0-9762e2d89e56", - "metadata": {}, - "source": [ - "Now let's send another message in" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "048805a4-3d97-4e76-ac45-8d80d4364c46", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "i like how much they win\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "That's understandable, the Celtics have been one of the more successful NBA franchises over the years. Their history of winning championships is very impressive. It's always fun to follow a team that regularly competes for titles. What do you think has been the key to the Celtics' sustained success? Is there a particular era or team that stands out as your favorite?\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "Here is a summary of our conversation so far:\n", - "\n", - "- You introduced yourself as Bob and said you like the Boston Celtics basketball team.\n", - "- I acknowledged that it's nice to meet you, Bob, and noted that you had shared your name earlier in the conversation.\n", - "- You expressed that you like how much the Celtics win, and I agreed that their history of sustained success and championship pedigree is impressive.\n", - "- I asked if you have a favorite Celtics player or moment that stands out to you, and invited further discussion about the team and the sport of basketball.\n", - "- The overall tone has been friendly and conversational, with me trying to engage with your interest in the Celtics by asking follow-up questions.\n" - ] - } - ], - "source": [ - "input_message = HumanMessage(content=\"i like how much they win\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)" - ] - }, - { - "cell_type": "markdown", - "id": "6b196367-6151-4982-9430-3db7373de06e", - "metadata": {}, - "source": [ - "If we check the state now, we can see that we have a summary of the conversation, as well as the last two messages" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "09ebb693-4738-4474-a095-6491def5c5f9", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='i like how much they win', id='bb916ce7-534c-4d48-9f92-e269f9dc4859'),\n", - " AIMessage(content=\"That's understandable, the Celtics have been one of the more successful NBA franchises over the years. Their history of winning championships is very impressive. It's always fun to follow a team that regularly competes for titles. What do you think has been the key to the Celtics' sustained success? Is there a particular era or team that stands out as your favorite?\", response_metadata={'id': 'msg_01B7TMagaM8xBnYXLSMwUDAG', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 148, 'output_tokens': 82}}, id='run-c5aa9a8f-7983-4a7f-9c1e-0c0055334ac1-0')],\n", - " 'summary': \"Here is a summary of our conversation so far:\\n\\n- You introduced yourself as Bob and said you like the Boston Celtics basketball team.\\n- I acknowledged that it's nice to meet you, Bob, and noted that you had shared your name earlier in the conversation.\\n- You expressed that you like how much the Celtics win, and I agreed that their history of sustained success and championship pedigree is impressive.\\n- I asked if you have a favorite Celtics player or moment that stands out to you, and invited further discussion about the team and the sport of basketball.\\n- The overall tone has been friendly and conversational, with me trying to engage with your interest in the Celtics by asking follow-up questions.\"}" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "values = app.get_state(config).values\n", - "values" - ] - }, - { - "cell_type": "markdown", - "id": "966e4177-c0fc-4fd0-a494-dd03f7f2fddb", - "metadata": {}, - "source": [ - "We can now resume having a conversation! Note that even though we only have the last two messages, we can still ask it questions about things mentioned earlier in the conversation (because we summarized those)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "7094c5ab-66f8-42ff-b1c3-90c8a9468e62", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "In our conversation so far, you introduced yourself as Bob. I acknowledged that earlier when you had shared your name.\n" - ] - } - ], - "source": [ - "input_message = HumanMessage(content=\"what's my name?\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "40e5db8e-9db9-4ac7-9d76-a99fd4034bf3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what NFL team do you think I like?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I don't actually have any information about what NFL team you might like. In our conversation so far, you've only mentioned that you're a fan of the Boston Celtics basketball team. I don't have any prior knowledge about your preferences for NFL teams. Unless you provide me with that information, I don't have a basis to guess which NFL team you might be a fan of.\n" - ] - } - ], - "source": [ - "input_message = HumanMessage(content=\"what NFL team do you think I like?\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "0a1a0fda-5309-45f0-9465-9f3dff604d74", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "i like the patriots!\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Okay, got it! Thanks for sharing that you're also a fan of the New England Patriots in the NFL. That makes sense, given your interest in other Boston sports teams like the Celtics. The Patriots have also had a very successful run over the past couple of decades, winning multiple Super Bowls. It's fun to follow winning franchises like the Celtics and Patriots. Do you have a favorite Patriots player or moment that stands out to you?\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "================================\u001b[1m Remove Message \u001b[0m================================\n", - "\n", - "\n", - "Okay, extending the summary with the new information:\n", - "\n", - "- You initially introduced yourself as Bob and said you like the Boston Celtics basketball team. \n", - "- I acknowledged that and we discussed your appreciation for the Celtics' history of winning.\n", - "- You then asked what your name was, and I reminded you that you had introduced yourself as Bob earlier in the conversation.\n", - "- You followed up by asking what NFL team I thought you might like, and I explained that I didn't have any prior information about your NFL team preferences.\n", - "- You then revealed that you are also a fan of the New England Patriots, which made sense given your Celtics fandom.\n", - "- I responded positively to this new information, noting the Patriots' own impressive success and dynasty over the past couple of decades.\n", - "- I then asked if you have a particular favorite Patriots player or moment that stands out to you, continuing the friendly, conversational tone.\n", - "\n", - "Overall, the discussion has focused on your sports team preferences, with you sharing that you are a fan of both the Celtics and the Patriots. I've tried to engage with your interests and ask follow-up questions to keep the dialogue flowing.\n" - ] - } - ], - "source": [ - "input_message = HumanMessage(content=\"i like the patriots!\")\n", - "input_message.pretty_print()\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"updates\"):\n", - " print_update(event)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.1" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/memory/delete-messages.ipynb b/docs/docs/how-tos/memory/delete-messages.ipynb deleted file mode 100644 index 3d8fc54d2..000000000 --- a/docs/docs/how-tos/memory/delete-messages.ipynb +++ /dev/null @@ -1,479 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to delete messages\n", - "\n", - "One of the common states for a graph is a list of messages. Usually you only add messages to that state. However, sometimes you may want to remove messages (either by directly modifying the state or as part of the graph). To do that, you can use the `RemoveMessage` modifier. In this guide, we will cover how to do that.\n", - "\n", - "The key idea is that each state key has a `reducer` key. This key specifies how to combine updates to the state. The default `MessagesState` has a messages key, and the reducer for that key accepts these `RemoveMessage` modifiers. That reducer then uses these `RemoveMessage` to delete messages from the key.\n", - "\n", - "So note that just because your graph state has a key that is a list of messages, it doesn't mean that that this `RemoveMessage` modifier will work. You also have to have a `reducer` defined that knows how to work with this.\n", - "\n", - "**NOTE**: Many models expect certain rules around lists of messages. For example, some expect them to start with a `user` message, others expect all messages with tool calls to be followed by a tool message. **When deleting messages, you will want to make sure you don't violate these rules.**" - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's build a simple graph that uses messages. Note that it's using the `MessagesState` which has the required `reducer`." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API keys for Anthropic (the LLM we will use)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ANTHROPIC_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "4767ef1c-a7cf-41f8-a301-558988cb7ac5", - "metadata": {}, - "source": [ - "## Build the agent\n", - "Let's now build a simple ReAct style agent." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "378899a9-3b9a-4748-95b6-eb00e0828677", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.tools import tool\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import MessagesState, StateGraph, START, END\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "@tool\n", - "def search(query: str):\n", - " \"\"\"Call to surf the web.\"\"\"\n", - " # This is a placeholder for the actual implementation\n", - " # Don't let the LLM know this though 😊\n", - " return \"It's sunny in San Francisco, but you better look out if you're a Gemini 😈.\"\n", - "\n", - "\n", - "tools = [search]\n", - "tool_node = ToolNode(tools)\n", - "model = ChatAnthropic(model_name=\"claude-3-haiku-20240307\")\n", - "bound_model = model.bind_tools(tools)\n", - "\n", - "\n", - "def should_continue(state: MessagesState):\n", - " \"\"\"Return the next node to execute.\"\"\"\n", - " last_message = state[\"messages\"][-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return END\n", - " # Otherwise if there is, we continue\n", - " return \"action\"\n", - "\n", - "\n", - "# Define the function that calls the model\n", - "def call_model(state: MessagesState):\n", - " response = model.invoke(state[\"messages\"])\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": response}\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " # Next, we pass in the path map - all the possible nodes this edge could go to\n", - " [\"action\", END],\n", - ")\n", - "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")\n", - "\n", - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", - "app = workflow.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "57b27553-21be-43e5-ac48-d1d0a3aa0dca", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "hi! I'm bob\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "It's nice to meet you, Bob! I'm an AI assistant created by Anthropic. I'm here to help out with any questions or tasks you might have. Please let me know if there's anything I can assist you with.\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "You said your name is Bob.\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "input_message = HumanMessage(content=\"hi! I'm bob\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()\n", - "\n", - "\n", - "input_message = HumanMessage(content=\"what's my name?\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "2fb0de5b-30ec-42d4-813a-7ad63fe1c367", - "metadata": {}, - "source": [ - "## Manually deleting messages\n", - "\n", - "First, we will cover how to manually delete messages. Let's take a look at the current state of the thread:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "8a850529-d038-48f7-b5a2-8d4d2923f83a", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[HumanMessage(content=\"hi! I'm bob\", additional_kwargs={}, response_metadata={}, id='db576005-3a60-4b3b-8925-dc602ac1c571'),\n", - " AIMessage(content=\"It's nice to meet you, Bob! I'm an AI assistant created by Anthropic. I'm here to help out with any questions or tasks you might have. Please let me know if there's anything I can assist you with.\", additional_kwargs={}, response_metadata={'id': 'msg_01BKAnYxmoC6bQ9PpCuHk8ZT', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 12, 'output_tokens': 52}}, id='run-3a60c536-b207-4c56-98f3-03f94d49a9e4-0', usage_metadata={'input_tokens': 12, 'output_tokens': 52, 'total_tokens': 64}),\n", - " HumanMessage(content=\"what's my name?\", additional_kwargs={}, response_metadata={}, id='2088c465-400b-430b-ad80-fad47dc1f2d6'),\n", - " AIMessage(content='You said your name is Bob.', additional_kwargs={}, response_metadata={'id': 'msg_013UWTLTzwZi81vke8mMQ2KP', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 72, 'output_tokens': 10}}, id='run-3a6883be-0c52-4938-af98-e9e7476659eb-0', usage_metadata={'input_tokens': 72, 'output_tokens': 10, 'total_tokens': 82})]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages = app.get_state(config).values[\"messages\"]\n", - "messages" - ] - }, - { - "cell_type": "markdown", - "id": "81be8a0a-1e94-4302-bd84-d1b72e3c501c", - "metadata": {}, - "source": [ - "We can call `update_state` and pass in the id of the first message. This will delete that message." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "df1a0970-7e64-4170-beef-2855d10eef42", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'configurable': {'thread_id': '2',\n", - " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1ef75157-f251-6a2a-8005-82a86a6593a0'}}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langchain_core.messages import RemoveMessage\n", - "\n", - "app.update_state(config, {\"messages\": RemoveMessage(id=messages[0].id)})" - ] - }, - { - "cell_type": "markdown", - "id": "9c9127ae-0d42-42b8-957f-ea69a5da555f", - "metadata": {}, - "source": [ - "If we now look at the messages, we can verify that the first one was deleted." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "8bfe4ffa-e170-43bc-aec4-6e36ac620931", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[AIMessage(content=\"It's nice to meet you, Bob! I'm Claude, an AI assistant created by Anthropic. How can I assist you today?\", response_metadata={'id': 'msg_01XPSAenmSqK8rX2WgPZHfz7', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 12, 'output_tokens': 32}}, id='run-1c69af09-adb1-412d-9010-2456e5a555fb-0', usage_metadata={'input_tokens': 12, 'output_tokens': 32, 'total_tokens': 44}),\n", - " HumanMessage(content=\"what's my name?\", id='f3c71afe-8ce2-4ed0-991e-65021f03b0a5'),\n", - " AIMessage(content='Your name is Bob, as you introduced yourself at the beginning of our conversation.', response_metadata={'id': 'msg_01BPZdwsjuMAbC1YAkqawXaF', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 52, 'output_tokens': 19}}, id='run-b2eb9137-2f4e-446f-95f5-3d5f621a2cf8-0', usage_metadata={'input_tokens': 52, 'output_tokens': 19, 'total_tokens': 71})]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages = app.get_state(config).values[\"messages\"]\n", - "messages" - ] - }, - { - "cell_type": "markdown", - "id": "ef129a75-4cad-44d7-b532-eb37b0553c0c", - "metadata": {}, - "source": [ - "## Programmatically deleting messages\n", - "\n", - "We can also delete messages programmatically from inside the graph. Here we'll modify the graph to delete any old messages (longer than 3 messages ago) at the end of a graph run." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "bb22ede0-e153-4fd0-a4c0-f9af2f7663b1", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import RemoveMessage\n", - "from langgraph.graph import END\n", - "\n", - "\n", - "def delete_messages(state):\n", - " messages = state[\"messages\"]\n", - " if len(messages) > 3:\n", - " return {\"messages\": [RemoveMessage(id=m.id) for m in messages[:-3]]}\n", - "\n", - "\n", - "# We need to modify the logic to call delete_messages rather than end right away\n", - "def should_continue(state: MessagesState) -> Literal[\"action\", \"delete_messages\"]:\n", - " \"\"\"Return the next node to execute.\"\"\"\n", - " last_message = state[\"messages\"][-1]\n", - " # If there is no function call, then we call our delete_messages function\n", - " if not last_message.tool_calls:\n", - " return \"delete_messages\"\n", - " # Otherwise if there is, we continue\n", - " return \"action\"\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# This is our new node we're defining\n", - "workflow.add_node(delete_messages)\n", - "\n", - "\n", - "workflow.add_edge(START, \"agent\")\n", - "workflow.add_conditional_edges(\n", - " \"agent\",\n", - " should_continue,\n", - ")\n", - "workflow.add_edge(\"action\", \"agent\")\n", - "\n", - "# This is the new edge we're adding: after we delete messages, we finish\n", - "workflow.add_edge(\"delete_messages\", END)\n", - "app = workflow.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "52cbdef6-7db7-45a2-8194-de4f8929bd1f", - "metadata": {}, - "source": [ - "We can now try this out. We can call the graph twice and then check the state" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "3975f34c-c243-40ea-b9d2-424d50a48dc9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('human', \"hi! I'm bob\")]\n", - "[('human', \"hi! I'm bob\"), ('ai', \"Hello Bob! It's nice to meet you. I'm an AI assistant created by Anthropic. I'm here to help with any questions or tasks you might have. Please let me know how I can assist you.\")]\n", - "[('human', \"hi! I'm bob\"), ('ai', \"Hello Bob! It's nice to meet you. I'm an AI assistant created by Anthropic. I'm here to help with any questions or tasks you might have. Please let me know how I can assist you.\"), ('human', \"what's my name?\")]\n", - "[('human', \"hi! I'm bob\"), ('ai', \"Hello Bob! It's nice to meet you. I'm an AI assistant created by Anthropic. I'm here to help with any questions or tasks you might have. Please let me know how I can assist you.\"), ('human', \"what's my name?\"), ('ai', 'You said your name is Bob, so that is the name I have for you.')]\n", - "[('ai', \"Hello Bob! It's nice to meet you. I'm an AI assistant created by Anthropic. I'm here to help with any questions or tasks you might have. Please let me know how I can assist you.\"), ('human', \"what's my name?\"), ('ai', 'You said your name is Bob, so that is the name I have for you.')]\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "config = {\"configurable\": {\"thread_id\": \"3\"}}\n", - "input_message = HumanMessage(content=\"hi! I'm bob\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " print([(message.type, message.content) for message in event[\"messages\"]])\n", - "\n", - "\n", - "input_message = HumanMessage(content=\"what's my name?\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " print([(message.type, message.content) for message in event[\"messages\"]])" - ] - }, - { - "cell_type": "markdown", - "id": "67b2fd2a-14a1-4c47-8632-f8cbb0ba1d35", - "metadata": {}, - "source": [ - "If we now check the state, we should see that it is only three messages long. This is because we just deleted the earlier messages - otherwise it would be four!" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "a3e15abb-81d8-4072-9f10-61ae0fd61dac", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[AIMessage(content=\"Hello Bob! It's nice to meet you. I'm an AI assistant created by Anthropic. I'm here to help with any questions or tasks you might have. Please let me know how I can assist you.\", response_metadata={'id': 'msg_01XPEgPPbcnz5BbGWUDWTmzG', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 12, 'output_tokens': 48}}, id='run-eded3820-b6a9-4d66-9210-03ca41787ce6-0', usage_metadata={'input_tokens': 12, 'output_tokens': 48, 'total_tokens': 60}),\n", - " HumanMessage(content=\"what's my name?\", id='a0ea2097-3280-402b-92e1-67177b807ae8'),\n", - " AIMessage(content='You said your name is Bob, so that is the name I have for you.', response_metadata={'id': 'msg_01JGT62pxhrhN4SykZ57CSjW', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 68, 'output_tokens': 20}}, id='run-ace3519c-81f8-45fe-a777-91f42d48b3a3-0', usage_metadata={'input_tokens': 68, 'output_tokens': 20, 'total_tokens': 88})]" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages = app.get_state(config).values[\"messages\"]\n", - "messages" - ] - }, - { - "cell_type": "markdown", - "id": "359cfeae-d43a-46ee-9069-a1cab9a5720a", - "metadata": {}, - "source": [ - "Remember, when deleting messages you will want to make sure that the remaining message list is still valid. This message list **may actually not be** - this is because it currently starts with an AI message, which some models do not allow." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/memory/manage-conversation-history.ipynb b/docs/docs/how-tos/memory/manage-conversation-history.ipynb deleted file mode 100644 index 6407d50ec..000000000 --- a/docs/docs/how-tos/memory/manage-conversation-history.ipynb +++ /dev/null @@ -1,380 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to manage conversation history\n", - "\n", - "One of the most common use cases for persistence is to use it to keep track of conversation history. This is great - it makes it easy to continue conversations. As conversations get longer and longer, however, this conversation history can build up and take up more and more of the context window. This can often be undesirable as it leads to more expensive and longer calls to the LLM, and potentially ones that error. In order to prevent this from happening, you need to properly manage the conversation history.\n", - "\n", - "Note: this guide focuses on how to do this in LangGraph, where you can fully customize how this is done. If you want a more off-the-shelf solution, you can look into functionality provided in LangChain:\n", - "\n", - "- [How to filter messages](https://python.langchain.com/docs/how_to/filter_messages/)\n", - "- [How to trim messages](https://python.langchain.com/docs/how_to/trim_messages/)" - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's set up the packages we're going to want to use" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API keys for Anthropic (the LLM we will use)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "4767ef1c-a7cf-41f8-a301-558988cb7ac5", - "metadata": {}, - "source": [ - "## Build the agent\n", - "Let's now build a simple ReAct style agent." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "378899a9-3b9a-4748-95b6-eb00e0828677", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.tools import tool\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import MessagesState, StateGraph, START, END\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "@tool\n", - "def search(query: str):\n", - " \"\"\"Call to surf the web.\"\"\"\n", - " # This is a placeholder for the actual implementation\n", - " # Don't let the LLM know this though 😊\n", - " return \"It's sunny in San Francisco, but you better look out if you're a Gemini 😈.\"\n", - "\n", - "\n", - "tools = [search]\n", - "tool_node = ToolNode(tools)\n", - "model = ChatAnthropic(model_name=\"claude-3-haiku-20240307\")\n", - "bound_model = model.bind_tools(tools)\n", - "\n", - "\n", - "def should_continue(state: MessagesState):\n", - " \"\"\"Return the next node to execute.\"\"\"\n", - " last_message = state[\"messages\"][-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return END\n", - " # Otherwise if there is, we continue\n", - " return \"action\"\n", - "\n", - "\n", - "# Define the function that calls the model\n", - "def call_model(state: MessagesState):\n", - " response = bound_model.invoke(state[\"messages\"])\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": response}\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " # Next, we pass in the path map - all the possible nodes this edge could go to\n", - " [\"action\", END],\n", - ")\n", - "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")\n", - "\n", - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", - "app = workflow.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "57b27553-21be-43e5-ac48-d1d0a3aa0dca", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "hi! I'm bob\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Nice to meet you, Bob! As an AI assistant, I don't have a physical form, but I'm happy to chat with you and try my best to help out however I can. Please feel free to ask me anything, and I'll do my best to provide useful information or assistance.\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "You said your name is Bob, so that is the name I have for you.\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "input_message = HumanMessage(content=\"hi! I'm bob\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()\n", - "\n", - "\n", - "input_message = HumanMessage(content=\"what's my name?\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "5d5da4c9-ba8b-46cb-a860-63fe585d15c5", - "metadata": {}, - "source": [ - "## Filtering messages\n", - "\n", - "The most straight-forward thing to do to prevent conversation history from blowing up is to filter the list of messages before they get passed to the LLM. This involves two parts: defining a function to filter messages, and then adding it to the graph. See the example below which defines a really simple `filter_messages` function and then uses it." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "eb20430f", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.tools import tool\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import MessagesState, StateGraph, START\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "@tool\n", - "def search(query: str):\n", - " \"\"\"Call to surf the web.\"\"\"\n", - " # This is a placeholder for the actual implementation\n", - " # Don't let the LLM know this though 😊\n", - " return \"It's sunny in San Francisco, but you better look out if you're a Gemini 😈.\"\n", - "\n", - "\n", - "tools = [search]\n", - "tool_node = ToolNode(tools)\n", - "model = ChatAnthropic(model_name=\"claude-3-haiku-20240307\")\n", - "bound_model = model.bind_tools(tools)\n", - "\n", - "\n", - "def should_continue(state: MessagesState):\n", - " \"\"\"Return the next node to execute.\"\"\"\n", - " last_message = state[\"messages\"][-1]\n", - " # If there is no function call, then we finish\n", - " if not last_message.tool_calls:\n", - " return END\n", - " # Otherwise if there is, we continue\n", - " return \"action\"\n", - "\n", - "\n", - "def filter_messages(messages: list):\n", - " # This is very simple helper function which only ever uses the last message\n", - " return messages[-1:]\n", - "\n", - "\n", - "# Define the function that calls the model\n", - "def call_model(state: MessagesState):\n", - " messages = filter_messages(state[\"messages\"])\n", - " response = bound_model.invoke(messages)\n", - " # We return a list, because this will get added to the existing list\n", - " return {\"messages\": response}\n", - "\n", - "\n", - "# Define a new graph\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"action\", tool_node)\n", - "\n", - "# Set the entrypoint as `agent`\n", - "# This means that this node is the first one called\n", - "workflow.add_edge(START, \"agent\")\n", - "\n", - "# We now add a conditional edge\n", - "workflow.add_conditional_edges(\n", - " # First, we define the start node. We use `agent`.\n", - " # This means these are the edges taken after the `agent` node is called.\n", - " \"agent\",\n", - " # Next, we pass in the function that will determine which node is called next.\n", - " should_continue,\n", - " # Next, we pass in the pathmap - all the possible nodes this edge could go to\n", - " [\"action\", END],\n", - ")\n", - "\n", - "# We now add a normal edge from `tools` to `agent`.\n", - "# This means that after `tools` is called, `agent` node is called next.\n", - "workflow.add_edge(\"action\", \"agent\")\n", - "\n", - "# Finally, we compile it!\n", - "# This compiles it into a LangChain Runnable,\n", - "# meaning you can use it as you would any other runnable\n", - "app = workflow.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "52468ebb-4b23-45ac-a98e-b4439f37740a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "hi! I'm bob\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Nice to meet you, Bob! I'm Claude, an AI assistant created by Anthropic. It's a pleasure to chat with you. Feel free to ask me anything, I'm here to help!\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I'm afraid I don't actually know your name. As an AI assistant, I don't have information about the specific identities of the people I talk to. I only know what is provided to me during our conversation.\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "input_message = HumanMessage(content=\"hi! I'm bob\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()\n", - "\n", - "# This will now not remember the previous messages\n", - "# (because we set `messages[-1:]` in the filter messages argument)\n", - "input_message = HumanMessage(content=\"what's my name?\")\n", - "for event in app.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "454102b6-7112-4710-aa08-ba675e8be14c", - "metadata": {}, - "source": [ - "In the above example we defined the `filter_messages` function ourselves. We also provide off-the-shelf ways to trim and filter messages in LangChain. \n", - "\n", - "- [How to filter messages](https://python.langchain.com/docs/how_to/filter_messages/)\n", - "- [How to trim messages](https://python.langchain.com/docs/how_to/trim_messages/)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/multi-agent-multi-turn-convo.ipynb b/docs/docs/how-tos/multi-agent-multi-turn-convo.ipynb deleted file mode 100644 index d1e454422..000000000 --- a/docs/docs/how-tos/multi-agent-multi-turn-convo.ipynb +++ /dev/null @@ -1,473 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "a2b182eb-1e31-43c8-85b1-706508dfa370", - "metadata": {}, - "source": [ - "# How to add multi-turn conversation in a multi-agent application\n", - "\n", - "!!! info \"Prerequisites\"\n", - " This guide assumes familiarity with the following:\n", - "\n", - " - [How to implement handoffs between agents](../agent-handoffs)\n", - " - [Multi-agent systems](../../concepts/multi_agent)\n", - " - [Human-in-the-loop](../../concepts/human_in_the_loop)\n", - " - [Command](../../concepts/low_level/#command)\n", - " - [LangGraph Glossary](../../concepts/low_level/)\n", - "\n", - "\n", - "In this how-to guide, we’ll build an application that allows an end-user to engage in a *multi-turn conversation* with one or more agents. We'll create a node that uses an [`interrupt`](../../reference/types/#langgraph.types.interrupt) to collect user input and routes back to the **active** agent.\n", - "\n", - "The agents will be implemented as nodes in a graph that executes agent steps and determines the next action: \n", - "\n", - "1. **Wait for user input** to continue the conversation, or \n", - "2. **Route to another agent** (or back to itself, such as in a loop) via a [**handoff**](../../concepts/multi_agent/#handoffs).\n", - "\n", - "```python\n", - "def human(state: MessagesState) -> Command[Literal[\"agent\", \"another_agent\"]]:\n", - " \"\"\"A node for collecting user input.\"\"\"\n", - " user_input = interrupt(value=\"Ready for user input.\")\n", - "\n", - " # Determine the active agent.\n", - " active_agent = ...\n", - "\n", - " ...\n", - " return Command(\n", - " update={\n", - " \"messages\": [{\n", - " \"role\": \"human\",\n", - " \"content\": user_input,\n", - " }]\n", - " },\n", - " goto=active_agent\n", - " )\n", - "\n", - "def agent(state) -> Command[Literal[\"agent\", \"another_agent\", \"human\"]]:\n", - " # The condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.\n", - " goto = get_next_agent(...) # 'agent' / 'another_agent'\n", - " if goto:\n", - " return Command(goto=goto, update={\"my_state_key\": \"my_state_value\"})\n", - " else:\n", - " return Command(goto=\"human\") # Go to human node\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "faaa4444-cd06-4813-b9ca-c9700fe12cb7", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "05038da0-31df-4066-a1a4-c4ccb5db4d3a", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain-anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0bcff5d4-130e-426d-9285-40d0f72c7cd3", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "c3ec6e48-85dc-4905-ba50-985e5d4788e6", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "c217c3fe-ca50-45a1-be91-912bc83ed8b3", - "metadata": {}, - "source": [ - "## Define agents\n", - "\n", - "In this example, we will build a team of travel assistant agents that can communicate with each other via handoffs.\n", - "\n", - "We will create 2 agents:\n", - "\n", - "* `travel_advisor`: can help with travel destination recommendations. Can ask `hotel_advisor` for help.\n", - "* `hotel_advisor`: can help with hotel recommendations. Can ask `travel_advisor` for help.\n", - "\n", - "We will be using prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] for the agents - each agent will have tools specific to its area of expertise as well as a special [tool for handoffs](../agent-handoffs#implementing-handoffs-using-tools) to another agent.\n", - "\n", - "First, let's define the tools we'll be using:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "eb51463a-4425-44ad-91d5-f21fd5b4e3b3", - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "from typing import Annotated, Literal\n", - "\n", - "from langchain_core.tools import tool\n", - "from langchain_core.tools.base import InjectedToolCallId\n", - "from langgraph.prebuilt import InjectedState\n", - "\n", - "\n", - "@tool\n", - "def get_travel_recommendations():\n", - " \"\"\"Get recommendation for travel destinations\"\"\"\n", - " return random.choice([\"aruba\", \"turks and caicos\"])\n", - "\n", - "\n", - "@tool\n", - "def get_hotel_recommendations(location: Literal[\"aruba\", \"turks and caicos\"]):\n", - " \"\"\"Get hotel recommendations for a given destination.\"\"\"\n", - " return {\n", - " \"aruba\": [\n", - " \"The Ritz-Carlton, Aruba (Palm Beach)\"\n", - " \"Bucuti & Tara Beach Resort (Eagle Beach)\"\n", - " ],\n", - " \"turks and caicos\": [\"Grace Bay Club\", \"COMO Parrot Cay\"],\n", - " }[location]\n", - "\n", - "\n", - "def make_handoff_tool(*, agent_name: str):\n", - " \"\"\"Create a tool that can return handoff via a Command\"\"\"\n", - " tool_name = f\"transfer_to_{agent_name}\"\n", - "\n", - " @tool(tool_name)\n", - " def handoff_to_agent(\n", - " state: Annotated[dict, InjectedState],\n", - " tool_call_id: Annotated[str, InjectedToolCallId],\n", - " ):\n", - " \"\"\"Ask another agent for help.\"\"\"\n", - " tool_message = {\n", - " \"role\": \"tool\",\n", - " \"content\": f\"Successfully transferred to {agent_name}\",\n", - " \"name\": tool_name,\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(\n", - " # navigate to another agent node in the PARENT graph\n", - " goto=agent_name,\n", - " graph=Command.PARENT,\n", - " # This is the state update that the agent `agent_name` will see when it is invoked.\n", - " # We're passing agent's FULL internal message history AND adding a tool message to make sure\n", - " # the resulting chat history is valid.\n", - " update={\"messages\": state[\"messages\"] + [tool_message]},\n", - " )\n", - "\n", - " return handoff_to_agent" - ] - }, - { - "cell_type": "markdown", - "id": "213d661e-6ba4-42b9-bc7f-6c8c423e3419", - "metadata": {}, - "source": [ - "Let's now create our agents using the the prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent]. We'll also define a dedicated `human` node with an [`interrupt`][langgraph.types.interrupt] -- we will route to this node after the final response from the agents. Note that to do so we're wrapping each agent invocation in a separate node function that returns `Command(goto=\"human\", ...)`." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "aa4bdbff-9461-46cc-aee9-8a22d3c3d9ec", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_anthropic import ChatAnthropic\n", - "from langgraph.graph import MessagesState, StateGraph, START\n", - "from langgraph.prebuilt import create_react_agent, InjectedState\n", - "from langgraph.types import Command, interrupt\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-latest\")\n", - "\n", - "\n", - "class MultiAgentState(MessagesState):\n", - " last_active_agent: str\n", - "\n", - "\n", - "# Define travel advisor tools and ReAct agent\n", - "travel_advisor_tools = [\n", - " get_travel_recommendations,\n", - " make_handoff_tool(agent_name=\"hotel_advisor\"),\n", - "]\n", - "travel_advisor = create_react_agent(\n", - " model,\n", - " travel_advisor_tools,\n", - " prompt=(\n", - " \"You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). \"\n", - " \"If you need hotel recommendations, ask 'hotel_advisor' for help. \"\n", - " \"You MUST include human-readable response before transferring to another agent.\"\n", - " ),\n", - ")\n", - "\n", - "\n", - "def call_travel_advisor(\n", - " state: MultiAgentState,\n", - ") -> Command[Literal[\"hotel_advisor\", \"human\"]]:\n", - " # You can also add additional logic like changing the input to the agent / output from the agent, etc.\n", - " # NOTE: we're invoking the ReAct agent with the full history of messages in the state\n", - " response = travel_advisor.invoke(state)\n", - " update = {**response, \"last_active_agent\": \"travel_advisor\"}\n", - " return Command(update=update, goto=\"human\")\n", - "\n", - "\n", - "# Define hotel advisor tools and ReAct agent\n", - "hotel_advisor_tools = [\n", - " get_hotel_recommendations,\n", - " make_handoff_tool(agent_name=\"travel_advisor\"),\n", - "]\n", - "hotel_advisor = create_react_agent(\n", - " model,\n", - " hotel_advisor_tools,\n", - " prompt=(\n", - " \"You are a hotel expert that can provide hotel recommendations for a given destination. \"\n", - " \"If you need help picking travel destinations, ask 'travel_advisor' for help.\"\n", - " \"You MUST include human-readable response before transferring to another agent.\"\n", - " ),\n", - ")\n", - "\n", - "\n", - "def call_hotel_advisor(\n", - " state: MultiAgentState,\n", - ") -> Command[Literal[\"travel_advisor\", \"human\"]]:\n", - " response = hotel_advisor.invoke(state)\n", - " update = {**response, \"last_active_agent\": \"hotel_advisor\"}\n", - " return Command(update=update, goto=\"human\")\n", - "\n", - "\n", - "def human_node(\n", - " state: MultiAgentState, config\n", - ") -> Command[Literal[\"hotel_advisor\", \"travel_advisor\", \"human\"]]:\n", - " \"\"\"A node for collecting user input.\"\"\"\n", - "\n", - " user_input = interrupt(value=\"Ready for user input.\")\n", - " active_agent = state[\"last_active_agent\"]\n", - "\n", - " return Command(\n", - " update={\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"human\",\n", - " \"content\": user_input,\n", - " }\n", - " ]\n", - " },\n", - " goto=active_agent,\n", - " )\n", - "\n", - "\n", - "builder = StateGraph(MultiAgentState)\n", - "builder.add_node(\"travel_advisor\", call_travel_advisor)\n", - "builder.add_node(\"hotel_advisor\", call_hotel_advisor)\n", - "\n", - "# This adds a node to collect human input, which will route\n", - "# back to the active agent.\n", - "builder.add_node(\"human\", human_node)\n", - "\n", - "# We'll always start with a general travel advisor.\n", - "builder.add_edge(START, \"travel_advisor\")\n", - "\n", - "\n", - "checkpointer = MemorySaver()\n", - "graph = builder.compile(checkpointer=checkpointer)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "d77921f6-599d-443f-8b15-56b1adafd3a8", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import display, Image\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "af856e1b-41fc-4041-8cbf-3818a60088e0", - "metadata": {}, - "source": [ - "## Test multi-turn conversation\n", - "\n", - "Let's test a multi turn conversation with this application." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "161e0cf1-d13a-4026-8f89-bdab67d1ad4d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "--- Conversation Turn 1 ---\n", - "\n", - "User: {'messages': [{'role': 'user', 'content': 'i wanna go somewhere warm in the caribbean'}]}\n", - "\n", - "travel_advisor: Based on the recommendations, Aruba would be an excellent choice for your Caribbean getaway! Aruba is known as \"One Happy Island\" and offers:\n", - "- Year-round warm weather with consistent temperatures around 82°F (28°C)\n", - "- Beautiful white sand beaches like Eagle Beach and Palm Beach\n", - "- Clear turquoise waters perfect for swimming and snorkeling\n", - "- Minimal rainfall and location outside the hurricane belt\n", - "- A blend of Caribbean and Dutch culture\n", - "- Great dining options and nightlife\n", - "- Various water sports and activities\n", - "\n", - "Would you like me to get some specific hotel recommendations in Aruba for your stay? I can transfer you to our hotel advisor who can help with accommodations.\n", - "\n", - "--- Conversation Turn 2 ---\n", - "\n", - "User: Command(resume='could you recommend a nice hotel in one of the areas and tell me which area it is.')\n", - "\n", - "hotel_advisor: Based on the recommendations, I can suggest two excellent options:\n", - "\n", - "1. The Ritz-Carlton, Aruba - Located in Palm Beach\n", - "- This luxury resort is situated in the vibrant Palm Beach area\n", - "- Known for its exceptional service and amenities\n", - "- Perfect if you want to be close to dining, shopping, and entertainment\n", - "- Features multiple restaurants, a casino, and a world-class spa\n", - "- Located on a pristine stretch of Palm Beach\n", - "\n", - "2. Bucuti & Tara Beach Resort - Located in Eagle Beach\n", - "- An adults-only boutique resort on Eagle Beach\n", - "- Known for being more intimate and peaceful\n", - "- Award-winning for its sustainability practices\n", - "- Perfect for a romantic getaway or peaceful vacation\n", - "- Located on one of the most beautiful beaches in the Caribbean\n", - "\n", - "Would you like more specific information about either of these properties or their locations?\n", - "\n", - "--- Conversation Turn 3 ---\n", - "\n", - "User: Command(resume='i like the first one. could you recommend something to do near the hotel?')\n", - "\n", - "travel_advisor: Near the Ritz-Carlton in Palm Beach, here are some highly recommended activities:\n", - "\n", - "1. Visit the Palm Beach Plaza Mall - Just a short walk from the hotel, featuring shopping, dining, and entertainment\n", - "2. Try your luck at the Stellaris Casino - It's right in the Ritz-Carlton\n", - "3. Take a sunset sailing cruise - Many depart from the nearby pier\n", - "4. Visit the California Lighthouse - A scenic landmark just north of Palm Beach\n", - "5. Enjoy water sports at Palm Beach:\n", - " - Jet skiing\n", - " - Parasailing\n", - " - Snorkeling\n", - " - Stand-up paddleboarding\n", - "\n", - "Would you like more specific information about any of these activities or would you like to know about other options in the area?\n" - ] - } - ], - "source": [ - "import uuid\n", - "\n", - "thread_config = {\"configurable\": {\"thread_id\": str(uuid.uuid4())}}\n", - "\n", - "inputs = [\n", - " # 1st round of conversation,\n", - " {\n", - " \"messages\": [\n", - " {\"role\": \"user\", \"content\": \"i wanna go somewhere warm in the caribbean\"}\n", - " ]\n", - " },\n", - " # Since we're using `interrupt`, we'll need to resume using the Command primitive.\n", - " # 2nd round of conversation,\n", - " Command(\n", - " resume=\"could you recommend a nice hotel in one of the areas and tell me which area it is.\"\n", - " ),\n", - " # 3rd round of conversation,\n", - " Command(\n", - " resume=\"i like the first one. could you recommend something to do near the hotel?\"\n", - " ),\n", - "]\n", - "\n", - "for idx, user_input in enumerate(inputs):\n", - " print()\n", - " print(f\"--- Conversation Turn {idx + 1} ---\")\n", - " print()\n", - " print(f\"User: {user_input}\")\n", - " print()\n", - " for update in graph.stream(\n", - " user_input,\n", - " config=thread_config,\n", - " stream_mode=\"updates\",\n", - " ):\n", - " for node_id, value in update.items():\n", - " if isinstance(value, dict) and value.get(\"messages\", []):\n", - " last_message = value[\"messages\"][-1]\n", - " if isinstance(last_message, dict) or last_message.type != \"ai\":\n", - " continue\n", - " print(f\"{node_id}: {last_message.content}\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/multi-agent-network.ipynb b/docs/docs/how-tos/multi-agent-network.ipynb deleted file mode 100644 index 1805e9b6c..000000000 --- a/docs/docs/how-tos/multi-agent-network.ipynb +++ /dev/null @@ -1,751 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "87684b48-150e-4e15-b0a5-a9dd7851f8fb", - "metadata": {}, - "source": [ - "# How to build a multi-agent network" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "2c65639c-9705-49f1-840a-370718852e98", - "metadata": {}, - "source": [ - "!!! info \"Prerequisites\" \n", - " This guide assumes familiarity with the following:\n", - "\n", - " - [How to implement handoffs between agents](../agent-handoffs)\n", - " - [Multi-agent systems](../../concepts/multi_agent)\n", - " - [Command](../../concepts/low_level/#command)\n", - " - [LangGraph Glossary](../../concepts/low_level/)\n", - "\n", - "In this how-to guide we will demonstrate how to implement a [multi-agent network](../../concepts/multi_agent#network) architecture where each agent can communicate with every other agent (many-to-many connections) and can decide which agent to call next. Individual agents will be defined as graph nodes.\n", - "\n", - "To implement communication between the agents, we will be using [handoffs](../agent-handoffs):\n", - "\n", - "```python\n", - "def agent(state) -> Command[Literal[\"agent\", \"another_agent\"]]:\n", - " # the condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.\n", - " goto = get_next_agent(...) # 'agent' / 'another_agent'\n", - " return Command(\n", - " # Specify which agent to call next\n", - " goto=goto,\n", - " # Update the graph state\n", - " update={\"my_state_key\": \"my_state_value\"}\n", - " )\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "faaa4444-cd06-4813-b9ca-c9700fe12cb7", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "05038da0-31df-4066-a1a4-c4ccb5db4d3a", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain-anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "0bcff5d4-130e-426d-9285-40d0f72c7cd3", - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "ANTHROPIC_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "c3ec6e48-85dc-4905-ba50-985e5d4788e6", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "id": "4a53f304-3709-4df7-8714-1ca61e615743", - "metadata": {}, - "source": [ - "## Using a custom agent implementation" - ] - }, - { - "cell_type": "markdown", - "id": "34cd131b-f0c2-4b69-887f-2cbd5afb14a7", - "metadata": {}, - "source": [ - "In this example we will build a team of travel assistant agents that can communicate with each other via handoffs.\n", - "\n", - "We will create 2 agents:\n", - "\n", - "* `travel_advisor`: can help with travel destination recommendations. Can ask `hotel_advisor` for help.\n", - "* `hotel_advisor`: can help with hotel recommendations. Can ask `travel_advisor` for help.\n", - "\n", - "This is a fully-connected network - every agent can talk to any other agent. \n", - "\n", - "Each agent will have a corresponding node function that can conditionally return a `Command` object (the handoff). The node function will use an LLM with a system prompt and a tool that lets it signal when it needs to hand off to another agent. If the LLM responds with the tool calls, we will return a `Command(goto=)`.\n", - "\n", - "> **Note**: while we're using tools for the LLM to signal that it needs a handoff, the condition for the handoff can be anything: a specific response text from the LLM, structured output from the LLM, any other custom logic, etc.\n", - "\n", - "Now, let's define our agent nodes and graph!" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "8a3f270f-4894-4a2d-98cd-e855353e3e0c", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from typing_extensions import Literal\n", - "\n", - "from langchain_core.messages import ToolMessage\n", - "from langchain_core.tools import tool\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langgraph.graph import MessagesState, StateGraph, START\n", - "from langgraph.types import Command\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-latest\")\n", - "\n", - "\n", - "# Define a helper for each of the agent nodes to call\n", - "\n", - "\n", - "@tool\n", - "def transfer_to_travel_advisor():\n", - " \"\"\"Ask travel advisor for help.\"\"\"\n", - " # This tool is not returning anything: we're just using it\n", - " # as a way for LLM to signal that it needs to hand off to another agent\n", - " # (See the paragraph above)\n", - " return\n", - "\n", - "\n", - "@tool\n", - "def transfer_to_hotel_advisor():\n", - " \"\"\"Ask hotel advisor for help.\"\"\"\n", - " return\n", - "\n", - "\n", - "def travel_advisor(\n", - " state: MessagesState,\n", - ") -> Command[Literal[\"hotel_advisor\", \"__end__\"]]:\n", - " system_prompt = (\n", - " \"You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). \"\n", - " \"If you need hotel recommendations, ask 'hotel_advisor' for help.\"\n", - " )\n", - " messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n", - " ai_msg = model.bind_tools([transfer_to_hotel_advisor]).invoke(messages)\n", - " # If there are tool calls, the LLM needs to hand off to another agent\n", - " if len(ai_msg.tool_calls) > 0:\n", - " tool_call_id = ai_msg.tool_calls[-1][\"id\"]\n", - " # NOTE: it's important to insert a tool message here because LLM providers are expecting\n", - " # all AI messages to be followed by a corresponding tool result message\n", - " tool_msg = {\n", - " \"role\": \"tool\",\n", - " \"content\": \"Successfully transferred\",\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(goto=\"hotel_advisor\", update={\"messages\": [ai_msg, tool_msg]})\n", - "\n", - " # If the expert has an answer, return it directly to the user\n", - " return {\"messages\": [ai_msg]}\n", - "\n", - "\n", - "def hotel_advisor(\n", - " state: MessagesState,\n", - ") -> Command[Literal[\"travel_advisor\", \"__end__\"]]:\n", - " system_prompt = (\n", - " \"You are a hotel expert that can provide hotel recommendations for a given destination. \"\n", - " \"If you need help picking travel destinations, ask 'travel_advisor' for help.\"\n", - " )\n", - " messages = [{\"role\": \"system\", \"content\": system_prompt}] + state[\"messages\"]\n", - " ai_msg = model.bind_tools([transfer_to_travel_advisor]).invoke(messages)\n", - " # If there are tool calls, the LLM needs to hand off to another agent\n", - " if len(ai_msg.tool_calls) > 0:\n", - " tool_call_id = ai_msg.tool_calls[-1][\"id\"]\n", - " # NOTE: it's important to insert a tool message here because LLM providers are expecting\n", - " # all AI messages to be followed by a corresponding tool result message\n", - " tool_msg = {\n", - " \"role\": \"tool\",\n", - " \"content\": \"Successfully transferred\",\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(goto=\"travel_advisor\", update={\"messages\": [ai_msg, tool_msg]})\n", - "\n", - " # If the expert has an answer, return it directly to the user\n", - " return {\"messages\": [ai_msg]}\n", - "\n", - "\n", - "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"travel_advisor\", travel_advisor)\n", - "builder.add_node(\"hotel_advisor\", hotel_advisor)\n", - "# we'll always start with a general travel advisor\n", - "builder.add_edge(START, \"travel_advisor\")\n", - "\n", - "graph = builder.compile()\n", - "\n", - "from IPython.display import display, Image\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "af856e1b-41fc-4041-8cbf-3818a60088e0", - "metadata": {}, - "source": [ - "First, let's invoke it with a generic input:" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "058f3d96-534f-4b97-afb3-799ba81224ea", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import convert_to_messages\n", - "\n", - "\n", - "def pretty_print_messages(update):\n", - " if isinstance(update, tuple):\n", - " ns, update = update\n", - " # skip parent graph updates in the printouts\n", - " if len(ns) == 0:\n", - " return\n", - "\n", - " graph_id = ns[-1].split(\":\")[0]\n", - " print(f\"Update from subgraph {graph_id}:\")\n", - " print(\"\\n\")\n", - "\n", - " for node_name, node_update in update.items():\n", - " print(f\"Update from node {node_name}:\")\n", - " print(\"\\n\")\n", - "\n", - " for m in convert_to_messages(node_update[\"messages\"]):\n", - " m.pretty_print()\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "26a0d4df-ff99-40f0-92a8-0b3f2c591040", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from node travel_advisor:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I'd be happy to help you plan a Caribbean vacation! The Caribbean is perfect for warm weather getaways. Let me suggest some fantastic destinations:\n", - "\n", - "1. Dominican Republic\n", - "- Known for beautiful beaches, all-inclusive resorts, and tropical climate\n", - "- Popular areas include Punta Cana and Puerto Plata\n", - "- Great mix of beaches, culture, and activities\n", - "\n", - "2. Jamaica\n", - "- Famous for its laid-back atmosphere and beautiful beaches\n", - "- Popular spots include Montego Bay, Negril, and Ocho Rios\n", - "- Known for reggae music, delicious cuisine, and water sports\n", - "\n", - "3. Bahamas\n", - "- Crystal clear waters and stunning beaches\n", - "- Perfect for island hopping\n", - "- Great for water activities and swimming with pigs at Pig Beach\n", - "\n", - "4. Turks and Caicos\n", - "- Pristine beaches and luxury resorts\n", - "- Excellent for snorkeling and diving\n", - "- More peaceful and less crowded than some other Caribbean destinations\n", - "\n", - "5. Aruba\n", - "- Known for constant sunny weather and minimal rainfall\n", - "- Beautiful white sand beaches\n", - "- Great shopping and dining options\n", - "\n", - "Would you like me to provide more specific information about any of these destinations? Also, if you'd like hotel recommendations for any of these locations, I can transfer you to our hotel advisor for specific accommodation suggestions. Just let me know which destination interests you most!\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"messages\": [(\"user\", \"i wanna go somewhere warm in the caribbean\")]}\n", - "):\n", - " pretty_print_messages(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "997ea9aa-36ee-40a1-a5fc-b44a079786a9", - "metadata": {}, - "source": [ - "You can see that in this case only the first agent (`travel_advisor`) ran. Let's now ask for more recommendations:" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "68a547d4-0a15-43bd-aeed-c9ba1dfe388f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from node travel_advisor:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you with a Caribbean destination recommendation! Given the vast number of beautiful Caribbean islands, I'll recommend one popular destination: the Dominican Republic, specifically Punta Cana. It offers pristine beaches, warm weather year-round, crystal-clear waters, and excellent resorts.\\n\\nLet me get some hotel recommendations for Punta Cana by consulting our hotel advisor.\", 'type': 'text'}, {'id': 'toolu_01B9djUstpDKHVSy3o3rfzsG', 'input': {}, 'name': 'transfer_to_hotel_advisor', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_hotel_advisor (toolu_01B9djUstpDKHVSy3o3rfzsG)\n", - " Call ID: toolu_01B9djUstpDKHVSy3o3rfzsG\n", - " Args:\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "\n", - "Successfully transferred\n", - "\n", - "\n", - "Update from node hotel_advisor:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "For Punta Cana, here are some top hotel recommendations:\n", - "\n", - "1. Hyatt Zilara Cap Cana - Adults-only, all-inclusive luxury resort with pristine beachfront location, multiple pools, and upscale dining options.\n", - "\n", - "2. Hard Rock Hotel & Casino Punta Cana - Perfect for entertainment lovers, featuring 13 pools, 9 restaurants, a casino, and extensive amenities.\n", - "\n", - "3. Excellence Punta Cana - Adults-only, all-inclusive resort known for its romantic atmosphere and excellent service.\n", - "\n", - "4. Secrets Cap Cana Resort & Spa - Sophisticated adults-only resort with beautiful swim-out suites and gourmet dining options.\n", - "\n", - "5. The Reserve at Paradisus Palma Real - Family-friendly luxury resort with dedicated family concierge, kids' activities, and beautiful pools.\n", - "\n", - "These resorts all offer:\n", - "- Direct beach access\n", - "- Multiple restaurants\n", - "- Swimming pools\n", - "- Spa facilities\n", - "- High-quality accommodations\n", - "\n", - "Would you like more specific information about any of these hotels or would you prefer to explore hotels in a different Caribbean destination?\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\n", - " \"messages\": [\n", - " (\n", - " \"user\",\n", - " \"i wanna go somewhere warm in the caribbean. pick one destination and give me hotel recommendations\",\n", - " )\n", - " ]\n", - " }\n", - "):\n", - " pretty_print_messages(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "c1c66f91-39b0-4ed2-91e8-6daf6d124f47", - "metadata": {}, - "source": [ - "Voila - `travel_advisor` picks a destination and then makes a decision to call `hotel_advisor` for more info!" - ] - }, - { - "cell_type": "markdown", - "id": "5f9ff04a-f2c6-408c-a332-1346a96d7f61", - "metadata": {}, - "source": [ - "## Using with a prebuilt ReAct agent" - ] - }, - { - "cell_type": "markdown", - "id": "1b560c3c-fa17-4879-a40f-147fc483c41c", - "metadata": {}, - "source": [ - "Let's now see how we can implement the same team of travel agents, but give each of the agents some tools to call. We'll be using prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] to implement the agents. First, let's create some of the tools that the agents will be using:" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "7e31f258-ec28-4020-b86d-c91dfa9a3bfc", - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "from typing_extensions import Literal\n", - "\n", - "\n", - "@tool\n", - "def get_travel_recommendations():\n", - " \"\"\"Get recommendation for travel destinations\"\"\"\n", - " return random.choice([\"aruba\", \"turks and caicos\"])\n", - "\n", - "\n", - "@tool\n", - "def get_hotel_recommendations(location: Literal[\"aruba\", \"turks and caicos\"]):\n", - " \"\"\"Get hotel recommendations for a given destination.\"\"\"\n", - " return {\n", - " \"aruba\": [\n", - " \"The Ritz-Carlton, Aruba (Palm Beach)\"\n", - " \"Bucuti & Tara Beach Resort (Eagle Beach)\"\n", - " ],\n", - " \"turks and caicos\": [\"Grace Bay Club\", \"COMO Parrot Cay\"],\n", - " }[location]" - ] - }, - { - "cell_type": "markdown", - "id": "2b64455a-8b28-42f0-90ac-a0ab92a433a3", - "metadata": {}, - "source": [ - "Let's also write a helper to create a handoff tool. See [this how-to guide](../agent-handoffs#implementing-handoffs-using-tools) for a more in-depth walkthrough of how to make a handoff tool." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "3b82280f-d171-4338-8ead-d1b3029ad9fb", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from langchain_core.tools import tool\n", - "from langchain_core.tools.base import InjectedToolCallId\n", - "from langgraph.prebuilt import InjectedState\n", - "\n", - "\n", - "def make_handoff_tool(*, agent_name: str):\n", - " \"\"\"Create a tool that can return handoff via a Command\"\"\"\n", - " tool_name = f\"transfer_to_{agent_name}\"\n", - "\n", - " @tool(tool_name)\n", - " def handoff_to_agent(\n", - " state: Annotated[dict, InjectedState],\n", - " tool_call_id: Annotated[str, InjectedToolCallId],\n", - " ):\n", - " \"\"\"Ask another agent for help.\"\"\"\n", - " tool_message = {\n", - " \"role\": \"tool\",\n", - " \"content\": f\"Successfully transferred to {agent_name}\",\n", - " \"name\": tool_name,\n", - " \"tool_call_id\": tool_call_id,\n", - " }\n", - " return Command(\n", - " # navigate to another agent node in the PARENT graph\n", - " goto=agent_name,\n", - " graph=Command.PARENT,\n", - " # This is the state update that the agent `agent_name` will see when it is invoked.\n", - " # We're passing agent's FULL internal message history AND adding a tool message to make sure\n", - " # the resulting chat history is valid.\n", - " update={\"messages\": state[\"messages\"] + [tool_message]},\n", - " )\n", - "\n", - " return handoff_to_agent" - ] - }, - { - "cell_type": "markdown", - "id": "93dbc3bd-27b9-4d79-b5dd-be592bc50f74", - "metadata": {}, - "source": [ - "Now let's define our agent nodes and combine them into a graph:" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "b638d6c4-3de6-4921-980c-2df1bd1cc9c7", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from langgraph.graph import MessagesState, StateGraph, START, END\n", - "from langgraph.prebuilt import create_react_agent\n", - "from langgraph.types import Command\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-latest\")\n", - "\n", - "# Define travel advisor ReAct agent\n", - "travel_advisor_tools = [\n", - " get_travel_recommendations,\n", - " make_handoff_tool(agent_name=\"hotel_advisor\"),\n", - "]\n", - "travel_advisor = create_react_agent(\n", - " model,\n", - " travel_advisor_tools,\n", - " prompt=(\n", - " \"You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). \"\n", - " \"If you need hotel recommendations, ask 'hotel_advisor' for help. \"\n", - " \"You MUST include human-readable response before transferring to another agent.\"\n", - " ),\n", - ")\n", - "\n", - "\n", - "def call_travel_advisor(\n", - " state: MessagesState,\n", - ") -> Command[Literal[\"hotel_advisor\", \"__end__\"]]:\n", - " # You can also add additional logic like changing the input to the agent / output from the agent, etc.\n", - " # NOTE: we're invoking the ReAct agent with the full history of messages in the state\n", - " return travel_advisor.invoke(state)\n", - "\n", - "\n", - "# Define hotel advisor ReAct agent\n", - "hotel_advisor_tools = [\n", - " get_hotel_recommendations,\n", - " make_handoff_tool(agent_name=\"travel_advisor\"),\n", - "]\n", - "hotel_advisor = create_react_agent(\n", - " model,\n", - " hotel_advisor_tools,\n", - " prompt=(\n", - " \"You are a hotel expert that can provide hotel recommendations for a given destination. \"\n", - " \"If you need help picking travel destinations, ask 'travel_advisor' for help.\"\n", - " \"You MUST include human-readable response before transferring to another agent.\"\n", - " ),\n", - ")\n", - "\n", - "\n", - "def call_hotel_advisor(\n", - " state: MessagesState,\n", - ") -> Command[Literal[\"travel_advisor\", \"__end__\"]]:\n", - " return hotel_advisor.invoke(state)\n", - "\n", - "\n", - "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"travel_advisor\", call_travel_advisor)\n", - "builder.add_node(\"hotel_advisor\", call_hotel_advisor)\n", - "# we'll always start with a general travel advisor\n", - "builder.add_edge(START, \"travel_advisor\")\n", - "\n", - "graph = builder.compile()\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "id": "7132e2c0-d937-4325-a30e-e715c5304fe0", - "metadata": {}, - "source": [ - "Let's test it out using the same input as our original multi-agent system:" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "29b47c57-ad05-4f10-83bf-c3ff6ff8eb93", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Update from subgraph travel_advisor:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you find a warm Caribbean destination and get some hotel recommendations for you.\\n\\nLet me first get some travel recommendations for Caribbean destinations.\", 'type': 'text'}, {'id': 'toolu_01GGDP6XSoJZFCYVA9Emhg89', 'input': {}, 'name': 'get_travel_recommendations', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " get_travel_recommendations (toolu_01GGDP6XSoJZFCYVA9Emhg89)\n", - " Call ID: toolu_01GGDP6XSoJZFCYVA9Emhg89\n", - " Args:\n", - "\n", - "\n", - "Update from subgraph travel_advisor:\n", - "\n", - "\n", - "Update from node tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_travel_recommendations\n", - "\n", - "turks and caicos\n", - "\n", - "\n", - "Update from subgraph travel_advisor:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'Based on the recommendations, I suggest Turks and Caicos! This beautiful British Overseas Territory is known for its stunning white-sand beaches, crystal-clear turquoise waters, and perfect warm weather year-round. The main island, Providenciales (often called \"Provo\"), is home to the famous Grace Bay Beach, consistently rated one of the world\\'s best beaches.\\n\\nNow, let me connect you with our hotel advisor to get some specific hotel recommendations for Turks and Caicos.', 'type': 'text'}, {'id': 'toolu_01JbPSSbTdbWSPNPwsKxifKR', 'input': {}, 'name': 'transfer_to_hotel_advisor', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " transfer_to_hotel_advisor (toolu_01JbPSSbTdbWSPNPwsKxifKR)\n", - " Call ID: toolu_01JbPSSbTdbWSPNPwsKxifKR\n", - " Args:\n", - "\n", - "\n", - "Update from subgraph hotel_advisor:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': 'Let me get some hotel recommendations for Turks and Caicos:', 'type': 'text'}, {'id': 'toolu_01JfcmUUmpdiYEFXaDFEkh1G', 'input': {'location': 'turks and caicos'}, 'name': 'get_hotel_recommendations', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " get_hotel_recommendations (toolu_01JfcmUUmpdiYEFXaDFEkh1G)\n", - " Call ID: toolu_01JfcmUUmpdiYEFXaDFEkh1G\n", - " Args:\n", - " location: turks and caicos\n", - "\n", - "\n", - "Update from subgraph hotel_advisor:\n", - "\n", - "\n", - "Update from node tools:\n", - "\n", - "\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_hotel_recommendations\n", - "\n", - "[\"Grace Bay Club\", \"COMO Parrot Cay\"]\n", - "\n", - "\n", - "Update from subgraph hotel_advisor:\n", - "\n", - "\n", - "Update from node agent:\n", - "\n", - "\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Here are two excellent hotel options in Turks and Caicos:\n", - "\n", - "1. Grace Bay Club: This luxury resort is located on the world-famous Grace Bay Beach. It offers elegant accommodations, multiple swimming pools, a spa, and several dining options. The resort is divided into different sections including adults-only and family-friendly areas.\n", - "\n", - "2. COMO Parrot Cay: This exclusive private island resort offers the ultimate luxury escape. It features pristine beaches, world-class spa facilities, and exceptional dining experiences. The resort is known for its serene atmosphere and excellent service.\n", - "\n", - "Would you like more specific information about either of these properties?\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\n", - " \"messages\": [\n", - " (\n", - " \"user\",\n", - " \"i wanna go somewhere warm in the caribbean. pick one destination and give me hotel recommendations\",\n", - " )\n", - " ]\n", - " },\n", - " subgraphs=True,\n", - "):\n", - " pretty_print_messages(chunk)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/multi_agent.ipynb b/docs/docs/how-tos/multi_agent.ipynb new file mode 100644 index 000000000..2f5dc2af8 --- /dev/null +++ b/docs/docs/how-tos/multi_agent.ipynb @@ -0,0 +1,657 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "34d3d54e-9a2b-481e-bccd-74aca7a53f9a", + "metadata": {}, + "source": [ + "# Build multi-agent systems" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3f0b4f70-f14e-4026-82c0-874786789ee8", + "metadata": {}, + "source": [ + "A single agent might struggle if it needs to specialize in multiple domains or manage many tools. To tackle this, you can break your agent into smaller, independent agents and composing them into a [multi-agent system](../../concepts/multi_agent).\n", + "\n", + "In multi-agent systems, agents need to communicate between each other. They do so via [handoffs](#handoffs) — a primitive that describes which agent to hand control to and the payload to send to that agent.\n", + "\n", + "This guide covers the following:\n", + "\n", + "* implementing [handoffs](#handoffs) between agents\n", + "* using handoffs and the prebuilt [agent](../../agents/agents) to [build a custom multi-agent system](#build-a-multi-agent-system)\n", + "\n", + "To get started with building multi-agent systems, check out LangGraph [prebuilt implementations](#prebuilt-implementations) of two of the most popular multi-agent architectures — [supervisor](../../agents/multi-agent#supervisor) and [swarm](../../agents/multi-agent#swarm)." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7d43e110-16fc-4899-97f1-015d5b804b87", + "metadata": {}, + "source": [ + "## Handoffs\n", + "\n", + "To set up communication between the agents in a multi-agent system you can use [**handoffs**](../../concepts/multi_agent#handoffs) — a pattern where one agent *hands off* control to another. Handoffs allow you to specify:\n", + "\n", + "- **destination**: target agent to navigate to (e.g., name of the LangGraph node to go to)\n", + "- **payload**: information to pass to that agent (e.g., state update)\n", + "\n", + "### Create handoffs\n", + "\n", + "To implement handoffs, you can return [`Command`](../command) objects from your agent nodes or tools:\n", + "\n", + "```python\n", + "from typing import Annotated\n", + "from langchain_core.tools import tool, InjectedToolCallId\n", + "from langgraph.prebuilt import create_react_agent, InjectedState\n", + "from langgraph.graph import StateGraph, START, MessagesState\n", + "from langgraph.types import Command\n", + "\n", + "def create_handoff_tool(*, agent_name: str, description: str | None = None):\n", + " name = f\"transfer_to_{agent_name}\"\n", + " description = description or f\"Transfer to {agent_name}\"\n", + "\n", + " @tool(name, description=description)\n", + " def handoff_tool(\n", + " # highlight-next-line\n", + " state: Annotated[MessagesState, InjectedState], # (1)!\n", + " # highlight-next-line\n", + " tool_call_id: Annotated[str, InjectedToolCallId],\n", + " ) -> Command:\n", + " tool_message = {\n", + " \"role\": \"tool\",\n", + " \"content\": f\"Successfully transferred to {agent_name}\",\n", + " \"name\": name,\n", + " \"tool_call_id\": tool_call_id,\n", + " }\n", + " return Command( # (2)!\n", + " # highlight-next-line\n", + " goto=agent_name, # (3)!\n", + " # highlight-next-line\n", + " update={\"messages\": state[\"messages\"] + [tool_message]}, # (4)!\n", + " # highlight-next-line\n", + " graph=Command.PARENT, # (5)!\n", + " )\n", + " return handoff_tool\n", + "```\n", + "\n", + "1. Access the [state](../../concepts/low_level#state) of the agent that is calling the handoff tool using the [InjectedState][langgraph.prebuilt.InjectedState] annotation. See [this guide](../tool-calling/#read-state) for more information.\n", + "2. The `Command` primitive allows specifying a state update and a node transition as a single operation, making it useful for implementing handoffs.\n", + "3. Name of the agent or node to hand off to.\n", + "4. Take the agent's messages and **add** them to the parent's **state** as part of the handoff. The next agent will see the parent state.\n", + "5. Indicate to LangGraph that we need to navigate to agent node in a **parent** multi-agent graph.\n", + "\n", + "!!! tip\n", + "\n", + " If you want to use tools that return `Command`, you can either use prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] components, or implement your own tool-executing node that collects `Command` objects returned by the tools and returns a list of them, e.g.:\n", + " \n", + " ```python\n", + " def call_tools(state):\n", + " ...\n", + " commands = [tools_by_name[tool_call[\"name\"]].invoke(tool_call) for tool_call in tool_calls]\n", + " return commands\n", + " ```\n", + "\n", + "!!! Important\n", + "\n", + " This handoff implementation assumes that:\n", + " \n", + " - each agent receives overall message history (across all agents) in the multi-agent system as its input. If you want more control over agent inputs, see [this section](#control-agent-inputs)\n", + " - each agent outputs its internal messages history to the overall message history of the multi-agent system. If you want more control over **how agent outputs are added**, wrap the agent in a separate node function:\n", + "\n", + " ```python\n", + " def call_hotel_assistant(state):\n", + " # return agent's final response,\n", + " # excluding inner monologue\n", + " response = hotel_assistant.invoke(state)\n", + " # highlight-next-line\n", + " return {\"messages\": response[\"messages\"][-1]}\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "3956f12d-285a-4799-a0a5-db13def58a15", + "metadata": {}, + "source": [ + "### Control agent inputs\n", + "\n", + "You can use the [`Send()`][langgraph.types.Send] primitive to directly send data to the worker agents during the handoff. For example, you can request that the calling agent populate a task description for the next agent:\n", + "\n", + "```python\n", + "\n", + "from typing import Annotated\n", + "from langchain_core.tools import tool, InjectedToolCallId\n", + "from langgraph.prebuilt import InjectedState\n", + "from langgraph.graph import StateGraph, START, MessagesState\n", + "# highlight-next-line\n", + "from langgraph.types import Command, Send\n", + "\n", + "def create_task_description_handoff_tool(\n", + " *, agent_name: str, description: str | None = None\n", + "):\n", + " name = f\"transfer_to_{agent_name}\"\n", + " description = description or f\"Ask {agent_name} for help.\"\n", + "\n", + " @tool(name, description=description)\n", + " def handoff_tool(\n", + " # this is populated by the calling agent\n", + " task_description: Annotated[\n", + " str,\n", + " \"Description of what the next agent should do, including all of the relevant context.\",\n", + " ],\n", + " # these parameters are ignored by the LLM\n", + " state: Annotated[MessagesState, InjectedState],\n", + " ) -> Command:\n", + " task_description_message = {\"role\": \"user\", \"content\": task_description}\n", + " agent_input = {**state, \"messages\": [task_description_message]}\n", + " return Command(\n", + " # highlight-next-line\n", + " goto=[Send(agent_name, agent_input)],\n", + " graph=Command.PARENT,\n", + " )\n", + "\n", + " return handoff_tool\n", + "```\n", + "\n", + "See the multi-agent [supervisor](../tutorials/agent_supervisor.ipynb#4-create-delegation-tasks) tutorial for a full example of using [`Send()`][langgraph.types.Send] in handoffs." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "21511f57-7bf3-4223-9a17-ce9fc84c40ab", + "metadata": {}, + "source": [ + "## Build a multi-agent system\n", + "\n", + "You can use handoffs in any agents built with LangGraph. We recommend using the prebuilt [agent](../../agents/overview) or [`ToolNode`](../tool-calling#use-prebuilt-toolnode), as they natively support handoffs tools returning `Command`. Below is an example of how you can implement a multi-agent system for booking travel using handoffs:\n", + "\n", + "```python\n", + "from langgraph.prebuilt import create_react_agent\n", + "from langgraph.graph import StateGraph, START, MessagesState\n", + "\n", + "def create_handoff_tool(*, agent_name: str, description: str | None = None):\n", + " # same implementation as above\n", + " ...\n", + " return Command(...)\n", + "\n", + "# Handoffs\n", + "transfer_to_hotel_assistant = create_handoff_tool(agent_name=\"hotel_assistant\")\n", + "transfer_to_flight_assistant = create_handoff_tool(agent_name=\"flight_assistant\")\n", + "\n", + "# Define agents\n", + "flight_assistant = create_react_agent(\n", + " model=\"anthropic:claude-3-5-sonnet-latest\",\n", + " # highlight-next-line\n", + " tools=[..., transfer_to_hotel_assistant],\n", + " # highlight-next-line\n", + " name=\"flight_assistant\"\n", + ")\n", + "hotel_assistant = create_react_agent(\n", + " model=\"anthropic:claude-3-5-sonnet-latest\",\n", + " # highlight-next-line\n", + " tools=[..., transfer_to_flight_assistant],\n", + " # highlight-next-line\n", + " name=\"hotel_assistant\"\n", + ")\n", + "\n", + "# Define multi-agent graph\n", + "multi_agent_graph = (\n", + " StateGraph(MessagesState)\n", + " # highlight-next-line\n", + " .add_node(flight_assistant)\n", + " # highlight-next-line\n", + " .add_node(hotel_assistant)\n", + " .add_edge(START, \"flight_assistant\")\n", + " .compile()\n", + ")\n", + "```\n", + "\n", + "??? example \"Full example: Multi-agent system for booking travel\"\n", + "\n", + " ```python\n", + " from typing import Annotated\n", + " from langchain_core.messages import convert_to_messages\n", + " from langchain_core.tools import tool, InjectedToolCallId\n", + " from langgraph.prebuilt import create_react_agent, InjectedState\n", + " from langgraph.graph import StateGraph, START, MessagesState\n", + " from langgraph.types import Command\n", + " \n", + " # We'll use `pretty_print_messages` helper to render the streamed agent outputs nicely\n", + " \n", + " def pretty_print_message(message, indent=False):\n", + " pretty_message = message.pretty_repr(html=True)\n", + " if not indent:\n", + " print(pretty_message)\n", + " return\n", + " \n", + " indented = \"\\n\".join(\"\\t\" + c for c in pretty_message.split(\"\\n\"))\n", + " print(indented)\n", + " \n", + " \n", + " def pretty_print_messages(update, last_message=False):\n", + " is_subgraph = False\n", + " if isinstance(update, tuple):\n", + " ns, update = update\n", + " # skip parent graph updates in the printouts\n", + " if len(ns) == 0:\n", + " return\n", + " \n", + " graph_id = ns[-1].split(\":\")[0]\n", + " print(f\"Update from subgraph {graph_id}:\")\n", + " print(\"\\n\")\n", + " is_subgraph = True\n", + " \n", + " for node_name, node_update in update.items():\n", + " update_label = f\"Update from node {node_name}:\"\n", + " if is_subgraph:\n", + " update_label = \"\\t\" + update_label\n", + " \n", + " print(update_label)\n", + " print(\"\\n\")\n", + " \n", + " messages = convert_to_messages(node_update[\"messages\"])\n", + " if last_message:\n", + " messages = messages[-1:]\n", + " \n", + " for m in messages:\n", + " pretty_print_message(m, indent=is_subgraph)\n", + " print(\"\\n\")\n", + "\n", + "\n", + " def create_handoff_tool(*, agent_name: str, description: str | None = None):\n", + " name = f\"transfer_to_{agent_name}\"\n", + " description = description or f\"Transfer to {agent_name}\"\n", + " \n", + " @tool(name, description=description)\n", + " def handoff_tool(\n", + " # highlight-next-line\n", + " state: Annotated[MessagesState, InjectedState], # (1)!\n", + " # highlight-next-line\n", + " tool_call_id: Annotated[str, InjectedToolCallId],\n", + " ) -> Command:\n", + " tool_message = {\n", + " \"role\": \"tool\",\n", + " \"content\": f\"Successfully transferred to {agent_name}\",\n", + " \"name\": name,\n", + " \"tool_call_id\": tool_call_id,\n", + " }\n", + " return Command( # (2)!\n", + " # highlight-next-line\n", + " goto=agent_name, # (3)!\n", + " # highlight-next-line\n", + " update={\"messages\": state[\"messages\"] + [tool_message]}, # (4)!\n", + " # highlight-next-line\n", + " graph=Command.PARENT, # (5)!\n", + " )\n", + " return handoff_tool\n", + " \n", + " # Handoffs\n", + " transfer_to_hotel_assistant = create_handoff_tool(\n", + " agent_name=\"hotel_assistant\",\n", + " description=\"Transfer user to the hotel-booking assistant.\",\n", + " )\n", + " transfer_to_flight_assistant = create_handoff_tool(\n", + " agent_name=\"flight_assistant\",\n", + " description=\"Transfer user to the flight-booking assistant.\",\n", + " )\n", + " \n", + " # Simple agent tools\n", + " def book_hotel(hotel_name: str):\n", + " \"\"\"Book a hotel\"\"\"\n", + " return f\"Successfully booked a stay at {hotel_name}.\"\n", + " \n", + " def book_flight(from_airport: str, to_airport: str):\n", + " \"\"\"Book a flight\"\"\"\n", + " return f\"Successfully booked a flight from {from_airport} to {to_airport}.\"\n", + " \n", + " # Define agents\n", + " flight_assistant = create_react_agent(\n", + " model=\"anthropic:claude-3-5-sonnet-latest\",\n", + " # highlight-next-line\n", + " tools=[book_flight, transfer_to_hotel_assistant],\n", + " prompt=\"You are a flight booking assistant\",\n", + " # highlight-next-line\n", + " name=\"flight_assistant\"\n", + " )\n", + " hotel_assistant = create_react_agent(\n", + " model=\"anthropic:claude-3-5-sonnet-latest\",\n", + " # highlight-next-line\n", + " tools=[book_hotel, transfer_to_flight_assistant],\n", + " prompt=\"You are a hotel booking assistant\",\n", + " # highlight-next-line\n", + " name=\"hotel_assistant\"\n", + " )\n", + " \n", + " # Define multi-agent graph\n", + " multi_agent_graph = (\n", + " StateGraph(MessagesState)\n", + " .add_node(flight_assistant)\n", + " .add_node(hotel_assistant)\n", + " .add_edge(START, \"flight_assistant\")\n", + " .compile()\n", + " )\n", + " \n", + " # Run the multi-agent graph\n", + " for chunk in multi_agent_graph.stream(\n", + " {\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"book a flight from BOS to JFK and a stay at McKittrick Hotel\"\n", + " }\n", + " ]\n", + " },\n", + " # highlight-next-line\n", + " subgraphs=True\n", + " ):\n", + " pretty_print_messages(chunk)\n", + " ```\n", + "\n", + " 1. Access agent's state\n", + " 2. The `Command` primitive allows specifying a state update and a node transition as a single operation, making it useful for implementing handoffs.\n", + " 3. Name of the agent or node to hand off to.\n", + " 4. Take the agent's messages and **add** them to the parent's **state** as part of the handoff. The next agent will see the parent state.\n", + " 5. Indicate to LangGraph that we need to navigate to agent node in a **parent** multi-agent graph." + ] + }, + { + "cell_type": "markdown", + "id": "e8314da4-9971-429b-9e70-58b40795de74", + "metadata": {}, + "source": [ + "## Multi-turn conversation\n", + "\n", + "Users might want to engage in a *multi-turn conversation* with one or more agents. To build a system that can handle this, you can create a node that uses an [`interrupt`][langgraph.types.interrupt] to collect user input and routes back to the **active** agent.\n", + "\n", + "The agents can then be implemented as nodes in a graph that executes agent steps and determines the next action:\n", + "\n", + "1. **Wait for user input** to continue the conversation, or \n", + "2. **Route to another agent** (or back to itself, such as in a loop) via a [handoff](#handoffs)\n", + "\n", + "```python\n", + "def human(state) -> Command[Literal[\"agent\", \"another_agent\"]]:\n", + " \"\"\"A node for collecting user input.\"\"\"\n", + " user_input = interrupt(value=\"Ready for user input.\")\n", + "\n", + " # Determine the active agent.\n", + " active_agent = ...\n", + "\n", + " ...\n", + " return Command(\n", + " update={\n", + " \"messages\": [{\n", + " \"role\": \"human\",\n", + " \"content\": user_input,\n", + " }]\n", + " },\n", + " goto=active_agent\n", + " )\n", + "\n", + "def agent(state) -> Command[Literal[\"agent\", \"another_agent\", \"human\"]]:\n", + " # The condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.\n", + " goto = get_next_agent(...) # 'agent' / 'another_agent'\n", + " if goto:\n", + " return Command(goto=goto, update={\"my_state_key\": \"my_state_value\"})\n", + " else:\n", + " return Command(goto=\"human\") # Go to human node\n", + "```\n", + "\n", + "??? example \"Full example: multi-agent system for travel recommendations\"\n", + "\n", + " In this example, we will build a team of travel assistant agents that can communicate with each other via handoffs.\n", + " \n", + " We will create 2 agents:\n", + " \n", + " * travel_advisor: can help with travel destination recommendations. Can ask hotel_advisor for help.\n", + " * hotel_advisor: can help with hotel recommendations. Can ask travel_advisor for help.\n", + "\n", + " ```python\n", + " from langchain_anthropic import ChatAnthropic\n", + " from langgraph.graph import MessagesState, StateGraph, START\n", + " from langgraph.prebuilt import create_react_agent, InjectedState\n", + " from langgraph.types import Command, interrupt\n", + " from langgraph.checkpoint.memory import MemorySaver\n", + " \n", + " \n", + " model = ChatAnthropic(model=\"claude-3-5-sonnet-latest\")\n", + "\n", + " class MultiAgentState(MessagesState):\n", + " last_active_agent: str\n", + " \n", + " \n", + " # Define travel advisor tools and ReAct agent\n", + " travel_advisor_tools = [\n", + " get_travel_recommendations,\n", + " make_handoff_tool(agent_name=\"hotel_advisor\"),\n", + " ]\n", + " travel_advisor = create_react_agent(\n", + " model,\n", + " travel_advisor_tools,\n", + " prompt=(\n", + " \"You are a general travel expert that can recommend travel destinations (e.g. countries, cities, etc). \"\n", + " \"If you need hotel recommendations, ask 'hotel_advisor' for help. \"\n", + " \"You MUST include human-readable response before transferring to another agent.\"\n", + " ),\n", + " )\n", + " \n", + " \n", + " def call_travel_advisor(\n", + " state: MultiAgentState,\n", + " ) -> Command[Literal[\"hotel_advisor\", \"human\"]]:\n", + " # You can also add additional logic like changing the input to the agent / output from the agent, etc.\n", + " # NOTE: we're invoking the ReAct agent with the full history of messages in the state\n", + " response = travel_advisor.invoke(state)\n", + " update = {**response, \"last_active_agent\": \"travel_advisor\"}\n", + " return Command(update=update, goto=\"human\")\n", + " \n", + " \n", + " # Define hotel advisor tools and ReAct agent\n", + " hotel_advisor_tools = [\n", + " get_hotel_recommendations,\n", + " make_handoff_tool(agent_name=\"travel_advisor\"),\n", + " ]\n", + " hotel_advisor = create_react_agent(\n", + " model,\n", + " hotel_advisor_tools,\n", + " prompt=(\n", + " \"You are a hotel expert that can provide hotel recommendations for a given destination. \"\n", + " \"If you need help picking travel destinations, ask 'travel_advisor' for help.\"\n", + " \"You MUST include human-readable response before transferring to another agent.\"\n", + " ),\n", + " )\n", + " \n", + " \n", + " def call_hotel_advisor(\n", + " state: MultiAgentState,\n", + " ) -> Command[Literal[\"travel_advisor\", \"human\"]]:\n", + " response = hotel_advisor.invoke(state)\n", + " update = {**response, \"last_active_agent\": \"hotel_advisor\"}\n", + " return Command(update=update, goto=\"human\")\n", + " \n", + " \n", + " def human_node(\n", + " state: MultiAgentState, config\n", + " ) -> Command[Literal[\"hotel_advisor\", \"travel_advisor\", \"human\"]]:\n", + " \"\"\"A node for collecting user input.\"\"\"\n", + " \n", + " user_input = interrupt(value=\"Ready for user input.\")\n", + " active_agent = state[\"last_active_agent\"]\n", + " \n", + " return Command(\n", + " update={\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"human\",\n", + " \"content\": user_input,\n", + " }\n", + " ]\n", + " },\n", + " goto=active_agent,\n", + " )\n", + " \n", + " \n", + " builder = StateGraph(MultiAgentState)\n", + " builder.add_node(\"travel_advisor\", call_travel_advisor)\n", + " builder.add_node(\"hotel_advisor\", call_hotel_advisor)\n", + " \n", + " # This adds a node to collect human input, which will route\n", + " # back to the active agent.\n", + " builder.add_node(\"human\", human_node)\n", + " \n", + " # We'll always start with a general travel advisor.\n", + " builder.add_edge(START, \"travel_advisor\")\n", + " \n", + " \n", + " checkpointer = MemorySaver()\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " ```\n", + " \n", + " Let's test a multi turn conversation with this application.\n", + "\n", + " ```python\n", + " import uuid\n", + " \n", + " thread_config = {\"configurable\": {\"thread_id\": str(uuid.uuid4())}}\n", + " \n", + " inputs = [\n", + " # 1st round of conversation,\n", + " {\n", + " \"messages\": [\n", + " {\"role\": \"user\", \"content\": \"i wanna go somewhere warm in the caribbean\"}\n", + " ]\n", + " },\n", + " # Since we're using `interrupt`, we'll need to resume using the Command primitive.\n", + " # 2nd round of conversation,\n", + " Command(\n", + " resume=\"could you recommend a nice hotel in one of the areas and tell me which area it is.\"\n", + " ),\n", + " # 3rd round of conversation,\n", + " Command(\n", + " resume=\"i like the first one. could you recommend something to do near the hotel?\"\n", + " ),\n", + " ]\n", + " \n", + " for idx, user_input in enumerate(inputs):\n", + " print()\n", + " print(f\"--- Conversation Turn {idx + 1} ---\")\n", + " print()\n", + " print(f\"User: {user_input}\")\n", + " print()\n", + " for update in graph.stream(\n", + " user_input,\n", + " config=thread_config,\n", + " stream_mode=\"updates\",\n", + " ):\n", + " for node_id, value in update.items():\n", + " if isinstance(value, dict) and value.get(\"messages\", []):\n", + " last_message = value[\"messages\"][-1]\n", + " if isinstance(last_message, dict) or last_message.type != \"ai\":\n", + " continue\n", + " print(f\"{node_id}: {last_message.content}\")\n", + " ```\n", + " \n", + " ```\n", + " --- Conversation Turn 1 ---\n", + " \n", + " User: {'messages': [{'role': 'user', 'content': 'i wanna go somewhere warm in the caribbean'}]}\n", + " \n", + " travel_advisor: Based on the recommendations, Aruba would be an excellent choice for your Caribbean getaway! Aruba is known as \"One Happy Island\" and offers:\n", + " - Year-round warm weather with consistent temperatures around 82°F (28°C)\n", + " - Beautiful white sand beaches like Eagle Beach and Palm Beach\n", + " - Clear turquoise waters perfect for swimming and snorkeling\n", + " - Minimal rainfall and location outside the hurricane belt\n", + " - A blend of Caribbean and Dutch culture\n", + " - Great dining options and nightlife\n", + " - Various water sports and activities\n", + " \n", + " Would you like me to get some specific hotel recommendations in Aruba for your stay? I can transfer you to our hotel advisor who can help with accommodations.\n", + " \n", + " --- Conversation Turn 2 ---\n", + " \n", + " User: Command(resume='could you recommend a nice hotel in one of the areas and tell me which area it is.')\n", + " \n", + " hotel_advisor: Based on the recommendations, I can suggest two excellent options:\n", + " \n", + " 1. The Ritz-Carlton, Aruba - Located in Palm Beach\n", + " - This luxury resort is situated in the vibrant Palm Beach area\n", + " - Known for its exceptional service and amenities\n", + " - Perfect if you want to be close to dining, shopping, and entertainment\n", + " - Features multiple restaurants, a casino, and a world-class spa\n", + " - Located on a pristine stretch of Palm Beach\n", + " \n", + " 2. Bucuti & Tara Beach Resort - Located in Eagle Beach\n", + " - An adults-only boutique resort on Eagle Beach\n", + " - Known for being more intimate and peaceful\n", + " - Award-winning for its sustainability practices\n", + " - Perfect for a romantic getaway or peaceful vacation\n", + " - Located on one of the most beautiful beaches in the Caribbean\n", + " \n", + " Would you like more specific information about either of these properties or their locations?\n", + " \n", + " --- Conversation Turn 3 ---\n", + " \n", + " User: Command(resume='i like the first one. could you recommend something to do near the hotel?')\n", + " \n", + " travel_advisor: Near the Ritz-Carlton in Palm Beach, here are some highly recommended activities:\n", + " \n", + " 1. Visit the Palm Beach Plaza Mall - Just a short walk from the hotel, featuring shopping, dining, and entertainment\n", + " 2. Try your luck at the Stellaris Casino - It's right in the Ritz-Carlton\n", + " 3. Take a sunset sailing cruise - Many depart from the nearby pier\n", + " 4. Visit the California Lighthouse - A scenic landmark just north of Palm Beach\n", + " 5. Enjoy water sports at Palm Beach:\n", + " - Jet skiing\n", + " - Parasailing\n", + " - Snorkeling\n", + " - Stand-up paddleboarding\n", + " \n", + " Would you like more specific information about any of these activities or would you like to know about other options in the area?\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "04d18c63-a0eb-45ac-86dc-0cc5bd683973", + "metadata": {}, + "source": [ + "## Prebuilt implementations" + ] + }, + { + "cell_type": "markdown", + "id": "e0e4ce57-f8de-4f37-836e-c1e1a02dd7b7", + "metadata": {}, + "source": [ + "LangGraph comes with prebuilt implementations of two of the most popular multi-agent architectures:\n", + "\n", + "- [supervisor](../../agents/multi-agent#supervisor) — individual agents are coordinated by a central supervisor agent. The supervisor controls all communication flow and task delegation, making decisions about which agent to invoke based on the current context and task requirements. You can use [`langgraph-supervisor`](https://github.com/langchain-ai/langgraph-supervisor-py) library to create a supervisor multi-agent systems.\n", + "- [swarm](../../agents/multi-agent#supervisor) — agents dynamically hand off control to one another based on their specializations. The system remembers which agent was last active, ensuring that on subsequent interactions, the conversation resumes with that agent. You can use [`langgraph-swarm`](https://github.com/langchain-ai/langgraph-swarm-py) library to create a swarm multi-agent systems." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "langgraph", + "language": "python", + "name": "langgraph" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/how-tos/node-retries.ipynb b/docs/docs/how-tos/node-retries.ipynb deleted file mode 100644 index b4bd89e1a..000000000 --- a/docs/docs/how-tos/node-retries.ipynb +++ /dev/null @@ -1,206 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to add node retry policies\n", - "\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "\n", - "There are many use cases where you may wish for your node to have a custom retry policy, for example if you are calling an API, querying a database, or calling an LLM, etc. \n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain_anthropic langchain_community" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to configure the retry policy, you have to pass the `retry` parameter to the [add_node](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph.add_node). The `retry` parameter takes in a `RetryPolicy` named tuple object. Below we instantiate a `RetryPolicy` object with the default parameters:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "RetryPolicy(initial_interval=0.5, backoff_factor=2.0, max_interval=128.0, max_attempts=3, jitter=True, retry_on=)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langgraph.pregel import RetryPolicy\n", - "\n", - "RetryPolicy()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By default, the `retry_on` parameter uses the `default_retry_on` function, which retries on any exception except for the following:\n", - "\n", - "* `ValueError`\n", - "* `TypeError`\n", - "* `ArithmeticError`\n", - "* `ImportError`\n", - "* `LookupError`\n", - "* `NameError`\n", - "* `SyntaxError`\n", - "* `RuntimeError`\n", - "* `ReferenceError`\n", - "* `StopIteration`\n", - "* `StopAsyncIteration`\n", - "* `OSError`\n", - "\n", - "In addition, for exceptions from popular http request libraries such as `requests` and `httpx` it only retries on 5xx status codes." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Passing a retry policy to a node\n", - "\n", - "Lastly, we can pass `RetryPolicy` objects when we call the [add_node](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph.add_node) function. In the example below we pass two different retry policies to each of our nodes:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "import sqlite3\n", - "from typing import Annotated, Sequence\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langchain_core.messages import BaseMessage\n", - "\n", - "from langgraph.graph import END, StateGraph, START\n", - "from langchain_community.utilities import SQLDatabase\n", - "from langchain_core.messages import AIMessage\n", - "\n", - "db = SQLDatabase.from_uri(\"sqlite:///:memory:\")\n", - "\n", - "model = ChatAnthropic(model_name=\"claude-2.1\")\n", - "\n", - "\n", - "class AgentState(TypedDict):\n", - " messages: Annotated[Sequence[BaseMessage], operator.add]\n", - "\n", - "\n", - "def query_database(state):\n", - " query_result = db.run(\"SELECT * FROM Artist LIMIT 10;\")\n", - " return {\"messages\": [AIMessage(content=query_result)]}\n", - "\n", - "\n", - "def call_model(state):\n", - " response = model.invoke(state[\"messages\"])\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "# Define a new graph\n", - "builder = StateGraph(AgentState)\n", - "builder.add_node(\n", - " \"query_database\",\n", - " query_database,\n", - " retry=RetryPolicy(retry_on=sqlite3.OperationalError),\n", - ")\n", - "builder.add_node(\"model\", call_model, retry=RetryPolicy(max_attempts=5))\n", - "builder.add_edge(START, \"model\")\n", - "builder.add_edge(\"model\", \"query_database\")\n", - "builder.add_edge(\"query_database\", END)\n", - "\n", - "graph = builder.compile()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/pass-config-to-tools.ipynb b/docs/docs/how-tos/pass-config-to-tools.ipynb deleted file mode 100644 index dec54fa1e..000000000 --- a/docs/docs/how-tos/pass-config-to-tools.ipynb +++ /dev/null @@ -1,407 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to pass config to tools" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide assumes familiarity with the following:\n", - "

\n", - "

\n", - "
\n", - "\n", - "\n", - "\n", - "At runtime, you may need to pass values to a tool, like a user ID, which should be set by the application logic, not controlled by the LLM, for security reasons. The LLM should only manage its intended parameters.\n", - "\n", - "LangChain tools use the `Runnable` interface, where methods like `invoke` accept runtime information through the config argument with a `RunnableConfig` type annotation.\n", - "\n", - "In the following example, we’ll set up an agent with tools to manage a user's favorite pets—adding, reading, and deleting entries—while fixing the user ID through application logic and letting the chat model control other parameters" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define tools and model" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "!!! warning \"Config type annotations\"\n", - "\n", - " Each tool function can take a `config` argument. In order for the config to be correctly propagated to the function, you MUST always add a `RunnableConfig` type annotation for your `config` argument. For example:\n", - "\n", - " ```python\n", - " def my_tool(tool_arg: str, config: RunnableConfig):\n", - " ...\n", - " ```" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import List\n", - "\n", - "from langchain_core.tools import tool\n", - "from langchain_core.runnables.config import RunnableConfig\n", - "\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "user_to_pets = {}\n", - "\n", - "\n", - "@tool(parse_docstring=True)\n", - "def update_favorite_pets(\n", - " # NOTE: config arg does not need to be added to docstring, as we don't want it to be included in the function signature attached to the LLM\n", - " pets: List[str],\n", - " config: RunnableConfig,\n", - ") -> None:\n", - " \"\"\"Add the list of favorite pets.\n", - "\n", - " Args:\n", - " pets: List of favorite pets to set.\n", - " \"\"\"\n", - " user_id = config.get(\"configurable\", {}).get(\"user_id\")\n", - " user_to_pets[user_id] = pets\n", - "\n", - "\n", - "@tool\n", - "def delete_favorite_pets(config: RunnableConfig) -> None:\n", - " \"\"\"Delete the list of favorite pets.\"\"\"\n", - " user_id = config.get(\"configurable\", {}).get(\"user_id\")\n", - " if user_id in user_to_pets:\n", - " del user_to_pets[user_id]\n", - "\n", - "\n", - "@tool\n", - "def list_favorite_pets(config: RunnableConfig) -> None:\n", - " \"\"\"List favorite pets if asked to.\"\"\"\n", - " user_id = config.get(\"configurable\", {}).get(\"user_id\")\n", - " return \", \".join(user_to_pets.get(user_id, []))\n", - "\n", - "\n", - "tools = [update_favorite_pets, delete_favorite_pets, list_favorite_pets]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll be using a small chat model from Anthropic in our example." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_anthropic import ChatAnthropic\n", - "from langgraph.graph import StateGraph, MessagesState\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-haiku-latest\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ReAct Agent\n", - "\n", - "Let's set up a graph implementation of the [ReAct agent](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-agent). This agent takes some query as input, then repeatedly call tools until it has enough information to resolve the query. We'll be using prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] and the Anthropic model with tools we just defined. Note: the tools are automatically added to the model via `model.bind_tools` inside the `create_react_agent` implementation." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from langgraph.prebuilt import create_react_agent\n", - "from IPython.display import Image, display\n", - "\n", - "graph = create_react_agent(model, tools)\n", - "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Use it!" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "User information prior to run: {}\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "my favorite pets are cats and dogs\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you update your favorite pets using the `update_favorite_pets` function.\", 'type': 'text'}, {'id': 'toolu_015jtecJ4jnosAfXEC3KADS2', 'input': {'pets': ['cats', 'dogs']}, 'name': 'update_favorite_pets', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " update_favorite_pets (toolu_015jtecJ4jnosAfXEC3KADS2)\n", - " Call ID: toolu_015jtecJ4jnosAfXEC3KADS2\n", - " Args:\n", - " pets: ['cats', 'dogs']\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: update_favorite_pets\n", - "\n", - "null\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Great! I've added cats and dogs to your list of favorite pets. Would you like to confirm the list or do anything else with it?\n", - "User information after the run: {'123': ['cats', 'dogs']}\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "user_to_pets.clear() # Clear the state\n", - "\n", - "print(f\"User information prior to run: {user_to_pets}\")\n", - "\n", - "inputs = {\"messages\": [HumanMessage(content=\"my favorite pets are cats and dogs\")]}\n", - "for chunk in graph.stream(\n", - " inputs, {\"configurable\": {\"user_id\": \"123\"}}, stream_mode=\"values\"\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()\n", - "\n", - "print(f\"User information after the run: {user_to_pets}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "User information prior to run: {'123': ['cats', 'dogs']}\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what are my favorite pets\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you check your favorite pets by using the list_favorite_pets function.\", 'type': 'text'}, {'id': 'toolu_01EMTtX5WtKJXMJ4WqXpxPUw', 'input': {}, 'name': 'list_favorite_pets', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " list_favorite_pets (toolu_01EMTtX5WtKJXMJ4WqXpxPUw)\n", - " Call ID: toolu_01EMTtX5WtKJXMJ4WqXpxPUw\n", - " Args:\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: list_favorite_pets\n", - "\n", - "cats, dogs\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Based on the results, your favorite pets are cats and dogs.\n", - "\n", - "Is there anything else you'd like to know about your favorite pets, or would you like to update the list?\n", - "User information prior to run: {'123': ['cats', 'dogs']}\n" - ] - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "print(f\"User information prior to run: {user_to_pets}\")\n", - "\n", - "inputs = {\"messages\": [HumanMessage(content=\"what are my favorite pets\")]}\n", - "for chunk in graph.stream(\n", - " inputs, {\"configurable\": {\"user_id\": \"123\"}}, stream_mode=\"values\"\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()\n", - "\n", - "print(f\"User information prior to run: {user_to_pets}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "User information prior to run: {'123': ['cats', 'dogs']}\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "please forget what i told you about my favorite animals\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"I'll help you delete the list of favorite pets. I'll use the delete_favorite_pets function to remove any previously saved list.\", 'type': 'text'}, {'id': 'toolu_01JqpxgxdsDJFMzSLeogoRtG', 'input': {}, 'name': 'delete_favorite_pets', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " delete_favorite_pets (toolu_01JqpxgxdsDJFMzSLeogoRtG)\n", - " Call ID: toolu_01JqpxgxdsDJFMzSLeogoRtG\n", - " Args:\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: delete_favorite_pets\n", - "\n", - "null\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The list of favorite pets has been deleted. If you'd like to create a new list of favorite pets in the future, just let me know.\n", - "User information prior to run: {}\n" - ] - } - ], - "source": [ - "print(f\"User information prior to run: {user_to_pets}\")\n", - "\n", - "inputs = {\n", - " \"messages\": [\n", - " HumanMessage(content=\"please forget what i told you about my favorite animals\")\n", - " ]\n", - "}\n", - "for chunk in graph.stream(\n", - " inputs, {\"configurable\": {\"user_id\": \"123\"}}, stream_mode=\"values\"\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()\n", - "\n", - "print(f\"User information prior to run: {user_to_pets}\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/pass-run-time-values-to-tools.ipynb b/docs/docs/how-tos/pass-run-time-values-to-tools.ipynb deleted file mode 100644 index dee49b953..000000000 --- a/docs/docs/how-tos/pass-run-time-values-to-tools.ipynb +++ /dev/null @@ -1,658 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to pass runtime values to tools\n", - "\n", - "Sometimes, you want to let a tool-calling LLM populate a *subset* of the tool functions' arguments and provide the other values for the other arguments at runtime. If you're using LangChain-style [tools](https://python.langchain.com/docs/concepts/#tools), an easy way to handle this is by annotating function parameters with [InjectedArg](https://python.langchain.com/docs/how_to/tool_runtime/). This annotation excludes that parameter from being shown to the LLM.\n", - "\n", - "In LangGraph applications you might want to pass the graph state or [shared memory](https://langchain-ai.github.io/langgraph/how-tos/cross-thread-persistence/) (store) to the tools at runtime. This type of stateful tools is useful when a tool's output is affected by past agent steps (e.g. if you're using a sub-agent as a tool, and want to pass the message history in to the sub-agent), or when a tool's input needs to be validated given context from past agent steps.\n", - "\n", - "In this guide we'll demonstrate how to do so using LangGraph's prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/how-tos/tool-calling/).\n", - "\n", - "
\n", - "

Prerequisites

\n", - "

\n", - " This guide targets **LangChain tool calling** assumes familiarity with the following:\n", - "

\n", - " You can still use tool calling in LangGraph using your provider SDK without losing any of LangGraph's core features.\n", - "

\n", - "
\n", - "\n", - "The core technique in the examples below is to **annotate** a parameter as \"injected\", meaning it will be injected by your program and should not be seen or populated by the LLM. Let the following codesnippet serve as a tl;dr:\n", - "\n", - "```python\n", - "from typing import Annotated\n", - "\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langchain_core.tools import InjectedToolArg\n", - "from langgraph.store.base import BaseStore\n", - "\n", - "from langgraph.prebuilt import InjectedState, InjectedStore\n", - "\n", - "\n", - "# Can be sync or async; @tool decorator not required\n", - "async def my_tool(\n", - " # These arguments are populated by the LLM\n", - " some_arg: str,\n", - " another_arg: float,\n", - " # The config: RunnableConfig is always available in LangChain calls\n", - " # This is not exposed to the LLM\n", - " config: RunnableConfig,\n", - " # The following three are specific to the prebuilt ToolNode\n", - " # (and `create_react_agent` by extension). If you are invoking the\n", - " # tool on its own (in your own node), then you would need to provide these yourself.\n", - " store: Annotated[BaseStore, InjectedStore],\n", - " # This passes in the full state.\n", - " state: Annotated[State, InjectedState],\n", - " # You can also inject single fields from your state if you\n", - " messages: Annotated[list, InjectedState(\"messages\")]\n", - " # The following is not compatible with create_react_agent or ToolNode\n", - " # You can also exclude other arguments from being shown to the model.\n", - " # These must be provided manually and are useful if you call the tools/functions in your own node\n", - " # some_other_arg=Annotated[\"MyPrivateClass\", InjectedToolArg],\n", - "):\n", - " \"\"\"Call my_tool to have an impact on the real world.\n", - "\n", - " Args:\n", - " some_arg: a very important argument\n", - " another_arg: another argument the LLM will provide\n", - " \"\"\" # The docstring becomes the description for your tool and is passed to the model\n", - " print(some_arg, another_arg, config, store, state, messages)\n", - " # Config, some_other_rag, store, and state are all \"hidden\" from\n", - " # LangChain models when passed to bind_tools or with_structured_output\n", - " return \"... some response\"\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5c205242", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First we need to install the packages required" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain-openai" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API keys for OpenAI (the chat model we will use)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c903a1cf-2977-4e2d-ad7d-8b3946821d89", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "OPENAI_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", - "metadata": {}, - "source": [ - "
\n", - "

Set up LangSmith for LangGraph development

\n", - "

\n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

\n", - "
" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "1a5908ab-7c1f-4832-85ae-511536b89b9f", - "metadata": {}, - "source": [ - "## Pass graph state to tools\n", - "\n", - "Let's first take a look at how to give our tools access to the graph state. We'll need to define our graph state:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "a2ded72f-1450-4295-a879-fd213ecfd4b5", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import List\n", - "\n", - "# this is the state schema used by the prebuilt create_react_agent we'll be using below\n", - "from langgraph.prebuilt.chat_agent_executor import AgentState\n", - "from langchain_core.documents import Document\n", - "\n", - "\n", - "class State(AgentState):\n", - " docs: List[str]" - ] - }, - { - "cell_type": "markdown", - "id": "75d2d28c-0da3-46c6-9c67-979a71b5f517", - "metadata": {}, - "source": [ - "### Define the tools\n", - "\n", - "We'll want our tool to take graph state as an input, but we don't want the model to try to generate this input when calling the tool. We can use the `InjectedState` annotation to mark arguments as required graph state (or some field of graph state. These arguments will not be generated by the model. When using `ToolNode`, graph state will automatically be passed in to the relevant tools and arguments.\n", - "\n", - "In this example we'll create a tool that returns Documents and then another tool that actually cites the Documents that justify a claim." - ] - }, - { - "cell_type": "markdown", - "id": "2f7e2c8d", - "metadata": {}, - "source": [ - "
\n", - "

Using Pydantic with LangChain

\n", - "

\n", - " This notebook uses Pydantic v2 BaseModel, which requires langchain-core >= 0.3. Using langchain-core < 0.3 will result in errors due to mixing of Pydantic v1 and v2 BaseModels.\n", - "

\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "1d36e782-80f4-4334-b7d7-ee4c79864480", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import List, Tuple\n", - "from typing_extensions import Annotated\n", - "\n", - "from langchain_core.messages import ToolMessage\n", - "from langchain_core.tools import tool\n", - "from langgraph.prebuilt import InjectedState\n", - "\n", - "\n", - "@tool\n", - "def get_context(question: str, state: Annotated[dict, InjectedState]):\n", - " \"\"\"Get relevant context for answering the question.\"\"\"\n", - " return \"\\n\\n\".join(doc for doc in state[\"docs\"])" - ] - }, - { - "cell_type": "markdown", - "id": "1c2d0de0-0f3e-4bbe-b0b6-cc0f70b11993", - "metadata": {}, - "source": [ - "If we look at the input schemas for these tools, we'll see that `state` is still listed:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "1092929b-c939-4b2a-9f9c-e725b0e34af2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'description': 'Get relevant context for answering the question.',\n", - " 'properties': {'question': {'title': 'Question', 'type': 'string'},\n", - " 'state': {'title': 'State', 'type': 'object'}},\n", - " 'required': ['question', 'state'],\n", - " 'title': 'get_context',\n", - " 'type': 'object'}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "get_context.get_input_schema().schema()" - ] - }, - { - "cell_type": "markdown", - "id": "e346a26e-e00b-48e5-82c5-c930ea6084a4", - "metadata": {}, - "source": [ - "But if we look at the tool call schema, which is what is passed to the model for tool-calling, `state` has been removed:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "3912bb51-3107-4335-a659-021c5d89fb37", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'description': 'Get relevant context for answering the question.',\n", - " 'properties': {'question': {'title': 'Question', 'type': 'string'}},\n", - " 'required': ['question'],\n", - " 'title': 'get_context',\n", - " 'type': 'object'}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "get_context.tool_call_schema.schema()" - ] - }, - { - "cell_type": "markdown", - "id": "8e8b9211-93d0-4ad5-aa7a-9c09099c53ff", - "metadata": {}, - "source": [ - "### Define the graph\n", - "\n", - "In this example we will be using a [prebuilt ReAct agent](https://langchain-ai.github.io/langgraph/how-tos/create-react-agent/). We'll first need to define our model and a tool-calling node ([ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode)):" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "be341be4-bdc3-4e78-9bc1-7486da27fd7c", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_openai import ChatOpenAI\n", - "from langgraph.prebuilt import ToolNode, create_react_agent\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "model = ChatOpenAI(model=\"gpt-4o\", temperature=0)\n", - "tools = [get_context]\n", - "\n", - "# ToolNode will automatically take care of injecting state into tools\n", - "tool_node = ToolNode(tools)\n", - "\n", - "checkpointer = MemorySaver()\n", - "graph = create_react_agent(model, tools, state_schema=State, checkpointer=checkpointer)" - ] - }, - { - "cell_type": "markdown", - "id": "547c3931-3dae-4281-ad4e-4b51305594d4", - "metadata": {}, - "source": [ - "### Use it!" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "c0858273-10f2-45c4-a922-b11321ac3fae", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the latest news about FooBar\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_context (call_UkqfR7z2cLJQjhatUpDeEa5H)\n", - " Call ID: call_UkqfR7z2cLJQjhatUpDeEa5H\n", - " Args:\n", - " question: latest news about FooBar\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_context\n", - "\n", - "FooBar company just raised 1 Billion dollars!\n", - "\n", - "FooBar company was founded in 2019\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The latest news about FooBar is that the company has just raised 1 billion dollars.\n" - ] - } - ], - "source": [ - "docs = [\n", - " \"FooBar company just raised 1 Billion dollars!\",\n", - " \"FooBar company was founded in 2019\",\n", - "]\n", - "\n", - "inputs = {\n", - " \"messages\": [{\"type\": \"user\", \"content\": \"what's the latest news about FooBar\"}],\n", - " \"docs\": docs,\n", - "}\n", - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "for chunk in graph.stream(inputs, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "09dd6d7d-d8a8-48f9-a30d-fba79fb7cb1e", - "metadata": {}, - "source": [ - "## Pass shared memory (store) to the graph\n", - "\n", - "You might also want to give tools access to memory that is shared across multiple conversations or users. We can do it by passing LangGraph [Store](https://langchain-ai.github.io/langgraph/how-tos/cross-thread-persistence/) to the tools using a different annotation -- `InjectedStore`.\n", - "\n", - "Let's modify our example to save the documents in an in-memory store and retrieve them using `get_context` tool. We'll also make the documents accessible based on a user ID, so that some documents are only visible to certain users. The tool will then use the `user_id` provided in the [config](https://langchain-ai.github.io/langgraph/how-tos/pass-config-to-tools/) to retrieve a correct set of documents." - ] - }, - { - "cell_type": "markdown", - "id": "41644e7e-bda2-4c0d-95da-99572554c02d", - "metadata": {}, - "source": [ - "
\n", - "

Note

\n", - " \n", - "
  • \n", - " Support for Store API and InjectedStore used in this notebook was added in LangGraph v0.2.34.\n", - "
  • \n", - "
  • \n", - " InjectedStore annotation requires langchain-core >= 0.3.8\n", - "
  • \n", - " \n", - "
    " - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "759186ed-5506-4e9a-80c4-0a2405ff58de", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.store.memory import InMemoryStore\n", - "\n", - "doc_store = InMemoryStore()\n", - "\n", - "namespace = (\"documents\", \"1\") # user ID\n", - "doc_store.put(\n", - " namespace, \"doc_0\", {\"doc\": \"FooBar company just raised 1 Billion dollars!\"}\n", - ")\n", - "namespace = (\"documents\", \"2\") # user ID\n", - "doc_store.put(namespace, \"doc_1\", {\"doc\": \"FooBar company was founded in 2019\"})" - ] - }, - { - "cell_type": "markdown", - "id": "c1a6e4e4-3256-4d42-aa5f-de337bfa6a97", - "metadata": {}, - "source": [ - "### Define the tools" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "91ab7e2b-7df4-41ea-8b20-e2ba950aacb2", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.store.base import BaseStore\n", - "from langchain_core.runnables import RunnableConfig\n", - "from langgraph.prebuilt import InjectedStore\n", - "\n", - "\n", - "@tool\n", - "def get_context(\n", - " question: str,\n", - " config: RunnableConfig,\n", - " store: Annotated[BaseStore, InjectedStore()],\n", - ") -> Tuple[str, List[Document]]:\n", - " \"\"\"Get relevant context for answering the question.\"\"\"\n", - " user_id = config.get(\"configurable\", {}).get(\"user_id\")\n", - " docs = [item.value[\"doc\"] for item in store.search((\"documents\", user_id))]\n", - " return \"\\n\\n\".join(doc for doc in docs)" - ] - }, - { - "cell_type": "markdown", - "id": "fcd29b33-b647-4e11-8942-2d47f129095b", - "metadata": {}, - "source": [ - "We can also verify that the tool-calling model will ignore `store` arg of `get_context` tool:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "07bdc124-06bb-4c25-a18e-700ab7aa6521", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'description': 'Get relevant context for answering the question.',\n", - " 'properties': {'question': {'title': 'Question', 'type': 'string'}},\n", - " 'required': ['question'],\n", - " 'title': 'get_context',\n", - " 'type': 'object'}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "get_context.tool_call_schema.schema()" - ] - }, - { - "cell_type": "markdown", - "id": "10622c58-db67-476b-81a3-1b964f5b471f", - "metadata": {}, - "source": [ - "### Define the graph\n", - "\n", - "Let's update our ReAct agent:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "10c70125-a105-4103-89d2-2e93b401080c", - "metadata": {}, - "outputs": [], - "source": [ - "tools = [get_context]\n", - "\n", - "# ToolNode will automatically take care of injecting Store into tools\n", - "tool_node = ToolNode(tools)\n", - "\n", - "checkpointer = MemorySaver()\n", - "# NOTE: we need to pass our store to `create_react_agent` to make sure our graph is aware of it\n", - "graph = create_react_agent(model, tools, checkpointer=checkpointer, store=doc_store)" - ] - }, - { - "cell_type": "markdown", - "id": "35ba8adc-c706-48a6-992f-24c03c4cee46", - "metadata": {}, - "source": [ - "### Use it!" - ] - }, - { - "cell_type": "markdown", - "id": "c155ef73-91fe-459d-a3af-7ed254c19e23", - "metadata": {}, - "source": [ - "Let's try running our graph with a `\"user_id\"` in the config." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "d683986f-faf4-4724-a13f-bac39ea9bafe", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the latest news about FooBar\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_context (call_ocyHBpGgF3LPFOgRKURBfkGG)\n", - " Call ID: call_ocyHBpGgF3LPFOgRKURBfkGG\n", - " Args:\n", - " question: latest news about FooBar\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_context\n", - "\n", - "FooBar company just raised 1 Billion dollars!\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The latest news about FooBar is that the company has just raised 1 billion dollars.\n" - ] - } - ], - "source": [ - "messages = [{\"type\": \"user\", \"content\": \"what's the latest news about FooBar\"}]\n", - "config = {\"configurable\": {\"thread_id\": \"1\", \"user_id\": \"1\"}}\n", - "for chunk in graph.stream({\"messages\": messages}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "4fac8ead-a4fa-488f-835d-21872c67ec72", - "metadata": {}, - "source": [ - "We can see that the tool only retrieved the correct document for user \"1\" when looking up the information in the store. Let's now try it again for a different user:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "2e3fd1e2-cc19-4023-8ffa-b0fc13da9e09", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the latest news about FooBar\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "Tool Calls:\n", - " get_context (call_zxO9KVlL8UxFQUMb8ETeHNvs)\n", - " Call ID: call_zxO9KVlL8UxFQUMb8ETeHNvs\n", - " Args:\n", - " question: latest news about FooBar\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_context\n", - "\n", - "FooBar company was founded in 2019\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "FooBar company was founded in 2019. If you need more specific or recent news, please let me know!\n" - ] - } - ], - "source": [ - "messages = [{\"type\": \"user\", \"content\": \"what's the latest news about FooBar\"}]\n", - "config = {\"configurable\": {\"thread_id\": \"2\", \"user_id\": \"2\"}}\n", - "for chunk in graph.stream({\"messages\": messages}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "196fd8ec-38e7-4300-88f6-9f8774bba313", - "metadata": {}, - "source": [ - "We can see that the tool pulled in a different document this time." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/pass_private_state.ipynb b/docs/docs/how-tos/pass_private_state.ipynb deleted file mode 100644 index 83374b580..000000000 --- a/docs/docs/how-tos/pass_private_state.ipynb +++ /dev/null @@ -1,177 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "47ed5db3-bda5-49e1-bf75-23e08c9a3af0", - "metadata": {}, - "source": [ - "# How to pass private state between nodes\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "In some cases, you may want nodes to exchange information that is crucial for intermediate logic but doesn’t need to be part of the main schema of the graph. This private data is not relevant to the overall input/output of the graph and should only be shared between certain nodes.\n", - "\n", - "In this how-to guide, we'll create an example sequential graph consisting of three nodes (node_1, node_2 and node_3), where private data is passed between the first two steps (node_1 and node_2), while the third step (node_3) only has access to the public overall state.\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "32d79ebd", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "e30836ce", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "a0028ced", - "metadata": {}, - "source": [ - "## Define and use the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "f0323902-ad88-4be1-a557-ac73a4419feb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Entered node `node_1`:\n", - "\tInput: {'a': 'set at start'}.\n", - "\tReturned: {'private_data': 'set by node_1'}\n", - "Entered node `node_2`:\n", - "\tInput: {'private_data': 'set by node_1'}.\n", - "\tReturned: {'a': 'set by node_2'}\n", - "Entered node `node_3`:\n", - "\tInput: {'a': 'set by node_2'}.\n", - "\tReturned: {'a': 'set by node_3'}\n", - "\n", - "Output of graph invocation: {'a': 'set by node_3'}\n" - ] - } - ], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from typing_extensions import TypedDict\n", - "\n", - "\n", - "# The overall state of the graph (this is the public state shared across nodes)\n", - "class OverallState(TypedDict):\n", - " a: str\n", - "\n", - "\n", - "# Output from node_1 contains private data that is not part of the overall state\n", - "class Node1Output(TypedDict):\n", - " private_data: str\n", - "\n", - "\n", - "# The private data is only shared between node_1 and node_2\n", - "def node_1(state: OverallState) -> Node1Output:\n", - " output = {\"private_data\": \"set by node_1\"}\n", - " print(f\"Entered node `node_1`:\\n\\tInput: {state}.\\n\\tReturned: {output}\")\n", - " return output\n", - "\n", - "\n", - "# Node 2 input only requests the private data available after node_1\n", - "class Node2Input(TypedDict):\n", - " private_data: str\n", - "\n", - "\n", - "def node_2(state: Node2Input) -> OverallState:\n", - " output = {\"a\": \"set by node_2\"}\n", - " print(f\"Entered node `node_2`:\\n\\tInput: {state}.\\n\\tReturned: {output}\")\n", - " return output\n", - "\n", - "\n", - "# Node 3 only has access to the overall state (no access to private data from node_1)\n", - "def node_3(state: OverallState) -> OverallState:\n", - " output = {\"a\": \"set by node_3\"}\n", - " print(f\"Entered node `node_3`:\\n\\tInput: {state}.\\n\\tReturned: {output}\")\n", - " return output\n", - "\n", - "\n", - "# Build the state graph\n", - "builder = StateGraph(OverallState)\n", - "builder.add_node(node_1) # node_1 is the first node\n", - "builder.add_node(\n", - " node_2\n", - ") # node_2 is the second node and accepts private data from node_1\n", - "builder.add_node(node_3) # node_3 is the third node and does not see the private data\n", - "builder.add_edge(START, \"node_1\") # Start the graph with node_1\n", - "builder.add_edge(\"node_1\", \"node_2\") # Pass from node_1 to node_2\n", - "builder.add_edge(\n", - " \"node_2\", \"node_3\"\n", - ") # Pass from node_2 to node_3 (only overall state is shared)\n", - "builder.add_edge(\"node_3\", END) # End the graph after node_3\n", - "graph = builder.compile()\n", - "\n", - "# Invoke the graph with the initial state\n", - "response = graph.invoke(\n", - " {\n", - " \"a\": \"set at start\",\n", - " }\n", - ")\n", - "\n", - "print()\n", - "print(f\"Output of graph invocation: {response}\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/persistence.ipynb b/docs/docs/how-tos/persistence.ipynb index 608add87c..448c42cc8 100644 --- a/docs/docs/how-tos/persistence.ipynb +++ b/docs/docs/how-tos/persistence.ipynb @@ -5,65 +5,22 @@ "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", "metadata": {}, "source": [ - "# How to add thread-level persistence to your graph\n", + "# Add persistence\n", "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", + "Many AI applications need memory to share context across multiple interactions. LangGraph supports two types of memory essential for building conversational agents:\n", "\n", - "!!! info \"Not needed for LangGraph API users\"\n", + "- **[Short-term memory](#add-short-term-memory)**: Tracks the ongoing conversation by maintaining message history within a session.\n", + "- **[Long-term memory](#add-long-term-memory)**: Stores user-specific or application-level data across sessions.\n", "\n", - " If you're using the LangGraph API, you needn't manually implement a checkpointer. The API automatically handles checkpointing for you. This guide is relevant when implementing LangGraph in your own custom server.\n", - "\n", - "Many AI applications need memory to share context across multiple interactions. In LangGraph, this kind of memory can be added to any [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph) using [thread-level persistence](https://langchain-ai.github.io/langgraph/concepts/persistence) .\n", - "\n", - "When creating any LangGraph graph, you can set it up to persist its state by adding a [checkpointer](https://langchain-ai.github.io/langgraph/reference/checkpoints/#basecheckpointsaver) when compiling the graph:\n", - "\n", - "```python\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "checkpointer = MemorySaver()\n", - "graph.compile(checkpointer=checkpointer)\n", - "```\n", - "\n", - "This guide shows how you can add thread-level persistence to your graph.\n", - "\n", - "
    \n", - "

    Note

    \n", - "

    \n", - " If you need memory that is shared across multiple conversations or users (cross-thread persistence), check out this how-to guide.\n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First we need to install the packages required" + "> **Terminology**\n", + ">\n", + "> In LangGraph:\n", + ">\n", + "> - *Short-term memory* is also referred to as **thread-level memory**.\n", + "> - *Long-term memory* is also called **cross-thread memory**.\n", + ">\n", + "> A [thread](../../concepts/persistence#threads) represents a sequence of related runs\n", + "> grouped by the same `thread_id`." ] }, { @@ -73,16 +30,9 @@ "metadata": {}, "outputs": [], "source": [ + "# hide-cell\n", "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "markdown", - "id": "0abe11f4-62ed-4dc4-8875-3db21e260d1d", - "metadata": {}, - "source": [ - "Next, we need to set API key for Anthropic (the LLM we will use)." + "%pip install --quiet -U langgraph \"langchain[anthropic]\"" ] }, { @@ -100,6 +50,7 @@ } ], "source": [ + "# hide-cell\n", "import getpass\n", "import os\n", "\n", @@ -114,61 +65,54 @@ }, { "cell_type": "markdown", - "id": "f0ed46a8-effe-4596-b0e1-a6a29ee16f5c", + "id": "702f9da1-9aaf-4a5f-9b1f-6ab1a273e6a9", "metadata": {}, "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " + "## Add short-term memory" ] }, { "cell_type": "markdown", - "id": "4cf509bc", + "id": "f7c171e2-82d2-423f-8eba-ff32d7c494fe", "metadata": {}, "source": [ - "## Define graph\n", - "\n", - "We will be using a single-node graph that calls a [chat model](https://python.langchain.com/docs/concepts/#chat-models).\n", - "\n", - "Let's first define the model we'll be using:" + "**Short-term** memory (thread-level persistence) enables agents to track multi-turn conversations. To add short-term memory:" ] }, { "cell_type": "code", - "execution_count": 3, - "id": "892b54b9-75f0-4804-9ed0-88b5e5532989", + "execution_count": 18, + "id": "07584f6a-7b8e-4f18-a135-e0435797e274", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "hi! I'm bob\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Hi Bob! How are you doing today? Is there anything I can help you with?\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "what's my name?\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "Your name is Bob.\n" + ] + } + ], "source": [ - "from langchain_anthropic import ChatAnthropic\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")" - ] - }, - { - "cell_type": "markdown", - "id": "7b7a2792-982b-4e47-83eb-0c594725d1c1", - "metadata": {}, - "source": [ - "Now we can define our `StateGraph` and add our model-calling node:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "87326ea6-34c5-46da-a41f-dda26ef9bd74", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "from typing_extensions import TypedDict\n", - "\n", + "from langchain.chat_models import init_chat_model\n", "from langgraph.graph import StateGraph, MessagesState, START\n", "\n", + "# highlight-next-line\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "\n", + "model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + "\n", "\n", "def call_model(state: MessagesState):\n", " response = model.invoke(state[\"messages\"])\n", @@ -176,103 +120,928 @@ "\n", "\n", "builder = StateGraph(MessagesState)\n", - "builder.add_node(\"call_model\", call_model)\n", + "builder.add_node(call_model)\n", "builder.add_edge(START, \"call_model\")\n", - "graph = builder.compile()" + "\n", + "checkpointer = InMemorySaver()\n", + "# highlight-next-line\n", + "graph = builder.compile(checkpointer=checkpointer)\n", + "\n", + "config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + "}\n", + "\n", + "for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + "):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + "\n", + "for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + "):\n", + " chunk[\"messages\"][-1].pretty_print()" ] }, { "cell_type": "markdown", - "id": "250d8fd9-2e7a-4892-9adc-19762a1e3cce", + "id": "504bf7c3-40f2-4b7f-86d9-390973a1700c", "metadata": {}, "source": [ - "If we try to use this graph, the context of the conversation will not be persisted across interactions:" + "!!! info \"Not needed for LangGraph API users\"\n", + "\n", + " If you're using the LangGraph API, **don't need** to provide checkpointer when compiling the graph. The API automatically handles checkpointing for you." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "988a98c0-15a6-492b-aa59-261fab3a4909", + "metadata": {}, + "source": [ + "### Use in production\n", + "\n", + "In production, you would want to use a checkpointer backed by a database:\n", + "\n", + "```python\n", + "from langgraph.checkpoint.postgres import PostgresSaver\n", + "\n", + "DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n", + "# highlight-next-line\n", + "with PostgresSaver.from_conn_string(DB_URI) as checkpointer:\n", + " builder = StateGraph(...)\n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + "```\n", + "\n", + "??? example \"Example: using [Postgres](https://pypi.org/project/langgraph-checkpoint-postgres/) checkpointer\"\n", + "\n", + " ```\n", + " pip install -U psycopg psycopg-pool langgraph langgraph-checkpoint-postgres\n", + " ```\n", + "\n", + " !!! Setup\n", + " You need to call `checkpointer.setup()` the first time you're using Postgres checkpointer\n", + "\n", + " === \"Sync\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " # highlight-next-line\n", + " from langgraph.checkpoint.postgres import PostgresSaver\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n", + " # highlight-next-line\n", + " with PostgresSaver.from_conn_string(DB_URI) as checkpointer:\n", + " # checkpointer.setup()\n", + " \n", + " def call_model(state: MessagesState):\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " === \"Async\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " # highlight-next-line\n", + " from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n", + " # highlight-next-line\n", + " async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:\n", + " # await checkpointer.setup()\n", + " \n", + " async def call_model(state: MessagesState):\n", + " response = await model.ainvoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " \n", + "\n", + "??? example \"Example: using [MongoDB](https://pypi.org/project/langgraph-checkpoint-mongodb/) checkpointer\"\n", + "\n", + " ```\n", + " pip install -U pymongo langgraph langgraph-checkpoint-mongodb\n", + " ```\n", + "\n", + " !!! note \"Setup\"\n", + "\n", + " To use the MongoDB checkpointer, you will need a MongoDB cluster. Follow [this guide](https://www.mongodb.com/docs/guides/atlas/cluster/) to create a cluster if you don't already have one.\n", + "\n", + " === \"Sync\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " # highlight-next-line\n", + " from langgraph.checkpoint.mongodb import MongoDBSaver\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"localhost:27017\"\n", + " # highlight-next-line\n", + " with MongoDBSaver.from_conn_string(DB_URI) as checkpointer:\n", + " \n", + " def call_model(state: MessagesState):\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " === \"Async\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " # highlight-next-line\n", + " from langgraph.checkpoint.mongodb.aio import AsyncMongoDBSaver\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"localhost:27017\"\n", + " # highlight-next-line\n", + " async with AsyncMongoDBSaver.from_conn_string(DB_URI) as checkpointer:\n", + " \n", + " async def call_model(state: MessagesState):\n", + " response = await model.ainvoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ``` \n", + "\n", + "??? example \"Example: using [Redis](https://pypi.org/project/langgraph-checkpoint-redis/) checkpointer\"\n", + "\n", + " ```\n", + " pip install -U langgraph langgraph-checkpoint-redis\n", + " ```\n", + "\n", + " !!! Setup\n", + " You need to call `checkpointer.setup()` the first time you're using Redis checkpointer\n", + "\n", + "\n", + " === \"Sync\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " # highlight-next-line\n", + " from langgraph.checkpoint.redis import RedisSaver\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"redis://localhost:6379\"\n", + " # highlight-next-line\n", + " with RedisSaver.from_conn_string(DB_URI) as checkpointer:\n", + " # checkpointer.setup()\n", + " \n", + " def call_model(state: MessagesState):\n", + " response = model.invoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " === \"Async\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " # highlight-next-line\n", + " from langgraph.checkpoint.redis.aio import AsyncRedisSaver\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"redis://localhost:6379\"\n", + " # highlight-next-line\n", + " async with AsyncRedisSaver.from_conn_string(DB_URI) as checkpointer:\n", + " # await checkpointer.asetup()\n", + " \n", + " async def call_model(state: MessagesState):\n", + " response = await model.ainvoke(state[\"messages\"])\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what's my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\"\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print() \n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "53f54d98-c659-49af-ae1e-a25641924ad1", + "metadata": {}, + "source": [ + "### Use with subgraphs" + ] + }, + { + "cell_type": "markdown", + "id": "cf3ec9f4-08bc-4118-af7b-1d3c4a5ef69b", + "metadata": {}, + "source": [ + "If your graph contains [subgraphs](../../concepts/subgraphs), you only need to **provide the checkpointer when compiling the parent graph**. LangGraph will automatically propagate the checkpointer to the child subgraphs.\n", + "\n", + "```python\n", + "from langgraph.graph import START, StateGraph\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "from typing import TypedDict\n", + "\n", + "class State(TypedDict):\n", + " foo: str\n", + "\n", + "# Subgraph\n", + "\n", + "def subgraph_node_1(state: State):\n", + " return {\"foo\": state[\"foo\"] + \"bar\"}\n", + "\n", + "subgraph_builder = StateGraph(State)\n", + "subgraph_builder.add_node(subgraph_node_1)\n", + "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + "# highlight-next-line\n", + "subgraph = subgraph_builder.compile()\n", + "\n", + "# Parent graph\n", + "\n", + "def node_1(state: State):\n", + " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", + "\n", + "builder = StateGraph(State)\n", + "# highlight-next-line\n", + "builder.add_node(\"node_1\", subgraph)\n", + "builder.add_edge(START, \"node_1\")\n", + "\n", + "checkpointer = InMemorySaver()\n", + "# highlight-next-line\n", + "graph = builder.compile(checkpointer=checkpointer)\n", + "``` \n", + "\n", + "If you want the subgraph to have its own memory, you can compile it `with checkpointer=True`. This is useful in [multi-agent](../../concepts/multi_agent) systems, if you want agents to keep track of their internal message histories:\n", + "\n", + "```python\n", + "subgraph_builder = StateGraph(...)\n", + "# highlight-next-line\n", + "subgraph = subgraph_builder.compile(checkpointer=True)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "f17b4493-c578-428f-857c-ef53f7139d53", + "metadata": {}, + "source": [ + "### Use with Functional API\n", + "\n", + "To add short-term memory to a [Functional API](../../concepts/functional_api) LangGraph workflow:\n", + "\n", + "1. Pass `checkpointer` instance to the [`entrypoint()`][langgraph.func.entrypoint] decorator:\n", + "\n", + " ```python\n", + " from langgraph.func import entrypoint\n", + " \n", + " @entrypoint(checkpointer=checkpointer)\n", + " def workflow(inputs)\n", + " ...\n", + " ```\n", + "\n", + "2. Optionally expose `previous` parameter in the workflow function signature:\n", + "\n", + " ```python\n", + " @entrypoint(checkpointer=checkpointer)\n", + " def workflow(\n", + " inputs,\n", + " *,\n", + " # you can optionally specify `previous` in the workflow function signature\n", + " # to access the return value from the workflow as of the last execution\n", + " previous\n", + " ):\n", + " previous = previous or []\n", + " combined_inputs = previous + inputs\n", + " result = do_something(combined_inputs)\n", + " ...\n", + " ```\n", + "\n", + "3. Optionally choose which values will be returned from the workflow and which will be saved by the checkpointer as `previous`:\n", + "\n", + " ```python\n", + " @entrypoint(checkpointer=checkpointer)\n", + " def workflow(inputs, *, previous):\n", + " ...\n", + " result = do_something(...)\n", + " return entrypoint.final(value=result, save=combine(inputs, result))\n", + " ```\n", + "\n", + "??? example \"Example: add short-term memory to Functional API workflow\"\n", + "\n", + " ```python\n", + " from langchain_core.messages import AnyMessage\n", + " from langgraph.graph import add_messages\n", + " from langgraph.func import entrypoint, task\n", + " from langgraph.checkpoint.memory import InMemorySaver\n", + "\n", + " # highlight-next-line\n", + " @task\n", + " def call_model(messages: list[AnyMessage]):\n", + " response = model.invoke(messages)\n", + " return response\n", + " \n", + " checkpointer = InMemorySaver()\n", + "\n", + " # highlight-next-line\n", + " @entrypoint(checkpointer=checkpointer)\n", + " def workflow(inputs: list[AnyMessage], *, previous: list[AnyMessage]):\n", + " if previous:\n", + " inputs = add_messages(previous, inputs)\n", + " \n", + " response = call_model(inputs).result()\n", + " return entrypoint.final(value=response, save=add_messages(inputs, response))\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " \n", + " for chunk in workflow.invoke(\n", + " [{\"role\": \"user\", \"content\": \"hi! I'm bob\"}],\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk.pretty_print()\n", + " \n", + " for chunk in workflow.stream(\n", + " [{\"role\": \"user\", \"content\": \"what's my name?\"}],\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk.pretty_print()\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "6d4bd273-98e6-4330-af93-b79fb7f50115", + "metadata": {}, + "source": [ + "### Manage checkpoints\n", + "\n", + "You can view and delete the information stored by the checkpointer:\n", + "\n", + "??? \"View thread state (checkpoint)\"\n", + "\n", + " === \"Graph/Functional API\"\n", + " \n", + " ```python\n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # optionally provide an ID for a specific checkpoint,\n", + " # otherwise the latest checkpoint is shown\n", + " # highlight-next-line\n", + " # \"checkpoint_id\": \"1f029ca3-1f5b-6704-8004-820c16b69a5a\"\n", + " \n", + " }\n", + " }\n", + " # highlight-next-line\n", + " graph.get_state(config)\n", + " ```\n", + " \n", + " ```\n", + " StateSnapshot(\n", + " values={'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today?), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]}, next=(), \n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1f5b-6704-8004-820c16b69a5a'}},\n", + " metadata={\n", + " 'source': 'loop',\n", + " 'writes': {'call_model': {'messages': AIMessage(content='Your name is Bob.')}},\n", + " 'step': 4,\n", + " 'parents': {},\n", + " 'thread_id': '1'\n", + " },\n", + " created_at='2025-05-05T16:01:24.680462+00:00',\n", + " parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}}, \n", + " tasks=(),\n", + " interrupts=()\n", + " )\n", + " ```\n", + "\n", + " === \"Checkpointer API\"\n", + " \n", + " ```python\n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # optionally provide an ID for a specific checkpoint,\n", + " # otherwise the latest checkpoint is shown\n", + " # highlight-next-line\n", + " # \"checkpoint_id\": \"1f029ca3-1f5b-6704-8004-820c16b69a5a\"\n", + " \n", + " }\n", + " }\n", + " # highlight-next-line\n", + " checkpointer.get_tuple(config)\n", + " ```\n", + "\n", + " ```\n", + " CheckpointTuple(\n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1f5b-6704-8004-820c16b69a5a'}},\n", + " checkpoint={\n", + " 'v': 3,\n", + " 'ts': '2025-05-05T16:01:24.680462+00:00',\n", + " 'id': '1f029ca3-1f5b-6704-8004-820c16b69a5a',\n", + " 'channel_versions': {'__start__': '00000000000000000000000000000005.0.5290678567601859', 'messages': '00000000000000000000000000000006.0.3205149138784782', 'branch:to:call_model': '00000000000000000000000000000006.0.14611156755133758'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000004.0.5736472536395331'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000005.0.1410174088651449'}},\n", + " 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today?), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]},\n", + " 'pending_sends': []\n", + " },\n", + " metadata={\n", + " 'source': 'loop',\n", + " 'writes': {'call_model': {'messages': AIMessage(content='Your name is Bob.')}},\n", + " 'step': 4,\n", + " 'parents': {},\n", + " 'thread_id': '1'\n", + " },\n", + " parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}},\n", + " pending_writes=[]\n", + " )\n", + " ```\n", + "\n", + "??? \"View the history of the thread (checkpoints)\"\n", + "\n", + " === \"Graph/Functional API\"\n", + "\n", + " ```python\n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " # highlight-next-line\n", + " list(graph.get_state_history(config))\n", + " ```\n", + " \n", + " ```\n", + " [\n", + " StateSnapshot(\n", + " values={'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]}, \n", + " next=(), \n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1f5b-6704-8004-820c16b69a5a'}}, \n", + " metadata={'source': 'loop', 'writes': {'call_model': {'messages': AIMessage(content='Your name is Bob.')}}, 'step': 4, 'parents': {}, 'thread_id': '1'},\n", + " created_at='2025-05-05T16:01:24.680462+00:00',\n", + " parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}},\n", + " tasks=(),\n", + " interrupts=()\n", + " ),\n", + " StateSnapshot(\n", + " values={'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\")]}, \n", + " next=('call_model',), \n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}},\n", + " metadata={'source': 'loop', 'writes': None, 'step': 3, 'parents': {}, 'thread_id': '1'},\n", + " created_at='2025-05-05T16:01:23.863421+00:00',\n", + " parent_config={...}\n", + " tasks=(PregelTask(id='8ab4155e-6b15-b885-9ce5-bed69a2c305c', name='call_model', path=('__pregel_pull', 'call_model'), error=None, interrupts=(), state=None, result={'messages': AIMessage(content='Your name is Bob.')}),),\n", + " interrupts=()\n", + " ),\n", + " StateSnapshot(\n", + " values={'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}, \n", + " next=('__start__',), \n", + " config={...}, \n", + " metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}}, 'step': 2, 'parents': {}, 'thread_id': '1'},\n", + " created_at='2025-05-05T16:01:23.863173+00:00',\n", + " parent_config={...}\n", + " tasks=(PregelTask(id='24ba39d6-6db1-4c9b-f4c5-682aeaf38dcd', name='__start__', path=('__pregel_pull', '__start__'), error=None, interrupts=(), state=None, result={'messages': [{'role': 'user', 'content': \"what's my name?\"}]}),),\n", + " interrupts=()\n", + " ),\n", + " StateSnapshot(\n", + " values={'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}, \n", + " next=(), \n", + " config={...}, \n", + " metadata={'source': 'loop', 'writes': {'call_model': {'messages': AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')}}, 'step': 1, 'parents': {}, 'thread_id': '1'},\n", + " created_at='2025-05-05T16:01:23.862295+00:00',\n", + " parent_config={...}\n", + " tasks=(),\n", + " interrupts=()\n", + " ),\n", + " StateSnapshot(\n", + " values={'messages': [HumanMessage(content=\"hi! I'm bob\")]}, \n", + " next=('call_model',), \n", + " config={...}, \n", + " metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}, 'thread_id': '1'}, \n", + " created_at='2025-05-05T16:01:22.278960+00:00', \n", + " parent_config={...}\n", + " tasks=(PregelTask(id='8cbd75e0-3720-b056-04f7-71ac805140a0', name='call_model', path=('__pregel_pull', 'call_model'), error=None, interrupts=(), state=None, result={'messages': AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')}),), \n", + " interrupts=()\n", + " ),\n", + " StateSnapshot(\n", + " values={'messages': []}, \n", + " next=('__start__',), \n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-0870-6ce2-bfff-1f3f14c3e565'}},\n", + " metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}, 'step': -1, 'parents': {}, 'thread_id': '1'}, \n", + " created_at='2025-05-05T16:01:22.277497+00:00', \n", + " parent_config=None,\n", + " tasks=(PregelTask(id='d458367b-8265-812c-18e2-33001d199ce6', name='__start__', path=('__pregel_pull', '__start__'), error=None, interrupts=(), state=None, result={'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}),), \n", + " interrupts=()\n", + " )\n", + " ] \n", + " ```\n", + "\n", + " === \"Checkpointer API\"\n", + "\n", + " ```python\n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\"\n", + " }\n", + " }\n", + " # highlight-next-line\n", + " list(checkpointer.list(config))\n", + " ```\n", + "\n", + " ```\n", + " [\n", + " CheckpointTuple(\n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1f5b-6704-8004-820c16b69a5a'}}, \n", + " checkpoint={\n", + " 'v': 3, \n", + " 'ts': '2025-05-05T16:01:24.680462+00:00', \n", + " 'id': '1f029ca3-1f5b-6704-8004-820c16b69a5a', \n", + " 'channel_versions': {'__start__': '00000000000000000000000000000005.0.5290678567601859', 'messages': '00000000000000000000000000000006.0.3205149138784782', 'branch:to:call_model': '00000000000000000000000000000006.0.14611156755133758'}, \n", + " 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000004.0.5736472536395331'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000005.0.1410174088651449'}},\n", + " 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\"), AIMessage(content='Your name is Bob.')]}, 'pending_sends': []\n", + " },\n", + " metadata={'source': 'loop', 'writes': {'call_model': {'messages': AIMessage(content='Your name is Bob.')}}, 'step': 4, 'parents': {}, 'thread_id': '1'}, \n", + " parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}}, \n", + " pending_writes=[]\n", + " ),\n", + " CheckpointTuple(\n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-1790-6b0a-8003-baf965b6a38f'}},\n", + " checkpoint={\n", + " 'v': 3, \n", + " 'ts': '2025-05-05T16:01:23.863421+00:00', \n", + " 'id': '1f029ca3-1790-6b0a-8003-baf965b6a38f', \n", + " 'channel_versions': {'__start__': '00000000000000000000000000000005.0.5290678567601859', 'messages': '00000000000000000000000000000005.0.7935064215293443', 'branch:to:call_model': '00000000000000000000000000000005.0.1410174088651449'}, \n", + " 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000004.0.5736472536395331'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}}, \n", + " 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'), HumanMessage(content=\"what's my name?\")], 'branch:to:call_model': None}, \n", + " 'pending_sends': []\n", + " }, \n", + " metadata={'source': 'loop', 'writes': None, 'step': 3, 'parents': {}, 'thread_id': '1'}, \n", + " parent_config={...}, \n", + " pending_writes=[('8ab4155e-6b15-b885-9ce5-bed69a2c305c', 'messages', AIMessage(content='Your name is Bob.'))]\n", + " ),\n", + " CheckpointTuple(\n", + " config={...}, \n", + " checkpoint={\n", + " 'v': 3, \n", + " 'ts': '2025-05-05T16:01:23.863173+00:00', \n", + " 'id': '1f029ca3-1790-616e-8002-9e021694a0cd', \n", + " 'channel_versions': {'__start__': '00000000000000000000000000000004.0.5736472536395331', 'messages': '00000000000000000000000000000003.0.7056767754077798', 'branch:to:call_model': '00000000000000000000000000000003.0.22059023329132854'}, \n", + " 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}}, \n", + " 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}, 'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}, \n", + " 'pending_sends': []\n", + " }, \n", + " metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"what's my name?\"}]}}, 'step': 2, 'parents': {}, 'thread_id': '1'}, \n", + " parent_config={...}, \n", + " pending_writes=[('24ba39d6-6db1-4c9b-f4c5-682aeaf38dcd', 'messages', [{'role': 'user', 'content': \"what's my name?\"}]), ('24ba39d6-6db1-4c9b-f4c5-682aeaf38dcd', 'branch:to:call_model', None)]\n", + " ),\n", + " CheckpointTuple(\n", + " config={...}, \n", + " checkpoint={\n", + " 'v': 3, \n", + " 'ts': '2025-05-05T16:01:23.862295+00:00', \n", + " 'id': '1f029ca3-178d-6f54-8001-d7b180db0c89', \n", + " 'channel_versions': {'__start__': '00000000000000000000000000000002.0.18673090920108737', 'messages': '00000000000000000000000000000003.0.7056767754077798', 'branch:to:call_model': '00000000000000000000000000000003.0.22059023329132854'}, \n", + " 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}, 'call_model': {'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}}, \n", + " 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\"), AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')]}, \n", + " 'pending_sends': []\n", + " }, \n", + " metadata={'source': 'loop', 'writes': {'call_model': {'messages': AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?')}}, 'step': 1, 'parents': {}, 'thread_id': '1'}, \n", + " parent_config={...}, \n", + " pending_writes=[]\n", + " ),\n", + " CheckpointTuple(\n", + " config={...}, \n", + " checkpoint={\n", + " 'v': 3, \n", + " 'ts': '2025-05-05T16:01:22.278960+00:00', \n", + " 'id': '1f029ca3-0874-6612-8000-339f2abc83b1', \n", + " 'channel_versions': {'__start__': '00000000000000000000000000000002.0.18673090920108737', 'messages': '00000000000000000000000000000002.0.30296526818059655', 'branch:to:call_model': '00000000000000000000000000000002.0.9300422176788571'}, \n", + " 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}}, \n", + " 'channel_values': {'messages': [HumanMessage(content=\"hi! I'm bob\")], 'branch:to:call_model': None}, \n", + " 'pending_sends': []\n", + " }, \n", + " metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}, 'thread_id': '1'}, \n", + " parent_config={...}, \n", + " pending_writes=[('8cbd75e0-3720-b056-04f7-71ac805140a0', 'messages', AIMessage(content='Hi Bob! How are you doing today? Is there anything I can help you with?'))]\n", + " ),\n", + " CheckpointTuple(\n", + " config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f029ca3-0870-6ce2-bfff-1f3f14c3e565'}}, \n", + " checkpoint={\n", + " 'v': 3, \n", + " 'ts': '2025-05-05T16:01:22.277497+00:00', \n", + " 'id': '1f029ca3-0870-6ce2-bfff-1f3f14c3e565', \n", + " 'channel_versions': {'__start__': '00000000000000000000000000000001.0.7040775356287469'}, \n", + " 'versions_seen': {'__input__': {}}, \n", + " 'channel_values': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}, \n", + " 'pending_sends': []\n", + " }, \n", + " metadata={'source': 'input', 'writes': {'__start__': {'messages': [{'role': 'user', 'content': \"hi! I'm bob\"}]}}, 'step': -1, 'parents': {}, 'thread_id': '1'}, \n", + " parent_config=None, \n", + " pending_writes=[('d458367b-8265-812c-18e2-33001d199ce6', 'messages', [{'role': 'user', 'content': \"hi! I'm bob\"}]), ('d458367b-8265-812c-18e2-33001d199ce6', 'branch:to:call_model', None)]\n", + " )\n", + " ]\n", + " ```\n", + "\n", + "\n", + "??? \"Delete all checkpoints for a thread\"\n", + "\n", + " ```python\n", + " thread_id = \"1\"\n", + " checkpointer.delete_thread(thread_id)\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "799eaf41-1a48-4a31-bc71-1a2a51e92b21", + "metadata": {}, + "source": [ + "## Add long-term memory" + ] + }, + { + "cell_type": "markdown", + "id": "303f3ae3-30e3-41d1-900a-c84879b50f86", + "metadata": {}, + "source": [ + "Use **long-term** memory (cross-thread persistence) to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information.\n", + "\n", + "To use long-term memory, we need to [provide a store][langgraph.store.base.BaseStore] when creating the graph:" ] }, { "cell_type": "code", "execution_count": 5, - "id": "6fa9a5e3-7101-43ab-a811-592e222b9580", + "id": "b88d8ede-ec8c-406c-917d-cda5610679c3", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "hi! I'm bob\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Hello Bob! It's nice to meet you. How are you doing today? Is there anything I can help you with or would you like to chat about something in particular?\n", - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I apologize, but I don't have access to your personal information, including your name. I'm an AI language model designed to provide general information and answer questions to the best of my ability based on my training data. I don't have any information about individual users or their personal details. If you'd like to share your name, you're welcome to do so, but I won't be able to recall it in future conversations.\n" - ] - } - ], + "outputs": [], "source": [ - "input_message = {\"role\": \"user\", \"content\": \"hi! I'm bob\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()\n", + "import uuid\n", + "from typing_extensions import Annotated, TypedDict\n", "\n", - "input_message = {\"role\": \"user\", \"content\": \"what's my name?\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" + "from langchain_core.runnables import RunnableConfig\n", + "from langgraph.graph import StateGraph, MessagesState, START\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "\n", + "# highlight-next-line\n", + "from langgraph.store.memory import InMemoryStore\n", + "from langgraph.store.base import BaseStore\n", + "\n", + "model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + "\n", + "\n", + "def call_model(\n", + " state: MessagesState,\n", + " config: RunnableConfig,\n", + " *,\n", + " # highlight-next-line\n", + " store: BaseStore, # (1)!\n", + "):\n", + " user_id = config[\"configurable\"][\"user_id\"]\n", + " namespace = (\"memories\", user_id)\n", + " # highlight-next-line\n", + " memories = store.search(namespace, query=str(state[\"messages\"][-1].content))\n", + " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", + " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", + "\n", + " # Store new memories if the user asks the model to remember\n", + " last_message = state[\"messages\"][-1]\n", + " if \"remember\" in last_message.content.lower():\n", + " memory = \"User name is Bob\"\n", + " # highlight-next-line\n", + " store.put(namespace, str(uuid.uuid4()), {\"data\": memory})\n", + "\n", + " response = model.invoke(\n", + " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", + " )\n", + " return {\"messages\": response}\n", + "\n", + "\n", + "builder = StateGraph(MessagesState)\n", + "builder.add_node(call_model)\n", + "builder.add_edge(START, \"call_model\")\n", + "\n", + "checkpointer = InMemorySaver()\n", + "store = InMemoryStore()\n", + "\n", + "graph = builder.compile(\n", + " checkpointer=checkpointer,\n", + " # highlight-next-line\n", + " store=store,\n", + ")" ] }, { "cell_type": "markdown", - "id": "bc9c8536-f90b-44fa-958d-5df016c66d8f", + "id": "ce33d6ee-5754-4a9d-8246-6ad188a28d94", "metadata": {}, "source": [ - "## Add persistence\n", - "\n", - "To add in persistence, we need to pass in a [Checkpointer](https://langchain-ai.github.io/langgraph/reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver) when compiling the graph." + "1. This is the `store` we compiled the graph with" ] }, { "cell_type": "code", "execution_count": 6, - "id": "f088933f-264c-477f-9a7d-03f6e9d4ee3a", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "memory = MemorySaver()\n", - "graph = builder.compile(checkpointer=memory)\n", - "# If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass the checkpointer when compiling the graph, since it's done automatically." - ] - }, - { - "cell_type": "markdown", - "id": "7654ebcc-2179-41b4-92d1-6666f6f8634f", - "metadata": {}, - "source": [ - "
    \n", - "

    Note

    \n", - "

    \n", - " If you're using LangGraph Cloud or LangGraph Studio, you don't need to pass checkpointer when compiling the graph, since it's done automatically.\n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "2a1b56c5-bd61-4192-8bdb-458a1e9f0159", - "metadata": {}, - "source": [ - "We can now interact with the agent and see that it remembers previous messages!" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "cfd140f0-a5a6-4697-8115-322242f197b5", + "id": "62ce2760-f23a-4ab1-b73c-d2680e20b611", "metadata": {}, "outputs": [ { @@ -281,96 +1050,563 @@ "text": [ "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", - "hi! I'm bob\n", + "Hi! Remember: my name is Bob\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Hello Bob! It's nice to meet you. How are you doing today? Is there anything in particular you'd like to chat about or any questions you have that I can help you with?\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "input_message = {\"role\": \"user\", \"content\": \"hi! I'm bob\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "1bb07bf8-68b7-4049-a0f1-eb67a4879a3a", - "metadata": {}, - "source": [ - "You can always resume previous threads:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "08ae8246-11d5-40e1-8567-361e5bef8917", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Hi Bob! I'll remember that your name is Bob. How are you doing today?\n", "================================\u001b[1m Human Message \u001b[0m=================================\n", "\n", - "what's my name?\n", + "what is my name?\n", "==================================\u001b[1m Ai Message \u001b[0m==================================\n", "\n", - "Your name is Bob, as you introduced yourself at the beginning of our conversation.\n" + "Your name is Bob.\n" ] } ], "source": [ - "input_message = {\"role\": \"user\", \"content\": \"what's my name?\"}\n", - "for chunk in graph.stream({\"messages\": [input_message]}, config, stream_mode=\"values\"):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "3f47bbfc-d9ef-4288-ba4a-ebbc0136fa9d", - "metadata": {}, - "source": [ - "If we want to start a new conversation, we can pass in a different `thread_id`. Poof! All the memories are gone!" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "273d56a8-f40f-4a51-a27f-7c6bb2bda0ba", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's is my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I apologize, but I don't have access to your personal information, including your name. As an AI language model, I don't have any information about individual users unless it's provided within the conversation. If you'd like to share your name, you're welcome to do so, but otherwise, I won't be able to know or guess it.\n" - ] - } - ], - "source": [ - "input_message = {\"role\": \"user\", \"content\": \"what's my name?\"}\n", + "config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # highlight-next-line\n", + " \"user_id\": \"1\",\n", + " }\n", + "}\n", "for chunk in graph.stream(\n", - " {\"messages\": [input_message]},\n", - " {\"configurable\": {\"thread_id\": \"2\"}},\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + "):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + "\n", + "config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"2\",\n", + " \"user_id\": \"1\",\n", + " }\n", + "}\n", + "\n", + "for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what is my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", " stream_mode=\"values\",\n", "):\n", " chunk[\"messages\"][-1].pretty_print()" ] + }, + { + "cell_type": "markdown", + "id": "cb96703d-3ab3-4d87-a6e6-22f4c0273346", + "metadata": {}, + "source": [ + "!!! info \"Not needed for LangGraph API users\"\n", + "\n", + " If you're using the LangGraph API, **don't need** to provide store when compiling the graph. The API automatically handles storage infrastructure for you." + ] + }, + { + "cell_type": "markdown", + "id": "b585dbb4-bd99-44bb-82e0-477a151556e6", + "metadata": {}, + "source": [ + "### Use in production\n", + "\n", + "In production, you would want to use a checkpointer backed by a database:\n", + "\n", + "```python\n", + "from langgraph.checkpoint.postgres import PostgresSaver\n", + "\n", + "DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n", + "# highlight-next-line\n", + "with PostgresStore.from_conn_string(DB_URI) as store:\n", + " builder = StateGraph(...)\n", + " # highlight-next-line\n", + " graph = builder.compile(store=store)\n", + "```\n", + "\n", + "??? example \"Example: using [Postgres](https://pypi.org/project/langgraph-checkpoint-postgres/) store\"\n", + "\n", + " ```\n", + " pip install -U psycopg psycopg-pool langgraph langgraph-checkpoint-postgres\n", + " ```\n", + "\n", + " !!! Setup\n", + " You need to call `store.setup()` the first time you're using Postgres store\n", + "\n", + " === \"Sync\"\n", + "\n", + " ```python\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " from langgraph.checkpoint.postgres import PostgresSaver\n", + " # highlight-next-line\n", + " from langgraph.store.postgres import PostgresStore\n", + " from langgraph.store.base import BaseStore\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n", + " \n", + " with (\n", + " # highlight-next-line\n", + " PostgresStore.from_conn_string(DB_URI) as store,\n", + " PostgresSaver.from_conn_string(DB_URI) as checkpointer,\n", + " ):\n", + " # store.setup()\n", + " # checkpointer.setup()\n", + " \n", + " def call_model(\n", + " state: MessagesState,\n", + " config: RunnableConfig,\n", + " *,\n", + " # highlight-next-line\n", + " store: BaseStore,\n", + " ):\n", + " user_id = config[\"configurable\"][\"user_id\"]\n", + " namespace = (\"memories\", user_id)\n", + " # highlight-next-line\n", + " memories = store.search(namespace, query=str(state[\"messages\"][-1].content))\n", + " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", + " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", + " \n", + " # Store new memories if the user asks the model to remember\n", + " last_message = state[\"messages\"][-1]\n", + " if \"remember\" in last_message.content.lower():\n", + " memory = \"User name is Bob\"\n", + " # highlight-next-line\n", + " store.put(namespace, str(uuid.uuid4()), {\"data\": memory})\n", + " \n", + " response = model.invoke(\n", + " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", + " )\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " graph = builder.compile(\n", + " checkpointer=checkpointer,\n", + " # highlight-next-line\n", + " store=store,\n", + " )\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # highlight-next-line\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"2\",\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what is my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " === \"Async\"\n", + "\n", + " ```python\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver\n", + " # highlight-next-line\n", + " from langgraph.store.postgres.aio import AsyncPostgresStore\n", + " from langgraph.store.base import BaseStore\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"postgresql://postgres:postgres@localhost:5442/postgres?sslmode=disable\"\n", + " \n", + " async with (\n", + " # highlight-next-line\n", + " AsyncPostgresStore.from_conn_string(DB_URI) as store,\n", + " AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer,\n", + " ):\n", + " # await store.setup()\n", + " # await checkpointer.setup()\n", + " \n", + " async def call_model(\n", + " state: MessagesState,\n", + " config: RunnableConfig,\n", + " *,\n", + " # highlight-next-line\n", + " store: BaseStore,\n", + " ):\n", + " user_id = config[\"configurable\"][\"user_id\"]\n", + " namespace = (\"memories\", user_id)\n", + " # highlight-next-line\n", + " memories = await store.asearch(namespace, query=str(state[\"messages\"][-1].content))\n", + " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", + " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", + " \n", + " # Store new memories if the user asks the model to remember\n", + " last_message = state[\"messages\"][-1]\n", + " if \"remember\" in last_message.content.lower():\n", + " memory = \"User name is Bob\"\n", + " # highlight-next-line\n", + " await store.aput(namespace, str(uuid.uuid4()), {\"data\": memory})\n", + " \n", + " response = await model.ainvoke(\n", + " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", + " )\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " graph = builder.compile(\n", + " checkpointer=checkpointer,\n", + " # highlight-next-line\n", + " store=store,\n", + " )\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # highlight-next-line\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"2\",\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what is my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + "??? example \"Example: using [Redis](https://pypi.org/project/langgraph-checkpoint-redis/) store\"\n", + "\n", + " ```\n", + " pip install -U langgraph langgraph-checkpoint-redis\n", + " ```\n", + "\n", + " !!! Setup\n", + " You need to call `store.setup()` the first time you're using Redis store\n", + "\n", + "\n", + " === \"Sync\"\n", + "\n", + " ```python\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " from langgraph.checkpoint.redis import RedisSaver\n", + " # highlight-next-line\n", + " from langgraph.store.redis import RedisStore\n", + " from langgraph.store.base import BaseStore\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"redis://localhost:6379\"\n", + " \n", + " with (\n", + " # highlight-next-line\n", + " RedisStore.from_conn_string(DB_URI) as store,\n", + " RedisSaver.from_conn_string(DB_URI) as checkpointer,\n", + " ):\n", + " store.setup()\n", + " checkpointer.setup()\n", + " \n", + " def call_model(\n", + " state: MessagesState,\n", + " config: RunnableConfig,\n", + " *,\n", + " # highlight-next-line\n", + " store: BaseStore,\n", + " ):\n", + " user_id = config[\"configurable\"][\"user_id\"]\n", + " namespace = (\"memories\", user_id)\n", + " # highlight-next-line\n", + " memories = store.search(namespace, query=str(state[\"messages\"][-1].content))\n", + " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", + " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", + " \n", + " # Store new memories if the user asks the model to remember\n", + " last_message = state[\"messages\"][-1]\n", + " if \"remember\" in last_message.content.lower():\n", + " memory = \"User name is Bob\"\n", + " # highlight-next-line\n", + " store.put(namespace, str(uuid.uuid4()), {\"data\": memory})\n", + " \n", + " response = model.invoke(\n", + " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", + " )\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " graph = builder.compile(\n", + " checkpointer=checkpointer,\n", + " # highlight-next-line\n", + " store=store,\n", + " )\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # highlight-next-line\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"2\",\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " \n", + " for chunk in graph.stream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what is my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " ```\n", + "\n", + " === \"Async\"\n", + "\n", + " ```python\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.graph import StateGraph, MessagesState, START\n", + " from langgraph.checkpoint.redis.aio import AsyncRedisSaver\n", + " # highlight-next-line\n", + " from langgraph.store.redis.aio import AsyncRedisStore\n", + " from langgraph.store.base import BaseStore\n", + " \n", + " model = init_chat_model(model=\"anthropic:claude-3-5-haiku-latest\")\n", + " \n", + " DB_URI = \"redis://localhost:6379\"\n", + " \n", + " async with (\n", + " # highlight-next-line\n", + " AsyncRedisStore.from_conn_string(DB_URI) as store,\n", + " AsyncRedisSaver.from_conn_string(DB_URI) as checkpointer,\n", + " ):\n", + " # await store.setup()\n", + " # await checkpointer.asetup()\n", + " \n", + " async def call_model(\n", + " state: MessagesState,\n", + " config: RunnableConfig,\n", + " *,\n", + " # highlight-next-line\n", + " store: BaseStore,\n", + " ):\n", + " user_id = config[\"configurable\"][\"user_id\"]\n", + " namespace = (\"memories\", user_id)\n", + " # highlight-next-line\n", + " memories = await store.asearch(namespace, query=str(state[\"messages\"][-1].content))\n", + " info = \"\\n\".join([d.value[\"data\"] for d in memories])\n", + " system_msg = f\"You are a helpful assistant talking to the user. User info: {info}\"\n", + " \n", + " # Store new memories if the user asks the model to remember\n", + " last_message = state[\"messages\"][-1]\n", + " if \"remember\" in last_message.content.lower():\n", + " memory = \"User name is Bob\"\n", + " # highlight-next-line\n", + " await store.aput(namespace, str(uuid.uuid4()), {\"data\": memory})\n", + " \n", + " response = await model.ainvoke(\n", + " [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]\n", + " )\n", + " return {\"messages\": response}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(call_model)\n", + " builder.add_edge(START, \"call_model\")\n", + " \n", + " graph = builder.compile(\n", + " checkpointer=checkpointer,\n", + " # highlight-next-line\n", + " store=store,\n", + " )\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"1\",\n", + " # highlight-next-line\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"Hi! Remember: my name is Bob\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print()\n", + " \n", + " config = {\n", + " \"configurable\": {\n", + " # highlight-next-line\n", + " \"thread_id\": \"2\",\n", + " \"user_id\": \"1\",\n", + " }\n", + " }\n", + " \n", + " async for chunk in graph.astream(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"what is my name?\"}]},\n", + " # highlight-next-line\n", + " config,\n", + " stream_mode=\"values\",\n", + " ):\n", + " chunk[\"messages\"][-1].pretty_print() \n", + " ```" + ] + }, + { + "cell_type": "markdown", + "id": "f8aff878-e1c1-4592-951a-380b5bec1f63", + "metadata": {}, + "source": [ + "### Use semantic search\n", + "\n", + "You can enable semantic search in your graph's memory store: this lets graph agent search for items in the store by semantic similarity.\n", + "\n", + "```python\n", + "from langchain.embeddings import init_embeddings\n", + "from langgraph.store.memory import InMemoryStore\n", + "\n", + "# Create store with semantic search enabled\n", + "embeddings = init_embeddings(\"openai:text-embedding-3-small\")\n", + "store = InMemoryStore(\n", + " index={\n", + " \"embed\": embeddings,\n", + " \"dims\": 1536,\n", + " }\n", + ")\n", + "\n", + "store.put((\"user_123\", \"memories\"), \"1\", {\"text\": \"I love pizza\"})\n", + "store.put((\"user_123\", \"memories\"), \"2\", {\"text\": \"I am a plumber\"})\n", + "\n", + "items = store.search(\n", + " (\"user_123\", \"memories\"), query=\"I'm hungry\", limit=1\n", + ")\n", + "```\n", + "\n", + "??? example \"Long-term memory with semantic search\"\n", + "\n", + " ```python\n", + " from typing import Optional\n", + " \n", + " from langchain.embeddings import init_embeddings\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.store.base import BaseStore\n", + " from langgraph.store.memory import InMemoryStore\n", + " from langgraph.graph import START, MessagesState, StateGraph\n", + " \n", + " llm = init_chat_model(\"openai:gpt-4o-mini\")\n", + " \n", + " # Create store with semantic search enabled\n", + " embeddings = init_embeddings(\"openai:text-embedding-3-small\")\n", + " store = InMemoryStore(\n", + " index={\n", + " \"embed\": embeddings,\n", + " \"dims\": 1536,\n", + " }\n", + " )\n", + " \n", + " store.put((\"user_123\", \"memories\"), \"1\", {\"text\": \"I love pizza\"})\n", + " store.put((\"user_123\", \"memories\"), \"2\", {\"text\": \"I am a plumber\"})\n", + " \n", + " def chat(state, *, store: BaseStore):\n", + " # Search based on user's last message\n", + " items = store.search(\n", + " (\"user_123\", \"memories\"), query=state[\"messages\"][-1].content, limit=2\n", + " )\n", + " memories = \"\\n\".join(item.value[\"text\"] for item in items)\n", + " memories = f\"## Memories of user\\n{memories}\" if memories else \"\"\n", + " response = llm.invoke(\n", + " [\n", + " {\"role\": \"system\", \"content\": f\"You are a helpful assistant.\\n{memories}\"},\n", + " *state[\"messages\"],\n", + " ]\n", + " )\n", + " return {\"messages\": [response]}\n", + " \n", + " \n", + " builder = StateGraph(MessagesState)\n", + " builder.add_node(chat)\n", + " builder.add_edge(START, \"chat\")\n", + " graph = builder.compile(store=store)\n", + " \n", + " for message, metadata in graph.stream(\n", + " input={\"messages\": [{\"role\": \"user\", \"content\": \"I'm hungry\"}]},\n", + " stream_mode=\"messages\",\n", + " ):\n", + " print(message.content, end=\"\")\n", + " ```\n", + "\n", + "See [this guide](../memory/semantic-search/) for more information on how to use semantic search with LangGraph memory store." + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "langgraph", "language": "python", - "name": "python3" + "name": "langgraph" }, "language_info": { "codemirror_mode": { @@ -382,7 +1618,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/docs/docs/how-tos/persistence_mongodb.ipynb b/docs/docs/how-tos/persistence_mongodb.ipynb deleted file mode 100644 index 5b8350595..000000000 --- a/docs/docs/how-tos/persistence_mongodb.ipynb +++ /dev/null @@ -1,454 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to use MongoDB checkpointer for persistence\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "When creating LangGraph agents, you can also set them up so that they persist their state. This allows you to do things like interact with an agent multiple times and have it remember previous interactions. \n", - "\n", - "This reference implementation shows how to use MongoDB as the backend for persisting checkpoint state using the `langgraph-checkpoint-mongodb` library.\n", - "\n", - "For demonstration purposes we add persistence to a [prebuilt ReAct agent](https://langchain-ai.github.io/langgraph/how-tos/create-react-agent/).\n", - "\n", - "In general, you can add a checkpointer to any custom graph that you build like this:\n", - "\n", - "```python\n", - "from langgraph.graph import StateGraph\n", - "\n", - "builder = StateGraph(...)\n", - "# ... define the graph\n", - "checkpointer = # mongodb checkpointer (see examples below)\n", - "graph = builder.compile(checkpointer=checkpointer)\n", - "...\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "456fa19c-93a5-4750-a410-f2d810b964ad", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "To use the MongoDB checkpointer, you will need a MongoDB cluster. Follow [this guide](https://www.mongodb.com/docs/guides/atlas/cluster/) to create a cluster if you don't already have one.\n", - "\n", - "Next, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "faadfb1b-cebe-4dcf-82fd-34044c380bc4", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U pymongo langgraph langgraph-checkpoint-mongodb" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "eca9aafb-a155-407a-8036-682a2f1297d7", - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "OPENAI_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "9a657ea8-fd68-4116-a484-d88b0a906888", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "e26b3204-cca2-414c-800e-7e09032445ae", - "metadata": {}, - "source": [ - "## Define model and tools for the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "ce7ccf56-9914-4557-97b8-13c95f3b7edc", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI\n", - "from langgraph.prebuilt import create_react_agent\n", - "\n", - "\n", - "@tool\n", - "def get_weather(city: Literal[\"nyc\", \"sf\"]):\n", - " \"\"\"Use this to get weather information.\"\"\"\n", - " if city == \"nyc\":\n", - " return \"It might be cloudy in nyc\"\n", - " elif city == \"sf\":\n", - " return \"It's always sunny in sf\"\n", - " else:\n", - " raise AssertionError(\"Unknown city\")\n", - "\n", - "\n", - "tools = [get_weather]\n", - "model = ChatOpenAI(model_name=\"gpt-4o-mini\", temperature=0)" - ] - }, - { - "cell_type": "markdown", - "id": "d92ba022", - "metadata": {}, - "source": [ - "## MongoDB checkpointer usage" - ] - }, - { - "cell_type": "markdown", - "id": "a3b78544", - "metadata": {}, - "source": [ - "### With a connection string\n", - "\n", - "This creates a connection to MongoDB directly using the connection string of your cluster. This is ideal for use in scripts, one-off operations and short-lived applications." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "2e65b3b2-8e3e-4d96-8db4-4846a3bc2eac", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.checkpoint.mongodb import MongoDBSaver\n", - "\n", - "MONGODB_URI = \"localhost:27017\" # replace this with your connection string\n", - "\n", - "with MongoDBSaver.from_conn_string(MONGODB_URI) as checkpointer:\n", - " graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)\n", - " config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - " response = graph.invoke(\n", - " {\"messages\": [(\"human\", \"what's the weather in sf\")]}, config\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "dfcb7da8", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='729afd6a-fdc0-4192-a255-1dac065c79b2'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_YqaO8oU3BhGmIz9VHTxqGyyN', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_39a40c96a0', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-b45c0c12-c68e-4392-92dd-5d325d0a9f60-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_YqaO8oU3BhGmIz9VHTxqGyyN', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}),\n", - " ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='0c72eb29-490b-44df-898f-8454c314eac1', tool_call_id='call_YqaO8oU3BhGmIz9VHTxqGyyN'),\n", - " AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_818c284075', 'finish_reason': 'stop', 'logprobs': None}, id='run-33f54c91-0ba9-48b7-9b25-5a972bbdeea9-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "response" - ] - }, - { - "cell_type": "markdown", - "id": "fe8fcb47", - "metadata": {}, - "source": [ - "### Using the MongoDB client\n", - "\n", - "This creates a connection to MongoDB using the MongoDB client. This is ideal for long-running applications since it allows you to reuse the client instance for multiple database operations without needing to reinitialize the connection each time." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e3a9889d-7a60-455f-96d6-95a8a2e7dbf6", - "metadata": {}, - "outputs": [], - "source": [ - "from pymongo import MongoClient\n", - "\n", - "mongodb_client = MongoClient(MONGODB_URI)\n", - "\n", - "checkpointer = MongoDBSaver(mongodb_client)\n", - "graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)\n", - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "response = graph.invoke({\"messages\": [(\"user\", \"What's the weather in sf?\")]}, config)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "fd2a16ad", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content=\"What's the weather in sf?\", additional_kwargs={}, response_metadata={}, id='4ce68bee-a843-4b08-9c02-7a0e3b010110'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_MvGxq9IU9wvW9mfYKSALHtGu', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-9712c5a4-376c-4812-a0c4-1b522334a59d-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_MvGxq9IU9wvW9mfYKSALHtGu', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}),\n", - " ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='b4eed38d-bcaf-4497-ad08-f21ccd6a8c30', tool_call_id='call_MvGxq9IU9wvW9mfYKSALHtGu'),\n", - " AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c6c4ad75-89ef-4b4f-9ca4-bd52ccb0729b-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "response" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "a0f28d9b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1efb8c75-9262-68b4-8003-1ac1ef198757'}}, checkpoint={'v': 1, 'ts': '2024-12-12T20:26:20.545003+00:00', 'id': '1efb8c75-9262-68b4-8003-1ac1ef198757', 'channel_values': {'messages': [HumanMessage(content=\"What's the weather in sf?\", additional_kwargs={}, response_metadata={}, id='4ce68bee-a843-4b08-9c02-7a0e3b010110'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_MvGxq9IU9wvW9mfYKSALHtGu', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-9712c5a4-376c-4812-a0c4-1b522334a59d-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_MvGxq9IU9wvW9mfYKSALHtGu', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='b4eed38d-bcaf-4497-ad08-f21ccd6a8c30', tool_call_id='call_MvGxq9IU9wvW9mfYKSALHtGu'), AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c6c4ad75-89ef-4b4f-9ca4-bd52ccb0729b-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'agent': 'agent'}, 'channel_versions': {'__start__': 2, 'messages': 5, 'start:agent': 3, 'agent': 5, 'branch:agent:should_continue:tools': 4, 'tools': 5}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': 1}, 'agent': {'start:agent': 2, 'tools': 4}, 'tools': {'branch:agent:should_continue:tools': 3}}, 'pending_sends': []}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-c6c4ad75-89ef-4b4f-9ca4-bd52ccb0729b-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}}, 'thread_id': '2', 'step': 3, 'parents': {}}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1efb8c75-8d89-6ffe-8002-84a4312c4fed'}}, pending_writes=[])" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Retrieve the latest checkpoint for the given thread ID\n", - "# To retrieve a specific checkpoint, pass the checkpoint_id in the config\n", - "checkpointer.get_tuple(config)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "935a00bf-fc2f-48d4-a8d7-56900a7071e2", - "metadata": {}, - "outputs": [], - "source": [ - "# Remember to close the connection after you're done\n", - "mongodb_client.close()" - ] - }, - { - "cell_type": "markdown", - "id": "47c33104", - "metadata": {}, - "source": [ - "### Using an async connection\n", - "\n", - "This creates a short-lived asynchronous connection to MongoDB. \n", - "\n", - "Async connections allow non-blocking database operations. This means other parts of your application can continue running while waiting for database operations to complete. It's particularly useful in high-concurrency scenarios or when dealing with I/O-bound operations." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "f7aaec32-1755-4ae4-a40b-ade58491a5bb", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.checkpoint.mongodb.aio import AsyncMongoDBSaver\n", - "\n", - "async with AsyncMongoDBSaver.from_conn_string(MONGODB_URI) as checkpointer:\n", - " graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)\n", - " config = {\"configurable\": {\"thread_id\": \"3\"}}\n", - " response = await graph.ainvoke(\n", - " {\"messages\": [(\"user\", \"What's the weather in sf?\")]}, config\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "40810610", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content=\"What's the weather in sf?\", additional_kwargs={}, response_metadata={}, id='fed70fe6-1b2e-4481-9bfc-063df3b587dc'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_miRiF3vPQv98wlDHl6CeRxBy', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-7f2d5153-973e-4a9e-8b71-a77625c342cf-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_miRiF3vPQv98wlDHl6CeRxBy', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}),\n", - " ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='49035e8e-8aee-4d9d-88ab-9a1bc10ecbd3', tool_call_id='call_miRiF3vPQv98wlDHl6CeRxBy'),\n", - " AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-9403d502-391e-4407-99fd-eec8ed184e50-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "response" - ] - }, - { - "cell_type": "markdown", - "id": "c9c39f64", - "metadata": {}, - "source": [ - "### Using the async MongoDB client\n", - "\n", - "This routes connections to MongoDB through an asynchronous MongoDB client." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "623b81ea-9415-4c49-9ded-9c7830a3ef6b", - "metadata": {}, - "outputs": [], - "source": [ - "from pymongo import AsyncMongoClient\n", - "\n", - "async_mongodb_client = AsyncMongoClient(MONGODB_URI)\n", - "\n", - "checkpointer = AsyncMongoDBSaver(async_mongodb_client)\n", - "graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)\n", - "config = {\"configurable\": {\"thread_id\": \"4\"}}\n", - "response = await graph.ainvoke(\n", - " {\"messages\": [(\"user\", \"What's the weather in sf?\")]}, config\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "80ec0420", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content=\"What's the weather in sf?\", additional_kwargs={}, response_metadata={}, id='58282e2b-4cc1-40a1-8e65-420a2177bbd6'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_SJFViVHl1tYTZDoZkNN3ePhJ', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_bba3c8e70b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-131af8c1-d388-4d7f-9137-da59ebd5fefd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_SJFViVHl1tYTZDoZkNN3ePhJ', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}),\n", - " ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='6090a56f-177b-4d3f-b16a-9c05f23800e3', tool_call_id='call_SJFViVHl1tYTZDoZkNN3ePhJ'),\n", - " AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-6ff5ddf5-6e13-4126-8df9-81c8638355fc-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "response" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "a948dcd4", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CheckpointTuple(config={'configurable': {'thread_id': '4', 'checkpoint_ns': '', 'checkpoint_id': '1efb8c76-21f4-6d10-8003-9496e1754e93'}}, checkpoint={'v': 1, 'ts': '2024-12-12T20:26:35.599560+00:00', 'id': '1efb8c76-21f4-6d10-8003-9496e1754e93', 'channel_values': {'messages': [HumanMessage(content=\"What's the weather in sf?\", additional_kwargs={}, response_metadata={}, id='58282e2b-4cc1-40a1-8e65-420a2177bbd6'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_SJFViVHl1tYTZDoZkNN3ePhJ', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_bba3c8e70b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-131af8c1-d388-4d7f-9137-da59ebd5fefd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_SJFViVHl1tYTZDoZkNN3ePhJ', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}}), ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='6090a56f-177b-4d3f-b16a-9c05f23800e3', tool_call_id='call_SJFViVHl1tYTZDoZkNN3ePhJ'), AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-6ff5ddf5-6e13-4126-8df9-81c8638355fc-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})], 'agent': 'agent'}, 'channel_versions': {'__start__': 2, 'messages': 5, 'start:agent': 3, 'agent': 5, 'branch:agent:should_continue:tools': 4, 'tools': 5}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': 1}, 'agent': {'start:agent': 2, 'tools': 4}, 'tools': {'branch:agent:should_continue:tools': 3}}, 'pending_sends': []}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='The weather in San Francisco is always sunny!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_6fc10e10eb', 'finish_reason': 'stop', 'logprobs': None}, id='run-6ff5ddf5-6e13-4126-8df9-81c8638355fc-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}}, 'thread_id': '4', 'step': 3, 'parents': {}}, parent_config={'configurable': {'thread_id': '4', 'checkpoint_ns': '', 'checkpoint_id': '1efb8c76-1c6c-6474-8002-9c2595cd481c'}}, pending_writes=[])\n" - ] - } - ], - "source": [ - "# Retrieve the latest checkpoint for the given thread ID\n", - "# To retrieve a specific checkpoint, pass the checkpoint_id in the config\n", - "latest_checkpoint = await checkpointer.aget_tuple(config)\n", - "print(latest_checkpoint)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "68ee7400-645d-4d00-b118-554698d8496a", - "metadata": {}, - "outputs": [], - "source": [ - "# Remember to close the connection after you're done\n", - "await async_mongodb_client.close()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/persistence_redis.ipynb b/docs/docs/how-tos/persistence_redis.ipynb deleted file mode 100644 index 8fab22b3c..000000000 --- a/docs/docs/how-tos/persistence_redis.ipynb +++ /dev/null @@ -1,1095 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to create a custom checkpointer using Redis\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "When creating LangGraph agents, you can also set them up so that they persist their state. This allows you to do things like interact with an agent multiple times and have it remember previous interactions.\n", - "\n", - "This reference implementation shows how to use Redis as the backend for persisting checkpoint state. Make sure that you have Redis running on port `6379` for going through this guide.\n", - "\n", - "
    \n", - "

    Note

    \n", - "

    \n", - " This is a **reference** implementation. You can implement your own checkpointer using a different database or modify this one as long as it conforms to the BaseCheckpointSaver interface.\n", - "

    \n", - "
    \n", - "\n", - "For demonstration purposes we add persistence to the [pre-built create react agent](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent).\n", - "\n", - "In general, you can add a checkpointer to any custom graph that you build like this:\n", - "\n", - "```python\n", - "from langgraph.graph import StateGraph\n", - "\n", - "builder = StateGraph(....)\n", - "# ... define the graph\n", - "checkpointer = # redis checkpointer (see examples below)\n", - "graph = builder.compile(checkpointer=checkpointer)\n", - "...\n", - "```" - ] - }, - { - "cell_type": "markdown", - "id": "456fa19c-93a5-4750-a410-f2d810b964ad", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "faadfb1b-cebe-4dcf-82fd-34044c380bc4", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U redis langgraph langchain_openai" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eca9aafb-a155-407a-8036-682a2f1297d7", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "49c80b63", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "ecb23436-f238-4f8c-a2b7-67c7956121e2", - "metadata": {}, - "source": [ - "## Checkpointer implementation" - ] - }, - { - "cell_type": "markdown", - "id": "752d570c-a9ad-48eb-a317-adf9fc700803", - "metadata": {}, - "source": [ - "### Define imports and helper functions" - ] - }, - { - "cell_type": "markdown", - "id": "cdea5bf7-4865-46f3-9bec-00147dd79895", - "metadata": {}, - "source": [ - "First, let's define some imports and shared utilities for both `RedisSaver` and `AsyncRedisSaver`" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "61e63348-7d56-4177-90bf-aad7645a707a", - "metadata": {}, - "outputs": [], - "source": [ - "\"\"\"Implementation of a langgraph checkpoint saver using Redis.\"\"\"\n", - "from contextlib import asynccontextmanager, contextmanager\n", - "from typing import (\n", - " Any,\n", - " AsyncGenerator,\n", - " AsyncIterator,\n", - " Iterator,\n", - " List,\n", - " Optional,\n", - " Tuple,\n", - ")\n", - "\n", - "from langchain_core.runnables import RunnableConfig\n", - "\n", - "from langgraph.checkpoint.base import (\n", - " WRITES_IDX_MAP,\n", - " BaseCheckpointSaver,\n", - " ChannelVersions,\n", - " Checkpoint,\n", - " CheckpointMetadata,\n", - " CheckpointTuple,\n", - " PendingWrite,\n", - " get_checkpoint_id,\n", - ")\n", - "from langgraph.checkpoint.serde.base import SerializerProtocol\n", - "from redis import Redis\n", - "from redis.asyncio import Redis as AsyncRedis\n", - "\n", - "REDIS_KEY_SEPARATOR = \"$\"\n", - "\n", - "\n", - "# Utilities shared by both RedisSaver and AsyncRedisSaver\n", - "\n", - "\n", - "def _make_redis_checkpoint_key(\n", - " thread_id: str, checkpoint_ns: str, checkpoint_id: str\n", - ") -> str:\n", - " return REDIS_KEY_SEPARATOR.join(\n", - " [\"checkpoint\", thread_id, checkpoint_ns, checkpoint_id]\n", - " )\n", - "\n", - "\n", - "def _make_redis_checkpoint_writes_key(\n", - " thread_id: str,\n", - " checkpoint_ns: str,\n", - " checkpoint_id: str,\n", - " task_id: str,\n", - " idx: Optional[int],\n", - ") -> str:\n", - " if idx is None:\n", - " return REDIS_KEY_SEPARATOR.join(\n", - " [\"writes\", thread_id, checkpoint_ns, checkpoint_id, task_id]\n", - " )\n", - "\n", - " return REDIS_KEY_SEPARATOR.join(\n", - " [\"writes\", thread_id, checkpoint_ns, checkpoint_id, task_id, str(idx)]\n", - " )\n", - "\n", - "\n", - "def _parse_redis_checkpoint_key(redis_key: str) -> dict:\n", - " namespace, thread_id, checkpoint_ns, checkpoint_id = redis_key.split(\n", - " REDIS_KEY_SEPARATOR\n", - " )\n", - " if namespace != \"checkpoint\":\n", - " raise ValueError(\"Expected checkpoint key to start with 'checkpoint'\")\n", - "\n", - " return {\n", - " \"thread_id\": thread_id,\n", - " \"checkpoint_ns\": checkpoint_ns,\n", - " \"checkpoint_id\": checkpoint_id,\n", - " }\n", - "\n", - "\n", - "def _parse_redis_checkpoint_writes_key(redis_key: str) -> dict:\n", - " namespace, thread_id, checkpoint_ns, checkpoint_id, task_id, idx = redis_key.split(\n", - " REDIS_KEY_SEPARATOR\n", - " )\n", - " if namespace != \"writes\":\n", - " raise ValueError(\"Expected checkpoint key to start with 'checkpoint'\")\n", - "\n", - " return {\n", - " \"thread_id\": thread_id,\n", - " \"checkpoint_ns\": checkpoint_ns,\n", - " \"checkpoint_id\": checkpoint_id,\n", - " \"task_id\": task_id,\n", - " \"idx\": idx,\n", - " }\n", - "\n", - "\n", - "def _filter_keys(\n", - " keys: List[str], before: Optional[RunnableConfig], limit: Optional[int]\n", - ") -> list:\n", - " \"\"\"Filter and sort Redis keys based on optional criteria.\"\"\"\n", - " if before:\n", - " keys = [\n", - " k\n", - " for k in keys\n", - " if _parse_redis_checkpoint_key(k.decode())[\"checkpoint_id\"]\n", - " < before[\"configurable\"][\"checkpoint_id\"]\n", - " ]\n", - "\n", - " keys = sorted(\n", - " keys,\n", - " key=lambda k: _parse_redis_checkpoint_key(k.decode())[\"checkpoint_id\"],\n", - " reverse=True,\n", - " )\n", - " if limit:\n", - " keys = keys[:limit]\n", - " return keys\n", - "\n", - "\n", - "def _load_writes(\n", - " serde: SerializerProtocol, task_id_to_data: dict[tuple[str, str], dict]\n", - ") -> list[PendingWrite]:\n", - " \"\"\"Deserialize pending writes.\"\"\"\n", - " writes = [\n", - " (\n", - " task_id,\n", - " data[b\"channel\"].decode(),\n", - " serde.loads_typed((data[b\"type\"].decode(), data[b\"value\"])),\n", - " )\n", - " for (task_id, _), data in task_id_to_data.items()\n", - " ]\n", - " return writes\n", - "\n", - "\n", - "def _parse_redis_checkpoint_data(\n", - " serde: SerializerProtocol,\n", - " key: str,\n", - " data: dict,\n", - " pending_writes: Optional[List[PendingWrite]] = None,\n", - ") -> Optional[CheckpointTuple]:\n", - " \"\"\"Parse checkpoint data retrieved from Redis.\"\"\"\n", - " if not data:\n", - " return None\n", - "\n", - " parsed_key = _parse_redis_checkpoint_key(key)\n", - " thread_id = parsed_key[\"thread_id\"]\n", - " checkpoint_ns = parsed_key[\"checkpoint_ns\"]\n", - " checkpoint_id = parsed_key[\"checkpoint_id\"]\n", - " config = {\n", - " \"configurable\": {\n", - " \"thread_id\": thread_id,\n", - " \"checkpoint_ns\": checkpoint_ns,\n", - " \"checkpoint_id\": checkpoint_id,\n", - " }\n", - " }\n", - "\n", - " checkpoint = serde.loads_typed((data[b\"type\"].decode(), data[b\"checkpoint\"]))\n", - " metadata = serde.loads(data[b\"metadata\"].decode())\n", - " parent_checkpoint_id = data.get(b\"parent_checkpoint_id\", b\"\").decode()\n", - " parent_config = (\n", - " {\n", - " \"configurable\": {\n", - " \"thread_id\": thread_id,\n", - " \"checkpoint_ns\": checkpoint_ns,\n", - " \"checkpoint_id\": parent_checkpoint_id,\n", - " }\n", - " }\n", - " if parent_checkpoint_id\n", - " else None\n", - " )\n", - " return CheckpointTuple(\n", - " config=config,\n", - " checkpoint=checkpoint,\n", - " metadata=metadata,\n", - " parent_config=parent_config,\n", - " pending_writes=pending_writes,\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "922822a8-f7d2-41ce-bada-206fc125c20c", - "metadata": {}, - "source": [ - "### RedisSaver" - ] - }, - { - "cell_type": "markdown", - "id": "c216852b-8318-4927-9000-1361d3ca81e8", - "metadata": {}, - "source": [ - "Below is an implementation of RedisSaver (for synchronous use of graph, i.e. `.invoke()`, `.stream()`). RedisSaver implements four methods that are required for any checkpointer:\n", - "\n", - "- `.put` - Store a checkpoint with its configuration and metadata.\n", - "- `.put_writes` - Store intermediate writes linked to a checkpoint (i.e. pending writes).\n", - "- `.get_tuple` - Fetch a checkpoint tuple using for a given configuration (`thread_id` and `checkpoint_id`).\n", - "- `.list` - List checkpoints that match a given configuration and filter criteria." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "98c8d65e-eb95-4cbd-8975-d33a52351d03", - "metadata": {}, - "outputs": [], - "source": [ - "class RedisSaver(BaseCheckpointSaver):\n", - " \"\"\"Redis-based checkpoint saver implementation.\"\"\"\n", - "\n", - " conn: Redis\n", - "\n", - " def __init__(self, conn: Redis):\n", - " super().__init__()\n", - " self.conn = conn\n", - "\n", - " @classmethod\n", - " @contextmanager\n", - " def from_conn_info(cls, *, host: str, port: int, db: int) -> Iterator[\"RedisSaver\"]:\n", - " conn = None\n", - " try:\n", - " conn = Redis(host=host, port=port, db=db)\n", - " yield RedisSaver(conn)\n", - " finally:\n", - " if conn:\n", - " conn.close()\n", - "\n", - " def put(\n", - " self,\n", - " config: RunnableConfig,\n", - " checkpoint: Checkpoint,\n", - " metadata: CheckpointMetadata,\n", - " new_versions: ChannelVersions,\n", - " ) -> RunnableConfig:\n", - " \"\"\"Save a checkpoint to Redis.\n", - "\n", - " Args:\n", - " config (RunnableConfig): The config to associate with the checkpoint.\n", - " checkpoint (Checkpoint): The checkpoint to save.\n", - " metadata (CheckpointMetadata): Additional metadata to save with the checkpoint.\n", - " new_versions (ChannelVersions): New channel versions as of this write.\n", - "\n", - " Returns:\n", - " RunnableConfig: Updated configuration after storing the checkpoint.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_ns = config[\"configurable\"][\"checkpoint_ns\"]\n", - " checkpoint_id = checkpoint[\"id\"]\n", - " parent_checkpoint_id = config[\"configurable\"].get(\"checkpoint_id\")\n", - " key = _make_redis_checkpoint_key(thread_id, checkpoint_ns, checkpoint_id)\n", - "\n", - " type_, serialized_checkpoint = self.serde.dumps_typed(checkpoint)\n", - " serialized_metadata = self.serde.dumps(metadata)\n", - " data = {\n", - " \"checkpoint\": serialized_checkpoint,\n", - " \"type\": type_,\n", - " \"metadata\": serialized_metadata,\n", - " \"parent_checkpoint_id\": parent_checkpoint_id\n", - " if parent_checkpoint_id\n", - " else \"\",\n", - " }\n", - " self.conn.hset(key, mapping=data)\n", - " return {\n", - " \"configurable\": {\n", - " \"thread_id\": thread_id,\n", - " \"checkpoint_ns\": checkpoint_ns,\n", - " \"checkpoint_id\": checkpoint_id,\n", - " }\n", - " }\n", - "\n", - " def put_writes(\n", - " self,\n", - " config: RunnableConfig,\n", - " writes: List[Tuple[str, Any]],\n", - " task_id: str,\n", - " ) -> None:\n", - " \"\"\"Store intermediate writes linked to a checkpoint.\n", - "\n", - " Args:\n", - " config (RunnableConfig): Configuration of the related checkpoint.\n", - " writes (Sequence[Tuple[str, Any]]): List of writes to store, each as (channel, value) pair.\n", - " task_id (str): Identifier for the task creating the writes.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_ns = config[\"configurable\"][\"checkpoint_ns\"]\n", - " checkpoint_id = config[\"configurable\"][\"checkpoint_id\"]\n", - "\n", - " for idx, (channel, value) in enumerate(writes):\n", - " key = _make_redis_checkpoint_writes_key(\n", - " thread_id,\n", - " checkpoint_ns,\n", - " checkpoint_id,\n", - " task_id,\n", - " WRITES_IDX_MAP.get(channel, idx),\n", - " )\n", - " type_, serialized_value = self.serde.dumps_typed(value)\n", - " data = {\"channel\": channel, \"type\": type_, \"value\": serialized_value}\n", - " if all(w[0] in WRITES_IDX_MAP for w in writes):\n", - " # Use HSET which will overwrite existing values\n", - " self.conn.hset(key, mapping=data)\n", - " else:\n", - " # Use HSETNX which will not overwrite existing values\n", - " for field, value in data.items():\n", - " self.conn.hsetnx(key, field, value)\n", - "\n", - " def get_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:\n", - " \"\"\"Get a checkpoint tuple from Redis.\n", - "\n", - " This method retrieves a checkpoint tuple from Redis based on the\n", - " provided config. If the config contains a \"checkpoint_id\" key, the checkpoint with\n", - " the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint\n", - " for the given thread ID is retrieved.\n", - "\n", - " Args:\n", - " config (RunnableConfig): The config to use for retrieving the checkpoint.\n", - "\n", - " Returns:\n", - " Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_id = get_checkpoint_id(config)\n", - " checkpoint_ns = config[\"configurable\"].get(\"checkpoint_ns\", \"\")\n", - "\n", - " checkpoint_key = self._get_checkpoint_key(\n", - " self.conn, thread_id, checkpoint_ns, checkpoint_id\n", - " )\n", - " if not checkpoint_key:\n", - " return None\n", - "\n", - " checkpoint_data = self.conn.hgetall(checkpoint_key)\n", - "\n", - " # load pending writes\n", - " checkpoint_id = (\n", - " checkpoint_id\n", - " or _parse_redis_checkpoint_key(checkpoint_key)[\"checkpoint_id\"]\n", - " )\n", - " pending_writes = self._load_pending_writes(\n", - " thread_id, checkpoint_ns, checkpoint_id\n", - " )\n", - " return _parse_redis_checkpoint_data(\n", - " self.serde, checkpoint_key, checkpoint_data, pending_writes=pending_writes\n", - " )\n", - "\n", - " def list(\n", - " self,\n", - " config: Optional[RunnableConfig],\n", - " *,\n", - " # TODO: implement filtering\n", - " filter: Optional[dict[str, Any]] = None,\n", - " before: Optional[RunnableConfig] = None,\n", - " limit: Optional[int] = None,\n", - " ) -> Iterator[CheckpointTuple]:\n", - " \"\"\"List checkpoints from the database.\n", - "\n", - " This method retrieves a list of checkpoint tuples from Redis based\n", - " on the provided config. The checkpoints are ordered by checkpoint ID in descending order (newest first).\n", - "\n", - " Args:\n", - " config (RunnableConfig): The config to use for listing the checkpoints.\n", - " filter (Optional[Dict[str, Any]]): Additional filtering criteria for metadata. Defaults to None.\n", - " before (Optional[RunnableConfig]): If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.\n", - " limit (Optional[int]): The maximum number of checkpoints to return. Defaults to None.\n", - "\n", - " Yields:\n", - " Iterator[CheckpointTuple]: An iterator of checkpoint tuples.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_ns = config[\"configurable\"].get(\"checkpoint_ns\", \"\")\n", - " pattern = _make_redis_checkpoint_key(thread_id, checkpoint_ns, \"*\")\n", - "\n", - " keys = _filter_keys(self.conn.keys(pattern), before, limit)\n", - " for key in keys:\n", - " data = self.conn.hgetall(key)\n", - " if data and b\"checkpoint\" in data and b\"metadata\" in data:\n", - " # load pending writes\n", - " checkpoint_id = _parse_redis_checkpoint_key(key.decode())[\n", - " \"checkpoint_id\"\n", - " ]\n", - " pending_writes = self._load_pending_writes(\n", - " thread_id, checkpoint_ns, checkpoint_id\n", - " )\n", - " yield _parse_redis_checkpoint_data(\n", - " self.serde, key.decode(), data, pending_writes=pending_writes\n", - " )\n", - "\n", - " def _load_pending_writes(\n", - " self, thread_id: str, checkpoint_ns: str, checkpoint_id: str\n", - " ) -> List[PendingWrite]:\n", - " writes_key = _make_redis_checkpoint_writes_key(\n", - " thread_id, checkpoint_ns, checkpoint_id, \"*\", None\n", - " )\n", - " matching_keys = self.conn.keys(pattern=writes_key)\n", - " parsed_keys = [\n", - " _parse_redis_checkpoint_writes_key(key.decode()) for key in matching_keys\n", - " ]\n", - " pending_writes = _load_writes(\n", - " self.serde,\n", - " {\n", - " (parsed_key[\"task_id\"], parsed_key[\"idx\"]): self.conn.hgetall(key)\n", - " for key, parsed_key in sorted(\n", - " zip(matching_keys, parsed_keys), key=lambda x: x[1][\"idx\"]\n", - " )\n", - " },\n", - " )\n", - " return pending_writes\n", - "\n", - " def _get_checkpoint_key(\n", - " self, conn, thread_id: str, checkpoint_ns: str, checkpoint_id: Optional[str]\n", - " ) -> Optional[str]:\n", - " \"\"\"Determine the Redis key for a checkpoint.\"\"\"\n", - " if checkpoint_id:\n", - " return _make_redis_checkpoint_key(thread_id, checkpoint_ns, checkpoint_id)\n", - "\n", - " all_keys = conn.keys(_make_redis_checkpoint_key(thread_id, checkpoint_ns, \"*\"))\n", - " if not all_keys:\n", - " return None\n", - "\n", - " latest_key = max(\n", - " all_keys,\n", - " key=lambda k: _parse_redis_checkpoint_key(k.decode())[\"checkpoint_id\"],\n", - " )\n", - " return latest_key.decode()" - ] - }, - { - "cell_type": "markdown", - "id": "ec21ff00-75a7-4789-b863-93fffcc0b32d", - "metadata": {}, - "source": [ - "### AsyncRedis" - ] - }, - { - "cell_type": "markdown", - "id": "9e5ad763-12ab-4918-af40-0be85678e35b", - "metadata": {}, - "source": [ - "Below is a reference implementation of AsyncRedisSaver (for asynchronous use of graph, i.e. `.ainvoke()`, `.astream()`). AsyncRedisSaver implements four methods that are required for any async checkpointer:\n", - "\n", - "- `.aput` - Store a checkpoint with its configuration and metadata.\n", - "- `.aput_writes` - Store intermediate writes linked to a checkpoint (i.e. pending writes).\n", - "- `.aget_tuple` - Fetch a checkpoint tuple using for a given configuration (`thread_id` and `checkpoint_id`).\n", - "- `.alist` - List checkpoints that match a given configuration and filter criteria." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "888302ee-c201-498f-b6e3-69ec5f1a039c", - "metadata": {}, - "outputs": [], - "source": [ - "class AsyncRedisSaver(BaseCheckpointSaver):\n", - " \"\"\"Async redis-based checkpoint saver implementation.\"\"\"\n", - "\n", - " conn: AsyncRedis\n", - "\n", - " def __init__(self, conn: AsyncRedis):\n", - " super().__init__()\n", - " self.conn = conn\n", - "\n", - " @classmethod\n", - " @asynccontextmanager\n", - " async def from_conn_info(\n", - " cls, *, host: str, port: int, db: int\n", - " ) -> AsyncIterator[\"AsyncRedisSaver\"]:\n", - " conn = None\n", - " try:\n", - " conn = AsyncRedis(host=host, port=port, db=db)\n", - " yield AsyncRedisSaver(conn)\n", - " finally:\n", - " if conn:\n", - " await conn.aclose()\n", - "\n", - " async def aput(\n", - " self,\n", - " config: RunnableConfig,\n", - " checkpoint: Checkpoint,\n", - " metadata: CheckpointMetadata,\n", - " new_versions: ChannelVersions,\n", - " ) -> RunnableConfig:\n", - " \"\"\"Save a checkpoint to the database asynchronously.\n", - "\n", - " This method saves a checkpoint to Redis. The checkpoint is associated\n", - " with the provided config and its parent config (if any).\n", - "\n", - " Args:\n", - " config (RunnableConfig): The config to associate with the checkpoint.\n", - " checkpoint (Checkpoint): The checkpoint to save.\n", - " metadata (CheckpointMetadata): Additional metadata to save with the checkpoint.\n", - " new_versions (ChannelVersions): New channel versions as of this write.\n", - "\n", - " Returns:\n", - " RunnableConfig: Updated configuration after storing the checkpoint.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_ns = config[\"configurable\"][\"checkpoint_ns\"]\n", - " checkpoint_id = checkpoint[\"id\"]\n", - " parent_checkpoint_id = config[\"configurable\"].get(\"checkpoint_id\")\n", - " key = _make_redis_checkpoint_key(thread_id, checkpoint_ns, checkpoint_id)\n", - "\n", - " type_, serialized_checkpoint = self.serde.dumps_typed(checkpoint)\n", - " serialized_metadata = self.serde.dumps(metadata)\n", - " data = {\n", - " \"checkpoint\": serialized_checkpoint,\n", - " \"type\": type_,\n", - " \"checkpoint_id\": checkpoint_id,\n", - " \"metadata\": serialized_metadata,\n", - " \"parent_checkpoint_id\": parent_checkpoint_id\n", - " if parent_checkpoint_id\n", - " else \"\",\n", - " }\n", - "\n", - " await self.conn.hset(key, mapping=data)\n", - " return {\n", - " \"configurable\": {\n", - " \"thread_id\": thread_id,\n", - " \"checkpoint_ns\": checkpoint_ns,\n", - " \"checkpoint_id\": checkpoint_id,\n", - " }\n", - " }\n", - "\n", - " async def aput_writes(\n", - " self,\n", - " config: RunnableConfig,\n", - " writes: List[Tuple[str, Any]],\n", - " task_id: str,\n", - " ) -> None:\n", - " \"\"\"Store intermediate writes linked to a checkpoint asynchronously.\n", - "\n", - " This method saves intermediate writes associated with a checkpoint to the database.\n", - "\n", - " Args:\n", - " config (RunnableConfig): Configuration of the related checkpoint.\n", - " writes (Sequence[Tuple[str, Any]]): List of writes to store, each as (channel, value) pair.\n", - " task_id (str): Identifier for the task creating the writes.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_ns = config[\"configurable\"][\"checkpoint_ns\"]\n", - " checkpoint_id = config[\"configurable\"][\"checkpoint_id\"]\n", - "\n", - " for idx, (channel, value) in enumerate(writes):\n", - " key = _make_redis_checkpoint_writes_key(\n", - " thread_id,\n", - " checkpoint_ns,\n", - " checkpoint_id,\n", - " task_id,\n", - " WRITES_IDX_MAP.get(channel, idx),\n", - " )\n", - " type_, serialized_value = self.serde.dumps_typed(value)\n", - " data = {\"channel\": channel, \"type\": type_, \"value\": serialized_value}\n", - " if all(w[0] in WRITES_IDX_MAP for w in writes):\n", - " # Use HSET which will overwrite existing values\n", - " await self.conn.hset(key, mapping=data)\n", - " else:\n", - " # Use HSETNX which will not overwrite existing values\n", - " for field, value in data.items():\n", - " await self.conn.hsetnx(key, field, value)\n", - "\n", - " async def aget_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:\n", - " \"\"\"Get a checkpoint tuple from Redis asynchronously.\n", - "\n", - " This method retrieves a checkpoint tuple from Redis based on the\n", - " provided config. If the config contains a \"checkpoint_id\" key, the checkpoint with\n", - " the matching thread ID and checkpoint ID is retrieved. Otherwise, the latest checkpoint\n", - " for the given thread ID is retrieved.\n", - "\n", - " Args:\n", - " config (RunnableConfig): The config to use for retrieving the checkpoint.\n", - "\n", - " Returns:\n", - " Optional[CheckpointTuple]: The retrieved checkpoint tuple, or None if no matching checkpoint was found.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_id = get_checkpoint_id(config)\n", - " checkpoint_ns = config[\"configurable\"].get(\"checkpoint_ns\", \"\")\n", - "\n", - " checkpoint_key = await self._aget_checkpoint_key(\n", - " self.conn, thread_id, checkpoint_ns, checkpoint_id\n", - " )\n", - " if not checkpoint_key:\n", - " return None\n", - " checkpoint_data = await self.conn.hgetall(checkpoint_key)\n", - "\n", - " # load pending writes\n", - " checkpoint_id = (\n", - " checkpoint_id\n", - " or _parse_redis_checkpoint_key(checkpoint_key)[\"checkpoint_id\"]\n", - " )\n", - " pending_writes = await self._aload_pending_writes(\n", - " thread_id, checkpoint_ns, checkpoint_id\n", - " )\n", - " return _parse_redis_checkpoint_data(\n", - " self.serde, checkpoint_key, checkpoint_data, pending_writes=pending_writes\n", - " )\n", - "\n", - " async def alist(\n", - " self,\n", - " config: Optional[RunnableConfig],\n", - " *,\n", - " # TODO: implement filtering\n", - " filter: Optional[dict[str, Any]] = None,\n", - " before: Optional[RunnableConfig] = None,\n", - " limit: Optional[int] = None,\n", - " ) -> AsyncGenerator[CheckpointTuple, None]:\n", - " \"\"\"List checkpoints from Redis asynchronously.\n", - "\n", - " This method retrieves a list of checkpoint tuples from Redis based\n", - " on the provided config. The checkpoints are ordered by checkpoint ID in descending order (newest first).\n", - "\n", - " Args:\n", - " config (Optional[RunnableConfig]): Base configuration for filtering checkpoints.\n", - " filter (Optional[Dict[str, Any]]): Additional filtering criteria for metadata.\n", - " before (Optional[RunnableConfig]): If provided, only checkpoints before the specified checkpoint ID are returned. Defaults to None.\n", - " limit (Optional[int]): Maximum number of checkpoints to return.\n", - "\n", - " Yields:\n", - " AsyncIterator[CheckpointTuple]: An asynchronous iterator of matching checkpoint tuples.\n", - " \"\"\"\n", - " thread_id = config[\"configurable\"][\"thread_id\"]\n", - " checkpoint_ns = config[\"configurable\"].get(\"checkpoint_ns\", \"\")\n", - " pattern = _make_redis_checkpoint_key(thread_id, checkpoint_ns, \"*\")\n", - " keys = _filter_keys(await self.conn.keys(pattern), before, limit)\n", - " for key in keys:\n", - " data = await self.conn.hgetall(key)\n", - " if data and b\"checkpoint\" in data and b\"metadata\" in data:\n", - " checkpoint_id = _parse_redis_checkpoint_key(key.decode())[\n", - " \"checkpoint_id\"\n", - " ]\n", - " pending_writes = await self._aload_pending_writes(\n", - " thread_id, checkpoint_ns, checkpoint_id\n", - " )\n", - " yield _parse_redis_checkpoint_data(\n", - " self.serde, key.decode(), data, pending_writes=pending_writes\n", - " )\n", - "\n", - " async def _aload_pending_writes(\n", - " self, thread_id: str, checkpoint_ns: str, checkpoint_id: str\n", - " ) -> List[PendingWrite]:\n", - " writes_key = _make_redis_checkpoint_writes_key(\n", - " thread_id, checkpoint_ns, checkpoint_id, \"*\", None\n", - " )\n", - " matching_keys = await self.conn.keys(pattern=writes_key)\n", - " parsed_keys = [\n", - " _parse_redis_checkpoint_writes_key(key.decode()) for key in matching_keys\n", - " ]\n", - " pending_writes = _load_writes(\n", - " self.serde,\n", - " {\n", - " (parsed_key[\"task_id\"], parsed_key[\"idx\"]): await self.conn.hgetall(key)\n", - " for key, parsed_key in sorted(\n", - " zip(matching_keys, parsed_keys), key=lambda x: x[1][\"idx\"]\n", - " )\n", - " },\n", - " )\n", - " return pending_writes\n", - "\n", - " async def _aget_checkpoint_key(\n", - " self, conn, thread_id: str, checkpoint_ns: str, checkpoint_id: Optional[str]\n", - " ) -> Optional[str]:\n", - " \"\"\"Asynchronously determine the Redis key for a checkpoint.\"\"\"\n", - " if checkpoint_id:\n", - " return _make_redis_checkpoint_key(thread_id, checkpoint_ns, checkpoint_id)\n", - "\n", - " all_keys = await conn.keys(\n", - " _make_redis_checkpoint_key(thread_id, checkpoint_ns, \"*\")\n", - " )\n", - " if not all_keys:\n", - " return None\n", - "\n", - " latest_key = max(\n", - " all_keys,\n", - " key=lambda k: _parse_redis_checkpoint_key(k.decode())[\"checkpoint_id\"],\n", - " )\n", - " return latest_key.decode()" - ] - }, - { - "cell_type": "markdown", - "id": "e26b3204-cca2-414c-800e-7e09032445ae", - "metadata": {}, - "source": [ - "## Setup model and tools for the graph" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "e5213193-5a7d-43e7-aeba-fe732bb1cd7a", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "from langchain_core.runnables import ConfigurableField\n", - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI\n", - "from langgraph.prebuilt import create_react_agent\n", - "\n", - "\n", - "@tool\n", - "def get_weather(city: Literal[\"nyc\", \"sf\"]):\n", - " \"\"\"Use this to get weather information.\"\"\"\n", - " if city == \"nyc\":\n", - " return \"It might be cloudy in nyc\"\n", - " elif city == \"sf\":\n", - " return \"It's always sunny in sf\"\n", - " else:\n", - " raise AssertionError(\"Unknown city\")\n", - "\n", - "\n", - "tools = [get_weather]\n", - "model = ChatOpenAI(model_name=\"gpt-4o-mini\", temperature=0)" - ] - }, - { - "cell_type": "markdown", - "id": "e9342c62-dbb4-40f6-9271-7393f1ca48c4", - "metadata": {}, - "source": [ - "## Use sync connection" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "5fe54e79-9eaf-44e2-b2d9-1e0284b984d0", - "metadata": {}, - "outputs": [], - "source": [ - "with RedisSaver.from_conn_info(host=\"localhost\", port=6379, db=0) as checkpointer:\n", - " graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)\n", - " config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - " res = graph.invoke({\"messages\": [(\"human\", \"what's the weather in sf\")]}, config)\n", - "\n", - " latest_checkpoint = checkpointer.get(config)\n", - " latest_checkpoint_tuple = checkpointer.get_tuple(config)\n", - " checkpoint_tuples = list(checkpointer.list(config))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "c298e627-115a-4b4c-ae17-520ca9a640cd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'v': 1,\n", - " 'ts': '2024-08-09T01:56:48.328315+00:00',\n", - " 'id': '1ef55f2a-3614-69b4-8003-2181cff935cc',\n", - " 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='f911e000-75a1-41f6-8e38-77bb086c2ecf'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4f1531f1-067c-4e16-8b62-7a6b663e93bd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71}),\n", - " ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='e27bb3a1-1798-494a-b4ad-2deadda8b2bf', tool_call_id='call_l5e5YcTJDJYOdvi4scBy9n2I'),\n", - " AIMessage(content='The weather in San Francisco is always sunny!', response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-ad546b5a-70ce-404e-9656-dcc6ecd482d3-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94})],\n", - " 'agent': 'agent'},\n", - " 'channel_versions': {'__start__': '00000000000000000000000000000002.',\n", - " 'messages': '00000000000000000000000000000005.16e98d6f7ece7598829eddf1b33a33c4',\n", - " 'start:agent': '00000000000000000000000000000003.',\n", - " 'agent': '00000000000000000000000000000005.065d90dd7f7cd091f0233855210bb2af',\n", - " 'branch:agent:should_continue:tools': '00000000000000000000000000000004.',\n", - " 'tools': '00000000000000000000000000000005.'},\n", - " 'versions_seen': {'__input__': {},\n", - " '__start__': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'},\n", - " 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc',\n", - " 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'},\n", - " 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}},\n", - " 'pending_sends': [],\n", - " 'current_tasks': {}}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "latest_checkpoint" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "922f9406-0f68-418a-9cb4-e0e29de4b5f9", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CheckpointTuple(config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3614-69b4-8003-2181cff935cc'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:48.328315+00:00', 'id': '1ef55f2a-3614-69b4-8003-2181cff935cc', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='f911e000-75a1-41f6-8e38-77bb086c2ecf'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4f1531f1-067c-4e16-8b62-7a6b663e93bd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71}), ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='e27bb3a1-1798-494a-b4ad-2deadda8b2bf', tool_call_id='call_l5e5YcTJDJYOdvi4scBy9n2I'), AIMessage(content='The weather in San Francisco is always sunny!', response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-ad546b5a-70ce-404e-9656-dcc6ecd482d3-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94})], 'agent': 'agent'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000005.16e98d6f7ece7598829eddf1b33a33c4', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000005.065d90dd7f7cd091f0233855210bb2af', 'branch:agent:should_continue:tools': '00000000000000000000000000000004.', 'tools': '00000000000000000000000000000005.'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc', 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'}, 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='The weather in San Francisco is always sunny!', response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-ad546b5a-70ce-404e-9656-dcc6ecd482d3-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94})]}}, 'step': 3}, parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-306f-6252-8002-47c2374ec1f2'}}, pending_writes=[])" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "latest_checkpoint_tuple" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "b2ce743b-5896-443b-9ec0-a655b065895c", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[CheckpointTuple(config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3614-69b4-8003-2181cff935cc'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:48.328315+00:00', 'id': '1ef55f2a-3614-69b4-8003-2181cff935cc', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='f911e000-75a1-41f6-8e38-77bb086c2ecf'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4f1531f1-067c-4e16-8b62-7a6b663e93bd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71}), ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='e27bb3a1-1798-494a-b4ad-2deadda8b2bf', tool_call_id='call_l5e5YcTJDJYOdvi4scBy9n2I'), AIMessage(content='The weather in San Francisco is always sunny!', response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-ad546b5a-70ce-404e-9656-dcc6ecd482d3-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94})], 'agent': 'agent'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000005.16e98d6f7ece7598829eddf1b33a33c4', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000005.065d90dd7f7cd091f0233855210bb2af', 'branch:agent:should_continue:tools': '00000000000000000000000000000004.', 'tools': '00000000000000000000000000000005.'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc', 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'}, 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='The weather in San Francisco is always sunny!', response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 84, 'total_tokens': 94}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-ad546b5a-70ce-404e-9656-dcc6ecd482d3-0', usage_metadata={'input_tokens': 84, 'output_tokens': 10, 'total_tokens': 94})]}}, 'step': 3}, parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-306f-6252-8002-47c2374ec1f2'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-306f-6252-8002-47c2374ec1f2'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:47.736251+00:00', 'id': '1ef55f2a-306f-6252-8002-47c2374ec1f2', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='f911e000-75a1-41f6-8e38-77bb086c2ecf'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4f1531f1-067c-4e16-8b62-7a6b663e93bd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71}), ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='e27bb3a1-1798-494a-b4ad-2deadda8b2bf', tool_call_id='call_l5e5YcTJDJYOdvi4scBy9n2I')], 'tools': 'tools'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000004.b16eb718f179ac1dcde54c5652768cf5', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000004.', 'branch:agent:should_continue:tools': '00000000000000000000000000000004.', 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc'}, 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'tools': {'messages': [ToolMessage(content=\"It's always sunny in sf\", name='get_weather', id='e27bb3a1-1798-494a-b4ad-2deadda8b2bf', tool_call_id='call_l5e5YcTJDJYOdvi4scBy9n2I')]}}, 'step': 2}, parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-305f-61cc-8001-efac33022ef7'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-305f-61cc-8001-efac33022ef7'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:47.729689+00:00', 'id': '1ef55f2a-305f-61cc-8001-efac33022ef7', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='f911e000-75a1-41f6-8e38-77bb086c2ecf'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4f1531f1-067c-4e16-8b62-7a6b663e93bd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71})], 'agent': 'agent', 'branch:agent:should_continue:tools': 'agent'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000003.4dd312547dcca1cf91a19adb620a18d6', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af', 'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'function': {'arguments': '{\"city\":\"sf\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 57, 'total_tokens': 71}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-4f1531f1-067c-4e16-8b62-7a6b663e93bd-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'sf'}, 'id': 'call_l5e5YcTJDJYOdvi4scBy9n2I', 'type': 'tool_call'}], usage_metadata={'input_tokens': 57, 'output_tokens': 14, 'total_tokens': 71})]}}, 'step': 1}, parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-2a52-6a7c-8000-27624d954d15'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-2a52-6a7c-8000-27624d954d15'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:47.095456+00:00', 'id': '1ef55f2a-2a52-6a7c-8000-27624d954d15', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='f911e000-75a1-41f6-8e38-77bb086c2ecf')], 'start:agent': '__start__'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000002.52e8b0c387f50c28345585c088150464', 'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': None, 'step': 0}, parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-2a50-6812-bfff-34e3be35d6f2'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-2a50-6812-bfff-34e3be35d6f2'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:47.094575+00:00', 'id': '1ef55f2a-2a50-6812-bfff-34e3be35d6f2', 'channel_values': {'messages': [], '__start__': {'messages': [['human', \"what's the weather in sf\"]]}}, 'channel_versions': {'__start__': '00000000000000000000000000000001.ab89befb52cc0e91e106ef7f500ea033'}, 'versions_seen': {'__input__': {}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'input', 'writes': {'messages': [['human', \"what's the weather in sf\"]]}, 'step': -1}, parent_config=None, pending_writes=None)]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "checkpoint_tuples" - ] - }, - { - "cell_type": "markdown", - "id": "c0a47d3e-e588-48fc-a5d4-2145dff17e77", - "metadata": {}, - "source": [ - "## Use async connection" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "6a39d1ff-ca37-4457-8b52-07d33b59c36e", - "metadata": {}, - "outputs": [], - "source": [ - "async with AsyncRedisSaver.from_conn_info(\n", - " host=\"localhost\", port=6379, db=0\n", - ") as checkpointer:\n", - " graph = create_react_agent(model, tools=tools, checkpointer=checkpointer)\n", - " config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - " res = await graph.ainvoke(\n", - " {\"messages\": [(\"human\", \"what's the weather in nyc\")]}, config\n", - " )\n", - "\n", - " latest_checkpoint = await checkpointer.aget(config)\n", - " latest_checkpoint_tuple = await checkpointer.aget_tuple(config)\n", - " checkpoint_tuples = [c async for c in checkpointer.alist(config)]" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "51125ef1-bdb6-454e-82cc-4ae19a113606", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'v': 1,\n", - " 'ts': '2024-08-09T01:56:49.503241+00:00',\n", - " 'id': '1ef55f2a-4149-61ea-8003-dc5506862287',\n", - " 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in nyc\", id='5a106e79-a617-4707-839f-134d4e4b762a'),\n", - " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'function': {'arguments': '{\"city\":\"nyc\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 58, 'total_tokens': 73}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0d6fa3b4-cace-41a8-b025-d01d16f6bbe9-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'nyc'}, 'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 15, 'total_tokens': 73}),\n", - " ToolMessage(content='It might be cloudy in nyc', name='get_weather', id='922124bd-d3b0-4929-a996-a75d842b8b44', tool_call_id='call_TvPLLyhuQQN99EcZc8SzL8x9'),\n", - " AIMessage(content='The weather in NYC might be cloudy.', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 88, 'total_tokens': 97}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-69a10e66-d61f-475e-b7de-a1ecd08a6c3a-0', usage_metadata={'input_tokens': 88, 'output_tokens': 9, 'total_tokens': 97})],\n", - " 'agent': 'agent'},\n", - " 'channel_versions': {'__start__': '00000000000000000000000000000002.',\n", - " 'messages': '00000000000000000000000000000005.2cb29d082da6435a7528b4c917fd0c28',\n", - " 'start:agent': '00000000000000000000000000000003.',\n", - " 'agent': '00000000000000000000000000000005.065d90dd7f7cd091f0233855210bb2af',\n", - " 'branch:agent:should_continue:tools': '00000000000000000000000000000004.',\n", - " 'tools': '00000000000000000000000000000005.'},\n", - " 'versions_seen': {'__input__': {},\n", - " '__start__': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'},\n", - " 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc',\n", - " 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'},\n", - " 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}},\n", - " 'pending_sends': [],\n", - " 'current_tasks': {}}" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "latest_checkpoint" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "97f8a87b-8423-41c6-a76b-9a6b30904e73", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-4149-61ea-8003-dc5506862287'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:49.503241+00:00', 'id': '1ef55f2a-4149-61ea-8003-dc5506862287', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in nyc\", id='5a106e79-a617-4707-839f-134d4e4b762a'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'function': {'arguments': '{\"city\":\"nyc\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 58, 'total_tokens': 73}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0d6fa3b4-cace-41a8-b025-d01d16f6bbe9-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'nyc'}, 'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 15, 'total_tokens': 73}), ToolMessage(content='It might be cloudy in nyc', name='get_weather', id='922124bd-d3b0-4929-a996-a75d842b8b44', tool_call_id='call_TvPLLyhuQQN99EcZc8SzL8x9'), AIMessage(content='The weather in NYC might be cloudy.', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 88, 'total_tokens': 97}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-69a10e66-d61f-475e-b7de-a1ecd08a6c3a-0', usage_metadata={'input_tokens': 88, 'output_tokens': 9, 'total_tokens': 97})], 'agent': 'agent'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000005.2cb29d082da6435a7528b4c917fd0c28', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000005.065d90dd7f7cd091f0233855210bb2af', 'branch:agent:should_continue:tools': '00000000000000000000000000000004.', 'tools': '00000000000000000000000000000005.'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc', 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'}, 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='The weather in NYC might be cloudy.', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 88, 'total_tokens': 97}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-69a10e66-d61f-475e-b7de-a1ecd08a6c3a-0', usage_metadata={'input_tokens': 88, 'output_tokens': 9, 'total_tokens': 97})]}}, 'step': 3}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3d07-647e-8002-b5e4d28c00c9'}}, pending_writes=[])" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "latest_checkpoint_tuple" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "2b6d73ca-519e-45f7-90c2-1b8596624505", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-4149-61ea-8003-dc5506862287'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:49.503241+00:00', 'id': '1ef55f2a-4149-61ea-8003-dc5506862287', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in nyc\", id='5a106e79-a617-4707-839f-134d4e4b762a'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'function': {'arguments': '{\"city\":\"nyc\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 58, 'total_tokens': 73}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0d6fa3b4-cace-41a8-b025-d01d16f6bbe9-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'nyc'}, 'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 15, 'total_tokens': 73}), ToolMessage(content='It might be cloudy in nyc', name='get_weather', id='922124bd-d3b0-4929-a996-a75d842b8b44', tool_call_id='call_TvPLLyhuQQN99EcZc8SzL8x9'), AIMessage(content='The weather in NYC might be cloudy.', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 88, 'total_tokens': 97}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-69a10e66-d61f-475e-b7de-a1ecd08a6c3a-0', usage_metadata={'input_tokens': 88, 'output_tokens': 9, 'total_tokens': 97})], 'agent': 'agent'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000005.2cb29d082da6435a7528b4c917fd0c28', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000005.065d90dd7f7cd091f0233855210bb2af', 'branch:agent:should_continue:tools': '00000000000000000000000000000004.', 'tools': '00000000000000000000000000000005.'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc', 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'}, 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='The weather in NYC might be cloudy.', response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 88, 'total_tokens': 97}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'stop', 'logprobs': None}, id='run-69a10e66-d61f-475e-b7de-a1ecd08a6c3a-0', usage_metadata={'input_tokens': 88, 'output_tokens': 9, 'total_tokens': 97})]}}, 'step': 3}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3d07-647e-8002-b5e4d28c00c9'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3d07-647e-8002-b5e4d28c00c9'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:49.056860+00:00', 'id': '1ef55f2a-3d07-647e-8002-b5e4d28c00c9', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in nyc\", id='5a106e79-a617-4707-839f-134d4e4b762a'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'function': {'arguments': '{\"city\":\"nyc\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 58, 'total_tokens': 73}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0d6fa3b4-cace-41a8-b025-d01d16f6bbe9-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'nyc'}, 'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 15, 'total_tokens': 73}), ToolMessage(content='It might be cloudy in nyc', name='get_weather', id='922124bd-d3b0-4929-a996-a75d842b8b44', tool_call_id='call_TvPLLyhuQQN99EcZc8SzL8x9')], 'tools': 'tools'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000004.07964a3a545f9ff95545db45a9753d11', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000004.', 'branch:agent:should_continue:tools': '00000000000000000000000000000004.', 'tools': '00000000000000000000000000000004.022986cd20ae85c77ea298a383f69ba8'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc'}, 'tools': {'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'tools': {'messages': [ToolMessage(content='It might be cloudy in nyc', name='get_weather', id='922124bd-d3b0-4929-a996-a75d842b8b44', tool_call_id='call_TvPLLyhuQQN99EcZc8SzL8x9')]}}, 'step': 2}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3cf9-6996-8001-88dab066840d'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-3cf9-6996-8001-88dab066840d'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:49.051234+00:00', 'id': '1ef55f2a-3cf9-6996-8001-88dab066840d', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in nyc\", id='5a106e79-a617-4707-839f-134d4e4b762a'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'function': {'arguments': '{\"city\":\"nyc\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 58, 'total_tokens': 73}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0d6fa3b4-cace-41a8-b025-d01d16f6bbe9-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'nyc'}, 'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 15, 'total_tokens': 73})], 'agent': 'agent', 'branch:agent:should_continue:tools': 'agent'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000003.cc96d93b1afbd1b69d53851320670b97', 'start:agent': '00000000000000000000000000000003.', 'agent': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af', 'branch:agent:should_continue:tools': '00000000000000000000000000000003.065d90dd7f7cd091f0233855210bb2af'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'}, 'agent': {'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': {'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'function': {'arguments': '{\"city\":\"nyc\"}', 'name': 'get_weather'}, 'type': 'function'}]}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 58, 'total_tokens': 73}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_48196bc67a', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-0d6fa3b4-cace-41a8-b025-d01d16f6bbe9-0', tool_calls=[{'name': 'get_weather', 'args': {'city': 'nyc'}, 'id': 'call_TvPLLyhuQQN99EcZc8SzL8x9', 'type': 'tool_call'}], usage_metadata={'input_tokens': 58, 'output_tokens': 15, 'total_tokens': 73})]}}, 'step': 1}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-36a6-6788-8000-9efe1769f8c1'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-36a6-6788-8000-9efe1769f8c1'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:48.388067+00:00', 'id': '1ef55f2a-36a6-6788-8000-9efe1769f8c1', 'channel_values': {'messages': [HumanMessage(content=\"what's the weather in nyc\", id='5a106e79-a617-4707-839f-134d4e4b762a')], 'start:agent': '__start__'}, 'channel_versions': {'__start__': '00000000000000000000000000000002.', 'messages': '00000000000000000000000000000002.a6994b785a651d88df51020401745af8', 'start:agent': '00000000000000000000000000000002.d6f25946c3108fc12f27abbcf9b4cedc'}, 'versions_seen': {'__input__': {}, '__start__': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'loop', 'writes': None, 'step': 0}, parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-36a3-6614-bfff-05dafa02b4d7'}}, pending_writes=None),\n", - " CheckpointTuple(config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef55f2a-36a3-6614-bfff-05dafa02b4d7'}}, checkpoint={'v': 1, 'ts': '2024-08-09T01:56:48.386807+00:00', 'id': '1ef55f2a-36a3-6614-bfff-05dafa02b4d7', 'channel_values': {'messages': [], '__start__': {'messages': [['human', \"what's the weather in nyc\"]]}}, 'channel_versions': {'__start__': '00000000000000000000000000000001.0e148ae3debe753278387e84f786e863'}, 'versions_seen': {'__input__': {}}, 'pending_sends': [], 'current_tasks': {}}, metadata={'source': 'input', 'writes': {'messages': [['human', \"what's the weather in nyc\"]]}, 'step': -1}, parent_config=None, pending_writes=None)]" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "checkpoint_tuples" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/recursion-limit.ipynb b/docs/docs/how-tos/recursion-limit.ipynb deleted file mode 100644 index 467ec8032..000000000 --- a/docs/docs/how-tos/recursion-limit.ipynb +++ /dev/null @@ -1,459 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to create and control loops\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "\n", - "When creating a graph with a loop, we require a mechanism for terminating execution. This is most commonly done by adding a [conditional edge](../../concepts/low_level/#conditional-edges) that routes to the [END](../../concepts/low_level/#end-node) node once we reach some termination condition.\n", - "\n", - "You can also set the graph recursion limit when invoking or streaming the graph. The recursion limit sets the number of [supersteps](../../concepts/low_level/#graphs) that the graph is allowed to execute before it raises an error. Read more about the concept of recursion limits [here](../../concepts/low_level/#recursion-limit). \n", - "\n", - "Let's consider a simple graph with a loop to better understand how these mechanisms work.\n", - "\n", - "!!! tip\n", - "\n", - " To return the last value of your state instead of receiving a recursion limit error, read [this how-to](../../how-tos/return-when-recursion-limit-hits/).\n", - "\n", - "\n", - "## Summary\n", - "\n", - "When creating a loop, you can include a conditional edge that specifies a termination condition:\n", - "```python\n", - "builder = StateGraph(State)\n", - "builder.add_node(a)\n", - "builder.add_node(b)\n", - "\n", - "def route(state: State) -> Literal[\"b\", END]:\n", - " if termination_condition(state):\n", - " return END\n", - " else:\n", - " return \"a\"\n", - "\n", - "builder.add_edge(START, \"a\")\n", - "builder.add_conditional_edges(\"a\", route)\n", - "builder.add_edge(\"b\", \"a\")\n", - "graph = builder.compile()\n", - "```\n", - "\n", - "To control the recursion limit, specify `\"recursion_limit\"` in the config. This will raise a `GraphRecursionError`, which you can catch and handle:\n", - "```python\n", - "from langgraph.errors import GraphRecursionError\n", - "\n", - "try:\n", - " graph.invoke(inputs, {\"recursion_limit\": 3})\n", - "except GraphRecursionError:\n", - " print(\"Recursion Error\")\n", - "```\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define the graph\n", - "\n", - "Let's define a graph with a simple loop. Note that we use a conditional edge to implement a termination condition." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing import Annotated, Literal\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "\n", - "\n", - "class State(TypedDict):\n", - " # The operator.add reducer fn makes this append-only\n", - " aggregate: Annotated[list, operator.add]\n", - "\n", - "\n", - "def a(state: State):\n", - " print(f'Node A sees {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"A\"]}\n", - "\n", - "\n", - "def b(state: State):\n", - " print(f'Node B sees {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"B\"]}\n", - "\n", - "\n", - "# Define nodes\n", - "builder = StateGraph(State)\n", - "builder.add_node(a)\n", - "builder.add_node(b)\n", - "\n", - "\n", - "# Define edges\n", - "def route(state: State) -> Literal[\"b\", END]:\n", - " if len(state[\"aggregate\"]) < 7:\n", - " return \"b\"\n", - " else:\n", - " return END\n", - "\n", - "\n", - "builder.add_edge(START, \"a\")\n", - "builder.add_conditional_edges(\"a\", route)\n", - "builder.add_edge(\"b\", \"a\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This architecture is similar to a [ReAct agent](../../how-tos/#prebuilt-react-agent) in which node `\"a\"` is a tool-calling model, and node `\"b\"` represents the tools.\n", - "\n", - "In our `route` conditional edge, we specify that we should end after the `\"aggregate\"` list in the state passes a threshold length.\n", - "\n", - "Invoking the graph, we see that we alternate between nodes `\"a\"` and `\"b\"` before terminating once we reach the termination condition." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node A sees []\n", - "Node B sees ['A']\n", - "Node A sees ['A', 'B']\n", - "Node B sees ['A', 'B', 'A']\n", - "Node A sees ['A', 'B', 'A', 'B']\n", - "Node B sees ['A', 'B', 'A', 'B', 'A']\n", - "Node A sees ['A', 'B', 'A', 'B', 'A', 'B']\n" - ] - }, - { - "data": { - "text/plain": [ - "{'aggregate': ['A', 'B', 'A', 'B', 'A', 'B', 'A']}" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"aggregate\": []})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Impose a recursion limit\n", - "\n", - "In some applications, we may not have a guarantee that we will reach a given termination condition. In these cases, we can set the graph's [recursion limit](../../concepts/low_level/#recursion-limit). This will raise a `GraphRecursionError` after a given number of [supersteps](../../concepts/low_level/#graphs). We can then catch and handle this exception:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node A sees []\n", - "Node B sees ['A']\n", - "Node A sees ['A', 'B']\n", - "Node B sees ['A', 'B', 'A']\n", - "Recursion Error\n" - ] - } - ], - "source": [ - "from langgraph.errors import GraphRecursionError\n", - "\n", - "try:\n", - " graph.invoke({\"aggregate\": []}, {\"recursion_limit\": 4})\n", - "except GraphRecursionError:\n", - " print(\"Recursion Error\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that this time we terminate after the fourth step." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Loops with branches\n", - "\n", - "To better understand how the recursion limit works, let's consider a more complex example. Below we implement a loop, but one step fans out into two nodes:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "from typing import Annotated, Literal\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "\n", - "\n", - "class State(TypedDict):\n", - " aggregate: Annotated[list, operator.add]\n", - "\n", - "\n", - "def a(state: State):\n", - " print(f'Node A sees {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"A\"]}\n", - "\n", - "\n", - "def b(state: State):\n", - " print(f'Node B sees {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"B\"]}\n", - "\n", - "\n", - "def c(state: State):\n", - " print(f'Node C sees {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"C\"]}\n", - "\n", - "\n", - "def d(state: State):\n", - " print(f'Node D sees {state[\"aggregate\"]}')\n", - " return {\"aggregate\": [\"D\"]}\n", - "\n", - "\n", - "# Define nodes\n", - "builder = StateGraph(State)\n", - "builder.add_node(a)\n", - "builder.add_node(b)\n", - "builder.add_node(c)\n", - "builder.add_node(d)\n", - "\n", - "\n", - "# Define edges\n", - "def route(state: State) -> Literal[\"b\", END]:\n", - " if len(state[\"aggregate\"]) < 7:\n", - " return \"b\"\n", - " else:\n", - " return END\n", - "\n", - "\n", - "builder.add_edge(START, \"a\")\n", - "builder.add_conditional_edges(\"a\", route)\n", - "builder.add_edge(\"b\", \"c\")\n", - "builder.add_edge(\"b\", \"d\")\n", - "builder.add_edge([\"c\", \"d\"], \"a\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This graph looks complex, but can be conceptualized as loop of [supersteps](../../concepts/low_level/#graphs):\n", - "\n", - "1. Node A\n", - "2. Node B\n", - "3. Nodes C and D\n", - "4. Node A\n", - "5. ...\n", - "\n", - "We have a loop of four supersteps, where nodes C and D are executed concurrently.\n", - "\n", - "Invoking the graph as before, we see that we complete two full \"laps\" before hitting the termination condition:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node A sees []\n", - "Node B sees ['A']\n", - "Node D sees ['A', 'B']\n", - "Node C sees ['A', 'B']\n", - "Node A sees ['A', 'B', 'C', 'D']\n", - "Node B sees ['A', 'B', 'C', 'D', 'A']\n", - "Node D sees ['A', 'B', 'C', 'D', 'A', 'B']\n", - "Node C sees ['A', 'B', 'C', 'D', 'A', 'B']\n", - "Node A sees ['A', 'B', 'C', 'D', 'A', 'B', 'C', 'D']\n" - ] - } - ], - "source": [ - "result = graph.invoke({\"aggregate\": []})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, if we set the recursion limit to four, we only complete one lap because each lap is four supersteps:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Node A sees []\n", - "Node B sees ['A']\n", - "Node C sees ['A', 'B']\n", - "Node D sees ['A', 'B']\n", - "Node A sees ['A', 'B', 'C', 'D']\n", - "Recursion Error\n" - ] - } - ], - "source": [ - "from langgraph.errors import GraphRecursionError\n", - "\n", - "try:\n", - " result = graph.invoke({\"aggregate\": []}, {\"recursion_limit\": 4})\n", - "except GraphRecursionError:\n", - " print(\"Recursion Error\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/return-when-recursion-limit-hits.ipynb b/docs/docs/how-tos/return-when-recursion-limit-hits.ipynb deleted file mode 100644 index 22d9243b7..000000000 --- a/docs/docs/how-tos/return-when-recursion-limit-hits.ipynb +++ /dev/null @@ -1,279 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to return state before hitting recursion limit\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "[Setting the graph recursion limit](https://langchain-ai.github.io/langgraph/how-tos/recursion-limit/) can help you control how long your graph will stay running, but if the recursion limit is hit your graph returns an error - which may not be ideal for all use cases. Instead you may wish to return the value of the state *just before* the recursion limit is hit. This how-to will show you how to do this." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's installed the required packages:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Without returning state\n", - "\n", - "We are going to define a dummy graph in this example that will always hit the recursion limit. First, we will implement it without returning the state and show that it hits the recursion limit. This graph is based on the ReAct architecture, but instead of actually making decisions and taking actions it just loops forever." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import TypedDict\n", - "from langgraph.graph import StateGraph\n", - "from langgraph.graph import START, END\n", - "\n", - "\n", - "class State(TypedDict):\n", - " value: str\n", - " action_result: str\n", - "\n", - "\n", - "def router(state: State):\n", - " if state[\"value\"] == \"end\":\n", - " return END\n", - " else:\n", - " return \"action\"\n", - "\n", - "\n", - "def decision_node(state):\n", - " return {\"value\": \"keep going!\"}\n", - "\n", - "\n", - "def action_node(state: State):\n", - " # Do your action here ...\n", - " return {\"action_result\": \"what a great result!\"}\n", - "\n", - "\n", - "workflow = StateGraph(State)\n", - "workflow.add_node(\"decision\", decision_node)\n", - "workflow.add_node(\"action\", action_node)\n", - "workflow.add_edge(START, \"decision\")\n", - "workflow.add_conditional_edges(\"decision\", router, [\"action\", END])\n", - "workflow.add_edge(\"action\", \"decision\")\n", - "app = workflow.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(app.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's verify that our graph will always hit the recursion limit:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Recursion Error\n" - ] - } - ], - "source": [ - "from langgraph.errors import GraphRecursionError\n", - "\n", - "try:\n", - " app.invoke({\"value\": \"hi!\"})\n", - "except GraphRecursionError:\n", - " print(\"Recursion Error\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## With returning state\n", - "\n", - "To avoid hitting the recursion limit, we can introduce a new key to our state called `remaining_steps`. It will keep track of number of steps until reaching the recursion limit. We can then check the value of `remaining_steps` to determine whether we should terminate the graph execution and return the state to the user without causing the `RecursionError`.\n", - "\n", - "To do so, we will use a special `RemainingSteps` annotation. Under the hood, it creates a special `ManagedValue` channel -- a state channel that will exist for the duration of our graph run and no longer.\n", - "\n", - "Since our `action` node is going to always induce at least 2 extra steps to our graph (since the `action` node ALWAYS calls the `decision` node afterwards), we will use this channel to check if we are within 2 steps of the limit.\n", - "\n", - "Now, when we run our graph we should receive no errors and instead get the last value of the state before the recursion limit was hit." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import TypedDict\n", - "from langgraph.graph import StateGraph\n", - "from typing import Annotated\n", - "\n", - "from langgraph.managed.is_last_step import RemainingSteps\n", - "\n", - "\n", - "class State(TypedDict):\n", - " value: str\n", - " action_result: str\n", - " remaining_steps: RemainingSteps\n", - "\n", - "\n", - "def router(state: State):\n", - " # Force the agent to end\n", - " if state[\"remaining_steps\"] <= 2:\n", - " return END\n", - " if state[\"value\"] == \"end\":\n", - " return END\n", - " else:\n", - " return \"action\"\n", - "\n", - "\n", - "def decision_node(state):\n", - " return {\"value\": \"keep going!\"}\n", - "\n", - "\n", - "def action_node(state: State):\n", - " # Do your action here ...\n", - " return {\"action_result\": \"what a great result!\"}\n", - "\n", - "\n", - "workflow = StateGraph(State)\n", - "workflow.add_node(\"decision\", decision_node)\n", - "workflow.add_node(\"action\", action_node)\n", - "workflow.add_edge(START, \"decision\")\n", - "workflow.add_conditional_edges(\"decision\", router, [\"action\", END])\n", - "workflow.add_edge(\"action\", \"decision\")\n", - "app = workflow.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'value': 'keep going!', 'action_result': 'what a great result!'}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "app.invoke({\"value\": \"hi!\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect! Our code ran with no error, just as we expected!" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/sequence.ipynb b/docs/docs/how-tos/sequence.ipynb deleted file mode 100644 index 1b805a521..000000000 --- a/docs/docs/how-tos/sequence.ipynb +++ /dev/null @@ -1,355 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to create a sequence of steps\n", - "\n", - "!!! info \"Prerequisites\"\n", - " This guide assumes familiarity with the following:\n", - "\n", - " - [How to define and update graph state](../../how-tos/state-reducers)\n", - "\n", - "This guide demonstrates how to construct a simple sequence of steps. We will demonstrate:\n", - "\n", - "1. How to build a sequential graph\n", - "2. Built-in short-hand for constructing similar graphs.\n", - "\n", - "\n", - "# Summary\n", - "\n", - "To add a sequence of nodes, we use the `.add_node` and `.add_edge` methods of our [graph](../../concepts/low_level/#stategraph):\n", - "```python\n", - "from langgraph.graph import START, StateGraph\n", - "\n", - "graph_builder = StateGraph(State)\n", - "\n", - "# Add nodes\n", - "graph_builder.add_node(step_1)\n", - "graph_builder.add_node(step_2)\n", - "graph_builder.add_node(step_3)\n", - "\n", - "# Add edges\n", - "graph_builder.add_edge(START, \"step_1\")\n", - "graph_builder.add_edge(\"step_1\", \"step_2\")\n", - "graph_builder.add_edge(\"step_2\", \"step_3\")\n", - "```\n", - "\n", - "We can also use the built-in shorthand `.add_sequence`:\n", - "```python\n", - "graph_builder = StateGraph(State).add_sequence([step_1, step_2, step_3])\n", - "graph_builder.add_edge(START, \"step_1\")\n", - "```\n", - "\n", - "\n", - "
    \n", - "Why split application steps into a sequence with LangGraph?\n", - "\n", - "LangGraph makes it easy to add an underlying persistence layer to your application.\n", - "This allows state to be checkpointed in between the execution of nodes, so your LangGraph nodes govern:\n", - "\n", - "
      \n", - "
    • How state updates are [checkpointed](../../concepts/persistence/)
    • \n", - "
    • How interruptions are resumed in [human-in-the-loop](../../concepts/human_in_the_loop/) workflows
    • \n", - "
    • How we can \"rewind\" and branch-off executions using LangGraph's [time travel](../../concepts/time-travel/) features
    • \n", - "
    \n", - "\n", - "They also determine how execution steps are [streamed](../../concepts/streaming/), and how your application is visualized\n", - "and debugged using [LangGraph Studio](../../concepts/langgraph_studio/).\n", - "\n", - "
    \n", - "\n", - "## Setup\n", - "\n", - "First, let's install langgraph:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for better debugging

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM aps built with LangGraph — read more about how to get started in the docs. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Build the graph\n", - "\n", - "Let's demonstrate a simple usage example. We will create a sequence of three steps:\n", - "\n", - "1. Populate a value in a key of the state\n", - "2. Update the same value\n", - "3. Populate a different value\n", - "\n", - "### Define state\n", - "\n", - "Let's first define our [state](../../concepts/low_level/#state). This governs the [schema of the graph](../../concepts/low_level/#schema), and can also specify how to apply updates. See [this guide](../../how-tos/state-reducers) for more detail.\n", - "\n", - "In our case, we will just keep track of two values:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import TypedDict\n", - "\n", - "\n", - "class State(TypedDict):\n", - " value_1: str\n", - " value_2: int" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define nodes\n", - "\n", - "Our [nodes](../../concepts/low_level/#nodes) are just Python functions that read our graph's state and make updates to it. The first argument to this function will always be the state:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "def step_1(state: State):\n", - " return {\"value_1\": \"a\"}\n", - "\n", - "\n", - "def step_2(state: State):\n", - " current_value_1 = state[\"value_1\"]\n", - " return {\"value_1\": f\"{current_value_1} b\"}\n", - "\n", - "\n", - "def step_3(state: State):\n", - " return {\"value_2\": 10}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "!!! note\n", - "\n", - " Note that when issuing updates to the state, each node can just specify the value of the key it wishes to update.\n", - "\n", - "By default, this will **overwrite** the value of the corresponding key. You can also use [reducers](../../concepts/low_level/#reducers) to control how updates are processed— for example, you can append successive updates to a key instead. See [this guide](../../how-tos/state-reducers) for more detail.\n", - "\n", - "### Define graph\n", - "\n", - "We use [StateGraph](../../concepts/low_level/#stategraph) to define a graph that operates on this state.\n", - "\n", - "We will then use [add_node](../../concepts/low_level/#messagesstate) and [add_edge](../../concepts/low_level/#edges) to populate our graph and define its control flow." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import START, StateGraph\n", - "\n", - "graph_builder = StateGraph(State)\n", - "\n", - "# Add nodes\n", - "graph_builder.add_node(step_1)\n", - "graph_builder.add_node(step_2)\n", - "graph_builder.add_node(step_3)\n", - "\n", - "# Add edges\n", - "graph_builder.add_edge(START, \"step_1\")\n", - "graph_builder.add_edge(\"step_1\", \"step_2\")\n", - "graph_builder.add_edge(\"step_2\", \"step_3\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "!!! tip \"Specifying custom names\"\n", - "\n", - " You can specify custom names for nodes using `.add_node`:\n", - "\n", - " ```python\n", - " graph_builder.add_node(\"my_node\", step_1)\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that:\n", - "\n", - "- `.add_edge` takes the names of nodes, which for functions defaults to `node.__name__`.\n", - "- We must specify the entry point of the graph. For this we add an edge with the [START node](../../concepts/low_level/#start-node).\n", - "- The graph halts when there are no more nodes to execute.\n", - "\n", - "We next [compile](../../concepts/low_level/#compiling-your-graph) our graph. This provides a few basic checks on the structure of the graph (e.g., identifying orphaned nodes). If we were adding persistence to our application via a [checkpointer](../../concepts/persistence/), it would also be passed in here." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "graph = graph_builder.compile()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "LangGraph provides built-in utilities for visualizing your graph. Let's inspect our sequence. See [this guide](../../how-tos/visualization) for detail on visualization." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Usage\n", - "\n", - "Let's proceed with a simple invocation:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'value_1': 'a b', 'value_2': 10}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.invoke({\"value_1\": \"c\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that:\n", - "\n", - "- We kicked off invocation by providing a value for a single state key. We must always provide a value for at least one key.\n", - "- The value we passed in was overwritten by the first node.\n", - "- The second node updated the value.\n", - "- The third node populated a different value." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Built-in shorthand\n", - "\n", - "!!! info \"Prerequisites\"\n", - " `.add_sequence` requires `langgraph>=0.2.46`\n", - "\n", - "\n", - "LangGraph includes a built-in shorthand `.add_sequence` for convenience:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'value_1': 'a b', 'value_2': 10}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# highlight-next-line\n", - "graph_builder = StateGraph(State).add_sequence([step_1, step_2, step_3])\n", - "graph_builder.add_edge(START, \"step_1\")\n", - "\n", - "graph = graph_builder.compile()\n", - "\n", - "graph.invoke({\"value_1\": \"c\"})" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/state-model.ipynb b/docs/docs/how-tos/state-model.ipynb deleted file mode 100644 index 2fadd7994..000000000 --- a/docs/docs/how-tos/state-model.ipynb +++ /dev/null @@ -1,521 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to use Pydantic model as graph state\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "A [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph) accepts a `state_schema` argument on initialization that specifies the \"shape\" of the state that the nodes in the graph can access and update.\n", - "\n", - "In our examples, we typically use a python-native `TypedDict` for `state_schema` (or in the case of [MessageGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#messagegraph), a [list](https://docs.python.org/3/library/stdtypes.html#list)), but `state_schema` can be any [type](https://docs.python.org/3/library/stdtypes.html#type-objects).\n", - "\n", - "In this how-to guide, we'll see how a [Pydantic BaseModel](https://docs.pydantic.dev/latest/api/base_model/). can be used for `state_schema` to add run time validation on **inputs**.\n", - "\n", - "\n", - "
    \n", - "

    Known Limitations

    \n", - "

    \n", - "

      \n", - "
    • \n", - " This notebook uses Pydantic v2 BaseModel, which requires langchain-core >= 0.3. Using langchain-core < 0.3 will result in errors due to mixing of Pydantic v1 and v2 BaseModels. \n", - "
    • \n", - "
    • \n", - " Currently, the `output` of the graph will **NOT** be an instance of a pydantic model.\n", - "
    • \n", - "
    • \n", - " Run-time validation only occurs on **inputs** into nodes, not on the outputs.\n", - "
    • \n", - "
    • \n", - " The validation error trace from pydantic does not show which node the error arises in.\n", - "
    • \n", - "
    \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First we need to install the packages required" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "01456d57-4064-4ccb-baf9-98df39c6b8e0", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "4f385bde-e013-4365-88f3-813c632d4b7c", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "e20dd648-df7a-40f5-9b32-afbdcf1ee4d8", - "metadata": {}, - "source": [ - "## Input Validation" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "efc46b36-425c-49c3-9f9e-d9785c70b034", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'a': 'goodbye'}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from typing_extensions import TypedDict\n", - "\n", - "from pydantic import BaseModel\n", - "\n", - "\n", - "# The overall state of the graph (this is the public state shared across nodes)\n", - "class OverallState(BaseModel):\n", - " a: str\n", - "\n", - "\n", - "def node(state: OverallState):\n", - " return {\"a\": \"goodbye\"}\n", - "\n", - "\n", - "# Build the state graph\n", - "builder = StateGraph(OverallState)\n", - "builder.add_node(node) # node_1 is the first node\n", - "builder.add_edge(START, \"node\") # Start the graph with node_1\n", - "builder.add_edge(\"node\", END) # End the graph after node_1\n", - "graph = builder.compile()\n", - "\n", - "# Test the graph with a valid input\n", - "graph.invoke({\"a\": \"hello\"})" - ] - }, - { - "cell_type": "markdown", - "id": "25b594c2-8198-4f76-9606-ea47151ff9d1", - "metadata": {}, - "source": [ - "Invoke the graph with an **invalid** input" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "05d7d43b-0b71-4e25-af6f-61d1560a46cb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "An exception was raised because `a` is an integer rather than a string.\n", - "1 validation error for OverallState\n", - "a\n", - " Input should be a valid string [type=string_type, input_value=123, input_type=int]\n", - " For further information visit https://errors.pydantic.dev/2.9/v/string_type\n" - ] - } - ], - "source": [ - "try:\n", - " graph.invoke({\"a\": 123}) # Should be a string\n", - "except Exception as e:\n", - " print(\"An exception was raised because `a` is an integer rather than a string.\")\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "id": "0aafc180-17b5-4364-b1df-fb41aa575067", - "metadata": {}, - "source": [ - "## Multiple Nodes\n", - "\n", - "Run-time validation will also work in a multi-node graph. In the example below `bad_node` updates `a` to an integer. \n", - "\n", - "Because run-time validation occurs on **inputs**, the validation error will occur when `ok_node` is called (not when `bad_node` returns an update to the state which is inconsistent with the schema)." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "25336b0d-2fe6-45c8-8204-f962c3995df7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "An exception was raised because bad_node sets `a` to an integer.\n", - "1 validation error for OverallState\n", - "a\n", - " Input should be a valid string [type=string_type, input_value=123, input_type=int]\n", - " For further information visit https://errors.pydantic.dev/2.9/v/string_type\n" - ] - } - ], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from typing_extensions import TypedDict\n", - "\n", - "from pydantic import BaseModel\n", - "\n", - "\n", - "# The overall state of the graph (this is the public state shared across nodes)\n", - "class OverallState(BaseModel):\n", - " a: str\n", - "\n", - "\n", - "def bad_node(state: OverallState):\n", - " return {\n", - " \"a\": 123 # Invalid\n", - " }\n", - "\n", - "\n", - "def ok_node(state: OverallState):\n", - " return {\"a\": \"goodbye\"}\n", - "\n", - "\n", - "# Build the state graph\n", - "builder = StateGraph(OverallState)\n", - "builder.add_node(bad_node)\n", - "builder.add_node(ok_node)\n", - "builder.add_edge(START, \"bad_node\")\n", - "builder.add_edge(\"bad_node\", \"ok_node\")\n", - "builder.add_edge(\"ok_node\", END)\n", - "graph = builder.compile()\n", - "\n", - "# Test the graph with a valid input\n", - "try:\n", - " graph.invoke({\"a\": \"hello\"})\n", - "except Exception as e:\n", - " print(\"An exception was raised because bad_node sets `a` to an integer.\")\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "id": "2270bc3c", - "metadata": {}, - "source": [ - "## Multiple Nodes\n", - "\n", - "Run-time validation will also work in a multi-node graph. In the example below `bad_node` updates `a` to an integer. \n", - "\n", - "Because run-time validation occurs on **inputs**, the validation error will occur when `ok_node` is called (not when `bad_node` returns an update to the state which is inconsistent with the schema)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d832cdcc", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from typing_extensions import TypedDict\n", - "\n", - "from pydantic import BaseModel\n", - "\n", - "\n", - "# The overall state of the graph (this is the public state shared across nodes)\n", - "class OverallState(BaseModel):\n", - " a: str\n", - "\n", - "\n", - "def bad_node(state: OverallState):\n", - " return {\n", - " \"a\": 123 # Invalid\n", - " }\n", - "\n", - "\n", - "def ok_node(state: OverallState):\n", - " return {\"a\": \"goodbye\"}\n", - "\n", - "\n", - "# Build the state graph\n", - "builder = StateGraph(OverallState)\n", - "builder.add_node(bad_node)\n", - "builder.add_node(ok_node)\n", - "builder.add_edge(START, \"bad_node\")\n", - "builder.add_edge(\"bad_node\", \"ok_node\")\n", - "builder.add_edge(\"ok_node\", END)\n", - "graph = builder.compile()\n", - "\n", - "# Test the graph with a valid input\n", - "try:\n", - " graph.invoke({\"a\": \"hello\"})\n", - "except Exception as e:\n", - " print(\"An exception was raised because bad_node sets `a` to an integer.\")\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "id": "456b1f77", - "metadata": {}, - "source": [ - "## Advanced Pydantic Model Usage\n", - "\n", - "This section covers more advanced topics when using Pydantic models with LangGraph.\n", - "\n", - "### Serialization Behavior\n", - "\n", - "When using Pydantic models as state schemas, it's important to understand how serialization works, especially when:\n", - "- Passing Pydantic objects as inputs\n", - "- Receiving outputs from the graph\n", - "- Working with nested Pydantic models\n", - "\n", - "Let's see these behaviors in action:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e919cdc", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from pydantic import BaseModel\n", - "\n", - "\n", - "class NestedModel(BaseModel):\n", - " value: str\n", - "\n", - "\n", - "class ComplexState(BaseModel):\n", - " text: str\n", - " count: int\n", - " nested: NestedModel\n", - "\n", - "\n", - "def process_node(state: ComplexState):\n", - " # Node receives a validated Pydantic object\n", - " print(f\"Input state type: {type(state)}\")\n", - " print(f\"Nested type: {type(state.nested)}\")\n", - "\n", - " # Return a dictionary update\n", - " return {\"text\": state.text + \" processed\", \"count\": state.count + 1}\n", - "\n", - "\n", - "# Build the graph\n", - "builder = StateGraph(ComplexState)\n", - "builder.add_node(\"process\", process_node)\n", - "builder.add_edge(START, \"process\")\n", - "builder.add_edge(\"process\", END)\n", - "graph = builder.compile()\n", - "\n", - "# Create a Pydantic instance for input\n", - "input_state = ComplexState(text=\"hello\", count=0, nested=NestedModel(value=\"test\"))\n", - "print(f\"Input object type: {type(input_state)}\")\n", - "\n", - "# Invoke graph with a Pydantic instance\n", - "result = graph.invoke(input_state)\n", - "print(f\"Output type: {type(result)}\")\n", - "print(f\"Output content: {result}\")\n", - "\n", - "# Convert back to Pydantic model if needed\n", - "output_model = ComplexState(**result)\n", - "print(f\"Converted back to Pydantic: {type(output_model)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "f13f28ce", - "metadata": {}, - "source": [ - "### Runtime Type Coercion\n", - "\n", - "Pydantic performs runtime type coercion for certain data types. This can be helpful but also lead to unexpected behavior if you're not aware of it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "faf59316", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from pydantic import BaseModel\n", - "\n", - "\n", - "class CoercionExample(BaseModel):\n", - " # Pydantic will coerce string numbers to integers\n", - " number: int\n", - " # Pydantic will parse string booleans to bool\n", - " flag: bool\n", - "\n", - "\n", - "def inspect_node(state: CoercionExample):\n", - " print(f\"number: {state.number} (type: {type(state.number)})\")\n", - " print(f\"flag: {state.flag} (type: {type(state.flag)})\")\n", - " return {}\n", - "\n", - "\n", - "builder = StateGraph(CoercionExample)\n", - "builder.add_node(\"inspect\", inspect_node)\n", - "builder.add_edge(START, \"inspect\")\n", - "builder.add_edge(\"inspect\", END)\n", - "graph = builder.compile()\n", - "\n", - "# Demonstrate coercion with string inputs that will be converted\n", - "result = graph.invoke({\"number\": \"42\", \"flag\": \"true\"})\n", - "\n", - "# This would fail with a validation error\n", - "try:\n", - " graph.invoke({\"number\": \"not-a-number\", \"flag\": \"true\"})\n", - "except Exception as e:\n", - " print(f\"\\nExpected validation error: {e}\")" - ] - }, - { - "cell_type": "markdown", - "id": "2844475b", - "metadata": {}, - "source": [ - "### Working with Message Models\n", - "\n", - "When working with LangChain message types in your state schema, there are important considerations for serialization. You should use `AnyMessage` (rather than `BaseMessage`) for proper serialization/deserialization when using message objects over the wire:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bd0734b0", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph, START, END\n", - "from pydantic import BaseModel\n", - "from langchain_core.messages import HumanMessage, AIMessage, AnyMessage\n", - "from typing import List\n", - "\n", - "\n", - "class ChatState(BaseModel):\n", - " messages: List[AnyMessage]\n", - " context: str\n", - "\n", - "\n", - "def add_message(state: ChatState):\n", - " return {\"messages\": state.messages + [AIMessage(content=\"Hello there!\")]}\n", - "\n", - "\n", - "builder = StateGraph(ChatState)\n", - "builder.add_node(\"add_message\", add_message)\n", - "builder.add_edge(START, \"add_message\")\n", - "builder.add_edge(\"add_message\", END)\n", - "graph = builder.compile()\n", - "\n", - "# Create input with a message\n", - "initial_state = ChatState(\n", - " messages=[HumanMessage(content=\"Hi\")], context=\"Customer support chat\"\n", - ")\n", - "\n", - "result = graph.invoke(initial_state)\n", - "print(f\"Output: {result}\")\n", - "\n", - "# Convert back to Pydantic model to see message types\n", - "output_model = ChatState(**result)\n", - "for i, msg in enumerate(output_model.messages):\n", - " print(f\"Message {i}: {type(msg).__name__} - {msg.content}\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/state-reducers.ipynb b/docs/docs/how-tos/state-reducers.ipynb deleted file mode 100644 index dd66a15c0..000000000 --- a/docs/docs/how-tos/state-reducers.ipynb +++ /dev/null @@ -1,430 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to update graph state from nodes\n", - "\n", - "This guide demonstrates how to define and update [state](../../concepts/low_level/#state) in LangGraph. We will demonstrate:\n", - "\n", - "1. How to use state to define a graph's [schema](../../concepts/low_level/#schema)\n", - "2. How to use [reducers](../../concepts/low_level/#reducers) to control how state updates are processed.\n", - "\n", - "We will use [messages](../../concepts/low_level/#messagesstate) in our examples. This represents a versatile formulation of state for many LLM applications. See our [concepts page](../../concepts/low_level/#working-with-messages-in-graph-state) for more detail.\n", - "\n", - "## Setup\n", - "\n", - "First, let's install langgraph:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for better debugging

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM aps built with LangGraph — read more about how to get started in the docs. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example graph\n", - "\n", - "### Define state\n", - "[State](../../concepts/low_level/#state) in LangGraph can be a `TypedDict`, `Pydantic` model, or dataclass. Below we will use `TypedDict`. See [this guide](../../how-tos/state-model) for detail on using Pydantic.\n", - "\n", - "By default, graphs will have the same input and output schema, and the state determines that schema. See [this guide](../../how-tos/input_output_schema/) for how to define distinct input and output schemas.\n", - "\n", - "Let's consider a simple example:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import AnyMessage\n", - "from typing_extensions import TypedDict\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: list[AnyMessage]\n", - " extra_field: int" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This state tracks a list of [message](https://python.langchain.com/docs/concepts/messages/) objects, as well as an extra integer field.\n", - "\n", - "### Define graph structure\n", - "\n", - "Let's build an example graph with a single node. Our [node](../../concepts/low_level/#nodes) is just a Python function that reads our graph's state and makes updates to it. The first argument to this function will always be the state:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import AIMessage\n", - "\n", - "\n", - "def node(state: State):\n", - " messages = state[\"messages\"]\n", - " new_message = AIMessage(\"Hello!\")\n", - "\n", - " return {\"messages\": messages + [new_message], \"extra_field\": 10}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This node simply appends a message to our message list, and populates an extra field.\n", - "\n", - "!!! important\n", - "\n", - " Nodes should return updates to the state directly, instead of mutating the state.\n", - "\n", - "Let's next define a simple graph containing this node. We use [StateGraph](../../concepts/low_level/#stategraph) to define a graph that operates on this state. We then use [add_node](../../concepts/low_level/#messagesstate) populate our graph." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph\n", - "\n", - "graph_builder = StateGraph(State)\n", - "graph_builder.add_node(node)\n", - "graph_builder.set_entry_point(\"node\")\n", - "graph = graph_builder.compile()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "LangGraph provides built-in utilities for visualizing your graph. Let's inspect our graph. See [this guide](../../how-tos/visualization) for detail on visualization." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "display(Image(graph.get_graph().draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this case, our graph just executes a single node." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Use graph\n", - "\n", - "Let's proceed with a simple invocation:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='Hi', additional_kwargs={}, response_metadata={}),\n", - " AIMessage(content='Hello!', additional_kwargs={}, response_metadata={})],\n", - " 'extra_field': 10}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langchain_core.messages import HumanMessage\n", - "\n", - "result = graph.invoke({\"messages\": [HumanMessage(\"Hi\")]})\n", - "result" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that:\n", - "\n", - "- We kicked off invocation by updating a single key of the state.\n", - "- We receive the entire state in the invocation result.\n", - "\n", - "For convenience, we frequently inspect the content of [message objects](https://python.langchain.com/docs/concepts/messages/) via pretty-print:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Hi\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Hello!\n" - ] - } - ], - "source": [ - "for message in result[\"messages\"]:\n", - " message.pretty_print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Process state updates with reducers\n", - "\n", - "Each key in the state can have its own independent [reducer](../../concepts/low_level/#reducers) function, which controls how updates from nodes are applied. If no reducer function is explicitly specified then it is assumed that all updates to the key should override it.\n", - "\n", - "For `TypedDict` state schemas, we can define reducers by annotating the corresponding field of the state with a reducer function.\n", - "\n", - "In the earlier example, our node updated the `\"messages\"` key in the state by appending a message to it. Below, we add a reducer to this key, such that updates are automatically appended:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import Annotated\n", - "\n", - "\n", - "def add(left, right):\n", - " \"\"\"Can also import `add` from the `operator` built-in.\"\"\"\n", - " return left + right\n", - "\n", - "\n", - "class State(TypedDict):\n", - " # highlight-next-line\n", - " messages: Annotated[list[AnyMessage], add]\n", - " extra_field: int" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now our node can be simplified:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "def node(state: State):\n", - " new_message = AIMessage(\"Hello!\")\n", - " # highlight-next-line\n", - " return {\"messages\": [new_message], \"extra_field\": 10}" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Hi\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Hello!\n" - ] - } - ], - "source": [ - "from langgraph.graph import START\n", - "\n", - "\n", - "graph = StateGraph(State).add_node(node).add_edge(START, \"node\").compile()\n", - "\n", - "result = graph.invoke({\"messages\": [HumanMessage(\"Hi\")]})\n", - "\n", - "for message in result[\"messages\"]:\n", - " message.pretty_print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### MessagesState\n", - "\n", - "In practice, there are additional considerations for updating lists of messages:\n", - "\n", - "- We may wish to update an existing message in the state.\n", - "- We may want to accept short-hands for [message formats](../../concepts/low_level/#using-messages-in-your-graph), such as [OpenAI format](https://python.langchain.com/docs/concepts/messages/#openai-format).\n", - "\n", - "LangGraph includes a built-in reducer `add_messages` that handles these considerations:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph.message import add_messages\n", - "\n", - "\n", - "class State(TypedDict):\n", - " # highlight-next-line\n", - " messages: Annotated[list[AnyMessage], add_messages]\n", - " extra_field: int\n", - "\n", - "\n", - "def node(state: State):\n", - " new_message = AIMessage(\"Hello!\")\n", - " return {\"messages\": [new_message], \"extra_field\": 10}\n", - "\n", - "\n", - "graph = StateGraph(State).add_node(node).set_entry_point(\"node\").compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Hi\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Hello!\n" - ] - } - ], - "source": [ - "# highlight-next-line\n", - "input_message = {\"role\": \"user\", \"content\": \"Hi\"}\n", - "\n", - "result = graph.invoke({\"messages\": [input_message]})\n", - "\n", - "for message in result[\"messages\"]:\n", - " message.pretty_print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is a versatile representation of state for applications involving [chat models](https://python.langchain.com/docs/concepts/chat_models/). LangGraph includes a pre-built `MessagesState` for convenience, so that we can have:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import MessagesState\n", - "\n", - "\n", - "class State(MessagesState):\n", - " extra_field: int" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Next steps\n", - "\n", - "- Continue with the [Graph API Basics](../../how-tos/#graph-api-basics) guides.\n", - "- See more detail on [state management](../../how-tos/#state-management)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/streaming-events-from-within-tools.ipynb b/docs/docs/how-tos/streaming-events-from-within-tools.ipynb deleted file mode 100644 index fca8586af..000000000 --- a/docs/docs/how-tos/streaming-events-from-within-tools.ipynb +++ /dev/null @@ -1,505 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "695d935e-b4fe-45a6-a061-a66d32cb832b", - "metadata": {}, - "source": [ - "# How to stream data from within a tool\n", - "\n", - "!!! info \"Prerequisites\"\n", - "\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [Streaming](../../concepts/streaming/)\n", - " - [Chat Models](https://python.langchain.com/docs/concepts/chat_models/)\n", - " - [Tools](https://python.langchain.com/docs/concepts/tools/)\n", - "\n", - "If your graph calls tools that use LLMs or any other streaming APIs, you might want to surface partial results during the execution of the tool, especially if the tool takes a longer time to run.\n", - "\n", - "1. To stream **arbitrary** data from inside a tool you can use [`stream_mode=\"custom\"`](../streaming#custom) and `get_stream_writer()`:\n", - "\n", - " ```python\n", - " # highlight-next-line\n", - " from langgraph.config import get_stream_writer\n", - " \n", - " def tool(tool_arg: str):\n", - " writer = get_stream_writer()\n", - " for chunk in custom_data_stream():\n", - " # stream any arbitrary data\n", - " # highlight-next-line\n", - " writer(chunk)\n", - " ...\n", - " \n", - " for chunk in graph.stream(\n", - " inputs,\n", - " # highlight-next-line\n", - " stream_mode=\"custom\"\n", - " ):\n", - " print(chunk)\n", - " ```\n", - "\n", - "2. To stream LLM tokens generated by a tool calling an LLM you can use [`stream_mode=\"messages\"`](../streaming#messages):\n", - "\n", - " ```python\n", - " from langgraph.graph import StateGraph, MessagesState\n", - " from langchain_openai import ChatOpenAI\n", - " \n", - " model = ChatOpenAI()\n", - " \n", - " def tool(tool_arg: str):\n", - " model.invoke(tool_arg)\n", - " ...\n", - " \n", - " def call_tools(state: MessagesState):\n", - " tool_call = get_tool_call(state)\n", - " tool_result = tool(**tool_call[\"args\"])\n", - " ...\n", - " \n", - " graph = (\n", - " StateGraph(MessagesState)\n", - " .add_node(call_tools)\n", - " ...\n", - " .compile()\n", - " \n", - " for msg, metadata in graph.stream(\n", - " inputs,\n", - " # highlight-next-line\n", - " stream_mode=\"messages\"\n", - " ):\n", - " print(msg)\n", - " ```\n", - "\n", - "!!! note \"Using without LangChain\"\n", - "\n", - " If you need to stream data from inside tools **without using LangChain**, you can use [`stream_mode=\"custom\"`](../streaming/#custom). Check out the [example below](#example-without-langchain) to learn more.\n", - "\n", - "!!! warning \"Async in Python < 3.11\"\n", - " \n", - " When using Python < 3.11 with async code, please ensure you manually pass the `RunnableConfig` through to the chat model when invoking it like so: `model.ainvoke(..., config)`.\n", - " The stream method collects all events from your nested code using a streaming tracer passed as a callback. In 3.11 and above, this is automatically handled via [contextvars](https://docs.python.org/3/library/contextvars.html); prior to 3.11, [asyncio's tasks](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) lacked proper `contextvar` support, meaning that the callbacks will only propagate if you manually pass the config through. We do this in the `call_model` function below.\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "b364dfe2-010b-4588-8489-fb4d8be1f200", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain-openai" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "0cf6b41d-7fcb-40b6-9a72-229cdd00a094", - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "OPENAI_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "767cd76a", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "b4ddc3ff-5620-48de-82f0-03b9137410cf", - "metadata": {}, - "source": [ - "## Streaming custom data\n", - "\n", - "We'll use a [prebuilt ReAct agent][langgraph.prebuilt.chat_agent_executor.create_react_agent] for this guide:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "f1975577-a485-42bd-b0f1-d3e987faf52b", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "from langgraph.prebuilt import create_react_agent\n", - "from langgraph.config import get_stream_writer\n", - "\n", - "\n", - "@tool\n", - "async def get_items(place: str) -> str:\n", - " \"\"\"Use this tool to list items one might find in a place you're asked about.\"\"\"\n", - " # highlight-next-line\n", - " writer = get_stream_writer()\n", - "\n", - " # this can be replaced with any actual streaming logic that you might have\n", - " items = [\"books\", \"penciles\", \"pictures\"]\n", - " for chunk in items:\n", - " # highlight-next-line\n", - " writer({\"custom_tool_data\": chunk})\n", - "\n", - " return \", \".join(items)\n", - "\n", - "\n", - "llm = ChatOpenAI(model_name=\"gpt-4o-mini\")\n", - "tools = [get_items]\n", - "# contains `agent` (tool-calling LLM) and `tools` (tool executor) nodes\n", - "agent = create_react_agent(llm, tools=tools)" - ] - }, - { - "cell_type": "markdown", - "id": "fa96d572-d15f-4f00-b629-cf25e0b4dece", - "metadata": {}, - "source": [ - "Let's now invoke our agent with an input that requires a tool call:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "8ae5051c-53b9-4c53-87b2-d7263cda3b7b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'custom_tool_data': 'books'}\n", - "{'custom_tool_data': 'penciles'}\n", - "{'custom_tool_data': 'pictures'}\n" - ] - } - ], - "source": [ - "inputs = {\n", - " \"messages\": [ # noqa\n", - " {\"role\": \"user\", \"content\": \"what items are in the office?\"}\n", - " ]\n", - "}\n", - "async for chunk in agent.astream(\n", - " inputs,\n", - " # highlight-next-line\n", - " stream_mode=\"custom\",\n", - "):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "6d8fa9fc-19af-47d6-9031-ee1720c51aa2", - "metadata": {}, - "source": [ - "## Streaming LLM tokens" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "38eaf453-9773-424d-a110-9e1038a69805", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import AIMessageChunk\n", - "from langchain_core.runnables import RunnableConfig\n", - "\n", - "\n", - "@tool\n", - "async def get_items(\n", - " place: str,\n", - " # Manually accept config (needed for Python <= 3.10)\n", - " # highlight-next-line\n", - " config: RunnableConfig,\n", - ") -> str:\n", - " \"\"\"Use this tool to list items one might find in a place you're asked about.\"\"\"\n", - " # Attention: when using async, you should be invoking the LLM using ainvoke!\n", - " # If you fail to do so, streaming will NOT work.\n", - " response = await llm.ainvoke(\n", - " [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": (\n", - " f\"Can you tell me what kind of items i might find in the following place: '{place}'. \"\n", - " \"List at least 3 such items separating them by a comma. And include a brief description of each item.\"\n", - " ),\n", - " }\n", - " ],\n", - " # highlight-next-line\n", - " config,\n", - " )\n", - " return response.content\n", - "\n", - "\n", - "tools = [get_items]\n", - "# contains `agent` (tool-calling LLM) and `tools` (tool executor) nodes\n", - "agent = create_react_agent(llm, tools=tools)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "4c9cdad3-3e9a-444f-9d9d-eae20b8d3486", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Certainly|!| Here| are| three| items| you| might| find| in| a| bedroom|:\n", - "\n", - "|1|.| **|Bed|**|:| The| central| piece| of| furniture| in| a| bedroom|,| typically| consisting| of| a| mattress| supported| by| a| frame|.| It| is| designed| for| sleeping| and| can| vary| in| size| from| twin| to| king|.| Beds| often| have| bedding|,| including| sheets|,| pillows|,| and| comfort|ers|,| to| enhance| comfort|.\n", - "\n", - "|2|.| **|D|resser|**|:| A| piece| of| furniture| with| drawers| used| for| storing| clothing| and| personal| items|.| Dress|ers| often| have| a| flat| surface| on| top|,| which| can| be| used| for| decorative| items|,| a| mirror|,| or| personal| accessories|.| They| help| keep| the| bedroom| organized| and| clutter|-free|.\n", - "\n", - "|3|.| **|Night|stand|**|:| A| small| table| or| cabinet| placed| beside| the| bed|,| used| for| holding| items| such| as| a| lamp|,| alarm| clock|,| books|,| or| personal| items|.| Night|stands| provide| convenience| for| easy| access| to| essentials| during| the| night|,| adding| functionality| and| style| to| the| bedroom| decor|.|" - ] - } - ], - "source": [ - "inputs = {\n", - " \"messages\": [ # noqa\n", - " {\"role\": \"user\", \"content\": \"what items are in the bedroom?\"}\n", - " ]\n", - "}\n", - "async for msg, metadata in agent.astream(\n", - " inputs,\n", - " # highlight-next-line\n", - " stream_mode=\"messages\",\n", - "):\n", - " if (\n", - " isinstance(msg, AIMessageChunk)\n", - " and msg.content\n", - " # Stream all messages from the tool node\n", - " # highlight-next-line\n", - " and metadata[\"langgraph_node\"] == \"tools\"\n", - " ):\n", - " print(msg.content, end=\"|\", flush=True)" - ] - }, - { - "cell_type": "markdown", - "id": "d598d7e2-617d-4c06-bc9a-6a03d5f58499", - "metadata": {}, - "source": [ - "## Example without LangChain" - ] - }, - { - "cell_type": "markdown", - "id": "780ddcb6-63a7-4c83-a739-bafbe3cd135a", - "metadata": {}, - "source": [ - "You can also stream data from within tool invocations **without using LangChain**. Below example demonstrates how to do it for a graph with a single tool-executing node. We'll leave it as an exercise for the reader to [implement ReAct agent from scratch](../react-agent-from-scratch) without using LangChain." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "3e8be67f-4bb8-4f14-9fdb-fc60340f3930", - "metadata": {}, - "outputs": [], - "source": [ - "import operator\n", - "import json\n", - "\n", - "from typing import TypedDict\n", - "from typing_extensions import Annotated\n", - "from langgraph.graph import StateGraph, START\n", - "\n", - "from openai import AsyncOpenAI\n", - "\n", - "openai_client = AsyncOpenAI()\n", - "model_name = \"gpt-4o-mini\"\n", - "\n", - "\n", - "async def stream_tokens(model_name: str, messages: list[dict]):\n", - " response = await openai_client.chat.completions.create(\n", - " messages=messages, model=model_name, stream=True\n", - " )\n", - " role = None\n", - " async for chunk in response:\n", - " delta = chunk.choices[0].delta\n", - "\n", - " if delta.role is not None:\n", - " role = delta.role\n", - "\n", - " if delta.content:\n", - " yield {\"role\": role, \"content\": delta.content}\n", - "\n", - "\n", - "# this is our tool\n", - "async def get_items(place: str) -> str:\n", - " \"\"\"Use this tool to list items one might find in a place you're asked about.\"\"\"\n", - " # highlight-next-line\n", - " writer = get_stream_writer()\n", - " response = \"\"\n", - " async for msg_chunk in stream_tokens(\n", - " model_name,\n", - " [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": (\n", - " \"Can you tell me what kind of items \"\n", - " f\"i might find in the following place: '{place}'. \"\n", - " \"List at least 3 such items separating them by a comma. \"\n", - " \"And include a brief description of each item.\"\n", - " ),\n", - " }\n", - " ],\n", - " ):\n", - " response += msg_chunk[\"content\"]\n", - " # highlight-next-line\n", - " writer(msg_chunk)\n", - "\n", - " return response\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list[dict], operator.add]\n", - "\n", - "\n", - "# this is the tool-calling graph node\n", - "async def call_tool(state: State):\n", - " ai_message = state[\"messages\"][-1]\n", - " tool_call = ai_message[\"tool_calls\"][-1]\n", - "\n", - " function_name = tool_call[\"function\"][\"name\"]\n", - " if function_name != \"get_items\":\n", - " raise ValueError(f\"Tool {function_name} not supported\")\n", - "\n", - " function_arguments = tool_call[\"function\"][\"arguments\"]\n", - " arguments = json.loads(function_arguments)\n", - "\n", - " function_response = await get_items(**arguments)\n", - " tool_message = {\n", - " \"tool_call_id\": tool_call[\"id\"],\n", - " \"role\": \"tool\",\n", - " \"name\": function_name,\n", - " \"content\": function_response,\n", - " }\n", - " return {\"messages\": [tool_message]}\n", - "\n", - "\n", - "graph = (\n", - " StateGraph(State) # noqa\n", - " .add_node(call_tool)\n", - " .add_edge(START, \"call_tool\")\n", - " .compile()\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "4e712d12-841c-4eac-a4d8-d01c73c86c8c", - "metadata": {}, - "source": [ - "Let's now invoke our graph with an AI message that contains a tool call:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "2c30c7b4-62df-4855-8219-d5e1a1a09be9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sure|!| Here| are| three| common| items| you| might| find| in| a| bedroom|:\n", - "\n", - "|1|.| **|Bed|**|:| The| focal| point| of| the| bedroom|,| a| bed| typically| consists| of| a| mattress| resting| on| a| frame|,| and| it| may| include| pillows| and| bedding|.| It| provides| a| comfortable| place| for| sleeping| and| resting|.\n", - "\n", - "|2|.| **|D|resser|**|:| A| piece| of| furniture| with| multiple| drawers|,| a| dresser| is| used| for| storing| clothes|,| accessories|,| and| personal| items|.| It| often| has| a| flat| surface| that| may| be| used| to| display| decorative| items| or| a| mirror|.\n", - "\n", - "|3|.| **|Night|stand|**|:| Also| known| as| a| bedside| table|,| a| night|stand| is| placed| next| to| the| bed| and| typically| holds| items| like| lamps|,| books|,| alarm| clocks|,| and| personal| belongings| for| convenience| during| the| night|.\n", - "\n", - "|These| items| contribute| to| the| functionality| and| comfort| of| the| bedroom| environment|.|" - ] - } - ], - "source": [ - "inputs = {\n", - " \"messages\": [\n", - " {\n", - " \"content\": None,\n", - " \"role\": \"assistant\",\n", - " \"tool_calls\": [\n", - " {\n", - " \"id\": \"1\",\n", - " \"function\": {\n", - " \"arguments\": '{\"place\":\"bedroom\"}',\n", - " \"name\": \"get_items\",\n", - " },\n", - " \"type\": \"function\",\n", - " }\n", - " ],\n", - " }\n", - " ]\n", - "}\n", - "\n", - "async for chunk in graph.astream(\n", - " inputs,\n", - " # highlight-next-line\n", - " stream_mode=\"custom\",\n", - "):\n", - " print(chunk[\"content\"], end=\"|\", flush=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/streaming-specific-nodes.ipynb b/docs/docs/how-tos/streaming-specific-nodes.ipynb deleted file mode 100644 index fd9d8c6ee..000000000 --- a/docs/docs/how-tos/streaming-specific-nodes.ipynb +++ /dev/null @@ -1,211 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "c5889ca0-6feb-4864-a630-e97ccc2c587e", - "metadata": {}, - "source": [ - "# How to stream LLM tokens from specific nodes\n", - "\n", - "!!! info \"Prerequisites\"\n", - "\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [Streaming](../../concepts/streaming/)\n", - " - [Chat Models](https://python.langchain.com/docs/concepts/chat_models/)\n", - "\n", - "A common use case when [streaming LLM tokens](../streaming-tokens) is to only stream them from specific nodes. To do so, you can use `stream_mode=\"messages\"` and filter the outputs by the `langgraph_node` field in the streamed metadata:\n", - "\n", - "```python\n", - "from langgraph.graph import StateGraph\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "model = ChatOpenAI()\n", - "\n", - "def node_a(state: State):\n", - " model.invoke(...)\n", - " ...\n", - "\n", - "def node_b(state: State):\n", - " model.invoke(...)\n", - " ...\n", - "\n", - "graph = (\n", - " StateGraph(State)\n", - " .add_node(node_a)\n", - " .add_node(node_b)\n", - " ...\n", - " .compile()\n", - " \n", - "for msg, metadata in graph.stream(\n", - " inputs,\n", - " # highlight-next-line\n", - " stream_mode=\"messages\"\n", - "):\n", - " # stream from 'node_a'\n", - " # highlight-next-line\n", - " if metadata[\"langgraph_node\"] == \"node_a\":\n", - " print(msg)\n", - "```\n", - "\n", - "!!! note \"Streaming from a specific LLM invocation\"\n", - "\n", - " If you need to instead filter streamed LLM tokens to a specific LLM invocation, check out [this guide](../streaming-tokens#filter-to-specific-llm-invocation)" - ] - }, - { - "cell_type": "markdown", - "id": "dcff85bd-8a5d-409e-93d4-e9242b5e976d", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First we need to install the packages required" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "05157237-783c-49de-9f29-7dca3c285647", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_openai" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "efd22cd2-3152-433b-ad50-65be8ace61d4", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "a0ce8c26-f38d-4bdb-89ff-b058e7560019", - "metadata": {}, - "source": [ - "## Example" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "419a3c71-7bf6-4656-99b8-b5d61f3f4bf1", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import TypedDict\n", - "from langgraph.graph import START, StateGraph, MessagesState\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "model = ChatOpenAI(model=\"gpt-4o-mini\")\n", - "\n", - "\n", - "class State(TypedDict):\n", - " topic: str\n", - " joke: str\n", - " poem: str\n", - "\n", - "\n", - "def write_joke(state: State):\n", - " topic = state[\"topic\"]\n", - " joke_response = model.invoke(\n", - " [{\"role\": \"user\", \"content\": f\"Write a joke about {topic}\"}]\n", - " )\n", - " return {\"joke\": joke_response.content}\n", - "\n", - "\n", - "def write_poem(state: State):\n", - " topic = state[\"topic\"]\n", - " poem_response = model.invoke(\n", - " [{\"role\": \"user\", \"content\": f\"Write a short poem about {topic}\"}]\n", - " )\n", - " return {\"poem\": poem_response.content}\n", - "\n", - "\n", - "graph = (\n", - " StateGraph(State)\n", - " .add_node(write_joke)\n", - " .add_node(write_poem)\n", - " # write both the joke and the poem concurrently\n", - " .add_edge(START, \"write_joke\")\n", - " .add_edge(START, \"write_poem\")\n", - " .compile()\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "fed84d5e-ba10-4324-a664-dca263951a33", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "In| shadows| soft|,| they| quietly| creep|,| \n", - "|Wh|isk|ered| wonders|,| in| dreams| they| leap|.| \n", - "|With| eyes| like| lantern|s|,| bright| and| wide|,| \n", - "|Myst|eries| linger| where| they| reside|.| \n", - "\n", - "|P|aws| that| pat|ter| on| silent| floors|,| \n", - "|Cur|led| in| sun|be|ams|,| they| seek| out| more|.| \n", - "|A| flick| of| a| tail|,| a| leap|,| a| p|ounce|,| \n", - "|In| their| playful| world|,| we| can't| help| but| bounce|.| \n", - "\n", - "|Guard|ians| of| secrets|,| with| gentle| grace|,| \n", - "|Each| little| me|ow|,| a| warm| embrace|.| \n", - "|Oh|,| the| joy| that| they| bring|,| so| pure| and| true|,| \n", - "|In| the| heart| of| a| cat|,| there's| magic| anew|.| |" - ] - } - ], - "source": [ - "for msg, metadata in graph.stream(\n", - " {\"topic\": \"cats\"},\n", - " # highlight-next-line\n", - " stream_mode=\"messages\",\n", - "):\n", - " # highlight-next-line\n", - " if msg.content and metadata[\"langgraph_node\"] == \"write_poem\":\n", - " print(msg.content, end=\"|\", flush=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/streaming-subgraphs.ipynb b/docs/docs/how-tos/streaming-subgraphs.ipynb deleted file mode 100644 index d21fc4cca..000000000 --- a/docs/docs/how-tos/streaming-subgraphs.ipynb +++ /dev/null @@ -1,206 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to stream from subgraphs\n", - "\n", - "!!! info \"Prerequisites\"\n", - "\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [Subgraphs](../../concepts/low_level/#subgraphs)\n", - " - [Chat Models](https://python.langchain.com/docs/concepts/chat_models/)\n", - "\n", - "If you have created a graph with [subgraphs](../subgraph), you may wish to stream outputs from those subgraphs. To do so, you can specify `subgraphs=True` in parent graph's `.stream()` method:\n", - "\n", - "\n", - "```python\n", - "for chunk in parent_graph.stream(\n", - " {\"foo\": \"foo\"},\n", - " # highlight-next-line\n", - " subgraphs=True\n", - "):\n", - " print(chunk)\n", - "```\n", - "\n", - "## Setup\n", - "\n", - "First let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's define a simple example:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import START, StateGraph\n", - "from typing import TypedDict\n", - "\n", - "\n", - "# Define subgraph\n", - "class SubgraphState(TypedDict):\n", - " foo: str # note that this key is shared with the parent graph state\n", - " bar: str\n", - "\n", - "\n", - "def subgraph_node_1(state: SubgraphState):\n", - " return {\"bar\": \"bar\"}\n", - "\n", - "\n", - "def subgraph_node_2(state: SubgraphState):\n", - " return {\"foo\": state[\"foo\"] + state[\"bar\"]}\n", - "\n", - "\n", - "subgraph_builder = StateGraph(SubgraphState)\n", - "subgraph_builder.add_node(subgraph_node_1)\n", - "subgraph_builder.add_node(subgraph_node_2)\n", - "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", - "subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", - "subgraph = subgraph_builder.compile()\n", - "\n", - "\n", - "# Define parent graph\n", - "class ParentState(TypedDict):\n", - " foo: str\n", - "\n", - "\n", - "def node_1(state: ParentState):\n", - " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", - "\n", - "\n", - "builder = StateGraph(ParentState)\n", - "builder.add_node(\"node_1\", node_1)\n", - "builder.add_node(\"node_2\", subgraph)\n", - "builder.add_edge(START, \"node_1\")\n", - "builder.add_edge(\"node_1\", \"node_2\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's now stream the outputs from the graph:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'node_1': {'foo': 'hi! foo'}}\n", - "{'node_2': {'foo': 'hi! foobar'}}\n" - ] - } - ], - "source": [ - "for chunk in graph.stream({\"foo\": \"foo\"}, stream_mode=\"updates\"):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can see that we're only emitting the updates from the parent graph nodes (`node_1` and `node_2`). To emit the updates from the _subgraph_ nodes you can specify `subgraphs=True`:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'node_1': {'foo': 'hi! foo'}})\n", - "(('node_2:b692b345-cfb3-b709-628c-f0ba9608f72e',), {'subgraph_node_1': {'bar': 'bar'}})\n", - "(('node_2:b692b345-cfb3-b709-628c-f0ba9608f72e',), {'subgraph_node_2': {'foo': 'hi! foobar'}})\n", - "((), {'node_2': {'foo': 'hi! foobar'}})\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"foo\": \"foo\"},\n", - " stream_mode=\"updates\",\n", - " # highlight-next-line\n", - " subgraphs=True,\n", - "):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Voila! The streamed outputs now contain updates from both the parent graph and the subgraph. **Note** that we are receiving not just the node updates, but we also the namespaces which tell us what graph (or subgraph) we are streaming from." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/streaming-tokens.ipynb b/docs/docs/how-tos/streaming-tokens.ipynb deleted file mode 100644 index 57812a460..000000000 --- a/docs/docs/how-tos/streaming-tokens.ipynb +++ /dev/null @@ -1,523 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "51466c8d-8ce4-4b3d-be4e-18fdbeda5f53", - "metadata": {}, - "source": [ - "# How to stream LLM tokens from your graph\n", - "\n", - "!!! info \"Prerequisites\"\n", - "\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [Streaming](../../concepts/streaming/)\n", - " - [Chat Models](https://python.langchain.com/docs/concepts/chat_models/)\n", - "\n", - "When building LLM applications with LangGraph, you might want to stream individual LLM tokens from the LLM calls inside LangGraph nodes. You can do so via `graph.stream(..., stream_mode=\"messages\")`:\n", - "\n", - "```python\n", - "from langgraph.graph import StateGraph\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "model = ChatOpenAI()\n", - "def call_model(state: State):\n", - " model.invoke(...)\n", - " ...\n", - "\n", - "graph = (\n", - " StateGraph(State)\n", - " .add_node(call_model)\n", - " ...\n", - " .compile()\n", - " \n", - "for msg, metadata in graph.stream(inputs, stream_mode=\"messages\"):\n", - " print(msg)\n", - "```\n", - "\n", - "The streamed outputs will be tuples of `(message chunk, metadata)`:\n", - "\n", - "* message chunk is the token streamed by the LLM\n", - "* metadata is a dictionary with information about the graph node where the LLM was called as well as the LLM invocation metadata\n", - "\n", - "!!! note \"Using without LangChain\"\n", - "\n", - " If you need to stream LLM tokens **without using LangChain**, you can use [`stream_mode=\"custom\"`](../streaming/#custom) to stream the outputs from LLM provider clients directly. Check out the [example below](#example-without-langchain) to learn more.\n", - "\n", - "!!! warning \"Async in Python < 3.11\"\n", - " \n", - " When using Python < 3.11 with async code, please ensure you manually pass the `RunnableConfig` through to the chat model when invoking it like so: `model.ainvoke(..., config)`.\n", - " The stream method collects all events from your nested code using a streaming tracer passed as a callback. In 3.11 and above, this is automatically handled via [contextvars](https://docs.python.org/3/library/contextvars.html); prior to 3.11, [asyncio's tasks](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) lacked proper `contextvar` support, meaning that the callbacks will only propagate if you manually pass the config through. We do this in the `call_model` function below." - ] - }, - { - "cell_type": "markdown", - "id": "7cbd446a-808f-4394-be92-d45ab818953c", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First we need to install the packages required" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "af4ce0ba-7596-4e5f-8bf8-0b0bd6e62833", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_openai" - ] - }, - { - "cell_type": "markdown", - "id": "d67b5425", - "metadata": {}, - "source": [ - "Next, we need to set API keys for OpenAI (the LLM we will use)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a372be6f", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "cc088bbd", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "e03c5094-9297-4d19-a04e-3eedc75cefb4", - "metadata": {}, - "source": [ - "!!! note Manual Callback Propagation\n", - "\n", - " Note that in `call_model(state: State, config: RunnableConfig):` below, we a) accept the [`RunnableConfig`](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.config.RunnableConfig.html#langchain_core.runnables.config.RunnableConfig) in the node function and b) pass it in as the second arg for `model.ainvoke(..., config)`. This is optional for python >= 3.11." - ] - }, - { - "cell_type": "markdown", - "id": "ad2c85b6-28f8-4c7f-843a-c05cb7fd7187", - "metadata": {}, - "source": [ - "## Example" - ] - }, - { - "cell_type": "markdown", - "id": "afcbdd41-dff8-4118-8901-a619f91f3feb", - "metadata": {}, - "source": [ - "Below we demonstrate an example with two LLM calls in a single node." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7cc5905f-df82-4b31-84ad-2054f463aee8", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import TypedDict\n", - "from langgraph.graph import START, StateGraph, MessagesState\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "\n", - "# Note: we're adding the tags here to be able to filter the model outputs down the line\n", - "joke_model = ChatOpenAI(model=\"gpt-4o-mini\", tags=[\"joke\"])\n", - "poem_model = ChatOpenAI(model=\"gpt-4o-mini\", tags=[\"poem\"])\n", - "\n", - "\n", - "class State(TypedDict):\n", - " topic: str\n", - " joke: str\n", - " poem: str\n", - "\n", - "\n", - "# highlight-next-line\n", - "async def call_model(state, config):\n", - " topic = state[\"topic\"]\n", - " print(\"Writing joke...\")\n", - " # Note: Passing the config through explicitly is required for python < 3.11\n", - " # Since context var support wasn't added before then: https://docs.python.org/3/library/asyncio-task.html#creating-tasks\n", - " joke_response = await joke_model.ainvoke(\n", - " [{\"role\": \"user\", \"content\": f\"Write a joke about {topic}\"}],\n", - " # highlight-next-line\n", - " config,\n", - " )\n", - " print(\"\\n\\nWriting poem...\")\n", - " poem_response = await poem_model.ainvoke(\n", - " [{\"role\": \"user\", \"content\": f\"Write a short poem about {topic}\"}],\n", - " # highlight-next-line\n", - " config,\n", - " )\n", - " return {\"joke\": joke_response.content, \"poem\": poem_response.content}\n", - "\n", - "\n", - "graph = StateGraph(State).add_node(call_model).add_edge(START, \"call_model\").compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "96050fba", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing joke...\n", - "Why| was| the| cat| sitting| on| the| computer|?\n", - "\n", - "|Because| it| wanted| to| keep| an| eye| on| the| mouse|!|\n", - "\n", - "Writing poem...\n", - "In| sun|lit| patches|,| sleek| and| sly|,| \n", - "|Wh|isk|ers| twitch| as| shadows| fly|.| \n", - "|With| velvet| paws| and| eyes| so| bright|,| \n", - "|They| dance| through| dreams|,| both| day| and| night|.| \n", - "\n", - "|A| playful| p|ounce|,| a| gentle| p|urr|,| \n", - "|In| every| leap|,| a| soft| allure|.| \n", - "|Cur|led| in| warmth|,| a| silent| grace|,| \n", - "|Each| furry| friend|,| a| warm| embrace|.| \n", - "\n", - "|Myst|ery| wrapped| in| fur| and| charm|,| \n", - "|A| soothing| presence|,| a| gentle| balm|.| \n", - "|In| their| gaze|,| the| world| slows| down|,| \n", - "|For| in| their| realm|,| we're| all| ren|own|.|" - ] - } - ], - "source": [ - "async for msg, metadata in graph.astream(\n", - " {\"topic\": \"cats\"},\n", - " # highlight-next-line\n", - " stream_mode=\"messages\",\n", - "):\n", - " if msg.content:\n", - " print(msg.content, end=\"|\", flush=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "bcdf561d-a5cd-4197-9c65-9ab8af85941f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'langgraph_step': 1,\n", - " 'langgraph_node': 'call_model',\n", - " 'langgraph_triggers': ['start:call_model'],\n", - " 'langgraph_path': ('__pregel_pull', 'call_model'),\n", - " 'langgraph_checkpoint_ns': 'call_model:6ddc5f0f-1dd0-325d-3014-f949286ce595',\n", - " 'checkpoint_ns': 'call_model:6ddc5f0f-1dd0-325d-3014-f949286ce595',\n", - " 'ls_provider': 'openai',\n", - " 'ls_model_name': 'gpt-4o-mini',\n", - " 'ls_model_type': 'chat',\n", - " 'ls_temperature': 0.7,\n", - " 'tags': ['poem']}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "metadata" - ] - }, - { - "cell_type": "markdown", - "id": "7db91f8d-3e17-47f4-b45e-c72bbbcbb5ed", - "metadata": {}, - "source": [ - "### Filter to specific LLM invocation" - ] - }, - { - "cell_type": "markdown", - "id": "a3a72acd-98cc-43f6-9dbb-0e97d03d211b", - "metadata": {}, - "source": [ - "You can see that we're streaming tokens from all of the LLM invocations. Let's now filter the streamed tokens to include only a specific LLM invocation. We can use the streamed metadata and filter events using the tags we've added to the LLMs previously:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "c9e0df34-6020-445e-8ecd-ca4239e9b22b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing joke...\n", - "Why| was| the| cat| sitting| on| the| computer|?\n", - "\n", - "|Because| it| wanted| to| keep| an| eye| on| the| mouse|!|\n", - "\n", - "Writing poem...\n" - ] - } - ], - "source": [ - "async for msg, metadata in graph.astream(\n", - " {\"topic\": \"cats\"},\n", - " stream_mode=\"messages\",\n", - "):\n", - " # highlight-next-line\n", - " if msg.content and \"joke\" in metadata.get(\"tags\", []):\n", - " print(msg.content, end=\"|\", flush=True)" - ] - }, - { - "cell_type": "markdown", - "id": "be8fd3d7-a227-41ad-bd08-7ef994ab291b", - "metadata": {}, - "source": [ - "## Example without LangChain" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "699b3bab-9da7-4f2a-8006-93289350d89d", - "metadata": {}, - "outputs": [], - "source": [ - "from openai import AsyncOpenAI\n", - "\n", - "openai_client = AsyncOpenAI()\n", - "model_name = \"gpt-4o-mini\"\n", - "\n", - "\n", - "async def stream_tokens(model_name: str, messages: list[dict]):\n", - " response = await openai_client.chat.completions.create(\n", - " messages=messages, model=model_name, stream=True\n", - " )\n", - "\n", - " role = None\n", - " async for chunk in response:\n", - " delta = chunk.choices[0].delta\n", - "\n", - " if delta.role is not None:\n", - " role = delta.role\n", - "\n", - " if delta.content:\n", - " yield {\"role\": role, \"content\": delta.content}\n", - "\n", - "\n", - "# highlight-next-line\n", - "async def call_model(state, config, writer):\n", - " topic = state[\"topic\"]\n", - " joke = \"\"\n", - " poem = \"\"\n", - "\n", - " print(\"Writing joke...\")\n", - " async for msg_chunk in stream_tokens(\n", - " model_name, [{\"role\": \"user\", \"content\": f\"Write a joke about {topic}\"}]\n", - " ):\n", - " joke += msg_chunk[\"content\"]\n", - " metadata = {**config[\"metadata\"], \"tags\": [\"joke\"]}\n", - " chunk_to_stream = (msg_chunk, metadata)\n", - " # highlight-next-line\n", - " writer(chunk_to_stream)\n", - "\n", - " print(\"\\n\\nWriting poem...\")\n", - " async for msg_chunk in stream_tokens(\n", - " model_name, [{\"role\": \"user\", \"content\": f\"Write a short poem about {topic}\"}]\n", - " ):\n", - " poem += msg_chunk[\"content\"]\n", - " metadata = {**config[\"metadata\"], \"tags\": [\"poem\"]}\n", - " chunk_to_stream = (msg_chunk, metadata)\n", - " # highlight-next-line\n", - " writer(chunk_to_stream)\n", - "\n", - " return {\"joke\": joke, \"poem\": poem}\n", - "\n", - "\n", - "graph = StateGraph(State).add_node(call_model).add_edge(START, \"call_model\").compile()" - ] - }, - { - "cell_type": "markdown", - "id": "8af13d73-a0ea-44c0-a92e-28676cd164dd", - "metadata": {}, - "source": [ - "!!! note \"stream_mode=\"custom\"\"\n", - "\n", - " When streaming LLM tokens without LangChain, we recommend using [`stream_mode=\"custom\"`](../streaming/#stream-modecustom). This allows you to explicitly control which data from the LLM provider APIs to include in LangGraph streamed outputs, including any additional metadata." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "e977406d-7be6-4c9f-9185-5e5551f848f3", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing joke...\n", - "Why| was| the| cat| sitting| on| the| computer|?\n", - "\n", - "|Because| it| wanted| to| keep| an| eye| on| the|\n", - "\n", - "Writing poem...\n", - " mouse|!|In| sun|lit| patches|,| they| stretch| and| y|awn|,| \n", - "|With| whispered| paws| at| the| break| of| dawn|.| \n", - "|Wh|isk|ers| twitch| in| the| morning| light|,| \n", - "|Sil|ken| shadows|,| a| graceful| sight|.| \n", - "\n", - "|The| gentle| p|urr|s|,| a| soothing| song|,| \n", - "|In| a| world| of| comfort|,| where| they| belong|.| \n", - "|M|yster|ious| hearts| wrapped| in| soft|est| fur|,| \n", - "|F|eline| whispers| in| every| p|urr|.| \n", - "\n", - "|Ch|asing| dreams| on| a| moon|lit| chase|,| \n", - "|With| a| flick| of| a| tail|,| they| glide| with| grace|.| \n", - "|Oh|,| playful| spirits| of| whisk|ered| cheer|,| \n", - "|In| your| quiet| company|,| the| world| feels| near|.| |" - ] - } - ], - "source": [ - "async for msg, metadata in graph.astream(\n", - " {\"topic\": \"cats\"},\n", - " # highlight-next-line\n", - " stream_mode=\"custom\",\n", - "):\n", - " print(msg[\"content\"], end=\"|\", flush=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "0bdc1635-f424-4a5f-95db-e993bb16adb2", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'langgraph_step': 1,\n", - " 'langgraph_node': 'call_model',\n", - " 'langgraph_triggers': ['start:call_model'],\n", - " 'langgraph_path': ('__pregel_pull', 'call_model'),\n", - " 'langgraph_checkpoint_ns': 'call_model:3fa3fbe1-39d8-5209-dd77-0da38d4cc1c9',\n", - " 'tags': ['poem']}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "metadata" - ] - }, - { - "cell_type": "markdown", - "id": "a3afbbee-fab8-4c7f-ad26-094f8c8f4dd9", - "metadata": {}, - "source": [ - "To filter to the specific LLM invocation, you can use the streamed metadata:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "fdeee9d9-2625-403a-9253-418a0feeed77", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Writing joke...\n", - "\n", - "\n", - "Writing poem...\n", - "In| shadows| soft|,| they| weave| and| play|,| \n", - "|With| whispered| paws|,| they| greet| the| day|.| \n", - "|Eyes| like| lantern|s|,| bright| and| keen|,| \n", - "|Guard|ians| of| secrets|,| unseen|,| serene|.| \n", - "\n", - "|They| twist| and| stretch| in| sun|lit| beams|,| \n", - "|Ch|asing| the| echoes| of| half|-|formed| dreams|.| \n", - "|With| p|urring| songs| that| soothe| the| night|,| \n", - "|F|eline| spirits|,| pure| delight|.| \n", - "\n", - "|On| windows|ills|,| they| perch| and| stare|,| \n", - "|Ad|vent|urers| bold| with| a| graceful| flair|.| \n", - "|In| every| leap| and| playful| bound|,| \n", - "|The| magic| of| cats|—|where| love| is| found|.|" - ] - } - ], - "source": [ - "async for msg, metadata in graph.astream(\n", - " {\"topic\": \"cats\"},\n", - " stream_mode=\"custom\",\n", - "):\n", - " # highlight-next-line\n", - " if \"poem\" in metadata.get(\"tags\", []):\n", - " print(msg[\"content\"], end=\"|\", flush=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/streaming.ipynb b/docs/docs/how-tos/streaming.ipynb deleted file mode 100644 index d0a349fb8..000000000 --- a/docs/docs/how-tos/streaming.ipynb +++ /dev/null @@ -1,547 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "76c4b04f-0c03-4321-9d40-38d12c59d088", - "metadata": {}, - "source": [ - "# How to stream" - ] - }, - { - "cell_type": "markdown", - "id": "15403cdb-441d-43af-a29f-fc15abe03dcc", - "metadata": {}, - "source": [ - "!!! info \"Prerequisites\"\n", - "\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [Streaming](../../concepts/streaming/)\n", - " - [Chat Models](https://python.langchain.com/docs/concepts/chat_models/)\n", - "\n", - "Streaming is crucial for enhancing the responsiveness of applications built on LLMs. By displaying output progressively, even before a complete response is ready, streaming significantly improves user experience (UX), particularly when dealing with the latency of LLMs.\n", - "\n", - "LangGraph is built with first class support for streaming. There are several different ways to stream back outputs from a graph run:\n", - "\n", - "- `\"values\"`: Emit all values in the state after each step.\n", - "- `\"updates\"`: Emit only the node names and updates returned by the nodes after each step.\n", - " If multiple updates are made in the same step (e.g. multiple nodes are run) then those updates are emitted separately.\n", - "- `\"custom\"`: Emit custom data from inside nodes using `StreamWriter`.\n", - "- [`\"messages\"`](../streaming-tokens): Emit LLM messages token-by-token together with metadata for any LLM invocations inside nodes.\n", - "- `\"debug\"`: Emit debug events with as much information as possible for each step.\n", - "\n", - "You can stream outputs from the graph by using `graph.stream(..., stream_mode=)` method, e.g.:\n", - "\n", - "=== \"Sync\"\n", - "\n", - " ```python\n", - " for chunk in graph.stream(inputs, stream_mode=\"updates\"):\n", - " print(chunk)\n", - " ```\n", - "\n", - "=== \"Async\"\n", - "\n", - " ```python\n", - " async for chunk in graph.astream(inputs, stream_mode=\"updates\"):\n", - " print(chunk)\n", - " ```\n", - "\n", - "You can also combine multiple streaming mode by providing a list to `stream_mode` parameter:\n", - "\n", - "=== \"Sync\"\n", - "\n", - " ```python\n", - " for chunk in graph.stream(inputs, stream_mode=[\"updates\", \"custom\"]):\n", - " print(chunk)\n", - " ```\n", - "\n", - "=== \"Async\"\n", - "\n", - " ```python\n", - " async for chunk in graph.astream(inputs, stream_mode=[\"updates\", \"custom\"]):\n", - " print(chunk)\n", - " ```" - ] - }, - { - "cell_type": "markdown", - "id": "9723cf76-6fe4-4b52-829f-3f28712ddcb7", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "427f8f66-7404-4c7d-a642-af5053b8b28f", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_openai" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "03310ce6-e21f-4378-93bf-dd273fdb3e9a", - "metadata": {}, - "outputs": [ - { - "name": "stdin", - "output_type": "stream", - "text": [ - "OPENAI_API_KEY: ········\n" - ] - } - ], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "80399508-bad8-43b7-8ec9-4c06ad1774cc", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "be4adbb2-61e8-4bb7-942d-b4dc27ba71ac", - "metadata": {}, - "source": [ - "Let's define a simple graph with two nodes:" - ] - }, - { - "cell_type": "markdown", - "id": "f6d4c513-1006-4179-bba9-d858fc952169", - "metadata": {}, - "source": [ - "## Define graph" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "faeb5ce8-d383-4277-b0a8-322e713638e4", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import TypedDict\n", - "from langgraph.graph import StateGraph, START\n", - "\n", - "\n", - "class State(TypedDict):\n", - " topic: str\n", - " joke: str\n", - "\n", - "\n", - "def refine_topic(state: State):\n", - " return {\"topic\": state[\"topic\"] + \" and cats\"}\n", - "\n", - "\n", - "def generate_joke(state: State):\n", - " return {\"joke\": f\"This is a joke about {state['topic']}\"}\n", - "\n", - "\n", - "graph = (\n", - " StateGraph(State)\n", - " .add_node(refine_topic)\n", - " .add_node(generate_joke)\n", - " .add_edge(START, \"refine_topic\")\n", - " .add_edge(\"refine_topic\", \"generate_joke\")\n", - " .compile()\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "f9b90850-85bf-4391-b6b7-22ad45edaa3b", - "metadata": {}, - "source": [ - "## Stream all values in the state (stream_mode=\"values\") {#values}" - ] - }, - { - "cell_type": "markdown", - "id": "d1ed60d4-cf78-4d4d-a660-6879539e168f", - "metadata": {}, - "source": [ - "Use this to stream **all values** in the state after each step." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "3daca06a-369b-41e5-8e4e-6edc4d4af3a7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'topic': 'ice cream'}\n", - "{'topic': 'ice cream and cats'}\n", - "{'topic': 'ice cream and cats', 'joke': 'This is a joke about ice cream and cats'}\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"topic\": \"ice cream\"},\n", - " # highlight-next-line\n", - " stream_mode=\"values\",\n", - "):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "adcb1bdb-f9fa-4d42-87ce-8e25d4290883", - "metadata": {}, - "source": [ - "## Stream state updates from the nodes (stream_mode=\"updates\") {#updates}" - ] - }, - { - "cell_type": "markdown", - "id": "44c55326-d077-4583-ae5b-396f45daf21c", - "metadata": {}, - "source": [ - "Use this to stream only the **state updates** returned by the nodes after each step. The streamed outputs include the name of the node as well as the update." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "eed7d401-37d1-4d15-b6dd-88956fff89e1", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'refine_topic': {'topic': 'ice cream and cats'}}\n", - "{'generate_joke': {'joke': 'This is a joke about ice cream and cats'}}\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"topic\": \"ice cream\"},\n", - " # highlight-next-line\n", - " stream_mode=\"updates\",\n", - "):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "b9ed9c68-b7c5-4420-945d-84fa33fcf88f", - "metadata": {}, - "source": [ - "## Stream debug events (stream_mode=\"debug\") {#debug}" - ] - }, - { - "cell_type": "markdown", - "id": "94690715-f86c-42f6-be2d-4df82f6f9a96", - "metadata": {}, - "source": [ - "Use this to stream **debug events** with as much information as possible for each step. Includes information about tasks that were scheduled to be executed as well as the results of the task executions." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "cc6354f6-0c39-49cf-a529-b9c6c8713d7c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'type': 'task', 'timestamp': '2025-01-28T22:06:34.789803+00:00', 'step': 1, 'payload': {'id': 'eb305d74-3460-9510-d516-beed71a63414', 'name': 'refine_topic', 'input': {'topic': 'ice cream'}, 'triggers': ['start:refine_topic']}}\n", - "{'type': 'task_result', 'timestamp': '2025-01-28T22:06:34.790013+00:00', 'step': 1, 'payload': {'id': 'eb305d74-3460-9510-d516-beed71a63414', 'name': 'refine_topic', 'error': None, 'result': [('topic', 'ice cream and cats')], 'interrupts': []}}\n", - "{'type': 'task', 'timestamp': '2025-01-28T22:06:34.790165+00:00', 'step': 2, 'payload': {'id': '74355cb8-6284-25e0-579f-430493c1bdab', 'name': 'generate_joke', 'input': {'topic': 'ice cream and cats'}, 'triggers': ['refine_topic']}}\n", - "{'type': 'task_result', 'timestamp': '2025-01-28T22:06:34.790337+00:00', 'step': 2, 'payload': {'id': '74355cb8-6284-25e0-579f-430493c1bdab', 'name': 'generate_joke', 'error': None, 'result': [('joke', 'This is a joke about ice cream and cats')], 'interrupts': []}}\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"topic\": \"ice cream\"},\n", - " # highlight-next-line\n", - " stream_mode=\"debug\",\n", - "):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "6791da60-0513-43e6-b445-788dd81683bb", - "metadata": {}, - "source": [ - "## Stream LLM tokens ([stream_mode=\"messages\"](../streaming-tokens)) {#messages}" - ] - }, - { - "cell_type": "markdown", - "id": "1f45d68b-f7ca-4012-96cc-d276a143f571", - "metadata": {}, - "source": [ - "Use this to stream **LLM messages token-by-token** together with metadata for any LLM invocations inside nodes or tasks. Let's modify the above example to include LLM calls:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "efa787e1-be4d-433b-a1af-46a9c99ad8f3", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_openai import ChatOpenAI\n", - "\n", - "llm = ChatOpenAI(model=\"gpt-4o-mini\")\n", - "\n", - "\n", - "def generate_joke(state: State):\n", - " # highlight-next-line\n", - " llm_response = llm.invoke(\n", - " # highlight-next-line\n", - " [\n", - " # highlight-next-line\n", - " {\"role\": \"user\", \"content\": f\"Generate a joke about {state['topic']}\"}\n", - " # highlight-next-line\n", - " ]\n", - " # highlight-next-line\n", - " )\n", - " return {\"joke\": llm_response.content}\n", - "\n", - "\n", - "graph = (\n", - " StateGraph(State)\n", - " .add_node(refine_topic)\n", - " .add_node(generate_joke)\n", - " .add_edge(START, \"refine_topic\")\n", - " .add_edge(\"refine_topic\", \"generate_joke\")\n", - " .compile()\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "c251f809-8922-46ea-bd5b-18264fcc523a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Why| did| the| cat| sit| on| the| ice| cream| cone|?\n", - "\n", - "|Because| it| wanted| to| be| a| \"|p|urr|-f|ect|\"| scoop|!| 🍦|🐱|" - ] - } - ], - "source": [ - "for message_chunk, metadata in graph.stream(\n", - " {\"topic\": \"ice cream\"},\n", - " # highlight-next-line\n", - " stream_mode=\"messages\",\n", - "):\n", - " if message_chunk.content:\n", - " print(message_chunk.content, end=\"|\", flush=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "b1912d72-7b68-4810-8b98-d7f3c35fbb6d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'langgraph_step': 2,\n", - " 'langgraph_node': 'generate_joke',\n", - " 'langgraph_triggers': ['refine_topic'],\n", - " 'langgraph_path': ('__pregel_pull', 'generate_joke'),\n", - " 'langgraph_checkpoint_ns': 'generate_joke:568879bc-8800-2b0d-a5b5-059526a4bebf',\n", - " 'checkpoint_ns': 'generate_joke:568879bc-8800-2b0d-a5b5-059526a4bebf',\n", - " 'ls_provider': 'openai',\n", - " 'ls_model_name': 'gpt-4o-mini',\n", - " 'ls_model_type': 'chat',\n", - " 'ls_temperature': 0.7}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "metadata" - ] - }, - { - "cell_type": "markdown", - "id": "0d1ebeda-4498-40e0-a30a-0844cb491425", - "metadata": {}, - "source": [ - "## Stream custom data (stream_mode=\"custom\") {#custom}" - ] - }, - { - "cell_type": "markdown", - "id": "e9ca56cc-d36e-4061-b1f6-9ade4e3e00a0", - "metadata": {}, - "source": [ - "Use this to stream custom data from inside nodes using [`StreamWriter`][langgraph.types.StreamWriter]." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "e3bf6a2b-afe3-4bd3-8474-57cccd994f23", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.types import StreamWriter\n", - "\n", - "\n", - "# highlight-next-line\n", - "def generate_joke(state: State, writer: StreamWriter):\n", - " # highlight-next-line\n", - " writer({\"custom_key\": \"Writing custom data while generating a joke\"})\n", - " return {\"joke\": f\"This is a joke about {state['topic']}\"}\n", - "\n", - "\n", - "graph = (\n", - " StateGraph(State)\n", - " .add_node(refine_topic)\n", - " .add_node(generate_joke)\n", - " .add_edge(START, \"refine_topic\")\n", - " .add_edge(\"refine_topic\", \"generate_joke\")\n", - " .compile()\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "2ecfb0b0-3311-46f5-9dc8-6c7853373792", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'custom_key': 'Writing custom data while generating a joke'}\n" - ] - } - ], - "source": [ - "for chunk in graph.stream(\n", - " {\"topic\": \"ice cream\"},\n", - " # highlight-next-line\n", - " stream_mode=\"custom\",\n", - "):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "28e67f4d-fcab-46a8-93e2-b7bee30336c1", - "metadata": {}, - "source": [ - "## Configure multiple streaming modes {#multiple}" - ] - }, - { - "cell_type": "markdown", - "id": "01ff946a-f38d-42ad-bc71-a2621fab1b6c", - "metadata": {}, - "source": [ - "Use this to combine multiple streaming modes. The outputs are streamed as tuples `(stream_mode, streamed_output)`." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "bf4cab4b-356c-4276-9035-26974abe1efe", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stream mode: updates\n", - "{'refine_topic': {'topic': 'ice cream and cats'}}\n", - "\n", - "\n", - "Stream mode: custom\n", - "{'custom_key': 'Writing custom data while generating a joke'}\n", - "\n", - "\n", - "Stream mode: updates\n", - "{'generate_joke': {'joke': 'This is a joke about ice cream and cats'}}\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for stream_mode, chunk in graph.stream(\n", - " {\"topic\": \"ice cream\"},\n", - " # highlight-next-line\n", - " stream_mode=[\"updates\", \"custom\"],\n", - "):\n", - " print(f\"Stream mode: {stream_mode}\")\n", - " print(chunk)\n", - " print(\"\\n\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/streaming.md b/docs/docs/how-tos/streaming.md new file mode 100644 index 000000000..424b38507 --- /dev/null +++ b/docs/docs/how-tos/streaming.md @@ -0,0 +1,817 @@ +# Stream outputs + +## Streaming API + +LangGraph graphs expose the [`.stream()`][langgraph.pregel.Pregel.stream] (sync) and [`.astream()`][langgraph.pregel.Pregel.astream] (async) methods to yield streamed outputs as iterators. + +Basic usage example: + +=== "Sync" + + ```python + for chunk in graph.stream(inputs, stream_mode="updates"): + print(chunk) + ``` + +=== "Async" + + ```python + async for chunk in graph.astream(inputs, stream_mode="updates"): + print(chunk) + ``` + +??? example "Extended example: streaming updates" + + ```python + from typing import TypedDict + from langgraph.graph import StateGraph, START, END + + class State(TypedDict): + topic: str + joke: str + + def refine_topic(state: State): + return {"topic": state["topic"] + " and cats"} + + def generate_joke(state: State): + return {"joke": f"This is a joke about {state['topic']}"} + + graph = ( + StateGraph(State) + .add_node(refine_topic) + .add_node(generate_joke) + .add_edge(START, "refine_topic") + .add_edge("refine_topic", "generate_joke") + .add_edge("generate_joke", END) + .compile() + ) + + # highlight-next-line + for chunk in graph.stream( # (1)! + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="updates", # (2)! + ): + print(chunk) + ``` + + 1. The `stream()` method returns an iterator that yields streamed outputs. + 2. Set `stream_mode="updates"` to stream only the updates to the graph state after each node. Other stream modes are also available. See [supported stream modes](#supported-stream-modes) for details. + + ```output + {'refine_topic': {'topic': 'ice cream and cats'}} + {'generate_joke': {'joke': 'This is a joke about ice cream and cats'}} + ``` + + +### Supported stream modes + +| Mode | Description | +|-------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [`values`](#stream-graph-state) | Streams the full value of the state after each step of the graph. | +| [`updates`](#stream-graph-state) | Streams the updates to the state after each step of the graph. If multiple updates are made in the same step (e.g., multiple nodes are run), those updates are streamed separately. | +| [`custom`](#custom) | Streams custom data from inside your graph nodes. | +| [`messages`](#messages) | Streams LLM tokens and metadata for the graph node where the LLM is invoked. | +| [`debug`](#debug) | Streams as much information as possible throughout the execution of the graph. | + + +### Stream multiple modes + +You can pass a list as the `stream_mode` parameter to stream multiple modes at once. + +The streamed outputs will be tuples of `(mode, chunk)` where `mode` is the name of the stream mode and `chunk` is the data streamed by that mode. + +=== "Sync" + + ```python + for mode, chunk in graph.stream(inputs, stream_mode=["updates", "custom"]): + print(chunk) + ``` + +=== "Async" + + ```python + async for mode, chunk in graph.astream(inputs, stream_mode=["updates", "custom"]): + print(chunk) + ``` + +## Stream graph state + +Use the stream modes `updates` and `values` to stream the state of the graph as it executes. + +* `updates` streams the **updates** to the state after each step of the graph. +* `values` streams the **full value** of the state after each step of the graph. + +```python +from typing import TypedDict +from langgraph.graph import StateGraph, START, END + + +class State(TypedDict): + topic: str + joke: str + + +def refine_topic(state: State): + return {"topic": state["topic"] + " and cats"} + + +def generate_joke(state: State): + return {"joke": f"This is a joke about {state['topic']}"} + +graph = ( + StateGraph(State) + .add_node(refine_topic) + .add_node(generate_joke) + .add_edge(START, "refine_topic") + .add_edge("refine_topic", "generate_joke") + .add_edge("generate_joke", END) + .compile() +) +``` + +=== "updates" + + Use this to stream only the **state updates** returned by the nodes after each step. The streamed outputs include the name of the node as well as the update. + + + ```python + for chunk in graph.stream( + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="updates", + ): + print(chunk) + ``` + +=== "values" + + Use this to stream the **full state** of the graph after each step. + + ```python + for chunk in graph.stream( + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="values", + ): + print(chunk) + ``` + + +## Subgraphs + +To include outputs from [subgraphs](../concepts/subgraphs.md) in the streamed outputs, you can set `subgraphs=True` in the `.stream()` method of the parent graph. This will stream outputs from both the parent graph and any subgraphs. + +```python +for chunk in graph.stream( + {"foo": "foo"}, + # highlight-next-line + subgraphs=True, # (1)! + stream_mode="updates", +): + print(chunk) +``` + +1. Set `subgraphs=True` to stream outputs from subgraphs. + +??? example "Extended example: streaming from subgraphs" + + ```python + from langgraph.graph import START, StateGraph + from typing import TypedDict + + + # Define subgraph + class SubgraphState(TypedDict): + foo: str # note that this key is shared with the parent graph state + bar: str + + + def subgraph_node_1(state: SubgraphState): + return {"bar": "bar"} + + + def subgraph_node_2(state: SubgraphState): + return {"foo": state["foo"] + state["bar"]} + + + subgraph_builder = StateGraph(SubgraphState) + subgraph_builder.add_node(subgraph_node_1) + subgraph_builder.add_node(subgraph_node_2) + subgraph_builder.add_edge(START, "subgraph_node_1") + subgraph_builder.add_edge("subgraph_node_1", "subgraph_node_2") + subgraph = subgraph_builder.compile() + + + # Define parent graph + class ParentState(TypedDict): + foo: str + + + def node_1(state: ParentState): + return {"foo": "hi! " + state["foo"]} + + + builder = StateGraph(ParentState) + builder.add_node("node_1", node_1) + builder.add_node("node_2", subgraph) + builder.add_edge(START, "node_1") + builder.add_edge("node_1", "node_2") + graph = builder.compile() + + for chunk in graph.stream( + {"foo": "foo"}, + stream_mode="updates", + # highlight-next-line + subgraphs=True, # (1)! + ): + print(chunk) + ``` + + 1. Set `subgraphs=True` to stream outputs from subgraphs. + + **Note** that we are receiving not just the node updates, but we also the namespaces which tell us what graph (or subgraph) we are streaming from. + +## Debugging {#debug} + +Use the `debug` streaming mode to stream as much information as possible throughout the execution of the graph. The streamed outputs include the name of the node as well as the full state. + +```python +for chunk in graph.stream( + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="debug", +): + print(chunk) +``` + + +## LLM tokens {#messages} + +Use the `messages` streaming mode to stream Large Language Model (LLM) outputs **token by token** from any part of your graph, including nodes, tools, subgraphs, or tasks. + +The streamed output from [`messages` mode](#supported-stream-modes) is a tuple `(message_chunk, metadata)` where: + +- `message_chunk`: the token or message segment from the LLM. +- `metadata`: a dictionary containing details about the graph node and LLM invocation. + +> If your LLM is not available as a LangChain integration, you can stream its outputs using `custom` mode instead. See [use with any LLM](#use-with-any-llm) for details. + +!!! warning "Manual config required for async in Python < 3.11" + + When using Python < 3.11 with async code, you must explicitly pass `RunnableConfig` to `ainvoke()` to enable proper streaming. See [Async with Python < 3.11](#async) for details or upgrade to Python 3.11+. + +```python +from dataclasses import dataclass + +from langchain.chat_models import init_chat_model +from langgraph.graph import StateGraph, START + + +@dataclass +class MyState: + topic: str + joke: str = "" + + +llm = init_chat_model(model="openai:gpt-4o-mini") + +def call_model(state: MyState): + """Call the LLM to generate a joke about a topic""" + # highlight-next-line + llm_response = llm.invoke( # (1)! + [ + {"role": "user", "content": f"Generate a joke about {state.topic}"} + ] + ) + return {"joke": llm_response.content} + +graph = ( + StateGraph(MyState) + .add_node(call_model) + .add_edge(START, "call_model") + .compile() +) + +for message_chunk, metadata in graph.stream( # (2)! + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="messages", +): + if message_chunk.content: + print(message_chunk.content, end="|", flush=True) +``` + +1. Note that the message events are emitted even when the LLM is run using `.invoke` rather than `.stream`. +2. The "messages" stream mode returns an iterator of tuples `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information. + + +### Filter by LLM invocation + +You can associate `tags` with LLM invocations to filter the streamed tokens by LLM invocation. + +```python +from langchain.chat_models import init_chat_model + +llm_1 = init_chat_model(model="openai:gpt-4o-mini", tags=['joke']) # (1)! +llm_2 = init_chat_model(model="openai:gpt-4o-mini", tags=['poem']) # (2)! + +graph = ... # define a graph that uses these LLMs + +async for msg, metadata in graph.astream( # (3)! + {"topic": "cats"}, + # highlight-next-line + stream_mode="messages", +): + if metadata["tags"] == ["joke"]: # (4)! + print(msg.content, end="|", flush=True) +``` + +1. llm_1 is tagged with "joke". +2. llm_2 is tagged with "poem". +3. The `stream_mode` is set to "messages" to stream LLM tokens. The `metadata` contains information about the LLM invocation, including the tags. +4. Filter the streamed tokens by the `tags` field in the metadata to only include the tokens from the LLM invocation with the "joke" tag. + + +??? example "Extended example: filtering by tags" + + ```python + from typing import TypedDict + + from langchain.chat_models import init_chat_model + from langgraph.graph import START, StateGraph + + joke_model = init_chat_model(model="openai:gpt-4o-mini", tags=["joke"]) # (1)! + poem_model = init_chat_model(model="openai:gpt-4o-mini", tags=["poem"]) # (2)! + + + class State(TypedDict): + topic: str + joke: str + poem: str + + + async def call_model(state, config): + topic = state["topic"] + print("Writing joke...") + # Note: Passing the config through explicitly is required for python < 3.11 + # Since context var support wasn't added before then: https://docs.python.org/3/library/asyncio-task.html#creating-tasks + joke_response = await joke_model.ainvoke( + [{"role": "user", "content": f"Write a joke about {topic}"}], + config, # (3)! + ) + print("\n\nWriting poem...") + poem_response = await poem_model.ainvoke( + [{"role": "user", "content": f"Write a short poem about {topic}"}], + config, # (3)! + ) + return {"joke": joke_response.content, "poem": poem_response.content} + + + graph = ( + StateGraph(State) + .add_node(call_model) + .add_edge(START, "call_model") + .compile() + ) + + async for msg, metadata in graph.astream( + {"topic": "cats"}, + # highlight-next-line + stream_mode="messages", # (4)! + ): + if metadata["tags"] == ["joke"]: # (4)! + print(msg.content, end="|", flush=True) + ``` + + 1. The `joke_model` is tagged with "joke". + 2. The `poem_model` is tagged with "poem". + 3. The `config` is passed through explicitly to ensure the context vars are propagated correctly. This is required for Python < 3.11 when using async code. Please see the [async section](#async) for more details. + 4. The `stream_mode` is set to "messages" to stream LLM tokens. The `metadata` contains information about the LLM invocation, including the tags. + + +### Filter by node + +To stream tokens only from specific nodes, use `stream_mode="messages"` and filter the outputs by the `langgraph_node` field in the streamed metadata: + +```python +for msg, metadata in graph.stream( # (1)! + inputs, + # highlight-next-line + stream_mode="messages", +): + # highlight-next-line + if msg.content and metadata["langgraph_node"] == "some_node_name": # (2)! + ... +``` + +1. The "messages" stream mode returns a tuple of `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information. +2. Filter the streamed tokens by the `langgraph_node` field in the metadata to only include the tokens from the `write_poem` node. + +??? example "Extended example: streaming LLM tokens from specific nodes" + + ```python + from typing import TypedDict + from langgraph.graph import START, StateGraph + from langchain_openai import ChatOpenAI + + model = ChatOpenAI(model="gpt-4o-mini") + + + class State(TypedDict): + topic: str + joke: str + poem: str + + + def write_joke(state: State): + topic = state["topic"] + joke_response = model.invoke( + [{"role": "user", "content": f"Write a joke about {topic}"}] + ) + return {"joke": joke_response.content} + + + def write_poem(state: State): + topic = state["topic"] + poem_response = model.invoke( + [{"role": "user", "content": f"Write a short poem about {topic}"}] + ) + return {"poem": poem_response.content} + + + graph = ( + StateGraph(State) + .add_node(write_joke) + .add_node(write_poem) + # write both the joke and the poem concurrently + .add_edge(START, "write_joke") + .add_edge(START, "write_poem") + .compile() + ) + + # highlight-next-line + for msg, metadata in graph.stream( # (1)! + {"topic": "cats"}, + stream_mode="messages", + ): + # highlight-next-line + if msg.content and metadata["langgraph_node"] == "write_poem": # (2)! + print(msg.content, end="|", flush=True) + ``` + + 1. The "messages" stream mode returns a tuple of `(message_chunk, metadata)` where `message_chunk` is the token streamed by the LLM and `metadata` is a dictionary with information about the graph node where the LLM was called and other information. + 2. Filter the streamed tokens by the `langgraph_node` field in the metadata to only include the tokens from the `write_poem` node. + +## Stream custom data + +To send **custom user-defined data** from inside a LangGraph node or tool, follow these steps: + +1. Use `get_stream_writer()` to access the stream writer and emit custom data. +2. Set `stream_mode="custom"` when calling `.stream()` or `.astream()` to get the custom data in the stream. You can combine multiple modes (e.g., `["updates", "custom"]`), but at least one must be `"custom"`. + +!!! warning "No `get_stream_writer()` in async for Python < 3.11" + + In async code running on Python < 3.11, `get_stream_writer()` will not work. + Instead, add a `writer` parameter to your node or tool and pass it manually. + See [Async with Python < 3.11](#async-with-python-3-11) for usage examples. + + +=== "node" + + ```python + from typing import TypedDict + from langgraph.config import get_stream_writer + from langgraph.graph import StateGraph, START + + class State(TypedDict): + query: str + answer: str + + def node(state: State): + writer = get_stream_writer() # (1)! + writer({"custom_key": "Generating custom data inside node"}) # (2)! + return {"answer": "some data"} + + graph = ( + StateGraph(State) + .add_node(node) + .add_edge(START, "node") + .compile() + ) + + inputs = {"query": "example"} + + # Usage + for chunk in graph.stream(inputs, stream_mode="custom"): # (3)! + print(chunk) + ``` + + 1. Get the stream writer to send custom data. + 2. Emit a custom key-value pair (e.g., progress update). + 3. Set `stream_mode="custom"` to receive the custom data in the stream. + +=== "tool" + + ```python + from langchain_core.tools import tool + from langgraph.config import get_stream_writer + + @tool + def query_database(query: str) -> str: + """Query the database.""" + writer = get_stream_writer() # (1)! + # highlight-next-line + writer({"data": "Retrieved 0/100 records", "type": "progress"}) # (2)! + # perform query + # highlight-next-line + writer({"data": "Retrieved 100/100 records", "type": "progress"}) # (3)! + return "some-answer" + + + graph = ... # define a graph that uses this tool + + for chunk in graph.stream(inputs, stream_mode="custom"): # (4)! + print(chunk) + ``` + + 1. Access the stream writer to send custom data. + 2. Emit a custom key-value pair (e.g., progress update). + 3. Emit another custom key-value pair. + 4. Set `stream_mode="custom"` to receive the custom data in the stream. + +## Use with any LLM + +You can use `stream_mode="custom"` to stream data from **any LLM API** — even if that API does **not** implement the LangChain chat model interface. + +This lets you integrate raw LLM clients or external services that provide their own streaming interfaces, making LangGraph highly flexible for custom setups. + +```python +from langgraph.config import get_stream_writer + +def call_arbitrary_model(state): + """Example node that calls an arbitrary model and streams the output""" + # highlight-next-line + writer = get_stream_writer() # (1)! + # Assume you have a streaming client that yields chunks + for chunk in your_custom_streaming_client(state["topic"]): # (2)! + # highlight-next-line + writer({"custom_llm_chunk": chunk}) # (3)! + return {"result": "completed"} + +graph = ( + StateGraph(State) + .add_node(call_arbitrary_model) + # Add other nodes and edges as needed + .compile() +) + +for chunk in graph.stream( + {"topic": "cats"}, + # highlight-next-line + stream_mode="custom", # (4)! +): + # The chunk will contain the custom data streamed from the llm + print(chunk) +``` + +1. Get the stream writer to send custom data. +2. Generate LLM tokens using your custom streaming client. +3. Use the writer to send custom data to the stream. +4. Set `stream_mode="custom"` to receive the custom data in the stream. + + +??? example "Extended example: streaming arbitrary chat model" + ```python + import operator + import json + + from typing import TypedDict + from typing_extensions import Annotated + from langgraph.graph import StateGraph, START + + from openai import AsyncOpenAI + + openai_client = AsyncOpenAI() + model_name = "gpt-4o-mini" + + + async def stream_tokens(model_name: str, messages: list[dict]): + response = await openai_client.chat.completions.create( + messages=messages, model=model_name, stream=True + ) + role = None + async for chunk in response: + delta = chunk.choices[0].delta + + if delta.role is not None: + role = delta.role + + if delta.content: + yield {"role": role, "content": delta.content} + + + # this is our tool + async def get_items(place: str) -> str: + """Use this tool to list items one might find in a place you're asked about.""" + writer = get_stream_writer() + response = "" + async for msg_chunk in stream_tokens( + model_name, + [ + { + "role": "user", + "content": ( + "Can you tell me what kind of items " + f"i might find in the following place: '{place}'. " + "List at least 3 such items separating them by a comma. " + "And include a brief description of each item." + ), + } + ], + ): + response += msg_chunk["content"] + writer(msg_chunk) + + return response + + + class State(TypedDict): + messages: Annotated[list[dict], operator.add] + + + # this is the tool-calling graph node + async def call_tool(state: State): + ai_message = state["messages"][-1] + tool_call = ai_message["tool_calls"][-1] + + function_name = tool_call["function"]["name"] + if function_name != "get_items": + raise ValueError(f"Tool {function_name} not supported") + + function_arguments = tool_call["function"]["arguments"] + arguments = json.loads(function_arguments) + + function_response = await get_items(**arguments) + tool_message = { + "tool_call_id": tool_call["id"], + "role": "tool", + "name": function_name, + "content": function_response, + } + return {"messages": [tool_message]} + + + graph = ( + StateGraph(State) + .add_node(call_tool) + .add_edge(START, "call_tool") + .compile() + ) + ``` + + Let's invoke the graph with an AI message that includes a tool call: + + ```python + inputs = { + "messages": [ + { + "content": None, + "role": "assistant", + "tool_calls": [ + { + "id": "1", + "function": { + "arguments": '{"place":"bedroom"}', + "name": "get_items", + }, + "type": "function", + } + ], + } + ] + } + + async for chunk in graph.astream( + inputs, + stream_mode="custom", + ): + print(chunk["content"], end="|", flush=True) + ``` + + +## Disable streaming for specific chat models + +If your application mixes models that support streaming with those that do not, you may need to explicitly disable streaming for +models that do not support it. + +Set `disable_streaming=True` when initializing the model. + +=== "init_chat_model" + + ```python + from langchain.chat_models import init_chat_model + + model = init_chat_model( + "anthropic:claude-3-7-sonnet-latest", + # highlight-next-line + disable_streaming=True # (1)! + ) + ``` + + 1. Set `disable_streaming=True` to disable streaming for the chat model. + +=== "chat model interface" + + ```python + from langchain_openai import ChatOpenAI + + llm = ChatOpenAI(model="o1-preview", disable_streaming=True) # (1)! + ``` + + 1. Set `disable_streaming=True` to disable streaming for the chat model. + + +## Async with Python < 3.11 { #async } + +In Python versions < 3.11, [asyncio tasks](https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task) do not support the `context` parameter. +This limits LangGraph ability to automatically propagate context, and affects LangGraph’s streaming mechanisms in two key ways: + +1. You **must** explicitly pass [`RunnableConfig`](https://python.langchain.com/docs/concepts/runnables/#runnableconfig) into async LLM calls (e.g., `ainvoke()`), as callbacks are not automatically propagated. +2. You **cannot** use `get_stream_writer()` in async nodes or tools — you must pass a `writer` argument directly. + +??? example "Extended example: async LLM call with manual config" + + ```python + from typing import TypedDict + from langgraph.graph import START, StateGraph + from langchain.chat_models import init_chat_model + + llm = init_chat_model(model="openai:gpt-4o-mini") + + class State(TypedDict): + topic: str + joke: str + + async def call_model(state, config): # (1)! + topic = state["topic"] + print("Generating joke...") + joke_response = await llm.ainvoke( + [{"role": "user", "content": f"Write a joke about {topic}"}], + # highlight-next-line + config, # (2)! + ) + return {"joke": joke_response.content} + + graph = ( + StateGraph(State) + .add_node(call_model) + .add_edge(START, "call_model") + .compile() + ) + + async for chunk, metadata in graph.astream( + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="messages", # (3)! + ): + if chunk.content: + print(chunk.content, end="|", flush=True) + ``` + + 1. Accept `config` as an argument in the async node function. + 2. Pass `config` to `llm.ainvoke()` to ensure proper context propagation. + 3. Set `stream_mode="messages"` to stream LLM tokens. + +??? example "Extended example: async custom streaming with stream writer" + + ```python + from typing import TypedDict + from langgraph.types import StreamWriter + + class State(TypedDict): + topic: str + joke: str + + # highlight-next-line + async def generate_joke(state: State, writer: StreamWriter): # (1)! + writer({"custom_key": "Streaming custom data while generating a joke"}) + return {"joke": f"This is a joke about {state['topic']}"} + + graph = ( + StateGraph(State) + .add_node(generate_joke) + .add_edge(START, "generate_joke") + .compile() + ) + + async for chunk in graph.astream( + {"topic": "ice cream"}, + # highlight-next-line + stream_mode="custom", # (2)! + ): + print(chunk) + ``` + + 1. Add `writer` as an argument in the function signature of the async node or tool. LangGraph will automatically pass the stream writer to the function. + 2. Set `stream_mode="custom"` to receive the custom data in the stream. diff --git a/docs/docs/how-tos/subgraph-persistence.ipynb b/docs/docs/how-tos/subgraph-persistence.ipynb deleted file mode 100644 index f505744b7..000000000 --- a/docs/docs/how-tos/subgraph-persistence.ipynb +++ /dev/null @@ -1,379 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "176e8dbb-1a0a-49ce-a10e-2417e8ea17a0", - "metadata": {}, - "source": [ - "# How to add thread-level persistence to a subgraph" - ] - }, - { - "cell_type": "markdown", - "id": "8c67581a-49fb-4597-a7fc-6774581c2160", - "metadata": {}, - "source": [ - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "This guide shows how you can add [thread-level](https://langchain-ai.github.io/langgraph/how-tos/persistence/) persistence to graphs that use [subgraphs](https://langchain-ai.github.io/langgraph/how-tos/subgraph/)." - ] - }, - { - "cell_type": "markdown", - "id": "8f83b855-ab23-4de7-9559-702cad9a29c6", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "77d1eafa-3252-45f6-9af0-d94e1f9c5c9e", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "2e60c6cd-bf4e-46af-9761-b872d0fbe3b6", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "871b9056-fec7-4683-8c22-f56c91f5b13b", - "metadata": {}, - "source": [ - "## Define the graph with persistence" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "9f1303ef-df37-48e0-8a59-8ff169c52c5b", - "metadata": {}, - "source": [ - "To add persistence to a graph with subgraphs, all you need to do is pass a [checkpointer](https://langchain-ai.github.io/langgraph/reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver) when **compiling the parent graph**. LangGraph will automatically propagate the checkpointer to the child subgraphs." - ] - }, - { - "cell_type": "markdown", - "id": "c74cde2e-c127-4326-8d36-b6acef987f0a", - "metadata": {}, - "source": [ - "!!! note\n", - " You **shouldn't provide** a checkpointer when compiling a subgraph. Instead, you must define a **single** checkpointer that you pass to `parent_graph.compile()`, and LangGraph will automatically propagate the checkpointer to the child subgraphs. If you pass the checkpointer to the `subgraph.compile()`, it will simply be ignored. This also applies when you [add a node function that invokes the subgraph](../subgraph#add-a-node-function-that-invokes-the-subgraph)." - ] - }, - { - "cell_type": "markdown", - "id": "c3a1fe22-1ca9-45eb-a35b-71b9c905e8c5", - "metadata": {}, - "source": [ - "Let's define a simple graph with a single subgraph node to show how to do this." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "0d76f0c0-bd77-4eca-9527-27bcdf85dd42", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langgraph.graph import START, StateGraph\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from typing import TypedDict\n", - "\n", - "\n", - "# subgraph\n", - "\n", - "\n", - "class SubgraphState(TypedDict):\n", - " foo: str # note that this key is shared with the parent graph state\n", - " bar: str\n", - "\n", - "\n", - "def subgraph_node_1(state: SubgraphState):\n", - " return {\"bar\": \"bar\"}\n", - "\n", - "\n", - "def subgraph_node_2(state: SubgraphState):\n", - " # note that this node is using a state key ('bar') that is only available in the subgraph\n", - " # and is sending update on the shared state key ('foo')\n", - " return {\"foo\": state[\"foo\"] + state[\"bar\"]}\n", - "\n", - "\n", - "subgraph_builder = StateGraph(SubgraphState)\n", - "subgraph_builder.add_node(subgraph_node_1)\n", - "subgraph_builder.add_node(subgraph_node_2)\n", - "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", - "subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", - "subgraph = subgraph_builder.compile()\n", - "\n", - "\n", - "# parent graph\n", - "\n", - "\n", - "class State(TypedDict):\n", - " foo: str\n", - "\n", - "\n", - "def node_1(state: State):\n", - " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", - "\n", - "\n", - "builder = StateGraph(State)\n", - "builder.add_node(\"node_1\", node_1)\n", - "# note that we're adding the compiled subgraph as a node to the parent graph\n", - "builder.add_node(\"node_2\", subgraph)\n", - "builder.add_edge(START, \"node_1\")\n", - "builder.add_edge(\"node_1\", \"node_2\")" - ] - }, - { - "cell_type": "markdown", - "id": "47084b1f-9fd5-40a9-9d75-89eb5f853d02", - "metadata": {}, - "source": [ - "We can now compile the graph with an in-memory checkpointer (`MemorySaver`)." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "7657d285-c896-40c9-a569-b4a3b9c230c7", - "metadata": {}, - "outputs": [], - "source": [ - "checkpointer = MemorySaver()\n", - "# You must only pass checkpointer when compiling the parent graph.\n", - "# LangGraph will automatically propagate the checkpointer to the child subgraphs.\n", - "graph = builder.compile(checkpointer=checkpointer)" - ] - }, - { - "cell_type": "markdown", - "id": "0d193e3c-4ec3-4034-beed-8e5550c6542c", - "metadata": {}, - "source": [ - "## Verify persistence works" - ] - }, - { - "cell_type": "markdown", - "id": "eb69a5f0-b92e-4d4e-9aa9-c4c4ec7de91a", - "metadata": {}, - "source": [ - "Let's now run the graph and inspect the persisted state for both the parent graph and the subgraph to verify that persistence works. We should expect to see the final execution results for both the parent and subgraph in `state.values`." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "13da686e-6ed6-4b83-93e8-1631fcc8c2a9", - "metadata": {}, - "outputs": [], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\"}}" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "8721f045-2e82-4bf0-9d85-5ba6ecf899d6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'node_1': {'foo': 'hi! foo'}}\n", - "{'subgraph_node_1': {'bar': 'bar'}}\n", - "{'subgraph_node_2': {'foo': 'hi! foobar'}}\n", - "{'node_2': {'foo': 'hi! foobar'}}\n" - ] - } - ], - "source": [ - "for _, chunk in graph.stream({\"foo\": \"foo\"}, config, subgraphs=True):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "ec6b5ce4-becc-4910-8a6d-d6b60d9d6f60", - "metadata": {}, - "source": [ - "We can now view the parent graph state by calling `graph.get_state()` with the same config that we used to invoke the graph." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "3e817283-142d-4fda-8cb1-8de34717f833", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'foo': 'hi! foobar'}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.get_state(config).values" - ] - }, - { - "cell_type": "markdown", - "id": "fbc4f30b-941e-4140-8bfa-3b8cc670489c", - "metadata": {}, - "source": [ - "To view the subgraph state, we need to do two things:\n", - "\n", - "1. Find the most recent config value for the subgraph\n", - "2. Use `graph.get_state()` to retrieve that value for the most recent subgraph config.\n", - "\n", - "To find the correct config, we can examine the state history from the parent graph and find the state snapshot before we return results from `node_2` (the node with subgraph):" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "e896628f-36b2-45eb-b7c5-c64c1098f328", - "metadata": {}, - "outputs": [], - "source": [ - "state_with_subgraph = [\n", - " s for s in graph.get_state_history(config) if s.next == (\"node_2\",)\n", - "][0]" - ] - }, - { - "cell_type": "markdown", - "id": "7af49977-42b1-40a1-88f1-f07437f8b7f9", - "metadata": {}, - "source": [ - "The state snapshot will include the list of `tasks` to be executed next. When using subgraphs, the `tasks` will contain the config that we can use to retrieve the subgraph state:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "21e96df3-946d-40f8-8d6d-055ae4177452", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'configurable': {'thread_id': '1',\n", - " 'checkpoint_ns': 'node_2:6ef111a6-f290-7376-0dfc-a4152307bc5b'}}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "subgraph_config = state_with_subgraph.tasks[0].state\n", - "subgraph_config" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "1d2401b3-d52b-4895-a5d1-dccf015ba216", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'foo': 'hi! foobar', 'bar': 'bar'}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.get_state(subgraph_config).values" - ] - }, - { - "cell_type": "markdown", - "id": "40aded92-99dd-427b-932d-aa78f474c271", - "metadata": {}, - "source": [ - "If you want to learn more about how to modify the subgraph state for human-in-the-loop workflows, check out this [how-to guide](https://langchain-ai.github.io/langgraph/how-tos/subgraphs-manage-state/)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/subgraph-transform-state.ipynb b/docs/docs/how-tos/subgraph-transform-state.ipynb deleted file mode 100644 index b2d837f0e..000000000 --- a/docs/docs/how-tos/subgraph-transform-state.ipynb +++ /dev/null @@ -1,297 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to transform inputs and outputs of a subgraph\n", - "\n", - "It's possible that your subgraph state is completely independent from the parent graph state, i.e. there are no overlapping channels (keys) between the two. For example, you might have a supervisor agent that needs to produce a report with a help of multiple ReAct agents. ReAct agent subgraphs might keep track of a list of messages whereas the supervisor only needs user input and final report in its state, and doesn't need to keep track of messages.\n", - "\n", - "In such cases you need to transform the inputs to the subgraph before calling it and then transform its outputs before returning. This guide shows how to do that.\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define graph and subgraphs\n", - "\n", - "Let's define 3 graphs:\n", - "- a parent graph\n", - "- a child subgraph that will be called by the parent graph\n", - "- a grandchild subgraph that will be called by the child graph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define grandchild" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from typing_extensions import TypedDict\n", - "from langgraph.graph.state import StateGraph, START, END\n", - "\n", - "\n", - "class GrandChildState(TypedDict):\n", - " my_grandchild_key: str\n", - "\n", - "\n", - "def grandchild_1(state: GrandChildState) -> GrandChildState:\n", - " # NOTE: child or parent keys will not be accessible here\n", - " return {\"my_grandchild_key\": state[\"my_grandchild_key\"] + \", how are you\"}\n", - "\n", - "\n", - "grandchild = StateGraph(GrandChildState)\n", - "grandchild.add_node(\"grandchild_1\", grandchild_1)\n", - "\n", - "grandchild.add_edge(START, \"grandchild_1\")\n", - "grandchild.add_edge(\"grandchild_1\", END)\n", - "\n", - "grandchild_graph = grandchild.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'my_grandchild_key': 'hi Bob, how are you'}" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "grandchild_graph.invoke({\"my_grandchild_key\": \"hi Bob\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define child" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "class ChildState(TypedDict):\n", - " my_child_key: str\n", - "\n", - "\n", - "def call_grandchild_graph(state: ChildState) -> ChildState:\n", - " # NOTE: parent or grandchild keys won't be accessible here\n", - " # we're transforming the state from the child state channels (`my_child_key`)\n", - " # to the child state channels (`my_grandchild_key`)\n", - " grandchild_graph_input = {\"my_grandchild_key\": state[\"my_child_key\"]}\n", - " # we're transforming the state from the grandchild state channels (`my_grandchild_key`)\n", - " # back to the child state channels (`my_child_key`)\n", - " grandchild_graph_output = grandchild_graph.invoke(grandchild_graph_input)\n", - " return {\"my_child_key\": grandchild_graph_output[\"my_grandchild_key\"] + \" today?\"}\n", - "\n", - "\n", - "child = StateGraph(ChildState)\n", - "# NOTE: we're passing a function here instead of just compiled graph (`child_graph`)\n", - "child.add_node(\"child_1\", call_grandchild_graph)\n", - "child.add_edge(START, \"child_1\")\n", - "child.add_edge(\"child_1\", END)\n", - "child_graph = child.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'my_child_key': 'hi Bob, how are you today?'}" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "child_graph.invoke({\"my_child_key\": \"hi Bob\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Note

    \n", - "

    \n", - " We're wrapping the grandchild_graph invocation in a separate function (call_grandchild_graph) that transforms the input state before calling the grandchild graph and then transforms the output of grandchild graph back to child graph state. If you just pass grandchild_graph directly to .add_node without the transformations, LangGraph will raise an error as there are no shared state channels (keys) between child and grandchild states.\n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that child and grandchild subgraphs have their own, **independent** state that is not shared with the parent graph." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define parent" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "class ParentState(TypedDict):\n", - " my_key: str\n", - "\n", - "\n", - "def parent_1(state: ParentState) -> ParentState:\n", - " # NOTE: child or grandchild keys won't be accessible here\n", - " return {\"my_key\": \"hi \" + state[\"my_key\"]}\n", - "\n", - "\n", - "def parent_2(state: ParentState) -> ParentState:\n", - " return {\"my_key\": state[\"my_key\"] + \" bye!\"}\n", - "\n", - "\n", - "def call_child_graph(state: ParentState) -> ParentState:\n", - " # we're transforming the state from the parent state channels (`my_key`)\n", - " # to the child state channels (`my_child_key`)\n", - " child_graph_input = {\"my_child_key\": state[\"my_key\"]}\n", - " # we're transforming the state from the child state channels (`my_child_key`)\n", - " # back to the parent state channels (`my_key`)\n", - " child_graph_output = child_graph.invoke(child_graph_input)\n", - " return {\"my_key\": child_graph_output[\"my_child_key\"]}\n", - "\n", - "\n", - "parent = StateGraph(ParentState)\n", - "parent.add_node(\"parent_1\", parent_1)\n", - "# NOTE: we're passing a function here instead of just a compiled graph (`child_graph`)\n", - "parent.add_node(\"child\", call_child_graph)\n", - "parent.add_node(\"parent_2\", parent_2)\n", - "\n", - "parent.add_edge(START, \"parent_1\")\n", - "parent.add_edge(\"parent_1\", \"child\")\n", - "parent.add_edge(\"child\", \"parent_2\")\n", - "parent.add_edge(\"parent_2\", END)\n", - "\n", - "parent_graph = parent.compile()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Note

    \n", - "

    \n", - " We're wrapping the child_graph invocation in a separate function (call_child_graph) that transforms the input state before calling the child graph and then transforms the output of the child graph back to parent graph state. If you just pass child_graph directly to .add_node without the transformations, LangGraph will raise an error as there are no shared state channels (keys) between parent and child states.\n", - "

    \n", - "
    \n", - "\n", - "Let's run the parent graph and make sure it correctly calls both the child and grandchild subgraphs:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'my_key': 'hi Bob, how are you today? bye!'}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "parent_graph.invoke({\"my_key\": \"Bob\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect! The parent graph correctly calls both the child and grandchild subgraphs (which we know since the \", how are you\" and \"today?\" are added to our original \"my_key\" state value)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/subgraph.ipynb b/docs/docs/how-tos/subgraph.ipynb index f877d559b..a16d99216 100644 --- a/docs/docs/how-tos/subgraph.ipynb +++ b/docs/docs/how-tos/subgraph.ipynb @@ -1,54 +1,25 @@ { "cells": [ { - "attachments": { - "71516aef-9c00-4730-a676-a54e90cb6472.png": { - "image/png": "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" - } - }, + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "# How to use subgraphs\n", + "# Use subgraphs\n", "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", + "This guide explains the mechanics of using [subgraphs](../../concepts/subgraphs). A common application of subgraphs is to build [multi-agent](../../concepts/multi_agent) systems.\n", "\n", - "[Subgraphs](https://langchain-ai.github.io/langgraph/concepts/low_level/#subgraphs) allow you to build complex systems with multiple components that are themselves graphs. A common use case for using subgraphs is building [multi-agent systems](https://langchain-ai.github.io/langgraph/concepts/multi_agent).\n", + "When adding subgraphs, you need to define how the parent graph and the subgraph communicate:\n", "\n", - "The main question when adding subgraphs is how the parent graph and subgraph communicate, i.e. how they pass the [state](https://langchain-ai.github.io/langgraph/concepts/low_level/#state) between each other during the graph execution. There are two scenarios:\n", - "\n", - "* parent graph and subgraph **share schema keys**. In this case, you can [add a node with the compiled subgraph](#add-a-node-with-the-compiled-subgraph)\n", - "* parent graph and subgraph have **different schemas**. In this case, you have to [add a node function that invokes the subgraph](#add-a-node-function-that-invokes-the-subgraph): this is useful when the parent graph and the subgraph have different state schemas and you need to transform state before or after calling the subgraph\n", - "\n", - "Below we show to to add subgraphs for each scenario.\n", - "\n", - "![Screenshot 2024-07-11 at 1.01.28 PM.png](attachment:71516aef-9c00-4730-a676-a54e90cb6472.png)" + "* [Shared state schemas](#shared-state-schemas) — parent and subgraph have **shared state keys** in their state [schemas](../../concepts/low_level#state)\n", + "* [Different state schemas](#different-state-schemas) — **no shared state keys** in parent and subgraph [schemas](../../concepts/low_level#state)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" + "## Setup" ] }, { @@ -74,214 +45,493 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "## Add a node with the compiled subgraph\n", + "## Shared state schemas\n", "\n", - "A common case is for the parent graph and subgraph to communicate over a shared state key (channel). For example, in [multi-agent](https://langchain-ai.github.io/langgraph/concepts/multi_agent) systems, the agents often communicate over a shared [messages](https://langchain-ai.github.io/langgraph/concepts/low_level/#why-use-messages) key.\n", + "A common case is for the parent graph and subgraph to communicate over a shared state key (channel) in the [schema](../../concepts/low_level#state). For example, in [multi-agent](../../concepts/multi_agent) systems, the agents often communicate over a shared [messages](https://langchain-ai.github.io/langgraph/concepts/low_level/#why-use-messages) key.\n", "\n", "If your subgraph shares state keys with the parent graph, you can follow these steps to add it to your graph:\n", "\n", "1. Define the subgraph workflow (`subgraph_builder` in the example below) and compile it\n", "2. Pass compiled subgraph to the `.add_node` method when defining the parent graph workflow\n", "\n", - "Let's take a look at a simple example. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import START, StateGraph\n", - "from typing import TypedDict\n", + "```python\n", + "from typing_extensions import TypedDict\n", + "from langgraph.graph.state import StateGraph, START\n", "\n", - "\n", - "# Define subgraph\n", - "class SubgraphState(TypedDict):\n", - " foo: str # note that this key is shared with the parent graph state\n", - " bar: str\n", - "\n", - "\n", - "def subgraph_node_1(state: SubgraphState):\n", - " return {\"bar\": \"bar\"}\n", - "\n", - "\n", - "def subgraph_node_2(state: SubgraphState):\n", - " # note that this node is using a state key ('bar') that is only available in the subgraph\n", - " # and is sending update on the shared state key ('foo')\n", - " return {\"foo\": state[\"foo\"] + state[\"bar\"]}\n", - "\n", - "\n", - "subgraph_builder = StateGraph(SubgraphState)\n", - "subgraph_builder.add_node(subgraph_node_1)\n", - "subgraph_builder.add_node(subgraph_node_2)\n", - "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", - "subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", - "subgraph = subgraph_builder.compile()\n", - "\n", - "\n", - "# Define parent graph\n", - "class ParentState(TypedDict):\n", + "class State(TypedDict):\n", " foo: str\n", "\n", + "# Subgraph\n", "\n", - "def node_1(state: ParentState):\n", + "def subgraph_node_1(state: State):\n", " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", "\n", + "subgraph_builder = StateGraph(State)\n", + "subgraph_builder.add_node(subgraph_node_1)\n", + "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + "# highlight-next-line\n", + "subgraph = subgraph_builder.compile()\n", "\n", - "builder = StateGraph(ParentState)\n", - "builder.add_node(\"node_1\", node_1)\n", - "# note that we're adding the compiled subgraph as a node to the parent graph\n", - "builder.add_node(\"node_2\", subgraph)\n", + "# Parent graph\n", + "\n", + "builder = StateGraph(State)\n", + "# highlight-next-line\n", + "builder.add_node(\"node_1\", subgraph)\n", "builder.add_edge(START, \"node_1\")\n", - "builder.add_edge(\"node_1\", \"node_2\")\n", - "graph = builder.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'node_1': {'foo': 'hi! foo'}}\n", - "{'node_2': {'foo': 'hi! foobar'}}\n" - ] - } - ], - "source": [ - "for chunk in graph.stream({\"foo\": \"foo\"}):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can see that the final output from the parent graph includes the results of subgraph invocation (i.e. string `\"bar\"`). If you would like to see outputs from the subgraph, you can specify `subgraphs=True` when streaming. See more on streaming from subgraphs in this [how-to guide](https://langchain-ai.github.io/langgraph/how-tos/streaming-subgraphs/#stream-subgraph)." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'node_1': {'foo': 'hi! foo'}})\n", - "(('node_2:e58e5673-a661-ebb0-70d4-e298a7fc28b7',), {'subgraph_node_1': {'bar': 'bar'}})\n", - "(('node_2:e58e5673-a661-ebb0-70d4-e298a7fc28b7',), {'subgraph_node_2': {'foo': 'hi! foobar'}})\n", - "((), {'node_2': {'foo': 'hi! foobar'}})\n" - ] - } - ], - "source": [ - "for chunk in graph.stream({\"foo\": \"foo\"}, subgraphs=True):\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Add a node function that invokes the subgraph\n", + "graph = builder.compile()\n", + "```\n", "\n", - "For more complex systems you might want to define subgraphs that have a completely different schema from the parent graph (no shared keys). For example, in a multi-agent RAG system, a search agent might only need to keep track of queries and retrieved documents.\n", + "??? example \"Full example: shared state schemas\"\n", + "\n", + " ```python\n", + " from typing_extensions import TypedDict\n", + " from langgraph.graph.state import StateGraph, START\n", + "\n", + " # Define subgraph\n", + " class SubgraphState(TypedDict):\n", + " foo: str # (1)! \n", + " bar: str # (2)!\n", + " \n", + " def subgraph_node_1(state: SubgraphState):\n", + " return {\"bar\": \"bar\"}\n", + " \n", + " def subgraph_node_2(state: SubgraphState):\n", + " # note that this node is using a state key ('bar') that is only available in the subgraph\n", + " # and is sending update on the shared state key ('foo')\n", + " return {\"foo\": state[\"foo\"] + state[\"bar\"]}\n", + " \n", + " subgraph_builder = StateGraph(SubgraphState)\n", + " subgraph_builder.add_node(subgraph_node_1)\n", + " subgraph_builder.add_node(subgraph_node_2)\n", + " subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + " subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", + " subgraph = subgraph_builder.compile()\n", + " \n", + " # Define parent graph\n", + " class ParentState(TypedDict):\n", + " foo: str\n", + " \n", + " def node_1(state: ParentState):\n", + " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", + " \n", + " builder = StateGraph(ParentState)\n", + " builder.add_node(\"node_1\", node_1)\n", + " # highlight-next-line\n", + " builder.add_node(\"node_2\", subgraph)\n", + " builder.add_edge(START, \"node_1\")\n", + " builder.add_edge(\"node_1\", \"node_2\")\n", + " graph = builder.compile()\n", + " \n", + " for chunk in graph.stream({\"foo\": \"foo\"}):\n", + " print(chunk)\n", + " ```\n", + "\n", + " 1. This key is shared with the parent graph state\n", + " 2. This key is private to the `SubgraphState` and is not visible to the parent graph\n", + " \n", + " ```\n", + " {'node_1': {'foo': 'hi! foo'}}\n", + " {'node_2': {'foo': 'hi! foobar'}}\n", + " ```\n", + "\n", + " ```" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Different state schemas\n", + "\n", + "For more complex systems you might want to define subgraphs that have a **completely different schema** from the parent graph (no shared keys). For example, you might want to keep a private message history for each of the agents in a [multi-agent](../concepts/multi_agent.md) system.\n", "\n", "If that's the case for your application, you need to define a node **function that invokes the subgraph**. This function needs to transform the input (parent) state to the subgraph state before invoking the subgraph, and transform the results back to the parent state before returning the state update from the node.\n", "\n", - "Below we show how to modify our original example to call a subgraph from inside the node." + "```python\n", + "from typing_extensions import TypedDict\n", + "from langgraph.graph.state import StateGraph, START\n", + "\n", + "class SubgraphState(TypedDict):\n", + " bar: str\n", + "\n", + "# Subgraph\n", + "\n", + "def subgraph_node_1(state: SubgraphState):\n", + " return {\"bar\": \"hi! \" + state[\"bar\"]}\n", + "\n", + "subgraph_builder = StateGraph(SubgraphState)\n", + "subgraph_builder.add_node(subgraph_node_1)\n", + "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + "# highlight-next-line\n", + "subgraph = subgraph_builder.compile()\n", + "\n", + "# Parent graph\n", + "\n", + "class State(TypedDict):\n", + " foo: str\n", + "\n", + "def call_subgraph(state: State):\n", + " # highlight-next-line\n", + " subgraph_output = subgraph.invoke({\"bar\": state[\"foo\"]}) # (1)!\n", + " # highlight-next-line\n", + " return {\"foo\": subgraph_output[\"bar\"]} # (2)!\n", + "\n", + "builder = StateGraph(State)\n", + "# highlight-next-line\n", + "builder.add_node(\"node_1\", call_subgraph)\n", + "builder.add_edge(START, \"node_1\")\n", + "graph = builder.compile()\n", + "```\n", + "\n", + "1. Transform the state to the subgraph state\n", + "2. Transform response back to the parent state\n", + "\n", + "??? example \"Full example: different state schemas\"\n", + "\n", + " ```python\n", + " from typing_extensions import TypedDict\n", + " from langgraph.graph.state import StateGraph, START\n", + "\n", + " # Define subgraph\n", + " class SubgraphState(TypedDict):\n", + " # note that none of these keys are shared with the parent graph state\n", + " bar: str\n", + " baz: str\n", + " \n", + " def subgraph_node_1(state: SubgraphState):\n", + " return {\"baz\": \"baz\"}\n", + " \n", + " def subgraph_node_2(state: SubgraphState):\n", + " return {\"bar\": state[\"bar\"] + state[\"baz\"]}\n", + " \n", + " subgraph_builder = StateGraph(SubgraphState)\n", + " subgraph_builder.add_node(subgraph_node_1)\n", + " subgraph_builder.add_node(subgraph_node_2)\n", + " subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + " subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", + " subgraph = subgraph_builder.compile()\n", + " \n", + " # Define parent graph\n", + " class ParentState(TypedDict):\n", + " foo: str\n", + " \n", + " def node_1(state: ParentState):\n", + " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", + " \n", + " def node_2(state: ParentState):\n", + " # highlight-next-line\n", + " response = subgraph.invoke({\"bar\": state[\"foo\"]}) # (1)!\n", + " # highlight-next-line\n", + " return {\"foo\": response[\"bar\"]} # (2)!\n", + " \n", + " \n", + " builder = StateGraph(ParentState)\n", + " builder.add_node(\"node_1\", node_1)\n", + " # highlight-next-line\n", + " builder.add_node(\"node_2\", node_2)\n", + " builder.add_edge(START, \"node_1\")\n", + " builder.add_edge(\"node_1\", \"node_2\")\n", + " graph = builder.compile()\n", + " \n", + " for chunk in graph.stream({\"foo\": \"foo\"}, subgraphs=True):\n", + " print(chunk)\n", + " ```\n", + "\n", + " 1. Transform the state to the subgraph state\n", + " 2. Transform response back to the parent state\n", + "\n", + " ```\n", + " ((), {'node_1': {'foo': 'hi! foo'}})\n", + " (('node_2:9c36dd0f-151a-cb42-cbad-fa2f851f9ab7',), {'subgraph_node_1': {'baz': 'baz'}})\n", + " (('node_2:9c36dd0f-151a-cb42-cbad-fa2f851f9ab7',), {'subgraph_node_2': {'bar': 'hi! foobaz'}})\n", + " ((), {'node_2': {'foo': 'hi! foobaz'}})\n", + " ```\n", + "\n", + "??? example \"Full example: different state schemas (two levels of subgraphs)\"\n", + "\n", + " This is an example with two levels of subgraphs: parent -> child -> grandchild.\n", + "\n", + " ```python\n", + " # Grandchild graph\n", + " from typing_extensions import TypedDict\n", + " from langgraph.graph.state import StateGraph, START, END\n", + " \n", + " class GrandChildState(TypedDict):\n", + " my_grandchild_key: str\n", + " \n", + " def grandchild_1(state: GrandChildState) -> GrandChildState:\n", + " # NOTE: child or parent keys will not be accessible here\n", + " return {\"my_grandchild_key\": state[\"my_grandchild_key\"] + \", how are you\"}\n", + " \n", + " \n", + " grandchild = StateGraph(GrandChildState)\n", + " grandchild.add_node(\"grandchild_1\", grandchild_1)\n", + " \n", + " grandchild.add_edge(START, \"grandchild_1\")\n", + " grandchild.add_edge(\"grandchild_1\", END)\n", + " \n", + " grandchild_graph = grandchild.compile()\n", + " \n", + " # Child graph\n", + " class ChildState(TypedDict):\n", + " my_child_key: str\n", + " \n", + " def call_grandchild_graph(state: ChildState) -> ChildState:\n", + " # NOTE: parent or grandchild keys won't be accessible here\n", + " grandchild_graph_input = {\"my_grandchild_key\": state[\"my_child_key\"]} # (1)!\n", + " # highlight-next-line\n", + " grandchild_graph_output = grandchild_graph.invoke(grandchild_graph_input)\n", + " return {\"my_child_key\": grandchild_graph_output[\"my_grandchild_key\"] + \" today?\"} # (2)!\n", + " \n", + " child = StateGraph(ChildState)\n", + " # highlight-next-line\n", + " child.add_node(\"child_1\", call_grandchild_graph) # (3)!\n", + " child.add_edge(START, \"child_1\")\n", + " child.add_edge(\"child_1\", END)\n", + " child_graph = child.compile()\n", + " \n", + " # Parent graph\n", + " class ParentState(TypedDict):\n", + " my_key: str\n", + " \n", + " def parent_1(state: ParentState) -> ParentState:\n", + " # NOTE: child or grandchild keys won't be accessible here\n", + " return {\"my_key\": \"hi \" + state[\"my_key\"]}\n", + " \n", + " def parent_2(state: ParentState) -> ParentState:\n", + " return {\"my_key\": state[\"my_key\"] + \" bye!\"}\n", + " \n", + " def call_child_graph(state: ParentState) -> ParentState:\n", + " child_graph_input = {\"my_child_key\": state[\"my_key\"]} # (4)!\n", + " # highlight-next-line\n", + " child_graph_output = child_graph.invoke(child_graph_input)\n", + " return {\"my_key\": child_graph_output[\"my_child_key\"]} # (5)!\n", + " \n", + " parent = StateGraph(ParentState)\n", + " parent.add_node(\"parent_1\", parent_1)\n", + " # highlight-next-line\n", + " parent.add_node(\"child\", call_child_graph) # (6)!\n", + " parent.add_node(\"parent_2\", parent_2)\n", + " \n", + " parent.add_edge(START, \"parent_1\")\n", + " parent.add_edge(\"parent_1\", \"child\")\n", + " parent.add_edge(\"child\", \"parent_2\")\n", + " parent.add_edge(\"parent_2\", END)\n", + " \n", + " parent_graph = parent.compile()\n", + " \n", + " for chunk in parent_graph.stream({\"my_key\": \"Bob\"}, subgraphs=True):\n", + " print(chunk)\n", + " ```\n", + "\n", + " 1. We're transforming the state from the child state channels (`my_child_key`) to the child state channels (`my_grandchild_key`)\n", + " 2. We're transforming the state from the grandchild state channels (`my_grandchild_key`) back to the child state channels (`my_child_key`)\n", + " 3. We're passing a function here instead of just compiled graph (`grandchild_graph`)\n", + " 4. We're transforming the state from the parent state channels (`my_key`) to the child state channels (`my_child_key`)\n", + " 5. We're transforming the state from the child state channels (`my_child_key`) back to the parent state channels (`my_key`)\n", + " 6. We're passing a function here instead of just a compiled graph (`child_graph`)\n", + "\n", + " ```\n", + " ((), {'parent_1': {'my_key': 'hi Bob'}})\n", + " (('child:2e26e9ce-602f-862c-aa66-1ea5a4655e3b', 'child_1:781bb3b1-3971-84ce-810b-acf819a03f9c'), {'grandchild_1': {'my_grandchild_key': 'hi Bob, how are you'}})\n", + " (('child:2e26e9ce-602f-862c-aa66-1ea5a4655e3b',), {'child_1': {'my_child_key': 'hi Bob, how are you today?'}})\n", + " ((), {'child': {'my_key': 'hi Bob, how are you today?'}})\n", + " ((), {'parent_2': {'my_key': 'hi Bob, how are you today? bye!'}})\n", + " ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "!!! warning\n", - " You **cannot** invoke more than one subgraph inside the same node." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Define subgraph\n", - "class SubgraphState(TypedDict):\n", - " # note that none of these keys are shared with the parent graph state\n", - " bar: str\n", - " baz: str\n", + "## Add persistence \n", "\n", + "You only need to **provide the checkpointer when compiling the parent graph**. LangGraph will automatically propagate the checkpointer to the child subgraphs.\n", "\n", - "def subgraph_node_1(state: SubgraphState):\n", - " return {\"baz\": \"baz\"}\n", + "```python\n", + "from langgraph.graph import START, StateGraph\n", + "from langgraph.checkpoint.memory import InMemorySaver\n", + "from typing_extensions import TypedDict\n", "\n", - "\n", - "def subgraph_node_2(state: SubgraphState):\n", - " return {\"bar\": state[\"bar\"] + state[\"baz\"]}\n", - "\n", - "\n", - "subgraph_builder = StateGraph(SubgraphState)\n", - "subgraph_builder.add_node(subgraph_node_1)\n", - "subgraph_builder.add_node(subgraph_node_2)\n", - "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", - "subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", - "subgraph = subgraph_builder.compile()\n", - "\n", - "\n", - "# Define parent graph\n", - "class ParentState(TypedDict):\n", + "class State(TypedDict):\n", " foo: str\n", "\n", + "# Subgraph\n", "\n", - "def node_1(state: ParentState):\n", - " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", + "def subgraph_node_1(state: State):\n", + " return {\"foo\": state[\"foo\"] + \"bar\"}\n", "\n", + "subgraph_builder = StateGraph(State)\n", + "subgraph_builder.add_node(subgraph_node_1)\n", + "subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + "# highlight-next-line\n", + "subgraph = subgraph_builder.compile()\n", "\n", - "def node_2(state: ParentState):\n", - " # transform the state to the subgraph state\n", - " response = subgraph.invoke({\"bar\": state[\"foo\"]})\n", - " # transform response back to the parent state\n", - " return {\"foo\": response[\"bar\"]}\n", + "# Parent graph\n", "\n", - "\n", - "builder = StateGraph(ParentState)\n", - "builder.add_node(\"node_1\", node_1)\n", - "# note that instead of using the compiled subgraph we are using `node_2` function that is calling the subgraph\n", - "builder.add_node(\"node_2\", node_2)\n", + "builder = StateGraph(State)\n", + "# highlight-next-line\n", + "builder.add_node(\"node_1\", subgraph)\n", "builder.add_edge(START, \"node_1\")\n", - "builder.add_edge(\"node_1\", \"node_2\")\n", - "graph = builder.compile()" + "\n", + "checkpointer = InMemorySaver()\n", + "# highlight-next-line\n", + "graph = builder.compile(checkpointer=checkpointer)\n", + "``` \n", + "\n", + "If you want the subgraph to **have its own memory**, you can compile it `with checkpointer=True`. This is useful in [multi-agent](../../concepts/multi_agent) systems, if you want agents to keep track of their internal message histories:\n", + "\n", + "```python\n", + "subgraph_builder = StateGraph(...)\n", + "# highlight-next-line\n", + "subgraph = subgraph_builder.compile(checkpointer=True)\n", + "```" ] }, { - "cell_type": "code", - "execution_count": 6, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'node_1': {'foo': 'hi! foo'}})\n", - "(('node_2:c47d7ea3-7798-87c4-adf4-2543a91d6891',), {'subgraph_node_1': {'baz': 'baz'}})\n", - "(('node_2:c47d7ea3-7798-87c4-adf4-2543a91d6891',), {'subgraph_node_2': {'bar': 'hi! foobaz'}})\n", - "((), {'node_2': {'foo': 'hi! foobaz'}})\n" - ] - } - ], "source": [ - "for chunk in graph.stream({\"foo\": \"foo\"}, subgraphs=True):\n", - " print(chunk)" + "## View subgraph state\n", + "\n", + "When you enable [persistence](../persistence), you can [inspect the graph state](../persistence#manage-checkpoints) (checkpoint) via `graph.get_state(config)`. To view the subgraph state, you can use `graph.get_state(config, subgraphs=True)`.\n", + "\n", + "!!! important \"Available **only** when interrupted\"\n", + "\n", + " Subgraph state can only be viewed **when the subgraph is interrupted**. Once you resume the graph, you won't be able to access the subgraph state.\n", + "\n", + "??? example \"View interrupted subgraph state\"\n", + "\n", + " ```python\n", + " from langgraph.graph import START, StateGraph\n", + " from langgraph.checkpoint.memory import InMemorySaver\n", + " from langgraph.types import interrupt, Command\n", + " from typing_extensions import TypedDict\n", + " \n", + " class State(TypedDict):\n", + " foo: str\n", + " \n", + " # Subgraph\n", + " \n", + " def subgraph_node_1(state: State):\n", + " # highlight-next-line\n", + " value = interrupt(\"Provide value:\")\n", + " return {\"foo\": state[\"foo\"] + value}\n", + " \n", + " subgraph_builder = StateGraph(State)\n", + " subgraph_builder.add_node(subgraph_node_1)\n", + " subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + " \n", + " subgraph = subgraph_builder.compile()\n", + " \n", + " # Parent graph\n", + " \n", + " builder = StateGraph(State)\n", + " # highlight-next-line\n", + " builder.add_node(\"node_1\", subgraph)\n", + " builder.add_edge(START, \"node_1\")\n", + " \n", + " checkpointer = InMemorySaver()\n", + " # highlight-next-line\n", + " graph = builder.compile(checkpointer=checkpointer)\n", + " \n", + " config = {\"configurable\": {\"thread_id\": \"1\"}}\n", + " \n", + " graph.invoke({\"foo\": \"\"}, config)\n", + " parent_state = graph.get_state(config)\n", + " # highlight-next-line\n", + " subgraph_state = graph.get_state(config, subgraphs=True).tasks[0].state # (1)!\n", + " \n", + " # resume the subgraph\n", + " graph.invoke(Command(resume=\"bar\"), config)\n", + " ```\n", + " \n", + " 1. This will be available only when the subgraph is interrupted. Once you resume the graph, you won't be able to access the subgraph state." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Stream subgraph outputs\n", + "\n", + "To include outputs from [subgraphs](../concepts/low_level.md#subgraphs) in the streamed outputs, you can set `subgraphs=True` in the `.stream()` method of the parent graph. This will stream outputs from both the parent graph and any subgraphs.\n", + "\n", + "```python\n", + "for chunk in graph.stream(\n", + " {\"foo\": \"foo\"},\n", + " # highlight-next-line\n", + " subgraphs=True, # (1)!\n", + " stream_mode=\"updates\",\n", + "):\n", + " print(chunk)\n", + "```\n", + "\n", + "1. Set `subgraphs=True` to stream outputs from subgraphs.\n", + "\n", + "??? example \"Stream from subgraphs\"\n", + "\n", + " ```python\n", + " from typing_extensions import TypedDict\n", + " from langgraph.graph.state import StateGraph, START\n", + "\n", + " # Define subgraph\n", + " class SubgraphState(TypedDict):\n", + " foo: str\n", + " bar: str\n", + " \n", + " def subgraph_node_1(state: SubgraphState):\n", + " return {\"bar\": \"bar\"}\n", + " \n", + " def subgraph_node_2(state: SubgraphState):\n", + " # note that this node is using a state key ('bar') that is only available in the subgraph\n", + " # and is sending update on the shared state key ('foo')\n", + " return {\"foo\": state[\"foo\"] + state[\"bar\"]}\n", + " \n", + " subgraph_builder = StateGraph(SubgraphState)\n", + " subgraph_builder.add_node(subgraph_node_1)\n", + " subgraph_builder.add_node(subgraph_node_2)\n", + " subgraph_builder.add_edge(START, \"subgraph_node_1\")\n", + " subgraph_builder.add_edge(\"subgraph_node_1\", \"subgraph_node_2\")\n", + " subgraph = subgraph_builder.compile()\n", + " \n", + " # Define parent graph\n", + " class ParentState(TypedDict):\n", + " foo: str\n", + " \n", + " def node_1(state: ParentState):\n", + " return {\"foo\": \"hi! \" + state[\"foo\"]}\n", + " \n", + " builder = StateGraph(ParentState)\n", + " builder.add_node(\"node_1\", node_1)\n", + " # highlight-next-line\n", + " builder.add_node(\"node_2\", subgraph)\n", + " builder.add_edge(START, \"node_1\")\n", + " builder.add_edge(\"node_1\", \"node_2\")\n", + " graph = builder.compile()\n", + "\n", + " for chunk in graph.stream(\n", + " {\"foo\": \"foo\"},\n", + " stream_mode=\"updates\",\n", + " # highlight-next-line\n", + " subgraphs=True, # (1)!\n", + " ):\n", + " print(chunk)\n", + " ```\n", + " \n", + " 1. Set `subgraphs=True` to stream outputs from subgraphs.\n", + "\n", + " ```\n", + " ((), {'node_1': {'foo': 'hi! foo'}})\n", + " (('node_2:e58e5673-a661-ebb0-70d4-e298a7fc28b7',), {'subgraph_node_1': {'bar': 'bar'}})\n", + " (('node_2:e58e5673-a661-ebb0-70d4-e298a7fc28b7',), {'subgraph_node_2': {'foo': 'hi! foobar'}})\n", + " ((), {'node_2': {'foo': 'hi! foobar'}})\n", + " ```" ] } ], diff --git a/docs/docs/how-tos/subgraphs-manage-state.ipynb b/docs/docs/how-tos/subgraphs-manage-state.ipynb deleted file mode 100644 index f60451ecc..000000000 --- a/docs/docs/how-tos/subgraphs-manage-state.ipynb +++ /dev/null @@ -1,1049 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to view and update state in subgraphs\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "Once you add [persistence](../subgraph-persistence), you can easily view and update the state of the subgraph at any point in time. This enables a lot of the human-in-the-loop interaction patterns:\n", - "\n", - "* You can surface a state during an interrupt to a user to let them accept an action.\n", - "* You can rewind the subgraph to reproduce or avoid issues.\n", - "* You can modify the state to let the user better control its actions.\n", - "\n", - "This guide shows how you can do this." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we need to set API keys for OpenAI (the LLM we will use):" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define subgraph\n", - "\n", - "First, let's set up our subgraph. For this, we will create a simple graph that can get the weather for a specific city. We will compile this graph with a [breakpoint](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/breakpoints/) before the `weather_node`:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.graph import StateGraph, END, START, MessagesState\n", - "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "\n", - "@tool\n", - "def get_weather(city: str):\n", - " \"\"\"Get the weather for a specific city\"\"\"\n", - " return f\"It's sunny in {city}!\"\n", - "\n", - "\n", - "raw_model = ChatOpenAI(model=\"gpt-4o\")\n", - "model = raw_model.with_structured_output(get_weather)\n", - "\n", - "\n", - "class SubGraphState(MessagesState):\n", - " city: str\n", - "\n", - "\n", - "def model_node(state: SubGraphState):\n", - " result = model.invoke(state[\"messages\"])\n", - " return {\"city\": result[\"city\"]}\n", - "\n", - "\n", - "def weather_node(state: SubGraphState):\n", - " result = get_weather.invoke({\"city\": state[\"city\"]})\n", - " return {\"messages\": [{\"role\": \"assistant\", \"content\": result}]}\n", - "\n", - "\n", - "subgraph = StateGraph(SubGraphState)\n", - "subgraph.add_node(model_node)\n", - "subgraph.add_node(weather_node)\n", - "subgraph.add_edge(START, \"model_node\")\n", - "subgraph.add_edge(\"model_node\", \"weather_node\")\n", - "subgraph.add_edge(\"weather_node\", END)\n", - "subgraph = subgraph.compile(interrupt_before=[\"weather_node\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define parent graph\n", - "\n", - "We can now setup the overall graph. This graph will first route to the subgraph if it needs to get the weather, otherwise it will route to a normal LLM." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "from typing_extensions import TypedDict\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "class RouterState(MessagesState):\n", - " route: Literal[\"weather\", \"other\"]\n", - "\n", - "\n", - "class Router(TypedDict):\n", - " route: Literal[\"weather\", \"other\"]\n", - "\n", - "\n", - "router_model = raw_model.with_structured_output(Router)\n", - "\n", - "\n", - "def router_node(state: RouterState):\n", - " system_message = \"Classify the incoming query as either about weather or not.\"\n", - " messages = [{\"role\": \"system\", \"content\": system_message}] + state[\"messages\"]\n", - " route = router_model.invoke(messages)\n", - " return {\"route\": route[\"route\"]}\n", - "\n", - "\n", - "def normal_llm_node(state: RouterState):\n", - " response = raw_model.invoke(state[\"messages\"])\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "def route_after_prediction(\n", - " state: RouterState,\n", - ") -> Literal[\"weather_graph\", \"normal_llm_node\"]:\n", - " if state[\"route\"] == \"weather\":\n", - " return \"weather_graph\"\n", - " else:\n", - " return \"normal_llm_node\"\n", - "\n", - "\n", - "graph = StateGraph(RouterState)\n", - "graph.add_node(router_node)\n", - "graph.add_node(normal_llm_node)\n", - "graph.add_node(\"weather_graph\", subgraph)\n", - "graph.add_edge(START, \"router_node\")\n", - "graph.add_conditional_edges(\"router_node\", route_after_prediction)\n", - "graph.add_edge(\"normal_llm_node\", END)\n", - "graph.add_edge(\"weather_graph\", END)\n", - "graph = graph.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "# Setting xray to 1 will show the internal structure of the nested graph\n", - "display(Image(graph.get_graph(xray=1).draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's test this out with a normal query to make sure it works as intended!" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'router_node': {'route': 'other'}}\n", - "{'normal_llm_node': {'messages': [AIMessage(content='Hello! How can I assist you today?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 9, 'prompt_tokens': 9, 'total_tokens': 18, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-35de4577-2117-40e4-ab3b-cd2ac6e27b4c-0', usage_metadata={'input_tokens': 9, 'output_tokens': 9, 'total_tokens': 18})]}}\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"hi!\"}]}\n", - "for update in graph.stream(inputs, config=config, stream_mode=\"updates\"):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Great! We didn't ask about the weather, so we got a normal response from the LLM.\n", - "\n", - "## Resuming from breakpoints\n", - "\n", - "Let's now look at what happens with breakpoints. Let's invoke it with a query that should get routed to the weather subgraph where we have the interrupt node." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'router_node': {'route': 'weather'}}\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", - "for update in graph.stream(inputs, config=config, stream_mode=\"updates\"):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the graph stream doesn't include subgraph events. If we want to stream subgraph events, we can pass `subgraphs=True` and get back subgraph events like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')]})\n", - "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'route': 'weather'})\n", - "(('weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20',), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')]})\n", - "(('weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20',), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'city': 'San Francisco'})\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"3\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", - "for update in graph.stream(inputs, config=config, stream_mode=\"values\", subgraphs=True):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we get the state now, we can see that it's paused on `weather_graph`" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('weather_graph',)" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "state = graph.get_state(config)\n", - "state.next" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we look at the pending tasks for our current state, we can see that we have one task named `weather_graph`, which corresponds to the subgraph task." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(PregelTask(id='0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20', name='weather_graph', path=('__pregel_pull', 'weather_graph'), error=None, interrupts=(), state={'configurable': {'thread_id': '3', 'checkpoint_ns': 'weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20'}}),)" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "state.tasks" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However since we got the state using the config of the parent graph, we don't have access to the subgraph state. If you look at the `state` value of the `PregelTask` above you will note that it is simply the configuration of the parent graph. If we want to actually populate the subgraph state, we can pass in `subgraphs=True` to `get_state` like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PregelTask(id='0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20', name='weather_graph', path=('__pregel_pull', 'weather_graph'), error=None, interrupts=(), state=StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'city': 'San Francisco'}, next=('weather_node',), config={'configurable': {'thread_id': '3', 'checkpoint_ns': 'weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20', 'checkpoint_id': '1ef75ee0-d9c3-6242-8001-440e7a3fb19f', 'checkpoint_map': {'': '1ef75ee0-d4e8-6ede-8001-2542067239ef', 'weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20': '1ef75ee0-d9c3-6242-8001-440e7a3fb19f'}}}, metadata={'source': 'loop', 'writes': {'model_node': {'city': 'San Francisco'}}, 'step': 1, 'parents': {'': '1ef75ee0-d4e8-6ede-8001-2542067239ef'}}, created_at='2024-09-18T18:44:36.278105+00:00', parent_config={'configurable': {'thread_id': '3', 'checkpoint_ns': 'weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20', 'checkpoint_id': '1ef75ee0-d4ef-6dec-8000-5d5724f3ef73'}}, tasks=(PregelTask(id='26f4384a-41d7-5ca9-cb94-4001de62e8aa', name='weather_node', path=('__pregel_pull', 'weather_node'), error=None, interrupts=(), state=None),)))" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "state = graph.get_state(config, subgraphs=True)\n", - "state.tasks[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we have access to the subgraph state! If you look at the `state` value of the `PregelTask` you can see that it has all the information we need, like the next node (`weather_node`) and the current state values (e.g. `city`).\n", - "\n", - "To resume execution, we can just invoke the outer graph as normal:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'route': 'weather'})\n", - "(('weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20',), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'city': 'San Francisco'})\n", - "(('weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20',), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc'), AIMessage(content=\"It's sunny in San Francisco!\", additional_kwargs={}, response_metadata={}, id='c996ce37-438c-44f4-9e60-5aed8bcdae8a')], 'city': 'San Francisco'})\n", - "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc'), AIMessage(content=\"It's sunny in San Francisco!\", additional_kwargs={}, response_metadata={}, id='c996ce37-438c-44f4-9e60-5aed8bcdae8a')], 'route': 'weather'})\n" - ] - } - ], - "source": [ - "for update in graph.stream(None, config=config, stream_mode=\"values\", subgraphs=True):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Resuming from specific subgraph node\n", - "\n", - "In the example above, we were replaying from the outer graph - which automatically replayed the subgraph from whatever state it was in previously (paused before the `weather_node` in our case), but it is also possible to replay from inside a subgraph. In order to do so, we need to get the configuration from the exact subgraph state that we want to replay from.\n", - "\n", - "We can do this by exploring the state history of the subgraph, and selecting the state before `model_node` - which we can do by filtering on the `.next` parameter.\n", - "\n", - "To get the state history of the subgraph, we need to first pass in " - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [], - "source": [ - "parent_graph_state_before_subgraph = next(\n", - " h for h in graph.get_state_history(config) if h.next == (\"weather_graph\",)\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [], - "source": [ - "subgraph_state_before_model_node = next(\n", - " h\n", - " for h in graph.get_state_history(parent_graph_state_before_subgraph.tasks[0].state)\n", - " if h.next == (\"model_node\",)\n", - ")\n", - "\n", - "# This pattern can be extended no matter how many levels deep\n", - "# subsubgraph_stat_history = next(h for h in graph.get_state_history(subgraph_state_before_model_node.tasks[0].state) if h.next == ('my_subsubgraph_node',))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can confirm that we have gotten the correct state by comparing the `.next` parameter of the `subgraph_state_before_model_node`." - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('model_node',)" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "subgraph_state_before_model_node.next" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect! We have gotten the correct state snaphshot, and we can now resume from the `model_node` inside of our subgraph:" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'route': 'weather'})\n", - "(('weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20',), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')]})\n", - "(('weather_graph:0c47aeb3-6f4d-5e68-ccf4-42bd48e8ef20',), {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='108eb27a-2cbf-48d2-a6e7-6e07e82eafbc')], 'city': 'San Francisco'})\n" - ] - } - ], - "source": [ - "for value in graph.stream(\n", - " None,\n", - " config=subgraph_state_before_model_node.config,\n", - " stream_mode=\"values\",\n", - " subgraphs=True,\n", - "):\n", - " print(value)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Great, this subsection has shown how you can replay from any node, no matter how deeply nested it is inside your graph - a powerful tool for testing how deterministic your agent is." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Modifying state\n", - "\n", - "### Update the state of a subgraph\n", - "\n", - "What if we want to modify the state of a subgraph? We can do this similarly to how we [update the state of normal graphs](https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/time-travel/), just being careful to pass in the config of the subgraph to `update_state`." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'router_node': {'route': 'weather'}}\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"4\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", - "for update in graph.stream(inputs, config=config, stream_mode=\"updates\"):\n", - " print(update)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='05ee2159-3b25-4d6c-97d6-82beda3cabd4')]" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "state = graph.get_state(config, subgraphs=True)\n", - "state.values[\"messages\"]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to update the state of the **inner** graph, we need to pass the config for the **inner** graph, which we can get by accessing calling `state.tasks[0].state.config` - since we interrupted inside the subgraph, the state of the task is just the state of the subgraph." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'configurable': {'thread_id': '4',\n", - " 'checkpoint_ns': 'weather_graph:67f32ef7-aee0-8a20-0eb0-eeea0fd6de6e',\n", - " 'checkpoint_id': '1ef75e5a-0b00-6bc0-8002-5726e210fef4',\n", - " 'checkpoint_map': {'': '1ef75e59-1b13-6ffe-8001-0844ae748fd5',\n", - " 'weather_graph:67f32ef7-aee0-8a20-0eb0-eeea0fd6de6e': '1ef75e5a-0b00-6bc0-8002-5726e210fef4'}}}" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.update_state(state.tasks[0].state.config, {\"city\": \"la\"})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now resume streaming the outer graph (which will resume the subgraph!) and check that we updated our search to use LA instead of SF." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(('weather_graph:9e512e8e-bac5-5412-babe-fe5c12a47cc2',), {'weather_node': {'messages': [{'role': 'assistant', 'content': \"It's sunny in la!\"}]}})\n", - "((), {'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='35e331c6-eb47-483c-a63c-585877b12f5d'), AIMessage(content=\"It's sunny in la!\", id='c3d6b224-9642-4b21-94d5-eef8dc3f2cc9')]}})\n" - ] - } - ], - "source": [ - "for update in graph.stream(None, config=config, stream_mode=\"updates\", subgraphs=True):\n", - " print(update)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Fantastic! The AI responded with \"It's sunny in LA!\" as we expected.\n", - "\n", - "### Acting as a subgraph node\n", - "\n", - "Another way we could update the state is by acting as the `weather_node` ourselves instead of editing the state before `weather_node` is ran as we did above. We can do this by passing the subgraph config and also the `as_node` argument, which allows us to update the state as if we are the node we specify. Thus by setting an interrupt before the `weather_node` and then using the update state function as the `weather_node`, the graph itself never calls `weather_node` directly but instead we decide what the output of `weather_node` should be." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'router_node': {'route': 'weather'}})\n", - "(('weather_graph:c7eb1fc7-efab-b0e3-12ed-8586f37bc7a2',), {'model_node': {'city': 'San Francisco'}})\n", - "interrupted!\n", - "((), {'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='ad694c4e-8aac-4e1f-b5ca-790c60c1775b'), AIMessage(content='rainy', additional_kwargs={}, response_metadata={}, id='98a73aaf-3524-482a-9d07-971407df0389')]}})\n", - "[HumanMessage(content=\"what's the weather in sf\", additional_kwargs={}, response_metadata={}, id='ad694c4e-8aac-4e1f-b5ca-790c60c1775b'), AIMessage(content='rainy', additional_kwargs={}, response_metadata={}, id='98a73aaf-3524-482a-9d07-971407df0389')]\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"14\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", - "for update in graph.stream(\n", - " inputs, config=config, stream_mode=\"updates\", subgraphs=True\n", - "):\n", - " print(update)\n", - "# Graph execution should stop before the weather node\n", - "print(\"interrupted!\")\n", - "\n", - "state = graph.get_state(config, subgraphs=True)\n", - "\n", - "# We update the state by passing in the message we want returned from the weather node, and make sure to use as_node\n", - "graph.update_state(\n", - " state.tasks[0].state.config,\n", - " {\"messages\": [{\"role\": \"assistant\", \"content\": \"rainy\"}]},\n", - " as_node=\"weather_node\",\n", - ")\n", - "for update in graph.stream(None, config=config, stream_mode=\"updates\", subgraphs=True):\n", - " print(update)\n", - "\n", - "print(graph.get_state(config).values[\"messages\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfect! The AI responded with the message we passed in ourselves.\n", - "\n", - "### Acting as the entire subgraph\n", - "\n", - "Lastly, we could also update the graph just acting as the **entire** subgraph. This is similar to the case above but instead of acting as just the `weather_node` we are acting as the entire subgraph. This is done by passing in the normal graph config as well as the `as_node` argument, where we specify the we are acting as the entire subgraph node." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'router_node': {'route': 'weather'}})\n", - "(('weather_graph:53ab3fb1-23e8-5de0-acc6-9fb904fd4dc4',), {'model_node': {'city': 'San Francisco'}})\n", - "interrupted!\n", - "[HumanMessage(content=\"what's the weather in sf\", id='64b1b683-778b-4623-b783-4a8f81322ec8'), AIMessage(content='rainy', id='c1d1a2f3-c117-41e9-8c1f-8fb0a02a3b70')]\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"8\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", - "for update in graph.stream(\n", - " inputs, config=config, stream_mode=\"updates\", subgraphs=True\n", - "):\n", - " print(update)\n", - "# Graph execution should stop before the weather node\n", - "print(\"interrupted!\")\n", - "\n", - "# We update the state by passing in the message we want returned from the weather graph, making sure to use as_node\n", - "# Note that we don't need to pass in the subgraph config, since we aren't updating the state inside the subgraph\n", - "graph.update_state(\n", - " config,\n", - " {\"messages\": [{\"role\": \"assistant\", \"content\": \"rainy\"}]},\n", - " as_node=\"weather_graph\",\n", - ")\n", - "for update in graph.stream(None, config=config, stream_mode=\"updates\"):\n", - " print(update)\n", - "\n", - "print(graph.get_state(config).values[\"messages\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Again, the AI responded with \"rainy\" as we expected.\n", - "\n", - "## Double nested subgraphs\n", - "\n", - "This same functionality continues to work no matter the level of nesting. Here is an example of doing the same things with a double nested subgraph (although any level of nesting will work). We add another router on top of our already defined graphs." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "from typing_extensions import TypedDict\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "class RouterState(MessagesState):\n", - " route: Literal[\"weather\", \"other\"]\n", - "\n", - "\n", - "class Router(TypedDict):\n", - " route: Literal[\"weather\", \"other\"]\n", - "\n", - "\n", - "router_model = raw_model.with_structured_output(Router)\n", - "\n", - "\n", - "def router_node(state: RouterState):\n", - " system_message = \"Classify the incoming query as either about weather or not.\"\n", - " messages = [{\"role\": \"system\", \"content\": system_message}] + state[\"messages\"]\n", - " route = router_model.invoke(messages)\n", - " return {\"route\": route[\"route\"]}\n", - "\n", - "\n", - "def normal_llm_node(state: RouterState):\n", - " response = raw_model.invoke(state[\"messages\"])\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "def route_after_prediction(\n", - " state: RouterState,\n", - ") -> Literal[\"weather_graph\", \"normal_llm_node\"]:\n", - " if state[\"route\"] == \"weather\":\n", - " return \"weather_graph\"\n", - " else:\n", - " return \"normal_llm_node\"\n", - "\n", - "\n", - "graph = StateGraph(RouterState)\n", - "graph.add_node(router_node)\n", - "graph.add_node(normal_llm_node)\n", - "graph.add_node(\"weather_graph\", subgraph)\n", - "graph.add_edge(START, \"router_node\")\n", - "graph.add_conditional_edges(\"router_node\", route_after_prediction)\n", - "graph.add_edge(\"normal_llm_node\", END)\n", - "graph.add_edge(\"weather_graph\", END)\n", - "graph = graph.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "memory = MemorySaver()\n", - "\n", - "\n", - "class GrandfatherState(MessagesState):\n", - " to_continue: bool\n", - "\n", - "\n", - "def router_node(state: GrandfatherState):\n", - " # Dummy logic that will always continue\n", - " return {\"to_continue\": True}\n", - "\n", - "\n", - "def route_after_prediction(state: GrandfatherState):\n", - " if state[\"to_continue\"]:\n", - " return \"graph\"\n", - " else:\n", - " return END\n", - "\n", - "\n", - "grandparent_graph = StateGraph(GrandfatherState)\n", - "grandparent_graph.add_node(router_node)\n", - "grandparent_graph.add_node(\"graph\", graph)\n", - "grandparent_graph.add_edge(START, \"router_node\")\n", - "grandparent_graph.add_conditional_edges(\n", - " \"router_node\", route_after_prediction, [\"graph\", END]\n", - ")\n", - "grandparent_graph.add_edge(\"graph\", END)\n", - "grandparent_graph = grandparent_graph.compile(checkpointer=MemorySaver())" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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fEjMjweDLiRCeABzqrqr/FJfeAACGAgobukuH7Rj2RCdEFDd0lw/aMeyIeS3+JZcX7alRslOiFvHtA79sx7ZAmhC3j2gd+2Y9sgZlndrXhn0KdsL6AAOCVLtLfbf+9uv/It09pSbu7DG21dkfKNrjj+0xjPeF0GstHkVCUel7SjVx91vTMtVuxxyMK4ozREGmnMmySXe2icrP6hs0BHXF3PyfmrvqGK/A9o47zZv1SFguLufk/NXfUMV+B7Rx3mzfqkMse8Tw+6tzOAAH1EgAAAAAAAAAAAAAIy5+5qW80e9QxJiMufualvNHvUMYNS9RV/uu2D5o7+IdG7RpLqKv912wfNHfxDo3aMp/DAAACgAAAAAAAAAAAAABBWZ2ld8+rfxTonRXKW3ZSPS61STSGqdb7ryULoyUado4pZlnW48VGPFa59NrTaU0zVERMart804zGCo2XLGAgutc749a6CXvB1rnfHrXQS94V29p8qr9P8AIujFOgILrXO+PWugl7wda53x610EveDt7T5VX6f5F0Yp0BBda53x610EveDrXO+PWugl7wdvafKq/T/IujFOgILrXO+PWugl7wda53x610EveDt7T5VX6f5F0Yp0BBda53x610EveDrXO+PWugl7wdvafKq/T/IujFOgILrXO+PWugl7wda53x610EveDt7T5VX6f5F0YtOdSh2703/4gyPqtDoAc1dS1QSzs1pp2Es2wab9kEuGdIStdWq3lX63D6hvjrXO+PWugl7wyLauNUWUz+X+TLvqnQEF1rnfHrXQS94Otc749a6CXvDe3tPlVfp/k26MU6Agutc749a6CXvB1rnfHrXQS94O3tPlVfp/kXRinQEF1rnfHrXQS94Otc749a6CXvB29p8qr9P8i6MU6Agutc749a6CXvB1rnfHrXQS94O3tPlVfp/kXRinQEF1rnfHrXQS94Otc749a6CXvB29p8qr9P8AIujFOiChu6S4ftGPZEHWud8etdBL3hkQkM/Gv11RU1nLH6paVKUTRNkWqkkkRFk/mHKZtLW0s/8AHMRE3683wzG6ZxNUROtKiFvHtA79sx7ZAmhC3j2gd+2Y9sgdMs7ta8M+hTthfQABwS1lo8lYSs0vaUaSPtR6GlqR2OKRmnEmSJc1U5m2aT7+zTlB/WNmil2lvtv/AHt1/wCRbp7Sk3d2GNtq7I+UbXHH9pjGe8LoAjri7n5PzV31DFfge0cd5s36pCwXF3PyfmrvqGK/A9o47zZv1SGWPeJ4fdW5nAAD6iQAAAAAAAAAAAAAEZc/c1LeaPeoYkxGXP3NS3mj3qGMGpeoq/3XbB80d/EOjdo0l1FX+67YPmjv4h0btGU/hgAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADn/qUO3em//EGR9VodADn/AKlDt3pv/wAQZH1Wh0AIp2AAALAAAAAAAAAAAAAAAAABC3j2gd+2Y9sgTQhbx7QO/bMe2QPHlndrXhn0VTthfQABwS1lo8ioSj0vaUauPut6Zlqt2OORhXFGaIg005k2SS720TlZ/UNmjWWjyVhKzS9pRpI+1HoaWpHY4pGacSZIlzVTmbZpPv7NOUH9Y2aAjri7n5PzV31DFfge0cd5s36pCwXF3PyfmrvqGK/A9o47zZv1SGWPeJ4fdW5nAAD6iQAAAAAAAAAAAAAGJL0apGJraVCiSt9hbSTVzEakmXH+YywAcpaLNINydSxYERZmkaxJNuCiELaRd1vH1yolINxSzW8hKScZItbHFJmfDgOhrE0m2ppOjOX2rcFBO0xERrOkeJS288xLR+sg/oURGLONR331LVgXvJ9eWY9+1LlSZqRPWy+dBWJUfOozR2Kz+lSTMRdMbBtwBz7yLTzoj40lVG6ZLfb/AOgrNWNmEJ+YnCy07gu+rslH9YnLP6q+xp+VTBzrlbYNzcCVDXXTnQuGfN2C1fo1kZ82FZP5hudG8bmAfEqJaSUkyUkyyRkeSMh9FAAAAAAAAAAAAAAAAAAAAAAAAAAAACj6SNN1jaJKcnLquSii3lFlujNe0qnfm1GUZWr6yLA1r8sOlbSr+j0c6P8AdmIc4Fcl9GdPlP7zVGjLiuHFKjPVPhkiEzMQN911dTRlI7VVlQ1SUrKTW4++skIQkuczUfAi+saSnOq3turk3obR9EymlGebPVUzbrWtRtK721q1fo0JP94jUQx6HqT6W6atqS0rXbL6TK9CicTRVS+SRbKvnRSNGSfoyozz3yG7YOAjLZjGY6HjqWKj2Sw3S0TKWWkF9CUkREM1z9BqrqaNHt0WTGXpJXbR0cZK3RcVTO9bqOq5QVIl1KC2anNUiNRGk+KcljHHvFuQAFRF0XAAANAAAAAAAAAAAAAAAAABC3j2gd+2Y9sgTQhbx7QO/bMe2QPHlndrXhn0VTthfQABwSpdpb7b/wB7df8AkW6e0pN3dhjbauyPlG1xx/aYxnvC6DWWjyKhKPS9pRq4+63pmWq3Y45GFcUZoiDTTmTZJLvbROVn9Q2aAjri7n5PzV31DFfge0cd5s36pCwXF3PyfmrvqGK/A9o47zZv1SGWPeJ4fdW5nAAD6iQAAAAAAAAAAAAAAAAAAAAQV4WLbukCKVG3LCUM5Qqz+hrmEukk/nTkspP6SwYnQGDn5XUyzmjpR1GiC/pK1GUnrFbkyZyUSr/qpSszWznvqSZmPn/pFXfoyPY6XNHtZGUaOC7otbWkYwy761oL9Kyn/tEox0EAnNu2CtWNpKtXSZGdcLWn6CdpcFrKo3iUpvPMS0frIP6FERiBh9O1qTGmCf0ZlUPUl1RDbLps1SUpbq0rZS6ZsKJR6xpStOsRkk+cyIyIzKi6eNCGiyIt6a0hSFNUWXJxNM5VqnrWqSjq1SiLglJkaW3HFq1UJJZZUpSU54j+TbF6T9Nem9TUnUouXlpyHXBJ/pTqDXrm59ZqMz+nI511zRdeP7wgNEdTZ1SbumXRoxIyUHW01z0zvIqmjZpzS3VukklG4ypeE6uDI1EauwNREZ9kg1bT3gnu9az2PprWfeHros6q6c6Nn1mI9W3LIArfX+e8lnums/mHX+e8lnums/mL7GrGOcdS5ZAFb6/z3ks901n8w6/z3ks901n8w7GrGOcdS5ZAFb6/z3ks901n8w6/z3ks901n8w7GrGOcdS5ZAFb6/wA95LPdNZ/MfmovVcTTuvTENXR6EtrW2bSSqtsaUmrZoS0alG4ZEeqnVyo+CcmZEMmxqiL9XOJ9y54aU9KVu6HLMrrnuas5LH0xYS2giU7UOGR6rTSTMtZascCyRFxMzIiMyz7avSNuaxoi7G1nQRMlHsyaFVxpbNpl1tLidoesaUmRKLPEy+kx/IvqqOqEn9Pl9qrK2nqom3qM1NRUU+Rp2aM8XFlzG4rgZmXNwSRmRZPenUG2TZunCCrrdveulpqqtpwqiPtmrkDbjSpXFGo3UMJUSlrJ4165mWqW0aLjrYHii0vquhjqyd6re2H5N6FsCMk9KM+2eqqntxnXpWj7xu1R/o0J/wCsRqEfuPpt0tdldd1Uui+Bc54a0jJ+RUn91ytWWEKL52iMhvKCt6LteMZjoaNpImPZLDdLRMJZaR9SUkREJAdLpnbI1ro36nOwNFlQdbDQLT00o9Z2aklHV1ziu+o3nMmkz7+rgvoGygAVERGwAABoAAAAAAAAAAAAAAAAAAAAAAAAhbx7QO/bMe2QJoQt49oHftmPbIHjyzu1rwz6Kp2wvoAA4Jay0eSsJWaXtKNJH2o9DS1I7HFIzTiTJEuaqczbNJ9/Zpyg/rGzRS7S323/AL26/wDIt09pSbu7DG21dkfKNrjj+0xjPeF0AR1xdz8n5q76hivwPaOO82b9UhYLi7n5PzV31DFfge0cd5s36pDLHvE8PurczgAB9RIAAAAAAAAAAAAAAAAAAAAAAAAAAPOop2qyndYfaQ+w6k0ONOJJSVpMsGRkfAyMu8PCOiKCIa2VBRU9E3jGpTtJbL+REQywAVzOtpFwfHViux+jL3H1S/kLGK2X9Iyv7qL2xiyDva/6/aFSAA1rp20tOaJrci3qOlTWS8xItxlEhbD77aFqStanFtsJU6tKUNqPVQRmZ4LhkzLzzN2tLZQDmV/qlL0irLu2sqIKlrq+IVGropJcRIxdDWJqKxthxk26pJOIcQSs6yTWns0ng8Gk7HL6d5/RbJXlRX5TxUgcPbqLjpHoFp1knkG6tk6dSXFrPX2hIIlkZEZKzqljAnOgb3Ac2tu3/UdUJojfvluAYceoJlynpoVL2tTmbLGu26pxRksy7Hsk6pGetw5jHSQ2JvAVzSEeralSouCkPU60n8xk+gyP+ZCxit6RO5Gr+0Y9sgemw+LR949WxthYH6dqqaU080h5tXOhxJKI/wCBjGoIWOinX3aKgpaN1/G2XTspQpzGcaxkXHGTxn5zGaA4MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQt49oHftmPbIE0IW8e0Dv2zHtkDx5Z3a14Z9FU7YX0AAcEtZaPIqEo9L2lGrj7remZardjjkYVxRmiINNOZNkku9tE5Wf1DZo1lo8lYSs0vaUaSPtR6GlqR2OKRmnEmSJc1U5m2aT7+zTlB/WNmgI64u5+T81d9QxX4HtHHebN+qQsFxdz8n5q76hivwPaOO82b9Uhlj3ieH3VuZwAA+okAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWy/pGV/dRe2MLtu6vtp2mRR2jN3MTqVGpcSqkImsY4K277R5PPDVI+bjgfZg+slxszTyHF0B0iqV9bTalqZPXJSFGksnq/rEZkR47Ez4ZMvnykWsXPPx5H8xvpIx6q7Ou0imaImdW5UxM7Ff+VWc/+FV5+nF/64RV1W9VadIdmmqYa4tHstCVzErEy9cVG6puqRrERpQ0+6S06pqSpC9UjJfA/muvykWt5QR/SE/mHykWt5QR/SE/mOWj2u+meTM2cFNn9ENzXro6l7bue+G5SrrqujqW61iHRTtUyWH2ntRLROGZ6xtYM1LPGtkuBYGRfugmO0jXTOyMtXLOOl7ZVbb1C01haCN83SfS5n9YjMsJNPORHk+YWr5SLW8oI/pCfzH5RpMtN1OUXFGrLOMpqUn/APkNGtfBPKW5s4Nb0mia8IC5bbu64Lvqb9ftakq6eljKKHYpairJ9DaDM3FPkk3CJBGZmaSPHMk+e1lpUnD/AP2rvIv/ABxf+uE/8pFreUEf0hP5h8pFreUEf0hP5ho9rGymeUszZwQ1DpMmaytp2HNGd3UbbriUKqH1xuzaIzwa1atYasFzngjPBcCPmEzpE7kav7Rj2yA+Ui1vKCP6Qn8xhy81Q3rRpiod9NebrzSnn2UmplltLiVqNS/1dYyLCU5yZnnGCUZdrKytLO0pqrpmIiY3NiJida4AADyJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQt49oHftmPbIE0IW8e0Dv2zHtkDx5Z3a14Z9FU7YX0AAcEqXaW+2/97df+Rbp7Sk3d2GNtq7I+UbXHH9pjGe8LoNZaPIqEo9L2lGrj7remZardjjkYVxRmiINNOZNkku9tE5Wf1DZoCOuLufk/NXfUMV+B7Rx3mzfqkLBcXc/J+au+oYr8D2jjvNm/VIZY94nh91bmcAAPqJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGgOoj/obrv+8Mp+IUN/jQHUR/0N13/eGU/EKET+KBv8AAWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhbx7QO/bMe2QJoQt49oHftmPbIHjyzu1rwz6Kp2wvoAA4Jay0eSsJWaXtKNJH2o9DS1I7HFIzTiTJEuaqczbNJ9/Zpyg/rGzRS7S323/vbr/yLdPaUm7uwxttXZHyja44/tMYz3hdAEdcXc/J+au+oYrMFVsFCR5G82R8nb/rl+6Quq0JdQpC0ktCiwpKiyRl8xiG3HtzxBF9Cb90cf8lFp2lnETqu1zd7SqLrrpYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dHXSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQ0D1E1SyjQ5Wkp1CT3hkzwaiL/3hQ6M3HtzxBF9Cb90c+9Q/asLIaGa52qh6CpdK4pRJLepkLPBVCiIsmXMQdvb7c2L/ALz0Zqb05Yx4dv0yDljHh2/TIZ249ueIIvoTfuhuPbniCL6E37oaRlHgp5z0bqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQcsY8O36ZDO3HtzxBF9Cb90Nx7c8QRfQm/dDSMo8FPOehqYPLGPDt+mQh7uqWVwTiUuoUo3mMESiM/2yBZtx7c8QRfQm/dH6bsy32XEuNwUahxBkpKk0bZGRlzGR4HK2tMotrOqzmmIviY2zv/8ARF0TemQAB2S1lo8ioSj0vaUauPut6Zlqt2OORhXFGaIg005k2SS720TlZ/UNmjWWjyVhKzS9pRpI+1HoaWpHY4pGacSZIlzVTmbZpPv7NOUH9Y2aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA526hT+hSu/7xyv4lQ6JHO3UKf0KV3/eOV/EqAdEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApdpb7b/wB7df8AkW6e0pN3dhjbauyPlG1xx/aYxnvC6DWWjyKhKPS9pRq4+63pmWq3Y45GFcUZoiDTTmTZJLvbROVn9Q2aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5xrdCF9aEJKumtDMsiShqqoXWVtg3C8Z0zq1malqpKg+yYWZ57FRmkzPJnwIh0cADUeivqlbZ0jy67br2Kuzb6YL/aLWn0bCqI/naM+xeQeDMlI4mXEyIhtwUbSroVs/TPEN0N1RDdatg9alrmjNqro185LZeT2SDyRHgjweCyRjUXLNL/U2cKxFZpo0dtf+8spLeGOb/66earSRd8sLPiZ6pFgB0sApui/TBaGmSB67WjN08rTpwTzKT1X6ZX7jrR4UhXA+cuOMlkuIsVZcEXHy0fFVUlSU0nIk4dFRPPpQ9Uk2RG4baDPWXqkZGrVI8EZZ5wEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi1XTCpn0wRy9AU2ps3kxp1KOUm2XOsm862r9OMCgx3VBQl42bdE5Y0fJXm9A1PInI+kpl07tQ8SkkpLe1JOSTk8nzdiYDaQDW8tMaTZhuxKu3oOFhqesWh+5aO4H1rqaJrLZqaYUzlKnMG6nWPscknmyeJCOsKcY0kz1wyF5yElb9fSFS0lsKZQ1T0XBvWWS09ktZmhZkZ4wThlxwRgLBdd4QViwrsvcUxRQcW0ZJXVyD6WWyM+YtZRkWT7xc594QEvpht6Iu62LcMq+srrib29E9RUTjtOTWDMnHHSLUSR47554lwweRi2noFsm0bIctJuHTMQbtXy96nnXFSG1f7E9orbGrjlKT+YjLOM5F9p6dqlYbYYbQyy2kkIbbSSUoSRYIiIuYiLvANfxt2X7cUjfUaizWrabj21s2/NyVcioYkn8LJLi2W8ONtkZNmffMlKIjyQjJbRrfV96NIaHuC/qi27mZqzqJCVs5vk5VDeXMMo2mTSWFN5VzmbfNxMhtcAEFE2RCQV0TtxUEe3SzE4mnTI1LeSOp2JKS0pRc2sSVmWcZMiIjzgsToAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0zpR6l63r5nN6rerqzR/fyMm3ckAezcdPvpqG+CX0nwySuJ4ItbHAfyt0rdU9pAvTSzGXPU3f12q7Xf2cLXUNOdLTGlCiI30MGRapvapLWSiyZGSTIkpSlP9qLhgKC64CThJWnKri5Kldo6unNSkk6y4g0LTlJkZZSoyyRkfHgOYL46h/qeLUokVdRaVVTuOHs2KSllqtS318/Alunzd8zMiIucXRRVaVRRRF8yNy9Tzpui+qA0Wxd2R2ozUOFsJCiSrJ0lUki2jZ/RxJSTPnSpJ98bKHF+iWxGNCXXpNkPVFt0suppT9OTpViyNvX1ezdSac4cVnVQWeHzEL6d43Uf/6pkfQY+EPv0/0PKKovqqpjn7Q3Vi6TAc2b4XV5UyPoMfCDfC6vKmR9Bj4Qr/wVv46fPoasXSYDmzfC6vKmR9Bj4Qb4XV5UyPoMfCD/AMFb+Onz6GrF0mA5s3wurypkfQY+EPVi+7upVEpu5alzH9Sop2FoV9eGyV/IyCf6Fb7q6fPoasXRwDWFk6YTkqxmNuBhmjqnTJDNdT5KndUfMlSTMzbUfMWTURnw1iMySdp0i6Sbb0T2pV3HdUozExNMXZOunlS1d5CElxWs8cEkRn/IfEyjJrXJq8y1i6WLMA/lhcX/ACiFzXp1RFoytHKVVnaN46WYS/QpTtFPUSlkiocqUpJW0UbRrMkER6h41MrLXPviL0yzl+aOp6dsywZlUzRVZUlFE3Qgorlxazeu8hatYtmRKWZH3zbMuGSHmG1x8MyIjMzwRd8a7lYzSVO1diVlDNRdr0zJIfueMOl5Yp9X6M1MMOnjVT+1Tr4I/wBUyLnIZMdogoaO97ouOqnJ6XTP03JHYeRrzdj6VrVSSksNY7DWwZnx/rKAZF96ZbM0bWg9dFwT9PSwLT/JlVjBKqU7XiWpholHrZIyxgfiv0mrp75tuAorWnpShmKY6pVw0tMRx1IjVWaSdcNWSWZpT2OOZaTyM+xtGFq6Nrap7ftuEpouHp3TfbpUEayS4fOvKzMzVw5zPItADXMU5pOnXL9pJNmEtemyti1pKjUqrf8A+kJNRUtqwg/+hUSCMv65H3jGDJ6D6q97DtyCvi9JmbkourOsqZWIUUT1wXrLNKXWmjNOoRKSWqR86CPJZMhtQAECVh24V4KuvrHQKuY2CpuuyqdJ1JNFnsCcMskXE+BHxE6lJISSUkSUlzERYH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMs5ca7ynauZWs1sOqNFGk+ZunI8Ix/2sa5/SrHMRDpCUbcdjKtDP7ZTKyRj97VPH/EcrQhpVDUBo/V2DeOOf6pD9X/QrOmZtLSdsXRzv6G5mgAD9agAar6o2vraOyoxtirboKCrmKWlkqp4lm01SqNWsbmopCiQa9mlWFJ4KMs8Rra6rK3V0c30/QXDCu0S6SkQuKt1pxlqnd5Qg0v4U+7qKUnJdjq51SPnLI8NrlM2dU0xTfdF+36TPs106IWWuyjhrjgYV9t9VVMqfTTrbSRoSbTe0VrmZkZZIuGCPj8w0xelArRldlztWZTHHuPWXVV2wpzMyXUtPISl7B51nCStXZHkz4ZyPC3bfs2J0iaJ6u2H6eqqaxmtcqqtFUbr1T/shntHcqPKjUZ8T5jMy4cwirKas7MiLpvi/XjMRq1a/K4dEAAD6LH5eZRUNLadQlxtaTSpCiySiPgZGQm5PQxaPVU2XRxd+t11ZJW087T09bTVi2nSQ6lCicMuKVmaUoSZrIz1m1GWNYxDDYmgZCuvV0OER7PZUaM54axG+Z/8FJ/mQ+N/V7OmvJKqp203THOI91xvctX5/wAk5SOuOPWXfb1OjHYUc7Sk4Zn9LzRp9mO7rLpZqhs6CprkrGZG4maBhuTrKZJJafqibSTziCJKSJKlkoyLVTwPmLmEyA/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA50vW03bMuKopybMoyrdU/ROkXYlrGalM/QpJ5wXfTjGcKx0WMGahKG4Y9yhkaZFVSuYM0L4YMuZRGXFKiPiRkZGR8w+nkGWzkdpnXX0ztb9HJtxwcjMnT8guKvgdnra5UTNO5tc4xrbZpeMYPGMc55zwxD7k3BqmXyhTmc8/I4/wD0w3lL6DZSlcUcLLsVTH9ViUQaVp/+agjyX/gz85mIo9D96Z4NwJl9Mi8X/wDnH7CMtyO1/u7TzmPJmbLWMRalZTFUty9w1ty0j7ZtKpJKmpSbwfOeGmUGeS4YMzLjzDJpLHtygin4ymgIunjagyU9RtUTaWXDI8kakEnB8SI+JDYvyP3r4KB+8X/9MHyP3r4KB+8X/wDTDpGV5HH/ACRzvM2VLVGUapFMgdIwdelo6cqo2y2pNmZKNGtjOqZkR45skQhUaPbfoVPPxUPHQskonDbkaGgYS+ytaTSbiTNBlrYM+cjI+YyMuA2d8j96+CgfvF//AEwfI/evgoH7xf8A9MNnK8knbXBmy1GiybgStJnpBnFkR5NJ0cfg/o4UwIsm4ErSZ6QZxZEeTSdHH4P6OFMNufI/evgoH7xf/wBMPan0MXa8tKX6iFo0H+s4289UGn6km2jP8yHOcqyONc2v6p6mbKmOObMiwhbi1GSUNtpNS1qM8ElJFxMzPBERc5mN9aMLRdtC2SaqyIpKsdOqqySeSSsyIiQR9/VQlKclwMyM++MeytFkdaVQmuefXKyxEZJqnkklLWSweyQXBGSyWTM1YMy1sHgXYfnP6n/UacpjsrL8OOP/AOGwAAH54AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/9k=", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "# Setting xray to 1 will show the internal structure of the nested graph\n", - "display(Image(grandparent_graph.get_graph(xray=2).draw_mermaid_png()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we run until the interrupt, we can now see that there are snapshots of the state of all three graphs" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "((), {'router_node': {'to_continue': True}})\n", - "(('graph:e18ecd45-5dfb-53b0-bcb7-db793924e9a8',), {'router_node': {'route': 'weather'}})\n", - "(('graph:e18ecd45-5dfb-53b0-bcb7-db793924e9a8', 'weather_graph:12bd3069-de24-5bc6-b4f1-f39527605781'), {'model_node': {'city': 'San Francisco'}})\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"2\"}}\n", - "inputs = {\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf\"}]}\n", - "for update in grandparent_graph.stream(\n", - " inputs, config=config, stream_mode=\"updates\", subgraphs=True\n", - "):\n", - " print(update)" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Grandparent State:\n", - "{'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848')], 'to_continue': True}\n", - "---------------\n", - "Parent Graph State:\n", - "{'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848')], 'route': 'weather'}\n", - "---------------\n", - "Subgraph State:\n", - "{'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848')], 'city': 'San Francisco'}\n" - ] - } - ], - "source": [ - "state = grandparent_graph.get_state(config, subgraphs=True)\n", - "print(\"Grandparent State:\")\n", - "print(state.values)\n", - "print(\"---------------\")\n", - "print(\"Parent Graph State:\")\n", - "print(state.tasks[0].state.values)\n", - "print(\"---------------\")\n", - "print(\"Subgraph State:\")\n", - "print(state.tasks[0].state.tasks[0].state.values)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now continue, acting as the node three levels down" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(('graph:e18ecd45-5dfb-53b0-bcb7-db793924e9a8',), {'weather_graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848'), AIMessage(content='rainy', id='be926b59-c647-4355-88fd-a429b9e2b420')]}})\n", - "((), {'graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848'), AIMessage(content='rainy', id='be926b59-c647-4355-88fd-a429b9e2b420')]}})\n", - "[HumanMessage(content=\"what's the weather in sf\", id='3bb28060-3d30-49a7-9f84-c90b6ada7848'), AIMessage(content='rainy', id='be926b59-c647-4355-88fd-a429b9e2b420')]\n" - ] - } - ], - "source": [ - "grandparent_graph_state = state\n", - "parent_graph_state = grandparent_graph_state.tasks[0].state\n", - "subgraph_state = parent_graph_state.tasks[0].state\n", - "grandparent_graph.update_state(\n", - " subgraph_state.config,\n", - " {\"messages\": [{\"role\": \"assistant\", \"content\": \"rainy\"}]},\n", - " as_node=\"weather_node\",\n", - ")\n", - "for update in grandparent_graph.stream(\n", - " None, config=config, stream_mode=\"updates\", subgraphs=True\n", - "):\n", - " print(update)\n", - "\n", - "print(grandparent_graph.get_state(config).values[\"messages\"])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As in the cases above, we can see that the AI responds with \"rainy\" as we expect.\n", - "\n", - "We can explore the state history to see how the state of the grandparent graph was updated at each step." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720'), AIMessage(content='rainy', id='7c80f847-248d-4b8f-8238-633ed757b353')], 'to_continue': True}, next=(), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f40-7a2c-6f9e-8002-a37a61b26709'}}, metadata={'source': 'loop', 'writes': {'graph': {'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720'), AIMessage(content='rainy', id='7c80f847-248d-4b8f-8238-633ed757b353')]}}, 'step': 2, 'parents': {}}, created_at='2024-08-30T17:19:35.793847+00:00', parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f312-6338-8001-766acddc781e'}}, tasks=())\n", - "-----\n", - "StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720')], 'to_continue': True}, next=('graph',), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f312-6338-8001-766acddc781e'}}, metadata={'source': 'loop', 'writes': {'router_node': {'to_continue': True}}, 'step': 1, 'parents': {}}, created_at='2024-08-30T17:19:21.627097+00:00', parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f303-61d0-8000-1945c8a74e9e'}}, tasks=(PregelTask(id='b59fe96f-fdce-5afe-aa58-bd2876a0d592', name='graph', error=None, interrupts=(), state={'configurable': {'thread_id': '2', 'checkpoint_ns': 'graph:b59fe96f-fdce-5afe-aa58-bd2876a0d592'}}),))\n", - "-----\n", - "StateSnapshot(values={'messages': [HumanMessage(content=\"what's the weather in sf\", id='5ff89e4d-8255-4d23-8b55-01633c112720')]}, next=('router_node',), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f303-61d0-8000-1945c8a74e9e'}}, metadata={'source': 'loop', 'writes': None, 'step': 0, 'parents': {}}, created_at='2024-08-30T17:19:21.620923+00:00', parent_config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f2f9-6d6a-bfff-c8b76e5b2462'}}, tasks=(PregelTask(id='e3d4a97a-f4ca-5260-801e-e65b02907825', name='router_node', error=None, interrupts=(), state=None),))\n", - "-----\n", - "StateSnapshot(values={'messages': []}, next=('__start__',), config={'configurable': {'thread_id': '2', 'checkpoint_ns': '', 'checkpoint_id': '1ef66f3f-f2f9-6d6a-bfff-c8b76e5b2462'}}, metadata={'source': 'input', 'writes': {'messages': [{'role': 'user', 'content': \"what's the weather in sf\"}]}, 'step': -1, 'parents': {}}, created_at='2024-08-30T17:19:21.617127+00:00', parent_config=None, tasks=(PregelTask(id='f0538638-b794-58fc-a406-980d2fea28a1', name='__start__', error=None, interrupts=(), state=None),))\n", - "-----\n" - ] - } - ], - "source": [ - "for state in grandparent_graph.get_state_history(config):\n", - " print(state)\n", - " print(\"-----\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/tool-calling-errors.ipynb b/docs/docs/how-tos/tool-calling-errors.ipynb deleted file mode 100644 index 75898fdf7..000000000 --- a/docs/docs/how-tos/tool-calling-errors.ipynb +++ /dev/null @@ -1,591 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# How to handle tool calling errors\n", - "\n", - "
    \n", - "

    Prerequisites

    \n", - "

    \n", - " This guide assumes familiarity with the following:\n", - "

    \n", - "

    \n", - "
    \n", - "\n", - "LLMs aren't perfect at calling tools. The model may try to call a tool that doesn't exist or fail to return arguments that match the requested schema. Strategies like keeping schemas simple, reducing the number of tools you pass at once, and having good names and descriptions can help mitigate this risk, but aren't foolproof.\n", - "\n", - "This guide covers some ways to build error handling into your graphs to mitigate these failure modes." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Using the prebuilt `ToolNode`\n", - "\n", - "To start, define a mock weather tool that has some hidden restrictions on input queries. The intent here is to simulate a real-world case where a model fails to call a tool correctly:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.tools import tool\n", - "\n", - "\n", - "@tool\n", - "def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location == \"san francisco\":\n", - " raise ValueError(\"Input queries must be proper nouns\")\n", - " elif location == \"San Francisco\":\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " raise ValueError(\"Invalid input.\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, set up a graph implementation of the [ReAct agent](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-agent). This agent takes some query as input, then repeatedly call tools until it has enough information to resolve the query. We'll use the prebuilt [`ToolNode`](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode) to execute called tools, and a small, fast model powered by Anthropic:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langgraph.graph import StateGraph, MessagesState, START, END\n", - "from langgraph.prebuilt import ToolNode\n", - "\n", - "tool_node = ToolNode([get_weather])\n", - "\n", - "model_with_tools = ChatAnthropic(\n", - " model=\"claude-3-haiku-20240307\", temperature=0\n", - ").bind_tools([get_weather])\n", - "\n", - "\n", - "def should_continue(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " if last_message.tool_calls:\n", - " return \"tools\"\n", - " return END\n", - "\n", - "\n", - "def call_model(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " response = model_with_tools.invoke(messages)\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"tools\", tool_node)\n", - "\n", - "workflow.add_edge(START, \"agent\")\n", - "workflow.add_conditional_edges(\"agent\", should_continue, [\"tools\", END])\n", - "workflow.add_edge(\"tools\", \"agent\")\n", - "\n", - "app = workflow.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(app.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When you try to call the tool, you can see that the model calls the tool with a bad input, causing the tool to throw an error. The prebuilt `ToolNode` that executes the tool has some built-in error handling that captures the error and passes it back to the model so that it can try again:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HUMAN: what is the weather in san francisco?\n", - "\n", - "AI: [{'id': 'toolu_01K5tXKVRbETcs7Q8U9PHy96', 'input': {'location': 'san francisco'}, 'name': 'get_weather', 'type': 'tool_use'}]\n", - "\n", - "TOOL: Error: ValueError('Input queries must be proper nouns')\n", - " Please fix your mistakes.\n", - "\n", - "AI: [{'text': 'Apologies, it looks like there was an issue with the weather lookup. Let me try that again with the proper format:', 'type': 'text'}, {'id': 'toolu_01KSCsme3Du2NBazSJQ1af4b', 'input': {'location': 'San Francisco'}, 'name': 'get_weather', 'type': 'tool_use'}]\n", - "\n", - "TOOL: It's 60 degrees and foggy.\n", - "\n", - "AI: The current weather in San Francisco is 60 degrees and foggy.\n", - "\n" - ] - } - ], - "source": [ - "response = app.invoke(\n", - " {\"messages\": [(\"human\", \"what is the weather in san francisco?\")]},\n", - ")\n", - "\n", - "for message in response[\"messages\"]:\n", - " string_representation = f\"{message.type.upper()}: {message.content}\\n\"\n", - " print(string_representation)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Custom strategies\n", - "\n", - "This is a fine default in many cases, but there are cases where custom fallbacks may be better.\n", - "\n", - "For example, the below tool requires as input a list of elements of a specific length - tricky for a small model! We'll also intentionally avoid pluralizing `topic` to trick the model into thinking it should pass a string:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HUMAN: Write me an incredible haiku about water.\n", - "\n", - "AI: [{'text': 'Here is a haiku about water:', 'type': 'text'}, {'id': 'toolu_01L13Z3Gtaym5KKgPXVyZhYn', 'input': {'topic': ['water']}, 'name': 'master_haiku_generator', 'type': 'tool_use'}]\n", - "\n", - "TOOL: Error: 1 validation error for master_haiku_generator\n", - "request\n", - " Field required [type=missing, input_value={'topic': ['water']}, input_type=dict]\n", - " For further information visit https://errors.pydantic.dev/2.7/v/missing\n", - " Please fix your mistakes.\n", - "\n", - "AI: [{'text': 'Oops, my apologies. Let me try that again with the correct format:', 'type': 'text'}, {'id': 'toolu_01HCQ5uXr5kXQHBQ3FyQ1Ysk', 'input': {'topic': ['water']}, 'name': 'master_haiku_generator', 'type': 'tool_use'}]\n", - "\n", - "TOOL: Error: 1 validation error for master_haiku_generator\n", - "request\n", - " Field required [type=missing, input_value={'topic': ['water']}, input_type=dict]\n", - " For further information visit https://errors.pydantic.dev/2.7/v/missing\n", - " Please fix your mistakes.\n", - "\n", - "AI: [{'text': 'Hmm, it seems there was an issue with the input format. Let me try a different approach:', 'type': 'text'}, {'id': 'toolu_01RF96nruwr4nMqhLBRsbfE5', 'input': {'request': {'topic': ['water']}}, 'name': 'master_haiku_generator', 'type': 'tool_use'}]\n", - "\n", - "TOOL: Error: 1 validation error for master_haiku_generator\n", - "request.topic\n", - " List should have at least 3 items after validation, not 1 [type=too_short, input_value=['water'], input_type=list]\n", - " For further information visit https://errors.pydantic.dev/2.7/v/too_short\n", - " Please fix your mistakes.\n", - "\n", - "AI: [{'text': 'Ah I see, the haiku generator requires at least 3 topics. Let me provide 3 topics related to water:', 'type': 'text'}, {'id': 'toolu_011jcgHuG2Kyr87By459huqQ', 'input': {'request': {'topic': ['ocean', 'rain', 'river']}}, 'name': 'master_haiku_generator', 'type': 'tool_use'}]\n", - "\n", - "TOOL: Here is a haiku about ocean, rain, and river:\n", - "\n", - "Vast ocean's embrace,\n", - "Raindrops caress the river,\n", - "Nature's symphony.\n", - "\n", - "AI: I hope this haiku about water captures the essence you were looking for! Let me know if you would like me to generate another one.\n", - "\n" - ] - } - ], - "source": [ - "from langchain_core.output_parsers import StrOutputParser\n", - "from pydantic import BaseModel, Field\n", - "\n", - "\n", - "class HaikuRequest(BaseModel):\n", - " topic: list[str] = Field(\n", - " max_length=3,\n", - " min_length=3,\n", - " )\n", - "\n", - "\n", - "@tool\n", - "def master_haiku_generator(request: HaikuRequest):\n", - " \"\"\"Generates a haiku based on the provided topics.\"\"\"\n", - " model = ChatAnthropic(model=\"claude-3-haiku-20240307\", temperature=0)\n", - " chain = model | StrOutputParser()\n", - " topics = \", \".join(request.topic)\n", - " haiku = chain.invoke(f\"Write a haiku about {topics}\")\n", - " return haiku\n", - "\n", - "\n", - "tool_node = ToolNode([master_haiku_generator])\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-haiku-20240307\", temperature=0)\n", - "model_with_tools = model.bind_tools([master_haiku_generator])\n", - "\n", - "\n", - "def should_continue(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " if last_message.tool_calls:\n", - " return \"tools\"\n", - " return END\n", - "\n", - "\n", - "def call_model(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " response = model_with_tools.invoke(messages)\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"tools\", tool_node)\n", - "\n", - "workflow.add_edge(START, \"agent\")\n", - "workflow.add_conditional_edges(\"agent\", should_continue, [\"tools\", END])\n", - "workflow.add_edge(\"tools\", \"agent\")\n", - "\n", - "app = workflow.compile()\n", - "\n", - "response = app.invoke(\n", - " {\"messages\": [(\"human\", \"Write me an incredible haiku about water.\")]},\n", - " {\"recursion_limit\": 10},\n", - ")\n", - "\n", - "for message in response[\"messages\"]:\n", - " string_representation = f\"{message.type.upper()}: {message.content}\\n\"\n", - " print(string_representation)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that the model takes two tries to get the input correct.\n", - "\n", - "A better strategy might be to trim the failed attempt to reduce distraction, then fall back to a more advanced model. Here's an example. We also use a custom-built node to call our tools instead of the prebuilt `ToolNode`:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "from langchain_core.messages import AIMessage, ToolMessage\n", - "from langchain_core.messages.modifier import RemoveMessage\n", - "\n", - "\n", - "@tool\n", - "def master_haiku_generator(request: HaikuRequest):\n", - " \"\"\"Generates a haiku based on the provided topics.\"\"\"\n", - " model = ChatAnthropic(model=\"claude-3-haiku-20240307\", temperature=0)\n", - " chain = model | StrOutputParser()\n", - " topics = \", \".join(request.topic)\n", - " haiku = chain.invoke(f\"Write a haiku about {topics}\")\n", - " return haiku\n", - "\n", - "\n", - "def call_tool(state: MessagesState):\n", - " tools_by_name = {master_haiku_generator.name: master_haiku_generator}\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " output_messages = []\n", - " for tool_call in last_message.tool_calls:\n", - " try:\n", - " tool_result = tools_by_name[tool_call[\"name\"]].invoke(tool_call[\"args\"])\n", - " output_messages.append(\n", - " ToolMessage(\n", - " content=json.dumps(tool_result),\n", - " name=tool_call[\"name\"],\n", - " tool_call_id=tool_call[\"id\"],\n", - " )\n", - " )\n", - " except Exception as e:\n", - " # Return the error if the tool call fails\n", - " output_messages.append(\n", - " ToolMessage(\n", - " content=\"\",\n", - " name=tool_call[\"name\"],\n", - " tool_call_id=tool_call[\"id\"],\n", - " additional_kwargs={\"error\": e},\n", - " )\n", - " )\n", - " return {\"messages\": output_messages}\n", - "\n", - "\n", - "model = ChatAnthropic(model=\"claude-3-haiku-20240307\", temperature=0)\n", - "model_with_tools = model.bind_tools([master_haiku_generator])\n", - "\n", - "better_model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\", temperature=0)\n", - "better_model_with_tools = better_model.bind_tools([master_haiku_generator])\n", - "\n", - "\n", - "def should_continue(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " if last_message.tool_calls:\n", - " return \"tools\"\n", - " return END\n", - "\n", - "\n", - "def should_fallback(\n", - " state: MessagesState,\n", - ") -> Literal[\"agent\", \"remove_failed_tool_call_attempt\"]:\n", - " messages = state[\"messages\"]\n", - " failed_tool_messages = [\n", - " msg\n", - " for msg in messages\n", - " if isinstance(msg, ToolMessage)\n", - " and msg.additional_kwargs.get(\"error\") is not None\n", - " ]\n", - " if failed_tool_messages:\n", - " return \"remove_failed_tool_call_attempt\"\n", - " return \"agent\"\n", - "\n", - "\n", - "def call_model(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " response = model_with_tools.invoke(messages)\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "def remove_failed_tool_call_attempt(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " # Remove all messages from the most recent\n", - " # instance of AIMessage onwards.\n", - " last_ai_message_index = next(\n", - " i\n", - " for i, msg in reversed(list(enumerate(messages)))\n", - " if isinstance(msg, AIMessage)\n", - " )\n", - " messages_to_remove = messages[last_ai_message_index:]\n", - " return {\"messages\": [RemoveMessage(id=m.id) for m in messages_to_remove]}\n", - "\n", - "\n", - "# Fallback to a better model if a tool call fails\n", - "def call_fallback_model(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " response = better_model_with_tools.invoke(messages)\n", - " return {\"messages\": [response]}\n", - "\n", - "\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"tools\", call_tool)\n", - "workflow.add_node(\"remove_failed_tool_call_attempt\", remove_failed_tool_call_attempt)\n", - "workflow.add_node(\"fallback_agent\", call_fallback_model)\n", - "\n", - "workflow.add_edge(START, \"agent\")\n", - "workflow.add_conditional_edges(\"agent\", should_continue, [\"tools\", END])\n", - "workflow.add_conditional_edges(\"tools\", should_fallback)\n", - "workflow.add_edge(\"remove_failed_tool_call_attempt\", \"fallback_agent\")\n", - "workflow.add_edge(\"fallback_agent\", \"tools\")\n", - "\n", - "app = workflow.compile()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `tools` node will now return `ToolMessage`s with an `error` field in `additional_kwargs` if a tool call fails. If that happens, it will go to another node that removes the failed tool messages, and has a better model retry the tool call generation.\n", - "\n", - "The diagram below shows this visually:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "try:\n", - " display(Image(app.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's try it out. To emphasize the removal steps, let's `stream` the responses from the model so that we can see each executed node:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'agent': {'messages': [AIMessage(content=[{'text': 'Here is a haiku about water:', 'type': 'text'}, {'id': 'toolu_019mY8NX4t7YkJBWeHG6jE4T', 'input': {'topic': ['water']}, 'name': 'master_haiku_generator', 'type': 'tool_use'}], additional_kwargs={}, response_metadata={'id': 'msg_01RmoaLh38DnRX2fv7E8vCFh', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'tool_use', 'stop_sequence': None, 'usage': {'input_tokens': 384, 'output_tokens': 67}}, id='run-a1511215-1a62-49b5-b5b3-b2c8f8c7920e-0', tool_calls=[{'name': 'master_haiku_generator', 'args': {'topic': ['water']}, 'id': 'toolu_019mY8NX4t7YkJBWeHG6jE4T', 'type': 'tool_call'}], usage_metadata={'input_tokens': 384, 'output_tokens': 67, 'total_tokens': 451})]}}\n", - "{'tools': {'messages': [ToolMessage(content='', name='master_haiku_generator', id='69f85339-dbc2-4341-8c4d-26300dfe31a5', tool_call_id='toolu_019mY8NX4t7YkJBWeHG6jE4T')]}}\n", - "{'remove_failed_tool_call_attempt': {'messages': [RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='run-a1511215-1a62-49b5-b5b3-b2c8f8c7920e-0'), RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='69f85339-dbc2-4341-8c4d-26300dfe31a5')]}}\n", - "{'fallback_agent': {'messages': [AIMessage(content=[{'text': 'Certainly! I\\'d be happy to help you create an incredible haiku about water. To do this, I\\'ll use the master_haiku_generator function, which requires three topics. Since you\\'ve specified water as the main theme, I\\'ll add two related concepts to create a more vivid and interesting haiku. Let\\'s use \"water,\" \"flow,\" and \"reflection\" as our three topics.', 'type': 'text'}, {'id': 'toolu_01FxSxy8LeQ5PjdNYq8vLFTd', 'input': {'request': {'topic': ['water', 'flow', 'reflection']}}, 'name': 'master_haiku_generator', 'type': 'tool_use'}], additional_kwargs={}, response_metadata={'id': 'msg_01U5HV3pt1NVm6syGbxx29no', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'tool_use', 'stop_sequence': None, 'usage': {'input_tokens': 414, 'output_tokens': 158}}, id='run-3eb746c7-b607-4ad3-881a-1c11a7638af7-0', tool_calls=[{'name': 'master_haiku_generator', 'args': {'request': {'topic': ['water', 'flow', 'reflection']}}, 'id': 'toolu_01FxSxy8LeQ5PjdNYq8vLFTd', 'type': 'tool_call'}], usage_metadata={'input_tokens': 414, 'output_tokens': 158, 'total_tokens': 572})]}}\n", - "{'tools': {'messages': [ToolMessage(content='\"Here is a haiku about water, flow, and reflection:\\\\n\\\\nRippling waters flow,\\\\nMirroring the sky above,\\\\nTranquil reflection.\"', name='master_haiku_generator', id='fdfc497d-939a-42c0-8748-31371b98a3a7', tool_call_id='toolu_01FxSxy8LeQ5PjdNYq8vLFTd')]}}\n", - "{'agent': {'messages': [AIMessage(content='I hope you enjoy this haiku about the beauty and serenity of water. Please let me know if you would like me to generate another one.', additional_kwargs={}, response_metadata={'id': 'msg_012rXWHapc8tPfBPEonpAT6W', 'model': 'claude-3-haiku-20240307', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 587, 'output_tokens': 35}}, id='run-ab6d412d-9374-4a4b-950d-6dcc43d87cf5-0', usage_metadata={'input_tokens': 587, 'output_tokens': 35, 'total_tokens': 622})]}}\n" - ] - } - ], - "source": [ - "stream = app.stream(\n", - " {\"messages\": [(\"human\", \"Write me an incredible haiku about water.\")]},\n", - " {\"recursion_limit\": 10},\n", - ")\n", - "\n", - "for chunk in stream:\n", - " print(chunk)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can see that you get a cleaner response - the more powerful model gets it right on the first try, and the smaller model's failure gets wiped from the graph state. This shorter message history also avoid overpopulating the graph state with attempts.\n", - "\n", - "You can also inspect this [LangSmith trace](https://smith.langchain.com/public/7ce6f1fe-48c4-400e-9cbe-1de2da6d2800/r), which shows the failed initial call to the smaller model.\n", - "\n", - "## Next steps\n", - "\n", - "You've now seen how to implement some strategies to handle tool calling errors.\n", - "\n", - "Next, check out some of the [other LangGraph how-to guides here](https://langchain-ai.github.io/langgraph/how-tos/)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/docs/docs/how-tos/tool-calling.ipynb b/docs/docs/how-tos/tool-calling.ipynb index 7aee38e77..ab934346b 100644 --- a/docs/docs/how-tos/tool-calling.ipynb +++ b/docs/docs/how-tos/tool-calling.ipynb @@ -4,295 +4,559 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# How to call tools using ToolNode\n", + "# Use tools\n", "\n", - "This guide covers how to use LangGraph's prebuilt [`ToolNode`](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.tool_node.ToolNode) for tool calling.\n", + "[Tools](https://python.langchain.com/docs/concepts/tools/) are a way to encapsulate a function and its input schema in a way that can be passed to a chat model that supports tool calling. This allows the model to request the execution of this function with specific inputs. This guide shows how you can create tools and use them in your graphs.\n", "\n", - "`ToolNode` is a LangChain Runnable that takes graph state (with a list of messages) as input and outputs state update with the result of tool calls. It is designed to work well out-of-box with LangGraph's prebuilt [ReAct agent](https://langchain-ai.github.io/langgraph/how-tos/create-react-agent/), but can also work with any `StateGraph` as long as its state has a `messages` key with an appropriate reducer (see [`MessagesState`](https://github.com/langchain-ai/langgraph/blob/e3ef9adac7395e5c0943c22bbc8a4a856b103aa3/libs/langgraph/langgraph/graph/message.py#L150))." + "## Create tools\n", + "\n", + "### Define simple tools\n", + "\n", + "To create tools, you can use [@tool](https://python.langchain.com/api_reference/core/tools/langchain_core.tools.convert.tool.html) decorator or vanilla Python functions.\n", + "\n", + "=== \"`@tool` decorator\"\n", + " ```python\n", + " from langchain_core.tools import tool\n", + "\n", + " # highlight-next-line\n", + " @tool\n", + " def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", + " ```\n", + "\n", + "=== \"Python functions\"\n", + "\n", + " This requires using LangGraph's prebuilt [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] or [agent](../../agents/agents), which automatically convert the functions to [LangChain tools](https://python.langchain.com/docs/concepts/tools/#tool-interface).\n", + " \n", + " ```python\n", + " def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", + " ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Setup\n", + "### Customize tools\n", "\n", - "First, let's install the required packages and set our API keys" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet -U langgraph langchain_anthropic" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", + "For more control over tool behavior, use the `@tool` decorator:\n", "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define tools" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import AIMessage\n", + "```python\n", + "# highlight-next-line\n", "from langchain_core.tools import tool\n", "\n", - "from langgraph.prebuilt import ToolNode" + "# highlight-next-line\n", + "@tool(\"multiply_tool\", parse_docstring=True)\n", + "def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\n", + "\n", + " Args:\n", + " a: First operand\n", + " b: Second operand\n", + " \"\"\"\n", + " return a * b\n", + "```\n", + "\n", + "You can also define a custom input schema using Pydantic:\n", + "\n", + "```python\n", + "from pydantic import BaseModel, Field\n", + "\n", + "class MultiplyInputSchema(BaseModel):\n", + " \"\"\"Multiply two numbers\"\"\"\n", + " a: int = Field(description=\"First operand\")\n", + " b: int = Field(description=\"Second operand\")\n", + "\n", + "# highlight-next-line\n", + "@tool(\"multiply_tool\", args_schema=MultiplyInputSchema)\n", + "def multiply(a: int, b: int) -> int:\n", + " return a * b\n", + "```\n", + "\n", + "For additional customization, refer to the [custom tools guide](https://python.langchain.com/docs/how_to/custom_tools/)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Hide arguments from the model\n", + "\n", + "Some tools require runtime-only arguments (e.g., user ID or session context) that should not be controllable by the model.\n", + "\n", + "You can put these arguments in the [`state`](#read-state) or [`config`](#access-config) of the agent, and access\n", + "this information inside the tool:\n", + "\n", + "```python\n", + "from langchain_core.tools import tool\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langgraph.prebuilt import InjectedState\n", + "from langgraph.graph import MessagesState\n", + "\n", + "@tool\n", + "def my_tool(\n", + " # This will be populated by an LLM\n", + " tool_arg: str,\n", + " # access information that's dynamically updated inside the agent\n", + " # highlight-next-line\n", + " state: Annotated[MessagesState, InjectedState],\n", + " # access static data that is passed at agent invocation\n", + " # highlight-next-line\n", + " config: RunnableConfig,\n", + ") -> str:\n", + " \"\"\"My tool.\"\"\"\n", + " do_something_with_state(state[\"messages\"])\n", + " do_something_with_config(config)\n", + " ...\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access config\n", + "\n", + "You can provide static information to the graph at runtime, like a `user_id` or API credentials. This information can be accessed inside the tools through a special parameter **annotation** — `RunnableConfig`:\n", + "\n", + "```python\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langchain_core.tools import tool\n", + "\n", + "@tool\n", + "def get_user_info(\n", + " # highlight-next-line\n", + " config: RunnableConfig,\n", + ") -> str:\n", + " \"\"\"Look up user info.\"\"\"\n", + " # highlight-next-line\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", + "```\n", + "\n", + "??? example \"Access config in tools\"\n", + "\n", + " ```python\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain_core.tools import tool\n", + " from langgraph.prebuilt import create_react_agent\n", + " \n", + " def get_user_info(\n", + " # highlight-next-line\n", + " config: RunnableConfig,\n", + " ) -> str:\n", + " \"\"\"Look up user info.\"\"\"\n", + " # highlight-next-line\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", + " \n", + " agent = create_react_agent(\n", + " model=\"anthropic:claude-3-7-sonnet-latest\",\n", + " tools=[get_user_info],\n", + " )\n", + " \n", + " agent.invoke(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"look up user information\"}]},\n", + " # highlight-next-line\n", + " config={\"configurable\": {\"user_id\": \"user_123\"}}\n", + " )\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Short-term memory\n", + "\n", + "LangGraph allows agents to access and update their [short-term memory](../../concepts/memory#short-term-memory) (state) inside the tools." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Read state\n", + "\n", + "To access the graph state inside the tools, you can use a special parameter **annotation** — [`InjectedState`][langgraph.prebuilt.InjectedState]: \n", + "\n", + "```python\n", + "from typing import Annotated\n", + "from langchain_core.tools import tool\n", + "# highlight-next-line\n", + "from langgraph.prebuilt import InjectedState\n", + "\n", + "class CustomState(AgentState):\n", + " # highlight-next-line\n", + " user_id: str\n", + "\n", + "@tool\n", + "def get_user_info(\n", + " # highlight-next-line\n", + " state: Annotated[CustomState, InjectedState]\n", + ") -> str:\n", + " \"\"\"Look up user info.\"\"\"\n", + " # highlight-next-line\n", + " user_id = state[\"user_id\"]\n", + " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", + "```\n", + "\n", + "??? example \"Access state in tools\"\n", + "\n", + " ```python\n", + " from typing import Annotated\n", + " from langchain_core.tools import tool\n", + " from langgraph.prebuilt import InjectedState, create_react_agent\n", + " \n", + " class CustomState(AgentState):\n", + " # highlight-next-line\n", + " user_id: str\n", + "\n", + " @tool\n", + " def get_user_info(\n", + " # highlight-next-line\n", + " state: Annotated[CustomState, InjectedState]\n", + " ) -> str:\n", + " \"\"\"Look up user info.\"\"\"\n", + " # highlight-next-line\n", + " user_id = state[\"user_id\"]\n", + " return \"User is John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", + " \n", + " agent = create_react_agent(\n", + " model=\"anthropic:claude-3-7-sonnet-latest\",\n", + " tools=[get_user_info],\n", + " # highlight-next-line\n", + " state_schema=CustomState,\n", + " )\n", + " \n", + " agent.invoke({\n", + " \"messages\": \"look up user information\",\n", + " # highlight-next-line\n", + " \"user_id\": \"user_123\"\n", + " })\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Update state\n", + "\n", + "You can return state updates directly from the tools. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts.\n", + "\n", + "```python\n", + "from langgraph.graph import MessagesState\n", + "from langgraph.types import Command\n", + "from langchain_core.tools import tool, InjectedToolCallId\n", + "\n", + "class CustomState(MessagesState):\n", + " # highlight-next-line\n", + " user_name: str\n", + "\n", + "@tool\n", + "def update_user_info(\n", + " tool_call_id: Annotated[str, InjectedToolCallId],\n", + " config: RunnableConfig\n", + ") -> Command:\n", + " \"\"\"Look up and update user info.\"\"\"\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " name = \"John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", + " # highlight-next-line\n", + " return Command(update={\n", + " # highlight-next-line\n", + " \"user_name\": name,\n", + " # update the message history\n", + " \"messages\": [\n", + " ToolMessage(\n", + " \"Successfully looked up user information\",\n", + " tool_call_id=tool_call_id\n", + " )\n", + " ]\n", + " })\n", + "```\n", + "\n", + "??? example \"Update state from tools\"\n", + "\n", + " This is an example of using the prebuilt agent with a tool that can update graph state.\n", + "\n", + " ```python\n", + " from typing import Annotated\n", + " from langchain_core.tools import tool, InjectedToolCallId\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain_core.messages import ToolMessage\n", + " from langgraph.prebuilt import InjectedState, create_react_agent\n", + " from langgraph.prebuilt.chat_agent_executor import AgentState\n", + " from langgraph.types import Command\n", + " \n", + " class CustomState(AgentState):\n", + " # highlight-next-line\n", + " user_name: str\n", + "\n", + " @tool\n", + " def update_user_info(\n", + " tool_call_id: Annotated[str, InjectedToolCallId],\n", + " config: RunnableConfig\n", + " ) -> Command:\n", + " \"\"\"Look up and update user info.\"\"\"\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " name = \"John Smith\" if user_id == \"user_123\" else \"Unknown user\"\n", + " # highlight-next-line\n", + " return Command(update={\n", + " # highlight-next-line\n", + " \"user_name\": name,\n", + " # update the message history\n", + " \"messages\": [\n", + " ToolMessage(\n", + " \"Successfully looked up user information\",\n", + " tool_call_id=tool_call_id\n", + " )\n", + " ]\n", + " })\n", + " \n", + " def greet(\n", + " # highlight-next-line\n", + " state: Annotated[CustomState, InjectedState]\n", + " ) -> str:\n", + " \"\"\"Use this to greet the user once you found their info.\"\"\"\n", + " user_name = state[\"user_name\"]\n", + " return f\"Hello {user_name}!\"\n", + " \n", + " agent = create_react_agent(\n", + " model=\"anthropic:claude-3-7-sonnet-latest\",\n", + " tools=[get_user_info, greet],\n", + " # highlight-next-line\n", + " state_schema=CustomState\n", + " )\n", + " \n", + " agent.invoke(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"greet the user\"}]},\n", + " # highlight-next-line\n", + " config={\"configurable\": {\"user_id\": \"user_123\"}}\n", + " )\n", + " ```\n", + "\n", + "!!! important\n", + "\n", + " If you want to use tools that return `Command` and update graph state, you can either use prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] components, or implement your own tool-executing node that collects `Command` objects returned by the tools and returns a list of them, e.g.:\n", + " \n", + " ```python\n", + " def call_tools(state):\n", + " ...\n", + " commands = [tools_by_name[tool_call[\"name\"]].invoke(tool_call) for tool_call in tool_calls]\n", + " return commands\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Long-term memory\n", + "\n", + "Use [long-term memory](../../concepts/memory#long-term-memory) to store user-specific or application-specific data across conversations. This is useful for applications like chatbots, where you want to remember user preferences or other information.\n", + "\n", + "To use long-term memory, you need to:\n", + "\n", + "1. [Configure a store](../persistence#add-long-term-memory) to persist data across invocations.\n", + "2. Use the [`get_store`][langgraph.config.get_store] function to access the store from within tools or prompts.\n", + "\n", + "### Read\n", + "\n", + "```python\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langchain_core.tools import tool\n", + "from langgraph.graph import StateGraph\n", + "# highlight-next-line\n", + "from langgraph.config import get_store\n", + "\n", + "@tool\n", + "def get_user_info(config: RunnableConfig) -> str:\n", + " \"\"\"Look up user info.\"\"\"\n", + " # Same as that provided to `builder.compile(store=store)` \n", + " # or `create_react_agent`\n", + " # highlight-next-line\n", + " store = get_store()\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " # highlight-next-line\n", + " user_info = store.get((\"users\",), user_id)\n", + " return str(user_info.value) if user_info else \"Unknown user\"\n", + "\n", + "builder = StateGraph(...)\n", + "...\n", + "graph = builder.compile(store=store)\n", + "```\n", + "\n", + "??? example \"Access long-term memory\"\n", + "\n", + " ```python\n", + " from langchain_core.runnables import RunnableConfig\n", + " from langchain_core.tools import tool\n", + " from langgraph.config import get_store\n", + " from langgraph.prebuilt import create_react_agent\n", + " from langgraph.store.memory import InMemoryStore\n", + " \n", + " # highlight-next-line\n", + " store = InMemoryStore() # (1)!\n", + " \n", + " # highlight-next-line\n", + " store.put( # (2)!\n", + " (\"users\",), # (3)!\n", + " \"user_123\", # (4)!\n", + " {\n", + " \"name\": \"John Smith\",\n", + " \"language\": \"English\",\n", + " } # (5)!\n", + " )\n", + "\n", + " @tool\n", + " def get_user_info(config: RunnableConfig) -> str:\n", + " \"\"\"Look up user info.\"\"\"\n", + " # Same as that provided to `create_react_agent`\n", + " # highlight-next-line\n", + " store = get_store() # (6)!\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " # highlight-next-line\n", + " user_info = store.get((\"users\",), user_id) # (7)!\n", + " return str(user_info.value) if user_info else \"Unknown user\"\n", + " \n", + " agent = create_react_agent(\n", + " model=\"anthropic:claude-3-7-sonnet-latest\",\n", + " tools=[get_user_info],\n", + " # highlight-next-line\n", + " store=store # (8)!\n", + " )\n", + " \n", + " # Run the agent\n", + " agent.invoke(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"look up user information\"}]},\n", + " # highlight-next-line\n", + " config={\"configurable\": {\"user_id\": \"user_123\"}}\n", + " )\n", + " ```\n", + " \n", + " 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation](../reference/store.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you.\n", + " 2. For this example, we write some sample data to the store using the `put` method. Please see the [BaseStore.put][langgraph.store.base.BaseStore.put] API reference for more details.\n", + " 3. The first argument is the namespace. This is used to group related data together. In this case, we are using the `users` namespace to group user data.\n", + " 4. A key within the namespace. This example uses a user ID for the key.\n", + " 5. The data that we want to store for the given user.\n", + " 6. The `get_store` function is used to access the store. You can call it from anywhere in your code, including tools and prompts. This function returns the store that was passed to the agent when it was created.\n", + " 7. The `get` method is used to retrieve data from the store. The first argument is the namespace, and the second argument is the key. This will return a `StoreValue` object, which contains the value and metadata about the value.\n", + " 8. The `store` is passed to the agent. This enables the agent to access the store when running tools. You can also use the `get_store` function to access the store from anywhere in your code." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Update\n", + "\n", + "```python\n", + "from langchain_core.runnables import RunnableConfig\n", + "from langchain_core.tools import tool\n", + "from langgraph.graph import StateGraph\n", + "# highlight-next-line\n", + "from langgraph.config import get_store\n", + "\n", + "@tool\n", + "def save_user_info(user_info: str, config: RunnableConfig) -> str:\n", + " \"\"\"Save user info.\"\"\"\n", + " # Same as that provided to `builder.compile(store=store)` \n", + " # or `create_react_agent`\n", + " # highlight-next-line\n", + " store = get_store()\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " # highlight-next-line\n", + " store.put((\"users\",), user_id, user_info)\n", + " return \"Successfully saved user info.\"\n", + "\n", + "builder = StateGraph(...)\n", + "...\n", + "graph = builder.compile(store=store)\n", + "```\n", + "\n", + "??? example \"Update long-term memory\"\n", + "\n", + " ```python\n", + " from typing_extensions import TypedDict\n", + "\n", + " from langchain_core.tools import tool\n", + " from langgraph.config import get_store\n", + " from langgraph.prebuilt import create_react_agent\n", + " from langgraph.store.memory import InMemoryStore\n", + " \n", + " store = InMemoryStore() # (1)!\n", + " \n", + " class UserInfo(TypedDict): # (2)!\n", + " name: str\n", + "\n", + " @tool\n", + " def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: # (3)!\n", + " \"\"\"Save user info.\"\"\"\n", + " # Same as that provided to `create_react_agent`\n", + " # highlight-next-line\n", + " store = get_store() # (4)!\n", + " user_id = config[\"configurable\"].get(\"user_id\")\n", + " # highlight-next-line\n", + " store.put((\"users\",), user_id, user_info) # (5)!\n", + " return \"Successfully saved user info.\"\n", + " \n", + " agent = create_react_agent(\n", + " model=\"anthropic:claude-3-7-sonnet-latest\",\n", + " tools=[save_user_info],\n", + " # highlight-next-line\n", + " store=store\n", + " )\n", + " \n", + " # Run the agent\n", + " agent.invoke(\n", + " {\"messages\": [{\"role\": \"user\", \"content\": \"My name is John Smith\"}]},\n", + " # highlight-next-line\n", + " config={\"configurable\": {\"user_id\": \"user_123\"}} # (6)!\n", + " )\n", + " \n", + " # You can access the store directly to get the value\n", + " store.get((\"users\",), \"user_123\").value\n", + " ```\n", + " \n", + " 1. The `InMemoryStore` is a store that stores data in memory. In a production setting, you would typically use a database or other persistent storage. Please review the [store documentation](../reference/store.md) for more options. If you're deploying with **LangGraph Platform**, the platform will provide a production-ready store for you.\n", + " 2. The `UserInfo` class is a `TypedDict` that defines the structure of the user information. The LLM will use this to format the response according to the schema.\n", + " 3. The `save_user_info` function is a tool that allows an agent to update user information. This could be useful for a chat application where the user wants to update their profile information.\n", + " 4. The `get_store` function is used to access the store. You can call it from anywhere in your code, including tools and prompts. This function returns the store that was passed to the agent when it was created.\n", + " 5. The `put` method is used to store data in the store. The first argument is the namespace, and the second argument is the key. This will store the user information in the store.\n", + " 6. The `user_id` is passed in the config. This is used to identify the user whose information is being updated." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "ToolMessage(content='294', name='multiply', tool_call_id='1')" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "@tool\n", - "def get_weather(location: str):\n", - " \"\"\"Call to get the current weather.\"\"\"\n", - " if location.lower() in [\"sf\", \"san francisco\"]:\n", - " return \"It's 60 degrees and foggy.\"\n", - " else:\n", - " return \"It's 90 degrees and sunny.\"\n", + "from langchain_core.tools import tool\n", "\n", "\n", "@tool\n", - "def get_coolest_cities():\n", - " \"\"\"Get a list of coolest cities\"\"\"\n", - " return \"nyc, sf\"" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "tools = [get_weather, get_coolest_cities]\n", - "tool_node = ToolNode(tools)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Manually call `ToolNode`" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`ToolNode` operates on graph state with a list of messages. It expects the last message in the list to be an `AIMessage` with `tool_calls` parameter. \n", - "\n", - "Let's first see how to invoke the tool node manually:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='tool_call_id')]}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "message_with_single_tool_call = AIMessage(\n", - " content=\"\",\n", - " tool_calls=[\n", - " {\n", - " \"name\": \"get_weather\",\n", - " \"args\": {\"location\": \"sf\"},\n", - " \"id\": \"tool_call_id\",\n", - " \"type\": \"tool_call\",\n", - " }\n", - " ],\n", - ")\n", - "\n", - "tool_node.invoke({\"messages\": [message_with_single_tool_call]})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that typically you don't need to create `AIMessage` manually, and it will be automatically generated by any LangChain chat model that supports tool calling.\n", - "\n", - "You can also do parallel tool calling using `ToolNode` if you pass multiple tool calls to `AIMessage`'s `tool_calls` parameter:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [ToolMessage(content='nyc, sf', name='get_coolest_cities', tool_call_id='tool_call_id_1'),\n", - " ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='tool_call_id_2')]}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "message_with_multiple_tool_calls = AIMessage(\n", - " content=\"\",\n", - " tool_calls=[\n", - " {\n", - " \"name\": \"get_coolest_cities\",\n", - " \"args\": {},\n", - " \"id\": \"tool_call_id_1\",\n", - " \"type\": \"tool_call\",\n", - " },\n", - " {\n", - " \"name\": \"get_weather\",\n", - " \"args\": {\"location\": \"sf\"},\n", - " \"id\": \"tool_call_id_2\",\n", - " \"type\": \"tool_call\",\n", - " },\n", - " ],\n", - ")\n", - "\n", - "tool_node.invoke({\"messages\": [message_with_multiple_tool_calls]})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Using with chat models" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll be using a small chat model from Anthropic in our example. To use chat models with tool calling, we need to first ensure that the model is aware of the available tools. We do this by calling `.bind_tools` method on `ChatAnthropic` model" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", - "\n", - "from langchain_anthropic import ChatAnthropic\n", - "from langgraph.graph import StateGraph, MessagesState\n", - "from langgraph.prebuilt import ToolNode\n", + "def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", "\n", "\n", - "model_with_tools = ChatAnthropic(\n", - " model=\"claude-3-haiku-20240307\", temperature=0\n", - ").bind_tools(tools)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'name': 'get_weather',\n", - " 'args': {'location': 'San Francisco'},\n", - " 'id': 'toolu_01Fwm7dg1mcJU43Fkx2pqgm8',\n", - " 'type': 'tool_call'}]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model_with_tools.invoke(\"what's the weather in sf?\").tool_calls" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you can see, the AI message generated by the chat model already has `tool_calls` populated, so we can just pass it directly to `ToolNode`" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'messages': [ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='toolu_01LFvAVT3xJMeZS6kbWwBGZK')]}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tool_node.invoke({\"messages\": [model_with_tools.invoke(\"what's the weather in sf?\")]})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ReAct Agent" + "multiply.invoke({\"type\": \"tool_call\", \"id\": \"1\", \"args\": {\"a\": 42, \"b\": 7}})" ] }, { @@ -300,190 +564,488 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's see how to use `ToolNode` inside a LangGraph graph. Let's set up a graph implementation of the [ReAct agent](https://langchain-ai.github.io/langgraph/concepts/agentic_concepts/#react-agent). This agent takes some query as input, then repeatedly call tools until it has enough information to resolve the query. We'll be using `ToolNode` and the Anthropic model with tools we just defined" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Literal\n", + "## Attach tools to a model\n", "\n", - "from langgraph.graph import StateGraph, MessagesState, START, END\n", + "To attach tool schemas to a [chat model](https://python.langchain.com/docs/concepts/chat_models) you need to use `model.bind_tools()`:\n", "\n", + "```python\n", + "from langchain_core.tools import tool\n", + "from langchain.chat_models import init_chat_model\n", "\n", - "def should_continue(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " last_message = messages[-1]\n", - " if last_message.tool_calls:\n", - " return \"tools\"\n", - " return END\n", + "@tool\n", + "def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", "\n", + "model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", + "# highlight-next-line\n", + "model_with_tools = model.bind_tools([multiply])\n", "\n", - "def call_model(state: MessagesState):\n", - " messages = state[\"messages\"]\n", - " response = model_with_tools.invoke(messages)\n", - " return {\"messages\": [response]}\n", + "model_with_tools.invoke(\"what's 42 x 7?\")\n", + "```\n", "\n", - "\n", - "workflow = StateGraph(MessagesState)\n", - "\n", - "# Define the two nodes we will cycle between\n", - "workflow.add_node(\"agent\", call_model)\n", - "workflow.add_node(\"tools\", tool_node)\n", - "\n", - "workflow.add_edge(START, \"agent\")\n", - "workflow.add_conditional_edges(\"agent\", should_continue, [\"tools\", END])\n", - "workflow.add_edge(\"tools\", \"agent\")\n", - "\n", - "app = workflow.compile()" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(app.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" + "```\n", + "AIMessage(\n", + " content=[{'text': \"I'll help you calculate that by using the multiply function.\", 'type': 'text'}, {'id': 'toolu_01GhULkqytMTFDsNv6FsXy3Y', 'input': {'a': 42, 'b': 7}, 'name': 'multiply', 'type': 'tool_use'}]\n", + " tool_calls=[{'name': 'multiply', 'args': {'a': 42, 'b': 7}, 'id': 'toolu_01GhULkqytMTFDsNv6FsXy3Y', 'type': 'tool_call'}]\n", + ")\n", + "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let's try it out!" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in sf?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Okay, let's check the weather in San Francisco:\", 'type': 'text'}, {'id': 'toolu_01LdmBXYeccWKdPrhZSwFCDX', 'input': {'location': 'San Francisco'}, 'name': 'get_weather', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " get_weather (toolu_01LdmBXYeccWKdPrhZSwFCDX)\n", - " Call ID: toolu_01LdmBXYeccWKdPrhZSwFCDX\n", - " Args:\n", - " location: San Francisco\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's 60 degrees and foggy.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "The weather in San Francisco is currently 60 degrees with foggy conditions.\n" - ] - } - ], - "source": [ - "# example with a single tool call\n", - "for chunk in app.stream(\n", - " {\"messages\": [(\"human\", \"what's the weather in sf?\")]}, stream_mode=\"values\"\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "what's the weather in the coolest cities?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Okay, let's find out the weather in the coolest cities:\", 'type': 'text'}, {'id': 'toolu_01LFZUWTccyveBdaSAisMi95', 'input': {}, 'name': 'get_coolest_cities', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " get_coolest_cities (toolu_01LFZUWTccyveBdaSAisMi95)\n", - " Call ID: toolu_01LFZUWTccyveBdaSAisMi95\n", - " Args:\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_coolest_cities\n", - "\n", - "nyc, sf\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Now let's get the weather for those cities:\", 'type': 'text'}, {'id': 'toolu_01RHPQBhT1u6eDnPqqkGUpsV', 'input': {'location': 'nyc'}, 'name': 'get_weather', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " get_weather (toolu_01RHPQBhT1u6eDnPqqkGUpsV)\n", - " Call ID: toolu_01RHPQBhT1u6eDnPqqkGUpsV\n", - " Args:\n", - " location: nyc\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's 90 degrees and sunny.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'id': 'toolu_01W5sFGF8PfgYzdY4CqT5c6e', 'input': {'location': 'sf'}, 'name': 'get_weather', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " get_weather (toolu_01W5sFGF8PfgYzdY4CqT5c6e)\n", - " Call ID: toolu_01W5sFGF8PfgYzdY4CqT5c6e\n", - " Args:\n", - " location: sf\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: get_weather\n", - "\n", - "It's 60 degrees and foggy.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Based on the results, it looks like the weather in the coolest cities is:\n", - "- New York City: 90 degrees and sunny\n", - "- San Francisco: 60 degrees and foggy\n", - "\n", - "So the weather in the coolest cities is a mix of warm and cool temperatures, with some sunny and some foggy conditions.\n" - ] - } - ], - "source": [ - "# example with a multiple tool calls in succession\n", + "## Use tools\n", "\n", - "for chunk in app.stream(\n", - " {\"messages\": [(\"human\", \"what's the weather in the coolest cities?\")]},\n", - " stream_mode=\"values\",\n", - "):\n", - " chunk[\"messages\"][-1].pretty_print()" + "LangChain tools conform to the [Runnable interface](https://python.langchain.com/docs/concepts/runnables/), which means that you can execute them using `.invoke()` / `.ainvoke()` methods:\n", + "\n", + "```python\n", + "from langchain_core.tools import tool\n", + "\n", + "@tool\n", + "def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", + "\n", + "# highlight-next-line\n", + "multiply.invoke({\"a\": 42, \"b\": 7})\n", + "```\n", + "\n", + "```\n", + "294\n", + "```\n", + "\n", + "If you want the tool to return a [ToolMessage](https://python.langchain.com/docs/concepts/messages/#toolmessage), invoke it with the tool call:\n", + "\n", + "```python\n", + "tool_call = {\n", + " \"type\": \"tool_call\",\n", + " \"id\": \"1\",\n", + " \"args\": {\"a\": 42, \"b\": 7}\n", + "}\n", + "multiply.invoke(tool_call)\n", + "```\n", + "\n", + "```\n", + "ToolMessage(content='294', name='multiply', tool_call_id='1')\n", + "```\n", + "\n", + "??? example \"Use with a chat model\"\n", + "\n", + " ```python\n", + " from langchain_core.tools import tool\n", + " from langchain.chat_models import init_chat_model\n", + " \n", + " @tool\n", + " def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", + " \n", + " model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", + " # highlight-next-line\n", + " model_with_tools = model.bind_tools([multiply])\n", + " \n", + " response_message = model_with_tools.invoke(\"what's 42 x 7?\")\n", + " tool_call = response_message.tool_calls[0]\n", + "\n", + " # highlight-next-line\n", + " multiply.invoke(tool_call)\n", + " ```\n", + "\n", + " ```\n", + " ToolMessage(content='294', name='multiply', tool_call_id='toolu_0176DV4YKSD8FndkeuuLj36c')\n", + " ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "`ToolNode` can also handle errors during tool execution. You can enable / disable this by setting `handle_tool_errors=True` (enabled by default). See our guide on handling errors in `ToolNode` [here](https://langchain-ai.github.io/langgraph/how-tos/tool-calling-errors/)" + "## Use prebuilt agent\n", + "\n", + "To create a tool-calling agent, you can use the prebuilt [create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent]\n", + "\n", + "```python\n", + "from langchain_core.tools import tool\n", + "# highlight-next-line\n", + "from langgraph.prebuilt import create_react_agent\n", + "\n", + "@tool\n", + "def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " return a * b\n", + "\n", + "# highlight-next-line\n", + "agent = create_react_agent(\n", + " model=\"anthropic:claude-3-7-sonnet\",\n", + " tools=[multiply]\n", + ")\n", + "graph.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"what's 42 x 7?\"}]})\n", + "```\n", + "\n", + "See this [guide](../../agents/overview) to learn more." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Use prebuilt `ToolNode`\n", + "\n", + "[`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] is a prebuilt LangGraph [node](../../concepts/low_level#nodes) for executing tool calls.\n", + "\n", + "**Why use `ToolNode`?**\n", + "\n", + "* support for both sync and async tools\n", + "* concurrent execution of the tools\n", + "* error handling during tool execution. You can enable / disable this by setting `handle_tool_errors=True` (enabled by default). See [this section](#handle-errors) for more details on handling errors\n", + "\n", + "ToolNode operates on [MessagesState](../../concepts/low_level#messagesstate):\n", + "\n", + "* input: `MessagesState` where the last message is an `AIMessage` with `tool_calls` parameter\n", + "* output: `MessagesState` with [`ToolMessage`](https://python.langchain.com/docs/concepts/messages/#toolmessage) the result of tool calls\n", + "\n", + "!!! tip\n", + "\n", + " `ToolNode` is designed to work well out-of-box with LangGraph's prebuilt [agent](../../agents/agents), but can also work with any `StateGraph` that uses `MessagesState.`\n", + "\n", + "```python\n", + "# highlight-next-line\n", + "from langgraph.prebuilt import ToolNode\n", + "\n", + "def get_weather(location: str):\n", + " \"\"\"Call to get the current weather.\"\"\"\n", + " if location.lower() in [\"sf\", \"san francisco\"]:\n", + " return \"It's 60 degrees and foggy.\"\n", + " else:\n", + " return \"It's 90 degrees and sunny.\"\n", + "\n", + "def get_coolest_cities():\n", + " \"\"\"Get a list of coolest cities\"\"\"\n", + " return \"nyc, sf\"\n", + "\n", + "# highlight-next-line\n", + "tool_node = ToolNode([get_weather, get_coolest_cities])\n", + "tool_node.invoke({\"messages\": [...]})\n", + "```\n", + "\n", + "??? example \"Single tool call\"\n", + "\n", + " ```python\n", + " from langchain_core.messages import AIMessage\n", + " from langgraph.prebuilt import ToolNode\n", + " \n", + " # Define tools\n", + " @tool\n", + " def get_weather(location: str):\n", + " \"\"\"Call to get the current weather.\"\"\"\n", + " if location.lower() in [\"sf\", \"san francisco\"]:\n", + " return \"It's 60 degrees and foggy.\"\n", + " else:\n", + " return \"It's 90 degrees and sunny.\"\n", + " \n", + " # highlight-next-line\n", + " tool_node = ToolNode([get_weather])\n", + " \n", + " message_with_single_tool_call = AIMessage(\n", + " content=\"\",\n", + " tool_calls=[\n", + " {\n", + " \"name\": \"get_weather\",\n", + " \"args\": {\"location\": \"sf\"},\n", + " \"id\": \"tool_call_id\",\n", + " \"type\": \"tool_call\",\n", + " }\n", + " ],\n", + " )\n", + " \n", + " tool_node.invoke({\"messages\": [message_with_single_tool_call]})\n", + " ```\n", + " \n", + " ```\n", + " {'messages': [ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='tool_call_id')]}\n", + " ```\n", + "\n", + "??? example \"Multiple tool calls\"\n", + "\n", + " ```python\n", + " from langchain_core.messages import AIMessage\n", + " from langgraph.prebuilt import ToolNode\n", + " \n", + " # Define tools\n", + " \n", + " def get_weather(location: str):\n", + " \"\"\"Call to get the current weather.\"\"\"\n", + " if location.lower() in [\"sf\", \"san francisco\"]:\n", + " return \"It's 60 degrees and foggy.\"\n", + " else:\n", + " return \"It's 90 degrees and sunny.\"\n", + " \n", + " def get_coolest_cities():\n", + " \"\"\"Get a list of coolest cities\"\"\"\n", + " return \"nyc, sf\"\n", + " \n", + " # highlight-next-line\n", + " tool_node = ToolNode([get_weather, get_coolest_cities])\n", + "\n", + " message_with_multiple_tool_calls = AIMessage(\n", + " content=\"\",\n", + " tool_calls=[\n", + " {\n", + " \"name\": \"get_coolest_cities\",\n", + " \"args\": {},\n", + " \"id\": \"tool_call_id_1\",\n", + " \"type\": \"tool_call\",\n", + " },\n", + " {\n", + " \"name\": \"get_weather\",\n", + " \"args\": {\"location\": \"sf\"},\n", + " \"id\": \"tool_call_id_2\",\n", + " \"type\": \"tool_call\",\n", + " },\n", + " ],\n", + " )\n", + "\n", + " # highlight-next-line\n", + " tool_node.invoke({\"messages\": [message_with_multiple_tool_calls]}) # (1)!\n", + " ```\n", + "\n", + " 1. `ToolNode` will execute both tools in parallel\n", + "\n", + " ```\n", + " {\n", + " 'messages': [\n", + " ToolMessage(content='nyc, sf', name='get_coolest_cities', tool_call_id='tool_call_id_1'),\n", + " ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='tool_call_id_2')\n", + " ]\n", + " }\n", + " ```\n", + "\n", + " \n", + "\n", + "??? example \"Use with a chat model\"\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.prebuilt import ToolNode\n", + " \n", + " def get_weather(location: str):\n", + " \"\"\"Call to get the current weather.\"\"\"\n", + " if location.lower() in [\"sf\", \"san francisco\"]:\n", + " return \"It's 60 degrees and foggy.\"\n", + " else:\n", + " return \"It's 90 degrees and sunny.\"\n", + " \n", + " # highlight-next-line\n", + " tool_node = ToolNode([get_weather])\n", + " \n", + " model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", + " # highlight-next-line\n", + " model_with_tools = model.bind_tools([get_weather]) # (1)!\n", + " \n", + " \n", + " # highlight-next-line\n", + " response_message = model_with_tools.invoke(\"what's the weather in sf?\")\n", + " tool_node.invoke({\"messages\": [response_message]})\n", + " ```\n", + "\n", + " 1. Use `.bind_tools()` to attach the tool schema to the chat model\n", + "\n", + " ```\n", + " {'messages': [ToolMessage(content=\"It's 60 degrees and foggy.\", name='get_weather', tool_call_id='toolu_01Pnkgw5JeTRxXAU7tyHT4UW')]}\n", + " ```\n", + "\n", + "??? example \"Use in a tool-calling agent\"\n", + "\n", + " This is an example of creating a tool-calling agent from scratch using `ToolNode`. You can also use LangGraph's prebuilt [agent](../../agents/agents).\n", + "\n", + " ```python\n", + " from langchain.chat_models import init_chat_model\n", + " from langgraph.prebuilt import ToolNode\n", + " from langgraph.graph import StateGraph, MessagesState, START, END\n", + " \n", + " def get_weather(location: str):\n", + " \"\"\"Call to get the current weather.\"\"\"\n", + " if location.lower() in [\"sf\", \"san francisco\"]:\n", + " return \"It's 60 degrees and foggy.\"\n", + " else:\n", + " return \"It's 90 degrees and sunny.\"\n", + " \n", + " # highlight-next-line\n", + " tool_node = ToolNode([get_weather])\n", + " \n", + " model = init_chat_model(model=\"claude-3-5-haiku-latest\")\n", + " # highlight-next-line\n", + " model_with_tools = model.bind_tools([get_weather])\n", + " \n", + " def should_continue(state: MessagesState):\n", + " messages = state[\"messages\"]\n", + " last_message = messages[-1]\n", + " if last_message.tool_calls:\n", + " return \"tools\"\n", + " return END\n", + " \n", + " def call_model(state: MessagesState):\n", + " messages = state[\"messages\"]\n", + " response = model_with_tools.invoke(messages)\n", + " return {\"messages\": [response]}\n", + " \n", + " builder = StateGraph(MessagesState)\n", + " \n", + " # Define the two nodes we will cycle between\n", + " builder.add_node(\"call_model\", call_model)\n", + " # highlight-next-line\n", + " builder.add_node(\"tools\", tool_node)\n", + " \n", + " builder.add_edge(START, \"call_model\")\n", + " builder.add_conditional_edges(\"call_model\", should_continue, [\"tools\", END])\n", + " builder.add_edge(\"tools\", \"call_model\")\n", + " \n", + " graph = builder.compile()\n", + " \n", + " graph.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"what's the weather in sf?\"}]})\n", + " ```\n", + " \n", + " ```\n", + " {\n", + " 'messages': [\n", + " HumanMessage(content=\"what's the weather in sf?\"),\n", + " AIMessage(\n", + " content=[{'text': \"I'll help you check the weather in San Francisco right now.\", 'type': 'text'}, {'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'input': {'location': 'San Francisco'}, 'name': 'get_weather', 'type': 'tool_use'}],\n", + " tool_calls=[{'name': 'get_weather', 'args': {'location': 'San Francisco'}, 'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'type': 'tool_call'}]\n", + " ),\n", + " ToolMessage(content=\"It's 60 degrees and foggy.\"),\n", + " AIMessage(content=\"The current weather in San Francisco is 60 degrees and foggy. Typical San Francisco weather with its famous marine layer!\")\n", + " ]\n", + " }\n", + " ```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Handle errors\n", + "\n", + "By default, the `ToolNode` will catch all exceptions raised during tool calls and will return those as tool messages. To control how the errors are handled, you can use `ToolNode`'s `handle_tool_errors` parameter:\n", + "\n", + "=== \"Enable error handling (default)\"\n", + "\n", + " ```python\n", + " from langchain_core.messages import AIMessage\n", + " from langgraph.prebuilt import ToolNode\n", + " \n", + " def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " if a == 42:\n", + " raise ValueError(\"The ultimate error\")\n", + " return a * b\n", + " \n", + " tool_node = ToolNode([multiply])\n", + " \n", + " # Run with error handling (default)\n", + " message = AIMessage(\n", + " content=\"\",\n", + " tool_calls=[\n", + " {\n", + " \"name\": \"multiply\",\n", + " \"args\": {\"a\": 42, \"b\": 7},\n", + " \"id\": \"tool_call_id\",\n", + " \"type\": \"tool_call\",\n", + " }\n", + " ],\n", + " )\n", + " \n", + " tool_node.invoke({\"messages\": [message]})\n", + " ```\n", + "\n", + " ```\n", + " {'messages': [ToolMessage(content=\"Error: ValueError('The ultimate error')\\n Please fix your mistakes.\", name='multiply', tool_call_id='tool_call_id', status='error')]}\n", + " ```\n", + "\n", + "=== \"Disable error handling\"\n", + "\n", + " ```python\n", + " from langchain_core.messages import AIMessage\n", + " from langgraph.prebuilt import ToolNode\n", + "\n", + " def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " if a == 42:\n", + " raise ValueError(\"The ultimate error\")\n", + " return a * b\n", + "\n", + " tool_node = ToolNode(\n", + " [multiply],\n", + " # highlight-next-line\n", + " handle_tool_errors=False # (1)!\n", + " )\n", + " message = AIMessage(\n", + " content=\"\",\n", + " tool_calls=[\n", + " {\n", + " \"name\": \"multiply\",\n", + " \"args\": {\"a\": 42, \"b\": 7},\n", + " \"id\": \"tool_call_id\",\n", + " \"type\": \"tool_call\",\n", + " }\n", + " ],\n", + " )\n", + " tool_node.invoke({\"messages\": [message]})\n", + " ```\n", + "\n", + " 1. This disables error handling (enabled by default). See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].\n", + "\n", + "=== \"Custom error handling\"\n", + "\n", + " ```python\n", + " from langchain_core.messages import AIMessage\n", + " from langgraph.prebuilt import ToolNode\n", + "\n", + " def multiply(a: int, b: int) -> int:\n", + " \"\"\"Multiply two numbers.\"\"\"\n", + " if a == 42:\n", + " raise ValueError(\"The ultimate error\")\n", + " return a * b\n", + "\n", + " # highlight-next-line\n", + " tool_node = ToolNode(\n", + " [multiply],\n", + " # highlight-next-line\n", + " handle_tool_errors=(\n", + " \"Can't use 42 as a first operand, you must switch operands!\" # (1)!\n", + " )\n", + " )\n", + " tool_node.invoke({\"messages\": [message]})\n", + " ```\n", + "\n", + " 1. This provides a custom message to send to the LLM in case of an exception. See all available strategies in the [API reference][langgraph.prebuilt.tool_node.ToolNode].\n", + "\n", + " ```\n", + " {'messages': [ToolMessage(content=\"Can't use 42 as a first operand, you must switch operands!\", name='multiply', tool_call_id='tool_call_id', status='error')]}\n", + " ```\n", + "\n", + "See [API reference][langgraph.prebuilt.tool_node.ToolNode] for more information on different tool error handling options." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Handle large numbers of tools" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the number of available tools grows, you may want to limit the scope of the LLM's selection, to decrease token consumption and to help manage sources of error in LLM reasoning.\n", + "\n", + "To address this, you can dynamically adjust the tools available to a model by retrieving relevant tools at runtime using semantic search.\n", + "\n", + "See [`langgraph-bigtool`](https://github.com/langchain-ai/langgraph-bigtool) prebuilt library for a ready-to-use implementation and this [how-to guide](../many-tools) for more details." ] } ], @@ -503,7 +1065,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/docs/docs/how-tos/ttl/configure_ttl.md b/docs/docs/how-tos/ttl/configure_ttl.md index de431946c..a5f1e0b05 100644 --- a/docs/docs/how-tos/ttl/configure_ttl.md +++ b/docs/docs/how-tos/ttl/configure_ttl.md @@ -2,7 +2,7 @@ !!! tip "Prerequisites" - This guide assumes familiarity with the [LangGraph Platform](../../concepts/index.md#langgraph-platform), [Persistence](../../concepts/persistence.md), and [Cross-thread persistence](../../concepts/persistence.md#memory-store) concepts. + This guide assumes familiarity with the [LangGraph Platform](../../concepts/langgraph_platform.md), [Persistence](../../concepts/persistence.md), and [Cross-thread persistence](../../concepts/persistence.md#memory-store) concepts. ???+ note "LangGraph platform only" diff --git a/docs/docs/how-tos/update-state-from-tools.ipynb b/docs/docs/how-tos/update-state-from-tools.ipynb deleted file mode 100644 index 1aea00556..000000000 --- a/docs/docs/how-tos/update-state-from-tools.ipynb +++ /dev/null @@ -1,381 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "7c58c957-83d8-44ff-8580-a9b3dd39a0a9", - "metadata": {}, - "source": [ - "# How to update graph state from tools" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "95f30587-8dd2-40be-920d-59539089c09f", - "metadata": {}, - "source": [ - "!!! info \"Prerequisites\"\n", - " This guide assumes familiarity with the following:\n", - " \n", - " - [Command](../../concepts/low_level/#command)\n", - "\n", - "A common use case is updating graph state from inside a tool. For example, in a customer support application you might want to look up customer account number or ID in the beginning of the conversation. To update the graph state from the tool, you can return `Command(update={\"my_custom_key\": \"foo\", \"messages\": [...]})` from the tool:\n", - "\n", - "```python\n", - "@tool\n", - "def lookup_user_info(tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig):\n", - " \"\"\"Use this to look up user information to better assist them with their questions.\"\"\"\n", - " user_info = get_user_info(config)\n", - " return Command(\n", - " update={\n", - " # update the state keys\n", - " \"user_info\": user_info,\n", - " # update the message history\n", - " \"messages\": [ToolMessage(\"Successfully looked up user information\", tool_call_id=tool_call_id)]\n", - " }\n", - " )\n", - "```\n", - "\n", - "!!! important\n", - "\n", - " If you want to use tools that return `Command` and update graph state, you can either use prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] components, or implement your own tool-executing node that collects `Command` objects returned by the tools and returns a list of them, e.g.:\n", - " \n", - " ```python\n", - " def call_tools(state):\n", - " ...\n", - " commands = [tools_by_name[tool_call[\"name\"]].invoke(tool_call) for tool_call in tool_calls]\n", - " return commands\n", - " ```\n", - "\n", - "This guide shows how you can do this using LangGraph's prebuilt components ([`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode]).\n", - "\n", - "!!! note\n", - "\n", - " Support for tools that return [`Command`][langgraph.types.Command] was added in LangGraph `v0.2.59`.\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages and set our API keys:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "64500eca-1cdc-43d9-9401-f4cd9999881f", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langchain-openai" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "a3f92fb2-9175-47fa-9c7d-ad5f44bfd20e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Please provide your OPENAI_API_KEY ········\n" - ] - } - ], - "source": [ - "import os\n", - "import getpass\n", - "\n", - "\n", - "def _set_if_undefined(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"Please provide your {var}\")\n", - "\n", - "\n", - "_set_if_undefined(\"OPENAI_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "caf6ff9f-c1e6-499e-a230-9fa231ea7d2f", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "10e9a9c6-fa3f-416c-bac0-3e58d7259908", - "metadata": {}, - "source": [ - "Let's create a simple ReAct style agent that can look up user information and personalize the response based on the user info." - ] - }, - { - "cell_type": "markdown", - "id": "4255b9b9-cf67-4cc3-8018-1708f5dfcfd2", - "metadata": {}, - "source": [ - "## Define tool" - ] - }, - { - "cell_type": "markdown", - "id": "7de6b010-aab1-4fe8-8251-907fcae78583", - "metadata": {}, - "source": [ - "First, let's define the tool that we'll be using to look up user information. We'll use a naive implementation that simply looks user information up using a dictionary:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8d070c9f-6e61-4724-85dc-ac4531b9c79a", - "metadata": {}, - "outputs": [], - "source": [ - "USER_INFO = [\n", - " {\"user_id\": \"1\", \"name\": \"Bob Dylan\", \"location\": \"New York, NY\"},\n", - " {\"user_id\": \"2\", \"name\": \"Taylor Swift\", \"location\": \"Beverly Hills, CA\"},\n", - "]\n", - "\n", - "USER_ID_TO_USER_INFO = {info[\"user_id\"]: info for info in USER_INFO}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "08d1ecca-ee57-4e97-b8d0-e09de85337d4", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.prebuilt.chat_agent_executor import AgentState\n", - "from langgraph.types import Command\n", - "from langchain_core.tools import tool\n", - "from langchain_core.tools.base import InjectedToolCallId\n", - "from langchain_core.messages import ToolMessage\n", - "from langchain_core.runnables import RunnableConfig\n", - "\n", - "from typing_extensions import Any, Annotated\n", - "\n", - "\n", - "class State(AgentState):\n", - " # updated by the tool\n", - " user_info: dict[str, Any]\n", - "\n", - "\n", - "@tool\n", - "def lookup_user_info(\n", - " tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig\n", - "):\n", - " \"\"\"Use this to look up user information to better assist them with their questions.\"\"\"\n", - " user_id = config.get(\"configurable\", {}).get(\"user_id\")\n", - " if user_id is None:\n", - " raise ValueError(\"Please provide user ID\")\n", - "\n", - " if user_id not in USER_ID_TO_USER_INFO:\n", - " raise ValueError(f\"User '{user_id}' not found\")\n", - "\n", - " user_info = USER_ID_TO_USER_INFO[user_id]\n", - " return Command(\n", - " update={\n", - " # update the state keys\n", - " \"user_info\": user_info,\n", - " # update the message history\n", - " \"messages\": [\n", - " ToolMessage(\n", - " \"Successfully looked up user information\", tool_call_id=tool_call_id\n", - " )\n", - " ],\n", - " }\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "b99e5f24-5e5e-4a34-baae-467182675bb5", - "metadata": {}, - "source": [ - "## Define prompt" - ] - }, - { - "cell_type": "markdown", - "id": "cbb06aea-6654-4245-91f8-af6e8f2b5377", - "metadata": {}, - "source": [ - "Let's now add personalization: we'll respond differently to the user based on the state values AFTER the state has been updated from the tool. To achieve this, let's define a function that will dynamically construct the system prompt based on the graph state. It will be called every time the LLM is called and the function output will be passed to the LLM:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "c553d062-d145-4145-84bd-9b798f7c95c2", - "metadata": {}, - "outputs": [], - "source": [ - "def prompt(state: State):\n", - " user_info = state.get(\"user_info\")\n", - " if user_info is None:\n", - " return state[\"messages\"]\n", - "\n", - " system_msg = (\n", - " f\"User name is {user_info['name']}. User lives in {user_info['location']}\"\n", - " )\n", - " return [{\"role\": \"system\", \"content\": system_msg}] + state[\"messages\"]" - ] - }, - { - "cell_type": "markdown", - "id": "c5acdd5d-68be-466b-9c21-46cbed91d2bc", - "metadata": {}, - "source": [ - "## Define graph" - ] - }, - { - "cell_type": "markdown", - "id": "afb65028-0359-46c8-b09c-ffc90180f759", - "metadata": {}, - "source": [ - "Finally, let's combine this into a single graph using the prebuilt `create_react_agent`:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "2d59db29-fd51-4d29-9854-21763a4855e3", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.prebuilt import create_react_agent\n", - "from langchain_openai import ChatOpenAI\n", - "\n", - "model = ChatOpenAI(model=\"gpt-4o\")\n", - "\n", - "agent = create_react_agent(\n", - " model,\n", - " # pass the tool that can update state\n", - " [lookup_user_info],\n", - " state_schema=State,\n", - " # pass dynamic prompt function\n", - " prompt=prompt,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "0782b8ab-a603-47b8-9a76-77f593402678", - "metadata": {}, - "source": [ - "## Use it!" - ] - }, - { - "cell_type": "markdown", - "id": "6165e153-ab28-4404-adea-796c7bd0701b", - "metadata": {}, - "source": [ - "Let's now try running our agent. We'll need to provide user ID in the config so that our tool knows what information to look up:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "de34a58b-1765-4b63-a232-d46790aff884", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_7LSUh6ZDvGJAUvlWvXiCK4Gf', 'function': {'arguments': '{}', 'name': 'lookup_user_info'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 56, 'total_tokens': 67, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_9d50cd990b', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-57eeb216-e35d-4501-aaac-b5c6b26fb17c-0', tool_calls=[{'name': 'lookup_user_info', 'args': {}, 'id': 'call_7LSUh6ZDvGJAUvlWvXiCK4Gf', 'type': 'tool_call'}], usage_metadata={'input_tokens': 56, 'output_tokens': 11, 'total_tokens': 67, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}}\n", - "\n", - "\n", - "{'tools': {'user_info': {'user_id': '1', 'name': 'Bob Dylan', 'location': 'New York, NY'}, 'messages': [ToolMessage(content='Successfully looked up user information', name='lookup_user_info', id='168d8ff8-b021-4c8b-a11a-3b50c30a072c', tool_call_id='call_7LSUh6ZDvGJAUvlWvXiCK4Gf')]}}\n", - "\n", - "\n", - "{'agent': {'messages': [AIMessage(content=\"Hi Bob! Since you're in New York, NY, there are plenty of exciting things to do over the weekend. Here are some suggestions:\\n\\n1. **Explore Central Park**: Take a leisurely walk, rent a bike, or have a picnic in this iconic park.\\n\\n2. **Visit a Museum**: Check out The Metropolitan Museum of Art or the Museum of Modern Art (MoMA) for an enriching cultural experience.\\n\\n3. **Broadway Show**: Catch a Broadway show or an off-Broadway performance for some world-class entertainment.\\n\\n4. **Food Tour**: Explore different neighborhoods like Greenwich Village or Williamsburg for diverse culinary experiences.\\n\\n5. **Brooklyn Bridge Walk**: Take a walk across the Brooklyn Bridge for stunning views of the city skyline.\\n\\n6. **Visit a Rooftop Bar**: Enjoy a drink with a view at one of New York’s many rooftop bars.\\n\\n7. **Explore a New Neighborhood**: Discover the unique charm of areas like SoHo, Chelsea, or Astoria.\\n\\n8. **Live Music**: Check out live music venues for a night of great performances.\\n\\n9. **Art Galleries**: Visit some of the smaller art galleries around Chelsea or the Lower East Side.\\n\\n10. **Attend a Local Event**: Look up any local events or festivals happening this weekend.\\n\\nFeel free to let me know if you want more details on any of these activities!\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 285, 'prompt_tokens': 95, 'total_tokens': 380, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_9d50cd990b', 'finish_reason': 'stop', 'logprobs': None}, id='run-f13ce15b-02b6-40e6-8264-c4d9edd0d03a-0', usage_metadata={'input_tokens': 95, 'output_tokens': 285, 'total_tokens': 380, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}}\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in agent.stream(\n", - " {\"messages\": [(\"user\", \"hi, what should i do this weekend?\")]},\n", - " # provide user ID in the config\n", - " {\"configurable\": {\"user_id\": \"1\"}},\n", - "):\n", - " print(chunk)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "d9b2281f-269c-41dd-b6b2-4c743f11ffc9", - "metadata": {}, - "source": [ - "We can see that the model correctly recommended some New York activities for Bob Dylan! Let's try getting recommendations for Taylor Swift:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "9d71af94-572a-4961-88a7-665e792cf96a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'agent': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_5HLtJtzcgmKbtmK6By21wW5Y', 'function': {'arguments': '{}', 'name': 'lookup_user_info'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 56, 'total_tokens': 67, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_c7ca0ebaca', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-bacacd7d-76cc-4f6b-9e9b-d9e6f00b9391-0', tool_calls=[{'name': 'lookup_user_info', 'args': {}, 'id': 'call_5HLtJtzcgmKbtmK6By21wW5Y', 'type': 'tool_call'}], usage_metadata={'input_tokens': 56, 'output_tokens': 11, 'total_tokens': 67, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}}\n", - "\n", - "\n", - "{'tools': {'user_info': {'user_id': '2', 'name': 'Taylor Swift', 'location': 'Beverly Hills, CA'}, 'messages': [ToolMessage(content='Successfully looked up user information', name='lookup_user_info', id='d81ef31e-6d77-4f13-ae86-e2e6ba567e3d', tool_call_id='call_5HLtJtzcgmKbtmK6By21wW5Y')]}}\n", - "\n", - "\n", - "{'agent': {'messages': [AIMessage(content=\"Hi Taylor! Since you're in Beverly Hills, here are a few suggestions for a fun weekend:\\n\\n1. **Hiking at Runyon Canyon**: Enjoy a scenic hike with beautiful views of Los Angeles. It's a great way to get some exercise and enjoy the outdoors.\\n\\n2. **Visit Rodeo Drive**: Spend some time shopping or window shopping at the famous Rodeo Drive. You might even spot some celebrities!\\n\\n3. **Explore the Getty Center**: Check out the art collections and beautiful gardens at the Getty Center. The architecture and views are stunning.\\n\\n4. **Relax at a Spa**: Treat yourself to a relaxing day at one of Beverly Hills' luxurious spas.\\n\\n5. **Dining Out**: Try a new restaurant or visit your favorite spot for a delicious meal. Beverly Hills has a fantastic dining scene.\\n\\n6. **Attend a Local Event**: Check out any local events or concerts happening this weekend. Beverly Hills often hosts exciting events.\\n\\nEnjoy your weekend!\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 198, 'prompt_tokens': 95, 'total_tokens': 293, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_c7ca0ebaca', 'finish_reason': 'stop', 'logprobs': None}, id='run-2057df76-f192-4c69-a66a-1f0a86bf5d66-0', usage_metadata={'input_tokens': 95, 'output_tokens': 198, 'total_tokens': 293, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})]}}\n", - "\n", - "\n" - ] - } - ], - "source": [ - "for chunk in agent.stream(\n", - " {\"messages\": [(\"user\", \"hi, what should i do this weekend?\")]},\n", - " {\"configurable\": {\"user_id\": \"2\"}},\n", - "):\n", - " print(chunk)\n", - " print(\"\\n\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/how-tos/use-functional-api.md b/docs/docs/how-tos/use-functional-api.md new file mode 100644 index 000000000..cea53c0ca --- /dev/null +++ b/docs/docs/how-tos/use-functional-api.md @@ -0,0 +1,532 @@ +# Use the functional API + +## Creating a simple workflow + +When defining an `entrypoint`, input is restricted to the first argument of the function. To pass multiple inputs, you can use a dictionary. + +```python +@entrypoint(checkpointer=checkpointer) +def my_workflow(inputs: dict) -> int: + value = inputs["value"] + another_value = inputs["another_value"] + ... + +my_workflow.invoke({"value": 1, "another_value": 2}) +``` + +??? example "Extended example: simple workflow" + + ```python + import uuid + from langgraph.func import entrypoint, task + from langgraph.checkpoint.memory import MemorySaver + + # Task that checks if a number is even + @task + def is_even(number: int) -> bool: + return number % 2 == 0 + + # Task that formats a message + @task + def format_message(is_even: bool) -> str: + return "The number is even." if is_even else "The number is odd." + + # Create a checkpointer for persistence + checkpointer = MemorySaver() + + @entrypoint(checkpointer=checkpointer) + def workflow(inputs: dict) -> str: + """Simple workflow to classify a number.""" + even = is_even(inputs["number"]).result() + return format_message(even).result() + + # Run the workflow with a unique thread ID + config = {"configurable": {"thread_id": str(uuid.uuid4())}} + result = workflow.invoke({"number": 7}, config=config) + print(result) + ``` + +??? example "Extended example: Compose an essay with an LLM" + + This example demonstrates how to use the `@task` and `@entrypoint` decorators + syntactically. Given that a checkpointer is provided, the workflow results will + be persisted in the checkpointer. + + ```python + import uuid + from langchain.chat_models import init_chat_model + from langgraph.func import entrypoint, task + from langgraph.checkpoint.memory import MemorySaver + + llm = init_chat_model('openai:gpt-3.5-turbo') + + # Task: generate essay using an LLM + @task + def compose_essay(topic: str) -> str: + """Generate an essay about the given topic.""" + return llm.invoke([ + {"role": "system", "content": "You are a helpful assistant that writes essays."}, + {"role": "user", "content": f"Write an essay about {topic}."} + ]).content + + # Create a checkpointer for persistence + checkpointer = MemorySaver() + + @entrypoint(checkpointer=checkpointer) + def workflow(topic: str) -> str: + """Simple workflow that generates an essay with an LLM.""" + return compose_essay(topic).result() + + # Execute the workflow + config = {"configurable": {"thread_id": str(uuid.uuid4())}} + result = workflow.invoke("the history of flight", config=config) + print(result) + ``` + +## Parallel execution + +Tasks can be executed in parallel by invoking them concurrently and waiting for the results. This is useful for improving performance in IO bound tasks (e.g., calling APIs for LLMs). + +```python +@task +def add_one(number: int) -> int: + return number + 1 + +@entrypoint(checkpointer=checkpointer) +def graph(numbers: list[int]) -> list[str]: + futures = [add_one(i) for i in numbers] + return [f.result() for f in futures] +``` + + +??? example "Extended example: parallel LLM calls" + + This example demonstrates how to run multiple LLM calls in parallel using `@task`. Each call generates a paragraph on a different topic, and results are joined into a single text output. + + ```python + import uuid + from langchain.chat_models import init_chat_model + from langgraph.func import entrypoint, task + from langgraph.checkpoint.memory import MemorySaver + + # Initialize the LLM model + llm = init_chat_model("openai:gpt-3.5-turbo") + + # Task that generates a paragraph about a given topic + @task + def generate_paragraph(topic: str) -> str: + response = llm.invoke([ + {"role": "system", "content": "You are a helpful assistant that writes educational paragraphs."}, + {"role": "user", "content": f"Write a paragraph about {topic}."} + ]) + return response.content + + # Create a checkpointer for persistence + checkpointer = MemorySaver() + + @entrypoint(checkpointer=checkpointer) + def workflow(topics: list[str]) -> str: + """Generates multiple paragraphs in parallel and combines them.""" + futures = [generate_paragraph(topic) for topic in topics] + paragraphs = [f.result() for f in futures] + return "\n\n".join(paragraphs) + + # Run the workflow + config = {"configurable": {"thread_id": str(uuid.uuid4())}} + result = workflow.invoke(["quantum computing", "climate change", "history of aviation"], config=config) + print(result) + ``` + + This example uses LangGraph's concurrency model to improve execution time, especially when tasks involve I/O like LLM completions. + +## Calling graphs + +The **Functional API** and the [**Graph API**](../concepts/low_level.md) can be used together in the same application as they share the same underlying runtime. + +```python +from langgraph.func import entrypoint +from langgraph.graph import StateGraph + +builder = StateGraph() +... +some_graph = builder.compile() + +@entrypoint() +def some_workflow(some_input: dict) -> int: + # Call a graph defined using the graph API + result_1 = some_graph.invoke(...) + # Call another graph defined using the graph API + result_2 = another_graph.invoke(...) + return { + "result_1": result_1, + "result_2": result_2 + } +``` + +??? example "Extended example: calling a simple graph from the functional API" + + ```python + import uuid + from typing import TypedDict + from langgraph.func import entrypoint + from langgraph.checkpoint.memory import MemorySaver + from langgraph.graph import StateGraph + + # Define the shared state type + class State(TypedDict): + foo: int + + # Define a simple transformation node + def double(state: State) -> State: + return {"foo": state["foo"] * 2} + + # Build the graph using the Graph API + builder = StateGraph(State) + builder.add_node("double", double) + builder.set_entry_point("double") + graph = builder.compile() + + # Define the functional API workflow + checkpointer = MemorySaver() + + @entrypoint(checkpointer=checkpointer) + def workflow(x: int) -> dict: + result = graph.invoke({"foo": x}) + return {"bar": result["foo"]} + + # Execute the workflow + config = {"configurable": {"thread_id": str(uuid.uuid4())}} + print(workflow.invoke(5, config=config)) # Output: {'bar': 10} + ``` + + +## Call other entrypoints + +You can call other **entrypoints** from within an **entrypoint** or a **task**. + +```python +@entrypoint() # Will automatically use the checkpointer from the parent entrypoint +def some_other_workflow(inputs: dict) -> int: + return inputs["value"] + +@entrypoint(checkpointer=checkpointer) +def my_workflow(inputs: dict) -> int: + value = some_other_workflow.invoke({"value": 1}) + return value +``` + +??? example "Extended example: calling another entrypoint" + + ```python + import uuid + from langgraph.func import entrypoint + from langgraph.checkpoint.memory import MemorySaver + + # Initialize a checkpointer + checkpointer = MemorySaver() + + # A reusable sub-workflow that multiplies a number + @entrypoint() + def multiply(inputs: dict) -> int: + return inputs["a"] * inputs["b"] + + # Main workflow that invokes the sub-workflow + @entrypoint(checkpointer=checkpointer) + def main(inputs: dict) -> dict: + result = multiply.invoke({"a": inputs["x"], "b": inputs["y"]}) + return {"product": result} + + # Execute the main workflow + config = {"configurable": {"thread_id": str(uuid.uuid4())}} + print(main.invoke({"x": 6, "y": 7}, config=config)) # Output: {'product': 42} + ``` + + +## Streaming + +The **Functional API** uses the same streaming mechanism as the **Graph API**. Please +read the [**streaming guide**](../concepts/streaming.md) section for more details. + +Example of using the streaming API to stream both updates and custom data. + +```python +from langgraph.func import entrypoint +from langgraph.checkpoint.memory import MemorySaver +from langgraph.config import get_stream_writer # (1)! + +checkpointer = MemorySaver() + +@entrypoint(checkpointer=checkpointer) +def main(inputs: dict) -> int: + writer = get_stream_writer() # (2)! + writer("Started processing") # (3)! + result = inputs["x"] * 2 + writer(f"Result is {result}") # (4)! + return result + +config = {"configurable": {"thread_id": "abc"}} + +# highlight-next-line +for mode, chunk in main.stream( # (5)! + {"x": 5}, + stream_mode=["custom", "updates"], # (6)! + config=config +): + print(f"{mode}: {chunk}") +``` + +1. Import `get_stream_writer` from `langgraph.config`. +2. Obtain a stream writer instance within the entrypoint. +3. Emit custom data before computation begins. +4. Emit another custom message after computing the result. +5. Use `.stream()` to process streamed output. +6. Specify which streaming modes to use. + +```pycon +('updates', {'add_one': 2}) +('updates', {'add_two': 3}) +('custom', 'hello') +('custom', 'world') +('updates', {'main': 5}) +``` + +!!! important "Async with Python < 3.11" + + If using Python < 3.11 and writing async code, using `get_stream_writer()` will not work. Instead please + use the `StreamWriter` class directly. See [Async with Python < 3.11](../how-tos/streaming.md#async-with-python-<3.11) for more details. + + ```python + from langgraph.types import StreamWriter + + @entrypoint(checkpointer=checkpointer) + # highlight-next-line + async def main(inputs: dict, writer: StreamWriter) -> int: + ... + ``` + +## Retry policy + +```python +from langgraph.checkpoint.memory import MemorySaver +from langgraph.func import entrypoint, task +from langgraph.types import RetryPolicy + +# This variable is just used for demonstration purposes to simulate a network failure. +# It's not something you will have in your actual code. +attempts = 0 + +# Let's configure the RetryPolicy to retry on ValueError. +# The default RetryPolicy is optimized for retrying specific network errors. +retry_policy = RetryPolicy(retry_on=ValueError) + +@task(retry=retry_policy) +def get_info(): + global attempts + attempts += 1 + + if attempts < 2: + raise ValueError('Failure') + return "OK" + +checkpointer = MemorySaver() + +@entrypoint(checkpointer=checkpointer) +def main(inputs, writer): + return get_info().result() + +config = { + "configurable": { + "thread_id": "1" + } +} + +main.invoke({'any_input': 'foobar'}, config=config) +``` + +```pycon +'OK' +``` + +## Resuming after an error + +```python +import time +from langgraph.checkpoint.memory import MemorySaver +from langgraph.func import entrypoint, task +from langgraph.types import StreamWriter + +# This variable is just used for demonstration purposes to simulate a network failure. +# It's not something you will have in your actual code. +attempts = 0 + +@task() +def get_info(): + """ + Simulates a task that fails once before succeeding. + Raises an exception on the first attempt, then returns "OK" on subsequent tries. + """ + global attempts + attempts += 1 + + if attempts < 2: + raise ValueError("Failure") # Simulate a failure on the first attempt + return "OK" + +# Initialize an in-memory checkpointer for persistence +checkpointer = MemorySaver() + +@task +def slow_task(): + """ + Simulates a slow-running task by introducing a 1-second delay. + """ + time.sleep(1) + return "Ran slow task." + +@entrypoint(checkpointer=checkpointer) +def main(inputs, writer: StreamWriter): + """ + Main workflow function that runs the slow_task and get_info tasks sequentially. + + Parameters: + - inputs: Dictionary containing workflow input values. + - writer: StreamWriter for streaming custom data. + + The workflow first executes `slow_task` and then attempts to execute `get_info`, + which will fail on the first invocation. + """ + slow_task_result = slow_task().result() # Blocking call to slow_task + get_info().result() # Exception will be raised here on the first attempt + return slow_task_result + +# Workflow execution configuration with a unique thread identifier +config = { + "configurable": { + "thread_id": "1" # Unique identifier to track workflow execution + } +} + +# This invocation will take ~1 second due to the slow_task execution +try: + # First invocation will raise an exception due to the `get_info` task failing + main.invoke({'any_input': 'foobar'}, config=config) +except ValueError: + pass # Handle the failure gracefully +``` + +When we resume execution, we won't need to re-run the `slow_task` as its result is already saved in the checkpoint. + +```python +main.invoke(None, config=config) +``` + +```pycon +'Ran slow task.' +``` + +## Human-in-the-loop + +The functional API supports [human-in-the-loop](../concepts/human_in_the_loop.md) workflows using the `interrupt` function and the `Command` primitive. + +Please see the following examples for more details: + +* [How to wait for user input (Functional API)](./wait-user-input-functional.ipynb): Shows how to implement a simple human-in-the-loop workflow using the functional API. +* [How to review tool calls (Functional API)](./review-tool-calls-functional.ipynb): Guide demonstrates how to implement human-in-the-loop workflows in a ReAct agent using the LangGraph Functional API. + +## Short-term memory + +Short-term memory allows storing information across different **invocations** of the same **thread id**. See [short-term memory](../concepts/functional_api.md#short-term-memory) for more details. + +### Decouple return value from saved value + +Use `entrypoint.final` to decouple what is returned to the caller from what is persisted in the checkpoint. This is useful when: + +* You want to return a computed result (e.g., a summary or status), but save a different internal value for use on the next invocation. +* You need to control what gets passed to the previous parameter on the next run. + +```python +from typing import Optional +from langgraph.func import entrypoint +from langgraph.checkpoint.memory import MemorySaver + +checkpointer = MemorySaver() + +@entrypoint(checkpointer=checkpointer) +def accumulate(n: int, *, previous: Optional[int]) -> entrypoint.final[int, int]: + previous = previous or 0 + total = previous + n + # Return the *previous* value to the caller but save the *new* total to the checkpoint. + return entrypoint.final(value=previous, save=total) + +config = {"configurable": {"thread_id": "my-thread"}} + +print(accumulate.invoke(1, config=config)) # 0 +print(accumulate.invoke(2, config=config)) # 1 +print(accumulate.invoke(3, config=config)) # 3 +``` + +### Chatbot example + +An example of a simple chatbot using the functional API and the `MemorySaver` checkpointer. +The bot is able to remember the previous conversation and continue from where it left off. + +```python +from langchain_core.messages import BaseMessage +from langgraph.graph import add_messages +from langgraph.func import entrypoint, task +from langgraph.checkpoint.memory import MemorySaver +from langchain_anthropic import ChatAnthropic + +model = ChatAnthropic(model="claude-3-5-sonnet-latest") + +@task +def call_model(messages: list[BaseMessage]): + response = model.invoke(messages) + return response + +checkpointer = MemorySaver() + +@entrypoint(checkpointer=checkpointer) +def workflow(inputs: list[BaseMessage], *, previous: list[BaseMessage]): + if previous: + inputs = add_messages(previous, inputs) + + response = call_model(inputs).result() + return entrypoint.final(value=response, save=add_messages(inputs, response)) + +config = {"configurable": {"thread_id": "1"}} +input_message = {"role": "user", "content": "hi! I'm bob"} +for chunk in workflow.stream([input_message], config, stream_mode="values"): + chunk.pretty_print() + +input_message = {"role": "user", "content": "what's my name?"} +for chunk in workflow.stream([input_message], config, stream_mode="values"): + chunk.pretty_print() +``` + +??? example "Extended example: build a simple chatbot" + + [How to add thread-level persistence (functional API)](./persistence-functional.ipynb): Shows how to add thread-level persistence to a functional API workflow and implements a simple chatbot. + +## Long-term memory + +[long-term memory](../concepts/memory.md#long-term-memory) allows storing information across different **thread ids**. This could be useful for learning information about a given user in one conversation and using it in another. + + +??? example "Extended example: add long-term memory" + + [How to add cross-thread persistence (functional API)](./cross-thread-persistence-functional.ipynb): Shows how to add cross-thread persistence to a functional API workflow and implements a simple chatbot. + +## Workflows + +* [Workflows and agent](../tutorials/workflows.md) guide for more examples of how to build workflows using the Functional API. + +## Agents + +* [How to create an agent from scratch (Functional API)](./react-agent-from-scratch-functional.ipynb): Shows how to create a simple agent from scratch using the functional API. +* [How to build a multi-agent network](./multi-agent-network-functional.ipynb): Shows how to build a multi-agent network using the functional API. +* [How to add multi-turn conversation in a multi-agent application (functional API)](./multi-agent-multi-turn-convo-functional.ipynb): allow an end-user to engage in a multi-turn conversation with one or more agents. + +## Integrate with other libraries + +* [Add LangGraph's features to other frameworks using the functional API](./autogen-integration-functional.ipynb): Add LangGraph features like persistence, memory and streaming to other agent frameworks that do not provide them out of the box. \ No newline at end of file diff --git a/docs/docs/how-tos/visualization.ipynb b/docs/docs/how-tos/visualization.ipynb deleted file mode 100644 index 544f7e66a..000000000 --- a/docs/docs/how-tos/visualization.ipynb +++ /dev/null @@ -1,381 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "8bcd1a3d-7c50-4f58-be4e-1ed654aa33be", - "metadata": {}, - "source": [ - "# How to visualize your graph\n", - "\n", - "This guide walks through how to visualize the graphs you create. This works with ANY [Graph](https://langchain-ai.github.io/langgraph/reference/graphs/).\n", - "\n", - "## Setup\n", - "\n", - "First, let's install the required packages" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32a0e7f4", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph" - ] - }, - { - "cell_type": "markdown", - "id": "e130cf70-a30e-47d7-8fd5-464f1a92e374", - "metadata": {}, - "source": [ - "## Set up Graph\n", - "\n", - "You can visualize any arbitrary [Graph](https://langchain-ai.github.io/langgraph/reference/graphs/), including [StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph). Let's have some fun by drawing fractals :)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "6d604311", - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "from typing import Annotated, Literal\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - "\n", - "\n", - "class MyNode:\n", - " def __init__(self, name: str):\n", - " self.name = name\n", - "\n", - " def __call__(self, state: State):\n", - " return {\"messages\": [(\"assistant\", f\"Called node {self.name}\")]}\n", - "\n", - "\n", - "def route(state) -> Literal[\"entry_node\", \"__end__\"]:\n", - " if len(state[\"messages\"]) > 10:\n", - " return \"__end__\"\n", - " return \"entry_node\"\n", - "\n", - "\n", - "def add_fractal_nodes(builder, current_node, level, max_level):\n", - " if level > max_level:\n", - " return\n", - "\n", - " # Number of nodes to create at this level\n", - " num_nodes = random.randint(1, 3) # Adjust randomness as needed\n", - " for i in range(num_nodes):\n", - " nm = [\"A\", \"B\", \"C\"][i]\n", - " node_name = f\"node_{current_node}_{nm}\"\n", - " builder.add_node(node_name, MyNode(node_name))\n", - " builder.add_edge(current_node, node_name)\n", - "\n", - " # Recursively add more nodes\n", - " r = random.random()\n", - " if r > 0.2 and level + 1 < max_level:\n", - " add_fractal_nodes(builder, node_name, level + 1, max_level)\n", - " elif r > 0.05:\n", - " builder.add_conditional_edges(node_name, route, node_name)\n", - " else:\n", - " # End\n", - " builder.add_edge(node_name, \"__end__\")\n", - "\n", - "\n", - "def build_fractal_graph(max_level: int):\n", - " builder = StateGraph(State)\n", - " entry_point = \"entry_node\"\n", - " builder.add_node(entry_point, MyNode(entry_point))\n", - " builder.add_edge(START, entry_point)\n", - "\n", - " add_fractal_nodes(builder, entry_point, 1, max_level)\n", - "\n", - " # Optional: set a finish point if required\n", - " builder.add_edge(entry_point, END) # or any specific node\n", - "\n", - " return builder.compile()\n", - "\n", - "\n", - "app = build_fractal_graph(3)" - ] - }, - { - "cell_type": "markdown", - "id": "edcd9ad2", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-18T12:18:30.629307Z", - "start_time": "2024-04-18T12:18:30.609323Z" - } - }, - "source": [ - "## Mermaid\n", - "\n", - "We can also convert a graph class into Mermaid syntax." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "66007b2d", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-19T11:25:38.733126Z", - "start_time": "2024-04-19T11:25:38.726838Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "%%{init: {'flowchart': {'curve': 'linear'}}}%%\n", - "graph TD;\n", - "\t__start__([

    __start__

    ]):::first\n", - "\tentry_node(entry_node)\n", - "\tnode_entry_node_A(node_entry_node_A)\n", - "\tnode_entry_node_B(node_entry_node_B)\n", - "\tnode_node_entry_node_B_A(node_node_entry_node_B_A)\n", - "\tnode_node_entry_node_B_B(node_node_entry_node_B_B)\n", - "\tnode_node_entry_node_B_C(node_node_entry_node_B_C)\n", - "\t__end__([

    __end__

    ]):::last\n", - "\t__start__ --> entry_node;\n", - "\tentry_node --> __end__;\n", - "\tentry_node --> node_entry_node_A;\n", - "\tentry_node --> node_entry_node_B;\n", - "\tnode_entry_node_B --> node_node_entry_node_B_A;\n", - "\tnode_entry_node_B --> node_node_entry_node_B_B;\n", - "\tnode_entry_node_B --> node_node_entry_node_B_C;\n", - "\tnode_entry_node_A -.-> entry_node;\n", - "\tnode_entry_node_A -.-> __end__;\n", - "\tnode_node_entry_node_B_A -.-> entry_node;\n", - "\tnode_node_entry_node_B_A -.-> __end__;\n", - "\tnode_node_entry_node_B_B -.-> entry_node;\n", - "\tnode_node_entry_node_B_B -.-> __end__;\n", - "\tnode_node_entry_node_B_C -.-> entry_node;\n", - "\tnode_node_entry_node_B_C -.-> __end__;\n", - "\tclassDef default fill:#f2f0ff,line-height:1.2\n", - "\tclassDef first fill-opacity:0\n", - "\tclassDef last fill:#bfb6fc\n", - "\n" - ] - } - ], - "source": [ - "print(app.get_graph().draw_mermaid())" - ] - }, - { - "cell_type": "markdown", - "id": "8f77ad75", - "metadata": {}, - "source": [ - "## PNG\n", - "\n", - "If preferred, we could render the Graph into a `.png`. Here we could use three options:\n", - "\n", - "- Using Mermaid.ink API (does not require additional packages)\n", - "- Using Mermaid + Pyppeteer (requires `pip install pyppeteer`)\n", - "- Using graphviz (which requires `pip install graphviz`)\n", - "\n", - "\n", - "### Using Mermaid.Ink\n", - "\n", - "By default, `draw_mermaid_png()` uses Mermaid.Ink's API to generate the diagram." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "967f116d", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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IgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIC17waINTV+xJ/958l3/8Aa/nWwlr3g1v5Jq/fb+s+S7tv879CDYSIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIC15wZG1TWHUH/3oyXcP/nLYa15wZ28k1ht7UZLw2/tkGw0REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEUzmdU3GZGbH4alDcs1w3yma1M6KGEkAhm4a4ufykO2AAAI3I3G+O8+6w/0DB+9zfVrqp6NXVF+yPWYWy3RRHn3WH+gYP3ub6tPPusP9Awfvc31a1utecawWW6KI8+6w/0DB+9zfVp591h/oGD97m+rTda841gs+3GHXd3hhwz1BqvH4N+pLGJr+VOxsc/YOlja4dq4P5XbcrOd/cd+Xbx3XmD4G3wvbXGbX+X0tR0LJSq2rd3OXMm7JB7abJHbtZyCFvOS8tbvuO8nw2XpafLasswyQzYzAyxSNLHxvsyua5pGxBBi6grU3wfeA1r4OsOpWafp4id2avutOkntS80MI37KAHs+rWczuvjum615xrBZ6TRRHn3WH+gYP3ub6tPPusP9Awfvc31abrXnGsFluiiPPusP9Awfvc31aefdYf6Bg/e5vq03WvONYLLdFEefdYf6Bg/e5vq1+2ai1VBvJPicXZjb1MVW69sjht+LzxhpPqBIHXqQm615xrBZaIupicpWzeOgvVHl9eZvM0uaWuHgQQeoIIIIPUEELtrkmJpm0oIiKAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIggNPnfNasJ7/Ox6/8A+vAs4sHp/wD6a1Z+lj/w8Kzi+vicY9I+kLPEREXmgi6NzOY/H5HH0LN2CC9kHPZUrSSASTljC9/I3vdytBJ27gu8gIiICIiAi6uVylbCYu5kbsvY06cL7E8vKXckbGlzjsASdgD0A3X4weap6kwuPy+Om8ox9+vHarTcrm9pE9ocx2zgCNwQdiAfWoO6iIqOtwxO+mJ/oyuSAAHcBenVYpLhh/Vix+lsn/x06rVy9J+PX6z9WquMiIi5mRERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEX5kkbExz3uDGNG5c47ABRuZ408P9PTdjktbafp2CdhXlycIlcfUGc3MT9ACC0Ra6dx60vO0nG19Q5vpuHYzTt6aI/8AfdiIh+t4UXmvhb4bHWvJIsDYbcPyYchl8bXkd+aFtl8//wBpBdaf/wCmtWfpY/8ADwrOKF4Salm1hjc5mJ6Xm6W1lHuNbeQ8m0UQHWSON3UAHqwd/TcbE3S+vicY9I+kLPF5d1bPr7ihxk1/hcNYsw0tMGpVqQU9VS4V0RmrNl7d7I6svb8znOA5zygR7cu+5PfxWB1dq7izR0prLVuXp2a2haVu/HprJy1IZr3ldiN07XMDXAkAEgcodsA4ENaBtjW/A3RHEXMsy2ewgs5JsPkzrVe1PWfLDvv2chie3tGdT6L9x1PRZ6lofCY7Uoz9aiIcsMdHiRO2R+wqxvc9kYZvyjZznHfbfrtvsufZm/ajyphq1ji5N8G/I6jzOY85XoMtVsW8fk56UkjoYJAJAYnt5Xu5PSc3YuG4O46LZun9PXdccfuJ1bI6o1FFh8JLifIcXQy09aFj31Gve48jgSCQN278p3cSCSCL27wI0NkNH4jTE2EPmbETGxQjjuTxy1pCXEuZM14kG/O7f0uoO3cqDTuhcJpTJZPIYuma9zJNrstyunkkMogiEUW/O47crABuNt+87nqkUz3jz9oDWmotTaj0TwxtZq+7PaTyl2TUt1th7ZrVSmA2oZXb7vbY8prPdzb8/JJvv1Xp9at4fcMc3g9R621lmJcMzWWpGwwsNCGSSpVigjLIWkuLXyEk8z/kb7ADbYFZGHFcVRMwy6n0c6IOHO1mnLYcR4gHy87H9RVi8DQeAyOoKHDPS3EB2r9RW8u/W3myWrZyUj6klN+XkqGAwn0T6B3D3AvBA2cAAB9tS53UV7hzxQ4ou1nmcXntM5u/Xx2KgulmOgiqTiOOvLWHoSmUD0nOBce0HKR0XoiPhJpOLS1XTjcVthquQGVhreUy+jaFk2RJzc/MfvxLuUnl8Ntuix2Y4B6Cz+qn6iv6eisZSSeO1LvPM2CeZm3JJJAHiKR42GznMJ6Dqs7MjTWqGZTjDLxks5PUmdwNbS1M06OCxV01WDmoNndNYa3+m53SFoa/doawjbfcqX0he1vxFtYTSmHksx43T2jcFPDVqanmwb5Xz1t3Tl0VeV0wBaGcpIa0t6hxd09G6z4CaE4gZybMZzBCzkp6/kk88Nuev5RFsQGSiJ7RIADsOcHbwX4z3wf9A6lrYSG9gd/M1JmOozVrlivPHWaAGwmWORr3s2A9F7iO895KbMjL8KqWqcdw+w1XWluve1LDG6O3Zqyc7JdnuDHc3IzdxZycx5Wgu32CrF1MRiaeAxVLGY+uyrQpwsr14I/kxxsaGtaPoAAC7a9IHS4bTx1tJW5ZpGxRMymUc97yA1oF6fcknuCosNnMdqPGxZDE5CrlKEpcI7VKZs0Ty1xa7Z7SQdnNIPXoQR4L+S/w4LuvaGsbkc8+oYND2MhdNJklg+bpJBZlEnZtbsA4O33D93b9fklq9q/AxlzWmPg58JcTZtsx8l9ly75Pcw08naUzLJK0NnY9scTi14ka6Tfna4ANO265uk/Hr9Z+rVXGXqFFB6d1zczcGDlq5PS2XiyU87xLTyD4+0qMJHPAzlf2j2no9u7QDv6Q7lmama1AfIRc04xjp7MkU7qeQZKyvEPkSkuawu5vFrRuPp71zMqNFO1NW2pjQbZ0zmaEluzJXLZWQSdgG90kjopXgMd4Hcn1hp6L9VdcY6xJjo3Q5KrLkJpIIGWcZYjPOwbu5yWbMBHc5xAd4EoKBFPUeIemci7Gsgz1DtclLLBShknbHJZki/pWRscQ5zm7dQB0HVZShmsflYYZqV+tcim5hHJXma9r+U7O5SD12PQ7dyDuoiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiLAaj4g6W0c0uz+pMRg2gbk5K/FXA/87ggz6LXXx/aMs9MXbyOoifknAYe5kGH/ALyGJzAPpLgPpXJ4oZ++SMTwz1LZb4WMhLTpRfrD5+1H+Gg2Ii123I8VMmfQwWlMBGQdn2cpYvyD1bxsgiaPzCQ/nXWyGA1xHVfZz/E+hg6rfly4bCQ1Gs/27ctgfrI/Ug2avnPPHWidLNIyKJg3c97g1oH0krQE2W4c3XvgucVtUa3sRk9pBgcvYml36DlMeJYw/wCzt49y/EGltG3pmS4vgXl9TzA7svakqQN5T6y7ITdsPzhhKDZ2V45cPMLY8mt63wEdvwqMyMT5z+aNri4/qC6h444K0wOxWK1PnC4kNNHTt0Rnu7pZImR+P5S6OKp8RYa/k+I0zovRVQ/JHlM15w/vQxRQNH5hIfzru/cDrXKf9LcS7lYH5UWnMTVpsP0bziw8D8zwfpQG8RdW5E7Y7hhmYWkHlmzOQo1WO9XSOaV4H52A/Qp7UvE3V2nml2eynDfQjenXKZyW44b927XMrdfoB/WVRHgXpq7G1uZsZzUhBLiMxm7U0Tt9t94e0EXh3cioNNcN9J6M/wCgNMYfCHvLsfQigJPrJa0En6UGnZOIeXzxkdT4hZfKMLtmjQ+h5HM2O+209htiLw7y7Zfj7l9W6had8PxCyO56Sai1dBhI3/TtjCXtH0FgP0L0QiDzxH8HHI5d7ZL+D0FScDvzZSlb1NMD62y2pYtj/rFh/MrHDcCZcfD2UutczXgI2dTwValioP1GCASj9cpW1kQa7b8H7Qczg7J4M6keDvzakuT5Xc+vay+QK0wunsVpyr5NicZTxdb/ADNKBkLP/BoAWQRBAaf/AOmtWfpY/wDDwrOKf1vYk4c1dQ6qMBuYJkL8lkI43ffq3ZRDtHsaej2mOMEtBDg5p2Duf0dI6P8Ah4cOdfamx2n8BXzeSy+QlEFetHRIL3H1kkADxJJAA6kr7E2xLVUzHCO+I7vnLUxd6ORYTztnvYzK+9Uvr087Z72MyvvVL69TY80e6OZZm0WE87Z72MyvvVL69PO2e9jMr71S+vTY80e6OZZm0WE87Z72MyvvVL69TGhOMlbibDlZtMYS9l48Xdkx1t0NmoOznZtzN9KYbjr0cN2nrsTsmx5o90cyzYSLCeds97GZX3ql9ennbPexmV96pfXpseaPdHMszaLCeds97GZX3ql9ennbPexmV96pfXpseaPdHMszaLCeds97GZX3ql9ev027qO0DHDpWzVlPRsl63XETT63dnI92w+gbpseaPdHMs6+nNIYXXfDnJ4TUOLrZjE28nk2TVLcYexw8un6/QR3hw2IPUEFWenNP4/SensXg8TX8kxeMqxUqlcPc/soY2BjG8ziSdmtA3JJO3UqGq29XcN43VptPt1ZgxI+by3CzBl5jnuL5C+tK4NcOZzjvHKXbdBHuOtLpPiNp3W0k8GJyTJL1cA2MdYjfXuV9+7ta8gbJH/tNG6+dj1RXi1VRwmZSe2Wcs42pcmimsVYZ5og4RySRhzmBw2cASOm46H1hYWrw707joqMWPxcWJgo15atWHGOdUjgjl6vaxsRaG9eoIG4PUbFUaLxROQaOkomiKeoMzBFUqvqthlsNsiXcHlkkdM173vaeocXddvS5lzXxmpaZqt8+078MVJ0Uot48tmns/iS87JGta38pgjO/eHN7lRIgm4buqYGQC5iMZc5aL5ZpKd57XG2PkxMjfHtyOH45eCD05SOqxkbsdHbxNi7oSepap0pr8NhlOvP5DI8ETQsdG5zhK8bg8g2eDtuT0VuiDXWJboDCnBGtWGnWYfGz5WnBNBPj4qdWTftnSMcGMbtuS5kg3Z37DvWT01hcD2eAOF1Feu1q0Mlyq3z5LdFuGYdHvfI97poxvuwlxDenKduisli8hpfDZZ8r7uKpW3y1X0ZHzV2Oc6u/5cJJG/I7xb3FB0cbpjJY3zQz7qcpdipNmbYbcjrPde59+QyubE0gx+HJy7gelzd64x2M1RT8yss56hfig7YZN8mLcyW3v/RGItmDYS3pzbtk5vDkT7gcRCP8kFzGluL8zxCldmhZDXHyeSMO5Gvb+LIG847gduiO0xka4/yPU+SjDMX5BFDZZBPGJh8m28mMSPl8CC/kI/F36oGPfq2IYll6HC2SRP5xmrzTQ8hG/Y9iwtfzb9A7mcNupHN3LnHZnULziWZDTkcElhkpuvqZBs0VRzd+RoLmsdIH9OoaNieo8Vw+vquqJDFdxOQazHBkcc9aSB8l0d73yNe4Nid+SGFzfyndyS5nUVMSGXTjLjYse2xtj77HPltfjV2CURjb8mRzmg+IagY7Vtq0cKy3pjM4ubIiYyR2GwSCiY9yBO+GV7RzgejylwO4B2PRMfr3GX24reDKU5MlHNJDFdxdmFzRFvziTmjAiPTcB5BcOrd0n1rHRbZfew+ZqMrUmXZXNous9Hd8TRB2hfI3xawO9Y3HVfuTX+nYJLUdnMVaT6laO5YFx/YdjC/5L38+3KCenXuPQ9UHGP4h6Zyhxba+doOlykUs9GF87Y5bLI/6RzGO2c4M/G2HTx2WUx+ax+Wr156N+tcgsNL4Za8zZGytB2JaQdiAfUvvFYr3G/epY527B3oODhsRuD+YhY86SwZs0LBw2P8AKKAkbTl8lZz1hINpBGdt2cwJDttt9+qDLIpyjw807im4xtDGMx8eMilgpxU5Hwxwsk352hjCG9d9+o6HqNlzS0RWxgxrauTzMcVCCWCNk2TmsdoH/jSulc90jm/iucSR3d3RBRIp2jpnJ0DjGjVOTtxVIZIpm3Iqzzbc75L5HNiaQ5nhycoI7we9cU8bqmo3HtlzuOvNiglZbdLjHMksSn+ie1zZg2NrenM3ldzeBago0U5Wl1bC2m2zWw1s+SyG1JFYlg3sD5AjaWP+9nxJdu3wDkr5vUDRUFvTQD303zWDTvxytinb3QNLxGX83g8ho9eyCjRTlfV1h3kotabzNF8tJ9uRr44pewc3vgeYpHgyHwDC4HwcuYNeYuXyUSR5Ko+xSffa21jLMXJE35QeTHsx4/zbiHeIBQUSKeqcQdM3n044s9jxNcqOv14ZLDY5Ja7flShjiHcjfE7bDx2WVo5ihk4oJad2vbjnj7WJ8ErXiRn5TSD1H0hB3EREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARdbIZKpiKklq9agpVYxu+exII2NH0uJAChpePWi5XFmJyU+qZeoDdNUZ8o3cHYgvrsexvUEbucAPFBsJFrxuvtZZk7YbhzbqsIPLY1Lk69KN3qIbCbEgH95jT9C/PmXifmf+ean0/pyE98OIxUludv5p5pQz/wAYEGxVjs3qPE6ZqeVZjKUsVW/z16wyFn/mcQFGfEzDkQPP+r9W6hPeQ/LOoMP0FlIQNI+gg/Tuv0zhnwx4eMdmJsBpzDvZ8vLZCGIS/wC1Yl9I/rcg4fx90RK7lxmTsaleQC0acx1nKNduNx6deN7QPpJA+lcDiZqPKEDD8Nc/Iw91nLT1KEP/AJTK6YfriQcedIXQW4Gxd1a4D0TpvHz34j4f08bDEP1vC/Uet9cZpxGK4ePx0ZB5Z9TZaCtv06EMreUO79ujuU+vZB+Ofixlu6HR2l2nuLpLWYcPzgCqN/o3/WVyOHerckD534mZZoPfDg8fUpRn9ckc0g/VIEbp7iVmHA5DWGHwUBPWDBYcyTN/7+xI9p/wQuPiSx+Q65/UmqtSuPe25mZa0Tv70NXsYnD6Cwj6EGF1Lw94Z6Xg7fW2op5oyN3O1XqmwYHD/spZhEP1MC6unNVcKNNhrtD6RF6Tc8kmlNLyPjcfX5QyIRDf1ukG/wBOxWwdO8LdHaSseU4bS2Hxtvpvar0o2zOIGwLpNuZx2A6knuVQg123XWuMsdsTw3mpNIPLLqXMV6jT6jy1/KXAfnAP0LjzRxSy/wDznUem9OxHvixuKmuTD800szG/+MJWxUQa8dwglybi7O661dmGuO5iiyLcbGPoHkTIXbfncT6yV2MfwK4f4+wyz9yWMvXGEltzJw+W2Gk95Es3O/rsPHwCu0QfOCCKrCyKGNkUTBs1jGhrWj1ABfREQEREBERAREQERfl8jYxu9waCQN3HbqTsB+snZB+lj87naenMZYv3nyCCFvO5sED55XdQAGRRtc97iSAGtBJJAAJKxUGoLup4YH4OB0OOsw2P+VLsT4nRSNJZGWV3ta6RpcC7mJa0tDS0uDwV38Vpqpjbbb8hdezJqRU5spYa3t52M3I35Q1rd3Fzi1jWt3JOwQdeWLNZe25pldgqlW9G9j4HRzS3YGt3c1wc0iJrnkDpu7ladiwuHLpLgH8C/SvAjipq7V2NAliuyCLB1ZXGV2OruY0yt53DcuMhe1veRG1u7nFztvRaICIiAiIgk+K+L1Pm+HOoMdo2zSpamt1XV6VnIyPjhhc7ZrnlzGucCGlxGwPpAfnXk/4DPwbOJvAnXGfuZLNYDIaXuulo5GtWsWu38phceSVjZK7A/Ylzd+YAteSN9gvbintG3PLIsufL7N/s8pZi3swGIxcr9uzbv8pje4O8UFCiIgIiICIiAsBqzQWntcwwx5zE1774Hc9ew4Fk9Z3dzwyt2fE7qfSY4Hqeqz6INeN0nrTR55tO6jbqPHtBIxGqSTIPU2O9G0vA+mZkzjv8ody+tPjFjKVmKlqylb0PkJHiNjc1yNqzPPQCK0xzoXk+DS4P6jdgPRXy+NunBkKsta1BHZrStLJIZmB7HtPeCD0I+hB9u9Frx3CV2mgJNBZmXSIYPRxJi8qxLuu+3kpc3sh9ED4vp3Q8ULuk3mLXmDfgK7d/+X6Mht4pw/KkkDQ+t06kzMbGN9hI/vQbDRfGpbgyFWGzVmjs1pmCSOaF4ex7SNw5pHQgjxC+yAiIgIiICIiAvxNDHYifFKxssbxs5jxuHD1EL9ogwWR0Jp3Km861hKL5b1dtSzO2BrJZYWndsbpGgO5QeoG/TwXytaIqy+XOq5HL46a1VZV7StkZS2FrPkuijeXRsf4Fwbu78bdUSIJ23gs63y59DU0jJJa0cVZl+lFPFXlb3ykM7N7+bxaXgb93L3JcfqyqL76sWGyfLXjNOGWWWn2k/wDaCR4bLysPUtIa4juO/eqJEE5d1JlscMi+TTF25FVgiliOPnhkfac75bGNe9mxZ37u2BA6deiZDX2KxDco/Isv0IMbHDLYsT4+fseWTbl5JAwtkIJ2cGklv42w6qjRBi4dU4axfyFGLL0ZLuOMQu1mWWGSr2g3i7Ru+7OcEFvNtuD03WUXQzGAxmoaFijlcdUydKy0MnrXIGyxytB3Ac1wIcAeux8VjMjoLD5F2XkDLVGzljA63ax12arM8w7dmQ+N7S3YAA7bcw9F246IKJFO5DTmWectLjtTXKli6+F8DLMEM8FPk25xGzla4iQfK5nnY9W8vXfm7Jqqo/IyVYMRlIzNF5FXkllpubD0EvaScsoc8dS3ZrQegPL8pBn3sbI0te0OaRsQ4bghYqXSGCnmhlkwuOfLDA+rFI6rGXRwv+XG07bhrvFo6HxXUt6tsYw33XdP5VlavYjginrRsteUtf8A2jGROdIGtPR3M0Ed43HVfeLWmDks2a5yleGavbbRkjsO7I9u4btjHPtzFw6jbffw3QfCrw90/Q8h8jx4oto1X0qzKcr4WRQv+U1rWOAH0HbceBCVdE16HkIq5TMxR06r6sbJclNY5g78eQyueZHt8HvJP51RIgnaumspS8hDNU5KwytVfA9tuGs82Hn5M0hbE08zfU0tafEE9VxVx2qawpNkzeNusjqyMsmXGPZJPP8A2cjXNm5WNH4zOVxPg5qo0QTlabVkIptsU8Na/wAkebUkNqWE+Uj5DY2GN33s+Li7dvqckGezzG1hb0xJzupPsT+RXopWxzt7q7S8xlxd4PIa318qo0QTkWsXfeRawGapOfj3X5A+s2bsS3vgcYXPBm9TWc2/gSuYtf4V/YCSazTdNQdkw27RnrlkDflF/aMbyOHix2zh4hUSIMLR1tp7J+TeSZzHWHWafnCFsdphdJW7u2A33Me/Tm7vpWXilZPEySN7ZI3gOa9h3Dge4gr42sbUvB4s1YbAfG6FwljDuZjvlNO46tPiO4rEP4faac8yMwdGvL5udiBLWhEL20ydzA1zNi1m/UNBAB6jZBQIp1uhqEBjNW3lafZY04uJsWTnLI4vB4jc8sMo8JS0v8C4jouG6YydYM8m1Tkto8aaTI7UVeVhm/FtvPZh7pB3FvOGEfig9UFGinDT1XWb97yeJvBmMEbWT0ZIny3x/aukbKQ2Fw/swzmB6857hyclqasXdrg6VuOPGduX1MgQ+W8O+u1j42gMP4srnj1Fo70FEinHaunrAm7p3L1gzGDIyviiZYax/wCNWAie5z5h6mtLXfiuPckvEPT9Rkz7uQGKZBQZk535OJ9RsFd348jpWtDNvxmuILfxgEFGi6lPK0siGGpcr2g+Js7TDK1/NG4bteNj1aR3HuK7aAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICKY1XxI0/o2zDTyF4yZWdhkr4mjE+1enbvsXMrxh0haCQC/blbv1IWDdk+IerTtjcbQ0RjnAEW81/l19wI67VoniOM+pzpn9e9nTYhsJzmsaXOIa0DcknYAKDv8AHDSEFyWljr8upslGeV9LTlWTIyRu79pDC1zYvDrI5o6jr1XxZwSwmTd2uq7mR1zOepZn5xJV79+lRgZXH0Hsy76SrylRrY2pFVqV4qtaJvLHDAwMYweoNHQBBBnU/ELUDQcRo6np2BxP+UanyLTM0eDhXq9oHb+ozMI/3cN4d6qzR5tRcQsg5hBDqWnKkWMrnf8A1ndrONv9WYLYiIIPH8C9C0LcdyXTtfMZCM7sv52STJ2Wn1iWy6R4/UVdMY2JjWMaGMaNmtaNgB6guSdgT6vUta4fCu4xYiln83esDTmQiZaoYCnM6GIwOHMx1p7CHTPcCCY9xG3fkLXlpe4MtmOMOmMXkZsZWuTZ/MwuDJcZga7708Tj3CURAiH88pYPpXROoeI2ogPNWlsbpes4f851Jd7ewz1f5LWLmO9fWw0/R6rbDYTHadx0OPxVCrjKEDeWKrThbDFGPU1rQAB+YLuoNeDhnnszs7UnEDM22kEPp4NkeKrHf1OjDrA/x/8A16ru4bgrobB3W3odNUrWSHQZHJNN236/6ecvk/8AqVsiDgDYbDuXKIgIiICIiAiIgIiICIiAiIgIvxPPHWhkmmkbFFG0vfI8gNa0Dckk9wCnotbV8tEx2Ary51tjHvyFS5X6UbA32jYLOxZu893Lzej6R6EbhSLHZ3UOP0zjZ7+SsivWh5edwa57t3ODGgNaC5xLiGgAEkkALGPxOdzcZGRyMeJq2ca2GajiuZ0sFpx3kkjtu5S5oHot+9MPe49SA3J4zT2Ow9mezVqMZcsMjjntu3fPO2NvKwSSO3c/Yb7cxPeT3koMfayOeyM9mvjcczGivbij8tynK+OxDtvK+GON/N0+QO05Ou52LQOb6QaPpG4LeQfJm7MV6S/UlyTWSGk9zOzAgAaBGGs3aCBzbOfu4lzic6iAiIgIiICIiAiIgKf0dZ8qhy58vt3+TJ2Y97cPZGLZ/wDRs6DmY3uDvEeKoFO6LnM8OYJvXL/LlLLN7sJjMWz/AOjZv8qNvc13iEFEiIgIiICIiAiIgIiICIiCCucLG4aaS9oe+NIXnyOmlpxQCTGW3u6uM1XcAEnqZIjG8nq5zhuD3tOa7msZOLBakx33P6ieHdjCZRLWvho3c+rLsOcAdSxzWSNAJLeXZxr1jNRacoapxclDIxGSFxDmPje6OWF4+TJG9pDo3tPVr2kEHqCgyaKR4d6hvZSvl8Tl3ibNYG6cfasCMRi0DGyWKcNHQc8UrC4N6B4kaPk7CuQEREBERAREQEREBERAREQEREBERAXwuUK2RiEVuvFaiDg8MmYHtDgdwdj4g9QV90QTz9C4yN8j6Js4mSbINyc7sfYdF28w+VzgHZzXD5TSNj394BQU9SUHs7DIVMrHJknSyi9F2Loabv7OMxghz2eBcPSHQkH0lQogn6uq3tnrV8niL+KsWbctWDeLyiJ/IN2yGSLmbGx7R6Jl5DuOXbcgHL47JVMvSiuUbUN2pMOaOxXkEkbx6w4Eg/qXZWDm0hRFirYomXEzVfKDEKMhihLph6bpIR97kPNs4F7SQ4Ejbd24ZxFMy6is6Wrl2o+zbjatHyi3qJpZDVY9ruV4kjLy6McpD+b0mAB/M5vKOam70BERAREQEREBERAREQYfJaPweYdafdxFKxJaqmjNK+BvaSVydzEXbb8m/Xl3236rqT6Fp8k/kV7K4qSSiygx1S/LyQMZ8h0cTy6Jsg7ufk5iOjiQAFRognLOI1FXGQkx+oIpZJK0cdSLJ0myRwyt6Oe4xOjc4P8AEbjYncdPRS3ltR40XpHYGDKwQVo5IG4661tizN3SRiOYMYwDva4ynfuPL3mjRBOX9fYvDR5OXLC1h6uObA6e3erPZX2l6N5Zdix2x9F2xPKe/YEE52G5XsyzRwzxyyQO5JWMeCY3bA7OA7jsQdj619lg8rorCZkWzPQZHNbkilns1HOrTyPi/oyZYy15Le4de4kdxQZxFPWcLm6klibGZztHT3Y53V8rXE0UUO20kMRjMbm83eHPL+U+BHoj9DU1ijKI8tirFPt8iaNWSo11tkjCN45nljd4mu+SecANd05iC0kM+i69DIVcpUjtUrMNyrJuWTQSB7HbHY7OHQ9QQuwgIiICIiAiIgIiICIiAiIgIiICIiAiLE6o1NU0niJL9tssvpNihrV2c81iVx2ZFG3pu5xIA3IA7yQASA/eo9TYvSOKkyWXux0abCG879yXvcdmsY0bue9xIDWNBc4kAAkgKQ7PV/EEtcZbGhNPO69mxsbstabv4uPMysxw8AHS7O74XDZZPT2kbFnKx6k1N2VrPtDhVrxkur4yN245IQe95adnzbBz+oHKzZgr0GD0rorCaKqSQYagyp2x5p53OdLYsO6+nNM8mSV3U+k9xP0rOIuplMvRwdN1vI3a9Cq07OntStjYD/ecQFYiZm0Dtopb40tHe1OI99j/AIp8aWjvanEe+x/xXvu+N4J0lrZnJUopb40tHe1OI99j/inxpaO9qcR77H/FN3xvBOkmzOSpUHein4Y2pshThfY0hKTJcowML5MfI5xc+xE0bl0R5iXxj5O3M0dXA5P40tHe1OI99j/inxpaO9qcR77H/FN3xvBOkmzOTOtzOPfHj5G3qzo8gQ2m4TNIskxukAjO/p+gxz+m/otJ7gV3F/KbiPn+KWlvhK4TW89GtPp3DZd1jGYnS+TF6hWrPkHbNjaDzNMrQXPcWR8zjvytAa1v9Lo+K2jZY2vGqMSA4AgOtsaf1gncfmKbvjeCdJNmclWilvjS0d7U4j32P+KfGlo72pxHvsf8U3fG8E6SbM5KlFLfGlo72pxHvsf8U+NLR3tTiPfY/wCKbvjeCdJNmclSilvjS0d7U4j32P8AinxpaO9qcR77H/FN3xvBOkmzOSpRS3xpaO9qcR77H/FPjS0d7U4j32P+KbvjeCdJNmclSilvjS0d7U4j32P+KfGlo72pxHvsf8U3fG8E6SbM5KlFLfGlo72pxHvsf8Vicxxz0di4LRr5aDLWYDEPJaU8QdJzu2HK+R7Izt1LvT9Ed+243bvjeCdJNmcl+uN9lF4zVdjWVu5XxOawVeKCzG+J9OyL889UfLLmegIXOd6IO8gAG/edm5RuhsZNL2mSEucezJHK1zlH9uKs+2zOxaRswMHydhuDudy4krxqpqom1UWllzW1xi8lZrQ4x8mYbLblpPsY6MzQV5Ih98Esg9FnKfR2J35twASDt+ce/U2TOItWmUcFCO3N/HbG3M8dRByTgsawgek8cj+vog7DmNCAGgADYDoAFysiexmhsdTONnuGbN5PHwyQw5LKES2NpDvIdwA0F3ceVo9H0RsOioURAREQEREBERAREQEREBERAU7ouwLEOYIyFvI8mUssJtxGMw7P/omb97G9wd4hUSnNFXG3IcyW5C3kOzytqIm3F2ZhIft2TPWxvcHeIQUaIiAiL8SysgifJI9scbAXOe47BoHeSUH7RS7uKGj2OIOqcPuPVejP/wC1x8aWjvanEe+x/wAV0bvjeCdJa2ZyVKKW+NLR3tTiPfY/4p8aWjvanEe+x/xTd8bwTpJszkqUUt8aWjvanEe+x/xT40tHe1OI99j/AIpu+N4J0k2ZyVKKW+NLR3tTiPfY/wCKfGlo72pxHvsf8U3fG8E6SbM5KlfC/frYujYu3bEVSnWjdNNYneGRxMaN3Oc49A0AEknoAFO/Glo72pxHvsf8V1ctr7QedxVzG39Q4W1QuQvr2IJLkfLJG9pa5p69xBI/Wm743gnSTZnJDcP+K+iLfFrXUVfWWAnkyNnHR02R5SBxsyGu1nLGA8855tm7N8enet2L+aPwXvg4YDQHwpNQZXUGaxr9MaVmM2Dtz2Y+S9JJuYHtO+xMbDu7Y+i8NC/oL8aWjvanEe+x/wAU3fG8E6SbM5KlFLfGlo72pxHvsf8AFPjS0d7U4j32P+KbvjeCdJNmclSilvjS0d7U4j32P+KfGlo72pxHvsf8U3fG8E6SbM5KlFLfGlo72pxHvsf8U+NLR3tTiPfY/wCKbvjeCdJNmclSilvjS0d7U4j32P8AinxpaO9qcR77H/FN3xvBOkmzOSpRYDHcQNMZe5HUo6hxdu1IdmQQ243Pf+ZoO5/Us+vKqiqibVxZLWERFhBERAREQEREBERAREQFP2opdMWJ8hDIJMVNM6xkBbsv2qMEXWSBvK4bczGc0e7W+k94PMC19AiD5VrMN2tFYrysnrzMEkcsTg5j2kbhwI6EEddwvqp7DzPxWoLuHmntWWTNN6mXVAyGCHdrHQNkaNnFrvSAcA7lkHyuUkUKAiIgIiICIiAiIgIiICIiAiIgIiIMJJpStFbr2sdI/EyRSzTuip7Mgsvlbs4zRjpIebldzdHbt+UAXA/rEZi06zBi8pX7PLNpssTTVonmpIeYteI3kd4IB5T1Ae3v6lZldPLYinnaD6d+uyzWe5r+R34r2uD2PaR1a5rmtc1w2LXNBBBAKDuIsJicvLFk5cNk7MEuVDZLcJgryRMkq9oWsPpbtL2Ata8NcevK7Zgka0ZtAREQEREBERAREQEREBERAREQFr/Bka44j5PMSOEuK01I7GY5gJ2Nws3tz7dxLWvbA097S2wN9nq8sTsq15ZpXcscbS9zj4ADclRHAuGUcJNL27BJtZOoMtYJfzntrTjZk9Lx9OVyC7REQFCzkZPXmUNgdqMbFAys13URF7XOe4Du5j6I3232btv1KulB1v696o/NV/dldvRfzz8vvDUd7MoiL2ZEREBERAREQEREBERAREQEREBERAREQTuvuSnpfIZZoDLuKgffrTtHpxyRtLuh6dCAWkb7FrnA7gkLYq1xxL/B1qn9F2v3TlsdY6R8KifnP2XuERF89BERAREQEREBERAREQEREBERAU7ou55bDmD5fayHZ5SzFvag7Ixcr9uyZ+UxvcHeIVEp3RdzyyHMHzlZyXZ5SzFzWYOyMOz9uyb+U1vcHeKCiREQFG66cLmY0/ipvTpWXzTTQn5MvZtBa13rHM4HY9CWhWSi9Yf1z0t/2dz/APGNdfRfi/pP0lY4sgAGgADYDuAXKIuhBERAREQEREBERAREQEREBERAREQEREHXv4+vlKkla1C2aB46td/6EHvBHeCOoPcu1w/yM+W0birNmQzWHRcj5Xd7y0lvMfpO2/61+V1+Fv8AUPFf3ZP3jlnF7cGfWPpK9yrREXzkEREBERAREQEREBERAREQT2ri6pLg8i3zxL5LkYmOrYkBwmE29f7+w/KhYZhK4jq3sg7ua4GhU7xDbvorLvDMvIYYe3EeBO16QsIeGw+tx5dtvHcjxVEgIiICIiAiIgIiICIiAiIgIiICIiAiIgn9byyUMMMtE7KOOJk8ufUxEQmmtsa1wfD2X9pu1x2aPS5g0t6gBUC+VmAWa8sLnPY2RhYXRuLXDcbbgjqD9Kw2g5nTaLwZfHlYntpxMc3OAeXbtaG7z7dDIdt3EdCSSgzyIiAiIgIiICIiAiIgIiICIiDBa9ldBobUUrTs5mOsuB326iJy+PDaMRcO9LMb8luKqtHd3di31LniP+DzVH6LtfuXLjhx+DzS/wCiqv7lqCjREQFB1v696o/NV/dlXig639e9Ufmq/uyu3ov5/T7w1HCWZWsNX8WM/jOJU+itN6Pj1DkYsLFmjPYyracIY6aWIxkmN55t428uwIPMdyzl3Oz1CQ6Evx8dLmtDNW81zabgw7YQ53biZlqWUuI5eXk5ZGjfm33B6eK9Jv3MpGn8I6TVmP0dHozS8uez+osbJlvN1u62nHRrxvEcjppeV/XtXdmA1p3IPcF+WfCUOTw+FrYbStq/rjJ5G5ijpqa2yHyWeof8qdLY2c0RsBaQ8Al3aM2G52E/o3gLrbhpjtFZTT9vAW9UYfF28LkKmQlnbTtVpbXlDHMlbGXtexwHewghzh07zzR+D1q/SsmA1Xhcxhrmv62UyeTyUd5ksWOti/ydtEwtDpGBnZRcjtjvyHcddli9QxWlfhBXdBYTiNmNZxPhyb9a+Z8fh7mYYYK8jqdd4iFmQhkcI2kkLtgACfR5jynZHBnj7R4sZnNYQwY6vl8XFDZf5nzEOVpyxSFwDmTxgekHMIcxzWkbtPUHdQ5+DzrLJYzM5S7ksDT1idYM1ZjPJxNNR3FWOB1ecOa1/K5rZGkt69WuG3yRsjE6lzehsNPkdf0sbWknsNhrQaOx97I8jeQk9oWQl53LT6XI1o6DckjexfvGf4m8Q8Xwq0PlNUZgu8hoMaSxjmtdI97wyNgLiGgue5o3JAG+5IAJWn8R8L6laj1BDbxmHlyWPwN3PVYcFqWvlIbDazOd8MkkTd4ZDu3bdrmkcxBPLsqTX9vBfCF0dktGYyzm8Tk5xHbqXr2nL9aKCeCVksbi6eFjCOZjd2825BOy+lnRvEXV+gNZ4LUkGjqFnKYOzjaT8K6wQZ5Yns7SV72AsZ6Q9FrXEdep7kmZmewfrTnG/N5TUOCxeT0Y3DHUuLnyOBkdlWzduYmMeYbAbH95cWyNO7TINt/EbKJ4ecfNZYf4NeW4havwdXJnHMnnglgye0t7a5LG5jmCu1sIZs1rSOfmA32ath/Fblfuq4TZPyin2GksfaqXm87+aR8taOJpiHLsRzMJPMW9Nu/uUI/gRrscEdWcMBa09Lipm2BhsiZp2TuElszgWGdmWt5Q5w3YXb7DoOqn8wvKvFnPY/VGlsZqfSMWn6epLFirTtNygsPilZCJoo5mCJrWPkaJhs17gHRbAu5gRQ8N9fniLVzl2LH+SY6ll7OMp2e27Ty1kDuzfMByjlHaCRoG7t+TffrsIT4WVuEcMW0qk8sesZbtezpmOtC6WeTIwytfHyNAPTvDi70Q1zt+izenspp/gLozTWj7bcvYko4+Npmx+EvXmyv6iSRz4IXtDnP53EEg+lvt1C1e0jJcVOJlvh5Y0rUoYF2oL2oMmcZBA222uI39hLKHuc5pHL962PiASQHEBpkpPhHvx2CzDMppeWDWOPzsGnWafqXWzNtW542SQdnYLWARujfzlzmgtDXbjoN8hmo4+MuoND5XAPs162l855wutzGMuY98kbqs8QETZoW855pGk+AAPXfYHA6p4BZ7M6j1hnqORx1XJz6kxmpMEZud8bZKtSOB0dloaCGvAlbuwkgOB7xspN+4d+x8JD7lqeqINZaYnweo8JDVsR4mjbbeGRZZkMVfyeTlZzF0oMZDmt5T16jqpeDjBqTA8aMnkde4qbSGExehrGVlxlfLC/A/ktx/feVrWN7UDdnyfHYOIK7Oofg96t4jyam1FqXK4jF6xtRY+HDMxQlnp48U7Bsx87pGsdJzyuPN6I2b3br6ZPgdrTijqPOXNfzaeoU8npKfTfJp+aeZ8cj52Sib77G0EDlJ236EAdd9xP5h2uHXwrsfrXW2D09bpYeq/OiXyB+J1JVykrHMjMvJZii2MLixruoL27jl5tyFvpan0PX19o6sJtbx6Ynw+Loua65p+ranv23t5Q2TsRH6JLQ7djO0JLumwGxyU3G7C5CJ9XEV847LTtMVMX9MZWCuZndI+1kNXZjOYjmce4bnwWom3ERlLirl5fhEljrP/uJZnm0lXaSQ3ztDELTpN+7qDNB/ehW+V5pPwSLdHhdi4aGoLz+IlCeDMstWs1cdijlGzCaWXyfcsDXuMo3Ee+zydtyV6WSm/eJviX+DrVP6LtfunLY61xxL/B1qn9F2v3TlsdOkfBo9avpSvcIiL56CIiAiIgIiICIiAiIgIiICIiApzRV3y2HMHzlYyXZZWzFzWYOyMPK/bsm/lNb3B3iqNTmir3l0GYd5znyfZ5W1FzWIOyMHK/bsW/lNb3B3j3oKNERAUXrD+uelv+zuf/jGrRResP656W/7O5/+Ma6+i/F/Sr/zKwyKhOLPEuzw1q6bNPBvz9zOZiPDQ1mWm1+WSSKZ7XlzgRtvEAfUHEjcjlN2oTinoS/re7oWajNWibgtSV8xZFhzml8LIZ2FrNmnd+8rdgdhsD19ftN7diJGb4Rz8NidSxZzS8tTVuGylPDswVC62y27YttY6qIp3NYOV/P1Lmjl5XdDt15sfCO+5GHU8Gu9NS6bzOEx8OTZRo3BfbfgmlMMYgkDGbvM20Za5o2Lmncg7rpay4BZrUmp9b5ypkqFO9dymGzWCkkD5GxWaMYHLYZsPQeeZvoknZ2/eNjjdTfB81ZxUdqnM6vymIxOo7mMq43ER4TtZ61EV7Qttke+RrHSOdM1m4DQA1u3UndY/mHXh4tapx3G2vc1zh5dFYKjovJZaehFlxege2OesTI9rGtHasbzDuPy9muO5Xf0F8LjGaw1dp/D2aOJqw6gkdFQfjtSVcjaif2bpGttV4vShLmtI3BeA7ZpI3XNzgxrniXquze4gyacqY+1pS/puWPT09iSTmsSQu7UdrG0bARu6b9Dt1dv0z+gcZr7QOPqx6wGmLeAwtIxuyGEqWpsjc5GhrH9g1noOIG7ms7QknpskXuNvucGNLnENaBuSe4Lzfjvhr6fyOWoSx1sS7Td+/HQgsx6irPyfpydkyZ+PHptjLiD8ovDTzFg2IW0a/GjS2ZsRY9tfURdbcIAJtLZSJhLjy+k91cNaOvVxIA7yQpHhRww19wvhxOlGy6Vyei8XM5kGSnZMMo6ru5zInRhvZ87dw3tOfYhvyd1qZmeA+Fn4SmUqV83mJdEFuk8JqKXT+QynnVhmaW2xXE8cHZ+mzdzC4FzSNyBzAcx7mi9ea6yvwhtfaes42jPpbGCgGSHI8slNkkMrw9kYg++OkcBzBzxybDYuXRy3AjP3+EfEDS0dzGjIag1NZzVWV0snZMhkvMsNbIeTcP5GEEAEb7dduqpoNCar07xrzWqMNLh7WntRw0o8nDekljtVnVw9gdAGsc14c1/c4t2IU7e8SGF+E1qDKcMGcRbHD9lHSLOU2J35nnssjFpsMsrYhB6TGNMkm5c0kRkbAEOW0MbxCGX4o5XSVOiJ62Lxde/bybZ/Rjlne8RQBnL1JZG55dzdAW9DvuJHSGksfwh+DhFp3X1yl5sp0Z6uTngL5IHRzSPGw3YHHcShu3LvuVMfBtoy8IeCtbO6xOWtZjOWGyzyMxdm1b7JkTYKjXxQxukbtXgjJ3aNnOIPU9UTPZcbZ4r6+bwu4c6g1Y+kcizE1XWXVWy9mZQCOgdsdu/1KOj49T4HPZPH62039y0VfBT6jgsRX23O0qwOaJmvDWN5JW87DyNL2nfo47Lp8Ts7Q478ONTaF04cnVzOYoSQV5szgclRqtd37vlkrhrR0/OfAFd/iVwVm4kazitWrMEOCl0rk9PWg1zvKA+06HlewcvKQ0RuPUjry9D12szPcPhpbjxlbmc01V1VoyTSeO1RDJLh7z8kyyXFkRm7OwwMb2LzEHOABePRIJ3UDqzjhqnXEXDzLYbTt3A6LyusMdBVzYyojnv1zMWntKzWgthlAOwLjuNt2gFVOI4P641NmtGs19ewMmE0nFKK7cMZjNkpnV3V2yzCRoEQDHvPK0v3ce/bosJjOB3Eulg9CaQsZDTFvS+kM7RvVshz2GXrFStISxj4+QxtkDDtuHEHYfJ71mdocZX4bOnsdkrlhlfEz6ap3nUZbR1HVZkncsvZPmjx59N0YduRu4Oc0cwbsRv6SWjuH/CvXfDCy3TuIfpXI6HZk5LUFrIsn84160sxlkg5Gt5HuBe8NkLxtuN2nbZWNjjnpetPJC+DUpfG4sdyaUyrm7g7dCKxBH0g7LUTP5h5x4x60fjOJvGQzaq1tjspiqtB2noMNZuDHwTvph284ANaNhk5S4zFo5ec+teutLW7F/TGIs27Fa3bmpwyTWKbg6CV5YC50ZHQtJJII8CFpS5oTiPLrbXmodIfcwcJrerRMc2dktxWqjY6vZEurdh1PpE8jntI2AOx3A2zwy0THw34e6d0tFbfeZiKMVPymRvKZeRoBdtudtyO7c7DopTe4pl1+Fv9Q8V/dk/eOXYXX4W/wBQ8V/dk/eOW8X4E+sfSV7lWiIvmoIiICIiAiIgIiICIiAiIgneIzO04e6nbyZaTfF2hyYA7ZB33p3SsfCb8j/W5VQg7jdT3EYb8PdTjky8m+Ltehp87ZF33p3Sr/8AP/I/1uVUIGwA/wB6DlERAREQEREBERAREQEREBERAREQEREBTvD5vJpKm3ky8fK+YcudO9v+lf8ALPq/J/1eVUSnOHu33J1OUZkDtJ+mf/55/TP+X9H5P+pyoKNERAREQEREBERAREQEREBERBO8R/weao/Rdr9y5ccOPweaX/RVX9y1c8R/weao/Rdr9y5ccOPweaX/AEVV/ctQUaIiAoOt/XvVH5qv7sq8ULZ5cVrvJ+UuETclFA+s9/RsjmNc17Ae7mHQ7b7kHfboV29F/PHy+8NR3suiIvZkREQEREBERAREQEREBERAREQEREBERBN8S/wdap/Rdr905bHWutellzTN/DscH3stBJRrQNPpyPkaW9B16AEuJ22AaSdgCtirHSPhUR85+y9wiIvnoIiICIiAiIgIiICIiAiIgIi/MkjYmOe9wYxo3c5x2AHrKD9Kc0ReGRo5OUZOfKNblbkIfYg7Ew8k72GFo/GawtLQ78YDfxWJynHLQGItupzauxU99vfRo2Bas/4MXM//AOlTukOLs+RxcoxOn9XazL7dyWO6/FMxsYYZ5XRxA2nwgtjaWxBw3JDAT1JQbbRa6898UMv/AM00tp7ARHulyuXkszN/PDDCGn9UyfcVr/Lf9K8RhjmnvZpnCQ1th6ua06yf1jb6NkGxVC6uuV3680zWbPG6yyK298IeC9oLWbEjvAXU+IvAXeubyWotSuPym5TOWjC788Eb2Qn/AMi6l/h7pfhxk8LkcDp7F6eoMfLFclx1OOAffGjlfKWNG45htzO7i7cldfRfi/pP0lY4q1Fw1we0OaQ5pG4I7iuV0IIiICIiAiIgIiICIiAiIgIiICIiAiIgLr8Lf6h4r+7J+8cuMhka2KqvsW5mwwt73O7yfAAd5J7gB1J6BSemdDa+w2Cpvxes4apeztTic7h47UNcuJcY2uhfBINt9t3OeQfX3LOL2YM+sfSV7m2EWuvuk4lYX/pDRmKz8I/ttP5js5n/APcWWRsb/jFPjww+P6agwupNLPHynZPDzPgb/esQCWAfrkXzkbFRYHTevdM6xBOB1Di8zsA4ihcjmLQRv1DSSP1rPICIiAiIgIiICIiAiIgneIo59BahZy5d/aUJo9tPnbIekwjeufCXr6J8DsVRKd183tdNPgDcufKbNWvzYI8tqMPsRsLw78Vjebme7wjDyqJAREQEREBERAREQEREBERAREQEREBERAU5w+PNpOoebLv++Telnhtb/pn/AC/o/J/1eVUaneH+/wByVInzwSXSn/l//nn9K75f0fk/6vKgokREBERAREQEREBERAREQEREE7xH/B5qj9F2v3Llxw4/B5pf9FVf3LVzxH/B5qj9F2v3Llxw4/B5pf8ARVX9y1BRoiIC6uTxVLNVH1MhTr36r/lQWYmyMd+drgQu0isTMTeBLfFXoz2Twn7Pi/lT4q9GeyeE/Z8X8qqUXvvGN451lbzmlvir0Z7J4T9nxfyp8VejPZPCfs+L+VVKJvGN451kvOaW+KvRnsnhP2fF/KnxV6M9k8J+z4v5VUom8Y3jnWS85pb4q9GeyeE/Z8X8qfFXoz2Twn7Pi/lVSibxjeOdZLzmlvir0Z7J4T9nxfyp8VejPZPCfs+L+VVKJvGN451kvObXWi+FGko9Pxtn0ZUrydvYJjydaKafbt37Eu2PokbFo8Glo8FnPir0Z7J4T9nxfyr76BgNbTMcZoXMafKbR8nvTGWUb2JDzFx/FdvzNHg1zR4KiTeMbxzrJec0t8VejPZPCfs+L+VPir0Z7J4T9nxfyqpRN4xvHOsl5zS3xV6M9k8J+z4v5U+KvRnsnhP2fF/KqlE3jG8c6yXnNLfFXoz2Twn7Pi/lT4q9GeyeE/Z8X8qqUTeMbxzrJec0t8VejPZPCfs+L+VPir0Z7J4T9nxfyqpRN4xvHOsl5zYnDaTwmnXufisPRxr3N5HOqVmREt332JaB0367LLIi8aqqq5vVN5QREWQREQERfmSRsTHPe4MY0Euc47AD1lB+kUHkeOmg8fbkps1LUyl+M7Po4UPyVlp9RhrtkeD/ALK67uKGcyh5cBw71BdY4Att5UwYyD9bZZO3H+CUGxEWvHw8VMyetrSmlIiBu2OGxlpR06gOLqzQfpLXD6Fx8U2RynXP8QdU5Rp+VXpWIsXEPoaasccoH55CfpQXeQyVPEVX2r1qClWZ8qaxII2N/OSQAoexx80G2Qx0c83UE3Udlp2tNlX777bbVmSbdQR17tuq+1DgXoGhajtO0rj8jej+ReyzDfst8ek05e//ANVcQwx14mRxMbHGwbNYwbAD1AINffGfn8oNsHw41BZafk2ctJWx0P62vkMw/wAJNuK2YaPS0jpRp7xtZzDwPz71QD/4gfStiIg138WGeyjR574j6hstJ9KvimVsdCfzGOIzD/FX6ZwB0FK9j8lgG6jlZ1EmpLM2VdvvvvvZfJ13/wDDw7lsJEGNiq4vSWHmNapXxuOqxuldHVhDGNa0bkhrR6h4BdbRHbfcfhXWchPlZ31IpH3bUHYSzlzQeZ0f4hO/yfDuXx1zZczAupxW7tC1kpWUILWOh7WaF0h27QA9GhreZxcejQ0nrsAaFAREQF+ZI2TRuY9oexwLXNcNwQe8EL9IgmH8LtHSPLnaUwpce8+b4v5V+fir0Z7J4T9nxfyqpRdG8Y3jnWVvOaW+KvRnsnhP2fF/KnxV6M9k8J+z4v5VUom8Y3jnWS85pb4q9GeyeE/Z8X8qfFXoz2Twn7Pi/lVSibxjeOdZLzmlvir0Z7J4T9nxfyp8VejPZPCfs+L+VVKJvGN451kvOaW+KvRnsnhP2fF/KnxV6M9k8J+z4v5VUom8Y3jnWS85tO6P4d6Xs8TOIFWbT2KmrVpKHYQPpxOZCHVwXcrdvR3PU9BuVc/FXoz2Twn7Pi/lWH0zvU4166rOd0s4zFX2Dr1BNqF30f2I7uvUb94WwU3jG8c6yXnNLfFXoz2Twn7Pi/lT4q9GeyeE/Z8X8qqUTeMbxzrJec0t8VejPZPCfs+L+VPir0Z7J4T9nxfyqpRN4xvHOsl5zS3xV6M9k8J+z4v5U+KvRnsnhP2fF/KqlE3jG8c6yXnNLfFXoz2Twn7Pi/lT4q9GeyeE/Z8X8qqUTeMbxzrJec2AxmgdM4W2y1Q07iqVpnyJ69KNj2/mcBuFn0ReVVdVc3rm5e4iIsIm9S8N9KaykEud01istOBs2e5TjklZ029F5HM07eIIWAPBajjmAae1LqjTBaSWtp5Z9qJv92G2Jomjp3BgHf06lbDRBr0YTiXhnt8j1Rg9Q1hsDDmMW+tYd6yZ4JOT/wCwvyNf6yxB2znDi5M0fKs6ayUF+Jv08svk8p/2YyfoWxEQa8j4+aIheI8tlZdLSkhvJqalPixzHuAfYYxrv9lxB8Fc43KUszUZboW4L1V/yJ60rZGO/M4EgrsPY2VjmPaHscNnNcNwR6iofJcDdCZK0+2NNU8beed3XsPzY6yT6zNXLH7/AO0gukWu/iuzeJ66f4h6gpMb8mpluxykH+06Vnbn/GCG1xUwe3a0NLatiHypKtifEzEf6sTxYa4/QZGj6fBBsRFrx3GB2JPLqLRmqcEABvPHjvOUPd381N0xA+l7W7eOwWY05xW0bq646niNT4q9faeV9GO2wWWH1OiJD2n6CAgq0REE7qOI389p2n2WUEbLD7zrFJ/JA3smFojnPi1xlBDB3lm/c0qiU9gar7udyuasVLFSV3LQrCS2JY5a8Zc4TNY08sZe+R/rcWsj5ttg1tCgIiICIiAiIgIiICIiAiIgIiICIiAiIgKc4eADRmM5RmQCxx21B/z4bvcfvv0+r6NlRqc4dEP0LgngZlofTjfy6h/6QbuN9rH/AMwb7EeBQUaIiAiIgIiICIiAiIgIiICIiCd4j/g81R+i7X7ly44cfg80v+iqv7lq54jHbh7qc+rF2u//ALJycOTvw90ufXi6vd/2TUFEiIgIiICIiAiIgIiICIiAiIgndA1G0dMxwtx9vGAWbTvJr0vayjexIeYu3PR2/M0eDXAeColO6BptoaZihZRtY1os2neT3ZTJIOaxI4uLj4O35gPBrgPBUSAiIgIiICIiAiIgIiICKU1RqzIQZAYPTdCHK590bZpPKpTFVpROJAlmeGuPUtdyxtHM8tPVrQ57cYeFP3QOdLrLOXdUF5383tJp41g3B5RXjd98b0/t3ynqeu3RB2M1xl0jhr8mOblDl8tH8rGYOvLkbTeu3pRQNe5g3B6vAA2O5ABXTGtNcZ7nGE0J5ri29C3qjIx1+br8psNcTPPTfo/sz+ZWmGweO07joqGJx9XGUYhtHVpwthiYPoa0ABd5Brv7iddZwb5viAcbGe+tpbFxVht+SZLBsOP95vIfVsv23gNou06OTM4yXVczOok1LbmyY3333DJ3OY07/ktG3gtgog62OxtPEVI6tGrBSqxjZkFeMRsb+ZoAAXZREBERAREQEREBEWFymbkOQ804qWlPmGtisTwWJHDyes+Qt7VwaCdzySBjTyh5jeA4BriA+bI5cpqx05OTqV8VG+ARlwZVuSStjdz7fKeYwOUHcN3lkGznNBbnl0cHhKenMTVxuPiMNSszkY18jpHnxLnPcS57iSSXOJc4kkkkkrvICIiAiIgIiICIiAiIgIiICIiDX2r2nTfE7Seo+z/yO/HLp+9IAfvZlLZar3fR2sbov71lv0rYKx+fwNHU+FuYrJQCzRtxmKWMkgkHxBHVrgdiHDYggEEEKb05qO5gLtXTOqbHPkXN5KGXeAyPKtaPHYBrLIHV0Y2DgC+Mcoe2MLRERAREQEREBERAREQEREBERAREQEREBERAWH1Fo7A6ugbDncJjs1Ezq1mQqRzhp+gPB2WYX5e9sbHOc4Na0blxOwAQa9HA3CY70tO5TP6TePktxGWl8nZ+atKZIB/hrDXsXxD7W9hMVqvDathiDI78WoMbLVmbFIx33sWqhbH2hHKSBFzMa9ryNnM5rzznd1FN2WNa6njWTWaty3ZjkhsczByA12ObsR2hJ7R3okR+iHh4cMzjqEWLx9WlAZDBWibDGZpXyv5WgAcz3kucdh1c4knvJJQa9p641FpOnXp5bhpdrUq8bYmyaWtQ5CrCxo2DWsPYzbAAbBsJ6epZGhxu0RdyDcfLqCvicm5xa2hmmPx1l5HeGxWGsc79QKuV1cli6WapyVMhTgvVJBs+CzE2SNw+lrgQUHZa4PaHNIc0jcEdxXK178ROlKEna6fivaPlB5gNOXpaUG/012O7B3+1GVw3T/EbTxb5v1VjdU1mnrBqKgK9lw//AMmrysHj/wBXO/0eIbDRa+bxQymFaBqrRWZxIHNz3cU0ZapsBvuDCO2A7+roW9ypNL6707rWOR+CzdHKmLbtY607XSQk+EjN+Zh+hwBQZ1ERAREQEREBERAREQEREBERB8rc3k1WaXkkk7NjnckTeZ7thvs0eJ9QWI0NAa2idPQmTKTGPHV2dpm3c1920bRvYPjMfxz+Vuudb2XUtF5+w2LJzuioTvEWFbzXnkRuIFceMp/E/wBbZZOhV8io1q/ayz9jG2PtZ388j9gBu53iT4n1oOwiIgIiICIiAiIgIiICIiAiIgneI/4PNUfou1+5cuOHH4PNL/oqr+5aueI/4PNUfou1+5cuOHH4PNL/AKKq/uWoKNERAREQEREBERAREQEREBERBOcP6vkemI4vN9vF7WbTvJrs3ayjexIeYu9Tt+Zo8GuA8FRqd0DVNPTMcRo3McRZtO8nvzdrKN7Eh5i71O35mjwa5o8FRICIiAiIgIiICIiAiIgis3ir2ldSXdVYipJlI7kEUOUxcZHavEXNyTwbnYvAe5roztztDS0hzOWSh03qbF6uxMeSxFyO9TeXM52bhzHtOz43tOzmPa4FrmOAc0gggEELKKP1LoaeXKv1Bpq8MLqMta2Yubz1Mi1o2EdqPx2HRsrSJGbDYlnNG4LBF5Kxvw+8XkfhI4vhlNgnYmqJ58Rk79uYPLMo2QxtjhLDsYeZhbzuAc4yN3bHyEO9aoCIiAiIgIiICIiAi61zI1ce6BtmxHC+w/soWPcA6V/KXcrB3udytcdh12aT4LA9jktY1iLLZsPgL1AB1YOkr5Nsrndd5Y3jsQIwB6J593kh0ZZ6Qd2XUBuX3UsQ2DIT1bkdfIky8rabTH2h36HmfylmzB1HasJ2B693DYw4fGV6jrdm/JG307dx4dNM49XPcQAASSTs0NaO5rWtAA7UUTIWBkbQxg7g0bBftAREQEREBERAREQEREBERAREQEREBdHN4OhqTFz43KVIr1GcASQzN3B2Ic0/QQ4AgjqCAQQQF3kQa+ZHqfhu0hpt6100zuY4h+WpsAP4xIFtg6DrtNsO+ZxVZprVOJ1hi25DDXor1UuMbnM3Do3j5Ub2nZzHt7ixwDgehAWVUpqPh7Uy+SOZxtufT2ow0N8648N5pmjbZk8bgWTM6bbPG7QTyOYTugq0Xm34Q3wrcn8GvQz36k09Dd1Rb3gw89KZox994HpyuYX9tEI9wXRkEemxrZTzOczcnCfiZiOMPD7DatwknNRyUAk7Mnd0Mnc+J3+s1wIPr23HQhBXIiICIiAiIgIiICIiAiIgIi6GTz+Nws9CG9egqTX5xWqRSyBr7EpBPIwd7jsHHYdwBJ6AoO+vzJIyGNz3uDGNBc5zjsAB3klYCpncrmX46WjhzVx8z522pcq90E8IZuInMgDSX87uuznRkN695AX4p6O8ogru1Belz1ttSWpYD94qc7ZDu/mqhxjPTZoLw4hu439JxcH6tasfdbPBp6p53u+RMuVppC+HHzB52jHlQY9p3G7jyB7g3YlvpN5v3JpRmVszy5uYZiu+avYgx9iFhrVJIQC1zBy7ud2np7vLti1nLsWgrORRMgiZHGxscbAGtY0bBoHcAPAL9oCIiAiIgIiICm9U8ONM60kjmzOFqXLcRBiu8nZ2YSN9jHM3aRh6nq1w71SIg147Q2rdMgO0vrCS5WZ3YvVUZus22+Syy0tnaenypHTePRDxWt6cPJrTS+Q0+wHY5Ohvkscfp7WJokjb63TRRt6962GiDH4HUOK1TjIclhcnTy+OmG8duhYZPE8fQ9pIP6isgo3OcJNN5nJvysNabB5t7ud2Vwk76ViR3rkMZAmHT5Moe36FjvJuIukW/eLdDX1Bg+ReDcdku/v7SNvYSu28OzhH0+oNhotXak+EXpTROBy2R1RHkdL2MdWmsux+YriCWz2bS7s68hd2M73bbNbHK7ckDou3wH46ac+EDoKrqTAS8jyBHdx8jgZaU23WN/rHqdts4denUANjIiICIiAiIgIiIJzX/M/Tbq7BmOa1aq1efBO5bMQksRsMgd+KxgcXPd4Ma/brsqNYDUMRuZrT1fs8oGNtPtOmoyckDeSJwDbB33cxxeNmjvc1pPQFZ9AREQEREBERAREQEREBERAREQTvEf8AB5qj9F2v3Llxw4/B5pf9FVf3LVzxH/B5qj9F2v3Llxw4/B5pf9FVf3LUFGiIgIiICIiAiIgIiICIiAiIgndAVDR0xHCaV3H7WbTuwvzdrKN7Eh5i78l2/M0eDXNHgqJTugKfkGmY4fN9rF7WbTvJrk/bSDmsSO5ub1O35gPAOA8FRICIiCb1Rm7de7TxONcyG7bjkmdZlZztgiYWhxDe4vJe0NBO3ynHm5eV2Gdic647/dnlm9O5talt/wCtcr7Z78JON/RNj99Csovq0Ww6KbRHbF+2InvnNrgwnmfO+2mY92o/Z08z5320zHu1H7Os2i11nlj208kuwnmfO+2mY92o/Z08z5320zHu1H7Os2idZ5Y9tPIuwnmfO+2mY92o/Z08z5320zHu1H7Os2idZ5Y9tPIuwnmfO+2mY92o/Z08z5320zHu1H7Os2idZ5Y9tPIu80T/APs+OFE9xtoV8nXnbIJWvq2Ww8rgdwQGMAH6lvpmEzkbGtGtcyQ0bDmgpE/rJr9VnUTrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F0tFovIR3jcOrsxNbD3yMmnhpyuiLmta4Rl1c9m0hjd2s2HTfbckrveZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs67uIy+TxObqY7JWzlKt8vZXtPiayWOVrXP5H8gDS0sa4ggAgt2PNzej3lhM1/WjRX6Wk/4C2r2YkTTVEcJ7ojhEz3QsTdfIiL47IiIgLqZXJQ4bF3MhY5vJ6sL55OQbnla0uOw8TsF21L8U/wY6v/AEPc/cvXrhUxXiU0T3zCx2yxTY9R5eJtmxnrGGkl2eKePggcyEeDS6WJ5cQCNz03I6ADouPM+d9tMx7tR+zrNjuRfS27cKY0jkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXaY4tfBX0zxzvULet8xnc5LQjdFVabTIY4WuO7i2OKNrQ52w3dtuQ1oJIa3bK8KPg/YzghhreJ0XqHO4jG2p/KZKzpYbDO02DS5olifykgAHl232G/cFtJE6zyx7aeRdhPM+d9tMx7tR+zp5nzvtpmPdqP2dZtE6zyx7aeRdhPM+d9tMx7tR+zp5nzvtpmPdqP2dZtE6zyx7aeRdhPM+d9tMx7tR+zp5nzvtpmPdqP2dZtE6zyx7aeRdhPM+d9tMx7tR+zp5nzvtpmPdqP2dZtE6zyx7aeRdhPM+d9tMx7tR+zp5nzvtpmPdqP2dZtE6zyx7aeRdhPM+d9tMx7tR+zp5nzvtpmPdqP2dZtE6zyx7aeRdP2dP5u1GGP1tm2gOa/eOKmw7ggjq2uDt06juI6HcFdPD6GtafFvzdqfJVDbsSW7Do6lEOmmeQXvcfJ9yTsBufBoHcAFWInWeWPbTyLsJ5nzvtpmPdqP2dPM+d9tMx7tR+zrNonWeWPbTyLsJ5nzvtpmPdqP2dPM+d9tMx7tR+zrNonWeWPbTyLsI8aiwsLrcOesZp0IL3U78EDWygd7Q6KNhadgdj1G56ghWmMyEOXxtS9X5jBahZPHzDY8rmgjcfmKwc/9BJ/dP8AuXPDP8G+lP0TU/csXhjxFWHt2iJibdkW43y9F4xdSoiL57IiIgKOyuXyWYzV3H424cXVx7mRz2mRNfNLK5rX8jOcFrWhjm7nZxJdt6PL6VioHB/1j1l+lm/8HWXZ0amJmqqY4R94hYPM+d9tMx7tR+zp5nzvtpmPdqP2dZtF19Z5Y9tPIuwnmfO+2mY92o/Z08z5320zHu1H7Os2idZ5Y9tPIuguIXCZvFTSF/S+p9TZnJYK/wBn5TVDasPackjZG+nHA1w2cxp6Eb7bHpuFHcKvglaU4JZixlNFZfP4S3Yi7GYttsmjkb37OjkY5p28CRuPBbuROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXYTzPnfbTMe7Ufs6eZ877aZj3aj9nWbROs8se2nkXTD9I5STMQ5N2s84bkMElZh5KnIGPcxzvQ7DlJJjZ6RG422B2J37nmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OnmfO+2mY92o/Z1m0TrPLHtp5F2E8z5320zHu1H7OuRiM607/AHZ5Z30OrUtv/SuFmkTrPLHtp5F3Gl83bnvXMRknsmu1Y2TMsxs5BPE8uAJb3B4LCHAHY+i4bc3K2kURg/wk3/0TB++lVuuLpNMU4nZ3xE/sSneI/wCDzVH6LtfuXLjhx+DzS/6Kq/uWrniKN+H2px68Xa/dOThz04e6X/RdXx3/ALJq5UUSIiAiIgIiICIiAiIgIiICIiCc4f1BS0xFEMfbxYFm07ya7N2so3sSHm5vU7fmaPBrgPBUanOH9YVNMRxCneoAWbTuwyMnaTDexIeYn8l2/M0eDXNHgqNAREQRGe/CTjf0TY/fQrKLF578JON/RNj99Csovq/ko9PvLU9wi0dxx05j9W8ZuD2Iy1cXcZZkywsVHucI52tqNeGvAI5m8zWktO4O3UFag7CtSiZozIWH0OGsPFC5ibdczujgjq+RNnr1HO39GB1h+3LuB8kfQvKarMvaCm6uvMfc4hZHRzIbIydHHQZOSVzW9iYpZJI2hp5t+YGJ24LQNiOp8PJGqL9HTF3XOl9O5F+N4SjVGn6OQnoWnCtQinY/y+KKYH70wubWD+VwDe2cOm5C/OvqeL4Y5bjGeFfk+Oig0dinudh5TMKwddmbYkbyuJa5sBc/0SD+N0J3WZrHt1F5u4HcMKmnuIGNzGA1lo99J+NldZxGla88ZyMT+Xs55hJcm5ix220nLzHncC47reuuv6kah/R1j905bibwM4i8h8PtK0NGY74NmocFVFXO56m2tk7RleX32PxMkvJM4kl7WyMYWg9G8oDdgNlPaXjwdXh1wy1lQu9txiyepakGRn8qcb9mV9ktu1p2b7iJkfaAtIDWBjSNu9Z2h654i68x/DLReU1PlIbNihj2NfLHTa10rg57WDlDnNHe4d5CpF4Q4iYzSmrOD3FbU+qLNezxMq56zT5bdwtsUI47jWV68MfMNozCGkADZ/MSd1ndR6ZdxM4j8VDqjVGlcDksRkjWpP1HBY8rxtHsIzXsVZG3IWxNJLn8wZuX83MSNgJtj2kixumaF3FabxNLI3zlchWqRQ2b5ZyeUytYA+Xl3O3MQXbbnbdeZuMuKm158Ii1p3PZPTdHD1MDBcxFPVdWeerO8ySCxLEGWYG9q3aMEnmIbsRy9SdzNh6rWF1JrDFaSfiGZOwYH5a/HjKbWxud2lh7XOa3oOnRjzudh09ey81YbhlRva+4R6Z1JmK2v8UNO5qZlprnmrbgNiq+FhBkf2sbGuYG87ng8jD1IBUpktOYDJ6A0PR1DTq3sJgeKt3BQuyYEjK+P7e0xsLnP3+97thbsTt6LB4BZmqR7aRecW8ONI6x+E3bp2sbTyWAx2iMaKWPGzqYAt2mxuDB6LuRrdm9/LudlMDHzM1+zgGYX+aW6lGp2jlPZeY9zb7H8wujsf7uyu0PWqIvFWr9KYscMeOWtRXP3VYLV9ybF5TtH9rSMcld4ER39AEudzBu3NzHfforM2HtVfieYV4JJXAlrGlxA79gN15I1zj9JaizfHTJ8Qb0cGoMAQMG6xcdDLjqgpMkrzVBzDZ75jIeZvVzhy9e5fDTMWJ4natyMfGaaIZTGaRw9rGY/K2jWjjdNVL7lpjeZoMonBYXjqzkA3Cztdw9Q8P9bUeJGicLqjGRWIMflqzLUEdtrWytY4bgODXOAP5iVQLwVpWlZ1fi+DGlstkcDR02/Q7LtKvqitNPRt3hNyygNjsQh0rIuzLQ4u2DnkDc7r1fwD0vNpHh5FQdqanqumbU8tK3jw7yeGAvO1eMvllcWRkOaN3uIAA8EpquMhxR4qU+FdPCS2cPlc7YzGRZi6dLDxxPmfM6OSQf0skbQNondd+/bouxw74mY3iTVyTqdS/i7+LtGnfxeVgENmrLyteA9oLmkFrmuDmuIIPQrW/wqYJLM/CeKLLyYCR+soA3JQiIvrnyS16QErXM/wDM0jqvl8HG62jxB4pacjykWrBUuVL82qWhpmuTTxEOhmLD2fNE2JjQIw1oaQOUHfe3nasN9qb0PxCwnEODLzYSz5THisnPibR2HozwkB4Gx6jqCD4ghYjjjr2bhvwuzmZpM7fL9kKmMrjYumuzOEVdgHj98e3ceoFaa4DWZ+G3FijpaxpnNaYxuodPQMhOb8nL7eSosDZpG9jNKN5IXsc4uIJMSTNpsPUCwma/rRor9LSf8BbWbWEzX9aNFfpaT/gLa98PjPpV9JWF8iIvkIIiICl+Kf4MdX/oe5+5eqhS/FP8GOr/AND3P3L10dH+NR6x9VjjD6juRB3LB66/qRqH9HWP3Tl1oziLyHw+0rQ0Zjvg2ahwVUVc7nqba2TtGV5ffY/EyS8kziSXtbIxhaD0bygN2A2U9pePB1eHXDLWVC723GLJ6lqQZGfypxv2ZX2S27WnZvuImR9oC0gNYGNI27157Q9c8Q9eY/hppK3qLKQ2Z6VaSCJ8dRrXSEyzMhbsHOaNg6RpPXuB7+5Ui8IaoxulNUcFtU6u1FYr2uKo1QK1ryq4RapFmWZHHVjjLvRjEAaQ3bY7l3eOmd1Hpl3EziPxUOqNUaVwOSxGSNak/UcFjyvG0ewjNexVkbchbE0kufzBm5fzcxI2Am2PaSLG6ZoXcVpvE0sjfOVyFapFDZvlnJ5TK1gD5eXc7cxBdtudt1pLVWgcBxE+FPkMdqTGx5fHM0TVkFSw5xhL/LrLQ8sB2Lmgu5XEbt3O2263M2G/0XijhV5s4iWeGmH4l22ZHTMejrE2Pr5eyW17V2K8+F73kkCSSOBsW2+5Ae5w9a/Om8lU1TT4aaZ1Vk5ZuFdvOaggpTXrbmw5KGvLtjYppSQXs5TIWtc7Z/ZNHXYBZ2x610jrzH6zyGpqdKGzFLgMmcVaNhrQ18oijl5mbOO7eWVo3Ox3B6eJpF4LvwVMLUz2ndPX8biNB3uJr6N6zYdLPj2xebYTFDMY5o3di6YBpHaNaC1oPo7tPoz4PHD77hruqTT1RgcriZ5II24bTcEkVPGzsaS8tY+xMWOka+MloLR6IO3VIqmewboRak+Fbmsvp/gPqS7hbMlKdprssXIWvL69V1iNtiQBhDukReSWkEDcggjcaWscMK2ltFcQ8phNX6RkoO0RlBawmk68sTLbXwOMVmUPuTAuaWuAkABPO4Enws1Wmw9iLDaP1hiteaer5vC2Daxth8rIpjG5nMY5HRu6OAI9Jju8LzzpzRGE0pxD4NjGUWwDVen8hXz3M90nnMCrBIHWC4ntHBxd6Ttzs4jfZa4xemNK4z4EeoWYitj8bqG1bbXyj6QYy2DFmeRgk29IFjXADfu3HrU2pHuZF554paW058HWfS3EXBYqPE4nD3ZKmoBUYS+enbayN00h6ukcyaOs8k7k7OO+5V18HXAW8Rwwp5LKRdlnNRzzagyTT3tmtO7QMP8AcYY4/wDu1q/bYbMRaQ4+YGjqjidwaxOThNrG28tfbYrl7mtmaMdO/kdsRzNJaN2noR0IIJC1BlK9fAxZjRb7D8Zw5i4nQY69Ayd0UNejLRjmFYu3HZwOsOaCAQPT26AqTVYezlNu15j28Ro9FmGz50finZgTcrew7FszYi3fm5ufmcDty7bePgvJ+s8jX0JHxawehL8mL0BXkwMd6bFTkxYo2Jyy95O4Ehh7Dsy4N+Tvv0K63EXGYPhfq7Wk/CFtarYj4bzzh2Gsmcxk3oQ6YbOOzxFzO5u88oO571max7dReZOB3DKjide6ezunta6PdVfQmms43TNaxFNlq72ANln7W7NzFkjo3doW825IJ9Jem1uJuNOaI+FBgdaTYBztOalwWNz9l1PF5bK1IRUtTjn+9h8Uzy1x7N+3OG78pW414N4dTO0xwq4O6hl1Z90UkOoGRU9EW2wcjJJrUsJlgEQbIZY2ve9plMgG56DoR7yUpmZjtGm8h8KDA4rLZ6G3pzUsWFwWU80ZHUQqQvoV5/Q+UWzGQN++x7u7PYc3VbkXhzVlNkemOPOWt62Zj6ON1fbuHSd1sBp5aSKCrIyOTYNnPaOa2PlbIGnlHon0t/aen8lLmcBjchPVfSnt1op5KsnyoXOYHFh+kE7fqSmZniO7P/QSf3T/ALlzwz/BvpT9E1P3LFxP/QSf3T/uXPDP8G+lP0TU/csVxfgz6x9Ja7lKiIvnMiIiAoHB/wBY9ZfpZv8AwdZXygcH/WPWX6Wb/wAHWXd0XhX6feFjvZtEXmrUXDzAcQuN3GGLUGPbko6encU+qyV7uWCRzLm8rWg7CQcjdn7czeuxG533M2R6VReOtCOxHFHM6Aq8U7UN/DfF1RyNCDLWSyvZtucW2rDiXAPmaxsXUkloeXDbfdYrh7dpa+t8NNOcQchJa4fyUszPhhlbLmRZaSG8Iqgmc4jtOSqeZgcevR3VZ2x620RrzH69hzUmPhswtxWVtYefylrWl00D+R7m8rjuwnuJ2PrAVIvBjI4q+msbprF5HG4zQOQ4kZunZtZEy2Mc9rWuNSGYxzRufG9w6AyAFzWc3MNwfSPwd9BHQ41Q2tqjCZnEz2omw4rTsMkVPFzNj++ta19iYtLw6JxYCAO8D0kpqmRuJFpz4WFdtvhNDA58kbZc/hoy6GR0bwDkIAS17SHNPXoQQR4LT/Fqg/hHlOLeH0IyTTuMl0li8pNBjeZorl16aC1YjA+Q/wAna4lzeu7AT1G6s1WHsNTee15j9O6v0vpyzDZfe1E+yypJE1pjYYIjK/tCXAjdo2GwPXv2715c167F8KNR3WcEnwtfNofK38lXxNg2ImmMReR2yN3AzEul2cfSd47r6YrTOhtNcROC2T4eS08pmb1HK2JbTLpnnvyebnObJPu4kuLydyeoJI6dym13D2Gi8T8DNCyaxpaE1cNeaXoatsXorN6YVbDc3bnY4utU53Pu7P3a2RpZ2QAaN2taAF7YWqZuCLxENH2OKeoeId3Oay0tpvVNLUVqhBay9ewMpioxIBTNaQXYmsYWGNzOWPZ5J35ySstqzQWMy+F+Ejm8tF5dqHAONnH5IPex1SzFiK8gmhAdtE8va0kt6kAAkgBZ2pyHq1usMU7WT9LCwTm2UG5N9fs3bNrukMbXc223VzXDbffp+ZZpeYsbgNJ5X4UmHzeo8fiXZW3onH5Svauxsa995llze1YT/aNb2Q3HUANThhwR0rxKqcXpc3jo7mRuarzlCG7OOd9KN+8Z7Hfow+m4kjYkkbnoNrtSPTqLzNwHz+T4vcQsTczsbxc4c4iTDX+0BAdmpJHQ2Hg+O0NYOB9Vlb911/UjUP6OsfunKxN4uM4i8h8PtK0NGY74NmocFVFXO56m2tk7RleX32PxMkvJM4kl7WyMYWg9G8oDdgNlPaXjwdXh1wy1lQu9txiyepakGRn8qcb9mV9ktu1p2b7iJkfaAtIDWBjSNu9Z2h654h68x/DTSVvUWUhsz0q0kET46jWukJlmZC3YOc0bB0jSevcD39ypF4Q1RjdKao4Lap1dqKxXtcVRqgVrXlVwi1SLMsyOOrHGXejGIA0hu2x3Lu8dM7qPTLuJnEfiodUao0rgcliMka1J+o4LHleNo9hGa9irI25C2JpJc/mDNy/m5iRsBNse0lrHW/HinovW8+lo9Kam1Ffr4xmXsSYStBLHDXfJIwEh8zHk7xO6NafDbdXmmaF3FabxNLI3zlchWqRQ2b5ZyeUytYA+Xl3O3MQXbbnbdedOJOHkzXwmtR1268saBidoeoJbtfyYdo027QIc6ZhLQO/dha76VqqZiB6I0pqjG6201jM/h7At4vJV2Wa0waW8zHDcbg9QfWD1BWJ4j8TMNwvw1e/l/KZ5LdhtOlj6EBntXZ3b8sUMY6ucQCfAADqQpX4LeebqLgPpSzHjq2MrwwyU4YqbXtgfFDK+JksYeS7le1geNyT6Xee8zvHXJVNJcbeDmqM7IyrpmpNk6E16chsFS1YgYIHyOPRodySMDj0HN39Uv2XGzdAa8k13UtzS6Zz+mJK0gjMGfqMgfJuN+ZnI97XD6Qe9VSwuC1rp/VF69Tw2bx+Ws0RG61HSssmMAfzcnPyk7b8jtt/Us0tQMXg/wk3/ANEwfvpVbqIwf4Sb/wCiYP30qt149K/vj0j6LLD6yrG5pDOV2jd0tGeMDbfvjcFjuFU/lXC/R82xHaYem/ZzeU9YGHqPD8yqHND2lrgC0jYg+K1/wBfycHNLUTy8+Kq+Z5A3f0X1HurPHXruHQkdfUuNGwUREBERAREQEREBERAREQEREE7oGv5JpsReSX6XLbufeslL2k3WzKebm/Jd8pg8GOaPBUSnNC1xTxN2AVchUazKX3BuSk53v57UsnOw/wCbPPuweDOUeCo0BERBEZ78JON/RNj99CsosZnhtxHxp8DibO30/foP/wDn/iFk19X8lHp95anudO1hsfeyFK/Zo1rF6iXmrZlha6Wvzt5X9m4jdvM3odttx0K6c+jcBaoZKjNg8bLSycxsXqz6kbo7cpDQXytI2e4hrRu7c+iPUFmEWGWGo6L09jNPPwNPBYypgntcx2MgpxsrOa75QMQHKQfEbL46e4f6X0iZDgtN4jCmWIQPOPoRQc8YJIYeRo3aC5x27t3H1rPolhJQ8McFg8fkYtKUKWib93btMlgsdVin3DgSSHROY7fYj0mnvPj1XQocOs/DcifkOI2ezNEH7/j7lDGCGwzxY/kqNdykdDs4H6VeIlhi49K4WGHEQx4egyLEbebY21WBtLZhjHYjb73swlvo7eiSO5daroPTVHUc2oK2ncVXz0wIlykVGJtp+/Q80obzHf6Ss6iCZzPDDRuo8nLkstpLBZTIysEclu7jYZpXsHc0vc0kjoOm6++d4f6X1RkquQzOm8Rl79UbQWr9GKeWHrv6D3NJb169Cs+iWgQ+Y0FqPI5OzZq8SdQYqtK8ujpVqWNfHCPyWmSq55H95xP0rvT8OMRnsDRxurq9XXL6jnPbbz+PrSvLiSebkbE2NpA2bu1o6NG+53KqkSwx0Om8RXt0bUWLpR2aMDq1SZldgfXidy80cbtt2tPI3do2B5R6gutY0Tp23iLuJnwGMmxd2Z9i1RkpxugsSvdzvfIwt5XOc70iSCSep6rNIgxWJ0lg8DOybGYbH46ZlZlJslSqyJzYGEuZEC0DZjS5xDe4Fx2HVTWmOGc2K4gZ7WWXzLs1mb8Ix9MiqyBlCg2V8jIGgEl55n7ue4+kWjYNA2V0iWGu/i11X/8AFnU/7PxP2JVLdFYJ+GvYuxiMfbp5B5myEM1OIsuynbnlmYGhr3O5QSSPAeoLNolhgs1oPTWpMpTyWX07isrkae3k1y7Simmg2O45HuaS3r16FfrUGhtN6ss1LGc0/i8zYqHmrS5ClHO6E+the0lv6lm0Swnr/DvSmV0/UwN3TGGuYOpsK+MnoRPrQ7dByRFvK3bw2Cx+a0Den8jh09qvI6MxtWEQsx2GpUDB0JPMBNXkLe/bZpA6d2+6sUSwh4uFVPL4uTH62uDiPV7Zs8EWpcZRkZXeGubuxscDG7kOI3IJ6nYjcrt3eHkVTBVsVpLIP0BVhlMnJp+hTa1+42LSyWF7AO47hoPTvVaiWENi+GdoZGvY1Hqq/rSvVkbYrU81j8d2dew0gx2GGKsxzZG9diHdOY/Qq25hsfkLtG5ao1rNyg90lSxNC18ldzmljnRuI3YS0lpI23BI7iu4iWBYTNf1o0V+lpP+AtrNrC5lpdqjRe23TKSOI38PIbQ//YXrh8Z9KvpKwvURF8hBERAUvxT/AAY6v/Q9z9y9VCmOJ7DJw01axo3c7EWwB9PYvXR0f41HrH1WOMPoO5fieCK1BJDNGyaGRpY+ORoc1zSNiCD3gjwX6aQ5oIIII3BC5XWjFx6VwsMOIhjw9BkWI282xtqsDaWzDGOxG33vZhLfR29Ekdy61XQemqOo5tQVtO4qvnpgRLlIqMTbT9+h5pQ3mO/0lZ1FBM5Thho3N5WbKZHSWCv5OYNEl21jYZJnhpBbzPc0k7FrSNz02HqX3zvD/S+qMlVyGZ03iMvfqjaC1foxTyw9d/Qe5pLevXoVn0S0CHzGgtR5HJ2bNXiTqDFVpXl0dKtSxr44R+S0yVXPI/vOJ+lZzT2lYsN2Vq5Y8955sHksudt1oI7k8Ikc9sbnRRsbytLjs0ADx23JJziJYTl7htpHKYKrhLmlsLbw1VxfXx0+OhfXhcSSSyMt5Wnck7geJXcyujsBnsGzC5PCY3I4dgaG4+3UjlrtDejQI3AtG3h06LLolhgKnD/S9DDXcRW03iK+JunmtUIqMTYJzytbu+MN5XHlY0dQejQPALHWeG9bH4SHF6Punh9WjlMrm6dx9NjZNxtsWSQvYPA7hoPQdVYIlhI6b0VmcRdlkyut8vqipJC6I0clUoMi3O3pbw143E7AjYu26ncdy7WJ4aaQwNHI0sZpXCY6nkWOiu16mOhijtMcCHNla1oDwQSCHb77lUiJYY/7ncV5RjbHmyn2+MY6OjL5Ozmqsc0Nc2I7bsBaACG7bgALGScNdIzWclYk0rhH2MmWuvSux0JfbLXB7TKeXd+zmtcObfqAe8KjRLCG4rcNZuKmLqYSxmXY/TkkodlqEdVkj8hG1zHti7Rx+9N3b6RAJIOwLe9ZDVWkcznrkMuM1rl9MQRxCM1cdVpSMedyecmevI4HYgbAgdB071UolhKae0JJjrEVnO5uzrC9VlMtG3l6VNstFxY5jzCYII+Uua4gnqdum+xIWVm0jgrFbKV5cLj5a+Vf2mQifVjLbj+VreaUbbSHla0bu36NA8FlkSwxGI0dgNP4R+GxeDxuNw7w4Px9SpHFXcHDZwMbQGncd/Tqupp3hzpPSFgz4HS+Gwk5idCZcdj4q7jGXBzmbsaDykgEju3AKokSwk4OGWAwlbJHS+NoaOyd5u0mUwuOrRWN99+Y80bmuP8Afa4LoYzh/qWjkatixxN1FkIIpWvkqT0sY2OZoO5Y4sqNcAR0Ja4Hr0IKu0SwlcBwn0TpTJHI4PR2AwuRII8sx+Lggm69/ptYD1WF+LXVf/xZ1P8As/E/YlsREtAkYuEmi25publ0lgrGoOYSyZiTFV/K5JRt98dIGA8xI33CrkRB+J/6CT+6f9y54Z/g30p+ian7li/NghteUkgANJJP5l++GzDHw60s1w2c3FVQR/3LVMX4M+sfSWu5SIiL5zIiIgKBwf8AWPWX6Wb/AMHWV8oHCDbUmsd9tzlWHbf/APp1l3dF4V+n3hY72bXRbgcYy/evNx1Rt29GyG3ZEDRJYjZzcjJHbbua3ndsDuBzHbvK7yL1RO5LhxpLNYahiMhpfC3sTjwG06FnHwyQVgBsBHG5pazYAAbAdy7Oc0Vp7U+KgxeYwOMy2NgLTFTvU45oYy0bNLWOBA2HQbDosyilhgo9BaZiwVrCM07iWYa090ljHNoxCvM9xBc58fLyuJIBJI67LGXOHEVPD1cZpDJScP6cMjpDFp7H0msk3AGxZLA9o7u9oB9ZVgiWEVieHNtsr26k1Tf1tQPI9mPzdDH9jHKx7XsmHZV4zztLQRuSAeu24BFO7BY1+TmyLsfVOQnripLbMDe1khBc4ROftuWAucQ0nbdx9ZXeRLDCaa0PpzRjLLdP6fxeCbZdzztxtKOuJXet3I0cx6nv9a6mI4YaO0/k2ZLF6SweNyLHvlbbp42GKZr3NLXOD2tB3IJBO/UEhUyJaBPM4eaZgz1jPVdPYmpqGYO5sxDQhFskjbcy8vMT+clTnxa6r/8Aizqf9n4n7EtiIlhP5Dh7pjM5mtmclp3E5LNVg0RZK3Qikss27uWQt5m/qIXck0rhZocvDJh6D4svv5yjdVYW3d2CM9sNvvm7AG+lv6IA7llEQYTK6H05njjTk9P4vInGkOom3Sjl8lI22MXM08ncPk7dwX28wQ47G5OHBxVMLbuumsGxDVaW+UvHWd7By9o7m2J3O7tupWVRBr3SPCefSGjspjKmp70Ofy95+UyGoq9Wu2eay9zS9zYnxvia3lY1gaWnZo79+q7GM4e56teikyPEPOZ2h1E+NvUcaIbDCCCx/Z1Wu2O/g4K6RLQMXHpXCww4iGPD0GRYjbzbG2qwNpbMMY7Ebfe9mEt9Hb0SR3LrVdB6ao6jm1BW07iq+emBEuUioxNtP36HmlDeY7/SVnUQTOU4YaNzeVmymR0lgr+TmDRJdtY2GSZ4aQW8z3NJOxa0jc9Nh6l987w/0vqjJVchmdN4jL36o2gtX6MU8sPXf0HuaS3r16FZ9EtAh8xoLUeRydmzV4k6gxVaV5dHSrUsa+OEfktMlVzyP7zifpXMnB3S+ajpT6sw+L1vm60fZDN57E05bbmc7nNbu2JrWhvMQA1oHj3kk26JaBH6g0PmMncjfiNb5fS9GOJsTMfjKdB8LdvEdtWkcOmw25tug2AXbxOjHswNzFaky8+tq9p27/PdSry8mw+9lkMMbHN3G/pNJ3Pf3bUqJYYnTekcFo2i6lp/C47B03O5zXxtWOvGXevlYAN/pWWREGLwf4Sb/wCiYP30qt1E4Ib8SMge/bEwb/R9+l2/3H/wKtl49K/vj0j6LItfaDf9zuu9ZaYlLmsmsNz9DnfuHQ2OkzW/3bEcrj6hOz1jfYKj+IGn71h+M1Fg4TPqDBukfDVEgj8urvAE9QuPQc/KxzSdgJIoiSACuNFgixundQ0dVYWrlcbN21Ow0lpc0texwJa9j2nqx7XBzXMcA5rmuaQCCFkkBERAREQEREBERAREQEREE7peuaOX1LXFO9BG6+LDJ7UvaRT9pDGXGH8locHNLfAgnucqJT81KSlrmC9BRszx36Rq2rTbI7GDsXF8IMR7y7tZhzt6+i0HcEFtAgIiIMPqHT3noV54LBpZCqSYLIbzgB23MxzdxzMdsNxuO4EEEArAnAavHdk8Ifp8gmG//wB5WyLoox66I2Y4fOIlbonzDrD5zwfuM31yeYdYfOeD9xm+uVsi9N6xMo0guifMOsPnPB+4zfXJ5h1h854P3Gb65WyJvWJlGkF0T5h1h854P3Gb65PMOsPnPB+4zfXK2RN6xMo0guifMOsPnPB+4zfXJ5h1h854P3Gb65WyJvWJlGkF0T5h1h854P3Gb65PMOsPnPB+4zfXK2RN6xMo0guifMOsPnPB+4zfXJ5h1h854P3Gb65WyJvWJlGkF0T5h1h854P3Gb65dDA4/XOTxFa1cnwVCzK3eSs2vJMIzv3c7ZtnfnC2Kp7h/T836NxdfzbWw/ZxbeQ1J+2ih6no1/4w8d/pTesTKNILsV5h1h854P3Gb65PMOsPnPB+4zfXK2RN6xMo0guifMOsPnPB+4zfXJ5h1h854P3Gb65WyJvWJlGkF0T5h1h854P3Gb65PMOsPnPB+4zfXK2RN6xMo0guifMOsPnPB+4zfXJ5h1h854P3Gb65WyJvWJlGkF0T5h1h854P3Gb65PMOsPnPB+4zfXK2RN6xMo0guifMOsPnPB+4zfXJ5h1h854P3Gb65WyJvWJlGkF0T5h1h854P3Gb65ZLCaWswZFmSy12O/dia5ldleExQwB3yiGlzi55Gw5ie4HlDeZ29IizV0jEqi3ZHpEFxERcqCIiAvnPBHZhkhmY2WKRpY9jxuHAjYgjxC+iIIo6Sz+MY2ti8vSfRjAbC3I1ZJZY2juaZGyDn2GwBI5th6RcSSuPMOsPnPB+4zfXK2Rde9YnfbSFuifMOsPnPB+4zfXJ5h1h854P3Gb65WyK71iZRpBdE+YdYfOeD9xm+uTzDrD5zwfuM31ytkTesTKNILonzDrD5zwfuM31yeYdYfOeD9xm+uVsib1iZRpBdE+YdYfOeD9xm+uTzDrD5zwfuM31ytkTesTKNILonzDrD5zwfuM31yeYdYfOeD9xm+uVsib1iZRpBdE+YdYfOeD9xm+uTzDrD5zwfuM31ytkTesTKNILtdDH658+ml2+C8j8mE3lfk8m/PzbcnZ9rv3debu8F3/MOsPnPB+4zfXLJ4+CO7rjKXxQqbVqkNJmSjsB8z3c73ywuYPkBm8RG/Ul56AAE0ab1iZRpBdE+YdYfOeD9xm+uTzDrD5zwfuM31ytkTesTKNILonzDrD5zwfuM31yeYdYfOeD9xm+uVsib1iZRpBdE+YdYfOeD9xm+uTzDrD5zwfuM31ytkTesTKNILonzDrD5zwfuM31yeYdYfOeD9xm+uVsib1iZRpBdE+YdYfOeD9xm+uTzDrD5zwfuM31ytkTesTKNILonzDrD5zwfuM31yeYdYfOeD9xm+uVsib1iZRpBdFfchncox1bLZem2hIC2ZmOqyRSyNPe0SOkdyAjcEgc2x9EtIBVlFEyCJkUTGxxsaGtYwbBoHcAPAL9ovHExa8T+7kXuIiLxQREQFN5rS1mbIyZHEXYqNuZrW2I7EJlhn5fkuLQ5pa8DpzA9224dyt2pEXpRiVYc3pW9kT5h1h854P3Gb65PMOsPnPB+4zfXK2RdG9YmUaQXRPmHWHzng/cZvrk8w6w+c8H7jN9crZE3rEyjSC6J8w6w+c8H7jN9cnmHWHzng/cZvrlbIm9YmUaQXRPmHWHzng/cZvrk8w6w+c8H7jN9crZE3rEyjSC6J8w6w+c8H7jN9cnmHWHzng/cZvrlbIm9YmUaQXRPmHWHzng/cZvrk8w6w+c8H7jN9crZE3rEyjSC6J8w6w+c8H7jN9cuhncfrnGYmzapz4K/ZjaCys6vJCHncdOd02w/WtiqY1S6rqR0mm2V6WVc50D8lUszFogrOc4h5DQSS4xODW9NyCd9mndvWJlGkF3Q8w6w+c8H7jN9cnmHWHzng/cZvrlbIm9YmUaQXRPmHWHzng/cZvrk8w6w+c8H7jN9crZE3rEyjSC6J8w6w+c8H7jN9cnmHWHzng/cZvrlbIm9YmUaQXRPmHWHzng/cZvrk8w6w+c8H7jN9crZE3rEyjSC6J8w6w+c8H7jN9cnmHWHzng/cZvrlbIm9YmUaQXRPmHWHzng/cZvrk8w6w+c8H7jN9crZE3rEyjSC6J8w6w+c8H7jN9cgwGrz35PCD6fIJjt/8AeVsib1iZRpBdhtPae8y+UTz2DdyNojt7JbyAhu/Kxjdzysbudhue8kkkkrMoi5qqprnaq4oIiLAjM9pvK4bLT6g0oYXWpy12Rw1lxZBkQBsHtd/Y2AAAJNi17Whjx0Y+Lv6T19itXunrQGahl6w/yvD5BnY3K30vj3O7T4SNLmO72ucOqpFP6s0JhNbR1/OtLtLNVxfVvQSOhtVXHvdDMwh8ZPjykbjodx0QUCLXhxuv9GxtGOv1ddY5hP8Ak+Yc2nkGt6bBtiNnZSkddg+NhP40hPVI+OOnsfI2DVMN/QtokN5dSQdhXJPcG22l1Z538Gyk93TqEGw0XxqW4L9aOxWmjsV5G8zJYnhzHj1gjoQvsgIiICIiAiIgIiIMbqDAVNR49ta3CyYRzRWYS/m+9zRvD43jlLT6LmtPQjfqO4lfPTuadlanZW3VIs1VZGzJUqljtm1pywOLQ4ta4tO+7XOa0uaQdhvsssuhkMU65ap2IbUtOavMHuMQbtOzZwMUm46t9MkbEEODT6wQ76LBYbUzrM1TG5as3F6gkqm1JRY900XK14jcY5uRrZGhxb4NcA9hcxhcAs6gIiICIiAiIgIiICIiAiIgIiICneHtA4vRmKquxMWCMUXL5uhsduyD0j6Ik/G9e/0qiU7w9x7sVozFVHYVunXRRcpxbbHlAr+kfR7T8b17/SgokREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARFwTt3oOUWA+7vBSTCKrkGZOQZE4mRuMY62a9oDmdFN2Qd2JaNi4ycobuNyNwvzWzOcyj67q+C83VxcfFYOVsNbKYGjpLEyLtA7nO2zXuYQNyQD6JCgJABJOwHipuTUEupojX09KTBYqCeLUETY5qjd5OTaM83pv2D3DYFo2bzdHAH9UdKTStoT53JzZi/UM55o+atWeJRsWuga4teGt9Fvac5G5O+53VBFEyCJkUTGxxsaGtYwbBoHcAPAIPjj8ZUxNd0FGrDThdLJO6OCMMaZJHukkeQO9znvc5x7y5xJ6krsoiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAi6trJ06D4W2bcFd00ohiEsjWmSQ9zG7nq4+odVh4+IemrBhFbNU73a33YtppSeUAWm/KhcWb8rm/jA7cvjsgokU7BravdFZ1PF5myya86i5zsdLX7It+VK4TBh7L1SNBDvxeZIM5nbnkjo9NPqMfcfDYGQuxMfFA3umaIu0D+bwYS07H0i3uQUSKdrw6rsupPsWsRQay1I61BDBLZM1f+zayQvj5H9xc4scPADxXNTS1sOx8l/UWTvzU55Z/RMdeOYO35Y5GRtbzMYO4H87i4oM5LahgfEyWVkb5XcsbXuALzsTsPWdgT+pYHGa9xef80SYbt8zRybZnw5GjEZKjWx7gl0vyRu4crep5u8dASPvi9EYLDtx/YY2KSXHumfUs2ibE8JlO8pbLIXPBd49eo2HcFnEE1UraizlevJlH18FDNUljs46jI6eZsrjsxzbXocvKzqQI/lHo4hu7s3jcbXxFKGrWa5sUTGxgySOke4NaGgue4lz3bNA5nEk7dSV2kQEREBERAREQEREBERAREQEREBERAREQEREBfmSNk0bo5Gh7HAtc1w3BB7wQv0iCBucDtISWHWcZRn0vdcSTZ03blxpc4nfd7IXNZJ1JOz2uH0L4jSGv8Fv5n15DmYh3V9U4qOV5HqE1Uwcv53MefXueq2IiDXf3Z6+wo/5X4fMyrB/baXzEM5I/KMdoVyPzBzj6t1y7jrpmgGjORZnS7iN3HNYezBC3rt1n5DD4eDz4HuIWw0QYLTevNNayjD8BqHFZxm2/NjrsVgbf7Dis6pjUfDDR+r5hNnNLYbLzg8zZrlCKWRp8CHlu4P0g7rBN4Gafonmw2Q1Fp52xDW43PW2wt/NA+R0P/0INiItdjQetsWD5r4l27fT0GaixFW21vu7aziPzu3+lPKOK2LaeejpDUmx747VrFEjxIaWWRv3dC79YQbERa7+MnU+OaPOvDLPAb+lNiLdK5G36djMyQ/qjPd4dEPHnStQDzqzN6fPicxgrtaNv/eui7P/AMHFBsRFK6f4raK1Y8Mwmr8FlpCduzpZKGV4PqLWuJB+hVSDqZXFU85jbWPyFaO5RsxuimgmbzMkYRsQQsNbw+axUWQnweQFyR8UDKmMyz/8mhLNg7aVrDKOdveXF+zgCB8oGkRBPXNYxYiW8crjr+NqQWIq8V10QmisdoOj29kXuY0O9FxkazY/QQTmamQq3zMKtmGyYJDDL2Ugd2bx3tdt3OHiD1XYWGyGj8Pk39pLSbFN5VHddNVe6vI+aPox7nxlpdsOmxJBHQgjogzKKe8w5mk/ehqGSVsuT8smZlazbAbWcPTrQmMxFg36te8yFpJBDm7NHEWaztR0TMhp/t+2vurNlxNtkzIa/fHYmEvZOb6nMjEhadtuYbkBRIsDR11g70lWE3hStW55atepkY31J55I/ltjjlDXP2HXdoII2cCQd1nkBERAREQEREBERAU5w7oebNFYmqcQzA9lFt5ujs+Utg9I+iJNzzevf6V0uKPFvSnBfTTM/rHKOxGIfYZVFkVZrAEjg4tBbExzgCGnqRt3DfchQPwafhDcO+LmEgwejLTmXcbU7azjGV7ZZUYX7AdvLG1riSdwN9z16bA7Bu5ERAREQEREBERAREQEREBERAREQERcEgAknYDxKDlFhMxrbT+n4MjNks3j6UeObG+4ZrLGmu2Q7Rl433bzEgN37z3br4ZHXVCiMu2Krk8hYxjYXTQUsdNI5/abcgjPKGyHY7kNJ5R1dsgokU5kdRZmMZePHaXt2p6bYTVks2oIILzn7cwY4Pc9vZj5Rexu56N5kyR1bYGYix7MLQ2EIxluy6a1zE7GYzwtEfLt1DQ2Q795Le5BRop3I4DN5J2XY3U9jG17LoDTdj6kInptbt2g5pWyNkMh36lnog9OvpLjI6Fo5huYjv3MparZN8TpK4yM0TIRHts2Ls3NLASN3AH0u5246IM1kclTw9KW5ftQUqkQBknsyCONnXYbuJAHUhYe/wAQMBjn5WN1/wAqs4p8MV2rj4ZLdiB8u3ZtdFE1zwXAg7bd3Xu6r7nReAddylx2FoPtZV0Lr8z6zHPtGIbRdoSPS5Pxd/k+GyzSCduaquNfcjo6byuQlrWo6x6RQMeHDd0rXSvbzRs8SNyT0aHddk82qrLrTK9XE49rLjGwTTzyWTNW/He5gazkee5rQ5w8SfxVRIgnZNOZa6J229S2omG+21CMdBFAWwN7qzy4PLmn8Zw5XHwLR0R3D/Azyc9yj51c3JjMRedJX3BBbA2ZJCJXOEXJ+KGcob3tAPVUSIPzHGyJpaxrWAku2aNupO5P6ySV+kRAREQEREBF+XvaxvM5waPWTssfd1Nh8ayR9vK0arI5W13umssYGyO+Sw7no4+A7ygySKdtcRNL0hd7XUGN3pWmUbTWWmPdBYf8iJ4BJa87jZp2KWtf4Wp5dvJcndStMpzsq4+xO5sr/kgNjjcXDr1cNwPEhBRIp23raGv5cI8TmrT6dmOq9sWOlHaOd+PGXBokYPF7SWj1pb1Tfi8uFbSuYuPrWY67Ax9WMWGu+VNGXzN9Bvjvs78lrkFEinbWa1ADdFXTYkMNqOKA2L7I22Ij8uUFocW8v5JG5+hLNrVjzcFfGYaMMtsZWfLkJXdrW/Hke0QDkkHXZgLgfF47kFEinZ4dWSmwIbmGqjy1hgc+pLNvUHy2uAlZ99Pg4HlH5LlxLiNSTicHUVeDmvtmhNfGgFlUd8DuaR3M4+MgDfoaEFGinJtMZKyLIfqvKxtkvNtRivFVZ2MQ/wCrAmE7xnxJ3f6nBczaLjsmx22YzL2zXm3g1l98XZlvdE0x8p7L1sJIPjugolw5wYN3EAesqek0Dh53SmZt2x2mQbkyJ8jZkDZ2/J5Q6QhjB/m27M/1Udw60vJ23a6extgTZAZZ/lFVku9wd1j0gdpB4OHUeCDvXNUYbHNc61l6NZrbDapM1ljAJnfJj6n5Z8G95XRl4iaZiM4GcpTOgvtxczYJhKYrbu6B4bvyv/1TsR4rJwYDF1nTOhxtSJ00/lUpZA0GSb/OO2HV3+seq76CddrzFhzmxxZOwW5IYl/YYq1IGTnxJEewiHjN/RjxduuH6xlLZjX07mrRiyIx7mtgjiJHjYb2j2h0I/KG5PgCqNEE7Jn848zivpecGO+2q02bkDBLX/Gst5XPPKPBjg159QR1vVUr3BmLxEDG5JsYc/ISvL6P40uwhHLN6o9y3xL/AAVEiCcNXVkzNvOeHqObk+03GPlm58eP7L+mbyzn/O+k0f5s96P0/m5+1EmqbMAORFqM1KcDS2sP+qu52P3afF42f6i1UaIJ46O7V7nT5vMz/wDKQyTGi32QZt3V/vYbzQetjt9/xiVwNAYQmMy157ZiyJy0ZuXJpzHZP4zed55WjwYPRb4NCokQYeho3AYrfyLB42pvbfkD2FSNm9l/y5+g/pHeL+8+JWXADRsBsPUFyiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIMJqHQ+nNWsLM5p/F5phGxbkKUc4I/22lS3/APH/AENX/wCjMVY06R3fc9krWLDfzNrSsG30bbLYiINdjhTl8f1xHEjVVFo7oLb6t+M/nM8DpD+qQLkYjiliw7sdS6ZzsYHox3sNNUlJ/wBaWOw9vd6oh/8ApbDRBrv7rOI2NafOGgMfkgD34DPtkc4evlswwAH6OY/nQ8ZWUAPPWi9Y4Xp6W+HdkA385pOnH6wSFsREGv6/H/h1NO2CfV+Mxdl52bXy8vkErj6gycMcT9GytsdlaWYrCxQuV71d3dLWlbIw/rBIX2sVorcL4Z4mTQvGzo5GhzXD6QVFZHgZw9ykz55dGYWK04gm1VpMrzk9dj2kYa7xPj4oLaWCObk7SNsnI4PbzNB5XDuI+lYGjoTFYd+OGJZNh61GWaZlLHzOirPMu/OHxD0HDc8wG3onqNtzvPDgrjaToziNRaswvJ3Mgz9mxH377dnZdKwD6A1fn7iNe4xp828SXXiD6P3R4OvZH5j5Mau6Chx1HUuKbhq0uTq5uCMTjIXLcPYWZe8wlgjHZgjo13QAjqNtuUqOrbAdjYMtg8hi7duCSWTkZ5TXruZvux80e4BIG7Sdt9wPleip91zirjC7fFaS1AwHviv2ca8j6GuinBP0Fw/OuHcTNSY5xGU4ZahawHrZxdmlci/8vbtlP6o0FlhdSYrUdWvZxeRrX4bEInidBKHc0ZJAdsOu24I/OCO8Ka4R8ZtJccNKx5/SWTbfq9GzwuHJPVkI3McrPBw7txu07EtJHVas488X9Ou4V61u1MdkcLq3zBdp1Luawd3HSQtfGeYR2jXI3Hy2ta7Zz2tBc3fmHij/ANnXiacvFCrdpcUPuTzbZWtl05LT5mZevzDniD3PDCSOg6czSQWg7dA/q+97Y2Oe9waxo3LnHYAetQmU42aXx8ro681nLPadicdXdJH+qQ7Md+pxWveImuZNbX5qVeTbT1eQxtjYelx7SQXv9bAR6Le47cx33byzAAAAA2AX6zof8GpqoivpEzee6PuXiG2Dx9w4J/5FzZ+nsYvrU+P3D/Mub/wYfrVqdF9L8H6JlOptfJUcXtZ6X4v8Ns/pHJ4TNCvk6zomymCImGQdY5B9972uDT+rZa1+BzicR8G3hpPjMjislb1LkrLrORtVIozGQ3dsUbSZAS1rdz1A9J7vDZUSJ+D9EynU2vk2x8fuH+Zc3/gw/Wp8fuH+Zc3/AIMP1q1Oifg/RMp1Nr5Nw1eO2nJZALUGTxzP85Ypl7R+cxl+35+5XeMylPM0o7lC1DcqyDdk0Dw9rv1heY13tN6gu6MyhyGNAIeR5VUJ2ZZb47+p4Hc/vHcdxuFx9I/gmHNMz0eZicp4TyLxL0wi1RxY+E3oPg7oerqTOZUFt6ETUMdB6Vq3uNwGs8NvEu2A2IJ36Lq8B/hL6d43cPMZqJvY4rJ2orc82Dhs+W2KzIJXMJdyMB3LQx4byg7SNA36E/jpiaZtPEbhRTkWtGXRA6jhszcbPQdfic6k6tzAfJhd25jLJXeDH8u343KFw3MajuR7wadipmTGGwwZG+1ro7hPo1pBE2QBu3V0jXOA8A5QUiKcNbVdtnpX8Vju0xnI5sNWSw+G+e+Rr3PaHQtHcwsDnHqXDuXE2mb1gPdd1Rk+zfjPIZYawgrx9r+Nba4R9oyU9wHacgHc3fqgpFj8pqHFYSGzLkcnToRVYDZnfasMjbFEO+R5cRytH5R6KcymG0jQiyE2ayLJIo8dHir5yuVe6EQO6NErHycgc/xeQHO36kriTOcP9JSZN3leAx1jDQVaN5sToWy0on7eTQyhvpMaenI12wPgEGRn4gYOIT9jYmyDoaLclyY6pLaMkDvkOj7Jrucu8Gt3JHXbZc2NV3CLbaOm8rcfFTZaiLxFAydzu6EGR4LXjvPMAB69+iZDiBhMa7LtlmtSyYl0LLcVWhYsPYZf6MNbGxxfvv15Adh1OyZDW1ej54DMXmrkmMfCySOvjJj2xk227FzmhsoG/pFhIb13IQcWbuqrDbbamKxlT/JI31Zbl57ybB+WySNkewY38pryXHwA6rm1i9S3fL2DPVaEU1aOOsamP3mrTf2khfJI5rwfxWlg28S5Mjqu9UGWFXSuZyUlF8TI2QGtH5Zz7czoXSzMGzN/S5y09Dyhx6Lm9m87HJkWU9NuseTzQsryTXo4mWmO27R425i0M7tnAFxHTp1Qfm7o12UbkY7mezMkF2CKExV7Qq9hyd74nwtZIxzz8o830DlHRc3+HmnMt51bksTBlYsoyGO7Bkd7UM7YtuzDo5C5uwIB7up6nc9Ut3dVuN4VcTiG8lqNlV9jJS/foP7SR4bB6Dx4MBcD4uauLserpmZJtSxhajzYZ5DJNBNOBD+P2rQ9m7z125SAPHdBm4MfVqzzTw1oYZpuXtZI4w10nKNm8xHfsOg37guwp69i9S2X5IQZ+nTilmhdS7PGFz68bdu0a8ulIkLjvs4NZyjwd3ri3pzL2zeA1XkKbZrMc0PklaqHV42/KhBkieHNd4lwLuvolqCiRTlvRz7ovtlz+a5LVllhrYrLYvJw3+yjLGAhh8QSSfWubmg8ZkPOYsz5WVmQmjnlZ52tNax0fyREGyDsm9OrWbB34wKCiXwtX61GMyWbEVdgIaXSvDRue4bnxKwlvh9p3IOvG3iobgu2Y7lhtkula+WP5DuVxIG2w2A2C+/3D6c7S5J9z+L57tlty07yKPeedvyZXnl9J48HHcj1oOMjrrTeIity3tQ4qlHUmZWsPsXY4xDK/wCRG8l3oud4NPU+C+NziFp6k7INkykT34+xHVtRwtdK+GWT5DHNYCQTv/FZuGjWrvlfFXiifK/tJHMYAXu/KPrP0r7oJ21rvG1jdAr5Ww+najpytr4m1J98f3FpEez2Dxe3drfEhLOsXw+WCHT+auOrW2VC2Ku1na83fKwyPaHRt8Xb/mBVEiCctaky7BeFbSeQmdXtMgiMlmqxtqM/KmYRKSGN9Tw158GnvXNrJ6m5rramAov7O1HHXdayZibNAflynlheWub12Zseb1tVEiCdnk1ZIbIhr4aANusEDpJ5Zeer+O54DG8svqaC5vrKS09VymcMy2IrDy9r4j5tlkIpj5UTvv4++n/OD0R+QVRIgnZMHnp+231M6EHINsR+T0YgWVh/1Y8/Nzb+MnR3q2XEmlL0/bCTVWZIfkBdYGCtH2UY/wCqtLYQTF6+bmkP5fgqNEE7LoitY7cT5TNSCW+3IANyc0XI4d0TTG5p7L1x9WnxBXE3D/CWRYE8Fmy2e83JPbPenkAnb8ktDnnkaPyG7M/1VRognpeHel7BtGfT2Ms+U3W5Gbt6jJOe035Mx5gfTHg7vHgsjHp7FRPsPZjKbH2JhYmc2uwGSUd0junV30nqsgiDgADuGy5REBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBhtaaVqa70dndNZB80VDM0J8dYfXcGytjmjdG4sJBAds47EgjfwK0Fjvgd8KeBWkMnnMHp039QY6tJPUy2WlNieKYDeORoOzGua7YhzWgghellitVYUak0zlcUXBnltWWuHn8UuaQD+ondeuDNNOJTNfC8XWOLzXBC2tBHEwbMjaGNH0AbBftfKrJJJCBMwxWGExzRHvjkaS17T9IcCP1LCag1Rdwl1kFbS+YzbHRh5sY81hG07kcp7WZjt+m/QbdR179v6jVVFMXliVAoHizxJm0HHhqdGFs2Vy9h8MDpa09iOFrGF75HRwNdI/YAANaB1duSACV3PjAym39QNTfm5qH2pY7O4C1xOioXW1MtonOYS15Rj712OvMd3MLXgsjleHMc0kOBLT3bFc+JXNVExhcfSf1427hJt41aobhJ98RWfkY8xQx0FuxRt0qltll/Ju1kzRIxzDuD8sDoeu+yyd/i9mdGs1hU1DUo5HJ4aGnNTOMa+GO2bT3RxRlr3PLCJG7E7kbHfbpsqDIcO8xn8HQqZvUzchcq5mrlRZZj2ws5YZGPELWB/QHlPpFziC4942C+WquD9XV+S1RYuZCWOLN0KlRrIY+V9aSvI+RkrX79TzOadth8nvO65tjpEReme39Mp9e+3/AFxNYIapHHvD/dQ7EPsnTdt0fmlkrWNHlFfma7tCSdunpDbf1BbmWsaeidRac1LDq7L5qfWV2njpMdHQx2NhqySNklicXgumDdxybncgEd222xzrdfZRx2OgdSt6E7l1D1d3/Ol7YM9XeK4ntm+f0uLFFKUNbZK7dggk0TqGlHK8MdYsOpdnECflO5bLnbD6AT9Cq3ODWlziAANyT4LrpqirgjRvwg/gza8494dmQ0jSwt9uBlkp9hKeyyMgftYIbI70DGDO7ZhIIJceu422p/7P7hbrnRnArVOGzT8porIzZx7q0NvGtbNBtFBzzM7VpbI14HKDsWgscQSe70NwUwz8ZooWpWlkuUsPv8p/IcGsjP642MP61fL+cdPmmrpWJNPC/wD9/d6TxTmR0peyPnhp1Vmasd9sLYWVhWZ5Bybcxhd2JcTJt6XaF+2/o8iZLRFfLeeG2MpmhFk2wtfHWyc1fsBHtt2DonNdEXbekWkF3j06KjRcCJzJcP8ACZjzyLsFm0zLiEW4pL05jcItuQMZz8sfd15A3mPV26/WR4d6XzDswchp7GZAZnsPOLblRkzbfY7dj2jXAh3JsC3fuI3CoUQY52ncS+e7M7GU3TXTG61Ia7OacsGzC87ekWgADffbwWQAAJ2AG/U/SuUQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREGsOJHDCfJW5M1gmB9143s0C4NFggdHsJ2DX+B3IDum5BG51BcvRYyya2QLsbaHfBeaYX/qDttx9I3C9XL5z1orUZjmiZMw/iyNDh/4FfoOifxfE6PRGHiU7URw7bT917J4vKfneiP8Artf/ABW/xXHnej/ptf8AxW/xXp/7msR81Uvd2fwT7msR81Uvd2fwX0fx3D/xzr/pLQ8wed6P+m1/8Vv8U870f9Nr/wCK3+K9P/c1iPmql7uz+Cfc1iPmql7uz+CfjuH/AI51/wBFoeYPO9H/AE2v/it/innej/ptf/Fb/Fen/uaxHzVS93Z/BPuaxHzVS93Z/BPx3D/xzr/otDy/55omRsbLUUsrzs2KJ3O9x9Qa3cn9QWwtDcLruoLEdzOVJMfiWEObUnHLNa+h7e9jPWDs49xAHfuirj6tEEVq0NcHv7KMN/3LsLj6T/Gq8SmaMGnZv33vP6cLHZHBwAGgADYDuAXKIvzQIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIP/Z", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "from langchain_core.runnables.graph import CurveStyle, MermaidDrawMethod, NodeStyles\n", - "\n", - "display(\n", - " Image(\n", - " app.get_graph().draw_mermaid_png(\n", - " draw_method=MermaidDrawMethod.API,\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "b9e767fc", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-18T12:18:30.873950Z", - "start_time": "2024-04-18T12:18:30.871750Z" - } - }, - "source": [ - "### Using Mermaid + Pyppeteer" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d403e1e7", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-19T11:25:44.798703Z", - "start_time": "2024-04-19T11:25:44.793438Z" - } - }, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install --quiet pyppeteer\n", - "%pip install --quiet nest_asyncio" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "058546ee", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-19T11:25:47.412695Z", - "start_time": "2024-04-19T11:25:45.405158Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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AAAAJpWJUwAAwEHt2zUw+nHjDG8hflVPT0++8IW/O2C9tbUt5557YXbs2J5HH30k3d37kiSXXnplqqurR89bsuS4XHDBpdm1a0ceffSRMde44IJLD7ju3Lnzxxy3t8/JZZe9Kffcc9eY9cbGpixbdnx27hyZCvWrPve5/5WPf/xPDutz/OY37xj9eNGipTn99Feno2NLfvrTH+f6629MfX19Zs5sG817//33jnn+2Wefd0BZ7MQTTzmse5dRY0ttsqk3e5/32gMAAAAAYOL5rgcAAHBQfb1DSZLaegNrx/OLX6wYLUXt9/GP/0kuvfSNo8c9PT25/fYv5J/+6dM5//xfG3PueeddlPPOuygbNz6T97//raPrS5celz/8wz87rAzvfOfNo8WpD3/4Y7nkkjfmmGNmjj6+efOz+Yu/+OMsX/6T0bV77/123vKWd+bUU1912J/r7/7u7+Xqq68fPV6z5qm0t89JkixYsGg07zve8cYxW/197GN/lLa2WYd9n7KrrRt5re1/7QEAAAAAMDkUpwAAgIPq/2V5o6ZWcWo8u3fvOmDt4ovfMOa4oaEhN974m3nTm64bU2iaKMuWHZ+PfeyTOeusc0eLTM83f/7C/NEf/WXe+95rxxSaVq1aedjFqf/0n/4gb3rTm8esHXfciS8vOOPaX1LsV5wCAAAAAJhUvvMBAAAc1P6pN3UmTo1rzpx5B6z94hc/H/fc9vbZqa2tnZQcr3/9VeOWpvZraGjI2972njFr423hN57jjjsxV1xxzcvKx+GrrR/ZytHEKQAAAACAyeU7HwAAwEH19/1yq766SsFJpqalS487YO2P/uijWbHi4QLSjLVz54488cRjeeCB+7J27dNZvHjpmMcPtzh13XW/kerq6smIyDj2b9W3/7UHAAAAAMDksFUfAABwUJXKSGFquOAcU1Vz84zcfPPv5B/+4W9H13bs6MpHP/rbueKKa3L99Tce0S3tHn74gXzxi/+YVatWprt730HP3bz58IpTS5YcOxHROEy/fMll2IsOAAAAAGBSKU4BAAAHtX/S1GC/FscLeetbb8zTT6/K97//nTHrd9/99dx999dz3nkX5eabPzSpBapVq1bm7/7uf2bFip8e9nMGBwcP67x58xa81Fi8BM9NeTMkGgAAAABgMvkqLAAAcFC19bYNO5S6urr83u/9t9x002+N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DgAAAAAAAABA76NVHwAAAIBeUVS0QTfccHnA0FQgL7/8rG644XLV1m7qcu2zzz6km266xi801dGiRR/rgQfu7NbzH6gVK/4dMDTV5txzLzUqZbX57LOPujxvXd1WU2hKkk444bT92+Q+euWVv+ruu//LLzTVUVHRBs2Y8Qs1NDQEXbNu3Wpdd91FAUNTHXm9bt1887WaPfsF+Xy+oOv27Nmjp5/+n4Chqf21bVud7rrr5oChqUA++2yerrrqPK1c+W2P7QEAAAAAAAAAEBpUnAIAAAAQcjt31uvuu/9LXq/bNG+12pWfP1oWS4y8XrfWrPnO9HhFRZmefPJ+3XffUwoLCwt6/u++W2oaH3bYWGVlOVVZ6TJVA5Kk5cu/0YYNa02VnYYOTdRPfrK3fds33ywxrZ8w4WhZLDGmueHDR3RxxXurLrVJSEjU+PFHS5IWL16gww4bq7y8kWppaTZVP1q06GNdd93vZLFYgp63Y9BowoSjZbMld7mfnuD1uk2fw/T0LB1++Hht3bpZ3377lWltY2ODPv74PV144RV+59m82aubb77Wbz4ry6lx446SxWJRQcGPWr16henx11//X2VlOXX88acG3N/99//R7/Mn7f06Gz36CEnSmjXf+bVj7MwTT9znd20xMbEaPfoIJSQMU339DhUUrDWds7GxQffcc5teffWfGjo0oeMpAQAAAAAAAAD9BMEpAAAAACE3a9ZzfqGpGTNu05lnnq9BgwYZc9u21em55x7V4sULjLnvvluqzz6bp9NPP7vL57nggst16aVXa8iQocbcqlXLdffdtxjt5iTp3Xff0J13/qcqUWpquu6662FJ0iWXnG4Kwdx22z1KTBy2D1drNmXKuZox4w9Gy8HrrvudsZeRI8coK8upiooySXsDN//+97900klnBD3f4sWfmMannDJ1v/e2v8aOnajf//5OpaVlGHObNlXrvvtuV1HRBmNu9uwXdN55lyoiwvyj5+uv/6/fOW+88Vadc87FprnS0iLdcceNps/Hyy8/o2OOOcGvheOyZV/7haYSEhJ1992PatSow405n8+n1157Xm+++XKX1/nll4v8znnOORfrqqt+bWr32NzcrHfeeU2zZj1nzDU2NuiFF57ULbfc1eXzAAAAAAAAAAD6Bq36AAAAAITU2rWr9MEHfzfNPfXULJ199kWm0JQkDR2a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379qGHV1dZo7d67mzp0rr9drzFssFk2bNk2XXXYZbfyAQ1Rtba2ee+45I1xVX1+vCy+8ULfffrtp3RNPPKHZs2cbY7vdrvvvv1/jxo3r7S0DPaKpqUlut9sIWG3ZskU///nPTWvWrFmj6dOnm+YuueQS3Xrrraa5++67T++//74kKS4uTna7XY888oiysrJM69avXy+bzSar1RqCKwIAAAAAdIbgFABgwNu9e7epelTbv5WVlWppaQl6XHx8vF/1qJycHKWkpAzYKkjbt283wlEbNmxQQUGBysvL1draGnC9xWLR8OHDTa328vLyTH/JC+DAtLb4tPKLzfp2oVe7mwL/twjg0JNgjdSE45OUP3aIYuIOvMpcc3OzFi1apDlz5uiHH34wPTZp0iRdeumlOu644wbsayBgIPB6vWppaVFysrnl50033aQvv/zSNPf2228rNzfXNDdt2jRZrVZlZ2fL4XAoPz9fP/3pT0O+byBUtmzZIrfbrc2bN6umpkY5OTkaP368aU37tn9tFixYYApI7dixQyeddJIxttvtOvHEE3XbbbeZjnO73WpoaFBKSgo/MwMAAABADyI4BQAYMNraUZSVlamkpMQISVVVVamzb4eJiYnKyckxhaOcTueA/0vQmpoaUxWpgoIC1dTUBF0/ZMgQo3pU283hcCg8PLwXdw0MXL+dcZMifamKDx+ulj2RptZbnfH5fEYQov39uLg45efnh2y/OHBbt2412swkJSUpOzu7j3eEUBocP0hDk6I0NClKw+xRSs8ZHLLnKigo0BtvvKFPP/3UVIUzIyNDF110kc477zwNHhy65wfQvzQ2Npra/pWWlv5/9u48Lup6+x/4i0U2kU1AcB3WGTZFBMR9QyX1uqQVopZL3TYzu9atzG5a3ntb7GplV7uZ4m5qRaWlaLngQkKKMOwgg4DADCAgwoAIvz/88vn5ccByYT4sr+fjMQ+d9+eM94A3kJnXnIN//vOforVkV69exfjx40WP8/DwwO7du0Vnly5dQnJysrD2jytBqSPIz88XVgNqNBrMnTtXdD0rKwvh4eGis7CwMKxevVp09t///hebN28GAFhYWMDR0RFvv/02BgwYIKrLyMiAtbW1TsiRiIiIiIiImsfgFBERdTharVY0OaopJFVQUHDXgJSDg4MoGOXq6go3NzdYWVnpsfu2p76+HtnZ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4OnpKTpLT0/HsmXLUFRUJJw98sgjeO+990R1O3bswLp164Q1gzKZDHPnzoVCodBL70REREQPisEpIhLJz8+HUqlEYmIikpKSWgzrGBsbw8PDA35+fujfvz9X7j2g6upqJCYmCpOklEolysvLdeoMDQ3h6uoqCqe5urrC0NBQgq6JiKi2thZbt27F1q1b0adPH+zevRsGBgZSt0VERG1QSUkJtmzZgu+++w51dXUAbq3RnDdvHmbNmgUzMzOJOyQiIildunQJubm56NKlC4YPHy669uGHH2Lv3r3CfVNTU7z11luYNGmSvtskok4qNTUVly9fRvfu3REYGCi69v7772P//v2is40bN+rUrVixAqampnB0dISjoyNkMhkGDhzY6r0TERER/REGp4g6sbq6OqSkpCAxMRGJiYm4ePEirl692mytg4MD/Pz8hJu3tzdMTEz03HHH0NjYCJVKJYTTEhMTkZOTg+a+HNvZ2cHPzw++vr7Cr3xBhYiobYiOjsbatWuh0WgAAGZmZoiMjOTUKSIiuqvS0lJs374d+/fvh1arBXBreu+cOXPw+OOPo2vXrhJ3SEREbc2ePXsQHR2NtLQ0IXzbXChh/fr16NKlC7y9vdG/f39YW1tL0S4RdTLp6elIT0+HRqOBWq2GRqPB8uXLYW9vL9Rcv34do0aNEj0uMDAQGzduFJ0lJSUhLy8Pffv2hbu7O58LJyIiIr1gcIqoEykpKcHFixeFkFRaWlqz06RMTEygUCiEkJSvry/3kz+AqqoqKJVKISSVlJSEqqoqnTpjY2MoFAohJOXn54eePXtK0DEREf0ZixYtwsWLFwEAU6ZMwZIlS7gqldqcL774AgAwduxYrnQhamMqKiqwfft27N27F9XV1QCAbt26ITw8HHPmzOHacyIialZaWhpSU1MxceJEWFhYiK6NHDlS+J4CAD179sQPP/yg7xaJiHRcvXoVn332GXJycpCTk4Oqqio8+uijWL58uahuzZo12LNnj3DfwcEBq1atQnBwsL5bJiIiok6EwSmiDurmzZvIzMwUTZMqLCxsttbe3h4DBgxA//79MWDAACgUChgbG+u5444jJydHCEglJSXh0qVLzU6TcnJyEk3xUigU6NKliwQdExHR/VCpVFi5ciVeffVV+Pr6St0OkQ6tViuseVm1ahUmT54scUdE1Jyqqirs3LkTu3fvFt5g0bVrV0RERDBARUREf9q1a9ewatUqxMfHC99PPD09sWvXLlFdUlISjh49iqCgIAQGBnKaCxFJoqSkBPX19Tpv2F66dClOnTolOouMjNR53uXRRx+FpaUl+vXrB5lMBrlcrrPmlIiIiOjPYnCKqIPQarVISkpCQkICEhISkJiYiJqaGp06Q0NDeHp6on///kJQytnZWYKOO4ba2loolUrRJK9r167p1JmYmMDLywt+fn7o378//P39OZWEiKidqK6uxpYtW7Bw4UKYm5tL3Q7Rn8bgFFH7cv36dXz99dfYtWsXysvLAdyaQDVv3jyEh4frTBUhIiJqiVKpRHx8PLp06YI5c+aIrm3atEm0GisgIACvvPIKvLy89N0mEZEOrVaLS5cuQaVS4fLly8jJycHy5ctFq0erq6sxcuRI0eOaC4qmp6cjMzMTrq6ucHFx4XM6RERE1CKOlCFqpyoqKnD+/HkhKJWWloabN2/q1HXr1k0UkvL19eU7yR5ASUmJKJyWnp7e7Oe9R48eQkiqf//+nOJFRNROHTp0COvWrUNJSQnMzc2xcOFCqVsiIqIOqmvXrli4cCEiIiKwe/dubN++HZWVlfjvf/+LXbt24cknn8Tjjz/On+eIiOgP+fr6tjgVt6KiQnT//PnzzU5AP3DgAIYNGwZbW9tW6ZGIqDlmZmbw9vaGt7d3izWGhoZ49913oVKpkJOTA5VKBU9PT526Y8eOYdOmTcJ9R0dHfPzxxwyKEhERkQ6+ik/UTuTn5yMhIQEXLlxAQkICcnNzm62TyWSioJSLi4ueO+04GhsbkZ2dLQSlWlp3aGRkBE9PTwwYMAADBgyAv78/HBwcJOiYiIgelpKSErz55pu4cOGCcKZUKiXsiIiIOgszMzMsWLAAjz32GHbv3o2dO3eivLwcn376KXbs2IEFCxZg5syZMDExkbpVIiJqh5YtW4bFixcjNTUVSUlJSE1Nhbu7u6gmMTERK1euBADI5XIEBQVh6tSpcHV1laJlIiIRMzMzTJo06Q/ramtrYW5uLmzmUKvVzW6BGDt2LPr27QuZTCas/RsyZMhD75uIiIjaLq7qI2qDGhoakJGRIQR2EhISUFJSolNnbGwMhUIBf39/+Pv7IyAgAFZWVhJ03DHU1dUJ6w6bVu9VVVXp1HXr1g1+fn5CUIpTvIiIOp66ujrMmDEDxcXFcHV1xeLFi3XGwBMREenDtWvXsGPHDuzevRvV1dUAAAcHByxatAjTp0/nZFsiInroDhw4IASnmrz77rs6QYX8/Hz07t1bn60REd2z4uJiYTJVeHi46FpeXh5mzJghOvP29sa2bdtEZ1lZWVCpVPD19YWTk1Or90xERET6xeAUURtw8+ZNpKSk4PfffxfW7zU9IX47c3Nz+Pn5YeDAgfD390f//v1hamoqQccdw/Xr14UJXufPn0dKSgrq6+t16nr27ClMkhowYADc3NxgYGAgQcdERKRPp06dwtWrV/GXv/xF6laIiIhQUVGBbdu24euvv4ZWqwVw62eVF154ARMnTuTPKERE9FBVV1fj3LlzOHv2LGJjY7F582Z0795duF5fX4/Ro0fDwsICwcHBCA4OxpAhQziFnYjalfz8fGzatAkqlQoqlQpVVVWYNGkS3n33XVHdV199hQ0bNgAAunfvDh8fHzz77LOQy+VStE1EREQPGYNTRBKor6+HUqnE+fPnhaBU0xPft7O1tRWmSQ0cOBByuRxGRkYSdNwxVFRUCOG0CxcuICMjA3d+CTQ0NISnp6cQkho4cCDs7e0l6piIiFpbcXExtm3bhsrKSrz33ntSt0NERPSHysvLsWXLFuzfvx+1tbUAbq1ReumllxASEiJxd0RE1FlcvHgRixYtEp15eXlh+/btEnVERPTgSkpKUF9frzNVasWKFTh06JDoLDIyEr6+vqKz1157TVj55+LiAldXV26rICIiagcYnCLSgxs3biAxMRHnz5/H77//jqSkJOEJ7tvZ29tj0KBBCAgIwKBBgyCTySTotuNQqVRISEhAYmIiLl68iNzcXJ2apqBUYGAgAgMDERAQAAsLCwm6JSIifcrLy8OWLVvw008/CdMGd+zYAYVCIXFnREREf45Go8HGjRvx448/oqGhAQAQEBCAZcuW8Z3vRESkFwkJCTh37hx+++03XLx4EfPnz8fixYtFNd9//z3UajUGDx6M/v37S9QpEdGD0Wq1UKlUyMnJEdb+vffee6KNILm5uZg5c6bocWFhYVi9erW+2yUiIqJ7xOAUUSuor69HcnIy4uLiEB8fj8TERNTV1enU9ejRQwhJBQQEoG/fvhJ023E0Te9KTExEQkICqqqqmq2Ty+UICAhAUFAQAgICYGlpqedOiYhIap988onwTmgTExOE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y5cvV3BwsObNm6e0tDQ5OzurY8eOWrp0qT7++GN17NiRoikHVatWLbVr106StGjRIh05csRwIgBAUTp8+LD+/e9/W4umJCk7O9tgIgAAgBtTp04dSdLvv/9uOAkAAI4lLS1NY8aM0Z49e/Too48qKirKdCQAwF/k10Hmvffe0759+/TCCy+ob9+++v777w0kAwD8GStOlXBZWVkKCwvTwoULlZiYaB3v1KmTRo4cqZo1axpMh+KUmJiohx56SBcvXpSfn5+WLl0qT09P07EAADfphx9+UKNGjfJcGdq3b19JUo8ePdSzZ0/atAIAALs0b948LViwQBUrVlR4eLjpOAAAOJStW7fqpZdeksVikYuLi5599ln169fPdCwAwFXs2bNHy5cv17fffmsdmzdvnlq2bGkwFQCUbq6mAyB/OTk52rhxo+bNm6fjx49bx4OCgjRq1CjVrVvXYDqYULVqVT3//POaPn26YmNjNWnSJM2ePdt0LADADTh16pRWr16tr776SqdPn9bYsWP1z3/+0+aYDz74QFWrVjWUEICjmDdvniSpQ4cOqlevnuE0AEqj3At+LBaL4SQAADieDh06yM/PT88++6wSEhIUHR1tOhIA4BoCAgIUEBCgw4cP64033tDly5cpmgIAw1hxqgT69ttv9cEHH9i0Y2vRooXGjh2rxo0bG0yGkuC1117Tl19+KUnq3r27pk6dajgRAOB67Ny5UyNHjrQZa9Omjd5//31DiQA4KovFoqCgIEnStGnT1K1bN8OJAJRGoaGhmjFjhiQpMjLScBoAABxTamqqlixZkud8AwCg5EtJScnTbeDgwYO69dZb83QpAAAUDVacKkGioqL01ltv6eDBg9axxo0b66mnnlKbNm0MJkNJMmnSJMXFxSkyMlJr166Vt7e3xo4dazoWAKCAWrRoIQ8PD126dEn33nuvevbsqbvvvtt0LAAAgCLx5xbzFotF7u7uBtMAAOCYvLy8KJoCADv116IpSZo4caLOnTunESNG6NFHHzWQCgBKF2fTASBFR0dr5MiRGjJkiLVoqnbt2po5c6aWLl1K0RTyeOedd9SgQQNJ0ieffELLPgAoYY4cOaKFCxeqX79++vXXX232lS1bVq+//rq+/vprzZw5U0FBQXJxcTGUFAAAoGi5ublZb1+8eNFgEgAASpecnByNHz+eFR8BwM78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DvYhqYCAALy9vQ3UitQ8q1evBqBhw4b27UBERKqLzp07a3BKRERqvUaNGjFkyBD76rGZmZlXrNx88OBBioqKKCwsZN++fezbt4/FixdjsVho3749PXr0ICAggMDAwHLbTu/ll19m+/btbNy4kVWrVpXLzxQRkdrp0qVLvPnmmwC88847hISEGC4SEfltGpwSERERkWuy2WwcOXLEPiSVmJhIWlraVec5OTnRuXNn+1OwAQEBuLi4GCgWqflsNht169Zl1KhRODg4mM4RESkTX19foqKiOHLkCIWFhdqmV0REBPDw8KB///70798fAKvVyvfff2//Pfz777/HarXaf0c/cuQIy5YtA6BFixYEBAQQEBBAjx49aN68eZn/+19//TXbt28HYOjQoeX3xkREpFbKycmxf12vXj2DJSIi1093qEREREQE+Peg1O7du+3b712+fPmq81xcXOjatSsBAQF0796drl27UrduXQPFIrXPyy+/TG5uLkVFRaZTRETKzM/PD4CioiL2799P9+7dDReJiIhUPS4uLgQHBxMcHAyU/Lt58OBBEhMT2bNnD0lJSfbf1VNSUkhJSWHNmjUANG7c+IqHmtq1a/er/62MjAxee+01ANq2bcvDDz9cge9MRERqg+zsbPvXbm5uBktERK6fBqdERMrgnnvuITU11X7DX0SkOrPZbBw7doyEhAQSEhJITEwkIyPjqvPc3d3tW+716NEDPz8/6tSpY6BYRABcXV1NJ4iI3JDOnTvj5OREQUEBcXFxGpwSERG5DnXq1MHf3x9/f38eeugh++/ye/bssQ9SpaamAnDhwgU2btzIxo0bAfDy8rIPUQUEBNChQwcsFov9Z1+8eBEPDw8yMzOZNWuWVoMUEZGb9ssVpzQ4JSLVhcVms9lMR1yP0NBQCgoKmDJlCpGRkaZzRERERKql48ePk5CQwO7du9m9ezfp6elXnePt7W1/QrVHjx5X3VgVERERuVGTJk1ix44d+Pv78/HHH5vOERERqRFOnz5tX5EqMTGRM2fOXPO80gejAgMDCQgIoFOnTtSpU4edO3fSq1evSq4WEZGaKDk52T7AO27cOFxcXAwXiYj8Nj0+ICIiIlKDnT9/nri4OOLj49m1axdpaWlXnePl5UVAQABBQUEEBQX95lL+IlL5fv75Zxo2bGg6Q0TkpvXu3ZsdO3awf/9+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Z4mIiFRJsbGx/N///R/z58+nS5cupnOMadSoEXfffTd33303NpuNH3/8kbi4OHbu3ElSUhL5+fmcOXOG5cuXs3z5chwdHenatat9kKpjx45YLBbTb0NEpEa4dOkSAD4+Pvq7VUSqFQ1OiYiUga+vL25ubrRu3dp0iohUkOPHj7NkyRKioqLIz8+3Hw8KCuKBBx6gX79+ODg4GCwUkZrkk08+ISwsjLZt21dsP9kAACAASURBVJpOERExrnHjxrz++us8/vjjJCcn88ILLzBnzhzTWSIiIlXOihUrePXVVwF46qmnWLdunYaNAYvFQseOHenYsSPjxo0jLy+P3bt3ExcXx44dOzhx4gSFhYXs2bOHPXv2MH/+fLy8vAgJCSE0NJTevXvToEED029DRKTaKl1xSqupi0h1Y7HZbDbTEdcjNDSUgoICpkyZQmRkpOkcERERqWGOHj3KO++8Q2xsrP2Yi4sLd911F5GRkbRp08ZgnYjURLGxsUyePBmAhQsXEhQUZLhIRKRqeO+99/j73/8OwNNPP82YMWMMF4mIiFQdn332GW+88QYAjo6OzJ49m/DwcMNV1UNqaiqxsbH2FakuX7581TmdOnWiT58+9OnTB39/fz08JyJSBlFRUcTFxeHj48MTTzxhOkdE5LppcEpERERqteTkZBYsWMDmzZvtxzw8PHjggQeIjIykfv36ButEpKY6d+4cY8eOJSMjg44dO/Lpp5+aThIRqTJsNhuPP/44u3fvpk6dOvz973+na9euprNERESqhPnz57No0SIaNmzIG2+8QefOnU0nVUvFxcX88MMP7Nixgx07dvDDDz9QXFx8xTmenp6EhobSp08fevfujaenp6FaEREREalIGpwSERGRWikrK4t3332X5cuX22+MNWzYkDFjxnDffffh6upquFBEaiqr1cr48eM5evQozs7OfPbZZ9oGWETkP6SnpxMZGcnFixfx9PTko48+0t+VIiIi/7Jw4UJGjx5Nw4YNTafUGFlZWezYsYPvvvuO7du327ebKmWxWOjcuTN9+vShb9++dOrUCYvFYqhWRERERMqTBqdERESk1lm7di1vv/02ly5dAqBp06Y89NBDjBw5krp16xquE5GarqCggFmzZrF+/XpmzJhBRESE6SQRkSrp2LFjPPLII2RlZeHj48MHH3xAixYtTGeJiIhIDWez2Th06BDfffcd33333TVXo/L29qZv376EhYUREhKiB/BEREREqjENTomIlMGKFStITU3Fz8+PsLAw0zkiUkZHjhzh1VdfZd++fQC4uLjwyCOP8NBDD+Ho6Gi4TkRqm/j4eIKDg01niIhUaT/88AN/+MMfyMvLo0mTJnz88cc0atTIdJaIiEiliI6OJioqijlz5uDg4GA6p9bKzMy8YjWq9PT0K153dHQkKCiIvn37MmDAAJo2bWqoVERERERuhAanRETKYOzYsRw+fJiRI0fy/PPPm84RkTL49NNPefvttykqKgIgPDycqVOn4uPjY7hMRERERH7N7t27+eMf/0hhYSGtWrXigw8+wNvb23SWiIhIhcnNzeVvf/sby5YtA+DRRx/lscceM1wlULIa1Q8//MC2bdvYtm0bP/7441Xn3HLLLfTv35/+/fvj5+enLf1EpFY4e/Ys8+bNo1GjRowfP15DpCJSrWhpBREREanRcnNzef755/n2228BaNmyJS+++CLdu3c3XCYitUlGRgaenp6mM0REqqXAwEDmzp3L008/zalTp/j973/PwoULadasmek0ERGRcnfo0CGmTp3KuXPnAAgKCuL+++83XCWlLBYL/v7++Pv7M3HiRFJTU9m6dSuxsbHEx8eTl5fHsWPHOHbsGB999BE+Pj6EhYXRv39/evXqhZOTk+m3ICJSIc6cOUNMTAwADzzwgOEaEZGy0dquIiIiUmOdOnWKMWPG2Iemhg4dyrJlyzQ0JSKV6vLlyzz88MM8++yz5OXlmc4REamWwsLCeOGFF4CSG/IPPfQQBw4cMFwlIiJS/ho1akRWVhYAEyZMYOHChXh5eRmukv/Gx8eHUaNG8dZbb7F582b++te/cvfdd9OgQQMAUlNTWblyJZMnT2bgwIFMnTqVdevWkZGRYbhcRKR8Xbhwwf61VpsSkepGK06JiIhIjXT27FnGjRvH5cuXqVOnDk8//bSe0BQRIyZPnszJkyc5efIkQ4cOpX///qaTRESqpWHDhmGxWJg5cybp6ek8+uijzJkzhz59+phOExERKTcNGzZk1qxZODo6EhoaajpHysDFxcW+RZ/NZuP7778nJiaGmJgYkpOTsVqtbN26la1bt2KxWOjevTsDBgxg4MCB/M///I/pfBGRm1I6OFWvXj1cXFwM14iIlI0Gp0REyuCee+4hNTUVPz8/0yki8isyMzOZOHEily9fxmKx8MorrzBo0CDTWSJSyxQVFTFlyhT27t0LwMSJEzU0JSJykyIiIvD09OTPf/4zeXl5TJ48menTpzN8+HDTaSIiIjfku+++u2oIOCwszFCNlBeLxULXrl3p2rUrkyZN4syZM3zzzTfExMSwd+9eiouLSUxMJDExkTfffJNbb72VgQMHMnDgQG699VbT+SIiZXbx4kUAGjdubLhERKTsLDabzWY64nqEhoZSUFDAlClTiIyMNJ0jIiIiVdjEiROJj48H4LnnnuPee+81XCQitdGZM2cYO3YsWVlZREREMGPGDNNJIiI1RlJSEpMnT7ZvZTR+/HieeOIJw1UiIiLX7+jRo8yYMYNDhw4xf/58evXqZTpJKklGRgYxMTFs2bKF2NjYq15v1qwZ4eHhDBo0CH9/fwOFIiI35uzZs+Tk5HDLLbeYThERKRMNTomIiEiNkpSUxIQJEwB49NFHeeyxxwwXiUhtduzYMd58803eeustHB214K+ISHk6evQoEydO5NKlSwCEhITw6quvUr9+fcNlIiIiv+6f//wnc+fOtf85PDyc1157zWCRmJKTk8N3333HN998Q2xsLDk5OVe8XjpENXjwYHx9fQ1VioiIiNRsGpwSERGRGmXKlCnExMTg4eHB119/rUEFERERkRrsp59+4n//939JSUkBSj5cnDdvHh07djRcJiIicm3JycmMGjUKAFdXV5588klGjx5tuEqqitjYWL755huio6PJzs6+4rUmTZowZMgQwsPDNUQlIiIiUo40OCUiIiI1St++fbFarYwdO5annnrKdI6I1DJZWVm4u7ubzhARqVWysrKYPn26fasbJycnZs6cyeDBgw2XiYiIXNubb77Jrl27mDt3Li1atDCdI1VQYWEhO3fuZNOmTWzdutW+PXGpli1bMmTIEIYOHUrLli0NVYqIiIjUDBqcEhEpg9mzZ3Pq1Cn69evHgw8+aDpHRP5DYWEhISEhAEybNs3+BKeISGXYunUrs2fPZuHChbRv3950johIrfPRRx+xYMECSm913X333fz5z3/GxcXFcJmIiNRmGRkZeHp6XnHMarXq3ye5boWFhezYsYOvv/6ab7/99qqVqPz8/Ljzzju544478Pb2NlQpIrVZTk4OKSkpNG7cGC8vL9M5IiJl5mA6QESkOjl48CB79uzh5MmTplNE5Bq0LZ+ImBIbG8vUqVNJT0/XanciIoY8/PDDvPvuu/aV/9asWcP999/PwYMHDZeJiEhtlJOTw5w5c7jrrrs4f/78Fa9paErKwtHRkbCwMGbNmkV0dDTz5s3jjjvuwNXVFYADBw7w17/+lSFDhvDHP/6RdevWkZOTY7haRGqTH374gTFjxhAeHk5ycrLpHBGRMtPglIiIiNQofn5+AMTHxxsuEZHaIj4+nqlTpwLg6urKnDlzDBeJiNRewcHBLF26lG7dugFw5swZfv/737N48WKqyaLrIiJSA0RFRTFixAiWLVuG1WplwYIFppOkhnBycmLAgAG8/PLLREdH88orr9C3b1/q1KlDcXExO3fuZMaMGYSHhzNt2jS2bt1KQUGB6WwRqeHOnDlj/7pp06YGS0REbowGp0RERKRG6dChA1CyZdbFixcN14hIbbBs2TIKCwtxcXHh3XffxdfX13SSiEit1rRpU/7+978zceJE6tSpQ2FhIX/729/4wx/+wNmzZ03niYhIDRcbG8v06dNJS0sDYNSoUfYHLUTKk7OzM4MHD+att97i66+/5tlnn6VLly4A5OfnEx0dzdSpU7njjjt4/fXXOXDggOFiEampfvrpJwAaNGigVRVFpFrS4JSIiIjUKPfccw8ARUVFLFq0yHCNiNQGs2bNonfv3rz77rv2m9QiImKWg4MDjzzyCB9//DHNmjUDIDExkfvvv59Vq1YZrhMRkZqsd+/etG/fniZNmrBo0SKmTZtm30ZWpKJ4enoyevRoFi1axOrVq3n88cdp1aoVAJmZmXzxxRf87ne/Y/To0XzyySf2wT4RkfJQOjhV+ruXiEh1Y7FVk3XKQ0NDKSgoYMqUKURGRprOERERkSrstddeY/ny5QC8/vrrDBo0yHCRiIiIiJiSk5PDG2+8ccXAVGhoKC+++CI+Pj4Gy0REpCZIT0/Hy8vrimOHDh2iRYsWGpgS4/bv38+6devYuHEjly9fth93cHAgJCSEiIgIBgwYQN26dQ1Wikh1t2zZMqKiomjZsiUzZ840nSMiUmYanBIREZEax2q18uCDD5KcnIyjoyMLFy6ke/fuprNEpIbYuXMnvXr1Mp0hIiJltH37dmbOnMnPP/8MgIeHB9OmTWPw4MGGy0REpDpKTk7mtddeIz09nc8//xyLxWI6SeS/KigoICYmhnXr1rF9+3aKi4vtr7m7uzN48GCGDRumVZRFRESkVtLglIiIiNRIycnJPPzww2RmZuLq6sqiRYto37696SwRqcaKioqYOXMm69ev1+8lIiLV1OXLl3nppZf45ptv7Mf69OnDiy++iLe3t8EyERGpLpKTk1m0aBFfffWV/dicOXO47bbbDFaJXL/09HTWrVvHunXrOHr06BWvtWnThuHDhzNs2LCrVlITERERqak0OCUiIiI11pEjR5gwYQLZ2dm4uroyZ84cQkNDTWeJSDWUlZXF1KlTSUhIAMDf35+PP/7YcJWIiNyojRs38tprr9m3rKlfvz5TpkwhIiLCcJmIiFR1f/3rX/n8888BaNCgAZMmTWLYsGFacUqqpUOHDrFu3TqioqJIT0+3H69Tpw5hYWGMGDGC0NBQ6tSpY7BSREREpGJpcEpEpAwOHjxIdnY2jRo1onXr1qZzROQ6HDp0iD/96U/2LVkmT57Mgw8+aLhKRKqbxx9/3D40dfvtt/Pqq68aLhIRkZv1888/M3PmTLZv324/FhgYyEsvvUSTJk0MlomISFWWnp7OsGHDGDFiBI8//jhubm6mk0RuWmFhITExMaxatYq4uDh++dGhj48PERERjBgxghYtWhisFBEREakYGpwSESmDsWPHcvjwYUaOHMnzzz9vOkdErtOlS5d45plnSEpKAuC2227jpZdewsXFxXCZiFQX33//PRMmTOD2229n1qxZeppcRKQGiYqKYu7cuWRkZADg6urKE088wX333ae/70VEarGcnBw++eQThg8fTrNmza54LTMzEw8PD0NlIhXrwoULrF69mtWrV3Pu3LkrXgsICGD48OEMGjRI99VEBIDo6Gg2b95Mq1atmDhxoukcEZEb4mA6QERERKSiNWjQgA8++IDbb78dgC1btjBu3DiSk5MNl4lIddGlSxfef/99Zs+erQ/RRURqmCFDhrB8+XIGDhwIQG5uLnPnzuWRRx7h1KlThutERKSyWa1WPvnkE4YNG8YHH3xwzS26NTQlNVnjxo159NFHWbduHW+//TaDBg2yv7Znzx5efPFF+0NF+/fvN1gqIlVBQkICmzZtYsuWLaZTRERumAanREREpNZ45ZVXGDFiBADHjh3jwQcfZNu2bYarRKQqunz58lXHunXrZqBEREQqQ4MGDZg7dy6vvfYaXl5eAOzbt4/7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IlLzZGVlXXVs6NChdOrUiaeeeooNGzbwpz/9iUaNGhmoE5GyaNasGZMmTWL9+vW8/vrrhISEYLFYKCoqIiYmhsmTJzNs2DDef/99Lly4YDpXRP7l2LFj9q+12pSIVHcanBIRERH5FR06dOCzzz4jKCgIgCNHjhAZGcmOHTsMl4lIWUVERDB//nz+8pe/ULduXdM5IiJSw3h4eDBjxgwWLlxI06ZNAdi/fz/3338/H330EUVFRYYLRUSqv5SUFObOncudd95JVFTUVa8vWbKEsWPHamVZkWrI0dGRQYMG8c4777B27VoeeeQRfHx8ADh//jzvv/8+ERERTJ48mZiYGF1biRh29OhRAFxcXOy//4iIVFcWWzVZMzw0NJSCggKmTJlCZGSk6RwRERGpZYqLi5k/fz6LFy8GwGKx8NhjjzFhwoQy/ZygoCASEhIqIlFEfuGLL77A19cXf39/0ykiIlILWa1W3nvvPT799FP71jK33HILL730Eh07djRcJyJS/Rw/fpx33nmHb7/91n6sW7du9q24RaRmKioqYtu2baxatYrvvvvuim2QfXx8GD58OCNHjtTQhogBGzZsYOXKlTg5OTF//nzTOSIiN0WDUyIiIiJlsGXLFl544QWsVisAffv2Zfbs2bi7u//m95auWuXk5KQVq0QqyE8//cT06dPZt28fLVu2ZOnSpTg7O5vOEhGRWurw4cO88MIL9m0sHBwcePDBB3n88cdvaPVDDeGLSG118uRJ7r33XqBkhb8777yTkSNHamsgkVrkwoULrFq1itWrV3P+/Hn7cYvFQq9evbjnnnvo168fjo6OBitFRESkOqozY8aMGaYjrseHH35IcXExvXv3pkuXLqZzREREpJZq27Ytt912Gzt37iQjI4NTp06xadMmQkND8fLy+q/fFxQUZH8qrri4mIKCAnr27FlZ2SK1wubNm3nyySdJSUkBoEmTJvTr14/69esbLhMRkdrKx8eHe+65B1dXV/bu3UthYSF79+4lKioKf39/mjRpct0/q3QI//3338fb2xs/P7+KyhYRMSouLg53d3dcXFzsx7y8vCgqKuLee+9l1qxZ9OnTB29vb4OVIlLZ3NzcCAwMJDIyks6dO5Obm0tKSgrFxcWkpKSwadMmvvzySzIyMmjZsqXuBYiIiMh104pTIiIiIjcgNzeX5557jtjYWKBk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Wrvh5FwyhnTmRK7hmuvnaDpARKQ6+fTTT00n1Chp5/MBcPN0sm99IyIiIlJVOdRxoElLN84mZ5N2Ps90jlSAtAv//v+1eTs3gyUiIiIiv635LfU5kpRBUYGNrPQC6jfQ/bWa5tK/fu9o0d7dcImIiIjIb7M4WGjaxo3Thy9Xq/unWnFKRESMycoseZrf3VM3dURERKR6qO9V8vxRdmah4RKpCKXXp6BrVBEREan63Dz+/Wx89i+uY6TmyPrX7x31dG0qIiIi1YS7Z+n90+pzfarBKRERMcaaXQSAs2sdwyUiIiIi16duvZJf/HOyigyXSEUovT4FcK6nRbpFRESkaqvn/u9hmpxsXZ/WRNacYgBc6+n+qYiIyP9n787Doqr+P4C/URQGFwbFBdlBFMXEfd9x18wtK5fU0qTUXHL7luWeS2mWmZpL5ZZbpua+b6louIUKoqAoYgiCKIsywO8PfozcubMBs13m/XqenriHO3c+cmfOvefczzmHpKFMudx71HQJ3Z8ycYqIiMwmJyf3/yV4NSIiIiKJKFHSBgCQk51j5kjIGPLuT2Fj1jCIiIiI9GKTr08tWzrPpUhf+ZscNrxBJSIiIon4/9uW7GzzhlEQHD5JRFQAt27dQmpqKipVqgRPT09zh0NERERERERERERERERERESFxDk+iIgKYO7cuQgODsbGjRvNHQoREREREREREREREREREREVAROniIiIiIiIiIiIiIiIiIiIiIjI6jBxioiIiIiIiIiIiIiIiIiIiIiIrA4Tp4iIiIiIiIiIiIiIiIiIiIiIyOrYmjsAIiIp6du3LxISElC7dm1zh0JERERERERERERERERERERFwMQpIqIC6Nevn7lDICIiIiIiIiIiIiIiIiIiIgPgUn1ERERERERERERERERERERERGR1mDhFRERERERERERERERERERERERWh4lTRERERERERERERERERERERERkdWzNHQARkZTMnTsXMTExaNOmDQYPHmzucIiIiIiIiIiIiIiIiIiIiKiQmDhFRFQAt27dQkREBDw9Pc0dChERERERERERERERERERERUBl+ojIiIiIiIiIiIiIiIiIiIiIiKrw8QpIiIiIiIiIiIiIiIiIiIiIiKyOkycIiIiIiIiIiIiIiIiIiIiIiIiq2Nr7gCIiKRk+vTpSE1NRaVKlcwdChERERERERERERERERERERUBE6eIiAqgVq1a5g6BiIiIiIiIiIiIiIiIiIiIDIBL9RERERERERERERERERERERERkdVh4hQREREREREREREREREREREREVkdJk4REREREREREREREREREREREZHVsTV3AEREUjJ37lzExMSgTZs2GDx4sLnDISIiIiIiIiIiIiIiIiIiokJi4hQRUQHcunULERER8PT0NHcoREREREREREREREREREREVARcqo+IiIiIiIiIiIiIiIiIiIiIiKwOE6eIiIiIiIiIiIiIiIiIiIiIiMjqMHGKiIiIiIiIiIiIiIiIiIiIiIisjq25AyAikpJNmzaZOwQiIiIiIiIiIiIiIiIiIiIyAM44RUREREREREREREREREREREREVoeJU0REREREREREREREREREREREZHWYOEVERERERERERERERERERERERFbH1twBEBFJya1bt5CamopKlSrB09PT3OEQERERERERERERERERERFRIXHGKSKiApg7dy6Cg4OxceNGc4dCRERERERERERERERERERERcDEKSIiIiIiIiIiIiIiIiIiIiIisjpMnCIiIiIiIiIiIiIiIiIiIiIiIqvDxCkiIiIiIiIiIiIiIiIiIiIiIrI6tuYOgIhISvr27YuEhATUrl3b3KEQERERERERERERERERERFRETBxioioAPr162fuEIiIiIiIiIiIiIiIiIiIiMgAmDhFRERkZWbOnISUlGQAQMmStpgzZyns7e3NHBXl2bRpDUJDLyi3g4M/Q40atcwYEVHxEBJyFlu3/qrc7tz5TXTt+pYZIyoahUKBly8zkJGRAYUiEwqFAtnZWShZ0hYVK1aCnZ2duUPUKisrC6GhF1Ctmjvc3DzMHQ4RmVlxq6OLG54fIuMpTu3znJwcvHz5Ei9fZiAz8xUyMzOhUGQiOzsbMpkDKlashJIlS5o7TGRlZeHVq1d4+TIDr169hEKhQFaWAjk5OShfXg653MncIRKRmcXHP8aCBdOV297efhg7dqoZIyJVxen6SWRJituzifz3fJmZmcjKykJWlgIymQOcnCrC1tayU2UePXqIhIR4PH2agOzsLDg6OkEurwC53AmOjk4WH7/U8K9JRERkZa5evYT09DTldlaWwozRkKp79+7ixo1ryu3k5KdmjIao+Hjy5LHguxUQEGjG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c4dFRMWYZBKn7OzsAHDGKSIyryVLlpg7BCIiKgZmz+b1hIiIiIgsx8CBH2LgwA/NHQYRERERERo0aIoGDZqaOwwisiIlzB2AvjjjFBERERERERERERERERERERERGQoTp4iIiIiIiIiIiIiIiIiIiIiIyOpIJnEqb6m+9PR0M0dCRERERERERERERERERERERERSZ2vuAPQlk8kAAKmpqWaOhIisWUxMDOLj41GmTBnUqlXL3OEQERERERERERERERERERFRIUkmcapMmTIAgLS0NDNHQkTWbOvWrdi6dSt8fHywbds2c4dDREREREREREREREREREREhSSZpfqYOEVElqB06dIAgMzMTDNHQkREREREREREREREREREREUhmcQpBwcH5c/p6elmjISIrBkTp4iIiIiIiIiIiIiIiIiIiIoHySROlS1bVvlzamqqGSMhImuWlzj16tUrM0dCRERERERERERERERERERERWFr7gD0Vb58eeXPKSkpcHZ2NmM0RGStGjVqhJEjR8Le3t7coRAREREREREREREREREREVERSCZxqkKFCsqfExIS4OPjY8ZoiMhaBQYGIjAw0NxhEBERERERERERERERERERURFJZqm+/DNMPX361IyREBERERERERERERERERERERGR1Ekmcaps2bKwtc2dICshIcHM0RARERERERERERERERERERERkZRJJnEKeD3rVGJiopkjISIiIiIiIiIiIiIiIiIiIiIiKZNk4hSX6iMic4mLi8OCBQvw2Wef4fHjx+YOh4iIiIiIiIiIiIiIiIiIiApJUolTFSpUAMAZp4jIfJ4+fYodO3bg1KlTSE5ONnc4REREREREREREREREREREVEiSSpyqWLEiACZOEZH5lClTRvlzamqqGSMhIiIiIiIiIiIiIiIiIiKiopBk4lRcXJyZIyEia5U/cSotLc2MkRAREREREREREREREREREVFRSCpxqmrVqgCAFy9e4NmzZ2aOhoiskYODg/JnzjhFREREREREREREREREREQkXbbmDqAgPDw8lD8/fPgQjo6OZoyGiP6PvTuPrqo82z9+hYRAJgiQSQYzAgHCaBgUEApRVKJSRKUOVBGLUxUp/gSHNq0T+mrFVl5wZBBb8aWCGgQlzKCAAYIkJDGQQUjICAmZTubfH+hpt6GtIMmTk3w/a53l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xXQMAAAAAAAAAAAAwK6srMx0BABocZxjYmJiTIdoau7u7vLy8tKXX36poqIi2Ww2XX755aZjAWiF7r33Xr3xxhs6c+aMfdodAKD5bdu2TZ9//rlOnDih8PBw03EAAADQhr344ot64403VFJSoqFDh5qOAwAAgDZs6dKlevLJJ1VdXa1hw4aZjgMALUKbmDglSbfeeqvGjBkjSXr//fe1d+9ew4kAtEYDBw6UJO3cuZPpdgBg0LZt2/TWW29p3bp1pqMAAACgjfvqq6+UnJysrKws01EAAADQhhUVFWn16tUqLi7W8ePHTccBgBajzTROSdKf/vQndevWTZL05JNPqri42HAiAK3NxIkTJUlVVVXatGmT4TQAAAAAAMCknJwcnThxQpIUGRlpOA0AAADaqoaGBj355JOqqqqSi4uLHnzwQdORAKDFaFONU506ddILL7wgSSouLtYTTzyhhoYGw6kAtCYDBgxQz549JUlbtmwxnAYAAAAAAJj0w7WBdu3a6corrzScBgAAAG3V4cOHFR8fL0m699575efnZzgRALQcbapxSpKGDRumO++8U5K0b98+rVy50nAiAK3NPffco2eeeUYvv/yy6SgAAAAAAMAgFxcXde7cWcOHD1enTp1MxwEAAEAbNWjQIC1ZskSXX3657r77btNxAKBFcWpogyOXamtr9etf/1qpqalq166d/vKXv2jUqFGmYwEAAAAAAABohQoKCuTr62s6BgAAAAAA+JE22TglSdnZ2br11ltls9nUsWNHLVu2TL179zYdCwAAAAAAAAAAAAAAAEAzaHNb9f2gR48eWrhwoZycnGSz2fTQQw8pLy/PdCwAAAAAAAAAAAAAAC7YkSNHNGvWLJWWlpqOAgAtXpttnJKkMWPGaMGCBZKkoqIiPfjggyorKzOcCkBrkpCQoMWLF5uOAQAAAAAAmtGOHTtMRwAAAEAbFRsbqxkzZighIUFz5841HQcAWrw23TglSVOnTtXMmTMlSZmZmZo7d65qa2sNpwLQGqxfv16zZs3SsmXLlJycbDoOAAAAAABoBtu3b9fcuXN11113KTc313QcAAAAtCEPP/ywYmJiJEne3t767W9/azgRALR8bb5xSpIeeOABRUdHS5IOHDhg/8cEAH6O8ePHq2PHjpKk5cuXG04DAG1LTEyMIiMjddddd5mOAgAAgDaksrJS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XJxqa2u1ceNGbdy4UWFhYZo8ebImT57MFCqglXFxcdH8+fPVv39//elPf1Jtba327NlD4xQAAAAAwCEUFRWpW7dullppaan9eVBQkKKiolRXV9fc0QAAANqU3NxcdejQQV26dLHUY2JiFBcXZ6ldf/31lsapjh076oYbbpC3t7eCg4MVEhKikJCQRr8Hk6UAAC0ZE6dakVOnTmnNmjX66KOPVFhYaK87OTlp5MiRmjx5sn7xi1+oY8eOBlMCuNiOHj2q559/XosWLVKnTp1MxwGAFoGJUwAAAC3P9u3btWnTJu3YsUPXXnutFixYYDn+xRdf6Pjx45o4caKCgoIMpQQAAGjdCgoKtHjxYqWnpysjI0OVlZV69NFHdfvtt1vWvfnmm3rzzTfl6uqq0NBQ9erVS7/61a80cOBAQ8kBAGgaNE61QrW1tfryyy+1fv167dixQzU1NfZjbm5umjhxoqKjo3XZZZfJycnJYFIATc1ms9EsCaBNWrFihXbv3q2QkBDNnz/fdBwAAIA27cyZM7ruuutks9nstUsuuUSffvqpwVQAAACtT0pKig4cOKDMzExlZWUpPT1db731lqUp/fTp07rqqqss75syZYqeeuopS62wsFC1tbUKCAholuwAAJhC41QrV1ZWps8//1yxsbE6fPiw5Zi/v7+uvfZaXX/99QoMDDSUEEBTWbx4sTZs2KCYmBhFRkaajgMAAAAAaOXKy8u1d+9e9e/fv9EXbNOnT9fRo0fl6empyMhIjRgxQrfccouhpAAAAI7JZrPp2LFjOn78uPz9/TV06FDL8ZdfflkffPCBpbZo0SKNGTPGUluwYIF69uyp4OBg+4ObsAEAbRWNU21Idna2Pv30U61fv14nT560HAsLC1NUVJSuvvpqXXrppYYSArhYsrOzdeONN9pfX3PNNZo3b568vb0NpgIAAAAAtDa5ubn65JNP9NVXX9lv2ps/f76mTZtmWbd371517NhRgwcPNhETAADAYaSlpal3796W2r59+/SHP/xBBQUF9toNN9yg3//+95Z1H3zwgV5++WV16NBBQUFBCgoK0m233aYBAwY0S3YAABwRjVNtUENDgw4ePKj169crLi5O5eXlluPBwcGaOHGioqKiFBYWZiglgJ/ryy+/1DPPPGP/QWrs2LF69dVXDacCAAAAALQm33zzjWbOnGmpRUVFaeHChYYSAQAAOJbY2Fht3rxZGRkZOnHihCRp69at8vLysq9JTEzUXXfdZX/doUMHRUdHa8GCBZZf6/Tp07LZbLrkkkuaJzwAAK0AjVNtXHV1tb788kvFxcVp586djZqoLr30Uk2YMEFRUVEKDw83lBLAhbLZbHrzzTe1evVq/e1vf2NbTgAAAADAeSkuLtaePXu0Z88excfHa926dXJxcbEfr62t1dixY9W5c2eNGjXK/mDiMQAAaOuKi4u1Y8cOfffdd8rIyFBWVpZGjhypxx57zLLuXNvrrVq1yvK9XFlZmTZs2KCgoCAFBgbKz8+vWc4BAIC2gMYp2NXU1GjPnj2Ki4vT9u3bVVZWZjnevXt3TZw4URMnTlRERIShlAAuRElJiTp37tyoXlpaarlrBQBai23btik1NVX+/v6aMmWK6TgAAAAOacmSJXrnnXcstbfffltDhgyx1E6cOKGePXs2ZzQAAACjysrKlJ6eroyMDGVmZspms+nxxx+3rDly5IhmzJhhqY0ZM0aLFi2y1DZv3qy4uDgFBASoW7du8vf318iRI9WpU6cmPw8AAEDjFP6N2tpaSxNVaWmp5bivr69Gjx6tsWPHauTIkerYsaOhpAAu1Icffqi3335bDz/8sKKjo03HAYCLKiYmRrGxsYqIiNDy5ctNxwEAAGixKioqlJiYqIqKCo0fP95yLDY2VjExMZIkLy8vRUREaNasWRo8eLCJqAAAAM3i1KlTys/PV1FRkXJzcxUaGtqocfz2229Xamqq/bWXl5e2bt1qWVNSUqLo6Gj5+vrKz89PPj4+ioiI0PTp05vlPAAAwE9D4xT+q9raWn399deKi4vTtm3bVFJSYjnevn17RUZGauzYsbryyisVEBBgKCmA8xEVFaXi4mJJUmhoqO6++25dc824ZhiFAAAgAElEQVQ1hlMBwMVB4xQAAMB/9oc//EFJSUnKzMyUJPn4+Gjjxo2WNUVFRfrqq68UERGhoKAgEzEBAAAuuuzsbB0/flzHjx/XzTffbDmWkJCgWbNmWWrTp0/XvHnzLLXHHnvM3ijVuXNn+fr6NtpuDwAAOAYap3Be6urqdOjQIe3YsUO7du2yX1z7VyEhIRo7dqzGjh2rgQMHytnZ2UBSAP/Nd999p2effVYHDhyQJLm5uemzzz5j6z4ArQKNUwAAAGedOXNGdXV16tKli6U+ZcoUnThxwv7a09NTH330kbp27drcEQEAAC6akpIS5efnq3v37vLw8LAce/DBB7V3715LLT4+3vL65MmTuv766+2v3d3dNXXqVM2ZM8ey7ofPUWxXDACA43MxHQCOxdnZWcOGDdOwYcM0Z84cnTx5Utu2bdPOnTt14MAB1dbWKj09Xenp6VqxYoW8vLw0evRojRkzRldccQX7MQMtyKWXXqo333xTO3fu1KuvvqoJEybQNAUAAAAADq6wsFCff/65kpKSlJSUpOzsbM2ePVv33nuvZV1kZKR69Oih4cOHa+TIkerXr5+hxAAAAD9Nbm6uysrKFBYWZqnHxcXp9ddfV35+vqqrqyVJS5Ys0fDhwy3rysvLG/2aOTk56t69u/31JZdcoscee0zBwcEKCgqSn5/fObPQMAUAQOvBxClcNBUVFfrqq6+0c+dO7d69W6dPn7Ycb9eunfr166cRI0Zo5MiRGjx4sNq3b28oLYAfKy8vb3QHzjvvvKOIiAiNHDnSUCoAuDDbtm1Tamqq/P39NWXKFNNxAAAAmkR6erpCQkIsteTkZN15552W2siRI7V48eLmjAYAAHBRzJkzR8nJySoqKpJ07u2FN23apAULFlhqMTExio6OttTi4uJUXl4uf39/+fj4yMfHR97e3k17AgAAoMWjcQpNoqGhQUlJSdqxY4d27typtLS0Rms6dOigoUOHasSIERoxYoT69u0rJycnA2kBnEtKSoruuOMOSVJ4eLjuuOMOXXPNNYZTAQAAAEDb9c0332jnzp06cuSIDh06JJvNpi1btjSa8H3NNdeoT58+6t+/vwYNGqSIiAimgAMAgBZl165d2rJliwoKCuyPp556Sr/4xS8s6+68804lJydbaj/eXu/bb7/VW2+9JT8/P/tj6NChCggIaPLzAAAAjo/GKTSLwsJC7d27V3v37tW+fftUWFjYaI23t7ciIyM1cuRIXX755XygBQxLSkrSq6++qoSEBHvttttu09y5cw2mAgAAAIDWz2az6fTp07rkkkss9YULF2rNmjWW2muvvabRo0c3ZzwAAIB/q7y8XP/7v/+rvLw8FRYWKi8vT+PHj9fjjz9uWbd8+XK9/vrrltrcuXN12223WWpLly7VyZMn7VOi/Pz8NH78+CY/DwAA0HbQOAUj0tPT7Y1U+/fvV2VlZaM1PXr0sG/rN3z4cHXu3NlAUgCHDx/WypUrtXXrVn300Ue69NJLTUcCAAAAgFalqqpKn332mZKSkpScnKzU1FRdeeWV+vOf/2xZ9/HHH+uZZ55RRESE/ZrJZZddZig1AABoa3bu3GmfEpWfn6/8/HwtXrxYAwYMsKyLjIy0vB4zZowWLVpkqe3Zs0dr166Vr6+v/TFw4ED16tWryc8DAADgX9E4BeNqa2uVmJioPXv2aN++fUpKSlJdXV2jdWFhYRoyZIiGDh2q4cOHq2vXrgbSAm3X6dOn1aVLl0b1l19+WdOnT1fPnj0NpAIAAAAAx1JSUqKGhgZ5e3tb6j/+gtHf31/r16+31EpLS+Xk5CRPT88mzwkAANqOoqIivfPOO8rPz1dhYaHy8/M1dOhQPffcc5Z177zzjpYsWWKpvfzyy40mQC1YsEAeHh7y9/eXr6+vQkNDNXDgwCY/DwAAgAtB4xRanIqKCn399dfat2+f9u7dq8zMzHOu69Gjh4YOHWp/MAUHaH4bN27UU089JensXUMTJ05UVFSU3NzcDCcD0NatWLFCu3fvVkhIiObPn286DgAAaMNOnTqlzz77TIcPH1ZycrJycnI0b948TZ8+3bJu9uzZKi0tVWBgoIKDgxUUFKSrr77aUGoAANBa/O1vf9ORI0fsU6JKSkq0ZcsWy5rCwkJdc801ltrAgQO1bNkyS2337t369NNP5evrKz8/P/n6+uqyyy6Tr69vk58HAABAU3ExHQD4MXd3d40bN07jxo2TdPYC44EDB3Tw4EEdPHhQaWlpamhoUHZ2trKzsxUbGytJ6tatm4YOHaohQ4Zo2LBh6t27t5ycnEyeCtDq5efn25/v2rVLu3btkqurqyZNmmQwFQBIGRkZOnDggKqrq01HAQAAbURKSoqSkpJ00003WeoFBQWNtqZJTExs9P433nijSfMBAADHVFBQoKKiIoWHh1vq2dnZeu+995Sfn6+ioiLl5ubq5ptv1qxZsyzrdu3apX379llqJSUl6ty5s/21j4+PxowZIx8fH/n7+8vHx0eBgYGNsowePVqjR4++iGcHAABgHo1TaPG6du2qqKgoRUVFSZLKy8uVkJCggwcPKiEhQUlJSaqpqVFRUZHi4uIUFxcnSfL09NTgwYPtE6kGDBggFxf+lwcuphkzZujaa6/V6tWr9fnnn6uysvKcTVOlpaXy8vIykBAAAAAAms6HH36ojRs36ptvvrHXhg8fbpmK3bdvX/n5+alPnz6KiIhQREQEW9UAAACdOXNGBQUF6tatW6MtfJ988knt379fhYWF9lp8fLxlTUVFhdasWWOp5eXlNfp9RowYoW7dutkbovz8/NShQ4dG637c6A0AANBW0EUCh+Ph4WG5q6G6ulpJSUk6ePCgDhw4oG+++UYVFRUqKyvT7t27tXv3bkmSq6urwsPDNXDgQPvD39/f5KkArYKvr68eeughPfTQQ8rNzW10fNu2bZo3b56uuuoq3XjjjRo1apSBlAAAAABw/mw2m44dO6asrCz17NlTgwYNshzPzMy0NE1J0rfffmtpnJKkzz77rMmzAgCAliMnJ0dVVVUKDg621P/xj39o5cqVKigosE/JjomJUXR0tGVdUVGRpWlKOrudno+Pj/21n5+frrzySsu2eT+eSiVJd91118U6LQAAgFaJxik4PFdXV/tUqZkzZ6q+vl7ffvutfWu/hIQEnTp1StXV1frmm28sFzR9fHw0aNAgeyNVv379znmnBYCfJiAgoFHtk08+kSRt2rRJmzZtkp+fn55//nkNGTKkueMBaEOCg4M1bNgwhYSEmI4CAAAc0K5du/Tss89avrCcMmVKo8apyy+/XBUVFQoKClJISIgCAwPPua0NAABwbGVlZSovL1dFRYXKy8sVGBjYaML+jBkzlJOTo+LiYknSwIEDtWzZMssam82m7OxsS62oqKjR7zd8+HD5+fnJz8/PPiXK09PTsqZz587685//fDFODwAAoE1zamhoaDAdAmhq6enpSkpKUlJSkhISEnT06NF/uzY8PFzh4eHq37+/+vfvf847NAD8dMePH9fatWsVGxurU6dOSZI2bNggX19fw8kAAAAAtEU2m03p6enKyMhQRkaGsrKy9D//8z+WNd98841mzpxpqU2aNEnPPfdcc0YFAABNrKSkRAUFBSosLFReXp68vLw0YcIEy5q33npLb7zxhqX26quvauzYsZbaddddp/z8fPvrgIAAxcbGWtbs2bNHa9eula+vr/0xcOBA9erV6yKfGQAAAH4qGqfQJtlsNiUmJioxMVGHDx/W4cOH7Q0dP+bq6qq+fftqwIAB9maqwMBAOTk5NXNqwPFt3bpVqampuu+++yz13Nxcvffee5o4caKGDRtmKB0AAACAtuDpp5/Whg0bLLV169apZ8+e9tdlZWV64YUX1L9/fw0YMEDh4eHq2LFjc0cFAAAXKCUlRTk5OaqoqFBZWZkqKioaNUWfPHlS119/vaU2fPhwLVmyxFJbs2aNFi5caKk98cQTmjp1qqX2ySefqF27dgoICJCPj48CAgL4/AAAAOAAaJwCvpeTk2NvokpMTFRKSopqa2vPudbDw0P9+vWzN1MNGDDgnFuUAfhpli9frtdff13S2S00x48fr9tvv507rQAAAACclw0bNigzM1MZGRnKzMxUaGioXnjhBcuaFStW6K9//askydvbW4MGDdIjjzzCFnsAADiA0tJS7d27V/n5+fYpUSNHjtQNN9xgWTdnzhzt2rXLUtu6datle72qqiqNHj3asiY0NFSrV6+21I4dO6b9+/fLz89Pvr6+9v8CAACgdXAxHQBoKbp3767u3btr0qRJkqSamhqlpaXpyJEj9kdGRobq6upUXl6u+Ph4xcfH29/v7e1t3+bvh0ePHj2YTAX8RJ6eniorK1NhYaHWrFmjyZMn0zgFAAAAoJGjR4/qyJEjGjdunDp37mw59vTTT1te22y2Ru8fO3asevTooYiICG6CAgCgBVmzZo0yMjJUXl6u8vJyVVZW2m+2/EFOTo7mz59vqXl6ejZqnOratav9uZeXl/z8/FRRUWFpnOrQoYPmzJkjHx8f+7Z5fn5+jXKFhoYqNDT0YpwiAAAAWiAmTgHnoaqqSqmpqZZmqqysLP27v0aenp7q06ePpZkqKChI7dq1a+bkgGPYs2ePNm3apNTUVK1atcpy7MyZM/rrX/+qqKgojRw50lBCAI4iMzNThYWF8vT0VHh4uOk4AADgZ4qNjdXHH3+s5ORkezPU0qVLFRkZaVl39913q6qqSsHBwQoODlZQUJCioqJMRAYAAN87ePCg1q9fr4KCAuXn56ugoEAPP/xwo2an2bNna//+/Zba5s2bLY3SBQUFuvbaa+2vAwICdN111+mBBx6wvC87O1v19fXcmAkAAID/iolTwHno0KGDBg0apEGDBtlrlZWVSk1NVUpKiv3xw2SqsrIyHThwQAcOHLCv79ixo3r37m1vpOrbt6/CwsLk4sJfR2DUqFEaNWrUOY9t2bJFa9eu1dq1a+Xl5aVx48Zp+vTpNEQAOKfly5crNjZWERERWr58uek4AADgP8jNzVVGRob9MXjwYEVHR1vWZGZm6uDBg5Zaenp6o8apZcuWNXleAADampKSEhUUFMjf398ysUmSZs6cqdLSUpWXl6uiokJ9+vTRm2++aVmTmZmpdevWWWqnT59u9Pt069ZN/v7+8vPzs0+B+jFfX1+tWrVKvr6+6tat27/N3KNHj/M5RQAAALRhdGoAP5Obm5uGDBmiIUOG2GvV1dVKS0tTSkqKkpOTlZKSomPHjqmmpkY2m02HDx/W4cOH7etdXFwUHBysvn37qnfv3urbt6/Cw8Pl6elp4pSAFqm+vl5du3bVqVOnVFpaqtjYWI0YMYLGKQAAAMBBnDx5Ul26dFHHjh3ttdzc3EZNUhUVFY1qkZGRKigoUFBQkEJDQ9WrVy8FBwc3S24AAFqbHxqhCgsLlZ+fLw8PD02cONGyZt26dVq2bJkKCgpUXV0tSXrttdc0evRoy7rjx49bmqCKiooa/X6BgYG64oor5O7uLg8PD7m7u5/zmt7zzz//k/JzPRAAAAAXE41TQBNwdXXVgAEDNGDAAHuttrZW6enp9kaqlJQUpaWlyWazqba2VmlpaUpLS7P8On5+furTp4/l0atXLzk5OTX3KQHGTZ06VVOnTlVCQoK2bNmiHTt2aNy4cY3WPffccxozZsw5jwEAAABoPkePHtW2bduUlJSkw4cPq7i4WO+8844GDx5sXxMQECA3NzdVVlZKOvvz9Ln8p+m0AADgrCNHjig3N1cVFRX2CVB33323Zc2pU6d09dVXW2qRkZGNGqeqqqqUnZ3d6L0/Nn78eNXV1cnPz0++vr7n3Bpv2LBhGjZs2IWeFgAAANCknBoaGhpMhwDaqvr6en333Xf69ttvLY/CwsJ/+54ftvr712aq3r17W+7YBdqq/fv3a/bs2ZLO/l0ZM2aMbr75Zl122WWGkwFobjExMWzVBwBAM8jIyFBmZqbq6+sbfeG6cuVK/eUvf7HUnn76ad14442WWmxsrLy9vRUUFKSePXs2eWYAABzNiRMntGbNGnszVHl5ua666ipNnjzZsu6+++5TfHy8pRYbG6uAgABL7cdb3YaGhmr16tWW2tGjR3Xw4EH5+vram6LOtXUeAAAA4OiYOAUY1K5dOwUFBSkoKMhyl8+ZM2d05MgRSzNVVlaW6urqzrnVn5OTk3r06KHevXtbHj169GA6FdqUyspK9ejRQ9nZ2bLZbIqLi1NYWBiNU0AbNH78eF1yySXy9/c3HQUAgFbppptuUlZWlv11UFBQo8ap0NBQ+fr6Kjg4WCEhIQoMDDzntIkfb8sHAEBrU1ZWpvz8fHXu3FndunWzHHv//feVnJysgoIC5efnq6SkRFu2bLGsKSkp0apVqyy1nj17Nmqc6tKli/25p6en/Pz8VFVV1SjPsmXL5ObmJnd3d7m7u8vb27vRmrCwMIWFhZ33uQIAAACOholTgIOoqanR0aNHlZqaqrS0NKWmpuro0aMqKyv7t+9xc3NTaGhoo4YqT0/PZkwONL+0tDRt3rxZmzdv1sKFCxUaGmo5fu+996pXr16aOHGiRo8ebSglAAAA0PKkpqZq//79yszM1HfffaeMjAy9+uqr6t+/v2XdDTfcoJycHPvrkJAQffjhh80dFwAAI6qqqizTn5ydnRs1GW3dulV/+ctfVFBQIJvNJkmaP3++pk2bZln3m9/8RgcOHLDUdu3aZdlhIDs7W7fffrt8fHwUEBAgHx8fjR49WldddZXlfcePH5eTkxMTHAEAAIDzwMQpwEG0b99e/fr1U79+/Sz1nJwcpaWlKS0tTUePHlVaWpqOHz+u+vp6VVZWKjExUYmJiZb3+Pv7q3fv3goLC7M3UwUGBsrZ2bk5TwloMj/8f33fffc1OlZYWKiDBw/q4MGD+uSTT+Tu7q6pU6dqzpw5BpICAAAAzS8jI0MZGRlydnbWuHHjLMc+/fRTffDBB5ZaZmZmo8aphx56SK6urvYpygAAtAZZWVnKyMiwNEVFR0fLx8fHvqayslJjx461vG/AgAFasWKFpVZVVaXjx49basXFxY1+z8suu0yenp5yd3e3/7eurs6ypkePHtq2bdt/zd+rV6//ugYAAACAFY1TgIPr3r27unfvbrnYXV1drWPHjtkbqn5oqvrhB/O8vDzl5eVp165d9ve0b99eQUFBCgsLU2hoqH0Uc0BAQLOfE9CUSkpKFBkZqfj4eElSRUXFOSe3FRYWWi6KAQAAAI7u5ptvVkZGhv314MGDGzVOhYSE2J+Hh4erZ8+e8vPza/Rr/et28wAAtHQ2m01ffvml8vPzVVhYqPz8fAUHB+vuu++2rPv444+1cuVKS23g/2fv3uObqu//gb/Spm2apPckvbdJy02BgrTc7wjqFLziVLygzAsiilO2oc7BvME23NiGtymKTh0iIk4R5YugyKW6cpGLFNsm6Y22SS8pTdL0mt8f/eXYDyfcSy/09Xw8eDR553NOPmcjtTSvvN+DBwu/IwoNDUVwcDAaGxulWlVVlew5k5KSMGXKFOj1eunP4MGDZeseeOCB8708IiIiIiI6DxzVR9SLVFZWCmGqvLw8WK1WNDc3n/QYjUaDtLQ0IUzVt29fREREdOLOiTqex+PBvn37kJ2djQkTJiAzM1N4fNGiRfjuu+8wefJkjvQjIiIiom7ParXCYrGgsLAQZrMZN954I4YOHSqsue6661BaWirdj4yMxJYtW4Q1DocDLpcLiYmJnbJvIiKiM1FfX4+KigpoNBro9XrhsQ0bNmDv3r2w2+2w2+2w2Wz473//i8jISGlNVVUVrrzySuG40aNH45///KdQe/vtt6VaaGgoDAYDnnrqKQwbNkxYt3btWmi1WhgMBml8XvvRekRERERE1HMwOEXUyzU3N6OwsBD5+fkoKCiQvrb/Zbo/0dHRSE9PFwJV6enpCA0N7aSdE11YkyZNEjpRaTQabN68GSEhIV24KyI6U2+//TZ27tyJtLQ0LFq0qKu3Q0RE1CHq6+tRXl4Ok8kk1D/99FP88Y9/FGoLFizAnXfeKdRefvlluN1umEwmpKWlwWg0Iioq6oLvm4iI6EQNDQ2oqKiQgk7Hjx/HLbfcIqzZs2cPXnjhBdhsNtTX1wNoGxV79913C+t++9vfYuvWrULto48+QmpqqlDLyspCeHi4NBIvIyMDTz75pLCmsrISTqcTsbGx/D0nEREREVEvwVF9RL2cUqmUAlDteTweWZgqPz8f1dXVAIDq6mpUV1fjf//7n3BcfHw80tPTkZaWhrS0NPTp0wcmk4lhE+pxHnjgAXz33XfIycmBx+NB3759ZX+Pi4qKcOzYMYwaNaqLdklEJ2OxWLB3715hdAIREVFP9Nprr+HAgQOwWCyw2WzQarX4+uuvhTXtx+sZjUYYjUYkJSXJzjVv3rwLvl8iIurdqqqqkJOTA7vdjsrKSlRUVODKK6/EpEmThHW/+tWvkJubK9RODE55vV4UFhYKNYfDIXvOjIwMNDU1QaPRQK1WQ6PR+A095eTknHb/Op1OGMtHREREREQXPwaniMgvlUqFQYMGYdCgQUK9trYWeXl5yM/PlwJVBQUFcLvdAICysjKUlZVhx44d0jEKhQKJiYlCmMr36ebg4OBOvS6iM3XbbbfhtttuAwDs27cPLS0tsjUbN27EqlWroNVqMWnSJOkPEREREdGZKCwshNVqlcbsTZ06FePGjRPW7NmzB3v37pXuO51OVFZWCm/qDhw4EB9++KGsExUREVFH+ve//42ysjK4XC64XC4olUosW7ZMWHPkyBE89dRTQi09PV32+xJ/HQ/dbjfUarV032g0Yv78+UIgymg0yo674447cMcdd5zPpRERERERUS/G4BQRnZWIiAhkZWUhKytLqJeXlyM/Px9msxlmsxn5+fmwWq3weDzwer0oKSlBSUkJtm/fLh0TEBCApKQkIUzlC1Qplfz2RN3HZZdd5rd+5MgRAG1vXn322Wf47LPPsHz5coaniIiIiEhysvF6W7ZskY2TjY6OlgWnJk+eLP07yWQyITU11W8nDIamiIjIn4aGBrhcLrjdbrhcLgQGBqJPnz7Cmi1btuCtt94S1j399NO46qqrhHUbN25Efn7+KZ8vIiJCuJ+QkACNRiNb99hjj6GhoQFarRZqtRpqtRoqlUpYo9PpZGP5iIiIiIiIOhqTCUTUIeLi4hAXFyf8kt/r9aK0tBQFBQUwm81Sdyqr1Yqmpia0traiqKgIRUVFwqiJwMBAJCcnS0EqBqqou/rHP/6B3NxcbN26Fdu2bYPFYvE7tu+5557D+PHjMXHixC7YJRERERF1tpdeegmHDx+G1Wo96Xi99kGn5ORkmEwmYeSej68LKhERUXv5+fkoKSkRwk433ngjwsPDhXVjx44V7g8aNAirV68WavX19Th69KhQq6mpkT2nTqeD0+lEbGws9Hq93yBveno63n//fRgMBkRGRp50/wz8EhERERFRd6Hwer3ert4EEfUuLS0tKC4uFsJUBQUFKC4uRnNz80mP8wWqTCYT0tPTpa+pqakICgrqxCsg8s9ms8FgMAi1vXv34v777wfQNgJz3LhxuOGGGzBy5Miu2CLRRSMrKwterxcKhUL4CkBW8/e1vZycnK64BCIi6qEsFgusVisKCwthsVhw7bXXIjMzU1hz991349ChQ0Jt06ZN0Ov1Qs1sNvsNSxERUe9lsVjwySefwO12w+12w+l04vLLL8eMGTOEdb///e/xxRdfCLV3330XAwYMEGrjxo2Dx+OR7icmJuKTTz4R1uzfvx//+c9/oNfrodfrYTAYMHjwYCQlJXXw1REREREREXU/bN1CRJ0uMDAQRqMRRqMRU6ZMkerNzc2wWq3CuD+z2YySkhK0traipaUFVqsVVqsV27Ztk44LCAg4aaAqODi4Ky6ReqkTQ1MA4PF4kJSUhJKSEng8HmzZsgUJCQkMThF1IF8Qqn0g6sSavzX+QlRERERA2yjmqqoqpKamCvV169Zh2bJlQs1oNMqCU1OmTMGAAQOk8XpGo1EWmgLA0BQR0UXE6XQK3Z9SUlJk3Z/mz58Pu90Ol8sFl8uFqKgorF+/Xlhjs9nw7rvvCrW4uDhZcCoqKkq6rdVqodfr0draKtvXggULoNFoYDAYoNfrERsbK1szdOhQDB069KyvmYiIiIiI6GLA4BQRdRtKpRJ9+vRBnz59hHpjYyMKCwthNpthsVikYFVxcTFaWlrQ2tqKwsJCFBYWCuMvAgICkJSU5HfkHwNV1FnGjBmDDRs2wGKx4KuvvsLWrVsxfvx42bp58+ZBpVJh9OjRGDVqFJKTk7tgt0Q9R2pqKgoLC885/OTrTqXVajt6a0RE1EMtXbpU+qBGVVUVjEYj1q1bJ6xpP1bI92EQfz+33XXXXRd8v0RE1Dl2794tBZ1cLhdiYmJw5ZVXCmtef/11vPbaa0Ltr3/9KyZMmCDUCgoKYLfbpfstLS2y54uIiEBYWJjU+Umn02HYsGGydbNmzcLMmTMRGxsLlUp10v3ffPPNZ3SdREREREREvRVH9RFRj9Xc3IyioiIhUGWxWFBYWIimpqaTHqdQKJCQkACTyYS0tDSYTCbptlqt7sQrIGpTXV2NK664QqhlZmbKfulKRD/78ssv8dRTT51XcEqhUOD222/Hr3/96wuwQyIi6k5yc3NRUFAAi8WCvLw8LFiwQNbt6eqrr4bNZhNqJ45z9Xg8KC8vh9FovOB7JiKiCysvLw9Hjx6F3W6HzWaD3W7HwoULERcXJ61pamrC6NGjheOGDBmCVatWCbW1a9fiz3/+s1BbvHixrEvUsmXL0NjYKAWiDAaDLFxFREREREREnYsdp4iox1IqlVIXqfZaW1tRUlIiC1RZrVZ4PB54vU93u9UAACAASURBVF6UlpaitLQUO3bsEI41GAxSmKr91xNbqxN1pICAAMyZMwdbt26F1WoFANlYGACoqKjw21KfqDeaNm0aXnvtNRQVFZ1zeCooKAh33nnnBdgdERF1hePHj6O2tlbWAerll1/Gm2++KdSuuOIKv8Epj8cjdZLyF45SqVQMTRERdRPl5eWorKzEoEGDhLrNZsPq1aulMJTdbseUKVOwcOFCYd3atWvx8ccfC7XZs2cLwamgoCCoVCp4PB6pVltbK9vLZZddhkceeQRqtRparRZqtRoDBgyQrVu0aNE5XSsRERERERFdOAxOEdFFJyAgACkpKUhJScGkSZOEx0pKSmRj/ywWC1wuF4C2X67ZbDZkZ2cLx0VFRcm6U5lMJuh0uk67Lrp4RUZGYt68eZg3bx7y8vLw9ddfY8iQIbJ1Tz31FHJzc5GVlYWRI0di5MiRsjf8iHqLgIAA3HvvvfjDH/5w1sf6glbXXXcdv48TEfVgHo8Hy5cvl8brORwODB06FG+88YawzvfzkkqlQt++fZGWlia8Ke4zf/78Ttk3ERH5V1lZKQWdbDYbBg0aJAsfLVmyBNnZ2aisrJRqJ3YHdLvdWLt2rezcJ4qJiYFarYZarYZGo4FGo/H7gYxXX30VISEh0Gg0UKvViIyMlK3p27cv+vbte1bXS0RERERERN0DR/UREQGw2+1SiKp9oMrhcJzyuLCwML+BKn9vxBCdD4fDgalTpwq1iIgIbNmy5Zw67RBdDFpaWnDTTTehpKTkjLtO+dYFBgbik08+4fdrIqJuLC8vD1arVfrgw9y5c5GSkiKsmTBhAtxut3Rfq9Xi66+/FtbU1dWhrq4OCQkJnbJvIiISbd++Xej+FBISgt/97nfCmnXr1mHZsmVCbcGCBbIOsfPnz5d92O2LL74QPhBRV1eHJ554QgpD+bo/TZ8+vYOvjIiIiIiIiC4G7DhFRARAr9dDr9dj5MiRQr2mpsZvoMr3ScW6ujr88MMP+OGHH4TjQkNDpSCV0WiURgomJCQgICCg066LLh6RkZF499138d1332H37t3IycnBpEmTZEGR/Px8VFRUIDMzEyqVqot2S9Q5AgMDMWfOHDzzzDNnfex1113H0BQRUTdQV1cHh8MhG6/30ksv4a233hJqU6ZMkQWnrr32WgQEBMBoNMJkMvkdoxcWFoawsLCO3zwRUS9RXFwMhUKBpKQkof7f//4XH330EZxOJ1wuF5xOJ1566SVZB+VFixahsbFRuh8XFycLTvkLt/obiXfDDTdg9OjR0Gg00Gq1CA8Ph1arFdaEhYVh5cqVZ32dRERERERE1DsxOEVEdApRUVHIzMxEZmamUHc6nSgoKBDCVBaLBeXl5QCA+vp6/Pjjj/jxxx+F44KDg5GamirrUpWcnAylkt+S6dQGDBiAAQMGYPbs2fB4PHA6nbI169evl0YSZGVlYdSoUbjhhhsQERHR2dsl6hRXX301/vWvf6G8vPyMu06p1Wo8+OCDnbA7IiLy54UXXoDVaoXFYkFNTQ0yMjLw5ptvCmvajyPu27cvUlNT/Y5GWrhw4QXfLxHRxaakpEToAHXHHXfIHn/88cdht9tx/PhxAG0/d5/4gYWioiIcPnxYqPkLOyUkJKCqqkrq/hQbGytbk5GRgdWrV0uj87RarSwQBQCXX375WV8vERERERER0anwXXoionOg1WoxZMgQ2aco6+vrpSBV+0BVaWkpvF4vGhsbkZeXh7y8POE4pVKJ5ORkYdyf7xPzwcHBnXlp1EOoVCq/HaXa/93KyclBTk4Obrzxxs7cGlGnUiqVmDNnDl544YXTrvUFq2bNmoWoqKhO2B0RUe+Tn58Pq9Uq/Zk9ezb69u0rrNm+fbvUwRUAzGaz7Dzjxo3Dhg0bZN1NiIjIP5vNhn379klhKJvNhl/84heYMGGCsO7uu+/GoUOHhNr1118vhJSUSiUKCgqENTU1NbLn7N+/P0aNGiWFnDQaDeLj42Xr1q1bd9r9a7VaDBo06LTriIiIiIiIiDoag1NERB0oNDQUAwcOxMCBA4V6Q0OD9Kn69oGq4uJitLS0oLm5Wapt3bpVOk6hUCAxMVHWocpkMiE0NLSzL496gNdffx1WqxXZ2dnIzs5Gc3MzwsPDhTV79+7Fiy++iMmTJ2PKlClCRweinmjGjBl44403YLPZTrtWrVbj9ttv74RdERFdvGpra1FXVycLNa1cuRKrV68WaiNGjJAFp66++mo0NjZKP9umpqbKnoPj9Yiot3E4HLDb7YiPj5d1WlqxYgUqKiqkUFRkZCTefvttYc2ePXvw9NNPC7X+/fvLglP+PkBQW1srPGdcXBweeughqNVqaDSakwaipk2bhmnTpp31tRIRERERERF1Jwqv1+vt6k0QEfVWzc3NKCwslAJVZrMZVqsVhYWFaGpqOuWxcXFxsjBVenq631b2RO298sorWLVqlXQ/KSkJCxcuxLhx47pwV0Tn58MPP8Sf/vSnk47r89XnzJmDefPmdcEOiYh6LpfLhb/97W/SBwFqa2sxcuRIvPTSS8K6zz77DEuWLAEA9OnTB6mpqbjhhhswatSortg2EVGXOn78OGw2GyorK2Gz2RAREYGJEycKa9asWYP//Oc/sNvtaGxsBAC8+uqryMrKEtZdfvnlwgg8nU6HL774QliTnZ2Nxx9/XBqHp9FocOONN+Kmm24S1lmtVng8HmGdv27GRERERERERL0FO04REXUhpVKJ9PR0pKenC/WWlhaUlJTIAlW+X3ACQHl5OcrLy7F7927h2JiYGNnIv7S0NERHR3fadVH3FhkZCaPRCKvVCgAoKSnxOxLSbrdDr9d39vaIzsl1112HVatWCaOffHyhqZCQEMyaNasLdkdE1L3l5eXBYrFIwaj58+cjMTFRelyj0WDDhg3CMSeOcAKACRMmcLweEV30cnNzkZeXB5vNJnWAevrppxEZGSmtsdlsuPrqq4Xjxo4dKwtOuVwulJaWCjWHwyF7zvHjx8PpdErdn/z9+37UqFHYuXPnafdvNBpPu4aIiIiIiIioN2HHKSKiHsTr9eLYsWOyQJXZbIbb7T7lsREREbIOVSaTCbGxsZ20e+pu7HY7srOz8d133+G5554THqupqcG0adPQv39/TJ48GdOmTfM7RoeoO1m3bh2WLVsm6zrluz979mw8/PDDXbhDIqKu43Q6UV1djZSUFKH+z3/+Uzbu6a9//atstNPSpUuhUqlgNBqlnyMjIiIu+L6JiDqa3W5HVVUVBgwYINQrKyvx5ptvSoEom82GadOm4bHHHhPWPf3009i0aZNQW7t2rTACvbm5WdZtb9CgQbJxpocPH8bevXuFkXiXXHIJdDpdR1wqEREREREREZ0BdpwiIupBFAoFEhMTkZiYKBurVlFRIQSqLBYLLBYLjh8/DgCora3F/v37sX//fuE4jUYDk8kEo9GItLQ0pKWlwWg0IjEx0e+4K7p46PV6zJgxAzNmzJA99u233wIAjh49iqNHj+LVV1/FnXfeiQULFnT2NonO2A033IA1a9bAarVKYSnfZwRCQkJw5513dvEOiYg61x/+8AfYbDZYLBZUVVXhkksuwb///W9hTfs3+vv164fU1FS/gagnnnjigu+XiOhc2Gw2YSTeqFGjZCHR3/zmNzh48KDQnTQnJ0dYU19fj7Vr1wq16upq2fPFxMRArVZDrVZDq9VCrVajtbVVWKNUKvHmm29K6zQajd/vrQMHDsTAgQPP+pqJiIiIiIiIqOMwOEVEdJGIjY1FbGys7FOtVVVVfgNVvl8Au1wuHDp0CIcOHRKOCwkJEToK+LpUJScnIzAwsNOui7rGFVdcgdDQUGzduhXbt29HQ0MD+vfvL1u3a9cuhIeHY9CgQV2wSyJRYGAg5s6di0WLFknBT9/XmTNnCuNTiIh6up9++glWqxWFhYWwWCy4//77ZeOXDhw4gJKSEum+xWKRnWf8+PEcr0dE3Y7H48Hu3buFcXipqamYM2eOsO7VV1/FG2+8IdSee+45WXCqoqJCNtK5trZWCDNFRUVh1KhRUucntVqNSy+9VLa3Rx99FI8++uhpryEjI+O0a4iIiIiIiIio6zE4RUR0kYuJiUFMTAyysrKE+vHjx6UwVftAlc1mAwA0NDRI3YbaUyqVSElJEcb9paWlITU1FUFBQZ12XXRhqVQqTJs2DdOmTUNDQwN2796NzMxM2bqlS5eirKwMYWFhGDFiBCZMmIBrrrmmC3ZM1Obyyy+H0WiUuk4B7DZFRD1XTU0N6uvrkZCQINSXL1+ONWvWCLWJEyfKglNTp06Fx+ORwvAnPg4A4eHhCA8P7/jNE1Gv5vF4UF5eDrVaDYPBIDz28ccfY//+/cJIvM8//xxarVZa43A48Jvf/EY4buTIkbLgVFRUlOy5HQ6HrDZr1ixUVVUJoagTO0BptVqsXLnyrK+ViIiIiIiIiHo2BqeIiHqp8PBwDB06FEOHDhXqLpdL1qHKbDajrKwMANDc3Cw91l5AQAASExOlQFX7YJVKpeq066KOFxISgkmTJsnqFRUVUueyuro6fPXVV7Db7QxOUZdSKBS477778NRTT0ndpm688UbodLou3hkR0enV1dVhxYoVsFqt0sjliRMn4sUXXxTWmUwm6faAAQOQlJSEmJgY2fnmz59/wfdMRL2Dx+MRuj85nU7MnDlTWLN//34899xzsNvtcLlcAIC5c+fi3nvvFdbt2LED33zzjVBzOBxCcCouLg4AEBERIQWdTgyRAm2h+UGDBklrfMGoE1111VXnduFEREREREREdNFTeH0fxSciIjoFj8cDq9UqC1SVlpaitbX1lMfGx8cLYSrf1/a/GKeeqaGhATt37sSWLVuwfft2zJ49G/fdd5+w5vPPP0dhYSFGjBjht2sVXTiNnlZUlXtQZWtAdUXbH7ezBY2eFjQ2tKKxwYumhlO/fqn7CgpWICgkAMEhAQhRBUKlDkR0XAii9cGIjg1BTGwIQrX8nARRd1FYWIiDBw9K3VVsNhsee+wxJCYmCutO7BKalJSEDRs2CDWHwwGXyyU7lojobFVWVmLv3r1C96drrrkG48aNE9bNnDkTVqtVuq9SqbBjxw5hzb59+2T/Frj11luxcOFCofbvf/8b+/btg1qthlarhVqtxqxZsxh0JyIiIiIiIqIuweAUERGdl8bGRhQVFckCVcXFxWhubj7lsTqdTjbyz2Qy+R23QD2Dw+FAZGSkULv33nuxf/9+AG3dqzIzM/Hkk09KnyKnjuFtBWyl9SgvqscxqxvHrG4crz71a5AufpqwQMQbQ5Fg1CA+NRSxyaEIVCq6eltEFy2r1YqSkhLU1tbKOjC+8847+Mc//iHUXnzxRUycOFGoPffcc9BqtTAajTAajUhLS+MoPSI6qbq6OtjtdkRGRiI6Olp47P3338ePP/4oBaKam5vx6aefCmu2bt2K3/72t0JtwYIFsjHH9913H/bt2yfUdu/eLYxrr6qqwqeffip0f/J9LyMiIiIiIiIi6q74EXQiIjovwcHB6NOnD/r06SPUm5ubUVJSIgtUFRYWorGxEUDbp5srKyvx/fffC8dGRkbKxv2lpaVBr9d32nXRuTkxNOWrBQcHo7GxEQ0NDdi1a5ffdXRuCn9yIndvLfIO1J2ye1SwKgBqrRKhWiWU/79LkTIoAMEqJRTM0fQ4Xi/Q1NiCpoZWNDa0ormxFY2eZjgdzWiob5HWuepakH/QifyDTqnWd0gYBlwWCdMALQKD+H8+0flqaGjAbbfdhqKiIqmm0+lkwamUlBTpdt++fZGamur3v4e///3vL9xmiajbczqdUle6yspKBAcH44orrhDWbN68Ga+88grsdjs8Hg+Atu8d119/vbBu69at0gcYTiYqKgohISHCmLuwsDDZuieeeAJNTU1CKKp9aAoAYmJicPfdd5/LZRMRERERERERdRkGp4iI6IJQKpXSp4unTJki1VtbW3Hs2DFZoMpqtaK+vh5AW9eiffv2yT7R7Ou+kJaWhrS0NOl2fHw8FEx+dFvLly+Hx+PBzp07sW3bNng8HqhUKmHNhx9+iE8++QQjRozAiBEjMHToUNka+lltVRP2fF2Jo/tq4amXh6U0EUok9w1DYroW2shgRMQEd8EuqSvV1TTCdbwJx8wulOTVwVHZKD2W90Md8n6ogzJYgb6DwzBsgg6GJL7eiPypr6/H4cOHcfjwYRw8eBBHjhzBK6+8IoSgQkJCcPz4ceG4yspKOJ1OYSxxVlYWPv74YyQnJ3fa/omo+8jPz0dubq7U/clut+Pxxx9HfHy8tKa5uRmTJk0Sjhs4cKAsONXQ0IDi4mKh5nA4ZM+ZlZWFiIgIKezkb1T6ZZddhp07d552/2lpaaddQ0RERERERETUE3FUHxERdRvl5eWyQJXFYoHT6TzlcSqVCkajUdalKikpCYGBgZ20ezof8+fPR3Z2tlBbunQppk2b1ml7yMrKAgDcf//9uP/++zvtec9GVXkDvttiw9F9dbLHYlPUSOmvRUJaGINSJFNf14SivDqU5DlRZnWjtUX8J4DxEg1GTdUj3qjuoh0SdZ28vDxYrVaEhYVh1KhRwmNLlizBZ599JtRWrFiBcePGCbXly5dDqVQiKSlJCo7rdLoLvnci6jyVlZWw2+245JJLhHpdXR1ee+01qUuU3W7H8OHDsWTJEmHdn/70J3z44YdC7c0330RGRoZQGzdunNRFCgCSkpKwYcMGYY3VasU333wjdYhSq9Xo06cPEhMTO+JSiYiIiIiIiIh6FXacIiKibiMuLg5xcXEYM2aMULfb7UKQyvfV96lqj8eD3Nxc5ObmCscFBQUhNTVV6FJlMpmQmpoKpZL/CexOrrvuOuj1euzevRuVlZUAgEsvvVS2btOmTRg/frzfT8ufL1+W/F//+hfsdjueeOIJBAQEdPjznIsaeyO+3ViOgoNiiDClfxiS+2mR0i8MQSEMCdLJhYYFof+waPQfFo2W5lYcs7hQfLQOliPH0dLkhfWIC9YjLiSYQjFheiwDVHTRczqduOOOO1BSUiLVxo8fLwtOGY1GAG0hbd/PFP7G6y1cuPDCbpiIOpwvCOXrADVw4EBZKOrZZ59FdnY2KioqpNq2bduEUXatra1Ys2aNcFx1dbXs+WJiYhAaGiqEnfz9rPnaa68hODhYGofn73uOL6BJRERERERERETnjx2niIiox6qpqfEbqPIFb04mMDAQSUlJUmcqX6DKaDRyPFw3YLVaceDAAVx77bVCfc+ePXjggQcAAKNHj8bkyZMxadIkREdHn/dzZmVlof2PRAqFAmPGjMFf/vIXhISEnPf5z1VLkxe7/8+GPV9XobWlrRYQAKRnRGDoeD1Cw4K6bG90cWiob8Hh7CocyalGS9PPr4FBIyMx/ppYqDQM5FHPU1xcjOzsbFitVlitVpjNZjz11FOyLlEndnVJTU3FRx99JKyprq5GY2Mj4uLiOmXvRHT+srOzUVpaKoWiAgMD8eSTTwprPvvsM1lHqEceeQR33XWXUFuwYIFsjJ2/kZvz58+Xgk4ajQZ9+vTB9ddf34FXRUREREREREREFwqDU0REdNFxOp1+R/6Vl5ef9tiEhARh3J/vtkaj6YSd06msXLkSq1evFmrXXXcdnn766fM+d2ZmJoC2wJTX64VCoQAAjBo1CitWrOiSDmX5h+qwbX0ZnLXNUi09IxxDxhmgjWRgijpWY30z9u+oRO7/aqRaSGgAxl1jQMbo8w8nEnW03NxclJSUQKVSyQJR69evxwsvvCDUFi5ciFtvvVWoLVu2TBr3azQakZ6eLnSRIaKuUVpaiubmZqSmpgr1ffv2YePGjUKXqEWLFmHq1KnCuquvvho2m026HxMTgy+//FJYs3PnTixYsECozZ49Gw8//LBQ27ZtG0pLS6HVaqFWq6FWqzFs2DCo1ezMSERERERERER0seCcIiIiuuhotVpkZGQgIyNDqNfX10shqvaBqtLSUqnb0LFjx3Ds2DHs2LFDONZgMMjCVOnp6QgPD++06+rt5syZg4yMDHz//ffIyclBfn4+Jk6cKFu3cuVKjBkzBsOGDTur8/vCUr7wFNDWsWDRokV44YUXEBwcfP4XcQaaG1uxeW0pju6rk2ox8SEYdVUcYuL5Jh1dGMGhSoyYFodLh0dj96YylFncaKhvxVfrypG7txYzZicjVMt/OlDXKi0txYMPPohjx45JtREjRsiCU+07wfhG9CYmJsrOt2jRogu3WSKStO/+ZLPZcNNNNwldXmtqavDggw+isrJSGsU9cuRIvPTSS8J5zGYzNmzYINR869vT6XRwu91S2Mlfd9IhQ4Zg9erV0sg8jUbjdxT05MmTz+maiYiIiIiIiIio52DHKSIi6vUaGxulMFX7QFVxcTFaWlpOeWxUVJTfDlU6na6Tdt97VVdXQ6PRCKP0zGYzfvnLXwJoC9CNGTMGN9xwA4YPH37S8/jG9PmCUz7ta0OHDsWKFSv8vqHWkWrsDfhkVRFq7E0AgGBVADIvN6BvRhSgOM3BRB2oJL8O331RDtfxto5nam0gZtydhAQTu+/RhfHjjz9i3759sFgssFqtsFgs+OijjxAZGSmtcbvdmDBhgnBcbGwsNm7cKNTcbjfsdrusWw0RdRyn04ns7GwpDGW32zFixAjZqOXHHnsM27dvF2r//e9/kZCQIN1vbm7GqFGjhDX9+/fHe++9J9T27NmDd955Rwg7TZ48GUOHDu3gqyMiIiIiIiIiot6EHxsnIqJeLzg4GP3790f//v2FenNzMwoLC2WBqsLCQjQ1tQVbampqsGfPHuzZs0c4VqvVygJVaWlpiIuL67Trutj56x5QVVWFyMhIOBwOOJ1ObN68GXFxcacMTp1M+85T+/fvx+zZs/Hyyy8jNjb2vPfuz08HjuPL/5SiubHtOWNT1Jh0YyJC1PxxjTpfUp8wxD2gxq6NZbD+WAe3swVrXy7E+GtikTkppqu3Rz1UYWEhrFYrmpqaZKO1Nm7ciA8++EColZSUCMEptVqNK6+8EnFxcUhOTobRaESfPn1kz6NWqxmaIjqNuro62O12REVFISoqSnhszZo1OHz4MOx2OyorK2Gz2fD5558LAfJjx47JurZpNBpZcOrEcwNAbW2tEJxSKpWYP38+VCqVFIoyGAyy4zIzM6XxykRERERERERERB2F78QRERGdhFKpRHp6OtLT04V6S0sLSkpKZIEqq9UKj8cDoO1T+AcOHMCBAweEY0NDQ2E0GmWhqsTERAQEBHTatV2shg8fji1btuDAgQPYsWMHvv32W1l3EgB46KGHEBQUhJEjR/rtNuXjC095vV4UFhbirrvuwssvvyz7O3G+9nxdie2f2v7/cwJDJuiQMUbPLlPUpZRBgZhwfRIS02uQvakCLc1ebP+0AvZj9bjytsSTvm6ITjR//nxkZ2dL9/v06SMLTqWkpAAAVCoVjEYjjEajMMrL5/nnn7+wmyXqoZxOp9D9KSgoCFdeeaWw5ssvv8Srr74Ku90u/cy6ePFizJgxQ1i3detW7N27V6jV1tYKwSlfgD0yMlIKO/nruHrPPffg5ptvhlqthlqthlar9fvavvvuu8/twomIiIiIiIiIiM4TR/URERF1EK/Xi2PHjskCVRaLBS6X65THBgcHIyUlRepM5QtXpaSkQKlkzrkj1dTUYNq0aWd1jO/HJYVCgbCwMLz++ut+u5yci/ahqRB1ICbflAhDMsehUffiqGzA1+uKcby6rdveJZnhDE8RSktLsXv3blitVmm83uOPP44pU6YI6x544AFZZ8acnBzhvsPhQH19PeLj4y/4vol6kpKSEhw8eFAKRNlsNtx3333o27evtMbr9cq6aw4YMADvvvuuUNuwYQOee+45ofbII4/grrvuEmqvvfYafvrpJ2kcnlqtxqxZsziKmoiIiIiIiIiILkp8J5aIiKiDKBQKJCYmIjExEePGjRMeq6iokAWqzGYzjh8/DgBobGxEfn4+8vPzheMCAwORnJwsdabydakymUwIDg7utGu7mCgUCvzqV7/Ctm3bYDabz/gYoO2Nybq6Ojz44IN47bXXkJaWdl572bmpAt9vqQIAhEUF4ao7UxGqDTqvcxJdCJG6EEyfY8JXa0tQUeTGkT3H0dLixS9uT0JAAMNTF7Pi4mIUFRXBbrfj+uuvFx47cOAAli1bJlt/ovHjx6NPnz5ITU2VwsEnioyMFMbyEV0sfKPuLr30UqFeXV2NVatWSWGoyspKDB48GEuXLhXWbdu2DX//+9+F2vTp04XglC/YXVdXJ9UcDodsLykpKZg6dSp0Oh0MBgP0ej0GDx4sW/fAAw+c07USERERERERERH1ROw4RURE1IWqqqpk3anMZjOqq6tPeZwvpNV+3J/vtlqt7qTd93yZmZkAcFZdc3yj/bRaLVasWIGhQ4ee03N/t8WOXZvsAAB9ogpTb01BUEjgOZ2LqDN983EJCo+0vTk/YFg4fnF7UhfviC6Eu+++G4cOHZLuh4aG4ttvvxXWHDp0SBqv5RuvN336dEyaNKlT90rUmdxuN9xuN5xOJ9xutxRCau/ZZ5/F7t27YbPZpNrOnTsREhIi3S8rK5ONyLvsssvw+uuvC7XPPvsMS5YsAdD2OjQYDFi4cCFGjx4trFu3bh3UajUMBgN0Oh3i4uL8jsQjIiIiIiIiIiIiEYNTRERE3dDx48dhNptlgar2b8CdTGxsrCxMlZ6ejrCwsE7Yec+SmZl5zqPGvF4vgoODsXTp0rMOCRzMrsGWD8sAAMn9tJg8M/mc9kDUVb7fXI7cnBoAwLAJ0Zh4XVwX74jOVFlZGXbt2gWLxYLCwkJYLBbMnTsX06dPF9bdfvvtOHr0qFD7/PPPhYCIx+NBeXm53w5SRD1NTk4OSkpKhA5Qf/vb34Q1xEc8HQAAIABJREFUu3btwiOPPCLU5s2bhzlz5gi1+fPnIzs7W6ht3LgRsbGx0n2Xy4Vf/OIX0Ov10p9LL70Ut912m3BcTU0NampqYDAYoNVqO+JSiYiIiIiIiIiIqB2O6iMiIuqGwsPDMXToUFk3o9raWuTl5cFiscBqtSIvLw9ms1kYx1JRUYGKigrZG3aRkZFIS0vDZZddBqPRCJPJBKPR2Gu7EWRlZZ33OZqamrBw4UIsWrQIM2fOPKNjDn33c2gqNkWNiTeyWw/1PCOuiENzYwvyDxzH3u3V8AKYxPBUt1FSUgKLxYK6ujpcffXVwmOHDh2SjQLzN15v8uTJGDZsGJKSkpCWloaUlBRZVx2VSsXQFHV72dnZ2LVrF9xuN1wuF9xuN+677z4MGjRIWPfnP/9ZNsLX6XQKYaWIiAjZ+f11Cc3MzERMTIwUiDIYDLJjNRoNtm/fftr9R0VFISoq6rTriIiIiIiIiIiI6NwwOEVERNSDREREICsrSxb6qa2tRX5+PsxmMwoKCmCxWFBQUCAEqhwOB/bu3Yu9e/cKx8bFxUmdqXxhKpPJhMjIyE65pq7SEU03fWP7li1bdkbBKUtuHf7v/4emovTBuPyWJAQEnFvHK6KuNvqaBHjcLSjJd2Hf9mpExwYjY1R0V2+rV/vtb3+LrVu3Svejo6NlwamUlBTpdmpqKoxGI9LS0mTnuvfeey/cRonOgNPphMvlksJOaWlpwjhip9OJ+fPnC2uysrKwfPly4TyHDh3C+++/L9SuvPJKWXCqfTgpMjISOp0ODQ0NQnAqMTERjz/+uBSGMhgMiIuTh0bvueee87p2IiIiIiIiIiIi6jwMThEREV0EIiIikJmZiczMTKHucDiQn58vBanMZjO8Xi/MZjNqa2sBAOXl5SgvL8fu3btl52zfmcp3OzExsdOu60I60xF9/gJWvmPPZsyfrcSDT98qAbxAWFQQrrg9FcqgwDM+nqi7USgUmHhTEja/Vwh7iQdfrStHqEaJvoPDu3prF53y8nLs3LlT6jZotVqxYMECTJs2TVjX1NQk3K+urpZ1zOnfvz8+/PBDmEymTtk7UXu1tbU4ePAg3G433G43nE4n0tLSMGbMGGHdypUrsXr1aqH2xhtvCJ04NRoNDh06JKzx1/0pMjIS0dHRwki85GT5iNwnnngCQUFBp/w5JzIyUjZKj4iIiIiIiIiIiHo2BqeIiIguYpGRkX47VAFAVVWV1KHKbDZLt+vq6gC0vbn5ww8/4IcffhCOU6lUUpeS9qGq1NRUBAUFdcp1na9TjenzdZHyBaZODEcpFAooFApceumlSE1NRXJy8mk7szR6WvHx64VoafZCGaTAtNtSEKLmj2HU8wUGBuDyXybj0zcscB1vxqZ3S6H/jQqRuuCu3lqPU1xcDKvVitraWkyfPl147MiRI7LxekVFRbJzjB07FgaDAUajEenp6TAajUJoyoehKboQ/vOf/6CkpETqABUQEIA//elPwhqz2YxHH31UqF199dWy4JS/rpc1NTXCfYVCgalTpyIsLAwGgwF6vd7v6MiZM2eeUVdIjp0kIiIiIiIiIiLqnfiOHRERUS8VExODmJgYDB8+XKhXVlaioKBAClT5Rv85nU4AgMfjwdGjR3H06FHhuICAACQmJgrj/ny3/b1x39VO1knqxG5SKSkp6NOnD5KSkpCQkICkpCQMHjwYGo3mjJ/ryw9K4Ha2AADGX58IbSRDJXTxCFYpMfnmJGx8y4qWZi82vlOCWY+aoOjgMZRFRUX43e9+h7y8PABATk5Oh56/qzz44IP43//+J93XarWy4JS/8XonC4gQnY2Ghga43W5p1F1LSwsuueQSYU1ubi5eeOEFKRDlcrkwb948WeeljRs3Ijc3V6j5wsg+7cfhAW3jgqOj5SM+s7KysGjRImkknl6vh06nk61btmzZWV8zERERERERERERUXsMThEREZFAp9NBp9Nh5MiRQr28vFzqTJWfny/d9ng8AIDW1lYUFxejuLgY27dvF46NiYkRulOlpaUhLS3N75ugncXfmD1fmGrw4MG45ZZbMGTIECQkJJzX8xzZ40D+gbbQ2SUjopDcN+y8zkfUHUXHhmLklbHI3lQBW6kHuzfbMeYqQ4ecu7m5GatXr8Ybb7whG0XXnfnG6/lG61ksFsydO1cWijrxmpxOJ6qrq4UwSXp6OtauXYu0tLRO2Tv1fGazGRaLBcePH0dQUBAcDgeuueYaIbjk9XoxduxY4TidTocvvvhCdr4ff/xRuO9vJJ5Op0NcXBwMBoMUdjrxv7Xx8fF47733oNfr/QamfAYMGIABAwac0bUSERERERERERERnQ8Gp4iIiOiMxMXFIS4uTjZOp6ysTBj3l5+fD6vVKgWqgLaxgFVVVbIOMVqtVgpR+QJVJpMJ8fHxF/RacnJycO+99yIzMxOvv/668MauQqHAoUOH4Ha7sWLFivN6nob6FmxdXw4A0CWokDkl9rzOR9Sd9bssGscsbhTl1uH7LZUYcFkEomNDzuuc+fn5WLRoEaxWawftsmOVlZWhsLAQxcXFuPnmm4XHDh48eEbj9SZOnIj+/fsjJSVFCpj6C5QwNEU+K1euFLo/9evXDw888ICwZv369VizZo1Qy8jIEIJTCoUCkZGRcDgcUq2yslL2fDqdDpMmTYJer0dsbCz0ej0GDhwoW3cm/80MCQlB//79T7uOiIiIiIiIiIiIqLMwOEVERETnJT4+HvHx8Rg3bpxU83q9KC0tlcJUvmCVxWJBY2OjtM7pdOLAgQM4cOCAcE6VSgWTySQFqXx/kpKSEBAQ0CH7fuONN6Sv7YNTvq5TZrMZN998Mx5++GHceuut5/Qc2z+tQKOnFQGBwMQbEhHQwaPLiLqbsdfEo9zqQqOnFZs/OIZbHzGd87m2bNmCxYsXo6GhQXpd+l6r/kZtdqbFixdjy5YtaGhokGpXXXUVwsJ+7iiXnJws3faN10tPT5ed684777ywm6VuwTcOzzcSz2AwyLouLl++HHv27JHWOBwOfPLJJ0hMTBTWrV27Fm63W7pfV1cne77IyEjptsFgQEREhN9Oi/PmzUNISAj0er3050Q6nQ7Lly8/62smIiIiIiIiIiIi6gkYnCIiIqIOp1AokJSUhKSkJEyYMEGqt7a24tixY1Kgymq1SoGq+vp6aZ3H48GRI0dw5MgR4bxBQUFITU2VBapSU1OhVHbMjzUKhQJerxderxcNDQ1Yvnw5cnJy8OyzzyI0NPSMz1N5zIND37V18Rg4KgaaiOAO2R9RdxYUEojh02Kx89MylBXW4+j+WvQfGnFW56ipqcHzzz+Pr7/+GgBkoSmfrKwsWRe78+VwOPDNN9/AYrGgsLAQFosF11xzDe677z7Z2vahqbi4OFRVVQnBqQEDBuDDDz+EyXTu4THq/nJzc1FWViaFohoaGnDXXXcJa7766iv87ne/E2oLFiyQheaOHTuGvLw8oVZTUyMLThkMBjQ3N5+y+9OMGTMwYcIEREREIDb25N0Ob7zxxjO6TiIiIiIiIiIiIqKLFYNTRERE1GkCAgL8BqoAoLy8HBaLRQpS+W6376TR1NSE/Px85OfnC8cGBgYiOTlZGvfnG/1nMpkQEnLyUWFZWVl+6+272igUCnz99df45S9/icWLF5/0mBN9+cExAIA6TImMsbrTrCa6eKQPjkTu/6pRVd6Arz8uR9qlYQgKPrNOcYcPH8bjjz+OmpqakwamTlY7U77vNUVFRbjllluEx8rKyvDss88KtYKCAtk5rr32WowePRpGoxFGoxEqlcrvczE01XNlZ2dj9+7dQpeo2bNnY9iwYcK6l156Cbt37xZqs2bNEsK8ERHy8GB1dbWsdtlll0Gj0cBgMECv10On0yElJUW2bt26dafdf2xs7CkDU0RERERERERERETUhsEpIiIi6hbi4uIQFxeH0aNHC/Wqqiq/gar2bzq3tLTAarXCarVKXWqAtnBFQkKC1JmqfacqjUZz2j35uk8BbYGKuXPnYvbs2XjooYdOOTIw72AdbCUeAMDwK+IQqOyY8YJEPcWYa+Lx6Sor3M4W7N9RheFT5OO/2mtqasKqVauwevVqNDc3nzI0BfwcajwbzzzzDDZv3gyPxyPVrrjiCkRFRUn3TSYTwsLCpOClyWTCoEGDZOfKzMw8q+emzuN0OqWgk8vlQkJCAqKjo4U1d999t7AmMzMTL774orDm8OHDeO+994TaxIkTZcGp9n9/IiIioNfr4Xa7ER4eLtVTU1OxcOFCaRSewWBAXFycbO8c20hERERERERERETU+RicIiIiom4tJiYGMTExsk5PdXV1KCgoEMJUFosFFRUV0hqv14vS0lKUlpZix44dwvEGg+GMnr999ykAePvtt3H48GEsXrwY8fHxfo/5fou9be9xIUjtH+Z3DdHFLCo2FMZLw2D9sQ57vq7GsAk6BCr9B50qKirw6KOPwmw2o6Wl5bShKd9jvnUOhwPbt2+HxWKB1WqFxWLBVVddhblz58qOaR+a8o3Xax98UalU2LZt2zlfN10YtbW1OHjwoBB2uuSSS2QBtmeffRaffPKJUPvDH/6Aa6+9Vqjl5+cLfxeqqqpkzxkREYGoqCip+5Ner/fbQez+++/H/fffj6SkpJPuX6/X49Zbbz2jayUiIiIiIiIiIiKizsXgFBEREfVIYWFhGDp0KIYOHSrU3W633w5VpaWlwjqbzXZWXWt8QQ2v14ucnBzMnDkTTzzxBKZPny6sKylwSd2mBo7hiD7qvQaPjoH1xzrUu1rw4x4HBo+Mkq3ZvHkz/vznP8PhcAA4t05SdrsdzzzzjFA7cZwnAMyYMQPDhw8/7Xg96lxbtmzB/v37pUCUy+XC8uXLhf9/zGYzHn30UeG4W2+9VRacOtOReJdffjmCgoJgMBhgMBiQmpoqWzNz5kzMnDnztPs/VWCKiIiIiIiIiIiIiLo/BqeIiIjooqJWqzFw4EAMHDhQqDc2NsJqtcJsNktfv/rqq7M6d/tAR0NDA5YsWYIjR47g4Ycflt7k/9/WSgCAJlzJblPUq0XFhiLOqEa51Y2crZUYNCJSeg25XC4sXrxYGq15Jl2mfHzhKt/avn37Ijw8HKmpqdKIvRNf/wBkIUs6Pw6HQwo7tba2on///sLjmzdvxjvvvCN0iVq4cCGuv/56YV12djY2bNgg1Kqrq5GQkCDdb98VDADi4+MRGRkp29OECROQkJAgdYjy/TnRH//4x7O+XiIiIiIiIiIiIiK6ODE4RURERL1CcHAw+vXrh379+km1E8f/nQ1f0OODDz7AN998g88++wxORxOsuS4AwOCxurPunEN0sRk8OgblVjcclU0oKXAjuY8GeXl5WLRoEQoLCwGcWZep0wWrtm7d2rEb76Vqampw+PBhqfOT2+1GRkYGMjIyhHUPPPAA9uzZI91PSkqShZ9cLhdyc3Nl5z9RVFQU9Hq9NBLPYDAgODhYWBMfH4/33nsPBoNBFqJqz18XQiIiIiIiIiIiIiKiU2FwioiIiHqlrKyscxoLBvwc9PCN7isvLwcA5O6rBQAEKhVIGxTeofsl6oniTVqow5Rw1zUjd28tkvtoMGvWLOm1A5y6y5RvjW9d+9eeQqFAVlYWcnJyLvh1XAzefvttVFRUSN2fgoOD8fzzzwtrDh8+LBuJd88998iCUyeOxPMXiEpJScHUqVOh0+mkUNSgQYNk6x566CE89NBDp9x7SEiIrKMVEREREREREREREVFHYHCKiIiIeq0zDU21D2/4jvMdGxgYKHWuyt3bFpxK6quFMiiwA3dK3ZXNVo5ly34v3TeZ+uLhh3/XhTvqftIGReDQ7irkHTiOKTfFy15PwKk7SrUPKfY2DQ0Nwqg7pVKJ9PR0Yc2mTZvw3nvvCV2i/vjHP+Lyyy8X1m3YsAHFxcXSfaVSKQtOnTj+LiEhAeHh8hDotddei7FjxyI2NhYGgwHx8fGyNZmZmcjMzDzrayYiIiIiIiIiIiIi6kwMThEREVGvdbqOUyd2u/FJSkrC6NGjMWLECIwYMQIajQa1VY2wH2sAABgvYbep3sLlcuLw4R+k+42NDV24m+7JeGk4Du2uQkN9K6xHnfj73/+OXbt24fvvv4fFYpFeW77XW2trq/B68/c6bd91qicym80oKiqSAlEulwvXX3+9EFyqr6/H+PHjheOGDBmCVatWCbUzHYmn0+nQ0tICvV4vjcQ7UVpaGt5//30YDAZZiKq9cePGndF1EhERERERERERERF1dwxOERERUa/kL3Thr7OUT3h4OKZMmYKbb77Z78io/IN1ANrG9CX31V6AHRP1TNGxKmgjg+B0NMFyuA5Tbx6LsWPHAgDKysqwefNmrF+/HqWlpT06DAUANpsNa9asEbo/jRw5Erfccouw7v3338eGDRuEWlZWlhBWCg0NhVKpRHNzs1Srrq6WPWdqaiqmTp0qhaH0ej2GDBkiW/f666+fdv9qtRr9+vU77ToiIiIiIiIiIiIioosFg1NERETUq52sq5RSqcTQoUMxatQojBgxApdccskpAx3F+U4AQFyqGgGBARduw0Q9UEo/LX78vgYlBS6hHh8fj9mzZ2P8+PF4+umncfTo0ZO+Jv3pqPF97Ts/uVwuKYDU3tKlS/HDDz9Ia2tra5GTkyOscblceOedd4SaSqWSBafaB6S0Wq3suXx+/etfIzw8XOoSFRsbK1szfPhwDB8+/Kyul4iIiIiIiIiIiIiI2jA4RURERL1e+3DGqFGjcNNNN2H06NFQqVRndLy31YuSAjeAtuAUEYkMyRr8+H0NauxNqHe1IFQTCADweDx49dVX8f7778Pr9UpBqI7qOpWTk4Pa2lqp+1NQUBBuuukmYc0XX3yB3//+90LtkUcewV133SXUSktLkZ+fL9QqKyuh0+mk++Hh4dBoNEL3p8zMTNm+br75ZsyYMQOxsbGn/D5zYuCKiIiIiIiIiIiIiIg6FoNTRERE1OtkZWVJwYzo6GiMGzcOw4cPx+jRoxEVFXXW56ssa0BTY1vgQ5/I4BTRiWKTQ6XbxQUu9MsIx5YtW7B8+XJUVVWhtbVVevxsQlMKhQKZmZkYO3Ys5s6di0svvVR4/IknnkBNTY10PyYmRhacioiIkJ3X30i8zMxMxMTESN2fDAYDtFpxLGdMTAy++eab0+7bX+coIiIiIiIiIiIiIiLqfAxOERERUa9z4nit81Vibhs/FhCogC4x9DSriXqfELUSYVFBqKtpwk8H7PjHv55Edna29Pj5dJhSKBTYtWsXrrnmGllwKioqSgpORUdH+x2JZzKZsHDhQqFLVFxcnGzdPffcc857JCIiIiIiIiIiIiKi7onBKSIiIqLzZC/1AAAidcEICOiYEWNEF5voOBXqapqw+5tDyN6XLY3lA84tOKVQKNC/f38p8JSUlCRbs3TpUmg0Gr9BKJ+4uDjceuutZ/38RERERERERERERETU8zE4RURERHSeHFVNAABtVHAX76TnqK+vx549u2E2/4SffjqCvLwj0OtjkZKShtRUE4zGPsjKGo3AwMCTnmPdun/D7W7r9nXLLfcgJCQEzc3NOHBgD44ePYwjRw7i6NHDMBjikZ7eH3379se0aTMQHHzm/z/V1jrw7bdb8P33O1FSUgSXqw6JiSlISEhGRsYwmEx9z/t/i94i7P+/PtTBMR1yPq/Xi6NHj+K999476Zr09PQOeS4iIiIiIiIiIiIiIro4MThFREREdJ5qqxoBAGGRQV28k57h8OEf8Je/LEZZWalQdzhqkJeXK90fMGAQFix4Emlp/sNJ7777Burr3QCAhIRkjB8/Fc8//wS+++5b2Xl/+ulHbNoEbNq0AYsWPY+kpJQz2uczz/wGDkeN7HyHD/+A//u/z87oeqmN7/WhVkVh5k03Y/P/fYnjx48DaAtBKRQK6SsREREREREREREREVFnCOjqDRARERH1ZK2tXjhrmwH83FGH/GtpacGbb67EY4/dKwtN+ZObewgPPjgLa9e+fdq1b731MpYseVwWmjpRXl4u5s+/E263+5TrNm3agMceu1cWmqJz9/PrQ4H75/waX3zxBZYsWYJ+/foJYSmv1yuM8SMiIiIiIiIiIiIiIrpQGJwiIiIiOg/1dc3SbXUYm3meysaNH+GDD+QhqIEDh2DSpCswadIVSEyUd4JatWolDh3af8pzV1basHfvd9L9xMQUXHXVdRg5cpxsbX29G59/vv6k59qwYQ1WrHheVg8NVWP48DGYNm26333SqYVqfn59uJ1NCA4OxvTp0/H+++/jrbfewlVXXYWgoCAoFAqp+xRDVEREREREREREREREdCHx3T0iIiKi89Dg+TnUERTMTPrJlJWV4qWX/iLUhgzJwoIFTyIxMVmo79r1Nf7858XSGD4AWL58CV59dQ1UKtUpn2fIkCw8+uhTSEhIEp77+ecXCWMA3333dVx//a1QKsUfh6uqKvHKKy/KzvvrX/8eV155rdAZKTv7Wyxe/Ngp90M/Cw75+fXR2NAqPDZ48GAMHjwYCxcuxPr167F+/XqUl5dLj/vCUxzjR0REREREREREREREHYnv7hERERGdh6aGFum2Mog/Wvnj9Xrxz38uE2pjxkzCn/70siw09f/au9fgOu86P+DfIx3dJVvyNYotX+JLnE1MwE5I2GwuTTCENJBlyLLpsk23SVvKTnlBNy/olu50tmyZ3RdkOrDTMLOZ6V5muiTQjQtTTMwGvEAG52ICueDYBN8j3y3ZsmRdT18Y7BxiO3Ek+cg+n88r/Z/znOf52tKZkeZ8z+//q8f+8i//ruxYd/eebNjw5Dnvc/vtH8rnP/8/ykpTSdLZOS+f+tRDZccGBvpz+PDBN13jb//2K2XrpqbmfOlLf5M777znTaWdG2+8OZ/7XPm/i7OrKytOjZ7xnPb29jzwwANZu3ZtvvCFL+S6665LElOoAAAAAACASeHdPQCAcRgaOj05p1hfW8EkU9eLL/44zz//o1Pr9vaOfOYznzvn9KB587py//2fLDu2fftr57zPH/7hQ6mvrz/jY1dffW06O+eVHTtwYF/Z+rXXtuRb33qi7NiDD/6HLF9+1VnvOX/+wnNm4rQ3vj6GB89dfKqtrc2aNWvyyCOP5PHHH8+9996bpqamUwUqk6cAAAAAAICJoDgFADAOb9xy7I1bkXHa9u0/L1vfcsuaTJs2/S2fd9117ytbv/balnOe/1ZlmgULFpetDx06ULZ+7rmny9adnfNy552//VYxOQ/F+pPfo6ETY29x5mmLFy/OZz/72axbty4PPfRQVqxYkSSpqfF6AwAAAAAAxqdY6QAAAJcMu4ed0fbtvyhbr1//zXR3737L5x07drRsvWXLK+PK0dEx89eu31u23rVrR9l6zZq7U1dXN657Uu5kue2dbbXX0tKS++67L/fdd9/EBwMAAAAAAKqS4hQAwDi8ccrU8PBYmiqYZar69YlTAwP9efbZp89y9tk1NDSMK0db27RzPv7rOefNWzCu+/Fmw7+c0FZnOhsAAAAAADAFeMcCAGAc6upObw83Mvz2tx+rJi+//JMJuc54i0zn2spvdHQ0W7duLjvW2TlvXPej3OgbXh+KUwAAAAAAwFRg4hQAwDjUNdSe+npkSHHqTJqamjMw0H9qfe+9v5/Vq2887+vMnDl7ImOVGR4eftOxsbHz/34WCgpBZ/PGYmH9G143AAAAAAAAlaI4BQAwDnX1p4syoyOKU2eyZMnyvPTSC6fWl112eVatuqGCid6ssbEx7e0d6ek5curYvn3dueqqled1nVLJz8DZDA+VTn1db+IUAAAAAAAwBXjHAgBgHJpbT0/O6e8bqWCSqWvJkivL1rt27ahQknNbuHBJ2Xrv3j0VSnJpGug7PdWrudXnNwAAAAAAgMpTnAIAGIdifU1app0sTx09PFThNFPTwoVXlK2ffPIbOXq0t0Jpzq6ra1HZet26tWfcwo935uiR06+Pjtn1FUwCAAAAAABwkuIUAMA4tc88WQI5ekhx6kx+fbu7gYH+PProlyqU5uyWLi2fjNXdvSfr1j1RoTSXnt5fvj5aptWmtliocBoAAAAAAADFKQCAcWuf3ZAkOXZ4sMJJpqYrrliWj33sE2XH1q1bm8ce++uMjJx5e8ORkZGsXfvV/Mmf/MeMjo5eiJi5/fYPZdasOWXHvvzlv8i6dWtTKpXO+JwXX9x0IaJdEn41ke1XRUMAAAAAAIBKK1Y6AADAxa59Vl2S5MiBoYyOjKa2WFvhRFPP/ff/+zz99PfS3b3n1LFHH/1ynnpqXT760X+RBQsWp61tevbv786uXduzdu1j2bNnZ5Jk/fpv5s4775n0jA0NDfnkJz+TP/uz/1R2/OGHP58NG9bnllven/nzF2b69PZs3fqzbNjwnWzc+P1Jz3WpOLx3IMnpoiEAAAAAAEClKU4BAIzT3K6mJEmplBx8/UTmLmipcKKpp7GxMQ899F/zR3/0b8uOb9v283zxi//tnM995JEv5rbbPpjGxsbJjJgkufnmO7J69Y15/vkflR3ftGljNm3aOOn3v1QN9A2nr+fkdLG58yf/+wgAAAAAAPB22KoPAGCc5i1uTuGXv1V17+ivbJgp7Jpr3p2vfOXvs3z5b5zX8+64464Uixem718oFPKnf/pwPv7x+y/I/apF947jp77uWqpYCAAAAAAATA0mTgEAjFOxriadC5ry+vaB7N+pOHUuixYtycMPP5onnvj7fPvb/zc7d2570zlNTc1Zvvw3smzZiqxZc3cWLVpyxms1NDRkYOD0/3dNzbk/E1BXV1e2LhbrznhesVjMgw9+Otdc85489thf56WXXjjjeR//+P25+eb359OfPl2yampSCjqT/TtPbtPX1FKbGXNt1QcAAAAAAEwNhVKpVKp0CACAi93T6/Zn4/oW+9D4AAAKuUlEQVSDqalJfvczy1PXUFvpSBeFEydOZNeu7dm7d086OmZm3rwF6eiYUelYZUZGRtLdvTu7d+9IW9v0dHbOz4wZM1MoFCod7aLxtS9tTf+xkVz5nrbc9ftdlY4DAAAAAACQxMQpAIAJseTqtmxcfzBjY8nOLceyZGX7pN9zaGgox4/3Tdj1RkdHUls7sb8evlUJqrGxMcuWrciyZSsm9L4TqVgspqtrUbq6Fp3X83p6jmQiP6MwMjIyoVsWNjQ0prm5ecKudzb7d/Wn/9hIkmTJ1dMm/X4AAAAAAABvl+IUAMAEmNvVlOkz69J7aDjbXzl6QYpTP/jBU/nzP/8vE3a92trajI6OTtj1kuSv/urx8y4cXQoOHTqQ3/u9uyb0mk1NzWVbE47XrbeuyR//8X+fsOudzfaf9SZJaouFLLmmbdLvBwAAAAAA8HbVVDoAAMCl4qrV05Mkr//ieAYHRib9fhO/U9zEbz03NjY24de8GEzGbtgX4w7bpVIp2145liRZ9q62FOv8+QEAAAAAAEwdJk4BAEyQFaum50dPHkyplOzYfCzL39MxqfebMWNWrr32ugm7Xl/fsbS2TuxEoIm+3sWioaExq1bdMKETvAYG+tPUNHFb612I7RH37ezPYP/J/4MVqyd/ChsAAAAAAMD5KJQuxo+uAwBMUV/7n9uz6+f9mT6zPh/5d1ekMPFjoeCi8b2v78rOV/vS1l7Mg/95WQo1Xg8AAAAAAMDUYa8MAIAJdP0ds5IkvYeGsmtrX4XTQOX0HDiRna+efA1cf/sspSkAAAAAAGDKUZwCAJhAC5e3ZtZl9UmSH393fwz3pFq98P2DSZKGpppcc8PkblsJAAAAAADwTihOAQBMsPd+YHaSk1Ontr3cW+E0cOEdfL0/OzcfS5KsunVGaoumTQEAAAAAAFOP4hQAwARbvnJa2jqKSZJnntyX4cHRCieCC6dUKuXpb3YnSWrrCnn3TTMrnAgAAAAAAODMFKcAACZYoaaQW+/pTJIMnRjLC98/UOFEcOFsfeFIeg4OJUlueP+sNDbXVjgRAAAAAADAmSlOAQBMgmUr27LwypYkyeZnj6T34GCFE8HkGzoxkuefOlkUnD6zLtf/s1kVTgQAAAAAAHB2ilMAAJNkze90praukFIp+acndmdsrFTpSDCpfvCN7gwPjiVJPvSJeampLVQ4EQAAAAAAwNkpTgEATJK2jvrcdOecJMmR/UN5/ql9FU4Ek+fV5w9n99a+JMnKG9vTubC5wokAAAAAAADOTXEKAGASrbplRuZfcbJA8rNnjmTPa8cqnAgm3uF9A3lm/cli4LQZxdzykcsqnAgAAAAAAOCtKU4BAEyiQk0hd/9BV5paapMk//TE6+k/OlzhVDBxhgdH893Hd6c0lhTrCvnov1mY+gZ/ZgAAAAAAAFOfdzQAACZZU0ttPvLA/BRqkuHBsXznqzszMjRa6VgwbqVSKd/9+u4cPzqSJLnzE/MyY25DhVMBAAAAAAC8PYpTAAAXwOWLWvLB+y5PkvQcGMpTX9udUqlU4VQwPs+u35u92/uTJNffMTPLVk6rcCIAAAAAAIC3T3EKAOACuWp1e2784Kwkyd7t/Xl2/d4KJ4J37tVNh7P5uZ4kydJ3tea37ppb4UQAAAAAAADnR3EKAOACet8H5uTq97YnSTY/15NXNh6qcCI4fztePZaN6/YlSRYsa86H/9WCCicCAAAAAAA4f4pTAAAX2Pt/pzMLr2xJkjz3j/vz/FP7KpwI3r5fvNSTDV/fnSSZObc+H/nXSlMAAAAAAMDFqVAqlUqVDgEAUG1GR0r5xv/amW0/O54kWbJyWn7z7stTKBQqnAzO7qc/PJAXNhxMkszurM+9n1qcxpbaCqcCAAAAAAB4ZxSnAAAqpDRWypNf3ZNXnjuaJJm3pCW3fWx+aouGgjK1lEqlbFzXnS0/7k2SdC1tzj0PLkhdvZ9VAAAAAADg4qU4BQBQYT/81r48851DSZKO2fW57d6utHXUVzgVnDTYP5Lv/Z892bezP0my9F2t+ef/sis1NaajAQAAAAAAFzfFKQCAKWDzpp48+Vh3RodLqS0WctOHO7PoqumVjkWV27ujLxv+4fUM9o+mUEh+80Oz8947Zlc6FgAAAAAAwIRQnAIAmCIO7RvM2kd3pvfQcJKka3lrbvjAZWmeVlfhZFSb4cHRPPeP+7L1hZNb8zU21+SeB7py+eKWCicDAAAAAACYOIpTAABTyPDgWNb97935+Yt9SZJifSGrbpudK1fPTMHOaFwA217pzTPf3pfBgdEkSefCpnz4D+anRYEPAAAAAAC4xChOAQBMQVt+0pvv/cPeHD92srzSMac+N919eWZc1lThZFyq+nqG8sNvdmffzv4kSV1DTX7rrjm59qYZSnsAAAAAAMAlSXEKAGCKGh4s5Qf/b29+8sMjKZWSFJL5S1tzzY0zM6erudLxuET0HDiRl390KNteOZqxkz29LLu2Lbf/dmeapxUrGw4AAAAAAGASKU4BAExxB14fzPqv7sm+3SdOHeuYU58V18/I4qump1hfU8F0XKy2vdyTLT/uPTVhKkna2otZ87uXZ+Hy1gomAwAAAAAAuDAUpwAALgal5Beb+7Jpw8Hs2nq66FJTLKRrWWuWXduezkUtKdTYU42zKCX7d/fntZ/2ZPvmYxkeHDv10Jx5jVl164xc+e721NRWMCMAAAAAAMAFpDgFAHCRObR3MD95+nBe3dSbEwOnyy/F+kJmz2vO3AVNmTO/ObPnNaW2aBpVNTuwuz8H9gxk787+7N/Vn6ET5T8vy1a25V3vm5HLF9v6EQAAAAAAqD6KUwAAF7EdW/qyeVNvtv60fILQr7S216VjTkOmz2rIjDkNaWotViAlF8LgibH0HDiRI/sGc/TQYI4cGDrjeUtXtuaq1R1ZvKI1tXUmlAEAAAAAANVLcQoA4BIwNpa8vu14tr/alx2bj2f/nhOVjsQU0TG7LguvbM2iFW3pWtqSorIUAAAAAABAEsUpAIBL0onjo+neNZC+nuEc6xlOX+9I+nqHc7x3OMd6RzI48ObpVFyc6htr0jqtNi3T69I6rZjW9rq0Ta9LS3td5l7emLaOukpHBAAAAAAAmJIUpwAAqlTvoeEcPzqcsTG/Dl5sCoVCmtuKaWuvM0EKAAAAAADgHVKcAgAAAAAAAAAAqk5NpQMAAAAAAAAAAABcaIpTAAAAAAAAAABA1VGcAgAAAAAAAAAAqo7iFAAAAAAAAAAAUHUUpwAAAAAAAAAAgKqjOAUAAAAAAAAAAFQdxSkAAAAAAAAAAKDqKE4BAAAAAAAAAABVR3EKAAAAAAAAAACoOopTAAAAAAAAAABA1VGcAgAAAAAAAAAAqo7iFAAAAAAAAAAAUHUUpwAAAAAAAAAAgKqjOAUAAAAAAAAAAFQdxSkAAAAAAAAAAKDqKE4BAAAAAAAAAABVR3EKAAAAAAAAAACoOopTAAAAAAAAAABA1VGcAgAAAAAAAAAAqo7iFAAAAAAAAAAAUHUUpwAAAAAAAAAAgKqjOAUAAAAAAAAAAFQdxSkAAAAAAAAAAKDqKE4BAAAAAAAAAABVR3EKAAAAAAAAAACoOopTAAAAAAAAAABA1VGcAgAAAAAAAAAAqo7iFAAAAAAAAAAAUHX+P1UgAwEKp2doAAAAAElFTkSuQmCC", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import nest_asyncio\n", - "\n", - "nest_asyncio.apply() # Required for Jupyter Notebook to run async functions\n", - "\n", - "display(\n", - " Image(\n", - " app.get_graph().draw_mermaid_png(\n", - " curve_style=CurveStyle.LINEAR,\n", - " node_colors=NodeStyles(first=\"#ffdfba\", last=\"#baffc9\", default=\"#fad7de\"),\n", - " wrap_label_n_words=9,\n", - " output_file_path=None,\n", - " draw_method=MermaidDrawMethod.PYPPETEER,\n", - " background_color=\"white\",\n", - " padding=10,\n", - " )\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "d821b2f6", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-18T12:18:30.629629Z", - "start_time": "2024-04-18T12:18:30.620092Z" - } - }, - "source": [ - "### Using Graphviz" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d4234400-75cd-4b13-aeff-828f7fb68ab1", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-19T11:25:42.057704Z", - "start_time": "2024-04-19T11:25:42.019017Z" - } - }, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install pygraphviz" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ee026342-f560-4ce0-ab43-1718bd19a366", - "metadata": { - "ExecuteTime": { - "end_time": "2024-04-19T11:25:42.631675Z", - "start_time": "2024-04-19T11:25:42.452377Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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P87s2bNZt24dDz/8MP/85z8xGAxahyWEEGesrKyMPXv2OBWn0tLSUBSlSXHq/PPPJzQ0VOuQRQdw8OBBbDYb/fr10zoUIYToSFq3EFVYWMiQIUOYOHEiq1ataq3ZCKGJJUuWoNPpmDdvntahCCGEaCNJSUksWrSItWvXMmLECObNm8f1118vB2mFEC5FURRefPFFEhMTGTFiBKtWrSIqKkrrsIQQ4pyVlpayd+9ep+LU/v37AZoUpy644AK5zbJo4u6772bFihVccsklrF69msDAQK1DEkKIjqB1C1EA33zzDVOnTuXVV1/lr3/9a2vOSgghhBCixdlsNr766iueeOIJkpOTiYuLIzExkWnTpmkdmhBCtKrU1FSuu+46fv/9d15++WWuu+46rUMSQogWV1JSwr59+9iyZQtJSUmkpKSQm5sLNC1OxcfHExwcrHHEQks2m401a9bwzTff8Morr2gdjhBCdBStX4gCeOihh3jhhRf46aefiI2Nbe3ZCSGEEEKcs5qaGv7zn//wr3/9i0OHDjFlyhQeffRRRo8erXVoQgjRZsxmM4mJiSxbtowbbriBFStW4Ofnp3VYQgjRqnJycpyumtq+fTt5eXkYDAb69+/vVJwaMWIEPj4+WocshBBCtGdtU4iyWq1MnjyZw4cPk5ycLJetCiGEEKLdKisr46233uLZZ5+lsLCQa665hkceeUTuAy+EcGv//e9/ue222/D392fVqlWMHTtW65CEEKJNnVic2rZtG/n5+RiNRvr16+dUnBo5ciTe3t5ahyw0lJubS5cuXeQW3kIIoWqbQhRAXl4esbGxxMfH89FHH7XFLIUQQgghTlteXh4vv/wyS5cuxWq1csstt5CYmEh4eLjWoQkhRLuQl5fHLbfcwvr163n44Yd59NFH0ev1WoclhBCaObE49fPPP1NYWNhscWr06NF4enpqHbJoIwkJCWRnZ3PnnXdy7733ah2OEEJore0KUQA//PADF198MUuXLuXOO+9sq9kKIYQQ7daRI0dQFIXu3btrHYrbyszMZOnSpaxcuZKAgAD+/ve/M3/+fIKCgrQOTQgh2h1FUXjxxRe5//77iYuL47333iMiIkLrsIQQot04sTi1ZcsWiouLMZlM9O3b16k4dd555+Hh4aF1yKIV/Prrr6xYsYK8vDw++OADrcMRQgittW0hCuCJJ57g6aef5ocffpDbOQghhHB7c+bM4eDBg/zvf//TOhS3s2vXLp5//nk++OADevbsydy5c7n99tvlNipCCHEaUlJSmDlzJsePH+eVV17h2muv1TqkDmPr1q1s3bqV+fPnax2KEKINWK1W0tPTnYpTO3fupKqqqqE4FR8fT1xcHCNHjmTgwIFytakQQghX0/aFKJvNxowZM/jll1/Ytm0bPXv2bMvZCyGEEO3KFVdcgYeHB6tXr9Y6FLeRlJTEokWLWLt2LcOGDWPBggXMnDkTo9GodWhCCNGhVFdX88ADD/Diiy9y44038vLLL+Pr66t1WO3e/fffz3fffceuXbu0DkUIoZHmilM7duyguroaPz8/hg0b5nTllBSnXJfFYpH9ECGEO2j7QhRARUUFcXFxWCwWfvrpJwIDA9s6BCHOWUpKCgUFBUyePFnrUIQQHdjq1avx9PTk8ssv1zoUl2az2fjqq6946qmn2LZtG3FxcSQmJjJ16lR0Op3W4QkhRIf2+eefc9tttxEaGsoHH3xAbGys1iG1axdeeCHR0dG8/vrrWocihGhHLBYLGRkZTsWplJQUzGYz/v7+DB061Kk4FRMTI/3YDs5mszFkyBBGjRrF3LlzGTlypNYhCSFEa9GmEAVw+PBhxowZw4gRI1izZg0Gg0GLMIQ4a3feeSepqan8+OOPWocihBDiJGpra1m9ejXPPPMMBw4cYMqUKTz88MOcf/75WocmhBAuJTs7m5tuuoktW7bw0EMP8eijj8rZ+ydRVFREVVUVkZGRWocihGjn6urqOHDggFNhavv27dTW1hIYGMjgwYOlONWBWSwW3n77bV566SXGjBnDq6++qnVIQgjRWrQrRAH89NNPXHjhhcybN49FixZpFYYQZ2XBggX8/PPP/Pzzz1qHIoQQ4gQVFRW88cYbLF68mOPHj3Pttdfy4IMPMnDgQK1DE0IIl6UoCi+++CL3338/48aN49133yU8PFzrsIQQwqU0Lk5t2bKFpKQkMjIysFqtBAUFMWjQoIbCVHx8PNHR0VqHLE5DdXW1PKtWCOHKtC1EAbz33nvcfPPNvPnmm8yaNUvLUIQ4I3v27KGsrIz4+HitQxFCCFEvPz+f5cuXs2zZMmpra5k9ezb33XefnHUuhBBtKDk5mZkzZ1JSUsLrr7/O9OnTtQ5JCCFcWkVFBbt27XK6cio9PR2bzUZYWJjTVVOjR4+mW7duWocshBDCvWhfiAJ46KGHeO6551izZg2XXHKJ1uEIIYQQooP57bffeOGFF3j99dfx9fXljjvuYO7cuXTq1Enr0IQQwi2Vl5dz7733snLlSm688UZeeeUVfHx8tA5LCCHcRnl5Obt373YqTqWlpaEoSpPi1JgxY+jSpYvWIYuTqKysZNq0adx4441cd911eHl5aR2SEEKcqfZRiFIUhVtvvZX//Oc/rF+/ngsuuEDrkIQQQgjRAezdu5d///vffPjhh0RGRjJ//nxuu+02OdgphBDtxKeffsrtt99O165d+eCDDxg+fLjWIQkhhNsqKytjz549p1WcGjt2LJ07d9Y6ZAHk5uZy77338sknn/D444/z4IMPah2SEEKcqfZRiAKwWq1cffXVbNq0ic2bN8szHIQQQghxUklJSSxatIivvvqKwYMHc++99zJz5kyMRqPWoQkhhDjB77//zo033sgvv/zC448/zn333Yder9c6LCGEEEBJSQn79u1zKk7t378foElxKi4uTu44oKFjx47h6elJcHCw1qEIIcSZaj+FKFAfzHfJJZeQlZXFli1b6Nmzp9YhCSGEEKKdUBSFtWvXsnDhQn766Sfi4uJITExk6tSp6HQ6rcMTQghxClarlcWLF/PPf/6TCRMm8M477xAWFqZ1WEIIIZqRm5tLcnJyQ2EqOTmZY8eOAY7iVHx8PHFxccTGxuLr66txxEIIIdq59lWIAigtLWX8+PFUVVWRlJQk96gVQgjhsr7//ntSUlK47777tA6lXaurq+PDDz/k2WefZf/+/Vx22WU88MADxMXFaR2aEEKIM/TLL79w/fXXU1payptvvsnUqVObHc9qtfLxxx/zl7/8pY0jbD0lJSX4+/tjMBi0DkUIIc5YTk6O01VTv/zyC8ePH8dgMNC/f3+nK6dGjhyJt7e31iG7naNHj7J8+XLuvPNOIiIitA5HCCEaa3+FKFA3nHFxcYSFhfHdd9/h7++vdUhCCCFEi3vkkUdYs2YNu3fv1jqUdqmyspLXX3+d559/niNHjnDllVfy2GOPMWjQIK1DE0IIcQ7Kysq46667eP/997ntttt44YUXmjzb78knn+Txxx/nxx9/ZNy4cRpF2rJuu+02fv/9d9atW6d1KEII0SJOLE5t3bqVgoICjEYj/fr1cypMjRo1Ci8vL61Ddmk//PAD119/PQUFBXz77bdceOGFWockhBB27bMQBZCRkcH48ePp27cv33zzDX5+flqHJIQQQrSoOXPmcOjQITZs2KB1KK2uoqLitHN5WVkZb731FgsXLqS4uJhrrrmGRx99lD59+rRylEIIIdrSxx9/zJw5cwgPD+eDDz5g6NChAPz888/Ex8ejKArh4eGkpqYSGBiocbTnLiYmhhkzZvD0009rHYoQQrSaE4tTP/30E0VFRc0Wp0aPHo2np6fWIbuU2tpaPvnkE6644gop/Akh2pP2W4gCtRg1ceJEoqOj+fbbb6UYJdoVm83Gn//8Z+6//36XOUtTCNG2SktLqaqqcvlnZCxdupTvv/+eL7744pTjHTt2jFdeeYUlS5agKAqzZs3igQcecPnfRwgh3Nnhw4e54YYbSE5OZuHChcyePZuhQ4dy5MgRLBYLJpOJa665hvfff1/rUM+JoigkJiYyffp04uPjtQ5HCCHalL04tWXLFpKSkti1axeVlZWYTCb69u3rVJw677zz8PDw0DpkIYQQLat9F6IA0tPTmThxIn369JEro0S7ExgYyHPPPcdf//pXrUMRQoh2afHixdx3333odDr27dtHTExMk3EOHjzIsmXLWLlyJUFBQcyZM4d//OMfLnH2uxBCiD9msVh44oknePrpp+nWrRvHjx+nrq7OaZwPP/zQpZ4XJYQQ7sxqtZKenu505dTOnTupqqrC19eX4cOHOxWnBg4ciF6v1zpsl3Ho0CGqq6sZPHiw1qEIIdxH+y9EgaMY1bdvX77++mspRol2IyYmhr///e/cfffdWocihBDtzrPPPktiYiIAJpOJv/zlL7z77rsNn+/YsYMlS5bwwQcf0KtXL+6++27mzJkjt5AQQgg39cQTT/DYY481Ga7T6fD19SU1NZUePXpoEJkQQojWZrFYyMjIcCpOpaSkYDab8ff3Z+jQoVKcaiH3338/ixcvZtKkSaxevZqQkBCtQxJCuL6OUYgC2LNnD5MmTSImJoavv/4aX19frUMSQgghxEksWrSIBx54wGmYwWDg0KFDZGdns2jRItauXUtsbCzz58/n+uuvx2AwaBStEEIIrWVlZTFkyBCqqqpobhfVZDJx3nnnsWnTJjnwKIQQbqK54lRycjI1NTUEBAQwZMgQp+JUTEwMOp1O67DbPUVRWLduHZ999hmv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5BNcvHgR0dHReOqppzB9+nS4ubkJHe+OKC0thbe3t9AxiIiI6BYYDAacOXMGiYmJcHFxwfPPPy90JCKyAnq9Hrm5ufD29oajo2Or44YPH47y8nIMGDAAH3/8sRkTEhEREVEHUCEWOgFRR+Tp6Ym//e1vuHDhAk6ePIl7770XL730Evz8/DB16lTs378fHbnHe+LECchkMmzatEnoKERERHSLxo4di1WrVqGoqEjoKERkBb744gs4Ojqia9euSElJaXPsgQMHcPr0aTahiIiIiOiGeEUU0R2iUCiwdetWrF+/vvGmun/5y1/wl7/8pcMtfaPX67Fo0SIsX74cJ06cQExMjNCRiIiI6CZyc3MRFBQEkUgkdBQislAGgwFr1qxBZmYmgoKCsHDhwlbHZmRk4OjRo+jWrRt69erF++MSERER0R/FpfmI2kNaWho2b96MDRs2QKlUYvz48Zg5cyYefPBB2NjYCB3vlqWmpvL+V0RERAJSKBRISEjADz/8gEcffRTjxo0TOhIRWSiNRoPs7GyEhoZCIpG0Oq5nz55wdnbGgw8+iNdff92MCYmIiIiok+LSfETtISoqCkuXLkV+fj6++OILVFRUYPz48ejatSv+8Y9/ICcnR+iIt4RNKKI7LzExEatWrRI6BhF1EEVFRZg9ezYKCws71GQWIjKv9957D46OjoiIiMDly5fbHHv+/HkcPXqUTSgiIiIiMhteEUVkJunp6di4cSM2btyIa9euYdiwYXj66acxYcIESKVSoeMRkZksXrwYiYmJSE1NFToKEXUQSqWSS2IRdUJKpRLr1q2DXC7HgAED8OSTT7Y69vTp08jIyEB4eDh69uwJOzs78wUlIiIiImobr4giMpeIiAgsXboUV69exZYtWwAAjz76KLp27YpXX331pjMXiYiIyHqcP38eixYtQnR0NPLz89scyyYUkfWpra3FxYsX2xxjY2ODDz74ABcuXEBdXV2bY/v27Ytp06YhJiaGTSgiIiIisji8IopIQHl5efjyyy+xdu1a5OTkICYmBjNnzsTMmTPh6ekpdLw2ffvtt7j33nsRHBwsdBSiDqW2thYajQaurq5CRyEiAf3vf//De++9hzFjxuDll19mPSXqRObNm4f169cDAFQqFRwcHARORERERETUrirYiCKyAHq9HklJSdi0aRN27twJvV6P+Ph4zJw5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IiIiItLgaWk+EZG64HQ62bFjB6tWrSIpKYlvvvkGX19frr/+ehITE7n55puJjo42OqbUk61bt3LNNdeccd5qtfL0008zY8YMA1LJxcrNzWXChAls3LiRJ554glmzZhkdSS7QnDlz+O677zCZTCxatKjWcXa7na1btxIVFUX79u0xmUz1mFJERERERETkkqRClIhIXSovLycuLo4hQ4YQFRXF1q1bSUpKori4mMjISBITE2v2lvL19TU6rtShyMhIcnJyzjj/448/0rlzZwMSycWqrKzk/vvvZ/DgwQwePJjg4GCjI8kp3G43ubm5ZGZm0qNHD1q3bl3r2D/84Q8UFBQQGxvLzJkz6zGliIiIiIiISKOnQpSISF0qKSnhpZdeYsGCBUyaNImnn34ah8PBxo0b+eqrr1i2bBnp6ekEBgZy4403MmLECIYPH06HDh2Mji5eNnPmTP7617/WLM9nMpno2bMn27dvNziZnI3b7Wb79u3ExMSoSHyJWrhwIXfddRcAixYt4tZbbzU4kYiIiIiIiMhlSYUoEZH64HK5qKioICAg4Ixr+fn5rFixgi+//JIVK1ZQWlpa0y2VmJjI8OHDCQwMNCC1eNPu3btPW47RYrEwe/ZsHnnkEQNTydksXryYBx54gPz8fFauXEliYqLRkeQUjz/+OBkZGYSHh/PGG2/UOi4/P5/MzEw6d+5MSEhIPSYUERERERERkVOoECUi0lAUFhYSFBTEhg0bWL58OStWrCA9PR1/f38GDBjA0KFDGTZsGF27djU6qlyg7t27k56ejtvtxmQykZubS7t27YyOJf8jPT2dpKQkhg0bRs+ePbUPUD1wOBzs27ePrKws+vfvf9ai/c9uu+02bDYb/fr148EHH6zHlCIiIiIiIiJyAVSIEhFpCH766SfCw8OJj4/n8ccfZ+TIkYDnX/SvX7+epKQkli5dytGjRwkNDWXw4MGMGjWKxMREWrRoYXB6OVezZ89m+vTpuFwubrjhBtauXWt0pMtOQUEBKSkpDBs2zOgocornnnuOGTNmALBlyxb69OljcCIRERERERER8RIVokREGoKqqipWrFjBhx9+yMiRI7nzzjvPGON0OtmxYwerVq1i1apVrFu3DpfLRa9evWqW8Rs4cCAWi8WAGci5yM3NpWPHjrjdbubNm8ekSZOMjnRZeeCBB3j77bcJCAigoKAAf39/oyM1asePH2fatGlkZWXRr18/nn766VrHHjhwgIKCAqKiomjevHk9phQRERERERGROqZClIjIpaqoqIhVq1axYsUKVqxYQV5eHq1bt2bw4MEMHTqUxMRELfvWAPXr14+tW7eSn5+vbrZ69vXXX1NeXk5CQgJNmjQxOs4lq6KigszMTLKyshg9enSt41wuF4MHD6Zjx44MHTqUsWPH1mNKEREREREREWkgVIgSEbnUzJw5k4EDB9K/f398fHxqzu/cubOmKLVx40YqKyuJjo4+rVuqadOmBiYXgLfeeovly5ezZMkSo6M0CAUFBYSEhFzUMxwOB5s2baKqqoohQ4Z4KZnUZvLkycybNw/w7G3XunVrgxOJiIiIiIiISAOmQpSIyKWkqKiIhIQEdu7cyf3338/cuXPPOu7EiRNs2rSpZhm/7du3YzKZTlvG74YbbsDX17eeZ9D4lZeXY7fbsdvtNefsdjsOhwOA0tJSUlJSGDhwYM31UzujfH19CQoKavRFw8rKSmbMmMFXX31FWlraBT/H5XLRoUMH8vLyGDNmDP/+97+9mPLycejQIWbOnElmZibjxo1j8uTJtY7du3cvFRUVREVFaXlDEREREREREfk1KkSJiFyK9u7di9vtpkuXLuc0/siRI6xZs6amMJWdnU1AQAB9+/atKUz17t0bs9nslXwul8trzzJSUVEReXl5HD58mPz8fAoLC8nPz/ccFxzm2NEjlJWVUlZWRklJGaX2cpxOl9e+v1nTJgQFNiEoMJDAoEBatGxNcEgYwcHBtGnThtDQ0Jrjtm3bEhYWhslk8tr315X09HTGjh1LRkYGbrebAwcO0KFDhwt+3tKlS4mOjiYyMtKLKRuH0tJSMjMzyc/PZ/jw4bWOKygoYPz48URFRTFmzBgGDx5cjylFREREREREpBFTIUpEpLHasmULXbt2PWtnTXZ2Nhs3bmTTpk18+eWX5OXlERwczMCBA0lMTGTIkCFERERc0PdmZWVx1113MX/+fLp27XqRs6hbTqeT7Oxsdu3aRU5OjueVncW+nL3s259LaVl5zVirxUxIcwshTU2ENq0mJMhJiyYQ5A+BftA8AIL8PMdB/p7jn/nbwM969gzVTiirOPn5RBXYKzznisuh7ITns70SjtqhsMxMod3C4RIT+ceqKa901tzra7PSMbwtEZ2uIKJTFBEREXTq1IkuXboQHR1tePeK2+1m3rx5PPzwwzidTqqrq7FYLMydO5dJkyadMT4rK4vly5dz3XXXERcXZ0DiS9/QoUNJTk4mKCiIkpKSS6JQKSIiIiIiIiKNigpRIiKNkdvtpn379hQVFXHffffx5ptv/uL47Ozsmm6p5cuXU1ZWRmRkZE231I033kjLli3P6bvfffddJk2ahM1m49lnn2XKlCmn7WVllP3797Nt2zZ27dpFWtoP7M7Yya7dmVRWeZbMC21pI6I1RLSqolMwRARDp2Bo3xJCmkGrQIMnUIvjlXC4GH4qhpxCyCmAfUdgX5GVnEITB484qHa6MZtNdOrYjpjYXnSLiaVbt2707NmTmJiYevnzyc/PZ8KECaxcuRKX62TXmI+PD6NGjWLx4sWnjd++fTtXXXUVTZs25e9//zsTJ06s84yXirS0NF544QUyMzOZPn06o0aNqnVseno6VquViIgIbDZbPaYUEREREREREQFUiBIRabyOHTtGUlISTqeTe++995zvq66uJjU1taYwtW7dOpxOJ717964pTF1//fX4+flRWVmJ1Wo9bRm+8ePH8+mnn1JdXY3ZbKZXr168//77dOvWrS6meValpaXs3LmTbdu2sWnjetavW0t+4VEAwlpaiWnnpFtbFzHtoVs76NXR08nUGFU74UARpB+EjEOQfshExk82dh2sprzCSZMAP3r17EFcH0/XUVxcHN26dfNq58znn3/OfffdR3l5ec1eWacKCAiguLgYq/Vk25jL5WLDhg307dv3tPON2ZEjR8jMzKS8vJyEhIRax6WmpjJ9+nSioqK46667uPrqq+sxpYiIiIiIiIjIeVEhSkTkcpednU3z5s1r7Xiy2+189913NYWplJQU/Pz86NevH6GhoezYsYOPP/6YmJgYAEJCQigsLKy532Kx4Ha7efTRR5k1a1addGWUlJSwfv16vv76a9Z8vYIf0vfgdrvpFGrjmk4O+kS6ueYKuCoCmvh6/esvSdVOSD8EW7NgcxZs3Wcj/YCne6p92xASEoeSkHAjCQkJF7x/U1lZGVOmTOGdd97BbDaf1gn1v9atW0f//v0vdDqNQteuXdmzZw+xsbH88MMPRscREREREREREfEGFaJERC53Y8aMISkpiX79+pGcnPyrhaLc3NyaotSSJUsoL/fsoxQbG8uYMWOYNWvW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4MTxEh64sZo/DoXQ5kYnk4tR4YB/roc5X1k5cMTNw398hBkzZtCsWTOjo4mIiIiIiIiISP3SHlEiImK8srIyXn/9dV59+SWOHSvm7hvcTB3h4sowo5PJ+Th2HOaugleTLRSXw90TJvD443/iiiuuMDqaiIiIiIiIiIgYQ4UoERFpOKqqqvj444/52/Oz2LUni7hIHyYPcjKuLwT6GZ1Ozsblhm9+hPc3mflgkwkfqy/33DuJxx57TEvwiYiIiIiIiIiIClEiItLwuFwuli9fzvx33yEpKQlfK9x+jYs7r3dxw5Xgox0ODZdxCD79DhZstLK/wEH8tVdz78TJ3HHHHQQFBRkdT0REREREREREGgYVokREpGE7cuQIH3zwAQvmz2PHznRaNbUyqlc1t1ztZkh38LcZnfDy4HLD5kxY8j0s2W7jx0NVhLVpzZ1338u9995LdHS00RFFRERERERERKThUSFKREQuHZmZmSxevJglny/iuy3f42czk9ANEro5SYiBHh3AZDI6ZeORWwSrM2B1uonkNAuHjzmIigznljG3c8sttxAfH4/ZrPY0ERERERERERGplQpRIiJyaTp8+DBffPEFyckrWLvma4qOltC6mZVB0U4GdnUR3xliO4DVx+ikl47MfNiSBet2wZrdVvbmOfDztRJ/3bUkDhnOzTffTGxsrNExRURERERERETk0qFClIiIXPpcLhepqamsWbOG1V+vZP36dZTZT+Dv60OvCDPXdHLQJxKujoSoNtpjCuDQMUjJga3ZsDXHhy1ZJo6WVWO1+HB1XG8SEoeSkJBAfHw8/v7+RscVEREREREREZFLkwpRIiLS+LhcLnbv3s2WLVvYunUrW77bSOrOdBzVTnytZqLbW4kOqyK2vZtu7SCmPXRsDTaL0cm9y+32FJx250H6Qcg4BGmHrGQcclNsr8ZkMtH5inD6XNuPa665lj59+tC7d2/8/PyMji4iIiIiIiIiIo2DClEiInJ5qKys5IcffiA9PZ2MjAzS03aSkf4D+w7k4Xa7MZtNtG1pJSLYTadWDiKCISIY2reE0GYQ0hSCmzasbqqjdsgvgcIyOHgU9hX+91VkYd8RHw4UOqh0uABo3bIZsbGxRMf0oHv37kRHR9OrVy+aN29u8CxERERERERERKQRUyFKREQub3a7nT179pCTk8O+ffs8r5wscrL3sm//QcpPVNaMNZtNBDezEtzURGgzFy38HTQLgEBfCPSDIH9oHgBBfmDx8exPFXhKc5G/DfysnmOnC0pPnLxW6YDyKs/xseNgr/C8yio840rKwV7lw+ESC4dL3BSWVFP13yITgNXiQ/t2oUREdCIisjMRERF06tSJiIgIunbtSnBwcF3+GEVERERERERERM5GhSgREZFfcuzYMQ4fPkxhYSGHDx8mPz+/5ri4uJiS4iLsZaWUlZVSVlZGSUkZpfZynE7Xrz+8Fs2aNiEosAmBTZoQ1DSIZs1a0KxFKwIDgwgJCSEsLIzg4GDatGlDaGgowcHBhISEYDY3oHYtERERERERERERFaJERETqTkVFBSdOnGx7stvtOByOms8tWrSoObZYL2SkjgAAAF9JREFULAQFBdVrPhERERERERERkTqmQpSIiIiIiIiIiIiIiIjUiWNaw0dERERERERERERERETqhApRIiIiIiIiIiIiIiIiUicswDajQ4iIiIiIiIiIiIiIiEijU/r/ARN5/xGPrsbJAAAAAElFTkSuQmCC", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "try:\n", - " display(Image(app.get_graph().draw_png()))\n", - "except ImportError:\n", - " print(\n", - " \"You likely need to install dependencies for pygraphviz, see more here https://github.com/pygraphviz/pygraphviz/blob/main/INSTALL.txt\"\n", - " )" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/index.md b/docs/docs/index.md index bc3661e22..60ec1b509 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -28,4 +28,4 @@ title: LangGraph } -{!../README.md!} +{!../README.md!} \ No newline at end of file diff --git a/docs/docs/llms.txt b/docs/docs/llms.txt index f48191903..6ce5dc889 100644 --- a/docs/docs/llms.txt +++ b/docs/docs/llms.txt @@ -20,15 +20,13 @@ [Authentication & Access Control](https://langchain-ai.github.io/langgraph/concepts/auth/): LLM should read this page when implementing authentication in LangGraph Platform, designing access control for LangGraph applications, or troubleshooting security issues in LangGraph deployments. This page explains LangGraph's authentication and authorization system, covering the difference between authentication and authorization, system architecture, implementing custom auth handlers, common access patterns, and supported resources/actions for access control. -[Bring Your Own Cloud (BYOC)](https://langchain-ai.github.io/langgraph/concepts/bring_your_own_cloud/): LLM should read this page when learning about LangGraph Platform deployment options, understanding Bring Your Own Cloud architecture, or managing deployments in AWS. This page explains LangGraph's BYOC deployment model, detailing how it separates control plane (managed by LangChain) from data plane (in customer's AWS account), outlines AWS requirements, infrastructure setup via Terraform, required permissions, and explains the deployment workflow. - [Deployment Options](https://langchain-ai.github.io/langgraph/concepts/deployment_options/): LLM should read this page when needing information about LangGraph deployment options, comparing different deployment methods, or understanding LangGraph Platform plans. This page outlines four deployment options for LangGraph Platform: Self-Hosted Lite (available for all plans), Self-Hosted Enterprise (Enterprise plan only), Cloud SaaS (Plus and Enterprise plans), and Bring Your Own Cloud (Enterprise plan only, AWS-only). [Double Texting](https://langchain-ai.github.io/langgraph/concepts/double_texting/): LLM should read this page when handling concurrent user interactions in LangGraph Platform, implementing double-texting safeguards, or designing stateful conversation systems. This page explains four approaches to handling "double texting" in LangGraph (when users send a second message before the first completes): Reject, Enqueue, Interrupt, and Rollback, noting these features are currently only available in LangGraph Platform. [Durable Execution](https://langchain-ai.github.io/langgraph/concepts/durable_execution/): LLM should read this page when needing to understand durable execution in LangGraph, implementing workflow persistence, or troubleshooting workflow resumption. This page explains durable execution in LangGraph: how workflows save progress to resume later, requirements (checkpointers and thread IDs), determinism guidelines for consistent replay, using tasks to encapsulate non-deterministic operations, and approaches for pausing/resuming workflows. -[FAQ](https://langchain-ai.github.io/langgraph/concepts/faq/): LLM should read this page when needing to understand differences between LangGraph and LangChain, exploring deployment options for LangGraph Platform, or determining compatibility with various LLMs. FAQ covering LangGraph basics, comparisons with other frameworks, deployment options (free self-hosted, Cloud SaaS, BYOC, Enterprise), compatibility with different LLMs including OSS models, and feature differences between open-source LangGraph and proprietary LangGraph Platform. +[FAQ](https://langchain-ai.github.io/langgraph/concepts/faq/): LLM should read this page when needing to understand differences between LangGraph and LangChain, exploring deployment options for LangGraph Platform, or determining compatibility with various LLMs. FAQ covering LangGraph basics, comparisons with other frameworks, deployment options (free self-hosted, Cloud SaaS, Enterprise), compatibility with different LLMs including OSS models, and feature differences between open-source LangGraph and proprietary LangGraph Platform. [Functional API](https://langchain-ai.github.io/langgraph/concepts/functional_api/): LLM should read this page when implementing workflows with persistent state, adding human-in-the-loop features, or converting existing code to use LangGraph. The page documents LangGraph's Functional API, which allows adding persistence, memory, and human-in-the-loop capabilities with minimal code changes using @entrypoint and @task decorators, handling serialization requirements, state management, and common patterns for parallel execution and error handling. diff --git a/docs/docs/reference/index.md b/docs/docs/reference/index.md index b0d9b67c0..49b101769 100644 --- a/docs/docs/reference/index.md +++ b/docs/docs/reference/index.md @@ -16,4 +16,7 @@ search: Welcome to the LangGraph API reference! This reference provides detailed information about the LangGraph API, including classes, methods, and other components. -If you are new to LangGraph, we recommend starting with the [Quick Start](../tutorials/introduction.ipynb) in the Tutorials section. \ No newline at end of file +!!! tip + + If you are new to LangGraph, we recommend starting with [LangGraph basics](../concepts/why-langgraph.md). + diff --git a/docs/docs/stylesheets/navigation_title_ovverides.css b/docs/docs/stylesheets/navigation_title_ovverides.css new file mode 100644 index 000000000..4e7c937d7 --- /dev/null +++ b/docs/docs/stylesheets/navigation_title_ovverides.css @@ -0,0 +1,29 @@ +/* + * This file is used to override the navigation title for the LangGraph documentation. + * It is used to change the title of the first and second items in the navigation menu. + * The first item is the Guides page, and the second item is the Reference page. + */ + +.md-nav--primary > .md-nav__list > .md-nav__item:nth-child(1) > .md-nav__link .md-ellipsis { + visibility: hidden !important; + position: relative; +} + +.md-nav--primary > .md-nav__list > .md-nav__item:nth-child(1) > .md-nav__link .md-ellipsis::after { + content: "Home"; + visibility: visible; + position: absolute; + left: 0; +} + +.md-nav--primary > .md-nav__list > .md-nav__item:nth-child(2) > .md-nav__link .md-ellipsis { + visibility: hidden !important; + position: relative; +} + +.md-nav--primary > .md-nav__list > .md-nav__item:nth-child(2) > .md-nav__link .md-ellipsis::after { + content: "Home"; + visibility: visible; + position: absolute; + left: 0; +} \ No newline at end of file diff --git a/docs/docs/stylesheets/sticky_navigation.css b/docs/docs/stylesheets/sticky_navigation.css new file mode 100644 index 000000000..d16c8ea88 --- /dev/null +++ b/docs/docs/stylesheets/sticky_navigation.css @@ -0,0 +1,23 @@ +@media screen and (min-width: 76.25em) { + .md-nav__toggle ~ .md-nav > .md-nav__list { + overflow: clip; + } + + .md-nav__link { + margin: 0; + padding: 0.325em 0; + } + + .md-nav__link:has(+ .md-nav[aria-expanded="true"]) { + position: sticky; + top: 2em; + + z-index: 1; + background-color: var(--md-default-bg-color); + } + + .md-nav__link.md-nav__container { + z-index: 2 !important; + box-shadow: none !important; + } +} diff --git a/docs/docs/troubleshooting/errors/INVALID_LICENSE.md b/docs/docs/troubleshooting/errors/INVALID_LICENSE.md index de6426455..b65ee2f61 100644 --- a/docs/docs/troubleshooting/errors/INVALID_LICENSE.md +++ b/docs/docs/troubleshooting/errors/INVALID_LICENSE.md @@ -21,18 +21,19 @@ See the [local server](../../tutorials/langgraph-platform/local-server.md) docs If you would like a fast managed environment, consider the [Cloud SaaS](../../concepts/langgraph_cloud.md) deployment option. This requires no additional license key. -#### For Self-Hosted Lite (Limited Features) +#### For Standalone container (Self-Hosted Lite) -If your deployment is unlikely to see more than 1 million node executions per year and don't need Crons and other enterprise features, consider the [Self-Hosted Lite](../../concepts/deployment_options.md#self-hosted-lite) deployment option. +If your deployment is unlikely to see more than 1 million node executions per year and don't need Crons and other enterprise features, consider the [Self-Hosted Lite](../../concepts/deployment_options.md) deployment option. You can deploy with Self-Hosted Lite by setting a valid `LANGSMITH_API_KEY` in your environment (e.g., in the `.env` file referenced by `langgraph.json`) and building a Docker image. The API key must be associated with an account on a **Plus** plan or greater. -#### For Self-Hosted Enterprise (Full Features) +#### For Standalone Container (Enterprise) For full self-hosting, set the `LANGGRAPH_CLOUD_LICENSE_KEY` environment variable. If you are interested in an enterprise license key, please contact the LangChain support team. For more information on deployment options and their features, see the [Deployment Options](../../concepts/deployment_options.md) documentation. + ### Confirm credentials If you have confirmed that you would like to self-host LangGraph Platform, please verify your credentials. @@ -42,7 +43,7 @@ If you have confirmed that you would like to self-host LangGraph Platform, pleas 1. Confirm that you have provided a working `LANGSMITH_API_KEY` environment variable in your deployment environment or `.env` file 2. Confirm the provided API key is associated with an account on a **Plus** or **Enterprise** plan (or equivalent) -#### For Self-Hosted Enterprise +#### For Standalone Container (Enterprise) 1. Confirm that you have provided a working `LANGGRAPH_CLOUD_LICENSE_KEY` environment variable in your deployment environment or `.env` file 2. Confirm the key is still valid and has not surpassed its expiration date \ No newline at end of file diff --git a/docs/docs/tutorials/auth/add_auth_server.md b/docs/docs/tutorials/auth/add_auth_server.md index 3ae46d257..05c9fad6f 100644 --- a/docs/docs/tutorials/auth/add_auth_server.md +++ b/docs/docs/tutorials/auth/add_auth_server.md @@ -6,11 +6,11 @@ 2. [Resource Authorization](resource_auth.md) - Let users have private conversations 3. Production Auth (you are here) - Add real user accounts and validate using OAuth2 -In the [Making Conversations Private](resource_auth.md) tutorial, we added [resource authorization](../../concepts/auth.md#resource-authorization) to give users private conversations. However, we were still using hard-coded tokens for authentication, which is not secure. Now we'll replace those tokens with real user accounts using [OAuth2](../../concepts/auth.md#oauth2-authentication). +In the [Making Conversations Private](resource_auth.md) tutorial, we added [resource authorization](../../tutorials/auth/resource_auth.md) to give users private conversations. However, we were still using hard-coded tokens for authentication, which is not secure. Now we'll replace those tokens with real user accounts using [OAuth2](../auth/getting_started.md). -We'll keep the same [`Auth`](../../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth) object and [resource-level access control](../../concepts/auth.md#resource-level-access-control), but upgrade our authentication to use Supabase as our identity provider. While we use Supabase in this tutorial, the concepts apply to any OAuth2 provider. You'll learn how to: +We'll keep the same [`Auth`](../../cloud/reference/sdk/python_sdk_ref.md#langgraph_sdk.auth.Auth) object and [resource-level access control](../../concepts/auth.md#single-owner-resources), but upgrade our authentication to use Supabase as our identity provider. While we use Supabase in this tutorial, the concepts apply to any OAuth2 provider. You'll learn how to: -1. Replace test tokens with real [JWT tokens](../../concepts/auth.md#jwt-tokens) +1. Replace test tokens with real JWT tokens 2. Integrate with OAuth2 providers for secure user authentication 3. Handle user sessions and metadata while maintaining our existing authorization logic diff --git a/docs/docs/tutorials/auth/getting_started.md b/docs/docs/tutorials/auth/getting_started.md index acfe8e0bd..6669be1cb 100644 --- a/docs/docs/tutorials/auth/getting_started.md +++ b/docs/docs/tutorials/auth/getting_started.md @@ -11,7 +11,7 @@ This guide assumes basic familiarity with the following concepts: * [**Authentication & Access Control**](../../concepts/auth.md) - * [**LangGraph Platform**](../../concepts/index.md#langgraph-platform) + * [**LangGraph Platform**](../../concepts/langgraph_platform.md) !!! note "Python only" diff --git a/docs/docs/tutorials/auth/resource_auth.md b/docs/docs/tutorials/auth/resource_auth.md index f8e3e9edb..54e3b8322 100644 --- a/docs/docs/tutorials/auth/resource_auth.md +++ b/docs/docs/tutorials/auth/resource_auth.md @@ -17,7 +17,7 @@ In this tutorial, we will extend our chatbot to give each user their own private ## Understanding Resource Authorization -In the last tutorial, we controlled who could access our bot. But right now, any authenticated user can see everyone else's conversations! Let's fix that by adding [resource authorization](../../concepts/auth.md#resource-authorization). +In the last tutorial, we controlled who could access our bot. But right now, any authenticated user can see everyone else's conversations! Let's fix that by adding [resource authorization](../auth/resource_auth.md). First, make sure you have completed the [Basic Authentication](getting_started.md) tutorial and that your secure bot can be run without errors: diff --git a/docs/docs/tutorials/deployment.md b/docs/docs/tutorials/deployment.md index d2c7567e7..3da0dc0be 100644 --- a/docs/docs/tutorials/deployment.md +++ b/docs/docs/tutorials/deployment.md @@ -3,32 +3,20 @@ search: boost: 2 --- -# Deployment +# Deployment 🚀 -Get started deploying your LangGraph applications locally or on the cloud with -[LangGraph Platform](../concepts/langgraph_platform.md). +There are two free options for deploying LangGraph applications via the LangGraph Server: -## Get Started 🚀 {#quick-start} +- [Local](./langgraph-platform/local-server.md): Deploy for local testing and development. +- Self-Hosted Lite: A limited version of Standalone Container for deployments unlikely to see more that 1 million node executions per year and that do not need crons and other enterprise features. Self-Hosted Lite is free with a LangSmith API key. -- [LangGraph Server Quickstart](../tutorials/langgraph-platform/local-server.md): Launch a LangGraph server locally and interact with it using REST API and LangGraph Studio Web UI. -- [LangGraph Template Quickstart](../concepts/template_applications.md): Start building with LangGraph Platform using a template application. -- [Deploy with LangGraph Cloud Quickstart](../cloud/quick_start.md): Deploy a LangGraph app using LangGraph Cloud. +## Other deployment options +Additionally, you can deploy to production with [LangGraph Platform](../concepts/langgraph_platform.md): -## Deployment Options - -- Cloud SaaS(Beta): Connect to your GitHub repositories and deploy LangGraph Servers to LangChain's cloud. We manage everything. -- Self-Hosted Data Plane(Beta): Create deployments from the [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to your cloud. We manage the [control plane](../concepts/langgraph_control_plane.md), you manage the deployments. -- Self-Hosted Control Plane(Beta): Create deployments from a self-hosted [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to your cloud. You manage everything. +- [Cloud SaaS](../concepts/langgraph_cloud.md): Connect your GitHub repositories and deploy LangGraph Servers within LangChain's cloud. *We manage everything.* +- [Self-Hosted Data Plane(Beta)](../concepts/langgraph_self_hosted_data_plane.md): Create deployments from the [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to **your** cloud. *We manage the [control plane](../concepts/langgraph_control_plane.md). You manage the deployments.* +- [Self-Hosted Control Plane(Beta)](../concepts/langgraph_self_hosted_control_plane.md): Create deployments from a self-hosted [Control Plane UI](../concepts/langgraph_control_plane.md#control-plane-ui) and deploy LangGraph Servers to **your** cloud. *You manage everything.* - [Standalone Container](../concepts/langgraph_standalone_container.md): Deploy LangGraph Server Docker images however you like. -A quick comparison... - -| | **Cloud SaaS** | **Self-Hosted [Data Plane](../concepts/langgraph_data_plane.md)** | **Self-Hosted [Control Plane](../concepts/langgraph_control_plane.md)** | **Standalone Container** | -|----------------------|----------------|----------------------------|-------------------------------|--------------------------| -| **[Control Plane UI/API](../concepts/langgraph_control_plane.md)** | Yes | Yes | Yes | No | -| **CI/CD** | Managed internally by platform | Managed externally by you | Managed externally by you | Managed externally by you | -| **Data/Compute Residency** | LangChain’s cloud | Your cloud | Your cloud | Your cloud | -| **Required Permissions** | None | See details [here](). | See details [here](). | None | -| **LangSmith Compatibility** | Trace to LangSmith SaaS | Trace to LangSmith SaaS | Trace to Self-Hosted LangSmith | Optional tracing | -| **[Pricing](https://www.langchain.com/pricing-langgraph-platform)** | Plus | Enterprise | Enterprise | Developer | +For more information, see [Deployment options](../concepts/deployment_options.md) diff --git a/docs/docs/tutorials/get-started/1-build-basic-chatbot.md b/docs/docs/tutorials/get-started/1-build-basic-chatbot.md new file mode 100644 index 000000000..a71d88390 --- /dev/null +++ b/docs/docs/tutorials/get-started/1-build-basic-chatbot.md @@ -0,0 +1,204 @@ +# Build a basic chatbot + +In this tutorial, you will build a basic chatbot. This chatbot is the basis for the following series of tutorials where you will progressively add more sophisticated capabilities, and be introduced to key LangGraph concepts along the way. Let’s dive in! 🌟 + +## Prerequisites + +Before you start this tutorial, ensure you have access to a LLM that supports +tool-calling features, such as [OpenAI](https://platform.openai.com/api-keys), +[Anthropic](https://console.anthropic.com/settings/admin-keys), or +[Google Gemini](https://ai.google.dev/gemini-api/docs/api-key). + +## 1. Install packages + +Install the required packages: + +```bash +pip install -U langgraph langsmith +``` + +!!! tip + + Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph. For more information on how to get started, see [LangSmith docs](https://docs.smith.langchain.com). + +## 2. Create a `StateGraph` + +Now you can create a basic chatbot using LangGraph. This chatbot will respond directly to user messages. + +Start by creating a `StateGraph`. A `StateGraph` object defines the structure of our chatbot as a "state machine". We'll add `nodes` to represent the llm and functions our chatbot can call and `edges` to specify how the bot should transition between these functions. + +```python +from typing import Annotated + +from typing_extensions import TypedDict + +from langgraph.graph import StateGraph, START +from langgraph.graph.message import add_messages + + +class State(TypedDict): + # Messages have the type "list". The `add_messages` function + # in the annotation defines how this state key should be updated + # (in this case, it appends messages to the list, rather than overwriting them) + messages: Annotated[list, add_messages] + + +graph_builder = StateGraph(State) +``` + +Our graph can now handle two key tasks: + +1. Each `node` can receive the current `State` as input and output an update to the state. +2. Updates to `messages` will be appended to the existing list rather than overwriting it, thanks to the prebuilt [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/?h=add+messages#add_messages) function used with the `Annotated` syntax. + +------ + +!!! tip "Concept" + + When defining a graph, the first step is to define its `State`. The `State` includes the graph's schema and [reducer functions](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers) that handle state updates. In our example, `State` is a `TypedDict` with one key: `messages`. The [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages) reducer function is used to append new messages to the list instead of overwriting it. Keys without a reducer annotation will overwrite previous values. To learn more about state, reducers, and related concepts, see [LangGraph reference docs](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages). + +## 3. Add a node + +Next, add a "`chatbot`" node. **Nodes** represent units of work and are typically regular Python functions. + +Let's first select a chat model: + +{!snippets/chat_model_tabs.md!} + + + + +We can now incorporate the chat model into a simple node: + +```python + +def chatbot(state: State): + return {"messages": [llm.invoke(state["messages"])]} + + +# The first argument is the unique node name +# The second argument is the function or object that will be called whenever +# the node is used. +graph_builder.add_node("chatbot", chatbot) +``` + +**Notice** how the `chatbot` node function takes the current `State` as input and returns a dictionary containing an updated `messages` list under the key "messages". This is the basic pattern for all LangGraph node functions. + +The `add_messages` function in our `State` will append the LLM's response messages to whatever messages are already in the state. + +## 4. Add an `entry` point + +Add an `entry` point to tell the graph **where to start its work** each time it is run: + +```python +graph_builder.add_edge(START, "chatbot") +``` + +## 5. Compile the graph + +Before running the graph, we'll need to compile it. We can do so by calling `compile()` +on the graph builder. This creates a `CompiledGraph` we can invoke on our state. + +```python +graph = graph_builder.compile() +``` + +## 6. Visualize the graph (optional) + +You can visualize the graph using the `get_graph` method and one of the "draw" methods, like `draw_ascii` or `draw_png`. The `draw` methods each require additional dependencies. + +```python +from IPython.display import Image, display + +try: + display(Image(graph.get_graph().draw_mermaid_png())) +except Exception: + # This requires some extra dependencies and is optional + pass +``` + +![basic chatbot diagram](basic-chatbot.png) + + +## 7. Run the chatbot + +Now run the chatbot! + +!!! tip + + You can exit the chat loop at any time by typing `quit`, `exit`, or `q`. + +```python +def stream_graph_updates(user_input: str): + for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}): + for value in event.values(): + print("Assistant:", value["messages"][-1].content) + + +while True: + try: + user_input = input("User: ") + if user_input.lower() in ["quit", "exit", "q"]: + print("Goodbye!") + break + stream_graph_updates(user_input) + except: + # fallback if input() is not available + user_input = "What do you know about LangGraph?" + print("User: " + user_input) + stream_graph_updates(user_input) + break +``` + +``` +Assistant: LangGraph is a library designed to help build stateful multi-agent applications using language models. It provides tools for creating workflows and state machines to coordinate multiple AI agents or language model interactions. LangGraph is built on top of LangChain, leveraging its components while adding graph-based coordination capabilities. It's particularly useful for developing more complex, stateful AI applications that go beyond simple query-response interactions. +Goodbye! +``` + +**Congratulations!** You've built your first chatbot using LangGraph. This bot can engage in basic conversation by taking user input and generating responses using an LLM. You can inspect a [LangSmith Trace](https://smith.langchain.com/public/7527e308-9502-4894-b347-f34385740d5a/r) for the call above. + +Below is the full code for this tutorial: + +```python +from typing import Annotated + +from langchain.chat_models import init_chat_model +from typing_extensions import TypedDict + +from langgraph.graph import StateGraph, START +from langgraph.graph.message import add_messages + + +class State(TypedDict): + messages: Annotated[list, add_messages] + + +graph_builder = StateGraph(State) + + +llm = init_chat_model("anthropic:claude-3-5-sonnet-latest") + + +def chatbot(state: State): + return {"messages": [llm.invoke(state["messages"])]} + + +# The first argument is the unique node name +# The second argument is the function or object that will be called whenever +# the node is used. +graph_builder.add_node("chatbot", chatbot) +graph_builder.add_edge(START, "chatbot") +graph = graph_builder.compile() +``` + +## Next steps + +You may have noticed that the bot's knowledge is limited to what's in its training data. In the next part, we'll [add a web search tool](./2-add-tools.md) to expand the bot's knowledge and make it more capable. + + diff --git a/docs/docs/tutorials/get-started/2-add-tools.md b/docs/docs/tutorials/get-started/2-add-tools.md new file mode 100644 index 000000000..f63597560 --- /dev/null +++ b/docs/docs/tutorials/get-started/2-add-tools.md @@ -0,0 +1,330 @@ +# Add tools + +To handle queries you chatbot can't answer "from memory", integrate a web search tool. The chatbot can use this tool to find relevant information and provide better responses. + +!!! note + + This tutorial builds on [Build a basic chatbot](./1-build-basic-chatbot.md). + +## Prerequisites + +Before you start this tutorial, ensure you have the following: + +- An API key for the [Tavily Search Engine](https://python.langchain.com/docs/integrations/tools/tavily_search/). + +## 1. Install the search engine + +Install the requirements to use the [Tavily Search Engine](https://python.langchain.com/docs/integrations/tools/tavily_search/): + +```bash +pip install -U langchain-tavily +``` +## 2. Configure your environment + +Configure your environment with your search engine API key: + +```bash +_set_env("TAVILY_API_KEY") +``` + +``` +TAVILY_API_KEY: ········ +``` + +## 3. Define the tool + +Define the web search tool: + +```python +from langchain_tavily import TavilySearch + +tool = TavilySearch(max_results=2) +tools = [tool] +tool.invoke("What's a 'node' in LangGraph?") +``` + +The results are page summaries our chat bot can use to answer questions: + +``` +{'query': "What's a 'node' in LangGraph?", +'follow_up_questions': None, +'answer': None, +'images': [], +'results': [{'title': "Introduction to LangGraph: A Beginner's Guide - Medium", +'url': 'https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141', +'content': 'Stateful Graph: LangGraph revolves around the concept of a stateful graph, where each node in the graph represents a step in your computation, and the graph maintains a state that is passed around and updated as the computation progresses. LangGraph supports conditional edges, allowing you to dynamically determine the next node to execute based on the current state of the graph. We define nodes for classifying the input, handling greetings, and handling search queries. def classify_input_node(state): LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its power for their projects. Remember to pay attention to state management, conditional edges, and ensuring there are no dead-end nodes in your graph.', +'score': 0.7065353, +'raw_content': None}, +{'title': 'LangGraph Tutorial: What Is LangGraph and How to Use It?', +'url': 'https://www.datacamp.com/tutorial/langgraph-tutorial', +'content': 'LangGraph is a library within the LangChain ecosystem that provides a framework for defining, coordinating, and executing multiple LLM agents (or chains) in a structured and efficient manner. By managing the flow of data and the sequence of operations, LangGraph allows developers to focus on the high-level logic of their applications rather than the intricacies of agent coordination. Whether you need a chatbot that can handle various types of user requests or a multi-agent system that performs complex tasks, LangGraph provides the tools to build exactly what you need. LangGraph significantly simplifies the development of complex LLM applications by providing a structured framework for managing state and coordinating agent interactions.', +'score': 0.5008063, +'raw_content': None}], +'response_time': 1.38} +``` + +## 4. Define the graph + +For the `StateGraph` you created in the [first tutorial](./1-build-basic-chatbot.md#2-create-a-stategraph), add `bind_tools` on the LLM. This lets the LLM know the correct JSON format to use if it wants to use the search engine. + +Let's first select our LLM: + +{!snippets/chat_model_tabs.md!} + + + +We can now incorporate it into a `StateGraph`: + +```python hl_lines="15" +from typing import Annotated + +from typing_extensions import TypedDict + +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages + +class State(TypedDict): + messages: Annotated[list, add_messages] + +graph_builder = StateGraph(State) + +# Modification: tell the LLM which tools it can call +# highlight-next-line +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + return {"messages": [llm_with_tools.invoke(state["messages"])]} + +graph_builder.add_node("chatbot", chatbot) +``` + +## 5. Create a function to run the tools + +Now, create a function to run the tools if they are called. Do this by adding the tools to a new node called`BasicToolNode` that checks the most recent message in the state and calls tools if the message contains `tool_calls`. It relies on the LLM's `tool_calling` support, which is available in Anthropic, OpenAI, Google Gemini, and a number of other LLM providers. + +```python +import json + +from langchain_core.messages import ToolMessage + + +class BasicToolNode: + """A node that runs the tools requested in the last AIMessage.""" + + def __init__(self, tools: list) -> None: + self.tools_by_name = {tool.name: tool for tool in tools} + + def __call__(self, inputs: dict): + if messages := inputs.get("messages", []): + message = messages[-1] + else: + raise ValueError("No message found in input") + outputs = [] + for tool_call in message.tool_calls: + tool_result = self.tools_by_name[tool_call["name"]].invoke( + tool_call["args"] + ) + outputs.append( + ToolMessage( + content=json.dumps(tool_result), + name=tool_call["name"], + tool_call_id=tool_call["id"], + ) + ) + return {"messages": outputs} + + +tool_node = BasicToolNode(tools=[tool]) +graph_builder.add_node("tools", tool_node) +``` + +!!! note + + If you do not want to build this yourself in the future, you can use LangGraph's prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode). + +## 6. Define the `conditional_edges` + +With the tool node added, now you can define the `conditional_edges`. + +**Edges** route the control flow from one node to the next. **Conditional edges** start from a single node and usually contain "if" statements to route to different nodes depending on the current graph state. These functions receive the current graph `state` and return a string or list of strings indicating which node(s) to call next. + +Next, define a router function called `route_tools` that checks for `tool_calls` in the chatbot's output. Provide this function to the graph by calling `add_conditional_edges`, which tells the graph that whenever the `chatbot` node completes to check this function to see where to go next. + +The condition will route to `tools` if tool calls are present and `END` if not. Because the condition can return `END`, you do not need to explicitly set a `finish_point` this time. + +```python +def route_tools( + state: State, +): + """ + Use in the conditional_edge to route to the ToolNode if the last message + has tool calls. Otherwise, route to the end. + """ + if isinstance(state, list): + ai_message = state[-1] + elif messages := state.get("messages", []): + ai_message = messages[-1] + else: + raise ValueError(f"No messages found in input state to tool_edge: {state}") + if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0: + return "tools" + return END + + +# The `tools_condition` function returns "tools" if the chatbot asks to use a tool, and "END" if +# it is fine directly responding. This conditional routing defines the main agent loop. +graph_builder.add_conditional_edges( + "chatbot", + route_tools, + # The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node + # It defaults to the identity function, but if you + # want to use a node named something else apart from "tools", + # You can update the value of the dictionary to something else + # e.g., "tools": "my_tools" + {"tools": "tools", END: END}, +) +# Any time a tool is called, we return to the chatbot to decide the next step +graph_builder.add_edge("tools", "chatbot") +graph_builder.add_edge(START, "chatbot") +graph = graph_builder.compile() +``` + +!!! note + + You can replace this with the prebuilt [tools_condition](https://langchain-ai.github.io/langgraph/reference/prebuilt/#tools_condition) to be more concise. + +## 7. Visualize the graph (optional) + +You can visualize the graph using the `get_graph` method and one of the "draw" methods, like `draw_ascii` or `draw_png`. The `draw` methods each require additional dependencies. + +```python +from IPython.display import Image, display + +try: + display(Image(graph.get_graph().draw_mermaid_png())) +except Exception: + # This requires some extra dependencies and is optional + pass +``` + +![chatbot-with-tools-diagram](chatbot-with-tools.png) + +## 8. Ask the bot questions + +Now you can ask the chatbot questions outside its training data: + +```python +def stream_graph_updates(user_input: str): + for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}): + for value in event.values(): + print("Assistant:", value["messages"][-1].content) + +while True: + try: + user_input = input("User: ") + if user_input.lower() in ["quit", "exit", "q"]: + print("Goodbye!") + break + + stream_graph_updates(user_input) + except: + # fallback if input() is not available + user_input = "What do you know about LangGraph?" + print("User: " + user_input) + stream_graph_updates(user_input) + break +``` + +``` +Assistant: [{'text': "To provide you with accurate and up-to-date information about LangGraph, I'll need to search for the latest details. Let me do that for you.", 'type': 'text'}, {'id': 'toolu_01Q588CszHaSvvP2MxRq9zRD', 'input': {'query': 'LangGraph AI tool information'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}] +Assistant: [{"url": "https://www.langchain.com/langgraph", "content": "LangGraph sets the foundation for how we can build and scale AI workloads \u2014 from conversational agents, complex task automation, to custom LLM-backed experiences that 'just work'. The next chapter in building complex production-ready features with LLMs is agentic, and with LangGraph and LangSmith, LangChain delivers an out-of-the-box solution ..."}, {"url": "https://github.com/langchain-ai/langgraph", "content": "Overview. LangGraph is a library for building stateful, multi-actor applications with LLMs, used to create agent and multi-agent workflows. Compared to other LLM frameworks, it offers these core benefits: cycles, controllability, and persistence. LangGraph allows you to define flows that involve cycles, essential for most agentic architectures ..."}] +Assistant: Based on the search results, I can provide you with information about LangGraph: + +1. Purpose: + LangGraph is a library designed for building stateful, multi-actor applications with Large Language Models (LLMs). It's particularly useful for creating agent and multi-agent workflows. + +2. Developer: + LangGraph is developed by LangChain, a company known for its tools and frameworks in the AI and LLM space. + +3. Key Features: + - Cycles: LangGraph allows the definition of flows that involve cycles, which is essential for most agentic architectures. + - Controllability: It offers enhanced control over the application flow. + - Persistence: The library provides ways to maintain state and persistence in LLM-based applications. + +4. Use Cases: + LangGraph can be used for various applications, including: + - Conversational agents + - Complex task automation + - Custom LLM-backed experiences + +5. Integration: + LangGraph works in conjunction with LangSmith, another tool by LangChain, to provide an out-of-the-box solution for building complex, production-ready features with LLMs. + +6. Significance: +... + LangGraph is noted to offer unique benefits compared to other LLM frameworks, particularly in its ability to handle cycles, provide controllability, and maintain persistence. + +LangGraph appears to be a significant tool in the evolving landscape of LLM-based application development, offering developers new ways to create more complex, stateful, and interactive AI systems. +Goodbye! +Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings... +``` + +## 9. Use prebuilts + +For ease of use, adjust your code to replace the following with LangGraph prebuilt components. These have built in functionality like parallel API execution. + +- `BasicToolNode` is replaced with the prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode) +- `route_tools` is replaced with the prebuilt [tools_condition](https://langchain-ai.github.io/langgraph/reference/prebuilt/#tools_condition) + +{!snippets/chat_model_tabs.md!} + + +```python hl_lines="25 30" +from typing import Annotated + +from langchain_tavily import TavilySearch +from langchain_core.messages import BaseMessage +from typing_extensions import TypedDict + +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.prebuilt import ToolNode, tools_condition + +class State(TypedDict): + messages: Annotated[list, add_messages] + +graph_builder = StateGraph(State) + +tool = TavilySearch(max_results=2) +tools = [tool] +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + return {"messages": [llm_with_tools.invoke(state["messages"])]} + +graph_builder.add_node("chatbot", chatbot) + +tool_node = ToolNode(tools=[tool]) +graph_builder.add_node("tools", tool_node) + +graph_builder.add_conditional_edges( + "chatbot", + tools_condition, +) +# Any time a tool is called, we return to the chatbot to decide the next step +graph_builder.add_edge("tools", "chatbot") +graph_builder.add_edge(START, "chatbot") +graph = graph_builder.compile() +``` + +**Congratulations!** You've created a conversational agent in LangGraph that can use a search engine to retrieve updated information when needed. Now it can handle a wider range of user queries. To inspect all the steps your agent just took, check out this [LangSmith trace](https://smith.langchain.com/public/4fbd7636-25af-4638-9587-5a02fdbb0172/r). + +## Next steps + +The chatbot cannot remember past interactions on its own, which limits its ability to have coherent, multi-turn conversations. In the next part, you will [add **memory**](./3-add-memory.md) to address this. diff --git a/docs/docs/tutorials/get-started/3-add-memory.md b/docs/docs/tutorials/get-started/3-add-memory.md new file mode 100644 index 000000000..854132f2c --- /dev/null +++ b/docs/docs/tutorials/get-started/3-add-memory.md @@ -0,0 +1,209 @@ +# Add memory + +The chatbot can now [use tools](./2-add-tools.md) to answer user questions, but it does not remember the context of previous interactions. This limits its ability to have coherent, multi-turn conversations. + +LangGraph solves this problem through **persistent checkpointing**. If you provide a `checkpointer` when compiling the graph and a `thread_id` when calling your graph, LangGraph automatically saves the state after each step. When you invoke the graph again using the same `thread_id`, the graph loads its saved state, allowing the chatbot to pick up where it left off. + +We will see later that **checkpointing** is _much_ more powerful than simple chat memory - it lets you save and resume complex state at any time for error recovery, human-in-the-loop workflows, time travel interactions, and more. But first, let's add checkpointing to enable multi-turn conversations. + +!!! note + + This tutorial builds on [Add tools](./2-add-tools.md). + +## 1. Create a `MemorySaver` checkpointer + +Create a `MemorySaver` checkpointer: + +``` python +from langgraph.checkpoint.memory import MemorySaver + +memory = MemorySaver() +``` + +This is in-memory checkpointer, which is convenient for the tutorial. However, in a production application, you would likely change this to use `SqliteSaver` or `PostgresSaver` and connect a database. + +## 2. Compile the graph + +Compile the graph with the provided checkpointer, which will checkpoint the `State` as the graph works through each node: + +``` python +graph = graph_builder.compile(checkpointer=memory) +``` + +``` python +from IPython.display import Image, display + +try: + display(Image(graph.get_graph().draw_mermaid_png())) +except Exception: + # This requires some extra dependencies and is optional + pass +``` + +## 3. Interact with your chatbot + +Now you can interact with your bot! + +1. Pick a thread to use as the key for this conversation. + + ```python + config = {"configurable": {"thread_id": "1"}} + ``` + +2. Call your chatbot: + + ```python + user_input = "Hi there! My name is Will." + + # The config is the **second positional argument** to stream() or invoke()! + events = graph.stream( + {"messages": [{"role": "user", "content": user_input}]}, + config, + stream_mode="values", + ) + for event in events: + event["messages"][-1].pretty_print() + ``` + + ``` + ================================ Human Message ================================= + + Hi there! My name is Will. + ================================== Ai Message ================================== + + Hello Will! It's nice to meet you. How can I assist you today? Is there anything specific you'd like to know or discuss? + ``` + + !!! note + + The config was provided as the **second positional argument** when calling our graph. It importantly is _not_ nested within the graph inputs (`{'messages': []}`). + +## 4. Ask a follow up question + +Ask a follow up question: + +```python +user_input = "Remember my name?" + +# The config is the **second positional argument** to stream() or invoke()! +events = graph.stream( + {"messages": [{"role": "user", "content": user_input}]}, + config, + stream_mode="values", +) +for event in events: + event["messages"][-1].pretty_print() +``` + +``` +================================ Human Message ================================= + +Remember my name? +================================== Ai Message ================================== + +Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks. +``` + +**Notice** that we aren't using an external list for memory: it's all handled by the checkpointer! You can inspect the full execution in this [LangSmith trace](https://smith.langchain.com/public/29ba22b5-6d40-4fbe-8d27-b369e3329c84/r) to see what's going on. + +Don't believe me? Try this using a different config. + +```python +# The only difference is we change the `thread_id` here to "2" instead of "1" +events = graph.stream( + {"messages": [{"role": "user", "content": user_input}]}, + # highlight-next-line + {"configurable": {"thread_id": "2"}}, + stream_mode="values", +) +for event in events: + event["messages"][-1].pretty_print() +``` + +``` +================================ Human Message ================================= + +Remember my name? +================================== Ai Message ================================== + +I apologize, but I don't have any previous context or memory of your name. As an AI assistant, I don't retain information from past conversations. Each interaction starts fresh. Could you please tell me your name so I can address you properly in this conversation? +``` + +**Notice** that the **only** change we've made is to modify the `thread_id` in the config. See this call's [LangSmith trace](https://smith.langchain.com/public/51a62351-2f0a-4058-91cc-9996c5561428/r) for comparison. + +## 5. Inspect the state + +By now, we have made a few checkpoints across two different threads. But what goes into a checkpoint? To inspect a graph's `state` for a given config at any time, call `get_state(config)`. + +```python +snapshot = graph.get_state(config) +snapshot +``` + +``` +StateSnapshot(values={'messages': [HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='8c1ca919-c553-4ebf-95d4-b59a2d61e078'), AIMessage(content="Hello Will! It's nice to meet you. How can I assist you today? Is there anything specific you'd like to know or discuss?", additional_kwargs={}, response_metadata={'id': 'msg_01WTQebPhNwmMrmmWojJ9KXJ', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 405, 'output_tokens': 32}}, id='run-58587b77-8c82-41e6-8a90-d62c444a261d-0', usage_metadata={'input_tokens': 405, 'output_tokens': 32, 'total_tokens': 437}), HumanMessage(content='Remember my name?', additional_kwargs={}, response_metadata={}, id='daba7df6-ad75-4d6b-8057-745881cea1ca'), AIMessage(content="Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.", additional_kwargs={}, response_metadata={'id': 'msg_01E41KitY74HpENRgXx94vag', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 444, 'output_tokens': 58}}, id='run-ffeaae5c-4d2d-4ddb-bd59-5d5cbf2a5af8-0', usage_metadata={'input_tokens': 444, 'output_tokens': 58, 'total_tokens': 502})]}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef7d06e-93e0-6acc-8004-f2ac846575d2'}}, metadata={'source': 'loop', 'writes': {'chatbot': {'messages': [AIMessage(content="Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.", additional_kwargs={}, response_metadata={'id': 'msg_01E41KitY74HpENRgXx94vag', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 444, 'output_tokens': 58}}, id='run-ffeaae5c-4d2d-4ddb-bd59-5d5cbf2a5af8-0', usage_metadata={'input_tokens': 444, 'output_tokens': 58, 'total_tokens': 502})]}}, 'step': 4, 'parents': {}}, created_at='2024-09-27T19:30:10.820758+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef7d06e-859f-6206-8003-e1bd3c264b8f'}}, tasks=()) +``` + +``` +snapshot.next # (since the graph ended this turn, `next` is empty. If you fetch a state from within a graph invocation, next tells which node will execute next) +``` + +The snapshot above contains the current state values, corresponding config, and the `next` node to process. In our case, the graph has reached an `END` state, so `next` is empty. + +**Congratulations!** Your chatbot can now maintain conversation state across sessions thanks to LangGraph's checkpointing system. This opens up exciting possibilities for more natural, contextual interactions. LangGraph's checkpointing even handles **arbitrarily complex graph states**, which is much more expressive and powerful than simple chat memory. + +Check out the code snippet below to review the graph from this tutorial: + +{!snippets/chat_model_tabs.md!} + + + +```python +from typing import Annotated + +from langchain.chat_models import init_chat_model +from langchain_tavily import TavilySearch +from langchain_core.messages import BaseMessage +from typing_extensions import TypedDict + +from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import StateGraph +from langgraph.graph.message import add_messages +from langgraph.prebuilt import ToolNode, tools_condition + +class State(TypedDict): + messages: Annotated[list, add_messages] + +graph_builder = StateGraph(State) + +tool = TavilySearch(max_results=2) +tools = [tool] +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + return {"messages": [llm_with_tools.invoke(state["messages"])]} + +graph_builder.add_node("chatbot", chatbot) + +tool_node = ToolNode(tools=[tool]) +graph_builder.add_node("tools", tool_node) + +graph_builder.add_conditional_edges( + "chatbot", + tools_condition, +) +graph_builder.add_edge("tools", "chatbot") +graph_builder.set_entry_point("chatbot") +memory = MemorySaver() +graph = graph_builder.compile(checkpointer=memory) +``` + +## Next steps + +In the next tutorial, you will [add human-in-the-loop to the chatbot](./4-human-in-the-loop.md) to handle situations where it may need guidance or verification before proceeding. \ No newline at end of file diff --git a/docs/docs/tutorials/get-started/4-human-in-the-loop.md b/docs/docs/tutorials/get-started/4-human-in-the-loop.md new file mode 100644 index 000000000..9cb0b3a76 --- /dev/null +++ b/docs/docs/tutorials/get-started/4-human-in-the-loop.md @@ -0,0 +1,277 @@ +# Add human-in-the-loop controls + +Agents can be unreliable and may need human input to successfully accomplish tasks. Similarly, for some actions, you may want to require human approval before running to ensure that everything is running as intended. + +LangGraph's [persistence](../../concepts/persistence.md) layer supports **human-in-the-loop** workflows, allowing execution to pause and resume based on user feedback. The primary interface to this functionality is the [`interrupt`](../../concepts/human_in_the_loop.md#interrupt) function. Calling `interrupt` inside a node will pause execution. Execution can be resumed, together with new input from a human, by passing in a [Command](../../concepts/human_in_the_loop.md#the-command-primitive). `interrupt` is ergonomically similar to Python's built-in `input()`, [with some caveats](../../concepts/human_in_the_loop.md#interrupt). + +!!! note + + This tutorial builds on [Add memory](./3-add-memory.md). + +## 1. Add the `human_assistance` tool + +Starting with the existing code from the [Add memory to the chatbot](./3-add-memory.md) tutorial, add the `human_assistance` tool to the chatbot. This tool uses `interrupt` to receive information from a human. + +Let's first select a chat model: + +{!snippets/chat_model_tabs.md!} + + + +We can now incorporate it into our `StateGraph` with an additional tool: + +``` python hl_lines="12 19 20 21 22 23" +from typing import Annotated + +from langchain_tavily import TavilySearch +from langchain_core.tools import tool +from typing_extensions import TypedDict + +from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.prebuilt import ToolNode, tools_condition + +from langgraph.types import Command, interrupt + +class State(TypedDict): + messages: Annotated[list, add_messages] + +graph_builder = StateGraph(State) + +@tool +def human_assistance(query: str) -> str: + """Request assistance from a human.""" + human_response = interrupt({"query": query}) + return human_response["data"] + +tool = TavilySearch(max_results=2) +tools = [tool, human_assistance] +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + message = llm_with_tools.invoke(state["messages"]) + # Because we will be interrupting during tool execution, + # we disable parallel tool calling to avoid repeating any + # tool invocations when we resume. + assert len(message.tool_calls) <= 1 + return {"messages": [message]} + +graph_builder.add_node("chatbot", chatbot) + +tool_node = ToolNode(tools=tools) +graph_builder.add_node("tools", tool_node) + +graph_builder.add_conditional_edges( + "chatbot", + tools_condition, +) +graph_builder.add_edge("tools", "chatbot") +graph_builder.add_edge(START, "chatbot") +``` + +!!! tip + + For more information and examples of human-in-the-loop workflows, see [Human-in-the-loop](../../concepts/human_in_the_loop.md). This includes how to [review and edit tool calls](../../how-tos/human_in_the_loop/review-tool-calls.ipynb) before they are executed. + +## 2. Compile the graph + +We compile the graph with a checkpointer, as before: + +```python +memory = MemorySaver() + +graph = graph_builder.compile(checkpointer=memory) +``` + +## 3. Visualize the graph (optional) + +Visualizing the graph, you get the same layout as before – just with the added tool! + +``` python +from IPython.display import Image, display + +try: + display(Image(graph.get_graph().draw_mermaid_png())) +except Exception: + # This requires some extra dependencies and is optional + pass +``` + +![chatbot-with-tools-diagram](chatbot-with-tools.png) + +## 4. Prompt the chatbot + +Now, prompt the chatbot with a question that will engage the new `human_assistance` tool: + +```python +user_input = "I need some expert guidance for building an AI agent. Could you request assistance for me?" +config = {"configurable": {"thread_id": "1"}} + +events = graph.stream( + {"messages": [{"role": "user", "content": user_input}]}, + config, + stream_mode="values", +) +for event in events: + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================ Human Message ================================= + +I need some expert guidance for building an AI agent. Could you request assistance for me? +================================== Ai Message ================================== + +[{'text': "Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}] +Tool Calls: + human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW) + Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW + Args: + query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic? +``` + +The chatbot generated a tool call, but then execution has been interrupted. If you inspect the graph state, you see that it stopped at the tools node: + +```python +snapshot = graph.get_state(config) +snapshot.next +``` + +``` +('tools',) +``` + +!!! info Additional information + + Take a closer look at the `human_assistance` tool: + + ```python + @tool + def human_assistance(query: str) -> str: + """Request assistance from a human.""" + human_response = interrupt({"query": query}) + return human_response["data"] + ``` + + Similar to Python's built-in `input()` function, calling `interrupt` inside the tool will pause execution. Progress is persisted based on the [checkpointer](../../concepts/persistence.md#checkpointer-libraries); so if it is persisting with Postgres, it can resume at any time as long as the database is alive. In this example, it is persisting with the in-memory checkpointer and can resume any time if the Python kernel is running. + +## 5. Resume execution + +To resume execution, pass a [`Command`](../../concepts/human_in_the_loop.md#the-command-primitive) object containing data expected by the tool. The format of this data can be customized based on needs. For this example, use a dict with a key `"data"`: + +``` python +human_response = ( + "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent." + " It's much more reliable and extensible than simple autonomous agents." +) + +human_command = Command(resume={"data": human_response}) + +events = graph.stream(human_command, config, stream_mode="values") +for event in events: + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================== Ai Message ================================== + +[{'text': "Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}] +Tool Calls: + human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW) + Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW + Args: + query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic? +================================= Tool Message ================================= +Name: human_assistance + +We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents. +================================== Ai Message ================================== + +Thank you for your patience. I've received some expert advice regarding your request for guidance on building an AI agent. Here's what the experts have suggested: + +The experts recommend that you look into LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents. + +LangGraph is likely a framework or library designed specifically for creating AI agents with advanced capabilities. Here are a few points to consider based on this recommendation: + +1. Reliability: The experts emphasize that LangGraph is more reliable than simpler autonomous agent approaches. This could mean it has better stability, error handling, or consistent performance. + +2. Extensibility: LangGraph is described as more extensible, which suggests that it probably offers a flexible architecture that allows you to easily add new features or modify existing ones as your agent's requirements evolve. + +3. Advanced capabilities: Given that it's recommended over "simple autonomous agents," LangGraph likely provides more sophisticated tools and techniques for building complex AI agents. +... +2. Look for tutorials or guides specifically focused on building AI agents with LangGraph. +3. Check if there are any community forums or discussion groups where you can ask questions and get support from other developers using LangGraph. + +If you'd like more specific information about LangGraph or have any questions about this recommendation, please feel free to ask, and I can request further assistance from the experts. +Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings... +``` + +The input has been received and processed as a tool message. Review this call's [LangSmith trace](https://smith.langchain.com/public/9f0f87e3-56a7-4dde-9c76-b71675624e91/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that our chatbot can continue where it left off. + +**Congratulations!** You've used an `interrupt` to add human-in-the-loop execution to your chatbot, allowing for human oversight and intervention when needed. This opens up the potential UIs you can create with your AI systems. Since you have already added a **checkpointer**, as long as the underlying persistence layer is running, the graph can be paused **indefinitely** and resumed at any time as if nothing had happened. + +Check out the code snippet below to review the graph from this tutorial: + +{!snippets/chat_model_tabs.md!} + +```python +from typing import Annotated + +from langchain_tavily import TavilySearch +from langchain_core.tools import tool +from typing_extensions import TypedDict + +from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.prebuilt import ToolNode, tools_condition +from langgraph.types import Command, interrupt + +class State(TypedDict): + messages: Annotated[list, add_messages] + +graph_builder = StateGraph(State) + +@tool +def human_assistance(query: str) -> str: + """Request assistance from a human.""" + human_response = interrupt({"query": query}) + return human_response["data"] + +tool = TavilySearch(max_results=2) +tools = [tool, human_assistance] +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + message = llm_with_tools.invoke(state["messages"]) + assert(len(message.tool_calls) <= 1) + return {"messages": [message]} + +graph_builder.add_node("chatbot", chatbot) + +tool_node = ToolNode(tools=tools) +graph_builder.add_node("tools", tool_node) + +graph_builder.add_conditional_edges( + "chatbot", + tools_condition, +) +graph_builder.add_edge("tools", "chatbot") +graph_builder.add_edge(START, "chatbot") + +memory = MemorySaver() +graph = graph_builder.compile(checkpointer=memory) +``` + +## Next steps + +So far, the tutorial examples have relied on a simple state with one entry: a list of messages. You can go far with this simple state, but if you want to define complex behavior without relying on the message list, you can [add additional fields to the state](./5-customize-state.md). \ No newline at end of file diff --git a/docs/docs/tutorials/get-started/5-customize-state.md b/docs/docs/tutorials/get-started/5-customize-state.md new file mode 100644 index 000000000..d887e7bfd --- /dev/null +++ b/docs/docs/tutorials/get-started/5-customize-state.md @@ -0,0 +1,311 @@ +# Customize state + +In this tutorial, you will add additional fields to the state to define complex behavior without relying on the message list. The chatbot will use its search tool to find specific information and forward them to a human for review. + +!!! note + + This tutorial builds on [Add human-in-the-loop controls](./4-human-in-the-loop.md). + +## 1. Add keys to the state + +Update the chatbot to research the birthday of an entity by adding `name` and `birthday` keys to the state: + +```python +from typing import Annotated + +from typing_extensions import TypedDict + +from langgraph.graph.message import add_messages + + +class State(TypedDict): + messages: Annotated[list, add_messages] + # highlight-next-line + name: str + # highlight-next-line + birthday: str +``` + +Adding this information to the state makes it easily accessible by other graph nodes (like a downstream node that stores or processes the information), as well as the graph's persistence layer. + +## 2. Update the state inside the tool + +Now, populate the state keys inside of the `human_assistance` tool. This allows a human to review the information before it is stored in the state. Use [`Command`](../../concepts/low_level.md#using-inside-tools) to issue a state update from inside the tool. + +``` python +from langchain_core.messages import ToolMessage +from langchain_core.tools import InjectedToolCallId, tool + +from langgraph.types import Command, interrupt + +@tool +# Note that because we are generating a ToolMessage for a state update, we +# generally require the ID of the corresponding tool call. We can use +# LangChain's InjectedToolCallId to signal that this argument should not +# be revealed to the model in the tool's schema. +def human_assistance( + name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId] +) -> str: + """Request assistance from a human.""" + human_response = interrupt( + { + "question": "Is this correct?", + "name": name, + "birthday": birthday, + }, + ) + # If the information is correct, update the state as-is. + if human_response.get("correct", "").lower().startswith("y"): + verified_name = name + verified_birthday = birthday + response = "Correct" + # Otherwise, receive information from the human reviewer. + else: + verified_name = human_response.get("name", name) + verified_birthday = human_response.get("birthday", birthday) + response = f"Made a correction: {human_response}" + + # This time we explicitly update the state with a ToolMessage inside + # the tool. + state_update = { + "name": verified_name, + "birthday": verified_birthday, + "messages": [ToolMessage(response, tool_call_id=tool_call_id)], + } + # We return a Command object in the tool to update our state. + return Command(update=state_update) +``` + +The rest of the graph stays the same. + +## 3. Prompt the chatbot + +Prompt the chatbot to look up the "birthday" of the LangGraph library and direct the chatbot to reach out to the `human_assistance` tool once it has the required information. By setting `name` and `birthday` in the arguments for the tool, you force the chatbot to generate proposals for these fields. + +```python +user_input = ( + "Can you look up when LangGraph was released? " + "When you have the answer, use the human_assistance tool for review." +) +config = {"configurable": {"thread_id": "1"}} + +events = graph.stream( + {"messages": [{"role": "user", "content": user_input}]}, + config, + stream_mode="values", +) +for event in events: + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================ Human Message ================================= + +Can you look up when LangGraph was released? When you have the answer, use the human_assistance tool for review. +================================== Ai Message ================================== + +[{'text': "Certainly! I'll start by searching for information about LangGraph's release date using the Tavily search function. Then, I'll use the human_assistance tool for review.", 'type': 'text'}, {'id': 'toolu_01JoXQPgTVJXiuma8xMVwqAi', 'input': {'query': 'LangGraph release date'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}] +Tool Calls: + tavily_search_results_json (toolu_01JoXQPgTVJXiuma8xMVwqAi) + Call ID: toolu_01JoXQPgTVJXiuma8xMVwqAi + Args: + query: LangGraph release date +================================= Tool Message ================================= +Name: tavily_search_results_json + +[{"url": "https://blog.langchain.dev/langgraph-cloud/", "content": "We also have a new stable release of LangGraph. By LangChain 6 min read Jun 27, 2024 (Oct '24) Edit: Since the launch of LangGraph Cloud, we now have multiple deployment options alongside LangGraph Studio - which now fall under LangGraph Platform. LangGraph Cloud is synonymous with our Cloud SaaS deployment option."}, {"url": "https://changelog.langchain.com/announcements/langgraph-cloud-deploy-at-scale-monitor-carefully-iterate-boldly", "content": "LangChain - Changelog | ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain Changelog Sign up for our newsletter to stay up to date DATE: The LangChain Team LangGraph LangGraph Cloud ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor carefully, iterate boldly DATE: June 27, 2024 AUTHOR: The LangChain Team LangGraph Cloud is now in closed beta, offering scalable, fault-tolerant deployment for LangGraph agents. LangGraph Cloud also includes a new playground-like studio for debugging agent failure modes and quick iteration: Join the waitlist today for LangGraph Cloud. And to learn more, read our blog post announcement or check out our docs. Subscribe By clicking subscribe, you accept our privacy policy and terms and conditions."}] +================================== Ai Message ================================== + +[{'text': "Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Cloud was announced. However, the search results don't provide a specific release date for the original LangGraph. \n\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}] +Tool Calls: + human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN) + Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN + Args: + name: Assistant + birthday: 2023-01-01 +``` + +We've hit the `interrupt` in the `human_assistance` tool again. + +## 4. Add human assistance + +The chatbot failed to identify the correct date, so supply it with information: + +```python +human_command = Command( + resume={ + "name": "LangGraph", + "birthday": "Jan 17, 2024", + }, +) + +events = graph.stream(human_command, config, stream_mode="values") +for event in events: + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================== Ai Message ================================== + +[{'text': "Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Cloud was announced. However, the search results don't provide a specific release date for the original LangGraph. \n\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}] +Tool Calls: + human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN) + Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN + Args: + name: Assistant + birthday: 2023-01-01 +================================= Tool Message ================================= +Name: human_assistance + +Made a correction: {'name': 'LangGraph', 'birthday': 'Jan 17, 2024'} +================================== Ai Message ================================== + +Thank you for the human assistance. I can now provide you with the correct information about LangGraph's release date. + +LangGraph was initially released on January 17, 2024. This information comes from the human assistance correction, which is more accurate than the search results I initially found. + +To summarize: +1. LangGraph's original release date: January 17, 2024 +2. LangGraph Cloud announcement: June 27, 2024 + +It's worth noting that LangGraph had been in development and use for some time before the LangGraph Cloud announcement, but the official initial release of LangGraph itself was on January 17, 2024. +``` + +Note that these fields are now reflected in the state: + +```python +snapshot = graph.get_state(config) + +{k: v for k, v in snapshot.values.items() if k in ("name", "birthday")} +``` + +``` +{'name': 'LangGraph', 'birthday': 'Jan 17, 2024'} +``` + +This makes them easily accessible to downstream nodes (e.g., a node that further processes or stores the information). + +## 5. Manually update the state + +LangGraph gives a high degree of control over the application state. For instance, at any point (including when interrupted), you can manually override a key using `graph.update_state`: + +``` python +graph.update_state(config, {"name": "LangGraph (library)"}) +``` + +``` +{'configurable': {'thread_id': '1', + 'checkpoint_ns': '', + 'checkpoint_id': '1efd4ec5-cf69-6352-8006-9278f1730162'}} +``` + +## 6. View the new value + +If you call `graph.get_state`, you can see the new value is reflected: + +``` python +snapshot = graph.get_state(config) + +{k: v for k, v in snapshot.values.items() if k in ("name", "birthday")} +``` + +``` +{'name': 'LangGraph (library)', 'birthday': 'Jan 17, 2024'} +``` + +Manual state updates will [generate a trace](https://smith.langchain.com/public/7ebb7827-378d-49fe-9f6c-5df0e90086c8/r) in LangSmith. If desired, they can also be used to [control human-in-the-loop workflows](../../how-tos/human_in_the_loop/edit-graph-state.md). Use of the `interrupt` function is generally recommended instead, as it allows data to be transmitted in a human-in-the-loop interaction independently of state updates. + +**Congratulations!** You've added custom keys to the state to facilitate a more complex workflow, and learned how to generate state updates from inside tools. + +Check out the code snippet below to review the graph from this tutorial: + +{!snippets/chat_model_tabs.md!} + + + +```python +from typing import Annotated + +from langchain_tavily import TavilySearch +from langchain_core.messages import ToolMessage +from langchain_core.tools import InjectedToolCallId, tool +from typing_extensions import TypedDict + +from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.prebuilt import ToolNode, tools_condition +from langgraph.types import Command, interrupt + +class State(TypedDict): + messages: Annotated[list, add_messages] + name: str + birthday: str + +@tool +def human_assistance( + name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId] +) -> str: + """Request assistance from a human.""" + human_response = interrupt( + { + "question": "Is this correct?", + "name": name, + "birthday": birthday, + }, + ) + if human_response.get("correct", "").lower().startswith("y"): + verified_name = name + verified_birthday = birthday + response = "Correct" + else: + verified_name = human_response.get("name", name) + verified_birthday = human_response.get("birthday", birthday) + response = f"Made a correction: {human_response}" + + state_update = { + "name": verified_name, + "birthday": verified_birthday, + "messages": [ToolMessage(response, tool_call_id=tool_call_id)], + } + return Command(update=state_update) + + +tool = TavilySearch(max_results=2) +tools = [tool, human_assistance] +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + message = llm_with_tools.invoke(state["messages"]) + assert(len(message.tool_calls) <= 1) + return {"messages": [message]} + +graph_builder = StateGraph(State) +graph_builder.add_node("chatbot", chatbot) + +tool_node = ToolNode(tools=tools) +graph_builder.add_node("tools", tool_node) + +graph_builder.add_conditional_edges( + "chatbot", + tools_condition, +) +graph_builder.add_edge("tools", "chatbot") +graph_builder.add_edge(START, "chatbot") + +memory = MemorySaver() +graph = graph_builder.compile(checkpointer=memory) +``` + +## Next steps + +There's one more concept to review before finishing the LangGraph basics tutorials: connecting `checkpointing` and `state updates` to [time travel](./6-time-travel.md). + diff --git a/docs/docs/tutorials/get-started/6-time-travel.md b/docs/docs/tutorials/get-started/6-time-travel.md new file mode 100644 index 000000000..f06cc72f4 --- /dev/null +++ b/docs/docs/tutorials/get-started/6-time-travel.md @@ -0,0 +1,288 @@ +# Time travel + +In a typical chatbot workflow, the user interacts with the bot one or more times to accomplish a task. [Memory](./3-add-memory.md) and a [human-in-the-loop](./4-human-in-the-loop.md) enable checkpoints in the graph state and control future responses. + +What if you want a user to be able to start from a previous response and explore a different outcome? Or what if you want users to be able to rewind your chatbot's work to fix mistakes or try a different strategy, something that is common in applications like autonomous software engineers? + +You can create these types of experiences using LangGraph's built-in **time travel** functionality. + +!!! note + + This tutorial builds on [Customize state](./5-customize-state.md). + +## 1. Rewind your graph + +Rewind your graph by fetching a checkpoint using the graph's `get_state_history` method. You can then resume execution at this previous point in time. + +{!snippets/chat_model_tabs.md!} + + + +```python +from typing import Annotated + +from langchain_tavily import TavilySearch +from langchain_core.messages import BaseMessage +from typing_extensions import TypedDict + +from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.prebuilt import ToolNode, tools_condition + +class State(TypedDict): + messages: Annotated[list, add_messages] + +graph_builder = StateGraph(State) + +tool = TavilySearch(max_results=2) +tools = [tool] +llm_with_tools = llm.bind_tools(tools) + +def chatbot(state: State): + return {"messages": [llm_with_tools.invoke(state["messages"])]} + +graph_builder.add_node("chatbot", chatbot) + +tool_node = ToolNode(tools=[tool]) +graph_builder.add_node("tools", tool_node) + +graph_builder.add_conditional_edges( + "chatbot", + tools_condition, +) +graph_builder.add_edge("tools", "chatbot") +graph_builder.add_edge(START, "chatbot") + +memory = MemorySaver() +graph = graph_builder.compile(checkpointer=memory) +``` + +## 2. Add steps + +Add steps to your graph. Every step will be checkpointed in its state history: + +``` python +config = {"configurable": {"thread_id": "1"}} +events = graph.stream( + { + "messages": [ + { + "role": "user", + "content": ( + "I'm learning LangGraph. " + "Could you do some research on it for me?" + ), + }, + ], + }, + config, + stream_mode="values", +) +for event in events: + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================ Human Message ================================= + +I'm learning LangGraph. Could you do some research on it for me? +================================== Ai Message ================================== + +[{'text': "Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine to look this up. Let me do that for you now.", 'type': 'text'}, {'id': 'toolu_01BscbfJJB9EWJFqGrN6E54e', 'input': {'query': 'LangGraph latest information and features'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}] +Tool Calls: + tavily_search_results_json (toolu_01BscbfJJB9EWJFqGrN6E54e) + Call ID: toolu_01BscbfJJB9EWJFqGrN6E54e + Args: + query: LangGraph latest information and features +================================= Tool Message ================================= +Name: tavily_search_results_json + +[{"url": "https://blockchain.news/news/langchain-new-features-upcoming-events-update", "content": "LangChain, a leading platform in the AI development space, has released its latest updates, showcasing new use cases and enhancements across its ecosystem. According to the LangChain Blog, the updates cover advancements in LangGraph Cloud, LangSmith's self-improving evaluators, and revamped documentation for LangGraph."}, {"url": "https://blog.langchain.dev/langgraph-platform-announce/", "content": "With these learnings under our belt, we decided to couple some of our latest offerings under LangGraph Platform. LangGraph Platform today includes LangGraph Server, LangGraph Studio, plus the CLI and SDK. ... we added features in LangGraph Server to deliver on a few key value areas. Below, we'll focus on these aspects of LangGraph Platform."}] +================================== Ai Message ================================== + +Thank you for your patience. I've found some recent information about LangGraph for you. Let me summarize the key points: + +1. LangGraph is part of the LangChain ecosystem, which is a leading platform in AI development. + +2. Recent updates and features of LangGraph include: + + a. LangGraph Cloud: This seems to be a cloud-based version of LangGraph, though specific details weren't provided in the search results. +... +3. Keep an eye on LangGraph Cloud developments, as cloud-based solutions often provide an easier starting point for learners. +4. Consider how LangGraph fits into the broader LangChain ecosystem, especially its interaction with tools like LangSmith. + +Is there any specific aspect of LangGraph you'd like to know more about? I'd be happy to do a more focused search on particular features or use cases. +Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings... +``` + +```python +events = graph.stream( + { + "messages": [ + { + "role": "user", + "content": ( + "Ya that's helpful. Maybe I'll " + "build an autonomous agent with it!" + ), + }, + ], + }, + config, + stream_mode="values", +) +for event in events: + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================ Human Message ================================= + +Ya that's helpful. Maybe I'll build an autonomous agent with it! +================================== Ai Message ================================== + +[{'text': "That's an exciting idea! Building an autonomous agent with LangGraph is indeed a great application of this technology. LangGraph is particularly well-suited for creating complex, multi-step AI workflows, which is perfect for autonomous agents. Let me gather some more specific information about using LangGraph for building autonomous agents.", 'type': 'text'}, {'id': 'toolu_01QWNHhUaeeWcGXvA4eHT7Zo', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}] +Tool Calls: + tavily_search_results_json (toolu_01QWNHhUaeeWcGXvA4eHT7Zo) + Call ID: toolu_01QWNHhUaeeWcGXvA4eHT7Zo + Args: + query: Building autonomous agents with LangGraph examples and tutorials +================================= Tool Message ================================= +Name: tavily_search_results_json + +[{"url": "https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d", "content": "Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow"}, {"url": "https://github.com/anmolaman20/Tools_and_Agents", "content": "GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph."}] +================================== Ai Message ================================== + +Great idea! Building an autonomous agent with LangGraph is definitely an exciting project. Based on the latest information I've found, here are some insights and tips for building autonomous agents with LangGraph: + +1. Multi-Tool Agents: LangGraph is particularly well-suited for creating autonomous agents that can use multiple tools. This allows your agent to have a diverse set of capabilities and choose the right tool for each task. + +2. Integration with Large Language Models (LLMs): You can combine LangGraph with powerful LLMs like Gemini 2.0 to create more intelligent and capable agents. The LLM can serve as the "brain" of your agent, making decisions and generating responses. + +3. Workflow Management: LangGraph excels at managing complex, multi-step AI workflows. This is crucial for autonomous agents that need to break down tasks into smaller steps and execute them in the right order. +... +6. Pay attention to how you structure the agent's decision-making process and workflow. +7. Don't forget to implement proper error handling and safety measures, especially if your agent will be interacting with external systems or making important decisions. + +Building an autonomous agent is an iterative process, so be prepared to refine and improve your agent over time. Good luck with your project! If you need any more specific information as you progress, feel free to ask. +Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings... +``` + +## 3. Replay the full state history + +Now that you have added steps to the chatbot, you can `replay` the full state history to see everything that occurred. + +``` python +to_replay = None +for state in graph.get_state_history(config): + print("Num Messages: ", len(state.values["messages"]), "Next: ", state.next) + print("-" * 80) + if len(state.values["messages"]) == 6: + # We are somewhat arbitrarily selecting a specific state based on the number of chat messages in the state. + to_replay = state +``` + +``` +Num Messages: 8 Next: () +-------------------------------------------------------------------------------- +Num Messages: 7 Next: ('chatbot',) +-------------------------------------------------------------------------------- +Num Messages: 6 Next: ('tools',) +-------------------------------------------------------------------------------- +Num Messages: 5 Next: ('chatbot',) +-------------------------------------------------------------------------------- +Num Messages: 4 Next: ('__start__',) +-------------------------------------------------------------------------------- +Num Messages: 4 Next: () +-------------------------------------------------------------------------------- +Num Messages: 3 Next: ('chatbot',) +-------------------------------------------------------------------------------- +Num Messages: 2 Next: ('tools',) +-------------------------------------------------------------------------------- +Num Messages: 1 Next: ('chatbot',) +-------------------------------------------------------------------------------- +Num Messages: 0 Next: ('__start__',) +-------------------------------------------------------------------------------- +``` + +Checkpoints are saved for every step of the graph. This __spans invocations__ so you can rewind across a full thread's history. + +## Resume from a checkpoint + +Resume from the `to_replay` state, which is after the `chatbot` node in the second graph invocation. Resuming from this point will call the **action** node next. + +```python +print(to_replay.next) +print(to_replay.config) +``` + +``` +('tools',) +{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd43e3-0c1f-6c4e-8006-891877d65740'}} +``` + +## 4. Load a state from a moment-in-time + +The checkpoint's `to_replay.config` contains a `checkpoint_id` timestamp. Providing this `checkpoint_id` value tells LangGraph's checkpointer to **load** the state from that moment in time. + + +``` python +# The `checkpoint_id` in the `to_replay.config` corresponds to a state we've persisted to our checkpointer. +for event in graph.stream(None, to_replay.config, stream_mode="values"): + if "messages" in event: + event["messages"][-1].pretty_print() +``` + +``` +================================== Ai Message ================================== + +[{'text': "That's an exciting idea! Building an autonomous agent with LangGraph is indeed a great application of this technology. LangGraph is particularly well-suited for creating complex, multi-step AI workflows, which is perfect for autonomous agents. Let me gather some more specific information about using LangGraph for building autonomous agents.", 'type': 'text'}, {'id': 'toolu_01QWNHhUaeeWcGXvA4eHT7Zo', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}] +Tool Calls: + tavily_search_results_json (toolu_01QWNHhUaeeWcGXvA4eHT7Zo) + Call ID: toolu_01QWNHhUaeeWcGXvA4eHT7Zo + Args: + query: Building autonomous agents with LangGraph examples and tutorials +================================= Tool Message ================================= +Name: tavily_search_results_json + +[{"url": "https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d", "content": "Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow"}, {"url": "https://github.com/anmolaman20/Tools_and_Agents", "content": "GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph."}] +================================== Ai Message ================================== + +Great idea! Building an autonomous agent with LangGraph is indeed an excellent way to apply and deepen your understanding of the technology. Based on the search results, I can provide you with some insights and resources to help you get started: + +1. Multi-Tool Agents: + LangGraph is well-suited for building autonomous agents that can use multiple tools. This allows your agent to have a variety of capabilities and choose the appropriate tool based on the task at hand. + +2. Integration with Large Language Models (LLMs): + There's a tutorial that specifically mentions using Gemini 2.0 (Google's LLM) with LangGraph to build autonomous agents. This suggests that LangGraph can be integrated with various LLMs, giving you flexibility in choosing the language model that best fits your needs. + +3. Practical Tutorials: + There are tutorials available that provide full code examples for building and running multi-tool agents. These can be invaluable as you start your project, giving you a concrete starting point and demonstrating best practices. +... + +Remember, building an autonomous agent is an iterative process. Start simple and gradually increase complexity as you become more comfortable with LangGraph and its capabilities. + +Would you like more information on any specific aspect of building your autonomous agent with LangGraph? +Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings... +``` + +The graph resumed execution from the `action` node. You can tell this is the case since the first value printed above is the response from our search engine tool. + +**Congratulations!** You've now used time-travel checkpoint traversal in LangGraph. Being able to rewind and explore alternative paths opens up a world of possibilities for debugging, experimentation, and interactive applications. + +## Learn more + +Take your LangGraph journey further by exploring deployment and advanced features: + +- **[LangGraph Server quickstart](../../tutorials/langgraph-platform/local-server.md)**: Launch a LangGraph server locally and interact with it using the REST API and LangGraph Studio Web UI. +- **[LangGraph Cloud quickstart](../../cloud/quick_start.md)**: Deploy your LangGraph app using LangGraph Cloud. +- **[LangGraph Platform concepts](../../concepts/langgraph_platform.md)**: Understand the foundational concepts of the LangGraph Platform. \ No newline at end of file diff --git a/docs/docs/tutorials/get-started/basic-chatbot.png b/docs/docs/tutorials/get-started/basic-chatbot.png new file mode 100644 index 000000000..525391837 Binary files /dev/null and b/docs/docs/tutorials/get-started/basic-chatbot.png differ diff --git a/docs/docs/tutorials/get-started/chatbot-with-tools.png b/docs/docs/tutorials/get-started/chatbot-with-tools.png new file mode 100644 index 000000000..6aff35019 Binary files /dev/null and b/docs/docs/tutorials/get-started/chatbot-with-tools.png differ diff --git a/docs/docs/tutorials/index.md b/docs/docs/tutorials/index.md index a63315acc..b02922fe2 100644 --- a/docs/docs/tutorials/index.md +++ b/docs/docs/tutorials/index.md @@ -10,7 +10,7 @@ New to LangGraph or LLM app development? Read this material to get up and runnin ## Get Started 🚀 {#quick-start} -- [LangGraph Quickstart](introduction.ipynb): Build a chatbot that can use tools and keep track of conversation history. Add human-in-the-loop capabilities and explore how time-travel works. +- [LangGraph basics](get-started/1-build-basic-chatbot.md): Build a chatbot that can use tools and keep track of conversation history. Add human-in-the-loop capabilities and explore how time-travel works. - [Common Workflows](workflows/index.md): Overview of the most common workflows using LLMs implemented with LangGraph. - [LangGraph Server Quickstart](langgraph-platform/local-server.md): Launch a LangGraph server locally and interact with it using REST API and LangGraph Studio Web UI. - [LangGraph Template Quickstart](../concepts/template_applications.md): Start building with LangGraph Platform using a template application. diff --git a/docs/docs/tutorials/introduction.ipynb b/docs/docs/tutorials/introduction.ipynb deleted file mode 100644 index 7d1fd7eed..000000000 --- a/docs/docs/tutorials/introduction.ipynb +++ /dev/null @@ -1,2483 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "4a1aae78-88a6-4133-b905-7e46c8e3772f", - "metadata": {}, - "source": [ - "# 🚀 LangGraph Quickstart\n", - "\n", - "In this tutorial, we will build a support chatbot in LangGraph that can:\n", - "\n", - "✅ **Answer common questions** by searching the web \n", - "✅ **Maintain conversation state** across calls \n", - "✅ **Route complex queries** to a human for review \n", - "✅ **Use custom state** to control its behavior \n", - "✅ **Rewind and explore** alternative conversation paths \n", - "\n", - "We'll start with a **basic chatbot** and progressively add more sophisticated capabilities, introducing key LangGraph concepts along the way. Let’s dive in! 🌟\n", - "\n", - "## Setup\n", - "\n", - "First, install the required packages and configure your environment:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "6f11d631-8679-4f28-822f-cdf1f2ddc21c", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langgraph langsmith \"langchain[anthropic]\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "705d4020-6ee8-44cc-b1a5-8c34e7172fc7", - "metadata": {}, - "outputs": [], - "source": [ - "import getpass\n", - "import os\n", - "\n", - "\n", - "def _set_env(var: str):\n", - " if not os.environ.get(var):\n", - " os.environ[var] = getpass.getpass(f\"{var}: \")\n", - "\n", - "\n", - "_set_env(\"ANTHROPIC_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "a98c72cf-33f9-4a37-9634-6c93a7c28815", - "metadata": {}, - "source": [ - "
    \n", - "

    Set up LangSmith for LangGraph development

    \n", - "

    \n", - " Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph — read more about how to get started here. \n", - "

    \n", - "
    " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "9c374e41-f9b7-439e-a520-6d8c853c5220", - "metadata": {}, - "source": [ - "## Part 1: Build a Basic Chatbot\n", - "\n", - "We'll first create a simple chatbot using LangGraph. This chatbot will respond directly to user messages. Though simple, it will illustrate the core concepts of building with LangGraph. By the end of this section, you will have a built rudimentary chatbot.\n", - "\n", - "Start by creating a `StateGraph`. A `StateGraph` object defines the structure of our chatbot as a \"state machine\". We'll add `nodes` to represent the llm and functions our chatbot can call and `edges` to specify how the bot should transition between these functions." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "e58df974-7579-4f25-9d91-66389b94eba2", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "\n", - "\n", - "class State(TypedDict):\n", - " # Messages have the type \"list\". The `add_messages` function\n", - " # in the annotation defines how this state key should be updated\n", - " # (in this case, it appends messages to the list, rather than overwriting them)\n", - " messages: Annotated[list, add_messages]\n", - "\n", - "\n", - "graph_builder = StateGraph(State)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "c08c41da-0855-49d3-9a3d-b7eb94413367", - "metadata": {}, - "source": [ - "Our graph can now handle two key tasks:\n", - "\n", - "1. Each `node` can receive the current `State` as input and output an update to the state.\n", - "2. Updates to `messages` will be appended to the existing list rather than overwriting it, thanks to the prebuilt [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/?h=add+messages#add_messages) function used with the `Annotated` syntax.\n", - "\n", - "------\n", - "\n", - "!!! tip \"Concept\"\n", - "\n", - " When defining a graph, the first step is to define its `State`. The `State` includes the graph's schema and [reducer functions](https://langchain-ai.github.io/langgraph/concepts/low_level/#reducers) that handle state updates. In our example, `State` is a `TypedDict` with one key: `messages`. The [`add_messages`](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages) reducer function is used to append new messages to the list instead of overwriting it. Keys without a reducer annotation will overwrite previous values. Learn more about state, reducers, and related concepts in [this guide](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.message.add_messages).\n", - "\n", - "---------\n", - "\n", - "\n", - "Next, add a \"`chatbot`\" node. Nodes represent units of work. They are typically regular python functions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f66edbfb-f374-4998-90a3-78bc8f18e0aa", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.chat_models import init_chat_model\n", - "\n", - "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n", - "\n", - "\n", - "def chatbot(state: State):\n", - " return {\"messages\": [llm.invoke(state[\"messages\"])]}\n", - "\n", - "\n", - "# The first argument is the unique node name\n", - "# The second argument is the function or object that will be called whenever\n", - "# the node is used.\n", - "graph_builder.add_node(\"chatbot\", chatbot)" - ] - }, - { - "cell_type": "markdown", - "id": "b6c1dcd9-fb86-4649-81b4-ff6ce20a2e46", - "metadata": {}, - "source": [ - "**Notice** how the `chatbot` node function takes the current `State` as input and returns a dictionary containing an updated `messages` list under the key \"messages\". This is the basic pattern for all LangGraph node functions.\n", - "\n", - "The `add_messages` function in our `State` will append the llm's response messages to whatever messages are already in the state.\n", - "\n", - "Next, add an `entry` point. This tells our graph **where to start its work** each time we run it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e331e10d-ebcf-4144-9bd3-999b4d656dd3", - "metadata": {}, - "outputs": [], - "source": [ - "graph_builder.add_edge(START, \"chatbot\")" - ] - }, - { - "cell_type": "markdown", - "id": "0499c318-d1e6-46fa-a652-8f9e65313355", - "metadata": {}, - "source": [ - "Similarly, set a `finish` point. This instructs the graph **\"any time this node is run, you can exit.\"**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "075f0929-3591-4852-b2d3-eaadde40662d", - "metadata": {}, - "outputs": [], - "source": [ - "graph_builder.add_edge(\"chatbot\", END)" - ] - }, - { - "cell_type": "markdown", - "id": "65a9b88c-2c53-4d95-8eb1-d544a8946f65", - "metadata": {}, - "source": [ - "Finally, we'll want to be able to run our graph. To do so, call \"`compile()`\" on the graph builder. This creates a \"`CompiledGraph`\" we can use invoke on our state." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "0bb67a01-cf5c-4625-8c07-6e8c0af50fca", - "metadata": {}, - "outputs": [], - "source": [ - "graph = graph_builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "0c39407b-d6f6-48a4-b1f6-31fc7f88b275", - "metadata": {}, - "source": [ - "You can visualize the graph using the `get_graph` method and one of the \"draw\" methods, like `draw_ascii` or `draw_png`. The `draw` methods each require additional dependencies." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "0eb93a3b-5378-479f-bc32-19afed9c3270", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "id": "a98097a3-a126-4081-b21e-697ec1185fff", - "metadata": {}, - "source": [ - "Now let's run the chatbot! \n", - "\n", - "**Tip:** You can exit the chat loop at any time by typing \"quit\", \"exit\", or \"q\"." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "6a385b06-8d34-4a2d-aded-1cf4bb0ca590", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Assistant: LangGraph is a library designed to help build stateful multi-agent applications using language models. It provides tools for creating workflows and state machines to coordinate multiple AI agents or language model interactions. LangGraph is built on top of LangChain, leveraging its components while adding graph-based coordination capabilities. It's particularly useful for developing more complex, stateful AI applications that go beyond simple query-response interactions.\n", - "Goodbye!\n" - ] - } - ], - "source": [ - "def stream_graph_updates(user_input: str):\n", - " for event in graph.stream({\"messages\": [{\"role\": \"user\", \"content\": user_input}]}):\n", - " for value in event.values():\n", - " print(\"Assistant:\", value[\"messages\"][-1].content)\n", - "\n", - "\n", - "while True:\n", - " try:\n", - " user_input = input(\"User: \")\n", - " if user_input.lower() in [\"quit\", \"exit\", \"q\"]:\n", - " print(\"Goodbye!\")\n", - " break\n", - " stream_graph_updates(user_input)\n", - " except:\n", - " # fallback if input() is not available\n", - " user_input = \"What do you know about LangGraph?\"\n", - " print(\"User: \" + user_input)\n", - " stream_graph_updates(user_input)\n", - " break" - ] - }, - { - "cell_type": "markdown", - "id": "98e1cdb5-869a-41ea-9dab-e28cfc524499", - "metadata": {}, - "source": [ - "**Congratulations!** You've built your first chatbot using LangGraph. This bot can engage in basic conversation by taking user input and generating responses using an LLM. You can inspect a [LangSmith Trace](https://smith.langchain.com/public/7527e308-9502-4894-b347-f34385740d5a/r) for the call above at the provided link.\n", - "\n", - "However, you may have noticed that the bot's knowledge is limited to what's in its training data. In the next part, we'll add a web search tool to expand the bot's knowledge and make it more capable.\n", - "\n", - "Below is the full code for this section for your reference:\n", - "\n", - "
    \n", - "Full Code\n", - "
    \n",
    -    "        \n",
    -    "```python\n",
    -    "from typing import Annotated\n",
    -    "\n",
    -    "from langchain.chat_models import init_chat_model\n",
    -    "from typing_extensions import TypedDict\n",
    -    "\n",
    -    "from langgraph.graph import StateGraph\n",
    -    "from langgraph.graph.message import add_messages\n",
    -    "\n",
    -    "\n",
    -    "class State(TypedDict):\n",
    -    "    messages: Annotated[list, add_messages]\n",
    -    "\n",
    -    "\n",
    -    "graph_builder = StateGraph(State)\n",
    -    "\n",
    -    "\n",
    -    "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n",
    -    "\n",
    -    "\n",
    -    "def chatbot(state: State):\n",
    -    "    return {\"messages\": [llm.invoke(state[\"messages\"])]}\n",
    -    "\n",
    -    "\n",
    -    "# The first argument is the unique node name\n",
    -    "# The second argument is the function or object that will be called whenever\n",
    -    "# the node is used.\n",
    -    "graph_builder.add_node(\"chatbot\", chatbot)\n",
    -    "graph_builder.set_entry_point(\"chatbot\")\n",
    -    "graph_builder.set_finish_point(\"chatbot\")\n",
    -    "graph = graph_builder.compile()\n",
    -    "```\n",
    -    "\n",
    -    "
    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "f22c5d4a-3134-413c-81fe-dd9752fbeb66", - "metadata": {}, - "source": [ - "## Part 2: 🛠️ Enhancing the Chatbot with Tools\n", - "\n", - "To handle queries our chatbot can't answer \"from memory\", we'll integrate a web search tool. Our bot can use this tool to find relevant information and provide better responses.\n", - "\n", - "#### Requirements\n", - "\n", - "Before we start, make sure you have the necessary packages installed and API keys set up:\n", - "\n", - "First, install the requirements to use the [Tavily Search Engine](https://python.langchain.com/docs/integrations/tools/tavily_search/), and set your [TAVILY_API_KEY](https://tavily.com/)." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "7451151f-41fc-4af0-9359-024ae51b7225", - "metadata": {}, - "outputs": [], - "source": [ - "%%capture --no-stderr\n", - "%pip install -U langchain-tavily" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "0c52923c-5665-4f8c-a1ba-9799e369c49e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TAVILY_API_KEY: ········\n" - ] - } - ], - "source": [ - "_set_env(\"TAVILY_API_KEY\")" - ] - }, - { - "cell_type": "markdown", - "id": "591ce9ba-c431-4165-b815-25c944ef7cdb", - "metadata": {}, - "source": [ - "Next, define the tool:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "a7cc7306-7a4e-466f-8d41-b1a3d07be8bc", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'query': \"What's a 'node' in LangGraph?\",\n", - " 'follow_up_questions': None,\n", - " 'answer': None,\n", - " 'images': [],\n", - " 'results': [{'title': \"Introduction to LangGraph: A Beginner's Guide - Medium\",\n", - " 'url': 'https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141',\n", - " 'content': 'Stateful Graph: LangGraph revolves around the concept of a stateful graph, where each node in the graph represents a step in your computation, and the graph maintains a state that is passed around and updated as the computation progresses. LangGraph supports conditional edges, allowing you to dynamically determine the next node to execute based on the current state of the graph. We define nodes for classifying the input, handling greetings, and handling search queries. def classify_input_node(state): LangGraph is a versatile tool for building complex, stateful applications with LLMs. By understanding its core concepts and working through simple examples, beginners can start to leverage its power for their projects. Remember to pay attention to state management, conditional edges, and ensuring there are no dead-end nodes in your graph.',\n", - " 'score': 0.7065353,\n", - " 'raw_content': None},\n", - " {'title': 'LangGraph Tutorial: What Is LangGraph and How to Use It?',\n", - " 'url': 'https://www.datacamp.com/tutorial/langgraph-tutorial',\n", - " 'content': 'LangGraph is a library within the LangChain ecosystem that provides a framework for defining, coordinating, and executing multiple LLM agents (or chains) in a structured and efficient manner. By managing the flow of data and the sequence of operations, LangGraph allows developers to focus on the high-level logic of their applications rather than the intricacies of agent coordination. Whether you need a chatbot that can handle various types of user requests or a multi-agent system that performs complex tasks, LangGraph provides the tools to build exactly what you need. LangGraph significantly simplifies the development of complex LLM applications by providing a structured framework for managing state and coordinating agent interactions.',\n", - " 'score': 0.5008063,\n", - " 'raw_content': None}],\n", - " 'response_time': 1.38}" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langchain_tavily import TavilySearch\n", - "\n", - "tool = TavilySearch(max_results=2)\n", - "tools = [tool]\n", - "tool.invoke(\"What's a 'node' in LangGraph?\")" - ] - }, - { - "cell_type": "markdown", - "id": "7f503f02-d23d-42e8-9b5d-eb2681b242f4", - "metadata": {}, - "source": [ - "The results are page summaries our chat bot can use to answer questions.\n", - "\n", - "\n", - "Next, we'll start defining our graph. The following is all **the same as in Part 1**, except we have added `bind_tools` on our LLM. This lets the LLM know the correct JSON format to use if it wants to use our search engine." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dc5af88b-47d2-43bf-9a2c-6c07506b1732", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from langchain.chat_models import init_chat_model\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - "\n", - "\n", - "graph_builder = StateGraph(State)\n", - "\n", - "\n", - "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n", - "# Modification: tell the LLM which tools it can call\n", - "# highlight-next-line\n", - "llm_with_tools = llm.bind_tools(tools)\n", - "\n", - "\n", - "def chatbot(state: State):\n", - " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", - "\n", - "\n", - "graph_builder.add_node(\"chatbot\", chatbot)" - ] - }, - { - "cell_type": "markdown", - "id": "d1e84cfc-b1b2-48e3-8550-152a408c3926", - "metadata": {}, - "source": [ - "Next we need to create a function to actually run the tools if they are called. We'll do this by adding the tools to a new node.\n", - "\n", - "Below, we implement a `BasicToolNode` that checks the most recent message in the state and calls tools if the message contains `tool_calls`. It relies on the LLM's `tool_calling` support, which is available in Anthropic, OpenAI, Google Gemini, and a number of other LLM providers.\n", - "\n", - "We will later replace this with LangGraph's prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode) to speed things up, but building it ourselves first is instructive." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12f1fc14-cd91-4cd4-9f2e-1d007f8beafc", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "\n", - "from langchain_core.messages import ToolMessage\n", - "\n", - "\n", - "class BasicToolNode:\n", - " \"\"\"A node that runs the tools requested in the last AIMessage.\"\"\"\n", - "\n", - " def __init__(self, tools: list) -> None:\n", - " self.tools_by_name = {tool.name: tool for tool in tools}\n", - "\n", - " def __call__(self, inputs: dict):\n", - " if messages := inputs.get(\"messages\", []):\n", - " message = messages[-1]\n", - " else:\n", - " raise ValueError(\"No message found in input\")\n", - " outputs = []\n", - " for tool_call in message.tool_calls:\n", - " tool_result = self.tools_by_name[tool_call[\"name\"]].invoke(\n", - " tool_call[\"args\"]\n", - " )\n", - " outputs.append(\n", - " ToolMessage(\n", - " content=json.dumps(tool_result),\n", - " name=tool_call[\"name\"],\n", - " tool_call_id=tool_call[\"id\"],\n", - " )\n", - " )\n", - " return {\"messages\": outputs}\n", - "\n", - "\n", - "tool_node = BasicToolNode(tools=[tool])\n", - "graph_builder.add_node(\"tools\", tool_node)" - ] - }, - { - "cell_type": "markdown", - "id": "b049afc4-7757-40ba-8e00-589d378e816d", - "metadata": {}, - "source": [ - "With the tool node added, we can define the `conditional_edges`. \n", - "\n", - "Recall that **edges** route the control flow from one node to the next. **Conditional edges** usually contain \"if\" statements to route to different nodes depending on the current graph state. These functions receive the current graph `state` and return a string or list of strings indicating which node(s) to call next.\n", - "\n", - "Below, call define a router function called `route_tools`, that checks for tool_calls in the chatbot's output. Provide this function to the graph by calling `add_conditional_edges`, which tells the graph that whenever the `chatbot` node completes to check this function to see where to go next. \n", - "\n", - "The condition will route to `tools` if tool calls are present and `END` if not.\n", - "\n", - "Later, we will replace this with the prebuilt [tools_condition](https://langchain-ai.github.io/langgraph/reference/prebuilt/#tools_condition) to be more concise, but implementing it ourselves first makes things more clear. " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "d662df94-66ac-4c6c-92f0-4c93620f1c74", - "metadata": {}, - "outputs": [], - "source": [ - "def route_tools(\n", - " state: State,\n", - "):\n", - " \"\"\"\n", - " Use in the conditional_edge to route to the ToolNode if the last message\n", - " has tool calls. Otherwise, route to the end.\n", - " \"\"\"\n", - " if isinstance(state, list):\n", - " ai_message = state[-1]\n", - " elif messages := state.get(\"messages\", []):\n", - " ai_message = messages[-1]\n", - " else:\n", - " raise ValueError(f\"No messages found in input state to tool_edge: {state}\")\n", - " if hasattr(ai_message, \"tool_calls\") and len(ai_message.tool_calls) > 0:\n", - " return \"tools\"\n", - " return END\n", - "\n", - "\n", - "# The `tools_condition` function returns \"tools\" if the chatbot asks to use a tool, and \"END\" if\n", - "# it is fine directly responding. This conditional routing defines the main agent loop.\n", - "graph_builder.add_conditional_edges(\n", - " \"chatbot\",\n", - " route_tools,\n", - " # The following dictionary lets you tell the graph to interpret the condition's outputs as a specific node\n", - " # It defaults to the identity function, but if you\n", - " # want to use a node named something else apart from \"tools\",\n", - " # You can update the value of the dictionary to something else\n", - " # e.g., \"tools\": \"my_tools\"\n", - " {\"tools\": \"tools\", END: END},\n", - ")\n", - "# Any time a tool is called, we return to the chatbot to decide the next step\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")\n", - "graph = graph_builder.compile()" - ] - }, - { - "cell_type": "markdown", - "id": "a2aa67c2-dd1b-4bf2-8c64-eea44296d15f", - "metadata": {}, - "source": [ - "**Notice** that conditional edges start from a single node. This tells the graph \"any time the '`chatbot`' node runs, either go to 'tools' if it calls a tool, or end the loop if it responds directly. \n", - "\n", - "Like the prebuilt `tools_condition`, our function returns the `END` string if no tool calls are made. When the graph transitions to `END`, it has no more tasks to complete and ceases execution. Because the condition can return `END`, we don't need to explicitly set a `finish_point` this time. Our graph already has a way to finish!\n", - "\n", - "Let's visualize the graph we've built. The following function has some additional dependencies to run that are unimportant for this tutorial." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "8b49509c-9d97-457c-a76a-c495fb30ccbc", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "id": "c59593ef-5073-4279-931e-828dae971f23", - "metadata": {}, - "source": [ - "Now we can ask the bot questions outside its training data." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "051dc374-67cc-4371-9dd1-221e07593148", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Assistant: [{'text': \"To provide you with accurate and up-to-date information about LangGraph, I'll need to search for the latest details. Let me do that for you.\", 'type': 'text'}, {'id': 'toolu_01Q588CszHaSvvP2MxRq9zRD', 'input': {'query': 'LangGraph AI tool information'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Assistant: [{\"url\": \"https://www.langchain.com/langgraph\", \"content\": \"LangGraph sets the foundation for how we can build and scale AI workloads \\u2014 from conversational agents, complex task automation, to custom LLM-backed experiences that 'just work'. The next chapter in building complex production-ready features with LLMs is agentic, and with LangGraph and LangSmith, LangChain delivers an out-of-the-box solution ...\"}, {\"url\": \"https://github.com/langchain-ai/langgraph\", \"content\": \"Overview. LangGraph is a library for building stateful, multi-actor applications with LLMs, used to create agent and multi-agent workflows. Compared to other LLM frameworks, it offers these core benefits: cycles, controllability, and persistence. LangGraph allows you to define flows that involve cycles, essential for most agentic architectures ...\"}]\n", - "Assistant: Based on the search results, I can provide you with information about LangGraph:\n", - "\n", - "1. Purpose:\n", - " LangGraph is a library designed for building stateful, multi-actor applications with Large Language Models (LLMs). It's particularly useful for creating agent and multi-agent workflows.\n", - "\n", - "2. Developer:\n", - " LangGraph is developed by LangChain, a company known for its tools and frameworks in the AI and LLM space.\n", - "\n", - "3. Key Features:\n", - " - Cycles: LangGraph allows the definition of flows that involve cycles, which is essential for most agentic architectures.\n", - " - Controllability: It offers enhanced control over the application flow.\n", - " - Persistence: The library provides ways to maintain state and persistence in LLM-based applications.\n", - "\n", - "4. Use Cases:\n", - " LangGraph can be used for various applications, including:\n", - " - Conversational agents\n", - " - Complex task automation\n", - " - Custom LLM-backed experiences\n", - "\n", - "5. Integration:\n", - " LangGraph works in conjunction with LangSmith, another tool by LangChain, to provide an out-of-the-box solution for building complex, production-ready features with LLMs.\n", - "\n", - "6. Significance:\n", - " LangGraph is described as setting the foundation for building and scaling AI workloads. It's positioned as a key tool in the next chapter of LLM-based application development, particularly in the realm of agentic AI.\n", - "\n", - "7. Availability:\n", - " LangGraph is open-source and available on GitHub, which suggests that developers can access and contribute to its codebase.\n", - "\n", - "8. Comparison to Other Frameworks:\n", - " LangGraph is noted to offer unique benefits compared to other LLM frameworks, particularly in its ability to handle cycles, provide controllability, and maintain persistence.\n", - "\n", - "LangGraph appears to be a significant tool in the evolving landscape of LLM-based application development, offering developers new ways to create more complex, stateful, and interactive AI systems.\n", - "Goodbye!\n" - ] - } - ], - "source": [ - "while True:\n", - " try:\n", - " user_input = input(\"User: \")\n", - " if user_input.lower() in [\"quit\", \"exit\", \"q\"]:\n", - " print(\"Goodbye!\")\n", - " break\n", - "\n", - " stream_graph_updates(user_input)\n", - " except:\n", - " # fallback if input() is not available\n", - " user_input = \"What do you know about LangGraph?\"\n", - " print(\"User: \" + user_input)\n", - " stream_graph_updates(user_input)\n", - " break" - ] - }, - { - "cell_type": "markdown", - "id": "89da9e85-2e5d-49c2-8cbd-572cbdb89135", - "metadata": {}, - "source": [ - "**Congrats!** You've created a conversational agent in langgraph that can use a search engine to retrieve updated information when needed. Now it can handle a wider range of user queries. To inspect all the steps your agent just took, check out this [LangSmith trace](https://smith.langchain.com/public/4fbd7636-25af-4638-9587-5a02fdbb0172/r).\n", - "\n", - "Our chatbot still can't remember past interactions on its own, limiting its ability to have coherent, multi-turn conversations. In the next part, we'll add **memory** to address this.\n", - "\n", - "\n", - "The full code for the graph we've created in this section is reproduced below, replacing our `BasicToolNode` for the prebuilt [ToolNode](https://langchain-ai.github.io/langgraph/reference/prebuilt/#toolnode), and our `route_tools` condition with the prebuilt [tools_condition](https://langchain-ai.github.io/langgraph/reference/prebuilt/#tools_condition)\n", - "\n", - "
    \n", - "Full Code\n", - "
    \n",
    -    "\n",
    -    "```python\n",
    -    "from typing import Annotated\n",
    -    "\n",
    -    "from langchain.chat_models import init_chat_model\n",
    -    "from langchain_tavily import TavilySearch\n",
    -    "from langchain_core.messages import BaseMessage\n",
    -    "from typing_extensions import TypedDict\n",
    -    "\n",
    -    "from langgraph.graph import StateGraph\n",
    -    "from langgraph.graph.message import add_messages\n",
    -    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    -    "\n",
    -    "\n",
    -    "class State(TypedDict):\n",
    -    "    messages: Annotated[list, add_messages]\n",
    -    "\n",
    -    "\n",
    -    "graph_builder = StateGraph(State)\n",
    -    "\n",
    -    "\n",
    -    "tool = TavilySearch(max_results=2)\n",
    -    "tools = [tool]\n",
    -    "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n",
    -    "llm_with_tools = llm.bind_tools(tools)\n",
    -    "\n",
    -    "\n",
    -    "def chatbot(state: State):\n",
    -    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
    -    "\n",
    -    "\n",
    -    "graph_builder.add_node(\"chatbot\", chatbot)\n",
    -    "\n",
    -    "tool_node = ToolNode(tools=[tool])\n",
    -    "graph_builder.add_node(\"tools\", tool_node)\n",
    -    "\n",
    -    "graph_builder.add_conditional_edges(\n",
    -    "    \"chatbot\",\n",
    -    "    tools_condition,\n",
    -    ")\n",
    -    "# Any time a tool is called, we return to the chatbot to decide the next step\n",
    -    "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    -    "graph_builder.set_entry_point(\"chatbot\")\n",
    -    "graph = graph_builder.compile()\n",
    -    "```\n",
    -    "\n",
    -    "
    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "ae45f2aa-396f-4f3f-848b-7750611617f8", - "metadata": {}, - "source": [ - "## Part 3: Adding Memory to the Chatbot\n", - "\n", - "Our chatbot can now use tools to answer user questions, but it doesn't remember the context of previous interactions. This limits its ability to have coherent, multi-turn conversations.\n", - "\n", - "LangGraph solves this problem through **persistent checkpointing**. If you provide a `checkpointer` when compiling the graph and a `thread_id` when calling your graph, LangGraph automatically saves the state after each step. When you invoke the graph again using the same `thread_id`, the graph loads its saved state, allowing the chatbot to pick up where it left off. \n", - "\n", - "We will see later that **checkpointing** is _much_ more powerful than simple chat memory - it lets you save and resume complex state at any time for error recovery, human-in-the-loop workflows, time travel interactions, and more. But before we get too ahead of ourselves, let's add checkpointing to enable multi-turn conversations.\n", - "\n", - "To get started, create a `MemorySaver` checkpointer." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "6baafdf6-6803-4305-9381-9dc970468a4d", - "metadata": {}, - "outputs": [], - "source": [ - "from langgraph.checkpoint.memory import MemorySaver\n", - "\n", - "memory = MemorySaver()" - ] - }, - { - "cell_type": "markdown", - "id": "08d3d11a-1b42-4cbb-8e11-2a4294263d90", - "metadata": {}, - "source": [ - "**Notice** we're using an in-memory checkpointer. This is convenient for our tutorial (it saves it all in-memory). In a production application, you would likely change this to use `SqliteSaver` or `PostgresSaver` and connect to your own DB.\n", - "\n", - "Next define the graph. Now that you've already built your own `BasicToolNode`, we'll replace it with LangGraph's prebuilt `ToolNode` and `tools_condition`, since these do some nice things like parallel API execution. Apart from that, the following is all copied from Part 2." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6a51f1e-00de-4701-8931-de8cf19294ae", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from langchain.chat_models import init_chat_model\n", - "from langchain_tavily import TavilySearch\n", - "from langchain_core.messages import BaseMessage\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - "\n", - "\n", - "graph_builder = StateGraph(State)\n", - "\n", - "\n", - "tool = TavilySearch(max_results=2)\n", - "tools = [tool]\n", - "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n", - "llm_with_tools = llm.bind_tools(tools)\n", - "\n", - "\n", - "def chatbot(state: State):\n", - " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", - "\n", - "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", - "\n", - "tool_node = ToolNode(tools=[tool])\n", - "graph_builder.add_node(\"tools\", tool_node)\n", - "\n", - "graph_builder.add_conditional_edges(\n", - " \"chatbot\",\n", - " tools_condition,\n", - ")\n", - "# Any time a tool is called, we return to the chatbot to decide the next step\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")" - ] - }, - { - "cell_type": "markdown", - "id": "8a292dfe-764f-4561-90aa-71317d679d3e", - "metadata": {}, - "source": [ - "Finally, compile the graph with the provided checkpointer." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "a06548bf-81fa-4436-b4c1-f68601fb4187", - "metadata": {}, - "outputs": [], - "source": [ - "graph = graph_builder.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "df01805c-4458-4474-b13b-59ecfe228f12", - "metadata": {}, - "source": [ - "Notice the connectivity of the graph hasn't changed since Part 2. All we are doing is checkpointing the `State` as the graph works through each node." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "761d15fb-d5e2-4d50-a630-126d77e77294", - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "id": "2c8265ef-e5b4-4c32-9856-5572b5652142", - "metadata": {}, - "source": [ - "Now you can interact with your bot! First, pick a thread to use as the key for this conversation." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "be7b5abb-04ef-4d53-83d1-d4d3139cc43a", - "metadata": {}, - "outputs": [], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\"}}" - ] - }, - { - "cell_type": "markdown", - "id": "d0b1a5ee-7fa2-475c-a9db-749694b90ba9", - "metadata": {}, - "source": [ - "Next, call your chat bot." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "dba1b168-f8e0-496d-9bd6-37198fb4776e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Hi there! My name is Will.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Hello Will! It's nice to meet you. How can I assist you today? Is there anything specific you'd like to know or discuss?\n" - ] - } - ], - "source": [ - "user_input = \"Hi there! My name is Will.\"\n", - "\n", - "# The config is the **second positional argument** to stream() or invoke()!\n", - "events = graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "33c6b470-5082-4c3e-b732-34de47c88735", - "metadata": {}, - "source": [ - "**Note:** The config was provided as the **second positional argument** when calling our graph. It importantly is _not_ nested within the graph inputs (`{'messages': []}`).\n", - "\n", - "Let's ask a followup: see if it remembers your name." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "f5447778-53d7-47f3-801b-f47bcf2185a0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Remember my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.\n" - ] - } - ], - "source": [ - "user_input = \"Remember my name?\"\n", - "\n", - "# The config is the **second positional argument** to stream() or invoke()!\n", - "events = graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "33be4cd8-f96f-4949-9d1f-48054502e5d0", - "metadata": {}, - "source": [ - "**Notice** that we aren't using an external list for memory: it's all handled by the checkpointer! You can inspect the full execution in this [LangSmith trace](https://smith.langchain.com/public/29ba22b5-6d40-4fbe-8d27-b369e3329c84/r) to see what's going on.\n", - "\n", - "Don't believe me? Try this using a different config." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "4527cf9a-b191-4bde-858a-e33a74a48c55", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Remember my name?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "I apologize, but I don't have any previous context or memory of your name. As an AI assistant, I don't retain information from past conversations. Each interaction starts fresh. Could you please tell me your name so I can address you properly in this conversation?\n" - ] - } - ], - "source": [ - "# The only difference is we change the `thread_id` here to \"2\" instead of \"1\"\n", - "events = graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n", - " # highlight-next-line\n", - " {\"configurable\": {\"thread_id\": \"2\"}},\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "5eeccbf0-ed74-4838-a7e9-31910d82b0b2", - "metadata": {}, - "source": [ - "**Notice** that the **only** change we've made is to modify the `thread_id` in the config. See this call's [LangSmith trace](https://smith.langchain.com/public/51a62351-2f0a-4058-91cc-9996c5561428/r) for comparison. \n", - "\n", - "By now, we have made a few checkpoints across two different threads. But what goes into a checkpoint? To inspect a graph's `state` for a given config at any time, call `get_state(config)`." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "0be77c25-1423-4f2d-9b2d-28530cc761a4", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "StateSnapshot(values={'messages': [HumanMessage(content='Hi there! My name is Will.', additional_kwargs={}, response_metadata={}, id='8c1ca919-c553-4ebf-95d4-b59a2d61e078'), AIMessage(content=\"Hello Will! It's nice to meet you. How can I assist you today? Is there anything specific you'd like to know or discuss?\", additional_kwargs={}, response_metadata={'id': 'msg_01WTQebPhNwmMrmmWojJ9KXJ', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 405, 'output_tokens': 32}}, id='run-58587b77-8c82-41e6-8a90-d62c444a261d-0', usage_metadata={'input_tokens': 405, 'output_tokens': 32, 'total_tokens': 437}), HumanMessage(content='Remember my name?', additional_kwargs={}, response_metadata={}, id='daba7df6-ad75-4d6b-8057-745881cea1ca'), AIMessage(content=\"Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.\", additional_kwargs={}, response_metadata={'id': 'msg_01E41KitY74HpENRgXx94vag', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 444, 'output_tokens': 58}}, id='run-ffeaae5c-4d2d-4ddb-bd59-5d5cbf2a5af8-0', usage_metadata={'input_tokens': 444, 'output_tokens': 58, 'total_tokens': 502})]}, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef7d06e-93e0-6acc-8004-f2ac846575d2'}}, metadata={'source': 'loop', 'writes': {'chatbot': {'messages': [AIMessage(content=\"Of course, I remember your name, Will. I always try to pay attention to important details that users share with me. Is there anything else you'd like to talk about or any questions you have? I'm here to help with a wide range of topics or tasks.\", additional_kwargs={}, response_metadata={'id': 'msg_01E41KitY74HpENRgXx94vag', 'model': 'claude-3-5-sonnet-20240620', 'stop_reason': 'end_turn', 'stop_sequence': None, 'usage': {'input_tokens': 444, 'output_tokens': 58}}, id='run-ffeaae5c-4d2d-4ddb-bd59-5d5cbf2a5af8-0', usage_metadata={'input_tokens': 444, 'output_tokens': 58, 'total_tokens': 502})]}}, 'step': 4, 'parents': {}}, created_at='2024-09-27T19:30:10.820758+00:00', parent_config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1ef7d06e-859f-6206-8003-e1bd3c264b8f'}}, tasks=())" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "snapshot = graph.get_state(config)\n", - "snapshot" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "c106bd09-f155-4e15-9120-c60c834106e5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "()" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "snapshot.next # (since the graph ended this turn, `next` is empty. If you fetch a state from within a graph invocation, next tells which node will execute next)" - ] - }, - { - "cell_type": "markdown", - "id": "627f4998-6780-4cce-8f3c-9a5580888e3a", - "metadata": {}, - "source": [ - "The snapshot above contains the current state values, corresponding config, and the `next` node to process. In our case, the graph has reached an `END` state, so `next` is empty.\n", - "\n", - "**Congratulations!** Your chatbot can now maintain conversation state across sessions thanks to LangGraph's checkpointing system. This opens up exciting possibilities for more natural, contextual interactions. LangGraph's checkpointing even handles **arbitrarily complex graph states**, which is much more expressive and powerful than simple chat memory.\n", - "\n", - "In the next part, we'll introduce human oversight to our bot to handle situations where it may need guidance or verification before proceeding.\n", - " \n", - "Check out the code snippet below to review our graph from this section.\n", - "\n", - "
    \n", - "Full Code\n", - "
    \n",
    -    "\n",
    -    "```python\n",
    -    "from typing import Annotated\n",
    -    "\n",
    -    "from langchain.chat_models import init_chat_model\n",
    -    "from langchain_tavily import TavilySearch\n",
    -    "from langchain_core.messages import BaseMessage\n",
    -    "from typing_extensions import TypedDict\n",
    -    "\n",
    -    "from langgraph.checkpoint.memory import MemorySaver\n",
    -    "from langgraph.graph import StateGraph\n",
    -    "from langgraph.graph.message import add_messages\n",
    -    "from langgraph.prebuilt import ToolNode\n",
    -    "\n",
    -    "\n",
    -    "class State(TypedDict):\n",
    -    "    messages: Annotated[list, add_messages]\n",
    -    "\n",
    -    "\n",
    -    "graph_builder = StateGraph(State)\n",
    -    "\n",
    -    "\n",
    -    "tool = TavilySearch(max_results=2)\n",
    -    "tools = [tool]\n",
    -    "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n",
    -    "llm_with_tools = llm.bind_tools(tools)\n",
    -    "\n",
    -    "\n",
    -    "def chatbot(state: State):\n",
    -    "    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n",
    -    "\n",
    -    "\n",
    -    "graph_builder.add_node(\"chatbot\", chatbot)\n",
    -    "\n",
    -    "tool_node = ToolNode(tools=[tool])\n",
    -    "graph_builder.add_node(\"tools\", tool_node)\n",
    -    "\n",
    -    "graph_builder.add_conditional_edges(\n",
    -    "    \"chatbot\",\n",
    -    "    tools_condition,\n",
    -    ")\n",
    -    "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    -    "graph_builder.set_entry_point(\"chatbot\")\n",
    -    "memory = MemorySaver()\n",
    -    "graph = graph_builder.compile(checkpointer=memory)\n",
    -    "```\n",
    -    "
    \n", - "\n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "6f1da240-ec9b-441f-9d47-44c6dc85d540", - "metadata": {}, - "source": [ - "## Part 4: Human-in-the-loop\n", - "\n", - "Agents can be unreliable and may need human input to successfully accomplish tasks. Similarly, for some actions, you may want to require human approval before running to ensure that everything is running as intended.\n", - "\n", - "LangGraph's [persistence](../../concepts/persistence) layer supports human-in-the-loop workflows, allowing execution to pause and resume based on user feedback. The primary interface to this functionality is the [interrupt](../../concepts/human_in_the_loop/#interrupt) function. Calling `interrupt` inside a node will pause execution. Execution can be resumed, together with new input from a human, by passing in a [Command](../../concepts/human_in_the_loop/#the-command-primitive). `interrupt` is ergonomically similar to Python's built-in `input()`, [with some caveats](../../concepts/human_in_the_loop/#interrupt). We demonstrate an example below.\n", - "\n", - "First, start with our existing code from Part 3. We will make one change, which is to add a simple `human_assistance` tool accessible to the chatbot. This tool uses `interrupt` to receive information from a human." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08439bb4-91e8-4abb-a57a-2511877abcb7", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from langchain.chat_models import init_chat_model\n", - "from langchain_tavily import TavilySearch\n", - "from langchain_core.tools import tool\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", - "\n", - "# highlight-next-line\n", - "from langgraph.types import Command, interrupt\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - "\n", - "\n", - "graph_builder = StateGraph(State)\n", - "\n", - "\n", - "# highlight-next-line\n", - "@tool\n", - "# highlight-next-line\n", - "def human_assistance(query: str) -> str:\n", - " # highlight-next-line\n", - " \"\"\"Request assistance from a human.\"\"\"\n", - " # highlight-next-line\n", - " human_response = interrupt({\"query\": query})\n", - " # highlight-next-line\n", - " return human_response[\"data\"]\n", - "\n", - "\n", - "tool = TavilySearch(max_results=2)\n", - "tools = [tool, human_assistance]\n", - "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n", - "llm_with_tools = llm.bind_tools(tools)\n", - "\n", - "\n", - "def chatbot(state: State):\n", - " message = llm_with_tools.invoke(state[\"messages\"])\n", - " # Because we will be interrupting during tool execution,\n", - " # we disable parallel tool calling to avoid repeating any\n", - " # tool invocations when we resume.\n", - " assert len(message.tool_calls) <= 1\n", - " return {\"messages\": [message]}\n", - "\n", - "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", - "\n", - "tool_node = ToolNode(tools=tools)\n", - "graph_builder.add_node(\"tools\", tool_node)\n", - "\n", - "graph_builder.add_conditional_edges(\n", - " \"chatbot\",\n", - " tools_condition,\n", - ")\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")" - ] - }, - { - "cell_type": "markdown", - "id": "cada4cd2-0316-487b-923e-0d12fa3473c2", - "metadata": {}, - "source": [ - "------\n", - "\n", - "!!! tip\n", - "\n", - " Check out the [Human-in-the-loop section](../../how-tos/#human-in-the-loop) of the How-to Guides for more examples of Human-in-the-loop workflows, including how to [review and edit tool calls](../../how-tos/human_in_the_loop/review-tool-calls/) before they are executed.\n", - "\n", - "---------\n", - "\n", - "We compile the graph with a checkpointer, as before:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "16cc6b14-f758-4590-beb7-7b76a6841521", - "metadata": {}, - "outputs": [], - "source": [ - "memory = MemorySaver()\n", - "\n", - "graph = graph_builder.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "bc0e84db-925c-4468-b3e0-639e6b25ac3c", - "metadata": {}, - "source": [ - "Visualizing the graph, we recover the same layout as before. We have just added a tool!" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "22ff19af-5a5b-4ca5-82d8-6a38445c24af", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "from IPython.display import Image, display\n", - "\n", - "try:\n", - " display(Image(graph.get_graph().draw_mermaid_png()))\n", - "except Exception:\n", - " # This requires some extra dependencies and is optional\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "id": "ae4663b8-176d-445d-bd07-56938c044f98", - "metadata": {}, - "source": [ - "Let's now prompt the chatbot with a question that will engage the new `human_assistance` tool:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "9f318020-ab7e-415b-a5e2-eddec6d9f3a6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "I need some expert guidance for building an AI agent. Could you request assistance for me?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW)\n", - " Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW\n", - " Args:\n", - " query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?\n" - ] - } - ], - "source": [ - "user_input = \"I need some expert guidance for building an AI agent. Could you request assistance for me?\"\n", - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "\n", - "events = graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "39405637-13b1-40b1-a51e-6d60bf675ff1", - "metadata": {}, - "source": [ - "The chatbot generated a tool call, but then execution has been interrupted! Note that if we inspect the graph state, we see that it stopped at the tools node:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "9f511371-98b6-4513-b450-9143778f12dc", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "('tools',)" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "snapshot = graph.get_state(config)\n", - "snapshot.next" - ] - }, - { - "cell_type": "markdown", - "id": "4574b267-b0d8-4056-aeea-6e8817e8844e", - "metadata": {}, - "source": [ - "Let's take a closer look at the `human_assistance` tool:\n", - "\n", - "```python\n", - "@tool\n", - "def human_assistance(query: str) -> str:\n", - " \"\"\"Request assistance from a human.\"\"\"\n", - " human_response = interrupt({\"query\": query})\n", - " return human_response[\"data\"]\n", - "```\n", - "\n", - "Similar to Python's built-in `input()` function, calling `interrupt` inside the tool will pause execution. Progress is persisted based on our choice of [checkpointer](../../concepts/persistence/#checkpointer-libraries)-- so if we are persisting with Postgres, we can resume at any time as long as the database is alive. Here we are persisting with the in-memory checkpointer, so we can resume any time as long as our Python kernel is running.\n", - "\n", - "To resume execution, we pass a [Command](../../concepts/human_in_the_loop/#the-command-primitive) object containing data expected by the tool. The format of this data can be customized based on our needs. Here, we just need a dict with a key `\"data\"`:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "df6d81bb-e674-44ef-a46e-17b1a8d2381a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to request expert assistance for you regarding building an AI agent. To do this, I'll use the human_assistance function to relay your request. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01ABUqneqnuHNuo1vhfDFQCW', 'input': {'query': 'A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " human_assistance (toolu_01ABUqneqnuHNuo1vhfDFQCW)\n", - " Call ID: toolu_01ABUqneqnuHNuo1vhfDFQCW\n", - " Args:\n", - " query: A user is requesting expert guidance for building an AI agent. Could you please provide some expert advice or resources on this topic?\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: human_assistance\n", - "\n", - "We, the experts are here to help! We'd recommend you check out LangGraph to build your agent. It's much more reliable and extensible than simple autonomous agents.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've received some expert advice regarding your request for guidance on building an AI agent. Here's what the experts have suggested:\n", - "\n", - "The experts recommend that you look into LangGraph for building your AI agent. They mention that LangGraph is a more reliable and extensible option compared to simple autonomous agents.\n", - "\n", - "LangGraph is likely a framework or library designed specifically for creating AI agents with advanced capabilities. Here are a few points to consider based on this recommendation:\n", - "\n", - "1. Reliability: The experts emphasize that LangGraph is more reliable than simpler autonomous agent approaches. This could mean it has better stability, error handling, or consistent performance.\n", - "\n", - "2. Extensibility: LangGraph is described as more extensible, which suggests that it probably offers a flexible architecture that allows you to easily add new features or modify existing ones as your agent's requirements evolve.\n", - "\n", - "3. Advanced capabilities: Given that it's recommended over \"simple autonomous agents,\" LangGraph likely provides more sophisticated tools and techniques for building complex AI agents.\n", - "\n", - "To get started with LangGraph, you might want to:\n", - "\n", - "1. Search for the official LangGraph documentation or website to learn more about its features and how to use it.\n", - "2. Look for tutorials or guides specifically focused on building AI agents with LangGraph.\n", - "3. Check if there are any community forums or discussion groups where you can ask questions and get support from other developers using LangGraph.\n", - "\n", - "If you'd like more specific information about LangGraph or have any questions about this recommendation, please feel free to ask, and I can request further assistance from the experts.\n" - ] - } - ], - "source": [ - "human_response = (\n", - " \"We, the experts are here to help! We'd recommend you check out LangGraph to build your agent.\"\n", - " \" It's much more reliable and extensible than simple autonomous agents.\"\n", - ")\n", - "\n", - "human_command = Command(resume={\"data\": human_response})\n", - "\n", - "events = graph.stream(human_command, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "21e78a97-474f-4709-b51d-9d5e8323e14c", - "metadata": {}, - "source": [ - "Our input has been received and processed as a tool message. Review this call's [LangSmith trace](https://smith.langchain.com/public/9f0f87e3-56a7-4dde-9c76-b71675624e91/r) to see the exact work that was done in the above call. Notice that the state is loaded in the first step so that our chatbot can continue where it left off.\n", - "\n", - "**Congrats!** You've used an `interrupt` to add human-in-the-loop execution to your chatbot, allowing for human oversight and intervention when needed. This opens up the potential UIs you can create with your AI systems. Since we have already added a **checkpointer**, as long as the underlying persistence layer is running, the graph can be paused **indefinitely** and resumed at any time as if nothing had happened.\n", - "\n", - "Human-in-the-loop workflows enable a variety of new workflows and user experiences. Check out [this section](../../how-tos/#human-in-the-loop) of the How-to Guides for more examples of Human-in-the-loop workflows, including how to [review and edit tool calls](../../how-tos/human_in_the_loop/review-tool-calls/) before they are executed.\n", - "\n", - "\n", - "
    \n", - "Full Code\n", - "
    \n",
    -    "\n",
    -    "```python\n",
    -    "from typing import Annotated\n",
    -    "\n",
    -    "from langchain.chat_models import init_chat_model\n",
    -    "from langchain_tavily import TavilySearch\n",
    -    "from langchain_core.tools import tool\n",
    -    "from typing_extensions import TypedDict\n",
    -    "\n",
    -    "from langgraph.checkpoint.memory import MemorySaver\n",
    -    "from langgraph.graph import StateGraph, START, END\n",
    -    "from langgraph.graph.message import add_messages\n",
    -    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    -    "from langgraph.types import Command, interrupt\n",
    -    "\n",
    -    "\n",
    -    "class State(TypedDict):\n",
    -    "    messages: Annotated[list, add_messages]\n",
    -    "\n",
    -    "\n",
    -    "graph_builder = StateGraph(State)\n",
    -    "\n",
    -    "\n",
    -    "@tool\n",
    -    "def human_assistance(query: str) -> str:\n",
    -    "    \"\"\"Request assistance from a human.\"\"\"\n",
    -    "    human_response = interrupt({\"query\": query})\n",
    -    "    return human_response[\"data\"]\n",
    -    "\n",
    -    "\n",
    -    "tool = TavilySearch(max_results=2)\n",
    -    "tools = [tool, human_assistance]\n",
    -    "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n",
    -    "llm_with_tools = llm.bind_tools(tools)\n",
    -    "\n",
    -    "\n",
    -    "def chatbot(state: State):\n",
    -    "    message = llm_with_tools.invoke(state[\"messages\"])\n",
    -    "    assert(len(message.tool_calls) <= 1)\n",
    -    "    return {\"messages\": [message]}\n",
    -    "\n",
    -    "\n",
    -    "graph_builder.add_node(\"chatbot\", chatbot)\n",
    -    "\n",
    -    "tool_node = ToolNode(tools=tools)\n",
    -    "graph_builder.add_node(\"tools\", tool_node)\n",
    -    "\n",
    -    "graph_builder.add_conditional_edges(\n",
    -    "    \"chatbot\",\n",
    -    "    tools_condition,\n",
    -    ")\n",
    -    "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    -    "graph_builder.add_edge(START, \"chatbot\")\n",
    -    "\n",
    -    "memory = MemorySaver()\n",
    -    "graph = graph_builder.compile(checkpointer=memory)\n",
    -    "```\n",
    -    "
    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "0d12578b-ff19-48b5-b1ad-67d9bf7f710e", - "metadata": {}, - "source": [ - "## Part 5: Customizing State\n", - "\n", - "So far, we've relied on a simple state with one entry-- a list of messages. You can go far with this simple state, but if you want to define complex behavior without relying on the message list, you can add additional fields to the state. Here we will demonstrate a new scenario, in which the chatbot is using its search tool to find specific information, and forwarding them to a human for review. Let's have the chatbot research the birthday of an entity. We will add `name` and `birthday` keys to the state:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "84627103-bcc8-4645-bd37-b93209fa09dd", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.graph.message import add_messages\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - " # highlight-next-line\n", - " name: str\n", - " # highlight-next-line\n", - " birthday: str" - ] - }, - { - "cell_type": "markdown", - "id": "c0057133-3dfd-4208-a11f-9cf7c0b82587", - "metadata": {}, - "source": [ - "Adding this information to the state makes it easily accessible by other graph nodes (e.g., a downstream node that stores or processes the information), as well as the graph's persistence layer.\n", - "\n", - "Here, we will populate the state keys inside of our `human_assistance` tool. This allows a human to review the information before it is stored in the state. We will again use `Command`, this time to issue a state update from inside our tool. Read more about use cases for `Command` [here](../../concepts/low_level/#using-inside-tools)." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "c4b65504-92c7-4c82-a6ee-824885d1a8a4", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.messages import ToolMessage\n", - "from langchain_core.tools import InjectedToolCallId, tool\n", - "\n", - "from langgraph.types import Command, interrupt\n", - "\n", - "\n", - "@tool\n", - "# Note that because we are generating a ToolMessage for a state update, we\n", - "# generally require the ID of the corresponding tool call. We can use\n", - "# LangChain's InjectedToolCallId to signal that this argument should not\n", - "# be revealed to the model in the tool's schema.\n", - "def human_assistance(\n", - " name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId]\n", - ") -> str:\n", - " \"\"\"Request assistance from a human.\"\"\"\n", - " human_response = interrupt(\n", - " {\n", - " \"question\": \"Is this correct?\",\n", - " \"name\": name,\n", - " \"birthday\": birthday,\n", - " },\n", - " )\n", - " # If the information is correct, update the state as-is.\n", - " if human_response.get(\"correct\", \"\").lower().startswith(\"y\"):\n", - " verified_name = name\n", - " verified_birthday = birthday\n", - " response = \"Correct\"\n", - " # Otherwise, receive information from the human reviewer.\n", - " else:\n", - " verified_name = human_response.get(\"name\", name)\n", - " verified_birthday = human_response.get(\"birthday\", birthday)\n", - " response = f\"Made a correction: {human_response}\"\n", - "\n", - " # This time we explicitly update the state with a ToolMessage inside\n", - " # the tool.\n", - " state_update = {\n", - " \"name\": verified_name,\n", - " \"birthday\": verified_birthday,\n", - " \"messages\": [ToolMessage(response, tool_call_id=tool_call_id)],\n", - " }\n", - " # We return a Command object in the tool to update our state.\n", - " return Command(update=state_update)" - ] - }, - { - "cell_type": "markdown", - "id": "268757ca-4b72-4fc1-a482-d878dd1bc0d9", - "metadata": {}, - "source": [ - "Otherwise, the rest of our graph is the same:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "e256fa2e-6c13-42dd-a0a5-d206ee4139bf", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain.chat_models import init_chat_model\n", - "from langchain_tavily import TavilySearch\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", - "\n", - "\n", - "tool = TavilySearch(max_results=2)\n", - "tools = [tool, human_assistance]\n", - "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n", - "llm_with_tools = llm.bind_tools(tools)\n", - "\n", - "\n", - "def chatbot(state: State):\n", - " message = llm_with_tools.invoke(state[\"messages\"])\n", - " assert len(message.tool_calls) <= 1\n", - " return {\"messages\": [message]}\n", - "\n", - "\n", - "graph_builder = StateGraph(State)\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", - "\n", - "tool_node = ToolNode(tools=tools)\n", - "graph_builder.add_node(\"tools\", tool_node)\n", - "\n", - "graph_builder.add_conditional_edges(\n", - " \"chatbot\",\n", - " tools_condition,\n", - ")\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")\n", - "\n", - "memory = MemorySaver()\n", - "graph = graph_builder.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "e9f77638-f957-4e1b-abcf-e9132c039be5", - "metadata": {}, - "source": [ - "Let's prompt our application to look up the \"birthday\" of the LangGraph library. We will direct the chatbot to reach out to the `human_assistance` tool once it has the required information. Note that setting `name` and `birthday` in the arguments for the tool, we force the chatbot to generate proposals for these fields." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "10701e49-d4b4-46db-bb30-f895fdf4411d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Can you look up when LangGraph was released? When you have the answer, use the human_assistance tool for review.\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'll start by searching for information about LangGraph's release date using the Tavily search function. Then, I'll use the human_assistance tool for review.\", 'type': 'text'}, {'id': 'toolu_01JoXQPgTVJXiuma8xMVwqAi', 'input': {'query': 'LangGraph release date'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01JoXQPgTVJXiuma8xMVwqAi)\n", - " Call ID: toolu_01JoXQPgTVJXiuma8xMVwqAi\n", - " Args:\n", - " query: LangGraph release date\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://blog.langchain.dev/langgraph-cloud/\", \"content\": \"We also have a new stable release of LangGraph. By LangChain 6 min read Jun 27, 2024 (Oct '24) Edit: Since the launch of LangGraph Cloud, we now have multiple deployment options alongside LangGraph Studio - which now fall under LangGraph Platform. LangGraph Cloud is synonymous with our Cloud SaaS deployment option.\"}, {\"url\": \"https://changelog.langchain.com/announcements/langgraph-cloud-deploy-at-scale-monitor-carefully-iterate-boldly\", \"content\": \"LangChain - Changelog | ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain LangSmith LangGraph LangChain Changelog Sign up for our newsletter to stay up to date DATE: The LangChain Team LangGraph LangGraph Cloud ☁ 🚀 LangGraph Cloud: Deploy at scale, monitor carefully, iterate boldly DATE: June 27, 2024 AUTHOR: The LangChain Team LangGraph Cloud is now in closed beta, offering scalable, fault-tolerant deployment for LangGraph agents. LangGraph Cloud also includes a new playground-like studio for debugging agent failure modes and quick iteration: Join the waitlist today for LangGraph Cloud. And to learn more, read our blog post announcement or check out our docs. Subscribe By clicking subscribe, you accept our privacy policy and terms and conditions.\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Cloud was announced. However, the search results don't provide a specific release date for the original LangGraph. \\n\\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.\", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN)\n", - " Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN\n", - " Args:\n", - " name: Assistant\n", - " birthday: 2023-01-01\n" - ] - } - ], - "source": [ - "user_input = (\n", - " \"Can you look up when LangGraph was released? \"\n", - " \"When you have the answer, use the human_assistance tool for review.\"\n", - ")\n", - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "\n", - "events = graph.stream(\n", - " {\"messages\": [{\"role\": \"user\", \"content\": user_input}]},\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "99dcaf45-e4d1-4597-b669-13a5330740ac", - "metadata": {}, - "source": [ - "We've hit the `interrupt` in the `human_assistance` tool again. In this case, the chatbot failed to identify the correct date, so we can supply it:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "7df33d9e-cc76-4a0f-8307-01e619483b3e", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Based on the search results, it appears that LangGraph was already in existence before June 27, 2024, when LangGraph Cloud was announced. However, the search results don't provide a specific release date for the original LangGraph. \\n\\nGiven this information, I'll use the human_assistance tool to review and potentially provide more accurate information about LangGraph's initial release date.\", 'type': 'text'}, {'id': 'toolu_01JDQAV7nPqMkHHhNs3j3XoN', 'input': {'name': 'Assistant', 'birthday': '2023-01-01'}, 'name': 'human_assistance', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " human_assistance (toolu_01JDQAV7nPqMkHHhNs3j3XoN)\n", - " Call ID: toolu_01JDQAV7nPqMkHHhNs3j3XoN\n", - " Args:\n", - " name: Assistant\n", - " birthday: 2023-01-01\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: human_assistance\n", - "\n", - "Made a correction: {'name': 'LangGraph', 'birthday': 'Jan 17, 2024'}\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for the human assistance. I can now provide you with the correct information about LangGraph's release date.\n", - "\n", - "LangGraph was initially released on January 17, 2024. This information comes from the human assistance correction, which is more accurate than the search results I initially found.\n", - "\n", - "To summarize:\n", - "1. LangGraph's original release date: January 17, 2024\n", - "2. LangGraph Cloud announcement: June 27, 2024\n", - "\n", - "It's worth noting that LangGraph had been in development and use for some time before the LangGraph Cloud announcement, but the official initial release of LangGraph itself was on January 17, 2024.\n" - ] - } - ], - "source": [ - "human_command = Command(\n", - " resume={\n", - " \"name\": \"LangGraph\",\n", - " \"birthday\": \"Jan 17, 2024\",\n", - " },\n", - ")\n", - "\n", - "events = graph.stream(human_command, config, stream_mode=\"values\")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "31581965-8d7d-4378-82b2-f5c2a84a54b1", - "metadata": {}, - "source": [ - "Note that these fields are now reflected in the state:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "b9fe6275-489d-4a6f-b19f-f1000d4133a0", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'name': 'LangGraph', 'birthday': 'Jan 17, 2024'}" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "snapshot = graph.get_state(config)\n", - "\n", - "{k: v for k, v in snapshot.values.items() if k in (\"name\", \"birthday\")}" - ] - }, - { - "cell_type": "markdown", - "id": "14593643-aa81-4b40-9c2d-9408bcaf88cb", - "metadata": {}, - "source": [ - "This makes them easily accessible to downstream nodes (e.g., a node that further processes or stores the information)." - ] - }, - { - "cell_type": "markdown", - "id": "238c359a-24ca-4fbf-8f6c-28a347fee2f2", - "metadata": {}, - "source": [ - "### Manually updating state\n", - "\n", - "LangGraph gives a high degree of control over the application state. For instance, at any point (including when interrupted), we can manually override a key using `graph.update_state`:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "b206e600-91f0-4f46-9587-ab00c05899de", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'configurable': {'thread_id': '1',\n", - " 'checkpoint_ns': '',\n", - " 'checkpoint_id': '1efd4ec5-cf69-6352-8006-9278f1730162'}}" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "graph.update_state(config, {\"name\": \"LangGraph (library)\"})" - ] - }, - { - "cell_type": "markdown", - "id": "3dfb8268-8c5a-4022-9189-6edd231436ae", - "metadata": {}, - "source": [ - "If we call `graph.get_state`, we can see the new value is reflected:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "10adcb89-55ab-4076-bc81-4488eff9e6b3", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'name': 'LangGraph (library)', 'birthday': 'Jan 17, 2024'}" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "snapshot = graph.get_state(config)\n", - "\n", - "{k: v for k, v in snapshot.values.items() if k in (\"name\", \"birthday\")}" - ] - }, - { - "cell_type": "markdown", - "id": "ab34ef46-a836-4dbd-b1ae-56c5e8dc75af", - "metadata": {}, - "source": [ - "Manual state updates will even [generate a trace](https://smith.langchain.com/public/7ebb7827-378d-49fe-9f6c-5df0e90086c8/r) in LangSmith. If desired, they can also be used to control human-in-the-loop workflows, as described in [this guide](../../how-tos/human_in_the_loop/edit-graph-state/). Use of the `interrupt` function is generally recommended instead, as it allows data to be transmitted in a human-in-the-loop interaction independently of state updates.\n", - "\n", - "**Congratulations!** You've added custom keys to the state to facilitate a more complex workflow, and learned how to generate state updates from inside tools.\n", - "\n", - "We're almost done with the tutorial, but there is one more concept we'd like to review before finishing that connects `checkpointing` and `state updates`. \n", - "\n", - "This section's code is reproduced below for your reference.\n", - "\n", - "\n", - "
    \n", - "Full Code\n", - "
    \n",
    -    "\n",
    -    "```python\n",
    -    "from typing import Annotated\n",
    -    "\n",
    -    "from langchain.chat_models import init_chat_model\n",
    -    "from langchain_tavily import TavilySearch\n",
    -    "from langchain_core.messages import ToolMessage\n",
    -    "from langchain_core.tools import InjectedToolCallId, tool\n",
    -    "from typing_extensions import TypedDict\n",
    -    "\n",
    -    "from langgraph.checkpoint.memory import MemorySaver\n",
    -    "from langgraph.graph import StateGraph, START, END\n",
    -    "from langgraph.graph.message import add_messages\n",
    -    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    -    "from langgraph.types import Command, interrupt\n",
    -    "\n",
    -    "\n",
    -    "\n",
    -    "class State(TypedDict):\n",
    -    "    messages: Annotated[list, add_messages]\n",
    -    "    name: str\n",
    -    "    birthday: str\n",
    -    "\n",
    -    "\n",
    -    "@tool\n",
    -    "def human_assistance(\n",
    -    "    name: str, birthday: str, tool_call_id: Annotated[str, InjectedToolCallId]\n",
    -    ") -> str:\n",
    -    "    \"\"\"Request assistance from a human.\"\"\"\n",
    -    "    human_response = interrupt(\n",
    -    "        {\n",
    -    "            \"question\": \"Is this correct?\",\n",
    -    "            \"name\": name,\n",
    -    "            \"birthday\": birthday,\n",
    -    "        },\n",
    -    "    )\n",
    -    "    if human_response.get(\"correct\", \"\").lower().startswith(\"y\"):\n",
    -    "        verified_name = name\n",
    -    "        verified_birthday = birthday\n",
    -    "        response = \"Correct\"\n",
    -    "    else:\n",
    -    "        verified_name = human_response.get(\"name\", name)\n",
    -    "        verified_birthday = human_response.get(\"birthday\", birthday)\n",
    -    "        response = f\"Made a correction: {human_response}\"\n",
    -    "\n",
    -    "    state_update = {\n",
    -    "        \"name\": verified_name,\n",
    -    "        \"birthday\": verified_birthday,\n",
    -    "        \"messages\": [ToolMessage(response, tool_call_id=tool_call_id)],\n",
    -    "    }\n",
    -    "    return Command(update=state_update)\n",
    -    "\n",
    -    "\n",
    -    "tool = TavilySearch(max_results=2)\n",
    -    "tools = [tool, human_assistance]\n",
    -    "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n",
    -    "llm_with_tools = llm.bind_tools(tools)\n",
    -    "\n",
    -    "\n",
    -    "def chatbot(state: State):\n",
    -    "    message = llm_with_tools.invoke(state[\"messages\"])\n",
    -    "    assert(len(message.tool_calls) <= 1)\n",
    -    "    return {\"messages\": [message]}\n",
    -    "\n",
    -    "\n",
    -    "graph_builder = StateGraph(State)\n",
    -    "graph_builder.add_node(\"chatbot\", chatbot)\n",
    -    "\n",
    -    "tool_node = ToolNode(tools=tools)\n",
    -    "graph_builder.add_node(\"tools\", tool_node)\n",
    -    "\n",
    -    "graph_builder.add_conditional_edges(\n",
    -    "    \"chatbot\",\n",
    -    "    tools_condition,\n",
    -    ")\n",
    -    "graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    -    "graph_builder.add_edge(START, \"chatbot\")\n",
    -    "\n",
    -    "memory = MemorySaver()\n",
    -    "graph = graph_builder.compile(checkpointer=memory)\n",
    -    "```\n",
    -    "
    \n", - "
    " - ] - }, - { - "cell_type": "markdown", - "id": "05283db2-2f26-4800-8eda-78a4468a3d8f", - "metadata": {}, - "source": [ - "## Part 6: Time Travel\n", - "\n", - "In a typical chat bot workflow, the user interacts with the bot 1 or more times to accomplish a task. In the previous sections, we saw how to add memory and a human-in-the-loop to be able to checkpoint our graph state and control future responses.\n", - "\n", - "But what if you want to let your user start from a previous response and \"branch off\" to explore a separate outcome? Or what if you want users to be able to \"rewind\" your assistant's work to fix some mistakes or try a different strategy (common in applications like autonomous software engineers)?\n", - "\n", - "You can create both of these experiences and more using LangGraph's built-in \"time travel\" functionality. \n", - "\n", - "In this section, you will \"rewind\" your graph by fetching a checkpoint using the graph's `get_state_history` method. You can then resume execution at this previous point in time.\n", - "\n", - "For this, let's use the simple chatbot with tools from [Part 3](#part-3-adding-memory-to-the-chatbot):" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "bb8a02de-a21b-4ef6-a714-7d6e44435e3a", - "metadata": {}, - "outputs": [], - "source": [ - "from typing import Annotated\n", - "\n", - "from langchain.chat_models import init_chat_model\n", - "from langchain_tavily import TavilySearch\n", - "from langchain_core.messages import BaseMessage\n", - "from typing_extensions import TypedDict\n", - "\n", - "from langgraph.checkpoint.memory import MemorySaver\n", - "from langgraph.graph import StateGraph, START, END\n", - "from langgraph.graph.message import add_messages\n", - "from langgraph.prebuilt import ToolNode, tools_condition\n", - "\n", - "\n", - "class State(TypedDict):\n", - " messages: Annotated[list, add_messages]\n", - "\n", - "\n", - "graph_builder = StateGraph(State)\n", - "\n", - "\n", - "tool = TavilySearch(max_results=2)\n", - "tools = [tool]\n", - "llm = init_chat_model(\"anthropic:claude-3-5-sonnet-latest\")\n", - "llm_with_tools = llm.bind_tools(tools)\n", - "\n", - "\n", - "def chatbot(state: State):\n", - " return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}\n", - "\n", - "\n", - "graph_builder.add_node(\"chatbot\", chatbot)\n", - "\n", - "tool_node = ToolNode(tools=[tool])\n", - "graph_builder.add_node(\"tools\", tool_node)\n", - "\n", - "graph_builder.add_conditional_edges(\n", - " \"chatbot\",\n", - " tools_condition,\n", - ")\n", - "graph_builder.add_edge(\"tools\", \"chatbot\")\n", - "graph_builder.add_edge(START, \"chatbot\")\n", - "\n", - "memory = MemorySaver()\n", - "graph = graph_builder.compile(checkpointer=memory)" - ] - }, - { - "cell_type": "markdown", - "id": "5414c482-215e-4cc0-9eef-4a8722d2f468", - "metadata": {}, - "source": [ - "Let's have our graph take a couple steps. Every step will be checkpointed in its state history:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "69071b02-c011-4b7f-90b1-8e89e032322d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "I'm learning LangGraph. Could you do some research on it for me?\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"Certainly! I'd be happy to research LangGraph for you. To get the most up-to-date and accurate information, I'll use the Tavily search engine to look this up. Let me do that for you now.\", 'type': 'text'}, {'id': 'toolu_01BscbfJJB9EWJFqGrN6E54e', 'input': {'query': 'LangGraph latest information and features'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01BscbfJJB9EWJFqGrN6E54e)\n", - " Call ID: toolu_01BscbfJJB9EWJFqGrN6E54e\n", - " Args:\n", - " query: LangGraph latest information and features\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://blockchain.news/news/langchain-new-features-upcoming-events-update\", \"content\": \"LangChain, a leading platform in the AI development space, has released its latest updates, showcasing new use cases and enhancements across its ecosystem. According to the LangChain Blog, the updates cover advancements in LangGraph Cloud, LangSmith's self-improving evaluators, and revamped documentation for LangGraph.\"}, {\"url\": \"https://blog.langchain.dev/langgraph-platform-announce/\", \"content\": \"With these learnings under our belt, we decided to couple some of our latest offerings under LangGraph Platform. LangGraph Platform today includes LangGraph Server, LangGraph Studio, plus the CLI and SDK. ... we added features in LangGraph Server to deliver on a few key value areas. Below, we'll focus on these aspects of LangGraph Platform.\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Thank you for your patience. I've found some recent information about LangGraph for you. Let me summarize the key points:\n", - "\n", - "1. LangGraph is part of the LangChain ecosystem, which is a leading platform in AI development.\n", - "\n", - "2. Recent updates and features of LangGraph include:\n", - "\n", - " a. LangGraph Cloud: This seems to be a cloud-based version of LangGraph, though specific details weren't provided in the search results.\n", - "\n", - " b. LangGraph Platform: This is a newly introduced concept that combines several offerings:\n", - " - LangGraph Server\n", - " - LangGraph Studio\n", - " - CLI (Command Line Interface)\n", - " - SDK (Software Development Kit)\n", - "\n", - "3. LangGraph Server: This component has received new features to enhance its value proposition, though the specific features weren't detailed in the search results.\n", - "\n", - "4. LangGraph Studio: This appears to be a new tool in the LangGraph ecosystem, likely providing a graphical interface for working with LangGraph.\n", - "\n", - "5. Documentation: The LangGraph documentation has been revamped, which should make it easier for learners like yourself to understand and use the tool.\n", - "\n", - "6. Integration with LangSmith: While not directly part of LangGraph, LangSmith (another tool in the LangChain ecosystem) now features self-improving evaluators, which might be relevant if you're using LangGraph as part of a larger LangChain project.\n", - "\n", - "As you're learning LangGraph, it would be beneficial to:\n", - "\n", - "1. Check out the official LangChain documentation, especially the newly revamped LangGraph sections.\n", - "2. Explore the different components of the LangGraph Platform (Server, Studio, CLI, and SDK) to see which best fits your learning needs.\n", - "3. Keep an eye on LangGraph Cloud developments, as cloud-based solutions often provide an easier starting point for learners.\n", - "4. Consider how LangGraph fits into the broader LangChain ecosystem, especially its interaction with tools like LangSmith.\n", - "\n", - "Is there any specific aspect of LangGraph you'd like to know more about? I'd be happy to do a more focused search on particular features or use cases.\n" - ] - } - ], - "source": [ - "config = {\"configurable\": {\"thread_id\": \"1\"}}\n", - "events = graph.stream(\n", - " {\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": (\n", - " \"I'm learning LangGraph. \"\n", - " \"Could you do some research on it for me?\"\n", - " ),\n", - " },\n", - " ],\n", - " },\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "acbec099-e5d2-497f-929e-c548d7bcbf77", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "================================\u001b[1m Human Message \u001b[0m=================================\n", - "\n", - "Ya that's helpful. Maybe I'll build an autonomous agent with it!\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph is indeed a great application of this technology. LangGraph is particularly well-suited for creating complex, multi-step AI workflows, which is perfect for autonomous agents. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01QWNHhUaeeWcGXvA4eHT7Zo', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01QWNHhUaeeWcGXvA4eHT7Zo)\n", - " Call ID: toolu_01QWNHhUaeeWcGXvA4eHT7Zo\n", - " Args:\n", - " query: Building autonomous agents with LangGraph examples and tutorials\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://github.com/anmolaman20/Tools_and_Agents\", \"content\": \"GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph.\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Great idea! Building an autonomous agent with LangGraph is definitely an exciting project. Based on the latest information I've found, here are some insights and tips for building autonomous agents with LangGraph:\n", - "\n", - "1. Multi-Tool Agents: LangGraph is particularly well-suited for creating autonomous agents that can use multiple tools. This allows your agent to have a diverse set of capabilities and choose the right tool for each task.\n", - "\n", - "2. Integration with Large Language Models (LLMs): You can combine LangGraph with powerful LLMs like Gemini 2.0 to create more intelligent and capable agents. The LLM can serve as the \"brain\" of your agent, making decisions and generating responses.\n", - "\n", - "3. Workflow Management: LangGraph excels at managing complex, multi-step AI workflows. This is crucial for autonomous agents that need to break down tasks into smaller steps and execute them in the right order.\n", - "\n", - "4. Practical Tutorials Available: There are tutorials available that provide full code examples for building and running multi-tool agents. These can be incredibly helpful as you start your project.\n", - "\n", - "5. Langchain Integration: LangGraph is often used in conjunction with Langchain. This combination provides a powerful framework for building AI agents, offering features like memory management, tool integration, and prompt management.\n", - "\n", - "6. GitHub Resources: There are repositories available (like the one by anmolaman20) that provide comprehensive resources for building AI agents using Langchain and LangGraph. These can be valuable references as you develop your agent.\n", - "\n", - "7. Real-time Adaptation: LangGraph allows you to create agents that can think, reason, and adapt in real-time, which is crucial for truly autonomous behavior.\n", - "\n", - "8. Customization: You can equip your agent with specific tools tailored to your use case. For example, you might include tools for web searching, data analysis, or interacting with specific APIs.\n", - "\n", - "To get started with your autonomous agent project:\n", - "\n", - "1. Familiarize yourself with LangGraph's documentation and basic concepts.\n", - "2. Look into tutorials that specifically deal with building autonomous agents, like the one mentioned from Towards Data Science.\n", - "3. Decide on the specific capabilities you want your agent to have and identify the tools it will need.\n", - "4. Start with a simple agent and gradually add complexity as you become more comfortable with the framework.\n", - "5. Experiment with different LLMs to find the one that works best for your use case.\n", - "6. Pay attention to how you structure the agent's decision-making process and workflow.\n", - "7. Don't forget to implement proper error handling and safety measures, especially if your agent will be interacting with external systems or making important decisions.\n", - "\n", - "Building an autonomous agent is an iterative process, so be prepared to refine and improve your agent over time. Good luck with your project! If you need any more specific information as you progress, feel free to ask.\n" - ] - } - ], - "source": [ - "events = graph.stream(\n", - " {\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": (\n", - " \"Ya that's helpful. Maybe I'll \"\n", - " \"build an autonomous agent with it!\"\n", - " ),\n", - " },\n", - " ],\n", - " },\n", - " config,\n", - " stream_mode=\"values\",\n", - ")\n", - "for event in events:\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "b2e48c77-65f3-4075-8030-ebf943a281f1", - "metadata": {}, - "source": [ - "Now that we've had the agent take a couple steps, we can `replay` the full state history to see everything that occurred." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "40953570-66bd-45b9-9469-1d018230d88a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Num Messages: 8 Next: ()\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 7 Next: ('chatbot',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 6 Next: ('tools',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 5 Next: ('chatbot',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 4 Next: ('__start__',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 4 Next: ()\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 3 Next: ('chatbot',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 2 Next: ('tools',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 1 Next: ('chatbot',)\n", - "--------------------------------------------------------------------------------\n", - "Num Messages: 0 Next: ('__start__',)\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "to_replay = None\n", - "for state in graph.get_state_history(config):\n", - " print(\"Num Messages: \", len(state.values[\"messages\"]), \"Next: \", state.next)\n", - " print(\"-\" * 80)\n", - " if len(state.values[\"messages\"]) == 6:\n", - " # We are somewhat arbitrarily selecting a specific state based on the number of chat messages in the state.\n", - " to_replay = state" - ] - }, - { - "cell_type": "markdown", - "id": "b182019e-bae3-4616-ba1b-f845c0ab6636", - "metadata": {}, - "source": [ - "**Notice** that checkpoints are saved for every step of the graph. This __spans invocations__ so you can rewind across a full thread's history. We've picked out `to_replay` as a state to resume from. This is the state after the `chatbot` node in the second graph invocation above.\n", - "\n", - "Resuming from this point should call the **action** node next." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "fdcf00af-8459-4132-85cc-742199391d4f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "('tools',)\n", - "{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1efd43e3-0c1f-6c4e-8006-891877d65740'}}\n" - ] - } - ], - "source": [ - "print(to_replay.next)\n", - "print(to_replay.config)" - ] - }, - { - "cell_type": "markdown", - "id": "7e8c61f5-3a4a-4cce-b81b-43fe1dcc971f", - "metadata": {}, - "source": [ - "**Notice** that the checkpoint's config (`to_replay.config`) contains a `checkpoint_id` **timestamp**. Providing this `checkpoint_id` value tells LangGraph's checkpointer to **load** the state from that moment in time. Let's try it below:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "c5382e81-bfcd-4508-b02a-099e3d9627fd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "[{'text': \"That's an exciting idea! Building an autonomous agent with LangGraph is indeed a great application of this technology. LangGraph is particularly well-suited for creating complex, multi-step AI workflows, which is perfect for autonomous agents. Let me gather some more specific information about using LangGraph for building autonomous agents.\", 'type': 'text'}, {'id': 'toolu_01QWNHhUaeeWcGXvA4eHT7Zo', 'input': {'query': 'Building autonomous agents with LangGraph examples and tutorials'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n", - "Tool Calls:\n", - " tavily_search_results_json (toolu_01QWNHhUaeeWcGXvA4eHT7Zo)\n", - " Call ID: toolu_01QWNHhUaeeWcGXvA4eHT7Zo\n", - " Args:\n", - " query: Building autonomous agents with LangGraph examples and tutorials\n", - "=================================\u001b[1m Tool Message \u001b[0m=================================\n", - "Name: tavily_search_results_json\n", - "\n", - "[{\"url\": \"https://towardsdatascience.com/building-autonomous-multi-tool-agents-with-gemini-2-0-and-langgraph-ad3d7bd5e79d\", \"content\": \"Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph | by Youness Mansar | Jan, 2025 | Towards Data Science Building Autonomous Multi-Tool Agents with Gemini 2.0 and LangGraph A practical tutorial with full code examples for building and running multi-tool agents Towards Data Science LLMs are remarkable — they can memorize vast amounts of information, answer general knowledge questions, write code, generate stories, and even fix your grammar. In this tutorial, we are going to build a simple LLM agent that is equipped with four tools that it can use to answer a user’s question. This Agent will have the following specifications: Follow Published in Towards Data Science --------------------------------- Your home for data science and AI. Follow Follow Follow\"}, {\"url\": \"https://github.com/anmolaman20/Tools_and_Agents\", \"content\": \"GitHub - anmolaman20/Tools_and_Agents: This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository provides resources for building AI agents using Langchain and Langgraph. This repository serves as a comprehensive guide for building AI-powered agents using Langchain and Langgraph. It provides hands-on examples, practical tutorials, and resources for developers and AI enthusiasts to master building intelligent systems and workflows. AI Agent Development: Gain insights into creating intelligent systems that think, reason, and adapt in real time. This repository is ideal for AI practitioners, developers exploring language models, or anyone interested in building intelligent systems. This repository provides resources for building AI agents using Langchain and Langgraph.\"}]\n", - "==================================\u001b[1m Ai Message \u001b[0m==================================\n", - "\n", - "Great idea! Building an autonomous agent with LangGraph is indeed an excellent way to apply and deepen your understanding of the technology. Based on the search results, I can provide you with some insights and resources to help you get started:\n", - "\n", - "1. Multi-Tool Agents:\n", - " LangGraph is well-suited for building autonomous agents that can use multiple tools. This allows your agent to have a variety of capabilities and choose the appropriate tool based on the task at hand.\n", - "\n", - "2. Integration with Large Language Models (LLMs):\n", - " There's a tutorial that specifically mentions using Gemini 2.0 (Google's LLM) with LangGraph to build autonomous agents. This suggests that LangGraph can be integrated with various LLMs, giving you flexibility in choosing the language model that best fits your needs.\n", - "\n", - "3. Practical Tutorials:\n", - " There are tutorials available that provide full code examples for building and running multi-tool agents. These can be invaluable as you start your project, giving you a concrete starting point and demonstrating best practices.\n", - "\n", - "4. GitHub Resources:\n", - " There's a GitHub repository (github.com/anmolaman20/Tools_and_Agents) that provides resources for building AI agents using both Langchain and Langgraph. This could be a great resource for code examples, tutorials, and understanding how LangGraph fits into the broader LangChain ecosystem.\n", - "\n", - "5. Real-Time Adaptation:\n", - " The resources mention creating intelligent systems that can think, reason, and adapt in real-time. This is a key feature of advanced autonomous agents and something you can aim for in your project.\n", - "\n", - "6. Diverse Applications:\n", - " The materials suggest that these techniques can be applied to various tasks, from answering questions to potentially more complex decision-making processes.\n", - "\n", - "To get started with your autonomous agent project using LangGraph, you might want to:\n", - "\n", - "1. Review the tutorials mentioned, especially those with full code examples.\n", - "2. Explore the GitHub repository for hands-on examples and resources.\n", - "3. Decide on the specific tasks or capabilities you want your agent to have.\n", - "4. Choose an LLM to integrate with LangGraph (like GPT, Gemini, or others).\n", - "5. Start with a simple agent that uses one or two tools, then gradually expand its capabilities.\n", - "6. Implement decision-making logic to help your agent choose between different tools or actions.\n", - "7. Test your agent thoroughly with various inputs and scenarios to ensure robust performance.\n", - "\n", - "Remember, building an autonomous agent is an iterative process. Start simple and gradually increase complexity as you become more comfortable with LangGraph and its capabilities.\n", - "\n", - "Would you like more information on any specific aspect of building your autonomous agent with LangGraph?\n" - ] - } - ], - "source": [ - "# The `checkpoint_id` in the `to_replay.config` corresponds to a state we've persisted to our checkpointer.\n", - "for event in graph.stream(None, to_replay.config, stream_mode=\"values\"):\n", - " if \"messages\" in event:\n", - " event[\"messages\"][-1].pretty_print()" - ] - }, - { - "cell_type": "markdown", - "id": "c2501fed-2591-420d-98e0-4a3836fb99a8", - "metadata": {}, - "source": [ - "Notice that the graph resumed execution from the `**action**` node. You can tell this is the case since the first value printed above is the response from our search engine tool.\n", - "\n", - "**Congratulations!** You've now used time-travel checkpoint traversal in LangGraph. Being able to rewind and explore alternative paths opens up a world of possibilities for debugging, experimentation, and interactive applications." - ] - }, - { - "cell_type": "markdown", - "id": "e584d57f-5aad-4507-815f-0b2e4b64b791", - "metadata": {}, - "source": [ - "## Next Steps\n", - "\n", - "Take your journey further by exploring deployment and advanced features:\n", - "\n", - "### Server Quickstart\n", - "\n", - "- **[LangGraph Server Quickstart](../langgraph-platform/local-server)**: Launch a LangGraph server locally and interact with it using the REST API and LangGraph Studio Web UI.\n", - "\n", - "### LangGraph Cloud\n", - "\n", - "- **[LangGraph Cloud QuickStart](../../cloud/quick_start)**: Deploy your LangGraph app using LangGraph Cloud.\n", - "\n", - "### LangGraph Framework\n", - "\n", - "- **[LangGraph Concepts](../../concepts)**: Learn the foundational concepts of LangGraph. \n", - "- **[LangGraph How-to Guides](../../how-tos)**: Guides for common tasks with LangGraph.\n", - "\n", - "### LangGraph Platform\n", - "\n", - "Expand your knowledge with these resources:\n", - "\n", - "- **[LangGraph Platform Concepts](../../concepts#langgraph-platform)**: Understand the foundational concepts of the LangGraph Platform. \n", - "- **[LangGraph Platform How-to Guides](../../how-tos#langgraph-platform)**: Guides for common tasks with LangGraph Platform. " - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/docs/docs/tutorials/langgraph-platform/local-server.md b/docs/docs/tutorials/langgraph-platform/local-server.md index 402ee77f7..b8eefd9a8 100644 --- a/docs/docs/tutorials/langgraph-platform/local-server.md +++ b/docs/docs/tutorials/langgraph-platform/local-server.md @@ -1,19 +1,28 @@ -# Quickstart: Launch Local LangGraph Server +# LangGraph Platform quickstart -This is a quick start guide to help you get a LangGraph app up and running locally. +This guide shows you how to run a LangGraph application locally. -!!! info "Requirements" +## Prerequisites - - Python >= 3.11 - - [LangGraph CLI](https://langchain-ai.github.io/langgraph/cloud/reference/cli/): Requires langchain-cli[inmem] >= 0.1.58 +Before you begin, ensure you have the following: -## Install the LangGraph CLI +- An API key for [LangSmith](https://smith.langchain.com/settings) - free to sign up + +This quickstart uses the `react-agent` template and requires the following: + +- An API key for [Anthropic](https://console.anthropic.com/) +- An API key for [OpenAI](https://openai.com/) +- An API key [Tavily](https://app.tavily.com/) + +## 1. Install the LangGraph CLI ```bash +# Python >= 3.11 is required. + pip install --upgrade "langgraph-cli[inmem]" ``` -## 🌱 Create a LangGraph App +## 2. Create a LangGraph app 🌱 Create a new app from the `react-agent` template. This template is a simple agent that can be flexibly extended to many tools. @@ -29,22 +38,31 @@ Create a new app from the `react-agent` template. This template is a simple agen langgraph new path/to/your/app --template react-agent-js ``` -!!! tip "Additional Templates" +!!! tip "Additional templates" If you use `langgraph new` without specifying a template, you will be presented with an interactive menu that will allow you to choose from a list of available templates. -## Install Dependencies +## 3. Install dependencies In the root of your new LangGraph app, install the dependencies in `edit` mode so your local changes are used by the server: -```shell -pip install -e . -``` +=== "Python server" -## Create a `.env` file + ```shell + cd path/to/your/app + pip install -e . + ``` -You will find a `.env.example` in the root of your new LangGraph app. Create -a `.env` file in the root of your new LangGraph app and copy the contents of the `.env.example` file into it, filling in the necessary API keys: +=== "Node server" + + ```shell + cd path/to/your/app + yarn install + ``` + +## 4. Create a `.env` file + +You will find a `.env.example` in the root of your new LangGraph app. Create a `.env` file in the root of your new LangGraph app and copy the contents of the `.env.example` file into it, filling in the necessary API keys: ```bash LANGSMITH_API_KEY=lsv2... @@ -53,21 +71,25 @@ ANTHROPIC_API_KEY=sk- OPENAI_API_KEY=sk-... ``` -??? note "Get API Keys" +## 5. Launch LangGraph Server 🚀 - - **LANGSMITH_API_KEY**: Go to the [LangSmith Settings page](https://smith.langchain.com/settings). Then clck **Create API Key**. - - **ANTHROPIC_API_KEY**: Get an API key from [Anthropic](https://console.anthropic.com/). - - **OPENAI_API_KEY**: Get an API key from [OpenAI](https://openai.com/). - - **TAVILY_API_KEY**: Get an API key on the [Tavily website](https://app.tavily.com/). +Start the LangGraph API server locally: -## 🚀 Launch LangGraph Server +=== "Python Server" + + ```shell + langgraph dev + ``` + +=== "Node Server" + + ```shell + npx @langchain/langgraph-cli dev + ``` + +Sample output: -```shell -langgraph dev ``` - -This will start up the LangGraph API server locally. If this runs successfully, you should see something like: - > Ready! > > - API: [http://localhost:2024](http://localhost:2024/) @@ -75,133 +97,130 @@ This will start up the LangGraph API server locally. If this runs successfully, > - Docs: http://localhost:2024/docs > > - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 +``` +The `langgraph dev` command starts LangGraph Server in an in-memory mode. This mode is suitable for development and testing purposes. For production use, deploy LangGraph Server with access to a persistent storage backend. For more information, see [Deployment options](../../concepts/deployment_options.md). -!!! note "In-Memory Mode" +## 6. Test your application in LangGraph Studio - The `langgraph dev` command starts LangGraph Server in an in-memory mode. This mode is suitable for development and testing purposes. For production use, you should deploy LangGraph Server with access to a persistent storage backend. - - If you want to test your application with a persistent storage backend, you can use the `langgraph up` command instead of `langgraph dev`. You will - need to have `docker` installed on your machine to use this command. - -## LangGraph Studio Web UI - -LangGraph Studio Web is a specialized UI that you can connect to LangGraph API server to enable visualization, interaction, and debugging of your application locally. Test your graph in the LangGraph Studio Web UI by visiting the URL provided in the output of the `langgraph dev` command. +[LangGraph Studio](../../concepts/langgraph_studio.md) is a specialized UI that you can connect to LangGraph API server to visualize, interact with, and debug your application locally. Test your graph in LangGraph Studio by visiting the URL provided in the output of the `langgraph dev` command: +``` > - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024 +``` -!!! info "Connecting to a server with a custom host/port" +For a LangGraph Server running on a custom host/port, update the baseURL parameter. - If you are running the LangGraph API server with a custom host / port, you can point the Studio Web UI at it by changing the `baseUrl` URL param. For example, if you are running your server on port 8000, you can change the above URL to the following: - - ``` - https://smith.langchain.com/studio/baseUrl=http://127.0.0.1:8000 - ``` - - -!!! warning "Safari Compatibility" +??? info "Safari compatibility" + + Use the `--tunnel` flag with your command to create a secure tunnel, as Safari has limitations when connecting to localhost servers: - Currently, LangGraph Studio Web does not support Safari when running a server locally. - -## Test the API - -=== "Python SDK (Async)" - - **Install the LangGraph Python SDK** - ```shell - pip install langgraph-sdk + langgraph dev --tunnel ``` - **Send a message to the assistant (threadless run)** +## 7. Test the API - ```python - from langgraph_sdk import get_client +=== "Python SDK (async)" - client = get_client(url="http://localhost:2024") + 1. Install the LangGraph Python SDK: - async for chunk in client.runs.stream( - None, # Threadless run - "agent", # Name of assistant. Defined in langgraph.json. - input={ - "messages": [{ - "role": "human", - "content": "What is LangGraph?", - }], - }, - stream_mode="updates", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` + ```shell + pip install langgraph-sdk + ``` -=== "Python SDK (Sync)" + 1. Send a message to the assistant (threadless run): - **Install the LangGraph Python SDK** + ```python + from langgraph_sdk import get_client + import asyncio - ```shell - pip install langgraph-sdk - ``` + client = get_client(url="http://localhost:2024") - **Send a message to the assistant (threadless run)** + async def main(): + async for chunk in client.runs.stream( + None, # Threadless run + "agent", # Name of assistant. Defined in langgraph.json. + input={ + "messages": [{ + "role": "human", + "content": "What is LangGraph?", + }], + }, + ): + print(f"Receiving new event of type: {chunk.event}...") + print(chunk.data) + print("\n\n") - ```python - from langgraph_sdk import get_sync_client + asyncio.run(main()) + ``` - client = get_sync_client(url="http://localhost:2024") +=== "Python SDK (sync)" - for chunk in client.runs.stream( - None, # Threadless run - "agent", # Name of assistant. Defined in langgraph.json. - input={ - "messages": [{ - "role": "human", - "content": "What is LangGraph?", - }], - }, - stream_mode="updates", - ): - print(f"Receiving new event of type: {chunk.event}...") - print(chunk.data) - print("\n\n") - ``` + 1. Install the LangGraph Python SDK: + + ```shell + pip install langgraph-sdk + ``` + + 1. Send a message to the assistant (threadless run): + + ```python + from langgraph_sdk import get_sync_client + + client = get_sync_client(url="http://localhost:2024") + + for chunk in client.runs.stream( + None, # Threadless run + "agent", # Name of assistant. Defined in langgraph.json. + input={ + "messages": [{ + "role": "human", + "content": "What is LangGraph?", + }], + }, + stream_mode="messages-tuple", + ): + print(f"Receiving new event of type: {chunk.event}...") + print(chunk.data) + print("\n\n") + ``` === "Javascript SDK" - **Install the LangGraph JS SDK** + 1. Install the LangGraph JS SDK: - ```shell - npm install @langchain/langgraph-sdk - ``` + ```shell + npm install @langchain/langgraph-sdk + ``` - **Send a message to the assistant (threadless run)** + 1. Send a message to the assistant (threadless run): - ```js - const { Client } = await import("@langchain/langgraph-sdk"); + ```js + const { Client } = await import("@langchain/langgraph-sdk"); - // only set the apiUrl if you changed the default port when calling langgraph dev - const client = new Client({ apiUrl: "http://localhost:2024"}); + // only set the apiUrl if you changed the default port when calling langgraph dev + const client = new Client({ apiUrl: "http://localhost:2024"}); - const streamResponse = client.runs.stream( - null, // Threadless run - "agent", // Assistant ID - { - input: { - "messages": [ - { "role": "user", "content": "What is LangGraph?"} - ] - }, - streamMode: "messages", + const streamResponse = client.runs.stream( + null, // Threadless run + "agent", // Assistant ID + { + input: { + "messages": [ + { "role": "user", "content": "What is LangGraph?"} + ] + }, + streamMode: "messages-tuple", + } + ); + + for await (const chunk of streamResponse) { + console.log(`Receiving new event of type: ${chunk.event}...`); + console.log(JSON.stringify(chunk.data)); + console.log("\n\n"); } - ); - - for await (const chunk of streamResponse) { - console.log(`Receiving new event of type: ${chunk.event}...`); - console.log(JSON.stringify(chunk.data)); - console.log("\n\n"); - } - ``` + ``` === "Rest API" @@ -219,35 +238,16 @@ LangGraph Studio Web is a specialized UI that you can connect to LangGraph API s } ] }, - \"stream_mode\": \"updates\" + \"stream_mode\": \"messages-tuple\" }" ``` -!!! tip "Auth" - - If you're connecting to a remote server, you will need to provide a LangSmith - API Key for authorization. Please see the API Reference for the clients - for more information. - ## Next Steps Now that you have a LangGraph app running locally, take your journey further by exploring deployment and advanced features: -### 🌐 Deploy to LangGraph Cloud - -- **[LangGraph Cloud Quickstart](../../cloud/quick_start.md)**: Deploy your LangGraph app using LangGraph Cloud. - -### 📚 Learn More about LangGraph Platform - -Expand your knowledge with these resources: - -- **[LangGraph Platform Concepts](../../concepts/index.md#langgraph-platform)**: Understand the foundational concepts of the LangGraph Platform. -- **[LangGraph Platform How-to Guides](../../how-tos/index.md#langgraph-platform)**: Discover step-by-step guides to build and deploy applications. - -### 🛠️ Developer References - -Access detailed documentation for development and API usage: - -- **[LangGraph Server API Reference](../../cloud/reference/api/api_ref.html)**: Explore the LangGraph Server API documentation. -- **[Python SDK Reference](../../cloud/reference/sdk/python_sdk_ref.md)**: Explore the Python SDK API Reference. -- **[JS/TS SDK Reference](../../cloud/reference/sdk/js_ts_sdk_ref.md)**: Explore the JS/TS SDK API Reference. +- [Deployment quickstart](../../cloud/quick_start.md): Deploy your LangGraph app using LangGraph Platform. +- [LangGraph Platform overview](../../concepts/langgraph_platform.md): Learn about foundational LangGraph Platform concepts. +- [LangGraph Server API Reference](../../cloud/reference/api/api_ref.html): Explore the LangGraph Server API documentation. +- [Python SDK Reference](../../cloud/reference/sdk/python_sdk_ref.md): Explore the Python SDK API Reference. +- [JS/TS SDK Reference](../../cloud/reference/sdk/js_ts_sdk_ref.md): Explore the JS/TS SDK API Reference. diff --git a/docs/docs/tutorials/workflows/index.md b/docs/docs/tutorials/workflows.md similarity index 98% rename from docs/docs/tutorials/workflows/index.md rename to docs/docs/tutorials/workflows.md index 0ae1012c7..a96c6d431 100644 --- a/docs/docs/tutorials/workflows/index.md +++ b/docs/docs/tutorials/workflows.md @@ -11,7 +11,7 @@ This guide reviews common patterns for agentic systems. In describing these syst Here is a simple way to visualize these differences: -![Agent Workflow](../../concepts/img/agent_workflow.png) +![Agent Workflow](../concepts/img/agent_workflow.png) When building agents and workflows, LangGraph offers a number of benefits including persistence, streaming, and support for debugging as well as deployment. @@ -47,7 +47,7 @@ llm = ChatAnthropic(model="claude-3-5-sonnet-latest") LLM have augmentations that support building workflows and agents. These include [structured outputs](https://python.langchain.com/docs/concepts/structured_outputs/) and [tool calling](https://python.langchain.com/docs/concepts/tool_calling/), as shown in this image from the Anthropic blog on `Building Effective Agents`: -![augmented_llm.png](./img/augmented_llm.png) +![augmented_llm.png](./workflows/img/augmented_llm.png) ```python @@ -91,7 +91,7 @@ As noted in the Anthropic blog on `Building Effective Agents`: > When to use this workflow: This workflow is ideal for situations where the task can be easily and cleanly decomposed into fixed subtasks. The main goal is to trade off latency for higher accuracy, by making each LLM call an easier task. -![prompt_chain.png](./img/prompt_chain.png) +![prompt_chain.png](./workflows/img/prompt_chain.png) === "Graph API" @@ -252,7 +252,7 @@ With parallelization, LLMs work simultaneously on a task: > When to use this workflow: Parallelization is effective when the divided subtasks can be parallelized for speed, or when multiple perspectives or attempts are needed for higher confidence results. For complex tasks with multiple considerations, LLMs generally perform better when each consideration is handled by a separate LLM call, allowing focused attention on each specific aspect. -![parallelization.png](./img/parallelization.png) +![parallelization.png](./workflows/img/parallelization.png) === "Graph API" @@ -402,7 +402,7 @@ Routing classifies an input and directs it to a followup task. As noted in the A > When to use this workflow: Routing works well for complex tasks where there are distinct categories that are better handled separately, and where classification can be handled accurately, either by an LLM or a more traditional classification model/algorithm. -![routing.png](./img/routing.png) +![routing.png](./workflows/img/routing.png) === "Graph API" @@ -613,7 +613,7 @@ With orchestrator-worker, an orchestrator breaks down a task and delegates each > When to use this workflow: This workflow is well-suited for complex tasks where you can’t predict the subtasks needed (in coding, for example, the number of files that need to be changed and the nature of the change in each file likely depend on the task). Whereas it’s topographically similar, the key difference from parallelization is its flexibility—subtasks aren't pre-defined, but determined by the orchestrator based on the specific input. -![worker.png](./img/worker.png) +![worker.png](./workflows/img/worker.png) === "Graph API" @@ -857,7 +857,7 @@ In the evaluator-optimizer workflow, one LLM call generates a response while ano > When to use this workflow: This workflow is particularly effective when we have clear evaluation criteria, and when iterative refinement provides measurable value. The two signs of good fit are, first, that LLM responses can be demonstrably improved when a human articulates their feedback; and second, that the LLM can provide such feedback. This is analogous to the iterative writing process a human writer might go through when producing a polished document. -![evaluator_optimizer.png](./img/evaluator_optimizer.png) +![evaluator_optimizer.png](./workflows/img/evaluator_optimizer.png) === "Graph API" @@ -1022,7 +1022,7 @@ Agents are typically implemented as an LLM performing actions (via tool-calling) > When to use agents: Agents can be used for open-ended problems where it’s difficult or impossible to predict the required number of steps, and where you can’t hardcode a fixed path. The LLM will potentially operate for many turns, and you must have some level of trust in its decision-making. Agents' autonomy makes them ideal for scaling tasks in trusted environments. -![agent.png](./img/agent.png) +![agent.png](./workflows/img/agent.png) ```python diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 5bc53e8ee..167be2d46 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -21,21 +21,20 @@ theme: - content.tooltips - header.autohide - navigation.indexes - - navigation.expand - navigation.footer - navigation.instant - navigation.sections - navigation.instant.prefetch - navigation.instant.progress - navigation.path - - navigation.prune - navigation.tabs + - navigation.tabs.sticky - navigation.top + - navigation.prune - navigation.tracking - search.highlight - search.share - search.suggest - - toc.follow palette: - scheme: default primary: white @@ -92,279 +91,21 @@ plugins: - "!^_" nav: - - LangGraph: + - Guides: - index.md - Get started: - - Learn the basics: tutorials/introduction.ipynb - - Deployment: - - tutorials/deployment.md - - Local Deploy: tutorials/langgraph-platform/local-server.md - - Template Applications: concepts/template_applications.md # TODO: make tutorial - - Cloud Deploy: cloud/quick_start.md - - Guides: - - How-to Guides: - - how-tos/index.md - - LangGraph: - - Graph API Basics: - - how-tos/state-reducers.ipynb - - how-tos/sequence.ipynb - - how-tos/branching.ipynb - - how-tos/recursion-limit.ipynb - - how-tos/visualization.ipynb - - Controllability: - - how-tos/map-reduce.ipynb - - how-tos/command.ipynb - - how-tos/configuration.ipynb - - how-tos/node-retries.ipynb - - how-tos/return-when-recursion-limit-hits.ipynb - - Persistence: - - how-tos/persistence.ipynb - - how-tos/subgraph-persistence.ipynb - - how-tos/cross-thread-persistence.ipynb - - how-tos/persistence_postgres.ipynb - - how-tos/persistence_mongodb.ipynb - - how-tos/persistence_redis.ipynb - - how-tos/persistence-functional.ipynb - - how-tos/cross-thread-persistence-functional.ipynb - - Memory: - - how-tos/memory/manage-conversation-history.ipynb - - how-tos/memory/delete-messages.ipynb - - how-tos/memory/add-summary-conversation-history.ipynb - - how-tos/memory/semantic-search.ipynb - - Human-in-the-loop: - - how-tos/human_in_the_loop/breakpoints.ipynb - - how-tos/human_in_the_loop/dynamic_breakpoints.ipynb - - how-tos/human_in_the_loop/edit-graph-state.ipynb - - how-tos/human_in_the_loop/wait-user-input.ipynb - - how-tos/human_in_the_loop/time-travel.ipynb - - how-tos/human_in_the_loop/review-tool-calls.ipynb - - how-tos/wait-user-input-functional.ipynb - - how-tos/review-tool-calls-functional.ipynb - - Streaming: - - how-tos/streaming.ipynb - - how-tos/streaming-tokens.ipynb - - how-tos/streaming-specific-nodes.ipynb - - how-tos/streaming-events-from-within-tools.ipynb - - how-tos/streaming-subgraphs.ipynb - - how-tos/disable-streaming.ipynb - - Tool calling: - - how-tos/tool-calling.ipynb - - how-tos/tool-calling-errors.ipynb - - how-tos/pass-run-time-values-to-tools.ipynb - - how-tos/update-state-from-tools.ipynb - - how-tos/pass-config-to-tools.ipynb - - how-tos/many-tools.ipynb - - Subgraphs: - - how-tos/subgraph.ipynb - - how-tos/subgraphs-manage-state.ipynb - - how-tos/subgraph-transform-state.ipynb - - Multi-agent: - - how-tos/agent-handoffs.ipynb - - how-tos/multi-agent-network.ipynb - - how-tos/multi-agent-multi-turn-convo.ipynb - - how-tos/multi-agent-network-functional.ipynb - - how-tos/multi-agent-multi-turn-convo-functional.ipynb - - State Management: - - how-tos/state-model.ipynb - - how-tos/input_output_schema.ipynb - - how-tos/pass_private_state.ipynb - - Other: - - how-tos/async.ipynb - - how-tos/react-agent-structured-output.ipynb - - how-tos/run-id-langsmith.ipynb - - how-tos/autogen-integration.ipynb - - how-tos/autogen-integration-functional.ipynb - - Prebuilt ReAct Agent: - - how-tos/create-react-agent-manage-message-history.ipynb - - how-tos/react-agent-from-scratch.ipynb - - how-tos/react-agent-from-scratch-functional.ipynb - - LangGraph Platform: - - Application Structure: - - cloud/deployment/setup.md - - cloud/deployment/setup_pyproject.md - - cloud/deployment/setup_javascript.md - - cloud/deployment/semantic_search.md - - cloud/deployment/custom_docker.md - - cloud/deployment/test_locally.md - - cloud/deployment/graph_rebuild.md - - how-tos/autogen-langgraph-platform.ipynb - - Deployment: - - cloud/deployment/cloud.md - - cloud/deployment/self_hosted_data_plane.md - - cloud/deployment/self_hosted_control_plane.md - - cloud/deployment/standalone_container.md - - how-tos/deploy-self-hosted.md - - how-tos/use-remote-graph.md - - how-tos/ttl/configure_ttl.md - - Data Management: - - how-tos/ttl/configure_ttl.md - - Authentication & Access Control: - - how-tos/auth/custom_auth.md - - how-tos/auth/openapi_security.md - - Assistants: - - cloud/how-tos/configuration_cloud.md - - cloud/how-tos/assistant_versioning.md - - Threads: - - cloud/how-tos/copy_threads.md - - cloud/how-tos/check_thread_status.md - - Runs: - - cloud/how-tos/background_run.md - - cloud/how-tos/same-thread.md - - cloud/how-tos/cron_jobs.md - - cloud/how-tos/stateless_runs.md - - cloud/how-tos/configurable_headers.md - - Streaming: - - cloud/how-tos/stream_values.md - - cloud/how-tos/stream_updates.md - - cloud/how-tos/stream_messages.md - - cloud/how-tos/stream_events.md - - cloud/how-tos/stream_debug.md - - cloud/how-tos/stream_multiple.md - - cloud/how-tos/use_stream_react.md - - cloud/how-tos/generative_ui_react.md - - Human-in-the-loop: - - cloud/how-tos/human_in_the_loop_breakpoint.md - - cloud/how-tos/human_in_the_loop_user_input.md - - cloud/how-tos/human_in_the_loop_edit_state.md - - cloud/how-tos/human_in_the_loop_time_travel.md - - cloud/how-tos/human_in_the_loop_review_tool_calls.md - - Double-texting: - - cloud/how-tos/interrupt_concurrent.md - - cloud/how-tos/rollback_concurrent.md - - cloud/how-tos/reject_concurrent.md - - cloud/how-tos/enqueue_concurrent.md - - Webhooks: - - cloud/how-tos/webhooks.md - - Cron Jobs: - - cloud/how-tos/cron_jobs.md - - Modifying the API: - - how-tos/http/custom_lifespan.md - - how-tos/http/custom_middleware.md - - how-tos/http/custom_routes.md - - LangGraph Studio: - - cloud/how-tos/test_deployment.md - - cloud/how-tos/test_local_deployment.md - - cloud/how-tos/invoke_studio.md - - cloud/how-tos/threads_studio.md - - cloud/how-tos/datasets_studio.md - - cloud/how-tos/iterate_graph_studio.md - - cloud/how-tos/clone_traces_studio.md - - how-tos/local-studio.md - - Concepts: - - concepts/index.md - - LangGraph: - - concepts/high_level.md - - concepts/low_level.md - - concepts/agentic_concepts.md - - concepts/multi_agent.md - - concepts/breakpoints.md - - concepts/human_in_the_loop.md - - concepts/v0-human-in-the-loop.md - - concepts/time-travel.md - - concepts/persistence.md - - concepts/memory.md - - concepts/streaming.md - - concepts/functional_api.md - - concepts/durable_execution.md - - concepts/pregel.md - - LangGraph Platform: - - High Level: - - concepts/langgraph_platform.md - - concepts/platform_architecture.md - - concepts/scalability_and_resilience.md - - concepts/deployment_options.md - - concepts/bring_your_own_cloud.md - - concepts/plans.md - - concepts/template_applications.md - - Components: - - concepts/langgraph_control_plane.md - - concepts/langgraph_data_plane.md - - concepts/langgraph_server.md - - concepts/langgraph_studio.md - - concepts/langgraph_cli.md - - concepts/sdk.md - - how-tos/use-remote-graph.md - - LangGraph Server: - - concepts/application_structure.md - - concepts/assistants.md - - concepts/double_texting.md - - concepts/auth.md - - concepts/server-mcp.md - - Deployment Options: - - concepts/langgraph_cloud.md - - concepts/langgraph_self_hosted_data_plane.md - - concepts/langgraph_self_hosted_control_plane.md - - concepts/langgraph_standalone_container.md - - concepts/self_hosted.md - - Tutorials: - - tutorials/index.md - - Quick Start: - - tutorials/introduction.ipynb - - tutorials/workflows/index.md - - tutorials/langgraph-platform/local-server.md - - cloud/quick_start.md - - Chatbots: - - tutorials/customer-support/customer-support.ipynb - - tutorials/chatbots/information-gather-prompting.ipynb - - tutorials/code_assistant/langgraph_code_assistant.ipynb - - RAG: - - tutorials/rag/langgraph_adaptive_rag.ipynb - - tutorials/rag/langgraph_adaptive_rag_local.ipynb - - tutorials/rag/langgraph_agentic_rag.ipynb - - tutorials/rag/langgraph_crag.ipynb - - tutorials/rag/langgraph_crag_local.ipynb - - tutorials/rag/langgraph_self_rag.ipynb - - tutorials/rag/langgraph_self_rag_local.ipynb - - tutorials/sql-agent.ipynb - - Agent Architectures: - - Multi-Agent Systems: - - tutorials/multi_agent/multi-agent-collaboration.ipynb - - tutorials/multi_agent/agent_supervisor.ipynb - - tutorials/multi_agent/hierarchical_agent_teams.ipynb - - Planning Agents: - - tutorials/plan-and-execute/plan-and-execute.ipynb - - tutorials/rewoo/rewoo.ipynb - - tutorials/llm-compiler/LLMCompiler.ipynb - - Reflection & Critique: - - tutorials/reflection/reflection.ipynb - - tutorials/reflexion/reflexion.ipynb - - tutorials/tot/tot.ipynb - - tutorials/lats/lats.ipynb - - tutorials/self-discover/self-discover.ipynb - - Evaluation & Analysis: - - tutorials/chatbot-simulation-evaluation/agent-simulation-evaluation.ipynb - - tutorials/chatbot-simulation-evaluation/langsmith-agent-simulation-evaluation.ipynb - - Experimental: - - tutorials/storm/storm.ipynb - - tutorials/tnt-llm/tnt-llm.ipynb - - tutorials/web-navigation/web_voyager.ipynb - - tutorials/usaco/usaco.ipynb - - tutorials/extraction/retries.ipynb - - LangGraph Platform: - - tutorials/auth/getting_started.md - - tutorials/auth/resource_auth.md - - tutorials/auth/add_auth_server.md - - Resources: - - Companies using LangGraph: adopters.md - - LLMS-txt: llms-txt-overview.md - - FAQ: concepts/faq.md - - Troubleshooting: - - Troubleshooting: troubleshooting/errors/index.md - - troubleshooting/errors/index.md - - troubleshooting/errors/GRAPH_RECURSION_LIMIT.md - - troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md - - troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md - - troubleshooting/errors/MULTIPLE_SUBGRAPHS.md - - troubleshooting/errors/INVALID_CHAT_HISTORY.md - - troubleshooting/errors/INVALID_LICENSE.md - - troubleshooting/studio.md - - LangGraph Academy Course: https://academy.langchain.com/courses/intro-to-langgraph - - - Agents: - - agents/overview.md - - Get started: - - agents/agents.md - - Documentation: + - Quickstart: agents/agents.md + - LangGraph basics: + - concepts/why-langgraph.md + - Build a basic chatbot: tutorials/get-started/1-build-basic-chatbot.md + - tutorials/get-started/2-add-tools.md + - tutorials/get-started/3-add-memory.md + - Add human-in-the-loop: tutorials/get-started/4-human-in-the-loop.md + - tutorials/get-started/5-customize-state.md + - tutorials/get-started/6-time-travel.md + - Deployment: tutorials/deployment.md + - Prebuilt agents: + - Overview: agents/overview.md - agents/run_agents.md - agents/streaming.md - agents/models.md @@ -377,21 +118,158 @@ nav: - agents/evals.md - agents/deployment.md - agents/ui.md - - Resources: - # NOTE: prebuilt.md is auto-generated by `make build-prebuilt` - - agents/prebuilt.md + - LangGraph framework: + - Agent architectures: + - Overview: concepts/agentic_concepts.md + - Workflows & agents: tutorials/workflows.md + - Graphs: + - Overview: concepts/low_level.md + - Use the Graph API: how-tos/graph-api.ipynb + - Persistence: + - Overview: concepts/persistence.md + - concepts/durable_execution.md + - how-tos/persistence.ipynb + - Memory: + - Overview: concepts/memory.md + - Manage memory: how-tos/memory.ipynb + - Human-in-the-loop: + - Overview: concepts/human_in_the_loop.md + - how-tos/human_in_the_loop/add-human-in-the-loop.md + - Streaming: + - Overview: concepts/streaming.md + - "Stream outputs": how-tos/streaming.md + - Breakpoints: + - Overview: concepts/breakpoints.md + - how-tos/human_in_the_loop/breakpoints.ipynb + - Time travel: + - Overview: concepts/time-travel.md + - how-tos/human_in_the_loop/time-travel.ipynb + - Tools: + - Overview: concepts/tools.md + - how-tos/tool-calling.ipynb + - Subgraphs: + - Overview: concepts/subgraphs.md + - how-tos/subgraph.ipynb + - Multi-agent: + - Overview: concepts/multi_agent.md + - how-tos/multi_agent.ipynb + - Functional API: + - Overview: concepts/functional_api.md + - how-tos/use-functional-api.md + - concepts/pregel.md + - Other: + # We want to push async higher (need to check the content inside it) + # and convert it into a concept rather than a how-to page. + - how-tos/async.ipynb + - how-tos/run-id-langsmith.ipynb + - how-tos/autogen-integration.ipynb + + - LangGraph Platform: + - Overview: concepts/langgraph_platform.md + - Get started: + - Quickstart: tutorials/langgraph-platform/local-server.md + - Deployment quickstart: cloud/quick_start.md + - Components: + - Overview: concepts/langgraph_components.md + - LangGraph Server: + - Overview: concepts/langgraph_server.md + - Application structure: + - Overview: concepts/application_structure.md + - cloud/deployment/setup.md + - cloud/deployment/setup_pyproject.md + - cloud/deployment/setup_javascript.md + - cloud/deployment/custom_docker.md + - LangGraph CLI: concepts/langgraph_cli.md + - LangGraph Studio: + - Overview: concepts/langgraph_studio.md + - Quickstart: cloud/how-tos/studio/quick_start.md + - cloud/how-tos/invoke_studio.md + - cloud/how-tos/threads_studio.md + - cloud/how-tos/datasets_studio.md + - cloud/how-tos/iterate_graph_studio.md + - cloud/how-tos/clone_traces_studio.md + - LangGraph SDK: concepts/sdk.md + - Data management: + - cloud/deployment/semantic_search.md + - how-tos/ttl/configure_ttl.md + - Authentication & access control: + - Overview: concepts/auth.md + - how-tos/auth/custom_auth.md + - how-tos/auth/openapi_security.md + - Assistants: + - Overview: concepts/assistants.md + - cloud/how-tos/configuration_cloud.md + - cloud/how-tos/assistant_versioning.md + - Threads: + - Overview: cloud/concepts/threads.md + - cloud/how-tos/copy_threads.md + - cloud/how-tos/check_thread_status.md + - Runs: + - Overview: cloud/concepts/runs.md + - cloud/how-tos/background_run.md + - cloud/how-tos/same-thread.md + - cloud/how-tos/cron_jobs.md + - cloud/how-tos/stateless_runs.md + - cloud/how-tos/configurable_headers.md + - Streaming: + - Overview: cloud/concepts/streaming.md + - cloud/how-tos/streaming.md + - Human-in-the-loop: + - cloud/how-tos/human_in_the_loop_breakpoint.md + - cloud/how-tos/human_in_the_loop_user_input.md + - cloud/how-tos/human_in_the_loop_edit_state.md + - cloud/how-tos/human_in_the_loop_time_travel.md + - cloud/how-tos/human_in_the_loop_review_tool_calls.md + - MCP: + - Overview: concepts/server-mcp.md + - Double-texting: + - Overview: concepts/double_texting.md + - cloud/how-tos/interrupt_concurrent.md + - cloud/how-tos/rollback_concurrent.md + - cloud/how-tos/reject_concurrent.md + - cloud/how-tos/enqueue_concurrent.md + - Webhooks: + - Overview: cloud/concepts/webhooks.md + - cloud/how-tos/webhooks.md + - Cron Jobs: + - Overview: cloud/concepts/cron_jobs.md + - cloud/how-tos/cron_jobs.md + - Server Customization: + - how-tos/http/custom_lifespan.md + - how-tos/http/custom_middleware.md + - how-tos/http/custom_routes.md + - Deployment: + - Overview: concepts/deployment_options.md + - Data Plane: concepts/langgraph_data_plane.md + - Control Plane: concepts/langgraph_control_plane.md + - Deployment options: + - Cloud SaaS: + - Overview: concepts/langgraph_cloud.md + - Deploy Cloud SaaS: cloud/deployment/cloud.md + - Self-Hosted Data Plane: + - Overview: concepts/langgraph_self_hosted_data_plane.md + - Deploy Self-Hosted Data Plane: cloud/deployment/self_hosted_data_plane.md + - Self-Hosted Control Plane: + - Overview: concepts/langgraph_self_hosted_control_plane.md + - Deploy Self-Hosted Control Plane: cloud/deployment/self_hosted_control_plane.md + - Standalone Container: + - Overview: concepts/langgraph_standalone_container.md + - Deploy Standalone Container: cloud/deployment/standalone_container.md + - Scalability and resilience: concepts/scalability_and_resilience.md + - Plans and pricing: concepts/plans.md + - Reference: - reference/index.md - LangGraph: - Graphs: reference/graphs.md + - Functional API: reference/func.md + - Pregel: reference/pregel.md - Checkpointing: reference/checkpoints.md - Storage: reference/store.md - Types: reference/types.md - Config: reference/config.md - - Functional API: reference/func.md - Errors: reference/errors.md - Constants: reference/constants.md - - Pregel: reference/pregel.md - Channels: reference/channels.md - Prebuilt: - Agents: reference/agents.md @@ -399,12 +277,48 @@ nav: - Swarm: reference/swarm.md - MCP Adapters: reference/mcp.md - LangGraph Platform: - - Server API: "cloud/reference/api/api_ref.md" - - CLI: "cloud/reference/cli.md" - - SDK (Python): "cloud/reference/sdk/python_sdk_ref.md" - - SDK (JS/TS): "cloud/reference/sdk/js_ts_sdk_ref.md" + - Server API: cloud/reference/api/api_ref.md + - CLI: cloud/reference/cli.md + - SDK (Python): cloud/reference/sdk/python_sdk_ref.md + - SDK (JS/TS): cloud/reference/sdk/js_ts_sdk_ref.md - RemoteGraph: reference/remote_graph.md - - Environment variables: "cloud/reference/env_var.md" + - Environment variables: cloud/reference/env_var.md + + - Examples: + - Agentic RAG: tutorials/rag/langgraph_agentic_rag.ipynb + - Agent Supervisor: tutorials/multi_agent/agent_supervisor.ipynb + - Customer Support: tutorials/customer-support/customer-support.ipynb + - SQL agent: tutorials/sql-agent.ipynb + - LangGraph Platform: + - Authentication: + - tutorials/auth/getting_started.md + - tutorials/auth/resource_auth.md + - tutorials/auth/add_auth_server.md + - Rebuild graph at runtime: cloud/deployment/graph_rebuild.md + - how-tos/use-remote-graph.md + - how-tos/autogen-langgraph-platform.ipynb + - Front-end and generative UI: + - Integrate LangGraph into a React app: cloud/how-tos/use_stream_react.md + - Implement generative UI with LangGraph: cloud/how-tos/generative_ui_react.md + + - Resources: + - concepts/faq.md + - agents/prebuilt.md # NOTE: prebuilt.md is auto-generated by `make build-prebuilt` + - Template applications: concepts/template_applications.md # TODO: make tutorial + - llms.txt: llms-txt-overview.md + - Troubleshooting: + - Errors: + - troubleshooting/errors/index.md + - troubleshooting/errors/GRAPH_RECURSION_LIMIT.md + - troubleshooting/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md + - troubleshooting/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md + - troubleshooting/errors/MULTIPLE_SUBGRAPHS.md + - troubleshooting/errors/INVALID_CHAT_HISTORY.md + - troubleshooting/errors/INVALID_LICENSE.md + - LangGraph Studio: troubleshooting/studio.md + - Learn: + - LangGraph Academy course: https://academy.langchain.com/courses/intro-to-langgraph + - Case studies: adopters.md markdown_extensions: - abbr @@ -500,7 +414,7 @@ extra: validation: # https://www.mkdocs.org/user-guide/configuration/ # We are still raising for omitted files because they determine the breadcrumbs for pages. - omitted_files: warn + omitted_files: info absolute_links: warn unrecognized_links: warn # TODO: figure out how to enable 'warn' for this @@ -513,5 +427,7 @@ validation: copyright: > Copyright © 2025 LangChain, Inc | Consent Preferences extra_css: + - stylesheets/navigation_title_ovverides.css - stylesheets/version_admonitions.css - stylesheets/logos.css + - stylesheets/sticky_navigation.css \ No newline at end of file diff --git a/docs/overrides/main.html b/docs/overrides/main.html index 9fb05670c..c2e7fe9e4 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -169,6 +169,10 @@ color: #000000; } + .md-header__title { + visibility: hidden; + } + /* Dark mode banner links */ [data-md-color-scheme="slate"] .md-banner a { color: #000000; @@ -178,15 +182,6 @@ color: #000000; } - /* control the navbar depth */ - [data-md-level="2"] .md-nav { - display: none; - } - - /* disable the collapse/expand icon in the navar */ - .md-nav__icon { - display: none; - } {% endblock %} diff --git a/docs/snippets/chat_model_tabs.md b/docs/snippets/chat_model_tabs.md new file mode 100644 index 000000000..107b493fc --- /dev/null +++ b/docs/snippets/chat_model_tabs.md @@ -0,0 +1,79 @@ +=== "OpenAI" + + ``` + pip install -U "langchain[openai]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["OPENAI_API_KEY"] = "sk-..." + + llm = init_chat_model("openai:gpt-4.1") + ``` + +=== "Anthropic" + + ``` + pip install -U "langchain[anthropic]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["ANTHROPIC_API_KEY"] = "sk-..." + + llm = init_chat_model("anthropic:claude-3-5-sonnet-latest") + ``` + +=== "Azure" + + ``` + pip install -U "langchain[openai]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["AZURE_OPENAI_API_KEY"] = "..." + os.environ["AZURE_OPENAI_ENDPOINT"] = "..." + os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview" + + llm = init_chat_model( + "azure_openai:gpt-4.1", + azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"], + ) + ``` + + +=== "Google Gemini" + + ``` + pip install -U "langchain[google-genai]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + os.environ["GOOGLE_API_KEY"] = "..." + + llm = init_chat_model("google_genai:gemini-2.0-flash") + ``` + +=== "AWS Bedrock" + + ``` + pip install -U "langchain[aws]" + ``` + ```python + import os + from langchain.chat_models import init_chat_model + + # Follow the steps here to configure your credentials: + # https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html + + llm = init_chat_model( + "anthropic.claude-3-5-sonnet-20240620-v1:0", + model_provider="bedrock_converse", + ) + ``` diff --git a/docs/stats.yml b/docs/stats.yml new file mode 100644 index 000000000..1e8abb034 --- /dev/null +++ b/docs/stats.yml @@ -0,0 +1,58 @@ +# This file is auto-generated. Do not edit. +- description: Tenacious tool calling built on LangGraph. + name: trustcall + repo: hinthornw/trustcall + weekly_downloads: -12345 +- description: A streamlined research system built inspired on STORM and built on + LangGraph. + name: breeze-agent + repo: andrestorres123/breeze-agent + weekly_downloads: -12345 +- description: Build supervisor multi-agent systems with LangGraph. + name: langgraph-supervisor + repo: langchain-ai/langgraph-supervisor-py + weekly_downloads: -12345 +- description: Build agents that learn and adapt from interactions over time. + name: langmem + repo: langchain-ai/langmem + weekly_downloads: -12345 +- description: Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph + agents. + name: langchain-mcp-adapters + repo: langchain-ai/langchain-mcp-adapters + weekly_downloads: -12345 +- description: Open source assistant for iterative web research and report writing. + name: open-deep-research + repo: langchain-ai/open_deep_research + weekly_downloads: -12345 +- description: Build swarm-style multi-agent systems using LangGraph. + name: langgraph-swarm + repo: langchain-ai/langgraph-swarm-py + weekly_downloads: -12345 +- description: A taxonomy generator for unstructured data + name: delve-taxonomy-generator + repo: andrestorres123/delve + weekly_downloads: -12345 +- description: Enable researcher to build scientific workflows easily with simplified + interface. + name: nodeology + repo: xyin-anl/Nodeology + weekly_downloads: -12345 +- description: Build LangGraph agents with large numbers of tools. + name: langgraph-bigtool + repo: langchain-ai/langgraph-bigtool + weekly_downloads: -12345 +- description: An AI-powered data science team of agents to help you perform common + data science tasks 10X faster. + name: ai-data-science-team + repo: business-science/ai-data-science-team + weekly_downloads: -12345 +- description: LangGraph agent that runs a reflection step. + name: langgraph-reflection + repo: langchain-ai/langgraph-reflection + weekly_downloads: -12345 +- description: LangGraph implementation of CodeAct agent that generates and executes + code instead of tool calling. + name: langgraph-codeact + repo: langchain-ai/langgraph-codeact + weekly_downloads: -12345 diff --git a/examples/introduction.ipynb b/examples/introduction.ipynb deleted file mode 100644 index ef8da7c11..000000000 --- a/examples/introduction.ipynb +++ /dev/null @@ -1,39 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "08c0351b", - "metadata": {}, - "source": [ - "This file has been moved to https://github.com/langchain-ai/langgraph/blob/main/docs/docs/tutorials/introduction.ipynb" - ] - }, - { - "cell_type": "markdown", - "id": "e8363fbc", - "metadata": {}, - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "env", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/libs/langgraph/README.md b/libs/langgraph/README.md index 799ab4b9a..ae8f0084f 100644 --- a/libs/langgraph/README.md +++ b/libs/langgraph/README.md @@ -16,48 +16,41 @@ > [!NOTE] > Looking for the JS version? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://langchain-ai.github.io/langgraphjs/). -LangGraph — used by Replit, Uber, LinkedIn, GitLab and more — is a low-level orchestration framework for building controllable agents. While langchain provides integrations and composable components to streamline LLM application development, the LangGraph library enables agent orchestration — offering customizable architectures, long-term memory, and human-in-the-loop to reliably handle complex tasks. +LangGraph is a low-level orchestration framework for building controllable agents. While [LangChain](https://python.langchain.com/docs/introduction/) provides integrations and composable components to streamline LLM application development, the LangGraph library enables agent orchestration — offering customizable architectures, long-term memory, and human-in-the-loop to reliably handle complex tasks. -```bash +## Get started + +First, install LangGraph: + +``` pip install -U langgraph ``` -To learn more about how to use LangGraph, check out [the docs](https://langchain-ai.github.io/langgraph/). We show a simple example below of how to create a ReAct agent. +There are two ways to get started with LangGraph: -```python -# This code depends on pip install langchain[anthropic] -from langgraph.prebuilt import create_react_agent +- [Use prebuilt components](https://langchain-ai.github.io/langgraph/agents/agents/): Construct agentic systems quickly and reliably without the need to implement orchestration, memory, or human feedback handling from scratch. +- [Use LangGraph](https://langchain-ai.github.io/langgraph/tutorials/introduction/): Customize your architectures, use long-term memory, and implement human-in-the-loop to reliably handle complex tasks. -def search(query: str): - """Call to surf the web.""" - if "sf" in query.lower() or "san francisco" in query.lower(): - return "It's 60 degrees and foggy." - return "It's 90 degrees and sunny." +Once you have a LangGraph application and are ready to move into production, use [LangGraph Platform](https://langchain-ai.github.io/langgraph/cloud/quick_start/) to test, debug, and deploy your application. -agent = create_react_agent("anthropic:claude-3-7-sonnet-latest", tools=[search]) -agent.invoke( - {"messages": [{"role": "user", "content": "what is the weather in sf"}]} -) -``` +## What LangGraph provides -> [!TIP] -> Check out [this guide](https://langchain-ai.github.io/langgraph/tutorials/workflows/) that walks through implementing common patterns (workflows and agents) in LangGraph. +LangGraph provides low-level supporting infrastructure that sits underneath *any* workflow or agent. It does not abstract prompts or architecture, and provides three central benefits: -## Why use LangGraph? +### Persistence -LangGraph is built for developers who want to build powerful, adaptable AI agents. Developers choose LangGraph for: +LangGraph has a [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), which offers a number of benefits: -- **Reliability and controllability.** Steer agent actions with moderation checks and human-in-the-loop approvals. LangGraph persists context for long-running workflows, keeping your agents on course. -- **Low-level and extensible.** Build custom agents with fully descriptive, low-level primitives – free from rigid abstractions that limit customization. Design scalable multi-agent systems, with each agent serving a specific role tailored to your use case. -- **First-class streaming support.** With token-by-token streaming and streaming of intermediate steps, LangGraph gives users clear visibility into agent reasoning and actions as they unfold in real time. +- [Memory](https://langchain-ai.github.io/langgraph/concepts/memory/): LangGraph persists arbitrary aspects of your application's state, supporting memory of conversations and other updates within and across user interactions; +- [Human-in-the-loop](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): Because state is checkpointed, execution can be interrupted and resumed, allowing for decisions, validation, and corrections via human input. -LangGraph is trusted in production and powering agents for companies like: +### Streaming -- [Klarna](https://blog.langchain.dev/customers-klarna/): Customer support bot for 85 million active users -- [Elastic](https://www.elastic.co/blog/elastic-security-generative-ai-features): Security AI assistant for threat detection -- [Uber](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/): Automated unit test generation -- [Replit](https://www.langchain.com/breakoutagents/replit): Code generation -- And many more ([see list here](https://www.langchain.com/built-with-langgraph)) +LangGraph provides support for [streaming](https://langchain-ai.github.io/langgraph/concepts/streaming/) workflow / agent state to the user (or developer) over the course of execution. LangGraph supports streaming of both events ([such as feedback from a tool call](https://langchain-ai.github.io/langgraph/how-tos/streaming.ipynb#updates)) and [tokens from LLM calls](https://langchain-ai.github.io/langgraph/how-tos/streaming-tokens.ipynb) embedded in an application. + +### Debugging and deployment + +LangGraph provides an easy onramp for testing, debugging, and deploying applications via [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). This includes [Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/), an IDE that enables visualization, interaction, and debugging of workflows or agents. This also includes numerous [options](https://langchain-ai.github.io/langgraph/tutorials/deployment/) for deployment. ## LangGraph’s ecosystem @@ -66,24 +59,14 @@ While LangGraph can be used standalone, it also integrates seamlessly with any L - [LangSmith](http://www.langchain.com/langsmith) — Helpful for agent evals and observability. Debug poor-performing LLM app runs, evaluate agent trajectories, gain visibility in production, and improve performance over time. - [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/#langgraph-platform) — Deploy and scale agents effortlessly with a purpose-built deployment platform for long running, stateful workflows. Discover, reuse, configure, and share agents across teams — and iterate quickly with visual prototyping in [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/). -## Pairing with LangGraph Platform - -While LangGraph is our open-source agent orchestration framework, enterprises that need scalable agent deployment can benefit from [LangGraph Platform](https://langchain-ai.github.io/langgraph/concepts/langgraph_platform/). - -LangGraph Platform can help engineering teams: - -- **Accelerate agent development**: Quickly create agent UXs with configurable templates and [LangGraph Studio](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/) for visualizing and debugging agent interactions. -- **Deploy seamlessly**: We handle the complexity of deploying your agent. LangGraph Platform includes robust APIs for memory, threads, and cron jobs plus auto-scaling task queues & servers. -- **Centralize agent management & reusability**: Discover, reuse, and manage agents across the organization. Business users can also modify agents without coding. - ## Additional resources +- [Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.). +- [Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components. +- [Examples](https://langchain-ai.github.io/langgraph/tutorials/): Guided examples on getting started with LangGraph. - [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course. -- [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Simple walkthroughs with guided examples on getting started with LangGraph. - [Templates](https://langchain-ai.github.io/langgraph/concepts/template_applications/): Pre-built reference apps for common agentic workflows (e.g. ReAct agent, memory, retrieval etc.) that can be cloned and adapted. -- [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Quick, actionable code snippets for topics such as streaming, adding memory & persistence, and design patterns (e.g. branching, subgraphs, etc.). -- [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Detailed reference on core classes, methods, how to use the graph and checkpointing APIs, and higher-level prebuilt components. -- [Built with LangGraph](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. +- [Case studies](https://www.langchain.com/built-with-langgraph): Hear how industry leaders use LangGraph to ship powerful, production-ready AI applications. ## Acknowledgements