Compare commits

...
Author SHA1 Message Date
Sydney Runkle 6fc5b3aeda release(langgraph): 0.6.7 (#6092) 2025-09-07 13:49:43 +00:00
Harrison Chase b543752878 chore: update emphemeral local (#6091)
basically - for conditional edges, we use this to merge the updates from
state with the state object (before the actual update really occurs in
the tick.after)

otherwise - an emphemeral value will actually last through the logic in
the conditional edge of the node after
2025-09-07 09:42:11 -04:00
William FH 8f6ad0b25a chore(sdk-py): Cleanup docstring indentation (#6087) 2025-09-05 22:56:03 +00:00
Isaac Francisco ada5d2ecb1 feat(cli): bump version (#6086)
version bump for: https://github.com/langchain-ai/langgraph/pull/6085
2025-09-05 15:52:30 -07:00
Isaac Francisco eaeafe54ab feat(cli): support prereleases (#6085)
We previously errored when a user had prerelease dependencies, this PR
passes the `--prereleases=allow` flag to our `uv pip install` call.

This PR also adds a test to verify that said deployments will build and
run as expected.
2025-09-05 15:45:48 -07:00
William FH f761116de7 chore(sdk-py): Clean up docstring for get_client (#6084)
Main thing here is to call out the ASGITransport behavior
2025-09-05 13:43:31 -07:00
Nuno Campos 36cf353d19 fix: Unwrap Required/NotRequired special forms before resolving channel/reducer annotations (#6080) 2025-09-05 10:27:10 +01:00
Isaac FranciscoandWilliam FH d503c0bf33 WIP: monorepo support in CLI (#6028)
This PR introduces the `--build-command` and `--install-command`
arguments to `langgraph build`.

`--install-command` is a custom install command. If passed, it will be
run from wherever the `langgraph build` call was made, i.e. NOT where
the langgraph.json file lives (except if these are the same place). This
will override the detected install command that we previously used.

`--build-command` is a custom build command. This will run from wherever
the langgraph.json file lives, and will be done after the install has
been run.

You don't need to provide both. Just providing one will make the install
(detected or supplied) run in the directory from where `langgraph build
was called` and then have the build command (if one exists) run in the
directory where langgraph.json exists.

I think we should probably allow configuring the directories from which
these commands get run, but I don't think this needs to be part of the
MVP.

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-09-04 12:29:11 -07:00
William FH 25ba4c3bda feat(sdk-py): Specify ttl on thread creation and update (#6075) 2025-09-03 18:48:57 -07:00
William FHandhinthornw dfc1c59ebf chore(docs): Update OpenAPI spec from LangGraph API v0.4.11 (#6074)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.11**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-03 18:37:39 -07:00
William FH 6f4c5fefee feat(sdk-py): Support ids filtering in threads search (#6067) 2025-09-02 17:49:11 -07:00
William FHandhinthornw 7cf230defa chore(docs): Update OpenAPI spec from LangGraph API v0.4.9 (#6066)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.9**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-02 17:04:30 -07:00
William FHandhinthornw 5db65e0281 chore(docs): Update OpenAPI spec from LangGraph API v0.4.8 (#6065)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.8**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-02 15:25:52 -07:00
William FHandhinthornw b08c2e092f chore(docs): Update OpenAPI spec from LangGraph API v0.4.8 (#6048)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.8**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-09-02 10:10:12 -07:00
Sydney Runkle 120ae38c12 chore(docs): fix runtime context link (#6043) 2025-08-29 13:45:39 -04:00
Isaac Francisco 22942d4eec release(sdk-py): 0.2.4 (#6038) 2025-08-28 23:34:33 +00:00
Isaac Francisco 1756ce1dd2 feat(sdk-py): add endpoint for thread streaming (#6009)
SDK support for:
https://github.com/langchain-ai/langgraph-api/pull/1217/
2025-08-28 16:12:04 +00:00
Isaac Francisco 0b4638269b feat(sdk-py): add durability flag (#5963) 2025-08-27 19:21:25 +00:00
Isaac Francisco 1ebdb1ba31 chore: Update schema for new config allowed in LGP (#5875) 2025-08-27 11:20:06 -07:00
hari-dhanushkodi f3423c052e fix(docs): add revision queuing docs (#5997) 2025-08-27 07:47:45 -07:00
William FHandhinthornw b63572ee16 chore: Update OpenAPI spec from LangGraph API v0.4.0 (#6011)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.4.0**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-08-26 20:51:30 -07:00
William FH ddf4e62bde release(cli): 0.4.0 (#6014)
Relax upper-bound to permit server versions 0.4.*
2025-08-26 12:59:12 +00:00
William FH d73902ae76 feat(sdk-py): Count endpoints (#5986) 2025-08-21 18:15:52 +00:00
William FH 501ba8be34 release(cli): Bump max bound of langgraph-api (#5978) 2025-08-21 00:59:27 +00:00
William FH 998e194e82 release(cli): Support bookworm, trixie, etc. (#5975)
Also add support for pinning to a semantic version.
2025-08-20 15:40:04 +00:00
William FHandhinthornw ef65d3cf88 chore(cli): Update OpenAPI spec from LangGraph API v0.2.137 (#5967)
This PR updates the OpenAPI specification with changes detected from the
LangGraph API server.

**Changes detected as of LangGraph API version 0.2.137**

This update was automatically generated by the sync workflow in the
langgraph-api repository.

Co-authored-by: hinthornw <hinthornw@users.noreply.github.com>
2025-08-20 07:42:33 -07:00
William FH a692e24a58 fix(langgraph): Remote Baggage (#5964)
Fix baggage propagation for opt-in distributed tracing when no
additional headers are provided.
2025-08-20 01:47:12 +00:00
Brody a566f1f892 fix(docs): update sales links (#5956)
**Description:** updates sales team links to point to our form.
  
**Issue:** DOC-170 (internal Linear ticket)
2025-08-19 08:11:51 -07:00
William FH c0b29a6df5 chore(langgraph): Add passthrough params/headers to invoke/stream/etc. (#5940) 2025-08-18 19:38:08 +00:00
Ankit R. a86eb4c5d0 docs(persistence): fix StateSnapshot formatting (#5928)
This PR fixes a minor formatting inconsistency in the StateSnapshot
examples within persistence.md.

Specifically, the next=('node_b',) value was inline with values={...},
which is inconsistent with other snapshots.
It has been moved to a new line for better readability and consistency
across examples.
2025-08-18 19:33:43 +00:00
William FH 3488eb2a2c chore(sdk-py): Update types (#5939) 2025-08-18 18:29:07 +00:00
wakita181009 875f20ba9f feat(sdk-py): define aclose method to LangGraphClient (#5931)
This PR adds an aclose method to the LangGraphClient.

When using the client in a FastAPI application, it's common to share a
single instance across the application's lifespan. The absence of an
aclose method makes it difficult to gracefully close the underlying HTTP
session on application shutdown. This change enables proper resource
management by allowing the client to be closed cleanly.
2025-08-18 11:22:02 -07:00
William FH 723d4641b0 chore(sdk-py): Update params type in SDK (#5937) 2025-08-18 17:53:20 +00:00
William FH ae62b8faf2 chore: Update release check of version (#5936) 2025-08-18 10:18:53 -07:00
William FH 9918488169 feat(sdk-py): client qparams (#5918)
And add linting & dyanmic version string
2025-08-18 10:05:24 -07:00
Lauren Hirata Singh c37c9cbab3 docs: update redirects (#5935) 2025-08-18 09:14:49 -07:00
William FH 0cd8745aad feat(sdk-py): Select-statement (#5933) 2025-08-18 06:42:01 -07:00
Lauren Hirata Singh 33d13c6f52 docs: update banner (#5911) 2025-08-14 10:54:18 -07:00
Lauren Hirata Singh 054e2759ca docs: banner for deep research (#5908)
Publish at 10AM PT
2025-08-14 10:04:48 -07:00
William FH 23b71048c1 release(langgraph): 0.6.5 (#5901) 2025-08-13 23:35:58 +00:00
Nuno Campos a15f542a1f fix: Persist resume_map values (#5898)
Thank you for contributing to LangGraph! Follow these steps to mark your
pull request as ready for review. **If any of these steps are not
completed, your PR will not be considered for review.**

- [ ] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION}
  - Examples:
    - feat(core): add multi-tenant support
    - fix(cli): resolve flag parsing error
    - docs(openai): update API usage examples
  - Allowed `{TYPE}` values:
- feat, fix, docs, style, refactor, perf, test, build, ci, chore,
revert, release
  - Allowed `{SCOPE}` values (optional):
- langgraph, docs, cli, checkpoint, checkpoint-postgres,
checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py
- Once you've written the title, please delete this checklist item; do
not include it in the PR.

- [ ] **PR message**: ***Delete this entire checklist*** and replace
with
- **Description:** a description of the change. Include a [closing
keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword)
if applicable.
  - **Issue:** the issue # it fixes, if applicable
  - **Dependencies:** any dependencies required for this change
- **Twitter handle:** if your PR gets announced, and you'd like a
mention, we'll gladly shout you out!

- [ ] **Add tests and docs**: If you're adding a new integration, you
must include:
1. A test for the integration, preferably unit tests that do not rely on
network access,
2. An example notebook showing its use. It lives in
`docs/docs/integrations` directory.

- [ ] **Lint and test**: Run `make format`, `make lint` and `make test`
from the root of the package(s) you've modified. We will not consider a
PR unless these three are passing in CI. See [contribution
guidelines](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md)
for more.

Additional guidelines:

- Make sure optional dependencies are imported within a function.
- Please do not add dependencies to `pyproject.toml` files (even
optional ones) unless they are **required** for unit tests.
- Most PRs should not touch more than one package.
- Changes should be backwards compatible.
2025-08-13 19:33:20 +01:00
Hunter LovellandBrody Klapko d43eaf1f42 chore(docs): add remaining js translations (#5825)
Related Linear ticket:
https://linear.app/langchain/issue/DOC-51/add-js-translations-for-remaining-pages

---------

Co-authored-by: Brody Klapko <brody@langchain.dev>
2025-08-12 09:47:11 -04:00
Sam Crowder 16b363fbb0 feat(langgraph): implement redis node level cache (#5834)
###   Description

Adds Redis as a supported cache backend for LangGraph node-level
caching, enabling distributed caching across multiple processes/servers.
This implementation follows the same patterns as existing InMemoryCache
and SqliteCache.

###  Key changes
  - New RedisCache class implementing the BaseCache interface
  - Support for TTL-based expiration and batch operations
  - Worker-specific cache prefixes for parallel test isolation

###  Dependencies

  - redis package (already included in dev dependencies)

### Test Plan

- Unit tests: Added Redis cache tests covering basic operations, TTL,
batch operations, and error handling
- Integration tests: Redis cache integrated into existing LangGraph test
suite, tested with all checkpointer combinations
2025-08-11 09:19:34 -07:00
Sydney Runkle 68a75135b0 release: langgraph + prebuilt 0.6.4 (#5854) 2025-08-07 18:12:26 +00:00
Isaac Francisco 5c0c0fb186 fix: mypy issue with conditional edges (#5851)
Send should inherit from hashable, and need to use Sequence since List
is invariant.

https://github.com/langchain-ai/langgraph/issues/5850
2025-08-07 08:46:44 -07:00
Eugene YurtsevandSydney Runkle 4571b708d9 fix(langgraph): support emitting messages from subgraphs when messages mode explicitly requested (#5836)
Reproduces:
https://github.com/langchain-ai/langgraph/issues/5249#issuecomment-3156519635
Caused after this change:
https://github.com/langchain-ai/langgraph/pull/4843

Fix to allow emitting messages from subgraphs if the subgraphs
explicitly used a stream mode "messages".

```python

def node_in_parent(...):
   # subgraph was called as a function.
   # messages are explicitly requested.
   for event in subgraph.stream(..., stream_mode="messages"):
      # something is done with `event`
   return ...

# subgraphs = False!
parent_graph.invoke(..., subgraphs=False)
```

The code above should continue to work correctly regardless of the value
of subgraphs as streaming messages was requested explicitly in the
parent node!

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-08-07 10:10:52 -04:00
Sydney Runkle e365b2b8bd fix(prebuilt): raise on additional deprecated kwargs (#5848) 2025-08-06 21:08:42 +00:00
Isaac Francisco b5504506a7 fix: add resiliency for task cancellation (#5846) 2025-08-06 13:31:52 -07:00
Nuno Campos c6ae8d25b9 perf: Save updated_channels to checkpoint (#5828)
- This makes prepare_next_tasks constant on number of nodes in all
cases, whereas before we were falling back to node iteration when
resuming from an existing checkpoint
2025-08-06 19:09:33 +01:00
Sydney Runkle 0bd7dd2c52 chore(langgraph): deprecate MessageGraph (#5843)
`MessageGraph` is deprecated, to be removed in v2.

A `StateGraph` with a `messages` key should be used instead.
Alternatively, folks can use `Annotated[list[AnyMessage], add_messages]` as their state schema.
2025-08-06 14:17:50 +00:00
Sydney Runkle 82978a8dd8 chore(prebuilt): revert tool arg injection refactor (#5842)
Reverts https://github.com/langchain-ai/langgraph/pull/5562

I anticipate that we want to do another pass at a refactor here in the
short term, but this makes it easier to adapt to new langchain core
message types for v0.4 support in the short term.
2025-08-06 10:12:08 -04:00
Kathryn May 925150a35d docs: Update redirects for deployment option renaming (#5823)
Updates the URLs for the new site deployment options after a rename.
2025-08-04 15:32:11 -04:00
Sydney Runkle 2920a9dd19 fix(langgraph): Tidy up AgentState (#5801)
Fixes https://github.com/langchain-ai/langgraph/issues/5784

* Removes usage of `is_last_step`, no longer needed with
`remaining_steps`
* Make `remaining_steps` `NotRequired` so that json schema doesn't
suggest need for user input
* Move `PregelScratchpad` to shared utils file to prevent circular
import issue (it's used from `channels/managed` and other pregel files).
* Ensures that managed values wrapped in `NotRequired` or `Required` are
still recognized!
2025-08-03 07:12:53 -04:00
Eugene Yurtsev db8ed4e9e4 fix(docs): update agents.md (#5800)
fix comment in tip
2025-08-02 06:09:09 -04:00
Lauren Hirata Singh b16fcc8468 docs: remove broken links (#5803) 2025-08-01 15:41:21 -04:00
Sydney Runkle a2fe4df89b release: langgraph + prebuilt 0.6.3 (#5799) 2025-08-01 14:52:38 -04:00
69dd20e523 fix(langgraph): Add warning for incorrect node signature with mistyped config param (#5798)
Fixes: #5787

Ensures that if `config` is not typed as one of `RunanbleConfig` or
`Optional[RunnableConfig]` a warning is raised to help developers avoid
unexpected results at invocation time.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
2025-08-01 17:25:14 +00:00
open-swe[bot]andopen-swe[bot] 5152a96fce fix(docs): Correct import statement for InMemorySaver in conceptual docs (#5797)
Fixes #5781

Fixes the incorrect import statement in the Python documentation
tutorial.

- Changed import from `MemorySaver` to `InMemorySaver`
- Ensures consistency between import statement and class instantiation
- Verified through formatting and linting checks

The documentation now correctly reflects the proper import for the
InMemorySaver class.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2025-08-01 14:54:30 +00:00
Sydney Runkle 220314b53a fix(langgraph): fix up deprecation warnings (#5796)
Fixes https://github.com/langchain-ai/langgraph/issues/5795

* Must use `category=None` on decorator so that we get type checking
support but no dupe warning
* Fixed tuple on `confix_type` warning causing false warning
2025-08-01 14:33:46 +00:00
38bbd92e01 feat(langgraph): add durability mode for invoke and ainvoke (#5771)
Fixes https://github.com/langchain-ai/langgraph/issues/5741

Follow up to https://github.com/langchain-ai/langgraph/pull/5432

Plus clean up deprecation logic for `checkpoint_during` and add tests.

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-08-01 10:30:24 -04:00
Eugene Yurtsev e3cb2dd23b chore(docs): fix more admonitions (#5792)
Fix more admonitions
2025-07-31 22:57:44 -04:00
Eugene Yurtsev 2f23d1a30d chore(docs): fix js build (#5793)
Fix js build
2025-07-31 22:57:32 -04:00
Eugene Yurtsev 88e195bb78 chore(docs): fix admonitions in graph api page (#5791)
fix many admonitions in the graph API page
2025-07-31 21:50:27 -04:00
Lauren Hirata SinghandHunter Lovell 41a4f993b1 docs: Update link maps for reference docs (#5745)
Update link maps

---------

Co-authored-by: Hunter Lovell <hunter@hntrl.io>
2025-07-31 18:06:35 -04:00
b8f3f48da9 fix(docs): Add missing imports to make examples runnable (#5477)
I suppose that the code snippets are intended to run each on its own. To
guarantee this the snippet for the example:
"Write long-temr memory from tools"
needs to include `RunnableConfig`
Same also for the second commit of this pull request.

The other commits are about similar issues, where imports are missing to
make a snippet executable on its own.

---------

Signed-off-by: Kai Wendel <kai.wendel@iws.uni-stuttgart.de>
Co-authored-by: Eugene Yurtsev <eugene@langchain.dev>
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-31 20:04:52 +00:00
MichaelandLauren Hirata Singh 94f7f0632d docs(docs): fix image in "Run graph nodes in parallel" section of N Graph API how-to (#5527)
**Description:**
Replaced the outdated image in the "Run graph nodes in parallel" section
of the N Graph API how-to guide to correctly show parallel node
execution.

**Twitter handle:** @MichaelLoukeris

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-31 20:02:33 +00:00
Xin Jin b3e0582255 docs: clarify draw_mermaid_png only works in jupyter (#5609)
Nit, without comments I thought image would somehow show in terminal,
but that's not true you'd only get image to show if in jupyter notebook.
Don't have to merge, i'm just seeing this particular as not a pleasure
DevX.

<img width="848" height="440" alt="Screenshot 2025-07-21 at 12 26 04 PM"
src="https://github.com/user-attachments/assets/50261b35-f09d-4516-86f4-14e8bf53f8e2"
/>
2025-07-31 15:54:45 -04:00
Srikanto RajbongshiandLauren Hirata Singh 24c7a8db3f Remove duplicated pretty_print_messages helper in Multi‑agent supervisor tutorial (#5617)
**Description:**  
Closes #___

Removed the redundant `pretty_print_message`/`pretty_print_messages`
helper snippet from
`docs/docs/tutorials/multi_agent/agent_supervisor.md`. Now there is a
single, authoritative definition of these functions, which:

- Simplifies the tutorial  
- Avoids reader confusion over which helper to use  
- Prevents future drift between duplicate code blocks  

**Issue:** Closes #___  
**Dependencies:** None

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-31 19:54:22 +00:00
Sakshi GuptaandEugene Yurtsev f8eb4244e0 docs(graphapi): update the graph image for the "Combine control flow and state updates with Command" example (#5626)
The example had the node names as - node_a, node_b & node_c. But the
graph shows the image of generate_topics. This change includes the
addition of complete & accurate graph.

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-31 19:52:55 +00:00
Syed Baqar Abbas 62c3bbc9fe docs: Removed repetition of block pretty_print_messages (#5636)
## docs: Removed repetition of block pretty_print_messages
- **Description:** The documentation had the same cell duplicated, I
fixed it by deleting one example
  - **Issue:** #5616
2025-07-31 19:49:48 +00:00
Kathryn May 76bbb761b4 docs: Add studio troubleshooting to redirects (#5783)
Add a redirect from
https://langchain-ai.github.io/langgraph/troubleshooting/studio/ to
https://docs.langchain.com/langgraph-platform/troubleshooting-studio
2025-07-31 15:31:35 -04:00
Sydney Runkle 80cd91344f chore: no ci on v1 branch (#5782) 2025-07-31 19:08:10 +00:00
Lauren Hirata Singh 9e4c41cbed docs: remove LGP mentions (#5780) 2025-07-31 14:13:56 -04:00
Shehab 1fda568df9 fix(docs): extended examples in graph API docs (#5774)
Fixes #5770
2025-07-31 18:00:54 +00:00
Mohammad MohtashimandEugene Yurtsev 08295ecadb chore(prebuilt): add supported input types for model in create_react_agent (#5748)
- **Description:** Update the type annotations in create_react_agent to
allow one to provide a callable for the model that uses bind_tools and
returns a Runnable[LanguageModelInput, BaseMessage]
  - **Issue:** #5739

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-31 14:00:12 -04:00
Lauren Hirata Singh 4ecbabafe8 docs: redirects for LGP mintlify (#5767)
- Added redirects for all of the LGP docs we're moving to Mintlify
- Exclude files not listed in nav from search
- Update banner
2025-07-31 13:10:45 -04:00
Sam Crowder 246efe71f4 fix: change from developer to enterprise (#5778) 2025-07-31 09:42:19 -07:00
Eugene Yurtsev 116121eb3a feat(docs): dynamic model and tool selection in create react agent (#5777)
Document dynamic models and dynamic tools
2025-07-31 11:22:30 -04:00
William FH 18887e9f86 fix(langgraph): Remove duplicate call to ensure_config (#5768) 2025-07-31 09:15:03 -04:00
Sam Crowder bec28226d0 fix: removing standalone container lite from old docs (#5759) 2025-07-30 18:21:37 -07:00
Sam Crowder 967e368e14 fix: add link that points to where changelog now lives (#5758) 2025-07-30 17:49:51 -07:00
Lauren Hirata Singh 9d4dd066e5 docs: Revert "docs: Delete LGP nav Items from docs" (#5753)
Reverts langchain-ai/langgraph#5743
2025-07-30 18:15:19 -04:00
Lauren Hirata Singh 81027b2b80 docs: fix redirects to external pages (#5752) 2025-07-30 16:52:13 -04:00
Sydney Runkle 296bf5f75e fix(docs): context docs formatting (#5751) 2025-07-30 16:41:49 -04:00
Sydney Runkle f43c806736 release(langgraph): 0.6.2 (#5750) 2025-07-30 20:35:27 +00:00
Sydney Runkle 36f444dcb6 release(prebuilt): 0.6.2 (#5749) 2025-07-30 20:27:10 +00:00
Sydney Runkle 781a115f92 fix(prebuilt): assign context_schema to config_schema with correct condition (#5746) 2025-07-30 20:08:45 +00:00
Kathryn MayandLauren Hirata Singh 95d056e735 docs: Delete LGP nav Items from docs (#5743)
Remove the files and nav for LGP docs in the mkdocs site.

---------

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-30 15:49:54 -04:00
64adb2bab3 feat: Add context coercion for LangGraph runtime (#5736)
Fixes #5735

Implement context coercion functionality for LangGraph runtime to
improve API usability.

Key changes:
- Added `_coerce_context` function in `pregel/main.py`
- Supports coercion for:
  - Pydantic BaseModel
  - Dataclasses
  - TypedDict
- Comprehensive test coverage added in `tests/test_runtime.py`
- Handles edge cases like None context and missing fields

The implementation allows users to pass dictionaries as context, which
will be automatically converted to the expected schema type, making the
API more flexible and user-friendly.

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-30 19:08:45 +00:00
Syed Baqar Abbas e87f0fb0cd docs: The notebook redirects to a page that does not exist (#5638)
**docs: The notebook redirects to a page that does not exist**
- **Description:** The current documentation redirects to a file that
does not exist. I have removed the doc to avoid confusion.
  - **Issue:** Fixes #5637
2025-07-30 18:26:28 +00:00
Neha Gawhaneandgawhaarya c70f283f83 chore(examples): remove outdated HITL notebooks pointing to 404s (#5731)
**Description:**  
Removed 4 broken notebooks in `examples/human_in_the_loop/` that
referenced missing files (list below). These notebooks displayed
redirect messages but the new paths are either invalid or don’t contain
content.
Filenames:
1. examples/human_in_the_loop/dynamic_breakpoints.ipynb
2. examples/human_in_the_loop/edit-graph-state.ipynb
3. examples/human_in_the_loop/review-tool-calls.ipynb
4. examples/human_in_the_loop/time-travel.ipynb


**Issue:**  
Closes #5642

**Dependencies:**  
None

Co-authored-by: gawhaarya <gawhaneaarya@gmail.com>
2025-07-30 18:25:55 +00:00
Sydney Runkle 1d6b0c36e9 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5732) 2025-07-30 14:20:35 -04:00
Hunter Lovell e5344d35af fix(docs): squash js docs build errors (#5723) 2025-07-30 16:14:51 +00:00
Sam Crowder 9f48bb0b61 Update changelog via LangGraph Server Changelog Bot 2025-07-30 08:39:34 -07:00
Sam Crowder 5333fc9c21 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5718) 2025-07-29 21:51:35 -07:00
d59091672f feat: add docs translations (#5552)
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Tat Dat Duong <david@duong.cz>
2025-07-30 02:18:30 +00:00
Sam Crowder da7ff1421d Update changelog via LangGraph Server Changelog Bot 2025-07-29 17:42:16 -07:00
Eugene Yurtsev 72e418e4d0 release(prebuilt): 0.6.1 (#5713)
Release 0.6.1 allowing ToolNode to handle Command that removes all
messages
2025-07-29 20:39:42 +00:00
samuel-pullelyandEugene Yurtsev 8cea8ae1de fix(prebuilt): update ToolNode to allow Command update to remove all messages (#5678)
## Description

Previously, when a tool returned `Command` to update the graph's state,
the `_validate_tool_command` method in `ToolNode` would raise a
`ValueError` if the `messages_update` list contained only a
`RemoveMessage(id=REMOVE_ALL_MESSAGES)` object. This was because the
validation logic expected a matching `ToolMessage` for the tool call and
did not account for this specific state-clearing scenario.

This commit modifies the validation logic to check if the
`messages_update` list contains a single
`RemoveMessage(id=REMOVE_ALL_MESSAGES)` element. If this condition is
met, the `ToolMessage` validation is bypassed, allowing a tool to clear
the entire message history without causing a validation error.

A new test case, `test_tool_node_command_remove_all_messages`, has been
added to `tests/test_tool_node.py` to verify this change and prevent
future regressions.

## Example

Here is a self-contained example that illustrates the problem and the
fix. Without this change, the code block for `Example 2` would raise a
`ValueError`.

```python
from typing import Annotated, List

from langchain_core.messages import (
    AIMessage,
    AnyMessage,
    HumanMessage,
    RemoveMessage,
    ToolMessage,
)
from langchain_core.tools import InjectedToolCallId, tool
from langchain_openai import ChatOpenAI
from langgraph.graph import END, StateGraph, add_messages
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.prebuilt import InjectedState, ToolNode
from langgraph.types import Command
from pydantic import BaseModel, Field


# Agent state tracks current and all messages
class AgentState(BaseModel):
    messages: Annotated[List[AnyMessage], add_messages] = Field(
        default_factory=list, description="Current conversation messages."
    )
    all_messages: Annotated[List[AnyMessage], add_messages] = Field(
        default_factory=list, description="All messages, including removed ones."
    )


# Tool to clear history if long enough, otherwise returns a warning
@tool
def clear_history_tool(
    state: Annotated[AgentState, InjectedState],
    tool_call_id: Annotated[str, InjectedToolCallId],
):
    """Clears message history if it's long enough."""
    if len(state.messages) < 3:
        return Command(
            update={
                "messages": [
                    ToolMessage(
                        "History is not long enough to be cleared. Please try again.",
                        tool_call_id=tool_call_id,
                    )
                ]
            }
        )
    else:
        return Command(
            update={
                "messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)],
                "all_messages": state.messages
                + [
                    ToolMessage(
                        "History has been successfully cleared.",
                        tool_call_id=tool_call_id,
                    )
                ],
            }
        )


# Bind the tool to the model
model = ChatOpenAI(model="gpt-4o-mini").bind_tools([clear_history_tool])


def model_node(state: AgentState):
    return {"messages": [model.invoke(state.messages)]}


# Build the agent graph
graph_builder = StateGraph(AgentState)
graph_builder.add_node("model", model_node)
graph_builder.add_node("tools", ToolNode([clear_history_tool]))
graph_builder.set_entry_point("model")
graph_builder.add_edge("model", "tools")
graph_builder.add_edge("tools", END)
graph = graph_builder.compile()


def print_messages(header, messages):
    print(f"\n{header}")
    for message in messages:
        message.pretty_print()


### Example 1: Not enough history to clear
state_1 = AgentState(
    messages=[HumanMessage(content="Please clear my message history.")]
)
output_1 = graph.invoke(state_1)
print_messages("First call: State 'messages'", output_1["messages"])
print_messages("First call: State 'all_messages'", output_1["all_messages"])

### Example 2: History is cleared
state_2 = AgentState(
    messages=[
        HumanMessage(content="Will this PR get merged?"),
        AIMessage(content="Maybe, if it's good enough."),
        HumanMessage(content="Please clear my message history."),
    ]
)
# Without the changes in this PR, the following line will raise a ValueError
output_2 = graph.invoke(state_2)
print_messages("Second call: State 'messages'", output_2["messages"])
print_messages("Second call: State 'all_messages'", output_2["all_messages"])
```

### Outputs

*Without the changes in this PR:*

```
First call: State 'messages'
================================ Human Message =================================

Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
  clear_history_tool (ba421ac3-1e1a-4208-a8f6-c5500ee0abcc)
 Call ID: ba421ac3-1e1a-4208-a8f6-c5500ee0abcc
  Args:
================================= Tool Message =================================
Name: clear_history_tool

History is not long enough to be cleared. Please try again.

First call: State 'all_messages'


Traceback (most recent call last):
  File "main.py", line 114, in <module>
    output_2 = graph.invoke(state_2)
               ^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 2844, in invoke
    for chunk in self.stream(
  File ".venv/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 2534, in stream
    for _ in runner.tick(
  File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 241, in _func
    outputs = [
              ^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 619, in result_iterator
    yield _result_or_cancel(fs.pop())
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 317, in _result_or_cancel
    return fut.result(timeout)
           ^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 449, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File ".venv/lib/python3.11/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langchain_core/runnables/config.py", line 555, in _wrapped_fn
    return contexts.pop().run(fn, *args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 353, in _run_one
    return self._validate_tool_command(response, call, input_type)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".venv/lib/python3.11/site-packages/langgraph/prebuilt/tool_node.py", line 616, in _validate_tool_command
    raise ValueError(
ValueError: Expected to have a matching ToolMessage in Command.update for tool 'clear_history_tool', got: [RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='__remove_all__')]. Every tool call (LLM requesting to call a tool) in the message history MUST have a corresponding ToolMessage. You can fix it by modifying the tool to return `Command(update={"messages": [ToolMessage("Success", tool_call_id=tool_call_id), ...]}, ...)`.
```

*With the changes in this PR:*

```
First call: State 'messages'
================================ Human Message =================================

Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
  clear_history_tool (ba421ac3-1e1a-4208-a8f6-c5500ee0abcc)
 Call ID: ba421ac3-1e1a-4208-a8f6-c5500ee0abcc
  Args:
================================= Tool Message =================================
Name: clear_history_tool

History is not long enough to be cleared. Please try again.

First call: State 'all_messages'


Second call: State 'messages'

Second call: State 'all_messages'
================================ Human Message =================================

Will this PR get merged?
================================== Ai Message ==================================

Maybe, if it's good enough.
================================ Human Message =================================

Please clear my message history.
================================== Ai Message ==================================
Tool Calls:
  clear_history_tool (499b1be3-6df1-493f-85e5-8d7e429dead8)
 Call ID: 499b1be3-6df1-493f-85e5-8d7e429dead8
  Args:
================================= Tool Message =================================
Name: clear_history_tool

History has been successfully cleared.
```

## Twitter handle

[@samuelpullely](https://x.com/samuelpullely)

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-29 20:30:42 +00:00
Sydney Runkle 85d2c7623a release(langgraph): 0.6.1 (#5712) 2025-07-29 20:25:49 +00:00
Sydney Runkle 7436777e7d fix(langgraph): enforce config injection even when optional (#5708) 2025-07-29 16:11:36 -04:00
Sydney Runkle 479373bd81 lint 2025-07-29 15:19:44 -04:00
Sydney Runkle dd91819c92 enforce config injection 2025-07-29 15:13:51 -04:00
Sydney Runkle b07964c98e fix(langgraph): always use parent runtime info if available (#5707) 2025-07-29 15:05:54 -04:00
Sydney Runkle 163d14f812 typo 2025-07-29 14:59:14 -04:00
Sydney Runkle c0185f04e5 more robust tests 2025-07-29 14:58:16 -04:00
Sydney Runkle 82b31c9ffd nits 2025-07-29 14:54:58 -04:00
Sydney Runkle aade865727 remove unintentional import 2025-07-29 14:50:11 -04:00
Sydney Runkle 184bcacb53 use parent runtime 2025-07-29 14:47:05 -04:00
Eugene Yurtsev d68bac3865 chore(docs): Support custom link titles (#5706)
Support custom link titles for custom link syntax
2025-07-29 14:17:03 -04:00
Sydney Runkle 824c309035 docs: update context conceptual page (#5696) 2025-07-29 11:06:08 -04:00
Sydney Runkle fdfd06056e move tip 2025-07-29 11:00:40 -04:00
Sydney RunkleandLauren Hirata Singh 469ebd3492 Apply suggestions from code review
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-29 10:58:59 -04:00
Sydney Runkle 474fb7b33e consolidate 2025-07-29 10:22:50 -04:00
Eugene Yurtsev 416da06d6b feat(docs): manually insert fill in most of the magic links (#5702)
These were done "manually" using openai. Likely error prone. We'll need to validate all the links.
2025-07-29 14:22:45 +00:00
Sydney Runkle 2297271863 refining tips 2025-07-29 10:19:48 -04:00
Sydney RunkleandLauren Hirata Singh 4910830efe Apply suggestions from code review
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-29 10:04:49 -04:00
Eugene Yurtsev 027bb0a1b8 feat(docs): Support cross language "auto links" (#5699)
Introduces a syntax for cross-reference links that work across language
and change behavior depending on which scope they appear in.


```markdown
@[interrupt]

:::python
@[StateGraph]
:::

:::js
@[create_react_agent]
:::

```

Can be compiled to

```markdown

# a link that changes based on global context or compile target
<div> ... </div>  -> `interrupt` in global context

:::python
[StateGraph](link to python cross reference)
:::

:::js
[create_react_agent](link to js cross reference)
:::
```



TODO:

- [x] fix broken unit test
- [x] no f strings in logger (it's a sin)
- [x] remove cross-refs.txt (we'll instead start updating the cross link
map)
2025-07-29 10:00:23 -04:00
Sydney Runkle cd30b9cfea docs: Add better definition for max_concurrency (#5701) 2025-07-29 08:39:46 -04:00
Lauren Hirata Singh 5eb9826c46 docs: Add better definition for max_concurrency 2025-07-29 07:15:47 -04:00
Lauren Hirata Singh fa43b4694a Apply suggestions from code review 2025-07-29 07:03:12 -04:00
Sydney Runkle 4d80f4b1a5 a few more nits 2025-07-28 19:11:30 -04:00
Sydney Runkle 70185d350e adding xlinks 2025-07-28 19:02:47 -04:00
Sydney Runkle 89efd6e915 formatting 2025-07-28 18:50:37 -04:00
Lance Martin d88ca6f649 Update 2025-07-28 15:15:45 -07:00
Sydney Runkle fadbe7d710 fix(docs): clarify value of context (#5689) 2025-07-28 16:38:02 -04:00
Sydney Runkle c861614337 Merge branch 'sr/more-context-for-context' of https://github.com/langchain-ai/langgraph into sr/more-context-for-context 2025-07-28 16:34:54 -04:00
Sydney Runkle c020f01425 final nits 2025-07-28 16:34:13 -04:00
Sydney RunkleandLauren Hirata Singh 14949c81c8 Apply suggestions from code review
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-28 16:22:16 -04:00
Sydney Runkle 3af857922a formatting for bullets 2025-07-28 16:19:27 -04:00
Sydney Runkle 7ec049e0c7 note on window 2025-07-28 16:15:56 -04:00
Sydney Runkle 1923ff8d85 first pass 2025-07-28 16:15:14 -04:00
Sydney Runkle 4b9b7d0b1c fix(docs): better docs for resuming multiple interrupts (#5688) 2025-07-28 16:05:22 -04:00
Sydney RunkleandEugene Yurtsev 624247a51f Update docs/docs/agents/context.md
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-28 15:31:36 -04:00
Sydney Runkle b21b595927 Merge branch 'sr/more-docs' of https://github.com/langchain-ai/langgraph into sr/more-docs 2025-07-28 15:21:24 -04:00
Sydney Runkle f4633a0015 single example 2025-07-28 15:20:32 -04:00
Sam Crowder 86017c010c docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5686) 2025-07-28 12:17:20 -07:00
Sydney Runkle 2115cffc94 notes on context 2025-07-28 15:17:05 -04:00
Sydney RunkleandEugene Yurtsev 03726f9bc6 Update docs/docs/how-tos/human_in_the_loop/add-human-in-the-loop.md
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-28 15:14:37 -04:00
Sydney Runkle 509dfd1f21 better hitl multi interrupt resume docs 2025-07-28 15:05:57 -04:00
Sam Crowder efca21070d Update changelog via LangGraph Server Changelog Bot 2025-07-28 10:10:50 -07:00
Sam Crowder dba20d0577 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5680) 2025-07-28 07:51:52 -07:00
Sam Crowder 5145dac12b Update changelog via LangGraph Server Changelog Bot 2025-07-28 07:39:31 -07:00
Sydney Runkle 440c7ff12a release(langgraph): v0.6.0 (#5684) 2025-07-28 09:11:43 -04:00
Sydney Runkle 5eef290c4e fix(langgraph): backwards compat config utils (#5683) 2025-07-28 09:06:38 -04:00
Sydney Runkle a8b3746356 release prep v0.6 2025-07-28 09:05:23 -04:00
Sydney Runkle 7541331643 no top level file 2025-07-28 09:00:09 -04:00
Sydney Runkle 76814676c2 finalize utils 2025-07-28 08:57:46 -04:00
Sydney Runkle 0804984f9d Merge branch 'main' into sr/config-utils 2025-07-28 08:54:49 -04:00
Sydney Runkle 8f11b6a003 ensure_config and patch_configurable 2025-07-28 08:53:10 -04:00
Sam Crowder aa6b122e4c Update changelog via LangGraph Server Changelog Bot 2025-07-27 08:43:43 -07:00
Sam CrowderandWilliam FH 23491e5c9a docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5676)
Automated changelog update created by the LangGraph Server Changelog
Bot.

Feel free to merge anytime.

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-07-27 13:38:15 +00:00
Sydney Runkle 1491f30a07 ensure config also 2025-07-25 16:23:28 -04:00
Sydney Runkle f63635d3c8 release: langgraph v0.6.0a1, langgraph-prebuilt v0.6.0a1 (#5671) 2025-07-25 15:53:08 -04:00
Sydney Runkle 6672032568 chore: add backwards compat utils imports to make v0.6 migration easier (#5670) 2025-07-25 15:44:02 -04:00
Sydney Runkle 311ce7b04f alpha bumps 2025-07-25 15:41:51 -04:00
Sydney Runkle 14b732740e removal notice 2025-07-25 15:37:41 -04:00
Sydney Runkle 370825a48a lint 2025-07-25 15:36:56 -04:00
Sydney Runkle 264bae5a7e adding backwards compat utils imports to make my life easier 2025-07-25 15:35:48 -04:00
Eugene YurtsevandSydney Runkle f6aa19709e feat(prebuilt): Add dynamic model to create_react_agent (#5651)
This PR allows a developer to change the model configuration at run time based on context. This includes that list of tools available to the model to call.

```python
def create_react_agent(
    model: Union[
        str, 
	LanguageModelLike,
        Callable[[SateLike, Runtime...], BaseChatModel], # <--- New
    ],
    tools: Union[
      Sequence[Union[BaseTool, Callable, dict[str, Any]]], ToolNode]
    ],
    *,
....


llm = init_chat_model(...)

def prepare_model(state, runtime):
   selected_tool_names = func(state, context)
   return llm.bind(tools=selected_tool_names)

create_react_agent(
  prepare_model,
  tools=all_known_tools
)
```

## Semantics

1. `tools` = are the known tools, used to configure ToolNode and will
configure:
    1. model provided as string
    2. model provided as BaseChatModel (if it has no tools bound to it)
2. If a user provides a dynamic model (callable), the user is
responsible for binding tools


Alternative considered:

1. Passing `Callable[[SateLike, Config...], list[BaseTool]]` to tools
2. Passing `Callable[[SateLike, Config...], list[str]]` to a tool
selector

Both have the issue that there's non obvious interplay between tool
selection and dynamic models. (i.e., if we want to introduce dynamic
models at in the future, the API will become tricky to explain)

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-07-25 14:48:15 -04:00
Sydney Runkle 8495f6f95d chore(ci): harden release workflow (#5669) 2025-07-25 14:45:18 -04:00
Eugene Yurtsev 6710908d40 x 2025-07-25 14:37:03 -04:00
Eugene Yurtsev d24ad3d980 x 2025-07-25 14:34:49 -04:00
Eugene Yurtsev 2d8288fd0f reduce permissions 2025-07-25 14:14:07 -04:00
dependabot[bot] c1ef10a0ec chore: bump form-data from 4.0.1 to 4.0.4 in /docs (#5615)
Bumps [form-data](https://github.com/form-data/form-data) from 4.0.1 to
4.0.4.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/form-data/form-data/blob/master/CHANGELOG.md">form-data's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/form-data/form-data/compare/v4.0.3...v4.0.4">v4.0.4</a>
- 2025-07-16</h2>
<h3>Commits</h3>
<ul>
<li>[meta] add <code>auto-changelog</code> <a
href="https://github.com/form-data/form-data/commit/811f68282fab0315209d0e2d1c44b6c32ea0d479"><code>811f682</code></a></li>
<li>[Tests] handle predict-v8-randomness failures in node &lt; 17 and
node &gt; 23 <a
href="https://github.com/form-data/form-data/commit/1d11a76434d101f22fdb26b8aef8615f28b98402"><code>1d11a76</code></a></li>
<li>[Fix] Switch to using <code>crypto</code> random for boundary values
<a
href="https://github.com/form-data/form-data/commit/3d1723080e6577a66f17f163ecd345a21d8d0fd0"><code>3d17230</code></a></li>
<li>[Tests] fix linting errors <a
href="https://github.com/form-data/form-data/commit/5e340800b5f8914213e4e0378c084aae71cfd73a"><code>5e34080</code></a></li>
<li>[meta] actually ensure the readme backup isn’t published <a
href="https://github.com/form-data/form-data/commit/316c82ba93fd4985af757b771b9a1f26d3b709ef"><code>316c82b</code></a></li>
<li>[Dev Deps] update <code>@ljharb/eslint-config</code> <a
href="https://github.com/form-data/form-data/commit/58c25d76406a5b0dfdf54045cf252563f2bbda8d"><code>58c25d7</code></a></li>
<li>[meta] fix readme capitalization <a
href="https://github.com/form-data/form-data/commit/2300ca19595b0ee96431e868fe2a40db79e41c61"><code>2300ca1</code></a></li>
</ul>
<h2><a
href="https://github.com/form-data/form-data/compare/v4.0.2...v4.0.3">v4.0.3</a>
- 2025-06-05</h2>
<h3>Fixed</h3>
<ul>
<li>[Fix] <code>append</code>: avoid a crash on nullish values <a
href="https://redirect.github.com/form-data/form-data/issues/577"><code>[#577](https://github.com/form-data/form-data/issues/577)</code></a></li>
</ul>
<h3>Commits</h3>
<ul>
<li>[eslint] use a shared config <a
href="https://github.com/form-data/form-data/commit/426ba9ac440f95d1998dac9a5cd8d738043b048f"><code>426ba9a</code></a></li>
<li>[eslint] fix some spacing issues <a
href="https://github.com/form-data/form-data/commit/20941917f0e9487e68c564ebc3157e23609e2939"><code>2094191</code></a></li>
<li>[Refactor] use <code>hasown</code> <a
href="https://github.com/form-data/form-data/commit/81ab41b46fdf34f5d89d7ff30b513b0925febfaa"><code>81ab41b</code></a></li>
<li>[Fix] validate boundary type in <code>setBoundary()</code> method <a
href="https://github.com/form-data/form-data/commit/8d8e4693093519f7f18e3c597d1e8df8c493de9e"><code>8d8e469</code></a></li>
<li>[Tests] add tests to check the behavior of <code>getBoundary</code>
with non-strings <a
href="https://github.com/form-data/form-data/commit/837b8a1f7562bfb8bda74f3fc538adb7a5858995"><code>837b8a1</code></a></li>
<li>[Dev Deps] remove unused deps <a
href="https://github.com/form-data/form-data/commit/870e4e665935e701bf983a051244ab928e62d58e"><code>870e4e6</code></a></li>
<li>[meta] remove local commit hooks <a
href="https://github.com/form-data/form-data/commit/e6e83ccb545a5619ed6cd04f31d5c2f655eb633e"><code>e6e83cc</code></a></li>
<li>[Dev Deps] update <code>eslint</code> <a
href="https://github.com/form-data/form-data/commit/4066fd6f65992b62fa324a6474a9292a4f88c916"><code>4066fd6</code></a></li>
<li>[meta] fix scripts to use prepublishOnly <a
href="https://github.com/form-data/form-data/commit/c4bbb13c0ef669916657bc129341301b1d331d75"><code>c4bbb13</code></a></li>
</ul>
<h2><a
href="https://github.com/form-data/form-data/compare/v4.0.1...v4.0.2">v4.0.2</a>
- 2025-02-14</h2>
<h3>Merged</h3>
<ul>
<li>[Fix] set <code>Symbol.toStringTag</code> when available <a
href="https://redirect.github.com/form-data/form-data/pull/573"><code>[#573](https://github.com/form-data/form-data/issues/573)</code></a></li>
<li>[Fix] set <code>Symbol.toStringTag</code> when available <a
href="https://redirect.github.com/form-data/form-data/pull/573"><code>[#573](https://github.com/form-data/form-data/issues/573)</code></a></li>
<li>fix (npmignore): ignore temporary build files <a
href="https://redirect.github.com/form-data/form-data/pull/532"><code>[#532](https://github.com/form-data/form-data/issues/532)</code></a></li>
<li>fix (npmignore): ignore temporary build files <a
href="https://redirect.github.com/form-data/form-data/pull/532"><code>[#532](https://github.com/form-data/form-data/issues/532)</code></a></li>
</ul>
<h3>Fixed</h3>
<ul>
<li>[Fix] set <code>Symbol.toStringTag</code> when available (<a
href="https://redirect.github.com/form-data/form-data/issues/573">#573</a>)
<a
href="https://redirect.github.com/form-data/form-data/issues/396"><code>[#396](https://github.com/form-data/form-data/issues/396)</code></a></li>
<li>[Fix] set <code>Symbol.toStringTag</code> when available (<a
href="https://redirect.github.com/form-data/form-data/issues/573">#573</a>)
<a
href="https://redirect.github.com/form-data/form-data/issues/396"><code>[#396](https://github.com/form-data/form-data/issues/396)</code></a></li>
<li>[Fix] set <code>Symbol.toStringTag</code> when available <a
href="https://redirect.github.com/form-data/form-data/issues/396"><code>[#396](https://github.com/form-data/form-data/issues/396)</code></a></li>
</ul>
<h3>Commits</h3>
<ul>
<li>Merge tags v2.5.3 and v3.0.3 <a
href="https://github.com/form-data/form-data/commit/92613b9208556eb4ebc482fdf599fae111626fb6"><code>92613b9</code></a></li>
<li>[Tests] migrate from travis to GHA <a
href="https://github.com/form-data/form-data/commit/806eda77740e6e3c67c7815afb216f2e1f187ba5"><code>806eda7</code></a></li>
<li>[Tests] migrate from travis to GHA <a
href="https://github.com/form-data/form-data/commit/8fdb3bc6b5d001f8909a9fca391d1d1d97ef1d79"><code>8fdb3bc</code></a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/form-data/form-data/commit/41996f5ac73a867046d48512cab62e64fc846dad"><code>41996f5</code></a>
v4.0.4</li>
<li><a
href="https://github.com/form-data/form-data/commit/316c82ba93fd4985af757b771b9a1f26d3b709ef"><code>316c82b</code></a>
[meta] actually ensure the readme backup isn’t published</li>
<li><a
href="https://github.com/form-data/form-data/commit/2300ca19595b0ee96431e868fe2a40db79e41c61"><code>2300ca1</code></a>
[meta] fix readme capitalization</li>
<li><a
href="https://github.com/form-data/form-data/commit/811f68282fab0315209d0e2d1c44b6c32ea0d479"><code>811f682</code></a>
[meta] add <code>auto-changelog</code></li>
<li><a
href="https://github.com/form-data/form-data/commit/5e340800b5f8914213e4e0378c084aae71cfd73a"><code>5e34080</code></a>
[Tests] fix linting errors</li>
<li><a
href="https://github.com/form-data/form-data/commit/1d11a76434d101f22fdb26b8aef8615f28b98402"><code>1d11a76</code></a>
[Tests] handle predict-v8-randomness failures in node &lt; 17 and node
&gt; 23</li>
<li><a
href="https://github.com/form-data/form-data/commit/58c25d76406a5b0dfdf54045cf252563f2bbda8d"><code>58c25d7</code></a>
[Dev Deps] update <code>@ljharb/eslint-config</code></li>
<li><a
href="https://github.com/form-data/form-data/commit/3d1723080e6577a66f17f163ecd345a21d8d0fd0"><code>3d17230</code></a>
[Fix] Switch to using <code>crypto</code> random for boundary
values</li>
<li><a
href="https://github.com/form-data/form-data/commit/d8d67dc8ac79285154edf7d3f57dbab593b9a146"><code>d8d67dc</code></a>
v4.0.3</li>
<li><a
href="https://github.com/form-data/form-data/commit/e6e83ccb545a5619ed6cd04f31d5c2f655eb633e"><code>e6e83cc</code></a>
[meta] remove local commit hooks</li>
<li>Additional commits viewable in <a
href="https://github.com/form-data/form-data/compare/v4.0.1...v4.0.4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=form-data&package-manager=npm_and_yarn&previous-version=4.0.1&new-version=4.0.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/langchain-ai/langgraph/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-25 13:31:18 -04:00
Eugene Yurtsev a3d7b6f44e chore(checkpoint-sqlite): Release 2.0.11 (#5667)
Release new version
2025-07-25 17:26:26 +00:00
Eugene Yurtsev bc9d45b476 fix(checkpoint-sqlite): add validation to filter keys in sql store (#5666)
This PR adds validation to keys used in filtering logic in the SQLite store implementation.
2025-07-25 13:01:13 -04:00
Sydney Runkle 7d3f0089aa docs: more thorough notes on v0.6 features and changes (#5623) 2025-07-25 09:33:53 -04:00
Sydney Runkle ed678f4701 Merge branch 'main' into sr/version-added-for-context 2025-07-25 09:27:52 -04:00
Sydney Runkle 22411ba0fd lint 2025-07-25 09:27:34 -04:00
Sydney Runkle 5b9021ff37 typo 2025-07-25 09:25:26 -04:00
Sydney Runkle aaff464115 move deprecation note for config_schema 2025-07-25 09:23:59 -04:00
Sam Crowder 3a23a256e2 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5657) 2025-07-24 20:37:10 -07:00
Sam Crowder f6857395b9 Update changelog via LangGraph Server Changelog Bot 2025-07-24 20:19:17 -07:00
William FH cdaa7ba003 chore: typing for headers in remote graph (#5653) 2025-07-24 18:00:44 -07:00
Sydney Runkle 39745ed794 Merge branch 'sr/version-added-for-context' of https://github.com/langchain-ai/langgraph into sr/version-added-for-context 2025-07-24 17:31:25 -04:00
Sydney Runkle 738bb8a343 Merge branch 'sr/fixes-for-v6' into sr/version-added-for-context 2025-07-24 17:31:21 -04:00
Sydney Runkle b2dde8d9af Merge branch 'main' into sr/version-added-for-context 2025-07-24 17:29:54 -04:00
Sydney Runkle 5312edc830 more runtime details 2025-07-24 17:28:58 -04:00
Sydney Runkle 276310e116 fix and interrupt 2025-07-24 16:54:20 -04:00
Sydney Runkle 39977ded8c runtime api ref 2025-07-24 16:36:51 -04:00
Sydney Runkle 439038fc3a deprecation for config_schema in docs 2025-07-24 16:23:42 -04:00
Sam Crowder 2e5445c565 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5650) 2025-07-24 11:35:22 -07:00
Sam Crowder d38510ad03 Update changelog via LangGraph Server Changelog Bot 2025-07-24 09:18:21 -07:00
Sydney Runkle 951486d107 release(prebuilt): 0.6.0 (#5648) 2025-07-24 10:38:24 -04:00
Sydney Runkle 745a1e7a29 bumping required prebuilt version 2025-07-24 10:27:20 -04:00
Sam Crowder 24731d6a28 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5625) 2025-07-23 20:06:22 -07:00
Sam Crowder a4689a5d10 Update changelog via LangGraph Server Changelog Bot 2025-07-23 18:59:50 -07:00
langchain-infra b05ce0bf60 release(cli): Release new CLI version with support for api-version flag (#5640) 2025-07-23 19:47:25 -04:00
David Asamu 4501e41991 uv sync 2025-07-24 00:36:02 +01:00
Asamu David bc83287fc8 bump version number
new CLI version with support for api-version flag
2025-07-24 00:19:57 +01:00
Andrew Nguonly 11547e1990 docs: Add more clarification about the LangSmith API key for LangGraph Platform deployments (#5635) 2025-07-23 11:39:39 -07:00
langchain-infra fadd9c4577 feat(cli): add support for api-version (#5584) 2025-07-23 12:33:04 -04:00
Asamu David fd2933a792 Merge branch 'main' into david/30-06/support-base-image-tag 2025-07-23 15:42:24 +01:00
David Asamu 40fa69f8ee lint and format fixes 2025-07-23 15:39:34 +01:00
Sam Crowder 0824161984 Update changelog via LangGraph Server Changelog Bot 2025-07-22 13:47:31 -07:00
Sam Crowder b028f502e1 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5611) 2025-07-22 12:47:33 -07:00
William FH 9dc3fed6b8 feat(langgraph): Support sending distributed tracing headers (#5619) 2025-07-22 12:47:23 -07:00
Sydney Runkle 0232201b7b improving docs for context 2025-07-22 13:28:27 -04:00
Sydney Runkle 869b0f2de4 release(sdk-py): 0.2.0 (#5622) 2025-07-22 13:27:04 -04:00
Sydney Runkle 90e3adcd71 bump sdk version 2025-07-22 13:20:55 -04:00
Sydney Runkle cb918601d1 release: prep for langgraph v0.6 (#5325) 2025-07-22 13:14:31 -04:00
Sydney Runkle 4a4c8db635 fix header 2025-07-22 12:54:21 -04:00
Sydney Runkle 56a9ce57b1 docs build fixes 2025-07-22 12:46:56 -04:00
Sydney Runkle d1ee1cf1f1 docs fix 2025-07-22 11:19:08 -04:00
Sydney Runkle 29c3a579b3 release(sdk-py): use v0.2.0a1 for testing with sdk (#5621) 2025-07-22 15:08:07 +00:00
Sydney Runkle 9e3cb1f034 feat(sdk-py): sdk support for context API (#5566)
Adding support for the `context` arg to `invoke/stream` to the sdk. This
is paired with an update to the API as well that adds `context` support
to the `assistants` and `runs` endpoints.

Bumping version to v0.2.0 on the `v1` branch given this and the
interrupt schema changes.
2025-07-22 10:48:12 -04:00
Sydney Runkle 508e333220 Merge branch 'main' into v1 2025-07-22 08:55:42 -04:00
Sam Crowder aa1bbe3d01 Update changelog via LangGraph Server Changelog Bot 2025-07-21 17:41:55 -07:00
Sydney Runkle 139cad373b fix(docs): use InMemorySaver instead of MemorySaver (#5608)
Also, remove comment from bash script that makes insertion of `uv`
harder
2025-07-21 18:49:55 +00:00
Sydney Runkle 2a86abb8c4 chore: lint v1 branch (due to auto merges) (#5607) 2025-07-21 18:43:22 +00:00
Sydney Runkle d1f0799002 Merge branch 'main' into v1 2025-07-21 14:35:13 -04:00
Sydney Runkle be088801ba fix(langgraph): fix assertion in test (#5606) 2025-07-21 14:25:37 -04:00
Sydney Runkle 1ee6bfeb8d release(langgraph): v0.5.4 (#5605) 2025-07-21 18:17:00 +00:00
Nuno Campos 2153d36726 feat(langgraph): Handle ParentCommand in RemoteGraph (#5600)
- when receiving a "command" stream event raise ParentCommand exception
for caller graph to handle
2025-07-21 18:48:40 +01:00
Sydney Runkle 819eae891e feat(sdk-py): add interrupts to ThreadState (#5603) 2025-07-21 16:33:00 +00:00
Sydney Runkle 457edaa75b locks 2025-07-21 12:32:23 -04:00
Sydney Runkle 90ba4c5205 Merge branch 'main' into v1 2025-07-21 10:06:23 -04:00
Sydney Runkle b3c5298100 fix(langgraph): ignore write to END with Command (#5601)
Fixes https://github.com/langchain-ai/langgraph/issues/5572

End is a special terminal node, so we don't need a branch to channel
like we do for other values passed to `Command.goto`
2025-07-21 14:03:00 +00:00
dependabot[bot] 9d9476e664 chore: bump codespell-project/actions-codespell from 2.0 to 2.1 (#5597)
Bumps
[codespell-project/actions-codespell](https://github.com/codespell-project/actions-codespell)
from 2.0 to 2.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/codespell-project/actions-codespell/releases">codespell-project/actions-codespell's
releases</a>.</em></p>
<blockquote>
<h2>v2.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Use v2 in README by <a
href="https://github.com/okuramasafumi"><code>@​okuramasafumi</code></a>
in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/69">codespell-project/actions-codespell#69</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/72">codespell-project/actions-codespell#72</a></li>
<li>Bump actions/setup-python from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/74">codespell-project/actions-codespell#74</a></li>
<li>feat: bump to use node20 runtime by <a
href="https://github.com/kbdharun"><code>@​kbdharun</code></a> in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/71">codespell-project/actions-codespell#71</a></li>
<li>[pre-commit.ci] pre-commit autoupdate by <a
href="https://github.com/pre-commit-ci"><code>@​pre-commit-ci</code></a>
in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/76">codespell-project/actions-codespell#76</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/okuramasafumi"><code>@​okuramasafumi</code></a>
made their first contribution in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/69">codespell-project/actions-codespell#69</a></li>
<li><a
href="https://github.com/dependabot"><code>@​dependabot</code></a> made
their first contribution in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/72">codespell-project/actions-codespell#72</a></li>
<li><a href="https://github.com/kbdharun"><code>@​kbdharun</code></a>
made their first contribution in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/71">codespell-project/actions-codespell#71</a></li>
<li><a
href="https://github.com/pre-commit-ci"><code>@​pre-commit-ci</code></a>
made their first contribution in <a
href="https://redirect.github.com/codespell-project/actions-codespell/pull/76">codespell-project/actions-codespell#76</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/codespell-project/actions-codespell/compare/v2...v2.1">https://github.com/codespell-project/actions-codespell/compare/v2...v2.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/codespell-project/actions-codespell/commit/406322ec52dd7b488e48c1c4b82e2a8b3a1bf630"><code>406322e</code></a>
[pre-commit.ci] pre-commit autoupdate (<a
href="https://redirect.github.com/codespell-project/actions-codespell/issues/76">#76</a>)</li>
<li><a
href="https://github.com/codespell-project/actions-codespell/commit/3174815d6231f5bdc24dbfb6fc3b8caec73d521c"><code>3174815</code></a>
feat: bump to use node20 runtime (<a
href="https://redirect.github.com/codespell-project/actions-codespell/issues/71">#71</a>)</li>
<li><a
href="https://github.com/codespell-project/actions-codespell/commit/8edd9f294002b35e8d7de67b06ac493e89114b91"><code>8edd9f2</code></a>
Bump actions/setup-python from 4 to 5 (<a
href="https://redirect.github.com/codespell-project/actions-codespell/issues/74">#74</a>)</li>
<li><a
href="https://github.com/codespell-project/actions-codespell/commit/8dc81685022bbd5008e21ddb6f44abe4eb4f27b1"><code>8dc8168</code></a>
Bump actions/checkout from 3 to 4 (<a
href="https://redirect.github.com/codespell-project/actions-codespell/issues/72">#72</a>)</li>
<li><a
href="https://github.com/codespell-project/actions-codespell/commit/41170f1b9c4f5c5788cb677c6c2f9ef26010243d"><code>41170f1</code></a>
Use v2 in README (<a
href="https://redirect.github.com/codespell-project/actions-codespell/issues/69">#69</a>)</li>
<li>See full diff in <a
href="https://github.com/codespell-project/actions-codespell/compare/v2.0...v2.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codespell-project/actions-codespell&package-manager=github_actions&previous-version=2.0&new-version=2.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-21 09:30:41 -04:00
Sydney Runkle 03bec97767 feat(sdk-py): add interrupts to thread state (#5580) 2025-07-20 23:46:38 +00:00
AG2AI-Admin dd9b5c42e8 chore(docs): Migrate from pyautogen to ag2 Library (#5577) 2025-07-20 19:43:54 -04:00
Eugene Yurtsev 951a3f2d1c ci: Update privileged.yml (#5481) 2025-07-20 17:34:20 -04:00
Sakshi Gupta adaa340c15 fix(docs): jokes needs reducer in graph-api.md (#5489) (#5489) 2025-07-20 17:32:47 -04:00
Yagnesh M. Bhadiyadra 2c85cba9ca fix(docs): Change of condition arguments in Command API example for ease of reading. (#5571) 2025-07-20 20:58:37 +00:00
Nuno CamposandSydney Runkle cb7b924006 feat: Implement durability mode argument (#5432)
- Replaces checkpoint_during: bool
- checkpoint_during is deprecated but still respected
- We implement three durability modes (from least to most durable):
- "exit" - save checkpoint only when the graph exits (equivalent to
checkpoint_during=False)
- "async" - save checkpoint asynchronously while the next step executes
(the default, equivalent to old checkpoint_during=True)
- "sync" - save checkpoint synchronously before the next step starts
(new mode, slower but most durable)

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-07-20 15:42:18 +01:00
Sydney Runkle c61ac946af feat(docs): add python alt for UI how to (#5593)
Fixes https://github.com/langchain-ai/langgraph/issues/5311
2025-07-20 09:33:17 -04:00
David Asamu ec0a30008c more semantic variable name 2025-07-19 03:30:29 +01:00
Asamu David 00c7909c27 Merge branch 'main' into david/30-06/support-base-image-tag 2025-07-19 03:20:09 +01:00
David Asamu 58d396fcf1 merge main 2025-07-19 03:17:17 +01:00
David Asamu 9f0abf014d format changed files 2025-07-19 03:06:17 +01:00
David Asamu 8d6cd15669 add api-version option 2025-07-19 02:55:47 +01:00
Andrew Nguonly 61676b8db0 docs: Change 'that' to 'than' (#5581) 2025-07-18 14:54:55 -07:00
langchain-infra 3b85e53360 docs: fix egress formatting (#5575) 2025-07-18 10:43:03 -04:00
infra 250a17d711 docs: fix egress formatting 2025-07-18 09:42:46 -05:00
Eugene Yurtsev f63bec8578 chore(prebuilt): restructure tool node and tool injection logic (#5562)
* Cleaning up the underlying tool injection logic which is happening in
multiple locations.
* State was being injected into the ToolCall via Send in two places in
create react agent and the logic doesn't belong there, the actual
injection should be happening inside the ToolNode where there's
awareness of what run time parameters the tool accepts.

Change is required to unblock:
https://github.com/langchain-ai/langgraph/pull/5537
2025-07-18 09:59:14 -04:00
langchain-infra dc0f0c5944 docs: add egress docs for LGP self hosted (#5569) 2025-07-18 03:14:40 -04:00
infra 777fe692d4 docs: add egress docs for LGP self hosted 2025-07-18 00:40:15 -04:00
infra fdbe31a3aa docs: add egress docs for LGP self hosted 2025-07-18 00:28:04 -04:00
Sam Crowder 78a9933144 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5561) 2025-07-17 20:45:42 -07:00
Eugene Yurtsev 5717eefa79 feat(docs): Document disabling webhooks (#5535)
Add information about disabling webhooks
2025-07-17 15:23:00 -04:00
William FHandSydney Runkle 5978012619 release(cli): Release new CLI version with increased bounds for server (#5565)
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-07-17 12:22:30 -07:00
Eugene Yurtsev b447a1c7cf fix(docs): fix langgraph cli reference (#5563)
Fix for wrong indentation that completely messes up formatting
2025-07-17 12:10:11 -07:00
f87608a16f chore(prebuilt): Remove dead code from prebuilt tests (#5555)
Fixes #5554

This PR removes unused utility classes and functions from the prebuilt
tests directory to clean up dead code.

Changes include:
- Removed unused classes from `libs/prebuilt/tests/any_str.py`:
  - Deleted FloatBetween, AnyDict, AnyVersion, and UnsortedSequence
  - Kept only AnyStr class

- Removed unused functions from `libs/prebuilt/tests/messages.py`:
  - Deleted _AnyIdDocument and _AnyIdAIMessageChunk
  - Kept _AnyIdHumanMessage and _AnyIdToolMessage

- Removed unused classes from `libs/prebuilt/tests/memory_assert.py`:
- Deleted NoopSerializer, MemorySaverAssertCheckpointMetadata, and
MemorySaverNoPending
  - Kept MemorySaverAssertImmutable

Verification:
- Manually checked for no remaining references to removed code
- Maintained existing import structures
- Preserved functionality of the prebuilt test suite

The changes reduce code complexity and remove unnecessary utility
classes that were not being used in the test suite.

---------

Co-authored-by: open-swe-dev[bot] <open-swe-dev@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-07-17 18:45:10 +00:00
Sydney Runkle a5fe3316b6 chore(langgraph): bump api version and prep for v0.6 alpha (#5559)
Bumping version on `v1` branch so that we can access most recent
`langgraph-cli[inmem]` changes (with v0.6 compat) for store injection.
2025-07-17 14:40:09 -04:00
Sam Crowder e0699fbdaf Update changelog via LangGraph Server Changelog Bot 2025-07-17 11:04:52 -07:00
Lauren Hirata Singh b4eb57da67 docs: Rearrange nav (#5560)
Move Prebuilts overview and Run an agent to the guides page
2025-07-17 13:47:43 -04:00
Sam Crowder cec3bef7ea docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5558)
Automated changelog update created by the LangGraph Server Changelog
Bot.

Feel free to merge anytime.
2025-07-17 12:41:13 -04:00
Sydney Runkle adc732272c refactor(langgraph): improve Runtime interface re patch/overrides (#5546) 2025-07-17 09:57:25 -04:00
Nuno Campos 71dc92b349 langgraph-checkpoint 2.1.1 2025-07-17 15:04:57 +02:00
jitoandNuno Campos 79b4642e55 fix(docs): broken URL in _AIO_ERROR_MSG for AsyncSqliteSaver (#5483)
remove unreachable `yield` from unimplemented async methods

---------

Co-authored-by: Nuno Campos <nuno@langchain.dev>
2025-07-17 12:26:22 +00:00
Nuno Campos 48446bcbd2 chore(docs): Mention dataclass (#5470) 2025-07-17 14:23:41 +02:00
Nuno Campos cf95c870fe fix(checkpoint): fix AsyncBatchedBaseStore getting stuck (#5504) 2025-07-17 12:50:18 +02:00
Nuno Campos a34c38a53d docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5547) 2025-07-17 12:24:24 +02:00
Sam Crowder db5276ded1 Update changelog via LangGraph Server Changelog Bot 2025-07-16 16:32:19 -07:00
Sam Crowder 9c67b9ce4b docs(docs): add disclaimer about overriding otel with DD_API_KEY (#5538) 2025-07-16 16:06:54 -07:00
Lauren Hirata Singh 08667fe786 docs: More tracing (#5545)
docs: add more about tracing
2025-07-16 19:06:43 -04:00
Sydney Runkle c6d674cd3e Merge branch 'main' into v1 2025-07-16 18:32:07 -04:00
Sydney Runkle 294078adab release(langgraph): revert alpha release, going to do v0.6 off main instead (#5543)
Revert "release(langgraph): v1.0.0a1 (#5520)"

This reverts commit 2eecaa8500.
2025-07-16 18:30:43 -04:00
Sam Crowder 48dabc0538 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5540)
Update changelog via LangGraph Server Changelog Bot
2025-07-16 18:24:46 -04:00
Sam CrowderandLauren Hirata Singh d2cc02d789 Update docs/docs/cloud/reference/env_var.md
Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-16 14:17:56 -07:00
Lauren Hirata Singh 92c66d13ec docs: add o11y overview (#5542)
* docs: add o11y overview

* add section for enabling tracing
2025-07-16 16:32:11 -04:00
Sam Crowder 7f821deded remove word tracing 2025-07-16 11:36:16 -07:00
Sam Crowder 12a601c8a3 fix: add disclaimer to the docs about DD_API_KEY overriding app-level tracing 2025-07-16 11:35:48 -07:00
Eugene Yurtsev d64447c4c2 chore(prebuilt): Allow testing fast (#5533)
Allow testing fast
2025-07-16 15:56:28 +00:00
Sam CrowderandWilliam FH 0d2db35d93 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5530)
* Update changelog via LangGraph Server Changelog Bot

* Update docs/docs/cloud/reference/langgraph_server_changelog.md

* Update docs/docs/cloud/reference/langgraph_server_changelog.md

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-07-16 14:01:46 +00:00
Sydney Runkle 6e9e1ca146 refactor(langgraph): make constants generally private with a few select exports (#5529) 2025-07-16 09:27:04 -04:00
renchao b290e1ffdc docs(mcp): update workflow usage examples (#5525)
Update mcp.md

 "END" is missing
2025-07-16 13:21:26 +00:00
Nuno Campos a5eb6a75bf checkpoint-postgres 2.0.23 2025-07-16 11:58:07 +02:00
Nuno Campos 7a136aaff6 perf(checkpoint-postgres): Reduce writes to checkpoint_blobs table (#5524) 2025-07-16 11:57:11 +02:00
Nuno Campos e973e936c3 perf: checkpoint-postgres: Reduce writes to checkpoint_blobs table
- Channels containing primitive values don't need to be stored in separate rows in blobs table, as the overhead of a separate row will usually be higher than the size of the value
- This applies for instance to all internal channels used to manage edges, so it has a big impact just from that. It can also apply to user-managed channels depending on their values
- The same channel may switch storage between versions without any issue
2025-07-16 11:43:51 +02:00
Sam CrowderandWilliam FH 066f3b21f8 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5523)
* Update changelog via LangGraph Server Changelog Bot

* Update docs/docs/cloud/reference/langgraph_server_changelog.md

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-07-16 06:39:09 +00:00
Sydney Runkle 2eecaa8500 release(langgraph): v1.0.0a1 (#5520)
prep for alpha release
2025-07-15 16:23:59 -04:00
Sydney Runkle d935a2d110 refactor(langgraph): move typing constructs in constants.py -> _internal/_typing.py (#5518) 2025-07-15 16:13:34 -04:00
+2 d5b8733a40 ci(docs): Add codespell for docs md and py files (#5494)
* docs: Add codespell for markdown files

* update

* remove path

* fix

* update linting guidelines

* chore[deps]: upgrade dependencies with `uv lock --upgrade` (#5471)

Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>

* fix(checkpoint): correct logging call to use logger (#5458)

fix[checkpoint]: correct logging call to use logger

* release(langgraph): v0.5.3 (#5498)

bump

* extend to cover python files used for reference docs

* fix(docs): Update the graph image link (#5500)

Update the graph image link

Point to the correct image reference for Map-Reduce and the Send API example

* fix(docs): Update graph-api.md File to reflect correct image (#5499)

Update graph-api.md File to reflect correct image

Referencing to the correct image file

* docs(prebuilt): improve documentation in ToolNode module (#5497)

Update documentation in ToolNode module

* Update changelog via LangGraph Server Changelog Bot

* feat(sdk-py): Show is_studio_user (#5505)

* Update changelog via LangGraph Server Changelog Bot

* fix(docs): Node caching explanation code required a small fix,. (#5473)

fix(docs): Node caching explanation code required a small fix, to avoid confusion to readers. The code had `time.sleep(2)` but the note mentioned one second only.

Co-authored-by: ygicp <yagnesh@infocusp.com>

* fix(langgraph): add `stacklevel=2` to the warnings to point to the caller’s codes (#5457)

chore: add stacklevel=2 to the warnings to point to the caller’s codes

* chore(docs): Improve example in use mcp (#5480)

* Make example more explicit

* Update docs/docs/agents/mcp.md

* fix(docs): update examples link (#5515)

Co-authored-by: ahmed murtaza <ahmed.gmurtaza@gmail.com>

* docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5514)

Update changelog via LangGraph Server Changelog Bot

* fix readmes

* fix

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Michael Li <michaelli65535@gmail.com>
Co-authored-by: Sakshi Gupta <64280320+sakshi1989@users.noreply.github.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: Sam Crowder <samecrowder@gmail.com>
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
Co-authored-by: Yagnesh M. Bhadiyadra <35532869+yagneshmb@users.noreply.github.com>
Co-authored-by: ygicp <yagnesh@infocusp.com>
Co-authored-by: Ahmed Murtaza <ahmed.gmurtaza@hotmail.com>
Co-authored-by: ahmed murtaza <ahmed.gmurtaza@gmail.com>
2025-07-15 19:22:48 +00:00
Lauren Hirata Singh 40c0e44b9a docs: Update with links to Forum (#5440)
Also updates some outdated references to LangChain
2025-07-15 14:55:15 -04:00
Mason Daugherty b5afec4b2a chore: add PR template (#5491) 2025-07-15 14:48:59 -04:00
Sam Crowder d674e1bddd docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5514)
Update changelog via LangGraph Server Changelog Bot
2025-07-15 11:13:18 -04:00
Ahmed Murtazaandahmed murtaza 8c68f739b9 fix(docs): update examples link (#5515)
Co-authored-by: ahmed murtaza <ahmed.gmurtaza@gmail.com>
2025-07-15 15:03:56 +00:00
Eugene Yurtsev 1500ebd3d7 chore(docs): Improve example in use mcp (#5480)
* Make example more explicit

* Update docs/docs/agents/mcp.md
2025-07-15 15:01:16 +00:00
Sydney Runkle 0837263542 feat(langgraph): new context api (replacing config['configurable'] and config_schema) (#5243) 2025-07-15 09:20:20 -04:00
Michael Li 18633bc99e fix(langgraph): add stacklevel=2 to the warnings to point to the caller’s codes (#5457)
chore: add stacklevel=2 to the warnings to point to the caller’s codes
2025-07-15 01:01:29 +00:00
Yagnesh M. Bhadiyadraandygicp 2558f81889 fix(docs): Node caching explanation code required a small fix,. (#5473)
fix(docs): Node caching explanation code required a small fix, to avoid confusion to readers. The code had `time.sleep(2)` but the note mentioned one second only.

Co-authored-by: ygicp <yagnesh@infocusp.com>
2025-07-15 00:58:32 +00:00
Sam Crowder b832fefc58 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5506) 2025-07-14 17:11:02 -07:00
Sam Crowder 444d699fe8 Update changelog via LangGraph Server Changelog Bot 2025-07-14 17:04:46 -07:00
William FH e315fb7397 feat(sdk-py): Show is_studio_user (#5505) 2025-07-14 16:55:32 -07:00
Darren Clark 0d8dfa7bba fix(checkpoint): fix AsyncBatchedBaseStore getting stuck
This commit fixes #5503

Gist of it is:

- `asyncio.exception.InvalidStateError` were being raised when the
  future was cancelled
- this exception bubbled up and killed the background task
- `AsyncBatchedBaseStore` stopped doing queries because the background
  task wasn't running anymore

This commit adds some "if future is not done" checks to guard against
this.
2025-07-14 18:03:51 -04:00
Sam Crowder 2c2ace2a40 docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5502) 2025-07-14 13:50:02 -07:00
Sam Crowder 74218fadad Update changelog via LangGraph Server Changelog Bot 2025-07-14 13:47:00 -07:00
Eugene Yurtsev 7a39e5fc6e docs(prebuilt): improve documentation in ToolNode module (#5497)
Update documentation in ToolNode module
2025-07-14 16:43:35 -04:00
Sakshi Gupta 06144b3b13 fix(docs): Update graph-api.md File to reflect correct image (#5499)
Update graph-api.md File to reflect correct image

Referencing to the correct image file
2025-07-14 20:39:47 +00:00
Sakshi Gupta b19572351e fix(docs): Update the graph image link (#5500)
Update the graph image link

Point to the correct image reference for Map-Reduce and the Send API example
2025-07-14 20:38:53 +00:00
Sydney Runkle a5ce13eb45 release(langgraph): v0.5.3 (#5498)
bump
2025-07-14 20:05:52 +00:00
Michael Li e91f72dd48 fix(checkpoint): correct logging call to use logger (#5458)
fix[checkpoint]: correct logging call to use logger
2025-07-14 19:16:10 +00:00
github-actions[bot]andsydney-runkle 3d9cb305b4 chore[deps]: upgrade dependencies with uv lock --upgrade (#5471)
Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-07-14 13:48:40 -04:00
jito de1460937a docs(checkpoint-postgres): fix typo in comment (#5486)
fix typo in comment

Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-14 16:58:13 +00:00
Sydney Runkle e0bf4a7bc3 Merge branch 'main' into v1 2025-07-14 12:54:11 -04:00
Hunter Lovell 06f311fffb chore: add forum to readme (#5488)
* chore: add forum to readme

* chore(langgraph): sync readme
2025-07-14 12:51:18 -04:00
Micael Jarniac 5bdb887638 docs: fix Langraph typo (#5490) 2025-07-14 12:49:38 -04:00
Sydney Runkle 6c4034420c fix(langgraph): remove ABC spec for PregelProtocol (#5485) 2025-07-14 12:24:49 -04:00
Lauren Hirata Singh fa5d93ac2f docs: Fix image in Graph API how to (#5487)
docs: Fix iimage in Graph API how to

Closes https://github.com/langchain-ai/langgraph/issues/5451
2025-07-14 11:48:50 -04:00
Krishna Nadiger d14a6e2c04 fix(docs): Corrected Send import in example code of "Map-Reduce and the Sen… (#5466)
Fix: Corrected Send import in example code of "Map-Reduce and the Send API"

Fixes #5465 - Moved Send import from langgraph.graph to langgraph.types
2025-07-14 14:49:13 +00:00
jito 54dadadac4 docs(prebuilt): fix typo in interrupt.py (#5478)
fix typo in interrupt.py

Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-14 14:06:13 +00:00
langchain-infra d073e1bd8a docs: fix langgraph dataplane docs (#5474) 2025-07-13 19:53:04 -04:00
infra 28c276f377 docs: fix langgraph dataplane docs 2025-07-13 19:10:57 -04:00
William Fu-Hinthorn a71eb09488 chore[docs]: Mention dataclass 2025-07-12 14:11:25 -07:00
Lauren Hirata Singh 579c7831b9 docs: static vs dynamic interrupts (#5426)
* docs: static vs dynamic interrupts

* fixes based on feedback

* fix image

* Add section about debugging in Studio

* Reorg content based on feedback

* fix

* fix links

* fix wording

* fix wording
2025-07-11 17:07:43 -04:00
Xin Jin 16da5f4779 fix: markdown title copy button (#5462)
fix url remove dup title
2025-07-11 21:02:58 +00:00
Eugene Yurtsev f59a1339c9 chore(docs): Consolidate hooks for copy markdown and notebooks (#5459)
Consolidating the hooks to avoid duplication of logic

We need this change for consolidating js and python content: we need include-markdown to run as a mkdocs plugin before our pipeline (rather than as markdown extension which runs after our hooks plugin).
2025-07-11 20:44:46 +00:00
Xin Jin d166e9b8e9 fix: llm.txt url link broken (#5460)
fix url issue
2025-07-11 16:40:37 -04:00
Xin Jin 4da35babda feat: add copy page button functionality and fix llms-text output (#5419)
* feat: add copy page button functionality and fix llms-text output

- Add copy page button with CSS and JS implementation
- Implement copy page hooks for MkDocs integration
- Fix HTML filtering and DOM text reinterpreted as HTML issues
- Update llms-text target to generate docs/llm.txt instead of docs/llms-full.txt
- Add necessary styling and package.json dependencies

* fix missing button in preview

* remove the over-processing

* disable API reference
2025-07-11 15:13:55 -04:00
Sam Crowder c3d882e87a docs: [LangGraph Server Changelog Bot] Changelog updates for new version(s) (#5455)
Update changelog via LangGraph Server Changelog Bot
2025-07-11 11:55:08 -07:00
jito fbade9e300 docs: fix variable reference in agent evaluator example (#5434)
Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-11 14:57:49 +00:00
jito 0b6a9e345d fix(langgraph): replace _state_schema to state_schema when accessing StateGraph (#5436) 2025-07-11 01:39:59 +00:00
William FH 9b9bf88aee fix(checkpoint-postgres): Remove python invalid escape warning (#5441) 2025-07-10 22:38:05 +00:00
Sydney Runkle 5f00938aa2 feat(langgraph): add type checking for matching node signatures vs input_schema for add_node (#5424) 2025-07-10 09:42:37 -04:00
William FH 67a86f2dc2 fix[docs]: Add missing flags for langgraph up command (#5429) 2025-07-10 02:07:48 +00:00
Sam Crowder ad44d1fe66 docs: [LangGraph Changelog Bot] Changelog updates for new version(s) (#5427) 2025-07-09 18:41:03 -07:00
Sam Crowder 5c45f7c330 Update changelog via LangGraph Changelog Bot 2025-07-09 18:06:04 -07:00
Sam Crowder bb2f448175 docs: [LangGraph Changelog Bot] Changelog updates for new version(s) (#5425) 2025-07-09 13:55:14 -07:00
Sam Crowder 8a9f3dbf6f Update changelog via LangGraph Changelog Bot 2025-07-09 13:34:04 -07:00
Sam Crowder 63f051ad28 Update changelog via LangGraph Changelog Bot 2025-07-09 13:25:47 -07:00
Sydney Runkle e5ded1888b Merge branch 'main' into v1 2025-07-09 15:26:08 -04:00
Sydney Runkle 0ab9770056 release(langgraph): v0.5.2 (#5421)
langgraph bump
2025-07-09 19:10:20 +00:00
Eugene Yurtsev 8ca5e56f52 fix(docs): links in examples file (#5420)
Fix broken links in examples
2025-07-09 14:59:41 -04:00
Sam CrowderandLauren Hirata Singh 0733ec65ad docs: introduce LangGraph Server changelog (#5417)
* introduce changelog

* fix spelling

* Update docs/mkdocs.yml

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>

* Update docs/docs/cloud/reference/langgraph_server_changelog.md

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>

* Update docs/docs/cloud/reference/langgraph_server_changelog.md

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>

* Update langgraph_server_changelog.md

---------

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-09 14:37:39 -04:00
Sydney Runkle 543cbe9032 chore: add PR title linter (#5416) 2025-07-09 14:12:00 -04:00
Sydney Runkle d1710e2eac change[langgraph]: clean up Interrupt interface for v1 (#5405) 2025-07-09 14:03:08 -04:00
Sydney Runkle 6eace78c53 patch[langgraph]: Fix hint for invoke/stream to allow for Command and None (#5414)
use Command and None as well
2025-07-09 13:23:28 -04:00
Sydney Runkle e5947bcd30 Merge branch 'main' into v1 2025-07-09 13:06:41 -04:00
jito 1240f8bdca fix: correct troubleshooting link path (#5411)
fix: correct troubleshooting link path from index.md.md to index.md

Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-09 16:20:33 +00:00
Eugene Yurtsev 4d7c107bb8 Update config.yml (#5412) 2025-07-09 12:19:49 -04:00
Andrew Nguonly 7a4fd25185 docs: Add RESUMABLE_STREAM_TTL_SECONDS to env vars list (#5413)
* Add RESUMABLE_STREAM_TTL_SECONDS to env vars list.

* Update default value for BG_JOB_SHUTDOWN_GRACE_PERIOD_SECS.

* Update LANGGRAPH_POSTGRES_POOL_MAX_SIZE description.
2025-07-09 10:53:21 -04:00
Kai-Wendel 7a66213535 Fix typo in types.py in the interrupt example (#5407)
Update types.py

This example still lacked to include `Command`.
2025-07-08 20:49:04 +00:00
nlimpid c8d32f104d fix(doc): remove incorrect navigation title overrides for mobile (#5399) 2025-07-08 20:09:57 +00:00
William FH 2fee649980 chore: (cli) Update description of disable_meta (#5406) 2025-07-08 19:55:10 +00:00
William FH 0d8a8c5847 feat: [CLI] Add arg to retain build deps (setuptools, pip, wheel) (#5404) 2025-07-08 19:41:47 +00:00
Michael Li 9cb6365914 docs: update file paths to make the examples more robust (#5382)
* cli: update file paths to make the examples more robust

* fix: fix the prompt path
2025-07-08 18:58:04 +00:00
Sydney Runkle b6dc566ec7 Merge branch 'main' into v1 2025-07-08 14:55:09 -04:00
Jake Broekhuizen fb1c0ae9f9 docs: Updating mcp_tools_node fn & referencing runtime graph rebuild docs (#5328)
Fix: Updating mcp_tools_node fn & referencing runtime graph rebuild docs
2025-07-08 12:55:15 -04:00
Lauren Hirata Singh 4de1bd6e66 docs: cleanup (#5401)
* docs: cleanup

* fix nav

* fix

* fix nits
2025-07-08 12:33:14 -04:00
+6 f21fc056bf docs: Convert example notebooks (#5381)
* Agentic RAG

* Fix formatting

* Agent supervisor

* fix links

* SQL agent

* Graph Runs in LS

* fix format

* Autogen + LG tutorial

* fixes

* update sql

* remove old notebooks

* docs: Add section about data region for LGP data plane (#5378)

Add section about data region.

* fix: remove empty notebook (#5379)

* Fix docstring for _unset_config_context function (#5374)

Signed-off-by: jitokim <pigberger70@gmail.com>

* Fix typo in StreamMode debug description: checlkpoints → checkpoints (#5371)

Signed-off-by: jitokim <pigberger70@gmail.com>

* fix: remove unused import in generate_llms_text.py (#5380)

* dcos: Fix deprecation of TavilySearch (#5375)

Fix deprecation: The class `TavilySearchResults` was deprecated in LangChain 0.3.25 and will be removed in 1.0

* Fix typo: funtion → function (#5370)

fix typos

Signed-off-by: jitokim <pigberger70@gmail.com>

* docs: feedback edits (#5387)

* docs: update lgp deployment metric list (#5388)

* chore(deps): bump peter-evans/create-pull-request from 6 to 7 (#5365)

Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6 to 7.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v6...v7)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* docs: correct link in docs/docs/how-tos/graph-api.md (#5377)

Update graph-api.md

* docs: Update quick_start.md Rest API Guide (#5368)

Update quick_start.md Rest API Guide

The curl command in the quick start needs some minor changes to work out of the box. I hope by adding these changes then new users can get started more quickly

* Remove duplicate CONFIG_KEY_CHECKPOINT_MAP from RESERVED set (#5372)

Signed-off-by: jitokim <pigberger70@gmail.com>

* docs: fix typo in persistence (#5329)

* docs: fix typo in application_structure

* docs: fix typo in persistence

* chore[deps]: upgrade dependencies with `uv lock --upgrade` (#5358)

* chore: upgrade dependencies with `uv lock --upgrade`

* linting

* upgrade PR title

---------

Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>

* Updated examples for SummarizationNode to account for serde with persistence layers (#5257)

* docs: move script into scripts (#5384)

* docs: update sql tutorial (#5389)

---------

Signed-off-by: jitokim <pigberger70@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Andrew Nguonly <andrewnguonly@users.noreply.github.com>
Co-authored-by: Michael Li <michaelli65535@gmail.com>
Co-authored-by: jito <pigberger70@gmail.com>
Co-authored-by: Serhii Polishchuk <serhii.polishchuk@gelato.com>
Co-authored-by: hari-dhanushkodi <hari@langchain.dev>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Fadel Akram <af8356207@gmail.com>
Co-authored-by: David <31293924+dreadn0ught@users.noreply.github.com>
Co-authored-by: Youssef Ahmed Mohamed Abdelrahman <109446360+unauthorised-401@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
Co-authored-by: Nick Riley <nick@sparkida.com>
Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
Co-authored-by: ccurme <chester.curme@gmail.com>
2025-07-08 10:36:47 -04:00
lc-arjun 1f1d032430 docs: add tunnel flag to node server docs (#5398) 2025-07-08 06:59:02 -07:00
Sydney Runkle a84b744eb6 Merge branch 'main' into v1 2025-07-08 09:55:13 -04:00
lc-arjun 6f86a8c4cb Revert "docs: add -tunnel flag for node server" (#5397)
Revert "docs: add -tunnel flag for node server (#5373)"

This reverts commit 4abf948462.
2025-07-08 06:49:13 -07:00
Nick Riley d5ab8b42e0 Updated examples for SummarizationNode to account for serde with persistence layers (#5257) 2025-07-07 16:31:55 -07:00
87f2e69395 chore[deps]: upgrade dependencies with uv lock --upgrade (#5358)
* chore: upgrade dependencies with `uv lock --upgrade`

* linting

* upgrade PR title

---------

Co-authored-by: sydney-runkle <54324534+sydney-runkle@users.noreply.github.com>
Co-authored-by: Sydney Runkle <sydneymarierunkle@gmail.com>
2025-07-07 23:24:32 +00:00
Youssef Ahmed Mohamed Abdelrahman 4c73b176ff docs: fix typo in persistence (#5329)
* docs: fix typo in application_structure

* docs: fix typo in persistence
2025-07-07 23:22:53 +00:00
jito 4321ed0f87 Remove duplicate CONFIG_KEY_CHECKPOINT_MAP from RESERVED set (#5372)
Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-07 19:19:16 -04:00
David cba4d9e3bc docs: Update quick_start.md Rest API Guide (#5368)
Update quick_start.md Rest API Guide

The curl command in the quick start needs some minor changes to work out of the box. I hope by adding these changes then new users can get started more quickly
2025-07-07 19:18:55 -04:00
Fadel Akram fa36a50444 docs: correct link in docs/docs/how-tos/graph-api.md (#5377)
Update graph-api.md
2025-07-07 23:14:17 +00:00
dependabot[bot] 5413f9db9f chore(deps): bump peter-evans/create-pull-request from 6 to 7 (#5365)
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 6 to 7.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v6...v7)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-07 19:00:51 -04:00
ccurme 8118e90543 docs: update sql tutorial (#5389) 2025-07-07 18:02:02 -04:00
hari-dhanushkodi c13c474626 docs: update lgp deployment metric list (#5388) 2025-07-07 17:44:57 -04:00
Lauren Hirata Singh cd58fad69d docs: feedback edits (#5387) 2025-07-07 17:03:05 -04:00
jito f3a7925d86 Fix typo: funtion → function (#5370)
fix typos

Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-07 20:09:55 +00:00
Serhii Polishchuk de6c25689d dcos: Fix deprecation of TavilySearch (#5375)
Fix deprecation: The class `TavilySearchResults` was deprecated in LangChain 0.3.25 and will be removed in 1.0
2025-07-07 16:00:57 -04:00
Michael Li 141afa8c62 fix: remove unused import in generate_llms_text.py (#5380) 2025-07-07 15:54:02 -04:00
jito e99f6292c5 Fix typo in StreamMode debug description: checlkpoints → checkpoints (#5371)
Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-07 19:27:09 +00:00
jito 1800df7048 Fix docstring for _unset_config_context function (#5374)
Signed-off-by: jitokim <pigberger70@gmail.com>
2025-07-07 19:25:06 +00:00
Eugene Yurtsev 7f57e00975 docs: move script into scripts (#5384) 2025-07-07 15:10:01 -04:00
Michael Li 844417591d fix: remove empty notebook (#5379) 2025-07-07 19:09:00 +00:00
Andrew Nguonly c9966c4feb docs: Add section about data region for LGP data plane (#5378)
Add section about data region.
2025-07-07 12:39:44 -04:00
lc-arjun 4abf948462 docs: add -tunnel flag for node server (#5373)
add -tunnel flag for node server
2025-07-07 08:05:46 -07:00
jessicaou 269590c4d9 docs: update case studies (#5353) 2025-07-06 20:37:54 -04:00
Shivang Agarwal d8756f257e Updated TAVILY Key Setup (#5346) 2025-07-07 00:36:28 +00:00
Chris G cac0cd5522 docs: update name of CompiledGraph CompiledStateGraph (#5348)
The name (and type) has changed. See:
https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.state.StateGraph.compile
2025-07-07 00:35:37 +00:00
David Duong c91208429e fix(docs): invalid command for creating langgraph app (#5349) 2025-07-04 16:30:06 +02:00
Tat Dat Duong 690b6f4ea1 fix(docs): invalid command for creating langgraph app
Closes https://github.com/langchain-ai/langgraphjs/issues/1331
2025-07-04 16:29:38 +02:00
Sydney Runkle f5b888dd72 run CI on v1 branch temporarily (#5341)
temporarily run CI on v1 as well
2025-07-03 23:53:38 +00:00
Sydney Runkle 7a8f29847b fix conflicts in state.py (#5340)
* fix conflicts
* lockfile fixes
2025-07-03 23:33:39 +00:00
Sydney Runkle f001246794 Merge branch 'main' into v1 2025-07-03 19:27:07 -04:00
Andrew Nguonly 07cd4d83e1 docs: Add note about preemptive compute infra (#5339)
* Add note about preemtive compute infra.

* Fix spelling error.
2025-07-03 16:04:27 -07:00
David Duong fcdfc1d5e4 chore: move sdk-js to langgraphjs (#5334) 2025-07-03 16:58:31 +02:00
Tat Dat Duong dc95d1af88 Add a README.md 2025-07-03 16:52:35 +02:00
Tat Dat Duong 042e8ef315 chore: remove sdk-js
`sdk-js` has been moved here: https://github.com/langchain-ai/langgraphjs/tree/main/libs/sdk
2025-07-03 16:50:51 +02:00
Eugene Yurtsev 37d1ac1dce ci: one more workflow without explicit permissions (#5326) 2025-07-02 22:26:32 -04:00
Josh Rogers ecfabdf73a Adding disable_webhook to cli docs (#5320)
* Adding disable_webhook to cli docs
* Adding disable_webhook config
2025-07-02 22:14:01 -04:00
Lauren Hirata Singh 543e4c4e7e docs: Convert notebooks (#5322)
* docs: Convert subgraphs notebook

* graph api conversion

* fix examples

* add

* fixes

* fix links

* fix links

* be gone!

* multi-agent conversion

* fix link

* fix links

* fix link
2025-07-02 23:28:42 +00:00
Jake BroekhuizenandLauren Hirata Singh 22e09d2739 Create user_agent_auth.md (#5299)
* Create user_agent_auth.md

Adding documentation for agent authentication on behalf of a user

* Update user_agent_auth.md

* Rename user_agent_auth.md to user-agent-auth.md

* break content out to separate guides

* add links/overview

* edits

* fix sentence

* Fix broken links

* Fix: Change 'get_user_config' fn name to 'my_node'

* Fix: Add reference to custom auth in MCP docs example

---------

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-07-02 22:05:07 +00:00
Andrew Nguonly 89451f4ea2 docs: Add LGP control plane API docs page (#5319)
Add control plane API docs page.
2025-07-02 14:30:00 -07:00
Sydney Runkle b7d11b4141 Merge branch 'main' into v1 2025-07-02 17:23:45 -04:00
Sydney Runkle 1d3fd9a46b chore: merge main into v1 (#5324) 2025-07-02 17:13:31 -04:00
Sydney Runkle 813a1d6d0c langgraph: release v0.5.1 (#5323)
* bump
* lock
2025-07-02 21:06:05 +00:00
Eugene Yurtsev e28af0ffc3 ci: set explicit workflow permissions to read (should be a no-op) (#5318)
* We're using restricted GITHUB_TOKENS by default.
* This is expected to be a no-op operation for codeql.
2025-07-02 17:02:17 -04:00
Sydney Runkle 8c4e698c5a langgraph[change]: solidify public/private differentiations (#5252)
* public interfaces for channels
* public interfaces for func
* public interfaces for graph
* pi for managed
* first pass public interface for top level modules
* first pass at private for utils -> _internal
* private interface for pregel
* scratchpad/stream protocol move
* docs update
* backwards compat for runnable
* deprecation warning for send and interrupt
* deprecation for pregel import
2025-07-02 16:48:53 -04:00
Sydney Runkle 339de4c204 langgraph[fix]: remove deprecated pydantic logic + fix schema gen behavior for typed dicts (#5296) 2025-07-02 20:08:48 +00:00
lc-arjun 0885e7833b docs: cli data storage handling (#5188)
Write up initial docs on how data is managed in the langgraph server, what telemetry is collected (and why), and how to opt-out.
2025-07-02 12:19:46 -07:00
Josh Rogers 669cf817e8 Bump js sdk to 0.0.89 (#5313) 2025-07-02 09:56:04 -07:00
Sydney Runkle 000f5c3043 fix[deps]: update lockfiles / deps bounds for internal tools (#5301)
update lockfiles / deps bounds
2025-07-02 10:30:55 -04:00
Sydney Runkle b3708bd7f6 ci: add automated uv lock --upgrade workflow (#5307) 2025-07-02 10:10:01 -04:00
Sydney Runkle 8271e39e00 dependabot: no kafka (#5306)
* fix list of dirs
* another patch
2025-07-02 13:15:00 +00:00
Sydney Runkle 60560ea755 dependabot: fix list of dirs for pip updates (#5305)
fix list of dirs
2025-07-02 13:12:22 +00:00
waqarahmed6095 e2acfb24cc Update use_stream_react.md (#5304)
Problem of two times heading 
"How to integrate LangGraph into your React application"
2025-07-02 13:10:57 +00:00
Sydney Runkle 191192b142 upgrade dependabot scope (#5303) 2025-07-02 09:09:11 -04:00
Josh Rogers df368bdd30 Updating message types to include all base message fields (#5298) 2025-07-01 15:40:13 -07:00
Josh Rogers 4ec897033f Update LGP api reference docs (#5297) 2025-07-01 11:45:30 -07:00
Sydney Runkle c989f1c898 langgraph: remove support for thread_ts (old alias for checkpoint_id) (#5295)
* remove support for thread_ts

* docs and tests
2025-07-01 13:42:25 -04:00
c16e42e6d5 fix broken link (#5291)
* fix broken link

* Apply suggestions from code review

Fix link

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>

---------

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-07-01 13:52:26 +00:00
David Duong 376469ea90 release(sdk-js): 0.0.88 (#5294) 2025-07-01 14:30:37 +02:00
Tat Dat Duong 7e2af0ce8d release(sdk-js): 0.0.88 2025-07-01 14:21:11 +02:00
Youssef Ahmed Mohamed Abdelrahman 1b205a99cb docs: fix typo in application_structure (#5289) 2025-07-01 12:09:14 +00:00
Sam Crowder 0a8ba20f5f docs: remove beta flag on self hosted plane (#5288) 2025-06-30 22:41:05 -04:00
Sam Crowder 048cb3584c self hosted control plane no longer in beta (#5286)
* self hosted control plane no longer in beta

* accidental changes
2025-06-30 17:34:18 -07:00
Sam Crowder 22c35b7bc8 switch order of MCP methods in API spec (#5287) 2025-06-30 17:33:59 -07:00
David Duong f3ed32e611 feat(react): enhance useStream with initialValues, newThreadId, and onStop callback for improved UX (#5111) 2025-07-01 01:53:28 +02:00
Tat Dat Duong 276675b618 Make sure to spread stream values 2025-07-01 01:39:53 +02:00
Tat Dat Duong 882de42996 Fix non-existent assistantId 2025-07-01 01:35:59 +02:00
Tat Dat Duong 70be50f37b Fix typo 2025-07-01 01:33:08 +02:00
Tat Dat Duong 1c7234e9c5 Update README.md 2025-07-01 01:32:27 +02:00
Tat Dat Duong 3d88f75254 Cleanup 2025-07-01 01:19:07 +02:00
Lauren Hirata Singh 407abbe9ff Add forum links (#5282) 2025-06-30 16:11:46 -04:00
ccurme 6182cd1dcb prebuilt: release 0.5.2 (#5280) 2025-06-30 15:50:21 -04:00
Lauren Hirata Singh 1d276dd753 docs: cronjob nav (#5281) 2025-06-30 15:34:29 -04:00
ccurme a48d8cb69b prebuilt[patch]: import recognized tool message content block types from langchain-core (#5275) 2025-06-30 15:22:19 -04:00
Lauren Hirata Singh a05a251caf docs: Fix nav (#5279) 2025-06-30 15:18:43 -04:00
MauritsBrinkman c7bbb26ac0 test: add useStream onStop callback tests 2025-06-30 16:43:48 +02:00
MauritsBrinkman ac9b6c416e feat: add onStop callback to useStream for custom stop behavior
Add onStop callback to useStream hook enabling developers to customize
UI behavior when streams are stopped. This is especially useful for
UI messages with loading states that need to show "stopped" status
instead of remaining in infinite loading state.

The callback provides the same mutate function as onCustomEvent for
immediate local state updates, while users can optionally update
server thread state using the threads client.

Example usage:
```typescript
const stream = useStream({
  assistantId: "my-assistant",
  onStop: async ({ mutate }) => {
    // Immediate UI update - stop loading components
    mutate((prev) => ({
      ...prev,
      ui: prev.ui?.map(component =>
        component.props?.isLoading
          ? {
              ...component,
              props: {
                ...component.props,
                isLoading: false,
                isStopped: true
              }
            }
          : component
      )
    }));

    // Optional server thread state update
    if (stream.threadId) {
      await stream.client.threads.updateState(stream.threadId, {
        values: {
          ui: prev.ui // persist stopped state to server
        }
      });
    }
  }
});
```

This is especially useful for cases where gen UI components have loading states,
where we don't want the loading state to persist on cancellation.
2025-06-30 16:43:13 +02:00
MauritsBrinkman d4b4eebe4a fix(sdk-js): convert SSE classes to factory functions to resolve tree shaking
- Convert BytesLineDecoder and SSEDecoder from classes extending TransformStream to factory functions
- Fixes tree shaking failures that prevented build completion
- Maintains identical API functionality, just removes 'new' keyword usage
- All tests continue to pass

Resolves tree shaking side effect detection issues with TransformStream extension
2025-06-30 16:43:13 +02:00
MauritsBrinkman f8e1e803e1 docs(react): add documentation and tests for initialValues and newThreadId options
- Document initialValues for cached thread display
- Document newThreadId for optimistic thread creation
- Add comprehensive test coverage for both features
2025-06-30 16:43:12 +02:00
MauritsBrinkman 141a6af4f7 feat(react): add initialValues option to useStream for cached thread display
Add initialValues parameter to UseStreamOptions to enable immediate display
of cached thread data while official history is being fetched from the server.

This addresses the common use case where applications cache thread data
locally (IndexedDB, localStorage, etc.) and want to show it instantly when
users navigate to existing threads, providing better UX with faster loading.

Key changes:
- Add initialValues?: Partial<StateType> | null to UseStreamOptions interface
- Update values precedence: streamValues > initialValues > historyValues
- Ensure optimisticValues properly override initialValues during submission
- Maintain full backward compatibility with existing API

Example usage:
```typescript
const stream = useStream({
  threadId,
  assistantId: 'my-assistant',
  initialValues: cachedThreadData?.values // Show cached data immediately
});
```

The values flow now follows this priority:
1. Initial load: shows initialValues while history loads
2. During submit: optimisticValues take precedence
3. After server response: official history replaces all
2025-06-30 16:43:12 +02:00
MauritsBrinkman 8a763ad358 feat(react): add newThreadId option to useStream for optimistic UI
Add optional newThreadId parameter to useStream hook that allows specifying
a thread ID for new thread creation while keeping threadId null. This enables
optimistic UI patterns where developers need to know the thread ID beforehand
for routing/navigation without causing 404 errors from attempting to fetch
non-existent thread history.

Usage:
- Set threadId: null and newThreadId: "predetermined-id"
- Submit message to create thread with specified ID
- Use onThreadId callback to update threadId after creation

This solves the UX problem of having to await thread creation before
enabling optimistic navigation to e.g. /[threadId] routes.
2025-06-30 16:43:12 +02:00
David Duong 16d02e63a1 fix: Allow configuring stream mode in useStream.joinStream() (#5146) 2025-06-30 16:37:56 +02:00
David Duong 03421c2b04 chore(sdk-js): use embed LGP server for MSW mocking (#5174) 2025-06-30 16:33:47 +02:00
Tat Dat Duong 2508aa45ea Use published package 2025-06-30 13:51:32 +02:00
Sam Crowder 9e035264f8 slightly more explanation when we say dont use in serverless (#5245)
slightly more explanation
2025-06-29 21:59:48 -04:00
joaquin-borggio-lc 84e14f47bf docs: Add pre-req for egress to control plane (#5241)
added pre-req for egress
2025-06-27 14:18:39 -07:00
Lauren Hirata Singh 83bbe42eab docs: Nav reorg (#5236)
* docs: Nav consolidation

* nav

* reorg

* fix links

* fix

* prebuilts

* fix spelling

* reorg

* reorg
2025-06-27 14:06:26 -04:00
David Duong 70894af72c fix(sdk-js): avoid stale client when fetching history (#5240) 2025-06-27 20:04:41 +02:00
Tat Dat Duong e466327524 Bump to 0.0.87 2025-06-27 20:03:03 +02:00
Tat Dat Duong b6655fe083 Use the client hash only in useEffect 2025-06-27 19:59:21 +02:00
Tat Dat Duong 9b7cc1c82e fix(sdk-js): avoid stale client when fetching history 2025-06-27 19:51:49 +02:00
Nuno Campos 80d6bddd1b Fix deadlock in SqliteStore (#5234) 2025-06-27 09:03:57 -07:00
Nuno Campos c406aede96 Fix deadlock in SqliteStore
- If setup wasnt called separately _cursor() and setup() would deadlock
- The call to setup() in _cursor() should be outside the lock block, as setup() also acquires the lock and re-checks the setup flag
2025-06-27 08:57:35 -07:00
Eugene Yurtsev 96bfc8bad9 docs: cross links for functional api (#5231)
add cross-links
2025-06-27 11:31:18 -04:00
Lauren Hirata SinghandEugene Yurtsev 0fd6306623 docs: Time travel and breakpoints (#5215)
* docs: Time travel and breakpoints

* fix links

* fix

* edits

* Fix link

* Remove circular redirects

* revert llms.txt

---------

Co-authored-by: Eugene Yurtsev <eyurtsev@gmail.com>
2025-06-27 14:49:53 +00:00
Yassin Nouh f01ab13cab DOC: Add missing docs_txt = format_docs() lines in adaptive RAG tutorial (#5222) 2025-06-27 10:45:12 -04:00
Eugene Yurtsev 1beaf48cf9 docs: quick nav fixes (#5229)
Quick nav fixes
2025-06-27 10:37:42 -04:00
Sam Crowder 847b0e8243 add warning about serverless (#5218) 2025-06-27 07:31:52 -07:00
Eugene Yurtsev 02a2467610 docs: context update (#5207)
Update context
2025-06-27 14:25:54 +00:00
Sydney Runkle fa5e7a97c2 release[prebuilt]: bump version to v0.5.1 (#5228)
version bump
2025-06-27 14:02:14 +00:00
Sydney Runkle 233a92ccb9 fix[prebuilt]: bind tools even if it's only provider tools (#5227)
bind tools even if just provider tools
2025-06-27 09:49:26 -04:00
lc-arjun e277a6bd9b chore: sdk bumps (#5220)
* chore: sdk bumps

* uv lock
2025-06-26 17:57:05 -07:00
lc-arjun 16250fe038 chore: update api ref docs and fix schemas (#5219) 2025-06-26 17:41:03 -07:00
Nuno Campos 216d1be0a5 Revert "Reapply "docs: deploy from v0 branch for now (#4960)" (#5184) (#5185)"
This reverts commit cb63c1ab72.
2025-06-26 15:52:45 -07:00
Nuno Campos 0a4cd5fcaa 0.5.0 2025-06-26 15:47:46 -07:00
Nuno Campos f8503670af Add test for reducer exceptions (#5217) 2025-06-26 12:48:07 -07:00
Nuno Campos 0f22841f78 Add test for reducer exceptions 2025-06-26 11:40:55 -07:00
lc-arjun 4a26ca5bc2 feat: crons sorting sdk (#5197)
* feat: crons sorting sdk

* update sync clients

* lock file

* lock file

* lock file
2025-06-26 11:27:44 -07:00
William FH a622218746 chore: (CLI) bump api minbound (#5206) 2025-06-25 19:28:13 -07:00
William FH 7fda427601 fix: [prebuilt] Checks for pre-bound model with builtin tools (#5203) 2025-06-26 01:34:21 +00:00
Nuno Campos 1c9bfba23a feat(langgraph): task masquerading with update state (#5189) 2025-06-25 17:13:54 -07:00
Nuno Campos cee9ac0b7a One more 2025-06-25 17:07:26 -07:00
Nuno Campos 3ddb6b1477 One more 2025-06-25 17:05:41 -07:00
Nuno Campos 8a5519da29 Fix update_state bugs 2025-06-25 17:02:08 -07:00
Nuno Campos abc5a5ff44 Update 2025-06-26 01:30:52 +02:00
Nuno Campos 38ab90217f Fix assertion 2025-06-26 01:30:52 +02:00
Tat Dat Duong 005edb2979 Async test 2025-06-26 01:30:51 +02:00
Tat Dat Duong c5a851cd91 Use as_node=END instead 2025-06-26 01:30:51 +02:00
Tat Dat Duong 06a42aee53 Remove if/else 2025-06-26 01:30:51 +02:00
Tat Dat Duong 04b9947a41 Fix mypy 2025-06-26 01:30:51 +02:00
Tat Dat Duong 239df52e74 Avoid creating new root checkpoint to preserve behaviour 2025-06-26 01:30:48 +02:00
Tat Dat Duong 8a67a5ac25 Fix format 2025-06-26 01:30:11 +02:00
Tat Dat Duong adb2eee54b Remove dict 2025-06-26 01:30:10 +02:00
Tat Dat Duong 263a583f01 Fix lint 2025-06-26 01:30:10 +02:00
Tat Dat Duong 565d52975c Fix test 2025-06-26 01:30:10 +02:00
Tat Dat Duong 865fba9d50 feat(langgraph): task masquerading with update state 2025-06-26 01:30:10 +02:00
Nuno Campos 929bba8337 Add print_mode= arg to invoke/stream (#5201) 2025-06-25 16:21:19 -07:00
Nuno Campos 634511350f Remove unused branch in update_state (#5195) 2025-06-25 16:08:48 -07:00
Nuno Campos c9dcd3fbb5 Map debug=True to print_mode=['values', 'updates'] 2025-06-25 16:08:20 -07:00
Eugene Yurtsev 10a0a8633a docs: consolidate models (#5200)
* Expand chat model documentation a bit. 
* Adds links to langchain docs to make relevant information easier to find.
* This is a stop-gap until we merge langchain and langgraph docs
2025-06-25 15:55:17 -04:00
Eugene Yurtsev 23327f5647 docs: update mcp docs (#5191)
Update MCP docs
2025-06-25 15:06:35 -04:00
Nuno Campos e23da72ccd Add print_mode= arg to invoke/stream
- This is more flexible version of the debug= flag, which we'll deprecate
2025-06-25 11:52:42 -07:00
Lauren Hirata SinghandSydney Runkle 0aefe68a5f docs: HITL consolidation (#5192)
* HITL consolidation, minus server

* Fix links

* Fix server page

* remove extra page

* nits

* updates based on feedback

* Update docs/docs/concepts/human_in_the_loop.md

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>

* edits based on feedback

---------

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-06-25 14:16:46 -04:00
Eugene Yurtsev 5b8edf3c72 docs: consolidate tool documentation (#5190)
Consolidate tool documentation

- [x] Cross links between conceptual doc and tools guide
- [x] Tools guide includes both workflow and agent usage example
2025-06-25 14:13:11 -04:00
Lauren Hirata Singh b64e1bcae4 docs: Add FAQ for nodes executed (#5198)
Add FAQ for nodes executed
2025-06-25 12:28:21 -04:00
Nuno Campos d877ea479b Remove unused branch in update_state
- update_state(None, as_node=None) was not tested/used, and was too similar in behavior to __copy__ / __end__, so removing it
2025-06-25 08:38:20 -07:00
Sydney Runkle cb63c1ab72 Reapply "docs: deploy from v0 branch for now (#4960)" (#5184) (#5185)
This reverts commit a7ea5e44ce.
2025-06-24 16:01:03 +00:00
Sydney Runkle a7ea5e44ce Revert "docs: deploy from v0 branch for now (#4960)" (#5184)
This reverts commit aedf974dfd.
2025-06-24 14:59:33 +00:00
Lauren Hirata Singh c3ae5e6b71 docs: Reorganize existing content (#5122)
* Organize existing content differently

* Fix broken links

* Remove cookie consent popup

* edits

* Consolidate streaming

* Remove agents/streaming

* Fix broken links

* Edit stream modes

* Change titles

* Fix titles based on feedback

* Move LGP to platform section

* Update navigation

* Consolidate assistant conceptual guides

* docs: Memory consolidation (#5149)

* Memory consolidation

* Fix broken links

* fix links

* Fix links

* Fix links

* General content clean up for memory

* fix links

* Fix link

* fix links

* Fix title

* Edits based on feedback

* Link to memory store
2025-06-24 09:29:59 -04:00
Vedant Panchal ac328c3fd8 [fix] snippet for Agents as a Tool (#5181)
snippet had a missing decorator that might lead the user to confuse whether it is really a tool
2025-06-24 11:44:32 +00:00
Nuno Campos ebd7977936 Revert change to default value of checkpoint_during arg (#5177) 2025-06-23 18:12:19 -07:00
Nuno Campos a6381c32b0 Revert change to default value of checkpoint_during arg 2025-06-23 18:05:46 -07:00
Nuno Campos 294d346650 Fix bug where Command(update=) could be ignored if there was a 2nd interrupt after it (#5175) 2025-06-23 17:35:36 -07:00
Nuno Campos 866c8009dc Fix bug where Command(update=) could be ignored if there was a 2nd interrupt after it
- writes from the null task (ie. from outside tasks) should be accummulated across invocations
2025-06-23 17:23:53 -07:00
Tat Dat Duong 9a0cee5cd0 chore(sdk-js): use embed LGP server for MSW mocking 2025-06-24 02:14:19 +02:00
Rauf Parchiev 73bed2cf7c Update workflows.md (#5116) 2025-06-23 23:54:45 +00:00
Eugene Yurtsev 4cffe58065 docs: fix tab syntax errors and admonition syntax errors (#5091) 2025-06-23 19:53:54 -04:00
nikhildigde e73964a971 Update custom_routes.md (#5110)
Updated the statement about app.py
2025-06-23 23:53:25 +00:00
William Fu-Hinthorn de91f21f6b Update cli config doc on pip_installer 2025-06-23 16:40:07 -07:00
David Duong 41eed326b8 Disable values update on use stream in interrupt events (#5041) 2025-06-24 00:08:14 +02:00
Mason Daugherty 946d23213d docs: add Homebrew install option to CLI docs (#5160)
Add Homebrew install option to CLI docs
2025-06-23 11:33:12 -04:00
hari-dhanushkodi c78197a583 add more docs for lgp deployment metrics (#5151) 2025-06-23 07:12:06 -07:00
Lauren Hirata Singh 50756207ee docs: fix a typo 'prebuit' to 'prebuilt' in notebook_hooks.py (#5154) 2025-06-23 09:44:45 -04:00
OfirTeneJuno 903cec0cfa Merge branch 'main' into interrupt-use-stream-values 2025-06-23 13:25:35 +03:00
foie0222 f63952595d fix: a typo prebuit to prebuilt 2025-06-21 17:49:40 +09:00
Andrew Nguonly 4a252bd03a docs: Remove note for LANGSMITH_TRACING environment variable (#5147)
Remove note for LANGSMITH_TRACING.
2025-06-20 13:36:29 -07:00
Eugene Yurtsev f0f329d9e1 docs: Add conditional js/python rendering (#5128)
# Overview

Adding conditional rendering logic to co-locate js and python documentation.

* `:::` conditional syntax can be used to switch between python only or js only content.
* Contains simple unit tests for `:::`
* PR adds set up for a way to implement a context switch between languages, but it will not be enabled until JS content is merged in.
* Contains a script that can add javascript documentation 

Implementation of: https://github.com/langchain-ai/langgraph/pull/5118

## Example

Example of conditional rendering / compilation.


```markdown

### Config (static context)

Config is for immutable data like user metadata or API keys. Use
when you have values that don't change mid-run.

Specify configuration using a key called **"configurable"** which is reserved
for this purpose:


:::python

This content will only be rendered for the python site.
:::

:::js
this content will only be rendered for the js / ts site.
:::

```
2025-06-20 16:20:16 -04:00
bracesproul 78bef6bc0c formatting 2025-06-19 11:20:17 -07:00
bracesproul 7bd364c457 fix: Allow configuring stream mode in useStream.joinStream() 2025-06-19 11:14:59 -07:00
OfirTeneJuno 77306c5142 Merge branch 'main' into interrupt-use-stream-values 2025-06-19 14:06:24 +03:00
Nuno Campos eba18c3213 Reduce extraneous keys in checkpoint.metadata (#5133) 2025-06-17 17:46:45 -07:00
Nuno Campos a1c856c088 Reduce extraneous keys in checkpoint.metadata
- Leave it up to each checkpointer implementation to decide whether to merge in configurable/metadata (previously PregelLoop would do some of this always)
- Never copy over internal langgraph keys into checkpoint.metadata (these are redundant/misleading to include)
2025-06-17 17:40:18 -07:00
Josh Rogers 92010f84ec Adding disable_mcp field to cli docs (#5132) 2025-06-17 16:22:50 -07:00
Nuno Campos 3b8f3f9de3 If FuturesDict callback has been GCed, don't call it (#5131) 2025-06-17 14:03:16 -07:00
Nuno Campos 6dcff8a839 If FuturesDict callback has been GCed, don't call it 2025-06-17 13:47:47 -07:00
lc-arjunandMarco Perini 1309243b29 docs: studio evals (#5129)
* docs: studio evals

* docs: added studio evals images (#5076)

* docs: added studio evals images

* Update docs/docs/cloud/how-tos/studio/run_evals.md

Co-authored-by: lc-arjun <arjun@langchain.dev>

* Update docs/docs/cloud/how-tos/studio/run_evals.md

Co-authored-by: lc-arjun <arjun@langchain.dev>

* Update docs/docs/cloud/how-tos/studio/run_evals.md

Co-authored-by: lc-arjun <arjun@langchain.dev>

* docs: updated studio evals

* Update docs/docs/cloud/how-tos/studio/run_evals.md

Co-authored-by: lc-arjun <arjun@langchain.dev>

* docs: removed images

---------

Co-authored-by: lc-arjun <arjun@langchain.dev>

* final changes

* i think its this

---------

Co-authored-by: Marco Perini <perinim.98@gmail.com>
2025-06-17 12:32:04 -07:00
Nuno Campos 771c6150a4 langgraph 0.5.0rc1 2025-06-16 17:52:13 -07:00
Nuno Campos edfb65fd3a langgraph-prebuilt 0.5.0rc0 2025-06-16 17:47:21 -07:00
Lauren Hirata Singh 0f92470e49 docs: Remove cookie consent (#5123) 2025-06-16 18:41:55 -04:00
Nuno Campos dfcaf97c73 langgraph 0.5.0rc0 2025-06-16 15:17:56 -07:00
Nuno Campos 63a0028372 langgraph-checkpoint 2.1.0 2025-06-16 14:58:50 -07:00
Nuno Campos 1134017d07 Preparation for 0.5 release: langgraph-checkpoint (#5124)
Prepare langgraph-checkpoint for 0.5

- Given we have no upper bound on langgraph-checkpoint dep need to undo all changes in langgraph-checkpoint that might break previous versions of langgraph
2025-06-16 21:57:11 +00:00
Lauren Hirata Singh 33feba4877 Remove cookie consent 2025-06-16 16:33:32 -04:00
Nuno Campos 4fec8e9dec Preparation for 0.5 release (#5121) 2025-06-16 13:14:25 -07:00
Nuno Campos c137169325 Preparation for 0.5 release
- Update deprecation warnings to mention 0.5, no 1.0
- Add back type hint support for Runnable arg to add_node
2025-06-16 13:07:52 -07:00
Nuno Campos 1e2672e63d Restore shallow checkpointer (#5105) 2025-06-16 11:23:27 -07:00
Nuno Campos 06803ab683 Add migration for pending_sends (#5106) 2025-06-16 11:23:17 -07:00
hari-dhanushkodi 3488ee47e0 chore: add docs for lgp deployment monitoring (#5104) 2025-06-16 10:21:42 -07:00
Nuno Campos 289bdd0cea Introduce "tasks" and "checkpoints" stream modes (#5117) 2025-06-16 10:14:18 -07:00
Nuno Campos 417103066b Lint 2025-06-16 09:29:03 -07:00
Nuno Campos 25a59447c1 Introduce "tasks" and "checkpoints" stream modes
- These are split out of "debug" stream mode, which is now an alias for ["tasks", "checkpoints"]
2025-06-16 08:47:45 -07:00
Nuno Campos 21906d2b7b Add migration for pending_sends
- Checkpoints saved on older versions of langgraph will be compatible with langgraph 0.5 and 1.0
2025-06-13 17:42:14 -07:00
Nuno Campos 0cad7019cb Restore shallow checkpointer
- This should definitely be removed soon, but let's give people more time to update
2025-06-13 17:37:40 -07:00
Nuno Campos 7e735672bf Restore compatibility with custom checkpointer classes created in prior versions (#5103) 2025-06-13 16:36:36 -07:00
Nuno Campos 5498893780 Restore compatibility with custom checkpointer classes created in prior versions
- Ensure existing custom checkpointer classes are compatible with new langgraph-checkpoint release
2025-06-13 16:29:55 -07:00
Nuno Campos e80f47aa01 Revert removals of APIs that were slated for removal in 1.0 (#5101) 2025-06-13 16:09:20 -07:00
Nuno Campos a0b2f742a3 Revert "Remove UntrackedValue channel"
This reverts commit 05f3904d09.
2025-06-13 15:36:47 -07:00
William FH b7973d65db fix: Update lockfile (#5102) 2025-06-13 14:53:40 -07:00
Nuno Campos 3fa3a586b5 Revert "Remove MessageGraph (#4875)"
This reverts commit a5e6223569.
2025-06-13 14:21:05 -07:00
William FH 053b606b46 cli: 0.3.3 (#5100) 2025-06-13 13:15:26 -07:00
William FH 4548a0ebe8 feat: Customizable Pip Installer (#5098)
Let you set "pip_installer": "pip" (or uv) to handle corner cases in install compatibilities
2025-06-13 10:35:28 -07:00
Sydney Runkle 0171e9a323 fix(langgraph): remove deprecated output usage in favor of output_schema (#5095)
use output_schema
2025-06-13 12:34:39 -04:00
Sydney Runkle c439cb0872 refactor(langgraph): Remove PregelNode's inheritance from Runnable (#5093)
remove Runnable inheritance for PregelNode
2025-06-13 10:17:42 -04:00
Nuno Campos 2a4d7e8889 Remove support for node reading a single managed value (#5083) 2025-06-12 15:19:55 -07:00
Nuno Campos 7f3578e0f1 Remove support for node reading a single managed value
- This has never been used and is not useful or intended functionality
2025-06-12 15:11:19 -07:00
Lauren Hirata Singh e2f96b5ae5 revert incident banner (#5082) 2025-06-12 17:24:36 -04:00
Lauren Hirata Singh 0d5f7e55bf revert incident banner 2025-06-12 17:10:22 -04:00
Lauren Hirata Singh 9209f11187 incident banner (#5081) 2025-06-12 16:04:20 -04:00
Lauren Hirata Singh bb1c5b8cdf Update docs/overrides/main.html 2025-06-12 15:57:14 -04:00
Nuno Campos d6bb008ff4 PregelLoop: Simplify tick() method (#5080)
* PregelLoop: Simplify tick() method

- Split out superstep finish into separate after_tick() method
- Handle input in __enter__
- Remove unnecessary recursive shortcut
- Remove input sentinel objects

* Lint
2025-06-12 19:53:55 +00:00
Lauren Hirata Singh 6130e08fa6 incident banner 2025-06-12 15:52:36 -04:00
Sydney Runkle 3ad061f0d7 serialize/deserialize pandas with pickle fallback (#5057) 2025-06-12 15:14:00 -04:00
Nuno Campos 116b5d1cac Remove code paths no longer needed (#5079) 2025-06-12 11:47:10 -07:00
Nuno Campos 0aff02e180 Remove code paths no longer needed
- These were only used by the kafka scheduler
2025-06-12 11:25:20 -07:00
Nuno Campos 074af5c122 Avoid saving checkpoints for subgraphs when checkpoint_during=False (#5051) 2025-06-11 11:11:02 -07:00
langchain-infra 29ffaa0e0b docs: fix config section (#5066) 2025-06-11 13:23:33 -04:00
Sydney Runkle 45cd4e1928 oss: auto apply labels to contributor issues (#5067)
auto apply labels
2025-06-11 17:19:49 +00:00
langchain-infra 480271f753 docs: add mount prefix environment variable (#5060) 2025-06-11 11:20:19 -04:00
infra 66fdf60e47 docs: add mount prefix environment variable 2025-06-11 11:18:16 -04:00
infra 0894daf3fc docs: add mount prefix environment variable 2025-06-11 11:17:45 -04:00
Lauren Hirata Singh 850c55d630 Revert "fix assistants overview link" (#5059) 2025-06-11 11:02:17 -04:00
Lauren Hirata Singh c0d65ff409 Revert "fix assistants overview link (#5058)"
This reverts commit be7b60a722.
2025-06-11 10:58:52 -04:00
Lauren Hirata Singh be7b60a722 fix assistants overview link (#5058) 2025-06-11 10:58:07 -04:00
Eugene Yurtsev d467ec6556 Remove gitmcp badge (#5055)
* Remove gitmcp badge

* xt

* x
2025-06-11 10:55:05 -04:00
Chitikela Veera Sai Charan TejaandEugene Yurtsev b8683ab67a docs: Update subgraphs.md (#5052)
* Update subgraphs.md

The state while defining the Subgraph is updated. Also an edge connecting START to the call_model node in the subgraph was created.

* Update docs/docs/concepts/subgraphs.md

* Update docs/docs/concepts/subgraphs.md

---------

Co-authored-by: Eugene Yurtsev <eugene@langchain.dev>
2025-06-11 13:49:51 +00:00
OfirTeneJuno 666279a241 Merge branch 'main' into interrupt-use-stream-values 2025-06-11 09:53:25 +03:00
William Fu-Hinthorn 6a9ca8d67e Update existing 2025-06-10 17:59:41 -07:00
William Fu-Hinthorn 3b98044f2f Add tests 2025-06-10 17:29:27 -07:00
Nuno Campos a4a8934bd3 Avoid saving checkpoints for subgraphs when checkpoint_during=False
- We can avoid saving checkpoints for successful subgraphs which do not request multi-turn memory
2025-06-10 17:25:05 -07:00
Nuno Campos 470b9a4b97 Clean up PregelNode attributes (#5049) 2025-06-10 17:24:03 -07:00
Nuno Campos 516175780d Clean up things for Matt! 2025-06-10 16:14:15 -07:00
William FH 571780f74c fix: header merging (#4926) 2025-06-10 14:44:34 -07:00
Emmanuel Ferdman d719438307 fix: throw exception on multiple injections (#5033)
Throw exception on for multiple injections

Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-06-10 16:54:01 -04:00
Simon Frank 85c809a651 docs: fixed a wrong import in persistence docs (#5045) 2025-06-10 20:53:50 +00:00
Nuno Campos 0441fd156f Add docs for checkpoint encryption (#5047)
docs: list CipherProtocol in API
2025-06-10 16:52:45 -04:00
Nuno Campos 37b5d3886c Add library overview to AGENTS.md (#5044) 2025-06-10 10:08:55 -07:00
Nuno Campos b95267a3cc Refine dependency map 2025-06-10 10:06:08 -07:00
OfirTeneJuno 2172bc89ed remove yarn 2025-06-10 17:37:27 +03:00
OfirTeneJuno 4138ef9c43 Change to continue 2025-06-10 17:33:52 +03:00
OfirTeneJuno 0ff181b7ce Disable values update on use stream in interrupt events 2025-06-10 17:21:17 +03:00
Nuno Campos 2e33c520a5 Support numpy array serialization in JsonPlusSerializer (#5035)
* Handle numpy Fortran arrays

* Lint

* Lint

* Lint
2025-06-10 01:17:28 +00:00
Nuno Campos 67b1dc602e Update ormsgpack (#5034)
* Update ormsgpack

- Now supports bytearray/memoryview passthrough

* Lint
2025-06-10 00:30:58 +00:00
Naohiro Yoshida 1519b90414 Centralized CheckpointTuple creation into a shared function for checkpoint_postgres (#4970) 2025-06-09 18:40:17 +00:00
Ykoh 0035ab9825 docs: Replace unsupported models with structured output-supported models (#3982) 2025-06-09 14:17:05 -04:00
Eyal SchullerandWilliam FH c42cd57a32 chore: Update variable naming in postgres store (#4096)
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-06-09 17:54:06 +00:00
ms-tungttandWilliam FH acc56e094a docs: add query params for Store semantic search (#4828)
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-06-09 17:47:50 +00:00
Yassin Nouh 6b30d4fd8f docs: enhance PostgresSaver connection requirements explanation (#4953)
docs: enhance PostgresSaver connection requirements explanation - Add detailed explanation of why autocommit=True and row_factory=dict_row are required - Include example of incorrect usage and resulting errors - Addresses issue #4937 about incomplete setup documentation
2025-06-09 17:12:44 +00:00
Jong Hyun ParkandSydney Runkle fcc37cd06b docs: update tutorial/rag/langgraph_adaptive_rag.ipynb (#2006)
- add some explanations of ipynb code in markdown cell.

Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com>
2025-06-09 12:54:29 -04:00
William FH c17ee1bf5a feat: [CLI] Add support for building deps with uv (#4995) 2025-06-09 08:57:29 -07:00
William FH 88c603b00b fix: (sdk-js) Expand ToolMessage Type (#5015) 2025-06-09 08:22:35 -07:00
Sydney Runkle c12f7cb2b9 github: support blank issues (help with v1 planning) (#4999)
blank issues
2025-06-09 13:52:14 +00:00
🤖Esteban Dalel R 6d7d689578 docs: highlight changed lines in 3-add-memory.md (#4930) 2025-06-08 14:08:04 +00:00
LostInCode404 f1b7eca7fc docs: Update 1-build-basic-chatbot.md to add a section about END node (#4886)
Update `1-build-basic-chatbot.md` to add a section about `END` node
2025-06-08 13:51:17 +00:00
Michael Li 93766a6df1 docs: fix assistants url at manage_assistants.md (#4993)
* docs: fix agent supervisor doc codes

* docs: fix assistants url at manage_assistants.md
2025-06-08 13:49:45 +00:00
Dionysis Glytsos a9d4e0da29 docs: fix typos (#4992)
Fix typos
2025-06-08 13:46:41 +00:00
Sydney Runkle 9105e60a34 graph: improve generics on StateGraph etc + move typing utils to private file (#4982) 2025-06-06 19:51:05 -04:00
Sydney Runkle b735452153 deprecate input and output in favor of input_schema and output_schema (#4983) 2025-06-06 19:44:56 -04:00
Sydney Runkle 5920d8aa92 using StateT as default for InputT 2025-06-06 12:58:19 -04:00
Michael Liandvbarda 533f5b3d6f docs: fix task description example in the agent supervisor tutorial (#4938)
* docs: fix agent supervisor doc codes

---------

Co-authored-by: vbarda <vadym@langchain.dev>
2025-06-06 13:41:41 +00:00
Asamu David be5889a7df docs: add docs for image_distro cli option (#4974) 2025-06-05 23:11:47 +01:00
David Asamu 0bf268feca add docs for image_distro cli option 2025-06-05 17:23:05 +01:00
Sydney Runkle 5e7566f4a3 lint: use pep 604 union syntax and pep 585 generic syntax (#4963)
* new union syntax

* fix test

* second round of conversions by injecting future annotations

* format + add top level makefile
2025-06-04 21:50:16 -04:00
Sydney Runkle 494c8ef0d2 docs: remove references to StateGraph(dict) (#4964)
remove StateGraph(dict)
2025-06-04 21:29:19 -04:00
lc-arjun 45e60ff9e1 fix: camel case to snake case conversion (#4966) 2025-06-04 17:31:12 -07:00
Nuno Campos 194c4c1d1c cli 0.2.12 2025-06-04 15:50:07 -07:00
Florian CourtialandNuno Campos 1a76f6a92a 🐛 [CLI] Generate one --build-context argument for each dependency in the docker build command. (#4962)
* Generate one `--build-context` for each dependency in the `docker build` command.

* Try and fix test

---------

Co-authored-by: Nuno Campos <nuno@langchain.dev>
2025-06-04 22:48:48 +00:00
Sydney Runkle aedf974dfd docs: deploy from v0 branch for now (#4960)
only deploy docs on v0
2025-06-04 13:27:48 -04:00
Sydney Runkle c0b6a85488 docs: format to allow for deploy (#4959)
formatting
2025-06-04 17:20:19 +00:00
Sydney Runkle 9fde14079a docs: use retry_policy instead of retry in docs (#4958) 2025-06-04 17:12:13 +00:00
Sydney Runkle 02f3944e88 rename retry -> retry_policy (#4957) 2025-06-04 14:55:06 +00:00
Nuno Campos 1ea5812ed0 Fix step_timeout causing ParentCommand/GraphInterrupt exception to bubble up (#4950) 2025-06-03 17:32:46 -07:00
Nuno Campos 314115513c Fix step_timeout causing ParentCommand/GraphInterrupt exception to bubble up
- We should not re-raise exceptions in commit() as that is now called in a future done callback
- panic_or_proceed takes care of re-raising exceptions as needed anyway
2025-06-03 17:26:29 -07:00
Nuno Campos 161a1e3af6 Remove from ci matrix 2025-06-03 17:26:13 -07:00
Nuno Campos f8995f234c Remove scheduler-kafka library
Superseded by upcoming distributed runner
2025-06-03 17:25:17 -07:00
Nuno Campos 5f1d76ba3b docs: fix a grammar issue in multiple files (#4935) 2025-06-03 17:04:20 -07:00
Asamu David 13ebe1ad8c cli v0.2.11 release (#4941) 2025-06-04 01:00:06 +01:00
David Asamu ae2b766d0f bump version 2025-06-04 00:53:56 +01:00
Nuno Campos b211d4e767 Make it possible to run test command without docker installed (#4948) 2025-06-03 16:29:14 -07:00
Nuno Campos 0b609646d5 Fix async callback manager tag handling (#4949) 2025-06-03 16:23:22 -07:00
Nuno Campos 5ab5da767b Pass tags when configuring async callback manager 2025-06-03 16:17:17 -07:00
Nuno Campos a534807ec9 Allow same-name channels and nodes in StateGraph (#4944) 2025-06-03 16:15:07 -07:00
Nuno Campos 89e827bd15 Make it possible to run test command without docker installed 2025-06-03 16:14:46 -07:00
Nuno Campos d4018497a9 Fix ensure_config docstring (#4947) 2025-06-03 16:02:44 -07:00
Nuno Campos 7080eaa79e docs: fix ensure_config docstring 2025-06-03 15:56:41 -07:00
Nuno Campos 9c6e8d5237 Fix duplicate article typos in docs (#4946) 2025-06-03 15:56:04 -07:00
langchain-infra ae3c2e0b89 fix: use right deployment link (#4945) 2025-06-03 18:55:05 -04:00
Nuno Campos cd2847ee07 docs: fix double article typos 2025-06-03 15:53:19 -07:00
infra 7335b80586 fix: use right deployment link 2025-06-03 18:42:11 -04:00
Asamu David 394ea1c12b Merge branch 'main' into david/06-03/update-cli-version 2025-06-03 23:40:10 +01:00
Nuno Campos b00ea605e2 checkpoint-postgres: Use lock also for pipeline mode (#4942) 2025-06-03 15:30:04 -07:00
Nuno Campos bb990715f1 Allow same-name channels and nodes in StateGraph
- We no longer auto create a same-name channel for each node, so this limitation can now be lifted
2025-06-03 15:29:49 -07:00
Asamu David fce7652b7c Merge branch 'main' into david/06-03/update-cli-version 2025-06-03 23:26:42 +01:00
langchain-infra 8837b8534f fix: use right link (#4943) 2025-06-03 18:15:51 -04:00
infra 4473db6361 fix: use right link 2025-06-03 18:12:41 -04:00
Nuno Campos c31c940bbb checkpoint-postgres: Use lock also for pipeline mode 2025-06-03 14:59:56 -07:00
Asamu David 5c18123bb7 cli v0.2.11 release
## Description 

bump cli version to 0.2.11
2025-06-03 21:37:25 +01:00
Asamu David 7ba5636200 add support for image_distro in config file (#4871) 2025-06-03 20:59:06 +01:00
Sydney Runkle 37c215b5a2 Improve type checking on graph init and invoke/stream (#4932) 2025-06-03 15:21:51 -04:00
Asamu David f528f5ebd6 Merge branch 'main' into david/05-28/support-image-distro-config 2025-06-03 18:18:22 +01:00
Michael Li cd28bef155 docs: fix a grammar issue in multiple files 2025-06-04 01:20:29 +10:00
David Duong 3a74514bc3 fix(sdk-js): uiMessageReducer should handle undefined metadata (#4931) 2025-06-03 15:21:25 +02:00
Tat Dat Duong 2b759a2a33 fix(sdk-js): uiMessageReducer should handle undefined metadata 2025-06-03 15:20:13 +02:00
dependabot[bot] 723cff9001 build(deps): bump actions/setup-node from 3 to 4 (#4915)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-03 08:37:31 -04:00
lc-arjun 7d27d108fc bump sdk (#4925) 2025-06-02 18:16:08 -07:00
Arjun Natarajan f4b480c4b8 bump sdk 2025-06-02 18:13:36 -07:00
lc-arjun 8c560ef62a feat: support custom tracer when creating run in ts sdk (#4924) 2025-06-02 18:10:01 -07:00
David Asamu 1e324b681a update dockerfile generation logic, fix pip removal in wolfi 2025-06-03 01:43:59 +01:00
Arjun Natarajan 6002aebec5 maybe nees the full lint rewrite 2025-06-02 17:35:12 -07:00
Arjun Natarajan b438210a0d maybe fixes lint 2025-06-02 17:33:29 -07:00
Arjun Natarajan b908e96541 need to export it here too 2025-06-02 17:27:33 -07:00
Arjun Natarajan 70dc0323c1 i want this exported 2025-06-02 17:26:20 -07:00
Arjun Natarajan a75e40192f perhaps better typing 2025-06-02 17:18:59 -07:00
Arjun Natarajan 952017fbe2 feat: support custom tracer when creating run in ts sdk 2025-06-02 17:17:07 -07:00
Nuno Campos 36bd88287f Fix makefile command file for dev server (#4922) 2025-06-02 16:41:59 -07:00
Nuno Campos 5e5840805e Fix makefile command file for dev server
- pidfile was always empty
2025-06-02 16:35:48 -07:00
Nuno Campos 7828003958 Fix Command(graph=PARENT) when used together w checkpointer=True (#4921) 2025-06-02 16:18:52 -07:00
Nuno Campos e5e78e4192 Fix Command(graph=PARENT) when used together w checkpointer=True 2025-06-02 16:05:32 -07:00
William FH e2b14a9499 feat: Add onRequest callback to JS SDK (#4919)
Add onRequest callback
2025-06-02 13:43:16 -07:00
Nuno Campos 2563301f39 Remove unused deprecation decorator/warning (#4917) 2025-06-02 15:53:26 -04:00
David Asamu bbbadc3db9 regenerate schema + lint & format 2025-06-02 20:50:48 +01:00
dependabot[bot] b4cb4e72ab build(deps): bump actions/configure-pages from 4 to 5 (#4916)
Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 4 to 5.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](https://github.com/actions/configure-pages/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 15:36:18 -04:00
dependabot[bot] 7e45a0530b build(deps): bump actions/cache from 3 to 4 (#4913)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 15:17:21 -04:00
dependabot[bot] dd059fea3c build(deps): bump actions/checkout from 3 to 4 (#4912)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 15:17:04 -04:00
Michael Li 871b1dccd8 docs: fix grammar issues in deployment_options.md and faq.md (#4905) 2025-06-02 15:04:03 -04:00
Daiki Inoue f8b5e05c47 docs: fix a typo (#4908) 2025-06-02 15:03:23 -04:00
Eugene Yurtsev 6cde3ee7a3 ci: add depandabot config for upgrading actions (#4911)
Depandabot config for suggesting to update old actions
2025-06-02 15:03:03 -04:00
Michael Li d44581d754 docs: fix typos in langgraph_studio.md and low_level.md (#4909) 2025-06-02 17:49:04 +00:00
Michael Li dc787b5aa6 docs: fix grammar issues in langgraph_data_plane.md and langgraph_platform.md (#4906)
* docs: fix grammar issues in langgraph_data_plane.md and langgraph_platform.md

* docs: further update the wording in langgraph_data_plane.md
2025-06-02 17:48:55 +00:00
Michael Li 0d6af09187 docs: fix grammar issues in application_structure.md and assistants.md (#4904)
* docs: fix a grammar error in mcp.md

* docs: fix a grammar error in multi-agent.md

* docs: fix grammar issues in application_structure.md and assistants.md
2025-06-02 13:48:50 -04:00
Michael Li 469576f966 docs: fix grammar issues in langgraph_self_hosted_control_plane.md and langgraph_server.md (#4907) 2025-06-02 17:47:16 +00:00
Michael Li f00b994692 docs: fix incorrect word in memory.md (#4902) 2025-06-02 13:48:18 +00:00
Michael Li 7d6243e6b4 docs: fix incorrect word in custom_docker.md (#4901) 2025-06-02 13:48:06 +00:00
Michael Li 8fd50a50d4 docs: fix grammar errors in mcp.md and multi-agent.md (#4903)
* docs: fix a grammar error in mcp.md

* docs: fix a grammar error in multi-agent.md
2025-06-02 13:46:29 +00:00
Sydney Runkle eaa1b37645 Require state_schema in StateGraph.__init__ (#4897) 2025-06-02 01:52:35 +00:00
David Duong 21f762140a docs(sdk-js): improve resumability docs (#4899) 2025-06-02 02:10:16 +02:00
Tat Dat Duong 5973fcb0ae docs(sdk-js): improve resumability docs 2025-06-02 02:09:43 +02:00
David Duong 624c688013 feat(sdk-js): add docs for reconnectOnMount, expose run metadata (#4898) 2025-06-02 01:53:46 +02:00
Tat Dat Duong d05b323b88 feat(sdk-js): add docs for reconnectOnMount, expose run metadata 2025-06-02 01:52:40 +02:00
Ikpreet S Babra 765bc3b9e0 docs: Update 2-add-tools.md (#4896)
Typo in first sentence.
2025-06-01 10:47:35 +00:00
Nuno Campos 78d3d8c802 Remove add_conditional_edge(..., then=) (#4893)
- This is redundant with deferred nodes, and not documented
2025-06-01 06:46:51 -04:00
Nuno Campos 3b85c83d51 Avoid repeated runtime calls to get_type_hints (#4888) 2025-05-31 08:37:23 -07:00
Eugene Yurtsev 08f88ce8da docs: add gtm (#4887)
Add google tag manager
2025-05-30 21:49:22 -04:00
Nuno Campos d661d528b2 Avoid repeated runtime calls to get_type_hints
- Replace get_type_hints logic with much simpler implementation which only collects annotated keys (not the annotations themselves)
- Cache annotations in a WeakKeyDictionary
2025-05-30 16:30:53 -07:00
Sydney Runkle 5cbf31e8a4 Remove non-state Graph (#4872) 2025-05-29 21:56:53 -04:00
Sydney RunkleandNuno Campos a5e6223569 Remove MessageGraph (#4875)
Remove MessageGraph

Co-authored-by: Nuno Campos <nuno@langchain.dev>
2025-05-29 21:50:23 -04:00
Nuno Campos afb83d2201 Remove non-state Graph
- Not used in any examples/docs
2025-05-29 21:38:58 -04:00
David Asamu 1e8f5dd2b6 add warning when image distro is not configured as wolfi 2025-05-30 00:25:27 +01:00
David Asamu 574a9246a6 add unit tests for image_distro config 2025-05-29 23:30:27 +01:00
David Asamu c46f7a4c3d add support for image_distro in config file 2025-05-29 21:54:54 +01:00
langchain-infra 8e82c7d1a0 docs: fix self hosted control plane concepts/docs (#4870) 2025-05-29 16:16:02 -04:00
infra 2066e4c018 docs: fix self hosted control plane concepts/docs 2025-05-29 13:10:16 -07:00
Sydney Runkle f8fae30aa9 docs: fix pprint import (#4869) 2025-05-29 19:37:43 +00:00
Nuno Campos 2615c7046c Remove UntrackedValue channel (#4868) 2025-05-29 12:14:36 -07:00
Nuno Campos 05f3904d09 Remove UntrackedValue channel
- This is incompatible with distributed execution modes, so needs to go
2025-05-29 12:07:51 -07:00
Nuno Campos 583fe9fd84 Remove UntrackedValue channel (#4859) 2025-05-29 11:52:10 -07:00
Nuno Campos 0afc4ebda3 Flip default for checkpoint_during
- Now defaulting to False, ie. saving only the final checkpoint
- All features other than time travel into an intermediate step are supported by checkpoint_during=False so this is a better default for almost all use cases
2025-05-29 11:45:54 -07:00
Nuno Campos d55cafad29 Remove Channel node builder (#4858) 2025-05-28 14:30:12 -07:00
Nuno Campos 1b961f68b9 Remove Channel node builder
- Replaced by NodeBuilder introduced in earlier PR
2025-05-28 14:14:47 -07:00
Nuno Campos 045d6dfb82 Update managed value usage in local_read (#4854) 2025-05-28 14:05:14 -07:00
Nuno Campos 26d5fccfa0 Modify stream mode messages and custom to respect subgraphs=False (#4843) 2025-05-28 14:05:03 -07:00
Nuno Campos 76661f4c9c Remove Checkpoint.writes (#4822) 2025-05-28 14:04:45 -07:00
Nuno Campos 9320bedd2a Remove Checkpoint.pending_sends (#4820) 2025-05-28 14:04:26 -07:00
Nuno Campos 3737d886e7 Pregel: Add NodeBuilder class to replace Channel.subscribe_to (#4819) 2025-05-28 14:04:08 -07:00
Nuno Campos 8386eaceab Remove dict subclasses used for values/updates stream chunks (#4816) 2025-05-28 14:03:40 -07:00
Nuno Campos c32677c92d Remove old checkpoint test fixtures (#4814) 2025-05-28 14:03:12 -07:00
Nuno Campos e384ccacaf Remove postgres shallow checkpointer (#4813) 2025-05-28 14:02:58 -07:00
Nuno Campos dc95f95181 Remove ChannelsManager, ManagedValues are now static classes and never instantiated (#4812) 2025-05-28 14:02:43 -07:00
Nuno Campos 2e4645ce61 Remove Context channel / managed value, Remove SharedValue (#4857) 2025-05-28 14:02:12 -07:00
Nuno Campos efb282a197 Remove SchemaCoercionMapper (#4855) 2025-05-28 10:51:32 -07:00
Nuno Campos 89ce6ea2a8 Remove SchemaCoercionMapper 2025-05-28 10:42:43 -07:00
Nuno Campos 197b01e985 Update managed value usage in local_read 2025-05-28 10:40:20 -07:00
DHPark 1e87312d1f Update graph-api.ipynb (#4824) 2025-05-28 13:39:22 +00:00
vksx bcc6485f6c (docs) fix broken links (#4823) 2025-05-28 13:36:48 +00:00
Sydney Runkle ce5f248e3b docs: fix typo (#4852)
minor fix
2025-05-28 13:35:17 +00:00
Sydney Runkle 5602c29668 prebuilt: release 0.2.2 (#4851)
bump prebuilt
2025-05-28 13:33:39 +00:00
Nuno Campos bc404d14f6 Format 2025-05-27 16:07:54 -07:00
Sydney Runkle 19ca6b416b fix: post_model_hook should inject state + store into tool calls if necessary (#4842) 2025-05-27 17:42:20 +00:00
Nuno Campos 936176eb21 Remove Checkpoint.writes
- This has been superseded by saving the individual writes of each task through put_writes()
- Removing this speeds up checkpoint operations as it was duplicating data saved elsewhere already
2025-05-25 19:06:46 -07:00
Nuno Campos 4e8fbe4525 Remove Checkpoint.pending_sends
- Instead store sends in a Topic channel, removing the need to fetch sends as writes against the parent checkpoint
- Remove deprecated/unused functions in langgraph-checkpoint (will require bumping min range for langgraph-checkpoint in langgraph lib)
- Implement migration of old pending sends in langgraph-checkpoint-postgres
- Ensure parent config of `checkpoint_during=False` checkpoints always points to checkpoints that were also saved
2025-05-25 19:06:02 -07:00
Nuno Campos 85522ec6a6 Pregel: Add NodeBuilder class to replace Channel.subscribe_to
- For now keeping Channel.subscribe_to given it was used in docs
2025-05-24 20:35:37 -07:00
Nuno Campos 0f8f5444bc Lint 2025-05-24 14:54:57 -07:00
Nuno Campos bc17c3522b Remove old checkpoint test fixtures
- Now all tests fully migrated to more recent sync_checkpointer and async_checkpointer fixtures for parametrising on checkpointer
- Use sync/async_store fixtures where tests used only in memory store
- Remove unused "should snapshot" check for older versions of langchain core no longer tested against
2025-05-24 14:27:13 -07:00
Nuno Campos 8c11c1155a Remove postgres shallow checkpointer
- This was deprecated, and superseded by checkpoint_during=False, which is available for all checkpointers
2025-05-24 12:39:50 -07:00
Nuno Campos 9c79d887a0 Remove ChannelsManager, ManagedValues are now static classes and never instantiated
- This keeps the existing API for accessing IsLastValue, RemainingSteps, but simplifies the internal implementation
- This lets us remove ChannelsManager completely, which no longer needs to be a context manager, now replaced w function channels_from_checkpoint
- Managed values are now simple functions that return a value given a PregelScratchpad, which will be easier to implement in distributed runner
2025-05-24 12:15:11 -07:00
Nuno Campos 889b40e7a8 Remove Context channel / managed value, Remove SharedValue
- Both have been deprecated long ago, have not been present in docs for quite a while
- Removing these lets us delete some code paths that were dedicated to this, easing work on distributed runner
2025-05-24 11:05:15 -07:00
Lauren Hirata Singh 2553ae0b87 docs: Fix links (#4807) 2025-05-23 22:34:08 -04:00
Lauren Hirata Singh 3e4b69af3f Fix links 2025-05-23 22:30:43 -04:00
Lauren Hirata Singh 0c6367c186 docs: fix link to examples page in readme.md (#4710) 2025-05-23 22:26:30 -04:00
Lauren Hirata Singh 99860b5713 Update README.md 2025-05-23 22:12:18 -04:00
Lauren Hirata Singh a69860baa6 Merge branch 'main' into fix-examples-link-readme 2025-05-23 22:08:32 -04:00
Lauren Hirata Singh 6fc21046cd Update libs/langgraph/README.md 2025-05-23 22:06:43 -04:00
Lauren Hirata Singh 754420e9a2 Update libs/langgraph/README.md 2025-05-23 22:03:39 -04:00
Lauren Hirata Singh 15126ad827 Create overview.md 2025-05-23 22:02:14 -04:00
芥子观须弥 6633173918 Fix: Ensure route function returns "b" to enable a → b → a loop (#4738)
fix: correct route function to return 'b' instead of 'a' when not terminating

This fixes a bug in the graph API how-to where the route function incorrectly returned 'a'. Now it correctly returns 'b' as intended.
2025-05-23 23:56:51 +00:00
Nuno Campos 0139e11ae5 0.4.7 2025-05-23 16:51:48 -07:00
Nuno Campos bfbe55ab64 Fix stream mode not respected in subgraphs (#4806) 2025-05-23 16:47:01 -07:00
Nuno Campos 36478eb745 Fix stream mode not respected in subgraphs
- The default applied for subgraphs should be applied only when stream mode arg not passed in
2025-05-23 16:40:51 -07:00
Nuno Campos 8fb91569b9 Add tests for stream_events when using imperative api (#4805) 2025-05-23 16:40:38 -07:00
Nuno Campos 9bf6728354 Try to make test less flaky 2025-05-23 16:32:51 -07:00
Nuno Campos 126a8f5bc6 Lock 2025-05-23 16:22:12 -07:00
Nuno Campos 9170f636d0 Lock 2025-05-23 16:14:15 -07:00
Nuno Campos 8207d3fefb Add tests for stream_events when using imperative api 2025-05-23 16:11:12 -07:00
Nuno Campos ade3f372a5 0.4.6 2025-05-23 15:24:07 -07:00
Nuno Campos 3a55d1137b Fix exception handling for imperative tasks (#4802) 2025-05-23 15:23:15 -07:00
Nuno Campos bece43dc67 Fix 2025-05-23 15:06:18 -07:00
Nuno Campos 913b8d5e95 Lint 2025-05-23 14:32:45 -07:00
Andrew Nguonly 29f6ea7f61 docs: Add warning about immutable deployment types (#4804)
* Add more details about database for deployment types. Clarify that deployment type cannot be changed.

* Add note about Development type disk capacity.
2025-05-23 14:04:46 -07:00
Nuno Campos 3c0d9346c2 Add sync test 2025-05-23 13:51:13 -07:00
Nuno Campos 0ebb78d9b2 Fix 2025-05-23 13:50:11 -07:00
Nuno Campos 70153ceba2 Fix exception handling for imperative tasks
- These exceptions should not be re-raised at end of tick, given they're handled explicitly by the developer in their entrypoint
2025-05-23 12:26:27 -07:00
Sydney Runkle a9c87ed8b6 prebuilt: release 0.2.1 (#4801)
lockfile and version updates
2025-05-23 18:07:24 +00:00
Sydney Runkle 837fe59e24 prebuilt: support provider builtin tools in create_react_agent (#4800) 2025-05-23 13:58:53 -04:00
Andrew Nguonly 596a26461c docs: Add note about Enterprise plan in banner for all self-hosted deployment options. (#4797)
Add note about Enterprise plan in banner for all self-hosted deployment options.
2025-05-22 18:38:06 -07:00
Sydney Runkle aff3be03dc prebuilt: release 0.2.0 (#4793) 2025-05-22 17:54:58 +00:00
David Duong 1000b81eca feat(langgraph): push_messages should directly write to the state (#4791) 2025-05-22 19:41:51 +02:00
Tat Dat Duong 10c6ed7320 Code review 2025-05-22 19:35:44 +02:00
Tat Dat Duong 28e0e7f3ae feat(langgraph): push_messages should directly write to the state 2025-05-22 19:35:15 +02:00
Sydney Runkle 87fa661ac0 temp: remove ToolInterruptNode code (#4792)
remove tool node specific code for post_model_hook release
2025-05-22 13:28:59 -04:00
David Duong 3189b8fcda feat(sdk-js): Add rejoining of streams (#4744) 2025-05-22 19:19:07 +02:00
Tat Dat Duong 74b18acfc2 Bump to 0.0.78 2025-05-22 19:08:39 +02:00
Tat Dat Duong 1ff5e2966b Add joinStream method 2025-05-22 19:07:01 +02:00
Diwakar Gupta 1ba2b3fba9 Merge branch 'main' into fix-examples-link-readme 2025-05-22 22:34:22 +05:30
Tat Dat Duong 102b1f63f3 Fix assumption on sessionStorage 2025-05-22 19:01:14 +02:00
Tat Dat Duong 74dbccd408 Rename to reconnectOnMount 2025-05-22 18:42:38 +02:00
Tat Dat Duong f5a2410ddc Make useStream more hackable 2025-05-22 18:38:09 +02:00
Sydney Runkle 4cade428d8 docs: adding interactive graph widget (#4785) 2025-05-22 12:23:43 -04:00
Tat Dat Duong 5823a659fc use sessionStorage instead 2025-05-22 18:11:38 +02:00
Tat Dat Duong f2c32727e8 Fix invalid states 2025-05-22 18:09:16 +02:00
Tat Dat Duong 9d71d941fd resumable 2025-05-22 17:45:52 +02:00
Tat Dat Duong 0db618ae75 Further cleanup 2025-05-22 17:45:52 +02:00
Tat Dat Duong 49746ab3a3 Code cleanup 2025-05-22 17:45:51 +02:00
Tat Dat Duong 5c7ef9a4fc Fix race condition 2025-05-22 17:45:51 +02:00
Tat Dat Duong 62e688bb37 Add rejoining of streams 2025-05-22 17:45:51 +02:00
Sydney Runkle 42eff39cd0 docs: fix top nav (#4783)
fix top nav
2025-05-21 19:30:13 -04:00
David Duong 39172f2ff9 feat(graph): add push_message method to push manually to messages / message-tuple stream (#4722) 2025-05-22 01:01:48 +02:00
Nuno Campos 0202c83e73 Apply same condition for stream_mode=values in suppress interrupt (#4782) 2025-05-21 15:55:55 -07:00
Tat Dat Duong ab924c72fa Add message state test 2025-05-22 00:49:23 +02:00
Nuno Campos 1833889316 Apply same condition for stream_mode=values in suppress interrupt 2025-05-21 15:23:27 -07:00
Tat Dat Duong 7a6bdb3441 Remove redundant cast 2025-05-22 00:23:26 +02:00
David Duong ea7f45dba7 feat(sdk-py): resumable streams (#4765) 2025-05-22 00:19:43 +02:00
Tat Dat Duong d2875cc576 feat(graph): add push_message method to push manually to messages / message-tuple stream 2025-05-22 00:18:12 +02:00
Tat Dat Duong e77197a00f Here as well 2025-05-22 00:13:22 +02:00
Tat Dat Duong 30e6ea7aed Last uv.lock? 2025-05-22 00:13:10 +02:00
Tat Dat Duong 461afe0aa6 Again? 2025-05-22 00:12:40 +02:00
Tat Dat Duong 92f8dde61e uv.lock? 2025-05-22 00:07:56 +02:00
Tat Dat Duong f4f7a79907 Bump to 0.1.70 2025-05-22 00:03:48 +02:00
Tat Dat Duong 9c1267af1a Import re 2025-05-22 00:03:41 +02:00
Tat Dat Duong e0a4420b8e feat(sdk-py): resumable streams 2025-05-22 00:03:41 +02:00
Andrew Nguonly 94a8067c12 docs: Remove outdated docs regarding graph construction (#4779)
Remove outdated docs regarding graph construction.
2025-05-21 12:21:32 -07:00
Lauren Hirata Singh 957db60d89 docs: fix (#4778) 2025-05-21 14:48:36 -04:00
Lauren Hirata Singh a17efb1120 fix 2025-05-21 14:47:55 -04:00
Eugene Yurtsev d4b428de62 docs: improved llms.txt (#4777)
Improved llms.txt
2025-05-21 14:40:01 -04:00
Eugene Yurtsev fd0b70eb05 docs: improve llms.txt to generate title and description based on content (#4775)
Update llms.txt based on content
2025-05-21 14:39:13 -04:00
Lauren Hirata Singh b8daf323ac docs: fix redirect (#4776) 2025-05-21 14:35:04 -04:00
Lauren Hirata Singh 2d3a3de1ce docs: fix redirect 2025-05-21 14:34:02 -04:00
Nuno Campos 96e2f68b2d Only emit stream values chunks when the output channels have changed (#4774) 2025-05-21 13:09:42 -04:00
Eugene Yurtsev 364508ff20 docs: Add script to generate llms-txt links from yaml (#4771)
A first pass at the script to fix the immediate issue. Will follow up with a few additional improvements.
2025-05-21 11:54:23 -04:00
Eugene Yurtsev fa1af5c364 docs: replace llms.txt with updated links (#4772)
This is a stop gap solution to fix broken links.

This PR will be followed up with a better llms.txt file
2025-05-21 11:53:26 -04:00
le-codeur-rapide 8ec29b4df7 docs: fix example pregel reducer (#4740) 2025-05-21 10:38:29 -04:00
Sydney Runkle 06607e08ea prebuilts hitl: fix branching logic + add structural snapshot tests (#4767) 2025-05-21 09:29:59 -04:00
Lauren Hirata Singh 0a8f54ca4a docs: add redirect (#4762) 2025-05-20 15:06:34 -04:00
Lauren Hirata Singh 9d41d439cc docs: add redirect 2025-05-20 14:52:02 -04:00
Diwakar Gupta 364fdf5dfe Merge branch 'main' into fix-examples-link-readme 2025-05-21 00:00:09 +05:30
Leeroy Brun ae5c01fbab docs: typo in npx command to install LangGraph CLI (#4761) 2025-05-20 17:08:02 +00:00
Sydney Runkle bd52b1faa1 docs: deferred nodes (#4759) 2025-05-20 13:07:11 -04:00
Stefano Lottini 4a04ca7268 [docs] Revise pip-install packages for PostgresSaver in "how-to/Persistence" notebook (#4752)
revise pip-install packages for PostgresSaver usage in how-to page
2025-05-20 15:46:39 +00:00
Yazan Jian 23b868da00 docs: fix async usage example from await .invoke() to `await .ainvo… (#4758)
docs: fix async usage example from `await .invoke()` to `await .ainvoke()`
2025-05-20 15:45:47 +00:00
David Duong 51bfd16460 feat(sdk-js): add stream_resumable flag, that marks the stream as resumable (#4757) 2025-05-20 14:16:39 +02:00
Tat Dat Duong 325d9e3134 Bump to 0.0.77 2025-05-20 14:14:48 +02:00
Tat Dat Duong b052ebf984 feat(sdk-js): add stream_resumable flag, that marks the stream as resumable 2025-05-20 14:13:47 +02:00
Sydney Runkle 1e938a692f docs: node caching (#4749) 2025-05-19 15:49:31 -04:00
Nuno Campos 46a9d3159d Remove local_write utility (#4751)
- The validation isn't worth the cost of having to pass list of nodes to task config
2025-05-19 15:49:17 -04:00
Nuno Campos d825e39df9 Print output for cached @task functions (#4750) 2025-05-19 11:42:16 -07:00
Nuno Campos 53a1e7c9de Print output for cached @task functions 2025-05-19 11:35:51 -07:00
Sydney Runkle 7bd8616b1e feature: Implement post_model_hook and HumanInterruptNode (#4583) 2025-05-19 14:07:42 -04:00
William FH 95f92069a7 sqlite: Add test for search with list filters (#4747) 2025-05-18 23:50:27 -07:00
William FH 6b28319796 sqlite: update list_namespaces with max_depth (#4746)
sqlite: update on conflict
2025-05-18 23:27:06 -07:00
Didier Durand 2ddf61201c docs: Fixing some typos (#4741) 2025-05-18 22:36:37 -07:00
Didier Durand 9453ee08dc docs: Fix a few spelling mistakes (#4742)
Fixing some typos
2025-05-18 22:35:54 -07:00
William Fu-Hinthorn 15bafc54c8 Update lockfile 2025-05-17 21:55:46 -07:00
William FH 725dd40fa7 Release sqlite store (#4737) 2025-05-17 21:49:03 -07:00
William FH c2a1b3af07 docs: Clean up adjective use in readme (#4734) 2025-05-17 21:43:14 -07:00
William FH 025b634d98 SqliteStore (#3608) 2025-05-17 21:40:19 -07:00
Diwakar Gupta fe5d303ccd Merge branch 'main' into fix-examples-link-readme 2025-05-17 13:56:41 +05:30
Brace Sproul 8edb3e7b65 release(sdk-js): 0.0.76 (#4733) 2025-05-16 14:59:50 -07:00
bracesproul c21cf9fc1d release(sdk-js): 0.0.76 2025-05-16 14:56:56 -07:00
David Duong cb95393c67 fix: Allow users to config whether or not stream subgraphs (#4732) 2025-05-16 23:51:25 +02:00
bracesproul bb1edb4415 cr 2025-05-16 14:49:57 -07:00
bracesproul 6f1db4c60a fix: Allow users to config whether or not stream subgraphs 2025-05-16 14:49:28 -07:00
Vadym Barda 119a03bb00 ci: fix benchmark command (#4729) 2025-05-16 12:53:46 -07:00
Vadym Barda 09138048bc docs: document tuples in streaming guides (#4690) 2025-05-16 14:59:51 -04:00
David Duong adc89440a6 feat(sdk-js): expose ID for SSE events, update joinStream (#4547) 2025-05-16 20:53:39 +02:00
Tat Dat Duong c65919b3b2 Remove onResponse 2025-05-16 11:52:07 -07:00
Tat Dat Duong 0fa2b6c600 Bump to 0.0.75 2025-05-16 11:50:35 -07:00
Tat Dat Duong 9b2071b103 Fix tests 2025-05-16 11:50:09 -07:00
Tat Dat Duong b3f13ee904 Add onRunCreated callback 2025-05-16 11:43:40 -07:00
Tat Dat Duong bf239a06e1 Add callback for response object to get headers 2025-05-16 11:43:39 -07:00
Tat Dat Duong cc25539018 feat(sdk-js): expose ID for SSE events, update joinStream 2025-05-16 11:43:39 -07:00
Lauren Hirata Singh 654096625a docs: add redirect (#4727) 2025-05-16 11:28:45 -07:00
David Duong 3ea1141d55 feat(sdk-js): switch from jest to vitest, add useStream FE tests (#4726) 2025-05-16 19:55:30 +02:00
Tat Dat Duong e9d1f5508a package.json 2025-05-16 10:53:06 -07:00
Tat Dat Duong c6157d90dd feat(sdk-js): switch from jest to vitest, add useStream FE tests 2025-05-16 10:48:11 -07:00
Lauren Hirata Singh f37a228b58 add redirect 2025-05-16 10:28:51 -07:00
Sydney Runkle d34299ac39 ci: fix issue with cache in integration tests (#4725) 2025-05-16 16:49:29 +00:00
Diwakar Gupta c9fa11ae7d Merge branch 'langchain-ai:main' into fix-examples-link-readme 2025-05-16 16:32:53 +05:30
Sydney Runkle 228a08b966 ci: migrate to uv! (#4698)
* Migrate to `uv`
* Format `pyproject.toml` files properly
* Remove upper bounds on dependencies, and bounds on dev dependencies
(we should be using latest)
* Move to hatch for packaing

In the future we should:
* Set up dependabot / automate lockfile updates and tests
* Add tests for min compatible versions (I'll do this right after merge)
* Use dynamic versioning
* Bump `pydantic` to v2.11.4 in the lockfile, we have some tests failing
2025-05-15 17:39:14 -07:00
Lauren Hirata Singh 217795eb72 docs: fix broken img (#4716) 2025-05-15 13:37:40 -07:00
Lauren Hirata Singh e873df678b fix broken img 2025-05-15 13:33:36 -07:00
Hussein Akbarzadeh 2b603a6ab0 Update sql-agent.ipynb (#4702)
On line 586, the check_query function should use
check_query_system_prompt. Instead, small mistake it is using the
generate_query_system_prompt prompt which is obviously incorrect.
2025-05-15 20:26:36 +00:00
Lauren Hirata Singh f60a06441b docs: fix nit (#4714) 2025-05-15 12:50:32 -07:00
Lauren Hirata Singh db5e956dc6 docs: fix nit 2025-05-15 12:48:49 -07:00
Yagnesh M. Bhadiyadra cacae7bd1f fix(docs): Correctify the Pass or Fail condition in the Graph API example. (#4712) 2025-05-15 19:37:36 +00:00
Vadym Barda 60df867872 docs: update MCP example (#4713) 2025-05-15 14:59:35 -04:00
Diw 988805d60b fix link to examples page in readme.md 2025-05-15 23:11:17 +05:30
Vadym Barda 6fb2a93212 langgraph: release 0.4.5 (#4709) 2025-05-15 13:33:02 -04:00
Vadym Barda 3f8944c1fc checkpoint: release 2.0.26 (#4708) 2025-05-15 13:28:10 -04:00
Nuno Campos e79f3ceedc Improve how we match cached writes for async imperative tasks (#4691)
- remove match_cached_writes from PregelRunner args (now called by
PregelLoop internally)
- this will be helpful when implementing distributed runner classes
2025-05-15 10:21:27 -07:00
Vadym Barda a64414c87c langgraph: release 0.4.4 (#4704) 2025-05-15 11:20:59 -04:00
Nuno Campos c9d85a22ec langgraph: fix drawing graph with __root__ channel (#4695) 2025-05-15 07:55:45 -07:00
Pablo 983243333c Missing space in langgraph_server.md (#4697)
Missing space
2025-05-15 08:39:01 -04:00
vbarda 3a1c02ff33 update for consistency 2025-05-15 08:38:25 -04:00
vbarda 5ab2aa79bb lint again 2025-05-14 22:11:09 -04:00
vbarda c33e64daa6 use list 2025-05-14 22:03:40 -04:00
vbarda 4ffae6065f lint + update 2025-05-14 22:01:54 -04:00
vbarda 54ddde9d4c update 2025-05-14 21:30:22 -04:00
vbarda 60c41ce69e update 2025-05-14 21:14:49 -04:00
vbarda efd33d860f update 2025-05-14 21:03:47 -04:00
vbarda 254a38560e langgraph: fix drawing graph with __root__ channel 2025-05-14 20:42:30 -04:00
Nuno Campos 3487f4eba5 langgraph: fix graph drawing for self-loops (#4688)
Fixes #4685
2025-05-14 11:44:44 -07:00
Nuno Campos 3bdb7d09be Lint 2025-05-14 11:30:49 -07:00
Nuno Campos 3acf63a918 Lint 2025-05-14 11:29:26 -07:00
Nuno Campos f51e5e2bd7 Improve how we match cached writes for async imperative tasks
- remove match_cached_writes from PregelRunner args (now called by PregelLoop internally)
- this will be helpful when implementing distributed runner classes
2025-05-14 11:25:49 -07:00
lc-arjun c1a4d77bd4 fix: update langgraph cli to include js and update template app description (#4687) 2025-05-14 07:04:04 -07:00
lc-arjunandWilliam FH 6e3eb6370e Update docs/docs/tutorials/langgraph-platform/local-server.md
Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
2025-05-14 06:56:36 -07:00
Arjun Natarajan ab0fa9dc77 use npx to install cli instead 2025-05-14 09:49:42 -04:00
vbarda b20130d4e4 langgraph: fix graph drawing for self-loops 2025-05-14 09:46:32 -04:00
Arjun Natarajan 5f821cf584 fix: update langgraph cli to include js and update template app description 2025-05-14 09:41:37 -04:00
lc-arjun c7691081d1 fix(docs): template app names (#4682) 2025-05-13 15:25:39 -07:00
Arjun Natarajan 2ff2972b67 oops js is js not python 2025-05-13 18:21:20 -04:00
Arjun Natarajan 873873e640 fix(docs): template app names 2025-05-13 18:17:42 -04:00
lc-arjun fba0d6f96c chore(docs): reformat troubleshooting section and remove faqs page (#4681) 2025-05-13 15:04:19 -07:00
Arjun Natarajan 8bc509578b fix formatting 2025-05-13 17:59:51 -04:00
Arjun Natarajan 72d085d9f8 reformat troubleshooting section and remove faqs page 2025-05-13 17:54:51 -04:00
ccurme 940c2b0e74 docs: add chat model tabs to models guide (#4679) 2025-05-13 17:50:26 -04:00
lc-arjun e705ea1961 feat(docs): studio nits (#4680) 2025-05-13 13:53:02 -07:00
Arjun Natarajan 18e8d334ed nits to threads 2025-05-13 16:48:07 -04:00
Arjun Natarajan 392606f5f7 feat(docs): studio nits 2025-05-13 16:29:10 -04:00
lc-arjun cff2be48c9 feat(docs): further improvements for studio guides docs (#4677) 2025-05-13 12:59:47 -07:00
Arjun Natarajan c63cc173b2 added page for running application 2025-05-13 15:54:46 -04:00
Lauren Hirata Singh 2b8c295898 docs: Simplify LGP quickstarts (#4678)
- Change quickstarts to use `new-langgraph-project`, which doesn't
require API keys for Anthropic, Tavily, etc.
2025-05-13 11:47:48 -07:00
Arjun Natarajan 03c5547e34 update dataset page 2025-05-13 14:46:26 -04:00
Lauren Hirata Singh a7faae6b54 nit 2025-05-13 11:40:30 -07:00
Lauren Hirata Singh 1d3f19763d add js sample code back 2025-05-13 11:36:45 -07:00
Lauren Hirata Singh 16d5ce364c nit 2025-05-13 11:24:19 -07:00
Lauren Hirata Singh ce235d0eb1 edits based on feedback 2025-05-13 11:20:19 -07:00
Arjun Natarajan 2e17857ca7 verb tense 2025-05-13 13:57:18 -04:00
Arjun Natarajan 304a59a1c9 feat(docs): further improvements for studio guides docs 2025-05-13 13:52:14 -04:00
Lauren Hirata Singh 063a0e027b docs: Simplify LGP quickstarts 2025-05-13 10:51:48 -07:00
ccurme 4534d174f4 docs: move async guide into graph-api (#4676) 2025-05-13 13:30:23 -04:00
Lauren Hirata Singh 8d9a99bb99 docs: address feedback (#4674) 2025-05-13 10:08:42 -07:00
Lauren Hirata Singh ee528f7d49 nit 2025-05-13 10:04:33 -07:00
Lauren Hirata Singh 9d3ea6fd7e docs: address feedback 2025-05-13 09:51:50 -07:00
Vadym Barda d256469f37 docs: fix warnings in links (#4672) 2025-05-13 11:38:54 -04:00
William Fu-Hinthorn 138f0eb003 fix: (docs) Rm unused api keys 2025-05-13 08:07:13 -07:00
Lauren Hirata Singh 1acad37bee docs: LGP nits (#4670) 2025-05-12 20:59:59 -07:00
Lauren Hirata Singh 0a7a7fb71f docs: LGP nits 2025-05-12 20:57:29 -07:00
lc-arjun b6f3e25ef7 fix: use absolute links for sdk reference (#4669) 2025-05-12 19:44:36 -07:00
Arjun Natarajan 70a10b0b57 fix: use absolute links for sdk reference 2025-05-12 22:39:05 -04:00
William FH bed5f80e2c Optionally use loop-safe asgi transport (#4668) 2025-05-12 19:31:44 -07:00
Vadym Barda 8057efc80a docs: update cassettes & notebook runner processing (#4667) 2025-05-12 21:54:42 -04:00
Marco PeriniandVadym Barda ce4caa3ac8 docs: mcp adapters example for deployed graph (#4666)
Example to connect to the MCP server of a deployed graph in langgraph
platform (langchain-mcp-adapters).
The graph can be used as a MCP tool.


![image](https://github.com/user-attachments/assets/fb5c36d4-0f04-4814-b0b7-bf7fcf6f8381)

---------

Co-authored-by: Vadym Barda <vadym@langchain.dev>
2025-05-12 17:55:38 -07:00
Vadym Barda ad315bb5e0 docs: update HITL platform docs (#4664) 2025-05-12 17:56:27 -04:00
Lauren Hirata Singh 5b9c9057a2 docs: General clean up (#4665)
- Change LG Cloud > Platform
- Misc. cleanup
2025-05-12 17:41:49 -04:00
Lauren Hirata Singh 280d612b2d Merge branch 'main' into clean 2025-05-12 17:26:17 -04:00
Lauren Hirata Singh ceee65c93c Fix headings 2025-05-12 14:25:34 -07:00
William Fu-Hinthorn a16176c5bf fix: (docs) Update openapi.json 2025-05-12 14:23:20 -07:00
lc-arjun 5537adc16a feat(docs): threads (#4662) 2025-05-12 14:19:48 -07:00
Ido Salomon 9fce01f884 [Proposal] add gitmcp badge for simple LLM-accessible documentation (#4502)
[gitmcp.io](https://gitmcp.io/) provides easy access to the latest
langgraph docs through a remote, free, open-source MCP. It's supported
by all major clients (including the new claude.ai web client). It
enables two access points -
- Empower AI agents (e.g., Cursor) with live documentation context to
prevent hallucinations.
- Chat with the documentation in the browser via the embedded chat

This PR proposes adding a new badge to help users make the most of
Langgraph's documentation with GitMCP. The badge is
[customizable](https://github.com/idosal/git-mcp?tab=readme-ov-file#-gitmcp-badge).
The count is a live count of users accessing Langgraph's documentation
through GitMCP.

Example:

[![GitMCP](https://img.shields.io/endpoint?url=https://gitmcp.io/badge/langchain-ai/langgraph)](https://gitmcp.io/langchain-ai/langgraph)

You can see a demo with Langgraph's GitHub pages at gitmcp.io.

Please let us know what you think :)
2025-05-12 17:08:47 -04:00
Arjun Natarajan e1ea8c9538 pr feedback 2025-05-12 16:55:03 -04:00
Lauren Hirata Singh 7ea406648f Simplify assistants 2025-05-12 13:37:25 -07:00
Lauren Hirata Singh f5423783f7 Change LG Cloud > Platform 2025-05-12 12:44:50 -07:00
Arjun Natarajan 04a42c014b rm accidental change 2025-05-12 15:22:26 -04:00
Arjun Natarajan 1e405274ba feat(docs): threads 2025-05-12 15:18:41 -04:00
Vadym Barda ae5b4e834e docs: replace state_modifier w/ prompt in func how-tos (#4659) 2025-05-12 13:46:50 +00:00
André Menezes 3d394740ce Fix AsyncPostgresStore._cursor row type (#4623)
`AsyncPostgresStore._cursor` is expected to yield
`AsyncCursor[DictRow]`. In the `else` branch the `row_factory` was not
defined, meaning that it would yield `AsyncCursor[TupleRow]` (default).
This resulted in an error in
[langgraph/store/postgres/aio.py#L249](https://github.com/langchain-ai/langgraph/blob/main/libs/checkpoint-postgres/langgraph/store/postgres/aio.py#L249)
(`TypeError: tuple indices must be integers or slices, not str`).
2025-05-12 13:34:56 +00:00
Emmanuel Ferdman 5ab6f77982 Fix invalid channels error message (#4357)
# PR Summary
This small PR resolves the error formatting in
`libs/langgraph/langgraph/pregel/algo.py` so the `proc.channels` will be
evaluated in the message.

Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
2025-05-12 09:29:49 -04:00
Hamza Kyamanywa fe11a71d28 docs: update link in agentic concepts tutorial for map-reduce implementation (#4650)
## PR for:
- Fix broken link in agentic concepts tutorial for map-reduce
implementation
2025-05-12 07:46:30 -04:00
Sydney Runkle 347fbf1625 docs: remove unused annotation comments in readmes (#4656) 2025-05-12 07:45:22 -04:00
Sydney Runkle 0b5529108f docs: fix broken API reference link (#4657) 2025-05-12 07:45:07 -04:00
Lauren Hirata Singh daf20b610b docs: General language cleanup (#4649)
- README updates based on feedback
- Auth tutorial cleanup
2025-05-12 06:11:08 +00:00
William FH f7c4f96e61 Ref index (#4644) 2025-05-11 16:46:03 -07:00
Andrew Nguonly 4bdbebb3e4 docs: Update beta labels for deployment options (#4643)
@lnhsingh, let me know if you're ok with this copy and messaging
placement.
2025-05-11 10:33:38 -07:00
Andrew NguonlyandLauren Hirata Singh ce5d3c9c5a docs: Remove self-hosted lite deployment option (#4645)
### Summary
Self-Hosted Lite is a server version, not a deployment option.

---------

Co-authored-by: Lauren Hirata Singh <lauren@langchain.dev>
2025-05-11 10:29:01 -07:00
Eugene Yurtsev dda4b02095 docs: remove customer support bot example (#4641)
Hide example temporarily until we bring it up to date
2025-05-09 21:19:35 -04:00
lc-arjun 0c57f2ab7e fix(docs): update footer color (#4646) 2025-05-09 18:09:44 -07:00
Arjun Natarajan 6f6ae8edce update footer color 2025-05-09 21:05:43 -04:00
lc-arjun ee11294351 feat(docs): assistants and threads and faqs (#4642) 2025-05-09 15:35:11 -07:00
Arjun Natarajan 6d3dae6fd1 assistants and threads and faqs 2025-05-09 18:11:44 -04:00
Eugene Yurtsev 200c09b662 docs: re-enable strict mode (#4638)
- Turn on strict mode to fail docs build if there are any internal
broken anchor links.
- Fix broken anchor links.
- Delete storm tutorial that has fake markdown inside it (we'll figure
out how to deal with it later)
2025-05-09 17:25:11 -04:00
Eugene Yurtsev af80d6b339 docs: re-org side bar (#4640) 2025-05-09 17:21:15 -04:00
Eugene Yurtsev 220f9aaaab docs: fix formatting in overview for getting started tutorial (#4639) 2025-05-09 16:48:13 -04:00
687 changed files with 95917 additions and 90839 deletions

No files matched your search

+12 -12
View File
@@ -1,29 +1,29 @@
name: "\U0001F41B Bug Report"
description: Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the GitHub Discussions.
labels: ["02 Bug Report"]
description: Report a bug in LangGraph. To report a security issue, please instead use the security option below. For questions, please use the LangChain Forum at forum.langchain.com.
labels: [pending,bug]
body:
- type: markdown
attributes:
value: >
value: |
Thank you for taking the time to file a bug report.
Use this to report BUGS in LangGraph. For usage questions, feature requests and general design questions, please use [GitHub Discussions](https://github.com/langchain-ai/langgraph/discussions).
Use this to report BUGS in LangGraph. For usage questions, feature requests and general design questions, please use the [LangChain Forum](https://forum.langchain.com/).
Relevant links to check before filing a bug report to see if your issue has already been reported, fixed or
if there's another way to solve your problem:
[LangGraph Github Discussions](https://github.com/langchain-ai/langgraph/discussions),
[LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues),
[LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/).
[LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
[GitHub search](https://github.com/langchain-ai/langgraph),
* [LangChain Forum](https://forum.langchain.com/),
* [LangGraph Github Issues](https://github.com/langchain-ai/langgraph/issues),
* [LangGraph how-to guides](https://langchain-ai.github.io/langgraph/how-tos/).
* [LangChain documentation with the integrated search](https://python.langchain.com/docs/get_started/introduction),
* [GitHub search](https://github.com/langchain-ai/langgraph),
- type: checkboxes
id: checks
attributes:
label: Checked other resources
description: Before submitting this issue, please confirm that you have completed all the steps below by checking each option. These steps help ensure your issue is well-defined, relevant, and actionable.
options:
- label: This is a bug, not a usage question. For questions, please use GitHub Discussions.
- label: This is a bug, not a usage question. For questions, please use the LangChain Forum (https://forum.langchain.com/).
required: true
- label: I added a clear and detailed title that summarizes the issue.
required: true
@@ -38,7 +38,7 @@ body:
attributes:
label: Example Code
description: |
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case. Replace this code with your own!
placeholder: |
from langgraph.graph import StateGraph
@@ -78,7 +78,7 @@ body:
attributes:
label: System Info
description: |
python -m langchain_core.sys_info
Run on your machine: `python -m langchain_core.sys_info`
placeholder: |
python -m langchain_core.sys_info
validations:
+3 -12
View File
@@ -1,15 +1,6 @@
blank_issues_enabled: false
version: 2.1
contact_links:
- name: 🤔 Question or Problem
about: Ask a question or ask about a problem in GitHub Discussions.
url: https://github.com/langchain-ai/langgraph/discussions/categories/q-a
- name: Feature Request
url: https://github.com/langchain-ai/langgraph/discussions/categories/ideas
about: Suggest a feature or an idea
- name: Show and tell
about: Show what you built with LangChain
url: https://github.com/langchain-ai/langgraph/discussions/categories/show-and-tell
- name: Slack
url: https://www.langchain.com/join-community
about: General community discussions
- name: LangChain Forum
url: https://forum.langchain.com/
about: General community discussions, support, and feature requests
+1 -1
View File
@@ -1,7 +1,7 @@
name: Documentation
description: Report an issue related to the LangGraph documentation.
title: "DOC: <Please write a comprehensive title after the 'DOC: ' prefix>"
labels: [03 - Documentation]
labels: [documentation]
body:
- type: textarea
+12 -8
View File
@@ -1,25 +1,29 @@
name: 🔒 Privileged
description: You are a LangChain maintainer, or was asked directly by a maintainer to create an issue here. If not, check the other options.
description: You are a LangGraph maintainer, or was asked directly by a maintainer to create an issue here. If not, check the other options.
body:
- type: markdown
attributes:
value: |
Thanks for your interest in LangChain! 🚀
If you are not a LangChain maintainer or were not asked directly by a maintainer to create an issue, then please start the conversation in a [Question in GitHub Discussions](https://github.com/langchain-ai/langchain/discussions/categories/q-a) instead.
You are a LangChain maintainer if you maintain any of the packages inside of the LangChain repository
or are a regular contributor to LangChain with previous merged merged pull requests.
Thanks for your interest in LangGraph! 🚀
If you are not a LangGraph maintainer or were not asked directly by a maintainer to create an issue, then please start the conversation on the [LangChain Forum](https://forum.langchain.com/) instead.
You are a LangGraph maintainer if you maintain any of the packages inside of the LangGraph repository
or are a regular contributor to LangGraph with previous merged merged pull requests.
- type: checkboxes
id: privileged
attributes:
label: Privileged issue
description: Confirm that you are allowed to create an issue here.
options:
- label: I am a LangChain maintainer, or was asked directly by a LangChain maintainer to create an issue here.
- label: I am a LangGraph maintainer, or was asked directly by a LangGraph maintainer to create an issue here.
required: true
- type: textarea
id: content
attributes:
label: Issue Content
description: Add the content of the issue here.
- type: markdown
attributes:
value: |
Community members should **NOT** work on Privileged issues unless these issues have been explicitly marked with a "help-wanted" tag.
+31
View File
@@ -0,0 +1,31 @@
Thank you for contributing to LangGraph! Follow these steps to mark your pull request as ready for review. **If any of these steps are not completed, your PR will not be considered for review.**
- [ ] **PR title**: Follows the format: {TYPE}({SCOPE}): {DESCRIPTION}
- Examples:
- feat(core): add multi-tenant support
- fix(cli): resolve flag parsing error
- docs(openai): update API usage examples
- Allowed `{TYPE}` values:
- feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, release
- Allowed `{SCOPE}` values (optional):
- langgraph, docs, cli, checkpoint, checkpoint-postgres, checkpoint-sqlite, prebuilt, scheduler-kafka, sdk-py
- Once you've written the title, please delete this checklist item; do not include it in the PR.
- [ ] **PR message**: ***Delete this entire checklist*** and replace with
- **Description:** a description of the change. Include a [closing keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) if applicable.
- **Issue:** the issue # it fixes, if applicable
- **Dependencies:** any dependencies required for this change
- **Twitter handle:** if your PR gets announced, and you'd like a mention, we'll gladly shout you out!
- [ ] **Add tests and docs**: If you're adding a new integration, you must include:
1. A test for the integration, preferably unit tests that do not rely on network access,
2. An example notebook showing its use. It lives in `docs/docs/integrations` directory.
- [ ] **Lint and test**: Run `make format`, `make lint` and `make test` from the root of the package(s) you've modified. We will not consider a PR unless these three are passing in CI. See [contribution guidelines](https://github.com/langchain-ai/langgraph/blob/main/CONTRIBUTING.md) for more.
Additional guidelines:
- Make sure optional dependencies are imported within a function.
- Please do not add dependencies to `pyproject.toml` files (even optional ones) unless they are **required** for unit tests.
- Most PRs should not touch more than one package.
- Changes should be backwards compatible.
-88
View File
@@ -1,88 +0,0 @@
# An action for setting up poetry install with caching.
# Using a custom action since the default action does not
# take poetry install groups into account.
# Action code from:
# https://github.com/actions/setup-python/issues/505#issuecomment-1273013236
name: poetry-install-with-caching
description: Poetry install with support for caching of dependency groups.
inputs:
python-version:
description: Python version, supporting MAJOR.MINOR only
required: true
poetry-version:
description: Poetry version
required: true
cache-key:
description: Cache key to use for manual handling of caching
required: true
runs:
using: composite
steps:
- uses: actions/setup-python@v5
name: Setup python ${{ inputs.python-version }}
id: setup-python
with:
python-version: ${{ inputs.python-version }}
- uses: actions/cache@v3
id: cache-bin-poetry
name: Cache Poetry binary - Python ${{ inputs.python-version }}
env:
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "1"
with:
path: |
/opt/pipx/venvs/poetry
# This step caches the poetry installation, so make sure it's keyed on the poetry version as well.
key: bin-poetry-${{ runner.os }}-${{ runner.arch }}-py-${{ inputs.python-version }}-${{ inputs.poetry-version }}
- name: Refresh shell hashtable and fixup softlinks
if: steps.cache-bin-poetry.outputs.cache-hit == 'true'
shell: bash
env:
POETRY_VERSION: ${{ inputs.poetry-version }}
PYTHON_VERSION: ${{ inputs.python-version }}
run: |
set -eux
# Refresh the shell hashtable, to ensure correct `which` output.
hash -r
# `actions/cache@v3` doesn't always seem able to correctly unpack softlinks.
# Delete and recreate the softlinks pipx expects to have.
rm /opt/pipx/venvs/poetry/bin/python
cd /opt/pipx/venvs/poetry/bin
ln -s "$(which "python$PYTHON_VERSION")" python
chmod +x python
cd /opt/pipx_bin/
ln -s /opt/pipx/venvs/poetry/bin/poetry poetry
chmod +x poetry
# Ensure everything got set up correctly.
/opt/pipx/venvs/poetry/bin/python --version
/opt/pipx_bin/poetry --version
- name: Install poetry
if: steps.cache-bin-poetry.outputs.cache-hit != 'true'
shell: bash
env:
POETRY_VERSION: ${{ inputs.poetry-version }}
PYTHON_VERSION: ${{ inputs.python-version }}
# Install poetry using the python version installed by setup-python step.
run: pipx install "poetry==$POETRY_VERSION" --python '${{ steps.setup-python.outputs.python-path }}' --verbose
- name: Restore pip and poetry cached dependencies
uses: actions/cache@v3
env:
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "4"
with:
path: |
~/.cache/pip
~/.cache/pypoetry/virtualenvs
~/.cache/pypoetry/cache
~/.cache/pypoetry/artifacts
./.venv
key: py-deps-${{ runner.os }}-${{ runner.arch }}-py-${{ inputs.python-version }}-poetry-${{ inputs.poetry-version }}-${{ inputs.cache-key }}-${{ hashFiles('./poetry.lock') }}
+18
View File
@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "pip"
directories:
- "libs/checkpoint"
- "libs/checkpoint-postgres"
- "libs/checkpoint-sqlite"
- "libs/cli"
- "libs/langgraph"
- "libs/prebuilt"
- "libs/sdk-py"
schedule:
interval: "weekly"
+7 -2
View File
@@ -1,10 +1,15 @@
import ast
import os
from itertools import filterfalse
from typing import List, Tuple
from typing import Dict, List, Tuple
ROOT_PATH = os.path.abspath(os.path.join(__file__, "..", "..", ".."))
CLIENT_PATH = os.path.join(ROOT_PATH, "libs", "sdk-py", "langgraph_sdk", "client.py")
ASYNC_TO_SYNC_METHOD_MAP: Dict[str, str] = {
"aclose": "close",
"__aenter__": "__enter__",
"__aexit__": "__exit__",
}
def get_class_methods(node: ast.ClassDef) -> List[str]:
@@ -22,7 +27,7 @@ def find_classes(tree: ast.AST) -> List[Tuple[str, List[str]]]:
def compare_sync_async_methods(sync_methods: List[str], async_methods: List[str]) -> List[str]:
sync_set = set(sync_methods)
async_set = set(async_methods)
async_set = {ASYNC_TO_SYNC_METHOD_MAP.get(async_method, async_method) for async_method in async_methods}
missing_in_sync = list(async_set - sync_set)
missing_in_async = list(sync_set - async_set)
return missing_in_sync + missing_in_async
+125 -87
View File
@@ -1,107 +1,145 @@
import asyncio
import json
import os
import pathlib
import sys
import langgraph_cli
import langgraph_cli.docker
import langgraph_cli.config
import time
from urllib import request, error
import langgraph_cli
import langgraph_cli.config
import langgraph_cli.docker
from langgraph_cli.cli import prepare_args_and_stdin
from langgraph_cli.constants import DEFAULT_PORT
from langgraph_cli.exec import Runner, subp_exec
from langgraph_cli.progress import Progress
from langgraph_cli.constants import DEFAULT_PORT
def test(
config: pathlib.Path,
port: int,
tag: str,
verbose: bool,
):
def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
"""Spin up API with Postgres/Redis via docker compose and wait until ready."""
with Runner() as runner, Progress(message="Pulling...") as set:
# check docker available
# Detect docker/compose capabilities
capabilities = langgraph_cli.docker.check_capabilities(runner)
# open config
# Validate config and prepare compose stdin/args using built image
config_json = langgraph_cli.config.validate_config_file(config)
args, stdin = prepare_args_and_stdin(
capabilities=capabilities,
config_path=config,
config=config_json,
docker_compose=None,
port=port,
watch=False,
debugger_port=None,
debugger_base_url=f"http://127.0.0.1:{port}",
postgres_uri=None,
api_version=None,
image=tag,
base_image=None,
)
set("Running...")
args = [
"run",
"--rm",
"-p",
f"{port}:8000",
]
if isinstance(config_json["env"], str):
args.extend(
[
"--env-file",
str(config.parent / config_json["env"]),
]
)
else:
for k, v in config_json["env"].items():
args.extend(
[
"-e",
f"{k}={v}",
]
)
if capabilities.healthcheck_start_interval:
args.extend(
[
"--health-interval",
"5s",
"--health-retries",
"1",
"--health-start-period",
"10s",
"--health-start-interval",
"1s",
]
)
else:
args.extend(
[
"--health-interval",
"5s",
"--health-retries",
"2",
]
)
# Compose up with wait (implies detach), similar to `langgraph up --wait`
args_up = [*args, "up", "--remove-orphans", "--wait"]
_task = None
def on_stdout(line: str):
nonlocal _task
if "GET /ok" in line or "Uvicorn running on" in line:
set("")
sys.stdout.write(
f"""Ready!
- API: http://localhost:{port}
"""
)
sys.stdout.flush()
_task.cancel()
return True
return False
async def subp_exec_task(*args, **kwargs):
nonlocal _task
_task = asyncio.create_task(subp_exec(*args, **kwargs))
await _task
compose_cmd = ["docker", "compose"]
if capabilities.compose_type == "standalone":
compose_cmd = ["docker-compose"]
set("Starting...")
try:
runner.run(
subp_exec_task(
"docker",
*args,
tag,
subp_exec(
*compose_cmd,
*args_up,
input=stdin,
verbose=verbose,
on_stdout=on_stdout,
)
)
except asyncio.CancelledError:
pass
except Exception as e: # noqa: BLE001
# On failure, show diagnostics then ensure clean teardown
sys.stderr.write(f"docker compose up failed: {e}\n")
try:
sys.stderr.write("\n== docker compose ps ==\n")
runner.run(subp_exec(*compose_cmd, *args, "ps", input=stdin, verbose=False))
except Exception:
pass
try:
sys.stderr.write("\n== docker compose logs (api) ==\n")
runner.run(
subp_exec(
*compose_cmd,
*args,
"logs",
"langgraph-api",
input=stdin,
verbose=False,
)
)
except Exception:
pass
finally:
try:
runner.run(
subp_exec(
*compose_cmd,
*args,
"down",
"-v",
"--remove-orphans",
input=stdin,
verbose=False,
)
)
finally:
raise
set("")
base_url = f"http://localhost:{port}"
ok_url = f"{base_url}/ok"
print(f"Waiting for {ok_url} to respond with 200...")
deadline = time.time() + 30
last_err: Exception | None = None
while time.time() < deadline:
try:
with request.urlopen(ok_url, timeout=2) as resp:
if resp.status == 200:
sys.stdout.write(
f"""Ready!\n- API: {base_url}\n- /ok: 200 OK\n"""
)
sys.stdout.flush()
break
else:
last_err = RuntimeError(f"Unexpected status: {resp.status}")
print(f"Unexpected status: {resp.status}")
except error.URLError as e:
last_err = e
except Exception as e: # noqa: BLE001
last_err = e
time.sleep(0.5)
else:
# Bring stack down before raising
args_down = [*args, "down", "-v", "--remove-orphans"]
try:
runner.run(
subp_exec(
*compose_cmd,
*args_down,
input=stdin,
verbose=verbose,
)
)
finally:
raise SystemExit(
f"/ok did not return 202 within timeout. Last error: {last_err}"
)
# Clean up: bring compose stack down to free ports for next test
args_down = [*args, "down", "-v", "--remove-orphans"]
runner.run(
subp_exec(
*compose_cmd,
*args_down,
input=stdin,
verbose=verbose,
)
)
if __name__ == "__main__":
@@ -110,6 +148,6 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--tag", type=str)
parser.add_argument("-c", "--config", type=str, default="./langgraph.json")
parser.add_argument("-p", "--port", default=DEFAULT_PORT)
parser.add_argument("-p", "--port", type=int, default=DEFAULT_PORT)
args = parser.parse_args()
test(pathlib.Path(args.config), args.port, args.tag, verbose=True)
+51 -11
View File
@@ -3,8 +3,8 @@ name: CLI integration test
on:
workflow_call:
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
jobs:
build:
@@ -25,13 +25,14 @@ jobs:
uses: Ana06/get-changed-files@v2.3.0
with:
filter: "libs/cli/**"
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
- name: Set up Python ${{ matrix.python-version }}
if: steps.changed-files.outputs.all
uses: "./.github/actions/poetry_setup"
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: integration-test-cli
enable-cache: true
cache-suffix: "cli-integration-test"
ignore-nothing-to-cache: true
- name: Setup env
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples
@@ -42,28 +43,43 @@ jobs:
- name: Build and test service A
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
# The build-arg isn't used; just testing that we accept other args
langgraph build -t langgraph-test-a --base-image "langchain/langgraph-trial"
cp .env.example .envg
langgraph build -t langgraph-test-a
cp .env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -c langgraph.json -t langgraph-test-a
- name: Build and test service B
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graphs
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
langgraph build -t langgraph-test-b --base-image "langchain/langgraph-trial"
langgraph build -t langgraph-test-b
cp ../.env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-b
- name: Build and test service C
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graphs_reqs_a
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
langgraph build -t langgraph-test-c --base-image "langchain/langgraph-trial"
langgraph build -t langgraph-test-c
cp ../.env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-c
- name: Build and test service D
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graphs_reqs_b
env:
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
run: |
langgraph build -t langgraph-test-d --base-image "langchain/langgraph-trial"
langgraph build -t langgraph-test-d
cp ../.env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-d
- name: Build JS service
@@ -71,3 +87,27 @@ jobs:
working-directory: libs/cli/js-examples
run: |
langgraph build -t langgraph-test-e
- name: Build JS monorepo service
if: steps.changed-files.outputs.all
working-directory: libs/cli/js-monorepo-example
run: |
langgraph build -t langgraph-test-f -c apps/agent/langgraph.json --build-command "yarn run turbo build" --install-command "yarn install"
- name: Build Python monorepo service
if: steps.changed-files.outputs.all
working-directory: libs/cli/python-monorepo-example
run: |
langgraph build -t langgraph-test-g -c apps/agent/langgraph.json
cp apps/agent/.env.example apps/agent/.env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env; fi
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json
- name: Build and test prerelease reqs service
if: steps.changed-files.outputs.all
working-directory: libs/cli/examples/graph_prerelease_reqs
run: |
langgraph build -t langgraph-test-h
cp ../.env.example .env
if [ -n "${{ secrets.LANGSMITH_API_KEY }}" ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env; fi
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h
+13 -35
View File
@@ -8,9 +8,10 @@ on:
type: string
description: "From which folder this pipeline executes"
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
env:
# This env var allows us to get inline annotations when ruff has complaints.
RUFF_OUTPUT_FORMAT: github
@@ -36,42 +37,28 @@ jobs:
uses: Ana06/get-changed-files@v2.3.0
with:
filter: "${{ inputs.working-directory }}/**"
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
- name: Set up Python ${{ matrix.python-version }}
if: steps.changed-files.outputs.all
uses: "./.github/actions/poetry_setup"
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: lint-${{ inputs.working-directory }}
- name: Check Poetry File
if: steps.changed-files.outputs.all
shell: bash
working-directory: ${{ inputs.working-directory }}
run: poetry check
enable-cache: true
cache-suffix: lint-${{ inputs.working-directory }}
- name: Install dependencies
if: steps.changed-files.outputs.all
# Also installs dev/lint/test/typing dependencies, to ensure we have
# type hints for as many of our libraries as possible.
# This helps catch errors that require dependencies to be spotted, for example:
# https://github.com/langchain-ai/langchain/pull/10249/files#diff-935185cd488d015f026dcd9e19616ff62863e8cde8c0bee70318d3ccbca98341
#
# If you change this configuration, make sure to change the `cache-key`
# in the `poetry_setup` action above to stop using the old cache.
# It doesn't matter how you change it, any change will cause a cache-bust.
working-directory: ${{ inputs.working-directory }}
run: poetry install --with dev
run: uv sync --frozen --group dev
- name: Get .mypy_cache to speed up mypy
if: steps.changed-files.outputs.all
uses: actions/cache@v3
uses: actions/cache@v4
env:
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
with:
path: |
${{ inputs.working-directory }}/.mypy_cache
key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }}
key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/uv.lock', inputs.working-directory)) }}
- name: Analysing package code with our lint
if: steps.changed-files.outputs.all
@@ -86,27 +73,18 @@ jobs:
- name: Install test dependencies
if: steps.changed-files.outputs.all
# Also installs dev/lint/test/typing dependencies, to ensure we have
# type hints for as many of our libraries as possible.
# This helps catch errors that require dependencies to be spotted, for example:
# https://github.com/langchain-ai/langchain/pull/10249/files#diff-935185cd488d015f026dcd9e19616ff62863e8cde8c0bee70318d3ccbca98341
#
# If you change this configuration, make sure to change the `cache-key`
# in the `poetry_setup` action above to stop using the old cache.
# It doesn't matter how you change it, any change will cause a cache-bust.
working-directory: ${{ inputs.working-directory }}
run: |
poetry install --with dev
run: uv sync --group dev
- name: Get .mypy_cache_test to speed up mypy
if: steps.changed-files.outputs.all
uses: actions/cache@v3
uses: actions/cache@v4
env:
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
with:
path: |
${{ inputs.working-directory }}/.mypy_cache_test
key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }}
key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/uv.lock', inputs.working-directory)) }}
- name: Analysing tests with our lint
if: steps.changed-files.outputs.all
+8 -10
View File
@@ -8,8 +8,8 @@ on:
type: string
description: "From which folder this pipeline executes"
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
jobs:
build:
@@ -26,12 +26,12 @@ jobs:
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: test-${{ inputs.working-directory }}
enable-cache: true
cache-suffix: test-${{ inputs.working-directory }}
- name: Login to Docker Hub
uses: docker/login-action@v3
if: ${{ !github.event.pull_request.head.repo.fork }}
@@ -42,14 +42,12 @@ jobs:
- name: Install dependencies
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
poetry install --with dev
run: uv sync --frozen --group dev
- name: Run tests
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
make test
run: make test
- name: Ensure the tests did not create any additional files
shell: bash
+8 -10
View File
@@ -3,8 +3,8 @@ name: test
on:
workflow_call:
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
jobs:
build:
@@ -24,12 +24,12 @@ jobs:
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: test-langgraph
enable-cache: true
cache-suffix: "test-langgraph"
- name: Login to Docker Hub
uses: docker/login-action@v3
if: ${{ !github.event.pull_request.head.repo.fork }}
@@ -39,13 +39,11 @@ jobs:
- name: Install dependencies
shell: bash
run: |
poetry install --with dev
run: uv sync --frozen --group dev
- name: Run tests
shell: bash
run: |
make test_parallel
run: make test_parallel
- name: Ensure the tests did not create any additional files
shell: bash
+10 -8
View File
@@ -9,9 +9,11 @@ on:
description: "From which folder this pipeline executes"
env:
POETRY_VERSION: "2.1.2"
PYTHON_VERSION: "3.10"
permissions:
contents: read
jobs:
build:
if: github.ref == 'refs/heads/main'
@@ -24,12 +26,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python $${ env.PYTHON_VERSION }}
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: release
enable-cache: true
cache-suffix: "release"
# We want to keep this build stage *separate* from the release stage,
# so that there's no sharing of permissions between them.
@@ -43,7 +45,7 @@ jobs:
# > from the publish job.
# https://github.com/pypa/gh-action-pypi-publish#non-goals
- name: Build project for distribution
run: poetry build
run: uv build
working-directory: ${{ inputs.working-directory }}
- name: Upload build
@@ -57,8 +59,8 @@ jobs:
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
echo pkg-name="$(poetry version | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT
echo version="$(poetry version --short)" >> $GITHUB_OUTPUT
echo pkg-name=$(grep -m 1 "^name = " pyproject.toml | cut -d '"' -f 2)
echo version=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
publish:
needs:
@@ -1,57 +0,0 @@
name: test
on:
workflow_call:
env:
POETRY_VERSION: "2.1.2"
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version:
- "3.11"
- "3.12"
defaults:
run:
working-directory: libs/scheduler-kafka
name: "test #${{ matrix.python-version }}"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
with:
python-version: ${{ matrix.python-version }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: test-scheduler-kafka
- name: Login to Docker Hub
uses: docker/login-action@v3
if: ${{ !github.event.pull_request.head.repo.fork }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_RO_TOKEN }}
- name: Install dependencies
shell: bash
run: |
poetry install --with dev
- name: Run tests
shell: bash
run: |
make test
- name: Ensure the tests did not create any additional files
shell: bash
run: |
set -eu
STATUS="$(git status)"
echo "$STATUS"
# grep will exit non-zero if the target message isn't found,
# and `set -e` above will cause the step to fail.
echo "$STATUS" | grep 'nothing to commit, working tree clean'
+7 -7
View File
@@ -7,8 +7,8 @@ on:
paths:
- "libs/**"
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
jobs:
benchmark:
@@ -19,14 +19,14 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
- name: Set up Python 3.11 + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python 3.11
uses: astral-sh/setup-uv@v6
with:
python-version: "3.11"
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: bench
enable-cache: true
cache-suffix: "bench"
- name: Install dependencies
run: poetry install --with dev
run: uv sync --group dev
- name: Run benchmarks
run: OUTPUT=out/benchmark-baseline.json make -s benchmark
- name: Save outputs
+8 -8
View File
@@ -5,8 +5,8 @@ on:
paths:
- "libs/**"
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
jobs:
benchmark:
@@ -21,14 +21,14 @@ jobs:
uses: Ana06/get-changed-files@v2.3.0
with:
format: json
- name: Set up Python 3.11 + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python 3.11
uses: astral-sh/setup-uv@v6
with:
python-version: "3.11"
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: bench
enable-cache: true
cache-suffix: "bench"
- name: Install dependencies
run: poetry install --with dev
run: uv sync --group dev
- name: Download baseline
uses: actions/cache/restore@v4
with:
@@ -53,7 +53,7 @@ jobs:
echo 'OUTPUT<<EOF'
mv out/benchmark-baseline.json out/main.json
mv out/benchmark.json out/changes.json
poetry run pyperf compare_to out/main.json out/changes.json --table --group-by-speed
uv run pyperf compare_to out/main.json out/changes.json --table --group-by-speed
echo EOF
} >> "$GITHUB_OUTPUT"
- name: Annotation
+22 -81
View File
@@ -3,9 +3,13 @@ name: CI
on:
push:
branches: [main]
branches:
- main
pull_request:
permissions:
contents: read
# If another push to the same PR or branch happens while this workflow is still running,
# cancel the earlier run in favor of the next run.
#
@@ -16,15 +20,12 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
POETRY_VERSION: "2.1.2"
jobs:
changes:
runs-on: ubuntu-latest
outputs:
python: ${{ steps.filter.outputs.python }}
sdk-js: ${{ steps.filter.outputs.sdk-js }}
deps: ${{ steps.filter.outputs.deps }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
@@ -38,10 +39,10 @@ jobs:
- 'libs/checkpoint/**'
- 'libs/checkpoint-sqlite/**'
- 'libs/checkpoint-postgres/**'
- 'libs/scheduler-kafka/**'
- 'libs/prebuilt/**'
sdk-js:
- 'libs/sdk-js/**'
deps:
- '**/pyproject.toml'
- '**/uv.lock'
lint:
needs: changes
@@ -56,10 +57,10 @@ jobs:
"libs/checkpoint",
"libs/checkpoint-sqlite",
"libs/checkpoint-postgres",
"libs/scheduler-kafka",
"libs/prebuilt",
]
if: needs.changes.outputs.python == 'true'
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
uses: ./.github/workflows/_lint.yml
with:
working-directory: ${{ matrix.working-directory }}
@@ -77,8 +78,9 @@ jobs:
"libs/checkpoint-sqlite",
"libs/checkpoint-postgres",
"libs/prebuilt",
"libs/sdk-py",
]
if: needs.changes.outputs.python == 'true'
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
uses: ./.github/workflows/_test.yml
with:
working-directory: ${{ matrix.working-directory }}
@@ -87,19 +89,11 @@ jobs:
# NOTE: we're testing langgraph separately because it requires a different matrix
test-langgraph:
needs: changes
if: needs.changes.outputs.python == 'true'
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
name: "cd libs/langgraph"
uses: ./.github/workflows/_test_langgraph.yml
secrets: inherit
# NOTE: we're testing scheduler-kafka separately because it requires a different matrix
test-scheduler-kafka:
needs: changes
if: needs.changes.outputs.python == 'true'
name: "cd libs/scheduler-kafka"
uses: ./.github/workflows/_test_scheduler_kafka.yml
secrets: inherit
check-sdk-methods:
needs: changes
if: needs.changes.outputs.python == 'true'
@@ -125,26 +119,26 @@ jobs:
- "3.11"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v6
with:
python-version: "3.11"
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: schema-check-cli
enable-cache: true
cache-suffix: "schema-check-cli"
- name: Install CLI dependencies
run: |
cd libs/cli
poetry install
uv sync
- name: Generate schema and check for changes
run: |
cd libs/cli
# Create a temporary copy of the current schema
cp schemas/schema.json schemas/schema.current.json
# Generate new schema
poetry run python generate_schema.py
uv run python generate_schema.py
# Compare the new schema with the original
if ! diff -q schemas/schema.json schemas/schema.current.json > /dev/null; then
echo "Error: Langgraph.json configuration schema has changed. Please run 'poetry run python generate_schema.py' in the libs/cli directory and commit the changes."
echo "Error: Langgraph.json configuration schema has changed. Please run 'uv run python generate_schema.py' in the libs/cli directory and commit the changes."
diff schemas/schema.json schemas/schema.current.json
exit 1
fi
@@ -152,74 +146,21 @@ jobs:
integration-test:
needs: changes
if: needs.changes.outputs.python == 'true'
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.deps == 'true'
name: CLI integration test
uses: ./.github/workflows/_integration_test.yml
secrets: inherit
lint-js:
needs: changes
if: needs.changes.outputs.sdk-js == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
- "libs/sdk-js"
defaults:
run:
working-directory: ${{ matrix.working-directory }}
steps:
- uses: actions/checkout@v3
- name: Setup Node.js (LTS)
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "yarn"
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
- name: Install dependencies
run: yarn install
- name: Run lint
run: yarn lint
- name: Build
run: yarn build
test-js:
needs: changes
if: needs.changes.outputs.sdk-js == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
- "libs/sdk-js"
defaults:
run:
working-directory: ${{ matrix.working-directory }}
steps:
- uses: actions/checkout@v3
- name: Setup Node.js (LTS)
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "yarn"
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
- name: Install dependencies
run: yarn install
- name: Run tests
run: yarn test
ci_success:
name: "CI Success"
needs:
[
lint,
lint-js,
test,
test-langgraph,
test-scheduler-kafka,
check-sdk-methods,
check-schema,
integration-test,
test-js,
]
if: |
always()
@@ -0,0 +1,11 @@
LangChain
LangGraph
LangSmith
thead
stdio
nd
jupyter
lets
lite
uis
deque
+9 -3
View File
@@ -34,10 +34,16 @@
id: extract_ignore_words
- name: Codespell
uses: codespell-project/actions-codespell@v2
uses: codespell-project/actions-codespell@v2.1
with:
skip: '*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.md'
skip: '*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.css.map,*.js.map'
ignore_words_list: ${{ steps.extract_ignore_words.outputs.ignore_words_list }}
# We do this to avoid spellchecking cell outputs
- name: Codespell Notebooks
run: make codespell
run: make codespell
- name: Codespell LangGraph Library
run: |
# Change to root directory to check the main LangGraph library
cd ..
codespell --skip="*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.css.map,*.js.map,*.pyc,__pycache__/*" --ignore-words-list="${{ steps.extract_ignore_words.outputs.ignore_words_list }}" libs/langgraph/langgraph/
+9 -21
View File
@@ -9,9 +9,6 @@ on:
- main
workflow_dispatch:
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
pages: write
@@ -38,16 +35,7 @@ jobs:
with:
filter: "docs/docs/**"
# 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
runs-on: ubuntu-latest
timeout-minutes: 10 # Job will be cancelled if it runs for more than 10 minutes
env:
@@ -57,21 +45,21 @@ jobs:
with:
fetch-depth: 0
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python
uses: astral-sh/setup-uv@v6
with:
python-version: "3.12"
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: docs
enable-cache: true
cache-suffix: "docs"
- name: Install dependencies
run: |
yarn
poetry install --with test --with docs --no-root
uv sync --all-groups
# we run this installation only for internal PRs
# as GITHUB_TOKEN is not available for PRs from outside contributors
if [ -n "${GITHUB_TOKEN}" ]; then
poetry run pip install "git+https://${GITHUB_TOKEN}@github.com/langchain-ai/mkdocs-material-insiders.git"
uv run pip install "git+https://${GITHUB_TOKEN}@github.com/langchain-ai/mkdocs-material-insiders.git"
fi
- name: Run unit tests
@@ -103,7 +91,7 @@ jobs:
run: |
if [ "${{ github.event_name }}" == "schedule" ]; then
echo "Running link check on all HTML files matching notebooks in docs directory..."
poetry run pytest -v \
uv run pytest -v \
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
--check-links-ignore "https://academy\.langchain\.com/.*" \
--check-links-ignore "https://x.com/.*" \
@@ -128,7 +116,7 @@ jobs:
echo "Changed files: ${CHANGED_FILES}"
if [ -n "${CHANGED_FILES}" ]; then
echo "Running link check on HTML files matching changed notebook files..."
poetry run pytest -v \
uv run pytest -v \
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
--check-links-ignore "https://academy\.langchain\.com/.*" \
--check-links-ignore "http://localhost:8123/.*" \
@@ -148,7 +136,7 @@ jobs:
- name: Configure GitHub Pages
if: github.ref == 'refs/heads/main'
uses: actions/configure-pages@v4
uses: actions/configure-pages@v5
- name: Upload Pages Artifact
# if: github.ref == 'refs/heads/main'
+2 -2
View File
@@ -11,8 +11,8 @@ on:
- cron: "0 5 * * *"
workflow_dispatch:
env:
POETRY_VERSION: "2.1.2"
permissions:
contents: read
jobs:
markdown-link-check:
+45
View File
@@ -0,0 +1,45 @@
name: PR Title Lint
permissions:
pull-requests: read
on:
pull_request:
types: [opened, edited, synchronize]
jobs:
lint-pr-title:
runs-on: ubuntu-latest
steps:
- name: Validate PR Title
uses: amannn/action-semantic-pull-request@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
docs
style
refactor
perf
test
build
ci
chore
revert
release
scopes: |
checkpoint
checkpoint-postgres
checkpoint-sqlite
cli
langgraph
prebuilt
scheduler-kafka
sdk-py
docs
ci
requireScope: false
ignoreLabels: |
ignore-lint-pr-title
+36 -26
View File
@@ -8,9 +8,11 @@ on:
type: string
default: "libs/langgraph"
permissions:
contents: read
env:
PYTHON_VERSION: "3.11"
POETRY_VERSION: "2.1.2"
jobs:
build:
@@ -26,12 +28,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: release
enable-cache: true
cache-suffix: "release"
# We want to keep this build stage *separate* from the release stage,
# so that there's no sharing of permissions between them.
@@ -45,7 +47,7 @@ jobs:
# > from the publish job.
# https://github.com/pypa/gh-action-pypi-publish#non-goals
- name: Build project for distribution
run: poetry build
run: uv build
working-directory: ${{ inputs.working-directory }}
- name: Upload build
@@ -59,8 +61,14 @@ jobs:
shell: bash
working-directory: ${{ inputs.working-directory }}
run: |
PKG_NAME="$(poetry version | cut -d ' ' -f 1)"
VERSION="$(poetry version --short)"
PKG_NAME=$(grep -m 1 "^name = " pyproject.toml | cut -d '"' -f 2)
if grep -q 'dynamic.*=.*\[.*"version".*\]' pyproject.toml; then
# handle dynamic versioning
DIR_NAME=$(echo "$PKG_NAME" | tr '-' '_')
VERSION=$(grep -m 1 '^__version__' "${DIR_NAME}/__init__.py" | cut -d '"' -f 2)
else
VERSION=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
fi
SHORT_PKG_NAME="$(echo "$PKG_NAME" | sed -e 's/langgraph//g' -e 's/-//g')"
if [ -z $SHORT_PKG_NAME ]; then
TAG="$VERSION"
@@ -135,7 +143,9 @@ jobs:
needs:
- build
- release-notes
permissions: write-all
permissions:
contents: read
id-token: write
uses: ./.github/workflows/_test_release.yml
with:
working-directory: ${{ inputs.working-directory }}
@@ -163,11 +173,11 @@ jobs:
# - The package is published, and it breaks on the missing dependency when
# used in the real world.
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
enable-cache: true
- name: Import published package
shell: bash
@@ -185,18 +195,18 @@ jobs:
# - attempt install again after 5 seconds if it fails because there is
# sometimes a delay in availability on test pypi
run: |
poetry run pip install \
uv run pip install \
--extra-index-url https://test.pypi.org/simple/ \
"$PKG_NAME==$VERSION" || \
( \
sleep 5 && \
poetry run pip install \
uv run pip install \
--extra-index-url https://test.pypi.org/simple/ \
"$PKG_NAME==$VERSION" \
)
if [[ "$PKG_NAME" == *prebuilt* ]]; then
poetry run pip install langgraph
uv run pip install langgraph
fi
if [[ "$PKG_NAME" == *checkpoint* || "$PKG_NAME" == *prebuilt* ]]; then
@@ -209,10 +219,10 @@ jobs:
IMPORT_NAME="$(echo "$PKG_NAME" | sed s/-/_/g)"
fi
poetry run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
uv run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))"
- name: Import test dependencies
run: poetry install --with dev
run: uv sync --group dev
working-directory: ${{ inputs.working-directory }}
# Overwrite the local version of the package with the test PyPI version.
@@ -223,7 +233,7 @@ jobs:
PKG_NAME: ${{ needs.build.outputs.pkg-name }}
VERSION: ${{ needs.build.outputs.version }}
run: |
poetry run pip install \
uv run pip install \
--extra-index-url https://test.pypi.org/simple/ \
"$PKG_NAME==$VERSION"
@@ -253,12 +263,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: release
enable-cache: true
cache-suffix: "release"
- uses: actions/download-artifact@v4
with:
@@ -294,12 +304,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python + Poetry ${{ env.POETRY_VERSION }}
uses: "./.github/actions/poetry_setup"
- name: Set up Python
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ env.PYTHON_VERSION }}
poetry-version: ${{ env.POETRY_VERSION }}
cache-key: release
enable-cache: true
cache-suffix: "release"
- uses: actions/download-artifact@v4
with:
-38
View File
@@ -1,38 +0,0 @@
name: JS Release
on:
workflow_dispatch:
jobs:
publish:
# Disallow publishing from branches that aren't `main`.
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
strategy:
matrix:
working-directory:
- "libs/sdk-js"
defaults:
run:
working-directory: ${{ matrix.working-directory }}
steps:
- uses: actions/checkout@v4
# JS Build
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: "20"
cache: "yarn"
cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock
- name: Install dependencies
run: yarn install
- name: Build
run: yarn build
- name: Publish package to NPM
run: |
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc
npm publish
+12 -9
View File
@@ -11,6 +11,9 @@ on:
schedule:
- cron: "0 13 * * *"
permissions:
contents: read
defaults:
run:
working-directory: docs
@@ -27,30 +30,30 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python + Poetry
uses: "./.github/actions/poetry_setup"
uses: astral-sh/setup-uv@v6
with:
python-version: 3.11
poetry-version: 2.1.2
cache-key: test-langgraph-notebooks
python-version: "3.11"
enable-cache: true
cache-suffix: "test-langgraph-notebooks"
- name: Install dependencies
run: |
poetry install --with test --no-root
poetry run pip install jupyter
uv sync --group test
uv run pip install jupyter
- name: Start services
run: make start-services
- name: Pre-download tiktoken files
run: |
poetry run python _scripts/download_tiktoken.py
uv run python _scripts/download_tiktoken.py
- name: Prepare notebooks
run: |
if [ "${{ matrix.lib-version }}" = "development" ]; then
poetry run python _scripts/prepare_notebooks_for_ci.py --comment-install-cells
uv run python _scripts/prepare_notebooks_for_ci.py --comment-install-cells
else
poetry run python _scripts/prepare_notebooks_for_ci.py
uv run python _scripts/prepare_notebooks_for_ci.py
fi
- name: Run notebooks
+45
View File
@@ -0,0 +1,45 @@
name: UV Lock Upgrade
on:
schedule:
# run at midnight every Sunday
- cron: '0 0 * * 0'
# allow manual triggering
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
upgrade-dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
# use minimum supported Python version
python-version: "3.9"
enable-cache: true
cache-suffix: "uv-lock-upgrade"
- name: Run uv lock --upgrade in all Python packages
run: make lock-upgrade
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "chore[deps]: upgrade dependencies with `uv lock --upgrade`"
title: "chore[deps]: upgrade dependencies with `uv lock --upgrade`"
body: |
This PR updates the dependencies in all Python packages using `uv lock --upgrade`.
This is an automated PR created by the UV Lock Upgrade workflow.
branch: deps/uv-lock-upgrade
delete-branch: true
labels: |
dependencies
+1
View File
@@ -181,3 +181,4 @@ Chinook.db
.vercel
.turbo
.editorconfig
.scratch
+55
View File
@@ -0,0 +1,55 @@
# AGENTS Instructions
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
- `make format` – run code formatters
- `make lint` – run the linter
- `make test` – execute the test suite
To run a particular test file or to pass additional pytest options you can specify the `TEST` variable:
```
TEST=path/to/test.py make test
```
Other pytest arguments can also be supplied inside the `TEST` variable.
## Libraries
The repository contains several Python and JavaScript/TypeScript libraries.
Below is a high-level overview:
- **checkpoint** – base interfaces for LangGraph checkpointers.
- **checkpoint-postgres** – Postgres implementation of the checkpoint saver.
- **checkpoint-sqlite** – SQLite implementation of the checkpoint saver.
- **cli** – official command-line interface for LangGraph.
- **langgraph** – core framework for building stateful, multi-actor agents.
- **prebuilt** – high-level APIs for creating and running agents and tools.
- **sdk-js** – JS/TS SDK for interacting with the LangGraph REST API.
- **sdk-py** – Python SDK for the LangGraph Platform API.
### Dependency map
The diagram below lists downstream libraries for each production dependency as
declared in that library's `pyproject.toml` (or `package.json`).
```text
checkpoint
├── checkpoint-postgres
├── checkpoint-sqlite
├── prebuilt
└── langgraph
prebuilt
└── langgraph
sdk-py
├── langgraph
└── cli
sdk-js (standalone)
```
Changes to a library may impact all of its dependents shown above.
+12 -12
View File
@@ -9,7 +9,7 @@ Here are some things to keep in mind for all types of contributions:
- Follow the ["fork and pull request"](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) workflow.
- Fill out the checked-in pull request template when opening pull requests. Note related issues and tag relevant maintainers.
- Ensure your PR passes formatting, linting, and testing checks before requesting a review.
- If you would like comments or feedback, please open an issue or discussion and tag a maintainer.
- If you would like comments or feedback, please tag a maintainer.
- Backwards compatibility is key. Your changes must not be breaking, except in case of critical bug and security fixes.
- Look for duplicate PRs or issues that have already been opened before opening a new one.
- Keep scope as isolated as possible. As a general rule, your changes should not affect more than one package at a time.
@@ -20,7 +20,7 @@ For bug fixes, please open up an issue before proposing a fix to ensure the prop
### New features
For new features, please start a new [discussion](https://github.com/langchain-ai/langgraph/discussions), where the maintainers will help with scoping out the necessary changes.
For new features, please start a new [discussion](https://forum.langchain.com/), where the maintainers will help with scoping out the necessary changes.
## Contribute Documentation
@@ -60,7 +60,7 @@ In LangGraph, these are often higher level guides that show off end-to-end use c
Some examples include:
- [Build a Customer Support Bot](https://langchain-ai.github.io/langgraph/tutorials/customer-support/customer-support/)
- [Build a SQL Agent](https://langchain-ai.github.io/langgraph/tutorials/sql-agent/)
- [Build a SQL Agent](https://langchain-ai.github.io/langgraph/tutorials/sql/sql-agent/)
Here are some high-level tips on writing a good tutorial:
@@ -109,8 +109,7 @@ Here are some high-level tips on writing a good how-to guide:
LangGraph's conceptual guides fall under the **Explanation** quadrant of Diataxis. They should cover LangChain terms and concepts
in a more abstract way than how-to guides or tutorials, and should be geared towards curious users interested in
gaining a deeper understanding of the framework. Try to avoid excessively large code examples. The goal here is to
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work they way they do.
impart perspective to the user rather than to finish a practical project. These guides should cover **why** things work the way they do.
To quote the Diataxis website:
@@ -153,7 +152,7 @@ Each category serves a distinct purpose and requires a specific approach to writ
Here are some other guidelines you should think about when writing and organizing documentation.
We generally do not merge new tutorials from outside contributors without an actue need.
We generally do not merge new tutorials from outside contributors without an actual need.
We welcome updates as well as new integration docs, how-tos, and references.
### Avoid duplication
@@ -187,9 +186,9 @@ Be concise, including in code samples.
## Setup
LangChain documentation consists of two components:
LangGraph documentation consists of two components:
1. Main Documentation: Hosted at [https://langchain-ai.github.io](https://langchain-ai.github.io/langgraph/),
1. Main Documentation: Hosted at [https://langchain-ai.github.io/langgraph/](https://langchain-ai.github.io/langgraph/),
this comprehensive resource serves as the primary user-facing documentation.
It covers a wide array of topics, including tutorials, use cases, integrations,
and more, offering extensive guidance on building with LangGraph.
@@ -227,6 +226,7 @@ see a preview of the documentation on the pull request page.
From the **monorepo root**, run the following command to install the dependencies:
<!-- TODO -->
```bash
poetry install --with docs --no-root
```
@@ -249,17 +249,17 @@ make serve-docs
#### Linting
The documentation is linted from the **monorepo root**. To lint it, run the following from there:
To spell check the docs, run the following from the `docs` directory:
```bash
make spellcheck
codespell --skip="*.ambr,*.lock,*.ipynb,*.yaml,*.zlib,*.css.map,*.js.map" --ignore-words-list="infor,thead,stdio,nd,jupyter,lets,lite,uis,deque" .
```
### ️In-code Documentation
The in-code documentation is autogenerated from docstrings.
For the API reference to be useful, the codebase must be well-documented. This means that all functions, classes, and methods should have a docstring that explains what they do, what the arguments are, and what the return value is. This is a good practice in general, but it is especially important for LangChain because the API reference is the primary resource for developers to understand how to use the codebase.
For the API reference to be useful, the codebase must be well-documented. This means that all functions, classes, and methods should have a docstring that explains what they do, what the arguments are, and what the return value is. This is a good practice in general, but it is especially important for LangGraph because the API reference is the primary resource for developers to understand how to use the codebase.
We generally follow the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings) for docstrings.
@@ -290,4 +290,4 @@ def my_function(arg1: int, arg2: str) -> float:
This is a description of the return value.
"""
return 3.14
```
```
+68
View File
@@ -0,0 +1,68 @@
# Define the directories containing projects
LIBS_DIRS := $(wildcard libs/*)
# Default target
.PHONY: all
all: lint format lock test
# Install dependencies for all projects
.PHONY: install
install:
@echo "Creating virtual environment..."
@uv venv
@for dir in $(LIBS_DIRS); do \
if [ -f $$dir/pyproject.toml ]; then \
echo "Installing dependencies for $$dir"; \
uv pip install -e $$dir; \
fi; \
done
# Lint all projects
.PHONY: lint
lint:
@for dir in $(LIBS_DIRS); do \
if [ -f $$dir/Makefile ]; then \
echo "Running lint in $$dir"; \
$(MAKE) -C $$dir lint; \
fi; \
done
# Format all projects
.PHONY: format
format:
@for dir in $(LIBS_DIRS); do \
if [ -f $$dir/Makefile ]; then \
echo "Running format in $$dir"; \
$(MAKE) -C $$dir format; \
fi; \
done
# Lock all projects
.PHONY: lock
lock:
@for dir in $(LIBS_DIRS); do \
if [ -f $$dir/Makefile ]; then \
echo "Running lock in $$dir"; \
(cd $$dir && uv lock); \
fi; \
done
# Lock all projects and upgrade dependencies
.PHONY: lock-upgrade
lock-upgrade:
@for dir in $(LIBS_DIRS); do \
if [ -f $$dir/Makefile ]; then \
echo "Running lock-upgrade in $$dir"; \
(cd $$dir && uv lock --upgrade); \
fi; \
done
# Test all projects
.PHONY: test
test:
@for dir in $(LIBS_DIRS); do \
if [ -f $$dir/Makefile ]; then \
echo "Running test in $$dir"; \
$(MAKE) -C $$dir test; \
fi; \
done
+35 -24
View File
@@ -13,60 +13,71 @@
[![Open Issues](https://img.shields.io/github/issues-raw/langchain-ai/langgraph)](https://github.com/langchain-ai/langgraph/issues)
[![Docs](https://img.shields.io/badge/docs-latest-blue)](https://langchain-ai.github.io/langgraph/)
> [!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 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.
Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic, and more – LangGraph is a low-level orchestration framework for building, managing, and deploying long-running, stateful agents.
## Get started
First, install LangGraph:
Install LangGraph:
```
pip install -U langgraph
```
There are two ways to get started with LangGraph:
Then, create an agent [using prebuilt components](https://langchain-ai.github.io/langgraph/agents/agents/):
- [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.
```python
# pip install -qU "langchain[anthropic]" to call the model
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.
from langgraph.prebuilt import create_react_agent
## What LangGraph provides
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"It's always sunny in {city}!"
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:
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
prompt="You are a helpful assistant"
)
### Persistence
# Run the agent
agent.invoke(
{"messages": [{"role": "user", "content": "what is the weather in sf"}]}
)
```
LangGraph has a [persistence layer](https://langchain-ai.github.io/langgraph/concepts/persistence/), which offers a number of benefits:
For more information, see the [Quickstart](https://langchain-ai.github.io/langgraph/agents/agents/). Or, to learn how to build an [agent workflow](https://langchain-ai.github.io/langgraph/concepts/low_level/) with a customizable architecture, long-term memory, and other complex task handling, see the [LangGraph basics tutorials](https://langchain-ai.github.io/langgraph/tutorials/get-started/1-build-basic-chatbot/).
- [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.
## Core benefits
### Streaming
LangGraph provides low-level supporting infrastructure for *any* long-running, stateful workflow or agent. LangGraph does not abstract prompts or architecture, and provides the following central benefits:
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.
- [Durable execution](https://langchain-ai.github.io/langgraph/concepts/durable_execution/): Build agents that persist through failures and can run for extended periods, automatically resuming from exactly where they left off.
- [Human-in-the-loop](https://langchain-ai.github.io/langgraph/concepts/human_in_the_loop/): Seamlessly incorporate human oversight by inspecting and modifying agent state at any point during execution.
- [Comprehensive memory](https://langchain-ai.github.io/langgraph/concepts/memory/): Create truly stateful agents with both short-term working memory for ongoing reasoning and long-term persistent memory across sessions.
- [Debugging with LangSmith](http://www.langchain.com/langsmith): Gain deep visibility into complex agent behavior with visualization tools that trace execution paths, capture state transitions, and provide detailed runtime metrics.
- [Production-ready deployment](https://langchain-ai.github.io/langgraph/concepts/deployment_options/): Deploy sophisticated agent systems confidently with scalable infrastructure designed to handle the unique challenges of stateful, long-running workflows.
## LangGraph’s ecosystem
While LangGraph can be used standalone, it also integrates seamlessly with any LangChain product, giving developers a full suite of tools for building agents. To improve your LLM application development, pair LangGraph with:
- [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/).
- [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/).
- [LangChain](https://python.langchain.com/docs/introduction/) – Provides integrations and composable components to streamline LLM application development.
> [!NOTE]
> Looking for the JS version of LangGraph? See the [JS repo](https://github.com/langchain-ai/langgraphjs) and the [JS docs](https://langchain-ai.github.io/langgraphjs/).
## 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.
- [Examples](https://langchain-ai.github.io/langgraph/examples/): Guided examples on getting started with LangGraph.
- [LangChain Forum](https://forum.langchain.com/): Connect with the community and share all of your technical questions, ideas, and feedback.
- [LangChain Academy](https://academy.langchain.com/courses/intro-to-langgraph): Learn the basics of LangGraph in our free, structured course.
- [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.
- [Case studies](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 AI applications at scale.
## Acknowledgements
-1
View File
@@ -1,4 +1,3 @@
site/
docs/cloud/reference/sdk/js_ts_sdk_ref.md
.vercel
+22 -27
View File
@@ -1,10 +1,4 @@
.PHONY: lint-docs format-docs build-docs serve-docs serve-clean-docs clean-docs codespell build-typedoc llms-text build-prebuilt tests
build-typedoc:
cd ../libs/sdk-js && yarn install --include-dev && yarn typedoc
cd ../libs/sdk-js && yarn --silent concat-md --decrease-title-levels --ignore=js_ts_sdk_ref.md --start-title-level-at 2 docs > ../../docs/docs/cloud/reference/sdk/js_ts_sdk_ref.md 2>/dev/null
# Add links to the monorepo
sed -e '1,10s|@langchain/langgraph-sdk|[@langchain/langgraph-sdk](https://github.com/langchain-ai/langgraph/tree/main/libs/sdk-js)|g' docs/cloud/reference/sdk/js_ts_sdk_ref.md > temp_file && mv temp_file docs/cloud/reference/sdk/js_ts_sdk_ref.md
.PHONY: lint-docs format-docs build-docs serve-docs serve-clean-docs clean-docs codespell llms-text build-prebuilt tests
build-prebuilt:
# Use to create an update to date prebuilt page.
@@ -12,32 +6,33 @@ build-prebuilt:
# generates the final prebuilt page.
@if [ "$(DOWNLOAD_STATS)" = "true" ]; then \
set -x; \
poetry run python -m _scripts.third_party_page.get_download_stats stats.yml; \
uv run python -m _scripts.third_party_page.get_download_stats stats.yml; \
set +x; \
else \
set -x; \
poetry run python -m _scripts.third_party_page.get_download_stats --fake stats.yml; \
uv run python -m _scripts.third_party_page.get_download_stats --fake stats.yml; \
set +x; \
fi
poetry run python -m _scripts.third_party_page.create_third_party_page stats.yml docs/agents/prebuilt.md --language python
uv run python -m _scripts.third_party_page.create_third_party_page stats.yml docs/agents/prebuilt.md
build-docs: build-typedoc build-prebuilt
poetry run python -m mkdocs build --clean -f mkdocs.yml --strict
build-docs: build-prebuilt
TARGET_LANGUAGE=python uv run python -m mkdocs build --clean -f mkdocs.yml --strict
build-docs-js: build-prebuilt
TARGET_LANGUAGE=js uv run python -m mkdocs build --clean -f mkdocs.yml --strict
llms-text:
poetry run python -m _scripts.generate_llms_text docs/llms-full.txt
uv run python -m _scripts.generate_llms_text docs/llms-full.txt
install-vercel-deps:
dnf install -y python3.11
curl -sSL https://install.python-poetry.org | python3 -
poetry self update 1.8.5
# don't use vercel's python - it wasn't compiled with sqlite support, and it fails when installing ipython's kernel
poetry env use /usr/bin/python3.11
poetry install --with docs --with test --no-root
curl -sL "https://astral.sh/uv/install.sh" | bash -s
export PATH="${HOME}/.cargo/bin:${PATH}"
uv venv --python 3.11
uv sync --all-groups
tests:
# Run unit tests
poetry run pytest tests/unit_tests
uv run pytest tests/unit_tests
vercel-build-docs: install-vercel-deps
@@ -45,10 +40,10 @@ vercel-build-docs: install-vercel-deps
serve-clean-docs: clean-docs
poetry run python -m mkdocs serve -c -f mkdocs.yml --strict -w ../libs/langgraph
uv run python -m mkdocs serve -c -f mkdocs.yml --strict -w ../libs/langgraph
serve-docs: build-typedoc
poetry run python -m mkdocs serve -f mkdocs.yml -w ../libs/langgraph -w ../libs/checkpoint -w ../libs/sdk-py --dirty
serve-docs:
uv run python -m mkdocs serve -f mkdocs.yml -w ../libs/langgraph -w ../libs/checkpoint -w ../libs/sdk-py --dirty
clean-docs:
find ./docs -name "*.ipynb" -type f -delete
@@ -56,13 +51,13 @@ clean-docs:
## Run format against the project documentation.
format-docs:
poetry run ruff format docs
poetry run ruff check --fix docs
uv run ruff format docs
uv run ruff check --fix docs
# Check the docs for linting violations
lint-docs:
poetry run ruff format --check docs
poetry run ruff check docs
uv run ruff format --check docs
uv run ruff check docs
codespell:
./codespell_notebooks.sh .
+1 -1
View File
@@ -3,7 +3,7 @@
To setup requirements for building docs you can run:
```bash
poetry install --with test
uv sync --group test
```
## Serving documentation locally
-157
View File
@@ -1,157 +0,0 @@
"""Add typescript translation to a given markdown file."""
import argparse
import re
import requests
from langchain_anthropic import ChatAnthropic
URL = "https://gist.githubusercontent.com/eyurtsev/e7486731415463a9bc5b4682358859c8/raw/b5a5fda9c7e3387cfcb781f25082814d43675d50/gistfile1.txt"
response = requests.get(URL)
response.raise_for_status()
reference_snippets = response.text
model = ChatAnthropic(model="claude-3-5-sonnet-latest")
def _get_tqdm():
try:
from tqdm import tqdm
except ImportError:
# If not available return a simple identity function
def tqdm(iterable, *args, **kwargs):
return iterable
return tqdm
_tqdm = _get_tqdm()
opening_pattern = re.compile(r"^\s*```python(?:\s+.*)?\s*$")
closing_pattern = re.compile(r"^\s*```\s*$")
def extract_python_snippets(markdown: str) -> list[str]:
"""
Extract all python code blocks (including their fence lines) from the markdown content.
A python block is defined as any block that starts with a line containing an opening fence
with '```python' (optionally with extra parameters) and ends with a closing fence '```'.
"""
snippets = []
inside_block = False
current_snippet = []
for line in markdown.splitlines(keepends=True):
if not inside_block:
if opening_pattern.match(line):
inside_block = True
current_snippet = [line]
else:
current_snippet.append(line)
if closing_pattern.match(line):
inside_block = False
snippets.append("".join(current_snippet))
current_snippet = []
return snippets
def translate_snippet(python_snippet: str) -> str:
"""Translate a python code block into a TypeScript code block using Langchain.
The response is expected to be a properly fenced TypeScript code block (i.e.
starting with ```typescript and ending with ```).
"""
ai_message = model.invoke(
[
{
"role": "system",
"content": (
f"You have access to the following up-to-date example TypeScript code "
f"snippets that show examples of building with langgraph "
f"and langchain:\n\n{reference_snippets}\n\n"
"Use this context to translate the following Python code to equivalent "
"TypeScript. Ensure that your output is a valid fenced TypeScript "
"code block (i.e. starts with ```typescript and ends with ```)."
),
},
{
"role": "user",
"content": f"Translate this Python snippet to TypeScript:\n\n{python_snippet}",
},
]
)
# Use a regular expression to search for a TypeScript code block in the response.
pattern = r"```typescript\s*(.*?)\s*```"
match = re.search(pattern, ai_message.content, re.DOTALL)
if match:
# Reconstruct the code block with proper fences.
typescript_code = match.group(1).strip()
return f"```typescript\n{typescript_code}\n```"
else:
raise ValueError("No TypeScript code block found in the model's response.")
def insert_translations_into_markdown(
markdown: str, typescript_snippets: list[str]
) -> str:
"""Walks through the original markdown content and, after each
Python snippet block, inserts the corresponding translated TypeScript snippet.
It assumes that the ordering of the Python snippets
(from extract_python_snippets) matches the order they appear in the markdown.
"""
output_lines = []
lines = markdown.splitlines(keepends=True)
inside_block = False
snippet_index = 0
for line in lines:
output_lines.append(line)
if not inside_block and opening_pattern.match(line):
# We've encountered the start of a python code block.
inside_block = True
elif inside_block:
if closing_pattern.match(line):
# End of a python snippet block.
inside_block = False
if snippet_index < len(typescript_snippets):
# Insert an extra newline for clarity, then the translated TypeScript snippet.
output_lines.append("\n")
output_lines.append(typescript_snippets[snippet_index])
output_lines.append("\n")
snippet_index += 1
return "".join(output_lines)
def main(file_path: str) -> None:
# Read the markdown file.
with open(file_path, "r") as f:
markdown_content = f.read()
# 1. Extract all Python snippets.
python_snippets = extract_python_snippets(markdown_content)[:1]
# 2. Translate each Python snippet to TypeScript.
typescript_snippets = []
# Replace with .batch() for faster translation
for python_snippet in _tqdm(python_snippets):
ts_snippet = translate_snippet(python_snippet)
typescript_snippets.append(ts_snippet)
# 3. Insert the TypeScript translations after their respective Python snippets.
updated_markdown = insert_translations_into_markdown(
markdown_content, typescript_snippets
)
# Overwrite the original markdown file with the updated content.
with open(file_path, "w") as f:
f.write(updated_markdown)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Translate Python snippets in a markdown file to TypeScript and insert them after each Python snippet."
)
parser.add_argument("file_path", type=str, help="Path to the markdown file.")
args = parser.parse_args()
main(args.file_path)
+1 -1
View File
@@ -8,7 +8,7 @@ execute_notebook() {
file="$1"
echo "Starting execution of $file"
start_time=$(date +%s)
if ! output=$(time poetry run jupyter execute "$file" 2>&1); then
if ! output=$(time uv run jupyter execute "$file" 2>&1); then
end_time=$(date +%s)
execution_time=$((end_time - start_time))
echo "Error in $file. Execution time: $execution_time seconds"
+239 -26
View File
@@ -1,10 +1,18 @@
"""Experimental script to generate consolidated llms text from the docs."""
import asyncio
import glob
import os
import re
from typing import TypedDict, List, Optional
import yaml
from langchain.chat_models import init_chat_model
from langchain_core.rate_limiters import InMemoryRateLimiter
from mkdocs.structure.files import File
from mkdocs.structure.pages import Page
from pydantic import BaseModel, Field
from yaml import SafeLoader
from _scripts.notebook_hooks import _on_page_markdown_with_config
@@ -13,7 +21,49 @@ HERE = os.path.dirname(os.path.abspath(__file__))
SOURCE_DIR = os.path.abspath(os.path.join(os.path.dirname(HERE), "docs"))
def _make_llms_text(output_file: str) -> str:
async def convert_ipynb_to_md(file_path: str) -> Optional[str]:
"""Process a file (markdown or notebook) to markdown format.
Args:
file_path: Path to the file to process
Returns:
Processed markdown content if successful, None otherwise
"""
rel_path = os.path.relpath(file_path, SOURCE_DIR)
# Create File and Page objects to match mkdocs structure
file_obj = File(
path=rel_path, src_dir=SOURCE_DIR, dest_dir="", use_directory_urls=True
)
page = Page(
title="",
file=file_obj,
config={},
)
try:
# Read raw content
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
# Convert to markdown without logic to resolve API references
processed_content = _on_page_markdown_with_config(
content, page, add_api_references=False, remove_base64_images=True
)
# Remove self-closing img tags <img ... />
processed_content = re.sub(r"<img[^>]*/>", "", processed_content)
# Remove img tags with content <img ...>...</img>
processed_content = re.sub(
r"<img[^>]*>.*?</img>", "", processed_content, flags=re.DOTALL
)
return processed_content
except Exception as e:
print(f"Error processing file {file_path}: {e}")
return None
async def generate_full_llms_text(output_file: str) -> None:
"""Generate a consolidated text file from markdown/notebook files for LLM training.
Args:
@@ -21,11 +71,9 @@ def _make_llms_text(output_file: str) -> str:
"""
# Collect all markdown and notebook files
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/*.ipynb"), recursive=True)
)
# Add all concepts
all_files.extend(
glob.glob(os.path.join(SOURCE_DIR, "concepts/*.md"), recursive=True)
)
@@ -35,30 +83,14 @@ def _make_llms_text(output_file: str) -> str:
all_content = []
# Process each file
for file_path in all_files:
print(f"Processing {file_path}")
rel_path = os.path.relpath(file_path, SOURCE_DIR)
# Process files concurrently
tasks = [convert_ipynb_to_md(file_path) for file_path in all_files]
results = await asyncio.gather(*tasks)
# Create File and Page objects to match mkdocs structure
file_obj = File(
path=rel_path, src_dir=SOURCE_DIR, dest_dir="", use_directory_urls=True
)
page = Page(
title="",
file=file_obj,
config={},
)
# Read raw content
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
# Convert to markdown without logic to resolve API references
processed_content = _on_page_markdown_with_config(
content, page, add_api_references=False, remove_base64_images=True
)
# Combine results with file paths
for file_path, processed_content in zip(all_files, results):
if processed_content:
rel_path = os.path.relpath(file_path, SOURCE_DIR)
# Add file name
all_content.append(f"---\n{rel_path}\n---")
# Add content
@@ -69,6 +101,170 @@ def _make_llms_text(output_file: str) -> str:
f.write("\n\n".join(all_content))
def no_op_constructor(*args):
"""No-op"""
SafeLoader.add_multi_constructor(
"tag:yaml.org,2002:python/name",
no_op_constructor,
)
class NavItem(TypedDict):
title: str
url: str
hierarchy: tuple[str, ...]
description: str
def _flatten_nav(
nav: list[dict[str, str | list] | str], path: tuple[str, ...] = ()
) -> list[NavItem]:
flat: List[NavItem] = []
for item in nav:
if isinstance(item, dict):
for title, node in item.items():
new_path = path + (title,)
if isinstance(node, str):
# Leaf page
flat.append(
{
"title": title,
"url": node,
"hierarchy": new_path,
"description": "",
}
)
elif isinstance(node, list):
# Dive in, carrying along the updated path
flat.extend(_flatten_nav(node, new_path))
else:
raise TypeError(
f"Unexpected node type {type(node)} under {title!r}"
)
elif isinstance(item, str):
# Bare string entry → use itself as title, and as URL
new_path = path + (item,)
flat.append(
{"title": item, "url": item, "hierarchy": new_path, "description": ""}
)
else:
raise TypeError(f"Unexpected item type {type(item)} in nav")
return flat
class PageInfo(BaseModel):
title: str = Field(description="The title of the page")
description: str = Field(
description="A short description of the page no longer than 3 sentences "
"explaining the kind of content that can be found in the page."
)
async def process_nav_items(nav_items: list[NavItem]) -> list[NavItem]:
"""Open the contents of each nav item and come up with a better title and description."""
rate_limiter = InMemoryRateLimiter(requests_per_second=10)
model = init_chat_model("gpt-4o-mini", temperature=0.0, rate_limiter=rate_limiter)
model = model.with_structured_output(PageInfo)
async def process_single_item(item: NavItem) -> NavItem:
path = item["url"]
file_path = os.path.join(SOURCE_DIR, path)
# Process the file content (handles both markdown and notebooks)
if path.endswith(".ipynb"):
content = await convert_ipynb_to_md(file_path)
else:
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
if not content:
return item
# Generate a better title and description
response = await model.ainvoke(
[
{
"role": "system",
"content": "You are a technical documentation writer. "
"You are given a markdown page of documentation. "
"Please come up with an appropriate title and "
"description for the page. The description should "
"be a short summary of the page content that is "
"no longer than 3 sentences.",
},
{
"role": "user",
"content": "The markdown page is as follows:\n\n" + content,
},
]
)
return {
"title": response.title,
"url": item["url"],
"hierarchy": item["hierarchy"],
"description": response.description,
}
# Remove any items that start with http:// or https:// looking only for
# local file at this stages.
nav_items = [
item
for item in nav_items
if not item["url"].startswith(("http://", "https://"))
]
# Process items in parallel
tasks = [process_single_item(item) for item in nav_items]
new_nav_items = await asyncio.gather(*tasks)
return new_nav_items
async def generate_nav_links_text(
output_file: str, *, replace_links: bool = False
) -> None:
"""Generate llms.txt from mkdocs.yaml."""
# Get path to mkdocs.yaml relative to this script
script_dir = os.path.dirname(os.path.abspath(__file__))
mkdocs_path = os.path.join(os.path.dirname(script_dir), "mkdocs.yml")
# Load and parse yaml
with open(mkdocs_path, "r") as f:
config = yaml.safe_load(f)
# Extract nav section
nav = config.get("nav", [])
flattened = _flatten_nav(nav)
processed_nav = await process_nav_items(flattened)
with open(output_file, "w") as f:
current_section = None
for item in processed_nav:
# Get the top-level section (first item in hierarchy)
section = item["hierarchy"][0]
if section not in {"Guides", "Examples", "Resources"}:
continue
# If we're starting a new section, add a heading
if section != current_section:
f.write(f"\n# {section}\n\n")
current_section = section
title = item["title"]
# Process URL based on replace_links flag
url = item["url"]
if replace_links:
# Remove .md extension and ensure single trailing slash
url = url.removesuffix(".md")
url = url.removesuffix(".ipynb")
url = url.rstrip("/") + "/"
url = f"https://langchain-ai.github.io/langgraph/{url}"
f.write(f"- [{title}]({url}): {item['description']}\n")
if __name__ == "__main__":
import argparse
@@ -78,6 +274,23 @@ if __name__ == "__main__":
)
)
parser.add_argument("output_file", help="Path to output the consolidated text file")
parser.add_argument(
"--link-only",
action="store_true",
help="Only include link references in the output",
)
parser.add_argument(
"--replace-links",
action="store_true",
help="Replace markdown links with full URLs in the output",
)
args = parser.parse_args()
_make_llms_text(args.output_file)
if args.link_only:
coro = generate_nav_links_text(
args.output_file, replace_links=args.replace_links
)
else:
coro = generate_full_llms_text(args.output_file)
asyncio.run(coro)
+181
View File
@@ -0,0 +1,181 @@
"""Logic to identify and transform cross-reference links in markdown files.
This module allows supporting custom markdown syntax for "autolinks". These are links
that will be transformed based on the current scope context, such as "global", "python",
or "js" into an appropriate markdown link format.
For example,
```markdown
@[StateGraph]
```
May be transformed into:
```markdown
[StateGraph](some_path/api-reference/state-graph.md)
```
The transformation value depends on the scope in which the link is used.
"""
import logging
import re
from typing import Optional
from _scripts.link_map import SCOPE_LINK_MAPS
logger = logging.getLogger(__name__)
def _transform_link(
link_name: str, scope: str, file_path: str, line_number: int, custom_title: Optional[str] = None
) -> Optional[str]:
"""Transform a cross-reference link based on the current scope.
Args:
link_name: The name of the link to transform (e.g., "StateGraph").
scope: The current scope context ("global", "python", "js", etc.).
file_path: The file path for error reporting.
line_number: The line number for error reporting.
custom_title: Optional custom title for the link. If None, uses link_name.
Returns:
A formatted markdown link if the link is found in the scope mapping,
None otherwise.
Example:
>>> _transform_link("StateGraph", "python", "file.md", 5)
"[StateGraph](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph)"
>>> _transform_link("StateGraph", "python", "file.md", 5, "Custom Title")
"[Custom Title](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph)"
>>> _transform_link("unknown-link", "python", "file.md", 5)
None
"""
if scope == "global":
# Special scope that is composed of both Python and JS links
# For now, we will substitute in the python scope!
# But we need to add support for handling both scopes.
scope = "python"
logger.error(
"Encountered unhandled 'global' scope. Defaulting to 'python'."
"In file: %s, line %d, link_name: %s",
file_path,
line_number,
link_name,
)
link_map = SCOPE_LINK_MAPS.get(scope, {})
url = link_map.get(link_name)
if url:
title = custom_title if custom_title is not None else link_name
return f"[{title}]({url})"
else:
# Log error with file location information
logger.info(
# Using %s
"Link '%s' not found in scope '%s'. "
"In file: %s, line %d. Available links in scope: %s",
link_name,
scope,
file_path,
line_number,
list(link_map.keys() if link_map else []),
)
return None
CONDITIONAL_FENCE_PATTERN = re.compile(
r"""
^ # Start of line
(?P<indent>[ \t]*) # Optional indentation (spaces or tabs)
::: # Literal fence marker
(?P<language>\w+)? # Optional language identifier (named group: language)
\s* # Optional trailing whitespace
$ # End of line
""",
re.VERBOSE,
)
CROSS_REFERENCE_PATTERN = re.compile(
r"""
(?: # Non-capturing group for two possible formats:
@\[ # @ symbol followed by opening bracket for title
(?P<title>[^\]]+) # Custom title - one or more non-bracket characters
\] # Closing bracket for title
\[ # Opening bracket for link name
(?P<link_name_with_title>[^\]]+) # Link name - one or more non-bracket characters
\] # Closing bracket for link name
| # OR
@\[ # @ symbol followed by opening bracket
(?P<link_name>[^\]]+) # Link name - one or more non-bracket characters
\] # Closing bracket
)
""",
re.VERBOSE,
)
def _replace_autolinks(markdown: str, file_path: str, *, default_scope: str = "python") -> str:
"""Preprocess markdown lines to handle @[links] with conditional fence scopes.
This function processes markdown content to transform @[link_name] references
based on the current conditional fence scope. Conditional fences use the
syntax :::language to define scope boundaries.
Args:
markdown: The markdown content to process.
file_path: The file path for error reporting.
default_scope: The default scope to use if no scope is matched.
Returns:
Processed markdown content with @[references] transformed to proper
markdown links or left unchanged if not found.
Example:
Input:
"@[StateGraph]\\n:::python\\n@[Command]\\n:::\\n"
Output:
"[StateGraph](url)\\n:::python\\n[Command](url)\\n:::\\n"
"""
# Track the current scope context
current_scope = default_scope
lines = markdown.splitlines(keepends=True)
processed_lines = []
for line_number, line in enumerate(lines, 1):
line_stripped = line.strip()
# Check if this line defines a new conditional fence scope
fence_match = CONDITIONAL_FENCE_PATTERN.match(line_stripped)
if fence_match:
language = fence_match.group("language")
# Set scope to the specified language, or reset to global if no language
current_scope = language.lower() if language else default_scope
processed_lines.append(line)
continue
# Transform all @[link_name] references in this line based on current scope
def replace_cross_reference(match: re.Match[str]) -> str:
"""Replace a single @[link_name] with the scoped equivalent."""
# Check if this is the @[title][ref] format or @[ref] format
title = match.group("title")
if title is not None:
# This is @[title][ref] format
link_name = match.group("link_name_with_title")
custom_title = title
else:
# This is @[ref] format
link_name = match.group("link_name")
custom_title = None
transformed = _transform_link(
link_name, current_scope, file_path, line_number, custom_title
)
return transformed if transformed is not None else match.group(0)
transformed_line = CROSS_REFERENCE_PATTERN.sub(replace_cross_reference, line)
processed_lines.append(transformed_line)
return "".join(processed_lines)
@@ -0,0 +1,236 @@
"""Translate Python markdown to TypeScript and/or consolidate Python-JS markdown into a single document."""
import argparse
import requests
from langchain_anthropic import ChatAnthropic
from textwrap import dedent
# Load reference TypeScript snippets
URL = "https://gist.githubusercontent.com/dqbd/b35d49e2ceec80e654fe1c5ab61ec477/raw/f4768aeedb67628190a4e06d063a938afc8e7672/snippets.md"
response = requests.get(URL)
response.raise_for_status()
reference_snippets = response.text
# Initialize model
model = ChatAnthropic(model="claude-sonnet-4-0", max_tokens=64_000)
FLUENT_INTERFACE_PROMPT = (
"CRITICAL: Always use method chaining (fluent interface) for StateGraph operations in TypeScript. "
"Never create separate variables for the graph builder or call methods individually. "
"The fluent interface provides better type safety and is the preferred pattern.\n\n"
"CORRECT examples with fluent interface:\n"
+ dedent(
"""
```typescript
const graph = new StateGraph(MyState)
.addNode('node1', node1)
.addNode('node2', node2)
.addEdge(START, 'node1')
.addEdge('node1', 'node2')
.addEdge('node2', END)
.compile()
```
```typescript
const graph = new StateGraph(MyState)
.addNode('chatbot', chatbot)
.addEdge(START, 'chatbot')
.addEdge('chatbot', END)
.compile()
```
```typescript
const graph = new StateGraph(MyState)
.addNode('chatbot', chatbot)
.addEdge(START, 'chatbot')
.addEdge('chatbot', END)
.compile()
```
"""
)
+ "\n"
+ "INCORRECT examples to avoid:\n"
+ dedent(
"""
```typescript
// WRONG: Creating separate builder variable
const graphBuilder = new StateGraph(MyState)
graphBuilder.addNode('node1', node1)
graphBuilder.addEdge(START, 'node1')
const graph = graphBuilder.compile()
```
```typescript
// WRONG: Using Python-style method names
const workflow = new StateGraph(MyState)
workflow.add_node('node1', node1)
workflow.add_edge(START, 'node1')
const graph = workflow.compile()
```
```typescript
// WRONG: Calling methods individually
const graphBuilder = new StateGraph(MyState)
graphBuilder.addNode('chatbot', chatbot)
graphBuilder.addEdge(START, 'chatbot')
graphBuilder.addEdge('chatbot', END)
const graph = graphBuilder.compile()
```
"""
)
+ "\n"
+ "Key rules:\n"
+ "- Always chain methods directly on the StateGraph constructor\n"
+ "- Use camelCase method names (addNode, addEdge, not add_node, add_edge)\n"
+ "- Always end with .compile()\n"
+ "- Never store the builder in a separate variable\n"
)
TRANSLATION_PROMPT = (
"You are a helpful assistant that translates Python-based technical "
"documentation written in Markdown to equivalent TypeScript-based documentation. "
"The input is a Markdown file written in mkdocs format. It contains "
"Python code snippets embedded in prose. "
"Your task is to rewrite the content by translating the Python code to "
"idiomatic TypeScript, using the provided TypeScript reference snippets "
"to ensure accurate and consistent usage (e.g., correct imports, function "
"names, and patterns). "
"Remove the original Python code and replace it with the corresponding "
"TypeScript version. "
"Do not alter the surrounding prose unless a change is necessary to "
"reflect differences between Python and TypeScript. "
"Preserve the structure and formatting of the original Markdown document. "
"Do not make stylistic or structural changes unless they directly support "
"the translation. "
"Use the reference TypeScript snippets as guidance whenever possible to "
"maintain alignment with existing conventions.\n\n"
"IMPORTANT REQUIREMENTS:\n"
"- Use Zod for state definition for StateGraph. Avoid using Annotation since it will be deprecated in the future.\n"
"- ALWAYS use fluent interface (method chaining) for StateGraph operations - this is CRITICAL\n"
"- Never create separate variables for graph builders\n"
"- Always chain methods directly on the StateGraph constructor and end with .compile()\n\n"
f"{FLUENT_INTERFACE_PROMPT}\n\n"
f"Here are the reference TypeScript snippets:\n\n{reference_snippets}\n\n"
)
CONSOLIDATION_PROMPT = (
"You are a helpful assistant that consolidates parallel Python and JavaScript (TypeScript) technical documentation "
"written in Markdown into a single unified Markdown document. "
"The input consists of two documents: the first is for Python users, and the second is for JavaScript/TypeScript users. "
"Your task is to merge these into one Markdown file using language-specific fenced blocks to separate the content where needed. "
"Use the following syntax to distinguish content for each language:\n\n"
":::python\n"
"# Python-specific content\n"
":::\n\n"
":::js\n"
"# JavaScript/TypeScript-specific content\n"
":::\n\n"
"Follow these consolidation rules:\n"
"- When content (prose or code) is the same or nearly identical in both versions, include it only once—outside of any fenced block.\n"
"- When content differs between the Python and JS versions, wrap each version in its corresponding fenced block.\n"
"- Prefer **paragraph-level separation** of language-specific content. Do not combine Python and JS snippets or terminology in the same sentence or paragraph using conditional phrases.\n"
" For example, avoid inline constructs like:\n"
" `The :::python add_messages ::: :::js reducer ::: function...`\n"
" Instead, write two distinct paragraphs:\n\n"
" :::python\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\n"
" :::js\n"
" The `reducer` function in our `StateAnnotation` will append the LLM's response messages to whatever messages are already in the state.\n"
" :::\n\n"
"- Preserve the overall structure, ordering, and formatting of the original Markdown documents.\n"
"- Do not rephrase or unify content unless it is logically and semantically identical.\n"
"- Use the fenced blocks for both prose and code as needed, and ensure output is clean, readable Markdown suitable for tools that parse these directives.\n"
"Your goal is to produce a cleanly merged documentation file that serves both Python and JavaScript users without redundancy, while maximizing clarity and separation of language-specific details."
)
def translate_python_to_ts(markdown_content: str) -> str:
response = model.invoke(
[
{
"role": "system",
"content": TRANSLATION_PROMPT,
"cache_control": {"type": "ephemeral"},
},
{"role": "user", "content": markdown_content},
]
)
return response.content
def consolidate_python_and_ts(combined_content: str) -> str:
response = model.invoke(
[
{
"role": "system",
"content": CONSOLIDATION_PROMPT,
"cache_control": {"type": "ephemeral"},
},
{"role": "user", "content": combined_content},
]
)
return response.content
def main(file_path: str, translate_only: bool, consolidate_only: bool) -> None:
with open(file_path, "r", encoding="utf-8") as f:
markdown_content = f.read()
if translate_only:
translated = translate_python_to_ts(markdown_content)
output_path = file_path.replace(".md", ".translated.md")
with open(output_path, "w", encoding="utf-8") as f:
f.write(translated)
print(f"Translated JS/TS version written to: {output_path}")
elif consolidate_only:
consolidated = consolidate_python_and_ts(markdown_content)
with open(file_path, "w", encoding="utf-8") as f:
f.write(consolidated)
print(f"Consolidated content written to: {file_path}")
else:
# Default behavior: translate first, then consolidate both
translated = translate_python_to_ts(markdown_content)
combined = f"{markdown_content.strip()}\n\n\n{translated.strip()}"
consolidated = consolidate_python_and_ts(combined)
with open(file_path, "w", encoding="utf-8") as f:
f.write(consolidated)
print(f"Translated and consolidated content written to: {file_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description=(
"Translate Python markdown to TypeScript and/or consolidate "
"Python-JS markdown into one file."
)
)
parser.add_argument("file_path", type=str, help="Path to the markdown file.")
parser.add_argument(
"--translate-only",
action="store_true",
help="Only generate the JS translation.",
)
parser.add_argument(
"--consolidate-only",
action="store_true",
help="Only consolidate pre-paired Python and JS content.",
)
args = parser.parse_args()
if args.translate_only and args.consolidate_only:
raise ValueError(
"Cannot use both --translate-only and --consolidate-only at the same time."
)
main(
args.file_path,
translate_only=args.translate_only,
consolidate_only=args.consolidate_only,
)
@@ -0,0 +1,6 @@
.prettierrc
.eslint.config.mjs
package.json
README.md
tsconfig.json
yarn.lock
@@ -0,0 +1,19 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"vueIndentScriptAndStyle": false,
"endOfLine": "lf"
}
@@ -0,0 +1 @@
# \_codeblocks
@@ -0,0 +1,14 @@
import js from "@eslint/js";
import globals from "globals";
import tseslint from "typescript-eslint";
import { defineConfig } from "eslint/config";
export default defineConfig([
{
files: ["**/*.{js,mjs,cjs,ts,mts,cts}"],
plugins: { js },
extends: ["js/recommended"],
languageOptions: { globals: globals.browser },
},
tseslint.configs.recommended,
]);
@@ -0,0 +1,27 @@
{
"name": "_codeblocks",
"packageManager": "yarn@4.6.0",
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:fix": "prettier --write . --fix"
},
"dependencies": {
"@langchain/anthropic": "^0.3.24",
"@langchain/core": "^0.3.66",
"@langchain/langgraph": "^0.3.11",
"@langchain/langgraph-api": "^0.0.52",
"@langchain/langgraph-sdk": "^0.0.102",
"@langchain/openai": "^0.6.3",
"zod": "^4.0.10"
},
"devDependencies": {
"@eslint/js": "^9.32.0",
"eslint": "^9.32.0",
"globals": "^16.3.0",
"jiti": "^2.5.1",
"typescript": "^5.8.3",
"typescript-eslint": "^8.38.0"
}
}
@@ -0,0 +1,114 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "esnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "libReplacement": true, /* Enable lib replacement. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "nodenext", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "noUncheckedSideEffectImports": true, /* Check side effect imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
// "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": false, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
""
}
}
File diff suppressed because it is too large. Load diff
+150
View File
@@ -0,0 +1,150 @@
#!/usr/bin/env python
"""Extracts typescript code blocks from a markdown file."""
import argparse
import json
import re
import os
from typing import List, TypedDict, Literal
class CodeBlock(TypedDict):
"""A code block extracted from a markdown file."""
starting_line: int
"""The line number where the code block starts in the source file"""
ending_line: int
"""The line number where the code block ends in the source file"""
indentation: int
"""Number of spaces/tabs used for indentation of the code block"""
source_file: str
"""Path to the markdown file containing this code block"""
frontmatter: str
"""Any metadata or frontmatter specified after the opening code fence"""
code: str
"""The actual code content within the code block"""
language: str
"""The language of the code block (e.g. typescript, javascript)"""
def extract_code_blocks(markdown_content: str, source_file: str) -> List[CodeBlock]:
"""Extracts code blocks from a markdown file.
Args:
markdown_content: The content of the markdown file.
source_file: The path to the markdown file.
Returns:
A list of TypedDicts, where each dict represents a code block.
"""
# Regex to find code blocks with specified languages, capturing indentation
# and frontmatter.
pattern = re.compile(
r"^(?P<indentation>\s*)```(?P<language>typescript|javascript|ts|js)(?P<frontmatter>[^\n]*)\n(?P<code>.*?)\n^(?P=indentation)```\s*$",
re.DOTALL | re.MULTILINE,
)
code_blocks: List[CodeBlock] = []
for match in pattern.finditer(markdown_content):
start_pos = match.start()
# Calculate line numbers
starting_line = markdown_content.count("\n", 0, start_pos) + 1
ending_line = starting_line + match.group(0).count("\n")
indentation_str = match.group("indentation")
code_block: CodeBlock = {
"starting_line": starting_line,
"ending_line": ending_line,
"indentation": len(indentation_str),
"source_file": source_file,
"frontmatter": match.group("frontmatter").strip(),
"code": match.group("code"),
"language": match.group("language"),
}
code_blocks.append(code_block)
return code_blocks
def dump_code_blocks(input_file: str, output_file: str, format: Literal["json", "inline"]) -> None:
"""Function to extract and save code blocks from a markdown file.
Args:
input_file: Path to the input markdown file.
output_file: Path to the output JSON file for the extracted code blocks.
format: Output format - either "json" or "inline"
"""
with open(input_file, "r", encoding="utf-8") as f:
markdown_content = f.read()
extracted_code = extract_code_blocks(markdown_content, input_file)
if len(extracted_code) == 0:
print(f"No code blocks found in {input_file}")
return
if format == "json":
with open(output_file, "w", encoding="utf-8") as f:
json.dump(extracted_code, f, indent=2)
elif format == "inline":
with open(output_file, "w", encoding="utf-8") as f:
for code_block in extracted_code:
f.write(f"// {json.dumps({k:v for k,v in code_block.items() if k != 'code'})}\n")
f.write("\n")
f.write(code_block["code"])
f.write("\n")
print(f"Extracted {len(extracted_code)} code blocks from {input_file} to {output_file}")
def main(input_path: str, output_path: str, format: Literal["json", "inline"]) -> None:
"""Main function to extract code blocks from a markdown file.
Args:
input_file: Path to the input markdown file.
output_file: Path to the output JSON file for the extracted code blocks.
format: Output format - either "json" or "inline"
"""
# Check if input path is a directory
if os.path.isdir(input_path):
if os.path.isfile(output_path):
raise ValueError("If input_path is a directory, output_path must also be a directory")
if not os.path.isdir(output_path):
os.makedirs(output_path, exist_ok=True)
# Process each markdown file in the directory recursively
for root, _, files in os.walk(input_path):
for filename in files:
if filename.endswith(".md"):
# Get relative path to maintain directory structure
rel_path = os.path.relpath(root, input_path)
input_file = os.path.join(root, filename)
# Create output directory if it doesn't exist
output_dir = os.path.join(output_path, rel_path)
os.makedirs(output_dir, exist_ok=True)
output_file = os.path.join(output_dir, filename.replace(".md", ".ts"))
dump_code_blocks(input_file, output_file, format)
else:
# Process single file
dump_code_blocks(input_path, output_path, format)
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Extract typescript code blocks from a markdown file."
)
parser.add_argument(
"input_file",
help="Path to the input markdown file.",
)
parser.add_argument(
"output_file",
help="Path to the output JSON file for the extracted code blocks.",
)
parser.add_argument(
"--format",
choices=["json", "inline"],
default="json",
help="Output format - either 'json' or 'inline'",
)
args = parser.parse_args()
main(args.input_file, args.output_file, args.format)
+127
View File
@@ -0,0 +1,127 @@
"""Link mapping for cross-reference resolution across different scopes.
This module provides link mappings for different language/framework scopes
to resolve @[link_name] references to actual URLs.
"""
# Python-specific link mappings
PYTHON_LINK_MAP = {
"StateGraph": "reference/graphs/#langgraph.graph.StateGraph",
"add_conditional_edges": "reference/graphs/#langgraph.graph.state.StateGraph.add_conditional_edges",
"add_edge": "reference/graphs/#langgraph.graph.state.StateGraph.add_edge",
"add_node": "reference/graphs/#langgraph.graph.state.StateGraph.add_node",
"add_messages": "reference/graphs/#langgraph.graph.message.add_messages",
"ToolNode": "reference/agents/#langgraph.prebuilt.tool_node.ToolNode",
"CompiledStateGraph.astream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.astream",
"Pregel.astream": "reference/pregel/#langgraph.pregel.Pregel.astream",
"AsyncPostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.aio.AsyncPostgresSaver",
"AsyncSqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.aio.AsyncSqliteSaver",
"BaseCheckpointSaver": "reference/checkpoints/#langgraph.checkpoint.base.BaseCheckpointSaver",
"BaseStore": "reference/store/#langgraph.store.base.BaseStore",
"BaseStore.put": "reference/store/#langgraph.store.base.BaseStore.put",
"BinaryOperatorAggregate": "reference/pregel/#langgraph.pregel.Pregel--advanced-channels-context-and-binaryoperatoraggregate",
"CipherProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.CipherProtocol",
"client.runs.stream": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.stream",
"client.runs.wait": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.RunsClient.wait",
"client.threads.get_history": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.ThreadsClient.get_history",
"client.threads.update_state": "cloud/reference/sdk/python_sdk_ref/#langgraph_sdk.client.ThreadsClient.update_state",
"Command": "reference/types/#langgraph.types.Command",
"CompiledStateGraph": "reference/graphs/#langgraph.graph.state.CompiledStateGraph",
"create_react_agent": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
"create_supervisor": "reference/supervisor/#langgraph_supervisor.supervisor.create_supervisor",
"EncryptedSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer",
"entrypoint.final": "reference/func/#langgraph.func.entrypoint.final",
"entrypoint": "reference/func/#langgraph.func.entrypoint",
"from_pycryptodome_aes": "reference/checkpoints/#langgraph.checkpoint.serde.encrypted.EncryptedSerializer.from_pycryptodome_aes",
"get_state_history": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.get_state_history",
"get_stream_writer": "reference/config/#langgraph.config.get_stream_writer",
"HumanInterrupt": "reference/prebuilt/#langgraph.prebuilt.interrupt.HumanInterrupt",
"InjectedState": "reference/agents/#langgraph.prebuilt.tool_node.InjectedState",
"InMemorySaver": "reference/checkpoints/#langgraph.checkpoint.memory.InMemorySaver",
"interrupt": "reference/types/#langgraph.types.Interrupt",
"CompiledStateGraph.invoke": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.invoke",
"JsonPlusSerializer": "reference/checkpoints/#langgraph.checkpoint.serde.jsonplus.JsonPlusSerializer",
"langgraph.json": "cloud/reference/cli/#configuration-file",
"LastValue": "reference/channels/#langgraph.channels.LastValue",
"PostgresSaver": "reference/checkpoints/#langgraph.checkpoint.postgres.PostgresSaver",
"Pregel": "reference/pregel/",
"Pregel.stream": "reference/pregel/#langgraph.pregel.Pregel.stream",
"pre_model_hook": "reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent",
"protocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
"Send": "reference/types/#langgraph.types.Send",
"SerializerProtocol": "reference/checkpoints/#langgraph.checkpoint.serde.base.SerializerProtocol",
"SqliteSaver": "reference/checkpoints/#langgraph.checkpoint.sqlite.SqliteSaver",
"START": "reference/constants/#langgraph.constants.START",
"CompiledStateGraph.stream": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.stream",
"task": "reference/func/#langgraph.func.task",
"Topic": "reference/channels/#langgraph.channels.Topic",
"update_state": "reference/graphs/#langgraph.graph.state.CompiledStateGraph.update_state",
}
# JavaScript-specific link mappings
JS_LINK_MAP = {
"Auth": "reference/classes/sdk_auth.Auth.html",
"StateGraph": "reference/classes/langgraph.StateGraph.html",
"add_conditional_edges": "/reference/classes/langgraph.StateGraph.html#addConditionalEdges",
"add_edge": "reference/classes/langgraph.StateGraph.html#addEdge",
"add_node": "reference/classes/langgraph.StateGraph.html#addNode",
"add_messages": "reference/modules/langgraph.html#addMessages",
"ToolNode": "reference/classes/langgraph_prebuilt.ToolNode.html",
"BaseCheckpointSaver": "reference/classes/checkpoint.BaseCheckpointSaver.html",
"BaseStore": "reference/classes/checkpoint.BaseStore.html",
"BaseStore.put": "reference/classes/checkpoint.BaseStore.html#put",
"BinaryOperatorAggregate": "reference/classes/langgraph.BinaryOperatorAggregate.html",
"client.runs.stream": "reference/classes/sdk_client.RunsClient.html#stream",
"client.runs.wait": "reference/classes/sdk_client.RunsClient.html#wait",
"client.threads.get_history": "reference/classes/sdk_client.ThreadsClient.html#getHistory",
"client.threads.update_state": "reference/classes/sdk_client.ThreadsClient.html#updateState",
"Command": "reference/classes/langgraph.Command.html",
"CompiledStateGraph": "reference/classes/langgraph.CompiledStateGraph.html",
"create_react_agent": "reference/functions/langgraph_prebuilt.createReactAgent.html",
"create_supervisor": "reference/functions/langgraph_supervisor.createSupervisor.html",
"entrypoint.final": "reference/functions/langgraph.entrypoint.html#final",
"entrypoint": "reference/functions/langgraph.entrypoint.html",
"getContextVariable": "https://v03.api.js.langchain.com/functions/_langchain_core.context.getContextVariable.html",
"get_state_history": "reference/classes/langgraph.CompiledStateGraph.html#getStateHistory",
"HumanInterrupt": "reference/interfaces/langgraph_prebuilt.HumanInterrupt.html",
"interrupt": "reference/functions/langgraph.interrupt-2.html",
"CompiledStateGraph.invoke": "reference/classes/langgraph.CompiledStateGraph.html#invoke",
"langgraph.json": "cloud/reference/cli/#configuration-file",
"MemorySaver": "reference/classes/checkpoint.MemorySaver.html",
"messagesStateReducer": "reference/functions/langgraph.messagesStateReducer.html",
"PostgresSaver": "reference/classes/checkpoint_postgres.PostgresSaver.html",
"Pregel": "reference/classes/langgraph.Pregel.html",
"Pregel.stream": "reference/classes/langgraph.Pregel.html#stream",
"pre_model_hook": "reference/functions/langgraph_prebuilt.createReactAgent.html",
"protocol": "reference/interfaces/checkpoint.SerializerProtocol.html",
"Send": "reference/classes/langgraph.Send.html",
"SerializerProtocol": "reference/interfaces/checkpoint.SerializerProtocol.html",
"SqliteSaver": "reference/classes/checkpoint_sqlite.SqliteSaver.html",
"START": "reference/variables/langgraph.START.html",
"CompiledStateGraph.stream": "reference/classes/langgraph.CompiledStateGraph.html#stream",
"task": "reference/functions/langgraph.task.html",
## TODO (hntrl): export Topic from langgraphjs
# "Topic": "reference/classes/langgraph_channels.Topic.html",
"update_state": "reference/classes/langgraph.CompiledStateGraph.html#updateState",
}
# TODO: Allow updating these to localhost for local development
PY_REFERENCE_HOST = "https://langchain-ai.github.io/langgraph/"
JS_REFERENCE_HOST = "https://langchain-ai.github.io/langgraphjs/"
for key, value in PYTHON_LINK_MAP.items():
# Ensure the link is absolute
if not value.startswith("http"):
PYTHON_LINK_MAP[key] = f"{PY_REFERENCE_HOST}{value}"
for key, value in JS_LINK_MAP.items():
# Ensure the link is absolute
if not value.startswith("http"):
JS_LINK_MAP[key] = f"{JS_REFERENCE_HOST}{value}"
# Global scope is assembled from the Python and JS mappings
# Combined mapping by scope
SCOPE_LINK_MAPS = {
"python": PYTHON_LINK_MAP,
"js": JS_LINK_MAP,
}
+345 -54
View File
@@ -1,13 +1,22 @@
"""mkdocs hooks for adding custom logic to documentation pipeline.
Lifecycle events: https://www.mkdocs.org/dev-guide/plugins/#events
"""
import json
import logging
import os
import posixpath
import re
from typing import Any, Dict
from bs4 import BeautifulSoup
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.structure.files import Files, File
from mkdocs.structure.pages import Page
from _scripts.generate_api_reference_links import update_markdown_with_imports
from _scripts.handle_auto_links import _replace_autolinks
from _scripts.notebook_convert import convert_notebook
logger = logging.getLogger(__name__)
@@ -26,64 +35,72 @@ REDIRECT_MAP = {
"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",
"how-tos/state-reducers.ipynb": "how-tos/graph-api.md#define-and-update-state",
"how-tos/sequence.ipynb": "how-tos/graph-api.md#create-a-sequence-of-steps",
"how-tos/branching.ipynb": "how-tos/graph-api.md#create-branches",
"how-tos/recursion-limit.ipynb": "how-tos/graph-api.md#create-and-control-loops",
"how-tos/visualization.ipynb": "how-tos/graph-api.md#visualize-your-graph",
"how-tos/input_output_schema.ipynb": "how-tos/graph-api.md#define-input-and-output-schemas",
"how-tos/pass_private_state.ipynb": "how-tos/graph-api.md#pass-private-state-between-nodes",
"how-tos/state-model.ipynb": "how-tos/graph-api.md#use-pydantic-models-for-graph-state",
"how-tos/map-reduce.ipynb": "how-tos/graph-api.md#map-reduce-and-the-send-api",
"how-tos/command.ipynb": "how-tos/graph-api.md#combine-control-flow-and-state-updates-with-command",
"how-tos/configuration.ipynb": "how-tos/graph-api.md#add-runtime-configuration",
"how-tos/node-retries.ipynb": "how-tos/graph-api.md#add-retry-policies",
"how-tos/return-when-recursion-limit-hits.ipynb": "how-tos/graph-api.md#impose-a-recursion-limit",
"how-tos/async.ipynb": "how-tos/graph-api.md#async",
# 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",
"how-tos/memory/manage-conversation-history.ipynb": "how-tos/memory/add-memory.md",
"how-tos/memory/delete-messages.ipynb": "how-tos/memory/add-memory.md#delete-messages",
"how-tos/memory/add-summary-conversation-history.ipynb": "how-tos/memory/add-memory.md#summarize-messages",
"how-tos/memory.ipynb": "how-tos/memory/add-memory.md",
"agents/memory.ipynb": "how-tos/memory/add-memory.md",
# 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",
"how-tos/subgraph-transform-state.ipynb": "how-tos/subgraph.md#different-state-schemas",
"how-tos/subgraphs-manage-state.ipynb": "how-tos/subgraph.md#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",
"how-tos/persistence_postgres.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/persistence_mongodb.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/persistence_redis.ipynb": "how-tos/memory/add-memory.md#use-in-production",
"how-tos/subgraph-persistence.ipynb": "how-tos/memory/add-memory.md#use-with-subgraphs",
"how-tos/cross-thread-persistence.ipynb": "how-tos/memory/add-memory.md#add-long-term-memory",
"cloud/how-tos/copy_threads": "cloud/how-tos/use_threads",
"cloud/how-tos/check-thread-status": "cloud/how-tos/use_threads",
"cloud/concepts/threads.md": "concepts/persistence.md#threads",
"how-tos/persistence.ipynb": "how-tos/memory/add-memory.md",
# 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",
"agents/tools.md": "how-tos/tool-calling.md",
# 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",
"how-tos/agent-handoffs.ipynb": "how-tos/multi_agent.md#handoffs",
"how-tos/multi-agent-network.ipynb": "how-tos/multi_agent.md#use-in-a-multi-agent-system",
"how-tos/multi-agent-multi-turn-convo.ipynb": "how-tos/multi_agent.md#multi-turn-conversation",
# cloud redirects
"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/how-tos/human_in_the_loop_edit_state.md": "cloud/how-tos/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_user_input.md": "cloud/how-tos/add-human-in-the-loop.md",
"concepts/platform_architecture.md": "concepts/langgraph_cloud#architecture",
# 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
"cloud/how-tos/stream_values.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_updates.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_messages.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_events.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_debug.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/how-tos/stream_multiple.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/concepts/streaming.md": "concepts/streaming.md",
"agents/streaming.md": "how-tos/streaming.md",
# prebuilt 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",
@@ -92,10 +109,103 @@ REDIRECT_MAP = {
"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",
"agents/deployment.md": "tutorials/langgraph-platform/local-server.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"
"concepts/self_hosted.md": "concepts/langgraph_self_hosted_data_plane.md",
"tutorials/deployment.md": "concepts/deployment_options.md",
# assistant redirects
"cloud/how-tos/assistant_versioning.md": "cloud/how-tos/configuration_cloud.md",
"cloud/concepts/runs.md": "concepts/assistants.md#execution",
# hitl redirects
"how-tos/wait-user-input-functional.ipynb": "how-tos/use-functional-api.md",
"how-tos/review-tool-calls-functional.ipynb": "how-tos/use-functional-api.md",
"how-tos/create-react-agent-hitl.ipynb": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"agents/human-in-the-loop.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/dynamic_breakpoints.ipynb": "how-tos/human_in_the_loop/breakpoints.md",
"concepts/breakpoints.md": "concepts/human_in_the_loop.md",
"how-tos/human_in_the_loop/breakpoints.md": "how-tos/human_in_the_loop/add-human-in-the-loop.md",
"cloud/how-tos/human_in_the_loop_breakpoint.md": "cloud/how-tos/add-human-in-the-loop.md",
"how-tos/human_in_the_loop/edit-graph-state.ipynb": "how-tos/human_in_the_loop/time-travel.md",
# LGP mintlify migration redirects
"tutorials/auth/getting_started.md": "https://docs.langchain.com/langgraph-platform/auth",
"tutorials/auth/resource_auth.md": "https://docs.langchain.com/langgraph-platform/resource-auth",
"tutorials/auth/add_auth_server.md": "https://docs.langchain.com/langgraph-platform/add-auth-server",
"how-tos/use-remote-graph.md": "https://docs.langchain.com/langgraph-platform/use-remote-graph",
"how-tos/autogen-integration.md": "https://docs.langchain.com/langgraph-platform/autogen-integration",
"cloud/how-tos/use_stream_react.md": "https://docs.langchain.com/langgraph-platform/use-stream-react",
"cloud/how-tos/generative_ui_react.md": "https://docs.langchain.com/langgraph-platform/generative-ui-react",
"concepts/langgraph_platform.md": "https://docs.langchain.com/langgraph-platform/index",
"concepts/langgraph_components.md": "https://docs.langchain.com/langgraph-platform/components",
"concepts/langgraph_server.md": "https://docs.langchain.com/langgraph-platform/langgraph-server",
"concepts/langgraph_data_plane.md": "https://docs.langchain.com/langgraph-platform/data-plane",
"concepts/langgraph_control_plane.md": "https://docs.langchain.com/langgraph-platform/control-plane",
"concepts/langgraph_cli.md": "https://docs.langchain.com/langgraph-platform/langgraph-cli",
"concepts/langgraph_studio.md": "https://docs.langchain.com/langgraph-platform/langgraph-studio",
"cloud/how-tos/studio/quick_start.md": "https://docs.langchain.com/langgraph-platform/quick-start-studio",
"cloud/how-tos/invoke_studio.md": "https://docs.langchain.com/langgraph-platform/invoke-studio",
"cloud/how-tos/studio/manage_assistants.md": "https://docs.langchain.com/langgraph-platform/manage-assistants-studio",
"cloud/how-tos/threads_studio.md": "https://docs.langchain.com/langgraph-platform/threads-studio",
"cloud/how-tos/iterate_graph_studio.md": "https://docs.langchain.com/langgraph-platform/iterate-graph-studio",
"cloud/how-tos/studio/run_evals.md": "https://docs.langchain.com/langgraph-platform/run-evals-studio",
"cloud/how-tos/clone_traces_studio.md": "https://docs.langchain.com/langgraph-platform/clone-traces-studio",
"cloud/how-tos/datasets_studio.md": "https://docs.langchain.com/langgraph-platform/datasets-studio",
"concepts/sdk.md": "https://docs.langchain.com/langgraph-platform/sdk",
"concepts/plans.md": "https://docs.langchain.com/langgraph-platform/plans",
"concepts/application_structure.md": "https://docs.langchain.com/langgraph-platform/application-structure",
"concepts/scalability_and_resilience.md": "https://docs.langchain.com/langgraph-platform/scalability-and-resilience",
"concepts/auth.md": "https://docs.langchain.com/langgraph-platform/auth",
"how-tos/auth/custom_auth.md": "https://docs.langchain.com/langgraph-platform/custom-auth",
"how-tos/auth/openapi_security.md": "https://docs.langchain.com/langgraph-platform/openapi-security",
"concepts/assistants.md": "https://docs.langchain.com/langgraph-platform/assistants",
"cloud/how-tos/configuration_cloud.md": "https://docs.langchain.com/langgraph-platform/configuration-cloud",
"cloud/how-tos/use_threads.md": "https://docs.langchain.com/langgraph-platform/use-threads",
"cloud/how-tos/background_run.md": "https://docs.langchain.com/langgraph-platform/background-run",
"cloud/how-tos/same-thread.md": "https://docs.langchain.com/langgraph-platform/same-thread",
"cloud/how-tos/stateless_runs.md": "https://docs.langchain.com/langgraph-platform/stateless-runs",
"cloud/how-tos/configurable_headers.md": "https://docs.langchain.com/langgraph-platform/configurable-headers",
"concepts/double_texting.md": "https://docs.langchain.com/langgraph-platform/double-texting",
"cloud/how-tos/interrupt_concurrent.md": "https://docs.langchain.com/langgraph-platform/interrupt-concurrent",
"cloud/how-tos/rollback_concurrent.md": "https://docs.langchain.com/langgraph-platform/rollback-concurrent",
"cloud/how-tos/reject_concurrent.md": "https://docs.langchain.com/langgraph-platform/reject-concurrent",
"cloud/how-tos/enqueue_concurrent.md": "https://docs.langchain.com/langgraph-platform/enqueue-concurrent",
"cloud/concepts/webhooks.md": "https://docs.langchain.com/langgraph-platform/use-webhooks",
"cloud/how-tos/webhooks.md": "https://docs.langchain.com/langgraph-platform/use-webhooks",
"cloud/concepts/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/cron-jobs",
"cloud/how-tos/cron_jobs.md": "https://docs.langchain.com/langgraph-platform/cron-jobs",
"how-tos/http/custom_lifespan.md": "https://docs.langchain.com/langgraph-platform/custom-lifespan",
"how-tos/http/custom_middleware.md": "https://docs.langchain.com/langgraph-platform/custom-middleware",
"how-tos/http/custom_routes.md": "https://docs.langchain.com/langgraph-platform/custom-routes",
"cloud/concepts/data_storage_and_privacy.md": "https://docs.langchain.com/langgraph-platform/data-storage-and-privacy",
"cloud/deployment/semantic_search.md": "https://docs.langchain.com/langgraph-platform/semantic-search",
"how-tos/ttl/configure_ttl.md": "https://docs.langchain.com/langgraph-platform/configure-ttl",
"concepts/deployment_options.md": "https://docs.langchain.com/langgraph-platform/deployment-options",
"cloud/quick_start.md": "https://docs.langchain.com/langgraph-platform/deployment-quickstart",
"cloud/deployment/setup.md": "https://docs.langchain.com/langgraph-platform/setup-app-requirements-txt",
"cloud/deployment/setup_pyproject.md": "https://docs.langchain.com/langgraph-platform/setup-pyproject",
"cloud/deployment/setup_javascript.md": "https://docs.langchain.com/langgraph-platform/setup-javascript",
"cloud/deployment/custom_docker.md": "https://docs.langchain.com/langgraph-platform/custom-docker",
"cloud/deployment/graph_rebuild.md": "https://docs.langchain.com/langgraph-platform/graph-rebuild",
"concepts/langgraph_cloud.md": "https://docs.langchain.com/langgraph-platform/cloud",
"concepts/langgraph_self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/hybrid",
"concepts/langgraph_self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/self-hosted",
"concepts/langgraph_standalone_container.md": "https://docs.langchain.com/langgraph-platform/self-hosted#standalone-server",
"cloud/deployment/cloud.md": "https://docs.langchain.com/langgraph-platform/cloud",
"cloud/deployment/self_hosted_data_plane.md": "https://docs.langchain.com/langgraph-platform/deploy-hybrid",
"cloud/deployment/self_hosted_control_plane.md": "https://docs.langchain.com/langgraph-platform/deploy-self-hosted-full-platform",
"cloud/deployment/standalone_container.md": "https://docs.langchain.com/langgraph-platform/deploy-standalone-server",
"concepts/server-mcp.md": "https://docs.langchain.com/langgraph-platform/server-mcp",
"cloud/how-tos/human_in_the_loop_time_travel.md": "https://docs.langchain.com/langgraph-platform/human-in-the-loop-time-travel",
"cloud/how-tos/add-human-in-the-loop.md": "https://docs.langchain.com/langgraph-platform/add-human-in-the-loop",
"cloud/deployment/egress.md": "https://docs.langchain.com/langgraph-platform/env-var",
"cloud/how-tos/streaming.md": "https://docs.langchain.com/langgraph-platform/streaming",
"cloud/reference/api/api_ref.md": "https://docs.langchain.com/langgraph-platform/server-api-ref",
"cloud/reference/langgraph_server_changelog.md": "https://docs.langchain.com/langgraph-platform/langgraph-server-changelog",
"cloud/reference/api/api_ref_control_plane.md": "https://docs.langchain.com/langgraph-platform/api-ref-control-plane",
"cloud/reference/cli.md": "https://docs.langchain.com/langgraph-platform/cli",
"cloud/reference/env_var.md": "https://docs.langchain.com/langgraph-platform/env-var",
"troubleshooting/studio.md": "https://docs.langchain.com/langgraph-platform/troubleshooting-studio",
}
@@ -145,6 +255,38 @@ def _add_path_to_code_blocks(markdown: str, page: Page) -> str:
return code_block_pattern.sub(replace_code_block_header, markdown)
# Compiled regex patterns for better performance and readability
def _apply_conditional_rendering(md_text: str, target_language: str) -> str:
if target_language not in {"python", "js"}:
raise ValueError("target_language must be 'python' or 'js'")
pattern = re.compile(
r"(?P<indent>[ \t]*):::(?P<language>\w+)\s*\n"
r"(?P<content>((?:.*\n)*?))" # Capture the content inside the block
r"(?P=indent)[ \t]*:::" # Match closing with the same indentation + any additional whitespace
)
def replace_conditional_blocks(match: re.Match) -> str:
"""Keep active conditionals."""
language = match.group("language")
content = match.group("content")
if language not in {"python", "js"}:
# If the language is not supported, return the original block
return match.group(0)
if language == target_language:
return content
# If the language does not match, return an empty string
return ""
processed = pattern.sub(replace_conditional_blocks, md_text)
return processed
def _highlight_code_blocks(markdown: str) -> str:
"""Find code blocks with highlight comments and add hl_lines attribute.
@@ -208,7 +350,7 @@ def _highlight_code_blocks(markdown: str) -> str:
opening_fence += f" {attributes}"
if highlighted_lines:
opening_fence += f" hl_lines=\"{' '.join(highlighted_lines)}\""
opening_fence += f' hl_lines="{" ".join(highlighted_lines)}"'
return (
# The indent and opening fence
@@ -223,6 +365,21 @@ def _highlight_code_blocks(markdown: str) -> str:
return markdown
def _save_page_output(markdown: str, output_path: str):
"""Save markdown content to a file, creating parent directories if needed.
Args:
markdown: The markdown content to save
output_path: The file path to save to
"""
# Create parent directories recursively if they don't exist
os.makedirs(os.path.dirname(output_path), exist_ok=True)
# Write the markdown content to the file
with open(output_path, "w", encoding="utf-8") as f:
f.write(markdown)
def _on_page_markdown_with_config(
markdown: str,
page: Page,
@@ -238,12 +395,23 @@ def _on_page_markdown_with_config(
# logger.info("Processing Jupyter notebook: %s", page.file.src_path)
markdown = convert_notebook(page.file.abs_src_path)
target_language = kwargs.get(
"target_language",
os.environ.get("TARGET_LANGUAGE", "python")
)
# Apply cross-reference preprocessing to all markdown content
markdown = _replace_autolinks(markdown, page.file.src_path, default_scope=target_language)
# Append API reference links to code blocks
if add_api_references:
markdown = update_markdown_with_imports(markdown, page.file.abs_src_path)
# Apply highlight comments to code blocks
markdown = _highlight_code_blocks(markdown)
# Apply conditional rendering for code blocks
markdown = _apply_conditional_rendering(markdown, target_language)
# Add file path as an attribute to code blocks that are executable.
# This file path is used to associate fixtures with the executable code
# which can be used in CI to test the docs without making network requests.
@@ -257,12 +425,20 @@ def _on_page_markdown_with_config(
def on_page_markdown(markdown: str, page: Page, **kwargs: Dict[str, Any]):
return _on_page_markdown_with_config(
finalized_markdown = _on_page_markdown_with_config(
markdown,
page,
add_api_references=True,
**kwargs,
)
page.meta["original_markdown"] = finalized_markdown
output_path = os.environ.get("MD_OUTPUT_PATH")
if output_path:
file_path = os.path.join(output_path, page.file.src_path)
_save_page_output(finalized_markdown, file_path)
return finalized_markdown
# redirects
@@ -285,7 +461,7 @@ Redirecting...
"""
def write_html(site_dir, old_path, new_path):
def _write_html(site_dir, old_path, new_path):
"""Write an HTML file in the site_dir with a meta redirect to the new page"""
# Determine all relevant paths
old_path_abs = os.path.join(site_dir, old_path)
@@ -301,20 +477,135 @@ def write_html(site_dir, old_path, new_path):
f.write(content)
def _inject_gtm(html: str) -> str:
"""Inject Google Tag Manager code into the HTML.
Code to inject Google Tag Manager noscript tag immediately after <body>.
This is done via hooks rather than via a template because the MkDocs material
theme does not seem to allow placing the code immediately after the <body> tag
without modifying the template files directly.
Args:
html: The HTML content to modify.
Returns:
The modified HTML content with GTM code injected.
"""
# Code was copied from Google Tag Manager setup instructions.
gtm_code = """
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-T35S4S46"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
"""
soup = BeautifulSoup(html, "html.parser")
body = soup.body
if body:
# Insert the GTM code as raw HTML at the top of <body>
body.insert(0, BeautifulSoup(gtm_code, "html.parser"))
return str(soup)
else:
return html # fallback if no <body> found
def _inject_markdown_into_html(html: str, page: Page) -> str:
"""Inject the original markdown content into the HTML page as JSON."""
original_markdown = page.meta.get("original_markdown", "")
if not original_markdown:
return html
markdown_data = {
"markdown": original_markdown,
"title": page.title or "Page Content",
"url": page.url or "",
}
# Properly escape the JSON for HTML
json_content = json.dumps(markdown_data, ensure_ascii=False)
json_content = (
json_content.replace("</", "\\u003c/")
.replace("<script", "\\u003cscript")
.replace("</script", "\\u003c/script")
)
script_content = (
f'<script id="page-markdown-content" '
f'type="application/json">{json_content}</script>'
)
# Insert before </head> if it exists, otherwise before </body>
if "</head>" not in html:
raise ValueError(
"HTML does not contain </head> tag. Cannot inject markdown content."
)
return html.replace("</head>", f"{script_content}</head>")
def on_post_page(html: str, page: Page, config: MkDocsConfig) -> str:
"""Inject Google Tag Manager noscript tag immediately after <body>.
Args:
html: The HTML output of the page.
page: The page instance.
config: The MkDocs configuration object.
Returns:
modified HTML output with GTM code injected.
"""
html = _inject_markdown_into_html(html, page)
return _inject_gtm(html)
# Create HTML files for redirects after site dir has been built
def on_post_build(config):
use_directory_urls = config.get("use_directory_urls")
for page_old, page_new in REDIRECT_MAP.items():
# Convert .ipynb to .md for path calculation
page_old = page_old.replace(".ipynb", ".md")
page_new = page_new.replace(".ipynb", ".md")
page_new_before_hash, hash, suffix = page_new.partition("#")
old_html_path = File(page_old, "", "", use_directory_urls).dest_path.replace(
os.sep, "/"
)
new_html_path = File(page_new_before_hash, "", "", True).url
new_html_path = (
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
+ hash
+ suffix
)
write_html(config["site_dir"], old_html_path, new_html_path)
# Calculate the HTML path for the old page (whether it exists or not)
if use_directory_urls:
# With directory URLs: /path/to/page/ becomes /path/to/page/index.html
if page_old.endswith(".md"):
old_html_path = page_old[:-3] + "/index.html"
else:
old_html_path = page_old + "/index.html"
else:
# Without directory URLs: /path/to/page.md becomes /path/to/page.html
if page_old.endswith(".md"):
old_html_path = page_old[:-3] + ".html"
else:
old_html_path = page_old + ".html"
if isinstance(page_new, str) and page_new.startswith("http"):
# Handle external redirects
_write_html(config["site_dir"], old_html_path, page_new)
else:
# Handle internal redirects
page_new = page_new.replace(".ipynb", ".md")
page_new_before_hash, hash, suffix = page_new.partition("#")
# Try to get the new path using File class, but fallback to manual calculation
try:
new_html_path = File(page_new_before_hash, "", "", True).url
new_html_path = (
posixpath.relpath(new_html_path, start=posixpath.dirname(old_html_path))
+ hash
+ suffix
)
except:
# Fallback: calculate relative path manually
if use_directory_urls:
if page_new_before_hash.endswith(".md"):
new_html_path = page_new_before_hash[:-3] + "/"
else:
new_html_path = page_new_before_hash + "/"
else:
if page_new_before_hash.endswith(".md"):
new_html_path = page_new_before_hash[:-3] + ".html"
else:
new_html_path = page_new_before_hash + ".html"
new_html_path += hash + suffix
_write_html(config["site_dir"], old_html_path, new_html_path)
+11 -5
View File
@@ -5,6 +5,7 @@ import os
import json
import click
import nbformat
import re
logger = logging.getLogger(__name__)
NOTEBOOK_DIRS = ("docs/how-tos","docs/tutorials")
@@ -88,12 +89,10 @@ def has_blocklisted_command(code: str, metadata: dict) -> bool:
return True
return False
MERMAID_PATTERN = re.compile(r'display\(Image\((\w+)\.get_graph\(\)\.draw_mermaid_png\(\)\)\)')
def remove_mermaid(code: str) -> str:
return code.replace(
"display(Image(graph.get_graph().draw_mermaid_png()))",
# replace with a dummy statement
"print()"
)
return MERMAID_PATTERN.sub('print()', code)
def add_vcr_to_notebook(
@@ -108,6 +107,8 @@ def add_vcr_to_notebook(
continue
lines = cell.source.splitlines()
# remove the special tag for hidden cells
lines = [line for line in lines if not line.strip().startswith("# hide-cell")]
# skip if empty cell
if not lines:
continue
@@ -195,6 +196,11 @@ def remove_mermaid_from_notebook(notebook: nbformat.NotebookNode) -> nbformat.No
continue
cell.source = remove_mermaid(cell.source)
# skip the cell entirely if it contains PYPPETEER
if "PYPPETEER" in cell.source:
cell.source = ""
return notebook
@@ -15,9 +15,10 @@ If you’re looking for other prebuilt libraries, explore the community-built op
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!)
{library_list}
:::python
{python_library_list}
## ✨ Contributing Your Library
@@ -28,16 +29,39 @@ To share your project, simply open a Pull Request adding an entry for your packa
**Guidelines**
- Your repo must be distributed as an installable package (e.g., PyPI for Python, npm
for JavaScript/TypeScript, etc.) 📦
- Your repo must be distributed as an installable package on PyPI 📦
- 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! 🚀
:::
:::js
{js_library_list}
## ✨ 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]({langgraph_url}) file.
**Guidelines**
- Your repo must be distributed as an installable package on npm 📦
- 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! 🚀
:::
"""
@@ -46,36 +70,18 @@ class ResolvedPackage(TypedDict):
"""The name of the package."""
repo: str
"""Repository ID within github. Format is: [orgname]/[repo_name]."""
monorepo_path: str | None
"""Optional: The path to the package in the monorepo. Must be relative to the root of the monorepo."""
language: str
"""The language of the package. (either 'python' or 'js')"""
weekly_downloads: int | None
"""The weekly download count of the package."""
description: str
"""A brief description of what the package does."""
def generate_markdown(resolved_packages: List[ResolvedPackage], language: str) -> str:
"""Generate the markdown content for the third party page.
Args:
resolved_packages: A list of resolved package information.
language: str
Returns:
The markdown content as a string.
def generate_package_table(resolved_packages: List[ResolvedPackage]) -> str:
"""Generate the package table for the third party page.
"""
# Update the URL to the actual file once the initial version is merged
if language == "python":
langgraph_url = (
"https://github.com/langchain-ai/langgraph/blob/main/docs"
"/_scripts/third_party_page/packages.yml"
)
elif language == "js":
langgraph_url = (
"https://github.com/langchain-ai/langgraphjs/blob/main/docs"
"/_scripts/third_party/packages.yml"
)
else:
raise ValueError(f"Invalid language '{language}'. Expected 'python' or 'js'.")
sorted_packages = sorted(
resolved_packages, key=lambda p: p["weekly_downloads"] or 0, reverse=True
)
@@ -85,7 +91,15 @@ def generate_markdown(resolved_packages: List[ResolvedPackage], language: str) -
]
for package in sorted_packages:
name = f"**{package['name']}**"
repo_url = f"[{package['repo']}](https://github.com/{package['repo']})"
monorepo_path = package.get("monorepo_path", "")
if monorepo_path:
monorepo_path = monorepo_path[1:] if monorepo_path.startswith('/') else monorepo_path
repo_url_suffix = f"/tree/main/{monorepo_path}"
else:
repo_url_suffix = ""
repo_url = f"https://github.com/{package['repo']}{repo_url_suffix}"
stars_badge = (
f"https://img.shields.io/github/stars/{package['repo']}?style=social"
)
@@ -93,13 +107,39 @@ def generate_markdown(resolved_packages: List[ResolvedPackage], language: str) -
downloads = package["weekly_downloads"] or "-"
row = f"| {name} | {repo_url} | {package['description']} | {downloads} | {stars}"
rows.append(row)
return "\n".join(rows)
def generate_markdown(resolved_packages: List[ResolvedPackage]) -> str:
"""Generate the markdown content for the third party page.
Args:
resolved_packages: A list of resolved package information.
Returns:
The markdown content as a string.
"""
# Update the URL to the actual file once the initial version is merged
langgraph_url = (
"https://github.com/langchain-ai/langgraph/blob/main/docs"
"/_scripts/third_party_page/packages.yml"
)
python_library_list = generate_package_table(
[p for p in resolved_packages if p["language"] == "python"]
)
js_library_list = generate_package_table(
[p for p in resolved_packages if p["language"] == "js"]
)
markdown_content = MARKDOWN.format(
library_list="\n".join(rows), langgraph_url=langgraph_url
python_library_list=python_library_list,
js_library_list=js_library_list,
langgraph_url=langgraph_url,
)
return markdown_content
def main(input_file: str, output_file: str, language: str) -> None:
def main(input_file: str, output_file: str) -> None:
"""Main function to create the third party page.
Args:
@@ -111,7 +151,7 @@ def main(input_file: str, output_file: str, language: str) -> None:
with open(input_file, "r") as f:
resolved_packages: List[ResolvedPackage] = yaml.safe_load(f)
markdown_content = generate_markdown(resolved_packages, language)
markdown_content = generate_markdown(resolved_packages)
# Write the markdown content to the output file
with open(output_file, "w", encoding="utf-8") as f:
@@ -127,12 +167,6 @@ if __name__ == "__main__":
parser.add_argument(
"output_file", help="Path to the output file for the third party page."
)
parser.add_argument(
"--language",
choices=["python", "js"],
default="python",
help="The language for which to generate the third party page. Defaults to 'python'.",
)
args = parser.parse_args()
main(args.input_file, args.output_file, args.language)
main(args.input_file, args.output_file)
@@ -11,101 +11,146 @@ import yaml
class Package(TypedDict):
"""A TypedDict representing a package"""
name: str
"""The name of the package."""
repo: str
"""Repository ID within github. Format is: [orgname]/[repo_name]."""
monorepo_path: str | None
"""The path to the package in the monorepo. Only used for JS packages."""
description: str
"""A brief description of what the package does."""
class ResolvedPackage(Package):
weekly_downloads: int | None
"""The weekly download count of the package."""
language: str
"""The language of the package. (either 'python' or 'js')"""
HERE = pathlib.Path(__file__).parent
PACKAGES_FILE = HERE / "packages.yml"
PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())['packages']
PACKAGES = yaml.safe_load(PACKAGES_FILE.read_text())["packages"]
def _get_pypi_downloads(package: Package) -> int:
"""Retrieve the weekly download count for a package from PyPIStats."""
def _get_weekly_downloads(packages: list[Package], fake: bool) -> list[ResolvedPackage]:
"""Retrieve the monthly download count for a list of packages from PyPIStats."""
# First check if package exists on PyPI
pypi_url = f"https://pypi.org/pypi/{package['name']}/json"
try:
pypi_response = requests.get(pypi_url)
pypi_response.raise_for_status()
except requests.exceptions.HTTPError:
raise AssertionError(f"Package {package['name']} does not exist on PyPI")
# Get first release date
pypi_data = pypi_response.json()
releases = pypi_data["releases"]
first_release_date = None
for version_releases in releases.values():
if version_releases: # Some versions may be empty lists
upload_time = datetime.fromisoformat(version_releases[0]["upload_time"])
if first_release_date is None or upload_time < first_release_date:
first_release_date = upload_time
if first_release_date is None:
raise AssertionError(f"Package {package['name']} has no releases yet")
# If package was published in last 48 hours, skip download stats
if (datetime.now() - first_release_date).total_seconds() >= 48 * 3600:
url = f"https://pypistats.org/api/packages/{package['name']}/overall"
response = requests.get(url)
response.raise_for_status()
data = response.json()
sorted_data = sorted(
data["data"],
key=lambda x: datetime.strptime(x["date"], "%Y-%m-%d"),
reverse=True,
)
# Sum the last 7 days of downloads
return sum(entry["downloads"] for entry in sorted_data[:7])
else:
return None
def _get_npm_downloads(package: Package) -> int:
"""Retrieve the weekly download count for a package on the npm registry."""
# Check if package exists on the npm registry
npm_url = f"https://registry.npmjs.org/{package['name']}"
try:
npm_response = requests.get(npm_url)
npm_response.raise_for_status()
except requests.exceptions.HTTPError:
raise AssertionError(f"Package {package['name']} does not exist on npm registry")
npm_data = npm_response.json()
# Retrieve the first publish date using the 'created' timestamp from the 'time' field.
created_str = npm_data.get("time", {}).get("created")
if created_str is None:
raise AssertionError(f"Package {package['name']} has no creation time in registry data")
# Remove the trailing 'Z' if present and parse the ISO format timestamp
first_publish_date = datetime.fromisoformat(created_str.rstrip("Z"))
# If package was published more than 48 hours ago, fetch download stats.
if (datetime.now() - first_publish_date).total_seconds() >= 48 * 3600:
stats_url = f"https://api.npmjs.org/downloads/point/last-week/{package['name']}"
stats_response = requests.get(stats_url)
stats_response.raise_for_status()
stats_data = stats_response.json()
return stats_data.get("downloads", None)
else:
return None
def _get_weekly_downloads(packages: dict[str, list[Package]], fake: bool) -> list[ResolvedPackage]:
"""Retrieve the weekly download count for a dictionary of python or js packages."""
resolved_packages: list[ResolvedPackage] = []
if fake:
# To avoid making network requests during testing, return fake download counts
for package in packages:
for language, package_list in packages.items():
for package in package_list:
resolved_packages.append(
{
"name": package["name"],
"repo": package["repo"],
"monorepo_path": package.get("monorepo_path", None),
"language": language,
"description": package["description"],
"weekly_downloads": -12345,
}
)
return resolved_packages
for language, package_list in packages.items():
for package in package_list:
if language == "python":
num_downloads = _get_pypi_downloads(package)
elif language == "js":
num_downloads = _get_npm_downloads(package)
else:
num_downloads = None
resolved_packages.append(
{
"name": package["name"],
"repo": package["repo"],
"weekly_downloads": -12345,
"monorepo_path": package.get("monorepo_path", None),
"language": language,
"description": package["description"],
"weekly_downloads": num_downloads,
}
)
return resolved_packages
for package in packages:
# First check if package exists on PyPI
pypi_url = f"https://pypi.org/pypi/{package['name']}/json"
try:
pypi_response = requests.get(pypi_url)
pypi_response.raise_for_status()
except requests.exceptions.HTTPError:
raise AssertionError(f"Package {package['name']} does not exist on PyPI")
# Get first release date
pypi_data = pypi_response.json()
releases = pypi_data["releases"]
first_release_date = None
for version_releases in releases.values():
if version_releases: # Some versions may be empty lists
upload_time = datetime.fromisoformat(version_releases[0]["upload_time"])
if first_release_date is None or upload_time < first_release_date:
first_release_date = upload_time
if first_release_date is None:
raise AssertionError(f"Package {package['name']} has no releases yet")
# If package was published in last 48 hours, skip download stats
if (datetime.now() - first_release_date).total_seconds() >= 48 * 3600:
url = f"https://pypistats.org/api/packages/{package['name']}/overall"
response = requests.get(url)
response.raise_for_status()
data = response.json()
sorted_data = sorted(
data["data"],
key=lambda x: datetime.strptime(x["date"], "%Y-%m-%d"),
reverse=True,
)
# Sum the last 7 days of downloads
num_downloads = sum(entry["downloads"] for entry in sorted_data[:7])
else:
num_downloads = None
resolved_packages.append(
{
"name": package["name"],
"repo": package["repo"],
"weekly_downloads": num_downloads,
"description": package["description"],
}
)
return resolved_packages
def main(output_file: str, fake: bool) -> None:
"""Main function to generate package download information.
Args:
output_file: Path to the output YAML file.
fake: If True, use fake download counts for testing purposes.
"""
resolved_packages: list[ResolvedPackage] = _get_weekly_downloads(PACKAGES, fake)
+56 -39
View File
@@ -1,41 +1,58 @@
#A list of third-party packages to surface on the third-party page.
packages:
- name: "trustcall"
repo: "hinthornw/trustcall"
description: "Tenacious tool calling built on LangGraph."
- name: "breeze-agent"
repo: "andrestorres123/breeze-agent"
description: "A streamlined research system built inspired on STORM and built on LangGraph."
- name: "langgraph-supervisor"
repo: "langchain-ai/langgraph-supervisor-py"
description: "Build supervisor multi-agent systems with LangGraph."
- name: "langmem"
repo: "langchain-ai/langmem"
description: "Build agents that learn and adapt from interactions over time."
- name: "langchain-mcp-adapters"
repo: "langchain-ai/langchain-mcp-adapters"
description: "Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents."
- name: "open-deep-research"
repo: "langchain-ai/open_deep_research"
description: "Open source assistant for iterative web research and report writing."
- name: "langgraph-swarm"
repo: "langchain-ai/langgraph-swarm-py"
description: "Build swarm-style multi-agent systems using LangGraph."
- name: "delve-taxonomy-generator"
repo: "andrestorres123/delve"
description: "A taxonomy generator for unstructured data"
- name: "nodeology"
repo: "xyin-anl/Nodeology"
description: "Enable researcher to build scientific workflows easily with simplified interface."
- name: "langgraph-bigtool"
repo: "langchain-ai/langgraph-bigtool"
description: "Build LangGraph agents with large numbers of tools."
- name: "ai-data-science-team"
repo: "business-science/ai-data-science-team"
description: "An AI-powered data science team of agents to help you perform common data science tasks 10X faster."
- name: "langgraph-reflection"
repo: "langchain-ai/langgraph-reflection"
description: "LangGraph agent that runs a reflection step."
- name: "langgraph-codeact"
repo: "langchain-ai/langgraph-codeact"
description: "LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling."
python:
- name: "trustcall"
repo: "hinthornw/trustcall"
description: "Tenacious tool calling built on LangGraph."
- name: "breeze-agent"
repo: "andrestorres123/breeze-agent"
description: "A streamlined research system built inspired on STORM and built on LangGraph."
- name: "langgraph-supervisor"
repo: "langchain-ai/langgraph-supervisor-py"
description: "Build supervisor multi-agent systems with LangGraph."
- name: "langmem"
repo: "langchain-ai/langmem"
description: "Build agents that learn and adapt from interactions over time."
- name: "langchain-mcp-adapters"
repo: "langchain-ai/langchain-mcp-adapters"
description: "Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents."
- name: "open-deep-research"
repo: "langchain-ai/open_deep_research"
description: "Open source assistant for iterative web research and report writing."
- name: "langgraph-swarm"
repo: "langchain-ai/langgraph-swarm-py"
description: "Build swarm-style multi-agent systems using LangGraph."
- name: "delve-taxonomy-generator"
repo: "andrestorres123/delve"
description: "A taxonomy generator for unstructured data"
- name: "nodeology"
repo: "xyin-anl/Nodeology"
description: "Enable researcher to build scientific workflows easily with simplified interface."
- name: "langgraph-bigtool"
repo: "langchain-ai/langgraph-bigtool"
description: "Build LangGraph agents with large numbers of tools."
- name: "ai-data-science-team"
repo: "business-science/ai-data-science-team"
description: "An AI-powered data science team of agents to help you perform common data science tasks 10X faster."
- name: "langgraph-reflection"
repo: "langchain-ai/langgraph-reflection"
description: "LangGraph agent that runs a reflection step."
- name: "langgraph-codeact"
repo: "langchain-ai/langgraph-codeact"
description: "LangGraph implementation of CodeAct agent that generates and executes code instead of tool calling."
js:
- name: "@langchain/mcp-adapters"
repo: "langchain-ai/langchainjs"
description: "Make Anthropic Model Context Protocol (MCP) tools compatible with LangGraph agents."
- name: "@langchain/langgraph-supervisor"
repo: "langchain-ai/langgraphjs"
monorepo_path: "libs/langgraph-supervisor"
description: "Build supervisor multi-agent systems with LangGraph"
- name: "@langchain/langgraph-swarm"
repo: "langchain-ai/langgraphjs"
monorepo_path: "libs/langgraph-swarm"
description: "Build multi-agent swarms with LangGraph"
- name: "@langchain/langgraph-cua"
repo: "langchain-ai/langgraphjs"
monorepo_path: "libs/langgraph-cua"
description: "Build computer use agents with LangGraph"
@@ -0,0 +1 @@
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 truncated
@@ -0,0 +1 @@
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 truncated
@@ -0,0 +1 @@
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 truncated
@@ -0,0 +1 @@
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
@@ -0,0 +1 @@
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
@@ -0,0 +1 @@
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 truncated
@@ -0,0 +1 @@
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 truncated
@@ -1 +1 @@
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
@@ -1 +1 @@
eNqNVGtMHFUUXoQ0FavRGAt/bCcThCrMMjMsWxarlAIlpVIorKW8bG5nLuzAvJjH8rKmYKkxlbRDUxoTCElZdulKYRGMTaiExpKYtFFrDbAxaeIfpRok0USNreDdZReovDrJJDP3nO+c73znnNvqcUJF5SQxYoATNagARkM/qtHqUWCdDlXtjFuAmkNiXYUFxfZeXeH8rzg0TVbTk5OBzJmBqDkUSeYYMyMJyU4qWYCqCqqh6jopsY3++mZcAA0nNKkWiiqejlEkbUnC8LATOilvxhWJh+gL11Wo4MjKSIiJqAWO6h1AS1AxoRETgQAz8FOVAbTEQj5gZXigs5BIIVIJVRJFqBE80BBn/JTHAQGLCjvvckiqZgyvoToEGAbKGgFFRmI5sdq4Vt3EyUkYC6sCMbxMIF5QC8NbC6FMAJ5zQvcSyvABWeY5BgTsyTUo90CIM6E1ynCt2RsojUAVi5rxeWaYR3JhI1JWxEhzisVM+xoIVQOcyCNtUB2IklsO2sdWG2TA1KI4RKhrhnsJPLjaR1KNvnzAFBQ/FhIojMPoA4pgtYysPld0UeMEaHiyCtemCxlX0qWYKcpsG34ssNooMkZfFeBVOLws8jLES5N0CkFaCZIaDKvEQ7Facxi9FGXrV6Aqo4mD77tRSE1XW12oI/DOV57QkFwpOBzu5n1TjCsbdcf4ogSySRhNY3lAxFD8VIym0klbOkVjufn2gaxQGvu6zRi2K0BUq1BDcsLN9zAOXayFrDdr3bb78ZWyFJSf5wROI0ILgpoV+DVcFpIk/fGbeipQQKoFMrpSbDbbFnGRMlAzRgP1IfEImraHqqTK1s/DibKORjC4bCFW7gArxOu1Lf1XuIUx8U+A2YAhXeZPWA8t6doain1pwWyJW/uvUAxhEp4EszFFbD34/+RbShS3iedq4Za8sU29N+TjDXWe4FjjBvo+QVJHGw5AzuI8mi2WHM+rLSnJrSm0C1KvkwOGlzJTWLUkVfNwKOsgkQUYBySKgytkeLJLj2TmH8oaOE4USSclNEt2gGZOlEToLoYKWk3Dy/CSzqLLToFuBC/KLDVGbaSVTrOSaawtjdzL0hYip6TIF16m5WVxBW7K4PXeglZWQUeTEW/vPrfdFHwi0bu4yF7IPxyZuePsYt6dyduDo+VvXI95tb/w23Otu7I766z6B1/H6x1XO79bNI+V9TdE75vPPeCMLRsYnv6riu7O2Nc01nP3J+fDR1pGzPi/12+Mf/mUMOa+meP9rds3EVdnOpLab7Mm+S534lOzvbeJSyO/X7GD+MRPDulvdttf2jnb1j7je8//cl77+Nm/02oqTv/RWflRuaOt4NljST2+S12nKwsu2Dp+MU3sOTj7IErsmp94RtpzdQTb0XMzffbp7yvoNojPRRe2TEq1P1ujWi53/NNzpvkiz8zd3TZXgW93bvumg3n909hjUfHPz3SM+u81dBVVvPPjwmf7U0v3ftgVzbTfEhgbtRCdt/vjmRenupgk8vziQH1sQ/c1qvSFxKl73v3z7+a2F1h2zTxKfeu5Jnx6YTruB8o29OdDKahdpOnXnbfuP4gwmf4DBVoOEg==
eNqNVX9sE3UU75ygIxoDIj806tkMZqTf7q7XbmtBFLaBQMoWWoENcXx792172/XuvPu20OE0GwwRouFAiCHTCOtarBO2jIQM0JAA4efCgoZY/sBEgyEhkYAuoBjn97p2P9wG3F/tvfd57/Pe5713TYkIUjVBlnLaBQkjFXKY/NH0poSK3gsjDW+OhxAOynysssLjbQ2rQmpWEGNFcxUWQkWwQgkHVVkROCsnhwojTGEIaRoMIC3mk/loSt5oDsENNViuQ5JmdjG0zW4xZ13MrjUbzaosIrPLHNaQaraYOZmQkDB5sT4IcYFGhaKUBEPoDXPDWgKUeSQSGyfCMI8ACxxAkyUJYSBCTLiaGxJBBHlS0DXT5FhQ1rDeOYrkIchxSMEASZzMC1JA7wrUC4qF4pHfiGKh6jXMJzkjbroXerIOIQVAUYigrg1Aw1CQRFIBwEIIyWGsf728wluzeMnK8uXxgdB6B1QUUeCgAS+sJRTbM3UBHFXQaHPSqB6QlkhYP7IgS7awMkoaL1G01e600h3DU4uQ8I4rafux4QYFcnUkDsiIqscHwAeH+8ia3uaGXIVnREiockG9DaqhIvuIKtWwZBSqJ0orR6fLGIfSsVaGsTo7RwTWohKnt/mhqKHOQSUGIUkbbWMBXQRo5siI0AirUcDJJIO+jz6YbaCIpAAO6q0MwxxQkaaQWUWb4gSGw1pTjCiKLp5NZAZsf8WyoXmYGSsj6urfecNEYoal3DBKkdQOiqZdDsZlZ6jFbm97aSaNd0ydOr0qlDQ/0ao8OzwJLhiW6hCfLB1zYFKzhypWSX5RCAkYCJISJrOQXgqQfqXH7bTxpF57qL+KQqRHRu4sZvYjYDSE9cNGvYB2AIb1Zqqmq1MFY6HJXI+i2FaSzjbn4f5DFDOYgkfBjEORqU6Zx4Jn7lOWXcw+bisGPYd4xVin0/mQuOMxYp3VKWos5P8EHSg9/wGew6Uc8KYe6D2uiMkMaSDw+nHyu4ZmmNJKO7d66cpy/9sb6m2CV3urCpaHuzWsChwJaQyyIqsYaIgjRx1H9ZSFXGrjCL3OMg62iLCZSwkSJ5JL6wn7ymSDqjaXUlQkypDvHiIqqwEoCfXpNTEIpPJZZxHr4FkfQD4/D+zOkmLgdNoY4LPZSnh7CVNs54taIwLUk4yVoQKyHBDRIc4POMgFERhYZj1RVrV8gXtJaftqsEL2yUQQLyTCSbKE4h6kkvuhJzlRDvPkbKsoXroIrFhQpR92sgjZfDZk5/yM3V9cDMpXrejIrvXg2saMm5/+RDXGjZZIgdM581/e/qQp/eTyO5i6k28+1dy/rffy6Tz3wi31t3qZqa7Y1NaW3fe2gu6CLzzP3vl5+w8Tn3ctOX733p+9M7lPZkUiB16afrPPXxI60yMde+f2733g1NpbL067wV3ybOu5cWL1usuRKWcte3eVTPtJ6AF7ZlSfd1xa2dV30bu54crOLrf+1S+WT6/f/2sL/ndvy81Xb0+o3f3ER6038hb15G12fXmSbZ7YdP7EubOtk1r2F/cyn3vUTQ2+ukl08wv79zU2LlzHKhN2Tv77VOmP4vr8XHevZnuu9pXz73ruak2RvQ21OVVX89hvr1T6tn4whz5zYXHjb1dXfXzO21G25+idlsc/fPrXSxenzFh2LrRm3ffzO+dxn83feL2eZyzTLzyW27zlmx33qvcdfWbetX9Oefvv2u/XoD7c/X6uydTfn2v6Y9nSXddyTKb/AC82UmY=
@@ -1 +1 @@
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
@@ -0,0 +1 @@
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
@@ -0,0 +1 @@
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
@@ -1 +1 @@
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 truncated
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 truncated
@@ -1 +1 @@
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 truncated
eNrtfHdUU9u2NwiISrWighKjgoVAIIXepIsQadJLSHZIII0UehGwISiCBRUEpTepUlSqKGIBRLooRTgiRQHp/SXo8Zzz7n3Hd+93vzG+MT72H0D2mmuuuX57zjVn9m8OglM9ABqdQCFzZhHIDICGxjBYH+hRwak0wJ0J0BlnUkgAA0/BJp1EmZknMmmEjgN4BoNKV5KRQVMJ0hQqQEYTpDEUkoyHrAxAcgawWALZhZ7kTMF6d1j6gglkKpMBVrK1hUOl5BTgSCkYFIpA2ttLgUkULEAEK4EZgBcD8nMmBAahk9BEIlgKDJAxFPYtRxyFRkKzlICd0XQACQf7p+IBNJZldxeHcBKeQmdEZv/Vlhw0BgNQWVp/aIgscPEhUKVAWABHRDMAKZAPnYHNwFDIZGB1v5EZbgBAhaCJBA8g5fvcyFw0lUokYNDscRlXOoWcxZJnAGQGhOFNBf5xOINJB2gQtAtLIvIBimWKpoHMSW8WdGSQrLQ8Qhqa6wWhM9AEMhGg0yFENMuqFOrq+OM/D1DRGDeWEsiPxxKZ8n1y9p9lKPTIZCM0BmX2F5VoGgYfmYymkZDwgj/fpzHJDAIJiEzVOvmPy/0Y/GM5mLSsrLRi3l8U073JmMhkHJpIB4r/Mhlg0LwhGApLR+Q9aAqGQnEjAJHvOHkdHTE4R2eSKsmL5s3UdXXDH3NEEBhWeJQsCa9NNtQx1SJCrfWZBvIeVjYuCAs3TwtPiKw8XB6qqACVQ0BkpaHSstKyEG19hpsbztVCgQDFWbrQsIZ4adwpF2OzEwyKMfwUxYeq6EXWM9QhUUk0pLYu2oyBNYDbaOrh8Ay6szZKGqoFw6I9LeQV9QyMDbwttY1NTnpjtDwMFaGwU9pQTU9rOMIZbw5QXIwpcGUQy2SmBwGr6iFPdfOUI2gbYqwV9Ei6ClY0fTSKiKSdJBmijDT19fXlCHQKw5VgaqLzJ5sRcvIQ6A+zkVC4ApR9Zf/uMUSA7MLARyYoyKfRADqVFWBASAoLRwaTHpzEclHgdW0qiYUo68EnoAz/8O7dSdosd40sM2eyfFYWBjJCe4PkWKuBoLJKUKgSTBakZ2SepfVjFfN/6pd55jQ0mY5j+abO79GQisEzyW4ANkPrn0bAY3YEsB4v23oahci6SaR4Qig0gguBHHnvSNl/Gwa8qBQ6APlhdGSWFcT0+9EBMdDO+h6TkNVYjyz656Fe8EOIQnNBkwk+q6ZHprMjBINnudqDH8NUGoW9LnsiiR6ZIA/P/jHwu+9msKCBQmShEKjsQzqDRsCwQpW9dyqFxoDQAQzr8GJ4R3ZIkdBe7DhVhckiYEjWY1IGEcgYIhMLmDGdtSkk1pJ0ZRCVBhApaGyiBwEdWQaQPSjeEBqFyTohIfJYBByBU8AhkBAq2d2dUeYF+T7OpLJWBdAk1lo0DwIGgKyGXYK8/CMvCI31HIkEEoHlC6s/f5yurECWZXtKyT9KMChuAJkembY6zrrK/yxCA9hmsqH4qShJkXWV/nOhH7pSFVcv5KO/StGBP9mTiCTRS/5x/IeGBCg9y+t3YQgBG9lxgPXBEYaEwXGKGKwzBg3A5RXROBwWJ6uAgCLh8rIIKAKRg8FBMGgMHoB8d/rIVG1rY00jA60iK8ifvReCoq6mn8hUMoVOJuBwKWYsKAFaZAaGSGFiWYc3DUjR0oWYalpHPlCEAQBMQQ7h7AzDKmDQshAdS9Pc37X99PUk9smfiiayPMADE1mAh6mCleBwGFgZREKrKiDhUOhqqgpKYXsM2eXZziPiYRs4Vi8u89u2QvnHi5NHKxzz8smDMrSTGa4f3KMKtm0Ceyjt0dDW1BG00PgystJV5eniOXMpdFvjIcRzsb5bU+Ir88M5FZ2l0mHjo4HL8wtTYjUVK899vty41NG9sjilvjLV5hi4NCVe0bYyWv/tTnRx54TZEnkFoqZeTFteiK+YXSn/FkiZH8ipoCgrJ5twt9glxU1oZ1d6wsOfupS/VyvaaHJq0mrrg8uhD7KVrh1uuZOSsheG3G3Io7712Bnf0Wp9r1sB6yl2B0wKJVX36wrxURVD4jZEdMIScBSRz5npfIW3J0SkUi7vu8Iv4nT0mU2dusLb024Bl3JlJU6pd6MfVSaOWCgcMuVuzzoh4RMFTzh71WQpZpMir7H9pTSucYnbNbn7c335EciXA62iGTEaTv176hX4jrajZtBXn3hTVVx3FLYYfr1PuivQTcmYOdJkPZW77trOKH0J/Qtd8QvlGm2kLR8fM+n7JcwHtr4/uhxqY3Kr+aO0QdHYeKSAT3vMHbWpltYro50uGlMd+js7vykLbjv1lWfxHo0ZGdLAQ7JZCG25mFHGGGkW9BAfP/Flq6pcY6ml5OxL04gb2U4zWvMA37xYNWTqaZw2seYxT2vQ9ahnxEKHj9JqQQWIlP7gooPCe3VndAdfZ1rlqZscKK2JjjD+TfKJx94Up/du6fwNEuqNZfOE9qww3107WlsSd7nyIruHH4aEGeDszAWBav92rNyRvNAPk4uf00+lq+WPdSacX29T+NkXzck1waixvI/yCe1UlNzpmR9q//RD+0df9Ea1DeppRZkRdyNTvY49m5m+N4e0YNpgM8LqjZ14tJAqHCHO5RpkDoEpvPuMtmg8Vtg/1ojjXCuP1ON+iNSJuk1v+zQvfDIiCECnuxecMMfdPzDfFp3Jd4ZlEXe82jqq4vKktjdich06I6zxC5LTUzSt2aabb35vcU+WqAtR6kStyNcRam6gzaaWh/22FR+uRgW5zyDGel99nVKJdTgIt3iaNtidUZqZtCxwh7iwsfyddzefYMVvIH6u7SIvs6dal7YE38k6YhV4UT/eIVKkut0XUjJWlGqXdnWYu/qS1JU2q8AFxVyEwHvYymlDyd2ThJcVwj03MVjBuy1Xh05sL5n00ApLvQje1OfLQd4+sIXzcnZ9ouQ1IPYyZ93MCYyff4WlckUE6sFJjyLph3lfj+0l9WuENz3ENYxjq+8peFptjuXqUb/NETmrSH1QW3g2T82NeE0qWaR2yR54egK+1zoiu8r6gyZyu51VwoyOYk/+Wz/Q0JvN6O6yPWLXLNLCJF+Qe75OKfaISZUV6z+pDWrg1/Lb7v+m4ZThtln/bgfzzhEDNafZm28KBMQVpAoa3X5Lt+ox3O2p4HBT2MgKJoDfcsv5caA8cVwrDnRFdN3UltjhJwsevb0HL8FH+C7WaO/TPeeXawzlaD4wX5rzcauK6Ixb5dsY+4Lwl3wMTsuTZjfe4RmxUSGjT3aN3W+KwQ/JpO5Al3dHkYa6OVeOvOPZY+jI78Hbm4B6BxvwmDdXz52D6lfclEl8l67R7VwxkWjXk2zJN3fV56knBjPIrd+6rq7r8jipdZ1GZYt+I+JdV25CESRG3IlyN2ToIdb0XKp8i+ENzSaR/RmIk6MDek5H06rOXqpuqOYM7tkml+X724kcI6d8nneiAlkL+zl4H7/2dsvf2F89rUFxqtCeeDHovfOQh9FESJ3O1nVn1+/3L8HcHzuQC39H5wucetTmoQPB2haeKSeLKqjKoeJ3eG3R5JI6LOyP1EtMoyhT38X6xJ69untj6ZxB787Q8+rx8iYut5xkOAn9RoQM624Fyhzj0UnatwXP8veDJtrbF2/PbrluoN7NAILy2922FVtX41Ij4r4d6xcoMlJdL6V8QS3fv7sq8rPOEu1W9Lq4BbM9Y9Hzb2TanuMr5+fGQkuHGnreW0vNXCvaJv70cbHKszB+TPVpzec8NpARjoaq/ivENFnDJHG1gGvgJxSEn/FVfxni20fadx4bbhS6fV4P0D3mtb1kj9qDCCFbvH3hBlXbW+c0o08TTpzY8IoWsjH1WYSNksNrnh1GzmYzYQ5zUoju1EW/d9ccZhc/5w0BqWOL6URwpsE9mYLXour+/Odei02my3/lg3e3eXI8I900FFGv7+lKQHrwR/0W3KxyxGvTw7gMX7/pp1cajNoX7l3Sun9PtdpYqaorjLu0QdJuZZJjk8jjynec7vPcBV1nlVterTM4OnJ71wTy7JfZj2mwN1y2XyePvMxc/jiBy2ZOE/x5zOfOcVMnyeGhhUV3zynx+m1+YwWbxitiSx8F7cXO10bDECBsMek4LMl+UrbkM3dKqg9/UV6zNt9U86aNCZOVQ8gFH/r5g8b1dxio0YEuq6l5lX31h/ljjS72hboM0U+WbY4Wrm1QMvF0D5e2lU7syjbsoH35sEni0peP/csmPvv4OncceW/BryDYurm3PB7y1vO43v5rhBN2geLhccd1LvlaB8si6rm7Fo/ca3s10TlTkI+osrSc5lQpd/Ch2EXsq1V/yv9UdWX9RF/KlmsKRlpLFIVmqaikHZeCF5MzYsQ4WwQ1S8tkv1xaslMOIqh/qqIEfixc8VKZLOdJisxpyneNX6KlqHE7i4qlO8QcsSIXHg5JY6K2DTwd4lme52/M2Xs9evmryCD66CH5eUPoeZ8mWEkHT8XSJdnOnafjHz3SaexVPfnc+I7f0FnToJ5T8+orzz713l2fNseI7sF0L124XyGkmvBNX0jHYcpMuwXS3PQq1PWZyjTG9EhL/LLYGx2u4IONnOTJoLfDr1QnC8zsvNPwV40Kn35SHVTaa5wbT7s+Tyzm9fMHJBkn1vO4vH6jEvBxD9dxB3XeYzWdp7upQ2YOU9HzDX1Nom3L/C9MLl4QO6WjCnEYP9dRwNmMiD9VBgr81jhYF8dr/Kh5/u2tfCFeHJ/V1hKMeuKYwt0iyGh7aaZ0z9ylLVolZ+R335Fj+WpqDee46Ze0eX/H4V5EDNfT5KQ3Grsx/gmXSytjWpVmoy7JIM/P0De+UunJ8z783kdzjvxYVO7rJYhIrw/3A5seAplZGihGXjKfr9oq0fZZdGRWYexA0A3h3Y3K/EWfJHJ8g85Kv9XKq5yOnJp3DtzB4yPi9DHE5Jniq8/5d/veMr3UW7t9LtbRz93E++HjNmy9aaFidAGleodjWtH31dxLine truncated
@@ -1 +1 @@
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 truncated
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 truncated
@@ -1 +1 @@
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 truncated
eNrsu2VQnN22Loq7BggSPIFAgru7BAjuQZumcWigGw0ugQDBg7u7B4fGJXhwd3d3uHxrrb3P2nfvqvNnnTq37t7zR1e9c4w5xnjHfJ75VtdT0y/fGeQIsQTbwZdY2kFBjgAg9OUBEuuX7whycAJBoAF5tiCoBdg0R0VZXSPbydFy9p0FFGoPEWBlBdhbsoDtQXYASxYg2JbVmZ0VZGsCMjW1tDOH5JiATd1m9b/SWtrZO0FpBfT0uNiYONk42Jm4+Di52Zk4efjZDQyYaG3BpiAbWgFaKMgVyvzvy5k5mSG2ABsbWiZakB0Q/NeUkRnY0RbwEonWBAAB8XDReuZbgACmL8UvweHlWIAh0Kiy/1hQOQAIBNm/RP1HhKhqc3dLeyZqU5CZDQAKYqJ2h0BNi4BgOzvQ3146qsgaBLJnBthYOoPy/r42qgJgb29jCQT8ZWe1goDtSl78oSA7KDPUzR70n81FThCQIzPA/MUjqkb5pRRxOVYVt5f+2VGzs/Bys7BVuDJDoABLOxsQBMJsA3ipKs/+b/amfzbYA4DWL0GY/7E3UXl/X1z2zz5gSFSuIgCorP4fQgIcgRZRuQBHWx6u6n+ed3Syg1ragqLyJVX+c7p/GP9XOk4WdnYW/sr/EBjiZgeMyjUD2EBAdf9hMQjq6MYMBL/EiMpkywOCwdaWoKg5eFQjI6CZkYmtsK2ro5uTjJW1hYQRtyVUx0KZ3dZCyk5BWk3Shk33k5Mcr7POF3NuTWsXTRdmdl4uXjZ+PjYObmZ2FjYWdhZ2ZqlPUGtrMytNPks2M21zR1MFCxYzLXMl9c9QsBKXFtjdnt/VTlZB2tbe1pFHSgagDjWV4/oiLmtmAYWYSCmzsElymgJcNHn5ZeWU5Ny0pZRUVdyAks4K/GycWlJs4i66XNwmFhogsLkSmEuQ+qVkJ2dLU2FnXntrFw5LKQWgLp+srQyfjuMngLINj6OKrYKyovinT584LCFgqJWlmqr0P9XMzcHLzPaPsnnYuPjY/hpl/4YYG5CdOdQiKoufo8ARBLF/YRnIP++lj1AniF/OC0RBg335ti8dfdn4LGWF/4VushypF7hGtWg4vWCWnZNaEeBGzfGSjZqNXYCNTYCTi1pWUaNE8h9ZNP5LXFZqOALsIGYv2JT+NzbkAy2c7KxBpkWS/yUDmv5iwMv2/lW9I9jmZdIG7MIMdrQ0t7SLyvzQ8v8yg1ztwRAQ8z+KjirRYVb7+/nBLCdV8ndOMv+N61G1/zXVq//hBHY0B9hZuv+t9KjCvxgCtHiBWs0/zPaO4L/y/rXQFhKVxcNR9g/Dv2G36KU1bMzsbMxs7A0QqKMl8IWqf727PdgRygwBAV9OMKhb1CyTLcD1L54Kc7Jzc/K8bJMgtaUd0MbJFKTuZCIFtn1JCRGktncE2YABptnOloCoFpCdM9iN2RHs9HJMMvNxmXBx8/Dz8JgxOzsDbRxaXJn/bneyf8kKAti+5HJ0tgSCmP9GuywerkZXZseXfbSxtLV8wcLffv9xxL4Qmf0vpNT/Zw8o2BpkB4kq+Jv9ZbT+s4sj6K8y/2rFvwfK4X8Zzf+10z9i5fP/bfA0/kcvCOif6snmsYXU/2f7PyJksUFKXP/NmdnSNGr23cuDEQcb20snQUAzHiAIwMPDD2Dj4TJj4+Li4OTj5ODg5ioHmjEDAUALEPPfQR+VL6WrJK4oJ1mrw/zP6GVWtv/bNygq3w4MsbM0M8tTf2klyDGqCGgDdjJ9ObwdQXmSMsxq4rpRNfycINBLfCAv3wvfgAB2ZmlttYp/i/bvWM/56+TPB9i8IMAZGFVtwSlMK8DFxUkrSG0LEObj4WJj+9v3yjfvL8TYmXeTiFCFosH9bSBqJOnhNspXbx0vK1dW2SVS8DMslggiSQ3/8AmO6UciVMXjd+a9GH46IniEzXJC1pEjfQwmNUeOC59GvB8vp5cNVOPrbo+9n+7uH5O2YM+913PC6eew59t976f9ctjT3b6oN+x5OQakF3t9v6/+SPm86OF5tHl2Lep9+uy5+SxyMWLkPf7Qjuw3SaG/FB1eVaXE3q3PGJidIcyJX3Q9T5Br7M2kZYiFYixPnJzgkyyT9FkZjYB9Vw5lyfIz77hT5GE8E34nx/B6COac2OKCY7uHImbtK9tkuGxjZEOkPTgHqhm6C+vS9uRp6aJErOzPu4cz4nu3kGJiwMfQk0Rt1NhW3c2y+plaYzve16dZX/kwFjRDCXPK4SszF/dmJOJVHG4L3zuz5h6FDSfB5ydbU2vbZuvgMXf65/nUSi2v4KOdcoNXGERoOMJl91hSI7QKcBPF/EppKybLOTX73dwlfDMY2Xu+bbXzughm6SVd3i107iJ7fqLqU20Marrb5wxs8XREoESrz4vYtvn91bb5bUQ7hc6fFfmfzF7D7c3zInB6SMIaNW9d3h0NGUBNiO6T1SgNOU5RvzpNbx1iV9y9U6/QI8BG48XMqYhred29YBKu1qPNuvmG6lVoP07Jqlbvb9ABrakgcbjqsuZ70ChHkCtr8xTTETa+nYHBuyD75V4+dwUCQiF1OsMUTBs19rhVLZulvjMl//nLeclckidn2p2EmzKVA3e0cpuq76wOfk3BuA2BSjDP7JNKXBlAttUHqXN8kxPybw6lyB2djNOk/CK/yQZRjb6t4P8M1g+PMkCjFS4PeTWL77g2jlwBZPqmUsoZmjPYJfbgabRhK5x1fGNOY2YluWqzrVah4IlEQkWXF933OoiFc1jf10iEwkP7Gt7Af0ftpJ0z2HgmV2RLeTPfUMjye8amK8qYEWLxNHwDGVbyenCN3vLrtc4r7QQjhJ86IqX70jnmRfWTPDSreeFWS/ZLWWrx2QEpX2VN3CNTX29Zl9Nepxw8l6DyLVpjHhqNnPf1TL5Z2V0o6PqVhhOZg5s16n6G9JOsJaIZ3o63YPkGhfP6F5VbuSo/w4GLnknqIW62puxbOqpJTon+j6T59wkF8pdXmK+YhtSUj5NnxQ+fCoLT0ADMh+kDRRflhZLbK4FWWQrJGkpGIwkkm9E9CmZYtK4LhhRzypY9AQfOl7HmBIdjSxEONFgxqWIA9NV0jxwnH6EZH7yYgWRbK4GkVozuztUApVccGHcSGuqjzsBsoFWKT1u6DyKr9qqv4/aHfQ38SS0HVDsZOYqdMleSCSm3qIPAquLM14hqgpTuidqZDKm8NgL6dAoNg8LPoS7N5OIfPxJXkauc3uHJTJDX+aQmIRDNX2qN8w4q9lknC6PLiE67hcNKxPDd3yxS3BOVp6srrLLwgjfQoKX07lvBkZOniMjlnGG7PzWYTQWffSjnNjt3NK3ebxL8pj2LpihsUkWigDa/o7EaYj8pI+NXiatfbb2/xXi9urtIvdrAqyUg63R7Q4nTVB2t/0nfu9bHltLrbQQavolhWqYSN6yIUDiLxev1FKOhpbKmNFtqCnU9/+5gkSpipudXakGZCsO9fRb/Fh3GHVWNXlW2Y5kCfXmIMtaQgw/XoTo2W2QeGmCZrHszEcIml0aLUTTB+M4d1s/WRxDC22NJkZhUhw19PPhWNzdkmnVL/lZak4mim3AvW4wlX8tBcFUGA8faOGnuJM9VqxtZorVl7w+DaCWt29a3nW9xxDZVvugjeVuvzluFpzzWGdFtLoc48VovA1HcytptkhyzrP1xKtrOi//s/SawpCEI6SZzwpJuFcpOrmI4yhm8VOjBeL+mfUQVCpqczXkXVb8GgunKNM/j8hM2RQSOHrkF5/4eAFns74RdCSbXH2C8KiK3j89a5+zkVgxj80/euJC4uzVhK+SVKBkcecQMalr6M9046JgL2hXccbZVZ6J64CHclxxJgAVmilhfqXQ08Jb3WX5cBv12tM3gtUSorNHDTKgtJu+m4iE4U5Ie6ltxJw9ThopFYeb4eaVYIwZsv++9ULUW4yNLu5o/fkcq0mvyPcUT6Zf1cTRbhrqw6CLyBz5F4Q2lhfevt/Lv1O48i/AXJ5hd+M+sUcuVuFBSoq3f0lDFox4IocJ7L4Eu3SttKTHS80Mo9fknbO61aivUMZAPz7UcZCuzfziux+PlNqd1xa6zavAIH/vbiCT00lF1KDmovX3XX6RS2ybkYEpkK3nBNs2cMVK6KDHsFftJMIjV07Z93K+7rHOndd5OLL6wsUC/k5r26TyWUGGbStvH94L+rqp6xqZmEPFM5DgKjEVB3W0Z3ybMBcpJXNgrK9F8VX+zjhzaqxlKp1ctnLvDS7nFW0keMQkdhJst0BcbPz10/hnC4BHX+ZqiPqynGLUTjSd9nlunrl3P6HAlUnydE3pTKLzsk3Gb1F44rtTndqzbgoBuag+bv2gn4okWWfGr/R3cjg6m21Y5gRbwJXwHybfean0ar2YFuDYVdz0eRXTPutA8jNK/DW+b/zyR1w8HIMrvIkm2fGc9TnqSOUZKeiWCqvaFjOwgQI26fX0OziYKHrHb9dhBU+TMT1567GBNepl6/d5bGzgofKMn+lXXX3Xmrj5wk1H0VYunMoun0DI9X68e6eL2+uq0MiM0gpd9JoBqp4xrzsXeNjrc9cFOvSJeSxIU9ZkmoZI9DPNsiexgd9tv0PZyIpFVt7/ciAZWf/H2fnDUt8uT8rtBcV7rEa4iDquMySu9cjadjOJTNspiXgEmTa4/ay3QM8mVzxvvLrgwZtTeuqZOE//Z62wnGkBTUiF+i53Im0EkpCtKb2r+Co+CUVXRTSn7d6MToYm7/5dg2Us4gColr5QBW1Hu1zanlRIysCPNxpCF7RzKRsM6JoX+17BZgaVXFY5mFM3YLm9wp05N23dB4V3zuTEKmfxn9t3Twg3do2PIenrMKnW33xMubH+sGVBB+HKW/A/MAcz0KSR0TEinISULKZdObX8wm4t7T/LTPov9BlfVY6MSLhmZGzT7UwfEX3PReP8Br/SP2V7Lis5vhe8e24UL3+TcId4ue9HwPCSqx4170ns1ay9Kz1M57sB7iN+fXJDnr7VgYYBLine truncated
@@ -1 +1 @@
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 truncated
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 truncated
@@ -1 +1 @@
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 truncated
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 truncated
@@ -1 +1 @@
eNpteHdUU9v2tRQFlCqKBemIFyUQWui9Su+9GEKoIQlJqNJELh1iVLp0JFTpvSpIF0R67yAgIL3DF+/1vd9933v7jzPG3mvuudbea651zjiBeHcoCu2IgBMVOMIxUBQYgiFM0LhAPArq6gZFY4KyXaAYB4Rtlo62vkGmG8pxjNMBg0Gixfn4wEhHXgQSCgc78kIQLnzu/HxQFxuora0j3B6dZYOw9RoDP2d3hCPdMOzirObmQkAeVn6gmCAPqyBIjJ/wBFpa8rCyuyBsoTACgB0D9cQA/s0AEASgXcAwGDsBAoVDEL/WrO0QKBfwLzZ2GzAaChJi98U7QMG2hBNMX6HNckCgMbgP/xlVERgCgSIJvL8pcIX23o5IHlZbqB0MjIHmQRBwOPSvM+PynKFQJAAMc3SHZv+9C1cMRiJhjhDwLzufExoBLyDgMVA4BoDxQkL/25znhoaiAGB7AgJXrk0IQu4pn44X4frgrPy8wiBegWJPABoDdoTDoGg0AAYmxJON/Mte908DEgxxJpAAfqcGl/335g//xCDQuPeaYIi2/n9QglEQB9x7MMoFJFT2z3WUGxzj6ALF4RV0/tvdb+P/uRPk5efnFSj5D2K0FxyCe28HhqGhVf+xGYpBeQEgCAIHLh2YDUEgnB2huLEda2uInbWNi5SRogrYQMPEy9CQ38DLTFfDGuKMVBRw9tITQMORvK5Cru5K2jB1ASN1FyEAv4igoKAwCAQUAPDzAnn5efkBnnZ2MDUvPXUblJKO11M1LUU5RzWzpyZQL0VDI2GIqZ68speeorCgmzyvjokC2o7X1EkFY6DFr+4KRNrD9Z0Vzbz1HFQ9jBVVRdRcRXiB8rxID3UvDwlWQnRu7o62UrqKYqIIFbSWiqs7Ss9EWV4Zo6ahDlUUAasJu6nKeyipCCKQcDgQ6K1u+I/whEAiAODvCEFAIVHgr/HhX9qAQeH2GAdchphIDgqKRhLKCfoym3BjGDd0YBZBhtCeDrwL4e4IKc7QVv8/Bd/NUiRIEtdgDLXlYQUKsSpCIawCBGesAoLiwiBxIUFWFU2DAoXfXgz+pwJLDFBgONqOoEKlfykeD3FwgztDbfMU/qfW635pnZDIX9GjEDDCIgzhAUCgHO0d4bj0xw3/nxnqiUSgoYDfQeMKTAB6fzcKwFPFgr/rDvBXSeMq/3dBl/0GIVD2YLij91+h43J/1QLEgSCq8t9mJArxy++vjS5oXCY/v/CH35Z/yTSPcDdAAD8QAOSvQWNQjhBCVf46PBKBwgDQUAihV2G8cGM8LmDPXyUpJcgvLAgi5EmC1REOgbnZQvXdbBQRLgSfaAlWJAoKQ4Btaz0BKEIOYI4ujoQ8/vX83QcJ5cb/K8vV/43AIJyhhJaZ85edMBr/CUFBf3n4dYx/E2WJEUb9/wb95sKL/TVAtf+JQkP/EU8myAVd/d/23wwZQHSB57/AAEdb3BgnYWINEhAQERW2sRGxgQDFIBBRMBRkJybELyAkICwKBQsLFikoAxTAEAcoQP8vweLwiqZacppPFSpNAP9UHkAb+feLAg9HoOGOdnbZ+lAUITO4PAgM4WZLaK4oaDaBS0/OFFcuCoXY2UD4BaB2wqIQOwE7gL6aQvG/2P6t06xfnRkPhhGS5w7BlTkISrGLCwkJskuwuoClREFCQOBfL5UX2b+SDbf/fBfIEkF+5a9BYpBoTlPaVZm9NVIUn1B1EE6uavhFIu2K2B3ix+7iTLIGsopit3QkTps8fk6MTflC2GNlk6f5p+0H/c/Wi5ou4GV5HSFNl8frW8ZjNP6X2P1xANO3X3P/i1/mk3UZv9RL6+6MzvCJQh8Zvy/+MrFb5vyX533Wk/7Wx01RF4Sdmw2LBgwp+lXfoYbNvanE8zIHgimR5v7XHOHdF5WtTuWTVGOyiuzaTp9NY/g5EpX30rS9FEd0o4MuHP3B+3spHKIygxrFXackXV5mJ7pCsEwlnXlSr5enXEZiHZFKP6RfWPqI0p63oXttRVljW3uGO6cQbs0OriJzE/5QxbjjyiSB7ZK0L2zEC2xdwbBpRCZxxXk/R/DiVjI3490QMybmMD9J7Ng37ZLglHZ7+Q9V+rqaUfv9AVYRTPtqVd2ed6BEQTy3V+VKyOM9scOnp/Rqg9wZvsIeGeLpjOSsYiBjwM3KKOtPaY/Y+bdw5ppMWUSch+zZ0wm+eUsNRWy2zwu5ouUjYAdS71oOT8+zjT47Plv74H0FXTitt1CNvhKSYko5qygzOPiYqk+/UG5vcf7Vcpfcld2LnJgOZEdS/MpUGSOf37Cs7zPqj/XStugXAOZxrdcDnh0W9nemDyVPOJWF/JSS7HYxb5Te2tmyLQd6jGHimtjq5fcVh667xc9NcMjGtWMyRxjAlacaNLd9tRJAWvBHAWI/G0GsKls/+lL5c+6S6FED2gX+qEnhqJRw2LxztrnlzkZatpasVv4W+8qK0Q3Jhbru+d1wLMVprv0HgyaL2DM4gqkhk2OLsrSR5ydD8O4fJtGWX7an89MBVMJSJ+3ObTF86zeaEr4eT3SQN6MWB0np/tAyoIqrWZs+zCZCvyLlNP/AQPt6kStw/MA7tUWuxaz7tsqRqTvN/SdXP9+YwLPTfj55WnQ8ja3eta0sfu5Dh+sW7XNvHg1CXheLYGYZLlvjdGFpSTq6r7xWJT6xOhOmUl9DeWETxJQpGMqwB+xi4j8ISW7pHWuRBR2Gqn6dErBPmImmqXevoeUY9m373j4063j4MItW8gl94uJpwEAgY7gzN/HZnGd5v2GOG0rxHaWdNjFHAONRtrES/K5EdiKPV9dAZtX71G3J8bIbsYsP9Y7X0sJdPnIoqZdxh/nmHh4xEsuEzG9j0mMPkXWWq6JEtLdyufxO7m1/q3SMmKzUUy7prdNCRlEFjckxOD4gJ6K3a3lHex7J9hH1XhGdxn5nZ6YvxvYkF1ouk6pc/sUtTvxzW3dQ/QDxdxZaFQHr2uLOrHfhvCIGr8/UDGS9ekD19Ssii8PLEBCP24h8vARJxXKPfd1uIzVt/MCjEkr1rbse9tJnigCu1HO/vj+G1EnusapcKG7nJ+7W2bAel1Lkek1zDx36SnToSCuN3vnhSvIHgBekitbPVlkBlI1JbjTmeL9+9HFhVBH91cJnlNFBu/zcMjc27hJJ11h5gyKM9cVH0du007GceFM6y7qrZP2B03yN6cydQ+F11nz2Rw6NNP4glSk678IttqLPIuGHpcFiC5PBaeLMnvNaptdijeibgBrbYd+HD2hdXeQVc2JsfuzWF8/O+Qja2N7d/bN6c2F8O27g/Z9VPeI3+6au9xb4yVK3zF/s5HPuM90v6SbOhVuHpi9ba8RMLd/oHeGwaN8a2t7ZfZURMtImZAS4Xfy8qLyYnIVsZr8FUl5nimA5GG7nxOvobuuERIVzcoT6nbQMn3e9PFWp01s4aCjhf/yIZFVz5DSCX74etqsXdJh+Rjswiepnl3n6eOlhb2jFjPVHi5DM67vc/Y46gjEbiwL30qs3oPO4+h92+A3DZoCf8uYborqLP1Ibi8WmrAebXLK+e/gLHWQrbJZ4oOw8Q9nEn7YlJxZtJFOMCt38yci31VMQ7Z9qGKqFL2VucoLY1SXT5oUOLYXMzlnaURJBFavudi3eGvI5sG+6mDYWq6e0596zD/xu/nHx8ZBCleLkgCw22/drwKBuu075HKv1HS5dNvGXB7BNrladzv7nYd2h29h88h4dClWDO9ULtx7UOEBOGNy4VjpHT6VByEbdhJvpiOajRiaDYug29Fa2eet3r3ynHJHK5/NWTzvb1jOvp5dr8uSRem8BLY9zyA1MWP3qu8WDFWgVHt3nytiuoGLI0bo6P0v9ej5fbzh1wC7wapzAvE8gdZF3TzqSmuUixbcXxp7Jm56Gm1nMy+/7gFCPVjjEur7fOeQRbWn5wLg3NPHWFp1D4lcZIitOTsSVvhQzZdBYwOC9fyzb8zUSeHjvCzGFck8/khOQ5LxS88I4vX+1xu/z7Tq8XMSaPS+tVD1g7FY9C01576Xqk7qwWKhk0NeNswAzfJSOZtdTdH+oZgIX/vnaz2HL0YCLwpG9KuvjSWGu71/Ul7baVQLtLwUehiYEatc/cc//LO3jZNJTzjVeUlD38GHnNdREV3rwZ7szKXDpC/bX9nm6RTbWo0FXVW37s0obC+s6a5IoJHP3JOCnb36QqxX6z3FC5BfbYfPJ20hOz8lrXIAPS3f6Shoc022xt3UrVH74KDxb1Hm39RhnrUdiMqjCIcsyp7X3TqsX5mhI+Z5v5XR+NWV+VXSYKiPT8qSSeD46DJurDBT3HswHxQgyHl2da8honvmzCrjAMuAg78cHQeGC0e3JA64v6r8dKzbkWQjjJBned4PFokEYlxC+cDS1SN3Dn1V4zy0gGhkx40kLaYqHBaPYPykQf7hwf5PVq3H9g+z6JQXdrWD7g1KIyaP9BO/JTGL1vH3/PffJWq1EQNy9oW/zLr3SFSnXR3PT+NIu/hBA3W248jNGlZG7th6dylJEFuJcgA8e3n5wDI4sraFFM0djxfFzuyUbbcL+L3u/mhnwt99hlnd9mzbnifDW+VhnoyDB+fXxGw7NPjUqOxJpL/KgQ3nyyQYT6xvtd506je7XaQHknvspZQ7CC6QamE6NK0wo3qRRTk/g1vGcSQqut8A8A6GJVtalvYUoOtjYsfwDc8V4NmOz2ZbptYU3M/78ZTVVNC2hA6p73g35NaEPqVEragf4fPR6dlFJ/ntDbK6Hnh3QdfaTHJEHnz/a+2ukcGdVkA015fyNlNtRPa5pts5s7JvsjWW5Y7Ik0/lEOlhPc7xmVSPF8Lk6om/lvfPwOXlqySmXuGepg3diCqXz0ryejdTtyoHNlzRFpxFyFlqO7IlbB7w804lq2kY9tU9HLTVFs/KUri8ADSiJnIMMmGkuqL+PzkkWjNIaWl827axnQkaeXYeFnXAiM1MbA0WMvOctpjWHaSzrX6ytJOpLine truncated
eNpteHdUU9v2tRQFVJooFqQjXpVAaIHQOwjSezeEAIE0k1CliVw6xKh06UhHepOqIF0Q6b13Aekdvniv7/3u+97bf2SMvVebZ+051zkjfpkuMCwOjkaR5cFReBgWAsWTNjiiXyYW9swZhsP7ZyBheAe0bbqOtr5BmjMWPszjgMdjcBICAhAMnB+NgaEgcH4oGingIigAQ9rAbG3hKHtcug3a1n3Y9DkXHIVxxnNJmJuLAPkEgWBhPmEQWJBPGGhpyceFRNvCEFwSXHiYGx7w71iAMACHhCAQXHxcMBQU/evI2g6NRUJIabhsIDgYSITLK9MBBrElIZ+4wJDugMbhiR/+E00BBAqFYUhZf2cglth7wDF8HLYwOwQED+Pj8MDhbXOgaBQK9tcTE3OcYDAMAIKAu8Ay/o4lFkIwGAQcCvllF3DEoVF5JH88DIUH4N0xsP825zjjYFgAxJ7kQSzVJkGRfyyg405qHopDkF9MlB9Y6AbA4SFwFAKGwwEQEBKqDMxf9up/GjAQqBMpCeD3xRAz/g7+8E8fNI74XhMC1db/j5QQLNSB+B6CRYJESv55jnVG4eFIGDFTUee/y/02/l85YX5BQX5w0X8kxrmjoMT3dhAEDlbxH8EwPNYdAEWTchBTgBlQNNoJDiOOkFFZW0PtrG2Q0kg3rLuziqOTg4K1KBxv4qAtiHRQQmko6ykigKZqzo/FXEzM7EUNnVwNXQGCYiJiQLA4UEgUIMgP5BfkFwQoqeGdnOwcDcXhQDtje6ythgO/nZG9lv4TPFpLxAjtgQG7oVQ1lJEYJBakpALRx9s+FjGTV7VzwONslLT5gYrCthBXQzGw6mOtx+7GSlq6Ou5QRRcNMFDYSAko72oqImrjYABD22uhRSQ5SJCdXeC20i5iGCdXIbiSBtRUXBWpIm6CVYNoI0BYHaSGtqa8mpqaEByHxjvC9XSV/4FZVEgMAPwNGwQUEQf+Wh/+xRgEDGWPdyCmioOzsDAchiQx2MsMUh/xzji/dBJFYZ2tmUhSR0kXn6qt8X/svpOuRKIrsdbAmcRZQWEOTYg7hxCpGgdQUAIIlBACc6hqGuQp/q5i8D95WWSAhaBwdiRuKv9LDZlQB2eUE8w2R/F/KqD6lwJI1/sLPRaNIB0i0K4ANBZuD0cRUx7W/n9mmBsGjYMBfoMm5pkA9P4eHoDHSnl/axLwl9aJ5f9b6iW/ndBYewgK7vEXdGL2L4VAHUhUK/1txmDRv+r+CkTiiGmCoiIfflv+Rd4cUm+AAEEgAChYhcNj4VCSVn89PAaNxQNwMChpfuHdicN8SIjbL6FKCwuKCoNI9yTJAUdBEc62MH1nGyU0klQTJ8mBwcIQaIhtmgscQqyFoVzQ7gAs2pk0JAGiIjZQWzsRqA0YIPTMwQVb6wb42+6MIVWFQZCkWlgXOBQG+Et3JKSgj24ALOkmEXAknMSGv35/T1iSlAV/caXyvz3waCcYaRhn/WUnrbp/umBhv3D+asa/E6WDSavmfzv9zpUJ/mv9Jx4SJWH/wJMGQuIq/9v+O0MqEJfn9i9nANyWOMxD2liDRCGiEJCNrSAYagu0ExUBC4mKQIF2wjYgKBAGgcAKoHYAKATqAAP8TXtippKplrzmY8VyE8A/+QvQxvz9CspEoXEouJ1dhj6plzAsMQeKQDvbksY3FpahqALQkzclloKFYTBhcUEw2AYKEodCBAHKxnqF/8r2b7an/5r9mRAEiQIuUGKJg7A0l4SIiDCXJAcSIi0OEgEC/3pdvcj4RRmU/ZdbQPZQ6gt/LQqDOHP64vbyjI3BgpjYir0QajXDr5LJF8A3yR+6SLDKGcgpga/rSB7Xu/4cHR73gnJFySVMCE7Y9/mcrBbUn6FKcloD688PVzeMh+l9zgm7IwDW77/2Pme/zEerst5J59YdqW0ho/mest5ffWSjNswFz0+7rcd8rA/rw89Ikeu1cwbMifoVSzDDhq4k8hnZPeHEMHOfS3BUx1l5k2PpGO2wnBKXtuMX00hB7jiVnWRtd6VB3Qj/M7gPZHcnkVtctu9JYfsxRbu72ZGuCCJNWWeG0v3lMa8RuDVM+YfMC0tPcYbTZlyXrThHVFPnQNs42rnB4ZnY9KgPTCn6sDxeaLMo+Ssn+SxnewBiAp1GXnbawx0wt5HwgOVWoBkrW7C3FGH4u3ZRQGKLvcKHCn1dzfDdHl+rUNZd9YoOt5swMn++G8vyRdQxboSB42Mm9b4HqV6irqkSKSzUHGCQMeBaebj15+T7XIIbRHNN1nQynn2ujIlYr5z52gJO2+f5vBEKoYg96XeN+8enGUZf4E9XPnhcwOVP6M1W4i4EJppenVKS7et7SNutny+/MzfzaqFd/sL2WVZkK6Y1PmZxvIRFwHtAzusp3acaGVvcCwDbiNbrXrdWC/ubE/tSRzwqIt7K8Xbb+DfKb+1sORf8XIfx0fWcNQq7Sv2XnWOmR7nlolvwaYPMkPLjJ/Q3vLRiQVqo+77gn3UgDtWNH91Jglm3KPToAC1Cf1QlcpdLOqzfPFnfcOGkLFlJUC99S3hlxeKM4cVedlsyHE50nG75wazJDn6KQrPWpnFvXC2u4/vJHLD9h0mE5dfNidwUAK2o9FGLU3OkwOqV+thvh6Ot1A3YuT5Kxj+0DGijq1Ym9jPIcK8oecw/MDO8nuP1G9nzSGqUbzTruKF6YOpCf+fRxS9XRjO5GL4cPS44nCBUbtuWFz73ZCR2iHe7NAz5Yy6DQ9nYB0pWeJDsjfEHd1RWKiRGlyeDVWuqrp7Z+LOmCQcx7wDbWQX3AhMau4Yb5UD7QWrfxoXsYycj6Gtcqhi4B7yal1r6p+D799IZpB4xxc0d+/b6sYQ4PSA/mXYr7THMcsYqvbtqp03O7ctykGGsjLolmRHH597em1bxPmlTaqTkStTcPb3DleQQ5CduZY2SB8Fe2fsHLOSygTOb+JSofUy15bI4GcP1bF7vo9ub38vhoWPleipFXdVamHBa/2F5ZvhdajImu8Z3DKdhnJ+w75VwyVw3tya7I22PsmGlskkqpV+doyW+NHf41/SSL7EzqApZfyxsS38Xwi9m8PpE3UDOvRNUU7MoNjewAAXxOQ8qxEhSlC102ldv19ExxPTeL7qqsXHL1V7mRAnAm3Tq3f1HvwbFbQ7VM6XN3LjtahuOw2KabPeJB/37XpKtOjLKQzd/PKP4A8APUsPpZ6guAkqGpdbqsjxe3/80O6SE+2bhOcTioF16apkdFX2OYawrv0ITzPHik/gNhokonkxTRsvqi1Q9fhMCdSlsbf0h1dYC9gcOdfQ+INVxRo/8Dc6CL2Ih+8UB4NmxgGQJNrcZLdNLUUZM9cAnm8FLA3sMz5AKSlmRNj+2awqnpj2FbWxvbf9ZuT47shnd+/7Pik6Ja93jl7vyvOXoGmfOtnJ5dlnvFHWQZ6Osg1IWrJ9Eji9c6RrktmjZ6N/c2n6VGjjYLGIEuFH4vKC0kJqdanK3EVpabYpm3xto4cnU0d3UCQwP4eEO8j5qHDhtf3msWq03u1dbJPjwPsWy5uBxqKBCDWJbz38/5YShdwzbwyX7+OH8va6gsknrTxaBaZe3H/TAdYQj1+aEbqdUrsFmiDU/7DLXDBsA3irrb8iqz/5IqisEj1v31SPTl1x9RPYyFNeLXLF2bkGcEo+bE+IK1hJohkSu/WQR2OjMi/BJMgzSyixmq3eE2lUnMOQE9c8HTk1b2l0lgylV3Gqfu97vuWdffzZhDK65av9gx95vyfzT3MN+xQqlsV45QobXN98+3Rad0mkO65u8upwSL/cQ67xNOm09z4M7gjYJudSdOjRqBjcrZ6/frXKAHjE78y62DR3LgDB1urHXUtANB3WsBoWwTdj1DPOmJfdcxyyx8uczVo/bmlfTLqeUavLlUHpsAC0Ps6gNTDi8azokAhQZFO/f4U3dLKNlztK6ODNF93omV28gqdfO72K00IynH12BR2cKho79LNGrC8GVxp+STJycy8nt/oDWiFDcJzx7v7XPJ97Y+IFlp3/0rS0ui8K7PFBOgpqMN2U+ctygLo/ZY/dQrvNbGHD/9ldyGpXOHgwPIN5pseqFcUrPcpX3lxvVmfKhK/b8DNI1gOHrNez0pV3nao+qg6NgUv7f1k58zTLDdTTbH+N6gjRjeTOfr/wcsBzyPcsf3KmwPhwT5V36qjG/0aLqZ38udC8o1k+75pFL7hcZT0eTzlLekaK86nv32i5hR9tTAr7YnUhDil9wvbbP0S2wsR7yv6hm25NeXJdf3VYVTyOVvSOJOn7zg1o932eaB6ow14KYSdjE8LiNXeIFfJi/2V1UC0+xJdzQLVP94an4dE7n3cZDorUehUmfKrcc+7TWzjutLgTc8Op7gcXjmeXEmWXxAdrUNMujcvKZiGBCtgpQwqMvFxQpzHJwcbo2tWHyzwrgLHuvg4K3ABRLDMC1JPQ+e1Hz/VCpNsdClCjF/L4DAo4A4ZGBAiE4OrHqez8rMt02gDhM6KQbA7Q+BhGA5fqsSP7hzOVNeteTyx/kVs9pGK8H2O8VQ03u78Z6jKWRa+Ts+uy4jH3UigNE3+7/PoPskilLvDyUnSyQfPaHEPZW7YWfkWosDz7W4JLYC6gCnfIyAwY27x5CwoqrGHBsEQSJzOntorVmUZ+XXd/MDARbbrIpPHubPO2G9tD5VG2jKMnz7eEbbs1udVo7Chl3av99BeqxWhPrKy23HNuM7lRrAeSfeyun9aHypGtZj43LTGjeJF+dGCWuZvLEKz67DuHrDYqzsi7uyscyIoYPFe6aK8VwGptNNU6szL6Z9BEsqaqgbwzqVdvxqM2tCrpHh11U38vMxa1mFBTlvjckZLvq2QGfTX2WJ3MV8MF5fAsTbavwt6G7OnMl8UZ457NkWydOrnWuupLsYTmKiVwyHYKbeaZmRR3NwKkGunvxvdPAKXVS0TGvhFuxg0dc4lWn+Rk9G+kb5b3rL+kLjkPlLbTgXHEbe/xLine truncated
@@ -0,0 +1 @@
eNrtVnlQFFceRhSjaDzwYNWsaSYcq9IwFwyDMcICAVFghBEEUezpfsP0MNPddvcIg0ciiiaLJbaYVIwohmMQFhUQFVQIKq4xGkxcYgp1EUy8a82uwdXEsOzrAUTXK7uVP1KVTNVUdff7Hd/vfF9W6VLAciRNDaggKR6wGM7DF25TVikLllgAx6+xmQFvoIliTUyctsjCkq0eBp5nuEBfX4whfTCKN7A0Q+I+OG32XSrzNQOOw1IBV6yjCWvrpmUSM5aRwtNpgOIkgTKpXOkt6RORBC5YJmFpE5AESiwcYCXeEpyGICgefggnlwLEDBAM0VsoyorwohNET7PwixGak6xYCC3RBDBBYdyEWQiAKlAVytEUBXjUhPEQPLTIAzMDw+ItLHQj9ZGuKDUAjIAxtzmMLjbQHC9UPRHHHgzHAcOjgMJpgqRShb2pmSTjjRBAL9r1RjI5nijHRU/2dAnlaQAwKGaCmPdmoByPkZQJBonypBnQFl4oi47RpoTPig+LtvWYFioxhjGROCaq+xoh6Ire0FHeyoAnj8vFBKEwaxQvHAjuA+urscLaUIjUR6n2kVY+6tqEQdw2xn5+6NEDBsPToB20t+6CrUd596MyNCeURGF4TNxjJjEWNwglGGv2Vz4WJWuhxECF0hDNk+56D/vdKXxkMh911WOGOSuFCyV6zMSBqoeVeKhSLpfKFajUH5XKDjxmGvCsFcVp6EH4SLq7L4EmQKXyBqFIpvTfyQKOge0MVtugGm/hsophRcHpT0p7e7AwZnZ/P0woDoXVFeqjaMobkcmRKMyKQNd+iEwZqFAGShVIeJS2IqTXjfapdarSshjF6WGtwvqapxQ3WKg0QJSHPLVhWj37I4Z9CkykmeRRkmIssBfsc4PaPwk2uVT8tU59oTwLzDBHou8+Hc+foMMBXqgR40WlfqhMru2NWpbU6vU0bdjXT0AsCbB7m/Zi+X6IvTpeP0XnGRAVSa2Sp6n3rrA+dMXKZ6bioWQ/rmKFWq1+gd3nJQ15muZ/FbQndPfnSD5ayh5p5LnSz8RT3gsaJQnhMHxOkcpkIRoFHZtojdcQ8jC/8LkM7e8/J6mO41kShybFRmZolkc5gMO9z1uFVm+4zMUlNEMh81P4QzTTEZLCTXD3xll0obQIlZuOMCww0RhR1w+UZlMxisy0j4kIoNVdofZX+BEKHQp0egJVqgNUqFotl6E6uTyAUAbIVErCv2gpiQnlMh8ZkkrTqSawB9ejOIYbANozzEJpaGJ0cNSskIr5aCyto2FBtBgsHEVTwBYHWLg/hHLcRFsIuLZZYAt5E40NThRq1AqAYXJ/uM0D9Eod3CthCbGVfWP9cGyLxZ1vv8VW2cSUUKnHB+x9NWeIg/03kJgblXYhaFTXtL/WfSNxvbDrwUc5Q80G5/qaEWvOjq0SPM9e/nJ9tWJS4u+671VHDkdnoNO/xS8dnlFIVzYtumCsSzLHq3648fcroV23T+x+sLLryj8yLNlO55UaPdwNQ4etd7nTWJbpd2Kt07/OahpdbrXHhuSocu4NG6evPp5Z1+b91Z9z5y9GTU1rr+z5urXl+sYr3829vG99+22PCRc7osIriwI3HVF1ByEjK/My97RPqHjt/itef0qvzS7YtPiMfHzQOreIzovNa1bGFl33mDL891WdTUdbbXmj+f1Gp9e3nu5sd1EtcSyVBrw67nZeMDojuPnrsS3cpIiUY+ZwYccWMKamOvtUxBlXP1f0pcUT3e57xe7YodQfH99g1Ic5qj4euTpn9z8jpfrpDZXW3GuD9zN5Za7OI7LmN287pmxYG8zmtGVz4zpDlxgvdlbfGXROvbqpLcJtSu2oRR030lcZ5Voh3xl/tykKTJE3OETmvlvr6a3O1iz+8ONDrxdec0sE1V7x3glbHdMS0rVfCvnWjpspR++sD2c/6/7A/cGyOx1/u9H5koNDd/dAh/Q725e/4+jg8PMwmfMDrv7fVCYBDo9IZDgDnCY7eUEwHVxtSASd3vuULNEaABIHcHinIXNIPUBoPRJH42kcHDCEh2ehrBWwyZKZSCJtQdIoOt0bARmMiRYb0y5gtnKQv5G0hUMYA6BoM/xTohkD9MLZTaXS0BpP28UhY6II1opgUBwjWQ7RQRgwcugZPsCvHDQMr1kfJMEAWIAQdjUrtDETCYbv9hc4hywvAqBAOiJeZhwC4B2eLmrMRGZxohRrDx36h35YjCA5gKSL5igv3h5HTwZmIlpR1IuDwiaaF3GLYAjI+RhazCOJmfpSAeBgWwl4OfeEDLmhAeMRCwWzzCEwfMxkcvuNHv5GD59PD5UBPzM9VP0q6aHyl08PVb84eqj4hdFD5bPpodEcveTN0ERjmHJeiAbzV/5a6KGKCAhQqv43evhjPz1Uzp29YYxsVH3kSW993ga945Avpr8xbONRx6ggZHDYuEO6rbWntpUb5btGu6xrX5M/SD0n/v3tXQ0rGXVt28sTD3ylKjh3KyH8rfs/gHu3789ddOLu1jNn4u9RHabJZfWSeeu/GR9tJB3K9X4EN0zVEnT8brNrvqMl5pDrtnh9NWWpz1xZf9B6Y3xzgr+O6zqwLmfnFyuKCnLbZqyKktR6+BKVzcuyDq67cHOk85YjLkcWbJl1+/6GS8feULwvD/nk5q0YF2cm0n3QfOfhiuGJftygGd/hThcnnUz0UL7nYfLEsgMTB16b5tZudG27dOktn+u5s152TLpau0b/b2ztwi1DNJeTh1RnFYS+s+s0+oc/lr1yiFl0YsyQcTXJiXGTOzaj+zLmqG0L35uWPb6rMXThpzL0wmDFcGKUJ+k0quXz6m93blSdnLx86znVyfjvu+VOXiPkx0bcDbJJC6dmn6KGzlZ3HDbdUOXu+0vW6c8ap2rKXhvAGhbp3m7ks842NBrdZ7u/fX7/hM+XFzrgfhH7BrksPJhyyTV614YFbi2f7k5vwtLyKpcd1gRGN21P7o6xlqjVgZEl7TXEvF2btyRoklxSNhVs+zChggBkedHm/A/yhYkFyZudR9RkaJ0GS78vbGkaO6fux7MuxOiQgafOJ4llFnnmkY0F4Vchz/wPnx2zzA==
@@ -1 +0,0 @@
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
@@ -1 +0,0 @@
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
@@ -1 +0,0 @@
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
@@ -0,0 +1 @@
eNqNVX1sE2UYLxkYQlyiEf5QEzgbBon0be96t3YdYFy2AYPsg7WCfDnf3r1tj13vPe59b6GDiU6UEIx6MQrGj8DWtVgX2AIJjA9jIhBiQCVgTBNi0BiNGogxkohR53tduw+3AfdXe+/z+z2/3/M873Pd2Q5kEhXrM/pVnSITypT9IXZ31kTbLETo7kwS0QRW0i3N4UivZar5igSlBqn2+aCheqFOEyY2VNkr46SvQ/AlESEwjkg6ipVU/q0d7iTc3kZxO9KJu1rg/ZLHXQpxV2/a4TaxhtzVbosg0+1xy5iJ0Cl7sd5UKeIgRxLYpNxWRsDBKLYoJydUucDWtYVRYQVpLFrWoKUgIIIgIFjXEQUapEw9o6QoaTBf1DJZHt7Ld2UTCCrM9Leuh9MJTKg9OMnIUSjLyKAA6TJWVD1uH4t3qoaHU1DM4fVwnYQqOdnJVKiXnWtHyABQUzvQse2AUKjqGnMJqJpETLT9UVNzpG1lw7r6pswItT0ADUNTZejAfVuZ6P6id0BTBpp8nHMqBFjZdGqfqCmJ9bWkWHN0jvdKIS8/MD61BpnujFE4Pz3+wIByO+MBxcbbmRHwkfExmNh9jVBuDk+ghKacsPugmQxIE1yalu4YtbO1LZPTFQ/H0oleQfCGBicQk5Qu230xqBE0ONqJUUjOz/tFwAcAL5yYQI2omQIyZhnsQ/yRUgE1pMdpwu4VpOBhExGDzTN6OcNg1CLdadZRdOlitjiEPc1rxubh0XQd6659thHrHk7wc40wxbHUlZwgVYtSNV/FrWyM9NcW00Sm7NNgxIQ6ibFe1ZeGJysnLL0dKbnaKQcmv2jMMZtTpKlJlQJVNyw2C4WLAwqv7Iyfd578k/eMN1GS1cjJXcIsug8MQdQ+7vgFfCUQ/JGS6435xVOh2VxPkthXVci25N7xYxKLmMX3g5leonsqeHGHldSlpWlLMRo5pisthkKhe/BOqyi4Mc9NhfxfQ0esL7xL5PhWjkRzd42etkK5omigKvYZ9ruNF4TaFhGHhTXtJCAlOyuDIX8y1h4eItRUZUbpDLLBti8gSGaLn6bsvIdtc2cJLReFSjHA1CzlVF3W2O4NW9E67EglSznDRBqGytCYUGzGoa52Fq6JIyC/UAwFxEpFjAIUjSlAClUFQSjkF0DU769SpCohKCmB3g4V2jnBK3BxjOMaOirHgAzlBAIjl9nO1m1oqmlsqO1/FrTiKGYNiUDWOB3rKBNGJtsfdk7WsKWwtW2iTO0K0FqzwT4eEhGE/pAUUIJRKcr2Sv361oHStR69tmln5xc+Yy9lnJLo8fMz5i3YN9tVeMqUN2rWnOPn7h5evfOnuaeesS/X/3ajYdbaudv6zv2QvxBrO5XyfWX9vGv/ls0ty8ovBUV+6ez5D/YPtf96/vLVz06eOT184PrNgYZv/F3L37k1S7rYca5rzrvJPQefyJ4MesjzgwsPwg+WreBv9ID5H1/9pef7ut2tlRZ5LrivImHsndnw6Zlbr/d2X/3khYfKvvxn3Z0bb/9xePOC6y+mnwpz6OvTFbuGeuZtOXTslbWz1p69PWfxHsG99/eh/g3dj/8588dguUfVxI1NMx94c+eSikf+dl1orDFnv7r6tcc+/+69fM3BwVVL1Kej/D6x/ItT8zftv7J61bV/y6+t/PDKX8OeeXduSreX7SpzuYaHy1zvH15VZs1wuf4DgoVD8g==
+11
View File
@@ -0,0 +1,11 @@
# Additional resources
This section contains additional resources for LangGraph.
- [Community agents](../agents/prebuilt.md): A collection of prebuilt libraries that you can use in your LangGraph applications.
- [LangGraph Academy](https://academy.langchain.com/courses/intro-to-langgraph): A collection of courses that teach you how to use LangGraph.
- [Case studies](../adopters.md): A collection of case studies that show how LangGraph is used in production.
- [FAQ](../concepts/faq.md): A collection of frequently asked questions about LangGraph.
- [llms.txt](../llms-txt-overview.md): A list of documentation files in the `llms.txt` format that allow LLMs and agents to access our documentation.
- [LangChain Forum](https://forum.langchain.com/): A place to ask questions and get help from other LangGraph users.
- [Troubleshooting](../troubleshooting/errors/index.md): A collection of troubleshooting guides for common issues.
+23 -6
View File
@@ -8,24 +8,41 @@ This list of companies using LangGraph and their success stories is compiled fro
| [AirTop](https://www.airtop.ai/) | Software & Technology (GenAI Native) | Browser automation for AI agents | [Case study, 2024](https://blog.langchain.dev/customers-airtop/) |
| [AppFolio](https://www.appfolio.com/) | Real Estate | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-appfolio/) |
| [Athena Intelligence](https://www.athenaintel.com/) | Software & Technology (GenAI Native) | Research & summarization | [Case study, 2024](https://blog.langchain.dev/customers-athena-intelligence/) |
| [BlackRock](https://www.blackrock.com/) | Financial Services | Copilot for domain-specific task | [Interrupt talk, 2025](https://youtu.be/oyqeCHFM5U4?feature=shared) |
| [Captide](https://www.captide.co/) | Software & Technology (GenAI Native) | Data extraction | [Case study, 2025](https://blog.langchain.dev/how-captide-is-redefining-equity-research-with-agentic-workflows-built-on-langgraph-and-langsmith/) |
| [Cisco Outshift](https://outshift.cisco.com/) | Software & Technology | DevOps | [Blog post, 2025](https://outshift.cisco.com/blog/build-react-agent-application-for-devops-tasks-using-rest-apis) |
| [Cisco CX](https://www.cisco.com/site/us/en/services/modern-data-center/index.html?CCID=cc005911&DTID=eivtotr001480&OID=srwsas032775) | Software & Technology | Customer support | [Interrupt Talk, 2025](https://youtu.be/gPhyPRtIMn0?feature=shared) |
| [Cisco Outshift](https://outshift.cisco.com/) | Software & Technology | DevOps | [Video story, 2025](https://www.youtube.com/watch?v=htcb-vGR_x0); [Case study, 2025](https://blog.langchain.com/cisco-outshift/); [Blog post, 2025](https://outshift.cisco.com/blog/build-react-agent-application-for-devops-tasks-using-rest-apis) |
| [Cisco TAC](https://www.cisco.com/c/en/us/support/index.html) | Software & Technology | Customer support | [Video story, 2025](https://youtu.be/EAj0HBDGqaE?feature=shared) |
| [City of Hope](https://www.cityofhope.org/) | Non-profit | Copilot for domain-specific task | [Video story, 2025](https://youtu.be/9ABwtK2gIZU?feature=shared) |
| [C.H. Robinson](https://www.chrobinson.com/en-us/) | Logistics | Automation | [Case study, 2025](https://blog.langchain.dev/customers-chrobinson/) |
| [Definely](https://www.definely.com/) | Legal | Copilot for domain-specific task | [Case study, 2025](https://blog.langchain.com/customers-definely/) |
| [Docent Pro](https://docentpro.com/) | Travel | GenAI embedded product experiences | [Case study, 2025](https://blog.langchain.com/customers-docentpro/) |
| [Elastic](https://www.elastic.co/) | Software & Technology | Copilot for domain-specific task | [Blog post, 2025](https://www.elastic.co/blog/elastic-security-generative-ai-features) |
| [Exa](https://exa.ai/) | Software & Technology (GenAI Native) | Search | [Case study, 2025](https://blog.langchain.com/exa/) |
| [GitLab](https://about.gitlab.com/) | Software & Technology | Code generation | [Duo workflow docs](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/duo_workflow/) |
| [Harmonic](https://harmonic.ai/) | Software & Technology | Search | [Case study, 2025](https://blog.langchain.com/customers-harmonic/) |
| [Inconvo](https://inconvo.ai/?ref=blog.langchain.dev) | Software & Technology | Code generation | [Case study, 2025](https://blog.langchain.dev/customers-inconvo/) |
| [Infor](https://infor.com/) | Software & Technology | GenAI embedded product experiences; customer support; copilot | [Case study, 2025](https://blog.langchain.dev/customers-infor/) |
| [J.P. Morgan](https://www.jpmorganchase.com/) | Financial Services | Copilot for domain-specific task | [Interrupt talk, 2025](https://youtu.be/yMalr0jiOAc?feature=shared) |
| [Klarna](https://www.klarna.com/) | Fintech | Copilot for domain-specific task | [Case study, 2025](https://blog.langchain.dev/customers-klarna/) |
| [Komodo Health](https://www.komodohealth.com/) | Healthcare | Copilot for domain-specific task | [Blog post](https://www.komodohealth.com/perspectives/new-gen-ai-assistant-empowers-the-enterprise/) |
| [LinkedIn](https://www.linkedin.com/) | Social Media | Code generation; Search & discovery | [Blog post, 2025](https://www.linkedin.com/blog/engineering/ai/practical-text-to-sql-for-data-analytics); [Blog post, 2024](https://www.linkedin.com/blog/engineering/generative-ai/behind-the-platform-the-journey-to-create-the-linkedin-genai-application-tech-stack) |
| [LinkedIn](https://www.linkedin.com/) | Social Media | Code generation; Search & discovery | [Interrupt talk, 2025](https://youtu.be/NmblVxyBhi8?feature=shared); [Blog post, 2025](https://www.linkedin.com/blog/engineering/ai/practical-text-to-sql-for-data-analytics); [Blog post, 2024](https://www.linkedin.com/blog/engineering/generative-ai/behind-the-platform-the-journey-to-create-the-linkedin-genai-application-tech-stack) |
| [Minimal](https://gominimal.ai/) | E-commerce | Customer support | [Case study, 2025](https://blog.langchain.dev/how-minimal-built-a-multi-agent-customer-support-system-with-langgraph-langsmith/) |
| [Modern Treasury](https://www.moderntreasury.com/) | Fintech | GenAI embedded product experiences | [Video story, 2025](https://youtu.be/AwAiffXqaCU?feature=shared) |
| [Monday](https://monday.com/) | Software & Technology | GenAI embedded product experiences | [Interrupt talk, 2025](https://blog.langchain.dev/how-minimal-built-a-multi-agent-customer-support-system-with-langgraph-langsmith/) |
| [Morningstar](https://www.morningstar.com/) | Financial Services | Research & summarization | [Video story, 2025](https://youtu.be/6LidoFXCJPs?feature=shared) |
| [OpenRecovery](https://www.openrecovery.com/) | Healthcare | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-openrecovery/) |
| [Pigment](https://www.pigment.com/) | Fintech | GenAI embedded product experiences | [Video story, 2025](https://youtu.be/5JVSO2KYOmE?feature=shared) |
| [Prosper](https://www.prosper.com/) | Fintech | Customer support | [Video story, 2025](https://youtu.be/9RFNOYtkwsc?feature=shared) |
| [Qodo](https://www.qodo.ai/) | Software & Technology (GenAI Native) | Code generation | [Blog post, 2025](https://www.qodo.ai/blog/why-we-chose-langgraph-to-build-our-coding-agent/) |
| [Rakuten](https://www.rakuten.com/) | E-commerce / Fintech | Copilot for domain-specific task | [Blog post, 2025](https://rakuten.today/blog/from-ai-hype-to-real-world-tools-rakuten-teams-up-with-langchain.html) |
| [Rakuten](https://www.rakuten.com/) | E-commerce / Fintech | Copilot for domain-specific task | [Video story, 2025](https://youtu.be/gD1LIjCkuA8?feature=shared); [Blog post, 2025](https://rakuten.today/blog/from-ai-hype-to-real-world-tools-rakuten-teams-up-with-langchain.html) |
| [Replit](https://replit.com/) | Software & Technology | Code generation | [Blog post, 2024](https://blog.langchain.dev/customers-replit/); [Breakout agent story, 2024](https://www.langchain.com/breakoutagents/replit); [Fireside chat video, 2024](https://www.youtube.com/watch?v=ViykMqljjxU) |
| [Rexera](https://www.rexera.com/) | Real Estate (GenAI Native) | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-rexera/) |
| [Abu Dhabi Government](https://www.tamm.abudhabi/) | Government | Search | [Case study, 2025](https://blog.langchain.com/customers-abu-dhabi-government/) |
| [Tradestack](https://www.tradestack.uk/) | Software & Technology (GenAI Native) | Copilot for domain-specific task | [Case study, 2024](https://blog.langchain.dev/customers-tradestack/) |
| [Uber](https://www.uber.com/) | Transportation | Developer productivity; Code generation | [Presentation, 2024](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/); [Video, 2024](https://www.youtube.com/watch?v=8rkA5vWUE4Y) |
| [Unify](https://www.unifygtm.com/) | Software & Technology (GenAI Native) | Copilot for domain-specific task | [Blog post, 2024](https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/) |
| [Vizient](https://www.vizientinc.com/) | Healthcare | Copilot for domain-specific task | [Case study, 2025](https://blog.langchain.dev/p/3d2cd58c-13a5-4df9-bd84-7d54ed0ed82c/) |
| [Uber](https://www.uber.com/) | Transportation | Developer productivity; Code generation | [Interrupt talk, 2025](https://youtu.be/Bugs0dVcNI8?feature=shared); [Presentation, 2024](https://dpe.org/sessions/ty-smith-adam-huda/this-year-in-ubers-ai-driven-developer-productivity-revolution/); [Video, 2024](https://www.youtube.com/watch?v=8rkA5vWUE4Y) |
| [Unify](https://www.unifygtm.com/) | Software & Technology (GenAI Native) | Copilot for domain-specific task | [Interrupt talk, 2025](https://youtu.be/pKk-LfhujwI?feature=shared); [Blog post, 2024](https://blog.langchain.dev/unify-launches-agents-for-account-qualification-using-langgraph-and-langsmith/) |
| [Vizient](https://www.vizientinc.com/) | Healthcare | Copilot for domain-specific task | [Video story, 2025](https://www.youtube.com/watch?v=vrjJ6NuyTWA); [Case study, 2025](https://blog.langchain.dev/p/3d2cd58c-13a5-4df9-bd84-7d54ed0ed82c/) |
| [Vodafone](https://www.vodafone.com/) | Telecommunications | Code generation; internal search | [Case study, 2025](https://blog.langchain.dev/customers-vodafone/) |
| [WebToon](https://www.webtoons.com/en/) | Media & Entertainment | Data extraction | [Case study, 2025](https://blog.langchain.com/customers-webtoon/) |
| [11x](https://www.11x.ai/) | Software & Technology (GenAI Native) | Research & outreach | [Interrupt talk, 2025](https://youtu.be/fegwPmaAPQk?feature=shared) |
+236 -12
View File
@@ -15,23 +15,40 @@ This guide shows you how to set up and use LangGraph's **prebuilt**, **reusable*
Before you start this tutorial, ensure you have the following:
- An [Anthropic](https://console.anthropic.com/settings/admin-keys) API key
- An [Anthropic](https://console.anthropic.com/settings/keys) API key
## 1. Install dependencies
If you haven't already, install LangGraph and LangChain:
:::python
```
pip install -U langgraph "langchain[anthropic]"
```
!!! info
!!! info
LangChain is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/).
`langchain[anthropic]` is installed so the agent can call the [model](https://python.langchain.com/docs/integrations/chat/).
:::
:::js
```bash
npm install @langchain/langgraph @langchain/core @langchain/anthropic
```
!!! info
`@langchain/core` `@langchain/anthropic` are installed so the agent can call the [model](https://js.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
To create an agent, use @[`create_react_agent`][create_react_agent]:
```python
from langgraph.prebuilt import create_react_agent
@@ -52,13 +69,56 @@ agent.invoke(
)
```
1. Define a tool for the agent to use. Tools can be defined as vanilla Python functions. For more advanced tool usage and customization, check the [tools](./tools.md) page.
1. Define a tool for the agent to use. Tools can be defined as vanilla Python functions. For more advanced tool usage and customization, check the [tools](../how-tos/tool-calling.md) page.
2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page.
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.
:::
:::js
To create an agent, use [`createReactAgent`](https://langchain-ai.github.io/langgraphjs/reference/functions/langgraph_prebuilt.createReactAgent.html):
```typescript
import { ChatAnthropic } from "@langchain/anthropic";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { tool } from "@langchain/core/tools";
import { z } from "zod";
const getWeather = tool(
// (1)!
async ({ city }) => {
return `It's always sunny in ${city}!`;
},
{
name: "get_weather",
description: "Get weather for a given city.",
schema: z.object({
city: z.string().describe("The city to get weather for"),
}),
}
);
const agent = createReactAgent({
llm: new ChatAnthropic({ model: "anthropic:claude-3-5-sonnet-latest" }), // (2)!
tools: [getWeather], // (3)!
stateModifier: "You are a helpful assistant", // (4)!
});
// Run the agent
await agent.invoke({
messages: [{ role: "user", content: "what is the weather in sf" }],
});
```
1. Define a tool for the agent to use. Tools can be defined using the `tool` function. For more advanced tool usage and customization, check the [tools](./tools.md) page.
2. Provide a language model for the agent to use. To learn more about configuring language models for the agents, check the [models](./models.md) page.
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.
:::
## 3. Configure an LLM
:::python
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
@@ -79,19 +139,45 @@ agent = create_react_agent(
)
```
:::
:::js
To configure an LLM with specific parameters, such as temperature, use a model instance:
```typescript
import { ChatAnthropic } from "@langchain/anthropic";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
// highlight-next-line
const model = new ChatAnthropic({
model: "claude-3-5-sonnet-latest",
// highlight-next-line
temperature: 0,
});
const agent = createReactAgent({
// highlight-next-line
llm: model,
tools: [getWeather],
});
```
:::
For more information on how to configure LLMs, see [Models](./models.md).
## 4. Add a custom prompt
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 prompt"
Define a fixed prompt string or list of messages:
:::python
```python
from langgraph.prebuilt import create_react_agent
@@ -107,9 +193,30 @@ Prompts instruct the LLM how to behave. Add one of the following types of prompt
{"messages": [{"role": "user", "content": "what is the weather in sf"}]}
)
```
:::
:::js
```typescript
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { ChatAnthropic } from "@langchain/anthropic";
const agent = createReactAgent({
llm: new ChatAnthropic({ model: "anthropic:claude-3-5-sonnet-latest" }),
tools: [getWeather],
// A static prompt that never changes
// highlight-next-line
stateModifier: "Never answer questions about the weather."
});
await agent.invoke({
messages: [{ role: "user", content: "what is the weather in sf" }]
});
```
:::
=== "Dynamic prompt"
:::python
Define a function that returns a message list based on the agent's state and configuration:
```python
@@ -144,12 +251,52 @@ Prompts instruct the LLM how to behave. Add one of the following types of prompt
- 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.
:::
:::js
Define a function that returns messages based on the agent's state and configuration:
```typescript
import { type BaseMessageLike } from "@langchain/core/messages";
import { type RunnableConfig } from "@langchain/core/runnables";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
// highlight-next-line
const dynamicPrompt = (state: { messages: BaseMessageLike[] }, config: RunnableConfig): BaseMessageLike[] => { // (1)!
const userName = config.configurable?.user_name;
const systemMsg = `You are a helpful assistant. Address the user as ${userName}.`;
return [{ role: "system", content: systemMsg }, ...state.messages];
};
const agent = createReactAgent({
llm: "anthropic:claude-3-5-sonnet-latest",
tools: [getWeather],
// highlight-next-line
stateModifier: dynamicPrompt
});
await agent.invoke(
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
// highlight-next-line
{ configurable: { user_name: "John Smith" } }
);
```
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.
:::
For more information, see [Context](./context.md).
## 5. Add 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
```python
from langgraph.prebuilt import create_react_agent
@@ -180,17 +327,60 @@ ny_response = agent.invoke(
)
```
1. `checkpointer` allows the agent to store its state at every step in the tool calling loop. This enables [short-term memory](./memory.md#short-term-memory) and [human-in-the-loop](./human-in-the-loop.md) capabilities.
1. `checkpointer` allows the agent to store its state at every step in the tool calling loop. This enables [short-term memory](../how-tos/memory/add-memory.md#add-short-term-memory) and [human-in-the-loop](../concepts/human_in_the_loop.md) capabilities.
2. Pass configuration with `thread_id` to be able to resume the same conversation on future agent invocations.
:::
:::js
```typescript
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MemorySaver } from "@langchain/langgraph";
// highlight-next-line
const checkpointer = new MemorySaver();
const agent = createReactAgent({
llm: "anthropic:claude-3-5-sonnet-latest",
tools: [getWeather],
// highlight-next-line
checkpointSaver: checkpointer, // (1)!
});
// Run the agent
// highlight-next-line
const config = { configurable: { thread_id: "1" } };
const sfResponse = await agent.invoke(
{ messages: [{ role: "user", content: "what is the weather in sf" }] },
// highlight-next-line
config // (2)!
);
const nyResponse = await agent.invoke(
{ messages: [{ role: "user", content: "what about new york?" }] },
// highlight-next-line
config
);
```
1. `checkpointSaver` allows the agent to store its state at every step in the tool calling loop. This enables [short-term memory](../how-tos/memory/add-memory.md#add-short-term-memory) and [human-in-the-loop](../concepts/human_in_the_loop.md) capabilities.
2. Pass configuration with `thread_id` to be able to resume the same conversation on future agent invocations.
:::
:::python
When you enable the checkpointer, it stores agent state at every step in the provided checkpointer database (or in memory, if using `InMemorySaver`).
:::
:::js
When you enable the checkpointer, it stores agent state at every step in the provided checkpointer database (or in memory, if using `MemorySaver`).
:::
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.
For more information, see [Memory](./memory.md).
For more information, see [Memory](../how-tos/memory/add-memory.md).
## 6. Configure structured output
:::python
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.
```python
@@ -215,9 +405,43 @@ response = agent.invoke(
response["structured_response"]
```
1. When `response_format` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
1. When `response_format` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
To provide a system prompt to this LLM, use a tuple `(prompt, schema)`, e.g., `response_format=(prompt, WeatherResponse)`.
To provide a system prompt to this LLM, use a tuple `(prompt, schema)`, e.g., `response_format=(prompt, WeatherResponse)`.
:::
:::js
To produce structured responses conforming to a schema, use the `responseFormat` parameter. The schema can be defined with a `Zod` schema. The result will be accessible via the `structuredResponse` field.
```typescript
import { z } from "zod";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const WeatherResponse = z.object({
conditions: z.string(),
});
const agent = createReactAgent({
llm: "anthropic:claude-3-5-sonnet-latest",
tools: [getWeather],
// highlight-next-line
responseFormat: WeatherResponse, // (1)!
});
const response = await agent.invoke({
messages: [{ role: "user", content: "what is the weather in sf" }],
});
// highlight-next-line
response.structuredResponse;
```
1. When `responseFormat` is provided, a separate step is added at the end of the agent loop: agent message history is passed to an LLM with structured output to generate a structured response.
To provide a system prompt to this LLM, use an object `{ prompt, schema }`, e.g., `responseFormat: { prompt, schema: WeatherResponse }`.
:::
!!! Note "LLM post-processing"
@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 106.265625 233.5625" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaiLine truncated

After

Width:  |  Height:  |  Size: 9.3 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 215.640625 248.5625" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaiLine truncated

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 165.203125 332.75" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-Line truncated

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 215.640625 347.75" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-Line truncated

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 172.3125 332.75" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svLine truncated

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 245.04296875 347.75" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaiLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 172.3125 431.9375" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-Line truncated

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 245.04296875 446.9375" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermLine truncated

After

Width:  |  Height:  |  Size: 14 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 263.921875 332.75" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-Line truncated

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 377.71875 332.75" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-sLine truncated

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 263.921875 431.9375" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaiLine truncated

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 377.71875 431.9375" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaidLine truncated

After

Width:  |  Height:  |  Size: 14 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 263.921875 431.9375" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaiLine truncated

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 377.71875 431.9375" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaidLine truncated

After

Width:  |  Height:  |  Size: 14 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 263.921875 531.125" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaidLine truncated

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1 @@
<svg id="mermaid-svg" xmlns="http://www.w3.org/2000/svg" class="flowchart" style="max-width: 100%; background-color: white;" viewBox="0 0 377.71875 531.125" role="graphics-document document" aria-roledescription="flowchart-v2" height="500px" xmlns:xlink="http://www.w3.org/1999/xlink"><style xmlns="http://www.w3.org/1999/xhtml">@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css");</style><style>#mermaid-svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg .error-icon{fill:#552222;}#mermaid-svg .error-text{fill:#552222;stroke:#552222;}#mermaid-svg .edge-thickness-normal{stroke-width:1px;}#mermaid-svg .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg .marker{fill:#333333;stroke:#333333;}#mermaid-svg .marker.cross{stroke:#333333;}#mermaid-svg svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg p{margin:0;}#mermaid-svg .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg .cluster-label text{fill:#333;}#mermaid-svg .cluster-label span{color:#333;}#mermaid-svg .cluster-label span p{background-color:transparent;}#mermaid-svg .label text,#mermaid-svg span{fill:#333;color:#333;}#mermaid-svg .node rect,#mermaid-svg .node circle,#mermaid-svg .node ellipse,#mermaid-svg .node polygon,#mermaid-svg .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg .rough-node .label text,#mermaid-svg .node .label text,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-anchor:middle;}#mermaid-svg .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg .rough-node .label,#mermaid-svg .node .label,#mermaid-svg .image-shape .label,#mermaid-svg .icon-shape .label{text-align:center;}#mermaid-svg .node.clickable{cursor:pointer;}#mermaid-svg .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg .arrowheadPath{fill:#333333;}#mermaid-svg .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg .cluster text{fill:#333;}#mermaid-svg .cluster span{color:#333;}#mermaid-svg div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg rect.text{fill:none;stroke-width:0;}#mermaid-svg .icon-shape,#mermaid-svg .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg .icon-shape p,#mermaid-svg .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg .icon-shape rect,#mermaid-svg .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg .default&gt;*{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .default span{fill:#f2f0ff!important;line-height:1.2!important;}#mermaid-svg .first&gt;*{fill-opacity:0!important;}#mermaid-svg .first span{fill-opacity:0!important;}#mermaid-svg .last&gt;*{fill:#bfb6fc!important;}#mermaid-svg .last span{fill:#bfb6fc!important;}</style><g><marker id="mermaid-svg_flowchart-v2-pointEnd" class="marker flowchart-v2" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-svg_flowchart-v2-pointStart" class="marker flowchart-v2" viewBox="0 0 10 10" refX="4.5" refY="5" markerUnits="userSpaceOnUse" markerWidth="8" markerHeight="8" orient="auto"><path d="M 0 5 L 10 10 L 10 0 z" class="arrowMarkerPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/></marker><marker id="mermaid-Line truncated

After

Width:  |  Height:  |  Size: 16 KiB

+224 -152
View File
@@ -1,147 +1,176 @@
---
search:
boost: 2
tags:
- agent
hide:
- tags
---
# Context
Agents often require more than a list of messages to function effectively. They need **context**.
**Context engineering** is the practice of building dynamic systems that provide the right information and tools, in the right format, so that an AI application can accomplish a task. Context can be characterized along two key dimensions:
Context includes *any* data outside the message list that can shape agent behavior or tool execution. This can be:
1. By **mutability**:
- **Static context**: Immutable data that doesn't change during execution (e.g., user metadata, database connections, tools)
- **Dynamic context**: Mutable data that evolves as the application runs (e.g., conversation history, intermediate results, tool call observations)
2. By **lifetime**:
- **Runtime context**: Data scoped to a single run or invocation
- **Cross-conversation context**: Data that persists across multiple conversations or sessions
- Information passed at runtime, like a `user_id` or API credentials.
- Internal state updated during a multi-step reasoning process.
- Persistent memory or facts from previous interactions.
!!! tip "Runtime context vs LLM context"
LangGraph provides **three** primary ways to supply context:
Runtime context refers to local context: data and dependencies your code needs to run. It does **not** refer to:
| Type | Description | Mutable? | Lifetime |
|------------------------------------------------------------------------------|-----------------------------------------------|----------|-------------------------|
| [**Config**](#config-static-context) | data passed at the start of a run | ❌ | per run |
| [**State**](#state-mutable-context) | dynamic data that can change during execution | ✅ | per run or conversation |
| [**Long-term Memory (Store)**](#long-term-memory-cross-conversation-context) | data that can be shared between conversations | ✅ | across conversations |
* The LLM context, which is the data passed into the LLM's prompt.
* The "context window", which is the maximum number of tokens that can be passed to the LLM.
You can use context to:
Runtime context can be used to optimize the LLM context. For example, you can use user metadata
in the runtime context to fetch user preferences and feed them into the context window.
- Adjust the system prompt the model sees
- Feed tools with necessary inputs
- Track facts during an ongoing conversation
LangGraph provides three ways to manage context, which combines the mutability and lifetime dimensions:
## Providing Runtime Context
:::python
Use this when you need to inject data into an agent at runtime.
| Context type | Description | Mutability | Lifetime | Access method |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ---------- | ------------------ | --------------------------------------- |
| [**Static runtime context**](#static-runtime-context) | User metadata, tools, db connections passed at startup | Static | Single run | `context` argument to `invoke`/`stream` |
| [**Dynamic runtime context (state)**](#dynamic-runtime-context-state) | Mutable data that evolves during a single run | Dynamic | Single run | LangGraph state object |
| [**Dynamic cross-conversation context (store)**](#dynamic-cross-conversation-context-store) | Persistent data shared across conversations | Dynamic | Cross-conversation | LangGraph store |
### Config (static context)
## Static runtime context
Config is for immutable data like user metadata or API keys. Use
when you have values that don't change mid-run.
**Static runtime context** represents immutable data like user metadata, tools, and database connections that are passed to an application at the start of a run via the `context` argument to `invoke`/`stream`. This data does not change during execution.
Specify configuration using a key called **"configurable"** which is reserved
for this purpose:
!!! version-added "New in LangGraph v0.6: `context` replaces `config['configurable']`"
Runtime context is now passed to the `context` argument of `invoke`/`stream`,
which replaces the previous pattern of passing application configuration to `config['configurable']`.
```python
agent.invoke(
{"messages": [{"role": "user", "content": "hi!"}]},
# highlight-next-line
config={"configurable": {"user_id": "user_123"}}
)
```
### State (mutable context)
State acts as short-term memory during a run. It holds dynamic data that can evolve during execution, such as values derived from tools or LLM outputs.
```python
class CustomState(AgentState):
# highlight-next-line
@dataclass
class ContextSchema:
user_name: str
agent = create_react_agent(
# Other agent parameters...
graph.invoke( # (1)!
{"messages": [{"role": "user", "content": "hi!"}]}, # (2)!
# highlight-next-line
state_schema=CustomState,
context={"user_name": "John Smith"} # (3)!
)
agent.invoke({
"messages": "hi!",
"user_name": "Jane"
})
```
!!! tip "Turning on memory"
1. This is the invocation of the agent or graph. The `invoke` method runs the underlying graph with the provided input.
2. This example uses messages as an input, which is common, but your application may use different input structures.
3. This is where you pass the runtime data. The `context` parameter allows you to provide additional dependencies that the agent can use during its execution.
Please see the [memory guide](./memory.md) for more details on how to enable memory. This is a powerful feature that allows you to persist the agent's state across multiple invocations.
Otherwise, the state is scoped only to a single agent run.
### Long-Term Memory (cross-conversation context)
For context that spans *across* conversations or sessions, LangGraph allows access to **long-term memory** via a `store`. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions). For more, see the [Memory guide](./memory.md).
## Customizing Prompts with Context { #prompts }
Prompts define how the agent behaves. To incorporate runtime context, you can dynamically generate prompts based on the agent's state or config.
Common use cases:
- Personalization
- Role or goal customization
- Conditional behavior (e.g., user is admin)
=== "Using config"
=== "Agent prompt"
```python
from langchain_core.messages import AnyMessage
from langchain_core.runnables import RunnableConfig
from langgraph.prebuilt import create_react_agent
from langgraph.runtime import get_runtime
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.prebuilt import create_react_agent
def prompt(
state: AgentState,
# highlight-next-line
config: RunnableConfig,
) -> list[AnyMessage]:
# highlight-next-line
user_name = config["configurable"].get("user_name")
system_msg = f"You are a helpful assistant. User's name is {user_name}"
# highlight-next-line
def prompt(state: AgentState) -> list[AnyMessage]:
runtime = get_runtime(ContextSchema)
system_msg = f"You are a helpful assistant. Address the user as {runtime.context.user_name}."
return [{"role": "system", "content": system_msg}] + state["messages"]
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
# highlight-next-line
prompt=prompt
prompt=prompt,
context_schema=ContextSchema
)
agent.invoke(
...,
{"messages": [{"role": "user", "content": "what is the weather in sf"}]},
# highlight-next-line
config={"configurable": {"user_name": "John Smith"}}
context={"user_name": "John Smith"}
)
```
=== "Using state"
* See [Agents](../agents/agents.md) for details.
=== "Workflow node"
```python
from langgraph.runtime import Runtime
# highlight-next-line
def node(state: State, config: Runtime[ContextSchema]):
user_name = runtime.context.user_name
...
```
* See [the Graph API](https://langchain-ai.github.io/langgraph/how-tos/graph-api/#add-runtime-configuration) for details.
=== "In a tool"
```python
from langgraph.runtime import get_runtime
@tool
# highlight-next-line
def get_user_email() -> str:
"""Retrieve user information based on user ID."""
# simulate fetching user info from a database
runtime = get_runtime(ContextSchema)
email = get_user_email_from_db(runtime.context.user_name)
return email
```
See the [tool calling guide](../how-tos/tool-calling.md#configuration) for details.
!!! tip
The `Runtime` object can be used to access static context and other utilities like the active store and stream writer.
See the [Runtime][langgraph.runtime.Runtime] documentation for details.
:::
:::js
| Context type | Description | Mutability | Lifetime |
| ------------------------------------------------------------------------------------------- | --------------------------------------------- | ---------- | ------------------ |
| [**Config**](#config-static-context) | data passed at the start of a run | Static | Single run |
| [**Dynamic runtime context (state)**](#dynamic-runtime-context-state) | Mutable data that evolves during a single run | Dynamic | Single run |
| [**Dynamic cross-conversation context (store)**](#dynamic-cross-conversation-context-store) | Persistent data shared across conversations | Dynamic | Cross-conversation |
## Config (static context)
Config is for immutable data like user metadata or API keys. Use this when you have values that don't change mid-run.
Specify configuration using a key called **"configurable"** which is reserved for this purpose.
```typescript
await graph.invoke(
// (1)!
{ messages: [{ role: "user", content: "hi!" }] }, // (2)!
// highlight-next-line
{ configurable: { user_id: "user_123" } } // (3)!
);
```
:::
## Dynamic runtime context (state)
**Dynamic runtime context** represents mutable data that can evolve during a single run and is managed through the LangGraph state object. This includes conversation history, intermediate results, and values derived from tools or LLM outputs. In LangGraph, the state object acts as [short-term memory](../concepts/memory.md) during a run.
=== "In an agent"
Example shows how to incorporate state into an agent **prompt**.
State can also be accessed by the agent's **tools**, which can read or update the state as needed. See [tool calling guide](../how-tos/tool-calling.md#short-term-memory) for details.
:::python
```python
from langchain_core.messages import AnyMessage
from langchain_core.runnables import RunnableConfig
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
class CustomState(AgentState):
# highlight-next-line
# highlight-next-line
class CustomState(AgentState): # (1)!
user_name: str
def prompt(
# highlight-next-line
state: CustomState
) -> list[AnyMessage]:
# highlight-next-line
user_name = state["user_name"]
system_msg = f"You are a helpful assistant. User's name is {user_name}"
return [{"role": "system", "content": system_msg}] + state["messages"]
@@ -150,87 +179,130 @@ Common use cases:
model="anthropic:claude-3-7-sonnet-latest",
tools=[...],
# highlight-next-line
state_schema=CustomState,
# highlight-next-line
state_schema=CustomState, # (2)!
prompt=prompt
)
agent.invoke({
"messages": "hi!",
# highlight-next-line
"user_name": "John Smith"
})
```
## Accessing Context in Tools { #tools }
1. Define a custom state schema that extends `AgentState` or `MessagesState`.
2. Pass the custom state schema to the agent. This allows the agent to access and modify the state during execution.
:::
Tools can access context through special parameter **annotations**.
:::js
```typescript
import type { BaseMessage } from "@langchain/core/messages";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MessagesZodState } from "@langchain/langgraph";
import { z } from "zod";
* Use `RunnableConfig` for config access
* Use `Annotated[StateSchema, InjectedState]` for agent state
// highlight-next-line
const CustomState = z.object({ // (1)!
messages: MessagesZodState.shape.messages,
userName: z.string(),
});
const prompt = (
// highlight-next-line
state: z.infer<typeof CustomState>
): BaseMessage[] => {
const userName = state.userName;
const systemMsg = `You are a helpful assistant. User's name is ${userName}`;
return [{ role: "system", content: systemMsg }, ...state.messages];
};
!!! tip
const agent = createReactAgent({
llm: model,
tools: [...],
// highlight-next-line
stateSchema: CustomState, // (2)!
stateModifier: prompt,
});
These annotations prevent LLMs from attempting to fill in the values. These parameters will be **hidden** from the LLM.
=== "Using config"
```python
def get_user_info(
# highlight-next-line
config: RunnableConfig,
) -> str:
"""Look up user info."""
# highlight-next-line
user_id = config["configurable"].get("user_id")
return "User is John Smith" if user_id == "user_123" else "Unknown user"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
)
agent.invoke(
{"messages": [{"role": "user", "content": "look up user information"}]},
# highlight-next-line
config={"configurable": {"user_id": "user_123"}}
)
await agent.invoke({
messages: [{ role: "user", content: "hi!" }],
userName: "John Smith",
});
```
=== "Using State"
1. Define a custom state schema that extends `MessagesZodState` or creates a new schema.
2. Pass the custom state schema to the agent. This allows the agent to access and modify the state during execution.
:::
=== "In a workflow"
:::python
```python
from typing import Annotated
from langgraph.prebuilt import InjectedState
from typing_extensions import TypedDict
from langchain_core.messages import AnyMessage
from langgraph.graph import StateGraph
class CustomState(AgentState):
# highlight-next-line
user_id: str
# highlight-next-line
class CustomState(TypedDict): # (1)!
messages: list[AnyMessage]
extra_field: int
def get_user_info(
# highlight-next-line
state: Annotated[CustomState, InjectedState]
) -> str:
"""Look up user info."""
# highlight-next-line
user_id = state["user_id"]
return "User is John Smith" if user_id == "user_123" else "Unknown user"
# highlight-next-line
def node(state: CustomState): # (2)!
messages = state["messages"]
...
return { # (3)!
# highlight-next-line
"extra_field": state["extra_field"] + 1
}
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
# highlight-next-line
state_schema=CustomState,
)
agent.invoke({
"messages": "look up user information",
# highlight-next-line
"user_id": "user_123"
})
builder = StateGraph(State)
builder.add_node(node)
builder.set_entry_point("node")
graph = builder.compile()
```
### Update Context from Tools
1. Define a custom state
2. Access the state in any node or tool
3. The Graph API is designed to work as easily as possible with state. The return value of a node represents a requested update to the state.
:::
Tools can update agent's context (state and long-term memory) during execution. This is useful for persisting intermediate results or making information accessible to subsequent tools or prompts. See [Memory](./memory.md#read-short-term) guide for more information.
:::js
```typescript
import type { BaseMessage } from "@langchain/core/messages";
import { StateGraph, MessagesZodState, START } from "@langchain/langgraph";
import { z } from "zod";
// highlight-next-line
const CustomState = z.object({ // (1)!
messages: MessagesZodState.shape.messages,
extraField: z.number(),
});
const builder = new StateGraph(CustomState)
.addNode("node", async (state) => { // (2)!
const messages = state.messages;
// ...
return { // (3)!
// highlight-next-line
extraField: state.extraField + 1,
};
})
.addEdge(START, "node");
const graph = builder.compile();
```
1. Define a custom state
2. Access the state in any node or tool
3. The Graph API is designed to work as easily as possible with state. The return value of a node represents a requested update to the state.
:::
!!! tip "Turning on memory"
Please see the [memory guide](../how-tos/memory/add-memory.md) for more details on how to enable memory. This is a powerful feature that allows you to persist the agent's state across multiple invocations. Otherwise, the state is scoped only to a single run.
## Dynamic cross-conversation context (store)
**Dynamic cross-conversation context** represents persistent, mutable data that spans across multiple conversations or sessions and is managed through the LangGraph store. This includes user profiles, preferences, and historical interactions. The LangGraph store acts as [long-term memory](../concepts/memory.md#long-term-memory) across multiple runs. This can be used to read or update persistent facts (e.g., user profiles, preferences, prior interactions).
For more information, see the [Memory guide](../how-tos/memory/add-memory.md).
-92
View File
@@ -1,92 +0,0 @@
---
search:
boost: 2
tags:
- agent
hide:
- tags
---
# Deployment
To deploy your LangGraph agent, create and configure a LangGraph app. This setup supports both local development and production deployments.
Features:
* 🖥️ Local server for development
* 🧩 Studio Web UI for visual debugging
* ☁️ Cloud and 🔧 self-hosted deployment options
* 📊 LangSmith integration for tracing and observability
!!! info "Requirements"
- ✅ You **must** have a [LangSmith account](https://www.langchain.com/langsmith). You can sign up for **free** and get started with the free tier.
## Create a LangGraph app
```bash
pip install -U "langgraph-cli[inmem]"
langgraph new path/to/your/app --template new-langgraph-project-python
```
This will create an empty LangGraph project. You can modify it by replacing the code in `src/agent/graph.py` with your agent code. For example:
```python
from langgraph.prebuilt import create_react_agent
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"It's always sunny in {city}!"
graph = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_weather],
prompt="You are a helpful assistant"
)
```
### 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 .
```
### Create an `.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...
ANTHROPIC_API_KEY=sk-
```
## Launch LangGraph server locally
```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
See this [tutorial](https://langchain-ai.github.io/langgraph/tutorials/langgraph-platform/local-server/) to learn more about running LangGraph app locally.
## 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 Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
## Deployment
Once your LangGraph app is running locally, you can deploy it using LangGraph Cloud or self-hosted options. Refer to the [deployment options guide](../tutorials/deployment.md) for detailed instructions on all supported deployment models.
+140 -3
View File
@@ -11,25 +11,62 @@ hide:
To evaluate your agent's performance you can use `LangSmith` [evaluations](https://docs.smith.langchain.com/evaluation). You would need to first define an evaluator function to judge the results from an agent, such as final outputs or trajectory. Depending on your evaluation technique, this may or may not involve a reference output:
:::python
```python
def evaluator(*, outputs: dict, reference_outputs: dict):
# compare agent outputs against reference outputs
output_messages = outputs["messages"]
reference_messages = reference["messages"]
reference_messages = reference_outputs["messages"]
score = compare_messages(output_messages, reference_messages)
return {"key": "evaluator_score", "score": score}
```
:::
:::js
```typescript
type EvaluatorParams = {
outputs: Record<string, any>;
referenceOutputs: Record<string, any>;
};
function evaluator({ outputs, referenceOutputs }: EvaluatorParams) {
// compare agent outputs against reference outputs
const outputMessages = outputs.messages;
const referenceMessages = referenceOutputs.messages;
const score = compareMessages(outputMessages, referenceMessages);
return { key: "evaluator_score", score: score };
}
```
:::
To get started, you can use prebuilt evaluators from `AgentEvals` package:
:::python
```bash
pip install -U agentevals
```
:::
:::js
```bash
npm install agentevals
```
:::
## Create evaluator
A common way to evaluate agent performance is by comparing its trajectory (the order in which it calls its tools) against a reference trajectory:
:::python
```python
import json
# highlight-next-line
@@ -80,8 +117,63 @@ result = evaluator(
)
```
1. Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: [strict](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#strict-match), [unordered](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#unordered-match) and [subset](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#subset-and-superset-match)
:::
:::js
```typescript
import { createTrajectoryMatchEvaluator } from "agentevals/trajectory/match";
const outputs = [
{
role: "assistant",
tool_calls: [
{
function: {
name: "get_weather",
arguments: JSON.stringify({ city: "san francisco" }),
},
},
{
function: {
name: "get_directions",
arguments: JSON.stringify({ destination: "presidio" }),
},
},
],
},
];
const referenceOutputs = [
{
role: "assistant",
tool_calls: [
{
function: {
name: "get_weather",
arguments: JSON.stringify({ city: "san francisco" }),
},
},
],
},
];
// Create the evaluator
const evaluator = createTrajectoryMatchEvaluator({
// Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: strict, unordered and subset
trajectoryMatchMode: "superset", // (1)!
});
// Run the evaluator
const result = evaluator({
outputs: outputs,
referenceOutputs: referenceOutputs,
});
```
:::
1. Specify how the trajectories will be compared. `superset` will accept output trajectory as valid if it's a superset of the reference one. Other options include: [strict](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#strict-match), [unordered](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#unordered-match) and [subset](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#subset-and-superset-match)
As a next step, learn more about how to [customize trajectory match evaluator](https://github.com/langchain-ai/agentevals?tab=readme-ov-file#agent-trajectory-match).
@@ -89,6 +181,8 @@ As a next step, learn more about how to [customize trajectory match evaluator](h
You can use LLM-as-a-judge evaluator that uses an LLM to compare the trajectory against the reference outputs and output a score:
:::python
```python
import json
from agentevals.trajectory.llm import (
@@ -103,6 +197,24 @@ evaluator = create_trajectory_llm_as_judge(
)
```
:::
:::js
```typescript
import {
createTrajectoryLlmAsJudge,
TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
} from "agentevals/trajectory/llm";
const evaluator = createTrajectoryLlmAsJudge({
prompt: TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
model: "openai:o3-mini",
});
```
:::
## Run evaluator
To run an evaluator, you will first need to create a [LangSmith dataset](https://docs.smith.langchain.com/evaluation/concepts#datasets). To use the prebuilt AgentEvals evaluators, you will need a dataset with the following schema:
@@ -110,6 +222,8 @@ To run an evaluator, you will first need to create a [LangSmith dataset](https:/
- **input**: `{"messages": [...]}` input messages to call the agent with.
- **output**: `{"messages": [...]}` expected message history in the agent output. For trajectory evaluation, you can choose to keep only assistant messages.
:::python
```python
from langsmith import Client
from langgraph.prebuilt import create_react_agent
@@ -125,4 +239,27 @@ experiment_results = client.evaluate(
data="<Name of your dataset>",
evaluators=[evaluator]
)
```
```
:::
:::js
```typescript
import { Client } from "langsmith";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { createTrajectoryMatchEvaluator } from "agentevals/trajectory/match";
const client = new Client();
const agent = createReactAgent({...});
const evaluator = createTrajectoryMatchEvaluator({...});
const experimentResults = await client.evaluate(
(inputs) => agent.invoke(inputs),
// replace with your dataset name
{ data: "<Name of your dataset>" },
{ evaluators: [evaluator] }
);
```
:::
Loaded 100 of 687 files, more files were not shown because too many files have changed in this diff. Show more