Merge branch 'main' into wfh/docs/auth

This commit is contained in:
William Fu-Hinthorn
2024-12-17 14:04:31 -08:00
27 changed files with 503 additions and 535 deletions
+2
View File
@@ -89,6 +89,7 @@ jobs:
--check-links-ignore "https://x.com/.*" \
--check-links-ignore "https://github\.com/.*" \
--check-links-ignore "http://localhost:8123/.*" \
--check-links-ignore "http://localhost:2024/.*" \
--check-links-ignore "/.*\.(ipynb|html)$" \
--check-links-ignore "https://python\.langchain\.com/.*" \
--check-links-ignore "https://openai\.com/.*" \
@@ -106,6 +107,7 @@ jobs:
poetry run pytest -v \
--check-links-ignore "https://(api|web|docs)\.smith\.langchain\.com/.*" \
--check-links-ignore "http://localhost:8123/.*" \
--check-links-ignore "http://localhost:2024/.*" \
--check-links-ignore "https://x.com/.*" \
--check-links-ignore "https://github\.com/.*" \
--check-links-ignore "/.*\.(ipynb|html)$" \
+1 -1
View File
@@ -13,7 +13,7 @@ serve-clean-docs: clean-docs
poetry run python -m mkdocs serve -c -f docs/mkdocs.yml --strict -w ./libs/langgraph
serve-docs: build-typedoc
poetry run python -m mkdocs serve -f docs/mkdocs.yml -w ./libs/langgraph -w ./libs/checkpoint --dirty
poetry run python -m mkdocs serve -f docs/mkdocs.yml -w ./libs/langgraph -w ./libs/checkpoint -w ./libs/sdk-py --dirty
clean-docs:
find ./docs/docs -name "*.ipynb" -type f -delete
Binary file not shown.

After

Width:  |  Height:  |  Size: 736 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

@@ -83,7 +83,7 @@ Now, let's import our required packages and instantiate our client, assistant, a
## Create runs
Now we can start our two runs and join the second on euntil it has completed:
Now we can start our two runs and join the second one until it has completed:
=== "Python"
+201 -390
View File
@@ -1,462 +1,273 @@
# LangGraph Cloud Quick Start
# Quickstart: Deploy on LangGraph Cloud
In this tutorial you will build and deploy a simple chatbot agent that can look things up on the internet. You will be using [LangGraph Cloud](../concepts/langgraph_cloud.md), [LangGraph Studio](../concepts/langgraph_studio.md) to visualize and test it out, and [LangGraph SDK](./reference/sdk/python_sdk_ref.md) to interact with the deployed agent.
!!! note "Prerequisites"
If you want to learn how to build an agent like this from scratch, take a look at the [LangGraph Quick Start tutorial](../tutorials/introduction.ipynb).
Before you begin, ensure you have the following:
## Set up requirements
- [GitHub account](https://github.com/)
- [LangSmith account](https://smith.langchain.com/)
This tutorial will use:
## Create a repository on GitHub
- Anthropic for the LLM - sign up and get an API key [here](https://console.anthropic.com/).
- Tavily for the search engine - sign up and get an API key [here](https://app.tavily.com/).
- LangSmith for hosting - sign up and get an API key [here](https://smith.langchain.com/).
To deploy a LangGraph application to **LangGraph Cloud**, your application code must reside in a GitHub repository. Both public and private repositories are supported.
## Create and configure your app
You can deploy any [LangGraph Application](../concepts/application_structure.md) to LangGraph Cloud.
First, let's set create all of the necessary files for our LangGraph application.
For this guide, we'll use the pre-built Python [**ReAct Agent**](https://github.com/langchain-ai/react-agent) template.
1. __Create application directory and files__
??? note "Get Required API Keys for the ReAct Agent template"
Create a new application `my-app` with the following file structure:
This **ReAct Agent** application requires an API key from [Anthropic](https://console.anthropic.com/) and [Tavily](https://app.tavily.com/). You can get these API keys by signing up on their respective websites.
```shell
mkdir my-app
```
**Alternative**: If you'd prefer a scaffold application that doesn't require API keys, use the [**New LangGraph Project**](https://github.com/langchain-ai/new-langgraph-project) template instead of the **ReAct Agent** template.
=== "Python"
my-app/
|-- agent.py # code for your LangGraph agent
|-- requirements.txt # Python packages required for your graph
|-- langgraph.json # configuration file for LangGraph
|-- .env # environment files with API keys
=== "Javascript"
my-app/
|-- agent.ts # code for your LangGraph agent
|-- package.json # Javascript packages required for your graph
|-- langgraph.json # configuration file for LangGraph
|-- .env # environment files with API keys
1. __Define your graph__
=== "Python"
The `agent.py` file should contain code with your graph.
=== "Javascript"
The `agent.ts` file should contain code with your graph.
The following code example is a simple chatbot agent (similar to the one in the [previous tutorial](../tutorials/introduction.ipynb)). Specifically, it uses [create_react_agent][langgraph.prebuilt.chat_agent_executor.create_react_agent], a prebuilt [ReAct](../concepts/agentic_concepts.md#react-implementation)-style agent.
The `agent` file needs to have a variable with a [CompiledGraph][langgraph.graph.graph.CompiledGraph] (in this case the `graph` variable).
=== "Python"
```python
# agent.py
from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults
from langgraph.prebuilt import create_react_agent
model = ChatAnthropic(model="claude-3-5-sonnet-20240620")
tools = [TavilySearchResults(max_results=2)]
# compiled graph
graph = create_react_agent(model, tools)
```
=== "Javascript"
```ts
// agent.ts
import { ChatAnthropic } from "@langchain/anthropic";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const model = new ChatAnthropic({
model: "claude-3-5-sonnet-20240620",
});
const tools = [
new TavilySearchResults({ maxResults: 3, }),
];
// compiled graph
export const graph = createReactAgent({ llm: model, tools });
```
1. __Specify dependencies__
=== "Python"
You should add dependencies for your graph(s) to `requirements.txt`.
=== "Javascript"
You should add dependencies for your graph(s) to `package.json`.
In this case we only require four packages for our graph to run:
=== "Python"
```python
langgraph
langchain_anthropic
tavily-python
langchain_community
```
=== "Javascript"
```js
{
"name": "my-app",
"packageManager": "yarn@1.22.22",
"dependencies": {
"@langchain/community": "^0.3.11",
"@langchain/core": "^0.3.16",
"@langchain/langgraph": "0.2.18",
"@langchain/anthropic": "^0.3.7"
}
}
```
1. __Create LangGraph configuration file__
The [`langgraph.json`][langgraph.json] file is a configuration file that describes what graph(s) you are going to deploy. In this case we only have one graph: the compiled `graph` object from `agent.py` / `agent.ts`.
=== "Python"
```json
{
"dependencies": ["."],
"graphs": {
"agent": "./agent.py:graph"
},
"env": ".env"
}
```
=== "Javascript"
```json
{
"node_version": "20",
"dockerfile_lines": [],
"dependencies": ["."],
"graphs": {
"agent": "./src/agent.ts:graph"
},
"env": ".env"
}
```
Learn more about the LangGraph CLI configuration file [here](./reference/cli.md#configuration-file).
1. __Specify environment variables__
The `.env` file should have any environment variables needed to run your graph. This will only be used for local testing, so if you are not testing locally you can skip this step.
!!! warning
The `.env` file should NOT be included with the rest of source code in your Github repository. When creating a deployment using LangGraph Cloud, you will be able to specify the environment variables manually.
For this graph, we need two environment variables:
```shell
ANTHROPIC_API_KEY=...
TAVILY_API_KEY=...
```
!!! tip
Learn more about different application structure options [here](../how-tos/index.md#application-structure).
Now that we have set everything up on our local file system, we are ready to test our graph locally.
## Test the app locally
To test the LangGraph app before deploying it using LangGraph Cloud, you can start the [LangGraph server](../concepts/langgraph_server.md) locally or use [LangGraph Studio](../concepts/langgraph_studio.md).
## Using local server
You can test your app by running [LangGraph server](../concepts/langgraph_server.md) locally. This is useful to make sure you have configured our [CLI configuration file][langgraph.json] correctly and can interact with your graph.
To run the server locally, you need to first install the LangGraph CLI:
```shell
pip install langgraph-cli
```
You can then test our API server locally. In order to run the server locally, you will need to add your `LANGSMITH_API_KEY` to the `.env` file.
```shell
langgraph up
```
This will start up the LangGraph API server locally. If this runs successfully, you should see something like:
```shell
Ready!
- API: http://localhost:8123
```
First, let's verify that the server is running correctly by calling `/ok` endpoint:
```shell
curl --request GET --url http://localhost:8123/ok
```
Output:
```
{"ok": "true"}
```
Now we're ready to test the app with the real inputs!
```shell
curl --request POST \
--url http://localhost:8123/runs/stream \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": "agent",
"input": {
"messages": [
{
"role": "user",
"content": "What is the weather in NYC?"
}
]
},
"stream_mode": "updates"
}'
```
Output:
```
...
data: {
"agent": {
"messages": [
{
"content": "The search results from Tavily provide the current weather conditions in New York City, including temperature, wind speed, precipitation, humidity, and cloud cover. According to the results, as of 3:00pm on October 30th, 2024, it is overcast in NYC with a temperature of around 66°F (19°C), light winds from the southwest around 8 mph (13 km/h), and 66% humidity.\n\nSo in summary, the current weather in NYC is overcast with mild temperatures in the mid 60sF and light winds, based on the search results. Let me know if you need any other details!",
"type": "ai",
...
}
]
}
}
```
You can see that our agent responds with the up-to-date search results!
### Using LangGraph Studio Desktop
You can also test your app locally with [LangGraph Studio](../concepts/langgraph_studio.md). LangGraph Studio offers a new way to develop LLM applications by providing a specialized agent IDE that enables visualization, interaction, and debugging of complex agentic applications.
With visual graphs and the ability to edit state, you can better understand agent workflows and iterate faster. LangGraph Studio integrates with LangSmith allowing you to collaborate with teammates to debug failure modes.
LangGraph Studio is available as a [desktop app](https://studio.langchain.com/) for MacOS users. Once you have installed the app, you can select `my-app` directory, which will automatically start the server locally and load the graph in the UI.
To interact with your chatbot agent in LangGraph Studio, you can add a new message in the `Input` section and press `Submit`.
![LangGraph Studio Desktop](./deployment/img/quick_start_studio.png)
1. Go to the [ReAct Agent](https://github.com/langchain-ai/react-agent) repository.
2. Fork the repository to your GitHub account by clicking the `Fork` button in the top right corner.
## Deploy to LangGraph Cloud
Once you've tested your graph locally and verified that it works as expected, you can deploy it to the LangGraph Cloud.
??? note "1. Log in to [LangSmith](https://smith.langchain.com/)"
First, you'll need to turn the `my-app` directory into a GitHub repo and [push it to GitHub](https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github).
<figure markdown="1">
[![Login to LangSmith](deployment/img/01_login.png){: style="max-height:300px"}](deployment/img/01_login.png)
<figcaption>
Go to [LangSmith](https://smith.langchain.com/) and log in. If you don't have an account, you can sign up for free.
</figcaption>
</figure>
Once you have created your GitHub repository with a Python file containing your compiled graph as well as a `langgraph.json` with the configuration, you can head over to [LangSmith](https://smith.langchain.com/) and click on the graph icon (`LangGraph Cloud`) on the bottom of the left navbar. This will open the LangGraph deployments page. On this page, click the `+ New Deployment` button in the top right corner.
![Langsmith Workflow](./deployment/img/cloud_deployment.png)
??? note "2. Click on <em>LangGraph Platform</em> (the left sidebar)"
**_If you have not deployed to LangGraph Cloud before:_** there will be a button that shows up saying `Import from GitHub`. Youll need to follow that flow to connect LangGraph Cloud to GitHub.
<figure markdown="1">
[![Login to LangSmith](deployment/img/02_langgraph_platform.png){: style="max-height:300px"}](deployment/img/02_langgraph_platform.png)
<figcaption>
Select **LangGraph Platform** from the left sidebar.
</figcaption>
</figure>
**_Once you have set up your GitHub connection:_** the new deployment page will look as follows:
??? note "3. Click on + New Deployment (top right corner)"
![Deployment before being filled out](./deployment/img/deployment_page.png)
<figure markdown="1">
[![Login to LangSmith](deployment/img/03_deployments_page.png){: style="max-height:300px"}](deployment/img/03_deployments_page.png)
<figcaption>
Click on **+ New Deployment** to create a new deployment. This button is located in the top right corner.
It'll open a new modal where you can fill out the required fields.
</figcaption>
</figure>
To deploy your application, you should do the following:
??? note "4. Click on Import from GitHub (first time users)"
1. Select your GitHub username or organization from the selector
1. Search for your repo to deploy in the search bar and select it
1. Choose a name for your deployment
1. In the `Git Branch` field, you can specify either the branch for the code you want to deploy, or the exact commit SHA.
1. In the `LangGraph API config file` field, enter the path to your `langgraph.json` file (which in this case is just `langgraph.json`)
1. If your application needs environment variables, add those in the `Environment Variables` section. They will be propagated to the underlying server so your code can access them. In this case, we will need `ANTHROPIC_API_KEY` and `TAVILY_API_KEY`.
<figure markdown="1">
[![image](deployment/img/04_create_new_deployment.png)](deployment/img/04_create_new_deployment.png)
<figcaption>
Click on **Import from GitHub** and follow the instructions to connect your GitHub account. This step is needed for **first-time users** or to add private repositories that haven't been connected before.</figcaption>
</figure>
Hit `Submit` and your application will start deploying!
??? note "5. Select the repository, configure ENV vars etc"
After your deployment is complete, your deployments page should look as follows:
<figure markdown="1">
[![image](deployment/img/05_configure_deployment.png){: style="max-height:300px"}](deployment/img/05_configure_deployment.png)
<figcaption>
Select the <strong>repository</strong>, add env variables and secrets, and set other configuration options.
</figcaption>
</figure>
![Deployed page](./deployment/img/deployed_page.png)
- **Repository**: Select the repository you forked earlier (or any other repository you want to deploy).
- Set the secrets and environment variables required by your application. For the **ReAct Agent** template, you need to set the following secrets:
- **ANTHROPIC_API_KEY**: Get an API key from [Anthropic](https://console.anthropic.com/).
- **TAVILY_API_KEY**: Get an API key on the [Tavily website](https://app.tavily.com/).
## Interact with your deployment
??? note "6. Click Submit to Deploy!"
### Using LangGraph Studio (Cloud)
On the deployment page for your application,, you should see a button in the top right corner that says `LangGraph Studio`. Clicking on this button will take you to the web version of LangGraph Studio. This is the same UI that you interacted with when [testing the app locally](#using-langgraph-studio-recommended), but instead of using a local LangGraph server, it uses the one from your LangGraph Cloud deployment.
<figure markdown="1">
[![image](deployment/img/05_configure_deployment.png){: style="max-height:300px"}](deployment/img/05_configure_deployment.png)
<figcaption>
Please note that this step may ~15 minutes to complete. You can check the status of your deployment in the **Deployments** view.
Click the <strong>Submit</strong> button at the top right corner to deploy your application.
</figcaption>
</figure>
![Studio UI once being run](./deployment/img/graph_run.png)
### Using LangGraph SDK
## Lagraph Studio Web UI
You can also interact with your deployed LangGraph application programmatically, using [LangGraph SDK](./reference/sdk/python_sdk_ref.md).
Once your application is deployed, you can test it in **LangGraph Studio**.
First, make sure you have the SDK installed:
??? note "1. Click on an existing deployment"
=== "Python"
<figure markdown="1">
[![image](deployment/img/07_deployments_page.png){: style="max-height:300px"}](deployment/img/07_deployments_page.png)
<figcaption>
Click on the deployment you just created to view more details.
</figcaption>
</figure>
```shell
pip install langgraph_sdk
```
??? note "2. Click on LangGraph Studio"
=== "Javascript"
<figure markdown="1">
[![image](deployment/img/08_deployment_view.png){: style="max-height:300px"}](deployment/img/08_deployment_view.png)
<figcaption>
Click on the <strong>LangGraph Studio</strong> button to open LangGraph Studio.
</figcaption>
</figure>
```shell
yarn add @langchain/langgraph-sdk
```
<figure markdown="1">
[![image](deployment/img/09_langgraph_studio.png){: style="max-height:400px"}](deployment/img/09_langgraph_studio.png)
<figcaption>
Sample graph run in LangGraph Studio.
</figcaption>
</figure>
Before using, you need to get the URL of your LangGraph deployment. You can find this in the `Deployment` view. Click the URL to copy it to the clipboard.
## Test the API
You also need to make sure you have set up your API key properly so you can authenticate with LangGraph Cloud.
!!! note
The API calls below are for the **ReAct Agent** template. If you're deploying a different application, you may need to adjust the API calls accordingly.
Before using, you need to get the `URL` of your LangGraph deployment. You can find this in the `Deployment` view. Click the `URL` to copy it to the clipboard.
You also need to make sure you have set up your API key properly, so you can authenticate with LangGraph Cloud.
```shell
export LANGSMITH_API_KEY=...
```
The first thing to do when using the SDK is to setup our client, access our assistant, and create a thread to execute a run on:
=== "Python SDK (Async)"
=== "Python"
**Install the LangGraph Python SDK**
```python
from langgraph_sdk import get_client
```shell
pip install langgraph-sdk
```
client = get_client(url=<DEPLOYMENT_URL>)
# get default assistant
assistants = await client.assistants.search(metadata={"created_by": "system"})
assistant = assistants[0]
# create thread
thread = await client.threads.create()
print(thread)
```
=== "Javascript"
```js
import { Client } from "@langchain/langgraph-sdk";
const client = new Client({ apiUrl: <DEPLOYMENT_URL> });
// get default assistant
const assistants = await client.assistants.search({ metadata: {"created_by": "system"} })
const assistant = assistants[0];
// create thread
const thread = await client.threads.create();
console.log(thread)
```
=== "CURL"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/assistants/search \
--header 'Content-Type: application/json' \
--data '{
"limit": 10,
"offset": 0,
"metadata": {"created_by": "system"}
}' &&
curl --request POST \
--url <DEPLOYMENT_URL>/threads \
--header 'Content-Type: application/json' \
--data '{}'
```
We can then execute a run on the thread:
=== "Python"
**Send a message to the assistant (threadless run)**
```python
input = {
"messages": [{"role": "user", "content": "What is the weather in NYC?"}]
}
from langgraph_sdk import get_client
client = get_client(url="your-deployment-url", api_key="your-langsmith-api-key")
async for chunk in client.runs.stream(
thread["thread_id"],
assistant["assistant_id"],
input=input,
None, # Threadless run
"agent", # Name of assistant. Defined in langgraph.json.
input={
"messages": [{
"role": "human",
"content": "What is LangGraph?",
}],
},
stream_mode="updates",
):
if chunk.data:
print(chunk.data)
print(f"Receiving new event of type: {chunk.event}...")
print(chunk.data)
print("\n\n")
```
=== "Javascript"
=== "Python SDK (Sync)"
**Install the LangGraph Python SDK**
```shell
pip install langgraph-sdk
```
**Send a message to the assistant (threadless run)**
```python
from langgraph_sdk import get_sync_client
client = get_sync_client(url="your-deployment-url", api_key="your-langsmith-api-key")
for chunk in client.runs.stream(
None, # Threadless run
"agent", # Name of assistant. Defined in langgraph.json.
input={
"messages": [{
"role": "human",
"content": "What is LangGraph?",
}],
},
stream_mode="updates",
):
print(f"Receiving new event of type: {chunk.event}...")
print(chunk.data)
print("\n\n")
```
=== "Javascript SDK"
**Install the LangGraph JS SDK**
```shell
npm install @langchain/langgraph-sdk
```
**Send a message to the assistant (threadless run)**
```js
const input = { "messages": [{ "role": "user", "content": "What is the weather in NYC?" }] };
const { Client } = await import("@langchain/langgraph-sdk");
// only set the apiUrl if you changed the default port when calling langgraph up
const client = new Client({ apiUrl: "your-deployment-url", apiKey: "your-langsmith-api-key" });
const streamResponse = client.runs.stream(
thread["thread_id"],
assistant["assistant_id"],
{
input,
streamMode: "updates"
}
null, // Threadless run
"agent", // Assistant ID
{
input: {
"messages": [
{ "role": "user", "content": "What is LangGraph?"}
]
},
streamMode: "messages",
}
);
for await (const chunk of streamResponse) {
if (chunk.data) {
console.log(chunk.data);
}
console.log(`Receiving new event of type: ${chunk.event}...`);
console.log(JSON.stringify(chunk.data));
console.log("\n\n");
}
```
=== "CURL"
=== "Rest API"
```bash
curl --request POST \
--url <DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream \
--header 'Content-Type: application/json' \
--data '{
"assistant_id": <ASSISTANT_ID>,
"input": {
"messages": [
{
"role": "user",
"content": "What is the weather in NYC?"
}
]
},
"stream_mode": "updates"
}'
curl -s --request POST \
--url <DEPLOYMENT_URL> \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
\"input\": {
\"messages\": [
{
\"role\": \"human\",
\"content\": \"What is LangGraph?\"
}
]
},
\"stream_mode\": \"updates\"
}"
```
Output:
```
...
data: {
"agent": {
"messages": [
{
"content": "The search results from Tavily provide the current weather conditions in New York City, including temperature, wind speed, precipitation, humidity, and cloud cover. According to the results, as of 3:00pm on October 30th, 2024, it is overcast in NYC with a temperature of around 66°F (19°C), light winds from the southwest around 8 mph (13 km/h), and 66% humidity.\n\nSo in summary, the current weather in NYC is overcast with mild temperatures in the mid 60sF and light winds, based on the search results. Let me know if you need any other details!",
"type": "ai",
...
}
]
}
}
```
## Next steps
## Next Steps
Congratulations! If you've worked your way through this tutorial you are well on your way to becoming a LangGraph Cloud expert. Here are some other resources to check out to help you out on the path to expertise:
* [LangGraph How-to guides](../how-tos/index.md)
* [LangGraph Tutorials](../tutorials/index.md)
### LangGraph Framework
- **[LangGraph Tutorial](../tutorials/introduction.ipynb)**: Get started with LangGraph framework.
- **[LangGraph Concepts](../concepts/index.md)**: Learn the foundational concepts of LangGraph.
- **[LangGraph How-to Guides](../how-tos/index.md)**: Guides for common tasks with LangGraph.
### 📚 Learn More about LangGraph Platform
Expand your knowledge with these resources:
- **[LangGraph Platform Concepts](../concepts/index.md#langgraph-platform)**: Understand the foundational concepts of the LangGraph Platform.
- **[LangGraph Platform How-to Guides](../how-tos/index.md#langgraph-platform)**: Discover step-by-step guides to build and deploy applications.
- **[Launch Local LangGraph Server](../tutorials/langgraph-platform/local-server.md)**: This quick start guide shows how to start a LangGraph Server locally for the **ReAct Agent** template. The steps are similar for other templates.
@@ -6,3 +6,25 @@
::: langgraph_sdk.schema
handler: python
::: langgraph_sdk.auth
handler: python
::: langgraph_sdk.auth.types.Authenticator
handler: python
::: langgraph_sdk.auth.types.Handler
handler: python
::: langgraph_sdk.auth.types.HandlerResult
handler: python
::: langgraph_sdk.auth.types.FilterType
handler: python
::: langgraph_sdk.auth.types.AuthContext
handler: python
::: langgraph_sdk.auth.exceptions
handler: python
+1 -1
View File
@@ -16,7 +16,7 @@ If you do not want to use LangGraph Platform, we describe the options we have im
## Reject
This is the simplest option, this just rejects any follow up runs and does not allow double texting.
This is the simplest option, this just rejects any follow-up runs and does not allow double texting.
See the [how-to guide](../cloud/how-tos/reject_concurrent.md) for configuring the reject double text option.
## Enqueue
+15 -15
View File
@@ -22,21 +22,21 @@ Yes. LangGraph is an MIT-licensed open-source library and is free to use.
LangGraph is a stateful, orchestration framework that brings added control to agent workflows. LangGraph Platform is a service for deploying and scaling LangGraph applications, with an opinionated API for building agent UXs, plus an integrated developer studio.
| Features | LangGraph (open source) | LangGraph Platform |
|----------|------------------------|-------------------|
| Description | Stateful orchestration framework for agentic applications | Scalable infrastructure for deploying LangGraph applications |
| SDKs | Python and JavaScript | Python and JavaScript |
| HTTP APIs | None | Yes - useful for retrieving & updating state or long-term memory, or creating a configurable assistant |
| Streaming | Basic | Dedicated mode for token-by-token messages |
| Checkpointer | Community contributed | Supported out-of-the-box |
| Persistence Layer | Self-managed | Managed Postgres with efficient storage |
| Deployment | Self-managed | • Cloud SaaS <br> • Free self-hosted <br> • Enterprise (BYOC or paid self-hosted) |
| Scalability | Self-managed | Auto-scaling of task queues and servers |
| Fault-tolerance | Self-managed | Automated retries |
| Concurrency Control | Simple threading | Supports double-texting |
| Scheduling | None | Cron scheduling |
| Monitoring | None | Integrated with LangSmith for observability |
| IDE integration | LangGraph Studio for Desktop | LangGraph Studio for Desktop & Cloud |
| Features | LangGraph (open source) | LangGraph Platform |
|---------------------|-----------------------------------------------------------|--------------------------------------------------------------------------------------------------------|
| Description | Stateful orchestration framework for agentic applications | Scalable infrastructure for deploying LangGraph applications |
| SDKs | Python and JavaScript | Python and JavaScript |
| HTTP APIs | None | Yes - useful for retrieving & updating state or long-term memory, or creating a configurable assistant |
| Streaming | Basic | Dedicated mode for token-by-token messages |
| Checkpointer | Community contributed | Supported out-of-the-box |
| Persistence Layer | Self-managed | Managed Postgres with efficient storage |
| Deployment | Self-managed | • Cloud SaaS <br> • Free self-hosted <br> • Enterprise (BYOC or paid self-hosted) |
| Scalability | Self-managed | Auto-scaling of task queues and servers |
| Fault-tolerance | Self-managed | Automated retries |
| Concurrency Control | Simple threading | Supports double-texting |
| Scheduling | None | Cron scheduling |
| Monitoring | None | Integrated with LangSmith for observability |
| IDE integration | LangGraph Studio for Desktop | LangGraph Studio for Desktop & Cloud |
## What are my deployment options for LangGraph Platform?
+1 -26
View File
@@ -18,32 +18,7 @@ The LangGraph Platform offers a few different deployment options described in th
## Why Use LangGraph Platform?
LangGraph Platform is designed to make deploying agentic applications seamless and production-ready.
For simpler applications, deploying a LangGraph agent can be as straightforward as using your own server logic—for example, setting up a FastAPI endpoint and invoking LangGraph directly.
### Option 1: Deploying with Custom Server Logic
For basic LangGraph applications, you may choose to handle deployment using your custom server infrastructure. Setting up endpoints with frameworks like [FastAPI](https://fastapi.tiangolo.com/) allows you to quickly deploy and run LangGraph as you would any other Python application:
```python
from fastapi import FastAPI
from your_agent_package import graph
app = FastAPI()
@app.get("/foo")
async def foo(...):
return await graph.ainvoke({...})
```
This approach works well for simple applications with straightforward needs and provides you with full control over the deployment setup. For example, you might use this for a single-assistant application that doesnt require long-running sessions or persistent memory.
### Option 2: Leveraging LangGraph Platform for Complex Deployments
As your applications scale or add complex features, the deployment requirements often evolve. Running an application with more nodes, longer processing times, or a need for persistent memory can introduce challenges that quickly become time-consuming and difficult to manage manually. [LangGraph Platform](./langgraph_platform.md) is built to handle these challenges seamlessly, allowing you to focus on agent logic rather than server infrastructure.
Here are some common issues that arise in complex deployments, which LangGraph Platform addresses:
**LangGraph Platform** handles common issues that arise when deploying LLM applications to production, allowing you to focus on agent logic instead of managing server infrastructure.
- **[Streaming Support](streaming.md)**: As agents grow more sophisticated, they often benefit from streaming both token outputs and intermediate states back to the user. Without this, users are left waiting for potentially long operations with no feedback. LangGraph Server provides [multiple streaming modes](streaming.md) optimized for various application needs.
+7 -7
View File
@@ -94,13 +94,13 @@ This is a special case of updating the graph state from tools where in addition
!!! important
If you want to use tools that return `Command`, you can either use prebuilt [`create_react_agent`][langgraph.prebuilt.chat_agent_executor.create_react_agent] / [`ToolNode`][langgraph.prebuilt.tool_node.ToolNode] components, or implement your own tool-executing node that collects `Command` objects returned by the tools and returns a list of them, e.g.:
```python
def call_tools(state):
...
commands = [tools_by_name[tool_call["name"]].invoke(tool_call) for tool_call in tool_calls]
return commands
```
```python
def call_tools(state):
...
commands = [tools_by_name[tool_call["name"]].invoke(tool_call) for tool_call in tool_calls]
return commands
```
Let's now take a closer look at the different multi-agent architectures.
+1 -1
View File
@@ -12,7 +12,7 @@ You can create an application from a template using the LangGraph CLI.
## Install the LangGraph CLI
```bash
pip install "langgraph-cli[inmem]==0.1.58" python-dotenv
pip install "langgraph-cli[inmem]" --upgrade
```
## Available Templates
@@ -40,7 +40,7 @@
" \"content\": user_input,\n",
" }]\n",
" },\n",
" goto=active_agent,\n",
" goto=active_agent,)\n",
"\n",
"def agent(state) -> Command[Literal[\"agent\", \"another_agent\", \"human\"]]:\n",
" # The condition for routing/halting can be anything, e.g. LLM tool call / structured output, etc.\n",
@@ -140,7 +140,6 @@
"\n",
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.messages import AnyMessage\n",
"from langchain_openai import ChatOpenAI\n",
"from langgraph.graph import MessagesState, StateGraph, START, END\n",
"from langgraph.types import Command, interrupt\n",
"from langgraph.checkpoint.memory import MemorySaver\n",
@@ -166,8 +166,6 @@
"\n",
"\n",
"class State(AgentState):\n",
" # user provided\n",
" last_name: str\n",
" # updated by the tool\n",
" user_info: dict[str, Any]\n",
"\n",
+3 -3
View File
@@ -11,9 +11,9 @@ New to LangGraph or LLM app development? Read this material to get up and runnin
## Get Started
- [LangGraph Quickstart](introduction.ipynb): Build a chatbot that can use tools and keep track of conversation history. Add human-in-the-loop capabilities and explore how time-travel works.
- [LangGraph Server Quickstart](langgraph-platform/local-server.md): Launch a LangGraph server locally and interact with it using the REST API and LangGraph Studio Web UI.
- [LangGraph Cloud QuickStart](../cloud/quick_start.md): Deploy a LangGraph app using LangGraph Cloud.
- [LangGraph Template Quickstart](../concepts/template_applications.md): Quickly start building with LangGraph Platform using a template application.
- [LangGraph Server Quickstart](langgraph-platform/local-server.md): Launch a LangGraph server locally and interact with it using REST API and LangGraph Studio Web UI.
- [LangGraph Template Quickstart](../concepts/template_applications.md): Start building with LangGraph Platform using a template application.
- [Deploy with LangGraph Cloud Quickstart](../cloud/quick_start.md): Deploy a LangGraph app using LangGraph Cloud.
## Use cases
@@ -1,4 +1,4 @@
# Quick Start: Launch Local LangGraph Server
# QuickStart: Launch Local LangGraph Server
This is a quick start guide to help you get a LangGraph app up and running locally.
@@ -10,7 +10,7 @@ This is a quick start guide to help you get a LangGraph app up and running local
## Install the LangGraph CLI
```bash
pip install -U "langgraph-cli[inmem]" python-dotenv
pip install --upgrade "langgraph-cli[inmem]"
```
## 🌱 Create a LangGraph App
@@ -53,21 +53,12 @@ ANTHROPIC_API_KEY=sk-
OPENAI_API_KEY=sk-...
```
<details><summary>Get API Keys</summary>
<ul>
<li> <b>LANGSMITH_API_KEY</b>: Go to the <a href="https://smith.langchain.com/settings">LangSmith Settings page</a>. Then clck <b>Create API Key</b>.
</li>
<li>
<b>ANTHROPIC_API_KEY</b>: Get an API key from <a href="https://console.anthropic.com/">Anthropic</a>.
</li>
<li>
<b>OPENAI_API_KEY</b>: Get an API key from <a href="https://openai.com/">OpenAI</a>.
</li>
<li>
<b>TAVILY_API_KEY</b>: Get an API key on the <a href="https://app.tavily.com/">Tavily website</a>.
</li>
</ul>
</details>
??? note "Get API Keys"
- **LANGSMITH_API_KEY**: Go to the [LangSmith Settings page](https://smith.langchain.com/settings). Then clck **Create API Key**.
- **ANTHROPIC_API_KEY**: Get an API key from [Anthropic](https://console.anthropic.com/).
- **OPENAI_API_KEY**: Get an API key from [OpenAI](https://openai.com/).
- **TAVILY_API_KEY**: Get an API key on the [Tavily website](https://app.tavily.com/).
## 🚀 Launch LangGraph Server
@@ -79,11 +70,11 @@ This will start up the LangGraph API server locally. If this runs successfully,
> Ready!
>
> - API: [http://localhost:8123](http://localhost:8123/)
> - API: [http://localhost:2024](http://localhost:2024/)
>
> - Docs: http://localhost:8123/docs
> - Docs: http://localhost:2024/docs
>
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:8123
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
!!! note "In-Memory Mode"
@@ -95,9 +86,9 @@ This will start up the LangGraph API server locally. If this runs successfully,
## LangGraph Studio Web UI
Test your graph in the LangGraph Studio Web UI by visiting the URL provided in the output of the `langgraph up` command.
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:8123
> - LangGraph Studio Web UI: https://smith.langchain.com/studio/?baseUrl=http://127.0.0.1:2024
!!! warning "Safari Compatibility"
@@ -118,7 +109,7 @@ Test your graph in the LangGraph Studio Web UI by visiting the URL provided in t
```python
from langgraph_sdk import get_client
client = get_client(url="http://localhost:8123")
client = get_client(url="http://localhost:2024")
async for chunk in client.runs.stream(
None, # Threadless run
@@ -149,7 +140,7 @@ Test your graph in the LangGraph Studio Web UI by visiting the URL provided in t
```python
from langgraph_sdk import get_sync_client
client = get_sync_client(url="http://localhost:8123")
client = get_sync_client(url="http://localhost:2024")
for chunk in client.runs.stream(
None, # Threadless run
@@ -181,7 +172,7 @@ Test your graph in the LangGraph Studio Web UI by visiting the URL provided in t
const { Client } = await import("@langchain/langgraph-sdk");
// only set the apiUrl if you changed the default port when calling langgraph up
const client = new Client({ apiUrl: "http://localhost:8123"});
const client = new Client({ apiUrl: "http://localhost:2024"});
const streamResponse = client.runs.stream(
null, // Threadless run
@@ -207,7 +198,7 @@ Test your graph in the LangGraph Studio Web UI by visiting the URL provided in t
```bash
curl -s --request POST \
--url "http://localhost:8123/runs/stream" \
--url "http://localhost:2024/runs/stream" \
--header 'Content-Type: application/json' \
--data "{
\"assistant_id\": \"agent\",
@@ -235,7 +226,7 @@ Now that you have a LangGraph app running locally, take your journey further by
### 🌐 Deploy to LangGraph Cloud
- **[LangGraph Cloud QuickStart](../../cloud/quick_start.md)**: Deploy your LangGraph app using LangGraph Cloud.
- **[LangGraph Cloud Quickstart](../../cloud/quick_start.md)**: Deploy your LangGraph app using LangGraph Cloud.
### 📚 Learn More about LangGraph Platform
+3 -1
View File
@@ -124,6 +124,7 @@ def validate_config(config: Config) -> Config:
{
"node_version": config.get("node_version"),
"dockerfile_lines": config.get("dockerfile_lines", []),
"dependencies": config.get("dependencies", []),
"graphs": config.get("graphs", {}),
"env": config.get("env", {}),
"store": config.get("store"),
@@ -528,8 +529,9 @@ def config_to_compose(
f"env_file: {config['env']}" if isinstance(config["env"], str) else ""
)
if watch:
dependencies = config.get("dependencies") or ["."]
watch_paths = [config_path.name] + [
dep for dep in config["dependencies"] if dep.startswith(".")
dep for dep in dependencies if dep.startswith(".")
]
watch_actions = "\n".join(
f"""- path: {path}
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langgraph-cli"
version = "0.1.63"
version = "0.1.64"
description = "CLI for interacting with LangGraph API"
authors = []
license = "MIT"
+186 -33
View File
@@ -11,26 +11,54 @@ AH = typing.TypeVar("AH", bound=types.Authenticator)
class Auth:
"""Authentication and authorization management for LangGraph.
"""Add custom authentication and authorization management to your LangGraph application.
The Auth class provides a unified system for handling authentication and
authorization in LangGraph applications. It supports:
authorization in LangGraph applications. It supports custom user authentication
protocols and fine-grained authorization rules for different resources and
actions.
1. Authentication via a decorator-based handler system
2. Fine-grained authorization rules for different resources and actions
3. Global and resource-specific authorization handlers
To use, create a separate python file and add the path to the file to your
LangGraph API configuration file (`langgraph.json`). Within that file, create
an instance of the Auth class and register authentication and authorization
handlers as needed.
Example `langgraph.json` file:
```json
{
"dependencies": ["."],
"graphs": {
"agent": "./my_agent/agent.py:graph"
},
"env": ".env",
"auth": {
"path": "./auth.py:my_auth"
}
```
Then the LangGraph server will load your auth file and run it server-side whenever a request comes in.
???+ example "Basic Usage"
```python
from langgraph_sdk import Auth
auth = Auth()
my_auth = Auth()
async def verify_token(token: str) -> str:
# Verify token and return user_id
# This would typically be a call to your auth server
return "user_id"
@auth.authenticate
async def authenticate(authorization: str) -> tuple[list[str], str]:
# Verify token and return (scopes, user_id)
user_id = verify_token(authorization)
return ["read", "write"], user_id
async def authenticate(authorization: str) -> str:
# Verify token and return user_id
result = await verify_token(authorization)
if result != "user_id":
raise Auth.exceptions.HTTPException(
status_code=401, detail="Unauthorized"
)
return result
# Global fallback handler
@auth.on
@@ -44,11 +72,12 @@ class Auth:
```
???+ note "Request Processing Flow"
1. Authentication is performed first on every request
1. Authentication (your `@auth.authenticate` handler) is performed first on **every request**
2. For authorization, the most specific matching handler is called:
- If a handler exists for the exact resource and action, it is used
- Otherwise, if a handler exists for the resource with any action, it is used
- Finally, if no specific handlers match, the global handler is used (if any)
* If a handler exists for the exact resource and action, it is used (e.g., `@auth.on.threads.create`)
* Otherwise, if a handler exists for the resource with any action, it is used (e.g., `@auth.on.threads`)
* Finally, if no specific handlers match, the global handler is used (e.g., `@auth.on`)
* If no global handler is set, the request is accepted
This allows you to set default behavior with a global handler while
overriding specific routes as needed.
@@ -71,10 +100,64 @@ class Auth:
"""Reference to auth exception definitions.
Provides access to all exception definitions used in the auth system,
like HTTPException, etc."""
like HTTPException, etc.
"""
def __init__(self) -> None:
self.on = _On(self)
"""Entry point for authorization handlers that control access to specific resources.
The on class provides a flexible way to define authorization rules for different
resources and actions in your application. It supports three main usage patterns:
1. Global handlers that run for all resources and actions
2. Resource-specific handlers that run for all actions on a resource
3. Resource and action specific handlers for fine-grained control
Each handler must be an async function that accepts two parameters:
- ctx (AuthContext): Contains request context and authenticated user info
- value: The data being authorized (type varies by endpoint)
The handler should return one of:
- None or True: Accept the request
- False: Reject with 403 error
- FilterType: Apply filtering rules to the response
???+ example "Examples"
Global handler for all requests:
```python
@auth.on
async def reject_unhandled_requests(ctx: AuthContext, value: Any) -> None:
print(f"Request to {ctx.path} by {ctx.user.identity}")
return False
```
Resource-specific handler. This would take precedence over the global handler
for all actions on the `threads` resource:
```python
@auth.on.threads
async def check_thread_access(ctx: AuthContext, value: Any) -> bool:
# Allow access only to threads created by the user
return value.get("created_by") == ctx.user.identity
```
Resource and action specific handler:
```python
@auth.on.threads.delete
async def prevent_thread_deletion(ctx: AuthContext, value: Any) -> bool:
# Only admins can delete threads
return "admin" in ctx.user.permissions
```
Multiple resources or actions:
```python
@auth.on(resources=["threads", "runs"], actions=["create", "update"])
async def rate_limit_writes(ctx: AuthContext, value: Any) -> bool:
# Implement rate limiting for write operations
return await check_rate_limit(ctx.user.identity)
```
"""
# These are accessed by the API. Changes to their names or types is
# will be considered a breaking change.
self._handlers: dict[tuple[str, str], list[types.Handler]] = {}
@@ -88,21 +171,23 @@ class Auth:
The authentication handler is responsible for verifying credentials
and returning user scopes. It can accept any of the following parameters
by name:
- request (Request): The raw ASGI request object
- body (dict): The parsed request body
- path (str): The request path
- method (str): The HTTP method
- scopes (list[str]): Required scopes
- path_params (dict[str, str]): URL path parameters
- query_params (dict[str, str]): URL query parameters
- headers (dict[str, bytes]): Request headers
- authorization (str): The Authorization header value
- path (str): The request path, e.g., "/threads/abcd-1234-abcd-1234/runs/abcd-1234-abcd-1234/stream"
- method (str): The HTTP method, e.g., "GET"
- path_params (dict[str, str]): URL path parameters, e.g., {"thread_id": "abcd-1234-abcd-1234", "run_id": "abcd-1234-abcd-1234"}
- query_params (dict[str, str]): URL query parameters, e.g., {"stream": "true"}
- headers (dict[bytes, bytes]): Request headers
- authorization (str | None): The Authorization header value (e.g., "Bearer <token>")
Args:
fn (Callable): The authentication handler function to register.
Must return tuple[scopes, user]
where scopes is a list of string claims (like "runs:read", etc.)
and user is either a user object (or similar dict) or a user id string.
Must return a representation of the user. This could be a:
- string (the user id)
- dict containing {"identity": str, "permissions": list[str]}
- or an object with identity and permissions properties
Permissions can be optionally used by your handlers downstream.
Returns:
The registered handler function.
@@ -114,21 +199,38 @@ class Auth:
Basic token authentication:
```python
@auth.authenticate
async def authenticate(authorization: str) -> tuple[list[str], str]:
async def authenticate(authorization: str) -> str:
user_id = verify_token(authorization)
return ["read"], user_id
return user_id
```
Complex authentication with request context:
Accept the full request context:
```python
@auth.authenticate
async def authenticate(
method: str,
path: str,
headers: dict[str, bytes]
) -> tuple[list[str], MinimalUser]:
) -> str:
user = await verify_request(method, path, headers)
return user.scopes, user
return user
```
Return user name and permissions:
```python
@auth.authenticate
async def authenticate(
method: str,
path: str,
headers: dict[str, bytes]
) -> Auth.types.MinimalUserDict:
permissions, user = await verify_request(method, path, headers)
# Permissions could be things like ["runs:read", "runs:write", "threads:read", "threads:write"]
return {
"identity": user["id"],
"permissions": permissions,
"display_name": user["name"],
}
```
"""
if self._authenticate_handler is not None:
@@ -363,9 +465,58 @@ AHO = typing.TypeVar("AHO", bound=_ActionHandler[dict[str, typing.Any]])
class _On:
"""Entry point for authorization handlers that control access to specific resources.
The _On class provides a flexible way to define authorization rules for different resources
and actions in your application. It supports three main usage patterns:
1. Global handlers that run for all resources and actions
2. Resource-specific handlers that run for all actions on a resource
3. Resource and action specific handlers for fine-grained control
Each handler must be an async function that accepts two parameters:
- ctx (AuthContext): Contains request context and authenticated user info
- value: The data being authorized (type varies by endpoint)
The handler should return one of:
- None or True: Accept the request
- False: Reject with 403 error
- FilterType: Apply filtering rules to the response
???+ example "Examples"
Global handler for all requests:
```python
@auth.on
async def log_all_requests(ctx: AuthContext, value: Any) -> None:
print(f"Request to {ctx.path} by {ctx.user.identity}")
return True
```
Resource-specific handler:
```python
@auth.on.threads
async def check_thread_access(ctx: AuthContext, value: Any) -> bool:
# Allow access only to threads created by the user
return value.get("created_by") == ctx.user.identity
```
Resource and action specific handler:
```python
@auth.on.threads.delete
async def prevent_thread_deletion(ctx: AuthContext, value: Any) -> bool:
# Only admins can delete threads
return "admin" in ctx.user.permissions
```
Multiple resources or actions:
```python
@auth.on(resources=["threads", "runs"], actions=["create", "update"])
async def rate_limit_writes(ctx: AuthContext, value: Any) -> bool:
# Implement rate limiting for write operations
return await check_rate_limit(ctx.user.identity)
```
"""
Entry point for @auth.on decorators.
Provides access to specific resources."""
__slots__ = (
"_auth",
@@ -420,7 +571,9 @@ class _On:
return fn
# Used with parameters, return a decorator
def decorator(handler: AHO) -> AHO:
def decorator(
handler: AHO,
) -> AHO:
if isinstance(resources, str):
resource_list = [resources]
else:
+38 -23
View File
@@ -16,6 +16,8 @@ from dataclasses import dataclass
from datetime import datetime
from uuid import UUID
import typing_extensions
RunStatus = typing.Literal["pending", "error", "success", "timeout", "interrupted"]
"""Status of a run execution.
@@ -143,9 +145,10 @@ class MinimalUser(typing.Protocol):
class MinimalUserDict(typing.TypedDict, total=False):
"""The minimal user dictionary."""
identity: str
identity: typing_extensions.Required[str]
display_name: str
is_authenticated: bool
permissions: Sequence[str]
@typing.runtime_checkable
@@ -167,17 +170,28 @@ class BaseUser(typing.Protocol):
"""The unique identifier for the user."""
...
@property
def permissions(self) -> Sequence[str]:
"""The permissions associated with the user."""
...
Authenticator = Callable[
..., Awaitable[tuple[list[str], typing.Union[MinimalUser, str, MinimalUserDict]]]
...,
Awaitable[
typing.Union[
MinimalUser, str, BaseUser, MinimalUserDict, typing.Mapping[str, typing.Any]
],
],
]
"""Type for authentication functions.
An authenticator can return either:
1. A tuple of (scopes, MinimalUser/BaseUser)
2. A tuple of (scopes, str) where str is the user identity
1. A string (user_id)
2. A dict containing {"identity": str, "permissions": list[str]}
3. An object with identity and permissions properties
Scopes can be used downstream by your authorization logic to determine
Permissions can be used downstream by your authorization logic to determine
access permissions to different resources.
The authenticate decorator will automatically inject any of the following parameters
@@ -188,11 +202,10 @@ Parameters:
body (dict): The parsed request body
path (str): The request path
method (str): The HTTP method (GET, POST, etc.)
scopes (list[str]): The required scopes for this endpoint
path_params (dict[str, str] | None): URL path parameters
query_params (dict[str, str] | None): URL query parameters
headers (dict[str, bytes] | None): Request headers
authorization (str | None): The Authorization header value
authorization (str | None): The Authorization header value (e.g. "Bearer <token>")
???+ example "Examples"
Basic authentication with token:
@@ -202,9 +215,8 @@ Parameters:
auth = Auth()
@auth.authenticate
async def authenticate1(authorization: str) -> tuple[list[str], MinimalUser]:
user = await get_user(authorization)
return ["read", "write"], user
async def authenticate1(authorization: str) -> Auth.types.MinimalUserDict:
return await get_user(authorization)
```
Authentication with multiple parameters:
@@ -214,17 +226,17 @@ Parameters:
method: str,
path: str,
headers: dict[str, bytes]
) -> tuple[list[str], str]:
) -> Auth.types.MinimalUserDict:
# Custom auth logic using method, path and headers
user_id = verify_request(method, path, headers)
return ["read"], user_id
user = verify_request(method, path, headers)
return user
```
Accepting the raw ASGI request:
```python
MY_SECRET = "my-secret-key"
@auth.authenticate
async def get_current_user(request: Request) -> tuple[list[str], dict]:
async def get_current_user(request: Request) -> Auth.types.MinimalUserDict:
try:
token = (request.headers.get("authorization") or "").split(" ", 1)[1]
payload = jwt.decode(token, MY_SECRET, algorithms=["HS256"])
@@ -244,10 +256,11 @@ Parameters:
raise HTTPException(status_code=401, detail="User not found")
user_data = response.json()
return payload.get("role", []), {
"username": user_data["id"],
"email": user_data["email"],
"full_name": user_data.get("user_metadata", {}).get("full_name")
return {
"identity": user_data["id"],
"display_name": user_data.get("name"),
"permissions": user_data.get("permissions", []),
"is_authenticated": True,
}
```
"""
@@ -261,8 +274,8 @@ class BaseAuthContext:
authorization decisions.
"""
scopes: Sequence[str]
"""The scopes granted to the authenticated user."""
permissions: Sequence[str]
"""The permissions granted to the authenticated user."""
user: BaseUser
"""The authenticated user."""
@@ -688,16 +701,18 @@ class on:
```python
from langgraph_sdk import Auth
@Auth.on
auth = Auth()
@auth.on
def handle_all(params: Auth.on.value):
raise Exception("Not authorized")
@Auth.on.threads.create
@auth.on.threads.create
def handle_thread_create(params: Auth.on.threads.create.value):
# Handle thread creation
pass
@Auth.on.assistants.search
@auth.on.assistants.search
def handle_assistant_search(params: Auth.on.assistants.search.value):
# Handle assistant search
pass
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "langgraph-sdk"
version = "0.1.46"
version = "0.1.47"
description = "SDK for interacting with LangGraph API"
authors = []
license = "MIT"